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