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 (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) {
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
162 } // namespace
163
GetChildMainAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const164 float FlexLayoutAlgorithm::GetChildMainAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
165 {
166 float size = 0.0f;
167 CHECK_NULL_RETURN(layoutWrapper, size);
168 return GetMainAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetMarginFrameSize(), direction_);
169 }
170
GetChildCrossAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const171 float FlexLayoutAlgorithm::GetChildCrossAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
172 {
173 CHECK_NULL_RETURN(layoutWrapper, 0.0f);
174 return GetCrossAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetMarginFrameSize(), direction_);
175 }
176
GetSelfCrossAxisSize(const RefPtr<LayoutWrapper> & layoutWrapper) const177 float FlexLayoutAlgorithm::GetSelfCrossAxisSize(const RefPtr<LayoutWrapper>& layoutWrapper) const
178 {
179 CHECK_NULL_RETURN(layoutWrapper, 0.0f);
180 return GetCrossAxisSizeHelper(layoutWrapper->GetGeometryNode()->GetFrameSize(), direction_);
181 }
182
CheckSizeValidity(const RefPtr<LayoutWrapper> & layoutWrapper)183 void FlexLayoutAlgorithm::CheckSizeValidity(const RefPtr<LayoutWrapper>& layoutWrapper)
184 {
185 if (layoutWrapper && layoutWrapper->GetHostNode() &&
186 layoutWrapper->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) ==
187 VisibleType::GONE) {
188 return;
189 }
190 ++validSizeCount_;
191 }
192
193 /**
194 * Check and record baseline distance.
195 */
CheckBaselineProperties(const RefPtr<LayoutWrapper> & layoutWrapper)196 void FlexLayoutAlgorithm::CheckBaselineProperties(const RefPtr<LayoutWrapper>& layoutWrapper)
197 {
198 if (crossAxisAlign_ != FlexAlign::BASELINE && !childrenHasAlignSelfBaseLine_) {
199 return;
200 }
201 float distance = layoutWrapper->GetBaselineDistance();
202 baselineProperties_.maxBaselineDistance = std::max(baselineProperties_.maxBaselineDistance, distance);
203 baselineProperties_.maxDistanceAboveBaseline = std::max(baselineProperties_.maxDistanceAboveBaseline, distance);
204 baselineProperties_.maxDistanceBelowBaseline =
205 std::max(baselineProperties_.maxDistanceBelowBaseline, GetSelfCrossAxisSize(layoutWrapper) - distance);
206 if (crossAxisAlign_ == FlexAlign::BASELINE) {
207 crossAxisSize_ = baselineProperties_.maxDistanceAboveBaseline + baselineProperties_.maxDistanceBelowBaseline;
208 }
209 }
210
211 /**
212 * Initialize the FlexLayoutAlgorithm property.
213 */
InitFlexProperties(LayoutWrapper * layoutWrapper)214 void FlexLayoutAlgorithm::InitFlexProperties(LayoutWrapper* layoutWrapper)
215 {
216 mainAxisSize_ = 0.0f;
217 crossAxisSize_ = 0.0f;
218 allocatedSize_ = 0.0f;
219 selfIdealCrossAxisSize_ = -1.0f;
220 validSizeCount_ = 0;
221 realSize_.Reset();
222 isInfiniteLayout_ = false;
223 auto layoutProperty = AceType::DynamicCast<FlexLayoutProperty>(layoutWrapper->GetLayoutProperty());
224 CHECK_NULL_VOID(layoutProperty);
225 space_ = static_cast<float>(layoutProperty->GetSpaceValue({}).ConvertToPx());
226 direction_ = layoutProperty->GetFlexDirection().value_or(FlexDirection::ROW);
227 mainAxisAlign_ = layoutProperty->GetMainAxisAlignValue(FlexAlign::FLEX_START);
228 secondaryMeasureList_.clear();
229 crossAxisAlign_ =
230 layoutProperty->GetCrossAxisAlignValue(isLinearLayoutFeature_ ? FlexAlign::CENTER : FlexAlign::FLEX_START);
231 baselineProperties_.Reset();
232 textDir_ = layoutProperty->GetLayoutDirection();
233 if (textDir_ == TextDirection::AUTO) {
234 textDir_ = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
235 }
236 /**
237 * FlexLayoutAlgorithm, as the parent class, should not handle the special logic of the subclass
238 * LinearLayout.
239 */
240 if (isLinearLayoutFeature_) {
241 bool isVertical = DynamicCast<LinearLayoutProperty>(layoutWrapper->GetLayoutProperty())->IsVertical();
242 direction_ = isVertical ? FlexDirection::COLUMN : FlexDirection::ROW;
243 }
244 }
245
TravelChildrenFlexProps(LayoutWrapper * layoutWrapper,const SizeF & realSize)246 void FlexLayoutAlgorithm::TravelChildrenFlexProps(LayoutWrapper* layoutWrapper, const SizeF& realSize)
247 {
248 maxDisplayPriority_ = 0;
249 totalFlexWeight_ = 0.0f;
250 outOfLayoutChildren_.clear();
251 magicNodes_.clear();
252 magicNodeWeights_.clear();
253 childrenHasAlignSelfBaseLine_ = false;
254 const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
255 const auto& children = layoutWrapper->GetAllChildrenWithBuild();
256 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
257 for (const auto& child : children) {
258 if (child->IsOutOfLayout()) {
259 outOfLayoutChildren_.emplace_back(child);
260 continue;
261 }
262 const auto& childLayoutProperty = child->GetLayoutProperty();
263 const auto& childMagicItemProperty = childLayoutProperty->GetMagicItemProperty();
264 const auto& childFlexItemProperty = childLayoutProperty->GetFlexItemProperty();
265 MagicLayoutNode node;
266 node.layoutWrapper = child;
267 node.layoutConstraint = childLayoutConstraint;
268
269 bool childGone =
270 child && child->GetHostNode() && child->GetHostNode()->GetLayoutProperty() &&
271 child->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::GONE;
272 int32_t childDisplayPriority = 1;
273 float childLayoutWeight = 0.0f;
274 if (!childGone) {
275 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
276 if (childFlexItemProperty) {
277 childDisplayPriority = childFlexItemProperty->GetDisplayIndex().value_or(1);
278 if (!childrenHasAlignSelfBaseLine_ &&
279 childFlexItemProperty->GetAlignSelf().value_or(FlexAlign::FLEX_START) == FlexAlign::BASELINE) {
280 childrenHasAlignSelfBaseLine_ = true;
281 }
282 }
283 }
284
285 auto iter = magicNodes_.find(childDisplayPriority);
286 if (iter == magicNodes_.end()) {
287 magicNodes_.insert(
288 std::map<int32_t, std::list<MagicLayoutNode>>::value_type(childDisplayPriority, { node }));
289 if (GreatNotEqual(childLayoutWeight, 0.0f)) {
290 magicNodeWeights_.insert(std::map<int32_t, float>::value_type(childDisplayPriority, childLayoutWeight));
291 }
292 } else {
293 iter->second.emplace_back(node);
294 if (GreatNotEqual(childLayoutWeight, 0.0f)) {
295 magicNodeWeights_[childDisplayPriority] += childLayoutWeight;
296 }
297 }
298 if (!childGone) {
299 totalFlexWeight_ += GreatNotEqual(childLayoutWeight, 0.0f) ? childLayoutWeight : 0.0f;
300 maxDisplayPriority_ = std::max(childDisplayPriority, maxDisplayPriority_);
301 }
302 }
303 }
304
UpdateAllocatedSize(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & crossAxisSize)305 void FlexLayoutAlgorithm::UpdateAllocatedSize(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& crossAxisSize)
306 {
307 float mainAxisSize = GetChildMainAxisSize(childLayoutWrapper);
308 if (GreaterOrEqualToInfinity(mainAxisSize)) {
309 mainAxisSize = 0.0f;
310 }
311 crossAxisSize = std::max(crossAxisSize, GetChildCrossAxisSize(childLayoutWrapper));
312 allocatedSize_ += mainAxisSize;
313 allocatedSize_ += space_;
314 }
315
MeasureOutOfLayoutChildren(LayoutWrapper * layoutWrapper)316 void FlexLayoutAlgorithm::MeasureOutOfLayoutChildren(LayoutWrapper* layoutWrapper)
317 {
318 const auto& layoutConstrain = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
319 for (const auto& child : outOfLayoutChildren_) {
320 child->Measure(layoutConstrain);
321 }
322 }
323
MeasureAndCleanMagicNodes(LayoutWrapper * containerLayoutWrapper,FlexItemProperties & flexItemProperties)324 void FlexLayoutAlgorithm::MeasureAndCleanMagicNodes(
325 LayoutWrapper* containerLayoutWrapper, FlexItemProperties& flexItemProperties)
326 {
327 if (GreatNotEqual(totalFlexWeight_, 0.0f)) {
328 auto newTotalFlexWeight = totalFlexWeight_;
329 /**
330 * The child elements with layoutWeight=0 are measured first.
331 * Then, measure the sub elements of layoutWeight>1 based on the remaining space.
332 * If the total main axis size of the element is larger than the main axis size of Flex, the lower priority
333 * element will be deleted.
334 */
335 auto firstLoopIter = magicNodes_.rbegin();
336 auto loopIter = firstLoopIter;
337 bool outOfDisplay = false;
338 while (loopIter != magicNodes_.rend()) {
339 auto& childList = loopIter->second;
340 float crossAxisSize = crossAxisSize_;
341 for (auto& child : childList) {
342 if (!outOfDisplay) {
343 const auto& childLayoutWrapper = child.layoutWrapper;
344 float childLayoutWeight = 0.0f;
345 const auto& childMagicItemProperty =
346 childLayoutWrapper->GetLayoutProperty()->GetMagicItemProperty();
347 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
348 if (LessOrEqual(childLayoutWeight, 0.0f)) {
349 if (child.layoutWrapper && child.layoutWrapper->GetHostNode() &&
350 child.layoutWrapper->GetHostNode()->GetLayoutProperty() &&
351 child.layoutWrapper->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(
352 VisibleType::VISIBLE) == VisibleType::GONE) {
353 continue;
354 }
355 childLayoutWrapper->Measure(child.layoutConstraint);
356 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize);
357 CheckSizeValidity(childLayoutWrapper);
358 CheckBaselineProperties(childLayoutWrapper);
359 } else {
360 allocatedSize_ += space_;
361 }
362 } else {
363 child.layoutWrapper->SetActive(false);
364 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
365 }
366 }
367 if (outOfDisplay) {
368 ++loopIter;
369 continue;
370 }
371 /**
372 * The main axis size of the element with layoutWeight of 0 is larger than the Flex main axis size
373 */
374 if (allocatedSize_ - space_ > mainAxisSize_ && magicNodes_.size() > 1) {
375 for (const auto& child : childList) {
376 allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper);
377 allocatedSize_ -= space_;
378 child.layoutWrapper->SetActive(false);
379 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
380 }
381 outOfDisplay = true;
382 firstLoopIter = loopIter++;
383 } else {
384 crossAxisSize_ = crossAxisSize;
385 firstLoopIter = ++loopIter;
386 }
387 }
388 allocatedSize_ -= space_;
389 auto remainedMainAxisSize = mainAxisSize_ - allocatedSize_;
390 auto spacePerWeight = remainedMainAxisSize / newTotalFlexWeight;
391 auto secondIterLoop = magicNodes_.rbegin();
392 while (secondIterLoop != firstLoopIter) {
393 auto& childList = secondIterLoop->second;
394 bool isExceed = false;
395 for (auto& child : childList) {
396 auto childLayoutWrapper = child.layoutWrapper;
397 auto& childConstraint = child.layoutConstraint;
398 float childLayoutWeight = 0.0f;
399 const auto& childMagicItemProperty = childLayoutWrapper->GetLayoutProperty()->GetMagicItemProperty();
400 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
401 if (LessOrEqual(childLayoutWeight, 0.0)) {
402 continue;
403 }
404 float childCalcSize = std::max(spacePerWeight * childLayoutWeight, 0.0f);
405 if (GetMainAxisSizeHelper(childConstraint.minSize, direction_) > childCalcSize) {
406 isExceed = true;
407 }
408 UpdateLayoutConstraintOnMainAxis(childConstraint, childCalcSize);
409 }
410 if (isExceed) {
411 if (magicNodes_.size() <= 1) {
412 break;
413 }
414 isExceed = true;
415 auto& lowPriorityChildList = magicNodes_.begin()->second;
416 for (const auto& child : lowPriorityChildList) {
417 allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper);
418 allocatedSize_ -= space_;
419 child.layoutWrapper->SetActive(false);
420 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
421 }
422 newTotalFlexWeight -= magicNodeWeights_[magicNodes_.begin()->first];
423 remainedMainAxisSize = mainAxisSize_ - allocatedSize_;
424 spacePerWeight = remainedMainAxisSize / newTotalFlexWeight;
425 isExceed = false;
426 magicNodes_.erase(magicNodes_.begin());
427 secondIterLoop = magicNodes_.rbegin();
428 } else {
429 secondIterLoop++;
430 }
431 }
432 auto iter = magicNodes_.rbegin();
433 while (iter != magicNodes_.rend()) {
434 auto& childList = iter->second;
435 for (auto& child : childList) {
436 auto childLayoutWrapper = child.layoutWrapper;
437 if (!childLayoutWrapper->IsActive()) {
438 continue;
439 }
440 float childLayoutWeight = 0.0f;
441 const auto& childMagicItemProperty = childLayoutWrapper->GetLayoutProperty()->GetMagicItemProperty();
442 childLayoutWeight = childMagicItemProperty.GetLayoutWeight().value_or(0.0f);
443 secondaryMeasureList_.emplace_back(child);
444 if (LessOrEqual(childLayoutWeight, 0.0)) {
445 continue;
446 }
447 childLayoutWrapper->Measure(child.layoutConstraint);
448 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
449 CheckSizeValidity(childLayoutWrapper);
450 CheckBaselineProperties(childLayoutWrapper);
451 }
452 iter++;
453 }
454 } else if (GreatNotEqual(maxDisplayPriority_, 1) && !isInfiniteLayout_) {
455 bool outOfDisplay = false;
456 auto iter = magicNodes_.rbegin();
457 while (iter != magicNodes_.rend()) {
458 auto childList = iter->second;
459 if (outOfDisplay) {
460 for (auto& child : childList) {
461 const auto& childLayoutWrapper = child.layoutWrapper;
462 auto childLayoutConstraint = child.layoutConstraint;
463 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, childLayoutConstraint);
464 child.layoutWrapper->ApplyConstraintWithoutMeasure(childLayoutConstraint);
465 child.layoutWrapper->SetActive(false);
466 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
467 }
468 ++iter;
469 continue;
470 }
471 float crossAxisSize = crossAxisSize_;
472 for (auto& child : childList) {
473 const auto& childLayoutWrapper = child.layoutWrapper;
474 auto childLayoutConstraint = child.layoutConstraint;
475 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, childLayoutConstraint);
476 childLayoutWrapper->Measure(childLayoutConstraint);
477 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize);
478 CheckSizeValidity(childLayoutWrapper);
479 CheckBaselineProperties(childLayoutWrapper);
480 const auto& flexItemProperty = childLayoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
481 if (flexItemProperty && GreatNotEqual(flexItemProperty->GetFlexGrow().value_or(0.0f), 0.0f)) {
482 flexItemProperties.totalGrow += flexItemProperty->GetFlexGrow().value_or(0.0f);
483 }
484 secondaryMeasureList_.emplace_back(child);
485 }
486 if (!LessOrEqual(allocatedSize_ - space_, mainAxisSize_)) {
487 outOfDisplay = true;
488 for (auto& child : childList) {
489 allocatedSize_ -= GetChildMainAxisSize(child.layoutWrapper);
490 allocatedSize_ -= space_;
491 child.layoutWrapper->SetActive(false);
492 --validSizeCount_;
493 child.layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
494 const auto& flexItemProperty = child.layoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
495 if (flexItemProperty && GreatNotEqual(flexItemProperty->GetFlexGrow().value_or(0.0f), 0.0f)) {
496 flexItemProperties.totalGrow -= flexItemProperty->GetFlexGrow().value_or(0.0f);
497 }
498 secondaryMeasureList_.pop_back();
499 }
500 } else {
501 crossAxisSize_ = crossAxisSize;
502 }
503 ++iter;
504 }
505 } else {
506 auto magicNodeSize = magicNodes_.size();
507 auto iter = magicNodes_.rbegin();
508 while (iter != magicNodes_.rend()) {
509 auto childList = iter->second;
510 for (auto& child : childList) {
511 if (HandleBlankFirstTimeMeasure(child, flexItemProperties)) {
512 continue;
513 }
514 const auto& childLayoutWrapper = child.layoutWrapper;
515 UpdateChildLayoutConstrainByFlexBasis(direction_, childLayoutWrapper, child.layoutConstraint);
516 childLayoutWrapper->Measure(child.layoutConstraint);
517 if (child.layoutWrapper && child.layoutWrapper->GetHostNode() &&
518 child.layoutWrapper->GetHostNode()->GetLayoutProperty() &&
519 child.layoutWrapper->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) ==
520 VisibleType::GONE) {
521 continue;
522 }
523 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
524 CheckSizeValidity(childLayoutWrapper);
525 CheckBaselineProperties(childLayoutWrapper);
526 if (!isInfiniteLayout_ || GreatNotEqual(MainAxisMinValue(containerLayoutWrapper), 0.0f)) {
527 UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
528 }
529 secondaryMeasureList_.emplace_back(child);
530 }
531 if (magicNodeSize != magicNodes_.size()) {
532 LOGE("magicNodes changed during use. oldsize: %{public}zu ,newsize: %{public}zu ",
533 magicNodeSize, magicNodes_.size());
534 break;
535 }
536 ++iter;
537 }
538 allocatedSize_ -= space_;
539 }
540 }
541
HandleBlankFirstTimeMeasure(const MagicLayoutNode & child,FlexItemProperties & flexItemProperties)542 bool FlexLayoutAlgorithm::HandleBlankFirstTimeMeasure(
543 const MagicLayoutNode& child, FlexItemProperties& flexItemProperties)
544 {
545 const auto& childLayoutWrapper = child.layoutWrapper;
546 if (!(childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG &&
547 Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN))) {
548 return false;
549 }
550
551 // if constainer is self adaptive, secondaryMeasure won't happen, blank can call Measure directly
552 if (selfAdaptive_ || isInfiniteLayout_) {
553 childLayoutWrapper->Measure(child.layoutConstraint);
554 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
555 CheckSizeValidity(childLayoutWrapper);
556 if (!isInfiniteLayout_) {
557 UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
558 }
559 secondaryMeasureList_.emplace_back(child);
560 return true;
561 }
562 // to make blank components splilt remain space(not selfAdaptive)
563 // min size should not participate in the first measure of blank
564 auto mainAxisSize = 0.0f;
565 auto crossAxisSize = 0.0f;
566 auto blankLayoutProperty = childLayoutWrapper->GetLayoutProperty();
567 childLayoutWrapper->GetHostNode()->GetPattern()->BeforeCreateLayoutWrapper();
568 if (blankLayoutProperty) {
569 const auto& calcConstraint = blankLayoutProperty->GetCalcLayoutConstraint();
570 if (calcConstraint && calcConstraint->selfIdealSize.has_value()) {
571 auto size = ConvertToSize(calcConstraint->selfIdealSize.value(), child.layoutConstraint.scaleProperty,
572 child.layoutConstraint.percentReference);
573 mainAxisSize = std::max(IsHorizontal(direction_) ? size.Width() : size.Height(), 0.0f);
574 crossAxisSize = std::max(IsHorizontal(direction_) ? size.Height() : size.Width(), 0.0f);
575 }
576 }
577 childLayoutWrapper->GetGeometryNode()->SetFrameSize(
578 IsHorizontal(direction_) ? SizeF(mainAxisSize, crossAxisSize) : SizeF(crossAxisSize, mainAxisSize));
579 secondaryMeasureList_.emplace_back(child);
580 UpdateAllocatedSize(childLayoutWrapper, crossAxisSize_);
581 CheckSizeValidity(childLayoutWrapper);
582 UpdateFlexProperties(flexItemProperties, childLayoutWrapper);
583 return true;
584 }
585
UpdateFlexProperties(FlexItemProperties & flexItemProperties,const RefPtr<LayoutWrapper> & layoutWrapper)586 void FlexLayoutAlgorithm::UpdateFlexProperties(
587 FlexItemProperties& flexItemProperties, const RefPtr<LayoutWrapper>& layoutWrapper)
588 {
589 const auto& flexItemProperty = layoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
590 float flexShrink = isLinearLayoutFeature_ ? 0.0f : 1.0f;
591 float flexGrow = 0.0f;
592 if (flexItemProperty) {
593 flexShrink = flexItemProperty->GetFlexShrink().value_or(flexShrink);
594 flexGrow = flexItemProperty->GetFlexGrow().value_or(flexGrow);
595 }
596 flexItemProperties.totalGrow += flexGrow;
597 flexItemProperties.totalShrink +=
598 (flexShrink * (GetChildMainAxisSize(layoutWrapper) - GetMainAxisMargin(layoutWrapper, direction_)));
599 }
600
SecondaryMeasureByProperty(FlexItemProperties & flexItemProperties,LayoutWrapper * layoutWrapper)601 void FlexLayoutAlgorithm::SecondaryMeasureByProperty(
602 FlexItemProperties& flexItemProperties, LayoutWrapper* layoutWrapper)
603 {
604 float remainSpace = mainAxisSize_ - allocatedSize_;
605 float spacePerFlex = 0;
606 float allocatedFlexSpace = 0;
607 std::function<float(const RefPtr<LayoutWrapper>&)> getFlex;
608 RefPtr<LayoutWrapper> lastChild;
609 /**
610 * get the real cross axis size.
611 */
612 auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
613 auto paddingLeft = padding.left.value_or(0.0f);
614 auto paddingRight = padding.right.value_or(0.0f);
615 auto paddingTop = padding.top.value_or(0.0f);
616 auto paddingBottom = padding.bottom.value_or(0.0f);
617 auto crossAxisSize = crossAxisSize_;
618 if (NonNegative(selfIdealCrossAxisSize_)) {
619 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
620 crossAxisSize = selfIdealCrossAxisSize_ - paddingTop - paddingBottom;
621 } else {
622 crossAxisSize = selfIdealCrossAxisSize_ - paddingLeft - paddingRight;
623 }
624 }
625 if (Negative(crossAxisSize)) {
626 crossAxisSize = 0.0f;
627 }
628 // calculate child
629 auto iter = secondaryMeasureList_.rbegin();
630 bool needSecondMeasure = true;
631 float reserveMainAxisSize = 0.0f;
632 while (needSecondMeasure) {
633 needSecondMeasure = false;
634 // when a child's flexSize equal 0, allocatedSize need to minus its MainAxisSize
635 allocatedSize_ -= reserveMainAxisSize;
636 reserveMainAxisSize = 0.0f;
637 remainSpace = mainAxisSize_ - allocatedSize_;
638
639 iter = secondaryMeasureList_.rbegin();
640 while (iter != secondaryMeasureList_.rend()) {
641 if (!(*iter).layoutWrapper->IsActive()) {
642 remainSpace += space_;
643 }
644 ++iter;
645 }
646 CheckIsGrowOrShrink(getFlex, remainSpace, spacePerFlex, flexItemProperties, lastChild);
647 iter = secondaryMeasureList_.rbegin();
648 while (iter != secondaryMeasureList_.rend()) {
649 auto& child = *iter;
650 auto childLayoutWrapper = child.layoutWrapper;
651 if (!childLayoutWrapper) {
652 continue;
653 }
654 if (GetSelfAlign(childLayoutWrapper) == FlexAlign::STRETCH) {
655 UpdateLayoutConstraintOnCrossAxis(child.layoutConstraint, crossAxisSize);
656 child.needSecondMeasure = true;
657 }
658 if (LessOrEqual(totalFlexWeight_, 0.0f) &&
659 (!isInfiniteLayout_ || GreatNotEqual(MainAxisMinValue(layoutWrapper), 0.0f) ||
660 (childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG && !selfAdaptive_ &&
661 Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)))) {
662 if (child.needKeepMinCalcSize) {
663 ++iter;
664 continue;
665 }
666 float childMainAxisMargin = GetMainAxisMargin(childLayoutWrapper, direction_);
667 float itemFlex = getFlex(child.layoutWrapper);
668 float flexSize =
669 (child.layoutWrapper == lastChild) ? (remainSpace - allocatedFlexSpace)
670 : GreatOrEqual(remainSpace, 0.0f) || GreatNotEqual(maxDisplayPriority_, 1)
671 ? spacePerFlex * itemFlex
672 : spacePerFlex * itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
673 if (!NearZero(flexSize) && childLayoutWrapper->IsActive()) {
674 flexSize += GetChildMainAxisSize(childLayoutWrapper);
675 child.needSecondMeasure = true;
676 CheckBlankAndKeepMin(childLayoutWrapper, flexSize);
677 if (LessOrEqual(flexSize, 0.0f)) {
678 child.layoutWrapper->SetActive(false);
679 flexItemProperties.totalShrink -=
680 itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
681 reserveMainAxisSize += GetChildMainAxisSize(childLayoutWrapper);
682 needSecondMeasure = true;
683 UpdateLayoutConstraintOnMainAxis(child.layoutConstraint, 0.0f);
684 break;
685 }
686 if (IsKeepMinSize(childLayoutWrapper, flexSize)) {
687 needSecondMeasure = true;
688 auto shrinkSize = itemFlex * (GetChildMainAxisSize(childLayoutWrapper) - childMainAxisMargin);
689 reserveMainAxisSize -= (flexSize - shrinkSize);
690 child.needKeepMinCalcSize = true;
691 flexItemProperties.totalShrink -= shrinkSize;
692 }
693 UpdateLayoutConstraintOnMainAxis(child.layoutConstraint, flexSize);
694 } else if (childLayoutWrapper->GetHostTag() == V2::BLANK_ETS_TAG && NearZero(flexSize) &&
695 childLayoutWrapper->IsActive()) {
696 child.needSecondMeasure = true;
697 }
698 }
699 ++iter;
700 }
701 }
702
703 // child need to second show
704 int32_t childMeasureCount = 0;
705 iter = secondaryMeasureList_.rbegin();
706 while (iter != secondaryMeasureList_.rend()) {
707 auto child = *iter;
708 auto childLayoutWrapper = child.layoutWrapper;
709 if (!child.needSecondMeasure || !childLayoutWrapper->IsActive()) {
710 ++iter;
711 continue;
712 }
713 childLayoutWrapper->Measure(child.layoutConstraint);
714 crossAxisSize_ = std::max(crossAxisSize_, GetChildCrossAxisSize(childLayoutWrapper));
715 CheckBaselineProperties(child.layoutWrapper);
716 ++iter;
717 ++childMeasureCount;
718 }
719 // if child has secondary measure, calculate crossAxis again
720 if (childMeasureCount) {
721 float chilMaxHeight = -1.0f;
722 iter = secondaryMeasureList_.rbegin();
723 while (iter != secondaryMeasureList_.rend()) {
724 auto child = *iter;
725 auto childLayoutWrapper = child.layoutWrapper;
726 chilMaxHeight = std::max(GetChildCrossAxisSize(childLayoutWrapper), chilMaxHeight);
727 ++iter;
728 }
729 if (GreatNotEqual(chilMaxHeight, 0.0f)) {
730 crossAxisSize_ = chilMaxHeight;
731 }
732 }
733 }
734
CheckIsGrowOrShrink(std::function<float (const RefPtr<LayoutWrapper> &)> & getFlex,float remainSpace,float & spacePerFlex,FlexItemProperties & flexItemProperties,RefPtr<LayoutWrapper> & lastChild)735 void FlexLayoutAlgorithm::CheckIsGrowOrShrink(std::function<float(const RefPtr<LayoutWrapper>&)>& getFlex,
736 float remainSpace, float& spacePerFlex, FlexItemProperties& flexItemProperties, RefPtr<LayoutWrapper>& lastChild)
737 {
738 if (GreatOrEqual(remainSpace, 0.0f) || GreatNotEqual(maxDisplayPriority_, 1)) {
739 getFlex = [](const RefPtr<LayoutWrapper>& item) -> float {
740 const auto& flexItemProperty = item->GetLayoutProperty()->GetFlexItemProperty();
741 float ret = 0.0f;
742 if (flexItemProperty) {
743 ret = flexItemProperty->GetFlexGrow().value_or(ret);
744 /**
745 * handle non positive flex grow.
746 */
747 if (NonPositive(ret)) {
748 ret = 0.0f;
749 }
750 }
751 return ret;
752 };
753 spacePerFlex = NearZero(flexItemProperties.totalGrow) ? 0.0f : remainSpace / flexItemProperties.totalGrow;
754 lastChild = flexItemProperties.lastGrowChild;
755 } else {
756 getFlex = [isLinearLayoutFeature = isLinearLayoutFeature_](const RefPtr<LayoutWrapper>& item) -> float {
757 const auto& flexItemProperty = item->GetLayoutProperty()->GetFlexItemProperty();
758 float ret = isLinearLayoutFeature ? 0.0f : 1.0f;
759 if (flexItemProperty) {
760 ret = flexItemProperty->GetFlexShrink().value_or(ret);
761 /**
762 * handle non positive flex shrink.
763 */
764 if (NonPositive(ret)) {
765 ret = 0.0f;
766 }
767 }
768 return ret;
769 };
770 spacePerFlex = NearZero(flexItemProperties.totalShrink) ? 0.0f : remainSpace / flexItemProperties.totalShrink;
771 lastChild = flexItemProperties.lastShrinkChild;
772 }
773 }
774
CheckBlankAndKeepMin(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & flexSize)775 void FlexLayoutAlgorithm::CheckBlankAndKeepMin(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& flexSize)
776 {
777 auto child = childLayoutWrapper->GetHostNode();
778 if (!child) {
779 return;
780 }
781 if (child->GetTag() != V2::BLANK_ETS_TAG) {
782 return;
783 }
784 auto blankProperty = child->GetLayoutProperty<BlankLayoutProperty>();
785 CHECK_NULL_VOID(blankProperty);
786 auto blankMin = blankProperty->GetMinSize();
787 if (GreatOrEqual(blankMin->ConvertToPx(), flexSize)) {
788 flexSize = blankMin->ConvertToPx();
789 }
790 }
791
IsKeepMinSize(const RefPtr<LayoutWrapper> & childLayoutWrapper,float & flexSize)792 bool FlexLayoutAlgorithm::IsKeepMinSize(const RefPtr<LayoutWrapper>& childLayoutWrapper, float& flexSize)
793 {
794 auto child = childLayoutWrapper->GetHostNode();
795 CHECK_NULL_RETURN(child, false);
796 auto minSize = MainAxisMinValue(AceType::RawPtr(childLayoutWrapper));
797 if (GreatOrEqual(minSize, flexSize)) {
798 flexSize = minSize;
799 return true;
800 }
801 return false;
802 }
803
UpdateLayoutConstraintOnMainAxis(LayoutConstraintF & layoutConstraint,float size)804 void FlexLayoutAlgorithm::UpdateLayoutConstraintOnMainAxis(LayoutConstraintF& layoutConstraint, float size)
805 {
806 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
807 layoutConstraint.selfIdealSize.SetWidth(size);
808 } else {
809 layoutConstraint.selfIdealSize.SetHeight(size);
810 }
811 }
812
UpdateLayoutConstraintOnCrossAxis(LayoutConstraintF & layoutConstraint,float size)813 void FlexLayoutAlgorithm::UpdateLayoutConstraintOnCrossAxis(LayoutConstraintF& layoutConstraint, float size)
814 {
815 OptionalSizeF& selfIdealSize = layoutConstraint.selfIdealSize;
816 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
817 selfIdealSize.SetHeight(size);
818 } else {
819 selfIdealSize.SetWidth(size);
820 }
821 }
822
MainAxisMinValue(LayoutWrapper * layoutWrapper)823 float FlexLayoutAlgorithm::MainAxisMinValue(LayoutWrapper* layoutWrapper)
824 {
825 CHECK_NULL_RETURN(layoutWrapper, 0.0f);
826 CHECK_NULL_RETURN(layoutWrapper->GetLayoutProperty(), 0.0f);
827 auto layoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
828 CHECK_NULL_RETURN(layoutConstraint, 0.0f);
829 return IsHorizontal(direction_) ? layoutConstraint->minSize.Width() : layoutConstraint->minSize.Height();
830 }
831
MarginOnMainAxisNegative(LayoutWrapper * layoutWrapper)832 bool FlexLayoutAlgorithm::MarginOnMainAxisNegative(LayoutWrapper* layoutWrapper)
833 {
834 const auto& margin = layoutWrapper->GetGeometryNode()->GetMargin();
835 CHECK_NULL_RETURN(margin, false);
836 if (IsHorizontal(direction_)) {
837 return LessNotEqual(margin->left.value_or(0.0f) + margin->right.value_or(0.0f), 0.0f);
838 }
839 return LessNotEqual(margin->top.value_or(0.0f) + margin->bottom.value_or(0.0f), 0.0f);
840 }
841
CheckSetConstraint(const std::unique_ptr<MeasureProperty> & propertyPtr)842 bool FlexLayoutAlgorithm::CheckSetConstraint(const std::unique_ptr<MeasureProperty>& propertyPtr)
843 {
844 return propertyPtr && (propertyPtr->minSize || propertyPtr->maxSize);
845 }
846
CheckMainAxisSizeAuto(const std::unique_ptr<MeasureProperty> & calcLayoutConstraint)847 void FlexLayoutAlgorithm::CheckMainAxisSizeAuto(const std::unique_ptr<MeasureProperty>& calcLayoutConstraint)
848 {
849 if (isInfiniteLayout_) {
850 mainAxisSize_ = allocatedSize_;
851 }
852 CHECK_NULL_VOID(calcLayoutConstraint);
853 CHECK_NULL_VOID(calcLayoutConstraint->selfIdealSize);
854 if (IsHorizontal(direction_) ? calcLayoutConstraint->selfIdealSize->IsWidthDimensionUnitAuto()
855 : calcLayoutConstraint->selfIdealSize->IsHeightDimensionUnitAuto()) {
856 mainAxisSize_ = allocatedSize_;
857 }
858 }
859
Measure(LayoutWrapper * layoutWrapper)860 void FlexLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
861 {
862 const auto& children = layoutWrapper->GetAllChildrenWithBuild();
863 /**
864 * Obtain the main axis size and cross axis size based on user setting.
865 */
866 const auto& layoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
867 const auto& rawConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
868 bool needToConstraint = CheckSetConstraint(rawConstraint) && children.empty();
869 const auto& measureType = layoutWrapper->GetLayoutProperty()->GetMeasureType();
870 InitFlexProperties(layoutWrapper);
871 Axis axis = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) ? Axis::HORIZONTAL
872 : Axis::VERTICAL;
873 auto realSize = CreateIdealSizeByPercentRef(layoutConstraint.value(), axis, measureType, needToConstraint,
874 rawConstraint).ConvertToSizeT();
875 if (children.empty()) {
876 layoutWrapper->GetGeometryNode()->SetFrameSize(realSize);
877 return;
878 }
879 mainAxisSize_ = GetMainAxisSizeHelper(realSize, direction_);
880 /**
881 * The user has not set the main axis size
882 */
883 isInfiniteLayout_ = false;
884 selfAdaptive_ = false;
885 bool mainAxisInf =
886 GreaterOrEqualToInfinity(direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE
887 ? layoutConstraint->maxSize.Width()
888 : layoutConstraint->maxSize.Height()) &&
889 NearEqual(mainAxisSize_, -1.0f);
890 if (NearEqual(mainAxisSize_, -1.0f)) {
891 auto marginOnMainAxisNegative = MarginOnMainAxisNegative(layoutWrapper);
892 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
893 mainAxisSize_ = direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE
894 ? layoutConstraint->maxSize.Width()
895 : layoutConstraint->maxSize.Height();
896 } else if (isLinearLayoutFeature_ && IsHorizontal(direction_) && !NearZero(layoutConstraint->minSize.Width()) &&
897 !marginOnMainAxisNegative) {
898 mainAxisSize_ = layoutConstraint->minSize.Width();
899 } else if (isLinearLayoutFeature_ && !IsHorizontal(direction_) &&
900 !NearZero(layoutConstraint->minSize.Height()) && !marginOnMainAxisNegative) {
901 mainAxisSize_ = layoutConstraint->minSize.Height();
902 } else {
903 mainAxisSize_ =
904 direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE
905 ? (mainAxisInf ? layoutConstraint->percentReference.Width() : layoutConstraint->maxSize.Width())
906 : (mainAxisInf ? layoutConstraint->percentReference.Height() : layoutConstraint->maxSize.Height());
907 }
908 isInfiniteLayout_ = isLinearLayoutFeature_;
909 }
910 selfAdaptive_ = isLinearLayoutFeature_;
911 if (!isInfiniteLayout_) {
912 isInfiniteLayout_ = mainAxisInf;
913 }
914 auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
915 auto horizontalPadding = padding.left.value_or(0.0f) + padding.right.value_or(0.0f);
916 auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
917 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
918 mainAxisSize_ -= horizontalPadding;
919 } else {
920 mainAxisSize_ -= verticalPadding;
921 }
922 if (Negative(mainAxisSize_)) {
923 mainAxisSize_ = 0.0f;
924 }
925 TravelChildrenFlexProps(layoutWrapper, realSize);
926 selfIdealCrossAxisSize_ = GetCrossAxisSizeHelper(realSize, direction_);
927 FlexItemProperties flexItemProperties;
928
929 /**
930 * first measure
931 */
932 MeasureAndCleanMagicNodes(layoutWrapper, flexItemProperties);
933
934 /**
935 * secondary measure
936 */
937 SecondaryMeasureByProperty(flexItemProperties, layoutWrapper);
938
939 /**
940 * position property measure.
941 */
942 MeasureOutOfLayoutChildren(layoutWrapper);
943
944 AdjustTotalAllocatedSize(layoutWrapper);
945
946 /**
947 * For Row and Column, the main axis size is wrapContent.
948 * And, FlexLayoutAlgorithm, as the parent class, should not handle the special logic of the subclass LinearLayout.
949 */
950 CheckMainAxisSizeAuto(rawConstraint);
951
952 auto finalMainAxisSize = mainAxisSize_;
953 auto finalCrossAxisSize = crossAxisSize_;
954 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
955 finalCrossAxisSize += verticalPadding;
956 finalMainAxisSize += horizontalPadding;
957 } else {
958 finalCrossAxisSize += horizontalPadding;
959 finalMainAxisSize += verticalPadding;
960 }
961 auto mainAxisSizeMin = GetMainAxisSizeHelper(layoutConstraint->minSize, direction_);
962 auto mainAxisSizeMax = GetMainAxisSizeHelper(layoutConstraint->maxSize, direction_);
963 auto crossAxisSizeMin = GetCrossAxisSizeHelper(layoutConstraint->minSize, direction_);
964 auto crossAxisSizeMax = GetCrossAxisSizeHelper(layoutConstraint->maxSize, direction_);
965 finalMainAxisSize = std::clamp(
966 finalMainAxisSize, std::min(mainAxisSizeMin, mainAxisSizeMax), std::max(mainAxisSizeMin, mainAxisSizeMax));
967 finalCrossAxisSize = std::clamp(
968 finalCrossAxisSize, std::min(crossAxisSizeMin, crossAxisSizeMax), std::max(crossAxisSizeMin, crossAxisSizeMax));
969
970 realSize.UpdateIllegalSizeWithCheck(
971 GetCalcSizeHelper(finalMainAxisSize, finalCrossAxisSize, direction_).ConvertToSizeT());
972 layoutWrapper->GetGeometryNode()->SetFrameSize(realSize);
973 }
974
AdjustTotalAllocatedSize(LayoutWrapper * layoutWrapper)975 void FlexLayoutAlgorithm::AdjustTotalAllocatedSize(LayoutWrapper* layoutWrapper)
976 {
977 const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
978 if (children.empty()) {
979 allocatedSize_ = 0.0f;
980 return;
981 }
982 allocatedSize_ = 0.0f;
983 allocatedSize_ += space_ * (validSizeCount_ - 1);
984 // space is not valid when mainAxisAlign is SPACE_AROUND/SPACE_BETWEEN/SPACE_EVENLY
985 if (mainAxisAlign_ == FlexAlign::SPACE_AROUND || mainAxisAlign_ == FlexAlign::SPACE_BETWEEN ||
986 mainAxisAlign_ == FlexAlign::SPACE_EVENLY) {
987 allocatedSize_ = 0.0;
988 }
989 for (const auto& child : children) {
990 if (child->IsOutOfLayout() ||
991 (layoutWrapper && layoutWrapper->GetHostNode() && layoutWrapper->GetHostNode()->GetLayoutProperty() &&
992 child->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) ==
993 VisibleType::GONE)) {
994 continue;
995 }
996 allocatedSize_ += GetChildMainAxisSize(child);
997 }
998 }
999
1000 /**
1001 * Get cross axis size in stretch.
1002 * At this time, the cross axis size has been determined.
1003 */
GetStretchCrossAxisLimit() const1004 float FlexLayoutAlgorithm::GetStretchCrossAxisLimit() const
1005 {
1006 float crossAxisLimit = GreatNotEqual(selfIdealCrossAxisSize_, -1.0f) ? selfIdealCrossAxisSize_ : crossAxisSize_;
1007 return crossAxisLimit;
1008 }
1009
Layout(LayoutWrapper * layoutWrapper)1010 void FlexLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
1011 {
1012 const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
1013 if (children.empty()) {
1014 return;
1015 }
1016 auto layoutProperty = AceType::DynamicCast<FlexLayoutProperty>(layoutWrapper->GetLayoutProperty());
1017 CHECK_NULL_VOID(layoutProperty);
1018 space_ = static_cast<float>(layoutProperty->GetSpaceValue({}).ConvertToPx());
1019 direction_ = layoutProperty->GetFlexDirection().value_or(FlexDirection::ROW);
1020 bool isReverse = layoutProperty->GetFlexLayoutAttribute()->GetIsReverse().value_or(false);
1021 if (isReverse) {
1022 direction_ = ReverseFlexDirection(direction_);
1023 }
1024 mainAxisAlign_ = layoutProperty->GetMainAxisAlignValue(FlexAlign::FLEX_START);
1025 crossAxisAlign_ =
1026 layoutProperty->GetCrossAxisAlignValue(isLinearLayoutFeature_ ? FlexAlign::CENTER : FlexAlign::FLEX_START);
1027 textDir_ = layoutProperty->GetLayoutDirection();
1028 if (textDir_ == TextDirection::AUTO) {
1029 textDir_ = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
1030 }
1031 auto contentSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
1032 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
1033 Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)
1034 ? MinusPaddingToNonNegativeSize(padding, contentSize)
1035 : MinusPaddingToSize(padding, contentSize);
1036 mainAxisSize_ = GetMainAxisSizeHelper(contentSize, direction_);
1037 crossAxisSize_ = GetCrossAxisSizeHelper(contentSize, direction_);
1038 auto paddingOffset = OffsetF(padding.left.value_or(0.0f), padding.top.value_or(0.0f));
1039 float remainSpace = std::max(mainAxisSize_ - allocatedSize_, 0.0f);
1040 float frontSpace = 0.0f;
1041 float betweenSpace = 0.0f;
1042 CalculateSpace(remainSpace, frontSpace, betweenSpace);
1043 PlaceChildren(layoutWrapper, frontSpace, betweenSpace, paddingOffset);
1044
1045 for (auto&& child : children) {
1046 if (!child->IsOutOfLayout() && child->IsActive()) {
1047 child->Layout();
1048 }
1049 }
1050 }
1051
CalculateSpace(float remainSpace,float & frontSpace,float & betweenSpace) const1052 void FlexLayoutAlgorithm::CalculateSpace(float remainSpace, float& frontSpace, float& betweenSpace) const
1053 {
1054 switch (mainAxisAlign_) {
1055 case FlexAlign::FLEX_START:
1056 frontSpace = 0.0f;
1057 betweenSpace = space_;
1058 break;
1059 case FlexAlign::FLEX_END:
1060 frontSpace = remainSpace;
1061 betweenSpace = space_;
1062 break;
1063 case FlexAlign::CENTER:
1064 frontSpace = remainSpace / 2;
1065 betweenSpace = space_;
1066 break;
1067 case FlexAlign::SPACE_BETWEEN:
1068 frontSpace = 0.0f;
1069 betweenSpace = validSizeCount_ > 1 ? remainSpace / static_cast<float>(validSizeCount_ - 1) : 0.0f;
1070 break;
1071 case FlexAlign::SPACE_AROUND:
1072 betweenSpace = validSizeCount_ > 0 ? remainSpace / static_cast<float>(validSizeCount_) : 0.0f;
1073 frontSpace = betweenSpace / 2;
1074 break;
1075 case FlexAlign::SPACE_EVENLY:
1076 betweenSpace = validSizeCount_ > 0 ? remainSpace / static_cast<float>(validSizeCount_ + 1) : 0.0f;
1077 frontSpace = betweenSpace;
1078 break;
1079 default:
1080 break;
1081 }
1082 }
1083
PlaceChildren(LayoutWrapper * layoutWrapper,float frontSpace,float betweenSpace,const OffsetF & paddingOffset)1084 void FlexLayoutAlgorithm::PlaceChildren(
1085 LayoutWrapper* layoutWrapper, float frontSpace, float betweenSpace, const OffsetF& paddingOffset)
1086 {
1087 float childMainPos = IsStartTopLeft(direction_, textDir_) ? frontSpace : mainAxisSize_ - frontSpace;
1088 float childCrossPos = 0.0f;
1089 const auto& children = layoutWrapper->GetAllChildrenWithBuild(false);
1090 for (const auto& child : children) {
1091 if (child->IsOutOfLayout() || !child->IsActive()) {
1092 // adjust by postion property.
1093 child->GetGeometryNode()->SetMarginFrameOffset({});
1094 child->Layout();
1095 continue;
1096 }
1097 if (layoutWrapper && layoutWrapper->GetHostNode() && layoutWrapper->GetHostNode()->GetLayoutProperty() &&
1098 child->GetHostNode()->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::GONE) {
1099 continue;
1100 }
1101 auto alignItem = GetSelfAlign(child);
1102 auto crossDirection = FlipAxis(direction_);
1103 switch (alignItem) {
1104 case FlexAlign::FLEX_START:
1105 case FlexAlign::FLEX_END:
1106 childCrossPos = (IsStartTopLeft(crossDirection, textDir_) == (alignItem == FlexAlign::FLEX_START))
1107 ? 0.0f
1108 : crossAxisSize_ - GetChildCrossAxisSize(child);
1109 break;
1110 case FlexAlign::CENTER:
1111 childCrossPos = crossAxisSize_ / 2 - GetChildCrossAxisSize(child) / 2;
1112 break;
1113 case FlexAlign::STRETCH:
1114 childCrossPos =
1115 IsStartTopLeft(crossDirection, textDir_) ? 0.0f : crossAxisSize_ - GetChildCrossAxisSize(child);
1116 break;
1117 case FlexAlign::BASELINE:
1118 childCrossPos = 0.0;
1119 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
1120 float distance = child->GetBaselineDistance();
1121 childCrossPos = baselineProperties_.maxBaselineDistance - distance;
1122 }
1123 break;
1124 default:
1125 break;
1126 }
1127 OffsetF offset;
1128 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) {
1129 offset = OffsetF(childMainPos, childCrossPos);
1130 } else {
1131 offset = OffsetF(childCrossPos, childMainPos);
1132 }
1133
1134 if (!IsStartTopLeft(direction_, textDir_)) {
1135 if (direction_ != FlexDirection::COLUMN_REVERSE) {
1136 offset.SetX(offset.GetX() - GetChildMainAxisSize(child));
1137 } else {
1138 offset.SetY(offset.GetY() - GetChildMainAxisSize(child));
1139 }
1140 child->GetGeometryNode()->SetMarginFrameOffset(offset + paddingOffset);
1141 childMainPos -= GetChildMainAxisSize(child) + betweenSpace;
1142 } else {
1143 child->GetGeometryNode()->SetMarginFrameOffset(offset + paddingOffset);
1144 childMainPos += GetChildMainAxisSize(child) + betweenSpace;
1145 }
1146 }
1147 }
1148
GetSelfAlign(const RefPtr<LayoutWrapper> & layoutWrapper) const1149 FlexAlign FlexLayoutAlgorithm::GetSelfAlign(const RefPtr<LayoutWrapper>& layoutWrapper) const
1150 {
1151 const auto& flexItemProperty = layoutWrapper->GetLayoutProperty()->GetFlexItemProperty();
1152 FlexAlign crossAxisAlign = (crossAxisAlign_ == FlexAlign::AUTO) ? FlexAlign::FLEX_START : crossAxisAlign_;
1153 if (!flexItemProperty || !flexItemProperty->GetAlignSelf().has_value() ||
1154 flexItemProperty->GetAlignSelf().value_or(crossAxisAlign_) == FlexAlign::AUTO) {
1155 return crossAxisAlign;
1156 }
1157 return flexItemProperty->GetAlignSelf().value_or(crossAxisAlign);
1158 }
1159
1160 } // namespace OHOS::Ace::NG
1161