1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/layout/layout_wrapper.h"
17
18 #include "base/log/ace_checker.h"
19 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
20
21 namespace OHOS::Ace::NG {
22 namespace {
InRangeStart(float number,float boundaryStart,float boundaryEnd)23 bool InRangeStart(float number, float boundaryStart, float boundaryEnd)
24 {
25 return GreatOrEqual(number, boundaryStart) && LessOrEqual(number, boundaryEnd + 1.0f);
26 }
27
InRangeEnd(float number,float boundaryStart,float boundaryEnd)28 bool InRangeEnd(float number, float boundaryStart, float boundaryEnd)
29 {
30 return GreatOrEqual(number, boundaryStart - 1.0f) && LessOrEqual(number, boundaryEnd);
31 }
32
CheckPaddingBorderGap(ExpandEdges & incomingExpand,const PaddingPropertyF & innerSpace)33 bool CheckPaddingBorderGap(ExpandEdges& incomingExpand, const PaddingPropertyF& innerSpace)
34 {
35 if (incomingExpand.left.has_value() && !NearZero(innerSpace.left.value_or(0.0f))) {
36 return false;
37 }
38 if (incomingExpand.right.has_value() && !NearZero(innerSpace.right.value_or(0.0f))) {
39 return false;
40 }
41 if (incomingExpand.top.has_value() && !NearZero(innerSpace.top.value_or(0.0f))) {
42 return false;
43 }
44 if (incomingExpand.bottom.has_value() && !NearZero(innerSpace.bottom.value_or(0.0f))) {
45 return false;
46 }
47 return true;
48 }
49
ReduceRectByRolling(RectF & rect,const ExpandEdges & rolling,double reducing)50 void ReduceRectByRolling(RectF& rect, const ExpandEdges& rolling, double reducing)
51 {
52 rect.SetLeft(rect.Left() - reducing * rolling.left.value_or(0.0f));
53 rect.SetTop(rect.Top() - reducing * rolling.top.value_or(0.0f));
54 rect.SetWidth(rect.Width() + reducing * (rolling.left.value_or(0.0f) + rolling.right.value_or(0.0f)));
55 rect.SetHeight(rect.Height() + reducing * (rolling.top.value_or(0.0f) + rolling.bottom.value_or(0.0f)));
56 }
57
IsIgnoreTypeTrivial(LayoutSafeAreaType ignoreType)58 bool IsIgnoreTypeTrivial(LayoutSafeAreaType ignoreType)
59 {
60 return ignoreType == LAYOUT_SAFE_AREA_TYPE_SYSTEM;
61 }
62
FilterEdges(const ExpandEdges & rawExpand,LayoutSafeAreaEdge edges)63 ExpandEdges FilterEdges(const ExpandEdges& rawExpand, LayoutSafeAreaEdge edges)
64 {
65 ExpandEdges res;
66 if (edges & LAYOUT_SAFE_AREA_EDGE_TOP) {
67 res.top = rawExpand.top;
68 }
69 if (edges & LAYOUT_SAFE_AREA_EDGE_BOTTOM) {
70 res.bottom = rawExpand.bottom;
71 }
72 if (edges & LAYOUT_SAFE_AREA_EDGE_START) {
73 res.left = rawExpand.left;
74 }
75 if (edges & LAYOUT_SAFE_AREA_EDGE_END) {
76 res.right = rawExpand.right;
77 }
78 return res;
79 }
80 } // namespace
81
SkipMeasureContent() const82 bool LayoutWrapper::SkipMeasureContent() const
83 {
84 return skipMeasureContent_ == true;
85 }
86
ApplySafeArea(const SafeAreaInsets & insets,LayoutConstraintF & constraint)87 void LayoutWrapper::ApplySafeArea(const SafeAreaInsets& insets, LayoutConstraintF& constraint)
88 {
89 constraint.MinusPadding(
90 insets.left_.Length(), insets.right_.Length(), insets.top_.Length(), insets.bottom_.Length());
91 }
92
OffsetNodeToSafeArea()93 void LayoutWrapper::OffsetNodeToSafeArea()
94 {
95 const auto& layoutProperty = GetLayoutProperty();
96 CHECK_NULL_VOID(layoutProperty);
97 auto&& insets = layoutProperty->GetSafeAreaInsets();
98 CHECK_NULL_VOID(insets);
99 auto geometryNode = GetGeometryNode();
100 auto offset = geometryNode->GetMarginFrameOffset();
101 if (offset.GetX() < insets->left_.end) {
102 offset.SetX(insets->left_.end);
103 }
104 if (offset.GetY() < insets->top_.end) {
105 offset.SetY(insets->top_.end);
106 }
107
108 auto right = offset.GetX() + geometryNode->GetMarginFrameSize().Width();
109 auto rightBound = insets->right_.IsValid() ? insets->right_.start : PipelineContext::GetCurrentRootWidth();
110 if (right > rightBound) {
111 offset.SetX(rightBound - geometryNode->GetMarginFrameSize().Width());
112 }
113 auto bottomBound = insets->bottom_.IsValid() ? insets->bottom_.start : PipelineContext::GetCurrentRootHeight();
114 auto bottom = offset.GetY() + geometryNode->GetMarginFrameSize().Height();
115 if (bottom > bottomBound) {
116 offset.SetY(bottomBound - geometryNode->GetMarginFrameSize().Height());
117 }
118 geometryNode->SetMarginFrameOffset(offset);
119 }
120
GetBackGroundAccumulatedSafeAreaExpand()121 RectF LayoutWrapper::GetBackGroundAccumulatedSafeAreaExpand()
122 {
123 const auto& layoutProperty = GetLayoutProperty();
124 CHECK_NULL_RETURN(layoutProperty, {});
125 auto ignoreLayoutSafeAreaEdges = layoutProperty->GetLocalizedBackgroundIgnoresLayoutSafeAreaEdges();
126 IgnoreLayoutSafeAreaOpts opts = { .type = NG::LAYOUT_SAFE_AREA_TYPE_SYSTEM, .edges = ignoreLayoutSafeAreaEdges };
127 auto expandEdges = GetAccumulatedSafeAreaExpand(false, opts);
128 auto geometryNode = GetGeometryNode();
129 RectF res = geometryNode->GetFrameRect();
130 res.SetOffset(OffsetF() - OffsetF(expandEdges.left.value_or(0.0f), expandEdges.top.value_or(0.0f)));
131 res.SetSize(res.GetSize() + SizeF(expandEdges.Width(), expandEdges.Height()));
132 return res;
133 }
134
AvoidKeyboard(bool isFocusOnPage)135 bool LayoutWrapper::AvoidKeyboard(bool isFocusOnPage)
136 {
137 auto host = GetHostNode();
138 CHECK_NULL_RETURN(host, false);
139 auto pipeline = host->GetContext();
140 CHECK_NULL_RETURN(pipeline, false);
141 auto manager = pipeline->GetSafeAreaManager();
142 bool isFocusOnOverlay = pipeline->CheckOverlayFocus();
143 bool isNeedAvoidKeyboard = manager->CheckPageNeedAvoidKeyboard(host);
144 bool isOverlay = GetHostTag() == V2::OVERLAY_ETS_TAG || GetHostTag() == V2::ORDER_OVERLAY_ETS_TAG;
145 // apply keyboard avoidance on Page or Overlay
146 if ((GetHostTag() == V2::PAGE_ETS_TAG && isNeedAvoidKeyboard) || isOverlay) {
147 CHECK_NULL_RETURN(IsActive(), false);
148 auto renderContext = GetHostNode()->GetRenderContext();
149 CHECK_NULL_RETURN(renderContext, false);
150 auto safeArea = manager->GetSafeArea();
151 auto pageCurrentOffset = GetPageCurrentOffset();
152 auto pageHasOffset = LessNotEqual(pageCurrentOffset, 0.0f);
153 auto keyboardOffset = manager->GetKeyboardOffset();
154 auto lastChild = host->GetLastChild();
155 if (GetHostTag() == V2::PAGE_ETS_TAG && lastChild && lastChild->GetTag() == V2::DIALOG_ETS_TAG) {
156 keyboardOffset = 0.0f;
157 }
158 ACE_MEASURE_SCOPED_TRACE("AvoidKeyboard isFocusOnPage: %d, isFocusOnOverlay: %d,"
159 "pageCurrentOffset: %f, keyboardOffset: %f", isFocusOnPage, isFocusOnOverlay,
160 pageCurrentOffset, keyboardOffset);
161 if (!(isFocusOnPage || (isFocusOnOverlay && isOverlay) || pageHasOffset) && LessNotEqual(keyboardOffset, 0.0)) {
162 const auto& layoutProperty = GetLayoutProperty();
163 CHECK_NULL_RETURN(layoutProperty, false);
164 renderContext->SavePaintRect(true, layoutProperty->GetPixelRound());
165 return false;
166 }
167 auto geometryNode = GetGeometryNode();
168 auto x = geometryNode->GetFrameOffset().GetX();
169 if (manager->IsAtomicService()) {
170 auto usingRect = RectF(OffsetF(x, keyboardOffset), geometryNode->GetFrameSize());
171 renderContext->UpdatePaintRect(usingRect);
172 geometryNode->SetSelfAdjust(usingRect - geometryNode->GetFrameRect());
173 pipeline->SetAreaChangeNodeMinDepth(host->GetDepth());
174 renderContext->SyncPartialRsProperties();
175 return true;
176 }
177 auto usingRect = RectF(OffsetF(x, safeArea.top_.Length() + keyboardOffset), geometryNode->GetFrameSize());
178 renderContext->UpdatePaintRect(usingRect);
179 geometryNode->SetSelfAdjust(usingRect - geometryNode->GetFrameRect());
180 pipeline->SetAreaChangeNodeMinDepth(host->GetDepth());
181 renderContext->SyncPartialRsProperties();
182 return true;
183 }
184 return false;
185 }
186
CheckValidSafeArea()187 bool LayoutWrapper::CheckValidSafeArea()
188 {
189 auto host = GetHostNode();
190 CHECK_NULL_RETURN(host, false);
191 auto pipeline = host->GetContext();
192 CHECK_NULL_RETURN(pipeline, false);
193 auto safeAreaManager = pipeline->GetSafeAreaManager();
194 CHECK_NULL_RETURN(safeAreaManager, false);
195 SafeAreaInsets safeArea;
196 const auto& layoutProperty = GetLayoutProperty();
197 CHECK_NULL_RETURN(layoutProperty, false);
198 auto&& opts = layoutProperty->GetSafeAreaExpandOpts();
199 // if self does not have opts, check parent's
200 if (!opts) {
201 auto parent = host->GetAncestorNodeOfFrame(false);
202 CHECK_NULL_RETURN(parent, false);
203 CHECK_NULL_RETURN(parent->GetLayoutProperty(), false);
204 auto&& parentOpts = parent->GetLayoutProperty()->GetSafeAreaExpandOpts();
205 CHECK_NULL_RETURN(parentOpts, false);
206 safeArea = safeAreaManager->GetCombinedSafeArea(*parentOpts);
207 } else {
208 safeArea = safeAreaManager->GetCombinedSafeArea(*opts);
209 }
210 return safeArea.IsValid();
211 }
212
GetParentGlobalOffsetWithSafeArea(bool checkBoundary,bool checkPosition) const213 OffsetF LayoutWrapper::GetParentGlobalOffsetWithSafeArea(bool checkBoundary, bool checkPosition) const
214 {
215 OffsetF offset {};
216 auto host = GetHostNode();
217 CHECK_NULL_RETURN(host, offset);
218 auto parent = host->GetAncestorNodeOfFrame(checkBoundary);
219 while (parent) {
220 auto parentRenderContext = parent->GetRenderContext();
221 if (checkPosition && parentRenderContext && parentRenderContext->GetPositionProperty() &&
222 parentRenderContext->GetPositionProperty()->HasPosition()) {
223 auto parentLayoutProp = parent->GetLayoutProperty();
224 CHECK_NULL_RETURN(parentLayoutProp, offset);
225 auto parentLayoutConstraint = parentLayoutProp->GetLayoutConstraint();
226 CHECK_NULL_RETURN(parentLayoutConstraint.has_value(), offset);
227 auto renderPosition = FrameNode::ContextPositionConvertToPX(
228 parentRenderContext, parentLayoutConstraint.value().percentReference);
229 offset += OffsetF(static_cast<float>(renderPosition.first), static_cast<float>(renderPosition.second));
230 } else {
231 offset += parent->GetFrameRectWithSafeArea().GetOffset();
232 }
233 parent = parent->GetAncestorNodeOfFrame(checkBoundary);
234 }
235 return offset;
236 }
237
GetFrameRectWithoutSafeArea() const238 RectF LayoutWrapper::GetFrameRectWithoutSafeArea() const
239 {
240 auto geometryNode = GetGeometryNode();
241 CHECK_NULL_RETURN(geometryNode, RectF());
242 return geometryNode->GetFrameRect();
243 }
244
GetFrameRectWithSafeArea(bool checkPosition) const245 RectF LayoutWrapper::GetFrameRectWithSafeArea(bool checkPosition) const
246 {
247 auto geometryNode = GetGeometryNode();
248 CHECK_NULL_RETURN(geometryNode, RectF());
249 RectF rect {};
250 auto host = GetHostNode();
251 CHECK_NULL_RETURN(host, rect);
252 auto renderContext = host->GetRenderContext();
253 if (checkPosition && renderContext && renderContext->GetPositionProperty() &&
254 renderContext->GetPositionProperty()->HasPosition()) {
255 auto layoutProp = host->GetLayoutProperty();
256 CHECK_NULL_RETURN(layoutProp, rect);
257 auto layoutConstraint = layoutProp->GetLayoutConstraint();
258 CHECK_NULL_RETURN(layoutConstraint.has_value(), rect);
259 auto renderPosition =
260 FrameNode::ContextPositionConvertToPX(renderContext, layoutConstraint.value().percentReference);
261 auto size = (geometryNode->GetSelfAdjust() + geometryNode->GetFrameRect()).GetSize();
262 rect =
263 RectF(OffsetF(static_cast<float>(renderPosition.first), static_cast<float>(renderPosition.second)), size);
264 return rect;
265 }
266 return geometryNode->GetSelfAdjust() + geometryNode->GetFrameRect();
267 }
268
AdjustNotExpandNode()269 void LayoutWrapper::AdjustNotExpandNode()
270 {
271 auto host = GetHostNode();
272 CHECK_NULL_VOID(host);
273 auto pipeline = host->GetContext();
274 CHECK_NULL_VOID(pipeline);
275 auto safeAreaManager = pipeline->GetSafeAreaManager();
276 CHECK_NULL_VOID(safeAreaManager);
277 auto parent = host->GetAncestorNodeOfFrame(false);
278 auto renderContext = host->GetRenderContext();
279 CHECK_NULL_VOID(renderContext);
280 auto geometryNode = GetGeometryNode();
281 CHECK_NULL_VOID(geometryNode);
282 auto adjustedRect = geometryNode->GetFrameRect();
283 if (safeAreaManager->IsSafeAreaValid()) {
284 adjustedRect += geometryNode->GetParentAdjust();
285 }
286 geometryNode->SetSelfAdjust(adjustedRect - geometryNode->GetFrameRect());
287 pipeline->SetAreaChangeNodeMinDepth(host->GetDepth());
288 renderContext->UpdatePaintRect(adjustedRect + geometryNode->GetPixelGridRoundRect() - geometryNode->GetFrameRect());
289 if (SystemProperties::GetSafeAreaDebugTraceEnabled()) {
290 ACE_SAFE_AREA_SCOPED_TRACE("AdjustNotExpandNode[%s][self:%d][parent:%d][key:%s][paintRectRect:%s]",
291 host->GetTag().c_str(), host->GetId(),
292 host->GetAncestorNodeOfFrame(false) ? host->GetAncestorNodeOfFrame(false)->GetId() : 0,
293 host->GetInspectorIdValue("").c_str(), renderContext->GetPaintRectWithoutTransform().ToString().c_str());
294 }
295 }
296
ExpandSafeArea()297 void LayoutWrapper::ExpandSafeArea()
298 {
299 auto host = GetHostNode();
300 CHECK_NULL_VOID(host);
301 auto pattern = host->GetPattern();
302 CHECK_NULL_VOID(pattern);
303 if (pattern->CustomizeExpandSafeArea()) {
304 return;
305 }
306 auto pipeline = host->GetContext();
307 CHECK_NULL_VOID(pipeline);
308 auto safeAreaManager = pipeline->GetSafeAreaManager();
309 CHECK_NULL_VOID(safeAreaManager);
310 const auto& layoutProperty = GetLayoutProperty();
311 CHECK_NULL_VOID(layoutProperty);
312 auto&& opts = GetLayoutProperty()->GetSafeAreaExpandOpts();
313 auto selfExpansive = host->SelfExpansive();
314 if (!selfExpansive) {
315 AdjustNotExpandNode();
316 return;
317 }
318 CHECK_NULL_VOID(selfExpansive);
319 opts->switchToNone = false;
320 auto geometryNode = GetGeometryNode();
321 CHECK_NULL_VOID(geometryNode);
322 OffsetF keyboardAdjust;
323 if ((opts->edges & SAFE_AREA_EDGE_BOTTOM) && (opts->type & SAFE_AREA_TYPE_KEYBOARD)) {
324 keyboardAdjust = ExpandIntoKeyboard();
325 }
326
327 // get frame in global offset
328 auto parentGlobalOffset = GetParentGlobalOffsetWithSafeArea();
329 auto parentAdjust = geometryNode->GetParentAdjust();
330 if (!safeAreaManager->IsSafeAreaValid()) {
331 parentAdjust = RectF();
332 }
333 auto frame = geometryNode->GetFrameRect() + parentGlobalOffset + keyboardAdjust + parentAdjust.GetOffset();
334 auto originGlobal = frame;
335
336 ExpandHelper(opts, frame);
337
338 AdjustFixedSizeNode(frame);
339 auto parent = host->GetAncestorNodeOfFrame(false);
340 auto parentScrollable = (parent && parent->GetPattern<ScrollablePattern>());
341 // restore to local offset
342 auto diff = originGlobal.GetOffset() - frame.GetOffset();
343 frame -= parentGlobalOffset;
344 // since adjustment is not accumulated and we did not track previous diff, diff need to be updated
345 AdjustChildren(diff, parentScrollable);
346
347 if (parentScrollable) {
348 AdjustNotExpandNode();
349 return;
350 }
351 auto selfAdjust = frame - geometryNode->GetFrameRect();
352 geometryNode->SetSelfAdjust(selfAdjust);
353 pipeline->SetAreaChangeNodeMinDepth(host->GetDepth());
354 auto renderContext = host->GetRenderContext();
355 CHECK_NULL_VOID(renderContext);
356 renderContext->UpdatePaintRect(frame + geometryNode->GetPixelGridRoundRect() - geometryNode->GetFrameRect());
357 if (SystemProperties::GetSafeAreaDebugTraceEnabled()) {
358 ACE_SAFE_AREA_SCOPED_TRACE(
359 "ExpandSafeAreaFinish[%s][self:%d][parent:%d][key:%s][opt:%s][paintRectRect:%s][selfAdjust:%s]",
360 host->GetTag().c_str(), host->GetId(),
361 host->GetAncestorNodeOfFrame(false) ? host->GetAncestorNodeOfFrame(false)->GetId() : 0,
362 host->GetInspectorIdValue("").c_str(), opts->ToString().c_str(),
363 renderContext->GetPaintRectWithoutTransform().ToString().c_str(), selfAdjust.ToString().c_str());
364 }
365 }
366
ResetSafeAreaPadding()367 void LayoutWrapper::ResetSafeAreaPadding()
368 {
369 // meant to reset everything each frame
370 const auto& geometryNode = GetGeometryNode();
371 CHECK_NULL_VOID(geometryNode);
372 geometryNode->ResetResolvedSelfSafeAreaPadding();
373 geometryNode->ResetAccumulatedSafeAreaPadding();
374 }
375
AccumulateExpandCacheHit(ExpandEdges & totalExpand,const PaddingPropertyF & innerSpace)376 bool LayoutWrapper::AccumulateExpandCacheHit(ExpandEdges& totalExpand, const PaddingPropertyF& innerSpace)
377 {
378 auto host = GetHostNode();
379 CHECK_NULL_RETURN(host, false);
380 const auto& geometryNode = GetGeometryNode();
381 CHECK_NULL_RETURN(geometryNode, false);
382 auto& selfAccumulateExpand = geometryNode->GetAccumulatedSafeAreaExpand();
383 CHECK_NULL_RETURN(selfAccumulateExpand, false);
384 // if parent has expand cache that covers child's, for example child expands toward left, top
385 // and parent already has cache toward left, top, bottom, then this is a cache hit
386 // and we can concatenate left and top cache to result
387 // otherwise meaning child is expanding toward a direction that parent does not have cache
388 CHECK_NULL_RETURN(selfAccumulateExpand->OptionalValueCover(totalExpand), false);
389 // parent's cache is with reference to frameRect, but during the recursive PaddingBorder need to
390 // be included in the increment.
391 // Only when the PaddingBorder is Zero, the cache can be utilized.
392 CHECK_NULL_RETURN(CheckPaddingBorderGap(totalExpand, innerSpace), false);
393 // if reaches page and totalExpand is still empty, then querying node is already as large as page
394 // then add page cache directly to total expand
395 totalExpand =
396 totalExpand.Plus(*(selfAccumulateExpand.get()), totalExpand.Empty() && host->GetTag() == V2::PAGE_ETS_TAG);
397 return true;
398 }
399
GetAccumulatedSafeAreaExpand(bool includingSelf,IgnoreLayoutSafeAreaOpts options,IgnoreStrategy strategy)400 ExpandEdges LayoutWrapper::GetAccumulatedSafeAreaExpand(
401 bool includingSelf, IgnoreLayoutSafeAreaOpts options, IgnoreStrategy strategy)
402 {
403 StartPoint startPoint = StartPoint::NORMAL;
404 if (strategy == IgnoreStrategy::FROM_MARGIN) {
405 startPoint = StartPoint::FROM_MARGIN;
406 } else if (strategy == IgnoreStrategy::AXIS_INSENSITIVE) {
407 isScrollableAxis_ = true;
408 auto sae = FilterEdges(GetAccumulatedSafeAreaExpandForAllEdges(
409 includingSelf ? StartPoint::INCLUDING_SELF : startPoint, options.type), options.edges);
410 isScrollableAxis_ = false;
411 return sae;
412 } else if (includingSelf) {
413 startPoint = StartPoint::INCLUDING_SELF;
414 }
415 return FilterEdges(GetAccumulatedSafeAreaExpandForAllEdges(startPoint, options.type), options.edges);
416 }
417
GetAccumulatedSafeAreaExpandForAllEdges(StartPoint startPoint,LayoutSafeAreaType ignoreType)418 ExpandEdges LayoutWrapper::GetAccumulatedSafeAreaExpandForAllEdges(StartPoint startPoint, LayoutSafeAreaType ignoreType)
419 {
420 ExpandEdges totalExpand;
421 auto host = GetHostNode();
422 CHECK_NULL_RETURN(host, totalExpand);
423 const auto& geometryNode = host->GetGeometryNode();
424 CHECK_NULL_RETURN(geometryNode, totalExpand);
425 RectF adjustingRect;
426 if (startPoint == StartPoint::FROM_MARGIN) {
427 adjustingRect = geometryNode->GetMarginFrameRect();
428 } else {
429 adjustingRect = geometryNode->GetFrameRect();
430 }
431 const auto& layoutProperty = GetLayoutProperty();
432 CHECK_NULL_RETURN(layoutProperty, totalExpand);
433 if (startPoint == StartPoint::INCLUDING_SELF) {
434 GetAccumulatedSafeAreaExpandHelper(adjustingRect, totalExpand, true, ignoreType);
435 return totalExpand;
436 }
437 // CreateMargin does get or create
438 auto hostMargin = layoutProperty->CreateMargin();
439 if (startPoint != StartPoint::FROM_MARGIN && hostMargin.AllSidesFilled(true)) {
440 return totalExpand;
441 }
442 // total expanding distance of four sides used to calculate cache
443 GetAccumulatedSafeAreaExpandHelper(adjustingRect, totalExpand, false, ignoreType);
444 if (IsIgnoreTypeTrivial(ignoreType) && !isScrollableAxis_) {
445 geometryNode->SetAccumulatedSafeAreaEdges(totalExpand);
446 }
447 return totalExpand;
448 }
449
ParseSafeAreaPaddingSides(const PaddingPropertyF & parentSafeAreaPadding,const PaddingPropertyF & parentInnerSpace,const RectF & adjustingRect,ExpandEdges & rollingExpand)450 void LayoutWrapper::ParseSafeAreaPaddingSides(const PaddingPropertyF& parentSafeAreaPadding,
451 const PaddingPropertyF& parentInnerSpace, const RectF& adjustingRect, ExpandEdges& rollingExpand)
452 {
453 auto host = GetHostNode();
454 CHECK_NULL_VOID(host);
455 auto parent = host->GetAncestorNodeOfFrame(false);
456 CHECK_NULL_VOID(parent);
457 const auto& parentGeometryNode = parent->GetGeometryNode();
458 CHECK_NULL_VOID(parentGeometryNode);
459 // check if current rect can overlap with four parent safeAreaPaddings
460 if (!NearZero(parentSafeAreaPadding.left.value_or(0.0f))) {
461 auto innerSpaceLeftLength = parentInnerSpace.left.value_or(0.0f);
462 // left side safeArea range is [border + padding, border + padding + safeAreaPadding]
463 if (InRangeStart(adjustingRect.Left(), innerSpaceLeftLength,
464 innerSpaceLeftLength + parentSafeAreaPadding.left.value_or(0.0f))) {
465 rollingExpand.left = adjustingRect.Left() - innerSpaceLeftLength;
466 }
467 }
468 if (!NearZero(parentSafeAreaPadding.top.value_or(0.0f))) {
469 auto innerSpaceTopLength = parentInnerSpace.top.value_or(0.0f);
470 // top side safeArea padding range is [top border + padding, top border + padding + safeAreaPadding]
471 if (InRangeStart(adjustingRect.Top(), innerSpaceTopLength,
472 innerSpaceTopLength + parentSafeAreaPadding.top.value_or(0.0f))) {
473 rollingExpand.top = adjustingRect.Top() - innerSpaceTopLength;
474 }
475 }
476 if (!NearZero(parentSafeAreaPadding.right.value_or(0.0f))) {
477 auto parentWidth = parentGeometryNode->GetFrameRect().Width();
478 auto innerSpaceRightLength = parentInnerSpace.right.value_or(0.0f);
479 // right side safeArea padding range is
480 // [parentWidth - (right border + padding) - right safeAreaPadding, parentWidth - (right border + padding)]
481 if (InRangeEnd(adjustingRect.Right(),
482 parentWidth - innerSpaceRightLength - parentSafeAreaPadding.right.value_or(0.0f),
483 parentWidth - innerSpaceRightLength)) {
484 rollingExpand.right = parentWidth - innerSpaceRightLength - adjustingRect.Right();
485 }
486 }
487 if (!NearZero(parentSafeAreaPadding.bottom.value_or(0.0f))) {
488 auto parentHeight = parentGeometryNode->GetFrameRect().Height();
489 // bottom side safeArea padding range is
490 // [parentHeight - (bottom border + padding) - bottom safeAreaPadding,
491 // parentHeight - (bottom border + padding)]
492 auto innerSpaceBottomLength = parentInnerSpace.bottom.value_or(0.0f);
493 if (InRangeEnd(adjustingRect.Bottom(),
494 parentHeight - innerSpaceBottomLength - parentSafeAreaPadding.bottom.value_or(0.0f),
495 parentHeight - innerSpaceBottomLength)) {
496 rollingExpand.bottom = parentHeight - innerSpaceBottomLength - adjustingRect.Bottom();
497 }
498 }
499 }
500
GetAccumulatedSafeAreaExpandHelper(RectF & adjustingRect,ExpandEdges & totalExpand,bool fromSelf,LayoutSafeAreaType ignoreType)501 void LayoutWrapper::GetAccumulatedSafeAreaExpandHelper(
502 RectF& adjustingRect, ExpandEdges& totalExpand, bool fromSelf, LayoutSafeAreaType ignoreType)
503 {
504 auto host = GetHostNode();
505 CHECK_NULL_VOID(host);
506 auto recursiveHost = host;
507 if (!fromSelf) {
508 auto parent = host->GetAncestorNodeOfFrame(false);
509 CHECK_NULL_VOID(parent);
510 recursiveHost = parent;
511 }
512 const auto& geometryNode = recursiveHost->GetGeometryNode();
513 CHECK_NULL_VOID(geometryNode);
514 ExpandEdges rollingExpand;
515 const auto& layoutProperty = recursiveHost->GetLayoutProperty();
516 CHECK_NULL_VOID(layoutProperty);
517 PaddingPropertyF safeAreaPadding;
518 if (recursiveHost->GetTag() == V2::STAGE_ETS_TAG) {
519 const auto& pipeline = recursiveHost->GetContext();
520 CHECK_NULL_VOID(pipeline);
521 const auto& safeAreaManager = pipeline->GetSafeAreaManager();
522 CHECK_NULL_VOID(safeAreaManager);
523 safeAreaPadding = safeAreaManager->SafeAreaToPadding(false, ignoreType);
524 } else {
525 safeAreaPadding = layoutProperty->GetOrCreateSafeAreaPadding();
526 }
527 auto innerSpace = layoutProperty->CreatePaddingAndBorder(false, false);
528
529 auto pattern = recursiveHost->GetPattern();
530 if (!isScrollableAxis_ && pattern && pattern->NeedCustomizeSafeAreaPadding()) {
531 innerSpace.Plus(pattern->CustomizeSafeAreaPadding(safeAreaPadding, true), true);
532 safeAreaPadding = pattern->CustomizeSafeAreaPadding(safeAreaPadding, false);
533 }
534
535 if (fromSelf) {
536 // if fromSelf is true, adjustingRect should cut innerSpace
537 ReduceRectByRolling(adjustingRect, innerSpace, -1.0);
538 } else {
539 ParseSafeAreaPaddingSides(safeAreaPadding, innerSpace, adjustingRect, rollingExpand);
540 // adjustingRect should append rollingExpand
541 ReduceRectByRolling(adjustingRect, rollingExpand, 1.0);
542 // after expanding based on parent safeAreaPadding, adjust rect to parent's coordinate
543 adjustingRect.SetOffset(adjustingRect.GetOffset() + geometryNode->GetFrameOffset());
544 }
545 totalExpand = totalExpand.Plus(fromSelf ? safeAreaPadding : rollingExpand);
546 auto margin = layoutProperty->CreateMargin();
547 // if parent has all four sides of innerSpace included(padding and border) or margin, stop expanding.
548 if (innerSpace.AllSidesFilled(true) || margin.AllSidesFilled(true) ||
549 (recursiveHost->GetTag() == V2::STAGE_ETS_TAG)) {
550 return;
551 }
552 if (IsIgnoreTypeTrivial(ignoreType) && !isScrollableAxis_ &&
553 recursiveHost->AccumulateExpandCacheHit(totalExpand, innerSpace)) {
554 return;
555 }
556 if (pattern && pattern->AccumulatingTerminateHelper(adjustingRect, totalExpand, fromSelf, ignoreType)) {
557 return;
558 }
559 recursiveHost->GetAccumulatedSafeAreaExpandHelper(adjustingRect, totalExpand, false, ignoreType);
560 }
561
PredictMeasureResult(LayoutWrapper * childWrapper,const std::optional<LayoutConstraintF> & parentConstraint)562 bool LayoutWrapper::PredictMeasureResult(
563 LayoutWrapper* childWrapper, const std::optional<LayoutConstraintF>& parentConstraint)
564 {
565 auto layoutProperty = childWrapper->GetLayoutProperty();
566 CHECK_NULL_RETURN(layoutProperty, false);
567 const auto& layoutConstraint = layoutProperty->GetLayoutConstraint();
568 if (!layoutConstraint.has_value() || !parentConstraint.has_value()) {
569 return false;
570 }
571 auto layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
572 if (!layoutPolicy || !layoutPolicy->IsMatch()) {
573 return false;
574 }
575 OptionalSizeF realSize;
576 auto parentIdealSize = parentConstraint->parentIdealSize;
577 auto widthLayoutPolicy = layoutPolicy->widthLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH);
578 auto heightLayoutPolicy = layoutPolicy->heightLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH);
579 if (parentIdealSize.Width().has_value() && widthLayoutPolicy == LayoutCalPolicy::MATCH_PARENT) {
580 realSize.SetWidth(parentIdealSize.Width().value());
581 }
582 if (parentIdealSize.Height().has_value() && heightLayoutPolicy == LayoutCalPolicy::MATCH_PARENT) {
583 realSize.SetHeight(parentIdealSize.Height().value());
584 }
585 auto selfIdealSize = layoutConstraint->selfIdealSize;
586 realSize.UpdateIllegalSizeWithCheck(selfIdealSize);
587 if (realSize.IsValid()) {
588 childWrapper->GetGeometryNode()->SetFrameSize(realSize.ConvertToSizeT());
589 return true;
590 }
591 return false;
592 }
593
ExpandHelper(const std::unique_ptr<SafeAreaExpandOpts> & opts,RectF & frame)594 void LayoutWrapper::ExpandHelper(const std::unique_ptr<SafeAreaExpandOpts>& opts, RectF& frame)
595 {
596 CHECK_NULL_VOID(opts);
597 auto host = GetHostNode();
598 CHECK_NULL_VOID(host);
599 auto pipeline = host->GetContext();
600 CHECK_NULL_VOID(pipeline);
601 auto safeArea = pipeline->GetSafeAreaManager()->GetCombinedSafeArea(*opts);
602 if ((opts->edges & SAFE_AREA_EDGE_START) && safeArea.left_.IsOverlapped(frame.Left())) {
603 frame.SetWidth(frame.Width() + frame.Left() - safeArea.left_.start);
604 frame.SetLeft(safeArea.left_.start);
605 }
606 if ((opts->edges & SAFE_AREA_EDGE_TOP) && safeArea.top_.IsOverlapped(frame.Top())) {
607 frame.SetHeight(frame.Height() + frame.Top() - safeArea.top_.start);
608 frame.SetTop(safeArea.top_.start);
609 }
610
611 if ((opts->edges & SAFE_AREA_EDGE_END) && safeArea.right_.IsOverlapped(frame.Right())) {
612 frame.SetWidth(frame.Width() + (safeArea.right_.end - frame.Right()));
613 }
614 if ((opts->edges & SAFE_AREA_EDGE_BOTTOM) && safeArea.bottom_.IsOverlapped(frame.Bottom())) {
615 frame.SetHeight(frame.Height() + (safeArea.bottom_.end - frame.Bottom()));
616 }
617 }
618
AdjustFixedSizeNode(RectF & frame)619 void LayoutWrapper::AdjustFixedSizeNode(RectF& frame)
620 {
621 // reset if User has fixed size
622 auto layoutProperty = GetLayoutProperty();
623 CHECK_NULL_VOID(layoutProperty);
624 auto geometryNode = GetGeometryNode();
625 CHECK_NULL_VOID(geometryNode);
626 if (layoutProperty->HasFixedWidth()) {
627 frame.SetWidth(geometryNode->GetFrameRect().Width());
628 }
629 if (layoutProperty->HasFixedHeight()) {
630 frame.SetHeight(geometryNode->GetFrameRect().Height());
631 }
632 if (layoutProperty->HasAspectRatio()) {
633 frame.SetHeight(frame.Width() / layoutProperty->GetAspectRatio());
634 }
635 }
636
AdjustChildren(const OffsetF & offset,bool parentScrollable)637 void LayoutWrapper::AdjustChildren(const OffsetF& offset, bool parentScrollable)
638 {
639 auto host = GetHostNode();
640 CHECK_NULL_VOID(host);
641 auto pattern = host->GetPattern();
642 if (pattern && pattern->ConsumeChildrenAdjustment(offset)) {
643 return;
644 }
645 for (const auto& childUI : GetHostNode()->GetChildren()) {
646 AdjustChild(childUI, offset, parentScrollable);
647 }
648 }
649
AdjustChild(RefPtr<UINode> childUI,const OffsetF & offset,bool parentScrollable)650 void LayoutWrapper::AdjustChild(RefPtr<UINode> childUI, const OffsetF& offset, bool parentScrollable)
651 {
652 auto child = DynamicCast<FrameNode>(childUI);
653 if (!child) {
654 if (!childUI->IsSyntaxNode()) {
655 return;
656 }
657 for (const auto& syntaxChild : childUI->GetChildren()) {
658 AdjustChild(syntaxChild, offset, parentScrollable);
659 }
660 return;
661 }
662 auto childGeo = child->GetGeometryNode();
663 auto parentAdjust = childGeo->GetParentAdjust();
664 if (parentAdjust.GetOffset() != offset) {
665 AddChildToExpandListIfNeeded(AceType::WeakClaim(AceType::RawPtr(child)));
666 }
667 if (!parentScrollable) {
668 childGeo->SetParentAdjust(RectF(offset, SizeF()));
669 }
670 }
671
AddChildToExpandListIfNeeded(const WeakPtr<FrameNode> & node)672 void LayoutWrapper::AddChildToExpandListIfNeeded(const WeakPtr<FrameNode>& node)
673 {
674 auto host = node.Upgrade();
675 CHECK_NULL_VOID(host);
676 auto pipeline = host->GetContext();
677 CHECK_NULL_VOID(pipeline);
678 auto safeAreaManager = pipeline->GetSafeAreaManager();
679 CHECK_NULL_VOID(safeAreaManager);
680 bool canAdd = safeAreaManager->AddNodeToExpandListIfNeeded(node);
681 CHECK_NULL_VOID(canAdd);
682 auto task = [weak = node]() {
683 auto frameNode = weak.Upgrade();
684 CHECK_NULL_VOID(frameNode);
685 DirtySwapConfig emptyConfig;
686 frameNode->SyncGeometryNode(true, emptyConfig);
687 };
688 pipeline->AddSyncGeometryNodeTask(task);
689 }
690
ExpandIntoKeyboard()691 OffsetF LayoutWrapper::ExpandIntoKeyboard()
692 {
693 auto pageOffset = GetPageCurrentOffset();
694 if (GreatOrEqual(pageOffset, 0.0f)) {
695 return OffsetF();
696 }
697 // if parent already expanded into keyboard, offset shouldn't be applied again
698 auto parent = GetHostNode()->GetAncestorNodeOfFrame(false);
699 while (parent) {
700 auto pattern = parent->GetPattern();
701 if (pattern && pattern->CheckCustomAvoidKeyboard()) {
702 // if parent need avoid keyboard and child need expand into keyboard,
703 // keep child expand into keyboard
704 break;
705 }
706 const auto& parentLayoutProperty = parent->GetLayoutProperty();
707 CHECK_NULL_RETURN(parentLayoutProperty, OffsetF());
708 auto&& opts = parentLayoutProperty->GetSafeAreaExpandOpts();
709 if (opts && (opts->edges & SAFE_AREA_EDGE_BOTTOM) && opts->type & SAFE_AREA_TYPE_KEYBOARD) {
710 return OffsetF();
711 }
712 parent = parent->GetAncestorNodeOfFrame(false);
713 }
714 auto host = GetHostNode();
715 CHECK_NULL_RETURN(host, OffsetF());
716 auto pipeline = host->GetContext();
717 CHECK_NULL_RETURN(pipeline, OffsetF());
718 return OffsetF(0.0f, -pipeline->GetSafeAreaManager()->GetKeyboardOffset());
719 }
720
GetPageCurrentOffset()721 float LayoutWrapper::GetPageCurrentOffset()
722 {
723 auto host = GetHostNode();
724 CHECK_NULL_RETURN(host, 0.0f);
725 auto pipeline = host->GetContext();
726 CHECK_NULL_RETURN(pipeline, 0.0f);
727 auto stageManager = pipeline->GetStageManager();
728 CHECK_NULL_RETURN(stageManager, 0.0f);
729 auto pageId = host->GetPageId();
730 auto parent = host;
731 while (parent) {
732 if (parent->GetPageId() > 0) {
733 pageId = parent->GetPageId();
734 break;
735 }
736 parent = parent->GetAncestorNodeOfFrame(false);
737 }
738 auto pageNode = stageManager->GetPageById(pageId);
739 if (pageId <= 0) {
740 pageNode = stageManager->GetLastPageWithTransition();
741 }
742 CHECK_NULL_RETURN(pageNode, 0.0f);
743 auto pageRenderContext = pageNode->GetRenderContext();
744 CHECK_NULL_RETURN(pageRenderContext, 0.0f);
745 auto safeAreaManager = pipeline->GetSafeAreaManager();
746 CHECK_NULL_RETURN(safeAreaManager, 0.0f);
747 auto safeArea = safeAreaManager->GetSafeArea();
748 auto safeAreaTop = safeAreaManager->IsAtomicService() ? 0 : safeArea.top_.Length();
749 auto paintRect = pageRenderContext->GetPaintRectWithoutTransform();
750 return paintRect.GetY() - safeAreaTop;
751 }
752
ApplyConstraint(LayoutConstraintF constraint)753 void LayoutWrapper::ApplyConstraint(LayoutConstraintF constraint)
754 {
755 GetGeometryNode()->SetParentLayoutConstraint(constraint);
756
757 auto layoutProperty = GetLayoutProperty();
758 CHECK_NULL_VOID(layoutProperty);
759 auto& magicItemProperty = layoutProperty->GetMagicItemProperty();
760 if (magicItemProperty.HasAspectRatio()) {
761 std::optional<CalcSize> idealSize = std::nullopt;
762 if (layoutProperty->GetCalcLayoutConstraint()) {
763 idealSize = layoutProperty->GetCalcLayoutConstraint()->selfIdealSize;
764 }
765 auto host = GetHostNode();
766 auto greaterThanApiTen = host ? host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TEN)
767 : Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN);
768 constraint.ApplyAspectRatio(magicItemProperty.GetAspectRatioValue(), idealSize,
769 layoutProperty->GetLayoutPolicyProperty(), greaterThanApiTen);
770 }
771
772 auto&& insets = layoutProperty->GetSafeAreaInsets();
773 if (insets) {
774 ApplySafeArea(*insets, constraint);
775 }
776
777 layoutProperty->UpdateLayoutConstraint(constraint);
778 }
779
ApplyConstraintWithoutMeasure(const std::optional<LayoutConstraintF> & constraint)780 void LayoutWrapper::ApplyConstraintWithoutMeasure(const std::optional<LayoutConstraintF>& constraint)
781 {
782 if (constraint) {
783 ApplyConstraint(*constraint);
784 }
785 }
786
CreateRootConstraint()787 void LayoutWrapper::CreateRootConstraint()
788 {
789 LayoutConstraintF layoutConstraint;
790 layoutConstraint.percentReference.SetWidth(PipelineContext::GetCurrentRootWidth());
791 auto layoutProperty = GetLayoutProperty();
792 CHECK_NULL_VOID(layoutProperty);
793 auto& magicItemProperty = layoutProperty->GetMagicItemProperty();
794 if (magicItemProperty.HasAspectRatio()) {
795 auto aspectRatio = magicItemProperty.GetAspectRatioValue();
796 if (Positive(aspectRatio)) {
797 auto height = PipelineContext::GetCurrentRootHeight() / aspectRatio;
798 layoutConstraint.percentReference.SetHeight(height);
799 }
800 } else {
801 layoutConstraint.percentReference.SetHeight(PipelineContext::GetCurrentRootHeight());
802 }
803 layoutProperty->UpdateLayoutConstraint(layoutConstraint);
804 }
805
GetHostNode() const806 RefPtr<FrameNode> LayoutWrapper::GetHostNode() const
807 {
808 return hostNode_.Upgrade();
809 }
810
AddNodeFlexLayouts()811 void LayoutWrapper::AddNodeFlexLayouts()
812 {
813 if (!AceChecker::IsPerformanceCheckEnabled()) {
814 return;
815 }
816 auto host = GetHostNode();
817 CHECK_NULL_VOID(host);
818 auto frameNodeParent = host->GetAncestorNodeOfFrame(false);
819 CHECK_NULL_VOID(frameNodeParent);
820 if (frameNodeParent->GetTag() == V2::FLEX_ETS_TAG) {
821 auto parent = host->GetParent();
822 CHECK_NULL_VOID(parent);
823 if (parent->GetTag() == V2::JS_VIEW_ETS_TAG) {
824 parent->AddFlexLayouts();
825 } else if (host->GetTag() == V2::COMMON_VIEW_ETS_TAG) {
826 auto children = host->GetChildren();
827 if (!children.empty()) {
828 auto begin = children.begin();
829 (*begin)->AddFlexLayouts();
830 }
831 } else {
832 host->AddFlexLayouts();
833 }
834 }
835 }
836
AddNodeLayoutTime(int64_t time)837 void LayoutWrapper::AddNodeLayoutTime(int64_t time)
838 {
839 if (!AceChecker::IsPerformanceCheckEnabled()) {
840 return;
841 }
842 auto host = GetHostNode();
843 CHECK_NULL_VOID(host);
844 host->SetLayoutTime(time);
845 }
846
IsIgnoreOptsValid()847 bool LayoutWrapper::IsIgnoreOptsValid()
848 {
849 auto layoutProperty = GetLayoutProperty();
850 CHECK_NULL_RETURN(layoutProperty, false);
851 return layoutProperty->IsIgnoreOptsValid();
852 }
853
854 } // namespace OHOS::Ace::NG
855