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