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