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