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