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