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