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