• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/wrap_layout_algorithm.h"
17 
18 #include <algorithm>
19 
20 #include "base/geometry/axis.h"
21 #include "base/geometry/ng/size_t.h"
22 #include "base/log/ace_trace.h"
23 #include "base/memory/referenced.h"
24 #include "base/utils/utils.h"
25 #include "core/components/common/layout/constants.h"
26 #include "core/components/common/properties/alignment.h"
27 #include "core/components_ng/base/frame_node.h"
28 #include "core/components_ng/base/geometry_node.h"
29 #include "core/components_ng/layout/layout_property.h"
30 #include "core/components_ng/layout/layout_wrapper.h"
31 #include "core/components_ng/pattern/flex/flex_layout_property.h"
32 #include "core/components_ng/property/layout_constraint.h"
33 #include "core/components_ng/property/measure_property.h"
34 #include "core/components_ng/property/measure_utils.h"
35 
36 namespace OHOS::Ace::NG {
37 
Measure(LayoutWrapper * layoutWrapper)38 void WrapLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
39 {
40     CHECK_NULL_VOID(layoutWrapper);
41     auto children = layoutWrapper->GetAllChildrenWithBuild();
42     if (children.empty()) {
43         layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF());
44         return;
45     }
46     outOfLayoutChildren_.clear();
47     auto flexProp = AceType::DynamicCast<FlexLayoutProperty>(layoutWrapper->GetLayoutProperty());
48     CHECK_NULL_VOID(flexProp);
49     direction_ = flexProp->GetWrapDirection().value_or(WrapDirection::HORIZONTAL);
50     // alignment for alignContent, alignment when cross axis has extra space
51     alignment_ = flexProp->GetAlignment().value_or(WrapAlignment::START);
52     // alignment for justifyContent, main axis alignment
53     mainAlignment_ = flexProp->GetMainAlignment().value_or(WrapAlignment::START);
54     // alignment for alignItems, crossAxisAlignment
55     crossAlignment_ = flexProp->GetCrossAlignment().value_or(WrapAlignment::START);
56     isHorizontal_ = direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE;
57     isReverse_ = direction_ == WrapDirection::HORIZONTAL_REVERSE || direction_ == WrapDirection::VERTICAL_REVERSE;
58     PerformLayoutInitialize(flexProp);
59     totalMainLength_ = 0.0f;
60     totalCrossLength_ = 0.0f;
61     auto realMaxSize = GetLeftSize(0.0f, mainLengthLimit_, crossLengthLimit_);
62     auto childLayoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
63     padding_ = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
64     MinusPaddingToSize(padding_, realMaxSize);
65     mainLengthLimit_ = GetMainAxisLengthOfSize(realMaxSize);
66     crossLengthLimit_ = GetCrossAxisLengthOfSize(realMaxSize);
67     childLayoutConstraint.UpdateMaxSizeWithCheck(realMaxSize);
68     childLayoutConstraint.UpdateMinSizeWithCheck(SizeF(0.0f, 0.0f));
69     if (isDialogStretch_) {
70         HandleDialogStretch();
71         return;
72     }
73     auto spacing = static_cast<float>(spacing_.ConvertToPx());
74     auto contentSpace = static_cast<float>(contentSpace_.ConvertToPx());
75     float currentMainLength = 0.0f;
76     float currentCrossLength = 0.0f;
77     int32_t currentItemCount = 0;
78     float baselineDistance = 0.0f;
79     contentList_.clear();
80     std::list<RefPtr<LayoutWrapper>> currentMainAxisItemsList;
81     for (auto& item : children) {
82         if (item->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::GONE) {
83             continue;
84         }
85         item->Measure(childLayoutConstraint);
86         if (item->IsOutOfLayout()) {
87             outOfLayoutChildren_.emplace_back(item);
88             continue;
89         }
90         // can place current child at current row
91         if (mainLengthLimit_ >= currentMainLength + GetItemMainAxisLength(item->GetGeometryNode())) {
92             currentMainLength += GetItemMainAxisLength(item->GetGeometryNode());
93             currentMainLength += spacing;
94             currentCrossLength = std::max(currentCrossLength, GetItemCrossAxisLength(item->GetGeometryNode()));
95             if (crossAlignment_ == WrapAlignment::BASELINE) {
96                 baselineDistance = std::max(baselineDistance, item->GetBaselineDistance());
97             }
98             currentMainAxisItemsList.emplace_back(item);
99             currentItemCount += 1;
100         } else {
101             // after finish processing previous row, reverse align order if developer meant to
102             currentMainLength -= spacing;
103             // save info of current main axis items into struct
104             auto contentInfo =
105                 ContentInfo(currentMainLength, currentCrossLength, currentItemCount, currentMainAxisItemsList);
106             contentInfo.maxBaselineDistance = baselineDistance;
107             // measure items again if cross axis alignment is stretch
108             // and a item has main axis size differ than content height
109             StretchItemsInContent(layoutWrapper, contentInfo);
110             contentList_.emplace_back(contentInfo);
111             currentMainAxisItemsList.clear();
112             // place current item on a new main axis
113             totalMainLength_ = std::max(currentMainLength, totalMainLength_);
114             totalCrossLength_ += currentCrossLength + contentSpace;
115             currentMainLength = GetItemMainAxisLength(item->GetGeometryNode()) + spacing;
116             currentCrossLength = GetItemCrossAxisLength(item->GetGeometryNode());
117             if (crossAlignment_ == WrapAlignment::BASELINE) {
118                 baselineDistance = item->GetBaselineDistance();
119             }
120             currentMainAxisItemsList.emplace_back(item);
121             currentItemCount = 1;
122         }
123     }
124     if (currentItemCount != 0) {
125         // Add last content into list
126         currentMainLength -= spacing;
127         auto contentInfo =
128             ContentInfo(currentMainLength, currentCrossLength, currentItemCount, currentMainAxisItemsList);
129         contentInfo.maxBaselineDistance = baselineDistance;
130         StretchItemsInContent(layoutWrapper, contentInfo);
131         contentList_.emplace_back(contentInfo);
132         totalMainLength_ = std::max(currentMainLength, totalMainLength_);
133         totalCrossLength_ += currentCrossLength;
134     }
135     if (isHorizontal_) {
136         frameSize_ = SizeF(mainLengthLimit_, hasIdealHeight_ ? crossLengthLimit_ : totalCrossLength_);
137     } else {
138         frameSize_ = SizeF(hasIdealWidth_ ? crossLengthLimit_ : totalCrossLength_, mainLengthLimit_);
139     }
140     AddPaddingToSize(padding_, frameSize_);
141     layoutWrapper->GetGeometryNode()->SetFrameSize(frameSize_);
142     frameOffset_ = layoutWrapper->GetGeometryNode()->GetFrameOffset();
143 }
144 
GetMainAxisLengthOfSize(const SizeF & size) const145 float WrapLayoutAlgorithm::GetMainAxisLengthOfSize(const SizeF& size) const
146 {
147     if (!isHorizontal_) {
148         return size.Height();
149     }
150     return size.Width();
151 }
152 
GetCrossAxisLengthOfSize(const SizeF & size) const153 float WrapLayoutAlgorithm::GetCrossAxisLengthOfSize(const SizeF& size) const
154 {
155     if (!isHorizontal_) {
156         return size.Width();
157     }
158     return size.Height();
159 }
160 
StretchItemsInContent(LayoutWrapper * layoutWrapper,const ContentInfo & content)161 void WrapLayoutAlgorithm::StretchItemsInContent(LayoutWrapper* layoutWrapper, const ContentInfo& content)
162 {
163     if (crossAlignment_ != WrapAlignment::STRETCH) {
164         return;
165     }
166     auto childLayoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
167     for (const auto& item : content.itemList) {
168         auto itemCrossAxisLength = GetItemCrossAxisLength(item->GetGeometryNode());
169         // if content cross axis size is larger than item cross axis size,
170         // measure items again with content cross axis size as ideal size
171         if (GreatNotEqual(content.crossLength, itemCrossAxisLength)) {
172             if (isHorizontal_) {
173                 childLayoutConstraint.selfIdealSize.SetHeight(content.crossLength);
174             } else {
175                 childLayoutConstraint.selfIdealSize.SetWidth(content.crossLength);
176             }
177             item->Measure(childLayoutConstraint);
178         }
179     }
180 }
181 
Layout(LayoutWrapper * layoutWrapper)182 void WrapLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
183 {
184     auto children = layoutWrapper->GetAllChildrenWithBuild();
185     if (children.empty()) {
186         LOGE("WrapLayoutAlgorithm::Layout, children is empty");
187         return;
188     }
189     OffsetF startPosition;
190     OffsetF spaceBetweenContentsOnCrossAxis;
191     LayoutWholeWrap(startPosition, spaceBetweenContentsOnCrossAxis, layoutWrapper);
192     TraverseContent(startPosition, spaceBetweenContentsOnCrossAxis);
193     for (const auto& child : children) {
194         child->Layout();
195     }
196     contentList_.clear();
197 }
198 
HandleDialogStretch()199 void WrapLayoutAlgorithm::HandleDialogStretch()
200 {
201     // TODO: Not completed.
202 }
203 
PerformLayoutInitialize(const RefPtr<LayoutProperty> & layoutProp)204 void WrapLayoutAlgorithm::PerformLayoutInitialize(const RefPtr<LayoutProperty>& layoutProp)
205 {
206     CHECK_NULL_VOID(layoutProp);
207     auto constraint = layoutProp->GetLayoutConstraint();
208     // if flex width and height is not set, wrap is as large as children, no need to set alignment_.
209     if (constraint->selfIdealSize.Height() || constraint->selfIdealSize.Width()) {
210         auto widthValue = constraint->selfIdealSize.Width();
211         auto heightValue = constraint->selfIdealSize.Height();
212         hasIdealWidth_ = widthValue.has_value();
213         hasIdealHeight_ = heightValue.has_value();
214         if (isHorizontal_) {
215             mainLengthLimit_ = hasIdealWidth_ ? widthValue.value() : constraint->maxSize.Width();
216             crossLengthLimit_ = hasIdealHeight_ ? heightValue.value() : constraint->maxSize.Height();
217         } else {
218             mainLengthLimit_ = hasIdealHeight_ ? heightValue.value() : constraint->maxSize.Height();
219             crossLengthLimit_ = hasIdealWidth_ ? widthValue.value() : constraint->maxSize.Width();
220         }
221         return;
222     }
223     if (isHorizontal_) {
224         mainLengthLimit_ = constraint->maxSize.Width();
225         crossLengthLimit_ = constraint->maxSize.Height();
226     } else {
227         mainLengthLimit_ = constraint->maxSize.Height();
228         crossLengthLimit_ = constraint->maxSize.Width();
229     }
230 }
231 
GetLeftSize(float crossLength,float mainLeftLength,float crossLeftLength)232 SizeF WrapLayoutAlgorithm::GetLeftSize(float crossLength, float mainLeftLength, float crossLeftLength)
233 {
234     if (isHorizontal_) {
235         return SizeF(mainLeftLength, crossLeftLength - crossLength);
236     }
237     return SizeF(crossLeftLength - crossLength, mainLeftLength);
238 }
239 
GetItemMainAxisLength(const RefPtr<GeometryNode> & item) const240 float WrapLayoutAlgorithm::GetItemMainAxisLength(const RefPtr<GeometryNode>& item) const
241 {
242     return isHorizontal_ ? item->GetMarginFrameSize().Width() : item->GetMarginFrameSize().Height();
243 }
244 
GetItemCrossAxisLength(const RefPtr<GeometryNode> & item) const245 float WrapLayoutAlgorithm::GetItemCrossAxisLength(const RefPtr<GeometryNode>& item) const
246 {
247     return !isHorizontal_ ? item->GetMarginFrameSize().Width() : item->GetMarginFrameSize().Height();
248 }
249 
AddPaddingToStartPosition(OffsetF & startPosition) const250 void WrapLayoutAlgorithm::AddPaddingToStartPosition(OffsetF& startPosition) const
251 {
252     switch (direction_) {
253         // horizontal or vertical will start from top left
254         case WrapDirection::HORIZONTAL:
255         case WrapDirection::VERTICAL:
256             startPosition.AddX(padding_.left.value_or(0.0f));
257             startPosition.AddY(padding_.top.value_or(0.0f));
258             break;
259         case WrapDirection::HORIZONTAL_REVERSE:
260             startPosition.AddX(-padding_.right.value_or(0.0f));
261             startPosition.AddY(padding_.top.value_or(0.0f));
262             break;
263         case WrapDirection::VERTICAL_REVERSE:
264             startPosition.AddX(padding_.left.value_or(0.0f));
265             startPosition.AddY(-padding_.bottom.value_or(0.0f));
266             break;
267         default:
268             LOGW("Unknown direction");
269     }
270 }
271 
AddExtraSpaceToStartPosition(OffsetF & startPosition,float extraSpace,bool onMainAxis) const272 void WrapLayoutAlgorithm::AddExtraSpaceToStartPosition(OffsetF& startPosition, float extraSpace, bool onMainAxis) const
273 {
274     if (isReverse_) {
275         extraSpace = -extraSpace;
276     }
277     if (onMainAxis) {
278         if (isHorizontal_) {
279             startPosition.AddX(extraSpace);
280         } else {
281             startPosition.AddY(extraSpace);
282         }
283         return;
284     }
285     if (isHorizontal_) {
286         startPosition.AddY(extraSpace);
287         return;
288     }
289     startPosition.AddX(extraSpace);
290 }
291 
LayoutWholeWrap(OffsetF & startPosition,OffsetF & spaceBetweenContentsOnCrossAxis,LayoutWrapper * layoutWrapper)292 void WrapLayoutAlgorithm::LayoutWholeWrap(
293     OffsetF& startPosition, OffsetF& spaceBetweenContentsOnCrossAxis, LayoutWrapper* layoutWrapper)
294 {
295     auto contentNum = static_cast<int32_t>(contentList_.size());
296     if (contentNum == 0) {
297         LOGW("no content in wrap");
298         return;
299     }
300 
301     const auto& layoutProp = layoutWrapper->GetLayoutProperty();
302     CHECK_NULL_VOID(layoutProp);
303     AddPaddingToStartPosition(startPosition);
304     if (isReverse_) {
305         AddExtraSpaceToStartPosition(startPosition, isHorizontal_ ? -frameSize_.Width() : -frameSize_.Height(), true);
306     }
307     // if cross axis size is not set, cross axis size is as large as children cross axis size sum
308     // no need to set alignment_.
309     if ((!isHorizontal_ && hasIdealWidth_ && crossLengthLimit_ <= totalCrossLength_) ||
310         (!isHorizontal_ && !hasIdealWidth_)) {
311         LOGD("Cross axis size does not support alignContent, use start");
312         return;
313     }
314     if ((isHorizontal_ && hasIdealHeight_ && crossLengthLimit_ <= totalCrossLength_) ||
315         (isHorizontal_ && !hasIdealHeight_)) {
316         LOGD("Cross axis size does not support alignContent, use start");
317         return;
318     }
319 
320     auto crossAxisRemainSpace = crossLengthLimit_ - totalCrossLength_;
321 
322     if (isReverse_) {
323         crossAxisRemainSpace = -crossAxisRemainSpace;
324     }
325     // switch align content enum, alignment when extra space exists in container extra spaces
326 
327     switch (alignment_) {
328         case WrapAlignment::START:
329             break;
330         // for reverse cases, start position will not include "first" item's main axis size
331         case WrapAlignment::END: {
332             AddExtraSpaceToStartPosition(startPosition, crossAxisRemainSpace, false);
333             break;
334         }
335         case WrapAlignment::CENTER: {
336             // divided the space by two
337             crossAxisRemainSpace /= 2.0f;
338             AddExtraSpaceToStartPosition(startPosition, crossAxisRemainSpace, false);
339             break;
340         }
341         case WrapAlignment::SPACE_BETWEEN: {
342             // space between will not affect start position, update space between only
343             float crossSpace =
344                 contentNum > 1 ? (crossLengthLimit_ - totalCrossLength_) / static_cast<float>(contentNum - 1) : 0.0f;
345             spaceBetweenContentsOnCrossAxis = isHorizontal_ ? OffsetF(0.0f, crossSpace) : OffsetF(crossSpace, 0.0f);
346             break;
347         }
348         case WrapAlignment::SPACE_EVENLY: {
349             float crossSpace = crossAxisRemainSpace / static_cast<float>(contentNum + 1);
350             AddExtraSpaceToStartPosition(startPosition, crossSpace, false);
351             spaceBetweenContentsOnCrossAxis =
352                 isHorizontal_ ? OffsetF(0.0f, std::abs(crossSpace)) : OffsetF(std::abs(crossSpace), 0.0f);
353             break;
354         }
355         case WrapAlignment::SPACE_AROUND: {
356             float crossSpace = crossAxisRemainSpace / static_cast<float>(contentNum);
357             AddExtraSpaceToStartPosition(startPosition, crossSpace / 2.0f, false);
358             spaceBetweenContentsOnCrossAxis =
359                 isHorizontal_ ? OffsetF(0.0f, std::abs(crossSpace)) : OffsetF(std::abs(crossSpace), 0.0);
360             break;
361         }
362         default: {
363             LOGE("Wrap::alignment setting error.");
364             break;
365         }
366     }
367 }
368 
GetMainAxisRemainSpace(float totalMainLength) const369 SizeF WrapLayoutAlgorithm::GetMainAxisRemainSpace(float totalMainLength) const
370 {
371     if (isHorizontal_) {
372         return SizeF(mainLengthLimit_ - totalMainLength, 0.0f);
373     }
374     return SizeF(0.0f, mainLengthLimit_ - totalMainLength);
375 }
376 
GetCrossAxisRemainSpace(float totalCrossLength) const377 SizeF WrapLayoutAlgorithm::GetCrossAxisRemainSpace(float totalCrossLength) const
378 {
379     if (isHorizontal_) {
380         return SizeF(0.0f, crossLengthLimit_ - totalCrossLength);
381     }
382     return SizeF(crossLengthLimit_ - totalCrossLength, 0.0f);
383 }
384 
GetMainAxisOffset(const OffsetF & offset) const385 float WrapLayoutAlgorithm::GetMainAxisOffset(const OffsetF& offset) const
386 {
387     if (isHorizontal_) {
388         return offset.GetX();
389     }
390     return offset.GetY();
391 }
392 
GetCrossAxisOffset(const OffsetF & offset) const393 float WrapLayoutAlgorithm::GetCrossAxisOffset(const OffsetF& offset) const
394 {
395     if (isHorizontal_) {
396         return offset.GetY();
397     }
398     return offset.GetX();
399 }
400 
TraverseContent(const OffsetF & startPosition,const OffsetF & spaceBetweenContentsOnCrossAxis)401 void WrapLayoutAlgorithm::TraverseContent(const OffsetF& startPosition, const OffsetF& spaceBetweenContentsOnCrossAxis)
402 {
403     // determine the content start position by main axis
404     OffsetF contentPosition(startPosition.GetX(), startPosition.GetY());
405     auto contentSpace = static_cast<float>(contentSpace_.ConvertToPx());
406     auto spaceBetween = isHorizontal_ ? spaceBetweenContentsOnCrossAxis.GetY() : spaceBetweenContentsOnCrossAxis.GetX();
407     for (const auto& content : contentList_) {
408         LOGD("Content position %{public}s", contentPosition.ToString().c_str());
409         LayoutContent(content, contentPosition);
410         if (isHorizontal_) {
411             contentPosition.AddY(content.crossLength + contentSpace + spaceBetween);
412         } else {
413             contentPosition.AddX(content.crossLength + contentSpace + spaceBetween);
414         }
415     }
416 }
417 
GetItemMainOffset(float mainSpace) const418 OffsetF WrapLayoutAlgorithm::GetItemMainOffset(float mainSpace) const
419 {
420     // calculate the offset of each item in content
421     if (isHorizontal_) {
422         return OffsetF(mainSpace, 0.0);
423     }
424     return OffsetF(0.0, mainSpace);
425 }
426 
CalcItemCrossAxisOffset(const ContentInfo & content,const OffsetF & contentOffset,const RefPtr<GeometryNode> & node)427 float WrapLayoutAlgorithm::CalcItemCrossAxisOffset(
428     const ContentInfo& content, const OffsetF& contentOffset, const RefPtr<GeometryNode>& node)
429 {
430     switch (crossAlignment_) {
431         case WrapAlignment::START:
432         // stretch has been processed in measure, result is the same as start
433         case WrapAlignment::STRETCH: {
434             if (isHorizontal_) {
435                 return contentOffset.GetY();
436             }
437             return contentOffset.GetX();
438         }
439         case WrapAlignment::END: {
440             auto itemFrameSize = node->GetMarginFrameSize();
441             if (isHorizontal_) {
442                 return contentOffset.GetY() + content.crossLength - itemFrameSize.Height();
443             }
444             return contentOffset.GetX() + content.crossLength - itemFrameSize.Width();
445         }
446         case WrapAlignment::CENTER: {
447             // divide the space by two
448             auto itemFrameSize = node->GetMarginFrameSize();
449             if (isHorizontal_) {
450                 return contentOffset.GetY() + (content.crossLength - itemFrameSize.Height()) / 2.0f;
451             }
452             return contentOffset.GetX() + (content.crossLength - itemFrameSize.Width()) / 2.0f;
453         }
454         case WrapAlignment::BASELINE: {
455             // TODO: Complete baseline
456             break;
457         }
458         default: {
459             LOGW("Unknown alignment, use start alignment");
460             if (isHorizontal_) {
461                 return contentOffset.GetY();
462             }
463             return contentOffset.GetX();
464 
465             break;
466         }
467     }
468     if (isHorizontal_) {
469         return contentOffset.GetY();
470     }
471     return contentOffset.GetX();
472 }
473 
CalcItemMainAxisStartAndSpaceBetween(OffsetF & startPosition,OffsetF & spaceBetweenItemsOnMainAxis,const ContentInfo & content)474 void WrapLayoutAlgorithm::CalcItemMainAxisStartAndSpaceBetween(
475     OffsetF& startPosition, OffsetF& spaceBetweenItemsOnMainAxis, const ContentInfo& content)
476 {
477     // switch align content enum, alignment when extra space exists in container extra spaces
478     float spaceLeftOnMainAxis = mainLengthLimit_ - content.mainLength;
479     switch (mainAlignment_) {
480         case WrapAlignment::START:
481             break;
482         case WrapAlignment::END: {
483             AddExtraSpaceToStartPosition(startPosition, spaceLeftOnMainAxis, true);
484             break;
485         }
486         case WrapAlignment::CENTER: {
487             AddExtraSpaceToStartPosition(startPosition, spaceLeftOnMainAxis / 2.0f, true);
488             break;
489         }
490         case WrapAlignment::SPACE_BETWEEN: {
491             float mainSpace = content.count > 1 ? spaceLeftOnMainAxis / static_cast<float>(content.count - 1) : 0.0f;
492             spaceBetweenItemsOnMainAxis = isHorizontal_ ? OffsetF(mainSpace, 0.0f) : OffsetF(0.0f, mainSpace);
493             break;
494         }
495         case WrapAlignment::SPACE_EVENLY: {
496             float mainSpace = spaceLeftOnMainAxis / static_cast<float>(content.count + 1);
497             AddExtraSpaceToStartPosition(startPosition, mainSpace, true);
498             spaceBetweenItemsOnMainAxis = isHorizontal_ ? OffsetF(mainSpace, 0.0f) : OffsetF(0.0f, mainSpace);
499             break;
500         }
501         case WrapAlignment::SPACE_AROUND: {
502             float mainSpace = spaceLeftOnMainAxis / static_cast<float>(content.count);
503             AddExtraSpaceToStartPosition(startPosition, mainSpace / 2.0f, true);
504             spaceBetweenItemsOnMainAxis = isHorizontal_ ? OffsetF(mainSpace, 0.0f) : OffsetF(0.0f, mainSpace);
505             break;
506         }
507         default: {
508             LOGE("Wrap::alignment setting error.");
509             break;
510         }
511     }
512 }
513 
LayoutContent(const ContentInfo & content,const OffsetF & position)514 void WrapLayoutAlgorithm::LayoutContent(const ContentInfo& content, const OffsetF& position)
515 {
516     int32_t itemNum = content.count;
517     if (itemNum == 0) {
518         LOGW("No item in current content struct");
519         return;
520     }
521     OffsetF contentStartPosition(position.GetX(), position.GetY());
522     OffsetF spaceBetweenItemsOnMainAxis;
523     CalcItemMainAxisStartAndSpaceBetween(contentStartPosition, spaceBetweenItemsOnMainAxis, content);
524 
525     FlexItemProperties flexItemProperties;
526     GetFlexItemProperties(content, flexItemProperties);
527     float remainSpace = mainLengthLimit_ - currentMainLength_;
528     for (const auto& itemWrapper : content.itemList) {
529         auto item = itemWrapper->GetGeometryNode();
530         if (GreatNotEqual(remainSpace, 0.0f)) {
531             CalcFlexGrowLayout(itemWrapper, flexItemProperties, remainSpace);
532         }
533         // calc start position and between space
534         auto itemMainAxisOffset = isHorizontal_ ? contentStartPosition.GetX() : contentStartPosition.GetY();
535         if (isReverse_) {
536             itemMainAxisOffset -= GetItemMainAxisLength(item);
537         }
538         auto itemCrossAxisOffset = CalcItemCrossAxisOffset(content, contentStartPosition, item);
539         OffsetF offset;
540         float contentMainAxisSpan = 0.0f;
541         if (isHorizontal_) {
542             offset = OffsetF(itemMainAxisOffset, itemCrossAxisOffset);
543             contentMainAxisSpan = item->GetMarginFrameSize().Width() + static_cast<float>(spacing_.ConvertToPx()) +
544                                   spaceBetweenItemsOnMainAxis.GetX();
545             contentStartPosition.AddX(isReverse_ ? -contentMainAxisSpan : contentMainAxisSpan);
546         } else {
547             offset = OffsetF(itemCrossAxisOffset, itemMainAxisOffset);
548             contentMainAxisSpan = item->GetMarginFrameSize().Height() + static_cast<float>(spacing_.ConvertToPx()) +
549                                   spaceBetweenItemsOnMainAxis.GetY();
550             contentStartPosition.AddY(isReverse_ ? -contentMainAxisSpan : contentMainAxisSpan);
551         }
552         itemWrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
553         LOGD("Node %{public}s offset %{public}s", itemWrapper->GetHostTag().c_str(), offset.ToString().c_str());
554     }
555 }
556 
GetFlexItemProperties(const ContentInfo & content,FlexItemProperties & flexItemProperties)557 void WrapLayoutAlgorithm::GetFlexItemProperties(const ContentInfo& content, FlexItemProperties& flexItemProperties)
558 {
559     auto spacing = static_cast<float>(spacing_.ConvertToPx());
560     currentMainLength_ = 0.0f;
561     for (const auto& itemWrapper : content.itemList) {
562         if (!itemWrapper) {
563             continue;
564         }
565         currentMainLength_ += GetItemMainAxisLength(itemWrapper->GetGeometryNode()) + spacing;
566         auto layoutProperty = itemWrapper->GetLayoutProperty();
567         if (!layoutProperty) {
568             continue;
569         }
570         const auto& flexItemProperty = layoutProperty->GetFlexItemProperty();
571         if (!flexItemProperty) {
572             continue;
573         }
574         auto flexGrow = flexItemProperty->GetFlexGrow().value_or(0.0f);
575         if (GreatNotEqual(flexGrow, 0.0f)) {
576             flexItemProperties.totalGrow += flexGrow;
577         }
578     }
579 }
580 
CalcFlexGrowLayout(const RefPtr<LayoutWrapper> & itemWrapper,const FlexItemProperties & flexItemProperties,float remainSpace)581 void WrapLayoutAlgorithm::CalcFlexGrowLayout(
582     const RefPtr<LayoutWrapper>& itemWrapper, const FlexItemProperties& flexItemProperties, float remainSpace)
583 {
584     CHECK_NULL_VOID(itemWrapper);
585     auto layoutProperty = itemWrapper->GetLayoutProperty();
586     CHECK_NULL_VOID(layoutProperty);
587     auto& flexItemProperty = layoutProperty->GetFlexItemProperty();
588     CHECK_NULL_VOID_NOLOG(flexItemProperty);
589     auto layoutConstraint = layoutProperty->GetLayoutConstraint();
590     if (!layoutConstraint.has_value()) {
591         return;
592     }
593 
594     auto layoutConstraintValue = layoutConstraint.value();
595     float itemFlex = flexItemProperty->GetFlexGrow().value_or(0.0f);
596     if (GreatNotEqual(itemFlex, 0.0f) && GreatNotEqual(remainSpace, 0.0f) &&
597         GreatNotEqual(flexItemProperties.totalGrow, 0.0f)) {
598         float flexSize = itemFlex * remainSpace / flexItemProperties.totalGrow;
599         flexSize += GetItemMainAxisLength(itemWrapper->GetGeometryNode());
600         OptionalSizeF& selfIdealSize = layoutConstraintValue.selfIdealSize;
601         if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
602             selfIdealSize.SetWidth(flexSize);
603         } else {
604             selfIdealSize.SetHeight(flexSize);
605         }
606         itemWrapper->Measure(layoutConstraintValue);
607     }
608 }
609 
610 } // namespace OHOS::Ace::NG
611