• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/flex/render_flex.h"
17 
18 #include <algorithm>
19 
20 #include "base/log/dump_log.h"
21 #include "core/components/flex/flex_component.h"
22 #include "core/components/scroll/render_single_child_scroll.h"
23 #include "core/pipeline/base/position_layout_utils.h"
24 
25 namespace OHOS::Ace {
26 namespace {
27 
28 const static int32_t PLATFORM_VERSION_FIVE = 5;
29 
FlipAxis(FlexDirection direction)30 inline FlexDirection FlipAxis(FlexDirection direction)
31 {
32     if (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
33         return FlexDirection::COLUMN;
34     } else {
35         return FlexDirection::ROW;
36     }
37 }
38 
GetMainAxisValue(const Size & size,FlexDirection direction)39 double GetMainAxisValue(const Size& size, FlexDirection direction)
40 {
41     return direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE ? size.Width() : size.Height();
42 }
43 
IsNonRelativePosition(PositionType pos)44 inline bool IsNonRelativePosition(PositionType pos)
45 {
46     return ((pos != PositionType::RELATIVE) && (pos != PositionType::SEMI_RELATIVE) && (pos != PositionType::OFFSET));
47 }
48 
49 } // namespace
50 
Create()51 RefPtr<RenderNode> RenderFlex::Create()
52 {
53     return AceType::MakeRefPtr<RenderFlex>();
54 }
55 
Update(const RefPtr<Component> & component)56 void RenderFlex::Update(const RefPtr<Component>& component)
57 {
58     const RefPtr<FlexComponent> flex = AceType::DynamicCast<FlexComponent>(component);
59     if (!flex) {
60         return;
61     }
62     direction_ = flex->GetDirection();
63     mainAxisAlign_ = flex->GetMainAxisAlign();
64     crossAxisAlign_ = flex->GetCrossAxisAlign();
65     mainAxisSize_ = flex->GetMainAxisSize();
66     crossAxisSize_ = flex->GetCrossAxisSize();
67     stretchToParent_ = flex->IsStretchToParent();
68     useViewPort_ = flex->GetUseViewPortFlag();
69     containsNavigation_ = flex->ContainsNavigation();
70     overflow_ = flex->GetOverflow();
71     SetTextDirection(flex->GetTextDirection());
72     alignPtr_ = flex->GetAlignDeclarationPtr();
73 
74     auto context = GetContext().Upgrade();
75     if (context) {
76         space_ = context->NormalizeToPx(flex->GetSpace());
77         inspectorSpace_ = flex->GetSpace();
78         useOldLayoutVersion_ = context->GetMinPlatformVersion() <= PLATFORM_VERSION_FIVE;
79         if (GreatNotEqual(space_, 0.0)) {
80             mainAxisAlign_ = FlexAlign::SPACE_CUSOMIZATION;
81         }
82     }
83     UpdateAccessibilityAttr();
84     MarkNeedLayout();
85 }
86 
UpdateAccessibilityAttr()87 void RenderFlex::UpdateAccessibilityAttr()
88 {
89     auto refPtr = accessibilityNode_.Upgrade();
90     if (!refPtr) {
91         return;
92     }
93     RefPtr<RenderSingleChildScroll> scroll;
94     auto parent = GetParent().Upgrade();
95     while (parent) {
96         scroll = AceType::DynamicCast<RenderSingleChildScroll>(parent);
97         if (scroll) {
98             break;
99         }
100         parent = parent->GetParent().Upgrade();
101     }
102     if (!scroll || !scroll->GetAccessibilityNode().Upgrade()) {
103         return;
104     }
105     if (scroll->GetAccessibilityNode().Upgrade()->GetNodeId() != refPtr->GetNodeId()) {
106         return;
107     }
108 
109     refPtr->SetScrollableState(true);
110     refPtr->SetActionScrollForward([weakScroll = AceType::WeakClaim(RawPtr(scroll))]() {
111         auto scroll = weakScroll.Upgrade();
112         if (scroll) {
113             LOGD("Trigger ScrollForward by Accessibility.");
114             scroll->ScrollPage(false, true);
115             return true;
116         }
117         return false;
118     });
119     refPtr->SetActionScrollBackward([weakScroll = AceType::WeakClaim(RawPtr(scroll))]() {
120         auto scroll = weakScroll.Upgrade();
121         if (scroll) {
122             LOGD("Trigger ScrollBackward by Accessibility.");
123             scroll->ScrollPage(true, true);
124             return true;
125         }
126         return false;
127     });
128     refPtr->AddSupportAction(AceAction::ACTION_SCROLL_FORWARD);
129     refPtr->AddSupportAction(AceAction::ACTION_SCROLL_BACKWARD);
130     scrollNode = scroll;
131 }
132 
OnPaintFinish()133 void RenderFlex::OnPaintFinish()
134 {
135     auto refPtr = accessibilityNode_.Upgrade();
136     if (!refPtr || !scrollNode) {
137         return;
138     }
139     auto collectionInfo = refPtr->GetCollectionInfo();
140     collectionInfo.rows = static_cast<int32_t>(GetChildren().size());
141     collectionInfo.columns = 1;
142     refPtr->SetCollectionInfo(collectionInfo);
143     Rect itemRect;
144     Rect viewPortRect(scrollNode->GetGlobalOffset(), scrollNode->GetChildViewPort());
145     for (const auto& item : GetChildren()) {
146         auto node = item->GetAccessibilityNode().Upgrade();
147         if (!node) {
148             continue;
149         }
150         bool visible = GetVisible();
151         if (visible) {
152             itemRect.SetSize(item->GetLayoutSize());
153             itemRect.SetOffset(item->GetGlobalOffset());
154             visible = itemRect.IsIntersectWith(viewPortRect);
155         }
156         item->SetAccessibilityVisible(visible);
157         if (visible) {
158             Rect clampRect = itemRect.Constrain(viewPortRect);
159             if (clampRect != itemRect) {
160                 item->SetAccessibilityRect(clampRect);
161             }
162         } else {
163             item->NotifyPaintFinish();
164         }
165     }
166 }
167 
MakeStretchInnerLayoutParam(const RefPtr<RenderNode> & item) const168 LayoutParam RenderFlex::MakeStretchInnerLayoutParam(const RefPtr<RenderNode>& item) const
169 {
170     // must be called in the second time layout, so that crossSize_ is determined.
171     LayoutParam innerLayout;
172     double crossAxisLimit = GetStretchCrossLimit();
173     if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
174         innerLayout.SetFixedSize(Size(GetMainSize(item), crossAxisLimit));
175     } else {
176         innerLayout.SetFixedSize(Size(crossAxisLimit, GetMainSize(item)));
177     }
178     return innerLayout;
179 }
180 
MakeLayoutParamWithLimit(double minMainLimit,double maxMainLimit,bool isStretch) const181 LayoutParam RenderFlex::MakeLayoutParamWithLimit(double minMainLimit, double maxMainLimit, bool isStretch) const
182 {
183     LayoutParam innerLayout;
184     double minCrossLimit = 0.0;
185     double maxCrossLimit = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE)
186                                ? GetLayoutParam().GetMaxSize().Height()
187                                : GetLayoutParam().GetMaxSize().Width();
188     if (isStretch) {
189         minCrossLimit = GetStretchCrossLimit();
190         maxCrossLimit = minCrossLimit;
191     }
192     if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
193         innerLayout.SetMinSize(Size(minMainLimit, minCrossLimit));
194         innerLayout.SetMaxSize(Size(maxMainLimit, maxCrossLimit));
195     } else {
196         innerLayout.SetMinSize(Size(minCrossLimit, minMainLimit));
197         innerLayout.SetMaxSize(Size(maxCrossLimit, maxMainLimit));
198     }
199     return innerLayout;
200 }
201 
MakeConstrainedLayoutParam(double mainFlexExtent,const LayoutParam & constraints,bool isStretch,bool supportZero) const202 LayoutParam RenderFlex::MakeConstrainedLayoutParam(
203     double mainFlexExtent, const LayoutParam& constraints, bool isStretch, bool supportZero) const
204 {
205     LayoutParam innerLayout;
206     if (LessNotEqual(mainFlexExtent, 0.0)) {
207         innerLayout.SetMaxSize(GetLayoutParam().GetMaxSize());
208     } else if (GreatNotEqual(mainFlexExtent, 0.0)) {
209         innerLayout = MakeLayoutParamWithLimit(mainFlexExtent, mainFlexExtent, isStretch);
210     } else {
211         if (supportZero) {
212             innerLayout = MakeLayoutParamWithLimit(mainFlexExtent, mainFlexExtent, isStretch);
213         } else {
214             innerLayout.SetMaxSize(GetLayoutParam().GetMaxSize());
215         }
216     }
217     innerLayout.SetMaxSize(constraints.Constrain(innerLayout.GetMaxSize()));
218     innerLayout.SetMinSize(constraints.Constrain(innerLayout.GetMinSize()));
219     // SetHasUsedPercentFlag is to tell box not to use constraints
220     innerLayout.SetHasUsedConstraints(true);
221     return innerLayout;
222 }
223 
GetStretchCrossLimit() const224 double RenderFlex::GetStretchCrossLimit() const
225 {
226     Size maxLayoutParam = GetLayoutParam().GetMaxSize();
227     double crossAxisLimit = 0.0;
228     if (!stretchToParent_) {
229         crossAxisLimit = crossSize_;
230     } else if (!isCrossInfinite_ || !useViewPort_) {
231         crossAxisLimit = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE)
232                              ? maxLayoutParam.Height()
233                              : maxLayoutParam.Width();
234     } else {
235         crossAxisLimit = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE)
236                              ? viewPort_.Height()
237                              : viewPort_.Width();
238     }
239     return crossAxisLimit;
240 }
241 
PerformLayout()242 void RenderFlex::PerformLayout()
243 {
244     if (GetChildren().empty()) {
245         SetLayoutSize(Size());
246         return;
247     }
248 
249     auto context = GetContext().Upgrade();
250     if (!context) {
251         return;
252     }
253     if (alignPtr_ != nullptr) {
254         context->AddAlignDeclarationNode(AceType::Claim(this));
255     }
256 
257     // init properties.
258     InitFlexProperties();
259     if (layoutMode_ == FlexLayoutMode::FLEX_WEIGHT_MODE) {
260         PerformLayoutInWeightMode();
261     } else if (maxDisplayIndex_ > 1) {
262         PerformLayoutInIndexMode();
263     } else {
264         PerformLayoutInItemMode();
265     }
266     ClearChildrenLists();
267 
268     if (alignPtr_ != nullptr) {
269         auto& nodeList = context->GetAlignDeclarationNodeList();
270         PerformItemAlign(nodeList);
271     }
272 }
273 
PerformLayoutInWeightMode()274 void RenderFlex::PerformLayoutInWeightMode()
275 {
276     double maxMainSize = GetMainAxisValue(GetLayoutParam().GetMaxSize(), direction_);
277     if (NearEqual(maxMainSize, Size::INFINITE_SIZE)) {
278         LOGW("not supported infinite size");
279         return;
280     }
281     BaselineProperties baselineProperties;
282     LayoutParam innerLayout;
283     double allocatedSize = allocatedSize_;
284     for (const auto& child : relativeNodes_) {
285         if (LessOrEqual(child->GetFlexWeight(), 0.0)) {
286             child->Layout(GetLayoutParam());
287             ResizeByItem(child, allocatedSize);
288             CheckSizeValidity(child);
289             CheckBaselineProperties(child, baselineProperties);
290         }
291     }
292     maxMainSize -= allocatedSize_;
293     // if remain size less than zero, adjust it to zero
294     if (!useOldLayoutVersion_ && LessNotEqual(maxMainSize, 0.0)) {
295         maxMainSize = 0.0;
296     }
297     // totalFlexWeight_ is guard in InitFlexProperties() so it won't be zero
298     auto spacePerWeight = maxMainSize / totalFlexWeight_;
299     bool isExceed = false;
300     auto iter = magicNodes_.rbegin();
301     // Calculate innerLayoutParam for each magic node
302     while (iter != magicNodes_.rend()) {
303         auto& layoutList = (*iter).second;
304         for (auto& node : layoutList) {
305             auto child = node.node;
306             if (LessOrEqual(child->GetFlexWeight(), 0.0)) {
307                 continue;
308             }
309             auto childFlexSize = spacePerWeight * child->GetFlexWeight();
310             auto flexItem = AceType::DynamicCast<RenderFlexItem>(child);
311             if (flexItem) {
312                 innerLayout = MakeConstrainedLayoutParam(
313                     childFlexSize, flexItem->GetNormalizedConstraints(), false, !useOldLayoutVersion_);
314             } else {
315                 innerLayout = MakeLayoutParamWithLimit(childFlexSize, childFlexSize, false);
316             }
317             // If min constraint is larger than flexSize, total size must exceed.
318             isExceed = isExceed || GetMainAxisValue(innerLayout.GetMaxSize(), direction_) > childFlexSize;
319             node.innerLayout = innerLayout;
320         }
321         if (!isExceed) {
322             iter++;
323         } else if (magicNodes_.size() <= 1) {
324             break;
325         } else {
326             // Hide nodes, reset properties and start next loop
327             totalFlexWeight_ -= magicWeightMaps_[(*magicNodes_.begin()).first];
328             spacePerWeight = maxMainSize / totalFlexWeight_;
329             isExceed = false;
330             magicNodes_.erase(magicNodes_.begin());
331             iter = magicNodes_.rbegin();
332         }
333     }
334     // Layout magic nodes
335     LayoutMagicNodes(baselineProperties);
336     if (crossAxisAlign_ == FlexAlign::STRETCH) {
337         RelayoutForStretchMagicNode();
338     }
339     LayoutAbsoluteChildren();
340     LayoutHiddenNodes();
341     Size layoutSize = GetConstrainedSize(GetMainAxisValue(GetLayoutParam().GetMaxSize(), direction_));
342     SetLayoutSize(layoutSize);
343     mainSize_ = GetMainAxisValue(layoutSize, direction_);
344     crossSize_ = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) ? layoutSize.Height()
345                                                                                                 : layoutSize.Width();
346     DetermineItemsPosition(baselineProperties);
347 }
348 
LayoutMagicNodes(BaselineProperties & baselineProperties)349 void RenderFlex::LayoutMagicNodes(BaselineProperties& baselineProperties)
350 {
351     double allocatedSize = allocatedSize_;
352     for (const auto& magicNode : magicNodes_) {
353         auto nodeList = magicNode.second;
354         for (const auto& child : nodeList) {
355             if (LessOrEqual(child.node->GetFlexWeight(), 0.0)) {
356                 continue;
357             }
358             child.node->Layout(child.innerLayout);
359             child.node->SetVisible(true);
360             ResizeByItem(child.node, allocatedSize);
361             CheckSizeValidity(child.node);
362             CheckBaselineProperties(child.node, baselineProperties);
363         }
364     }
365 }
366 
RelayoutForStretchMagicNode()367 void RenderFlex::RelayoutForStretchMagicNode()
368 {
369     LayoutParam innerLayout;
370     for (const auto& magicNodeMap : magicNodes_) {
371         auto nodeList = magicNodeMap.second;
372         for (const auto& node : nodeList) {
373             auto child = node.node;
374             auto flexItem = AceType::DynamicCast<RenderFlexItem>(child);
375             if (!flexItem) {
376                 innerLayout = MakeLayoutParamWithLimit(GetMainSize(child), GetMainSize(child), true);
377             } else if (flexItem->GetStretchFlag()) {
378                 innerLayout =
379                     MakeConstrainedLayoutParam(GetMainSize(flexItem), flexItem->GetNormalizedConstraints(), true);
380             } else {
381                 // FlexItem cannot be stretched, skip it.
382                 continue;
383             }
384             child->Layout(innerLayout);
385             // stretch only need to adjust crossSize
386             crossSize_ = std::max(crossSize_, GetCrossSize(child));
387         }
388     }
389 }
390 
PerformLayoutInIndexMode()391 void RenderFlex::PerformLayoutInIndexMode()
392 {
393     auto maxMainSize = GetMainAxisValue(GetLayoutParam().GetMaxSize(), direction_);
394     LayoutParam innerLayout;
395     innerLayout.SetMaxSize(GetLayoutParam().GetMaxSize());
396     FlexItemProperties flexItemProperties;
397     for (auto iter = magicNodes_.rbegin(); iter != magicNodes_.rend();) {
398         auto nodeList = (*iter).second;
399         for (const auto& node : nodeList) {
400             auto child = node.node;
401             child->Layout(innerLayout);
402             allocatedSize_ += GetMainSize(child);
403         }
404         if (allocatedSize_ > maxMainSize) {
405             for (const auto& node : nodeList) {
406                 auto child = node.node;
407                 allocatedSize_ -= GetMainSize(child);
408             }
409             break;
410         }
411         // If not fill all the main size, record the node and continue the loop.
412         for (const auto& node : nodeList) {
413             auto child = node.node;
414             CheckSizeValidity(child);
415             child->SetVisible(true);
416             auto flexItem = AceType::DynamicCast<RenderFlexItem>(child);
417             if (flexItem && GreatNotEqual(flexItem->GetFlexGrow(), 0.0)) {
418                 flexItemProperties.totalGrow += flexItem->GetFlexGrow();
419                 flexItemProperties.lastGrowChild = flexItem;
420             }
421             crossSize_ = std::max(crossSize_, GetCrossSize(child));
422         }
423         if (NearEqual(allocatedSize_, maxMainSize)) {
424             break;
425         }
426         iter++;
427     }
428     // Second Layout for grow/stretch
429     if (crossAxisAlign_ == FlexAlign::STRETCH || flexItemProperties.totalGrow > 0) {
430         RelayoutForStretchFlexNode(flexItemProperties);
431     }
432     LayoutHiddenNodes();
433     LayoutAbsoluteChildren();
434     Size layoutSize = GetConstrainedSize(maxMainSize);
435     SetLayoutSize(layoutSize);
436     mainSize_ = GetMainAxisValue(layoutSize, direction_);
437     crossSize_ = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) ? layoutSize.Height()
438                                                                                                 : layoutSize.Width();
439     BaselineProperties baselineProperties;
440     DetermineItemsPosition(baselineProperties);
441 }
442 
RelayoutForStretchFlexNode(const FlexItemProperties & flexItemProperties)443 void RenderFlex::RelayoutForStretchFlexNode(const FlexItemProperties& flexItemProperties)
444 {
445     auto remainSpace = GetMainAxisValue(GetLayoutParam().GetMaxSize(), direction_) - allocatedSize_;
446     // only grow applied in display index mode.
447     double spacePerFlex = 0.0;
448     if (GreatNotEqual(flexItemProperties.totalGrow, 0.0)) {
449         spacePerFlex = remainSpace / flexItemProperties.totalGrow;
450     }
451     double allocatedFlexSpace = 0.0;
452     BaselineProperties baselineProperties;
453     for (const auto& item : displayNodes_) {
454         auto flexItem = AceType::DynamicCast<RenderFlexItem>(item);
455         if (!flexItem) {
456             if (crossAxisAlign_ == FlexAlign::STRETCH) {
457                 item->Layout(MakeStretchInnerLayoutParam(item));
458                 // stretch only need to adjust cross size
459                 crossSize_ = std::max(crossSize_, GetCrossSize(item));
460             }
461             continue;
462         }
463         if (GreatNotEqual(flexItem->GetFlexGrow(), 0.0)) {
464             double flexSize = 0.0;
465             flexSize = flexItem == flexItemProperties.lastGrowChild ? remainSpace - allocatedFlexSpace
466                                                                     : spacePerFlex * flexItem->GetFlexGrow();
467             RelayoutFlexItem(flexItem, flexSize, baselineProperties, allocatedFlexSpace);
468         } else if (crossAxisAlign_ == FlexAlign::STRETCH && flexItem->GetStretchFlag()) {
469             flexItem->Layout(
470                 MakeConstrainedLayoutParam(GetMainSize(flexItem), flexItem->GetNormalizedConstraints(), true));
471             crossSize_ = std::max(crossSize_, GetCrossSize(flexItem));
472         } else {
473             // not stretch or grow, continue.
474             continue;
475         }
476     }
477 }
478 
LayoutHiddenNodes()479 void RenderFlex::LayoutHiddenNodes()
480 {
481     LayoutParam innerLayout = LayoutParam(Size(), Size());
482     for (const auto& child : relativeNodes_) {
483         if (displayNodes_.find(child) != displayNodes_.end()) {
484             continue;
485         }
486         child->SetVisible(false);
487         child->Layout(innerLayout);
488     }
489 }
490 
PerformLayoutInItemMode()491 void RenderFlex::PerformLayoutInItemMode()
492 {
493     LayoutParam innerLayout;
494     innerLayout.SetMaxSize(GetLayoutParam().GetMaxSize());
495     FlexItemProperties flexItemProperties;
496     BaselineProperties baselineProperties;
497     double allocatedSize = allocatedSize_;
498     // first time layout
499     for (const auto& item : relativeNodes_) {
500         auto flexItem = AceType::DynamicCast<RenderFlexItem>(item);
501         if (!flexItem || flexItem->IsHidden()) {
502             item->Layout(innerLayout);
503         } else {
504             LayoutFlexItem(flexItem, flexItemProperties);
505         }
506         if (item == GetChildren().front() && containsNavigation_) {
507             navigationMainSize_ = GetMainAxisValue(item->GetLayoutSize(), direction_);
508         }
509         ResizeByItem(item, allocatedSize);
510         CheckSizeValidity(item);
511         CheckBaselineProperties(item, baselineProperties);
512     }
513     // second time layout
514     double mainViewPort = GetMainAxisValue(viewPort_, direction_);
515     bool useViewPort = useViewPort_ && !viewPort_.IsInfinite() && (allocatedSize_ < mainViewPort);
516     auto mainAxisSize = mainAxisSize_;
517     if (!isMainInfinite_ || useViewPort) {
518         ResizeItems(flexItemProperties, baselineProperties);
519     } else if (!infinityLayoutNodes_.empty()) {
520         if (allocatedSize_ < mainViewPort) {
521             allocatedSize_ = Size::INFINITE_SIZE;
522         } else {
523             double availableMainSize = GetAvailableMainSize();
524             for (auto& infinityItem : infinityLayoutNodes_) {
525                 LayoutInfinityChild(infinityItem, availableMainSize, baselineProperties);
526             }
527             mainAxisSize = MainAxisSize::MIN;
528         }
529     } else if (allocatedSize_ >= mainViewPort && crossAxisAlign_ == FlexAlign::STRETCH) {
530         // Children size larger than viewPort, second layout only do stretch.
531         for (const auto& item : relativeNodes_) {
532             // If Item has set width/height in main axis, not need to stretch.
533             auto flexItem = AceType::DynamicCast<RenderFlexItem>(item);
534             if (flexItem && !flexItem->GetStretchFlag()) {
535                 continue;
536             }
537             item->Layout(MakeStretchInnerLayoutParam(item));
538         }
539     } else {
540         for (const auto& item : stretchNodes_) {
541             item->Layout(MakeStretchInnerLayoutParam(item));
542         }
543         mainAxisSize = MainAxisSize::MIN;
544     }
545     LayoutAbsoluteChildren();
546     // get layout size and set positions
547     DetermineSelfSize(mainAxisSize, useViewPort);
548     DetermineItemsPosition(baselineProperties);
549 }
550 
ResizeItems(const FlexItemProperties & flexItemProps,BaselineProperties & baselineProps)551 void RenderFlex::ResizeItems(const FlexItemProperties& flexItemProps, BaselineProperties& baselineProps)
552 {
553     double availableMainSize = GetAvailableMainSize();
554     auto context = GetContext().Upgrade();
555     bool isDeclarative = context ? context->GetIsDeclarative() : false;
556     if (flexItemProps.totalGrow > 0 && availableMainSize > allocatedSize_ && !isDeclarative) {
557         mainAxisSize_ = MainAxisSize::MAX;
558     }
559     // remainSpace should be (availableMainSize - allocatedSize_), and do not remain space when MainAxisSize::MIN.
560     // Handle infinity children specially, because allocatedSize_ not include infinity child.
561     double remainSpace =
562         (mainAxisSize_ == MainAxisSize::MIN && availableMainSize >= allocatedSize_ && infinityLayoutNodes_.empty())
563             ? 0.0
564             : availableMainSize - allocatedSize_;
565     double infiniteLayoutSize = availableMainSize;
566     if (!infinityLayoutNodes_.empty()) {
567         if (remainSpace > 0.0) {
568             infiniteLayoutSize = remainSpace / infinityLayoutNodes_.size();
569             remainSpace = 0.0;
570         } else {
571             remainSpace -= infiniteLayoutSize;
572         }
573     }
574     double spacePerFlex = 0.0;
575     double allocatedFlexSpace = 0.0;
576     double (*getFlex)(const RefPtr<RenderFlexItem>&) = nullptr;
577     RefPtr<RenderFlexItem> lastChild;
578     if (remainSpace > 0) {
579         getFlex = [](const RefPtr<RenderFlexItem>& item) { return item->GetFlexGrow(); };
580         spacePerFlex = NearZero(flexItemProps.totalGrow) ? 0.0 : remainSpace / flexItemProps.totalGrow;
581         lastChild = flexItemProps.lastGrowChild;
582     } else {
583         getFlex = [](const RefPtr<RenderFlexItem>& item) { return item->GetFlexShrink(); };
584         spacePerFlex = NearZero(flexItemProps.totalShrink) ? 0.0 : remainSpace / flexItemProps.totalShrink;
585         lastChild = flexItemProps.lastShrinkChild;
586     }
587     // In second layout, do not need to check the size validity, they are all checked.
588     for (const auto& item : relativeNodes_) {
589         if (infinityLayoutNodes_.find(item) != infinityLayoutNodes_.end()) {
590             LayoutInfinityChild(item, infiniteLayoutSize, baselineProps);
591             continue;
592         }
593         auto flexItem = AceType::DynamicCast<RenderFlexItem>(item);
594         if (!flexItem || flexItem->IsHidden()) {
595             if (crossAxisAlign_ == FlexAlign::STRETCH) {
596                 item->Layout(MakeStretchInnerLayoutParam(item));
597             }
598             continue;
599         }
600         double itemFlex = getFlex(flexItem);
601         double flexSize = (flexItem == lastChild) ? (remainSpace - allocatedFlexSpace)
602                                                   : ((remainSpace > 0) ? spacePerFlex * itemFlex
603                                                                        : spacePerFlex * itemFlex * GetMainSize(item));
604         RelayoutFlexItem(flexItem, flexSize, baselineProps, allocatedFlexSpace);
605     }
606 }
607 
DetermineSelfSize(MainAxisSize mainAxisSize,bool useViewPort)608 void RenderFlex::DetermineSelfSize(MainAxisSize mainAxisSize, bool useViewPort)
609 {
610     double maxMainSize = GetMainAxisValue(GetLayoutParam().GetMaxSize(), direction_);
611     double mainViewPort = GetMainAxisValue(viewPort_, direction_);
612     if (NearEqual(maxMainSize, Size::INFINITE_SIZE)) {
613         // If max size of layoutParam is infinity, use children's allocated size as max size.
614         maxMainSize = allocatedSize_;
615     }
616     // useViewPort means that it is the root flex, should be as large as viewPort.
617     Size layoutSize = (mainAxisSize == MainAxisSize::MIN) ? GetConstrainedSize(allocatedSize_)
618                       : useViewPort                       ? GetConstrainedSize(mainViewPort)
619                                                           : GetConstrainedSize(maxMainSize);
620     if (useViewPort && !absoluteNodes_.empty()) {
621         layoutSize = GetConstrainedSize(mainViewPort);
622     }
623     isChildOverflow_ = allocatedSize_ > GetMainAxisValue(layoutSize, direction_);
624     SetLayoutSize(layoutSize);
625     mainSize_ = GetMainAxisValue(layoutSize, direction_);
626     crossSize_ = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) ? layoutSize.Height()
627                                                                                                 : layoutSize.Width();
628 }
629 
DetermineItemsPosition(const BaselineProperties & baselineProperties)630 void RenderFlex::DetermineItemsPosition(const BaselineProperties& baselineProperties)
631 {
632     double remainSpace = (mainSize_ - allocatedSize_) > 0.0 ? (mainSize_ - allocatedSize_) : 0.0;
633     double frontSpace = 0.0;
634     double betweenSpace = 0.0;
635     // make use of remain space
636     CalculateSpace(remainSpace, frontSpace, betweenSpace);
637     // position elements
638     PlaceChildren(frontSpace, betweenSpace, baselineProperties);
639 }
640 
CalculateSpace(double remainSpace,double & frontSpace,double & betweenSpace) const641 void RenderFlex::CalculateSpace(double remainSpace, double& frontSpace, double& betweenSpace) const
642 {
643     if (NearZero(remainSpace) && mainAxisAlign_ != FlexAlign::SPACE_CUSOMIZATION) {
644         return;
645     }
646     switch (mainAxisAlign_) {
647         case FlexAlign::FLEX_START:
648             frontSpace = 0.0;
649             betweenSpace = 0.0;
650             break;
651         case FlexAlign::FLEX_END:
652             frontSpace = remainSpace;
653             betweenSpace = 0.0;
654             break;
655         case FlexAlign::CENTER:
656             frontSpace = remainSpace / 2.0;
657             betweenSpace = 0.0;
658             break;
659         case FlexAlign::SPACE_BETWEEN:
660             frontSpace = 0.0;
661             betweenSpace = validSizeCount_ > 1 ? remainSpace / (validSizeCount_ - 1) : 0.0;
662             break;
663         case FlexAlign::SPACE_AROUND:
664             betweenSpace = validSizeCount_ > 0 ? remainSpace / validSizeCount_ : 0.0;
665             frontSpace = betweenSpace / 2.0;
666             break;
667         case FlexAlign::SPACE_EVENLY:
668             betweenSpace = validSizeCount_ > 0 ? remainSpace / (validSizeCount_ + 1) : 0.0;
669             frontSpace = betweenSpace;
670             break;
671         case FlexAlign::SPACE_CUSOMIZATION:
672             betweenSpace = space_;
673             frontSpace = 0.0;
674             break;
675         default:
676             break;
677     }
678 }
679 
PlaceChildren(double frontSpace,double betweenSpace,const BaselineProperties & baselineProperties)680 void RenderFlex::PlaceChildren(double frontSpace, double betweenSpace, const BaselineProperties& baselineProperties)
681 {
682     double childMainPos = IsStartTopLeft(direction_, GetTextDirection()) ? frontSpace : mainSize_ - frontSpace;
683     double childCrossPos = 0.0;
684     for (const auto& item : GetChildren()) {
685         if (item->IsIgnored()) {
686             continue;
687         }
688         auto flexItem = AceType::DynamicCast<RenderFlexItem>(item);
689         if (flexItem && flexItem->IsHidden() && !flexItem->GetLayoutSize().IsValid()) {
690             continue;
691         }
692         if (IsNonRelativePosition(item->GetPositionType())) {
693             Offset absoluteOffset = PositionLayoutUtils::GetAbsoluteOffset(Claim(this), item);
694             item->SetAbsolutePosition(absoluteOffset);
695             continue;
696         }
697         auto alignItem = GetSelfAlign(item);
698         auto textDirection = AdjustTextDirectionByDir();
699         switch (alignItem) {
700             case FlexAlign::FLEX_START:
701             case FlexAlign::FLEX_END:
702                 childCrossPos =
703                     (IsStartTopLeft(FlipAxis(direction_), textDirection) == (alignItem == FlexAlign::FLEX_START))
704                         ? 0.0
705                         : (crossSize_ - GetCrossSize(item));
706                 break;
707             case FlexAlign::CENTER:
708                 childCrossPos = (crossSize_ / 2.0) - (GetCrossSize(item) / 2.0);
709                 break;
710             case FlexAlign::STRETCH:
711                 childCrossPos =
712                     IsStartTopLeft(FlipAxis(direction_), textDirection) ? 0.0 : (crossSize_ - GetCrossSize(item));
713                 break;
714             case FlexAlign::BASELINE:
715                 childCrossPos = 0.0;
716                 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
717                     double distance = item->GetBaselineDistance(textBaseline_);
718                     childCrossPos = baselineProperties.maxBaselineDistance - distance;
719                 }
720                 break;
721             default:
722                 break;
723         }
724         Offset offset;
725         if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
726             if (item->GetPositionType() == PositionType::SEMI_RELATIVE) {
727                 childMainPos = 0.0;
728             }
729             offset = Offset(childMainPos, childCrossPos);
730         } else {
731             offset =
732                 Offset((item->GetPositionType() == PositionType::SEMI_RELATIVE) ? 0.0 : childCrossPos, childMainPos);
733         }
734 
735         if (!IsStartTopLeft(direction_, GetTextDirection())) {
736             if (direction_ != FlexDirection::COLUMN_REVERSE) {
737                 offset.SetX(offset.GetX() - GetMainSize(item));
738             } else {
739                 offset.SetY(offset.GetY() - GetMainSize(item));
740             }
741             item->SetPosition(offset);
742             childMainPos -= GetMainSize(item) + betweenSpace;
743         } else {
744             item->SetPosition(offset);
745             childMainPos += GetMainSize(item) + betweenSpace;
746         }
747     }
748 }
749 
LayoutFlexItem(RefPtr<RenderFlexItem> & flexItem,FlexItemProperties & flexItemProperties)750 void RenderFlex::LayoutFlexItem(RefPtr<RenderFlexItem>& flexItem, FlexItemProperties& flexItemProperties)
751 {
752     double itemShrink = flexItem->GetFlexShrink();
753     double itemGrow = flexItem->GetFlexGrow();
754     double itemBasis = flexItem->GetFlexBasisToPx();
755     if (flexItem->MustStretch()) {
756         stretchNodes_.emplace_back(flexItem);
757     }
758     if (itemGrow > 0) {
759         flexItemProperties.lastGrowChild = flexItem;
760     }
761     if (itemShrink > 0) {
762         flexItemProperties.lastShrinkChild = flexItem;
763     }
764     LayoutParam innerLayout;
765     if (GreatNotEqual(itemBasis, 0.0)) {
766         innerLayout = MakeLayoutParamWithLimit(itemBasis, itemBasis, false);
767     } else {
768         innerLayout.SetMaxSize(GetLayoutParam().GetMaxSize());
769     }
770     // first time layout flex item
771     flexItem->Layout(innerLayout);
772     flexItemProperties.totalShrink += itemShrink * GetMainSize(flexItem);
773     flexItemProperties.totalGrow += itemGrow;
774 }
775 
RelayoutFlexItem(const RefPtr<RenderFlexItem> & flexItem,double flexSize,BaselineProperties & baselineProps,double & allocatedFlexSpace)776 void RenderFlex::RelayoutFlexItem(const RefPtr<RenderFlexItem>& flexItem, double flexSize,
777     BaselineProperties& baselineProps, double& allocatedFlexSpace)
778 {
779     bool canItemStretch = flexItem->MustStretch() || ((GetSelfAlign(flexItem) == FlexAlign::STRETCH) &&
780                                                          (flexItem->GetStretchFlag()) && (relativeNodes_.size() > 1));
781     // less or equal than api 5
782     if (useOldLayoutVersion_) {
783         canItemStretch =
784             flexItem->MustStretch() || ((GetSelfAlign(flexItem) == FlexAlign::STRETCH) && (flexItem->GetStretchFlag()));
785     }
786 
787     if (NearZero(flexSize) && !canItemStretch) {
788         return;
789     }
790     auto mainFlexExtent = flexSize + GetMainSize(flexItem);
791     auto childMainContent = GetMainAxisValue(flexItem->GetContentSize(), direction_);
792     if (childMainContent > mainFlexExtent) {
793         mainFlexExtent = childMainContent;
794     }
795     allocatedSize_ -= GetMainSize(flexItem);
796     auto innerLayout = MakeConstrainedLayoutParam(mainFlexExtent, flexItem->GetNormalizedConstraints(), canItemStretch,
797         flexItem->MustStretch() || !useOldLayoutVersion_);
798     if (flexItem->MustStretch()) {
799         auto crossStretch = crossAxisSize_ == CrossAxisSize::MAX
800                                 ? GetMainAxisValue(GetLayoutParam().GetMaxSize(), FlipAxis(direction_))
801                                 : crossSize_;
802         auto innerMax = innerLayout.GetMaxSize();
803         if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
804             innerMax.SetHeight(crossStretch);
805         } else {
806             innerMax.SetWidth(crossStretch);
807         }
808         innerLayout.SetMaxSize(innerMax);
809         innerLayout.SetMinSize(innerMax);
810     }
811     flexItem->Layout(innerLayout);
812     allocatedFlexSpace += flexSize;
813     allocatedSize_ -= space_;
814     double allocatedSize = allocatedSize_;
815     ResizeByItem(flexItem, allocatedSize);
816     CheckBaselineProperties(flexItem, baselineProps);
817 }
818 
LayoutInfinityChild(const RefPtr<RenderNode> & item,double mainSize,BaselineProperties & baselineProps)819 void RenderFlex::LayoutInfinityChild(const RefPtr<RenderNode>& item, double mainSize, BaselineProperties& baselineProps)
820 {
821     auto flexItem = AceType::DynamicCast<RenderFlexItem>(item);
822     bool isStretch = false;
823     if (flexItem) {
824         isStretch = (crossAxisAlign_ == FlexAlign::STRETCH) && (flexItem->GetStretchFlag());
825     } else {
826         isStretch = crossAxisAlign_ == FlexAlign::STRETCH;
827     }
828     LayoutParam innerLayout = MakeLayoutParamWithLimit(mainSize, mainSize, isStretch);
829     item->Layout(innerLayout);
830     double allocatedSize = allocatedSize_;
831     ResizeByItem(item, allocatedSize);
832     CheckBaselineProperties(item, baselineProps);
833 }
834 
LayoutAbsoluteChildren()835 void RenderFlex::LayoutAbsoluteChildren()
836 {
837     if (absoluteNodes_.empty()) {
838         return;
839     }
840     for (const auto& item : absoluteNodes_) {
841         item->Layout(GetLayoutParam());
842     }
843 }
844 
CheckBaselineProperties(const RefPtr<RenderNode> & item,BaselineProperties & baselineProperties)845 void RenderFlex::CheckBaselineProperties(const RefPtr<RenderNode>& item, BaselineProperties& baselineProperties)
846 {
847     auto flexItem = AceType::DynamicCast<RenderFlexItem>(item);
848     bool isChildBaselineAlign = flexItem ? flexItem->GetAlignSelf() == FlexAlign::BASELINE : false;
849     if (crossAxisAlign_ == FlexAlign::BASELINE || isChildBaselineAlign) {
850         double distance = item->GetBaselineDistance(textBaseline_);
851         baselineProperties.maxBaselineDistance = std::max(baselineProperties.maxBaselineDistance, distance);
852         baselineProperties.maxDistanceAboveBaseline = std::max(baselineProperties.maxDistanceAboveBaseline, distance);
853         baselineProperties.maxDistanceBelowBaseline =
854             std::max(baselineProperties.maxDistanceBelowBaseline, GetCrossSize(item) - distance);
855         if (crossAxisAlign_ == FlexAlign::BASELINE) {
856             crossSize_ = baselineProperties.maxDistanceAboveBaseline + baselineProperties.maxDistanceBelowBaseline;
857         }
858     }
859 }
860 
GetBaselineDistance(TextBaseline baseline)861 double RenderFlex::GetBaselineDistance(TextBaseline baseline)
862 {
863     if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
864         // in row, use default children baseline defined in render node.
865         return GetHighestChildBaseline(baseline);
866     } else {
867         // in column, just get the first child baseline
868         return GetFirstChildBaseline(baseline);
869     }
870 }
871 
GetChildViewPort()872 Size RenderFlex::GetChildViewPort()
873 {
874     if (containsNavigation_) {
875         double width = viewPort_.Width();
876         double height = viewPort_.Height();
877         if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
878             width -= navigationMainSize_;
879         } else {
880             height -= navigationMainSize_;
881         }
882         return Size(width, height);
883     } else {
884         return viewPort_;
885     }
886 }
887 
InitFlexProperties()888 void RenderFlex::InitFlexProperties()
889 {
890     mainSize_ = 0.0;
891     crossSize_ = 0.0;
892     allocatedSize_ = 0.0;
893     validSizeCount_ = 0;
894     layoutMode_ = FlexLayoutMode::FLEX_WEIGHT_MODE;
895     totalFlexWeight_ = 0.0;
896     maxDisplayIndex_ = 0;
897     if (direction_ == FlexDirection::ROW) {
898         isMainInfinite_ = GetLayoutParam().GetMaxSize().IsWidthInfinite();
899         isCrossInfinite_ = GetLayoutParam().GetMaxSize().IsHeightInfinite();
900     } else {
901         isMainInfinite_ = GetLayoutParam().GetMaxSize().IsHeightInfinite();
902         isCrossInfinite_ = GetLayoutParam().GetMaxSize().IsWidthInfinite();
903     }
904     // determine the flex layout mode
905     TravelChildrenFlexProps();
906 }
907 
TravelChildrenFlexProps()908 void RenderFlex::TravelChildrenFlexProps()
909 {
910     for (const auto& child : GetChildren()) {
911         child->SetVisible(true);
912         if (IsNonRelativePosition(child->GetPositionType())) {
913             absoluteNodes_.insert(child);
914             continue;
915         }
916         maxDisplayIndex_ = std::max(child->GetDisplayIndex(), maxDisplayIndex_);
917         relativeNodes_.emplace_back(child);
918         MagicLayoutNode node;
919         node.node = child;
920         auto idx = child->GetDisplayIndex();
921         if (magicNodes_.find(idx) != magicNodes_.end()) {
922             magicNodes_[idx].emplace_back(node);
923             magicWeightMaps_[idx] += child->GetFlexWeight();
924         } else {
925             std::list<MagicLayoutNode> nodes;
926             nodes.emplace_back(node);
927             magicNodes_[idx] = nodes;
928             magicWeightMaps_[idx] = child->GetFlexWeight();
929         }
930         // FLEX_WEIGHT_MODE now active if one child has set flexWeight
931         totalFlexWeight_ += child->GetFlexWeight();
932     }
933     layoutMode_ =
934         LessOrEqual(totalFlexWeight_, 0.0) ? FlexLayoutMode::FLEX_ITEM_MODE : FlexLayoutMode::FLEX_WEIGHT_MODE;
935     if (relativeNodes_.empty() && !absoluteNodes_.empty()) {
936         layoutMode_ = FlexLayoutMode::FLEX_ITEM_MODE;
937     }
938 }
939 
ClearChildrenLists()940 void RenderFlex::ClearChildrenLists()
941 {
942     infinityLayoutNodes_.clear();
943     absoluteNodes_.clear();
944     relativeNodes_.clear();
945     magicNodes_.clear();
946     magicWeightMaps_.clear();
947     displayNodes_.clear();
948     stretchNodes_.clear();
949 }
950 
ResizeByItem(const RefPtr<RenderNode> & item,double & allocatedSize)951 void RenderFlex::ResizeByItem(const RefPtr<RenderNode>& item, double &allocatedSize)
952 {
953     double mainSize = GetMainSize(item);
954     if (NearEqual(mainSize, Size::INFINITE_SIZE)) {
955         mainSize = 0.0;
956         // push infinite nodes
957         infinityLayoutNodes_.insert(item);
958     }
959     if (IsNonRelativePosition(item->GetPositionType())) {
960         return;
961     }
962 
963     crossSize_ = std::max(crossSize_, GetCrossSize(item));
964     // Semi relative and variable allocatedSize is used for grid container.
965     if ((item->GetPositionType() == PositionType::SEMI_RELATIVE) &&
966         (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE)) {
967         allocatedSize_ = std::max(allocatedSize_, mainSize);
968         allocatedSize = mainSize;
969     } else {
970         allocatedSize_ += mainSize;
971         allocatedSize_ += space_;
972         allocatedSize += mainSize;
973         allocatedSize += space_;
974     }
975 }
976 
CheckSizeValidity(const RefPtr<RenderNode> & item)977 void RenderFlex::CheckSizeValidity(const RefPtr<RenderNode>& item)
978 {
979     if (item->IsIgnored() || IsNonRelativePosition(item->GetPositionType())) {
980         return;
981     }
982     if (!item->GetLayoutSize().IsValid()) {
983         auto flexItem = AceType::DynamicCast<RenderFlexItem>(item);
984         if (flexItem && flexItem->IsHidden()) {
985             return;
986         }
987     }
988     ++validSizeCount_;
989     displayNodes_.insert(item);
990 }
991 
GetAvailableMainSize()992 double RenderFlex::GetAvailableMainSize()
993 {
994     double maxMainSize = 0.0;
995     if (!isMainInfinite_ || !useViewPort_) {
996         maxMainSize = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE)
997                           ? GetLayoutParam().GetMaxSize().Width()
998                           : GetLayoutParam().GetMaxSize().Height();
999     } else {
1000         maxMainSize = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE)
1001                           ? viewPort_.Width()
1002                           : viewPort_.Height();
1003     }
1004     return maxMainSize;
1005 }
1006 
GetMainSize(const RefPtr<RenderNode> & item) const1007 double RenderFlex::GetMainSize(const RefPtr<RenderNode>& item) const
1008 {
1009     double size;
1010     if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
1011         size = item->GetLayoutSize().Width();
1012         if (item->GetPositionType() == PositionType::SEMI_RELATIVE) {
1013             Offset absoluteOffset = PositionLayoutUtils::GetAbsoluteOffset(Claim(const_cast<RenderFlex*>(this)), item);
1014             size += absoluteOffset.GetX();
1015         }
1016     } else {
1017         size = item->GetLayoutSize().Height();
1018     }
1019     return size;
1020 }
1021 
GetCrossSize(const RefPtr<RenderNode> & item) const1022 double RenderFlex::GetCrossSize(const RefPtr<RenderNode>& item) const
1023 {
1024     double size;
1025     if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
1026         size = item->GetLayoutSize().Height();
1027     } else {
1028         size = item->GetLayoutSize().Width();
1029         if (item->GetPositionType() == PositionType::SEMI_RELATIVE) {
1030             Offset absoluteOffset = PositionLayoutUtils::GetAbsoluteOffset(Claim(const_cast<RenderFlex*>(this)), item);
1031             size += absoluteOffset.GetX();
1032         }
1033     }
1034     return size;
1035 }
1036 
IsStartTopLeft(FlexDirection direction,TextDirection textDirection) const1037 bool RenderFlex::IsStartTopLeft(FlexDirection direction, TextDirection textDirection) const
1038 {
1039     switch (direction) {
1040         case FlexDirection::ROW:
1041             return textDirection == TextDirection::LTR;
1042         case FlexDirection::ROW_REVERSE:
1043             return textDirection == TextDirection::RTL;
1044         case FlexDirection::COLUMN:
1045             return true;
1046         case FlexDirection::COLUMN_REVERSE:
1047             return false;
1048         default:
1049             return true;
1050     }
1051 }
1052 
GetConstrainedSize(double mainSize)1053 Size RenderFlex::GetConstrainedSize(double mainSize)
1054 {
1055     if ((stretchToParent_ && crossAxisAlign_ == FlexAlign::STRETCH) || (crossAxisSize_ == CrossAxisSize::MAX)) {
1056         if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
1057             return GetLayoutParam().Constrain(Size(mainSize, GetLayoutParam().GetMaxSize().Height()));
1058         } else {
1059             return GetLayoutParam().Constrain(Size(GetLayoutParam().GetMaxSize().Width(), mainSize));
1060         }
1061     }
1062     if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
1063         return GetLayoutParam().Constrain(Size(mainSize, crossSize_));
1064     } else {
1065         return GetLayoutParam().Constrain(Size(crossSize_, mainSize));
1066     }
1067 }
1068 
GetSelfAlign(const RefPtr<RenderNode> & item) const1069 FlexAlign RenderFlex::GetSelfAlign(const RefPtr<RenderNode>& item) const
1070 {
1071     auto flexItem = AceType::DynamicCast<RenderFlexItem>(item);
1072     if (flexItem) {
1073         auto alignSelf = flexItem->GetAlignSelf();
1074         return alignSelf == FlexAlign::AUTO ? crossAxisAlign_ : alignSelf;
1075     }
1076     return crossAxisAlign_;
1077 }
1078 
AdjustTextDirectionByDir()1079 TextDirection RenderFlex::AdjustTextDirectionByDir()
1080 {
1081     auto textDir = GetTextDirection();
1082     if (direction_ == FlexDirection::ROW_REVERSE) {
1083         textDir = GetTextDirection() == TextDirection::RTL ? TextDirection::LTR : TextDirection::RTL;
1084     }
1085     return textDir;
1086 }
1087 
OnChildRemoved(const RefPtr<RenderNode> & child)1088 void RenderFlex::OnChildRemoved(const RefPtr<RenderNode>& child)
1089 {
1090     if (child) {
1091         child->SetAccessibilityVisible(false);
1092         child->ClearAccessibilityRect();
1093     }
1094     MarkNeedLayout();
1095 }
1096 
ClearRenderObject()1097 void RenderFlex::ClearRenderObject()
1098 {
1099     RenderNode::ClearRenderObject();
1100     direction_ = FlexDirection::ROW;
1101     mainAxisAlign_ = FlexAlign::FLEX_START;
1102     crossAxisAlign_ = FlexAlign::FLEX_START;
1103     mainAxisSize_ = MainAxisSize::MAX;
1104     crossAxisSize_ = CrossAxisSize::MIN;
1105     textBaseline_ = TextBaseline::ALPHABETIC;
1106     layoutMode_ = FlexLayoutMode::FLEX_ITEM_MODE;
1107     stretchToParent_ = false;
1108     mainSize_ = 0.0;
1109     crossSize_ = 0.0;
1110     allocatedSize_ = 0.0;
1111     infinityLayoutNodes_.clear();
1112     absoluteNodes_.clear();
1113     relativeNodes_.clear();
1114     magicNodes_.clear();
1115     magicWeightMaps_.clear();
1116     displayNodes_.clear();
1117     stretchNodes_.clear();
1118     scrollNode = nullptr;
1119     isMainInfinite_ = false;
1120     isCrossInfinite_ = false;
1121     useViewPort_ = false;
1122     containsNavigation_ = false;
1123     navigationMainSize_ = 0.0;
1124     validSizeCount_ = 0;
1125     totalFlexWeight_ = 0.0;
1126     maxDisplayIndex_ = 0;
1127     space_ = 0.0;
1128     alignPtr_ = nullptr;
1129 }
1130 
MaybeRelease()1131 bool RenderFlex::MaybeRelease()
1132 {
1133     auto context = GetContext().Upgrade();
1134     if (context && context->GetRenderFactory() && context->GetRenderFactory()->GetRenderFlexFactory()->Recycle(this)) {
1135         ClearRenderObject();
1136         return false;
1137     }
1138     return true;
1139 }
1140 
GetAlignDeclarationOffset(AlignDeclarationPtr alignDeclarationPtr,Offset & offset) const1141 bool RenderFlex::GetAlignDeclarationOffset(AlignDeclarationPtr alignDeclarationPtr, Offset& offset) const
1142 {
1143     if (alignPtr_ != alignDeclarationPtr) {
1144         return RenderNode::GetAlignDeclarationOffset(alignDeclarationPtr, offset);
1145     }
1146     if (alignDeclarationPtr->GetDeclarationType() == AlignDeclaration::DeclarationType::HORIZONTAL) {
1147         switch (alignDeclarationPtr->GetHorizontalAlign()) {
1148             case HorizontalAlign::START:
1149                 break;
1150             case HorizontalAlign::CENTER: {
1151                 offset = offset + Offset(GetLayoutSize().Width() / 2, 0);
1152                 break;
1153             }
1154             case HorizontalAlign::END: {
1155                 offset = offset + Offset(GetLayoutSize().Width(), 0);
1156                 break;
1157             }
1158         }
1159         offset.SetY(0.0);
1160     } else {
1161         switch (alignDeclarationPtr->GetVerticalAlign()) {
1162             case VerticalAlign::TOP:
1163                 break;
1164             case VerticalAlign::CENTER: {
1165                 offset = offset + Offset(0, GetLayoutSize().Height() / 2);
1166                 break;
1167             }
1168             case VerticalAlign::BOTTOM: {
1169                 offset = offset + Offset(0, GetLayoutSize().Height());
1170                 break;
1171             }
1172             case VerticalAlign::BASELINE:
1173             case VerticalAlign::NONE:
1174                 return false;
1175         }
1176         offset.SetX(0.0);
1177     }
1178     return true;
1179 }
1180 
PerformItemAlign(std::list<RefPtr<RenderNode>> & nodelist)1181 void RenderFlex::PerformItemAlign(std::list<RefPtr<RenderNode>>& nodelist)
1182 {
1183     auto item = nodelist.begin();
1184 
1185     while (item != nodelist.end()) {
1186         if (*item == AceType::Claim(this)) {
1187             nodelist.erase(item);
1188             return;
1189         }
1190         const RefPtr<RenderBox> box = AceType::DynamicCast<RenderBox>(*item);
1191         if (!box) {
1192             nodelist.clear();
1193             LOGE("PerformItemAlign error");
1194             return;
1195         }
1196         if (box->GetAlignDeclarationPtr() != alignPtr_) {
1197             item++;
1198             continue;
1199         }
1200         box->CalculateAlignDeclaration();
1201         item = nodelist.erase(item);
1202     }
1203 }
1204 
Dump()1205 void RenderFlex::Dump()
1206 {
1207     DumpLog::GetInstance().AddDesc(std::string("Direction: ")
1208                                        .append(std::to_string(static_cast<int32_t>(direction_)))
1209                                        .append(", Mode: ")
1210                                        .append(std::to_string(static_cast<int32_t>(layoutMode_)))
1211                                        .append(", MainAlign: ")
1212                                        .append(std::to_string(static_cast<int32_t>(mainAxisAlign_)))
1213                                        .append(", CrossAlign: ")
1214                                        .append(std::to_string(static_cast<int32_t>(crossAxisAlign_)))
1215                                        .append(", MainAxisSize: ")
1216                                        .append(std::to_string(static_cast<int32_t>(mainAxisSize_)))
1217                                        .append(", CrossAxisSize: ")
1218                                        .append(std::to_string(static_cast<int32_t>(crossAxisSize_))));
1219 }
1220 
CheckIfNeedLayoutAgain()1221 bool RenderFlex::CheckIfNeedLayoutAgain()
1222 {
1223     if (NeedLayout()) {
1224         return true;
1225     }
1226     return layoutMode_ != FlexLayoutMode::FLEX_WEIGHT_MODE;
1227 }
1228 
1229 } // namespace OHOS::Ace
1230