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