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