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