• 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/layout/layout_wrapper.h"
17 
18 #include "base/log/ace_checker.h"
19 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
20 
21 namespace OHOS::Ace::NG {
22 namespace {
InRangeStart(float number,float boundaryStart,float boundaryEnd)23 bool InRangeStart(float number, float boundaryStart, float boundaryEnd)
24 {
25     return GreatOrEqual(number, boundaryStart) && LessOrEqual(number, boundaryEnd + 1.0f);
26 }
27 
InRangeEnd(float number,float boundaryStart,float boundaryEnd)28 bool InRangeEnd(float number, float boundaryStart, float boundaryEnd)
29 {
30     return GreatOrEqual(number, boundaryStart - 1.0f) && LessOrEqual(number, boundaryEnd);
31 }
32 
CheckPaddingBorderGap(ExpandEdges & incomingExpand,const PaddingPropertyF & innerSpace)33 bool CheckPaddingBorderGap(ExpandEdges& incomingExpand, const PaddingPropertyF& innerSpace)
34 {
35     if (incomingExpand.left.has_value() && !NearZero(innerSpace.left.value_or(0.0f))) {
36         return false;
37     }
38     if (incomingExpand.right.has_value() && !NearZero(innerSpace.right.value_or(0.0f))) {
39         return false;
40     }
41     if (incomingExpand.top.has_value() && !NearZero(innerSpace.top.value_or(0.0f))) {
42         return false;
43     }
44     if (incomingExpand.bottom.has_value() && !NearZero(innerSpace.bottom.value_or(0.0f))) {
45         return false;
46     }
47     return true;
48 }
49 
ReduceRectByRolling(RectF & rect,const ExpandEdges & rolling,double reducing)50 void ReduceRectByRolling(RectF& rect, const ExpandEdges& rolling, double reducing)
51 {
52     rect.SetLeft(rect.Left() - reducing * rolling.left.value_or(0.0f));
53     rect.SetTop(rect.Top() - reducing * rolling.top.value_or(0.0f));
54     rect.SetWidth(rect.Width() + reducing * (rolling.left.value_or(0.0f) + rolling.right.value_or(0.0f)));
55     rect.SetHeight(rect.Height() + reducing * (rolling.top.value_or(0.0f) + rolling.bottom.value_or(0.0f)));
56 }
57 
IsIgnoreTypeTrivial(LayoutSafeAreaType ignoreType)58 bool IsIgnoreTypeTrivial(LayoutSafeAreaType ignoreType)
59 {
60     return ignoreType == LAYOUT_SAFE_AREA_TYPE_SYSTEM;
61 }
62 
FilterEdges(const ExpandEdges & rawExpand,LayoutSafeAreaEdge edges)63 ExpandEdges FilterEdges(const ExpandEdges& rawExpand, LayoutSafeAreaEdge edges)
64 {
65     ExpandEdges res;
66     if (edges & LAYOUT_SAFE_AREA_EDGE_TOP) {
67         res.top = rawExpand.top;
68     }
69     if (edges & LAYOUT_SAFE_AREA_EDGE_BOTTOM) {
70         res.bottom = rawExpand.bottom;
71     }
72     if (edges & LAYOUT_SAFE_AREA_EDGE_START) {
73         res.left = rawExpand.left;
74     }
75     if (edges & LAYOUT_SAFE_AREA_EDGE_END) {
76         res.right = rawExpand.right;
77     }
78     return res;
79 }
80 } // namespace
81 
SkipMeasureContent() const82 bool LayoutWrapper::SkipMeasureContent() const
83 {
84     return skipMeasureContent_ == true;
85 }
86 
ApplySafeArea(const SafeAreaInsets & insets,LayoutConstraintF & constraint)87 void LayoutWrapper::ApplySafeArea(const SafeAreaInsets& insets, LayoutConstraintF& constraint)
88 {
89     constraint.MinusPadding(
90         insets.left_.Length(), insets.right_.Length(), insets.top_.Length(), insets.bottom_.Length());
91 }
92 
OffsetNodeToSafeArea()93 void LayoutWrapper::OffsetNodeToSafeArea()
94 {
95     const auto& layoutProperty = GetLayoutProperty();
96     CHECK_NULL_VOID(layoutProperty);
97     auto&& insets = layoutProperty->GetSafeAreaInsets();
98     CHECK_NULL_VOID(insets);
99     auto geometryNode = GetGeometryNode();
100     auto offset = geometryNode->GetMarginFrameOffset();
101     if (offset.GetX() < insets->left_.end) {
102         offset.SetX(insets->left_.end);
103     }
104     if (offset.GetY() < insets->top_.end) {
105         offset.SetY(insets->top_.end);
106     }
107 
108     auto right = offset.GetX() + geometryNode->GetMarginFrameSize().Width();
109     auto rightBound = insets->right_.IsValid() ? insets->right_.start : PipelineContext::GetCurrentRootWidth();
110     if (right > rightBound) {
111         offset.SetX(rightBound - geometryNode->GetMarginFrameSize().Width());
112     }
113     auto bottomBound = insets->bottom_.IsValid() ? insets->bottom_.start : PipelineContext::GetCurrentRootHeight();
114     auto bottom = offset.GetY() + geometryNode->GetMarginFrameSize().Height();
115     if (bottom > bottomBound) {
116         offset.SetY(bottomBound - geometryNode->GetMarginFrameSize().Height());
117     }
118     geometryNode->SetMarginFrameOffset(offset);
119 }
120 
GetBackGroundAccumulatedSafeAreaExpand()121 RectF LayoutWrapper::GetBackGroundAccumulatedSafeAreaExpand()
122 {
123     const auto& layoutProperty = GetLayoutProperty();
124     CHECK_NULL_RETURN(layoutProperty, {});
125     auto ignoreLayoutSafeAreaEdges = layoutProperty->GetLocalizedBackgroundIgnoresLayoutSafeAreaEdges();
126     IgnoreLayoutSafeAreaOpts opts = { .type = NG::LAYOUT_SAFE_AREA_TYPE_SYSTEM, .edges = ignoreLayoutSafeAreaEdges };
127     auto expandEdges = GetAccumulatedSafeAreaExpand(false, opts);
128     auto geometryNode = GetGeometryNode();
129     RectF res = geometryNode->GetFrameRect();
130     res.SetOffset(OffsetF() - OffsetF(expandEdges.left.value_or(0.0f), expandEdges.top.value_or(0.0f)));
131     res.SetSize(res.GetSize() + SizeF(expandEdges.Width(), expandEdges.Height()));
132     return res;
133 }
134 
AvoidKeyboard(bool isFocusOnPage)135 bool LayoutWrapper::AvoidKeyboard(bool isFocusOnPage)
136 {
137     auto host = GetHostNode();
138     CHECK_NULL_RETURN(host, false);
139     auto pipeline = host->GetContext();
140     CHECK_NULL_RETURN(pipeline, false);
141     auto manager = pipeline->GetSafeAreaManager();
142     bool isFocusOnOverlay = pipeline->CheckOverlayFocus();
143     bool isNeedAvoidKeyboard = manager->CheckPageNeedAvoidKeyboard(host);
144     bool isOverlay = GetHostTag() == V2::OVERLAY_ETS_TAG || GetHostTag() == V2::ORDER_OVERLAY_ETS_TAG;
145     // apply keyboard avoidance on Page or Overlay
146     if ((GetHostTag() == V2::PAGE_ETS_TAG && isNeedAvoidKeyboard) || isOverlay) {
147         CHECK_NULL_RETURN(IsActive(), false);
148         auto renderContext = GetHostNode()->GetRenderContext();
149         CHECK_NULL_RETURN(renderContext, false);
150         auto safeArea = manager->GetSafeArea();
151         auto pageCurrentOffset = GetPageCurrentOffset();
152         auto pageHasOffset = LessNotEqual(pageCurrentOffset, 0.0f);
153         auto keyboardOffset = manager->GetKeyboardOffset();
154         auto lastChild = host->GetLastChild();
155         if (GetHostTag() == V2::PAGE_ETS_TAG && lastChild && lastChild->GetTag() == V2::DIALOG_ETS_TAG) {
156             keyboardOffset = 0.0f;
157         }
158         ACE_MEASURE_SCOPED_TRACE("AvoidKeyboard isFocusOnPage: %d, isFocusOnOverlay: %d,"
159             "pageCurrentOffset: %f, keyboardOffset: %f", isFocusOnPage, isFocusOnOverlay,
160             pageCurrentOffset, keyboardOffset);
161         if (!(isFocusOnPage || (isFocusOnOverlay && isOverlay) || pageHasOffset) && LessNotEqual(keyboardOffset, 0.0)) {
162             const auto& layoutProperty = GetLayoutProperty();
163             CHECK_NULL_RETURN(layoutProperty, false);
164             renderContext->SavePaintRect(true, layoutProperty->GetPixelRound());
165             return false;
166         }
167         auto geometryNode = GetGeometryNode();
168         auto x = geometryNode->GetFrameOffset().GetX();
169         if (manager->IsAtomicService()) {
170             auto usingRect = RectF(OffsetF(x, keyboardOffset), geometryNode->GetFrameSize());
171             renderContext->UpdatePaintRect(usingRect);
172             geometryNode->SetSelfAdjust(usingRect - geometryNode->GetFrameRect());
173             pipeline->SetAreaChangeNodeMinDepth(host->GetDepth());
174             renderContext->SyncPartialRsProperties();
175             return true;
176         }
177         auto usingRect = RectF(OffsetF(x, safeArea.top_.Length() + keyboardOffset), geometryNode->GetFrameSize());
178         renderContext->UpdatePaintRect(usingRect);
179         geometryNode->SetSelfAdjust(usingRect - geometryNode->GetFrameRect());
180         pipeline->SetAreaChangeNodeMinDepth(host->GetDepth());
181         renderContext->SyncPartialRsProperties();
182         return true;
183     }
184     return false;
185 }
186 
CheckValidSafeArea()187 bool LayoutWrapper::CheckValidSafeArea()
188 {
189     auto host = GetHostNode();
190     CHECK_NULL_RETURN(host, false);
191     auto pipeline = host->GetContext();
192     CHECK_NULL_RETURN(pipeline, false);
193     auto safeAreaManager = pipeline->GetSafeAreaManager();
194     CHECK_NULL_RETURN(safeAreaManager, false);
195     SafeAreaInsets safeArea;
196     const auto& layoutProperty = GetLayoutProperty();
197     CHECK_NULL_RETURN(layoutProperty, false);
198     auto&& opts = layoutProperty->GetSafeAreaExpandOpts();
199     // if self does not have opts, check parent's
200     if (!opts) {
201         auto parent = host->GetAncestorNodeOfFrame(false);
202         CHECK_NULL_RETURN(parent, false);
203         CHECK_NULL_RETURN(parent->GetLayoutProperty(), false);
204         auto&& parentOpts = parent->GetLayoutProperty()->GetSafeAreaExpandOpts();
205         CHECK_NULL_RETURN(parentOpts, false);
206         safeArea = safeAreaManager->GetCombinedSafeArea(*parentOpts);
207     } else {
208         safeArea = safeAreaManager->GetCombinedSafeArea(*opts);
209     }
210     return safeArea.IsValid();
211 }
212 
GetParentGlobalOffsetWithSafeArea(bool checkBoundary,bool checkPosition) const213 OffsetF LayoutWrapper::GetParentGlobalOffsetWithSafeArea(bool checkBoundary, bool checkPosition) const
214 {
215     OffsetF offset {};
216     auto host = GetHostNode();
217     CHECK_NULL_RETURN(host, offset);
218     auto parent = host->GetAncestorNodeOfFrame(checkBoundary);
219     while (parent) {
220         auto parentRenderContext = parent->GetRenderContext();
221         if (checkPosition && parentRenderContext && parentRenderContext->GetPositionProperty() &&
222             parentRenderContext->GetPositionProperty()->HasPosition()) {
223             auto parentLayoutProp = parent->GetLayoutProperty();
224             CHECK_NULL_RETURN(parentLayoutProp, offset);
225             auto parentLayoutConstraint = parentLayoutProp->GetLayoutConstraint();
226             CHECK_NULL_RETURN(parentLayoutConstraint.has_value(), offset);
227             auto renderPosition = FrameNode::ContextPositionConvertToPX(
228                 parentRenderContext, parentLayoutConstraint.value().percentReference);
229             offset += OffsetF(static_cast<float>(renderPosition.first), static_cast<float>(renderPosition.second));
230         } else {
231             offset += parent->GetFrameRectWithSafeArea().GetOffset();
232         }
233         parent = parent->GetAncestorNodeOfFrame(checkBoundary);
234     }
235     return offset;
236 }
237 
GetFrameRectWithoutSafeArea() const238 RectF LayoutWrapper::GetFrameRectWithoutSafeArea() const
239 {
240     auto geometryNode = GetGeometryNode();
241     CHECK_NULL_RETURN(geometryNode, RectF());
242     return geometryNode->GetFrameRect();
243 }
244 
GetFrameRectWithSafeArea(bool checkPosition) const245 RectF LayoutWrapper::GetFrameRectWithSafeArea(bool checkPosition) const
246 {
247     auto geometryNode = GetGeometryNode();
248     CHECK_NULL_RETURN(geometryNode, RectF());
249     RectF rect {};
250     auto host = GetHostNode();
251     CHECK_NULL_RETURN(host, rect);
252     auto renderContext = host->GetRenderContext();
253     if (checkPosition && renderContext && renderContext->GetPositionProperty() &&
254         renderContext->GetPositionProperty()->HasPosition()) {
255         auto layoutProp = host->GetLayoutProperty();
256         CHECK_NULL_RETURN(layoutProp, rect);
257         auto layoutConstraint = layoutProp->GetLayoutConstraint();
258         CHECK_NULL_RETURN(layoutConstraint.has_value(), rect);
259         auto renderPosition =
260             FrameNode::ContextPositionConvertToPX(renderContext, layoutConstraint.value().percentReference);
261         auto size = (geometryNode->GetSelfAdjust() + geometryNode->GetFrameRect()).GetSize();
262         rect =
263             RectF(OffsetF(static_cast<float>(renderPosition.first), static_cast<float>(renderPosition.second)), size);
264         return rect;
265     }
266     return geometryNode->GetSelfAdjust() + geometryNode->GetFrameRect();
267 }
268 
AdjustNotExpandNode()269 void LayoutWrapper::AdjustNotExpandNode()
270 {
271     auto host = GetHostNode();
272     CHECK_NULL_VOID(host);
273     auto pipeline = host->GetContext();
274     CHECK_NULL_VOID(pipeline);
275     auto safeAreaManager = pipeline->GetSafeAreaManager();
276     CHECK_NULL_VOID(safeAreaManager);
277     auto parent = host->GetAncestorNodeOfFrame(false);
278     auto renderContext = host->GetRenderContext();
279     CHECK_NULL_VOID(renderContext);
280     auto geometryNode = GetGeometryNode();
281     CHECK_NULL_VOID(geometryNode);
282     auto adjustedRect = geometryNode->GetFrameRect();
283     if (safeAreaManager->IsSafeAreaValid()) {
284         adjustedRect += geometryNode->GetParentAdjust();
285     }
286     geometryNode->SetSelfAdjust(adjustedRect - geometryNode->GetFrameRect());
287     pipeline->SetAreaChangeNodeMinDepth(host->GetDepth());
288     renderContext->UpdatePaintRect(adjustedRect + geometryNode->GetPixelGridRoundRect() - geometryNode->GetFrameRect());
289     if (SystemProperties::GetSafeAreaDebugTraceEnabled()) {
290         ACE_SAFE_AREA_SCOPED_TRACE("AdjustNotExpandNode[%s][self:%d][parent:%d][key:%s][paintRectRect:%s]",
291             host->GetTag().c_str(), host->GetId(),
292             host->GetAncestorNodeOfFrame(false) ? host->GetAncestorNodeOfFrame(false)->GetId() : 0,
293             host->GetInspectorIdValue("").c_str(), renderContext->GetPaintRectWithoutTransform().ToString().c_str());
294     }
295 }
296 
ExpandSafeArea()297 void LayoutWrapper::ExpandSafeArea()
298 {
299     auto host = GetHostNode();
300     CHECK_NULL_VOID(host);
301     auto pattern = host->GetPattern();
302     CHECK_NULL_VOID(pattern);
303     if (pattern->CustomizeExpandSafeArea()) {
304         return;
305     }
306     auto pipeline = host->GetContext();
307     CHECK_NULL_VOID(pipeline);
308     auto safeAreaManager = pipeline->GetSafeAreaManager();
309     CHECK_NULL_VOID(safeAreaManager);
310     const auto& layoutProperty = GetLayoutProperty();
311     CHECK_NULL_VOID(layoutProperty);
312     auto&& opts = GetLayoutProperty()->GetSafeAreaExpandOpts();
313     auto selfExpansive = host->SelfExpansive();
314     if (!selfExpansive) {
315         AdjustNotExpandNode();
316         return;
317     }
318     CHECK_NULL_VOID(selfExpansive);
319     opts->switchToNone = false;
320     auto geometryNode = GetGeometryNode();
321     CHECK_NULL_VOID(geometryNode);
322     OffsetF keyboardAdjust;
323     if ((opts->edges & SAFE_AREA_EDGE_BOTTOM) && (opts->type & SAFE_AREA_TYPE_KEYBOARD)) {
324         keyboardAdjust = ExpandIntoKeyboard();
325     }
326 
327     // get frame in global offset
328     auto parentGlobalOffset = GetParentGlobalOffsetWithSafeArea();
329     auto parentAdjust = geometryNode->GetParentAdjust();
330     if (!safeAreaManager->IsSafeAreaValid()) {
331         parentAdjust = RectF();
332     }
333     auto frame = geometryNode->GetFrameRect() + parentGlobalOffset + keyboardAdjust + parentAdjust.GetOffset();
334     auto originGlobal = frame;
335 
336     ExpandHelper(opts, frame);
337 
338     AdjustFixedSizeNode(frame);
339     auto parent = host->GetAncestorNodeOfFrame(false);
340     auto parentScrollable = (parent && parent->GetPattern<ScrollablePattern>());
341     // restore to local offset
342     auto diff = originGlobal.GetOffset() - frame.GetOffset();
343     frame -= parentGlobalOffset;
344     // since adjustment is not accumulated and we did not track previous diff, diff need to be updated
345     AdjustChildren(diff, parentScrollable);
346 
347     if (parentScrollable) {
348         AdjustNotExpandNode();
349         return;
350     }
351     auto selfAdjust = frame - geometryNode->GetFrameRect();
352     geometryNode->SetSelfAdjust(selfAdjust);
353     pipeline->SetAreaChangeNodeMinDepth(host->GetDepth());
354     auto renderContext = host->GetRenderContext();
355     CHECK_NULL_VOID(renderContext);
356     renderContext->UpdatePaintRect(frame + geometryNode->GetPixelGridRoundRect() - geometryNode->GetFrameRect());
357     if (SystemProperties::GetSafeAreaDebugTraceEnabled()) {
358         ACE_SAFE_AREA_SCOPED_TRACE(
359             "ExpandSafeAreaFinish[%s][self:%d][parent:%d][key:%s][opt:%s][paintRectRect:%s][selfAdjust:%s]",
360             host->GetTag().c_str(), host->GetId(),
361             host->GetAncestorNodeOfFrame(false) ? host->GetAncestorNodeOfFrame(false)->GetId() : 0,
362             host->GetInspectorIdValue("").c_str(), opts->ToString().c_str(),
363             renderContext->GetPaintRectWithoutTransform().ToString().c_str(), selfAdjust.ToString().c_str());
364     }
365 }
366 
ResetSafeAreaPadding()367 void LayoutWrapper::ResetSafeAreaPadding()
368 {
369     // meant to reset everything each frame
370     const auto& geometryNode = GetGeometryNode();
371     CHECK_NULL_VOID(geometryNode);
372     geometryNode->ResetResolvedSelfSafeAreaPadding();
373     geometryNode->ResetAccumulatedSafeAreaPadding();
374 }
375 
AccumulateExpandCacheHit(ExpandEdges & totalExpand,const PaddingPropertyF & innerSpace)376 bool LayoutWrapper::AccumulateExpandCacheHit(ExpandEdges& totalExpand, const PaddingPropertyF& innerSpace)
377 {
378     auto host = GetHostNode();
379     CHECK_NULL_RETURN(host, false);
380     const auto& geometryNode = GetGeometryNode();
381     CHECK_NULL_RETURN(geometryNode, false);
382     auto& selfAccumulateExpand = geometryNode->GetAccumulatedSafeAreaExpand();
383     CHECK_NULL_RETURN(selfAccumulateExpand, false);
384     // if parent has expand cache that covers child's, for example child expands toward left, top
385     // and parent already has cache toward left, top, bottom, then this is a cache hit
386     // and we can concatenate left and top cache to result
387     // otherwise meaning child is expanding toward a direction that parent does not have cache
388     CHECK_NULL_RETURN(selfAccumulateExpand->OptionalValueCover(totalExpand), false);
389     // parent's cache is with reference to frameRect, but during the recursive PaddingBorder need to
390     // be included in the increment.
391     // Only when the PaddingBorder is Zero, the cache can be utilized.
392     CHECK_NULL_RETURN(CheckPaddingBorderGap(totalExpand, innerSpace), false);
393     // if reaches page and totalExpand is still empty, then querying node is already as large as page
394     // then add page cache directly to total expand
395     totalExpand =
396         totalExpand.Plus(*(selfAccumulateExpand.get()), totalExpand.Empty() && host->GetTag() == V2::PAGE_ETS_TAG);
397     return true;
398 }
399 
GetAccumulatedSafeAreaExpand(bool includingSelf,IgnoreLayoutSafeAreaOpts options,IgnoreStrategy strategy)400 ExpandEdges LayoutWrapper::GetAccumulatedSafeAreaExpand(
401     bool includingSelf, IgnoreLayoutSafeAreaOpts options, IgnoreStrategy strategy)
402 {
403     StartPoint startPoint = StartPoint::NORMAL;
404     if (strategy == IgnoreStrategy::FROM_MARGIN) {
405         startPoint = StartPoint::FROM_MARGIN;
406     } else if (strategy == IgnoreStrategy::AXIS_INSENSITIVE) {
407         isScrollableAxis_ = true;
408         auto sae = FilterEdges(GetAccumulatedSafeAreaExpandForAllEdges(
409             includingSelf ? StartPoint::INCLUDING_SELF : startPoint, options.type), options.edges);
410         isScrollableAxis_ = false;
411         return sae;
412     } else if (includingSelf) {
413         startPoint = StartPoint::INCLUDING_SELF;
414     }
415     return FilterEdges(GetAccumulatedSafeAreaExpandForAllEdges(startPoint, options.type), options.edges);
416 }
417 
GetAccumulatedSafeAreaExpandForAllEdges(StartPoint startPoint,LayoutSafeAreaType ignoreType)418 ExpandEdges LayoutWrapper::GetAccumulatedSafeAreaExpandForAllEdges(StartPoint startPoint, LayoutSafeAreaType ignoreType)
419 {
420     ExpandEdges totalExpand;
421     auto host = GetHostNode();
422     CHECK_NULL_RETURN(host, totalExpand);
423     const auto& geometryNode = host->GetGeometryNode();
424     CHECK_NULL_RETURN(geometryNode, totalExpand);
425     RectF adjustingRect;
426     if (startPoint == StartPoint::FROM_MARGIN) {
427         adjustingRect = geometryNode->GetMarginFrameRect();
428     } else {
429         adjustingRect = geometryNode->GetFrameRect();
430     }
431     const auto& layoutProperty = GetLayoutProperty();
432     CHECK_NULL_RETURN(layoutProperty, totalExpand);
433     if (startPoint == StartPoint::INCLUDING_SELF) {
434         GetAccumulatedSafeAreaExpandHelper(adjustingRect, totalExpand, true, ignoreType);
435         return totalExpand;
436     }
437     // CreateMargin does get or create
438     auto hostMargin = layoutProperty->CreateMargin();
439     if (startPoint != StartPoint::FROM_MARGIN && hostMargin.AllSidesFilled(true)) {
440         return totalExpand;
441     }
442     // total expanding distance of four sides used to calculate cache
443     GetAccumulatedSafeAreaExpandHelper(adjustingRect, totalExpand, false, ignoreType);
444     if (IsIgnoreTypeTrivial(ignoreType) && !isScrollableAxis_) {
445         geometryNode->SetAccumulatedSafeAreaEdges(totalExpand);
446     }
447     return totalExpand;
448 }
449 
ParseSafeAreaPaddingSides(const PaddingPropertyF & parentSafeAreaPadding,const PaddingPropertyF & parentInnerSpace,const RectF & adjustingRect,ExpandEdges & rollingExpand)450 void LayoutWrapper::ParseSafeAreaPaddingSides(const PaddingPropertyF& parentSafeAreaPadding,
451     const PaddingPropertyF& parentInnerSpace, const RectF& adjustingRect, ExpandEdges& rollingExpand)
452 {
453     auto host = GetHostNode();
454     CHECK_NULL_VOID(host);
455     auto parent = host->GetAncestorNodeOfFrame(false);
456     CHECK_NULL_VOID(parent);
457     const auto& parentGeometryNode = parent->GetGeometryNode();
458     CHECK_NULL_VOID(parentGeometryNode);
459     // check if current rect can overlap with four parent safeAreaPaddings
460     if (!NearZero(parentSafeAreaPadding.left.value_or(0.0f))) {
461         auto innerSpaceLeftLength = parentInnerSpace.left.value_or(0.0f);
462         // left side safeArea range is [border + padding, border + padding + safeAreaPadding]
463         if (InRangeStart(adjustingRect.Left(), innerSpaceLeftLength,
464             innerSpaceLeftLength + parentSafeAreaPadding.left.value_or(0.0f))) {
465             rollingExpand.left = adjustingRect.Left() - innerSpaceLeftLength;
466         }
467     }
468     if (!NearZero(parentSafeAreaPadding.top.value_or(0.0f))) {
469         auto innerSpaceTopLength = parentInnerSpace.top.value_or(0.0f);
470         // top side safeArea padding range is [top border + padding, top border + padding + safeAreaPadding]
471         if (InRangeStart(adjustingRect.Top(), innerSpaceTopLength,
472             innerSpaceTopLength + parentSafeAreaPadding.top.value_or(0.0f))) {
473             rollingExpand.top = adjustingRect.Top() - innerSpaceTopLength;
474         }
475     }
476     if (!NearZero(parentSafeAreaPadding.right.value_or(0.0f))) {
477         auto parentWidth = parentGeometryNode->GetFrameRect().Width();
478         auto innerSpaceRightLength = parentInnerSpace.right.value_or(0.0f);
479         // right side safeArea padding range is
480         // [parentWidth - (right border + padding) - right safeAreaPadding, parentWidth - (right border + padding)]
481         if (InRangeEnd(adjustingRect.Right(),
482             parentWidth - innerSpaceRightLength - parentSafeAreaPadding.right.value_or(0.0f),
483             parentWidth - innerSpaceRightLength)) {
484             rollingExpand.right = parentWidth - innerSpaceRightLength - adjustingRect.Right();
485         }
486     }
487     if (!NearZero(parentSafeAreaPadding.bottom.value_or(0.0f))) {
488         auto parentHeight = parentGeometryNode->GetFrameRect().Height();
489         // bottom side safeArea padding range is
490         // [parentHeight - (bottom border + padding) - bottom safeAreaPadding,
491         // parentHeight - (bottom border + padding)]
492         auto innerSpaceBottomLength = parentInnerSpace.bottom.value_or(0.0f);
493         if (InRangeEnd(adjustingRect.Bottom(),
494             parentHeight - innerSpaceBottomLength - parentSafeAreaPadding.bottom.value_or(0.0f),
495             parentHeight - innerSpaceBottomLength)) {
496             rollingExpand.bottom = parentHeight - innerSpaceBottomLength - adjustingRect.Bottom();
497         }
498     }
499 }
500 
GetAccumulatedSafeAreaExpandHelper(RectF & adjustingRect,ExpandEdges & totalExpand,bool fromSelf,LayoutSafeAreaType ignoreType)501 void LayoutWrapper::GetAccumulatedSafeAreaExpandHelper(
502     RectF& adjustingRect, ExpandEdges& totalExpand, bool fromSelf, LayoutSafeAreaType ignoreType)
503 {
504     auto host = GetHostNode();
505     CHECK_NULL_VOID(host);
506     auto recursiveHost = host;
507     if (!fromSelf) {
508         auto parent = host->GetAncestorNodeOfFrame(false);
509         CHECK_NULL_VOID(parent);
510         recursiveHost = parent;
511     }
512     const auto& geometryNode = recursiveHost->GetGeometryNode();
513     CHECK_NULL_VOID(geometryNode);
514     ExpandEdges rollingExpand;
515     const auto& layoutProperty = recursiveHost->GetLayoutProperty();
516     CHECK_NULL_VOID(layoutProperty);
517     PaddingPropertyF safeAreaPadding;
518     if (recursiveHost->GetTag() == V2::STAGE_ETS_TAG) {
519         const auto& pipeline = recursiveHost->GetContext();
520         CHECK_NULL_VOID(pipeline);
521         const auto& safeAreaManager = pipeline->GetSafeAreaManager();
522         CHECK_NULL_VOID(safeAreaManager);
523         safeAreaPadding = safeAreaManager->SafeAreaToPadding(false, ignoreType);
524     } else {
525         safeAreaPadding = layoutProperty->GetOrCreateSafeAreaPadding();
526     }
527     auto innerSpace = layoutProperty->CreatePaddingAndBorder(false, false);
528 
529     auto pattern = recursiveHost->GetPattern();
530     if (!isScrollableAxis_ && pattern && pattern->NeedCustomizeSafeAreaPadding()) {
531         innerSpace.Plus(pattern->CustomizeSafeAreaPadding(safeAreaPadding, true), true);
532         safeAreaPadding = pattern->CustomizeSafeAreaPadding(safeAreaPadding, false);
533     }
534 
535     if (fromSelf) {
536         // if fromSelf is true, adjustingRect should cut innerSpace
537         ReduceRectByRolling(adjustingRect, innerSpace, -1.0);
538     } else {
539         ParseSafeAreaPaddingSides(safeAreaPadding, innerSpace, adjustingRect, rollingExpand);
540         // adjustingRect should append rollingExpand
541         ReduceRectByRolling(adjustingRect, rollingExpand, 1.0);
542         // after expanding based on parent safeAreaPadding, adjust rect to parent's coordinate
543         adjustingRect.SetOffset(adjustingRect.GetOffset() + geometryNode->GetFrameOffset());
544     }
545     totalExpand = totalExpand.Plus(fromSelf ? safeAreaPadding : rollingExpand);
546     auto margin = layoutProperty->CreateMargin();
547     // if parent has all four sides of innerSpace included(padding and border) or margin, stop expanding.
548     if (innerSpace.AllSidesFilled(true) || margin.AllSidesFilled(true) ||
549         (recursiveHost->GetTag() == V2::STAGE_ETS_TAG)) {
550         return;
551     }
552     if (IsIgnoreTypeTrivial(ignoreType) && !isScrollableAxis_ &&
553         recursiveHost->AccumulateExpandCacheHit(totalExpand, innerSpace)) {
554         return;
555     }
556     if (pattern && pattern->AccumulatingTerminateHelper(adjustingRect, totalExpand, fromSelf, ignoreType)) {
557         return;
558     }
559     recursiveHost->GetAccumulatedSafeAreaExpandHelper(adjustingRect, totalExpand, false, ignoreType);
560 }
561 
PredictMeasureResult(LayoutWrapper * childWrapper,const std::optional<LayoutConstraintF> & parentConstraint)562 bool LayoutWrapper::PredictMeasureResult(
563     LayoutWrapper* childWrapper, const std::optional<LayoutConstraintF>& parentConstraint)
564 {
565     auto layoutProperty = childWrapper->GetLayoutProperty();
566     CHECK_NULL_RETURN(layoutProperty, false);
567     const auto& layoutConstraint = layoutProperty->GetLayoutConstraint();
568     if (!layoutConstraint.has_value() || !parentConstraint.has_value()) {
569         return false;
570     }
571     auto layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
572     if (!layoutPolicy || !layoutPolicy->IsMatch()) {
573         return false;
574     }
575     OptionalSizeF realSize;
576     auto parentIdealSize = parentConstraint->parentIdealSize;
577     auto widthLayoutPolicy = layoutPolicy->widthLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH);
578     auto heightLayoutPolicy = layoutPolicy->heightLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH);
579     if (parentIdealSize.Width().has_value() && widthLayoutPolicy == LayoutCalPolicy::MATCH_PARENT) {
580         realSize.SetWidth(parentIdealSize.Width().value());
581     }
582     if (parentIdealSize.Height().has_value() && heightLayoutPolicy == LayoutCalPolicy::MATCH_PARENT) {
583         realSize.SetHeight(parentIdealSize.Height().value());
584     }
585     auto selfIdealSize = layoutConstraint->selfIdealSize;
586     realSize.UpdateIllegalSizeWithCheck(selfIdealSize);
587     if (realSize.IsValid()) {
588         childWrapper->GetGeometryNode()->SetFrameSize(realSize.ConvertToSizeT());
589         return true;
590     }
591     return false;
592 }
593 
ExpandHelper(const std::unique_ptr<SafeAreaExpandOpts> & opts,RectF & frame)594 void LayoutWrapper::ExpandHelper(const std::unique_ptr<SafeAreaExpandOpts>& opts, RectF& frame)
595 {
596     CHECK_NULL_VOID(opts);
597     auto host = GetHostNode();
598     CHECK_NULL_VOID(host);
599     auto pipeline = host->GetContext();
600     CHECK_NULL_VOID(pipeline);
601     auto safeArea = pipeline->GetSafeAreaManager()->GetCombinedSafeArea(*opts);
602     if ((opts->edges & SAFE_AREA_EDGE_START) && safeArea.left_.IsOverlapped(frame.Left())) {
603         frame.SetWidth(frame.Width() + frame.Left() - safeArea.left_.start);
604         frame.SetLeft(safeArea.left_.start);
605     }
606     if ((opts->edges & SAFE_AREA_EDGE_TOP) && safeArea.top_.IsOverlapped(frame.Top())) {
607         frame.SetHeight(frame.Height() + frame.Top() - safeArea.top_.start);
608         frame.SetTop(safeArea.top_.start);
609     }
610 
611     if ((opts->edges & SAFE_AREA_EDGE_END) && safeArea.right_.IsOverlapped(frame.Right())) {
612         frame.SetWidth(frame.Width() + (safeArea.right_.end - frame.Right()));
613     }
614     if ((opts->edges & SAFE_AREA_EDGE_BOTTOM) && safeArea.bottom_.IsOverlapped(frame.Bottom())) {
615         frame.SetHeight(frame.Height() + (safeArea.bottom_.end - frame.Bottom()));
616     }
617 }
618 
AdjustFixedSizeNode(RectF & frame)619 void LayoutWrapper::AdjustFixedSizeNode(RectF& frame)
620 {
621     // reset if User has fixed size
622     auto layoutProperty = GetLayoutProperty();
623     CHECK_NULL_VOID(layoutProperty);
624     auto geometryNode = GetGeometryNode();
625     CHECK_NULL_VOID(geometryNode);
626     if (layoutProperty->HasFixedWidth()) {
627         frame.SetWidth(geometryNode->GetFrameRect().Width());
628     }
629     if (layoutProperty->HasFixedHeight()) {
630         frame.SetHeight(geometryNode->GetFrameRect().Height());
631     }
632     if (layoutProperty->HasAspectRatio()) {
633         frame.SetHeight(frame.Width() / layoutProperty->GetAspectRatio());
634     }
635 }
636 
AdjustChildren(const OffsetF & offset,bool parentScrollable)637 void LayoutWrapper::AdjustChildren(const OffsetF& offset, bool parentScrollable)
638 {
639     auto host = GetHostNode();
640     CHECK_NULL_VOID(host);
641     auto pattern = host->GetPattern();
642     if (pattern && pattern->ConsumeChildrenAdjustment(offset)) {
643         return;
644     }
645     for (const auto& childUI : GetHostNode()->GetChildren()) {
646         AdjustChild(childUI, offset, parentScrollable);
647     }
648 }
649 
AdjustChild(RefPtr<UINode> childUI,const OffsetF & offset,bool parentScrollable)650 void LayoutWrapper::AdjustChild(RefPtr<UINode> childUI, const OffsetF& offset, bool parentScrollable)
651 {
652     auto child = DynamicCast<FrameNode>(childUI);
653     if (!child) {
654         if (!childUI->IsSyntaxNode()) {
655             return;
656         }
657         for (const auto& syntaxChild : childUI->GetChildren()) {
658             AdjustChild(syntaxChild, offset, parentScrollable);
659         }
660         return;
661     }
662     auto childGeo = child->GetGeometryNode();
663     auto parentAdjust = childGeo->GetParentAdjust();
664     if (parentAdjust.GetOffset() != offset) {
665         AddChildToExpandListIfNeeded(AceType::WeakClaim(AceType::RawPtr(child)));
666     }
667     if (!parentScrollable) {
668         childGeo->SetParentAdjust(RectF(offset, SizeF()));
669     }
670 }
671 
AddChildToExpandListIfNeeded(const WeakPtr<FrameNode> & node)672 void LayoutWrapper::AddChildToExpandListIfNeeded(const WeakPtr<FrameNode>& node)
673 {
674     auto host = node.Upgrade();
675     CHECK_NULL_VOID(host);
676     auto pipeline = host->GetContext();
677     CHECK_NULL_VOID(pipeline);
678     auto safeAreaManager = pipeline->GetSafeAreaManager();
679     CHECK_NULL_VOID(safeAreaManager);
680     bool canAdd = safeAreaManager->AddNodeToExpandListIfNeeded(node);
681     CHECK_NULL_VOID(canAdd);
682     auto task = [weak = node]() {
683         auto frameNode = weak.Upgrade();
684         CHECK_NULL_VOID(frameNode);
685         DirtySwapConfig emptyConfig;
686         frameNode->SyncGeometryNode(true, emptyConfig);
687     };
688     pipeline->AddSyncGeometryNodeTask(task);
689 }
690 
ExpandIntoKeyboard()691 OffsetF LayoutWrapper::ExpandIntoKeyboard()
692 {
693     auto pageOffset = GetPageCurrentOffset();
694     if (GreatOrEqual(pageOffset, 0.0f)) {
695         return OffsetF();
696     }
697     // if parent already expanded into keyboard, offset shouldn't be applied again
698     auto parent = GetHostNode()->GetAncestorNodeOfFrame(false);
699     while (parent) {
700         auto pattern = parent->GetPattern();
701         if (pattern && pattern->CheckCustomAvoidKeyboard()) {
702             // if parent need avoid keyboard and child need expand into keyboard,
703             // keep child expand into keyboard
704             break;
705         }
706         const auto& parentLayoutProperty = parent->GetLayoutProperty();
707         CHECK_NULL_RETURN(parentLayoutProperty, OffsetF());
708         auto&& opts = parentLayoutProperty->GetSafeAreaExpandOpts();
709         if (opts && (opts->edges & SAFE_AREA_EDGE_BOTTOM) && opts->type & SAFE_AREA_TYPE_KEYBOARD) {
710             return OffsetF();
711         }
712         parent = parent->GetAncestorNodeOfFrame(false);
713     }
714     auto host = GetHostNode();
715     CHECK_NULL_RETURN(host, OffsetF());
716     auto pipeline = host->GetContext();
717     CHECK_NULL_RETURN(pipeline, OffsetF());
718     return OffsetF(0.0f, -pipeline->GetSafeAreaManager()->GetKeyboardOffset());
719 }
720 
GetPageCurrentOffset()721 float LayoutWrapper::GetPageCurrentOffset()
722 {
723     auto host = GetHostNode();
724     CHECK_NULL_RETURN(host, 0.0f);
725     auto pipeline = host->GetContext();
726     CHECK_NULL_RETURN(pipeline, 0.0f);
727     auto stageManager = pipeline->GetStageManager();
728     CHECK_NULL_RETURN(stageManager, 0.0f);
729     auto pageId = host->GetPageId();
730     auto parent = host;
731     while (parent) {
732         if (parent->GetPageId() > 0) {
733             pageId = parent->GetPageId();
734             break;
735         }
736         parent = parent->GetAncestorNodeOfFrame(false);
737     }
738     auto pageNode = stageManager->GetPageById(pageId);
739     if (pageId <= 0) {
740         pageNode = stageManager->GetLastPageWithTransition();
741     }
742     CHECK_NULL_RETURN(pageNode, 0.0f);
743     auto pageRenderContext = pageNode->GetRenderContext();
744     CHECK_NULL_RETURN(pageRenderContext, 0.0f);
745     auto safeAreaManager = pipeline->GetSafeAreaManager();
746     CHECK_NULL_RETURN(safeAreaManager, 0.0f);
747     auto safeArea = safeAreaManager->GetSafeArea();
748     auto safeAreaTop = safeAreaManager->IsAtomicService() ? 0 : safeArea.top_.Length();
749     auto paintRect = pageRenderContext->GetPaintRectWithoutTransform();
750     return paintRect.GetY() - safeAreaTop;
751 }
752 
ApplyConstraint(LayoutConstraintF constraint)753 void LayoutWrapper::ApplyConstraint(LayoutConstraintF constraint)
754 {
755     GetGeometryNode()->SetParentLayoutConstraint(constraint);
756 
757     auto layoutProperty = GetLayoutProperty();
758     CHECK_NULL_VOID(layoutProperty);
759     auto& magicItemProperty = layoutProperty->GetMagicItemProperty();
760     if (magicItemProperty.HasAspectRatio()) {
761         std::optional<CalcSize> idealSize = std::nullopt;
762         if (layoutProperty->GetCalcLayoutConstraint()) {
763             idealSize = layoutProperty->GetCalcLayoutConstraint()->selfIdealSize;
764         }
765         auto host = GetHostNode();
766         auto greaterThanApiTen = host ? host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TEN)
767                                       : Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN);
768         constraint.ApplyAspectRatio(magicItemProperty.GetAspectRatioValue(), idealSize,
769             layoutProperty->GetLayoutPolicyProperty(), greaterThanApiTen);
770     }
771 
772     auto&& insets = layoutProperty->GetSafeAreaInsets();
773     if (insets) {
774         ApplySafeArea(*insets, constraint);
775     }
776 
777     layoutProperty->UpdateLayoutConstraint(constraint);
778 }
779 
ApplyConstraintWithoutMeasure(const std::optional<LayoutConstraintF> & constraint)780 void LayoutWrapper::ApplyConstraintWithoutMeasure(const std::optional<LayoutConstraintF>& constraint)
781 {
782     if (constraint) {
783         ApplyConstraint(*constraint);
784     }
785 }
786 
CreateRootConstraint()787 void LayoutWrapper::CreateRootConstraint()
788 {
789     LayoutConstraintF layoutConstraint;
790     layoutConstraint.percentReference.SetWidth(PipelineContext::GetCurrentRootWidth());
791     auto layoutProperty = GetLayoutProperty();
792     CHECK_NULL_VOID(layoutProperty);
793     auto& magicItemProperty = layoutProperty->GetMagicItemProperty();
794     if (magicItemProperty.HasAspectRatio()) {
795         auto aspectRatio = magicItemProperty.GetAspectRatioValue();
796         if (Positive(aspectRatio)) {
797             auto height = PipelineContext::GetCurrentRootHeight() / aspectRatio;
798             layoutConstraint.percentReference.SetHeight(height);
799         }
800     } else {
801         layoutConstraint.percentReference.SetHeight(PipelineContext::GetCurrentRootHeight());
802     }
803     layoutProperty->UpdateLayoutConstraint(layoutConstraint);
804 }
805 
GetHostNode() const806 RefPtr<FrameNode> LayoutWrapper::GetHostNode() const
807 {
808     return hostNode_.Upgrade();
809 }
810 
AddNodeFlexLayouts()811 void LayoutWrapper::AddNodeFlexLayouts()
812 {
813     if (!AceChecker::IsPerformanceCheckEnabled()) {
814         return;
815     }
816     auto host = GetHostNode();
817     CHECK_NULL_VOID(host);
818     auto frameNodeParent = host->GetAncestorNodeOfFrame(false);
819     CHECK_NULL_VOID(frameNodeParent);
820     if (frameNodeParent->GetTag() == V2::FLEX_ETS_TAG) {
821         auto parent = host->GetParent();
822         CHECK_NULL_VOID(parent);
823         if (parent->GetTag() == V2::JS_VIEW_ETS_TAG) {
824             parent->AddFlexLayouts();
825         } else if (host->GetTag() == V2::COMMON_VIEW_ETS_TAG) {
826             auto children = host->GetChildren();
827             if (!children.empty()) {
828                 auto begin = children.begin();
829                 (*begin)->AddFlexLayouts();
830             }
831         } else {
832             host->AddFlexLayouts();
833         }
834     }
835 }
836 
AddNodeLayoutTime(int64_t time)837 void LayoutWrapper::AddNodeLayoutTime(int64_t time)
838 {
839     if (!AceChecker::IsPerformanceCheckEnabled()) {
840         return;
841     }
842     auto host = GetHostNode();
843     CHECK_NULL_VOID(host);
844     host->SetLayoutTime(time);
845 }
846 
IsIgnoreOptsValid()847 bool LayoutWrapper::IsIgnoreOptsValid()
848 {
849     auto layoutProperty = GetLayoutProperty();
850     CHECK_NULL_RETURN(layoutProperty, false);
851     return layoutProperty->IsIgnoreOptsValid();
852 }
853 
854 } // namespace OHOS::Ace::NG
855