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