• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "core/components_ng/pattern/toast/toast_pattern.h"
16 #include "core/animation/animation_util.h"
17 
18 #include "base/subwindow/subwindow_manager.h"
19 #include "base/utils/system_properties.h"
20 #include "base/utils/utils.h"
21 #include "base/log/dump_log.h"
22 #include "core/common/ace_engine.h"
23 #include "core/common/container.h"
24 #include "core/components/common/layout/grid_system_manager.h"
25 #include "core/components/dialog/dialog_theme.h"
26 #include "core/components_ng/layout/layout_wrapper.h"
27 #include "core/components_ng/pattern/text/text_layout_algorithm.h"
28 #include "core/components_ng/pattern/text/text_layout_property.h"
29 #include "core/pipeline/pipeline_base.h"
30 #include "core/pipeline_ng/pipeline_context.h"
31 
32 namespace OHOS::Ace::NG {
33 namespace {
34 constexpr int32_t API_VERSION_9 = 9;
35 constexpr Dimension ADAPT_TOAST_MIN_FONT_SIZE = 12.0_fp;
36 
37 // get main window's pipeline
GetMainPipelineContext()38 RefPtr<PipelineContext> GetMainPipelineContext()
39 {
40     auto containerId = Container::CurrentId();
41     RefPtr<PipelineContext> context;
42     if (containerId >= MIN_SUBCONTAINER_ID) {
43         auto parentContainerId = SubwindowManager::GetInstance()->GetParentContainerId(containerId);
44         auto parentContainer = AceEngine::Get().GetContainer(parentContainerId);
45         CHECK_NULL_RETURN(parentContainer, nullptr);
46         context = AceType::DynamicCast<PipelineContext>(parentContainer->GetPipelineContext());
47     } else {
48         context = PipelineContext::GetCurrentContext();
49     }
50     return context;
51 }
52 } // namespace
53 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & changeConfig)54 bool ToastPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& changeConfig)
55 {
56     CHECK_NULL_RETURN(dirty, false);
57     auto context = IsDefaultToast() ? PipelineContext::GetCurrentContext() : GetMainPipelineContext();
58     CHECK_NULL_RETURN(context, false);
59     auto toastNode = dirty->GetHostNode();
60     CHECK_NULL_RETURN(toastNode, false);
61     auto toastContext = toastNode->GetRenderContext();
62     CHECK_NULL_RETURN(toastContext, false);
63     auto dialogTheme = context->GetTheme<DialogTheme>();
64     CHECK_NULL_RETURN(dialogTheme, false);
65     expandDisplay_ = dialogTheme->GetExpandDisplay() || IsShowInFreeMultiWindow();
66     OffsetT<Dimension> offset { GetOffsetX(dirty), GetOffsetY(dirty) };
67     // show in the float subwindow
68     if (!IsSystemTopMost() && (IsUIExtensionSubWindow() || (!IsDefaultToast() && expandDisplay_))) {
69         auto nodeContext = toastNode->GetContextWithCheck();
70         CHECK_NULL_RETURN(nodeContext, false);
71         auto subwindowOffset = nodeContext->GetDisplayWindowRectInfo().GetOffset();
72         if (!IsUIExtensionSubWindow() && (!NearEqual(subwindowOffset.GetX(), 0) ||
73             !NearEqual(subwindowOffset.GetY(), 0))) {
74             TAG_LOGW(AceLogTag::ACE_OVERLAY, "toast subwindow offset, x: %{public}f, y: %{public}f",
75                 subwindowOffset.GetX(), subwindowOffset.GetY());
76         }
77         OffsetT<Dimension> displayWindowOffset = { Dimension(context->GetDisplayWindowRectInfo().GetOffset().GetX() -
78             subwindowOffset.GetX()), Dimension(context->GetDisplayWindowRectInfo().GetOffset().GetY() -
79             subwindowOffset.GetY()) };
80         TAG_LOGD(AceLogTag::ACE_OVERLAY, "toast displayWindowOffset, x: %{public}.2f vp, y: %{public}.2f vp",
81             displayWindowOffset.GetX().ConvertToVp(), displayWindowOffset.GetY().ConvertToVp());
82         offset += displayWindowOffset;
83     }
84     auto func = [toastContext, offset]() { toastContext->UpdateOffset(offset); };
85     auto toastProp = DynamicCast<ToastLayoutProperty>(dirty->GetLayoutProperty());
86     CHECK_NULL_RETURN(toastProp, false);
87     auto showMode = toastProp->GetShowModeValue(ToastShowMode::DEFAULT);
88     if (showMode == ToastShowMode::TOP_MOST) {
89         auto keyboardAnimationConfig = context->GetKeyboardAnimationConfig();
90         auto safeAreaManager = context->GetSafeAreaManager();
91         auto keyboardHeight = safeAreaManager ? safeAreaManager->GetKeyboardInset().Length() : 0;
92         if (safeAreaManager && NearEqual(keyboardHeight, 0.0f)) {
93             keyboardHeight = safeAreaManager->GetRawKeyboardHeight();
94         }
95         AnimationOption option = AnimationUtil::CreateKeyboardAnimationOption(keyboardAnimationConfig, keyboardHeight);
96         context->Animate(option, option.GetCurve(), func);
97     } else {
98         func();
99     }
100     return true;
101 }
102 
GetOffsetX(const RefPtr<LayoutWrapper> & layoutWrapper)103 Dimension ToastPattern::GetOffsetX(const RefPtr<LayoutWrapper>& layoutWrapper)
104 {
105     auto context = IsDefaultToast() ? PipelineContext::GetCurrentContext() : GetMainPipelineContext();
106     CHECK_NULL_RETURN(context, Dimension(0.0));
107     auto text = layoutWrapper->GetOrCreateChildByIndex(0);
108     CHECK_NULL_RETURN(text, Dimension(0.0));
109     auto rootWidth = context->GetRootWidth();
110     if (IsSystemTopMost()) {
111         rootWidth = static_cast<double>(SystemProperties::GetDeviceWidth());
112     }
113     auto toastProp = DynamicCast<ToastLayoutProperty>(layoutWrapper->GetLayoutProperty());
114     CHECK_NULL_RETURN(toastProp, Dimension(0.0));
115     auto textWidth = text->GetGeometryNode()->GetMarginFrameSize().Width();
116     Alignment alignment = toastProp->GetToastAlignmentValue(Alignment::BOTTOM_CENTER);
117     Dimension offsetX;
118     if (alignment == Alignment::TOP_LEFT || alignment == Alignment::CENTER_LEFT ||
119         alignment == Alignment::BOTTOM_LEFT) {
120         offsetX = Dimension(0.0);
121     } else if (alignment == Alignment::TOP_RIGHT || alignment == Alignment::CENTER_RIGHT ||
122                alignment == Alignment::BOTTOM_RIGHT) {
123         offsetX = Dimension(rootWidth - textWidth);
124     } else {
125         offsetX = Dimension((rootWidth - textWidth) / 2.0f);
126     }
127     return offsetX + toastProp->GetToastOffsetValue(DimensionOffset()).GetX();
128 }
129 
GetOffsetY(const RefPtr<LayoutWrapper> & layoutWrapper)130 Dimension ToastPattern::GetOffsetY(const RefPtr<LayoutWrapper>& layoutWrapper)
131 {
132     auto context = IsDefaultToast() ? PipelineContext::GetCurrentContext() : GetMainPipelineContext();
133     CHECK_NULL_RETURN(context, Dimension(0.0));
134     auto text = layoutWrapper->GetOrCreateChildByIndex(0);
135     CHECK_NULL_RETURN(text, Dimension(0.0));
136     auto rootHeight = IsSystemTopMost() ? static_cast<double>(SystemProperties::GetDeviceHeight())
137                                         : context->GetRootHeight();
138     auto toastProp = DynamicCast<ToastLayoutProperty>(layoutWrapper->GetLayoutProperty());
139     CHECK_NULL_RETURN(toastProp, Dimension(0.0));
140     auto textHeight = text->GetGeometryNode()->GetMarginFrameSize().Height();
141     Dimension offsetY;
142     auto safeAreaManager = context->GetSafeAreaManager();
143     auto safeAreaOffset = safeAreaManager ? safeAreaManager->GetSafeAreaWithoutProcess().bottom_.Length() : 0;
144     auto showMode = toastProp->GetShowModeValue(ToastShowMode::DEFAULT);
145     auto keyboardInset = safeAreaManager ? safeAreaManager->GetKeyboardInset().Length() : 0;
146     if (safeAreaManager && NearEqual(keyboardInset, 0.0f)) {
147         keyboardInset = safeAreaManager->GetRawKeyboardHeight();
148     }
149     auto keyboardOffset = GreatNotEqual(keyboardInset, 0) ? keyboardInset : 0;
150     if (showMode == ToastShowMode::DEFAULT) {
151         safeAreaOffset = std::max(keyboardOffset, safeAreaOffset);
152     }
153     // Get toastBottom and update defaultBottom_
154     auto toastBottom = GetBottomValue(layoutWrapper);
155     if (!toastProp->HasToastAlignment()) {
156         toastBottom_ = toastBottom;
157         if (context->GetMinPlatformVersion() > API_VERSION_9) {
158             offsetY = Dimension(rootHeight - toastBottom - textHeight - safeAreaOffset);
159         } else {
160             offsetY = Dimension(rootHeight - toastBottom);
161         }
162     } else {
163         Alignment alignment = toastProp->GetToastAlignmentValue(Alignment::BOTTOM_CENTER);
164         if (alignment == Alignment::TOP_LEFT || alignment == Alignment::TOP_CENTER ||
165             alignment == Alignment::TOP_RIGHT) {
166             // Top Needs Avoid System Navigation Bar
167             auto safeAreaManager = context->GetSafeAreaManager();
168             auto sysTop = safeAreaManager ? safeAreaManager->GetSystemSafeArea().top_.Length() : 0.0f;
169             offsetY = Dimension(sysTop);
170         } else if (alignment == Alignment::CENTER_LEFT || alignment == Alignment::CENTER ||
171                    alignment == Alignment::CENTER_RIGHT) {
172             offsetY = Dimension((rootHeight - textHeight - safeAreaOffset) / 2.0f);
173         } else {
174             offsetY = Dimension(rootHeight - textHeight - safeAreaOffset);
175         }
176     }
177     //TOP_MOST Toast need to avoid keyboard
178     auto deviceHeight = context->GetRootHeight();
179     if (showMode == ToastShowMode::TOP_MOST && (offsetY.Value() + textHeight > deviceHeight - keyboardOffset)) {
180         offsetY = Dimension(deviceHeight - keyboardOffset - defaultBottom_.ConvertToPx() -textHeight);
181     }
182     TAG_LOGD(AceLogTag::ACE_OVERLAY,
183         "toast device height: %{public}.2f, keyboardOffset: %{public}d, "
184         "textHeight: %{public}.2f, offsetY: %{public}.2f",
185         deviceHeight, (uint32_t)keyboardOffset, textHeight, offsetY.Value());
186     return offsetY + toastProp->GetToastOffsetValue(DimensionOffset()).GetY();
187 }
188 
GetBottomValue(const RefPtr<LayoutWrapper> & layoutWrapper)189 double ToastPattern::GetBottomValue(const RefPtr<LayoutWrapper>& layoutWrapper)
190 {
191     // Obtain the height relative to the main window
192     auto pipeline = IsDefaultToast() ? PipelineContext::GetCurrentContext() : GetMainPipelineContext();
193     CHECK_NULL_RETURN(pipeline, 0.0);
194     auto rootHeight = Dimension(pipeline->GetRootHeight());
195     if (IsSystemTopMost()) {
196         rootHeight = Dimension(static_cast<double>(SystemProperties::GetDeviceHeight()));
197     }
198     auto toastTheme = pipeline->GetTheme<ToastTheme>();
199     CHECK_NULL_RETURN(toastTheme, 0.0);
200 
201     auto toastProp = DynamicCast<ToastLayoutProperty>(layoutWrapper->GetLayoutProperty());
202     CHECK_NULL_RETURN(toastProp, 0.0);
203     defaultBottom_ = toastTheme->GetBottom();
204     auto toastBottom = toastProp->GetBottomValue(defaultBottom_);
205     if (toastBottom.Unit() == DimensionUnit::PERCENT) {
206         toastBottom = rootHeight * toastBottom.Value();
207     }
208     return GreatOrEqual(toastBottom.ConvertToPx(), 0.0) ? toastBottom.ConvertToPx()
209                                                         : toastTheme->GetBottom().ConvertToPx();
210 }
211 
BeforeCreateLayoutWrapper()212 void ToastPattern::BeforeCreateLayoutWrapper()
213 {
214     PopupBasePattern::BeforeCreateLayoutWrapper();
215 
216     auto toastNode = GetHost();
217     CHECK_NULL_VOID(toastNode);
218     auto pipelineContext = IsDefaultToast() ? toastNode->GetContextRefPtr() : GetMainPipelineContext();
219     if (!pipelineContext) {
220         TAG_LOGD(AceLogTag::ACE_OVERLAY, "toast get pipelineContext failed");
221         return;
222     }
223     auto textNode = DynamicCast<FrameNode>(toastNode->GetFirstChild());
224     CHECK_NULL_VOID(textNode);
225     UpdateTextSizeConstraint(textNode);
226 }
227 
UpdateToastSize(const RefPtr<FrameNode> & toast)228 void ToastPattern::UpdateToastSize(const RefPtr<FrameNode>& toast)
229 {
230     CHECK_NULL_VOID(toast);
231     auto toastProperty = toast->GetLayoutProperty<ToastLayoutProperty>();
232     CHECK_NULL_VOID(toastProperty);
233     auto context = PipelineBase::GetCurrentContext();
234     CHECK_NULL_VOID(context);
235     auto rootWidth = Dimension(context->GetRootWidth());
236     if (IsSystemTopMost()) {
237         rootWidth = Dimension(static_cast<double>(SystemProperties::GetDeviceWidth()));
238     }
239     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
240         auto limitWidth = Dimension(GetTextMaxWidth());
241         toastProperty->UpdateUserDefinedIdealSize(CalcSize(NG::CalcLength(limitWidth), std::nullopt));
242     } else {
243         toastProperty->UpdateUserDefinedIdealSize(CalcSize(NG::CalcLength(rootWidth), std::nullopt));
244     }
245 }
246 
UpdateTextSizeConstraint(const RefPtr<FrameNode> & text)247 void ToastPattern::UpdateTextSizeConstraint(const RefPtr<FrameNode>& text)
248 {
249     CHECK_NULL_VOID(text);
250     auto context = PipelineBase::GetCurrentContext();
251     CHECK_NULL_VOID(context);
252     auto gridColumnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::TOAST);
253     auto parent = gridColumnInfo->GetParent();
254     if (parent) {
255         parent->BuildColumnWidth(context->GetRootWidth());
256     }
257     auto maxWidth = Dimension(gridColumnInfo->GetMaxWidth());
258     auto textLayoutProperty = text->GetLayoutProperty();
259     CHECK_NULL_VOID(textLayoutProperty);
260 
261     auto toastTheme = context->GetTheme<ToastTheme>();
262     CHECK_NULL_VOID(toastTheme);
263     auto minWidth = Dimension(toastTheme->GetMinWidth().ConvertToPx());
264     auto minHeight = Dimension(toastTheme->GetMinHeight().ConvertToPx());
265     textLayoutProperty->UpdateCalcMinSize(CalcSize(NG::CalcLength(minWidth), NG::CalcLength(minHeight)));
266 
267     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
268         auto limitHeight = GetTextMaxHeight();
269         textLayoutProperty->UpdateCalcMaxSize(
270             CalcSize(NG::CalcLength(maxWidth), NG::CalcLength(Dimension(limitHeight))));
271 
272         auto textProperty = textNode_->GetLayoutProperty<TextLayoutProperty>();
273         CHECK_NULL_VOID(textProperty);
274         auto toastMaxFontSize = toastTheme->GetTextStyle().GetFontSize();
275         textProperty->UpdateAdaptMaxFontSize(toastMaxFontSize);
276         textProperty->UpdateAdaptMinFontSize(ADAPT_TOAST_MIN_FONT_SIZE);
277         textProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::LAYOUT_CONSTRAINT_FIRST);
278 
279         auto textLineHeight = GetTextLineHeight(text);
280         if (textLineHeight > 0) {
281             auto maxLines = static_cast<int32_t>(limitHeight / textLineHeight);
282             textProperty->UpdateMaxLines(maxLines);
283         }
284     } else {
285         textLayoutProperty->UpdateCalcMaxSize(CalcSize(NG::CalcLength(maxWidth), std::nullopt));
286     }
287 }
288 
OnColorConfigurationUpdate()289 void ToastPattern::OnColorConfigurationUpdate()
290 {
291     auto host = GetHost();
292     CHECK_NULL_VOID(host);
293     auto textContext = host->GetRenderContext();
294     CHECK_NULL_VOID(textContext);
295     auto pipelineContext = PipelineBase::GetCurrentContext();
296     CHECK_NULL_VOID(pipelineContext);
297     auto toastTheme = pipelineContext->GetTheme<ToastTheme>();
298     CHECK_NULL_VOID(toastTheme);
299     auto textColor = toastTheme->GetTextStyle().GetTextColor();
300     auto textLayoutProperty = textNode_->GetLayoutProperty<TextLayoutProperty>();
301     CHECK_NULL_VOID(textLayoutProperty);
302     auto toastInfo = GetToastInfo();
303     textLayoutProperty->UpdateTextColor(toastInfo.textColor.value_or(textColor));
304     host->SetNeedCallChildrenUpdate(false);
305     ToastView::UpdateToastNodeStyle(host);
306 }
307 
OnAttachToFrameNode()308 void ToastPattern::OnAttachToFrameNode()
309 {
310     auto containerId = Container::CurrentId();
311     auto parentContainerId = SubwindowManager::GetInstance()->GetParentContainerId(containerId);
312     auto pipeline =
313         parentContainerId < 0 ? PipelineContext::GetCurrentContext() : PipelineContext::GetMainPipelineContext();
314     CHECK_NULL_VOID(pipeline);
315     auto callbackId =
316         pipeline->RegisterFoldDisplayModeChangedCallback([parentContainerId](FoldDisplayMode foldDisplayMode) {
317             if (foldDisplayMode == FoldDisplayMode::FULL || foldDisplayMode == FoldDisplayMode::MAIN) {
318                 TAG_LOGI(AceLogTag::ACE_OVERLAY, "Window status changes, displayMode is %{public}d", foldDisplayMode);
319                 SubwindowManager::GetInstance()->ResizeWindowForFoldStatus(parentContainerId);
320             }
321         });
322     UpdateFoldDisplayModeChangedCallbackId(callbackId);
323 }
324 
OnDetachFromFrameNode(FrameNode * node)325 void ToastPattern::OnDetachFromFrameNode(FrameNode* node)
326 {
327     auto containerId = Container::CurrentId();
328     auto parentContainerId = SubwindowManager::GetInstance()->GetParentContainerId(containerId);
329     auto pipeline =
330         parentContainerId < 0 ? PipelineContext::GetCurrentContext() : PipelineContext::GetMainPipelineContext();
331     CHECK_NULL_VOID(pipeline);
332     if (HasFoldDisplayModeChangedCallbackId()) {
333         pipeline->UnRegisterFoldDisplayModeChangedCallback(foldDisplayModeChangedCallbackId_.value_or(-1));
334     }
335 }
336 
IsShowInFreeMultiWindow()337 bool ToastPattern::IsShowInFreeMultiWindow()
338 {
339     auto currentId = Container::CurrentId();
340     auto container = Container::Current();
341     if (!container) {
342         TAG_LOGW(AceLogTag::ACE_OVERLAY, "container is null");
343         return false;
344     }
345     if (container->IsSubContainer()) {
346         currentId = SubwindowManager::GetInstance()->GetParentContainerId(currentId);
347         container = AceEngine::Get().GetContainer(currentId);
348         if (!container) {
349             TAG_LOGW(AceLogTag::ACE_OVERLAY, "parent container is null");
350             return false;
351         }
352     }
353     return container->IsFreeMultiWindow();
354 }
355 
IsUIExtensionSubWindow()356 bool ToastPattern::IsUIExtensionSubWindow()
357 {
358     if (IsDefaultToast()) {
359         return false;
360     }
361 
362     auto currentId = Container::CurrentId();
363     auto container = Container::Current();
364     CHECK_NULL_RETURN(container, false);
365     if (container->IsSubContainer()) {
366         currentId = SubwindowManager::GetInstance()->GetParentContainerId(currentId);
367         container = AceEngine::Get().GetContainer(currentId);
368         CHECK_NULL_RETURN(container, false);
369     }
370     return container->IsUIExtensionWindow();
371 }
372 
DumpInfo()373 void ToastPattern::DumpInfo()
374 {
375     DumpLog::GetInstance().AddDesc("Message: " + toastInfo_.message);
376     DumpLog::GetInstance().AddDesc("Duration: " + std::to_string(toastInfo_.duration));
377     DumpLog::GetInstance().AddDesc("Bottom: " + toastInfo_.bottom);
378     std::string isRightToLeft = toastInfo_.isRightToLeft ? "true" : "false";
379     DumpLog::GetInstance().AddDesc("IsRightToLeft: " + isRightToLeft);
380     std::string showMode = toastInfo_.showMode == ToastShowMode::DEFAULT ? "DEFAULT" : "TOP_MOST";
381     DumpLog::GetInstance().AddDesc("ShowMode: " + showMode);
382     auto host = GetHost();
383     CHECK_NULL_VOID(host);
384     auto toastProp = DynamicCast<ToastLayoutProperty>(host->GetLayoutProperty());
385     CHECK_NULL_VOID(toastProp);
386     if (!toastProp->HasToastAlignment()) {
387         DumpLog::GetInstance().AddDesc("Alignment: NONE");
388     } else {
389         DumpLog::GetInstance().AddDesc(
390             "Alignment: " + toastProp->GetToastAlignmentValue().GetAlignmentStr(toastProp->GetLayoutDirection()));
391     }
392     auto offset = toastProp->GetToastOffsetValue(DimensionOffset());
393     DumpLog::GetInstance().AddDesc(
394         "Offset: { dx: " + offset.GetX().ToString() + " dy: " + offset.GetY().ToString() + " }");
395 }
396 
GetTextMaxHeight()397 double ToastPattern::GetTextMaxHeight()
398 {
399     auto pipelineContext = IsDefaultToast() ? PipelineContext::GetCurrentContext() : GetMainPipelineContext();
400     CHECK_NULL_RETURN(pipelineContext, 0.0);
401     double deviceHeight = 0.0;
402     if (IsSystemTopMost()) {
403         deviceHeight = static_cast<double>(SystemProperties::GetDeviceHeight());
404         TAG_LOGD(AceLogTag::ACE_OVERLAY, "SystemTopMost toast get device height: %{public}f.", deviceHeight);
405     } else if (IsUIExtensionSubWindow()) {
406         auto toastNode = GetHost();
407         CHECK_NULL_RETURN(toastNode, 0.0);
408         auto nodeContext = toastNode->GetContextWithCheck();
409         CHECK_NULL_RETURN(nodeContext, 0.0);
410         deviceHeight = nodeContext->GetDisplayWindowRectInfo().Height();
411         TAG_LOGD(AceLogTag::ACE_OVERLAY, "toast in UIExtension subwindow, device height: %{public}f.", deviceHeight);
412     } else {
413         deviceHeight = pipelineContext->GetRootHeight();
414         TAG_LOGD(AceLogTag::ACE_OVERLAY, "toast get device height: %{public}f.", deviceHeight);
415     }
416     if (LessOrEqual(deviceHeight, 0.0)) {
417         TAG_LOGE(AceLogTag::ACE_OVERLAY, "toast get device height is invalid.");
418         deviceHeight = static_cast<double>(SystemProperties::GetDeviceHeight());
419     }
420     auto safeAreaManager = pipelineContext->GetSafeAreaManager();
421     auto bottom = safeAreaManager ? safeAreaManager->GetSafeAreaWithoutProcess().bottom_.Length() : 0;
422     auto top = safeAreaManager ? safeAreaManager->GetSafeAreaWithoutProcess().top_.Length() : 0;
423     auto maxHeight = deviceHeight - bottom - top - toastBottom_;
424     auto limitHeight = (deviceHeight - bottom - top) * 0.65;
425     if (GreatNotEqual(maxHeight, limitHeight)) {
426         maxHeight = limitHeight;
427     }
428 
429     maxHeight = GreatOrEqual(maxHeight, 0.0) ? maxHeight : 0.0;
430     return maxHeight;
431 }
432 
GetTextMaxWidth()433 double ToastPattern::GetTextMaxWidth()
434 {
435     auto pipelineContext = IsDefaultToast() ? PipelineContext::GetCurrentContext() : GetMainPipelineContext();
436     CHECK_NULL_RETURN(pipelineContext, 0.0);
437     double deviceWidth = 0.0;
438     if (IsSystemTopMost()) {
439         deviceWidth = static_cast<double>(SystemProperties::GetDeviceWidth());
440         TAG_LOGD(AceLogTag::ACE_OVERLAY, "SystemTopMost toast get device width: %{public}f.", deviceWidth);
441     } else if (IsUIExtensionSubWindow()) {
442         auto toastNode = GetHost();
443         CHECK_NULL_RETURN(toastNode, 0.0);
444         auto nodeContext = toastNode->GetContextWithCheck();
445         CHECK_NULL_RETURN(nodeContext, 0.0);
446         deviceWidth = nodeContext->GetDisplayWindowRectInfo().Width();
447         TAG_LOGD(AceLogTag::ACE_OVERLAY, "toast in UIExtension subwindow, device width: %{public}f.", deviceWidth);
448     } else {
449         deviceWidth = pipelineContext->GetRootWidth();
450         TAG_LOGD(AceLogTag::ACE_OVERLAY, "toast get device width: %{public}f.", deviceWidth);
451     }
452     if (LessOrEqual(deviceWidth, 0.0)) {
453         TAG_LOGE(AceLogTag::ACE_OVERLAY, "toast get device width is invalid.");
454         deviceWidth = static_cast<double>(SystemProperties::GetDeviceWidth());
455     }
456     auto toastTheme = pipelineContext->GetTheme<ToastTheme>();
457     CHECK_NULL_RETURN(toastTheme, 0.0);
458     auto marging = toastTheme->GetMarging();
459     auto maxWidth = deviceWidth - marging.Left().ConvertToPx() - marging.Right().ConvertToPx();
460     auto maxLimitWidth = toastTheme->GetMaxWidth();
461     if (GreatNotEqual(maxWidth, maxLimitWidth.ConvertToPx())) {
462         maxWidth = maxLimitWidth.ConvertToPx();
463     }
464     return maxWidth;
465 }
466 
GetTextLineHeight(const RefPtr<FrameNode> & textNode)467 int32_t ToastPattern::GetTextLineHeight(const RefPtr<FrameNode>& textNode)
468 {
469     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
470     CHECK_NULL_RETURN(textLayoutProperty, 0);
471     auto layoutConstraint = textLayoutProperty->GetLayoutConstraint();
472     auto textLayoutWrapper = textNode->CreateLayoutWrapper();
473     CHECK_NULL_RETURN(textLayoutWrapper, 0);
474     textLayoutWrapper->Measure(layoutConstraint);
475     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(textLayoutWrapper->GetLayoutAlgorithm());
476     CHECK_NULL_RETURN(layoutAlgorithmWrapper, 0);
477     auto textLayoutAlgorithm = DynamicCast<TextLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
478     CHECK_NULL_RETURN(textLayoutAlgorithm, 0);
479     auto paragraph = textLayoutAlgorithm->GetSingleParagraph();
480     CHECK_NULL_RETURN(paragraph, 0);
481     auto paragHeight = paragraph->GetHeight();
482     auto paragLineCount = paragraph->GetLineCount();
483     int32_t paragLineHeight = 0;
484     if (paragLineCount > 0) {
485         paragLineHeight = static_cast<int32_t>(paragHeight / paragLineCount);
486     }
487     return paragLineHeight;
488 }
489 } // namespace OHOS::Ace::NG
490