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/pattern/flex/flex_layout_algorithm.h"
17
18 #include "core/components_ng/pattern/blank/blank_layout_property.h"
19 #include "core/components_ng/pattern/flex/flex_layout_pattern.h"
20 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
21 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
22 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
23 #include "core/components_ng/property/measure_utils.h"
24
25 namespace OHOS::Ace::NG {
26
27 namespace {
28 /**
29 * Get the main axis direction based on direction.
30 */
FlipAxis(FlexDirection direction)31 FlexDirection FlipAxis(FlexDirection direction)
32 {
33 if (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
34 return FlexDirection::COLUMN;
35 }
36 return FlexDirection::ROW;
37 }
38
39 /**
40 * Determine whether to start the layout from the upper left corner
41 */
IsStartTopLeft(FlexDirection direction,TextDirection textDirection)42 bool IsStartTopLeft(FlexDirection direction, TextDirection textDirection)
43 {
44 switch (direction) {
45 case FlexDirection::ROW:
46 return textDirection == TextDirection::LTR;
47 case FlexDirection::ROW_REVERSE:
48 return textDirection == TextDirection::RTL;
49 case FlexDirection::COLUMN:
50 return true;
51 case FlexDirection::COLUMN_REVERSE:
52 return false;
53 default:
54 return true;
55 }
56 }
57
ReverseFlexDirection(FlexDirection direction)58 FlexDirection ReverseFlexDirection(FlexDirection direction)
59 {
60 switch (direction) {
61 case FlexDirection::ROW:
62 return FlexDirection::ROW_REVERSE;
63 case FlexDirection::ROW_REVERSE:
64 return FlexDirection::ROW;
65 case FlexDirection::COLUMN:
66 return FlexDirection::COLUMN_REVERSE;
67 case FlexDirection::COLUMN_REVERSE:
68 return FlexDirection::COLUMN;
69 default:
70 return FlexDirection::ROW;
71 }
72 }
73
GetCrossAxisSizeHelper(const SizeF & size,FlexDirection direction)74 float GetCrossAxisSizeHelper(const SizeF& size, FlexDirection direction)
75 {
76 if (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
77 return size.Height();
78 }
79 return size.Width();
80 }
81
GetMainAxisSizeHelper(const SizeF & size,FlexDirection direction)82 float GetMainAxisSizeHelper(const SizeF& size, FlexDirection direction)
83 {
84 if (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
85 return size.Width();
86 }
87 return size.Height();
88 }
89
GetCalcSizeHelper(float mainAxisSize,float crossAxisSize,FlexDirection direction)90 OptionalSizeF GetCalcSizeHelper(float mainAxisSize, float crossAxisSize, FlexDirection direction)
91 {
92 OptionalSizeF size;
93 if (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
94 size.SetWidth(mainAxisSize);
95 size.SetHeight(crossAxisSize);
96 } else {
97 size.SetHeight(mainAxisSize);
98 size.SetWidth(crossAxisSize);
99 }
100 return size;
101 }
102
IsHorizontal(FlexDirection direction)103 bool IsHorizontal(FlexDirection direction)
104 {
105 return direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE;
106 }
107
UpdateChildLayoutConstrainByFlexBasis(FlexDirection direction,const RefPtr<LayoutWrapper> & child,LayoutConstraintF & layoutConstraint)108 void UpdateChildLayoutConstrainByFlexBasis(
109 FlexDirection direction, const RefPtr<LayoutWrapper>& child, LayoutConstraintF& layoutConstraint)
110 {
111 const auto& childLayoutProperty = child->GetLayoutProperty();
112 CHECK_NULL_VOID(childLayoutProperty);
113 auto& flexItemProperty = childLayoutProperty->GetFlexItemProperty();
114 CHECK_NULL_VOID(flexItemProperty);
115 const auto& flexBasis = flexItemProperty->GetFlexBasis();
116 CHECK_NULL_VOID(flexBasis);
117 if (flexBasis->Unit() == DimensionUnit::AUTO || !flexBasis->IsValid()) {
118 return;
119 }
120 if (childLayoutProperty->GetCalcLayoutConstraint()) {
121 auto selfIdealSize = childLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize;
122 if (child->GetHostTag() == V2::BLANK_ETS_TAG && selfIdealSize.has_value()) {
123 if (IsHorizontal(direction) && selfIdealSize->Width().has_value() &&
124 selfIdealSize->Width()->GetDimension().ConvertToPx() > flexBasis->ConvertToPx()) {
125 return;
126 } else if (!IsHorizontal(direction) && selfIdealSize->Height().has_value() &&
127 selfIdealSize->Height()->GetDimension().ConvertToPx() > flexBasis->ConvertToPx()) {
128 return;
129 }
130 }
131 }
132 if (IsHorizontal(direction)) {
133 layoutConstraint.selfIdealSize.SetWidth(flexBasis->ConvertToPx());
134 } else {
135 layoutConstraint.selfIdealSize.SetHeight(flexBasis->ConvertToPx());
136 }
137 }
138
GetMainAxisMargin(const RefPtr<LayoutWrapper> & child,FlexDirection direction)139 float GetMainAxisMargin(const RefPtr<LayoutWrapper>& child, FlexDirection direction)
140 {
141 float childMainAxisMargin = 0.0f;
142 if (child && child->GetGeometryNode() && child->GetGeometryNode()->GetMargin()) {
143 childMainAxisMargin = GetMainAxisSizeHelper(child->GetGeometryNode()->GetMargin()->Size(), direction);
144 }
145 return childMainAxisMargin;
146 }
147
IsVisibleGone(const RefPtr<LayoutWrapper> & layoutWrapper)148 bool IsVisibleGone(const RefPtr<LayoutWrapper>& layoutWrapper)
149 {
150 return layoutWrapper && layoutWrapper->GetHostNode() && layoutWrapper->GetHostNode()->GetLayoutProperty() &&
151 layoutWrapper->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) ==
152 VisibleType::GONE;
153 }
154
155 const float HALF = 0.5f;
156
157 } // namespace
158
GetChildMainAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const159 float FlexLayoutAlgorithm::GetChildMainAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
160 {
161 float size = 0.0f;
162 CHECK_NULL_RETURN(layoutWrapper, size);
163 return GetMainAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetMarginFrameSize(), direction_);
164 }
165
GetChildCrossAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const166 float FlexLayoutAlgorithm::GetChildCrossAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
167 {
168 CHECK_NULL_RETURN(layoutWrapper, 0.0f);
169 return GetCrossAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetMarginFrameSize(), direction_);
170 }
171
GetSelfCrossAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const172 float FlexLayoutAlgorithm::GetSelfCrossAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
173 {
174 CHECK_NULL_RETURN(layoutWrapper, 0.0f);
175 return GetCrossAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetFrameSize(), direction_);
176 }
177
CheckSizeValidity(const RefPtr<LayoutWrapper> & layoutWrapper)178 void FlexLayoutAlgorithm::CheckSizeValidity(const RefPtr<LayoutWrapper>& layoutWrapper)
179 {
180 if (IsVisibleGone(layoutWrapper)) {
181 return;
182 }
183 ++validSizeCount_;
184 }
185
186 /**
187 * Check and record baseline distance.
188 */
CheckBaselineProperties(const RefPtr<LayoutWrapper> & layoutWrapper)189 void FlexLayoutAlgorithm::CheckBaselineProperties(const RefPtr<LayoutWrapper>& layoutWrapper)
190 {
191 if (crossAxisAlign_ != FlexAlign::BASELINE && !childrenHasAlignSelfBaseLine_) {
192 return;
193 }
194 float distance = layoutWrapper->GetBaselineDistance();
195 baselineProperties_.maxBaselineDistance = std::max(baselineProperties_.maxBaselineDistance, distance);
196 baselineProperties_.maxDistanceAboveBaseline = std::max(baselineProperties_.maxDistanceAboveBaseline, distance);
197 baselineProperties_.maxDistanceBelowBaseline =
198 std::max(baselineProperties_.maxDistanceBelowBaseline, GetSelfCrossAxisSize(layoutWrapper) - distance);
199 if (crossAxisAlign_ == FlexAlign::BASELINE) {
200 crossAxisSize_ = baselineProperties_.maxDistanceAboveBaseline + baselineProperties_.maxDistanceBelowBaseline;
201 }
202 }
203
204 /**
205 * Initialize the FlexLayoutAlgorithm property.
206 */
InitFlexProperties(LayoutWrapper * layoutWrapper)207 void FlexLayoutAlgorithm::InitFlexProperties(LayoutWrapper* layoutWrapper)
208 {
209 mainAxisSize_ = 0.0f;
210 crossAxisSize_ = 0.0f;
211 allocatedSize_ = 0.0f;
212 selfIdealCrossAxisSize_ = -1.0f;
213 validSizeCount_ = 0;
214 realSize_.Reset();
215 isInfiniteLayout_ = false;
216 selfAdaptive_ = false;
217 auto layoutProperty = AceType::DynamicCast<FlexLayoutProperty>(layoutWrapper->GetLayoutProperty());
218 CHECK_NULL_VOID(layoutProperty);
219 space_ = static_cast<float>(layoutProperty->GetSpaceValue({}).ConvertToPx());
220 direction_ = layoutProperty->GetFlexDirection().value_or(FlexDirection::ROW);
221 mainAxisAlign_ = layoutProperty->GetMainAxisAlignValue(FlexAlign::FLEX_START);
222 secondaryMeasureList_.clear();
223 crossAxisAlign_ =
224 layoutProperty->GetCrossAxisAlignValue(isLinearLayoutFeature_ ? FlexAlign::CENTER : FlexAlign::FLEX_START);
225 baselineProperties_.Reset();
226 textDir_ = layoutProperty->GetLayoutDirection();
227 if (textDir_ == TextDirection::AUTO) {
228 textDir_ = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
229 }
230 /**
231 * FlexLayoutAlgorithm, as the parent class, should not handle the special logic of the subclass
232 * LinearLayout.
233 */
234 if (isLinearLayoutFeature_) {
235 const auto& linearLayoutProperty = DynamicCast<LinearLayoutProperty>(layoutWrapper->GetLayoutProperty());
236 CHECK_NULL_VOID(linearLayoutProperty);
237 bool isVertical = linearLayoutProperty->IsVertical();
238 direction_ = isVertical ? FlexDirection::COLUMN : FlexDirection::ROW;
239 }
240 }
241
AddElementIntoMagicNodes(int32_t childDisplayPriority,MagicLayoutNode node,float childLayoutWeight)242 void FlexLayoutAlgorithm::AddElementIntoMagicNodes(
243 int32_t childDisplayPriority, MagicLayoutNode node, float childLayoutWeight)
244 {
245 auto iter = magicNodes_.find(childDisplayPriority);
246 /**
247 * if current childDisplayPriority is not a key of magicNodes_, create a key and add current node into its value
248 * list.
249 */
250 if (iter == magicNodes_.end()) {
251 magicNodes_.insert(std::map<int32_t, std::list<MagicLayoutNode>>::value_type(childDisplayPriority, { node }));
252 if (GreatNotEqual(childLayoutWeight, 0.0f)) {
253 magicNodeWeights_.insert(std::map<int32_t, float>::value_type(childDisplayPriority, childLayoutWeight));
254 }
255 return;
256 }
257 iter->second.emplace_back(node);
258 if (GreatNotEqual(childLayoutWeight, 0.0f)) {
259 magicNodeWeights_[childDisplayPriority] += childLayoutWeight;
260 }
261 }
262
TravelChildrenFlexProps(LayoutWrapper * layoutWrapper)263 void FlexLayoutAlgorithm::TravelChildrenFlexProps(LayoutWrapper* layoutWrapper)
264 {
265 maxDisplayPriority_ = 0;
266 totalFlexWeight_ = 0.0f;
267 outOfLayoutChildren_.clear();
268 layoutPolicyChildren_.clear();
269 magicNodes_.clear();
270 magicNodeWeights_.clear();
271 childrenHasAlignSelfBaseLine_ = false;
272 const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
273 CHECK_NULL_VOID(layoutProperty);
274 const auto& children = layoutWrapper->GetAllChildrenWithBuild();
275 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
276 for (const auto& child : children) {
277 bool checkNeedSkip = AddElementIntoLayoutPolicyChildren(layoutWrapper, child);
278 if (child->IsOutOfLayout()) {
279 outOfLayoutChildren_.emplace_back(child);
280 checkNeedSkip = true;
281 }
282 if (checkNeedSkip) {
283 continue;
284 }
285 const auto& childLayoutProperty = child->GetLayoutProperty();
286 CHECK_NULL_CONTINUE(childLayoutProperty);
287 const auto& childMagicItemProperty = childLayoutProperty->GetMagicItemProperty();
288 const auto& childFlexItemProperty = childLayoutProperty->GetFlexItemProperty();
289 MagicLayoutNode node;
290 node.layoutWrapper = child;
291 node.layoutConstraint = childLayoutConstraint;
292
293 bool childGone = IsVisibleGone(child);
294 int32_t childDisplayPriority = 1;
295 float childLayoutWeight = 0.0f;
296 if (childGone) {
297 AddElementIntoMagicNodes(childDisplayPriority, node, childLayoutWeight);
298 continue;
299 }
300 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
301 if (childFlexItemProperty) {
302 childDisplayPriority = childFlexItemProperty->GetDisplayIndex().value_or(1);
303 if (!childrenHasAlignSelfBaseLine_ &&
304 childFlexItemProperty->GetAlignSelf().value_or(FlexAlign::FLEX_START) == FlexAlign::BASELINE) {
305 childrenHasAlignSelfBaseLine_ = true;
306 }
307 }
308 AddElementIntoMagicNodes(childDisplayPriority, node, childLayoutWeight);
309 totalFlexWeight_ += GreatNotEqual(childLayoutWeight, 0.0f) ? childLayoutWeight : 0.0f;
310 maxDisplayPriority_ = std::max(childDisplayPriority, maxDisplayPriority_);
311 }
312 }
313
AddElementIntoLayoutPolicyChildren(LayoutWrapper * layoutWrapper,RefPtr<LayoutWrapper> child)314 bool FlexLayoutAlgorithm::AddElementIntoLayoutPolicyChildren(LayoutWrapper* layoutWrapper, RefPtr<LayoutWrapper> child)
315 {
316 CHECK_NULL_RETURN(layoutWrapper, false);
317 CHECK_NULL_RETURN(child, false);
318 const auto& childLayoutProperty = child->GetLayoutProperty();
319 CHECK_NULL_RETURN(childLayoutProperty, false);
320 auto layoutPolicy = childLayoutProperty->GetLayoutPolicyProperty();
321 CHECK_NULL_RETURN(layoutPolicy, false);
322 if (!layoutPolicy.value().IsMatch()) {
323 return false;
324 }
325 layoutPolicyChildren_.emplace_back(child);
326 return true;
327 }
328
UpdateAllocatedSize(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & crossAxisSize)329 void FlexLayoutAlgorithm::UpdateAllocatedSize(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& crossAxisSize)
330 {
331 float mainAxisSize = GetChildMainAxisSize(childLayoutWrapper);
332 if (GreaterOrEqualToInfinity(mainAxisSize)) {
333 mainAxisSize = 0.0f;
334 }
335 crossAxisSize = std::max(crossAxisSize, GetChildCrossAxisSize(childLayoutWrapper));
336 allocatedSize_ += mainAxisSize;
337 allocatedSize_ += space_;
338 }
339
MeasureOutOfLayoutChildren(LayoutWrapper * layoutWrapper)340 void FlexLayoutAlgorithm::MeasureOutOfLayoutChildren(LayoutWrapper* layoutWrapper)
341 {
342 const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
343 CHECK_NULL_VOID(layoutProperty);
344 const auto& layoutConstraint = layoutProperty->CreateChildConstraint();
345 for (const auto& child : outOfLayoutChildren_) {
346 child->Measure(layoutConstraint);
347 }
348 }
349
MeasureAdaptiveLayoutChildren(LayoutWrapper * layoutWrapper,SizeF & realSize)350 void FlexLayoutAlgorithm::MeasureAdaptiveLayoutChildren(LayoutWrapper* layoutWrapper, SizeF& realSize)
351 {
352 const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
353 CHECK_NULL_VOID(layoutProperty);
354 auto layoutConstraint = layoutProperty->CreateChildConstraint();
355 auto host = layoutWrapper->GetHostNode();
356 CHECK_NULL_VOID(host);
357 if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWENTY) || host->GetTag() == V2::FLEX_ETS_TAG) {
358 auto padding = layoutProperty->CreatePaddingAndBorder();
359 MinusPaddingToNonNegativeSize(padding, realSize);
360 }
361 layoutConstraint.parentIdealSize.SetSize(realSize);
362 auto context = host->GetContext();
363 IgnoreLayoutSafeAreaBundle bundle;
364 for (const auto& child : layoutPolicyChildren_) {
365 auto childNode = child->GetHostNode();
366 if (childNode && childNode->GetLayoutProperty() && childNode->GetLayoutProperty()->IsExpandConstraintNeeded()) {
367 bundle.first.emplace_back(childNode);
368 child->SetDelaySelfLayoutForIgnore();
369 child->GetGeometryNode()->SetParentLayoutConstraint(layoutConstraint);
370 continue;
371 }
372 child->Measure(layoutConstraint);
373 }
374 if (context && !bundle.first.empty()) {
375 host->SetDelaySelfLayoutForIgnore();
376 bundle.second = host;
377 context->AddIgnoreLayoutSafeAreaBundle(std::move(bundle));
378 }
379 }
380
FirstMeasureInWeightMode()381 std::map<int32_t, std::list<MagicLayoutNode>>::reverse_iterator FlexLayoutAlgorithm::FirstMeasureInWeightMode()
382 {
383 auto firstLoopIter = magicNodes_.rbegin();
384 auto loopIter = firstLoopIter;
385 bool outOfDisplay = false;
386 while (loopIter != magicNodes_.rend()) {
387 auto& childList = loopIter->second;
388 float crossAxisSize = crossAxisSize_;
389 for (auto& child : childList) {
390 if (outOfDisplay) {
391 child.layoutWrapper->SetActive(false);
392 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
393 continue;
394 }
395 const auto& childLayoutWrapper = child.layoutWrapper;
396 float childLayoutWeight = 0.0f;
397 auto childLayoutProperty = childLayoutWrapper->GetLayoutProperty();
398 CHECK_NULL_CONTINUE(childLayoutProperty);
399 const auto& childMagicItemProperty = childLayoutProperty->GetMagicItemProperty();
400 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
401 if (GreatNotEqual(childLayoutWeight, 0.0f)) {
402 allocatedSize_ += space_;
403 continue;
404 }
405 if (IsVisibleGone(child.layoutWrapper)) {
406 continue;
407 }
408 childLayoutWrapper->Measure(child.layoutConstraint);
409 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize);
410 CheckSizeValidity(childLayoutWrapper);
411 CheckBaselineProperties(childLayoutWrapper);
412 }
413 if (outOfDisplay) {
414 ++loopIter;
415 continue;
416 }
417 if (!(allocatedSize_ - space_ > mainAxisSize_ && magicNodes_.size() > 1)) {
418 crossAxisSize_ = crossAxisSize;
419 firstLoopIter = ++loopIter;
420 continue;
421 }
422 /**
423 * The main axis size of the element with layoutWeight of 0 is larger than the Flex main axis size
424 */
425 for (const auto& child : childList) {
426 allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper);
427 allocatedSize_ -= space_;
428 child.layoutWrapper->SetActive(false);
429 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
430 }
431 outOfDisplay = true;
432 firstLoopIter = loopIter++;
433 }
434 return firstLoopIter;
435 }
436
SecondMeasureInWeightMode(std::map<int32_t,std::list<MagicLayoutNode>>::reverse_iterator firstLoopIter)437 void FlexLayoutAlgorithm::SecondMeasureInWeightMode(
438 std::map<int32_t, std::list<MagicLayoutNode>>::reverse_iterator firstLoopIter)
439 {
440 auto newTotalFlexWeight = totalFlexWeight_;
441 allocatedSize_ -= space_;
442 auto remainedMainAxisSize = mainAxisSize_ - allocatedSize_;
443 auto spacePerWeight = remainedMainAxisSize / newTotalFlexWeight;
444 auto secondIterLoop = magicNodes_.rbegin();
445 while (secondIterLoop != firstLoopIter && secondIterLoop != magicNodes_.rend()) {
446 auto& childList = secondIterLoop->second;
447 bool isExceed = false;
448 for (auto& child : childList) {
449 auto childLayoutWrapper = child.layoutWrapper;
450 auto& childConstraint = child.layoutConstraint;
451 float childLayoutWeight = 0.0f;
452 auto childLayoutProperty = childLayoutWrapper->GetLayoutProperty();
453 CHECK_NULL_CONTINUE(childLayoutProperty);
454 const auto& childMagicItemProperty = childLayoutProperty->GetMagicItemProperty();
455 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
456 if (LessOrEqual(childLayoutWeight, 0.0)) {
457 continue;
458 }
459 float childCalcSize = std::max(spacePerWeight * childLayoutWeight, 0.0f);
460 if (GetMainAxisSizeHelper(childConstraint.minSize, direction_) > childCalcSize) {
461 isExceed = true;
462 }
463 UpdateLayoutConstraintOnMainAxis(childConstraint, childCalcSize);
464 }
465 if (isExceed) {
466 if (magicNodes_.size() <= 1) {
467 break;
468 }
469 isExceed = true;
470 auto& lowPriorityChildList = magicNodes_.begin()->second;
471 for (const auto& child : lowPriorityChildList) {
472 allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper);
473 allocatedSize_ -= space_;
474 child.layoutWrapper->SetActive(false);
475 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
476 }
477 newTotalFlexWeight -= magicNodeWeights_[magicNodes_.begin()->first];
478 remainedMainAxisSize = mainAxisSize_ - allocatedSize_;
479 spacePerWeight = remainedMainAxisSize / newTotalFlexWeight;
480 isExceed = false;
481 magicNodes_.erase(magicNodes_.begin());
482 secondIterLoop = magicNodes_.rbegin();
483 } else {
484 secondIterLoop++;
485 }
486 }
487 }
488
FinalMeasureInWeightMode()489 void FlexLayoutAlgorithm::FinalMeasureInWeightMode()
490 {
491 auto iter = magicNodes_.rbegin();
492 while (iter != magicNodes_.rend()) {
493 auto& childList = iter->second;
494 for (auto& child : childList) {
495 auto childLayoutWrapper = child.layoutWrapper;
496 if (!childLayoutWrapper->IsActive()) {
497 continue;
498 }
499 float childLayoutWeight = 0.0f;
500 auto childLayoutProperty = childLayoutWrapper->GetLayoutProperty();
501 CHECK_NULL_CONTINUE(childLayoutProperty);
502 const auto& childMagicItemProperty = childLayoutProperty->GetMagicItemProperty();
503 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
504 secondaryMeasureList_.emplace_back(child);
505 if (LessOrEqual(childLayoutWeight, 0.0)) {
506 continue;
507 }
508 childLayoutWrapper->Measure(child.layoutConstraint);
509 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
510 CheckSizeValidity(childLayoutWrapper);
511 CheckBaselineProperties(childLayoutWrapper);
512 }
513 iter++;
514 }
515 }
516
PopOutOfDispayMagicNodesInPriorityMode(const std::list<MagicLayoutNode> & childList,FlexItemProperties & flexItemProperties)517 void FlexLayoutAlgorithm::PopOutOfDispayMagicNodesInPriorityMode(const std::list<MagicLayoutNode>& childList,
518 FlexItemProperties& flexItemProperties)
519 {
520 if (childList.empty()) {
521 return;
522 }
523 for (auto& child : childList) {
524 allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper) + space_;
525 child.layoutWrapper->SetActive(false);
526 --validSizeCount_;
527 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
528 const auto& childLayoutProperty = child.layoutWrapper->GetLayoutProperty();
529 CHECK_NULL_CONTINUE(childLayoutProperty);
530 const auto& flexItemProperty = childLayoutProperty->GetFlexItemProperty();
531 if (flexItemProperty && GreatNotEqual(flexItemProperty->GetFlexGrow().value_or(0.0f), 0.0f)) {
532 flexItemProperties.totalGrow -= flexItemProperty->GetFlexGrow().value_or(0.0f);
533 }
534 secondaryMeasureList_.pop_back();
535 }
536 }
537
MeasureInPriorityMode(FlexItemProperties & flexItemProperties)538 void FlexLayoutAlgorithm::MeasureInPriorityMode(FlexItemProperties& flexItemProperties)
539 {
540 bool outOfDisplay = false;
541 auto iter = magicNodes_.rbegin();
542 while (iter != magicNodes_.rend()) {
543 auto childList = iter->second;
544 if (outOfDisplay) {
545 for (auto& child : childList) {
546 const auto& childLayoutWrapper = child.layoutWrapper;
547 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, child.layoutConstraint);
548 child.layoutWrapper->ApplyConstraintWithoutMeasure(child.layoutConstraint);
549 child.layoutWrapper->SetActive(false);
550 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
551 }
552 ++iter;
553 continue;
554 }
555 float crossAxisSize = crossAxisSize_;
556 for (auto& child : childList) {
557 const auto& childLayoutWrapper = child.layoutWrapper;
558 const auto& childLayoutProperty = childLayoutWrapper->GetLayoutProperty();
559 CHECK_NULL_CONTINUE(childLayoutProperty);
560 childLayoutProperty->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
561 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, child.layoutConstraint);
562 childLayoutWrapper->Measure(child.layoutConstraint);
563 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize);
564 CheckSizeValidity(childLayoutWrapper);
565 CheckBaselineProperties(childLayoutWrapper);
566 const auto& flexItemProperty = childLayoutProperty->GetFlexItemProperty();
567 if (flexItemProperty && GreatNotEqual(flexItemProperty->GetFlexGrow().value_or(0.0f), 0.0f)) {
568 flexItemProperties.totalGrow += flexItemProperty->GetFlexGrow().value_or(0.0f);
569 }
570 secondaryMeasureList_.emplace_back(child);
571 }
572 if (LessOrEqual(allocatedSize_ - space_, mainAxisSize_)) {
573 crossAxisSize_ = crossAxisSize;
574 ++iter;
575 continue;
576 }
577 outOfDisplay = true;
578 PopOutOfDispayMagicNodesInPriorityMode(childList, flexItemProperties);
579 ++iter;
580 }
581 }
582
MeasureAndCleanMagicNodes(LayoutWrapper * containerLayoutWrapper,FlexItemProperties & flexItemProperties)583 void FlexLayoutAlgorithm::MeasureAndCleanMagicNodes(
584 LayoutWrapper* containerLayoutWrapper, FlexItemProperties& flexItemProperties)
585 {
586 if (GreatNotEqual(totalFlexWeight_, 0.0f)) {
587 /**
588 * The child elements with layoutWeight=0 are measured first.
589 * Then, measure the sub elements of layoutWeight>1 based on the remaining space.
590 * If the total main axis size of the element is larger than the main axis size of Flex, the lower priority
591 * element will be deleted.
592 */
593 auto firstLoopIter = FirstMeasureInWeightMode();
594 SecondMeasureInWeightMode(firstLoopIter);
595 FinalMeasureInWeightMode();
596 } else if (GreatNotEqual(maxDisplayPriority_, 1) && !isInfiniteLayout_) {
597 MeasureInPriorityMode(flexItemProperties);
598 } else {
599 auto magicNodeSize = magicNodes_.size();
600 auto iter = magicNodes_.rbegin();
601 while (iter != magicNodes_.rend()) {
602 auto childList = iter->second;
603 for (auto& child : childList) {
604 if (HandleBlankFirstTimeMeasure(child, flexItemProperties)) {
605 continue;
606 }
607 const auto& childLayoutWrapper = child.layoutWrapper;
608 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, child.layoutConstraint);
609 childLayoutWrapper->Measure(child.layoutConstraint);
610 if (IsVisibleGone(child.layoutWrapper)) {
611 continue;
612 }
613 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
614 CheckSizeValidity(childLayoutWrapper);
615 CheckBaselineProperties(childLayoutWrapper);
616 if (!isInfiniteLayout_ || GreatNotEqual(MainAxisMinValue(containerLayoutWrapper), 0.0f)) {
617 UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
618 }
619 secondaryMeasureList_.emplace_back(child);
620 }
621 if (magicNodeSize != magicNodes_.size()) {
622 LOGE("magicNodes changed during use. oldsize: %{public}zu ,newsize: %{public}zu ",
623 magicNodeSize, magicNodes_.size());
624 break;
625 }
626 ++iter;
627 }
628 allocatedSize_ -= space_;
629 }
630 }
631
HandleBlankFirstTimeMeasure(const MagicLayoutNode & child,FlexItemProperties & flexItemProperties)632 bool FlexLayoutAlgorithm::HandleBlankFirstTimeMeasure(
633 const MagicLayoutNode& child, FlexItemProperties& flexItemProperties)
634 {
635 const auto& childLayoutWrapper = child.layoutWrapper;
636 if (!(childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG &&
637 Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN))) {
638 return false;
639 }
640 auto blankLayoutProperty = childLayoutWrapper->GetLayoutProperty();
641 // if constainer is self adaptive, secondaryMeasure won't happen, blank can call Measure directly
642 if (selfAdaptive_ || isInfiniteLayout_) {
643 childLayoutWrapper->Measure(child.layoutConstraint);
644 if (CheckBlankIllegality(blankLayoutProperty)) {
645 childLayoutWrapper->GetGeometryNode()->SetFrameSize(SizeF(0.0f, 0.0f));
646 }
647 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
648 CheckSizeValidity(childLayoutWrapper);
649 if (!isInfiniteLayout_) {
650 UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
651 }
652 secondaryMeasureList_.emplace_back(child);
653 return true;
654 }
655 // to make blank components splilt remain space(not selfAdaptive)
656 // min size should not participate in the first measure of blank
657 auto mainAxisSize = 0.0f;
658 auto crossAxisSize = 0.0f;
659 childLayoutWrapper->GetHostNode()->GetPattern()->BeforeCreateLayoutWrapper();
660 if (blankLayoutProperty) {
661 const auto& calcConstraint = blankLayoutProperty->GetCalcLayoutConstraint();
662 if (calcConstraint && calcConstraint->selfIdealSize.has_value()) {
663 auto size = ConvertToSize(calcConstraint->selfIdealSize.value(), child.layoutConstraint.scaleProperty,
664 child.layoutConstraint.percentReference);
665 mainAxisSize = std::max(IsHorizontal(direction_) ? size.Width() : size.Height(), 0.0f);
666 crossAxisSize = std::max(IsHorizontal(direction_) ? size.Height() : size.Width(), 0.0f);
667 }
668 if (CheckBlankIllegality(blankLayoutProperty)) {
669 mainAxisSize = 0.0f;
670 crossAxisSize = 0.0f;
671 }
672 }
673 childLayoutWrapper->GetGeometryNode()->SetFrameSize(
674 IsHorizontal(direction_) ? SizeF(mainAxisSize, crossAxisSize) : SizeF(crossAxisSize, mainAxisSize));
675 secondaryMeasureList_.emplace_back(child);
676 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
677 CheckSizeValidity(childLayoutWrapper);
678 UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
679 return true;
680 }
681
UpdateFlexProperties(FlexItemProperties & flexItemProperties,const RefPtr<LayoutWrapper> & layoutWrapper)682 void FlexLayoutAlgorithm::UpdateFlexProperties(
683 FlexItemProperties& flexItemProperties, const RefPtr<LayoutWrapper>& layoutWrapper)
684 {
685 auto layoutProperty = layoutWrapper->GetLayoutProperty();
686 CHECK_NULL_VOID(layoutProperty);
687 const auto& flexItemProperty = layoutProperty->GetFlexItemProperty();
688 float flexShrink = isLinearLayoutFeature_ ? 0.0f : 1.0f;
689 float flexGrow = 0.0f;
690 if (flexItemProperty) {
691 flexShrink = flexItemProperty->GetFlexShrink().value_or(flexShrink);
692 flexGrow = flexItemProperty->GetFlexGrow().value_or(flexGrow);
693 }
694 flexItemProperties.totalGrow += flexGrow;
695 flexItemProperties.totalShrink +=
696 (flexShrink * (GetChildMainAxisSize(layoutWrapper) - GetMainAxisMargin(layoutWrapper, direction_)));
697 }
698
SecondMeasureInGrowOrShrink()699 void FlexLayoutAlgorithm::SecondMeasureInGrowOrShrink()
700 {
701 // child need to second show
702 int32_t childMeasureCount = 0;
703 auto iter = secondaryMeasureList_.rbegin();
704 while (iter != secondaryMeasureList_.rend()) {
705 auto child = *iter;
706 auto childLayoutWrapper = child.layoutWrapper;
707 if (!child.needSecondMeasure || !childLayoutWrapper->IsActive()) {
708 ++iter;
709 continue;
710 }
711 childLayoutWrapper->Measure(child.layoutConstraint);
712 if (childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG) {
713 auto blankLayoutProperty = childLayoutWrapper->GetLayoutProperty();
714 if (CheckBlankIllegality(blankLayoutProperty)) {
715 childLayoutWrapper->GetGeometryNode()->SetFrameSize(SizeF(0.0f, 0.0f));
716 }
717 }
718 crossAxisSize_ = std::max(crossAxisSize_, GetChildCrossAxisSize(childLayoutWrapper));
719 CheckBaselineProperties(child.layoutWrapper);
720 ++iter;
721 ++childMeasureCount;
722 }
723 // if child has secondary measure, calculate crossAxis again
724 if (childMeasureCount) {
725 float childMaxHeight = -1.0f;
726 iter = secondaryMeasureList_.rbegin();
727 while (iter != secondaryMeasureList_.rend()) {
728 auto child = *iter;
729 auto childLayoutWrapper = child.layoutWrapper;
730 childMaxHeight = std::max(GetChildCrossAxisSize(childLayoutWrapper), childMaxHeight);
731 ++iter;
732 }
733 if (GreatNotEqual(childMaxHeight, 0.0f)) {
734 crossAxisSize_ = childMaxHeight;
735 }
736 }
737 }
738
CheckBlankIllegality(const RefPtr<LayoutProperty> & blankLayoutProperty)739 bool FlexLayoutAlgorithm::CheckBlankIllegality(const RefPtr<LayoutProperty>& blankLayoutProperty)
740 {
741 CHECK_NULL_RETURN(blankLayoutProperty, false);
742 auto layoutPolicy = blankLayoutProperty->GetLayoutPolicyProperty();
743 return layoutPolicy.has_value() && (layoutPolicy.value().IsWrap() || layoutPolicy.value().IsFix());
744 }
745
SecondaryMeasureByProperty(FlexItemProperties & flexItemProperties,LayoutWrapper * layoutWrapper)746 void FlexLayoutAlgorithm::SecondaryMeasureByProperty(
747 FlexItemProperties& flexItemProperties, LayoutWrapper* layoutWrapper)
748 {
749 float remainSpace = mainAxisSize_ - allocatedSize_;
750 float spacePerFlex = 0;
751 float allocatedFlexSpace = 0;
752 std::function<float(const RefPtr<LayoutWrapper>&)> getFlex;
753 RefPtr<LayoutWrapper> lastChild;
754 /**
755 * get the real cross axis size.
756 */
757 auto layoutProperty = layoutWrapper->GetLayoutProperty();
758 CHECK_NULL_VOID(layoutProperty);
759 auto padding = layoutProperty->CreatePaddingAndBorder();
760 auto paddingLeft = padding.left.value_or(0.0f);
761 auto paddingRight = padding.right.value_or(0.0f);
762 auto paddingTop = padding.top.value_or(0.0f);
763 auto paddingBottom = padding.bottom.value_or(0.0f);
764 auto crossAxisSize = crossAxisSize_;
765 if (NonNegative(selfIdealCrossAxisSize_)) {
766 if (IsHorizontal(direction_)) {
767 crossAxisSize = selfIdealCrossAxisSize_ - paddingTop - paddingBottom;
768 } else {
769 crossAxisSize = selfIdealCrossAxisSize_ - paddingLeft - paddingRight;
770 }
771 }
772 if (Negative(crossAxisSize)) {
773 crossAxisSize = 0.0f;
774 }
775 // calculate child
776 auto iter = secondaryMeasureList_.rbegin();
777 bool needSecondMeasure = true;
778 float reserveMainAxisSize = 0.0f;
779 while (needSecondMeasure) {
780 needSecondMeasure = false;
781 // when a child's flexSize equal 0, allocatedSize need to minus its MainAxisSize
782 allocatedSize_ -= reserveMainAxisSize;
783 reserveMainAxisSize = 0.0f;
784 remainSpace = mainAxisSize_ - allocatedSize_;
785
786 iter = secondaryMeasureList_.rbegin();
787 while (iter != secondaryMeasureList_.rend()) {
788 if (!(*iter).layoutWrapper->IsActive()) {
789 remainSpace += space_;
790 }
791 ++iter;
792 }
793 CheckIsGrowOrShrink(getFlex, remainSpace, spacePerFlex, flexItemProperties, lastChild);
794 iter = secondaryMeasureList_.rbegin();
795 while (iter != secondaryMeasureList_.rend()) {
796 auto& child = *iter;
797 auto childLayoutWrapper = child.layoutWrapper;
798 if (!childLayoutWrapper) {
799 continue;
800 }
801 if (GetSelfAlign(childLayoutWrapper) == FlexAlign::STRETCH) {
802 UpdateLayoutConstraintOnCrossAxis(child.layoutConstraint, crossAxisSize);
803 child.needSecondMeasure = true;
804 }
805 if (LessOrEqual(totalFlexWeight_, 0.0f) &&
806 (!isInfiniteLayout_ || GreatNotEqual(MainAxisMinValue(layoutWrapper), 0.0f) ||
807 (childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG && !selfAdaptive_ &&
808 Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)))) {
809 if (child.needKeepMinCalcSize) {
810 ++iter;
811 continue;
812 }
813 float childMainAxisMargin = GetMainAxisMargin(childLayoutWrapper, direction_);
814 float itemFlex = getFlex(child.layoutWrapper);
815 float flexSize =
816 (child.layoutWrapper == lastChild) ? (remainSpace - allocatedFlexSpace)
817 : GreatOrEqual(remainSpace, 0.0f) || GreatNotEqual(maxDisplayPriority_, 1)
818 ? spacePerFlex * itemFlex
819 : spacePerFlex * itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
820 if (!NearZero(flexSize) && childLayoutWrapper->IsActive()) {
821 flexSize += GetChildMainAxisSize(childLayoutWrapper);
822 child.needSecondMeasure = true;
823 CheckBlankAndKeepMin(childLayoutWrapper, flexSize);
824 if (LessOrEqual(flexSize, 0.0f)) {
825 child.layoutWrapper->SetActive(false);
826 flexItemProperties.totalShrink -=
827 itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
828 reserveMainAxisSize += GetChildMainAxisSize(childLayoutWrapper);
829 needSecondMeasure = true;
830 UpdateLayoutConstraintOnMainAxis(child.layoutConstraint, 0.0f);
831 break;
832 }
833 if (IsKeepMinSize(childLayoutWrapper, flexSize)) {
834 needSecondMeasure = true;
835 auto shrinkSize = itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
836 reserveMainAxisSize -= (flexSize - shrinkSize);
837 child.needKeepMinCalcSize = true;
838 flexItemProperties.totalShrink -= shrinkSize;
839 }
840 UpdateLayoutConstraintOnMainAxis(child.layoutConstraint, flexSize);
841 } else if (childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG && NearZero(flexSize) &&
842 childLayoutWrapper->IsActive()) {
843 child.needSecondMeasure = true;
844 }
845 }
846 ++iter;
847 }
848 }
849 SecondMeasureInGrowOrShrink();
850 }
851
CheckIsGrowOrShrink(std::function<float (const RefPtr<LayoutWrapper> &)> & getFlex,float remainSpace,float & spacePerFlex,FlexItemProperties & flexItemProperties,RefPtr<LayoutWrapper> & lastChild)852 void FlexLayoutAlgorithm::CheckIsGrowOrShrink(std::function<float(const RefPtr<LayoutWrapper>&)>& getFlex,
853 float remainSpace, float& spacePerFlex, FlexItemProperties& flexItemProperties, RefPtr<LayoutWrapper>& lastChild)
854 {
855 if (GreatOrEqual(remainSpace, 0.0f) || GreatNotEqual(maxDisplayPriority_, 1)) {
856 getFlex = [](const RefPtr<LayoutWrapper>& item) -> float {
857 float ret = 0.0f;
858 const auto& layoutProperty = item->GetLayoutProperty();
859 CHECK_NULL_RETURN(layoutProperty, ret);
860 const auto& flexItemProperty = layoutProperty->GetFlexItemProperty();
861 if (flexItemProperty) {
862 ret = flexItemProperty->GetFlexGrow().value_or(ret);
863 /**
864 * handle non positive flex grow.
865 */
866 if (NonPositive(ret)) {
867 ret = 0.0f;
868 }
869 }
870 return ret;
871 };
872 spacePerFlex = NearZero(flexItemProperties.totalGrow) ? 0.0f : remainSpace / flexItemProperties.totalGrow;
873 lastChild = flexItemProperties.lastGrowChild;
874 } else {
875 getFlex = [isLinearLayoutFeature = isLinearLayoutFeature_](const RefPtr<LayoutWrapper>& item) -> float {
876 float ret = isLinearLayoutFeature ? 0.0f : 1.0f;
877 const auto& layoutProperty = item->GetLayoutProperty();
878 CHECK_NULL_RETURN(layoutProperty, ret);
879 const auto& flexItemProperty = layoutProperty->GetFlexItemProperty();
880 if (flexItemProperty) {
881 ret = flexItemProperty->GetFlexShrink().value_or(ret);
882 /**
883 * handle non positive flex shrink.
884 */
885 if (NonPositive(ret)) {
886 ret = 0.0f;
887 }
888 }
889 return ret;
890 };
891 spacePerFlex = NearZero(flexItemProperties.totalShrink) ? 0.0f : remainSpace / flexItemProperties.totalShrink;
892 lastChild = flexItemProperties.lastShrinkChild;
893 }
894 }
895
CheckBlankAndKeepMin(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & flexSize)896 void FlexLayoutAlgorithm::CheckBlankAndKeepMin(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& flexSize)
897 {
898 auto child = childLayoutWrapper->GetHostNode();
899 if (!child) {
900 return;
901 }
902 if (child->GetTag() != V2::BLANK_ETS_TAG) {
903 return;
904 }
905 auto blankProperty = child->GetLayoutProperty<BlankLayoutProperty>();
906 CHECK_NULL_VOID(blankProperty);
907 auto blankMin = blankProperty->GetMinSize();
908 if (GreatOrEqual(blankMin->ConvertToPx(), flexSize)) {
909 flexSize = blankMin->ConvertToPx();
910 }
911 }
912
IsKeepMinSize(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & flexSize)913 bool FlexLayoutAlgorithm::IsKeepMinSize(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& flexSize)
914 {
915 auto child = childLayoutWrapper->GetHostNode();
916 CHECK_NULL_RETURN(child, false);
917 const auto& childlayoutProperty = childLayoutWrapper->GetLayoutProperty();
918 CHECK_NULL_RETURN(childlayoutProperty, false);
919 auto layoutPolicy = childlayoutProperty->GetLayoutPolicyProperty();
920 bool isFix = IsHorizontal(direction_) ? layoutPolicy.has_value() && layoutPolicy.value().IsWidthFix()
921 : layoutPolicy.has_value() && layoutPolicy.value().IsHeightFix();
922 auto minSize = isFix ? GetMainAxisSizeHelper(childLayoutWrapper->GetGeometryNode()->GetFrameSize(), direction_)
923 : MainAxisMinValue(AceType::RawPtr(childLayoutWrapper));
924 if (GreatOrEqual(minSize, flexSize)) {
925 flexSize = minSize;
926 return true;
927 }
928 return false;
929 }
930
UpdateLayoutConstraintOnMainAxis(LayoutConstraintF & layoutConstraint,float size)931 void FlexLayoutAlgorithm::UpdateLayoutConstraintOnMainAxis(LayoutConstraintF& layoutConstraint, float size)
932 {
933 if (IsHorizontal(direction_)) {
934 layoutConstraint.selfIdealSize.SetWidth(size);
935 } else {
936 layoutConstraint.selfIdealSize.SetHeight(size);
937 }
938 }
939
UpdateLayoutConstraintOnCrossAxis(LayoutConstraintF & layoutConstraint,float size)940 void FlexLayoutAlgorithm::UpdateLayoutConstraintOnCrossAxis(LayoutConstraintF& layoutConstraint, float size)
941 {
942 OptionalSizeF& selfIdealSize = layoutConstraint.selfIdealSize;
943 if (IsHorizontal(direction_)) {
944 selfIdealSize.SetHeight(size);
945 } else {
946 selfIdealSize.SetWidth(size);
947 }
948 }
949
MainAxisMinValue(LayoutWrapper * layoutWrapper)950 float FlexLayoutAlgorithm::MainAxisMinValue(LayoutWrapper* layoutWrapper)
951 {
952 CHECK_NULL_RETURN(layoutWrapper, 0.0f);
953 const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
954 CHECK_NULL_RETURN(layoutProperty, 0.0f);
955 auto layoutConstraint = layoutProperty->GetLayoutConstraint();
956 CHECK_NULL_RETURN(layoutConstraint, 0.0f);
957 return IsHorizontal(direction_) ? layoutConstraint->minSize.Width() : layoutConstraint->minSize.Height();
958 }
959
MarginOnMainAxisNegative(LayoutWrapper * layoutWrapper)960 bool FlexLayoutAlgorithm::MarginOnMainAxisNegative(LayoutWrapper* layoutWrapper)
961 {
962 const auto& margin = layoutWrapper->GetGeometryNode()->GetMargin();
963 CHECK_NULL_RETURN(margin, false);
964 if (IsHorizontal(direction_)) {
965 return LessNotEqual(margin->left.value_or(0.0f) + margin->right.value_or(0.0f), 0.0f);
966 }
967 return LessNotEqual(margin->top.value_or(0.0f) + margin->bottom.value_or(0.0f), 0.0f);
968 }
969
CheckSetConstraint(const std::unique_ptr<MeasureProperty> & propertyPtr)970 bool FlexLayoutAlgorithm::CheckSetConstraint(const std::unique_ptr<MeasureProperty>& propertyPtr)
971 {
972 return propertyPtr && (propertyPtr->minSize || propertyPtr->maxSize);
973 }
974
CheckMainAxisSizeAuto(LayoutWrapper * layoutWrapper,const std::unique_ptr<MeasureProperty> & calcLayoutConstraint)975 void FlexLayoutAlgorithm::CheckMainAxisSizeAuto(
976 LayoutWrapper* layoutWrapper, const std::unique_ptr<MeasureProperty>& calcLayoutConstraint)
977 {
978 if (isInfiniteLayout_) {
979 mainAxisSize_ = allocatedSize_;
980 }
981 bool isWidthAuto = calcLayoutConstraint && calcLayoutConstraint->selfIdealSize &&
982 calcLayoutConstraint->selfIdealSize->IsWidthDimensionUnitAuto();
983 bool isHeightAuto = calcLayoutConstraint && calcLayoutConstraint->selfIdealSize &&
984 calcLayoutConstraint->selfIdealSize->IsHeightDimensionUnitAuto();
985 auto layoutProperty = layoutWrapper->GetLayoutProperty();
986 CHECK_NULL_VOID(layoutProperty);
987 auto layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
988 bool isWidthWrap = layoutPolicy.has_value() && layoutPolicy.value().IsWidthWrap();
989 bool isHeightWrap = layoutPolicy.has_value() && layoutPolicy.value().IsHeightWrap();
990 bool isWidthFix = layoutPolicy.has_value() && layoutPolicy.value().IsWidthFix();
991 bool isHeightFix = layoutPolicy.has_value() && layoutPolicy.value().IsHeightFix();
992 if (IsHorizontal(direction_) ? isWidthAuto || isWidthWrap || isWidthFix
993 : isHeightAuto || isHeightWrap || isHeightFix) {
994 mainAxisSize_ = allocatedSize_;
995 }
996 }
997
SetInitMainAxisSize(LayoutWrapper * layoutWrapper)998 void FlexLayoutAlgorithm::SetInitMainAxisSize(LayoutWrapper* layoutWrapper)
999 {
1000 auto layoutProperty = layoutWrapper->GetLayoutProperty();
1001 CHECK_NULL_VOID(layoutProperty);
1002 const auto& layoutConstraint = layoutProperty->GetLayoutConstraint();
1003 bool mainAxisInf = GreaterOrEqualToInfinity(IsHorizontal(direction_) ? layoutConstraint->maxSize.Width()
1004 : layoutConstraint->maxSize.Height()) &&
1005 NearEqual(mainAxisSize_, -1.0f);
1006 if (NearEqual(mainAxisSize_, -1.0f)) {
1007 auto marginOnMainAxisNegative = MarginOnMainAxisNegative(layoutWrapper);
1008 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
1009 mainAxisSize_ =
1010 IsHorizontal(direction_) ? layoutConstraint->maxSize.Width() : layoutConstraint->maxSize.Height();
1011 } else if (isLinearLayoutFeature_ && IsHorizontal(direction_) && !NearZero(layoutConstraint->minSize.Width()) &&
1012 !marginOnMainAxisNegative) {
1013 mainAxisSize_ = layoutConstraint->minSize.Width();
1014 } else if (isLinearLayoutFeature_ && !IsHorizontal(direction_) &&
1015 !NearZero(layoutConstraint->minSize.Height()) && !marginOnMainAxisNegative) {
1016 mainAxisSize_ = layoutConstraint->minSize.Height();
1017 } else {
1018 mainAxisSize_ =
1019 IsHorizontal(direction_)
1020 ? (mainAxisInf ? layoutConstraint->percentReference.Width() : layoutConstraint->maxSize.Width())
1021 : (mainAxisInf ? layoutConstraint->percentReference.Height() : layoutConstraint->maxSize.Height());
1022 }
1023 isInfiniteLayout_ = isLinearLayoutFeature_;
1024 }
1025 selfAdaptive_ = isLinearLayoutFeature_;
1026 if (!isInfiniteLayout_) {
1027 isInfiniteLayout_ = mainAxisInf;
1028 }
1029 }
1030
SetFinalRealSize(LayoutWrapper * layoutWrapper,SizeF & realSize,std::optional<NG::LayoutPolicyProperty> layoutPolicy)1031 void FlexLayoutAlgorithm::SetFinalRealSize(
1032 LayoutWrapper* layoutWrapper, SizeF& realSize, std::optional<NG::LayoutPolicyProperty> layoutPolicy)
1033 {
1034 auto layoutProperty = layoutWrapper->GetLayoutProperty();
1035 CHECK_NULL_VOID(layoutProperty);
1036 const auto& layoutConstraint = layoutProperty->GetLayoutConstraint();
1037 auto widthLayoutPolicy = LayoutCalPolicy::NO_MATCH;
1038 auto heightLayoutPolicy = LayoutCalPolicy::NO_MATCH;
1039 if (layoutPolicy.has_value()) {
1040 widthLayoutPolicy = layoutPolicy.value().widthLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH);
1041 heightLayoutPolicy = layoutPolicy.value().heightLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH);
1042 }
1043 auto padding = layoutProperty->CreatePaddingAndBorder();
1044 auto horizontalPadding = padding.left.value_or(0.0f) + padding.right.value_or(0.0f);
1045 auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
1046 auto finalMainAxisSize = mainAxisSize_;
1047 auto finalCrossAxisSize = crossAxisSize_;
1048 auto fixIdealSize = OptionalSizeF();
1049 if (IsHorizontal(direction_)) {
1050 finalCrossAxisSize += verticalPadding;
1051 finalMainAxisSize += horizontalPadding;
1052 fixIdealSize.SetSize(SizeF(finalMainAxisSize, finalCrossAxisSize));
1053 } else {
1054 finalCrossAxisSize += horizontalPadding;
1055 finalMainAxisSize += verticalPadding;
1056 fixIdealSize.SetSize(SizeF(finalCrossAxisSize, finalMainAxisSize));
1057 }
1058 fixIdealSize = UpdateOptionSizeByCalcLayoutConstraint(fixIdealSize,
1059 layoutProperty->GetCalcLayoutConstraint(),
1060 layoutProperty->GetLayoutConstraint()->percentReference);
1061 auto mainAxisSizeMin = GetMainAxisSizeHelper(layoutConstraint->minSize, direction_);
1062 auto mainAxisSizeMax = GetMainAxisSizeHelper(layoutConstraint->maxSize, direction_);
1063 auto crossAxisSizeMin = GetCrossAxisSizeHelper(layoutConstraint->minSize, direction_);
1064 auto crossAxisSizeMax = GetCrossAxisSizeHelper(layoutConstraint->maxSize, direction_);
1065 finalMainAxisSize = std::clamp(
1066 finalMainAxisSize, std::min(mainAxisSizeMin, mainAxisSizeMax), std::max(mainAxisSizeMin, mainAxisSizeMax));
1067 finalCrossAxisSize = std::clamp(
1068 finalCrossAxisSize, std::min(crossAxisSizeMin, crossAxisSizeMax), std::max(crossAxisSizeMin, crossAxisSizeMax));
1069 if (IsHorizontal(direction_)) {
1070 if (widthLayoutPolicy == LayoutCalPolicy::FIX_AT_IDEAL_SIZE) {
1071 finalMainAxisSize = fixIdealSize.Width().value_or(0.0f);
1072 }
1073 if (heightLayoutPolicy == LayoutCalPolicy::FIX_AT_IDEAL_SIZE) {
1074 finalCrossAxisSize = fixIdealSize.Height().value_or(0.0f);
1075 }
1076 } else {
1077 if (widthLayoutPolicy == LayoutCalPolicy::FIX_AT_IDEAL_SIZE) {
1078 finalCrossAxisSize = fixIdealSize.Width().value_or(0.0f);
1079 }
1080 if (heightLayoutPolicy == LayoutCalPolicy::FIX_AT_IDEAL_SIZE) {
1081 finalMainAxisSize = fixIdealSize.Height().value_or(0.0f);
1082 }
1083 }
1084 realSize.UpdateIllegalSizeWithCheck(
1085 GetCalcSizeHelper(finalMainAxisSize, finalCrossAxisSize, direction_).ConvertToSizeT());
1086 }
1087
Measure(LayoutWrapper * layoutWrapper)1088 void FlexLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
1089 {
1090 const auto& children = layoutWrapper->GetAllChildrenWithBuild();
1091 const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
1092 CHECK_NULL_VOID(layoutProperty);
1093 const auto& layoutConstraint = layoutProperty->GetLayoutConstraint();
1094 const auto& calcConstraint = layoutProperty->GetCalcLayoutConstraint();
1095 bool needToConstraint = CheckSetConstraint(calcConstraint) && children.empty();
1096 const auto& measureType = layoutProperty->GetMeasureType();
1097 InitFlexProperties(layoutWrapper);
1098 Axis axis = (IsHorizontal(direction_)) ? Axis::HORIZONTAL : Axis::VERTICAL;
1099 auto realSize =
1100 CreateIdealSizeByPercentRef(layoutConstraint.value(), axis, measureType, needToConstraint, calcConstraint)
1101 .ConvertToSizeT();
1102 auto layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
1103 if (layoutPolicy.has_value()) {
1104 auto widthLayoutPolicy = layoutPolicy.value().widthLayoutPolicy_;
1105 auto heightLayoutPolicy = layoutPolicy.value().heightLayoutPolicy_;
1106 auto layoutPolicySize = ConstrainIdealSizeByLayoutPolicy(layoutConstraint.value(),
1107 widthLayoutPolicy.value_or(LayoutCalPolicy::NO_MATCH),
1108 heightLayoutPolicy.value_or(LayoutCalPolicy::NO_MATCH), axis)
1109 .ConvertToSizeT();
1110 realSize.UpdateIllegalSizeWithCheck(layoutPolicySize);
1111 }
1112 if (children.empty()) {
1113 layoutWrapper->GetGeometryNode()->SetFrameSize(realSize);
1114 return;
1115 }
1116 mainAxisSize_ = GetMainAxisSizeHelper(realSize, direction_);
1117 SetInitMainAxisSize(layoutWrapper);
1118 auto padding = layoutProperty->CreatePaddingAndBorder();
1119 auto horizontalPadding = padding.left.value_or(0.0f) + padding.right.value_or(0.0f);
1120 auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
1121 if (IsHorizontal(direction_)) {
1122 mainAxisSize_ -= horizontalPadding;
1123 } else {
1124 mainAxisSize_ -= verticalPadding;
1125 }
1126 if (Negative(mainAxisSize_)) {
1127 mainAxisSize_ = 0.0f;
1128 }
1129 TravelChildrenFlexProps(layoutWrapper);
1130 selfIdealCrossAxisSize_ = GetCrossAxisSizeHelper(realSize, direction_);
1131 FlexItemProperties flexItemProperties;
1132
1133 /**
1134 * first measure
1135 */
1136 MeasureAndCleanMagicNodes(layoutWrapper, flexItemProperties);
1137
1138 /**
1139 * secondary measure
1140 */
1141 SecondaryMeasureByProperty(flexItemProperties, layoutWrapper);
1142
1143 /**
1144 * position property measure.
1145 */
1146 MeasureOutOfLayoutChildren(layoutWrapper);
1147
1148 AdjustTotalAllocatedSize(layoutWrapper);
1149
1150 CheckMainAxisSizeAuto(layoutWrapper, calcConstraint);
1151
1152 SetFinalRealSize(layoutWrapper, realSize, layoutPolicy);
1153
1154 layoutWrapper->GetGeometryNode()->SetFrameSize(realSize);
1155
1156 MeasureAdaptiveLayoutChildren(layoutWrapper, realSize);
1157
1158 ApplyPatternOperation(layoutWrapper, FlexOperatorType::UPDATE_MEASURE_RESULT, reinterpret_cast<uintptr_t>(this));
1159 }
1160
ApplyPatternOperation(LayoutWrapper * layoutWrapper,FlexOperatorType operation,uintptr_t addr,FlexLayoutResult layoutResult)1161 void FlexLayoutAlgorithm::ApplyPatternOperation(
1162 LayoutWrapper* layoutWrapper, FlexOperatorType operation, uintptr_t addr, FlexLayoutResult layoutResult)
1163 {
1164 CHECK_NULL_VOID(layoutWrapper);
1165 auto host = layoutWrapper->GetHostNode();
1166 CHECK_NULL_VOID(host);
1167 auto pattern = host->GetPattern();
1168 CHECK_NULL_VOID(pattern);
1169 FlexMeasureResult measureResult;
1170 if (AceType::InstanceOf<LinearLayoutPattern>(pattern)) {
1171 auto linearPattern = DynamicCast<LinearLayoutPattern>(pattern);
1172 CHECK_NULL_VOID(linearPattern);
1173 PatternOperator(linearPattern, operation, measureResult, layoutResult, addr);
1174 } else {
1175 auto flexPattern = DynamicCast<FlexLayoutPattern>(pattern);
1176 CHECK_NULL_VOID(flexPattern);
1177 PatternOperator(flexPattern, operation, measureResult, layoutResult, addr);
1178 }
1179
1180 if (operation == FlexOperatorType::RESTORE_MEASURE_RESULT) {
1181 allocatedSize_ = measureResult.allocatedSize;
1182 validSizeCount_ = measureResult.validSizeCount;
1183 }
1184 }
1185
AdjustTotalAllocatedSize(LayoutWrapper * layoutWrapper,bool includeLayoutPolicyChildren)1186 void FlexLayoutAlgorithm::AdjustTotalAllocatedSize(LayoutWrapper* layoutWrapper, bool includeLayoutPolicyChildren)
1187 {
1188 const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
1189 if (children.empty()) {
1190 allocatedSize_ = 0.0f;
1191 return;
1192 }
1193 allocatedSize_ = 0.0f;
1194 allocatedSize_ += space_ * (validSizeCount_ - 1);
1195 // space is not valid when mainAxisAlign is SPACE_AROUND/SPACE_BETWEEN/SPACE_EVENLY
1196 if (mainAxisAlign_ == FlexAlign::SPACE_AROUND || mainAxisAlign_ == FlexAlign::SPACE_BETWEEN ||
1197 mainAxisAlign_ == FlexAlign::SPACE_EVENLY) {
1198 allocatedSize_ = 0.0;
1199 }
1200 for (const auto& child : children) {
1201 if (child->IsOutOfLayout() || IsVisibleGone(child)) {
1202 continue;
1203 }
1204 if (!includeLayoutPolicyChildren &&
1205 find(layoutPolicyChildren_.begin(), layoutPolicyChildren_.end(), child) != layoutPolicyChildren_.end()) {
1206 continue;
1207 }
1208 allocatedSize_ += GetChildMainAxisSize(child);
1209 }
1210 }
1211
1212 /**
1213 * Get cross axis size in stretch.
1214 * At this time, the cross axis size has been determined.
1215 */
GetStretchCrossAxisLimit() const1216 float FlexLayoutAlgorithm::GetStretchCrossAxisLimit() const
1217 {
1218 float crossAxisLimit = GreatNotEqual(selfIdealCrossAxisSize_, -1.0f) ? selfIdealCrossAxisSize_ : crossAxisSize_;
1219 return crossAxisLimit;
1220 }
1221
Layout(LayoutWrapper * layoutWrapper)1222 void FlexLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
1223 {
1224 const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
1225 if (children.empty()) {
1226 return;
1227 }
1228 if (!hasMeasured_) {
1229 ApplyPatternOperation(layoutWrapper, FlexOperatorType::RESTORE_MEASURE_RESULT);
1230 }
1231 auto layoutProperty = AceType::DynamicCast<FlexLayoutProperty>(layoutWrapper->GetLayoutProperty());
1232 CHECK_NULL_VOID(layoutProperty);
1233 space_ = static_cast<float>(layoutProperty->GetSpaceValue({}).ConvertToPx());
1234 direction_ = layoutProperty->GetFlexDirection().value_or(FlexDirection::ROW);
1235 bool isReverse = layoutProperty->GetFlexLayoutAttribute()->GetIsReverse().value_or(false);
1236 if (isReverse) {
1237 direction_ = ReverseFlexDirection(direction_);
1238 }
1239 mainAxisAlign_ = layoutProperty->GetMainAxisAlignValue(FlexAlign::FLEX_START);
1240 crossAxisAlign_ =
1241 layoutProperty->GetCrossAxisAlignValue(isLinearLayoutFeature_ ? FlexAlign::CENTER : FlexAlign::FLEX_START);
1242 textDir_ = layoutProperty->GetLayoutDirection();
1243 if (textDir_ == TextDirection::AUTO) {
1244 textDir_ = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
1245 }
1246 auto contentSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
1247 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
1248 AdjustTotalAllocatedSize(layoutWrapper, true);
1249 Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)
1250 ? MinusPaddingToNonNegativeSize(padding, contentSize)
1251 : MinusPaddingToSize(padding, contentSize);
1252 mainAxisSize_ = GetMainAxisSizeHelper(contentSize, direction_);
1253 crossAxisSize_ = GetCrossAxisSizeHelper(contentSize, direction_);
1254 auto paddingOffset = OffsetF(padding.left.value_or(0.0f), padding.top.value_or(0.0f));
1255 float remainSpace = std::max(mainAxisSize_ - allocatedSize_, 0.0f);
1256 float frontSpace = 0.0f;
1257 float betweenSpace = 0.0f;
1258 CalculateSpace(remainSpace, frontSpace, betweenSpace);
1259 PlaceChildren(layoutWrapper, frontSpace, betweenSpace, paddingOffset);
1260
1261 for (auto&& child : children) {
1262 if (!child->IsOutOfLayout() && child->IsActive()) {
1263 child->Layout();
1264 }
1265 }
1266 ApplyPatternOperation(layoutWrapper, FlexOperatorType::UPDATE_LAYOUT_RESULT, reinterpret_cast<uintptr_t>(this),
1267 { .frontSpace = frontSpace, .betweenSpace = betweenSpace });
1268 }
1269
CalculateSpace(float remainSpace,float & frontSpace,float & betweenSpace) const1270 void FlexLayoutAlgorithm::CalculateSpace(float remainSpace, float& frontSpace, float& betweenSpace) const
1271 {
1272 switch (mainAxisAlign_) {
1273 case FlexAlign::FLEX_START:
1274 frontSpace = 0.0f;
1275 betweenSpace = space_;
1276 break;
1277 case FlexAlign::FLEX_END:
1278 frontSpace = remainSpace;
1279 betweenSpace = space_;
1280 break;
1281 case FlexAlign::CENTER:
1282 frontSpace = remainSpace * HALF;
1283 betweenSpace = space_;
1284 break;
1285 case FlexAlign::SPACE_BETWEEN:
1286 frontSpace = 0.0f;
1287 betweenSpace = validSizeCount_ > 1 ? remainSpace / static_cast<float>(validSizeCount_ - 1) : 0.0f;
1288 break;
1289 case FlexAlign::SPACE_AROUND:
1290 betweenSpace = validSizeCount_ > 0 ? remainSpace / static_cast<float>(validSizeCount_) : 0.0f;
1291 frontSpace = betweenSpace * HALF;
1292 break;
1293 case FlexAlign::SPACE_EVENLY:
1294 betweenSpace = validSizeCount_ > 0 ? remainSpace / static_cast<float>(validSizeCount_ + 1) : 0.0f;
1295 frontSpace = betweenSpace;
1296 break;
1297 default:
1298 break;
1299 }
1300 }
1301
SetCrossPos(const RefPtr<LayoutWrapper> & layoutWrapper,float & crossPos,const float & crossAxisSize)1302 void FlexLayoutAlgorithm::SetCrossPos(const RefPtr<LayoutWrapper>& layoutWrapper, float& crossPos, const float& crossAxisSize)
1303 {
1304 auto alignItem = GetSelfAlign(layoutWrapper);
1305 auto crossDirection = FlipAxis(direction_);
1306 auto childCrossAxisSize = GetChildCrossAxisSize(layoutWrapper);
1307 switch (alignItem) {
1308 case FlexAlign::FLEX_START:
1309 case FlexAlign::FLEX_END:
1310 crossPos = (IsStartTopLeft(crossDirection, textDir_) == (alignItem == FlexAlign::FLEX_START))
1311 ? 0.0f
1312 : crossAxisSize - childCrossAxisSize;
1313 break;
1314 case FlexAlign::CENTER:
1315 crossPos = crossAxisSize * HALF - childCrossAxisSize * HALF;
1316 break;
1317 case FlexAlign::STRETCH:
1318 crossPos =
1319 IsStartTopLeft(crossDirection, textDir_) ? 0.0f : crossAxisSize - childCrossAxisSize;
1320 break;
1321 case FlexAlign::BASELINE:
1322 crossPos = 0.0;
1323 if (IsHorizontal(direction_)) {
1324 float distance = layoutWrapper->GetBaselineDistance();
1325 crossPos = baselineProperties_.maxBaselineDistance - distance;
1326 }
1327 break;
1328 default:
1329 break;
1330 }
1331 }
1332
PlaceChildren(LayoutWrapper * layoutWrapper,float frontSpace,float betweenSpace,const OffsetF & paddingOffset)1333 void FlexLayoutAlgorithm::PlaceChildren(
1334 LayoutWrapper* layoutWrapper, float frontSpace, float betweenSpace, const OffsetF& paddingOffset)
1335 {
1336 float childMainPos = IsStartTopLeft(direction_, textDir_) ? frontSpace : mainAxisSize_ - frontSpace;
1337 float childCrossPos = 0.0f;
1338 const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
1339 bool needExpandMainAxis = true;
1340 for (const auto& child : children) {
1341 if (child->IsOutOfLayout() || !child->IsActive()) {
1342 // adjust by postion property.
1343 child->GetGeometryNode()->SetMarginFrameOffset({});
1344 child->Layout();
1345 continue;
1346 }
1347 if (IsVisibleGone(child)) {
1348 continue;
1349 }
1350 SetCrossPos(child, childCrossPos, crossAxisSize_);
1351 OffsetF offset;
1352 if (IsHorizontal(direction_)) {
1353 offset = OffsetF(childMainPos, childCrossPos);
1354 } else {
1355 offset = OffsetF(childCrossPos, childMainPos);
1356 }
1357 float maxAxisAdjust = 0.0f;
1358 if (!IsStartTopLeft(direction_, textDir_)) {
1359 if (direction_ != FlexDirection::COLUMN_REVERSE) {
1360 offset.SetX(offset.GetX() - GetChildMainAxisSize(child));
1361 } else {
1362 offset.SetY(offset.GetY() - GetChildMainAxisSize(child));
1363 }
1364 auto childPos = offset + paddingOffset;
1365 child->GetGeometryNode()->SetMarginFrameOffset(childPos);
1366 maxAxisAdjust = UpdateChildPositionWidthIgnoreLayoutSafeArea(
1367 layoutWrapper->GetHostNode(), child, childPos, paddingOffset, needExpandMainAxis);
1368 childMainPos -= GetChildMainAxisSize(child) + betweenSpace;
1369 } else {
1370 auto childPos = offset + paddingOffset;
1371 child->GetGeometryNode()->SetMarginFrameOffset(childPos);
1372 maxAxisAdjust = UpdateChildPositionWidthIgnoreLayoutSafeArea(
1373 layoutWrapper->GetHostNode(), child, childPos, paddingOffset, needExpandMainAxis);
1374 childMainPos += GetChildMainAxisSize(child) + betweenSpace;
1375 }
1376 if (needExpandMainAxis) {
1377 childMainPos -= maxAxisAdjust;
1378 }
1379 needExpandMainAxis = false;
1380 }
1381 }
1382
UpdateChildPositionWidthIgnoreLayoutSafeArea(const RefPtr<FrameNode> & host,const RefPtr<LayoutWrapper> & childLayoutWrapper,const OffsetF & originOffset,const OffsetF & paddingOffset,bool needExpandMainAxis)1383 float FlexLayoutAlgorithm::UpdateChildPositionWidthIgnoreLayoutSafeArea(const RefPtr<FrameNode>& host,
1384 const RefPtr<LayoutWrapper>& childLayoutWrapper, const OffsetF& originOffset, const OffsetF& paddingOffset,
1385 bool needExpandMainAxis)
1386 {
1387 CHECK_NULL_RETURN(host, 0.0f);
1388 auto childNode = childLayoutWrapper->GetHostNode();
1389 CHECK_NULL_RETURN(childNode, 0.0f);
1390 const auto& childLayoutProperty = childNode->GetLayoutProperty();
1391 CHECK_NULL_RETURN(childLayoutProperty, 0.0f);
1392 if (!childLayoutProperty->IsIgnoreOptsValid()) {
1393 return 0.0f;
1394 }
1395 auto isExpandConstraintNeeded = childLayoutProperty->IsExpandConstraintNeeded();
1396 IgnoreLayoutSafeAreaOpts& opts = *(childLayoutProperty->GetIgnoreLayoutSafeAreaOpts());
1397 auto sae = host->GetAccumulatedSafeAreaExpand(true, opts);
1398 float offsetX = 0.0f;
1399 float offsetY = 0.0f;
1400 float offsetEdgeExpand = 0.0f;
1401 if (IsHorizontal(direction_)) {
1402 CalcMainExpand(childNode->GetAccumulatedSafeAreaExpand(false, opts, IgnoreStrategy::FROM_MARGIN), sae, true,
1403 isExpandConstraintNeeded);
1404 offsetX = originOffset.GetX();
1405 offsetEdgeExpand = needExpandMainAxis ? (IsStartTopLeft(direction_, textDir_) ? sae.left.value_or(0.0f)
1406 : -sae.right.value_or(0.0f))
1407 : 0.0f;
1408 offsetX -= offsetEdgeExpand;
1409 if (!CheckReCalcMainExpand(GetSelfAlign(childLayoutWrapper))) {
1410 offsetY = originOffset.GetY();
1411 } else {
1412 auto adjustedChildPos = crossAxisSize_ + sae.Height();
1413 SetCrossPos(childLayoutWrapper, offsetY, adjustedChildPos);
1414 offsetY -= (sae.top.value_or(0.0f) - paddingOffset.GetY());
1415 }
1416 } else {
1417 CalcMainExpand(childNode->GetAccumulatedSafeAreaExpand(false, opts, IgnoreStrategy::FROM_MARGIN), sae, false,
1418 isExpandConstraintNeeded);
1419 offsetY = originOffset.GetY();
1420 offsetEdgeExpand = needExpandMainAxis ? (IsStartTopLeft(direction_, textDir_) ? sae.top.value_or(0.0f)
1421 : -sae.bottom.value_or(0.0f))
1422 : 0.0f;
1423 offsetY -= offsetEdgeExpand;
1424 if (!CheckReCalcMainExpand(GetSelfAlign(childLayoutWrapper))) {
1425 offsetX = originOffset.GetX();
1426 } else {
1427 auto adjustedChildPos = crossAxisSize_ + sae.Width();
1428 SetCrossPos(childLayoutWrapper, offsetX, adjustedChildPos);
1429 offsetX -= (sae.left.value_or(0.0f) - paddingOffset.GetX());
1430 }
1431 }
1432 OffsetF saeTrans = OffsetF(offsetX, offsetY);
1433 childLayoutWrapper->GetGeometryNode()->SetMarginFrameOffset(saeTrans);
1434 return isExpandConstraintNeeded ? offsetEdgeExpand : 0.0f;
1435 }
1436
CalcMainExpand(const ExpandEdges & mainExpand,ExpandEdges & sae,bool isHorizontal,bool isExpandConstraintNeeded)1437 void FlexLayoutAlgorithm::CalcMainExpand(
1438 const ExpandEdges& mainExpand, ExpandEdges& sae, bool isHorizontal, bool isExpandConstraintNeeded)
1439 {
1440 if (isExpandConstraintNeeded) {
1441 return;
1442 }
1443 if (isHorizontal) {
1444 sae.left = mainExpand.left;
1445 sae.right = mainExpand.right;
1446 } else {
1447 sae.top = mainExpand.top;
1448 sae.bottom = mainExpand.bottom;
1449 }
1450 }
1451
CheckReCalcMainExpand(const FlexAlign & crossAlign)1452 bool FlexLayoutAlgorithm::CheckReCalcMainExpand(const FlexAlign& crossAlign)
1453 {
1454 if (crossAxisAlign_ == FlexAlign::BASELINE) {
1455 return false;
1456 }
1457 switch (crossAlign) {
1458 case FlexAlign::BASELINE:
1459 return false;
1460 default:
1461 return true;
1462 }
1463 }
1464
GetSelfAlign(const RefPtr<LayoutWrapper> & layoutWrapper) const1465 FlexAlign FlexLayoutAlgorithm::GetSelfAlign(const RefPtr<LayoutWrapper>& layoutWrapper) const
1466 {
1467 FlexAlign crossAxisAlign = (crossAxisAlign_ == FlexAlign::AUTO) ? FlexAlign::FLEX_START : crossAxisAlign_;
1468 const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
1469 CHECK_NULL_RETURN(layoutProperty, crossAxisAlign);
1470 const auto& flexItemProperty = layoutProperty->GetFlexItemProperty();
1471 if (!flexItemProperty || !flexItemProperty->GetAlignSelf().has_value() ||
1472 flexItemProperty->GetAlignSelf().value_or(crossAxisAlign_) == FlexAlign::AUTO) {
1473 return crossAxisAlign;
1474 }
1475 return flexItemProperty->GetAlignSelf().value_or(crossAxisAlign);
1476 }
1477
1478 } // namespace OHOS::Ace::NG
1479