1 /*
2 * Copyright (c) 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_ng/pattern/flex/flex_layout_algorithm.h"
17
18 #include <algorithm>
19 #include <functional>
20 #include <iterator>
21
22 #include "base/geometry/axis.h"
23 #include "base/geometry/dimension.h"
24 #include "base/geometry/ng/offset_t.h"
25 #include "base/log/ace_trace.h"
26 #include "base/memory/ace_type.h"
27 #include "base/utils/utils.h"
28 #include "core/common/ace_application_info.h"
29 #include "core/common/container.h"
30 #include "core/components/common/layout/constants.h"
31 #include "core/components_ng/layout/layout_wrapper.h"
32 #include "core/components_ng/pattern/blank/blank_layout_property.h"
33 #include "core/components_ng/pattern/flex/flex_layout_property.h"
34 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
35 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
36 #include "core/components_ng/property/layout_constraint.h"
37 #include "core/components_ng/property/measure_property.h"
38 #include "core/components_ng/property/measure_utils.h"
39 #include "core/components_v2/inspector/inspector_constants.h"
40
41 namespace OHOS::Ace::NG {
42
43 namespace {
44 /**
45 * Get the main axis direction based on direction.
46 */
FlipAxis(FlexDirection direction)47 FlexDirection FlipAxis(FlexDirection direction)
48 {
49 if (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
50 return FlexDirection::COLUMN;
51 }
52 return FlexDirection::ROW;
53 }
54
55 /**
56 * Determine whether to start the layout from the upper left corner
57 */
IsStartTopLeft(FlexDirection direction,TextDirection textDirection)58 bool IsStartTopLeft(FlexDirection direction, TextDirection textDirection)
59 {
60 switch (direction) {
61 case FlexDirection::ROW:
62 return textDirection == TextDirection::LTR;
63 case FlexDirection::ROW_REVERSE:
64 return textDirection == TextDirection::RTL;
65 case FlexDirection::COLUMN:
66 return true;
67 case FlexDirection::COLUMN_REVERSE:
68 return false;
69 default:
70 return true;
71 }
72 }
73
ReverseFlexDirection(FlexDirection direction)74 FlexDirection ReverseFlexDirection(FlexDirection direction)
75 {
76 switch (direction) {
77 case FlexDirection::ROW:
78 return FlexDirection::ROW_REVERSE;
79 case FlexDirection::ROW_REVERSE:
80 return FlexDirection::ROW;
81 case FlexDirection::COLUMN:
82 return FlexDirection::COLUMN_REVERSE;
83 case FlexDirection::COLUMN_REVERSE:
84 return FlexDirection::COLUMN;
85 default:
86 return FlexDirection::ROW;
87 }
88 }
89
GetCrossAxisSizeHelper(const SizeF & size,FlexDirection direction)90 float GetCrossAxisSizeHelper(const SizeF& size, FlexDirection direction)
91 {
92 if (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
93 return size.Height();
94 }
95 return size.Width();
96 }
97
GetMainAxisSizeHelper(const SizeF & size,FlexDirection direction)98 float GetMainAxisSizeHelper(const SizeF& size, FlexDirection direction)
99 {
100 if (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
101 return size.Width();
102 }
103 return size.Height();
104 }
105
GetCalcSizeHelper(float mainAxisSize,float crossAxisSize,FlexDirection direction)106 OptionalSizeF GetCalcSizeHelper(float mainAxisSize, float crossAxisSize, FlexDirection direction)
107 {
108 OptionalSizeF size;
109 if (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
110 size.SetWidth(mainAxisSize);
111 size.SetHeight(crossAxisSize);
112 } else {
113 size.SetHeight(mainAxisSize);
114 size.SetWidth(crossAxisSize);
115 }
116 return size;
117 }
118
IsHorizontal(FlexDirection direction)119 bool IsHorizontal(FlexDirection direction)
120 {
121 return direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE;
122 }
123
UpdateChildLayoutConstrainByFlexBasis(FlexDirection direction,const RefPtr<LayoutWrapper> & child,LayoutConstraintF & layoutConstraint)124 void UpdateChildLayoutConstrainByFlexBasis(
125 FlexDirection direction, const RefPtr<LayoutWrapper>& child, LayoutConstraintF& layoutConstraint)
126 {
127 const auto& flexItemProperty = child->GetLayoutProperty()->GetFlexItemProperty();
128 CHECK_NULL_VOID(flexItemProperty);
129 const auto& flexBasis = flexItemProperty->GetFlexBasis();
130 CHECK_NULL_VOID(flexBasis);
131 if (flexBasis->Unit() == DimensionUnit::AUTO || !flexBasis->IsValid()) {
132 return;
133 }
134 if (child->GetLayoutProperty()->GetCalcLayoutConstraint()) {
135 auto selfIdealSize = child->GetLayoutProperty()->GetCalcLayoutConstraint()->selfIdealSize;
136 if (child->GetHostTag() == V2::BLANK_ETS_TAG && selfIdealSize.has_value()) {
137 if (IsHorizontal(direction) && selfIdealSize->Width().has_value() &&
138 selfIdealSize->Width()->GetDimension().ConvertToPx() > flexBasis->ConvertToPx()) {
139 return;
140 } else if (!IsHorizontal(direction) && selfIdealSize->Height().has_value() &&
141 selfIdealSize->Height()->GetDimension().ConvertToPx() > flexBasis->ConvertToPx()) {
142 return;
143 }
144 }
145 }
146 if (IsHorizontal(direction)) {
147 layoutConstraint.selfIdealSize.SetWidth(flexBasis->ConvertToPx());
148 } else {
149 layoutConstraint.selfIdealSize.SetHeight(flexBasis->ConvertToPx());
150 }
151 }
152
GetMainAxisMargin(const RefPtr<LayoutWrapper> & child,FlexDirection direction)153 float GetMainAxisMargin(const RefPtr<LayoutWrapper>& child, FlexDirection direction)
154 {
155 float childMainAxisMargin = 0.0f;
156 if (child && child->GetGeometryNode() && child->GetGeometryNode()->GetMargin()) {
157 childMainAxisMargin = GetMainAxisSizeHelper(child->GetGeometryNode()->GetMargin()->Size(), direction);
158 }
159 return childMainAxisMargin;
160 }
161
IsVisibleGone(const RefPtr<LayoutWrapper> & layoutWrapper)162 bool IsVisibleGone(const RefPtr<LayoutWrapper>& layoutWrapper)
163 {
164 return layoutWrapper && layoutWrapper->GetHostNode() && layoutWrapper->GetHostNode()->GetLayoutProperty() &&
165 layoutWrapper->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) ==
166 VisibleType::GONE;
167 }
168
169 const float HALF = 0.5f;
170
171 } // namespace
172
GetChildMainAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const173 float FlexLayoutAlgorithm::GetChildMainAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
174 {
175 float size = 0.0f;
176 CHECK_NULL_RETURN(layoutWrapper, size);
177 return GetMainAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetMarginFrameSize(), direction_);
178 }
179
GetChildCrossAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const180 float FlexLayoutAlgorithm::GetChildCrossAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
181 {
182 CHECK_NULL_RETURN(layoutWrapper, 0.0f);
183 return GetCrossAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetMarginFrameSize(), direction_);
184 }
185
GetSelfCrossAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const186 float FlexLayoutAlgorithm::GetSelfCrossAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
187 {
188 CHECK_NULL_RETURN(layoutWrapper, 0.0f);
189 return GetCrossAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetFrameSize(), direction_);
190 }
191
CheckSizeValidity(const RefPtr<LayoutWrapper> & layoutWrapper)192 void FlexLayoutAlgorithm::CheckSizeValidity(const RefPtr<LayoutWrapper>& layoutWrapper)
193 {
194 if (IsVisibleGone(layoutWrapper)) {
195 return;
196 }
197 ++validSizeCount_;
198 }
199
200 /**
201 * Check and record baseline distance.
202 */
CheckBaselineProperties(const RefPtr<LayoutWrapper> & layoutWrapper)203 void FlexLayoutAlgorithm::CheckBaselineProperties(const RefPtr<LayoutWrapper>& layoutWrapper)
204 {
205 if (crossAxisAlign_ != FlexAlign::BASELINE && !childrenHasAlignSelfBaseLine_) {
206 return;
207 }
208 float distance = layoutWrapper->GetBaselineDistance();
209 baselineProperties_.maxBaselineDistance = std::max(baselineProperties_.maxBaselineDistance, distance);
210 baselineProperties_.maxDistanceAboveBaseline = std::max(baselineProperties_.maxDistanceAboveBaseline, distance);
211 baselineProperties_.maxDistanceBelowBaseline =
212 std::max(baselineProperties_.maxDistanceBelowBaseline, GetSelfCrossAxisSize(layoutWrapper) - distance);
213 if (crossAxisAlign_ == FlexAlign::BASELINE) {
214 crossAxisSize_ = baselineProperties_.maxDistanceAboveBaseline + baselineProperties_.maxDistanceBelowBaseline;
215 }
216 }
217
218 /**
219 * Initialize the FlexLayoutAlgorithm property.
220 */
InitFlexProperties(LayoutWrapper * layoutWrapper)221 void FlexLayoutAlgorithm::InitFlexProperties(LayoutWrapper* layoutWrapper)
222 {
223 mainAxisSize_ = 0.0f;
224 crossAxisSize_ = 0.0f;
225 allocatedSize_ = 0.0f;
226 selfIdealCrossAxisSize_ = -1.0f;
227 validSizeCount_ = 0;
228 realSize_.Reset();
229 isInfiniteLayout_ = false;
230 selfAdaptive_ = false;
231 auto layoutProperty = AceType::DynamicCast<FlexLayoutProperty>(layoutWrapper->GetLayoutProperty());
232 CHECK_NULL_VOID(layoutProperty);
233 space_ = static_cast<float>(layoutProperty->GetSpaceValue({}).ConvertToPx());
234 direction_ = layoutProperty->GetFlexDirection().value_or(FlexDirection::ROW);
235 mainAxisAlign_ = layoutProperty->GetMainAxisAlignValue(FlexAlign::FLEX_START);
236 secondaryMeasureList_.clear();
237 crossAxisAlign_ =
238 layoutProperty->GetCrossAxisAlignValue(isLinearLayoutFeature_ ? FlexAlign::CENTER : FlexAlign::FLEX_START);
239 baselineProperties_.Reset();
240 textDir_ = layoutProperty->GetLayoutDirection();
241 if (textDir_ == TextDirection::AUTO) {
242 textDir_ = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
243 }
244 /**
245 * FlexLayoutAlgorithm, as the parent class, should not handle the special logic of the subclass
246 * LinearLayout.
247 */
248 if (isLinearLayoutFeature_) {
249 bool isVertical = DynamicCast<LinearLayoutProperty>(layoutWrapper->GetLayoutProperty())->IsVertical();
250 direction_ = isVertical ? FlexDirection::COLUMN : FlexDirection::ROW;
251 }
252 }
253
AddElementIntoMagicNodes(int32_t childDisplayPriority,MagicLayoutNode node,float childLayoutWeight)254 void FlexLayoutAlgorithm::AddElementIntoMagicNodes(
255 int32_t childDisplayPriority, MagicLayoutNode node, float childLayoutWeight)
256 {
257 auto iter = magicNodes_.find(childDisplayPriority);
258 /**
259 * if current childDisplayPriority is not a key of magicNodes_, create a key and add current node into its value
260 * list.
261 */
262 if (iter == magicNodes_.end()) {
263 magicNodes_.insert(std::map<int32_t, std::list<MagicLayoutNode>>::value_type(childDisplayPriority, { node }));
264 if (GreatNotEqual(childLayoutWeight, 0.0f)) {
265 magicNodeWeights_.insert(std::map<int32_t, float>::value_type(childDisplayPriority, childLayoutWeight));
266 }
267 return;
268 }
269 iter->second.emplace_back(node);
270 if (GreatNotEqual(childLayoutWeight, 0.0f)) {
271 magicNodeWeights_[childDisplayPriority] += childLayoutWeight;
272 }
273 }
274
TravelChildrenFlexProps(LayoutWrapper * layoutWrapper)275 void FlexLayoutAlgorithm::TravelChildrenFlexProps(LayoutWrapper* layoutWrapper)
276 {
277 maxDisplayPriority_ = 0;
278 totalFlexWeight_ = 0.0f;
279 outOfLayoutChildren_.clear();
280 layoutPolicyChildren_.clear();
281 magicNodes_.clear();
282 magicNodeWeights_.clear();
283 childrenHasAlignSelfBaseLine_ = false;
284 const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
285 const auto& children = layoutWrapper->GetAllChildrenWithBuild();
286 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
287 for (const auto& child : children) {
288 bool checkNeedSkip = false;
289 if (child->GetHostTag() == V2::COLUMN_ETS_TAG || child->GetHostTag() == V2::ROW_ETS_TAG) {
290 checkNeedSkip = AddElementIntoLayoutPolicyChildren(layoutWrapper, child);
291 }
292 if (child->IsOutOfLayout()) {
293 outOfLayoutChildren_.emplace_back(child);
294 checkNeedSkip = true;
295 }
296 if (checkNeedSkip) {
297 continue;
298 }
299 const auto& childLayoutProperty = child->GetLayoutProperty();
300 const auto& childMagicItemProperty = childLayoutProperty->GetMagicItemProperty();
301 const auto& childFlexItemProperty = childLayoutProperty->GetFlexItemProperty();
302 MagicLayoutNode node;
303 node.layoutWrapper = child;
304 node.layoutConstraint = childLayoutConstraint;
305
306 bool childGone = IsVisibleGone(child);
307 int32_t childDisplayPriority = 1;
308 float childLayoutWeight = 0.0f;
309 if (childGone) {
310 AddElementIntoMagicNodes(childDisplayPriority, node, childLayoutWeight);
311 continue;
312 }
313 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
314 if (childFlexItemProperty) {
315 childDisplayPriority = childFlexItemProperty->GetDisplayIndex().value_or(1);
316 if (!childrenHasAlignSelfBaseLine_ &&
317 childFlexItemProperty->GetAlignSelf().value_or(FlexAlign::FLEX_START) == FlexAlign::BASELINE) {
318 childrenHasAlignSelfBaseLine_ = true;
319 }
320 }
321 AddElementIntoMagicNodes(childDisplayPriority, node, childLayoutWeight);
322 totalFlexWeight_ += GreatNotEqual(childLayoutWeight, 0.0f) ? childLayoutWeight : 0.0f;
323 maxDisplayPriority_ = std::max(childDisplayPriority, maxDisplayPriority_);
324 }
325 }
326
AddElementIntoLayoutPolicyChildren(LayoutWrapper * layoutWrapper,RefPtr<LayoutWrapper> child)327 bool FlexLayoutAlgorithm::AddElementIntoLayoutPolicyChildren(LayoutWrapper* layoutWrapper, RefPtr<LayoutWrapper> child)
328 {
329 CHECK_NULL_RETURN(layoutWrapper, false);
330 CHECK_NULL_RETURN(child, false);
331 auto childLayoutProperty = AceType::DynamicCast<FlexLayoutProperty>(child->GetLayoutProperty());
332 CHECK_NULL_RETURN(childLayoutProperty, false);
333 auto widthLayoutPolicy = childLayoutProperty->GetWidthLayoutPolicy();
334 auto heightLayoutPolicy = childLayoutProperty->GetHeightLayoutPolicy();
335 if (widthLayoutPolicy.value_or(static_cast<uint8_t>(LayoutCalPolicy::NO_MATCH)) ==
336 static_cast<uint8_t>(LayoutCalPolicy::NO_MATCH) &&
337 heightLayoutPolicy.value_or(static_cast<uint8_t>(LayoutCalPolicy::NO_MATCH)) ==
338 static_cast<uint8_t>(LayoutCalPolicy::NO_MATCH)) {
339 return false;
340 }
341 layoutPolicyChildren_.emplace_back(child);
342 return true;
343 }
344
UpdateAllocatedSize(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & crossAxisSize)345 void FlexLayoutAlgorithm::UpdateAllocatedSize(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& crossAxisSize)
346 {
347 float mainAxisSize = GetChildMainAxisSize(childLayoutWrapper);
348 if (GreaterOrEqualToInfinity(mainAxisSize)) {
349 mainAxisSize = 0.0f;
350 }
351 crossAxisSize = std::max(crossAxisSize, GetChildCrossAxisSize(childLayoutWrapper));
352 allocatedSize_ += mainAxisSize;
353 allocatedSize_ += space_;
354 }
355
MeasureOutOfLayoutChildren(LayoutWrapper * layoutWrapper)356 void FlexLayoutAlgorithm::MeasureOutOfLayoutChildren(LayoutWrapper* layoutWrapper)
357 {
358 const auto& layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
359 for (const auto& child : outOfLayoutChildren_) {
360 child->Measure(layoutConstraint);
361 }
362 }
363
MeasureAdaptiveLayoutChildren(LayoutWrapper * layoutWrapper,const SizeF & realSize)364 void FlexLayoutAlgorithm::MeasureAdaptiveLayoutChildren(LayoutWrapper* layoutWrapper, const SizeF& realSize)
365 {
366 auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
367 layoutConstraint.parentIdealSize.SetSize(realSize);
368 for (const auto& child : layoutPolicyChildren_) {
369 child->Measure(layoutConstraint);
370 auto geometryNode = child->GetGeometryNode();
371 CHECK_NULL_CONTINUE(geometryNode);
372 auto childLayoutProperty = AceType::DynamicCast<FlexLayoutProperty>(child->GetLayoutProperty());
373 CHECK_NULL_CONTINUE(childLayoutProperty);
374 auto widthLayoutPolicy = childLayoutProperty->GetWidthLayoutPolicy();
375 auto heightLayoutPolicy = childLayoutProperty->GetHeightLayoutPolicy();
376 if (widthLayoutPolicy.value_or(static_cast<uint8_t>(LayoutCalPolicy::NO_MATCH)) ==
377 static_cast<uint8_t>(LayoutCalPolicy::MATCH_PARENT)) {
378 geometryNode->SetFrameWidth(realSize.Width());
379 }
380 if (heightLayoutPolicy.value_or(static_cast<uint8_t>(LayoutCalPolicy::NO_MATCH)) ==
381 static_cast<uint8_t>(LayoutCalPolicy::MATCH_PARENT)) {
382 geometryNode->SetFrameHeight(realSize.Height());
383 }
384 }
385 }
386
FirstMeasureInWeightMode()387 std::map<int32_t, std::list<MagicLayoutNode>>::reverse_iterator FlexLayoutAlgorithm::FirstMeasureInWeightMode()
388 {
389 auto firstLoopIter = magicNodes_.rbegin();
390 auto loopIter = firstLoopIter;
391 bool outOfDisplay = false;
392 while (loopIter != magicNodes_.rend()) {
393 auto& childList = loopIter->second;
394 float crossAxisSize = crossAxisSize_;
395 for (auto& child : childList) {
396 if (outOfDisplay) {
397 child.layoutWrapper->SetActive(false);
398 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
399 continue;
400 }
401 const auto& childLayoutWrapper = child.layoutWrapper;
402 float childLayoutWeight = 0.0f;
403 const auto& childMagicItemProperty = childLayoutWrapper->GetLayoutProperty()->GetMagicItemProperty();
404 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
405 if (GreatNotEqual(childLayoutWeight, 0.0f)) {
406 allocatedSize_ += space_;
407 continue;
408 }
409 if (IsVisibleGone(child.layoutWrapper)) {
410 continue;
411 }
412 childLayoutWrapper->Measure(child.layoutConstraint);
413 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize);
414 CheckSizeValidity(childLayoutWrapper);
415 CheckBaselineProperties(childLayoutWrapper);
416 }
417 if (outOfDisplay) {
418 ++loopIter;
419 continue;
420 }
421 if (!(allocatedSize_ - space_ > mainAxisSize_ && magicNodes_.size() > 1)) {
422 crossAxisSize_ = crossAxisSize;
423 firstLoopIter = ++loopIter;
424 continue;
425 }
426 /**
427 * The main axis size of the element with layoutWeight of 0 is larger than the Flex main axis size
428 */
429 for (const auto& child : childList) {
430 allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper);
431 allocatedSize_ -= space_;
432 child.layoutWrapper->SetActive(false);
433 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
434 }
435 outOfDisplay = true;
436 firstLoopIter = loopIter++;
437 }
438 return firstLoopIter;
439 }
440
SecondMeasureInWeightMode(std::map<int32_t,std::list<MagicLayoutNode>>::reverse_iterator firstLoopIter)441 void FlexLayoutAlgorithm::SecondMeasureInWeightMode(
442 std::map<int32_t, std::list<MagicLayoutNode>>::reverse_iterator firstLoopIter)
443 {
444 auto newTotalFlexWeight = totalFlexWeight_;
445 allocatedSize_ -= space_;
446 auto remainedMainAxisSize = mainAxisSize_ - allocatedSize_;
447 auto spacePerWeight = remainedMainAxisSize / newTotalFlexWeight;
448 auto secondIterLoop = magicNodes_.rbegin();
449 while (secondIterLoop != firstLoopIter) {
450 auto& childList = secondIterLoop->second;
451 bool isExceed = false;
452 for (auto& child : childList) {
453 auto childLayoutWrapper = child.layoutWrapper;
454 auto& childConstraint = child.layoutConstraint;
455 float childLayoutWeight = 0.0f;
456 const auto& childMagicItemProperty = childLayoutWrapper->GetLayoutProperty()->GetMagicItemProperty();
457 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
458 if (LessOrEqual(childLayoutWeight, 0.0)) {
459 continue;
460 }
461 float childCalcSize = std::max(spacePerWeight * childLayoutWeight, 0.0f);
462 if (GetMainAxisSizeHelper(childConstraint.minSize, direction_) > childCalcSize) {
463 isExceed = true;
464 }
465 UpdateLayoutConstraintOnMainAxis(childConstraint, childCalcSize);
466 }
467 if (isExceed) {
468 if (magicNodes_.size() <= 1) {
469 break;
470 }
471 isExceed = true;
472 auto& lowPriorityChildList = magicNodes_.begin()->second;
473 for (const auto& child : lowPriorityChildList) {
474 allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper);
475 allocatedSize_ -= space_;
476 child.layoutWrapper->SetActive(false);
477 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
478 }
479 newTotalFlexWeight -= magicNodeWeights_[magicNodes_.begin()->first];
480 remainedMainAxisSize = mainAxisSize_ - allocatedSize_;
481 spacePerWeight = remainedMainAxisSize / newTotalFlexWeight;
482 isExceed = false;
483 magicNodes_.erase(magicNodes_.begin());
484 secondIterLoop = magicNodes_.rbegin();
485 } else {
486 secondIterLoop++;
487 }
488 }
489 }
490
FinalMeasureInWeightMode()491 void FlexLayoutAlgorithm::FinalMeasureInWeightMode()
492 {
493 auto iter = magicNodes_.rbegin();
494 while (iter != magicNodes_.rend()) {
495 auto& childList = iter->second;
496 for (auto& child : childList) {
497 auto childLayoutWrapper = child.layoutWrapper;
498 if (!childLayoutWrapper->IsActive()) {
499 continue;
500 }
501 float childLayoutWeight = 0.0f;
502 const auto& childMagicItemProperty = childLayoutWrapper->GetLayoutProperty()->GetMagicItemProperty();
503 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
504 secondaryMeasureList_.emplace_back(child);
505 if (LessOrEqual(childLayoutWeight, 0.0)) {
506 continue;
507 }
508 childLayoutWrapper->Measure(child.layoutConstraint);
509 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
510 CheckSizeValidity(childLayoutWrapper);
511 CheckBaselineProperties(childLayoutWrapper);
512 }
513 iter++;
514 }
515 }
516
MeasureInPriorityMode(FlexItemProperties & flexItemProperties)517 void FlexLayoutAlgorithm::MeasureInPriorityMode(FlexItemProperties& flexItemProperties)
518 {
519 bool outOfDisplay = false;
520 auto iter = magicNodes_.rbegin();
521 while (iter != magicNodes_.rend()) {
522 auto childList = iter->second;
523 if (outOfDisplay) {
524 for (auto& child : childList) {
525 const auto& childLayoutWrapper = child.layoutWrapper;
526 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, child.layoutConstraint);
527 child.layoutWrapper->ApplyConstraintWithoutMeasure(child.layoutConstraint);
528 child.layoutWrapper->SetActive(false);
529 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
530 }
531 ++iter;
532 continue;
533 }
534 float crossAxisSize = crossAxisSize_;
535 for (auto& child : childList) {
536 const auto& childLayoutWrapper = child.layoutWrapper;
537 childLayoutWrapper->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
538 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, child.layoutConstraint);
539 childLayoutWrapper->Measure(child.layoutConstraint);
540 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize);
541 CheckSizeValidity(childLayoutWrapper);
542 CheckBaselineProperties(childLayoutWrapper);
543 const auto& flexItemProperty = childLayoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
544 if (flexItemProperty && GreatNotEqual(flexItemProperty->GetFlexGrow().value_or(0.0f), 0.0f)) {
545 flexItemProperties.totalGrow += flexItemProperty->GetFlexGrow().value_or(0.0f);
546 }
547 secondaryMeasureList_.emplace_back(child);
548 }
549 if (LessOrEqual(allocatedSize_ - space_, mainAxisSize_)) {
550 crossAxisSize_ = crossAxisSize;
551 ++iter;
552 continue;
553 }
554 outOfDisplay = true;
555 for (auto& child : childList) {
556 allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper) + space_;
557 child.layoutWrapper->SetActive(false);
558 --validSizeCount_;
559 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
560 const auto& flexItemProperty = child.layoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
561 if (flexItemProperty && GreatNotEqual(flexItemProperty->GetFlexGrow().value_or(0.0f), 0.0f)) {
562 flexItemProperties.totalGrow -= flexItemProperty->GetFlexGrow().value_or(0.0f);
563 }
564 secondaryMeasureList_.pop_back();
565 }
566 ++iter;
567 }
568 }
569
MeasureAndCleanMagicNodes(LayoutWrapper * containerLayoutWrapper,FlexItemProperties & flexItemProperties)570 void FlexLayoutAlgorithm::MeasureAndCleanMagicNodes(
571 LayoutWrapper* containerLayoutWrapper, FlexItemProperties& flexItemProperties)
572 {
573 if (GreatNotEqual(totalFlexWeight_, 0.0f)) {
574 /**
575 * The child elements with layoutWeight=0 are measured first.
576 * Then, measure the sub elements of layoutWeight>1 based on the remaining space.
577 * If the total main axis size of the element is larger than the main axis size of Flex, the lower priority
578 * element will be deleted.
579 */
580 auto firstLoopIter = FirstMeasureInWeightMode();
581 SecondMeasureInWeightMode(firstLoopIter);
582 FinalMeasureInWeightMode();
583 } else if (GreatNotEqual(maxDisplayPriority_, 1) && !isInfiniteLayout_) {
584 MeasureInPriorityMode(flexItemProperties);
585 } else {
586 auto magicNodeSize = magicNodes_.size();
587 auto iter = magicNodes_.rbegin();
588 while (iter != magicNodes_.rend()) {
589 auto childList = iter->second;
590 for (auto& child : childList) {
591 if (HandleBlankFirstTimeMeasure(child, flexItemProperties)) {
592 continue;
593 }
594 const auto& childLayoutWrapper = child.layoutWrapper;
595 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, child.layoutConstraint);
596 childLayoutWrapper->Measure(child.layoutConstraint);
597 if (IsVisibleGone(child.layoutWrapper)) {
598 continue;
599 }
600 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
601 CheckSizeValidity(childLayoutWrapper);
602 CheckBaselineProperties(childLayoutWrapper);
603 if (!isInfiniteLayout_ || GreatNotEqual(MainAxisMinValue(containerLayoutWrapper), 0.0f)) {
604 UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
605 }
606 secondaryMeasureList_.emplace_back(child);
607 }
608 if (magicNodeSize != magicNodes_.size()) {
609 LOGE("magicNodes changed during use. oldsize: %{public}zu ,newsize: %{public}zu ",
610 magicNodeSize, magicNodes_.size());
611 break;
612 }
613 ++iter;
614 }
615 allocatedSize_ -= space_;
616 }
617 }
618
HandleBlankFirstTimeMeasure(const MagicLayoutNode & child,FlexItemProperties & flexItemProperties)619 bool FlexLayoutAlgorithm::HandleBlankFirstTimeMeasure(
620 const MagicLayoutNode& child, FlexItemProperties& flexItemProperties)
621 {
622 const auto& childLayoutWrapper = child.layoutWrapper;
623 if (!(childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG &&
624 Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN))) {
625 return false;
626 }
627
628 // if constainer is self adaptive, secondaryMeasure won't happen, blank can call Measure directly
629 if (selfAdaptive_ || isInfiniteLayout_) {
630 childLayoutWrapper->Measure(child.layoutConstraint);
631 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
632 CheckSizeValidity(childLayoutWrapper);
633 if (!isInfiniteLayout_) {
634 UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
635 }
636 secondaryMeasureList_.emplace_back(child);
637 return true;
638 }
639 // to make blank components splilt remain space(not selfAdaptive)
640 // min size should not participate in the first measure of blank
641 auto mainAxisSize = 0.0f;
642 auto crossAxisSize = 0.0f;
643 auto blankLayoutProperty = childLayoutWrapper->GetLayoutProperty();
644 childLayoutWrapper->GetHostNode()->GetPattern()->BeforeCreateLayoutWrapper();
645 if (blankLayoutProperty) {
646 const auto& calcConstraint = blankLayoutProperty->GetCalcLayoutConstraint();
647 if (calcConstraint && calcConstraint->selfIdealSize.has_value()) {
648 auto size = ConvertToSize(calcConstraint->selfIdealSize.value(), child.layoutConstraint.scaleProperty,
649 child.layoutConstraint.percentReference);
650 mainAxisSize = std::max(IsHorizontal(direction_) ? size.Width() : size.Height(), 0.0f);
651 crossAxisSize = std::max(IsHorizontal(direction_) ? size.Height() : size.Width(), 0.0f);
652 }
653 }
654 childLayoutWrapper->GetGeometryNode()->SetFrameSize(
655 IsHorizontal(direction_) ? SizeF(mainAxisSize, crossAxisSize) : SizeF(crossAxisSize, mainAxisSize));
656 secondaryMeasureList_.emplace_back(child);
657 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
658 CheckSizeValidity(childLayoutWrapper);
659 UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
660 return true;
661 }
662
UpdateFlexProperties(FlexItemProperties & flexItemProperties,const RefPtr<LayoutWrapper> & layoutWrapper)663 void FlexLayoutAlgorithm::UpdateFlexProperties(
664 FlexItemProperties& flexItemProperties, const RefPtr<LayoutWrapper>& layoutWrapper)
665 {
666 const auto& flexItemProperty = layoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
667 float flexShrink = isLinearLayoutFeature_ ? 0.0f : 1.0f;
668 float flexGrow = 0.0f;
669 if (flexItemProperty) {
670 flexShrink = flexItemProperty->GetFlexShrink().value_or(flexShrink);
671 flexGrow = flexItemProperty->GetFlexGrow().value_or(flexGrow);
672 }
673 flexItemProperties.totalGrow += flexGrow;
674 flexItemProperties.totalShrink +=
675 (flexShrink * (GetChildMainAxisSize(layoutWrapper) - GetMainAxisMargin(layoutWrapper, direction_)));
676 }
677
SecondMeasureInGrowOrShrink()678 void FlexLayoutAlgorithm::SecondMeasureInGrowOrShrink()
679 {
680 // child need to second show
681 int32_t childMeasureCount = 0;
682 auto iter = secondaryMeasureList_.rbegin();
683 while (iter != secondaryMeasureList_.rend()) {
684 auto child = *iter;
685 auto childLayoutWrapper = child.layoutWrapper;
686 if (!child.needSecondMeasure || !childLayoutWrapper->IsActive()) {
687 ++iter;
688 continue;
689 }
690 childLayoutWrapper->Measure(child.layoutConstraint);
691 crossAxisSize_ = std::max(crossAxisSize_, GetChildCrossAxisSize(childLayoutWrapper));
692 CheckBaselineProperties(child.layoutWrapper);
693 ++iter;
694 ++childMeasureCount;
695 }
696 // if child has secondary measure, calculate crossAxis again
697 if (childMeasureCount) {
698 float childMaxHeight = -1.0f;
699 iter = secondaryMeasureList_.rbegin();
700 while (iter != secondaryMeasureList_.rend()) {
701 auto child = *iter;
702 auto childLayoutWrapper = child.layoutWrapper;
703 childMaxHeight = std::max(GetChildCrossAxisSize(childLayoutWrapper), childMaxHeight);
704 ++iter;
705 }
706 if (GreatNotEqual(childMaxHeight, 0.0f)) {
707 crossAxisSize_ = childMaxHeight;
708 }
709 }
710 }
711
SecondaryMeasureByProperty(FlexItemProperties & flexItemProperties,LayoutWrapper * layoutWrapper)712 void FlexLayoutAlgorithm::SecondaryMeasureByProperty(
713 FlexItemProperties& flexItemProperties, LayoutWrapper* layoutWrapper)
714 {
715 float remainSpace = mainAxisSize_ - allocatedSize_;
716 float spacePerFlex = 0;
717 float allocatedFlexSpace = 0;
718 std::function<float(const RefPtr<LayoutWrapper>&)> getFlex;
719 RefPtr<LayoutWrapper> lastChild;
720 /**
721 * get the real cross axis size.
722 */
723 auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
724 auto paddingLeft = padding.left.value_or(0.0f);
725 auto paddingRight = padding.right.value_or(0.0f);
726 auto paddingTop = padding.top.value_or(0.0f);
727 auto paddingBottom = padding.bottom.value_or(0.0f);
728 auto crossAxisSize = crossAxisSize_;
729 if (NonNegative(selfIdealCrossAxisSize_)) {
730 if (IsHorizontal(direction_)) {
731 crossAxisSize = selfIdealCrossAxisSize_ - paddingTop - paddingBottom;
732 } else {
733 crossAxisSize = selfIdealCrossAxisSize_ - paddingLeft - paddingRight;
734 }
735 }
736 if (Negative(crossAxisSize)) {
737 crossAxisSize = 0.0f;
738 }
739 // calculate child
740 auto iter = secondaryMeasureList_.rbegin();
741 bool needSecondMeasure = true;
742 float reserveMainAxisSize = 0.0f;
743 while (needSecondMeasure) {
744 needSecondMeasure = false;
745 // when a child's flexSize equal 0, allocatedSize need to minus its MainAxisSize
746 allocatedSize_ -= reserveMainAxisSize;
747 reserveMainAxisSize = 0.0f;
748 remainSpace = mainAxisSize_ - allocatedSize_;
749
750 iter = secondaryMeasureList_.rbegin();
751 while (iter != secondaryMeasureList_.rend()) {
752 if (!(*iter).layoutWrapper->IsActive()) {
753 remainSpace += space_;
754 }
755 ++iter;
756 }
757 CheckIsGrowOrShrink(getFlex, remainSpace, spacePerFlex, flexItemProperties, lastChild);
758 iter = secondaryMeasureList_.rbegin();
759 while (iter != secondaryMeasureList_.rend()) {
760 auto& child = *iter;
761 auto childLayoutWrapper = child.layoutWrapper;
762 if (!childLayoutWrapper) {
763 continue;
764 }
765 if (GetSelfAlign(childLayoutWrapper) == FlexAlign::STRETCH) {
766 UpdateLayoutConstraintOnCrossAxis(child.layoutConstraint, crossAxisSize);
767 child.needSecondMeasure = true;
768 }
769 if (LessOrEqual(totalFlexWeight_, 0.0f) &&
770 (!isInfiniteLayout_ || GreatNotEqual(MainAxisMinValue(layoutWrapper), 0.0f) ||
771 (childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG && !selfAdaptive_ &&
772 Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)))) {
773 if (child.needKeepMinCalcSize) {
774 ++iter;
775 continue;
776 }
777 float childMainAxisMargin = GetMainAxisMargin(childLayoutWrapper, direction_);
778 float itemFlex = getFlex(child.layoutWrapper);
779 float flexSize =
780 (child.layoutWrapper == lastChild) ? (remainSpace - allocatedFlexSpace)
781 : GreatOrEqual(remainSpace, 0.0f) || GreatNotEqual(maxDisplayPriority_, 1)
782 ? spacePerFlex * itemFlex
783 : spacePerFlex * itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
784 if (!NearZero(flexSize) && childLayoutWrapper->IsActive()) {
785 flexSize += GetChildMainAxisSize(childLayoutWrapper);
786 child.needSecondMeasure = true;
787 CheckBlankAndKeepMin(childLayoutWrapper, flexSize);
788 if (LessOrEqual(flexSize, 0.0f)) {
789 child.layoutWrapper->SetActive(false);
790 flexItemProperties.totalShrink -=
791 itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
792 reserveMainAxisSize += GetChildMainAxisSize(childLayoutWrapper);
793 needSecondMeasure = true;
794 UpdateLayoutConstraintOnMainAxis(child.layoutConstraint, 0.0f);
795 break;
796 }
797 if (IsKeepMinSize(childLayoutWrapper, flexSize)) {
798 needSecondMeasure = true;
799 auto shrinkSize = itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
800 reserveMainAxisSize -= (flexSize - shrinkSize);
801 child.needKeepMinCalcSize = true;
802 flexItemProperties.totalShrink -= shrinkSize;
803 }
804 UpdateLayoutConstraintOnMainAxis(child.layoutConstraint, flexSize);
805 } else if (childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG && NearZero(flexSize) &&
806 childLayoutWrapper->IsActive()) {
807 child.needSecondMeasure = true;
808 }
809 }
810 ++iter;
811 }
812 }
813 SecondMeasureInGrowOrShrink();
814 }
815
CheckIsGrowOrShrink(std::function<float (const RefPtr<LayoutWrapper> &)> & getFlex,float remainSpace,float & spacePerFlex,FlexItemProperties & flexItemProperties,RefPtr<LayoutWrapper> & lastChild)816 void FlexLayoutAlgorithm::CheckIsGrowOrShrink(std::function<float(const RefPtr<LayoutWrapper>&)>& getFlex,
817 float remainSpace, float& spacePerFlex, FlexItemProperties& flexItemProperties, RefPtr<LayoutWrapper>& lastChild)
818 {
819 if (GreatOrEqual(remainSpace, 0.0f) || GreatNotEqual(maxDisplayPriority_, 1)) {
820 getFlex = [](const RefPtr<LayoutWrapper>& item) -> float {
821 const auto& flexItemProperty = item->GetLayoutProperty()->GetFlexItemProperty();
822 float ret = 0.0f;
823 if (flexItemProperty) {
824 ret = flexItemProperty->GetFlexGrow().value_or(ret);
825 /**
826 * handle non positive flex grow.
827 */
828 if (NonPositive(ret)) {
829 ret = 0.0f;
830 }
831 }
832 return ret;
833 };
834 spacePerFlex = NearZero(flexItemProperties.totalGrow) ? 0.0f : remainSpace / flexItemProperties.totalGrow;
835 lastChild = flexItemProperties.lastGrowChild;
836 } else {
837 getFlex = [isLinearLayoutFeature = isLinearLayoutFeature_](const RefPtr<LayoutWrapper>& item) -> float {
838 const auto& flexItemProperty = item->GetLayoutProperty()->GetFlexItemProperty();
839 float ret = isLinearLayoutFeature ? 0.0f : 1.0f;
840 if (flexItemProperty) {
841 ret = flexItemProperty->GetFlexShrink().value_or(ret);
842 /**
843 * handle non positive flex shrink.
844 */
845 if (NonPositive(ret)) {
846 ret = 0.0f;
847 }
848 }
849 return ret;
850 };
851 spacePerFlex = NearZero(flexItemProperties.totalShrink) ? 0.0f : remainSpace / flexItemProperties.totalShrink;
852 lastChild = flexItemProperties.lastShrinkChild;
853 }
854 }
855
CheckBlankAndKeepMin(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & flexSize)856 void FlexLayoutAlgorithm::CheckBlankAndKeepMin(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& flexSize)
857 {
858 auto child = childLayoutWrapper->GetHostNode();
859 if (!child) {
860 return;
861 }
862 if (child->GetTag() != V2::BLANK_ETS_TAG) {
863 return;
864 }
865 auto blankProperty = child->GetLayoutProperty<BlankLayoutProperty>();
866 CHECK_NULL_VOID(blankProperty);
867 auto blankMin = blankProperty->GetMinSize();
868 if (GreatOrEqual(blankMin->ConvertToPx(), flexSize)) {
869 flexSize = blankMin->ConvertToPx();
870 }
871 }
872
IsKeepMinSize(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & flexSize)873 bool FlexLayoutAlgorithm::IsKeepMinSize(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& flexSize)
874 {
875 auto child = childLayoutWrapper->GetHostNode();
876 CHECK_NULL_RETURN(child, false);
877 auto minSize = MainAxisMinValue(AceType::RawPtr(childLayoutWrapper));
878 if (GreatOrEqual(minSize, flexSize)) {
879 flexSize = minSize;
880 return true;
881 }
882 return false;
883 }
884
UpdateLayoutConstraintOnMainAxis(LayoutConstraintF & layoutConstraint,float size)885 void FlexLayoutAlgorithm::UpdateLayoutConstraintOnMainAxis(LayoutConstraintF& layoutConstraint, float size)
886 {
887 if (IsHorizontal(direction_)) {
888 layoutConstraint.selfIdealSize.SetWidth(size);
889 } else {
890 layoutConstraint.selfIdealSize.SetHeight(size);
891 }
892 }
893
UpdateLayoutConstraintOnCrossAxis(LayoutConstraintF & layoutConstraint,float size)894 void FlexLayoutAlgorithm::UpdateLayoutConstraintOnCrossAxis(LayoutConstraintF& layoutConstraint, float size)
895 {
896 OptionalSizeF& selfIdealSize = layoutConstraint.selfIdealSize;
897 if (IsHorizontal(direction_)) {
898 selfIdealSize.SetHeight(size);
899 } else {
900 selfIdealSize.SetWidth(size);
901 }
902 }
903
MainAxisMinValue(LayoutWrapper * layoutWrapper)904 float FlexLayoutAlgorithm::MainAxisMinValue(LayoutWrapper* layoutWrapper)
905 {
906 CHECK_NULL_RETURN(layoutWrapper, 0.0f);
907 CHECK_NULL_RETURN(layoutWrapper->GetLayoutProperty(), 0.0f);
908 auto layoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
909 CHECK_NULL_RETURN(layoutConstraint, 0.0f);
910 return IsHorizontal(direction_) ? layoutConstraint->minSize.Width() : layoutConstraint->minSize.Height();
911 }
912
MarginOnMainAxisNegative(LayoutWrapper * layoutWrapper)913 bool FlexLayoutAlgorithm::MarginOnMainAxisNegative(LayoutWrapper* layoutWrapper)
914 {
915 const auto& margin = layoutWrapper->GetGeometryNode()->GetMargin();
916 CHECK_NULL_RETURN(margin, false);
917 if (IsHorizontal(direction_)) {
918 return LessNotEqual(margin->left.value_or(0.0f) + margin->right.value_or(0.0f), 0.0f);
919 }
920 return LessNotEqual(margin->top.value_or(0.0f) + margin->bottom.value_or(0.0f), 0.0f);
921 }
922
CheckSetConstraint(const std::unique_ptr<MeasureProperty> & propertyPtr)923 bool FlexLayoutAlgorithm::CheckSetConstraint(const std::unique_ptr<MeasureProperty>& propertyPtr)
924 {
925 return propertyPtr && (propertyPtr->minSize || propertyPtr->maxSize);
926 }
927
CheckMainAxisSizeAuto(const std::unique_ptr<MeasureProperty> & calcLayoutConstraint)928 void FlexLayoutAlgorithm::CheckMainAxisSizeAuto(const std::unique_ptr<MeasureProperty>& calcLayoutConstraint)
929 {
930 if (isInfiniteLayout_) {
931 mainAxisSize_ = allocatedSize_;
932 }
933 CHECK_NULL_VOID(calcLayoutConstraint);
934 CHECK_NULL_VOID(calcLayoutConstraint->selfIdealSize);
935 if (IsHorizontal(direction_) ? calcLayoutConstraint->selfIdealSize->IsWidthDimensionUnitAuto()
936 : calcLayoutConstraint->selfIdealSize->IsHeightDimensionUnitAuto()) {
937 mainAxisSize_ = allocatedSize_;
938 }
939 }
940
SetInitMainAxisSize(LayoutWrapper * layoutWrapper)941 void FlexLayoutAlgorithm::SetInitMainAxisSize(LayoutWrapper* layoutWrapper)
942 {
943 const auto& layoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
944 bool mainAxisInf = GreaterOrEqualToInfinity(IsHorizontal(direction_) ? layoutConstraint->maxSize.Width()
945 : layoutConstraint->maxSize.Height()) &&
946 NearEqual(mainAxisSize_, -1.0f);
947 if (NearEqual(mainAxisSize_, -1.0f)) {
948 auto marginOnMainAxisNegative = MarginOnMainAxisNegative(layoutWrapper);
949 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
950 mainAxisSize_ =
951 IsHorizontal(direction_) ? layoutConstraint->maxSize.Width() : layoutConstraint->maxSize.Height();
952 } else if (isLinearLayoutFeature_ && IsHorizontal(direction_) && !NearZero(layoutConstraint->minSize.Width()) &&
953 !marginOnMainAxisNegative) {
954 mainAxisSize_ = layoutConstraint->minSize.Width();
955 } else if (isLinearLayoutFeature_ && !IsHorizontal(direction_) &&
956 !NearZero(layoutConstraint->minSize.Height()) && !marginOnMainAxisNegative) {
957 mainAxisSize_ = layoutConstraint->minSize.Height();
958 } else {
959 mainAxisSize_ =
960 IsHorizontal(direction_)
961 ? (mainAxisInf ? layoutConstraint->percentReference.Width() : layoutConstraint->maxSize.Width())
962 : (mainAxisInf ? layoutConstraint->percentReference.Height() : layoutConstraint->maxSize.Height());
963 }
964 isInfiniteLayout_ = isLinearLayoutFeature_;
965 }
966 selfAdaptive_ = isLinearLayoutFeature_;
967 if (!isInfiniteLayout_) {
968 isInfiniteLayout_ = mainAxisInf;
969 }
970 }
971
SetFinalRealSize(LayoutWrapper * layoutWrapper,SizeF & realSize)972 void FlexLayoutAlgorithm::SetFinalRealSize(LayoutWrapper* layoutWrapper, SizeF& realSize)
973 {
974 const auto& layoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
975 auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
976 auto horizontalPadding = padding.left.value_or(0.0f) + padding.right.value_or(0.0f);
977 auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
978 auto finalMainAxisSize = mainAxisSize_;
979 auto finalCrossAxisSize = crossAxisSize_;
980 if (IsHorizontal(direction_)) {
981 finalCrossAxisSize += verticalPadding;
982 finalMainAxisSize += horizontalPadding;
983 } else {
984 finalCrossAxisSize += horizontalPadding;
985 finalMainAxisSize += verticalPadding;
986 }
987 auto mainAxisSizeMin = GetMainAxisSizeHelper(layoutConstraint->minSize, direction_);
988 auto mainAxisSizeMax = GetMainAxisSizeHelper(layoutConstraint->maxSize, direction_);
989 auto crossAxisSizeMin = GetCrossAxisSizeHelper(layoutConstraint->minSize, direction_);
990 auto crossAxisSizeMax = GetCrossAxisSizeHelper(layoutConstraint->maxSize, direction_);
991 finalMainAxisSize = std::clamp(
992 finalMainAxisSize, std::min(mainAxisSizeMin, mainAxisSizeMax), std::max(mainAxisSizeMin, mainAxisSizeMax));
993 finalCrossAxisSize = std::clamp(
994 finalCrossAxisSize, std::min(crossAxisSizeMin, crossAxisSizeMax), std::max(crossAxisSizeMin, crossAxisSizeMax));
995
996 realSize.UpdateIllegalSizeWithCheck(
997 GetCalcSizeHelper(finalMainAxisSize, finalCrossAxisSize, direction_).ConvertToSizeT());
998 }
999
Measure(LayoutWrapper * layoutWrapper)1000 void FlexLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
1001 {
1002 const auto& children = layoutWrapper->GetAllChildrenWithBuild();
1003 const auto& layoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
1004 const auto& calcConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
1005 bool needToConstraint = CheckSetConstraint(calcConstraint) && children.empty();
1006 const auto& measureType = layoutWrapper->GetLayoutProperty()->GetMeasureType();
1007 InitFlexProperties(layoutWrapper);
1008 Axis axis = (IsHorizontal(direction_)) ? Axis::HORIZONTAL : Axis::VERTICAL;
1009 auto realSize =
1010 CreateIdealSizeByPercentRef(layoutConstraint.value(), axis, measureType, needToConstraint, calcConstraint)
1011 .ConvertToSizeT();
1012 if (layoutWrapper->GetHostTag() == V2::COLUMN_ETS_TAG || layoutWrapper->GetHostTag() == V2::ROW_ETS_TAG) {
1013 auto layoutPolicy = AceType::DynamicCast<FlexLayoutProperty>(layoutWrapper->GetLayoutProperty());
1014 auto widthLayoutPolicy = layoutPolicy ? layoutPolicy->GetWidthLayoutPolicy()
1015 .value_or(static_cast<uint8_t>(LayoutCalPolicy::NO_MATCH)) : 0;
1016 auto heightLayoutPolicy = layoutPolicy ? layoutPolicy->GetHeightLayoutPolicy()
1017 .value_or(static_cast<uint8_t>(LayoutCalPolicy::NO_MATCH)) : 0;
1018 auto layoutPolicySize =
1019 ConstrainIdealSizeByLayoutPolicy(layoutConstraint.value(), widthLayoutPolicy, heightLayoutPolicy, axis)
1020 .ConvertToSizeT();
1021 realSize.UpdateIllegalSizeWithCheck(layoutPolicySize);
1022 }
1023 if (children.empty()) {
1024 layoutWrapper->GetGeometryNode()->SetFrameSize(realSize);
1025 return;
1026 }
1027 mainAxisSize_ = GetMainAxisSizeHelper(realSize, direction_);
1028 SetInitMainAxisSize(layoutWrapper);
1029 auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
1030 auto horizontalPadding = padding.left.value_or(0.0f) + padding.right.value_or(0.0f);
1031 auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
1032 if (IsHorizontal(direction_)) {
1033 mainAxisSize_ -= horizontalPadding;
1034 } else {
1035 mainAxisSize_ -= verticalPadding;
1036 }
1037 if (Negative(mainAxisSize_)) {
1038 mainAxisSize_ = 0.0f;
1039 }
1040 TravelChildrenFlexProps(layoutWrapper);
1041 selfIdealCrossAxisSize_ = GetCrossAxisSizeHelper(realSize, direction_);
1042 FlexItemProperties flexItemProperties;
1043
1044 /**
1045 * first measure
1046 */
1047 MeasureAndCleanMagicNodes(layoutWrapper, flexItemProperties);
1048
1049 /**
1050 * secondary measure
1051 */
1052 SecondaryMeasureByProperty(flexItemProperties, layoutWrapper);
1053
1054 /**
1055 * position property measure.
1056 */
1057 MeasureOutOfLayoutChildren(layoutWrapper);
1058
1059 AdjustTotalAllocatedSize(layoutWrapper);
1060
1061 CheckMainAxisSizeAuto(calcConstraint);
1062
1063 SetFinalRealSize(layoutWrapper, realSize);
1064
1065 layoutWrapper->GetGeometryNode()->SetFrameSize(realSize);
1066
1067 if (layoutWrapper->GetHostTag() == V2::COLUMN_ETS_TAG || layoutWrapper->GetHostTag() == V2::ROW_ETS_TAG) {
1068 MeasureAdaptiveLayoutChildren(layoutWrapper, realSize);
1069 }
1070 }
1071
AdjustTotalAllocatedSize(LayoutWrapper * layoutWrapper)1072 void FlexLayoutAlgorithm::AdjustTotalAllocatedSize(LayoutWrapper* layoutWrapper)
1073 {
1074 const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
1075 if (children.empty()) {
1076 allocatedSize_ = 0.0f;
1077 return;
1078 }
1079 allocatedSize_ = 0.0f;
1080 allocatedSize_ += space_ * (validSizeCount_ - 1);
1081 // space is not valid when mainAxisAlign is SPACE_AROUND/SPACE_BETWEEN/SPACE_EVENLY
1082 if (mainAxisAlign_ == FlexAlign::SPACE_AROUND || mainAxisAlign_ == FlexAlign::SPACE_BETWEEN ||
1083 mainAxisAlign_ == FlexAlign::SPACE_EVENLY) {
1084 allocatedSize_ = 0.0;
1085 }
1086 for (const auto& child : children) {
1087 if (child->IsOutOfLayout() || IsVisibleGone(child) ||
1088 find(layoutPolicyChildren_.begin(), layoutPolicyChildren_.end(), child) != layoutPolicyChildren_.end()) {
1089 continue;
1090 }
1091 allocatedSize_ += GetChildMainAxisSize(child);
1092 }
1093 }
1094
1095 /**
1096 * Get cross axis size in stretch.
1097 * At this time, the cross axis size has been determined.
1098 */
GetStretchCrossAxisLimit() const1099 float FlexLayoutAlgorithm::GetStretchCrossAxisLimit() const
1100 {
1101 float crossAxisLimit = GreatNotEqual(selfIdealCrossAxisSize_, -1.0f) ? selfIdealCrossAxisSize_ : crossAxisSize_;
1102 return crossAxisLimit;
1103 }
1104
Layout(LayoutWrapper * layoutWrapper)1105 void FlexLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
1106 {
1107 const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
1108 if (children.empty()) {
1109 return;
1110 }
1111 auto layoutProperty = AceType::DynamicCast<FlexLayoutProperty>(layoutWrapper->GetLayoutProperty());
1112 CHECK_NULL_VOID(layoutProperty);
1113 space_ = static_cast<float>(layoutProperty->GetSpaceValue({}).ConvertToPx());
1114 direction_ = layoutProperty->GetFlexDirection().value_or(FlexDirection::ROW);
1115 bool isReverse = layoutProperty->GetFlexLayoutAttribute()->GetIsReverse().value_or(false);
1116 if (isReverse) {
1117 direction_ = ReverseFlexDirection(direction_);
1118 }
1119 mainAxisAlign_ = layoutProperty->GetMainAxisAlignValue(FlexAlign::FLEX_START);
1120 crossAxisAlign_ =
1121 layoutProperty->GetCrossAxisAlignValue(isLinearLayoutFeature_ ? FlexAlign::CENTER : FlexAlign::FLEX_START);
1122 textDir_ = layoutProperty->GetLayoutDirection();
1123 if (textDir_ == TextDirection::AUTO) {
1124 textDir_ = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
1125 }
1126 auto contentSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
1127 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
1128 Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)
1129 ? MinusPaddingToNonNegativeSize(padding, contentSize)
1130 : MinusPaddingToSize(padding, contentSize);
1131 mainAxisSize_ = GetMainAxisSizeHelper(contentSize, direction_);
1132 crossAxisSize_ = GetCrossAxisSizeHelper(contentSize, direction_);
1133 auto paddingOffset = OffsetF(padding.left.value_or(0.0f), padding.top.value_or(0.0f));
1134 float remainSpace = std::max(mainAxisSize_ - allocatedSize_, 0.0f);
1135 float frontSpace = 0.0f;
1136 float betweenSpace = 0.0f;
1137 CalculateSpace(remainSpace, frontSpace, betweenSpace);
1138 PlaceChildren(layoutWrapper, frontSpace, betweenSpace, paddingOffset);
1139
1140 for (auto&& child : children) {
1141 if (!child->IsOutOfLayout() && child->IsActive()) {
1142 child->Layout();
1143 }
1144 }
1145 }
1146
CalculateSpace(float remainSpace,float & frontSpace,float & betweenSpace) const1147 void FlexLayoutAlgorithm::CalculateSpace(float remainSpace, float& frontSpace, float& betweenSpace) const
1148 {
1149 switch (mainAxisAlign_) {
1150 case FlexAlign::FLEX_START:
1151 frontSpace = 0.0f;
1152 betweenSpace = space_;
1153 break;
1154 case FlexAlign::FLEX_END:
1155 frontSpace = remainSpace;
1156 betweenSpace = space_;
1157 break;
1158 case FlexAlign::CENTER:
1159 frontSpace = remainSpace * HALF;
1160 betweenSpace = space_;
1161 break;
1162 case FlexAlign::SPACE_BETWEEN:
1163 frontSpace = 0.0f;
1164 betweenSpace = validSizeCount_ > 1 ? remainSpace / static_cast<float>(validSizeCount_ - 1) : 0.0f;
1165 break;
1166 case FlexAlign::SPACE_AROUND:
1167 betweenSpace = validSizeCount_ > 0 ? remainSpace / static_cast<float>(validSizeCount_) : 0.0f;
1168 frontSpace = betweenSpace * HALF;
1169 break;
1170 case FlexAlign::SPACE_EVENLY:
1171 betweenSpace = validSizeCount_ > 0 ? remainSpace / static_cast<float>(validSizeCount_ + 1) : 0.0f;
1172 frontSpace = betweenSpace;
1173 break;
1174 default:
1175 break;
1176 }
1177 }
1178
SetCrossPos(const RefPtr<LayoutWrapper> & layoutWrapper,float & crossPos)1179 void FlexLayoutAlgorithm::SetCrossPos(const RefPtr<LayoutWrapper>& layoutWrapper, float& crossPos)
1180 {
1181 auto alignItem = GetSelfAlign(layoutWrapper);
1182 auto crossDirection = FlipAxis(direction_);
1183 switch (alignItem) {
1184 case FlexAlign::FLEX_START:
1185 case FlexAlign::FLEX_END:
1186 crossPos = (IsStartTopLeft(crossDirection, textDir_) == (alignItem == FlexAlign::FLEX_START))
1187 ? 0.0f
1188 : crossAxisSize_ - GetChildCrossAxisSize(layoutWrapper);
1189 break;
1190 case FlexAlign::CENTER:
1191 crossPos = crossAxisSize_ * HALF - GetChildCrossAxisSize(layoutWrapper) * HALF;
1192 break;
1193 case FlexAlign::STRETCH:
1194 crossPos =
1195 IsStartTopLeft(crossDirection, textDir_) ? 0.0f : crossAxisSize_ - GetChildCrossAxisSize(layoutWrapper);
1196 break;
1197 case FlexAlign::BASELINE:
1198 crossPos = 0.0;
1199 if (IsHorizontal(direction_)) {
1200 float distance = layoutWrapper->GetBaselineDistance();
1201 crossPos = baselineProperties_.maxBaselineDistance - distance;
1202 }
1203 break;
1204 default:
1205 break;
1206 }
1207 }
1208
PlaceChildren(LayoutWrapper * layoutWrapper,float frontSpace,float betweenSpace,const OffsetF & paddingOffset)1209 void FlexLayoutAlgorithm::PlaceChildren(
1210 LayoutWrapper* layoutWrapper, float frontSpace, float betweenSpace, const OffsetF& paddingOffset)
1211 {
1212 float childMainPos = IsStartTopLeft(direction_, textDir_) ? frontSpace : mainAxisSize_ - frontSpace;
1213 float childCrossPos = 0.0f;
1214 const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
1215 for (const auto& child : children) {
1216 if (child->IsOutOfLayout() || !child->IsActive()) {
1217 // adjust by postion property.
1218 child->GetGeometryNode()->SetMarginFrameOffset({});
1219 child->Layout();
1220 continue;
1221 }
1222 if (IsVisibleGone(child)) {
1223 continue;
1224 }
1225 SetCrossPos(child, childCrossPos);
1226 OffsetF offset;
1227 if (IsHorizontal(direction_)) {
1228 offset = OffsetF(childMainPos, childCrossPos);
1229 } else {
1230 offset = OffsetF(childCrossPos, childMainPos);
1231 }
1232
1233 if (!IsStartTopLeft(direction_, textDir_)) {
1234 if (direction_ != FlexDirection::COLUMN_REVERSE) {
1235 offset.SetX(offset.GetX() - GetChildMainAxisSize(child));
1236 } else {
1237 offset.SetY(offset.GetY() - GetChildMainAxisSize(child));
1238 }
1239 child->GetGeometryNode()->SetMarginFrameOffset(offset + paddingOffset);
1240 childMainPos -= GetChildMainAxisSize(child) + betweenSpace;
1241 } else {
1242 child->GetGeometryNode()->SetMarginFrameOffset(offset + paddingOffset);
1243 childMainPos += GetChildMainAxisSize(child) + betweenSpace;
1244 }
1245 }
1246 }
1247
GetSelfAlign(const RefPtr<LayoutWrapper> & layoutWrapper) const1248 FlexAlign FlexLayoutAlgorithm::GetSelfAlign(const RefPtr<LayoutWrapper>& layoutWrapper) const
1249 {
1250 const auto& flexItemProperty = layoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
1251 FlexAlign crossAxisAlign = (crossAxisAlign_ == FlexAlign::AUTO) ? FlexAlign::FLEX_START : crossAxisAlign_;
1252 if (!flexItemProperty || !flexItemProperty->GetAlignSelf().has_value() ||
1253 flexItemProperty->GetAlignSelf().value_or(crossAxisAlign_) == FlexAlign::AUTO) {
1254 return crossAxisAlign;
1255 }
1256 return flexItemProperty->GetAlignSelf().value_or(crossAxisAlign);
1257 }
1258
1259 } // namespace OHOS::Ace::NG
1260