• 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/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     auto parent = hostNode->GetParent();
81     expandDisplay_ = dialogTheme->GetExpandDisplay() || dialogPattern->IsShowInFreeMultiWindow();
82     keyboardAvoidMode_ = dialogPattern->GetDialogProperties().keyboardAvoidMode;
83     keyboardAvoidDistance_ = dialogPattern->GetDialogProperties().keyboardAvoidDistance;
84     isUIExtensionSubWindow_ = dialogPattern->IsUIExtensionSubWindow();
85     hostWindowRect_ = dialogPattern->GetHostWindowRect();
86     customSize_ = dialogProp->GetUseCustomStyle().value_or(false);
87     gridCount_ = dialogProp->GetGridCount().value_or(-1);
88     isShowInSubWindow_ = dialogProp->GetShowInSubWindowValue(false);
89     isModal_ = dialogProp->GetIsModal().value_or(true);
90     auto enableHoverMode = dialogProp->GetEnableHoverMode().value_or(false);
91     hoverModeArea_ = dialogProp->GetHoverModeArea().value_or(HoverModeAreaType::BOTTOM_SCREEN);
92     auto safeAreaManager = pipeline->GetSafeAreaManager();
93     auto keyboardInsert = safeAreaManager->GetKeyboardInset();
94     isKeyBoardShow_ = keyboardInsert.IsValid();
95     isHoverMode_ = enableHoverMode ? pipeline->IsHalfFoldHoverStatus() : false;
96     auto windowManager = pipeline->GetWindowManager();
97     CHECK_NULL_VOID(windowManager);
98     dialogPattern->UpdateFontScale();
99     isSuitOldMeasure_ = dialogPattern->GetIsSuitOldMeasure();
100     auto dialogContext = dialogPattern->GetDialogContext();
101     CHECK_NULL_VOID(dialogContext);
102     isSuitableForElderly_ = (dialogPattern->GetIsSuitableForAging() && dialogPattern->GetCustomNode()) &&
103                             windowManager->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING &&
104                             GreatOrEqual(dialogContext->GetFontScale(), 1.75f);
105     auto isPickerDialog = dialogPattern->GetIsPickerDialog();
106     if (isPickerDialog || customSize_) {
107         isSuitableForElderly_ = false;
108     }
109     if (isSuitableForElderly_ || GreatOrEqual(dialogContext->GetFontScale(), 1.75f)) {
110         dialogPattern->UpdateDeviceOrientation(SystemProperties::GetDeviceOrientation());
111     }
112     UpdateSafeArea(hostNode);
113     const auto& layoutConstraint = dialogProp->GetLayoutConstraint();
114     const auto& parentIdealSize = layoutConstraint->parentIdealSize;
115     OptionalSizeF realSize;
116     // dialog size fit screen.
117     realSize.UpdateIllegalSizeWithCheck(parentIdealSize);
118     embeddedDialogOffsetY_ = 0.0f;
119     if (IsEmbeddedDialog(hostNode)) {
120         if (!realSize.IsValid()) {
121             realSize.UpdateIllegalSizeWithCheck(layoutConstraint->maxSize);
122         }
123         if (dialogPattern->GetDialogProperties().dialogImmersiveMode == ImmersiveMode::EXTEND) {
124             SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_SYSTEM,
125                 .edges = SAFE_AREA_EDGE_TOP | SAFE_AREA_EDGE_BOTTOM };
126             dialogProp->UpdateSafeAreaExpandOpts(opts);
127         }
128         embeddedDialogOffsetY_ = GetEmbeddedDialogOffsetY(hostNode);
129     }
130     layoutWrapper->GetGeometryNode()->SetFrameSize(realSize.ConvertToSizeT());
131     layoutWrapper->GetGeometryNode()->SetContentSize(realSize.ConvertToSizeT());
132     // update child layout constraint
133     auto childLayoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
134     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
135     if (children.empty()) {
136         return;
137     }
138     auto child = children.front();
139     // constraint child size unless developer is using customStyle
140     if (!customSize_) {
141         auto maxSize = layoutConstraint->maxSize;
142         if (isSuitOldMeasure_) {
143             maxSize.SetWidth(pipeline->GetRootWidth());
144             maxSize.SetHeight(pipeline->GetRootHeight());
145         }
146         UpdateChildMaxSizeHeight(maxSize);
147         childLayoutConstraint.UpdateMaxSizeWithCheck(maxSize);
148         ComputeInnerLayoutParam(childLayoutConstraint, dialogProp);
149         UpdateChildLayoutConstraint(dialogProp, childLayoutConstraint, child);
150     }
151 
152     if (isSuitableForElderly_ && SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
153         childLayoutConstraint.maxSize.SetWidth(LANDSCAPE_DIALOG_WIDTH_RATIO * pipeline->GetRootWidth());
154     }
155     // childSize_ and childOffset_ is used in Layout.
156     child->Measure(childLayoutConstraint);
157     if (!layoutWrapper->GetHostNode()->GetPattern<DialogPattern>()->GetCustomNode()) {
158         if (isSuitOldMeasure_) {
159             dialogMaxHeight_ = childLayoutConstraint.maxSize.Height();
160         }
161         AnalysisHeightOfChild(layoutWrapper);
162     }
163 }
164 
UpdateChildMaxSizeHeight(SizeT<float> & maxSize)165 void DialogLayoutAlgorithm::UpdateChildMaxSizeHeight(SizeT<float>& maxSize)
166 {
167     if (!isHoverMode_) {
168         maxSize.MinusPadding(0, 0, safeAreaInsets_.top_.Length(), 0);
169         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE) && LessNotEqual(gridCount_, 0)) {
170             maxSize.MinusPadding(0, 0, 0, safeAreaInsets_.bottom_.Length());
171         }
172         return;
173     }
174     alignBottomScreen_ = !isKeyBoardShow_ && hoverModeArea_ == HoverModeAreaType::BOTTOM_SCREEN;
175     if (alignBottomScreen_) {
176         maxSize.MinusPadding(0, 0, foldCreaseRect.Bottom(), safeAreaInsets_.bottom_.Length());
177         return;
178     }
179     maxSize.SetHeight(foldCreaseRect.Top() - safeAreaInsets_.top_.Length());
180 }
181 
UpdateChildLayoutConstraint(const RefPtr<DialogLayoutProperty> & dialogProp,LayoutConstraintF & childLayoutConstraint,RefPtr<LayoutWrapper> & childLayoutWrapper)182 void DialogLayoutAlgorithm::UpdateChildLayoutConstraint(const RefPtr<DialogLayoutProperty>& dialogProp,
183     LayoutConstraintF& childLayoutConstraint, RefPtr<LayoutWrapper>& childLayoutWrapper)
184 {
185     auto childLayoutProperty = childLayoutWrapper->GetLayoutProperty();
186     auto dialogWidth = dialogProp->GetWidth().value_or(Dimension(-1, DimensionUnit::VP));
187     auto dialogHeight = dialogProp->GetHeight().value_or(Dimension(-1, DimensionUnit::VP));
188     if (NonNegative(dialogHeight.Value())) {
189         childLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(dialogHeight)));
190     }
191     if (NonNegative(dialogWidth.Value())) {
192         childLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(dialogWidth), std::nullopt));
193     }
194     childLayoutConstraint.UpdateMaxSizeWithCheck(SizeF(dialogWidth.Value(), dialogHeight.Value()));
195 }
196 
AnalysisHeightOfChild(LayoutWrapper * layoutWrapper)197 void DialogLayoutAlgorithm::AnalysisHeightOfChild(LayoutWrapper* layoutWrapper)
198 {
199     float scrollHeight = 0.0f;
200     float listHeight = 0.0f;
201     float restHeight = 0.0f;
202     float restWidth = 0.0f;
203     RefPtr<LayoutWrapper> scroll;
204     RefPtr<LayoutWrapper> list;
205     for (const auto& children : layoutWrapper->GetAllChildrenWithBuild()) {
206         restWidth = children->GetGeometryNode()->GetMarginFrameSize().Width();
207         restHeight = children->GetGeometryNode()->GetMarginFrameSize().Height();
208         for (const auto& grandson : children->GetAllChildrenWithBuild()) {
209             if (grandson->GetHostTag() == V2::SCROLL_ETS_TAG) {
210                 scroll = grandson;
211                 scrollHeight = grandson->GetGeometryNode()->GetMarginFrameSize().Height();
212             } else if (grandson->GetHostTag() == V2::LIST_ETS_TAG) {
213                 list = grandson;
214                 listHeight = grandson->GetGeometryNode()->GetMarginFrameSize().Height();
215             } else {
216                 restHeight -= grandson->GetGeometryNode()->GetMarginFrameSize().Height();
217             }
218         }
219     }
220 
221     if (scroll != nullptr) {
222         AnalysisLayoutOfContent(layoutWrapper, scroll);
223     }
224 
225     if (scroll != nullptr && list != nullptr) {
226         Distribute(scrollHeight, listHeight, restHeight);
227         auto childConstraint = CreateDialogChildConstraint(layoutWrapper, scrollHeight, restWidth);
228         scroll->Measure(childConstraint);
229         childConstraint = CreateDialogChildConstraint(layoutWrapper, listHeight, restWidth);
230         list->Measure(childConstraint);
231     } else {
232         if (scroll != nullptr) {
233             auto childConstraint =
234                 CreateDialogChildConstraint(layoutWrapper, std::min(restHeight, scrollHeight), restWidth);
235             UpdateIsScrollHeightNegative(layoutWrapper, std::min(restHeight, scrollHeight));
236             scroll->Measure(childConstraint);
237         }
238         if (list != nullptr) {
239             auto childConstraint =
240                 CreateDialogChildConstraint(layoutWrapper, std::min(restHeight, listHeight), restWidth);
241             list->Measure(childConstraint);
242         }
243     }
244 }
245 
AnalysisLayoutOfContent(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & scroll)246 void DialogLayoutAlgorithm::AnalysisLayoutOfContent(LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& scroll)
247 {
248     auto hostNode = layoutWrapper->GetHostNode();
249     CHECK_NULL_VOID(hostNode);
250     auto dialogPattern = hostNode->GetPattern<DialogPattern>();
251     CHECK_NULL_VOID(dialogPattern);
252     auto text = scroll->GetAllChildrenWithBuild().front();
253     CHECK_NULL_VOID(text);
254     auto textLayoutProperty = DynamicCast<TextLayoutProperty>(text->GetLayoutProperty());
255     CHECK_NULL_VOID(textLayoutProperty);
256     textLayoutProperty->UpdateWordBreak(dialogPattern->GetDialogProperties().wordBreak);
257     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(text->GetLayoutAlgorithm());
258     CHECK_NULL_VOID(layoutAlgorithmWrapper);
259     auto textLayoutAlgorithm = DynamicCast<TextLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
260     CHECK_NULL_VOID(textLayoutAlgorithm);
261     auto scrollPropery = scroll->GetLayoutProperty();
262     CHECK_NULL_VOID(scrollPropery);
263     if (dialogPattern->GetTitle().empty() && dialogPattern->GetSubtitle().empty()) {
264         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) &&
265             GreatNotEqual(textLayoutAlgorithm->GetLineCount(), 1)) {
266             scroll->GetLayoutProperty()->UpdateAlignment(Alignment::CENTER_LEFT);
267         } else {
268             scroll->GetLayoutProperty()->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 
321     if (dialogProp->GetWidth().has_value()) {
322         auto dialogWidth = dialogProp->GetWidth().value_or(Dimension(-1, DimensionUnit::VP));
323         auto widthVal = dialogWidth.Unit() == DimensionUnit::PERCENT ? maxSize.Width() : dialogWidth.ConvertToPx();
324         if (Positive(widthVal)) {
325             width = widthVal;
326         }
327     }
328 
329     auto defaultMinHeight = DIALOG_MIN_HEIGHT.ConvertToPx();
330     auto defaultMaxHeight = IsGetExpandDisplayValidHeight() ? expandDisplayValidHeight_ : maxSize.Height();
331     innerLayout.minSize = SizeF(width, defaultMinHeight);
332     innerLayout.maxSize = SizeF(width, defaultMaxHeight * DIALOG_MAX_HEIGHT_RATIO);
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 * DIALOG_MAX_HEIGHT_RATIO;
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_ && expandDisplay_) {
524         ClipUIExtensionSubWindowContent(dialog, clipMask);
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     subWindowId_ = SubwindowManager::GetInstance()->GetDialogSubWindowId();
556     CHECK_NULL_VOID(layoutWrapper);
557     auto frameNode = layoutWrapper->GetHostNode();
558     CHECK_NULL_VOID(frameNode);
559     auto dialogProp = DynamicCast<DialogLayoutProperty>(layoutWrapper->GetLayoutProperty());
560     CHECK_NULL_VOID(dialogProp);
561     auto pipelineContext = PipelineContext::GetCurrentContext();
562     CHECK_NULL_VOID(pipelineContext);
563     auto dialogTheme = pipelineContext->GetTheme<DialogTheme>();
564     CHECK_NULL_VOID(dialogTheme);
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 subWindow = SubwindowManager::GetInstance()->GetSubwindow(subWindowId_);
583         CHECK_NULL_VOID(subWindow);
584         auto subOverlayManager = subWindow->GetOverlayManager();
585         CHECK_NULL_VOID(subOverlayManager);
586         MultipleDialog(dialogProp, childSize, selfSize, subOverlayManager);
587     }
588     dialogOffset_ = dialogProp->GetDialogOffset().value_or(DimensionOffset());
589     alignment_ = dialogProp->GetDialogAlignment().value_or(DialogAlignment::DEFAULT);
590     topLeftPoint_ = ComputeChildPosition(childSize, dialogProp, selfSize);
591     auto isNonUIExtensionSubwindow = isShowInSubWindow_ && !isUIExtensionSubWindow_;
592     if ((!isModal_ || isNonUIExtensionSubwindow) && !dialogProp->GetIsScenceBoardDialog().value_or(false)) {
593         ProcessMaskRect(
594             DimensionRect(Dimension(childSize.Width()), Dimension(childSize.Height()), DimensionOffset(topLeftPoint_)),
595             frameNode);
596     }
597     child->GetGeometryNode()->SetMarginFrameOffset(topLeftPoint_);
598     AdjustHeightForKeyboard(layoutWrapper, child);
599     child->Layout();
600     SetSubWindowHotarea(dialogProp, childSize, selfSize, frameNode->GetId());
601 }
602 
AdjustHeightForKeyboard(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & child)603 void DialogLayoutAlgorithm::AdjustHeightForKeyboard(LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& child)
604 {
605     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE) || !child || !resizeFlag_ ||
606         keyboardAvoidMode_ == KeyboardAvoidMode::NONE) {
607         return;
608     }
609     auto childLayoutProperty = child->GetLayoutProperty();
610     auto dialogProp = DynamicCast<DialogLayoutProperty>(layoutWrapper->GetLayoutProperty());
611     CHECK_NULL_VOID(childLayoutProperty);
612     CHECK_NULL_VOID(dialogProp);
613     auto childConstraint =
614         CreateDialogChildConstraint(layoutWrapper, dialogChildSize_.Height(), dialogChildSize_.Width());
615     auto dialogHeight = Dimension(dialogChildSize_.Height(), DimensionUnit::PX);
616     auto dialogWidth = Dimension(dialogChildSize_.Width(), DimensionUnit::PX);
617     if (dialogProp->GetWidth().has_value()) {
618         childLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(dialogWidth), std::nullopt));
619     }
620     if (dialogProp->GetHeight().has_value()) {
621         childLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(dialogHeight)));
622     }
623     child->Measure(childConstraint);
624     child->GetGeometryNode()->SetFrameSize(dialogChildSize_);
625     auto renderContext = child->GetHostNode()->GetRenderContext();
626     CHECK_NULL_VOID(renderContext);
627     renderContext->SetClipToFrame(true);
628     renderContext->UpdateClipEdge(true);
629 }
630 
SetSubWindowHotarea(const RefPtr<DialogLayoutProperty> & dialogProp,SizeF childSize,SizeF selfSize,int32_t frameNodeId)631 void DialogLayoutAlgorithm::SetSubWindowHotarea(
632     const RefPtr<DialogLayoutProperty>& dialogProp, SizeF childSize, SizeF selfSize, int32_t frameNodeId)
633 {
634     if (!dialogProp->GetShowInSubWindowValue(false)) {
635         return;
636     }
637 
638     std::vector<Rect> rects;
639     Rect rect;
640     if (!dialogProp->GetIsScenceBoardDialog().value_or(false)) {
641         rect = Rect(topLeftPoint_.GetX(), topLeftPoint_.GetY(), childSize.Width(), childSize.Height());
642     } else {
643         rect = Rect(0.0f, 0.0f, selfSize.Width(), selfSize.Height());
644     }
645     if (isUIExtensionSubWindow_ && isModal_) {
646         if (expandDisplay_) {
647             auto isValid = hostWindowRect_.GetSize().IsPositive();
648             auto hostOffset = Offset(hostWindowRect_.GetX(), hostWindowRect_.GetY());
649             auto hostSize = Size(hostWindowRect_.Width(), hostWindowRect_.Height());
650             rect = isValid ? Rect(hostOffset, hostSize) : Rect(0.0f, 0.0f, selfSize.Width(), selfSize.Height());
651         } else {
652             rect = Rect(0.0f, 0.0f, selfSize.Width(), selfSize.Height());
653         }
654     }
655     rects.emplace_back(rect);
656     SubwindowManager::GetInstance()->SetHotAreas(rects, frameNodeId, subWindowId_);
657 }
658 
IsDialogTouchingBoundary(OffsetF topLeftPoint,SizeF childSize,SizeF selfSize)659 bool DialogLayoutAlgorithm::IsDialogTouchingBoundary(OffsetF topLeftPoint, SizeF childSize, SizeF selfSize)
660 {
661     auto pipelineContext = PipelineContext::GetCurrentContext();
662     CHECK_NULL_RETURN(pipelineContext, false);
663     auto safeAreaInsets = pipelineContext->GetSafeArea();
664     float bottomSecurity = static_cast<float>(PORTRAIT_BOTTOM_SECURITY.ConvertToPx());
665     auto height = safeAreaInsets.bottom_.start == 0 ? selfSize.Height() - bottomSecurity : safeAreaInsets.bottom_.start;
666     auto width = selfSize.Width();
667     if (topLeftPoint.GetY() + childSize.Height() >= height) {
668         touchingBoundaryFlag_ = TouchingBoundaryType::TouchBottomBoundary;
669     } else if (topLeftPoint.GetX() + childSize.Width() >= width) {
670         touchingBoundaryFlag_ = TouchingBoundaryType::TouchRightBoundary;
671     } else {
672         touchingBoundaryFlag_ = TouchingBoundaryType::NotTouchBoundary;
673         return false;
674     }
675     return true;
676 }
677 
MultipleDialog(const RefPtr<DialogLayoutProperty> & dialogProp,const SizeF & childSize,const SizeF & selfSize,const RefPtr<OverlayManager> subOverlayManager)678 void DialogLayoutAlgorithm::MultipleDialog(const RefPtr<DialogLayoutProperty>& dialogProp, const SizeF& childSize,
679     const SizeF& selfSize, const RefPtr<OverlayManager> subOverlayManager)
680 {
681     std::map<int32_t, RefPtr<FrameNode>> DialogMap(
682         subOverlayManager->GetDialogMap().begin(), subOverlayManager->GetDialogMap().end());
683     int dialogMapSize = static_cast<int>(DialogMap.size());
684     if (dialogMapSize > 1) {
685         auto it = DialogMap.begin();
686         for (int i = 1; i < dialogMapSize - 1; i++) {
687             it++;
688         }
689         auto predialogProp = DynamicCast<DialogLayoutProperty>(it->second->GetLayoutProperty());
690         auto firstdialogProp = DynamicCast<DialogLayoutProperty>(DialogMap.begin()->second->GetLayoutProperty());
691         dialogProp->UpdateDialogOffset(predialogProp->GetDialogOffset().value_or(DimensionOffset()) +
692                                        DimensionOffset(MULTIPLE_DIALOG_OFFSET_X, MULTIPLE_DIALOG_OFFSET_Y));
693         dialogOffset_ = dialogProp->GetDialogOffset().value_or(DimensionOffset());
694         alignment_ = dialogProp->GetDialogAlignment().value_or(DialogAlignment::DEFAULT);
695         topLeftPoint_ = ComputeChildPosition(childSize, dialogProp, selfSize);
696         if (IsDialogTouchingBoundary(topLeftPoint_, childSize, selfSize)) {
697             if (touchingBoundaryFlag_ == TouchingBoundaryType::TouchBottomBoundary) {
698                 dialogProp->UpdateDialogOffset(
699                     DimensionOffset(predialogProp->GetDialogOffset().value_or(DimensionOffset()).GetX(),
700                         firstdialogProp->GetDialogOffset().value_or(DimensionOffset()).GetY()));
701             } else if (touchingBoundaryFlag_ == TouchingBoundaryType::TouchRightBoundary) {
702                 dialogProp->UpdateDialogOffset(firstdialogProp->GetDialogOffset().value_or(DimensionOffset()));
703             }
704         }
705     }
706 }
707 
ComputeChildPosition(const SizeF & childSize,const RefPtr<DialogLayoutProperty> & prop,const SizeF & selfSize)708 OffsetF DialogLayoutAlgorithm::ComputeChildPosition(
709     const SizeF& childSize, const RefPtr<DialogLayoutProperty>& prop, const SizeF& selfSize)
710 {
711     OffsetF topLeftPoint;
712     auto pipelineContext = PipelineContext::GetCurrentContext();
713     CHECK_NULL_RETURN(pipelineContext, OffsetF());
714     auto dialogTheme = pipelineContext->GetTheme<DialogTheme>();
715     const auto& layoutConstraint = prop->GetLayoutConstraint();
716     CHECK_NULL_RETURN(dialogTheme, OffsetF());
717     auto dialogOffsetX =
718         ConvertToPx(CalcLength(dialogOffset_.GetX()), layoutConstraint->scaleProperty, selfSize.Width());
719     auto dialogOffsetY =
720         ConvertToPx(CalcLength(dialogOffset_.GetY()), layoutConstraint->scaleProperty, selfSize.Height());
721     OffsetF dialogOffset = OffsetF(dialogOffsetX.value_or(0.0), dialogOffsetY.value_or(0.0));
722     auto isHostWindowAlign = isUIExtensionSubWindow_ && expandDisplay_ && hostWindowRect_.GetSize().IsPositive();
723     auto maxSize = isHostWindowAlign ? hostWindowRect_.GetSize() : layoutConstraint->maxSize;
724     if (!SetAlignmentSwitch(maxSize, childSize, topLeftPoint)) {
725         topLeftPoint = OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / HALF;
726     }
727     if (isHostWindowAlign) {
728         topLeftPoint += hostWindowRect_.GetOffset();
729     }
730     const auto& expandSafeAreaOpts = prop->GetSafeAreaExpandOpts();
731     bool needAvoidKeyboard = true;
732     if ((expandSafeAreaOpts && (expandSafeAreaOpts->type & SAFE_AREA_TYPE_KEYBOARD)) ||
733         keyboardAvoidMode_ == KeyboardAvoidMode::NONE) {
734         needAvoidKeyboard = false;
735     }
736     return AdjustChildPosition(topLeftPoint, dialogOffset, childSize, needAvoidKeyboard);
737 }
738 
IsAlignmentByWholeScreen()739 bool DialogLayoutAlgorithm::IsAlignmentByWholeScreen()
740 {
741     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
742         return false;
743     }
744 
745     switch (alignment_) {
746         case DialogAlignment::TOP:
747         case DialogAlignment::TOP_START:
748         case DialogAlignment::TOP_END:
749         case DialogAlignment::BOTTOM:
750         case DialogAlignment::BOTTOM_START:
751         case DialogAlignment::BOTTOM_END:
752             return false;
753         case DialogAlignment::CENTER:
754         case DialogAlignment::CENTER_START:
755         case DialogAlignment::CENTER_END:
756         default:
757             return true;
758     }
759 }
760 
CaculateMaxSize(SizeF & maxSize)761 void DialogLayoutAlgorithm::CaculateMaxSize(SizeF& maxSize)
762 {
763     auto halfScreenHeight = maxSize.Height() / HALF;
764     if (!customSize_ && isHoverMode_) {
765         maxSize.SetHeight(halfScreenHeight);
766     }
767     if (!customSize_ && !IsAlignmentByWholeScreen()) {
768         if (isHoverMode_ && hoverModeArea_ == HoverModeAreaType::TOP_SCREEN) {
769             maxSize.SetHeight(foldCreaseRect.Top());
770             return;
771         }
772         maxSize.MinusHeight(safeAreaBottomLength_);
773     }
774 }
775 
SetAlignmentSwitch(SizeF & maxSize,const SizeF & childSize,OffsetF & topLeftPoint)776 bool DialogLayoutAlgorithm::SetAlignmentSwitch(SizeF& maxSize, const SizeF& childSize, OffsetF& topLeftPoint)
777 {
778     auto halfScreenHeight = maxSize.Height() / HALF;
779     CaculateMaxSize(maxSize);
780     if (alignment_ != DialogAlignment::DEFAULT || Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
781         switch (alignment_) {
782             case DialogAlignment::TOP:
783                 topLeftPoint = OffsetF((maxSize.Width() - childSize.Width()) / HALF, 0.0);
784                 break;
785             case DialogAlignment::CENTER:
786                 topLeftPoint =
787                     OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / HALF;
788                 break;
789             case DialogAlignment::BOTTOM:
790                 topLeftPoint =
791                     OffsetF((maxSize.Width() - childSize.Width()) / HALF, maxSize.Height() - childSize.Height());
792                 break;
793             case DialogAlignment::TOP_START:
794                 topLeftPoint = OffsetF(0.0, 0.0);
795                 break;
796             case DialogAlignment::TOP_END:
797                 topLeftPoint = OffsetF(maxSize.Width() - childSize.Width(), 0.0);
798                 break;
799             case DialogAlignment::CENTER_START:
800                 topLeftPoint = OffsetF(0.0, maxSize.Height() - childSize.Height()) / HALF;
801                 break;
802             case DialogAlignment::CENTER_END:
803                 topLeftPoint =
804                     OffsetF(maxSize.Width() - childSize.Width(), (maxSize.Height() - childSize.Height()) / HALF);
805                 break;
806             case DialogAlignment::BOTTOM_START:
807                 topLeftPoint = OffsetF(0.0, maxSize.Height() - childSize.Height());
808                 break;
809             case DialogAlignment::BOTTOM_END:
810                 topLeftPoint = OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height());
811                 break;
812             default:
813                 topLeftPoint =
814                     OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / HALF;
815                 break;
816         }
817         if (alignBottomScreen_) {
818             topLeftPoint.SetY(topLeftPoint.GetY() + halfScreenHeight);
819         }
820         return true;
821     }
822 
823     return SetAlignmentSwitchLessThanAPITwelve(maxSize, childSize, topLeftPoint);
824 }
825 
SetAlignmentSwitchLessThanAPITwelve(const SizeF & maxSize,const SizeF & childSize,OffsetF & topLeftPoint)826 bool DialogLayoutAlgorithm::SetAlignmentSwitchLessThanAPITwelve(const SizeF& maxSize, const SizeF& childSize,
827     OffsetF& topLeftPoint)
828 {
829     auto container = Container::Current();
830     CHECK_NULL_RETURN(container, false);
831     auto displayInfo = container->GetDisplayInfo();
832     CHECK_NULL_RETURN(displayInfo, false);
833     auto foldStatus = displayInfo->GetFoldStatus();
834     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && displayInfo->GetIsFoldable() &&
835         (foldStatus == FoldStatus::EXPAND || foldStatus == FoldStatus::HALF_FOLD)) {
836         topLeftPoint = OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / HALF;
837         return true;
838     }
839 
840     bool version10OrLarger = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN);
841     if (version10OrLarger && SystemProperties::GetDeviceType() == DeviceType::PHONE) {
842         if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
843             topLeftPoint = OffsetF(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / HALF;
844             return true;
845         }
846         if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::PORTRAIT) {
847             topLeftPoint = OffsetF((maxSize.Width() - childSize.Width()) / HALF,
848                 std::max(maxSize.Height() - childSize.Height() - GetPaddingBottom(), 0.0));
849             return true;
850         }
851     }
852     return false;
853 }
854 
UpdateTouchRegion()855 void DialogLayoutAlgorithm::UpdateTouchRegion()
856 {
857     //update touch region is not completed.
858 }
859 
GetPaddingBottom() const860 double DialogLayoutAlgorithm::GetPaddingBottom() const
861 {
862     auto pipelineContext = PipelineContext::GetCurrentContext();
863     CHECK_NULL_RETURN(pipelineContext, 0);
864     auto dialogTheme = pipelineContext->GetTheme<DialogTheme>();
865     CHECK_NULL_RETURN(dialogTheme, 0);
866     auto bottom = dialogTheme->GetDefaultDialogMarginBottom();
867     if (keyboardAvoidDistance_.has_value()) {
868         return pipelineContext->NormalizeToPx(keyboardAvoidDistance_.value());
869     } else {
870         return pipelineContext->NormalizeToPx(bottom);
871     }
872 }
873 
AdjustChildPosition(OffsetF & topLeftPoint,const OffsetF & dialogOffset,const SizeF & childSize,bool needAvoidKeyboard)874 OffsetF DialogLayoutAlgorithm::AdjustChildPosition(
875     OffsetF& topLeftPoint, const OffsetF& dialogOffset, const SizeF& childSize, bool needAvoidKeyboard)
876 {
877     auto pipelineContext = PipelineContext::GetCurrentContext();
878     CHECK_NULL_RETURN(pipelineContext, topLeftPoint + dialogOffset);
879     if (!customSize_ && LessNotEqual(topLeftPoint.GetY() + embeddedDialogOffsetY_, safeAreaInsets_.top_.end)) {
880         topLeftPoint.SetY(safeAreaInsets_.top_.end);
881     }
882     if (alignBottomScreen_) {
883         bool alignTop = alignment_ == DialogAlignment::TOP || alignment_ == DialogAlignment::TOP_START ||
884             alignment_ == DialogAlignment::TOP_END;
885         if (topLeftPoint.GetY() < foldCreaseRect.Bottom() || alignTop) {
886             topLeftPoint.SetY(foldCreaseRect.Bottom());
887         }
888     }
889     auto childOffset = topLeftPoint + dialogOffset;
890     auto manager = pipelineContext->GetSafeAreaManager();
891     auto keyboardInsert = manager->GetKeyboardInset();
892     auto childBottom = childOffset.GetY() + childSize.Height() + embeddedDialogOffsetY_;
893     auto paddingBottom = static_cast<float>(GetPaddingBottom());
894     if (needAvoidKeyboard && keyboardInsert.Length() > 0 && childBottom > (keyboardInsert.start - paddingBottom)) {
895         auto limitPos = std::min(childOffset.GetY(),
896             static_cast<float>(safeAreaInsets_.top_.Length() + AVOID_LIMIT_PADDING.ConvertToPx()));
897         childOffset.SetY(childOffset.GetY() - (childBottom - (keyboardInsert.start - paddingBottom)));
898 
899         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) && childOffset.GetY() < limitPos) {
900             resizeFlag_ = true;
901             dialogChildSize_ = childSize;
902             if (limitPos - childOffset.GetY() > dialogChildSize_.Height()) {
903                 dialogChildSize_.MinusHeight(dialogChildSize_.Height());
904             } else {
905                 dialogChildSize_.MinusHeight(limitPos - childOffset.GetY());
906             }
907             childOffset.SetY(limitPos);
908         }
909     }
910     return childOffset;
911 }
912 
UpdateSafeArea(const RefPtr<FrameNode> & frameNode)913 void DialogLayoutAlgorithm::UpdateSafeArea(const RefPtr<FrameNode>& frameNode)
914 {
915     auto container = Container::Current();
916     auto currentId = Container::CurrentId();
917     CHECK_NULL_VOID(container);
918     if (container->IsSubContainer()) {
919         currentId = SubwindowManager::GetInstance()->GetParentContainerId(Container::CurrentId());
920         container = AceEngine::Get().GetContainer(currentId);
921         CHECK_NULL_VOID(container);
922         ContainerScope scope(currentId);
923     }
924     auto pipelineContext = container->GetPipelineContext();
925     CHECK_NULL_VOID(pipelineContext);
926     auto context = AceType::DynamicCast<NG::PipelineContext>(pipelineContext);
927     CHECK_NULL_VOID(context);
928     safeAreaInsets_ = context->GetSafeAreaWithoutProcess();
929     if (!IsEmbeddedDialog(frameNode)) {
930         safeAreaBottomLength_ = safeAreaInsets_.bottom_.Length();
931     }
932     auto displayInfo = container->GetDisplayInfo();
933     CHECK_NULL_VOID(displayInfo);
934     auto foldCreaseRects = displayInfo->GetCurrentFoldCreaseRegion();
935     if (!foldCreaseRects.empty()) {
936         foldCreaseRect = foldCreaseRects.front();
937     }
938 }
939 
ClipUIExtensionSubWindowContent(const RefPtr<FrameNode> & dialog,bool isClip)940 void DialogLayoutAlgorithm::ClipUIExtensionSubWindowContent(const RefPtr<FrameNode>& dialog, bool isClip)
941 {
942     CHECK_NULL_VOID(dialog);
943     auto dialogContext = dialog->GetRenderContext();
944     CHECK_NULL_VOID(dialogContext);
945 
946     if (isClip) {
947         auto shapeRect = AceType::MakeRefPtr<ShapeRect>();
948         shapeRect->SetWidth(Dimension(hostWindowRect_.Width()));
949         shapeRect->SetHeight(Dimension(hostWindowRect_.Height()));
950         shapeRect->SetOffset(DimensionOffset(Dimension(hostWindowRect_.GetX()), Dimension(hostWindowRect_.GetY())));
951         auto isFullScreen =
952             IsGetExpandDisplayValidHeight() && NearEqual(expandDisplayValidHeight_, hostWindowRect_.Height());
953         if (expandDisplay_ && !isFullScreen) {
954             shapeRect->SetRadiusWidth(CONTAINER_OUTER_RADIUS);
955         }
956         dialogContext->UpdateClipShape(shapeRect);
957     } else {
958         dialogContext->UpdateClipShape(nullptr);
959     }
960 }
961 
UpdateIsScrollHeightNegative(LayoutWrapper * layoutWrapper,float height)962 void DialogLayoutAlgorithm::UpdateIsScrollHeightNegative(LayoutWrapper* layoutWrapper, float height)
963 {
964     if (height < SCROLL_MIN_HEIGHT_SUITOLD.ConvertToPx()) {
965         const auto& children = layoutWrapper->GetAllChildrenWithBuild();
966         auto child = children.front();
967         auto childSize = child->GetGeometryNode()->GetMarginFrameSize();
968         if (childSize.Height() == dialogMaxHeight_ && childSize.Height() > 0) {
969             auto hostNode = layoutWrapper->GetHostNode();
970             CHECK_NULL_VOID(hostNode);
971             auto dialogPattern = hostNode->GetPattern<DialogPattern>();
972             CHECK_NULL_VOID(dialogPattern);
973             dialogPattern->SetIsScrollHeightNegative(true);
974         }
975     }
976 }
977 
IsEmbeddedDialog(const RefPtr<FrameNode> & frameNode)978 bool DialogLayoutAlgorithm::IsEmbeddedDialog(const RefPtr<FrameNode>& frameNode)
979 {
980     auto parent = frameNode->GetParent();
981     if (parent && (parent->GetTag() == V2::PAGE_ETS_TAG || parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG)) {
982         return true;
983     }
984     return false;
985 }
986 
GetEmbeddedDialogOffsetY(const RefPtr<FrameNode> & frameNode)987 float DialogLayoutAlgorithm::GetEmbeddedDialogOffsetY(const RefPtr<FrameNode>& frameNode)
988 {
989     auto parent = AceType::DynamicCast<FrameNode>(frameNode->GetParent());
990     CHECK_NULL_RETURN(parent, 0.0f);
991     if (parent->GetTag() == V2::PAGE_ETS_TAG) {
992         return parent->GetOffsetRelativeToWindow().GetY();
993     }
994     if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
995         return parent->GetGeometryNode()->GetParentAdjust().GetY();
996     }
997     return 0.0f;
998 }
999 } // namespace OHOS::Ace::NG
1000