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