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 (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
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 
162 } // namespace
163 
GetChildMainAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const164 float FlexLayoutAlgorithm::GetChildMainAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
165 {
166     float size = 0.0f;
167     CHECK_NULL_RETURN(layoutWrapper, size);
168     return GetMainAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetMarginFrameSize(), direction_);
169 }
170 
GetChildCrossAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const171 float FlexLayoutAlgorithm::GetChildCrossAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
172 {
173     CHECK_NULL_RETURN(layoutWrapper, 0.0f);
174     return GetCrossAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetMarginFrameSize(), direction_);
175 }
176 
GetSelfCrossAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const177 float FlexLayoutAlgorithm::GetSelfCrossAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
178 {
179     CHECK_NULL_RETURN(layoutWrapper, 0.0f);
180     return GetCrossAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetFrameSize(), direction_);
181 }
182 
CheckSizeValidity(const RefPtr<LayoutWrapper> & layoutWrapper)183 void FlexLayoutAlgorithm::CheckSizeValidity(const RefPtr<LayoutWrapper>& layoutWrapper)
184 {
185     if (layoutWrapper && layoutWrapper->GetHostNode() &&
186         layoutWrapper->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) ==
187             VisibleType::GONE) {
188         return;
189     }
190     ++validSizeCount_;
191 }
192 
193 /**
194  * Check and record baseline distance.
195  */
CheckBaselineProperties(const RefPtr<LayoutWrapper> & layoutWrapper)196 void FlexLayoutAlgorithm::CheckBaselineProperties(const RefPtr<LayoutWrapper>& layoutWrapper)
197 {
198     if (crossAxisAlign_ != FlexAlign::BASELINE && !childrenHasAlignSelfBaseLine_) {
199         return;
200     }
201     float distance = layoutWrapper->GetBaselineDistance();
202     baselineProperties_.maxBaselineDistance = std::max(baselineProperties_.maxBaselineDistance, distance);
203     baselineProperties_.maxDistanceAboveBaseline = std::max(baselineProperties_.maxDistanceAboveBaseline, distance);
204     baselineProperties_.maxDistanceBelowBaseline =
205         std::max(baselineProperties_.maxDistanceBelowBaseline, GetSelfCrossAxisSize(layoutWrapper) - distance);
206     if (crossAxisAlign_ == FlexAlign::BASELINE) {
207         crossAxisSize_ = baselineProperties_.maxDistanceAboveBaseline + baselineProperties_.maxDistanceBelowBaseline;
208     }
209 }
210 
211 /**
212  * Initialize the FlexLayoutAlgorithm property.
213  */
InitFlexProperties(LayoutWrapper * layoutWrapper)214 void FlexLayoutAlgorithm::InitFlexProperties(LayoutWrapper* layoutWrapper)
215 {
216     mainAxisSize_ = 0.0f;
217     crossAxisSize_ = 0.0f;
218     allocatedSize_ = 0.0f;
219     selfIdealCrossAxisSize_ = -1.0f;
220     validSizeCount_ = 0;
221     realSize_.Reset();
222     isInfiniteLayout_ = false;
223     auto layoutProperty = AceType::DynamicCast<FlexLayoutProperty>(layoutWrapper->GetLayoutProperty());
224     CHECK_NULL_VOID(layoutProperty);
225     space_ = static_cast<float>(layoutProperty->GetSpaceValue({}).ConvertToPx());
226     direction_ = layoutProperty->GetFlexDirection().value_or(FlexDirection::ROW);
227     mainAxisAlign_ = layoutProperty->GetMainAxisAlignValue(FlexAlign::FLEX_START);
228     secondaryMeasureList_.clear();
229     crossAxisAlign_ =
230         layoutProperty->GetCrossAxisAlignValue(isLinearLayoutFeature_ ? FlexAlign::CENTER : FlexAlign::FLEX_START);
231     baselineProperties_.Reset();
232     textDir_ = layoutProperty->GetLayoutDirection();
233     if (textDir_ == TextDirection::AUTO) {
234         textDir_ = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
235     }
236     /**
237      * FlexLayoutAlgorithm, as the parent class, should not handle the special logic of the subclass
238      * LinearLayout.
239      */
240     if (isLinearLayoutFeature_) {
241         bool isVertical = DynamicCast<LinearLayoutProperty>(layoutWrapper->GetLayoutProperty())->IsVertical();
242         direction_ = isVertical ? FlexDirection::COLUMN : FlexDirection::ROW;
243     }
244 }
245 
TravelChildrenFlexProps(LayoutWrapper * layoutWrapper,const SizeF & realSize)246 void FlexLayoutAlgorithm::TravelChildrenFlexProps(LayoutWrapper* layoutWrapper, const SizeF& realSize)
247 {
248     maxDisplayPriority_ = 0;
249     totalFlexWeight_ = 0.0f;
250     outOfLayoutChildren_.clear();
251     magicNodes_.clear();
252     magicNodeWeights_.clear();
253     childrenHasAlignSelfBaseLine_ = false;
254     const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
255     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
256     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
257     for (const auto& child : children) {
258         if (child->IsOutOfLayout()) {
259             outOfLayoutChildren_.emplace_back(child);
260             continue;
261         }
262         const auto& childLayoutProperty = child->GetLayoutProperty();
263         const auto& childMagicItemProperty = childLayoutProperty->GetMagicItemProperty();
264         const auto& childFlexItemProperty = childLayoutProperty->GetFlexItemProperty();
265         MagicLayoutNode node;
266         node.layoutWrapper = child;
267         node.layoutConstraint = childLayoutConstraint;
268 
269         bool childGone =
270             child && child->GetHostNode() && child->GetHostNode()->GetLayoutProperty() &&
271             child->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::GONE;
272         int32_t childDisplayPriority = 1;
273         float childLayoutWeight = 0.0f;
274         if (!childGone) {
275             childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
276             if (childFlexItemProperty) {
277                 childDisplayPriority = childFlexItemProperty->GetDisplayIndex().value_or(1);
278                 if (!childrenHasAlignSelfBaseLine_ &&
279                     childFlexItemProperty->GetAlignSelf().value_or(FlexAlign::FLEX_START) == FlexAlign::BASELINE) {
280                     childrenHasAlignSelfBaseLine_ = true;
281                 }
282             }
283         }
284 
285         auto iter = magicNodes_.find(childDisplayPriority);
286         if (iter == magicNodes_.end()) {
287             magicNodes_.insert(
288                 std::map<int32_t, std::list<MagicLayoutNode>>::value_type(childDisplayPriority, { node }));
289             if (GreatNotEqual(childLayoutWeight, 0.0f)) {
290                 magicNodeWeights_.insert(std::map<int32_t, float>::value_type(childDisplayPriority, childLayoutWeight));
291             }
292         } else {
293             iter->second.emplace_back(node);
294             if (GreatNotEqual(childLayoutWeight, 0.0f)) {
295                 magicNodeWeights_[childDisplayPriority] += childLayoutWeight;
296             }
297         }
298         if (!childGone) {
299             totalFlexWeight_ += GreatNotEqual(childLayoutWeight, 0.0f) ? childLayoutWeight : 0.0f;
300             maxDisplayPriority_ = std::max(childDisplayPriority, maxDisplayPriority_);
301         }
302     }
303 }
304 
UpdateAllocatedSize(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & crossAxisSize)305 void FlexLayoutAlgorithm::UpdateAllocatedSize(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& crossAxisSize)
306 {
307     float mainAxisSize = GetChildMainAxisSize(childLayoutWrapper);
308     if (GreaterOrEqualToInfinity(mainAxisSize)) {
309         mainAxisSize = 0.0f;
310     }
311     crossAxisSize = std::max(crossAxisSize, GetChildCrossAxisSize(childLayoutWrapper));
312     allocatedSize_ += mainAxisSize;
313     allocatedSize_ += space_;
314 }
315 
MeasureOutOfLayoutChildren(LayoutWrapper * layoutWrapper)316 void FlexLayoutAlgorithm::MeasureOutOfLayoutChildren(LayoutWrapper* layoutWrapper)
317 {
318     const auto& layoutConstrain = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
319     for (const auto& child : outOfLayoutChildren_) {
320         child->Measure(layoutConstrain);
321     }
322 }
323 
MeasureAndCleanMagicNodes(LayoutWrapper * containerLayoutWrapper,FlexItemProperties & flexItemProperties)324 void FlexLayoutAlgorithm::MeasureAndCleanMagicNodes(
325     LayoutWrapper* containerLayoutWrapper, FlexItemProperties& flexItemProperties)
326 {
327     if (GreatNotEqual(totalFlexWeight_, 0.0f)) {
328         auto newTotalFlexWeight = totalFlexWeight_;
329         /**
330          * The child elements with layoutWeight=0 are measured first.
331          * Then, measure the sub elements of layoutWeight>1 based on the remaining space.
332          * If the total main axis size of the element is larger than the main axis size of Flex, the lower priority
333          * element will be deleted.
334          */
335         auto firstLoopIter = magicNodes_.rbegin();
336         auto loopIter = firstLoopIter;
337         bool outOfDisplay = false;
338         while (loopIter != magicNodes_.rend()) {
339             auto& childList = loopIter->second;
340             float crossAxisSize = crossAxisSize_;
341             for (auto& child : childList) {
342                 if (!outOfDisplay) {
343                     const auto& childLayoutWrapper = child.layoutWrapper;
344                     float childLayoutWeight = 0.0f;
345                     const auto& childMagicItemProperty =
346                         childLayoutWrapper->GetLayoutProperty()->GetMagicItemProperty();
347                     childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
348                     if (LessOrEqual(childLayoutWeight, 0.0f)) {
349                         if (child.layoutWrapper && child.layoutWrapper->GetHostNode() &&
350                             child.layoutWrapper->GetHostNode()->GetLayoutProperty() &&
351                             child.layoutWrapper->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(
352                                 VisibleType::VISIBLE) == VisibleType::GONE) {
353                             continue;
354                         }
355                         childLayoutWrapper->Measure(child.layoutConstraint);
356                         UpdateAllocatedSize(childLayoutWrapper, crossAxisSize);
357                         CheckSizeValidity(childLayoutWrapper);
358                         CheckBaselineProperties(childLayoutWrapper);
359                     } else {
360                         allocatedSize_ += space_;
361                     }
362                 } else {
363                     child.layoutWrapper->SetActive(false);
364                     child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
365                 }
366             }
367             if (outOfDisplay) {
368                 ++loopIter;
369                 continue;
370             }
371             /**
372              * The main axis size of the element with layoutWeight of 0 is larger than the Flex main axis size
373              */
374             if (allocatedSize_ - space_ > mainAxisSize_ && magicNodes_.size() > 1) {
375                 for (const auto& child : childList) {
376                     allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper);
377                     allocatedSize_ -= space_;
378                     child.layoutWrapper->SetActive(false);
379                     child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
380                 }
381                 outOfDisplay = true;
382                 firstLoopIter = loopIter++;
383             } else {
384                 crossAxisSize_ = crossAxisSize;
385                 firstLoopIter = ++loopIter;
386             }
387         }
388         allocatedSize_ -= space_;
389         auto remainedMainAxisSize = mainAxisSize_ - allocatedSize_;
390         auto spacePerWeight = remainedMainAxisSize / newTotalFlexWeight;
391         auto secondIterLoop = magicNodes_.rbegin();
392         while (secondIterLoop != firstLoopIter) {
393             auto& childList = secondIterLoop->second;
394             bool isExceed = false;
395             for (auto& child : childList) {
396                 auto childLayoutWrapper = child.layoutWrapper;
397                 auto& childConstraint = child.layoutConstraint;
398                 float childLayoutWeight = 0.0f;
399                 const auto& childMagicItemProperty = childLayoutWrapper->GetLayoutProperty()->GetMagicItemProperty();
400                 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
401                 if (LessOrEqual(childLayoutWeight, 0.0)) {
402                     continue;
403                 }
404                 float childCalcSize = std::max(spacePerWeight * childLayoutWeight, 0.0f);
405                 if (GetMainAxisSizeHelper(childConstraint.minSize, direction_) > childCalcSize) {
406                     isExceed = true;
407                 }
408                 UpdateLayoutConstraintOnMainAxis(childConstraint, childCalcSize);
409             }
410             if (isExceed) {
411                 if (magicNodes_.size() <= 1) {
412                     break;
413                 }
414                 isExceed = true;
415                 auto& lowPriorityChildList = magicNodes_.begin()->second;
416                 for (const auto& child : lowPriorityChildList) {
417                     allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper);
418                     allocatedSize_ -= space_;
419                     child.layoutWrapper->SetActive(false);
420                     child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
421                 }
422                 newTotalFlexWeight -= magicNodeWeights_[magicNodes_.begin()->first];
423                 remainedMainAxisSize = mainAxisSize_ - allocatedSize_;
424                 spacePerWeight = remainedMainAxisSize / newTotalFlexWeight;
425                 isExceed = false;
426                 magicNodes_.erase(magicNodes_.begin());
427                 secondIterLoop = magicNodes_.rbegin();
428             } else {
429                 secondIterLoop++;
430             }
431         }
432         auto iter = magicNodes_.rbegin();
433         while (iter != magicNodes_.rend()) {
434             auto& childList = iter->second;
435             for (auto& child : childList) {
436                 auto childLayoutWrapper = child.layoutWrapper;
437                 if (!childLayoutWrapper->IsActive()) {
438                     continue;
439                 }
440                 float childLayoutWeight = 0.0f;
441                 const auto& childMagicItemProperty = childLayoutWrapper->GetLayoutProperty()->GetMagicItemProperty();
442                 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
443                 secondaryMeasureList_.emplace_back(child);
444                 if (LessOrEqual(childLayoutWeight, 0.0)) {
445                     continue;
446                 }
447                 childLayoutWrapper->Measure(child.layoutConstraint);
448                 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
449                 CheckSizeValidity(childLayoutWrapper);
450                 CheckBaselineProperties(childLayoutWrapper);
451             }
452             iter++;
453         }
454     } else if (GreatNotEqual(maxDisplayPriority_, 1) && !isInfiniteLayout_) {
455         bool outOfDisplay = false;
456         auto iter = magicNodes_.rbegin();
457         while (iter != magicNodes_.rend()) {
458             auto childList = iter->second;
459             if (outOfDisplay) {
460                 for (auto& child : childList) {
461                     const auto& childLayoutWrapper = child.layoutWrapper;
462                     auto childLayoutConstraint = child.layoutConstraint;
463                     UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, childLayoutConstraint);
464                     child.layoutWrapper->ApplyConstraintWithoutMeasure(childLayoutConstraint);
465                     child.layoutWrapper->SetActive(false);
466                     child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
467                 }
468                 ++iter;
469                 continue;
470             }
471             float crossAxisSize = crossAxisSize_;
472             for (auto& child : childList) {
473                 const auto& childLayoutWrapper = child.layoutWrapper;
474                 auto childLayoutConstraint = child.layoutConstraint;
475                 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, childLayoutConstraint);
476                 childLayoutWrapper->Measure(childLayoutConstraint);
477                 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize);
478                 CheckSizeValidity(childLayoutWrapper);
479                 CheckBaselineProperties(childLayoutWrapper);
480                 const auto& flexItemProperty = childLayoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
481                 if (flexItemProperty && GreatNotEqual(flexItemProperty->GetFlexGrow().value_or(0.0f), 0.0f)) {
482                     flexItemProperties.totalGrow += flexItemProperty->GetFlexGrow().value_or(0.0f);
483                 }
484                 secondaryMeasureList_.emplace_back(child);
485             }
486             if (!LessOrEqual(allocatedSize_ - space_, mainAxisSize_)) {
487                 outOfDisplay = true;
488                 for (auto& child : childList) {
489                     allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper);
490                     allocatedSize_ -= space_;
491                     child.layoutWrapper->SetActive(false);
492                     --validSizeCount_;
493                     child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
494                     const auto& flexItemProperty = child.layoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
495                     if (flexItemProperty && GreatNotEqual(flexItemProperty->GetFlexGrow().value_or(0.0f), 0.0f)) {
496                         flexItemProperties.totalGrow -= flexItemProperty->GetFlexGrow().value_or(0.0f);
497                     }
498                     secondaryMeasureList_.pop_back();
499                 }
500             } else {
501                 crossAxisSize_ = crossAxisSize;
502             }
503             ++iter;
504         }
505     } else {
506         auto magicNodeSize = magicNodes_.size();
507         auto iter = magicNodes_.rbegin();
508         while (iter != magicNodes_.rend()) {
509             auto childList = iter->second;
510             for (auto& child : childList) {
511                 if (HandleBlankFirstTimeMeasure(child, flexItemProperties)) {
512                     continue;
513                 }
514                 const auto& childLayoutWrapper = child.layoutWrapper;
515                 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, child.layoutConstraint);
516                 childLayoutWrapper->Measure(child.layoutConstraint);
517                 if (child.layoutWrapper && child.layoutWrapper->GetHostNode() &&
518                     child.layoutWrapper->GetHostNode()->GetLayoutProperty() &&
519                     child.layoutWrapper->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) ==
520                         VisibleType::GONE) {
521                     continue;
522                 }
523                 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
524                 CheckSizeValidity(childLayoutWrapper);
525                 CheckBaselineProperties(childLayoutWrapper);
526                 if (!isInfiniteLayout_ || GreatNotEqual(MainAxisMinValue(containerLayoutWrapper), 0.0f)) {
527                     UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
528                 }
529                 secondaryMeasureList_.emplace_back(child);
530             }
531             if (magicNodeSize != magicNodes_.size()) {
532                 LOGE("magicNodes changed during use. oldsize: %{public}zu ,newsize: %{public}zu ",
533                     magicNodeSize, magicNodes_.size());
534                 break;
535             }
536             ++iter;
537         }
538         allocatedSize_ -= space_;
539     }
540 }
541 
HandleBlankFirstTimeMeasure(const MagicLayoutNode & child,FlexItemProperties & flexItemProperties)542 bool FlexLayoutAlgorithm::HandleBlankFirstTimeMeasure(
543     const MagicLayoutNode& child, FlexItemProperties& flexItemProperties)
544 {
545     const auto& childLayoutWrapper = child.layoutWrapper;
546     if (!(childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG &&
547             Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN))) {
548         return false;
549     }
550 
551     // if constainer is self adaptive, secondaryMeasure won't happen, blank can call Measure directly
552     if (selfAdaptive_ || isInfiniteLayout_) {
553         childLayoutWrapper->Measure(child.layoutConstraint);
554         UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
555         CheckSizeValidity(childLayoutWrapper);
556         if (!isInfiniteLayout_) {
557             UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
558         }
559         secondaryMeasureList_.emplace_back(child);
560         return true;
561     }
562     // to make blank components splilt remain space(not selfAdaptive)
563     // min size should not participate in the first measure of blank
564     auto mainAxisSize = 0.0f;
565     auto crossAxisSize = 0.0f;
566     auto blankLayoutProperty = childLayoutWrapper->GetLayoutProperty();
567     childLayoutWrapper->GetHostNode()->GetPattern()->BeforeCreateLayoutWrapper();
568     if (blankLayoutProperty) {
569         const auto& calcConstraint = blankLayoutProperty->GetCalcLayoutConstraint();
570         if (calcConstraint && calcConstraint->selfIdealSize.has_value()) {
571             auto size = ConvertToSize(calcConstraint->selfIdealSize.value(), child.layoutConstraint.scaleProperty,
572                 child.layoutConstraint.percentReference);
573             mainAxisSize = std::max(IsHorizontal(direction_) ? size.Width() : size.Height(), 0.0f);
574             crossAxisSize = std::max(IsHorizontal(direction_) ? size.Height() : size.Width(), 0.0f);
575         }
576     }
577     childLayoutWrapper->GetGeometryNode()->SetFrameSize(
578         IsHorizontal(direction_) ? SizeF(mainAxisSize, crossAxisSize) : SizeF(crossAxisSize, mainAxisSize));
579     secondaryMeasureList_.emplace_back(child);
580     UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
581     CheckSizeValidity(childLayoutWrapper);
582     UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
583     return true;
584 }
585 
UpdateFlexProperties(FlexItemProperties & flexItemProperties,const RefPtr<LayoutWrapper> & layoutWrapper)586 void FlexLayoutAlgorithm::UpdateFlexProperties(
587     FlexItemProperties& flexItemProperties, const RefPtr<LayoutWrapper>& layoutWrapper)
588 {
589     const auto& flexItemProperty = layoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
590     float flexShrink = isLinearLayoutFeature_ ? 0.0f : 1.0f;
591     float flexGrow = 0.0f;
592     if (flexItemProperty) {
593         flexShrink = flexItemProperty->GetFlexShrink().value_or(flexShrink);
594         flexGrow = flexItemProperty->GetFlexGrow().value_or(flexGrow);
595     }
596     flexItemProperties.totalGrow += flexGrow;
597     flexItemProperties.totalShrink +=
598         (flexShrink * (GetChildMainAxisSize(layoutWrapper) - GetMainAxisMargin(layoutWrapper, direction_)));
599 }
600 
SecondaryMeasureByProperty(FlexItemProperties & flexItemProperties,LayoutWrapper * layoutWrapper)601 void FlexLayoutAlgorithm::SecondaryMeasureByProperty(
602     FlexItemProperties& flexItemProperties, LayoutWrapper* layoutWrapper)
603 {
604     float remainSpace = mainAxisSize_ - allocatedSize_;
605     float spacePerFlex = 0;
606     float allocatedFlexSpace = 0;
607     std::function<float(const RefPtr<LayoutWrapper>&)> getFlex;
608     RefPtr<LayoutWrapper> lastChild;
609     /**
610      * get the real cross axis size.
611      */
612     auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
613     auto paddingLeft = padding.left.value_or(0.0f);
614     auto paddingRight = padding.right.value_or(0.0f);
615     auto paddingTop = padding.top.value_or(0.0f);
616     auto paddingBottom = padding.bottom.value_or(0.0f);
617     auto crossAxisSize = crossAxisSize_;
618     if (NonNegative(selfIdealCrossAxisSize_)) {
619         if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
620             crossAxisSize = selfIdealCrossAxisSize_ - paddingTop - paddingBottom;
621         } else {
622             crossAxisSize = selfIdealCrossAxisSize_ - paddingLeft - paddingRight;
623         }
624     }
625     if (Negative(crossAxisSize)) {
626         crossAxisSize = 0.0f;
627     }
628     // calculate child
629     auto iter = secondaryMeasureList_.rbegin();
630     bool needSecondMeasure = true;
631     float reserveMainAxisSize = 0.0f;
632     while (needSecondMeasure) {
633         needSecondMeasure = false;
634         // when a child's flexSize equal 0, allocatedSize need to minus its MainAxisSize
635         allocatedSize_ -= reserveMainAxisSize;
636         reserveMainAxisSize = 0.0f;
637         remainSpace = mainAxisSize_ - allocatedSize_;
638 
639         iter = secondaryMeasureList_.rbegin();
640         while (iter != secondaryMeasureList_.rend()) {
641             if (!(*iter).layoutWrapper->IsActive()) {
642                 remainSpace += space_;
643             }
644             ++iter;
645         }
646         CheckIsGrowOrShrink(getFlex, remainSpace, spacePerFlex, flexItemProperties, lastChild);
647         iter = secondaryMeasureList_.rbegin();
648         while (iter != secondaryMeasureList_.rend()) {
649             auto& child = *iter;
650             auto childLayoutWrapper = child.layoutWrapper;
651             if (!childLayoutWrapper) {
652                 continue;
653             }
654             if (GetSelfAlign(childLayoutWrapper) == FlexAlign::STRETCH) {
655                 UpdateLayoutConstraintOnCrossAxis(child.layoutConstraint, crossAxisSize);
656                 child.needSecondMeasure = true;
657             }
658             if (LessOrEqual(totalFlexWeight_, 0.0f) &&
659                 (!isInfiniteLayout_ || GreatNotEqual(MainAxisMinValue(layoutWrapper), 0.0f) ||
660                     (childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG && !selfAdaptive_ &&
661                         Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)))) {
662                 if (child.needKeepMinCalcSize) {
663                     ++iter;
664                     continue;
665                 }
666                 float childMainAxisMargin = GetMainAxisMargin(childLayoutWrapper, direction_);
667                 float itemFlex = getFlex(child.layoutWrapper);
668                 float flexSize =
669                     (child.layoutWrapper == lastChild) ? (remainSpace - allocatedFlexSpace)
670                     : GreatOrEqual(remainSpace, 0.0f) || GreatNotEqual(maxDisplayPriority_, 1)
671                         ? spacePerFlex * itemFlex
672                         : spacePerFlex * itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
673                 if (!NearZero(flexSize) && childLayoutWrapper->IsActive()) {
674                     flexSize += GetChildMainAxisSize(childLayoutWrapper);
675                     child.needSecondMeasure = true;
676                     CheckBlankAndKeepMin(childLayoutWrapper, flexSize);
677                     if (LessOrEqual(flexSize, 0.0f)) {
678                         child.layoutWrapper->SetActive(false);
679                         flexItemProperties.totalShrink -=
680                             itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
681                         reserveMainAxisSize += GetChildMainAxisSize(childLayoutWrapper);
682                         needSecondMeasure = true;
683                         UpdateLayoutConstraintOnMainAxis(child.layoutConstraint, 0.0f);
684                         break;
685                     }
686                     if (IsKeepMinSize(childLayoutWrapper, flexSize)) {
687                         needSecondMeasure = true;
688                         auto shrinkSize = itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
689                         reserveMainAxisSize -= (flexSize - shrinkSize);
690                         child.needKeepMinCalcSize = true;
691                         flexItemProperties.totalShrink -= shrinkSize;
692                     }
693                     UpdateLayoutConstraintOnMainAxis(child.layoutConstraint, flexSize);
694                 } else if (childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG && NearZero(flexSize) &&
695                            childLayoutWrapper->IsActive()) {
696                     child.needSecondMeasure = true;
697                 }
698             }
699             ++iter;
700         }
701     }
702 
703     // child need to second show
704     int32_t childMeasureCount = 0;
705     iter = secondaryMeasureList_.rbegin();
706     while (iter != secondaryMeasureList_.rend()) {
707         auto child = *iter;
708         auto childLayoutWrapper = child.layoutWrapper;
709         if (!child.needSecondMeasure || !childLayoutWrapper->IsActive()) {
710             ++iter;
711             continue;
712         }
713         childLayoutWrapper->Measure(child.layoutConstraint);
714         crossAxisSize_ = std::max(crossAxisSize_, GetChildCrossAxisSize(childLayoutWrapper));
715         CheckBaselineProperties(child.layoutWrapper);
716         ++iter;
717         ++childMeasureCount;
718     }
719     // if child has secondary measure, calculate crossAxis again
720     if (childMeasureCount) {
721         float chilMaxHeight = -1.0f;
722         iter = secondaryMeasureList_.rbegin();
723         while (iter != secondaryMeasureList_.rend()) {
724             auto child = *iter;
725             auto childLayoutWrapper = child.layoutWrapper;
726             chilMaxHeight = std::max(GetChildCrossAxisSize(childLayoutWrapper), chilMaxHeight);
727             ++iter;
728         }
729         if (GreatNotEqual(chilMaxHeight, 0.0f)) {
730             crossAxisSize_ = chilMaxHeight;
731         }
732     }
733 }
734 
CheckIsGrowOrShrink(std::function<float (const RefPtr<LayoutWrapper> &)> & getFlex,float remainSpace,float & spacePerFlex,FlexItemProperties & flexItemProperties,RefPtr<LayoutWrapper> & lastChild)735 void FlexLayoutAlgorithm::CheckIsGrowOrShrink(std::function<float(const RefPtr<LayoutWrapper>&)>& getFlex,
736     float remainSpace, float& spacePerFlex, FlexItemProperties& flexItemProperties, RefPtr<LayoutWrapper>& lastChild)
737 {
738     if (GreatOrEqual(remainSpace, 0.0f) || GreatNotEqual(maxDisplayPriority_, 1)) {
739         getFlex = [](const RefPtr<LayoutWrapper>& item) -> float {
740             const auto& flexItemProperty = item->GetLayoutProperty()->GetFlexItemProperty();
741             float ret = 0.0f;
742             if (flexItemProperty) {
743                 ret = flexItemProperty->GetFlexGrow().value_or(ret);
744                 /**
745                  * handle non positive flex grow.
746                  */
747                 if (NonPositive(ret)) {
748                     ret = 0.0f;
749                 }
750             }
751             return ret;
752         };
753         spacePerFlex = NearZero(flexItemProperties.totalGrow) ? 0.0f : remainSpace / flexItemProperties.totalGrow;
754         lastChild = flexItemProperties.lastGrowChild;
755     } else {
756         getFlex = [isLinearLayoutFeature = isLinearLayoutFeature_](const RefPtr<LayoutWrapper>& item) -> float {
757             const auto& flexItemProperty = item->GetLayoutProperty()->GetFlexItemProperty();
758             float ret = isLinearLayoutFeature ? 0.0f : 1.0f;
759             if (flexItemProperty) {
760                 ret = flexItemProperty->GetFlexShrink().value_or(ret);
761                 /**
762                  * handle non positive flex shrink.
763                  */
764                 if (NonPositive(ret)) {
765                     ret = 0.0f;
766                 }
767             }
768             return ret;
769         };
770         spacePerFlex = NearZero(flexItemProperties.totalShrink) ? 0.0f : remainSpace / flexItemProperties.totalShrink;
771         lastChild = flexItemProperties.lastShrinkChild;
772     }
773 }
774 
CheckBlankAndKeepMin(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & flexSize)775 void FlexLayoutAlgorithm::CheckBlankAndKeepMin(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& flexSize)
776 {
777     auto child = childLayoutWrapper->GetHostNode();
778     if (!child) {
779         return;
780     }
781     if (child->GetTag() != V2::BLANK_ETS_TAG) {
782         return;
783     }
784     auto blankProperty = child->GetLayoutProperty<BlankLayoutProperty>();
785     CHECK_NULL_VOID(blankProperty);
786     auto blankMin = blankProperty->GetMinSize();
787     if (GreatOrEqual(blankMin->ConvertToPx(), flexSize)) {
788         flexSize = blankMin->ConvertToPx();
789     }
790 }
791 
IsKeepMinSize(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & flexSize)792 bool FlexLayoutAlgorithm::IsKeepMinSize(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& flexSize)
793 {
794     auto child = childLayoutWrapper->GetHostNode();
795     CHECK_NULL_RETURN(child, false);
796     auto minSize = MainAxisMinValue(AceType::RawPtr(childLayoutWrapper));
797     if (GreatOrEqual(minSize, flexSize)) {
798         flexSize = minSize;
799         return true;
800     }
801     return false;
802 }
803 
UpdateLayoutConstraintOnMainAxis(LayoutConstraintF & layoutConstraint,float size)804 void FlexLayoutAlgorithm::UpdateLayoutConstraintOnMainAxis(LayoutConstraintF& layoutConstraint, float size)
805 {
806     if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
807         layoutConstraint.selfIdealSize.SetWidth(size);
808     } else {
809         layoutConstraint.selfIdealSize.SetHeight(size);
810     }
811 }
812 
UpdateLayoutConstraintOnCrossAxis(LayoutConstraintF & layoutConstraint,float size)813 void FlexLayoutAlgorithm::UpdateLayoutConstraintOnCrossAxis(LayoutConstraintF& layoutConstraint, float size)
814 {
815     OptionalSizeF& selfIdealSize = layoutConstraint.selfIdealSize;
816     if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
817         selfIdealSize.SetHeight(size);
818     } else {
819         selfIdealSize.SetWidth(size);
820     }
821 }
822 
MainAxisMinValue(LayoutWrapper * layoutWrapper)823 float FlexLayoutAlgorithm::MainAxisMinValue(LayoutWrapper* layoutWrapper)
824 {
825     CHECK_NULL_RETURN(layoutWrapper, 0.0f);
826     CHECK_NULL_RETURN(layoutWrapper->GetLayoutProperty(), 0.0f);
827     auto layoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
828     CHECK_NULL_RETURN(layoutConstraint, 0.0f);
829     return IsHorizontal(direction_) ? layoutConstraint->minSize.Width() : layoutConstraint->minSize.Height();
830 }
831 
MarginOnMainAxisNegative(LayoutWrapper * layoutWrapper)832 bool FlexLayoutAlgorithm::MarginOnMainAxisNegative(LayoutWrapper* layoutWrapper)
833 {
834     const auto& margin = layoutWrapper->GetGeometryNode()->GetMargin();
835     CHECK_NULL_RETURN(margin, false);
836     if (IsHorizontal(direction_)) {
837         return LessNotEqual(margin->left.value_or(0.0f) + margin->right.value_or(0.0f), 0.0f);
838     }
839     return LessNotEqual(margin->top.value_or(0.0f) + margin->bottom.value_or(0.0f), 0.0f);
840 }
841 
CheckSetConstraint(const std::unique_ptr<MeasureProperty> & propertyPtr)842 bool FlexLayoutAlgorithm::CheckSetConstraint(const std::unique_ptr<MeasureProperty>& propertyPtr)
843 {
844     return propertyPtr && (propertyPtr->minSize || propertyPtr->maxSize);
845 }
846 
CheckMainAxisSizeAuto(const std::unique_ptr<MeasureProperty> & calcLayoutConstraint)847 void FlexLayoutAlgorithm::CheckMainAxisSizeAuto(const std::unique_ptr<MeasureProperty>& calcLayoutConstraint)
848 {
849     if (isInfiniteLayout_) {
850         mainAxisSize_ = allocatedSize_;
851     }
852     CHECK_NULL_VOID(calcLayoutConstraint);
853     CHECK_NULL_VOID(calcLayoutConstraint->selfIdealSize);
854     if (IsHorizontal(direction_) ? calcLayoutConstraint->selfIdealSize->IsWidthDimensionUnitAuto()
855                                  : calcLayoutConstraint->selfIdealSize->IsHeightDimensionUnitAuto()) {
856         mainAxisSize_ = allocatedSize_;
857     }
858 }
859 
Measure(LayoutWrapper * layoutWrapper)860 void FlexLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
861 {
862     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
863     /**
864      * Obtain the main axis size and cross axis size based on user setting.
865      */
866     const auto& layoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
867     const auto& rawConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
868     bool needToConstraint = CheckSetConstraint(rawConstraint) && children.empty();
869     const auto& measureType = layoutWrapper->GetLayoutProperty()->GetMeasureType();
870     InitFlexProperties(layoutWrapper);
871     Axis axis = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) ? Axis::HORIZONTAL
872                                                                                                : Axis::VERTICAL;
873     auto realSize = CreateIdealSizeByPercentRef(layoutConstraint.value(), axis, measureType, needToConstraint,
874         rawConstraint).ConvertToSizeT();
875     if (children.empty()) {
876         layoutWrapper->GetGeometryNode()->SetFrameSize(realSize);
877         return;
878     }
879     mainAxisSize_ = GetMainAxisSizeHelper(realSize, direction_);
880     /**
881      * The user has not set the main axis size
882      */
883     isInfiniteLayout_ = false;
884     selfAdaptive_ = false;
885     bool mainAxisInf =
886         GreaterOrEqualToInfinity(direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE
887                                      ? layoutConstraint->maxSize.Width()
888                                      : layoutConstraint->maxSize.Height()) &&
889         NearEqual(mainAxisSize_, -1.0f);
890     if (NearEqual(mainAxisSize_, -1.0f)) {
891         auto marginOnMainAxisNegative = MarginOnMainAxisNegative(layoutWrapper);
892         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
893             mainAxisSize_ = direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE
894                                 ? layoutConstraint->maxSize.Width()
895                                 : layoutConstraint->maxSize.Height();
896         } else if (isLinearLayoutFeature_ && IsHorizontal(direction_) && !NearZero(layoutConstraint->minSize.Width()) &&
897                    !marginOnMainAxisNegative) {
898             mainAxisSize_ = layoutConstraint->minSize.Width();
899         } else if (isLinearLayoutFeature_ && !IsHorizontal(direction_) &&
900                    !NearZero(layoutConstraint->minSize.Height()) && !marginOnMainAxisNegative) {
901             mainAxisSize_ = layoutConstraint->minSize.Height();
902         } else {
903             mainAxisSize_ =
904                 direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE
905                     ? (mainAxisInf ? layoutConstraint->percentReference.Width() : layoutConstraint->maxSize.Width())
906                     : (mainAxisInf ? layoutConstraint->percentReference.Height() : layoutConstraint->maxSize.Height());
907         }
908         isInfiniteLayout_ = isLinearLayoutFeature_;
909     }
910     selfAdaptive_ = isLinearLayoutFeature_;
911     if (!isInfiniteLayout_) {
912         isInfiniteLayout_ = mainAxisInf;
913     }
914     auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
915     auto horizontalPadding = padding.left.value_or(0.0f) + padding.right.value_or(0.0f);
916     auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
917     if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
918         mainAxisSize_ -= horizontalPadding;
919     } else {
920         mainAxisSize_ -= verticalPadding;
921     }
922     if (Negative(mainAxisSize_)) {
923         mainAxisSize_ = 0.0f;
924     }
925     TravelChildrenFlexProps(layoutWrapper, realSize);
926     selfIdealCrossAxisSize_ = GetCrossAxisSizeHelper(realSize, direction_);
927     FlexItemProperties flexItemProperties;
928 
929     /**
930      * first measure
931      */
932     MeasureAndCleanMagicNodes(layoutWrapper, flexItemProperties);
933 
934     /**
935      * secondary measure
936      */
937     SecondaryMeasureByProperty(flexItemProperties, layoutWrapper);
938 
939     /**
940      *  position property measure.
941      */
942     MeasureOutOfLayoutChildren(layoutWrapper);
943 
944     AdjustTotalAllocatedSize(layoutWrapper);
945 
946     /**
947      * For Row and Column, the main axis size is wrapContent.
948      * And, FlexLayoutAlgorithm, as the parent class, should not handle the special logic of the subclass LinearLayout.
949      */
950     CheckMainAxisSizeAuto(rawConstraint);
951 
952     auto finalMainAxisSize = mainAxisSize_;
953     auto finalCrossAxisSize = crossAxisSize_;
954     if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
955         finalCrossAxisSize += verticalPadding;
956         finalMainAxisSize += horizontalPadding;
957     } else {
958         finalCrossAxisSize += horizontalPadding;
959         finalMainAxisSize += verticalPadding;
960     }
961     auto mainAxisSizeMin = GetMainAxisSizeHelper(layoutConstraint->minSize, direction_);
962     auto mainAxisSizeMax = GetMainAxisSizeHelper(layoutConstraint->maxSize, direction_);
963     auto crossAxisSizeMin = GetCrossAxisSizeHelper(layoutConstraint->minSize, direction_);
964     auto crossAxisSizeMax = GetCrossAxisSizeHelper(layoutConstraint->maxSize, direction_);
965     finalMainAxisSize = std::clamp(
966         finalMainAxisSize, std::min(mainAxisSizeMin, mainAxisSizeMax), std::max(mainAxisSizeMin, mainAxisSizeMax));
967     finalCrossAxisSize = std::clamp(
968         finalCrossAxisSize, std::min(crossAxisSizeMin, crossAxisSizeMax), std::max(crossAxisSizeMin, crossAxisSizeMax));
969 
970     realSize.UpdateIllegalSizeWithCheck(
971         GetCalcSizeHelper(finalMainAxisSize, finalCrossAxisSize, direction_).ConvertToSizeT());
972     layoutWrapper->GetGeometryNode()->SetFrameSize(realSize);
973 }
974 
AdjustTotalAllocatedSize(LayoutWrapper * layoutWrapper)975 void FlexLayoutAlgorithm::AdjustTotalAllocatedSize(LayoutWrapper* layoutWrapper)
976 {
977     const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
978     if (children.empty()) {
979         allocatedSize_ = 0.0f;
980         return;
981     }
982     allocatedSize_ = 0.0f;
983     allocatedSize_ += space_ * (validSizeCount_ - 1);
984     // space is not valid when mainAxisAlign is SPACE_AROUND/SPACE_BETWEEN/SPACE_EVENLY
985     if (mainAxisAlign_ == FlexAlign::SPACE_AROUND || mainAxisAlign_ == FlexAlign::SPACE_BETWEEN ||
986         mainAxisAlign_ == FlexAlign::SPACE_EVENLY) {
987         allocatedSize_ = 0.0;
988     }
989     for (const auto& child : children) {
990         if (child->IsOutOfLayout() ||
991             (layoutWrapper && layoutWrapper->GetHostNode() && layoutWrapper->GetHostNode()->GetLayoutProperty() &&
992                 child->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) ==
993                     VisibleType::GONE)) {
994             continue;
995         }
996         allocatedSize_ += GetChildMainAxisSize(child);
997     }
998 }
999 
1000 /**
1001  * Get cross axis size in stretch.
1002  * At this time, the cross axis size has been determined.
1003  */
GetStretchCrossAxisLimit() const1004 float FlexLayoutAlgorithm::GetStretchCrossAxisLimit() const
1005 {
1006     float crossAxisLimit = GreatNotEqual(selfIdealCrossAxisSize_, -1.0f) ? selfIdealCrossAxisSize_ : crossAxisSize_;
1007     return crossAxisLimit;
1008 }
1009 
Layout(LayoutWrapper * layoutWrapper)1010 void FlexLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
1011 {
1012     const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
1013     if (children.empty()) {
1014         return;
1015     }
1016     auto layoutProperty = AceType::DynamicCast<FlexLayoutProperty>(layoutWrapper->GetLayoutProperty());
1017     CHECK_NULL_VOID(layoutProperty);
1018     space_ = static_cast<float>(layoutProperty->GetSpaceValue({}).ConvertToPx());
1019     direction_ = layoutProperty->GetFlexDirection().value_or(FlexDirection::ROW);
1020     bool isReverse = layoutProperty->GetFlexLayoutAttribute()->GetIsReverse().value_or(false);
1021     if (isReverse) {
1022         direction_ = ReverseFlexDirection(direction_);
1023     }
1024     mainAxisAlign_ = layoutProperty->GetMainAxisAlignValue(FlexAlign::FLEX_START);
1025     crossAxisAlign_ =
1026         layoutProperty->GetCrossAxisAlignValue(isLinearLayoutFeature_ ? FlexAlign::CENTER : FlexAlign::FLEX_START);
1027     textDir_ = layoutProperty->GetLayoutDirection();
1028     if (textDir_ == TextDirection::AUTO) {
1029         textDir_ = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
1030     }
1031     auto contentSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
1032     const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
1033     Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)
1034         ? MinusPaddingToNonNegativeSize(padding, contentSize)
1035         : MinusPaddingToSize(padding, contentSize);
1036     mainAxisSize_ = GetMainAxisSizeHelper(contentSize, direction_);
1037     crossAxisSize_ = GetCrossAxisSizeHelper(contentSize, direction_);
1038     auto paddingOffset = OffsetF(padding.left.value_or(0.0f), padding.top.value_or(0.0f));
1039     float remainSpace = std::max(mainAxisSize_ - allocatedSize_, 0.0f);
1040     float frontSpace = 0.0f;
1041     float betweenSpace = 0.0f;
1042     CalculateSpace(remainSpace, frontSpace, betweenSpace);
1043     PlaceChildren(layoutWrapper, frontSpace, betweenSpace, paddingOffset);
1044 
1045     for (auto&& child : children) {
1046         if (!child->IsOutOfLayout() && child->IsActive()) {
1047             child->Layout();
1048         }
1049     }
1050 }
1051 
CalculateSpace(float remainSpace,float & frontSpace,float & betweenSpace) const1052 void FlexLayoutAlgorithm::CalculateSpace(float remainSpace, float& frontSpace, float& betweenSpace) const
1053 {
1054     switch (mainAxisAlign_) {
1055         case FlexAlign::FLEX_START:
1056             frontSpace = 0.0f;
1057             betweenSpace = space_;
1058             break;
1059         case FlexAlign::FLEX_END:
1060             frontSpace = remainSpace;
1061             betweenSpace = space_;
1062             break;
1063         case FlexAlign::CENTER:
1064             frontSpace = remainSpace / 2;
1065             betweenSpace = space_;
1066             break;
1067         case FlexAlign::SPACE_BETWEEN:
1068             frontSpace = 0.0f;
1069             betweenSpace = validSizeCount_ > 1 ? remainSpace / static_cast<float>(validSizeCount_ - 1) : 0.0f;
1070             break;
1071         case FlexAlign::SPACE_AROUND:
1072             betweenSpace = validSizeCount_ > 0 ? remainSpace / static_cast<float>(validSizeCount_) : 0.0f;
1073             frontSpace = betweenSpace / 2;
1074             break;
1075         case FlexAlign::SPACE_EVENLY:
1076             betweenSpace = validSizeCount_ > 0 ? remainSpace / static_cast<float>(validSizeCount_ + 1) : 0.0f;
1077             frontSpace = betweenSpace;
1078             break;
1079         default:
1080             break;
1081     }
1082 }
1083 
PlaceChildren(LayoutWrapper * layoutWrapper,float frontSpace,float betweenSpace,const OffsetF & paddingOffset)1084 void FlexLayoutAlgorithm::PlaceChildren(
1085     LayoutWrapper* layoutWrapper, float frontSpace, float betweenSpace, const OffsetF& paddingOffset)
1086 {
1087     float childMainPos = IsStartTopLeft(direction_, textDir_) ? frontSpace : mainAxisSize_ - frontSpace;
1088     float childCrossPos = 0.0f;
1089     const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
1090     for (const auto& child : children) {
1091         if (child->IsOutOfLayout() || !child->IsActive()) {
1092             // adjust by postion property.
1093             child->GetGeometryNode()->SetMarginFrameOffset({});
1094             child->Layout();
1095             continue;
1096         }
1097         if (layoutWrapper && layoutWrapper->GetHostNode() && layoutWrapper->GetHostNode()->GetLayoutProperty() &&
1098             child->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::GONE) {
1099             continue;
1100         }
1101         auto alignItem = GetSelfAlign(child);
1102         auto crossDirection = FlipAxis(direction_);
1103         switch (alignItem) {
1104             case FlexAlign::FLEX_START:
1105             case FlexAlign::FLEX_END:
1106                 childCrossPos = (IsStartTopLeft(crossDirection, textDir_) == (alignItem == FlexAlign::FLEX_START))
1107                                     ? 0.0f
1108                                     : crossAxisSize_ - GetChildCrossAxisSize(child);
1109                 break;
1110             case FlexAlign::CENTER:
1111                 childCrossPos = crossAxisSize_ / 2 - GetChildCrossAxisSize(child) / 2;
1112                 break;
1113             case FlexAlign::STRETCH:
1114                 childCrossPos =
1115                     IsStartTopLeft(crossDirection, textDir_) ? 0.0f : crossAxisSize_ - GetChildCrossAxisSize(child);
1116                 break;
1117             case FlexAlign::BASELINE:
1118                 childCrossPos = 0.0;
1119                 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
1120                     float distance = child->GetBaselineDistance();
1121                     childCrossPos = baselineProperties_.maxBaselineDistance - distance;
1122                 }
1123                 break;
1124             default:
1125                 break;
1126         }
1127         OffsetF offset;
1128         if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
1129             offset = OffsetF(childMainPos, childCrossPos);
1130         } else {
1131             offset = OffsetF(childCrossPos, childMainPos);
1132         }
1133 
1134         if (!IsStartTopLeft(direction_, textDir_)) {
1135             if (direction_ != FlexDirection::COLUMN_REVERSE) {
1136                 offset.SetX(offset.GetX() - GetChildMainAxisSize(child));
1137             } else {
1138                 offset.SetY(offset.GetY() - GetChildMainAxisSize(child));
1139             }
1140             child->GetGeometryNode()->SetMarginFrameOffset(offset + paddingOffset);
1141             childMainPos -= GetChildMainAxisSize(child) + betweenSpace;
1142         } else {
1143             child->GetGeometryNode()->SetMarginFrameOffset(offset + paddingOffset);
1144             childMainPos += GetChildMainAxisSize(child) + betweenSpace;
1145         }
1146     }
1147 }
1148 
GetSelfAlign(const RefPtr<LayoutWrapper> & layoutWrapper) const1149 FlexAlign FlexLayoutAlgorithm::GetSelfAlign(const RefPtr<LayoutWrapper>& layoutWrapper) const
1150 {
1151     const auto& flexItemProperty = layoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
1152     FlexAlign crossAxisAlign = (crossAxisAlign_ == FlexAlign::AUTO) ? FlexAlign::FLEX_START : crossAxisAlign_;
1153     if (!flexItemProperty || !flexItemProperty->GetAlignSelf().has_value() ||
1154         flexItemProperty->GetAlignSelf().value_or(crossAxisAlign_) == FlexAlign::AUTO) {
1155         return crossAxisAlign;
1156     }
1157     return flexItemProperty->GetAlignSelf().value_or(crossAxisAlign);
1158 }
1159 
1160 } // namespace OHOS::Ace::NG
1161