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