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