• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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