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