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