• 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 
16 #include "core/components_ng/pattern/toast/toast_layout_algorithm.h"
17 
18 #include "core/common/ace_engine.h"
19 #include "core/components_ng/pattern/toast/toast_pattern.h"
20 #include "core/components_ng/pattern/text/text_layout_algorithm.h"
21 
22 namespace OHOS::Ace::NG {
23 namespace {
24     constexpr Dimension LIMIT_SPACING = 8.0_vp;
25 } // namespace
26 
UpdateToastAlign(int32_t & alignment)27 void UpdateToastAlign(int32_t& alignment)
28 {
29     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
30     if (alignment == static_cast<int32_t>(ToastAlignment::TOP_START)) {
31         if (isRtl) {
32             alignment = static_cast<int32_t>(ToastAlignment::TOP_END);
33         }
34     } else if (alignment == static_cast<int32_t>(ToastAlignment::TOP_END)) {
35         if (isRtl) {
36             alignment = static_cast<int32_t>(ToastAlignment::TOP_START);
37         }
38     } else if (alignment == static_cast<int32_t>(ToastAlignment::CENTER_START)) {
39         if (isRtl) {
40             alignment = static_cast<int32_t>(ToastAlignment::CENTER_END);
41         }
42     } else if (alignment == static_cast<int32_t>(ToastAlignment::CENTER_END)) {
43         if (isRtl) {
44             alignment = static_cast<int32_t>(ToastAlignment::CENTER_START);
45         }
46     } else if (alignment == static_cast<int32_t>(ToastAlignment::BOTTOM_START)) {
47         if (isRtl) {
48             alignment = static_cast<int32_t>(ToastAlignment::BOTTOM_END);
49         }
50     } else if (alignment == static_cast<int32_t>(ToastAlignment::BOTTOM_END)) {
51         if (isRtl) {
52             alignment = static_cast<int32_t>(ToastAlignment::BOTTOM_START);
53         }
54     }
55 }
56 
Layout(LayoutWrapper * layoutWrapper)57 void ToastLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
58 {
59     CHECK_NULL_VOID(layoutWrapper);
60     auto frameNode = layoutWrapper->GetHostNode();
61     CHECK_NULL_VOID(frameNode);
62     auto toastPattern = frameNode->GetPattern<ToastPattern>();
63     CHECK_NULL_VOID(toastPattern);
64     auto toastProperty = frameNode->GetLayoutProperty<ToastLayoutProperty>();
65     CHECK_NULL_VOID(toastProperty);
66     auto alignment = toastPattern->GetToastInfo().alignment;
67     UpdateToastAlign(alignment);
68     auto align = Alignment::ParseAlignment(alignment);
69     if (align.has_value()) {
70         toastProperty->UpdateToastAlignment(align.value());
71     } else {
72         toastProperty->ResetToastAlignment();
73     }
74     auto offset = toastPattern->GetToastInfo().offset;
75     if (offset.has_value()) {
76         bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
77         Dimension offsetX = isRtl ? offset->GetX() * (-1) : offset->GetX();
78         offset->SetX(offsetX);
79         toastProperty->UpdateToastOffset(offset.value());
80     } else {
81         toastProperty->ResetToastOffset();
82     }
83     auto text = layoutWrapper->GetOrCreateChildByIndex(0);
84     text->Layout();
85 }
86 
GetLineCount(const RefPtr<LayoutWrapper> & textWrapper,LayoutConstraintF & layoutConstraint)87 size_t GetLineCount(const RefPtr<LayoutWrapper>& textWrapper, LayoutConstraintF& layoutConstraint)
88 {
89     textWrapper->Measure(layoutConstraint);
90     auto layoutAlgorithmWrapper = AceType::DynamicCast<LayoutAlgorithmWrapper>(textWrapper->GetLayoutAlgorithm());
91     CHECK_NULL_RETURN(layoutAlgorithmWrapper, 0);
92     auto textLayoutAlgorithm = AceType::DynamicCast<TextLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
93     CHECK_NULL_RETURN(textLayoutAlgorithm, 0);
94     auto paragraph = textLayoutAlgorithm->GetSingleParagraph();
95     CHECK_NULL_RETURN(paragraph, 0);
96     auto paragLineCount = paragraph->GetLineCount();
97     return paragLineCount;
98 }
99 
Measure(LayoutWrapper * layoutWrapper)100 void ToastLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
101 {
102     CHECK_NULL_VOID(layoutWrapper);
103     auto toastProps = DynamicCast<ToastLayoutProperty>(layoutWrapper->GetLayoutProperty());
104     CHECK_NULL_VOID(toastProps);
105     auto toastNode = layoutWrapper->GetHostNode();
106     CHECK_NULL_VOID(toastNode);
107     auto toastPattern = toastNode->GetPattern<ToastPattern>();
108     CHECK_NULL_VOID(toastPattern);
109     toastPattern->InitWrapperRect(layoutWrapper, toastProps);
110     auto text = layoutWrapper->GetOrCreateChildByIndex(0);
111     auto layoutConstraint = GetTextLayoutConstraint(layoutWrapper);
112     // TextAlign should be START when lines of text are greater than 1
113     if (GetLineCount(text, layoutConstraint) > 1) {
114         auto textLayoutProp = DynamicCast<TextLayoutProperty>(text->GetLayoutProperty());
115         CHECK_NULL_VOID(textLayoutProp);
116         auto context = toastNode->GetContext();
117         CHECK_NULL_VOID(context);
118         auto toastTheme = context->GetTheme<ToastTheme>();
119         CHECK_NULL_VOID(toastTheme);
120         textLayoutProp->UpdateTextAlign(toastTheme->GetMultiLineTextAlign());
121     }
122     text->Measure(layoutConstraint);
123     PerformMeasureSelf(layoutWrapper);
124 }
125 
GetTextLayoutConstraint(LayoutWrapper * layoutWrapper)126 LayoutConstraintF ToastLayoutAlgorithm::GetTextLayoutConstraint(LayoutWrapper* layoutWrapper)
127 {
128     auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
129     auto frameNode = layoutWrapper->GetHostNode();
130     CHECK_NULL_RETURN(frameNode, layoutConstraint);
131     auto toastPattern = frameNode->GetPattern<ToastPattern>();
132     CHECK_NULL_RETURN(toastPattern, layoutConstraint);
133     auto toastProperty = frameNode->GetLayoutProperty<ToastLayoutProperty>();
134     CHECK_NULL_RETURN(toastProperty, layoutConstraint);
135     auto context = toastPattern->GetToastContext();
136     CHECK_NULL_RETURN(context, layoutConstraint);
137     auto safeAreaManager = context->GetSafeAreaManager();
138     auto keyboardInset = 0;
139     if (safeAreaManager) {
140         auto inset = safeAreaManager->GetKeyboardInset().Length();
141         keyboardInset = NearEqual(inset, 0.0f) ? safeAreaManager->GetRawKeyboardHeight() : inset;
142     }
143     auto deviceHeight = context->GetRootHeight();
144     auto keyboardOffset = deviceHeight - keyboardInset;
145     if (toastPattern->IsAlignedWithHostWindow() && GreatNotEqual(keyboardInset, 0)) {
146         deviceHeight = toastPattern->GetUiExtensionHostWindowRect().Height();
147 
148         auto currentId = Container::CurrentId();
149         auto container = Container::Current();
150         CHECK_NULL_RETURN(container, layoutConstraint);
151         if (container->IsSubContainer()) {
152             auto parentContainerId = SubwindowManager::GetInstance()->GetParentContainerId(currentId);
153             auto parentContainer = AceEngine::Get().GetContainer(parentContainerId);
154             CHECK_NULL_RETURN(parentContainer, layoutConstraint);
155             CHECK_NULL_RETURN(parentContainer->IsUIExtensionWindow(), layoutConstraint);
156             auto toastSubwindow = SubwindowManager::GetInstance()->GetToastSubwindow(parentContainer);
157             if (toastSubwindow) {
158                 auto parentWindowRect = toastSubwindow->GetParentWindowRect();
159                 keyboardOffset = deviceHeight - keyboardInset - toastPattern->GetUiExtensionHostWindowRect().Bottom() +
160                                  parentWindowRect.Bottom();
161             }
162         }
163     }
164     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN) && GreatNotEqual(keyboardInset, 0) &&
165         (toastPattern->IsDefaultToast() || toastPattern->IsTopMostToast())) {
166         auto maxHeight = keyboardOffset - toastPattern->GetLimitPos().Value() - LIMIT_SPACING.ConvertToPx();
167         layoutConstraint.maxSize.SetHeight(maxHeight);
168     }
169     return layoutConstraint;
170 }
171 } // namespace OHOS::Ace::NG
172