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