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