• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/dialog/dialog_layout_algorithm.h"
17 
18 #include "base/subwindow/subwindow_manager.h"
19 #include "core/common/ace_engine.h"
20 #include "core/components/container_modal/container_modal_constants.h"
21 #include "core/components_ng/pattern/dialog/dialog_pattern.h"
22 #include "core/components_ng/pattern/overlay/overlay_manager.h"
23 #include "core/components_ng/pattern/text/text_layout_algorithm.h"
24 
25 namespace OHOS::Ace::NG {
26 namespace {
27 
28 // Using UX spec: Constrain max height within 4/5 of screen height.
29 constexpr double DIALOG_HEIGHT_RATIO = 0.8;
30 constexpr double DIALOG_HEIGHT_RATIO_FOR_LANDSCAPE = 0.9;
31 constexpr double DIALOG_HEIGHT_RATIO_FOR_CAR = 0.95;
32 constexpr Dimension DIALOG_MIN_HEIGHT = 70.0_vp;
33 constexpr Dimension FULLSCREEN = 100.0_pct;
34 constexpr Dimension MULTIPLE_DIALOG_OFFSET_X = 48.0_vp;
35 constexpr Dimension MULTIPLE_DIALOG_OFFSET_Y = 48.0_vp;
36 constexpr Dimension SUBWINDOW_DIALOG_DEFAULT_WIDTH = 400.0_vp;
37 constexpr Dimension AVOID_LIMIT_PADDING = 8.0_vp;
38 constexpr double EXPAND_DISPLAY_WINDOW_HEIGHT_RATIO = 0.67;
39 constexpr double EXPAND_DISPLAY_DIALOG_HEIGHT_RATIO = 0.9;
40 constexpr double HALF = 2.0;
41 constexpr double LANDSCAPE_DIALOG_WIDTH_RATIO = 0.75;
42 constexpr Dimension SCROLL_MIN_HEIGHT_SUITOLD = 100.0_vp;
43 constexpr int32_t TEXT_ALIGN_CONTENT_CENTER = 1;
44 constexpr int32_t EXTRA_MASK_NODE_INDEX = 1;
45 } // namespace
46 
Measure(LayoutWrapper * layoutWrapper)47 void DialogLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
48 {
49     CHECK_NULL_VOID(layoutWrapper);
50     auto pipeline = PipelineContext::GetCurrentContext();
51     CHECK_NULL_VOID(pipeline);
52     auto dialogTheme = pipeline->GetTheme<DialogTheme>();
53     CHECK_NULL_VOID(dialogTheme);
54     auto dialogProp = AceType::DynamicCast<DialogLayoutProperty>(layoutWrapper->GetLayoutProperty());
55     CHECK_NULL_VOID(dialogProp);
56     auto hostNode = layoutWrapper->GetHostNode();
57     CHECK_NULL_VOID(hostNode);
58     auto dialogPattern = hostNode->GetPattern<DialogPattern>();
59     CHECK_NULL_VOID(dialogPattern);
60     auto parent = hostNode->GetParent();
61     expandDisplay_ = dialogTheme->GetExpandDisplay() || dialogPattern->IsShowInFreeMultiWindow();
62     keyboardAvoidMode_ = dialogPattern->GetDialogProperties().keyboardAvoidMode;
63     keyboardAvoidDistance_ = dialogPattern->GetDialogProperties().keyboardAvoidDistance;
64     isUIExtensionSubWindow_ = dialogPattern->IsUIExtensionSubWindow();
65     hostWindowRect_ = dialogPattern->GetHostWindowRect();
66     customSize_ = dialogProp->GetUseCustomStyle().value_or(false);
67     gridCount_ = dialogProp->GetGridCount().value_or(-1);
68     isShowInSubWindow_ = dialogProp->GetShowInSubWindowValue(false);
69     isModal_ = dialogProp->GetIsModal().value_or(true);
70     auto enableHoverMode = dialogProp->GetEnableHoverMode().value_or(false);
71     hoverModeArea_ = dialogProp->GetHoverModeArea().value_or(HoverModeAreaType::BOTTOM_SCREEN);
72     auto safeAreaManager = pipeline->GetSafeAreaManager();
73     auto keyboardInsert = safeAreaManager->GetKeyboardInset();
74     isKeyBoardShow_ = keyboardInsert.IsValid();
75     isHoverMode_ = enableHoverMode ? pipeline->IsHalfFoldHoverStatus() : false;
76     auto windowManager = pipeline->GetWindowManager();
77     CHECK_NULL_VOID(windowManager);
78     dialogPattern->UpdateFontScale();
79     isSuitOldMeasure_ = dialogPattern->GetIsSuitOldMeasure();
80     auto dialogContext = dialogPattern->GetContext();
81     CHECK_NULL_VOID(dialogContext);
82     isSuitableForElderly_ = (dialogPattern->GetIsSuitableForAging() || dialogPattern->GetCustomNode()) &&
83                             windowManager->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING &&
84                             GreatOrEqual(dialogContext->GetFontScale(), 1.75f);
85     auto isPickerDialog = dialogPattern->GetIsPickerDialog();
86     if (isPickerDialog || customSize_) {
87         isSuitableForElderly_ = false;
88     }
89     if (isSuitableForElderly_ || GreatOrEqual(dialogContext->GetFontScale(), 1.75f)) {
90         dialogPattern->UpdateDeviceOrientation(SystemProperties::GetDeviceOrientation());
91     }
92     UpdateSafeArea(hostNode);
93     isShowInFloatingWindow_ = dialogPattern->IsShowInFloatingWindow();
94     ResizeDialogSubwindow(dialogPattern->IsShowInFreeMultiWindow(), isShowInSubWindow_, isShowInFloatingWindow_);
95     const auto& layoutConstraint = dialogProp->GetLayoutConstraint();
96     const auto& parentIdealSize = layoutConstraint->parentIdealSize;
97     OptionalSizeF realSize;
98     // dialog size fit screen.
99     realSize.UpdateIllegalSizeWithCheck(parentIdealSize);
100     embeddedDialogOffsetY_ = 0.0f;
101     if (IsEmbeddedDialog(hostNode)) {
102         if (!realSize.IsValid()) {
103             realSize.UpdateIllegalSizeWithCheck(layoutConstraint->maxSize);
104         }
105         if (dialogPattern->GetDialogProperties().dialogImmersiveMode == ImmersiveMode::EXTEND) {
106             SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_SYSTEM,
107                 .edges = SAFE_AREA_EDGE_TOP | SAFE_AREA_EDGE_BOTTOM };
108             dialogProp->UpdateSafeAreaExpandOpts(opts);
109         }
110         embeddedDialogOffsetY_ = GetEmbeddedDialogOffsetY(hostNode);
111     }
112     layoutWrapper->GetGeometryNode()->SetFrameSize(realSize.ConvertToSizeT());
113     layoutWrapper->GetGeometryNode()->SetContentSize(realSize.ConvertToSizeT());
114     // update child layout constraint
115     auto childLayoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
116     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
117     if (children.empty()) {
118         return;
119     }
120     auto child = children.front();
121     // constraint child size unless developer is using customStyle
122     if (!customSize_) {
123         auto maxSize = layoutConstraint->maxSize;
124         if (isSuitOldMeasure_) {
125             maxSize.SetWidth(pipeline->GetRootWidth());
126             maxSize.SetHeight(pipeline->GetRootHeight());
127         }
128         UpdateChildMaxSizeHeight(maxSize);
129         childLayoutConstraint.UpdateMaxSizeWithCheck(maxSize);
130         ComputeInnerLayoutParam(childLayoutConstraint, dialogProp);
131         UpdateChildLayoutConstraint(dialogProp, childLayoutConstraint, child);
132     }
133 
134     if (isSuitableForElderly_ && SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
135         childLayoutConstraint.maxSize.SetWidth(LANDSCAPE_DIALOG_WIDTH_RATIO * pipeline->GetRootWidth());
136     }
137     // childSize_ and childOffset_ is used in Layout.
138     child->Measure(childLayoutConstraint);
139     if (!layoutWrapper->GetHostNode()->GetPattern<DialogPattern>()->GetCustomNode()) {
140         if (isSuitOldMeasure_) {
141             dialogMaxHeight_ = childLayoutConstraint.maxSize.Height();
142         }
143         AnalysisHeightOfChild(layoutWrapper);
144     }
145 }
146 
ResizeDialogSubwindow(bool expandDisplay,bool isShowInSubWindow,bool isShowInFloatingWindow)147 void DialogLayoutAlgorithm::ResizeDialogSubwindow(
148     bool expandDisplay, bool isShowInSubWindow, bool isShowInFloatingWindow)
149 {
150     if (expandDisplay && isShowInSubWindow && isShowInFloatingWindow) {
151         auto currentId = Container::CurrentId();
152         auto subWindow = SubwindowManager::GetInstance()->GetSubwindowByType(currentId, SubwindowType::TYPE_DIALOG);
153         CHECK_NULL_VOID(subWindow);
154         subWindow->ResizeDialogSubwindow();
155     }
156 }
157 
UpdateChildMaxSizeHeight(SizeT<float> & maxSize)158 void DialogLayoutAlgorithm::UpdateChildMaxSizeHeight(SizeT<float>& maxSize)
159 {
160     if (!isHoverMode_) {
161         maxSize.MinusPadding(0, 0, safeAreaInsets_.top_.Length(), 0);
162         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE) && LessNotEqual(gridCount_, 0)) {
163             maxSize.MinusPadding(0, 0, 0, safeAreaInsets_.bottom_.Length());
164         }
165         return;
166     }
167     alignBottomScreen_ = !isKeyBoardShow_ && hoverModeArea_ == HoverModeAreaType::BOTTOM_SCREEN;
168     if (alignBottomScreen_) {
169         maxSize.MinusPadding(0, 0, foldCreaseRect.Bottom(), safeAreaInsets_.bottom_.Length());
170         return;
171     }
172     maxSize.SetHeight(foldCreaseRect.Top() - safeAreaInsets_.top_.Length());
173 }
174 
UpdateChildLayoutConstraint(const RefPtr<DialogLayoutProperty> & dialogProp,LayoutConstraintF & childLayoutConstraint,RefPtr<LayoutWrapper> & childLayoutWrapper)175 void DialogLayoutAlgorithm::UpdateChildLayoutConstraint(const RefPtr<DialogLayoutProperty>& dialogProp,
176     LayoutConstraintF& childLayoutConstraint, RefPtr<LayoutWrapper>& childLayoutWrapper)
177 {
178     auto childLayoutProperty = childLayoutWrapper->GetLayoutProperty();
179     auto dialogWidth = dialogProp->GetWidth().value_or(Dimension(-1, DimensionUnit::VP));
180     auto dialogHeight = dialogProp->GetHeight().value_or(Dimension(-1, DimensionUnit::VP));
181     if (NonNegative(dialogHeight.Value())) {
182         childLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(dialogHeight)));
183     }
184     if (NonNegative(dialogWidth.Value())) {
185         childLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(dialogWidth), std::nullopt));
186     }
187     childLayoutConstraint.UpdateMaxSizeWithCheck(SizeF(
188         dialogWidth.ConvertToPxWithSize(childLayoutConstraint.maxSize.Width()),
189         dialogHeight.ConvertToPxWithSize(childLayoutConstraint.maxSize.Height())));
190 }
191 
AnalysisHeightOfChild(LayoutWrapper * layoutWrapper)192 void DialogLayoutAlgorithm::AnalysisHeightOfChild(LayoutWrapper* layoutWrapper)
193 {
194     float scrollHeight = 0.0f;
195     float listHeight = 0.0f;
196     float restHeight = 0.0f;
197     float restWidth = 0.0f;
198     RefPtr<LayoutWrapper> scroll;
199     RefPtr<LayoutWrapper> list;
200     auto child = layoutWrapper->GetAllChildrenWithBuild().front();
201     CHECK_NULL_VOID(child);
202     restWidth = child->GetLayoutProperty()->GetContentLayoutConstraint()->maxSize.Width();
203     restHeight = child->GetLayoutProperty()->GetContentLayoutConstraint()->maxSize.Height();
204     for (const auto& grandson : child->GetAllChildrenWithBuild()) {
205         if (grandson->GetHostTag() == V2::SCROLL_ETS_TAG) {
206             scroll = grandson;
207             scrollHeight = grandson->GetGeometryNode()->GetMarginFrameSize().Height();
208         } else if (grandson->GetHostTag() == V2::LIST_ETS_TAG) {
209             list = grandson;
210             listHeight = grandson->GetGeometryNode()->GetMarginFrameSize().Height();
211         } else {
212             restHeight -= grandson->GetGeometryNode()->GetMarginFrameSize().Height();
213         }
214     }
215 
216     if (scroll != nullptr) {
217         AnalysisLayoutOfContent(layoutWrapper, scroll);
218     }
219 
220     if (scroll != nullptr && list != nullptr) {
221         Distribute(scrollHeight, listHeight, restHeight);
222         auto childConstraint = CreateDialogChildConstraint(layoutWrapper, scrollHeight, restWidth);
223         scroll->Measure(childConstraint);
224         childConstraint = CreateDialogChildConstraint(layoutWrapper, listHeight, restWidth);
225         list->Measure(childConstraint);
226     } else {
227         if (scroll != nullptr) {
228             auto childConstraint =
229                 CreateDialogChildConstraint(layoutWrapper, std::min(restHeight, scrollHeight), restWidth);
230             UpdateIsScrollHeightNegative(layoutWrapper, std::min(restHeight, scrollHeight));
231             scroll->Measure(childConstraint);
232         }
233         if (list != nullptr) {
234             auto childConstraint =
235                 CreateDialogChildConstraint(layoutWrapper, std::min(restHeight, listHeight), restWidth);
236             list->Measure(childConstraint);
237         }
238     }
239 }
240 
AnalysisLayoutOfContent(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & scroll)241 void DialogLayoutAlgorithm::AnalysisLayoutOfContent(LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& scroll)
242 {
243     auto hostNode = layoutWrapper->GetHostNode();
244     CHECK_NULL_VOID(hostNode);
245     auto dialogPattern = hostNode->GetPattern<DialogPattern>();
246     CHECK_NULL_VOID(dialogPattern);
247     auto text = scroll->GetAllChildrenWithBuild().front();
248     CHECK_NULL_VOID(text);
249     auto textLayoutProperty = DynamicCast<TextLayoutProperty>(text->GetLayoutProperty());
250     CHECK_NULL_VOID(textLayoutProperty);
251     textLayoutProperty->UpdateWordBreak(dialogPattern->GetDialogProperties().wordBreak);
252     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(text->GetLayoutAlgorithm());
253     CHECK_NULL_VOID(layoutAlgorithmWrapper);
254     auto textLayoutAlgorithm = DynamicCast<TextLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
255     CHECK_NULL_VOID(textLayoutAlgorithm);
256     auto pipelineContext = PipelineContext::GetCurrentContext();
257     CHECK_NULL_VOID(pipelineContext);
258     auto dialogTheme = pipelineContext->GetTheme<DialogTheme>();
259     CHECK_NULL_VOID(dialogTheme);
260     auto scrollPropery = scroll->GetLayoutProperty();
261     CHECK_NULL_VOID(scrollPropery);
262     if ((dialogPattern->GetTitle().empty() && dialogPattern->GetSubtitle().empty()) ||
263         dialogTheme->GetTextAlignContent() == TEXT_ALIGN_CONTENT_CENTER) {
264         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) &&
265             GreatNotEqual(textLayoutAlgorithm->GetLineCount(), 1)) {
266             scrollPropery->UpdateAlignment(Alignment::CENTER_LEFT);
267         } else {
268             scrollPropery->UpdateAlignment(Alignment::CENTER);
269         }
270     } else {
271         scrollPropery->UpdateAlignment(Alignment::CENTER_LEFT);
272     }
273 }
274 
Distribute(float & scrollHeight,float & listHeight,float restHeight)275 void DialogLayoutAlgorithm::Distribute(float& scrollHeight, float& listHeight, float restHeight)
276 {
277     if (scrollHeight + listHeight > restHeight) {
278         if (scrollHeight > restHeight / 2.0 && listHeight > restHeight / 2.0) {
279             scrollHeight = restHeight / 2.0;
280             listHeight = restHeight / 2.0;
281         } else if (scrollHeight > restHeight / 2.0) {
282             scrollHeight = restHeight - listHeight;
283         } else {
284             listHeight = restHeight - scrollHeight;
285         }
286     }
287 }
288 
CreateDialogChildConstraint(LayoutWrapper * layoutWrapper,float height,float width)289 LayoutConstraintF DialogLayoutAlgorithm::CreateDialogChildConstraint(
290     LayoutWrapper* layoutWrapper, float height, float width)
291 {
292     auto childConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
293     childConstraint.minSize.SetHeight(height);
294     childConstraint.maxSize.SetHeight(height);
295     childConstraint.percentReference.SetHeight(height);
296     childConstraint.minSize.SetWidth(width);
297     childConstraint.maxSize.SetWidth(width);
298     childConstraint.percentReference.SetWidth(width);
299     return childConstraint;
300 }
301 
ComputeInnerLayoutSizeParam(LayoutConstraintF & innerLayout,const RefPtr<DialogLayoutProperty> & dialogProp)302 bool DialogLayoutAlgorithm::ComputeInnerLayoutSizeParam(LayoutConstraintF& innerLayout,
303     const RefPtr<DialogLayoutProperty>& dialogProp)
304 {
305     // when width is valid, gridCount_ is -1
306     if (GreatOrEqual(gridCount_, 0)) {
307         return false;
308     }
309     CHECK_NULL_RETURN(Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE), false);
310     auto pipeline = PipelineContext::GetCurrentContext();
311     CHECK_NULL_RETURN(pipeline, false);
312     auto dialogTheme = pipeline->GetTheme<DialogTheme>();
313     CHECK_NULL_RETURN(dialogTheme, false);
314 
315     auto maxSize = innerLayout.maxSize;
316     auto width =
317         maxSize.Width() - dialogTheme->GetMarginLeft().ConvertToPx() - dialogTheme->GetMarginRight().ConvertToPx();
318     auto defaultMaxWidth = dialogTheme->GetContainerMaxWidth().ConvertToPx();
319     width = defaultMaxWidth < width ? defaultMaxWidth : width;
320     if (dialogProp->GetWidth().has_value()) {
321         auto dialogWidth = dialogProp->GetWidth().value_or(Dimension(-1, DimensionUnit::VP));
322         auto widthVal = dialogWidth.Unit() == DimensionUnit::PERCENT ? maxSize.Width() : dialogWidth.ConvertToPx();
323         if (Positive(widthVal)) {
324             width = widthVal;
325         }
326     }
327 
328     auto defaultMinHeight = DIALOG_MIN_HEIGHT.ConvertToPx();
329     auto defaultMaxHeight = IsGetExpandDisplayValidHeight() ? expandDisplayValidHeight_ : maxSize.Height();
330     innerLayout.minSize = SizeF(width, defaultMinHeight);
331     double ratioHeight = dialogTheme->GetDialogRatioHeight();
332     innerLayout.maxSize = SizeF(width, defaultMaxHeight * ratioHeight);
333 
334     if (dialogProp->GetHeight().has_value()) {
335         auto dialogHeight = dialogProp->GetHeight().value_or(Dimension(-1, DimensionUnit::VP));
336         // covert user input height to px
337         auto realHeight = dialogHeight.Unit() == DimensionUnit::PERCENT ?
338             dialogHeight.ConvertToPxWithSize(defaultMaxHeight) : dialogHeight.ConvertToPx();
339         // percent and abs height default max value
340         auto height = dialogHeight.Unit() == DimensionUnit::PERCENT ? defaultMaxHeight : realHeight;
341         // abnormal height proc
342         if (NonPositive(realHeight)) {
343             height = defaultMaxHeight * ratioHeight;
344         }
345         innerLayout.minSize = SizeF(width, 0.0);
346         innerLayout.maxSize = SizeF(width, height);
347     }
348     if (isSuitableForElderly_) {
349         if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
350             innerLayout.minSize = SizeF(width, 0.0);
351             innerLayout.maxSize.SetWidth(pipeline->GetRootWidth() * LANDSCAPE_DIALOG_WIDTH_RATIO);
352         }
353     }
354     // update percentRef
355     innerLayout.percentReference = innerLayout.maxSize;
356     return true;
357 }
358 
IsGetExpandDisplayValidHeight()359 bool DialogLayoutAlgorithm::IsGetExpandDisplayValidHeight()
360 {
361     CHECK_NULL_RETURN(expandDisplay_ && isShowInSubWindow_, false);
362     auto pipelineContext = GetCurrentPipelineContext();
363     CHECK_NULL_RETURN(pipelineContext, false);
364     auto expandDisplayValidHeight = pipelineContext->GetDisplayAvailableRect().Height();
365     if (Positive(expandDisplayValidHeight)) {
366         expandDisplayValidHeight_ = expandDisplayValidHeight;
367         return true;
368     }
369     return false;
370 }
371 
GetCurrentPipelineContext()372 RefPtr<PipelineContext> DialogLayoutAlgorithm::GetCurrentPipelineContext()
373 {
374     auto containerId = Container::CurrentId();
375     RefPtr<PipelineContext> context;
376     if (containerId >= MIN_SUBCONTAINER_ID) {
377         auto parentContainerId = SubwindowManager::GetInstance()->GetParentContainerId(containerId);
378         auto parentContainer = AceEngine::Get().GetContainer(parentContainerId);
379         CHECK_NULL_RETURN(parentContainer, nullptr);
380         context = DynamicCast<PipelineContext>(parentContainer->GetPipelineContext());
381     } else {
382         context = PipelineContext::GetCurrentContext();
383     }
384     return context;
385 }
386 
ComputeInnerLayoutParam(LayoutConstraintF & innerLayout,const RefPtr<DialogLayoutProperty> & dialogProp)387 void DialogLayoutAlgorithm::ComputeInnerLayoutParam(LayoutConstraintF& innerLayout,
388     const RefPtr<DialogLayoutProperty>& dialogProp)
389 {
390     CHECK_EQUAL_VOID(ComputeInnerLayoutSizeParam(innerLayout, dialogProp), true);
391     auto maxSize = innerLayout.maxSize;
392     // Set different layout param for different devices
393     // need to use theme json to replace this function.
394     // get grid size type based on the screen where the dialog locate
395     auto gridSizeType = ScreenSystemManager::GetInstance().GetSize(maxSize.Width());
396     RefPtr<GridColumnInfo> columnInfo;
397     if (SystemProperties::GetDeviceType() == DeviceType::CAR) {
398         columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::CAR_DIALOG);
399     } else {
400         columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::DIALOG);
401     }
402     columnInfo->GetParent()->BuildColumnWidth(maxSize.Width());
403     auto pipelineContext = PipelineContext::GetCurrentContext();
404     CHECK_NULL_VOID(pipelineContext);
405     auto width = GetMaxWidthBasedOnGridType(columnInfo, gridSizeType, SystemProperties::GetDeviceType());
406     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
407         width =
408             SUBWINDOW_DIALOG_DEFAULT_WIDTH.ConvertToPx() < width ? SUBWINDOW_DIALOG_DEFAULT_WIDTH.ConvertToPx() : width;
409     }
410     if (SystemProperties::GetDeviceType() == DeviceType::WATCH) {
411         innerLayout.minSize = SizeF(width, 0.0);
412         innerLayout.maxSize = SizeF(width, maxSize.Height());
413     } else if (SystemProperties::GetDeviceType() == DeviceType::PHONE) {
414         if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
415             innerLayout.minSize = SizeF(width, 0.0);
416             innerLayout.maxSize = SizeF(width, maxSize.Height() * DIALOG_HEIGHT_RATIO_FOR_LANDSCAPE);
417         } else {
418             innerLayout.minSize = SizeF(width, 0.0);
419             innerLayout.maxSize = SizeF(width, maxSize.Height() * DIALOG_HEIGHT_RATIO);
420         }
421     } else if (SystemProperties::GetDeviceType() == DeviceType::CAR) {
422         innerLayout.minSize = SizeF(width, 0.0);
423         innerLayout.maxSize = SizeF(width, maxSize.Height() * DIALOG_HEIGHT_RATIO_FOR_CAR);
424     } else {
425         innerLayout.minSize = SizeF(width, 0.0);
426         innerLayout.maxSize = SizeF(width, maxSize.Height() * DIALOG_HEIGHT_RATIO);
427     }
428     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && expandDisplay_) {
429         auto maxHeight = SystemProperties::GetDevicePhysicalHeight() *
430             EXPAND_DISPLAY_WINDOW_HEIGHT_RATIO * EXPAND_DISPLAY_DIALOG_HEIGHT_RATIO;
431         innerLayout.minSize = SizeF(SUBWINDOW_DIALOG_DEFAULT_WIDTH.ConvertToPx(), 0.0);
432         innerLayout.maxSize = SizeF(SUBWINDOW_DIALOG_DEFAULT_WIDTH.ConvertToPx(), maxHeight);
433     }
434     if (isSuitableForElderly_) {
435         if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
436             innerLayout.minSize = SizeF(width, 0.0);
437             innerLayout.maxSize.SetWidth(pipelineContext->GetRootWidth() * LANDSCAPE_DIALOG_WIDTH_RATIO);
438         }
439     }
440     // update percentRef
441     innerLayout.percentReference = innerLayout.maxSize;
442 }
443 
GetMaxWidthBasedOnGridType(const RefPtr<GridColumnInfo> & info,GridSizeType type,DeviceType deviceType)444 double DialogLayoutAlgorithm::GetMaxWidthBasedOnGridType(
445     const RefPtr<GridColumnInfo>& info, GridSizeType type, DeviceType deviceType)
446 {
447     auto parentColumns = info->GetParent()->GetColumns();
448     if (gridCount_ >= 0) {
449         return info->GetWidth(std::min(gridCount_, parentColumns));
450     }
451 
452     return info->GetWidth(std::min(GetDeviceColumns(type, deviceType), parentColumns));
453 }
454 
GetDeviceColumns(GridSizeType type,DeviceType deviceType)455 int32_t DialogLayoutAlgorithm::GetDeviceColumns(GridSizeType type, DeviceType deviceType)
456 {
457     int32_t deviceColumns;
458     if (deviceType == DeviceType::WATCH) {
459         if (type == GridSizeType::SM) {
460             deviceColumns = 3; // 3: the number of deviceColumns
461         } else if (type == GridSizeType::MD) {
462             deviceColumns = 4; // 4: the number of deviceColumns
463         } else {
464             deviceColumns = 5; // 5: the number of deviceColumns
465         }
466     } else if (deviceType == DeviceType::PHONE) {
467         if (type == GridSizeType::SM) {
468             deviceColumns = 4; // 4: the number of deviceColumns
469         } else if (type == GridSizeType::MD) {
470             deviceColumns = 5; // 5: the number of deviceColumns
471         } else {
472             deviceColumns = 6; // 6: the number of deviceColumns
473         }
474     } else if (deviceType == DeviceType::CAR) {
475         if (type == GridSizeType::SM) {
476             deviceColumns = 4; // 4: the number of deviceColumns
477         } else if (type == GridSizeType::MD) {
478             deviceColumns = 6; // 6: the number of deviceColumns
479         } else {
480             deviceColumns = 8; // 8: the number of deviceColumns
481         }
482     } else if (deviceType == DeviceType::TABLET && type == GridSizeType::MD &&
483                Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
484         deviceColumns = 5; // 5: the number of deviceColumns
485     } else {
486         if (type == GridSizeType::SM) {
487             deviceColumns = 2;
488         } else if (type == GridSizeType::MD) {
489             deviceColumns = 3;
490         } else {
491             deviceColumns = 4;
492         }
493     }
494     return deviceColumns;
495 }
496 
ProcessMaskRect(std::optional<DimensionRect> maskRect,const RefPtr<FrameNode> & dialog,bool isMask)497 void DialogLayoutAlgorithm::ProcessMaskRect(
498     std::optional<DimensionRect> maskRect, const RefPtr<FrameNode>& dialog, bool isMask)
499 {
500     auto dialogContext = dialog->GetRenderContext();
501     CHECK_NULL_VOID(dialogContext);
502     auto hub = dialog->GetEventHub<DialogEventHub>();
503     auto width = maskRect->GetWidth();
504     auto height = maskRect->GetHeight();
505     auto offset = maskRect->GetOffset();
506     if (width.IsNegative()) {
507         width = FULLSCREEN;
508     }
509     if (height.IsNegative()) {
510         height = FULLSCREEN;
511     }
512     auto rootWidth = PipelineContext::GetCurrentRootWidth();
513     auto rootHeight = PipelineContext::GetCurrentRootHeight();
514     RectF rect = RectF(offset.GetX().ConvertToPxWithSize(rootWidth), offset.GetY().ConvertToPxWithSize(rootHeight),
515         width.ConvertToPxWithSize(rootWidth), height.ConvertToPxWithSize(rootHeight));
516     auto isMaskFullScreen =
517         rect == RectF(0.0, 0.0, PipelineContext::GetCurrentRootWidth(), PipelineContext::GetCurrentRootHeight());
518     auto clipMask = isModal_ && isMask && !isMaskFullScreen;
519     if (!isShowInSubWindow_ && clipMask) {
520         dialogContext->ClipWithRect(rect);
521         dialogContext->UpdateClipEdge(true);
522     }
523     if (isUIExtensionSubWindow_ && isModal_) {
524         ClipUIExtensionSubWindowContent(dialog);
525     }
526     auto gestureHub = hub->GetOrCreateGestureEventHub();
527     std::vector<DimensionRect> mouseResponseRegion;
528     mouseResponseRegion.emplace_back(width, height, offset);
529     gestureHub->SetMouseResponseRegion(mouseResponseRegion);
530     gestureHub->SetResponseRegion(mouseResponseRegion);
531 }
532 
GetMaskRect(const RefPtr<FrameNode> & dialog)533 std::optional<DimensionRect> DialogLayoutAlgorithm::GetMaskRect(const RefPtr<FrameNode>& dialog)
534 {
535     std::optional<DimensionRect> maskRect;
536     auto dialogPattern = dialog->GetPattern<DialogPattern>();
537     CHECK_NULL_RETURN(dialogPattern, maskRect);
538     maskRect = dialogPattern->GetDialogProperties().maskRect;
539     if (!isUIExtensionSubWindow_) {
540         return maskRect;
541     }
542 
543     if (expandDisplay_ && hostWindowRect_.GetSize().IsPositive()) {
544         auto offset = DimensionOffset(Dimension(hostWindowRect_.GetX()), Dimension(hostWindowRect_.GetY()));
545         maskRect = DimensionRect(Dimension(hostWindowRect_.Width()), Dimension(hostWindowRect_.Height()), offset);
546     } else {
547         maskRect = DimensionRect(CalcDimension(1, DimensionUnit::PERCENT), CalcDimension(1, DimensionUnit::PERCENT),
548             DimensionOffset(CalcDimension(0, DimensionUnit::VP), CalcDimension(0, DimensionUnit::VP)));
549     }
550     return maskRect;
551 }
552 
Layout(LayoutWrapper * layoutWrapper)553 void DialogLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
554 {
555     CHECK_NULL_VOID(layoutWrapper);
556     auto frameNode = layoutWrapper->GetHostNode();
557     CHECK_NULL_VOID(frameNode);
558     auto dialogProp = DynamicCast<DialogLayoutProperty>(layoutWrapper->GetLayoutProperty());
559     CHECK_NULL_VOID(dialogProp);
560     auto pipelineContext = PipelineContext::GetCurrentContext();
561     CHECK_NULL_VOID(pipelineContext);
562     auto dialogTheme = pipelineContext->GetTheme<DialogTheme>();
563     CHECK_NULL_VOID(dialogTheme);
564     ParseSubwindowId(dialogProp);
565     auto selfSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
566     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
567     if (children.empty()) {
568         return;
569     }
570     auto dialogPattern = frameNode->GetPattern<DialogPattern>();
571     CHECK_NULL_VOID(dialogPattern);
572     if (isModal_ && dialogPattern->GetDialogProperties().maskRect.has_value()) {
573         std::optional<DimensionRect> maskRect = GetMaskRect(frameNode);
574         ProcessMaskRect(maskRect, frameNode, true);
575     }
576     auto child = children.front();
577     auto childSize = child->GetGeometryNode()->GetMarginFrameSize();
578     dialogChildSize_ = childSize;
579     // is PcDevice MultipleDialog Offset to the bottom right
580     if (dialogTheme->GetMultipleDialogDisplay() != "stack" && !dialogProp->GetIsModal().value_or(true) &&
581         dialogProp->GetShowInSubWindowValue(false)) {
582         auto pipeline = frameNode->GetContextRefPtr();
583         auto currentId = pipeline ? pipeline->GetInstanceId() : Container::CurrentIdSafely();
584         auto subWindow = SubwindowManager::GetInstance()->GetSubwindowByType(currentId, SubwindowType::TYPE_DIALOG);
585         CHECK_NULL_VOID(subWindow);
586         auto subOverlayManager = subWindow->GetOverlayManager();
587         CHECK_NULL_VOID(subOverlayManager);
588         MultipleDialog(dialogProp, childSize, selfSize, subOverlayManager);
589     }
590     dialogOffset_ = dialogProp->GetDialogOffset().value_or(DimensionOffset());
591     alignment_ = dialogProp->GetDialogAlignment().value_or(DialogAlignment::DEFAULT);
592     topLeftPoint_ = ComputeChildPosition(childSize, dialogProp, selfSize);
593     auto isNonUIExtensionSubwindow = isShowInSubWindow_ && !isUIExtensionSubWindow_;
594     if ((!isModal_ || isNonUIExtensionSubwindow) && !dialogProp->GetIsScenceBoardDialog().value_or(false)) {
595         ProcessMaskRect(
596             DimensionRect(Dimension(childSize.Width()), Dimension(childSize.Height()), DimensionOffset(topLeftPoint_)),
597             frameNode);
598     }
599     child->GetGeometryNode()->SetMarginFrameOffset(topLeftPoint_);
600     AdjustHeightForKeyboard(layoutWrapper, child);
601     child->Layout();
602     SetSubWindowHotarea(dialogProp, childSize, selfSize, frameNode->GetId());
603 }
604 
ParseSubwindowId(const RefPtr<DialogLayoutProperty> & dialogProp)605 void DialogLayoutAlgorithm::ParseSubwindowId(const RefPtr<DialogLayoutProperty>& dialogProp)
606 {
607     CHECK_NULL_VOID(dialogProp);
608     if (!dialogProp->GetShowInSubWindowValue(false)) {
609         return;
610     }
611 
612     subWindowId_ = Container::CurrentId();
613     auto dialogNode = dialogProp->GetHost();
614     CHECK_NULL_VOID(dialogNode);
615     auto pipeline = dialogNode->GetContextRefPtr();
616     CHECK_NULL_VOID(pipeline);
617     subWindowId_ = pipeline->GetInstanceId();
618 }
619 
AdjustHeightForKeyboard(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & child)620 void DialogLayoutAlgorithm::AdjustHeightForKeyboard(LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& child)
621 {
622     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE) || !child || !resizeFlag_ ||
623         keyboardAvoidMode_ == KeyboardAvoidMode::NONE) {
624         return;
625     }
626     auto childLayoutProperty = child->GetLayoutProperty();
627     auto dialogProp = DynamicCast<DialogLayoutProperty>(layoutWrapper->GetLayoutProperty());
628     CHECK_NULL_VOID(childLayoutProperty);
629     CHECK_NULL_VOID(dialogProp);
630     auto childConstraint =
631         CreateDialogChildConstraint(layoutWrapper, dialogChildSize_.Height(), dialogChildSize_.Width());
632     auto dialogHeight = Dimension(dialogChildSize_.Height(), DimensionUnit::PX);
633     auto dialogWidth = Dimension(dialogChildSize_.Width(), DimensionUnit::PX);
634     if (!customSize_ && dialogProp->GetWidth().has_value()) {
635         childLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(dialogWidth), std::nullopt));
636     }
637     if (!customSize_ && dialogProp->GetHeight().has_value()) {
638         childLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(dialogHeight)));
639     }
640     child->Measure(childConstraint);
641     child->GetGeometryNode()->SetFrameSize(dialogChildSize_);
642     auto renderContext = child->GetHostNode()->GetRenderContext();
643     CHECK_NULL_VOID(renderContext);
644     renderContext->SetClipToFrame(true);
645     renderContext->UpdateClipEdge(true);
646 }
647 
SetSubWindowHotarea(const RefPtr<DialogLayoutProperty> & dialogProp,SizeF childSize,SizeF selfSize,int32_t frameNodeId)648 void DialogLayoutAlgorithm::SetSubWindowHotarea(
649     const RefPtr<DialogLayoutProperty>& dialogProp, SizeF childSize, SizeF selfSize, int32_t frameNodeId)
650 {
651     if (!dialogProp->GetShowInSubWindowValue(false)) {
652         return;
653     }
654 
655     std::vector<Rect> rects;
656     Rect rect;
657     if (!dialogProp->GetIsScenceBoardDialog().value_or(false)) {
658         rect = Rect(topLeftPoint_.GetX(), topLeftPoint_.GetY(), childSize.Width(), childSize.Height());
659     } else {
660         rect = Rect(0.0f, 0.0f, selfSize.Width(), selfSize.Height());
661     }
662     if (isUIExtensionSubWindow_ && isModal_) {
663         if (expandDisplay_) {
664             auto isValid = hostWindowRect_.GetSize().IsPositive();
665             auto hostOffset = Offset(hostWindowRect_.GetX(), hostWindowRect_.GetY());
666             auto hostSize = Size(hostWindowRect_.Width(), hostWindowRect_.Height());
667             rect = isValid ? Rect(hostOffset, hostSize) : Rect(0.0f, 0.0f, selfSize.Width(), selfSize.Height());
668             auto contentRect = Rect(topLeftPoint_.GetX(), topLeftPoint_.GetY(), childSize.Width(), childSize.Height());
669             rects.emplace_back(contentRect);
670         } else {
671             rect = Rect(0.0f, 0.0f, selfSize.Width(), selfSize.Height());
672         }
673     }
674     rects.emplace_back(rect);
675     SubwindowManager::GetInstance()->SetHotAreas(rects, SubwindowType::TYPE_DIALOG, frameNodeId, subWindowId_);
676 }
677 
IsDialogTouchingBoundary(OffsetF topLeftPoint,SizeF childSize,SizeF selfSize)678 bool DialogLayoutAlgorithm::IsDialogTouchingBoundary(OffsetF topLeftPoint, SizeF childSize, SizeF selfSize)
679 {
680     auto pipelineContext = PipelineContext::GetCurrentContext();
681     CHECK_NULL_RETURN(pipelineContext, false);
682     auto safeAreaInsets = pipelineContext->GetSafeArea();
683     float bottomSecurity = static_cast<float>(PORTRAIT_BOTTOM_SECURITY.ConvertToPx());
684     auto height = safeAreaInsets.bottom_.start == 0 ? selfSize.Height() - bottomSecurity : safeAreaInsets.bottom_.start;
685     auto width = selfSize.Width();
686     if (topLeftPoint.GetY() + childSize.Height() >= height) {
687         touchingBoundaryFlag_ = TouchingBoundaryType::TouchBottomBoundary;
688     } else if (topLeftPoint.GetX() + childSize.Width() >= width) {
689         touchingBoundaryFlag_ = TouchingBoundaryType::TouchRightBoundary;
690     } else {
691         touchingBoundaryFlag_ = TouchingBoundaryType::NotTouchBoundary;
692         return false;
693     }
694     return true;
695 }
696 
MultipleDialog(const RefPtr<DialogLayoutProperty> & dialogProp,const SizeF & childSize,const SizeF & selfSize,const RefPtr<OverlayManager> subOverlayManager)697 void DialogLayoutAlgorithm::MultipleDialog(const RefPtr<DialogLayoutProperty>& dialogProp, const SizeF& childSize,
698     const SizeF& selfSize, const RefPtr<OverlayManager> subOverlayManager)
699 {
700     std::map<int32_t, RefPtr<FrameNode>> DialogMap(
701         subOverlayManager->GetDialogMap().begin(), subOverlayManager->GetDialogMap().end());
702     int dialogMapSize = static_cast<int>(DialogMap.size());
703     if (dialogMapSize > 1) {
704         auto it = DialogMap.begin();
705         for (int i = 1; i < dialogMapSize - 1; i++) {
706             it++;
707         }
708         auto predialogProp = DynamicCast<DialogLayoutProperty>(it->second->GetLayoutProperty());
709         auto firstdialogProp = DynamicCast<DialogLayoutProperty>(DialogMap.begin()->second->GetLayoutProperty());
710         dialogProp->UpdateDialogOffset(predialogProp->GetDialogOffset().value_or(DimensionOffset()) +
711                                        DimensionOffset(MULTIPLE_DIALOG_OFFSET_X, MULTIPLE_DIALOG_OFFSET_Y));
712         dialogOffset_ = dialogProp->GetDialogOffset().value_or(DimensionOffset());
713         alignment_ = dialogProp->GetDialogAlignment().value_or(DialogAlignment::DEFAULT);
714         topLeftPoint_ = ComputeChildPosition(childSize, dialogProp, selfSize);
715         if (IsDialogTouchingBoundary(topLeftPoint_, childSize, selfSize)) {
716             if (touchingBoundaryFlag_ == TouchingBoundaryType::TouchBottomBoundary) {
717                 dialogProp->UpdateDialogOffset(
718                     DimensionOffset(predialogProp->GetDialogOffset().value_or(DimensionOffset()).GetX(),
719                         firstdialogProp->GetDialogOffset().value_or(DimensionOffset()).GetY()));
720             } else if (touchingBoundaryFlag_ == TouchingBoundaryType::TouchRightBoundary) {
721                 dialogProp->UpdateDialogOffset(firstdialogProp->GetDialogOffset().value_or(DimensionOffset()));
722             }
723         }
724     }
725 }
726 
ComputeChildPosition(const SizeF & childSize,const RefPtr<DialogLayoutProperty> & prop,const SizeF & selfSize)727 OffsetF DialogLayoutAlgorithm::ComputeChildPosition(
728     const SizeF& childSize, const RefPtr<DialogLayoutProperty>& prop, const SizeF& selfSize)
729 {
730     OffsetF topLeftPoint;
731     auto pipelineContext = PipelineContext::GetCurrentContext();
732     CHECK_NULL_RETURN(pipelineContext, OffsetF());
733     auto dialogTheme = pipelineContext->GetTheme<DialogTheme>();
734     const auto& layoutConstraint = prop->GetLayoutConstraint();
735     CHECK_NULL_RETURN(dialogTheme, OffsetF());
736     auto dialogOffsetX =
737         ConvertToPx(CalcLength(dialogOffset_.GetX()), layoutConstraint->scaleProperty, selfSize.Width());
738     auto dialogOffsetY =
739         ConvertToPx(CalcLength(dialogOffset_.GetY()), layoutConstraint->scaleProperty, selfSize.Height());
740     OffsetF dialogOffset = OffsetF(dialogOffsetX.value_or(0.0), dialogOffsetY.value_or(0.0));
741     auto isHostWindowAlign = isUIExtensionSubWindow_ && expandDisplay_ && hostWindowRect_.GetSize().IsPositive();
742     auto maxSize = isHostWindowAlign ? hostWindowRect_.GetSize() : layoutConstraint->maxSize;
743     if (!SetAlignmentSwitch(maxSize, childSize, topLeftPoint)) {
744         topLeftPoint = OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / HALF;
745     }
746     if (isHostWindowAlign) {
747         topLeftPoint += hostWindowRect_.GetOffset();
748     }
749     const auto& expandSafeAreaOpts = prop->GetSafeAreaExpandOpts();
750     bool needAvoidKeyboard = true;
751     if ((expandSafeAreaOpts && (expandSafeAreaOpts->type & SAFE_AREA_TYPE_KEYBOARD)) ||
752         keyboardAvoidMode_ == KeyboardAvoidMode::NONE) {
753         needAvoidKeyboard = false;
754     }
755     return AdjustChildPosition(topLeftPoint, dialogOffset, childSize, needAvoidKeyboard);
756 }
757 
IsAlignmentByWholeScreen()758 bool DialogLayoutAlgorithm::IsAlignmentByWholeScreen()
759 {
760     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
761         return false;
762     }
763 
764     switch (alignment_) {
765         case DialogAlignment::TOP:
766         case DialogAlignment::TOP_START:
767         case DialogAlignment::TOP_END:
768         case DialogAlignment::BOTTOM:
769         case DialogAlignment::BOTTOM_START:
770         case DialogAlignment::BOTTOM_END:
771             return false;
772         case DialogAlignment::CENTER:
773         case DialogAlignment::CENTER_START:
774         case DialogAlignment::CENTER_END:
775         default:
776             return true;
777     }
778 }
779 
CaculateMaxSize(SizeF & maxSize)780 void DialogLayoutAlgorithm::CaculateMaxSize(SizeF& maxSize)
781 {
782     auto halfScreenHeight = maxSize.Height() / HALF;
783     if (!customSize_ && isHoverMode_) {
784         maxSize.SetHeight(halfScreenHeight);
785     }
786     if (!customSize_ && !IsAlignmentByWholeScreen()) {
787         if (isHoverMode_ && hoverModeArea_ == HoverModeAreaType::TOP_SCREEN) {
788             maxSize.SetHeight(foldCreaseRect.Top());
789             return;
790         }
791         maxSize.MinusHeight(safeAreaBottomLength_);
792     }
793 }
794 
SetAlignmentSwitch(SizeF & maxSize,const SizeF & childSize,OffsetF & topLeftPoint)795 bool DialogLayoutAlgorithm::SetAlignmentSwitch(SizeF& maxSize, const SizeF& childSize, OffsetF& topLeftPoint)
796 {
797     auto halfScreenHeight = maxSize.Height() / HALF;
798     CaculateMaxSize(maxSize);
799     if (alignment_ != DialogAlignment::DEFAULT || Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
800         switch (alignment_) {
801             case DialogAlignment::TOP:
802                 topLeftPoint = OffsetF((maxSize.Width() - childSize.Width()) / HALF, 0.0);
803                 break;
804             case DialogAlignment::CENTER:
805                 topLeftPoint =
806                     OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / HALF;
807                 break;
808             case DialogAlignment::BOTTOM:
809                 topLeftPoint =
810                     OffsetF((maxSize.Width() - childSize.Width()) / HALF, maxSize.Height() - childSize.Height());
811                 break;
812             case DialogAlignment::TOP_START:
813                 topLeftPoint = OffsetF(0.0, 0.0);
814                 break;
815             case DialogAlignment::TOP_END:
816                 topLeftPoint = OffsetF(maxSize.Width() - childSize.Width(), 0.0);
817                 break;
818             case DialogAlignment::CENTER_START:
819                 topLeftPoint = OffsetF(0.0, maxSize.Height() - childSize.Height()) / HALF;
820                 break;
821             case DialogAlignment::CENTER_END:
822                 topLeftPoint =
823                     OffsetF(maxSize.Width() - childSize.Width(), (maxSize.Height() - childSize.Height()) / HALF);
824                 break;
825             case DialogAlignment::BOTTOM_START:
826                 topLeftPoint = OffsetF(0.0, maxSize.Height() - childSize.Height());
827                 break;
828             case DialogAlignment::BOTTOM_END:
829                 topLeftPoint = OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height());
830                 break;
831             default:
832                 topLeftPoint =
833                     OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / HALF;
834                 break;
835         }
836         if (alignBottomScreen_) {
837             topLeftPoint.SetY(topLeftPoint.GetY() + halfScreenHeight);
838         }
839         return true;
840     }
841 
842     return SetAlignmentSwitchLessThanAPITwelve(maxSize, childSize, topLeftPoint);
843 }
844 
SetAlignmentSwitchLessThanAPITwelve(const SizeF & maxSize,const SizeF & childSize,OffsetF & topLeftPoint)845 bool DialogLayoutAlgorithm::SetAlignmentSwitchLessThanAPITwelve(const SizeF& maxSize, const SizeF& childSize,
846     OffsetF& topLeftPoint)
847 {
848     auto container = Container::Current();
849     CHECK_NULL_RETURN(container, false);
850     auto displayInfo = container->GetDisplayInfo();
851     CHECK_NULL_RETURN(displayInfo, false);
852     auto foldStatus = displayInfo->GetFoldStatus();
853     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && displayInfo->GetIsFoldable() &&
854         (foldStatus == FoldStatus::EXPAND || foldStatus == FoldStatus::HALF_FOLD)) {
855         topLeftPoint = OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / HALF;
856         return true;
857     }
858 
859     bool version10OrLarger = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN);
860     if (version10OrLarger && SystemProperties::GetDeviceType() == DeviceType::PHONE) {
861         if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
862             topLeftPoint = OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / HALF;
863             return true;
864         }
865         if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::PORTRAIT) {
866             topLeftPoint = OffsetF((maxSize.Width() - childSize.Width()) / HALF,
867                 std::max(maxSize.Height() - childSize.Height() - GetPaddingBottom(), 0.0));
868             return true;
869         }
870     }
871     return false;
872 }
873 
UpdateTouchRegion()874 void DialogLayoutAlgorithm::UpdateTouchRegion()
875 {
876     //update touch region is not completed.
877 }
878 
GetPaddingBottom() const879 double DialogLayoutAlgorithm::GetPaddingBottom() const
880 {
881     auto pipelineContext = PipelineContext::GetCurrentContext();
882     CHECK_NULL_RETURN(pipelineContext, 0);
883     auto dialogTheme = pipelineContext->GetTheme<DialogTheme>();
884     CHECK_NULL_RETURN(dialogTheme, 0);
885     auto bottom = dialogTheme->GetDefaultDialogMarginBottom();
886     if (keyboardAvoidDistance_.has_value()) {
887         return pipelineContext->NormalizeToPx(keyboardAvoidDistance_.value());
888     } else {
889         return pipelineContext->NormalizeToPx(bottom);
890     }
891 }
892 
AdjustChildPosition(OffsetF & topLeftPoint,const OffsetF & dialogOffset,const SizeF & childSize,bool needAvoidKeyboard)893 OffsetF DialogLayoutAlgorithm::AdjustChildPosition(
894     OffsetF& topLeftPoint, const OffsetF& dialogOffset, const SizeF& childSize, bool needAvoidKeyboard)
895 {
896     auto pipelineContext = PipelineContext::GetCurrentContext();
897     CHECK_NULL_RETURN(pipelineContext, topLeftPoint + dialogOffset);
898     if (!customSize_ && LessNotEqual(topLeftPoint.GetY() + embeddedDialogOffsetY_, safeAreaInsets_.top_.end)) {
899         topLeftPoint.SetY(safeAreaInsets_.top_.end);
900     }
901     if (alignBottomScreen_) {
902         bool alignTop = alignment_ == DialogAlignment::TOP || alignment_ == DialogAlignment::TOP_START ||
903             alignment_ == DialogAlignment::TOP_END;
904         if (topLeftPoint.GetY() < foldCreaseRect.Bottom() || alignTop) {
905             topLeftPoint.SetY(foldCreaseRect.Bottom());
906         }
907     }
908     auto childOffset = topLeftPoint + dialogOffset;
909     auto manager = pipelineContext->GetSafeAreaManager();
910     auto keyboardInsert = manager->GetKeyboardInset();
911     auto childBottom = childOffset.GetY() + childSize.Height() + embeddedDialogOffsetY_;
912     auto paddingBottom = static_cast<float>(GetPaddingBottom());
913     if (needAvoidKeyboard && keyboardInsert.Length() > 0 && childBottom > (keyboardInsert.start - paddingBottom)) {
914         auto limitPos = std::min(childOffset.GetY(),
915             static_cast<float>(safeAreaInsets_.top_.Length() + AVOID_LIMIT_PADDING.ConvertToPx()));
916         childOffset.SetY(childOffset.GetY() - (childBottom - (keyboardInsert.start - paddingBottom)));
917 
918         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) && childOffset.GetY() < limitPos) {
919             resizeFlag_ = true;
920             dialogChildSize_ = childSize;
921             if (limitPos - childOffset.GetY() > dialogChildSize_.Height()) {
922                 dialogChildSize_.MinusHeight(dialogChildSize_.Height());
923             } else {
924                 dialogChildSize_.MinusHeight(limitPos - childOffset.GetY());
925             }
926             childOffset.SetY(limitPos);
927         }
928     }
929     return childOffset;
930 }
931 
UpdateSafeArea(const RefPtr<FrameNode> & frameNode)932 void DialogLayoutAlgorithm::UpdateSafeArea(const RefPtr<FrameNode>& frameNode)
933 {
934     auto container = Container::Current();
935     auto currentId = Container::CurrentId();
936     CHECK_NULL_VOID(container);
937     if (container->IsSubContainer()) {
938         currentId = SubwindowManager::GetInstance()->GetParentContainerId(Container::CurrentId());
939         container = AceEngine::Get().GetContainer(currentId);
940         CHECK_NULL_VOID(container);
941         ContainerScope scope(currentId);
942     }
943     safeAreaInsets_ = OverlayManager::GetSafeAreaInsets(frameNode);
944     if (!IsEmbeddedDialog(frameNode)) {
945         safeAreaBottomLength_ = safeAreaInsets_.bottom_.Length();
946     }
947     if (isHoverMode_) {
948         auto displayInfo = container->GetDisplayInfo();
949         CHECK_NULL_VOID(displayInfo);
950         auto foldCreaseRects = displayInfo->GetCurrentFoldCreaseRegion();
951         if (!foldCreaseRects.empty()) {
952             foldCreaseRect = foldCreaseRects.front();
953         }
954     }
955     TAG_LOGI(AceLogTag::ACE_DIALOG, "safeAreaInsets: %{public}s", safeAreaInsets_.ToString().c_str());
956 }
957 
ClipUIExtensionSubWindowContent(const RefPtr<FrameNode> & dialog)958 void DialogLayoutAlgorithm::ClipUIExtensionSubWindowContent(const RefPtr<FrameNode>& dialog)
959 {
960     CHECK_NULL_VOID(dialog);
961     auto isFullScreen =
962         IsGetExpandDisplayValidHeight() && NearEqual(expandDisplayValidHeight_, hostWindowRect_.Height());
963     auto maskNodePtr = dialog->GetChildByIndex(EXTRA_MASK_NODE_INDEX);
964     CHECK_NULL_VOID(maskNodePtr);
965     auto maskNode = AceType::DynamicCast<FrameNode>(maskNodePtr);
966     CHECK_NULL_VOID(maskNode);
967     auto maskNodeLayoutProp = maskNode->GetLayoutProperty();
968     CHECK_NULL_VOID(maskNodeLayoutProp);
969     auto maskGeometryNode = maskNode->GetGeometryNode();
970     CHECK_NULL_VOID(maskGeometryNode);
971     if (expandDisplay_) {
972         maskNodeLayoutProp->ClearUserDefinedIdealSize(true, true);
973         SizeF realSize;
974         realSize.SetWidth(hostWindowRect_.Width());
975         realSize.SetHeight(hostWindowRect_.Height());
976         maskGeometryNode->SetFrameSize(realSize);
977         OffsetF offset;
978         offset.SetX(hostWindowRect_.GetX());
979         offset.SetY(hostWindowRect_.GetY());
980         maskGeometryNode->SetFrameOffset(offset);
981         if (!isFullScreen) {
982             auto maskNodeContext = maskNode->GetRenderContext();
983             CHECK_NULL_VOID(maskNodeContext);
984             maskNodeContext->UpdateBorderRadius(NG::BorderRadiusPropertyT<Dimension>(CONTAINER_OUTER_RADIUS));
985         }
986     } else {
987         maskNodeLayoutProp->UpdateUserDefinedIdealSize(
988             CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(1.0, DimensionUnit::PERCENT)));
989         maskGeometryNode->SetFrameOffset(OffsetF(0, 0));
990         maskNode->Measure(dialog->GetLayoutConstraint());
991     }
992     maskNode->Layout();
993 }
994 
UpdateIsScrollHeightNegative(LayoutWrapper * layoutWrapper,float height)995 void DialogLayoutAlgorithm::UpdateIsScrollHeightNegative(LayoutWrapper* layoutWrapper, float height)
996 {
997     if (height < SCROLL_MIN_HEIGHT_SUITOLD.ConvertToPx()) {
998         const auto& children = layoutWrapper->GetAllChildrenWithBuild();
999         auto child = children.front();
1000         auto childSize = child->GetGeometryNode()->GetMarginFrameSize();
1001         if (childSize.Height() == dialogMaxHeight_ && childSize.Height() > 0) {
1002             auto hostNode = layoutWrapper->GetHostNode();
1003             CHECK_NULL_VOID(hostNode);
1004             auto dialogPattern = hostNode->GetPattern<DialogPattern>();
1005             CHECK_NULL_VOID(dialogPattern);
1006             dialogPattern->SetIsScrollHeightNegative(true);
1007         }
1008     }
1009 }
1010 
IsEmbeddedDialog(const RefPtr<FrameNode> & frameNode)1011 bool DialogLayoutAlgorithm::IsEmbeddedDialog(const RefPtr<FrameNode>& frameNode)
1012 {
1013     auto parent = frameNode->GetParent();
1014     if (parent && (parent->GetTag() == V2::PAGE_ETS_TAG || parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG)) {
1015         return true;
1016     }
1017     return false;
1018 }
1019 
GetEmbeddedDialogOffsetY(const RefPtr<FrameNode> & frameNode)1020 float DialogLayoutAlgorithm::GetEmbeddedDialogOffsetY(const RefPtr<FrameNode>& frameNode)
1021 {
1022     auto parent = AceType::DynamicCast<FrameNode>(frameNode->GetParent());
1023     CHECK_NULL_RETURN(parent, 0.0f);
1024     if (parent->GetTag() == V2::PAGE_ETS_TAG) {
1025         return parent->GetOffsetRelativeToWindow().GetY();
1026     }
1027     if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1028         return parent->GetGeometryNode()->GetParentAdjust().GetY();
1029     }
1030     return 0.0f;
1031 }
1032 } // namespace OHOS::Ace::NG
1033