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