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