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