1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/overlay/sheet_presentation_layout_algorithm.h"
17 
18 #include "base/geometry/axis.h"
19 #include "base/geometry/ng/offset_t.h"
20 #include "base/geometry/ng/size_t.h"
21 #include "base/log/ace_trace.h"
22 #include "base/memory/ace_type.h"
23 #include "base/utils/utils.h"
24 #include "base/window/foldable_window.h"
25 #include "core/components/common/layout/grid_system_manager.h"
26 #include "core/components_ng/base/frame_node.h"
27 #include "core/components_ng/layout/layout_algorithm.h"
28 #include "core/components_ng/pattern/overlay/sheet_presentation_pattern.h"
29 #include "core/components_ng/property/layout_constraint.h"
30 #include "core/components_ng/property/measure_property.h"
31 #include "core/components_ng/property/measure_utils.h"
32 #include "core/components_v2/inspector/inspector_constants.h"
33 #include "core/pipeline_ng/pipeline_context.h"
34 
35 namespace OHOS::Ace::NG {
36 namespace {
37 constexpr int32_t SHEET_HALF_SIZE = 2;
38 constexpr Dimension WINDOW_EDGE_SPACE = 6.0_vp;
39 constexpr Dimension ARROW_VERTICAL_P1_OFFSET_X = 8.0_vp;
40 constexpr Dimension ARROW_VERTICAL_P5_OFFSET_X = 8.0_vp;
41 std::map<Placement, std::vector<Placement>> DIRECTIONS_STATES = {
42     { Placement::BOTTOM,
43         {
44             Placement::BOTTOM,
45         } },
46 };
47 std::map<Placement, std::vector<Placement>> PLACEMENT_STATES = {
48     { Placement::BOTTOM,
49         {
50             Placement::BOTTOM,
51             Placement::BOTTOM_RIGHT,
52             Placement::BOTTOM_LEFT,
53         } },
54 };
55 } // namespace
56 
InitParameter()57 void SheetPresentationLayoutAlgorithm::InitParameter()
58 {
59     auto pipeline = PipelineContext::GetCurrentContext();
60     CHECK_NULL_VOID(pipeline);
61     auto sheetTheme = pipeline->GetTheme<SheetTheme>();
62     CHECK_NULL_VOID(sheetTheme);
63     sheetRadius_ = sheetTheme->GetSheetRadius().ConvertToPx();
64     // if 2in1, enableHoverMode is true by default.
65     auto enableHoverMode = sheetStyle_.enableHoverMode.value_or(false);
66     hoverModeArea_ = sheetStyle_.hoverModeArea.value_or(HoverModeAreaType::BOTTOM_SCREEN);
67     auto safeAreaManager = pipeline->GetSafeAreaManager();
68     CHECK_NULL_VOID(safeAreaManager);
69     auto keyboardInsert = safeAreaManager->GetKeyboardInset();
70     isKeyBoardShow_ = keyboardInsert.IsValid();
71     isHoverMode_ = enableHoverMode ? pipeline->IsHalfFoldHoverStatus() : false;
72 }
73 
CalculateSheetHeightInOtherScenes(LayoutWrapper * layoutWrapper)74 void SheetPresentationLayoutAlgorithm::CalculateSheetHeightInOtherScenes(LayoutWrapper* layoutWrapper)
75 {
76     CHECK_NULL_VOID(layoutWrapper);
77     auto host = layoutWrapper->GetHostNode();
78     CHECK_NULL_VOID(host);
79     auto sheetPattern = host->GetPattern<SheetPresentationPattern>();
80     CHECK_NULL_VOID(sheetPattern);
81     auto foldCreaseRect = sheetPattern->GetFoldScreenRect();
82     if (sheetType_ == SheetType::SHEET_CENTER && isHoverMode_) {
83         float upScreenHeight = foldCreaseRect.Top() - SHEET_HOVERMODE_UP_HEIGHT.ConvertToPx();
84         float downScreenHeight = sheetMaxHeight_ - SHEET_HOVERMODE_DOWN_HEIGHT.ConvertToPx() - foldCreaseRect.Bottom();
85         TAG_LOGD(AceLogTag::ACE_SHEET, "upScreenHeight: %{public}f, downScreenHeight: %{public}f.", upScreenHeight,
86             downScreenHeight);
87         sheetHeight_ = std::min(sheetHeight_,
88             (hoverModeArea_ == HoverModeAreaType::TOP_SCREEN || isKeyBoardShow_) ? upScreenHeight : downScreenHeight);
89     }
90 }
91 
CalculateSheetOffsetInOtherScenes(LayoutWrapper * layoutWrapper)92 void SheetPresentationLayoutAlgorithm::CalculateSheetOffsetInOtherScenes(LayoutWrapper* layoutWrapper)
93 {
94     CHECK_NULL_VOID(layoutWrapper);
95     auto host = layoutWrapper->GetHostNode();
96     CHECK_NULL_VOID(host);
97     auto sheetPattern = host->GetPattern<SheetPresentationPattern>();
98     CHECK_NULL_VOID(sheetPattern);
99     auto geometryNode = layoutWrapper->GetGeometryNode();
100     CHECK_NULL_VOID(geometryNode);
101     auto foldCreaseRect = sheetPattern->GetFoldScreenRect();
102     auto frameSizeHeight = geometryNode->GetFrameSize().Height();
103     if (sheetType_ == SheetType::SHEET_CENTER && isHoverMode_) {
104         float upScreenHeight = foldCreaseRect.Top() - SHEET_HOVERMODE_UP_HEIGHT.ConvertToPx();
105         float downScreenHeight = sheetMaxHeight_ - SHEET_HOVERMODE_DOWN_HEIGHT.ConvertToPx() - foldCreaseRect.Bottom();
106         sheetOffsetY_ = (hoverModeArea_ == HoverModeAreaType::TOP_SCREEN || isKeyBoardShow_)
107                             ? (SHEET_HOVERMODE_UP_HEIGHT.ConvertToPx() +
108                                   (upScreenHeight - frameSizeHeight) / SHEET_HALF_SIZE)
109                             : (foldCreaseRect.Bottom() + (downScreenHeight - frameSizeHeight) / SHEET_HALF_SIZE);
110     }
111 }
112 
Measure(LayoutWrapper * layoutWrapper)113 void SheetPresentationLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
114 {
115     CHECK_NULL_VOID(layoutWrapper);
116     auto layoutProperty = AceType::DynamicCast<SheetPresentationProperty>(layoutWrapper->GetLayoutProperty());
117     CHECK_NULL_VOID(layoutProperty);
118     sheetStyle_ = layoutProperty->GetSheetStyleValue();
119     auto layoutConstraint = layoutProperty->GetLayoutConstraint();
120     if (!layoutConstraint) {
121         TAG_LOGE(AceLogTag::ACE_SHEET, "fail to measure sheet due to layoutConstraint is nullptr");
122         return;
123     }
124     InitParameter();
125     auto maxSize = layoutConstraint->maxSize;
126     if (layoutWrapper->GetGeometryNode() && layoutWrapper->GetGeometryNode()->GetParentLayoutConstraint()) {
127         auto parentConstraint = layoutWrapper->GetGeometryNode()->GetParentLayoutConstraint();
128         layoutConstraint = parentConstraint.value();
129         layoutProperty->UpdateLayoutConstraint(layoutConstraint.value());
130         maxSize = layoutConstraint->maxSize;
131         sheetMaxHeight_ = maxSize.Height();
132         sheetMaxWidth_ = maxSize.Width();
133         sheetWidth_ = GetWidthByScreenSizeType(maxSize, layoutWrapper);
134         sheetHeight_ = GetHeightByScreenSizeType(maxSize);
135         if (sheetStyle_.width.has_value()) {
136             float width = 0.0f;
137             if (sheetStyle_.width->Unit() == DimensionUnit::PERCENT) {
138                 width = sheetStyle_.width->ConvertToPxWithSize(maxSize.Width());
139             } else {
140                 width = sheetStyle_.width->ConvertToPx();
141             }
142             if (width > maxSize.Width() || width < 0.0f) {
143                 width = sheetWidth_;
144             }
145             sheetWidth_ = width;
146         }
147         CalculateSheetHeightInOtherScenes(layoutWrapper);
148         SizeF idealSize(sheetWidth_, sheetHeight_);
149         layoutWrapper->GetGeometryNode()->SetFrameSize(idealSize);
150         layoutWrapper->GetGeometryNode()->SetContentSize(idealSize);
151         auto childConstraint = CreateSheetChildConstraint(layoutProperty);
152         layoutConstraint->percentReference = SizeF(sheetWidth_, sheetHeight_);
153         for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
154             child->Measure(childConstraint);
155         }
156         auto scrollNode = layoutWrapper->GetChildByIndex(1);
157         CHECK_NULL_VOID(scrollNode);
158         childConstraint.selfIdealSize.SetWidth(childConstraint.maxSize.Width());
159         scrollNode->Measure(childConstraint);
160         if ((sheetType_ == SheetType::SHEET_CENTER || sheetType_ == SheetType::SHEET_POPUP)
161             && (sheetStyle_.sheetMode.value_or(SheetMode::LARGE) == SheetMode::AUTO)) {
162             auto&& children = layoutWrapper->GetAllChildrenWithBuild();
163             auto secondIter = std::next(children.begin(), 1);
164             auto secondChild = *secondIter;
165             CHECK_NULL_VOID(secondChild);
166             auto&& scrollChild = secondChild->GetAllChildrenWithBuild();
167             auto builder = scrollChild.front();
168             CHECK_NULL_VOID(builder);
169             auto operatoration = children.front();
170             CHECK_NULL_VOID(operatoration);
171             auto operatorGeometryNode = operatoration->GetGeometryNode();
172             CHECK_NULL_VOID(operatorGeometryNode);
173             auto builderGeometryNode = builder->GetGeometryNode();
174             CHECK_NULL_VOID(builderGeometryNode);
175             sheetHeight_ =
176                 operatorGeometryNode->GetFrameSize().Height() + builderGeometryNode->GetFrameSize().Height();
177             float sheetMaxHeight = sheetMaxHeight_;
178             if (SheetInSplitWindow()) {
179                 auto pipelineContext = PipelineContext::GetCurrentContext();
180                 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
181                 sheetMaxHeight = windowGlobalRect.Height() - SHEET_SPLIT_STATUS_BAR.ConvertToPx()-
182                     SHEET_SPLIT_AI_BAR.ConvertToPx();
183             }
184             auto maxHeight = std::min(sheetMaxHeight, sheetMaxWidth_) * POPUP_LARGE_SIZE;
185             maxHeight = SheetInSplitWindow()
186                 ? maxHeight : std::max(maxHeight, static_cast<float>(SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx()));
187             if (LessNotEqual(sheetHeight_, 0.0f)) {
188                 sheetHeight_ = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
189             } else if (LessOrEqual(sheetHeight_, SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx()) && !SheetInSplitWindow()) {
190                 sheetHeight_ = SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx();
191             } else if (GreatOrEqual(sheetHeight_, maxHeight)) {
192                 sheetHeight_ = maxHeight;
193             }
194             SizeF idealSize(sheetWidth_, sheetHeight_);
195             layoutWrapper->GetGeometryNode()->SetFrameSize(idealSize);
196             childConstraint.maxSize.SetWidth(sheetWidth_);
197             childConstraint.maxSize.SetHeight(sheetHeight_);
198             secondChild->Measure(childConstraint);
199         }
200     }
201 }
202 
Layout(LayoutWrapper * layoutWrapper)203 void SheetPresentationLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
204 {
205     CHECK_NULL_VOID(layoutWrapper);
206     const auto& pipeline = PipelineContext::GetCurrentContext();
207     CHECK_NULL_VOID(pipeline);
208     sheetOffsetX_ = (sheetMaxWidth_ - sheetWidth_) / SHEET_HALF_SIZE;
209     if (sheetType_ == SheetType::SHEET_BOTTOMLANDSPACE) {
210         sheetOffsetX_ = (sheetMaxWidth_ - sheetWidth_) / SHEET_HALF_SIZE;
211     } else if (sheetType_ == SheetType::SHEET_CENTER) {
212         sheetOffsetX_ = (sheetMaxWidth_ - sheetWidth_) / SHEET_HALF_SIZE;
213     } else if (sheetType_ == SheetType::SHEET_POPUP) {
214         auto frameNode = layoutWrapper->GetHostNode();
215         CHECK_NULL_VOID(frameNode);
216         auto parent = DynamicCast<FrameNode>(frameNode->GetParent());
217         CHECK_NULL_VOID(parent);
218         auto parentOffset = parent->GetPaintRectOffset();
219         OffsetF popupStyleSheetOffset = GetPopupStyleSheetOffset();
220         // need to subtract the SheetWrapper relative to the upper left corner of the window,
221         // which is the offset of the upper left corner of the bubble relative to the SheetWrapper
222         sheetOffsetX_ = popupStyleSheetOffset.GetX() - parentOffset.GetX();
223         sheetOffsetY_ = popupStyleSheetOffset.GetY() - parentOffset.GetY();
224     }
225     CalculateSheetOffsetInOtherScenes(layoutWrapper);
226     TAG_LOGD(AceLogTag::ACE_SHEET, "Sheet layout info, sheetOffsetX_ is: %{public}f, sheetOffsetY_ is: %{public}f",
227         sheetOffsetX_, sheetOffsetY_);
228     OffsetF positionOffset;
229     positionOffset.SetX(sheetOffsetX_);
230     positionOffset.SetY(0.0f);
231     auto geometryNode = layoutWrapper->GetGeometryNode();
232     CHECK_NULL_VOID(geometryNode);
233     // This step is only to determine the position of x, because y is to be done by the bit movement effect
234     geometryNode->SetMarginFrameOffset(positionOffset);
235     OffsetF translate(0.0f, 0.0f);
236     if (sheetType_ == SheetType::SHEET_POPUP) {
237         translate += OffsetF(0, SHEET_ARROW_HEIGHT.ConvertToPx());
238     }
239     for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
240         child->GetGeometryNode()->SetMarginFrameOffset(translate);
241         child->Layout();
242         translate += OffsetF(0, child->GetGeometryNode()->GetFrameSize().Height());
243     }
244 }
245 
246 // Get the offset of the popupSheet relative to the upper left corner of the window
GetPopupStyleSheetOffset()247 OffsetF SheetPresentationLayoutAlgorithm::GetPopupStyleSheetOffset()
248 {
249     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
250     CHECK_NULL_RETURN(targetNode, OffsetF());
251     auto geometryNode = targetNode->GetGeometryNode();
252     CHECK_NULL_RETURN(geometryNode, OffsetF());
253     auto targetSize = geometryNode->GetFrameSize();
254     auto targetOffset = targetNode->GetPaintRectOffset();
255     return GetOffsetInAvoidanceRule(targetSize, targetOffset);
256 }
257 
GetOffsetInAvoidanceRule(const SizeF & targetSize,const OffsetF & targetOffset)258 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetInAvoidanceRule(const SizeF& targetSize, const OffsetF& targetOffset)
259 {
260     // The current default Placement is Placement::BOTTOM
261     auto placement = Placement::BOTTOM;
262     auto targetPlacement = AvoidanceRuleOfPlacement(placement, targetSize, targetOffset);
263     if (getOffsetFunc_.find(targetPlacement) == getOffsetFunc_.end()) {
264         TAG_LOGW(AceLogTag::ACE_SHEET, "It is an invalid Placement for current PopSheet.");
265         return {};
266     }
267     auto offsetFunc = getOffsetFunc_[targetPlacement];
268     CHECK_NULL_RETURN(offsetFunc, OffsetF());
269     return (this->*offsetFunc)(targetSize, targetOffset);
270 }
271 
AvoidanceRuleOfPlacement(const Placement & currentPlacement,const SizeF & targetSize,const OffsetF & targetOffset)272 Placement SheetPresentationLayoutAlgorithm::AvoidanceRuleOfPlacement(
273     const Placement& currentPlacement, const SizeF& targetSize, const OffsetF& targetOffset)
274 {
275     Placement targetPlacement = currentPlacement;
276     TAG_LOGD(AceLogTag::ACE_SHEET, "Init PopupSheet placement: %{public}s",
277         PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
278     // Step1: Determine the direction
279     auto& directionVec = DIRECTIONS_STATES[targetPlacement];
280     for (auto placement : directionVec) {
281         auto& placementFunc = directionCheckFunc_[placement];
282         if (placementFunc == nullptr) {
283             continue;
284         }
285         if ((this->*placementFunc)(targetSize, targetOffset)) {
286             targetPlacement = placement;
287             break;
288         }
289     }
290     TAG_LOGD(AceLogTag::ACE_SHEET, "After step1, placement: %{public}s",
291         PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
292     // Step2: Determine the Placement in that direction
293     auto& placementVec = PLACEMENT_STATES[targetPlacement];
294     for (auto placement : placementVec) {
295         auto& placementFunc = placementCheckFunc_[placement];
296         if (placementFunc == nullptr) {
297             continue;
298         }
299         if ((this->*placementFunc)(targetSize, targetOffset)) {
300             targetPlacement = placement;
301             break;
302         }
303     }
304     TAG_LOGD(AceLogTag::ACE_SHEET, "After step2, placement: %{public}s",
305         PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
306     return targetPlacement;
307 }
308 
CheckDirectionBottom(const SizeF & targetSize,const OffsetF & targetOffset)309 bool SheetPresentationLayoutAlgorithm::CheckDirectionBottom(const SizeF& targetSize, const OffsetF& targetOffset)
310 {
311     // Generalized bottom direction,
312     // determine whether the space below the component is enough to place the sheet of size
313     return true;
314 }
315 
CheckPlacementBottom(const SizeF & targetSize,const OffsetF & targetOffset)316 bool SheetPresentationLayoutAlgorithm::CheckPlacementBottom(const SizeF& targetSize, const OffsetF& targetOffset)
317 {
318     auto pipelineContext = PipelineContext::GetCurrentContext();
319     auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
320     return GreatOrEqual(
321         windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx(),
322         targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE + sheetWidth_ / SHEET_HALF_SIZE) &&
323         LessOrEqual(
324             WINDOW_EDGE_SPACE.ConvertToPx(),
325             targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE - sheetWidth_ / SHEET_HALF_SIZE);
326 }
327 
CheckPlacementBottomLeft(const SizeF & targetSize,const OffsetF & targetOffset)328 bool SheetPresentationLayoutAlgorithm::CheckPlacementBottomLeft(const SizeF& targetSize, const OffsetF& targetOffset)
329 {
330     auto pipelineContext = PipelineContext::GetCurrentContext();
331     auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
332     return LessOrEqual(WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX()) &&
333            GreatOrEqual(windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + sheetWidth_);
334 }
335 
CheckPlacementBottomRight(const SizeF & targetSize,const OffsetF & targetOffset)336 bool SheetPresentationLayoutAlgorithm::CheckPlacementBottomRight(const SizeF& targetSize, const OffsetF& targetOffset)
337 {
338     auto pipelineContext = PipelineContext::GetCurrentContext();
339     auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
340     return LessOrEqual(WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + targetSize.Width() - sheetWidth_) &&
341            GreatOrEqual(
342                windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + targetSize.Width());
343 }
344 
GetOffsetWithBottom(const SizeF & targetSize,const OffsetF & targetOffset)345 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetWithBottom(const SizeF& targetSize, const OffsetF& targetOffset)
346 {
347     arrowOffsetX_ = sheetWidth_ / SHEET_HALF_SIZE;
348     return OffsetF(targetOffset.GetX() + (targetSize.Width() - sheetWidth_) / SHEET_HALF_SIZE,
349         targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
350 }
351 
GetOffsetWithBottomLeft(const SizeF & targetSize,const OffsetF & targetOffset)352 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetWithBottomLeft(const SizeF& targetSize, const OffsetF& targetOffset)
353 {
354     arrowOffsetX_ = targetSize.Width() / SHEET_HALF_SIZE;
355     auto sheetOffset =
356         OffsetF(targetOffset.GetX(), targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
357 
358     // if the arrow overlaps the sheet left corner, move sheet to the 6vp from the left edge
359     if (LessNotEqual(arrowOffsetX_ - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(), sheetRadius_)) {
360         sheetOffset.SetX(WINDOW_EDGE_SPACE.ConvertToPx());
361         arrowOffsetX_ = targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE - sheetOffset.GetX();
362         TAG_LOGD(AceLogTag::ACE_SHEET, "Adjust sheet to the left boundary of the screen");
363     }
364 
365     // if the arrow still overlaps the sheet left corner, the arrow will become a right angle.
366     if (LessNotEqual(arrowOffsetX_ - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(), sheetRadius_)) {
367         isRightAngleArrow_ = true;
368         TAG_LOGD(AceLogTag::ACE_SHEET, "Need to switch the arrow into the right-angle arrow");
369     }
370     return sheetOffset;
371 }
372 
GetOffsetWithBottomRight(const SizeF & targetSize,const OffsetF & targetOffset)373 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetWithBottomRight(const SizeF& targetSize, const OffsetF& targetOffset)
374 {
375     auto pipelineContext = PipelineContext::GetCurrentContext();
376     auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
377     arrowOffsetX_ = sheetWidth_ - targetSize.Width() / SHEET_HALF_SIZE;
378     auto sheetOffset = OffsetF(targetOffset.GetX() + targetSize.Width() - sheetWidth_,
379         targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
380 
381     // if the arrow overlaps the sheet right corner, move sheet to the 6vp from the right edge
382     if (GreatNotEqual(arrowOffsetX_ + sheetRadius_ + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), sheetWidth_)) {
383         sheetOffset.SetX(windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx() - sheetWidth_);
384         arrowOffsetX_ = targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE - sheetOffset.GetX();
385         TAG_LOGD(AceLogTag::ACE_SHEET, "Adjust sheet to the right boundary of the screen");
386     }
387 
388     // if the arrow still overlaps the sheet right corner, the arrow will become a right angle.
389     if (GreatNotEqual(arrowOffsetX_ + sheetRadius_ + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), sheetWidth_)) {
390         isRightAngleArrow_ = true;
391         TAG_LOGD(AceLogTag::ACE_SHEET, "Need to switch the arrow into the right angle arrow");
392     }
393     return sheetOffset;
394 }
395 
GetHeightByScreenSizeType(const SizeF & maxSize) const396 float SheetPresentationLayoutAlgorithm::GetHeightByScreenSizeType(const SizeF& maxSize) const
397 {
398     float height = maxSize.Height();
399     switch (sheetType_) {
400         case SheetType::SHEET_BOTTOM:
401         case SheetType::SHEET_BOTTOM_FREE_WINDOW:
402         case SheetType::SHEET_BOTTOMLANDSPACE:
403             height = maxSize.Height();
404             break;
405         case SheetType::SHEET_CENTER:
406             height = GetHeightBySheetStyle();
407             break;
408         case SheetType::SHEET_POPUP:
409             height = GetHeightBySheetStyle() + SHEET_ARROW_HEIGHT.ConvertToPx();
410             break;
411         default:
412             break;
413     }
414 
415     return height;
416 }
417 
GetWidthByScreenSizeType(const SizeF & maxSize,LayoutWrapper * layoutWrapper) const418 float SheetPresentationLayoutAlgorithm::GetWidthByScreenSizeType(const SizeF& maxSize,
419     LayoutWrapper* layoutWrapper) const
420 {
421     float width = maxSize.Width();
422     auto host = layoutWrapper->GetHostNode();
423     CHECK_NULL_RETURN(host, width);
424     auto sheetPattern = host->GetPattern<SheetPresentationPattern>();
425     CHECK_NULL_RETURN(sheetPattern, width);
426     switch (sheetType_) {
427         case SheetType::SHEET_BOTTOM:
428             if (sheetPattern->IsPhoneInLandScape()) {
429                 width = std::min(static_cast<float>(SHEET_LANDSCAPE_WIDTH.ConvertToPx()), maxSize.Width());
430                 break;
431             }
432         case SheetType::SHEET_BOTTOM_FREE_WINDOW:
433             width = maxSize.Width();
434             break;
435         case SheetType::SHEET_BOTTOMLANDSPACE:
436         case SheetType::SHEET_CENTER:
437             width = SHEET_LANDSCAPE_WIDTH.ConvertToPx();
438             break;
439         case SheetType::SHEET_POPUP:
440             width = SHEET_POPUP_WIDTH.ConvertToPx();
441             break;
442         default:
443             break;
444     }
445     return width;
446 }
447 
GetHeightBySheetStyle() const448 float SheetPresentationLayoutAlgorithm::GetHeightBySheetStyle() const
449 {
450     float height = 0.0f;
451     bool isMediumOrLargeMode = false;
452     if (sheetStyle_.sheetMode == SheetMode::MEDIUM || sheetStyle_.sheetMode == SheetMode::LARGE) {
453         isMediumOrLargeMode =  true;
454     }
455     if (sheetStyle_.height.has_value() || isMediumOrLargeMode) {
456         float sheetMaxHeight = sheetMaxHeight_;
457         if (SheetInSplitWindow()) {
458             sheetMaxHeight = sheetMaxHeight_ - SHEET_SPLIT_STATUS_BAR.ConvertToPx()-
459                 SHEET_SPLIT_AI_BAR.ConvertToPx();
460         }
461         auto maxHeight = std::min(sheetMaxHeight, sheetMaxWidth_) * POPUP_LARGE_SIZE;
462         if (sheetStyle_.height->Unit() == DimensionUnit::PERCENT) {
463             height = sheetStyle_.height->ConvertToPxWithSize(maxHeight);
464         } else if (isMediumOrLargeMode) {
465             height = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
466         } else {
467             height = sheetStyle_.height->ConvertToPx();
468         }
469 
470         maxHeight = SheetInSplitWindow()
471             ? maxHeight : std::max(maxHeight, static_cast<float>(SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx()));
472         if (LessNotEqual(height, 0.0f)) {
473             height = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
474         } else if (LessOrEqual(height, SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx()) && !SheetInSplitWindow()) {
475             height = SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx();
476         } else if (GreatOrEqual(height, maxHeight)) {
477             height = maxHeight;
478         }
479     } else {
480         height = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
481     }
482     return height;
483 }
484 
CreateSheetChildConstraint(RefPtr<SheetPresentationProperty> layoutprop)485 LayoutConstraintF SheetPresentationLayoutAlgorithm::CreateSheetChildConstraint(
486     RefPtr<SheetPresentationProperty> layoutprop)
487 {
488     auto childConstraint = layoutprop->CreateChildConstraint();
489     auto pipeline = PipelineContext::GetCurrentContext();
490     CHECK_NULL_RETURN(pipeline, childConstraint);
491     auto sheetTheme = pipeline->GetTheme<SheetTheme>();
492     CHECK_NULL_RETURN(sheetTheme, childConstraint);
493 
494     childConstraint.maxSize.SetWidth(sheetWidth_);
495     auto maxHeight = sheetHeight_;
496     if ((sheetStyle_.isTitleBuilder.has_value()) &&
497         ((sheetType_ == SheetType::SHEET_CENTER) || (sheetType_ == SheetType::SHEET_POPUP))) {
498         maxHeight -= SHEET_OPERATION_AREA_HEIGHT.ConvertToPx();
499     }
500     childConstraint.maxSize.SetHeight(maxHeight);
501     childConstraint.parentIdealSize = OptionalSizeF(sheetWidth_, sheetHeight_);
502     childConstraint.percentReference = SizeF(sheetWidth_, sheetHeight_);
503     return childConstraint;
504 }
505 
SheetInSplitWindow() const506 bool SheetPresentationLayoutAlgorithm::SheetInSplitWindow() const
507 {
508     //whether window in up and down split mode
509     auto pipelineContext = PipelineContext::GetCurrentContext();
510     auto windowManager = pipelineContext->GetWindowManager();
511     auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
512     int32_t deviceHeight = SystemProperties::GetDeviceHeight();
513     if (sheetType_ == SheetType::SHEET_CENTER && windowManager && windowGlobalRect.Height() < deviceHeight &&
514         (windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY ||
515         windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY)) {
516         return true;
517     }
518     return false;
519 }
520 } // namespace OHOS::Ace::NG