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