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