• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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/wrap/render_wrap.h"
17 
18 #include "core/components/marquee/render_marquee.h"
19 #include "core/components/progress/render_progress.h"
20 #include "core/components/search/render_search.h"
21 #include "core/components/slider/render_slider.h"
22 #include "core/components/wrap/wrap_component.h"
23 
24 namespace OHOS::Ace {
25 namespace {
26 
27 constexpr int32_t MIN_COMPATIBLE_VERSION = 6;
28 
29 }
30 
Create()31 RefPtr<RenderNode> RenderWrap::Create()
32 {
33     return AceType::MakeRefPtr<RenderWrap>();
34 }
35 
Update(const RefPtr<Component> & component)36 void RenderWrap::Update(const RefPtr<Component>& component)
37 {
38     const RefPtr<WrapComponent> wrap = AceType::DynamicCast<WrapComponent>(component);
39     if (!wrap) {
40         LOGE("Wrap::RenderWrap update dynamicCast to nullptr error");
41         return;
42     }
43     direction_ = wrap->GetDirection();
44     // Whole alignment
45     alignment_ = wrap->GetAlignment();
46     // content main alignment
47     mainAlignment_ = wrap->GetMainAlignment();
48     // content cross alignment
49     crossAlignment_ = wrap->GetCrossAlignment();
50     spacing_ = wrap->GetSpacing();
51     contentSpace_ = wrap->GetContentSpacing();
52     dialogStretch_ = wrap->GetDialogStretch();
53     horizontalMeasure_ = wrap->GetHorizontalMeasure();
54     verticalMeasure_ = wrap->GetVerticalMeasure();
55     SetTextDirection(wrap->GetTextDirection());
56     isLeftToRight_ = (wrap->GetTextDirection() == TextDirection::LTR);
57     contentList_.clear();
58     MarkNeedLayout();
59 }
60 
PerformLayout()61 void RenderWrap::PerformLayout()
62 {
63     if (GetChildren().empty()) {
64         // no child will set current to empty and return
65         SetLayoutSize(Size(0.0, 0.0));
66         return;
67     }
68 
69     PerformLayoutInitialize();
70 
71     // overall size including space
72     totalMainLength_ = 0.0;
73     totalCrossLength_ = 0.0;
74 
75     LayoutParam layoutParam;
76     layoutParam.SetMinSize(Size(0.0, 0.0));
77     layoutParam.SetMaxSize(GetLeftSize(0.0, mainLengthLimit_, crossLengthLimit_));
78     if (dialogStretch_) {
79         HandleDialogStretch(layoutParam);
80     } else {
81         auto spacing = NormalizeToPx(spacing_);
82         auto contentSpace = NormalizeToPx(contentSpace_);
83         // content size
84         double currentMainLength = 0.0;
85         // the cross length is without space
86         double currentCrossLength = 0.0;
87         // number of item in content
88         int32_t count = 0;
89         // max baseline of each line
90         double baselineDistance = 0.0;
91         std::list<RefPtr<RenderNode>> itemsList;
92         bool beforeIsBlock = false;
93         double beforeMarginBottom = 0.0;
94 
95         for (auto& item : GetChildren()) {
96             auto flexItem = AceType::DynamicCast<RenderFlexItem>(item);
97             if (flexItem &&
98                 (flexItem->GetDisplayType() == DisplayType::BLOCK)) {
99                 CalculateMargin(item, beforeIsBlock, beforeMarginBottom);
100                 item->Layout(layoutParam);
101                 AddBlock(count, item, itemsList, currentMainLength, currentCrossLength, baselineDistance);
102                 continue;
103             } else if (flexItem && flexItem->GetDisplayType() == DisplayType::INLINE) {
104                 beforeIsBlock = false;
105                 beforeMarginBottom = 0.0;
106                 SetDefault(item);
107                 item->Layout(layoutParam);
108             } else {
109                 beforeIsBlock = false;
110                 beforeMarginBottom = 0.0;
111                 item->Layout(layoutParam);
112             }
113 
114             if (mainLengthLimit_ >= currentMainLength + GetMainItemLength(item)) {
115                 currentMainLength += GetMainItemLength(item);
116                 currentMainLength += spacing;
117                 currentCrossLength = std::max(currentCrossLength, GetCrossItemLength(item));
118                 if (crossAlignment_ == WrapAlignment::BASELINE) {
119                     baselineDistance = std::max(baselineDistance, item->GetBaselineDistance(TextBaseline::ALPHABETIC));
120                 }
121                 itemsList.push_back(item);
122                 count += 1;
123             } else {
124                 currentMainLength -= spacing;
125                 if ((direction_ == WrapDirection::HORIZONTAL && !isLeftToRight_) ||
126                     (direction_ == WrapDirection::HORIZONTAL_REVERSE && isLeftToRight_) ||
127                     direction_ == WrapDirection::VERTICAL_REVERSE) {
128                     itemsList.reverse();
129                 }
130                 auto contentInfo = ContentInfo(currentMainLength, currentCrossLength, count, itemsList);
131                 contentInfo.maxBaselineDistance = baselineDistance;
132                 contentList_.emplace_back(contentInfo);
133                 itemsList.clear();
134                 totalMainLength_ = std::max(currentMainLength, totalMainLength_);
135                 totalCrossLength_ += currentCrossLength + contentSpace;
136                 currentMainLength = GetMainItemLength(item) + spacing;
137                 currentCrossLength = GetCrossItemLength(item);
138                 if (crossAlignment_ == WrapAlignment::BASELINE) {
139                     baselineDistance = item->GetBaselineDistance(TextBaseline::ALPHABETIC);
140                 }
141                 itemsList.push_back(item);
142                 count = 1;
143             }
144         }
145         if (count != 0) {
146             // Add last content into list
147             currentMainLength -= spacing;
148             if ((direction_ == WrapDirection::HORIZONTAL && !isLeftToRight_) ||
149                 (direction_ == WrapDirection::HORIZONTAL_REVERSE && isLeftToRight_) ||
150                 (direction_ == WrapDirection::VERTICAL_REVERSE)) {
151                 itemsList.reverse();
152             }
153             auto contentInfo = ContentInfo(currentMainLength, currentCrossLength, count, itemsList);
154             contentInfo.maxBaselineDistance = baselineDistance;
155             contentList_.emplace_back(contentInfo);
156             if ((direction_ == WrapDirection::VERTICAL || direction_ == WrapDirection::VERTICAL_REVERSE) &&
157                 !isLeftToRight_) {
158                 contentList_.reverse();
159             }
160             totalMainLength_ = std::max(currentMainLength, totalMainLength_);
161             // n contents has n - 1 space
162             totalCrossLength_ += currentCrossLength;
163         }
164     }
165     LayoutWholeWrap();
166     SetWrapLayoutSize(mainLengthLimit_, totalCrossLength_);
167     contentList_.clear();
168 }
169 
AddBlock(int32_t & count,const RefPtr<RenderNode> & item,std::list<RefPtr<RenderNode>> & itemsList,double & currentMainLength,double & currentCrossLength,double & baselineDistance)170 void RenderWrap::AddBlock(int32_t& count, const RefPtr<RenderNode>& item, std::list<RefPtr<RenderNode>>& itemsList,
171     double& currentMainLength, double& currentCrossLength, double& baselineDistance)
172 {
173     auto contentSpace = NormalizeToPx(contentSpace_);
174     if (count != 0) {
175         auto contentInfo = ContentInfo(currentMainLength, currentCrossLength, count, itemsList);
176         contentInfo.maxBaselineDistance = item->GetBaselineDistance(TextBaseline::ALPHABETIC);
177         contentList_.emplace_back(contentInfo);
178         itemsList.clear();
179         totalCrossLength_ += currentCrossLength + contentSpace;
180     }
181     itemsList.push_back(item);
182     double itemLength = GetMainItemLength(item);
183     currentCrossLength = GetCrossItemLength(item);
184     totalMainLength_ = std::max(itemLength, totalMainLength_);
185     totalCrossLength_ += currentCrossLength + contentSpace;
186     auto contentInfo2 = ContentInfo(itemLength, currentCrossLength, 1, itemsList);
187     contentInfo2.maxBaselineDistance = baselineDistance;
188     contentList_.emplace_back(contentInfo2);
189     itemsList.clear();
190     currentCrossLength = 0.0;
191     count = 0;
192 }
193 
CalculateMargin(const RefPtr<RenderNode> & item,bool & beforeIsBlock,double & beforeMarginBottom)194 void RenderWrap::CalculateMargin(const RefPtr<RenderNode>& item, bool& beforeIsBlock, double& beforeMarginBottom)
195 {
196     double currentItemMarginBottom = 0.0;
197     RefPtr<RenderNode> itemNode = item;
198     while (itemNode) {
199         if (itemNode->GetChildren().empty()) {
200             break;
201         }
202         itemNode = itemNode->GetChildren().front();
203         auto itemTemp = AceType::DynamicCast < RenderBoxBase >(itemNode);
204         if (!itemTemp) {
205             continue;
206         }
207         if (!beforeIsBlock) {
208             beforeIsBlock = true;
209             auto setterBottom = DimensionHelper(&Edge::SetBottom, &Edge::Bottom);
210             beforeMarginBottom = itemTemp->GetMargin(setterBottom).Value();
211         } else {
212             auto setterTop = DimensionHelper(&Edge::SetTop, &Edge::Top);
213             auto setterBottom = DimensionHelper(&Edge::SetBottom, &Edge::Bottom);
214             double currentItemMarginTop = itemTemp->GetMargin(setterTop).Value();
215             currentItemMarginBottom =  itemTemp->GetMargin(setterBottom).Value();
216             if (GreatOrEqual(beforeMarginBottom, 0.0) && GreatOrEqual(currentItemMarginTop, 0.0)) {
217                 double minMargin = std::min(beforeMarginBottom, currentItemMarginTop);
218                 AnimatableDimension distance = AnimatableDimension(currentItemMarginTop - minMargin);
219                 auto setter = DimensionHelper(&Edge::SetTop, &Edge::Top);
220                 itemTemp->SetMargin(distance, setter);
221                 beforeMarginBottom = currentItemMarginBottom;
222                 break;
223             }
224         }
225     }
226 }
227 
SetDefault(const RefPtr<RenderNode> & item)228 void RenderWrap::SetDefault(const RefPtr<RenderNode>& item)
229 {
230     RefPtr<RenderBoxBase> boxItem = nullptr;
231     RefPtr<BoxComponent> boxComponent = nullptr;
232     RefPtr<RenderNode> itemNode = item;
233     while (itemNode) {
234         if (itemNode->GetChildren().empty()) {
235             break;
236         }
237         itemNode = itemNode->GetChildren().front();
238         auto itemTemp = AceType::DynamicCast <RenderBoxBase>(itemNode);
239         if (itemTemp) {
240             boxItem = itemTemp;
241         }
242 
243         auto sliderItem = AceType::DynamicCast <RenderSlider>(itemNode);
244         if (sliderItem && boxItem) {
245             boxItem->SetWidth(Dimension(400.0f, DimensionUnit::VP));
246             break;
247         }
248 
249         auto progressItem = AceType::DynamicCast <RenderProgress>(itemNode);
250         if (progressItem && boxItem) {
251             boxItem->SetWidth(Dimension(200.0f, DimensionUnit::VP));
252             break;
253         }
254 
255         auto imageItem = AceType::DynamicCast <RenderImage>(itemNode);
256         if (imageItem && boxItem) {
257             boxItem->SetWidth(Dimension(200.0f, DimensionUnit::VP));
258             boxItem->SetHeight(Dimension(200.0f, DimensionUnit::VP));
259             break;
260         }
261         auto marqueeItem = AceType::DynamicCast <RenderMarquee>(itemNode);
262         if (marqueeItem && boxItem) {
263             boxItem->SetWidth(Dimension(400.0f, DimensionUnit::VP));
264             break;
265         }
266         auto searchItem = AceType::DynamicCast <RenderSearch>(itemNode);
267         if (searchItem && boxItem) {
268             boxItem->SetWidth(Dimension(400.0f, DimensionUnit::VP));
269             break;
270         }
271         auto textFieldItem = AceType::DynamicCast <RenderTextField>(itemNode);
272         if (textFieldItem && boxItem) {
273             boxItem->SetWidth(Dimension(400.0f, DimensionUnit::VP));
274             break;
275         }
276     };
277 }
278 
HandleDialogStretch(const LayoutParam & layoutParam)279 void RenderWrap::HandleDialogStretch(const LayoutParam& layoutParam)
280 {
281     int32_t dialogButtonNum = 0;
282     double totalLength = 0.0;
283     auto spacing = NormalizeToPx(spacing_);
284     auto contentSpace = NormalizeToPx(contentSpace_);
285     // whether the btn in the wrap needs wrap
286     for (const auto& item : GetChildren()) {
287         dialogButtonNum += 1;
288         item->Layout(layoutParam);
289         totalLength += GetMainItemLength(item) + spacing;
290         if (totalLength - spacing > mainLengthLimit_) {
291             dialogDirection_ = WrapDirection::VERTICAL;
292         }
293     }
294     if (dialogButtonNum == 0) {
295         LOGW("dialog button number is 0");
296         return;
297     }
298 
299     double buttonSize = (mainLengthLimit_ - spacing * (dialogButtonNum - 1)) / dialogButtonNum;
300     std::list<RefPtr<RenderNode>> itemsList;
301     for (const auto& item : GetChildren()) {
302         LayoutParam newParam;
303         // if dialog is vertical, stretch each button equally to fill max length, otherwise stretch equally in same line
304         double stretchSize = dialogDirection_ == WrapDirection::VERTICAL ? mainLengthLimit_ : buttonSize;
305         newParam.SetFixedSize(
306             (direction_ == WrapDirection::HORIZONTAL ? Size(stretchSize, item->GetLayoutSize().Height())
307                                                      : Size(item->GetLayoutSize().Width(), stretchSize)));
308         item->Layout(newParam);
309         itemsList.push_back(item);
310         totalMainLength_ = mainLengthLimit_;
311 
312         if (dialogDirection_ == WrapDirection::VERTICAL) {
313             // stretch each button equally to fill max length
314 
315             totalCrossLength_ += direction_ == WrapDirection::HORIZONTAL ? item->GetLayoutSize().Height()
316                                                                          : item->GetLayoutSize().Width();
317             totalCrossLength_ += contentSpace;
318             contentList_.emplace_back(
319                 ContentInfo(newParam.GetMaxSize().Width(), newParam.GetMaxSize().Height(), 1, itemsList));
320             itemsList.clear();
321         } else {
322             // stretch each button equally in same line
323             totalCrossLength_ = std::max(direction_ == WrapDirection::HORIZONTAL ? item->GetLayoutSize().Height()
324                                                                                  : item->GetLayoutSize().Width(),
325                 totalCrossLength_);
326         }
327     }
328     // if wrap direction is vertical, item has already added into content list
329     if (dialogDirection_ == WrapDirection::VERTICAL) {
330         totalCrossLength_ -= contentSpace;
331         return;
332     }
333     if (!isLeftToRight_) {
334         itemsList.reverse();
335     }
336     if (direction_ == WrapDirection::HORIZONTAL) {
337         contentList_.emplace_back(ContentInfo(mainLengthLimit_, totalCrossLength_, dialogButtonNum, itemsList));
338     } else {
339         contentList_.emplace_back(ContentInfo(totalCrossLength_, mainLengthLimit_, dialogButtonNum, itemsList));
340     }
341 }
342 
GetMainItemLength(const RefPtr<RenderNode> & item) const343 double RenderWrap::GetMainItemLength(const RefPtr<RenderNode>& item) const
344 {
345     return direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE
346                ? item->GetLayoutSize().Width()
347                : item->GetLayoutSize().Height();
348 }
349 
GetCrossItemLength(const RefPtr<RenderNode> & item) const350 double RenderWrap::GetCrossItemLength(const RefPtr<RenderNode>& item) const
351 {
352     return direction_ == WrapDirection::VERTICAL || direction_ == WrapDirection::VERTICAL_REVERSE
353                ? item->GetLayoutSize().Width()
354                : item->GetLayoutSize().Height();
355 }
356 
PerformLayoutInitialize()357 void RenderWrap::PerformLayoutInitialize()
358 {
359     if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
360         mainLengthLimit_ = GetLayoutParam().GetMaxSize().Width();
361         crossLengthLimit_ = GetLayoutParam().GetMaxSize().Height();
362     } else {
363         mainLengthLimit_ =
364             GetLayoutParam().GetMaxSize().IsInfinite() ? viewPort_.Height() : GetLayoutParam().GetMaxSize().Height();
365         crossLengthLimit_ = GetLayoutParam().GetMaxSize().Width();
366     }
367 }
368 
GetLeftSize(double crossLength,double mainLeftLength,double crossLeftLength) const369 Size RenderWrap::GetLeftSize(double crossLength, double mainLeftLength, double crossLeftLength) const
370 {
371     if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
372         return Size(mainLeftLength, crossLeftLength - crossLength);
373     } else {
374         return Size(crossLeftLength - crossLength, mainLeftLength);
375     }
376 }
377 
LayoutWholeWrap()378 void RenderWrap::LayoutWholeWrap()
379 {
380     int32_t contentNum = static_cast<int32_t>(contentList_.size());
381     if (contentNum == 0) {
382         LOGW("no content in wrap");
383         return;
384     }
385     Offset startPosition;
386     Offset betweenPosition;
387     bool isHorizontal = direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE;
388 
389     switch (alignment_) {
390         case WrapAlignment::START: {
391             startPosition = Offset(0.0, 0.0);
392             betweenPosition = Offset();
393             break;
394         }
395         case WrapAlignment::END: {
396             startPosition = GetContentOffset(totalCrossLength_);
397             betweenPosition = Offset();
398             break;
399         }
400         case WrapAlignment::CENTER: {
401             // divided the space by two
402             startPosition = GetContentOffset(totalCrossLength_) / 2;
403             betweenPosition = Offset();
404             break;
405         }
406         case WrapAlignment::SPACE_BETWEEN: {
407             startPosition = Offset(0.0, 0.0);
408             double crossSpace =
409                 contentNum > 1 ? (crossLengthLimit_ - totalCrossLength_) / static_cast<double>(contentNum - 1) : 0.0;
410             betweenPosition = isHorizontal ? Offset(0.0, crossSpace) : Offset(crossSpace, 0.0);
411             break;
412         }
413         case WrapAlignment::SPACE_EVENLY: {
414             double leftSpace = crossLengthLimit_ - totalCrossLength_;
415             double crossSpace = leftSpace / static_cast<double>(contentNum + 1);
416             startPosition = isHorizontal ? Offset(0.0, crossSpace) : Offset(crossSpace, 0.0);
417             betweenPosition = isHorizontal ? Offset(0.0, crossSpace) : Offset(crossSpace, 0.0);
418             break;
419         }
420         case WrapAlignment::SPACE_AROUND: {
421             double leftSpace = crossLengthLimit_ - totalCrossLength_;
422             double crossSpace = leftSpace / static_cast<double>(contentNum);
423             startPosition = isHorizontal ? Offset(0.0, crossSpace / 2) : Offset(crossSpace / 2, 0.0);
424             betweenPosition = isHorizontal ? Offset(0.0, crossSpace) : Offset(crossSpace, 0.0);
425             break;
426         }
427         default: {
428             LOGE("Wrap::alignment setting error.");
429             startPosition = Offset(0.0, 0.0);
430             betweenPosition = Offset();
431             break;
432         }
433     }
434     auto context = context_.Upgrade();
435     bool applyNewOffset = context ? context->GetMinPlatformVersion() >= MIN_COMPATIBLE_VERSION : false;
436     if (applyNewOffset) {
437         // In content type, wrap is as large as children, no need to set alignment_.
438         if ((!isHorizontal && horizontalMeasure_ == MeasureType::CONTENT) ||
439             (isHorizontal && verticalMeasure_ == MeasureType::CONTENT)) {
440             startPosition = Offset();
441             betweenPosition = Offset();
442         }
443     }
444     TraverseContent(startPosition, betweenPosition);
445 }
446 
GetContentOffset(double totalCrossLength) const447 Offset RenderWrap::GetContentOffset(double totalCrossLength) const
448 {
449     if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
450         return Offset(0.0, crossLengthLimit_ - totalCrossLength);
451     } else {
452         return Offset(crossLengthLimit_ - totalCrossLength, 0.0);
453     }
454 }
455 
TraverseContent(const Offset & startPosition,const Offset & betweenPosition) const456 void RenderWrap::TraverseContent(const Offset& startPosition, const Offset& betweenPosition) const
457 {
458     // determine the content start position by main axis
459     Offset accumulateOffset = startPosition;
460     double currentMainSpaceLength = 0.0;
461     for (const auto& content : contentList_) {
462         // dfs positioned item in each content
463         currentMainSpaceLength = mainLengthLimit_ - content.mainLength_;
464         int32_t itemNum = content.count_;
465         if (itemNum == 0) {
466             LOGE("fail to TraverseContent due to item num is zero");
467             return;
468         }
469 
470         switch (mainAlignment_) {
471             case WrapAlignment::START: {
472                 if ((direction_ == WrapDirection::HORIZONTAL && !isLeftToRight_) ||
473                     (direction_ == WrapDirection::HORIZONTAL_REVERSE && isLeftToRight_) ||
474                     (direction_ == WrapDirection::VERTICAL_REVERSE)) {
475                     PositionedItem(0.0, content, accumulateOffset + GetItemMainOffset(currentMainSpaceLength),
476                         content.crossLength_);
477                 } else {
478                     PositionedItem(0.0, content, accumulateOffset, content.crossLength_);
479                 }
480                 break;
481             }
482             case WrapAlignment::END: {
483                 if ((direction_ == WrapDirection::HORIZONTAL && !isLeftToRight_) ||
484                     (direction_ == WrapDirection::HORIZONTAL_REVERSE && isLeftToRight_) ||
485                     direction_ == WrapDirection::VERTICAL_REVERSE) {
486                     PositionedItem(0.0, content, accumulateOffset, content.crossLength_);
487                 } else {
488                     PositionedItem(0.0, content, accumulateOffset + GetItemMainOffset(currentMainSpaceLength),
489                         content.crossLength_);
490                 }
491                 break;
492             }
493             case WrapAlignment::CENTER: {
494                 // divided the space by two
495                 PositionedItem(0.0, content, accumulateOffset + GetItemMainOffset(currentMainSpaceLength / 2),
496                     content.crossLength_);
497                 break;
498             }
499             case WrapAlignment::SPACE_BETWEEN: {
500                 double betweenSpace = (itemNum - 1 == 0) ? 0.0 : currentMainSpaceLength / (itemNum - 1);
501                 PositionedItem(betweenSpace, content, accumulateOffset, content.crossLength_);
502                 break;
503             }
504             case WrapAlignment::SPACE_AROUND: {
505                 double itemMainSpace = currentMainSpaceLength / itemNum;
506                 PositionedItem(itemMainSpace, content, accumulateOffset + GetItemMainOffset(itemMainSpace / 2),
507                     content.crossLength_);
508                 break;
509             }
510             case WrapAlignment::SPACE_EVENLY: {
511                 double itemMainSpace = currentMainSpaceLength / (itemNum + 1);
512                 PositionedItem(
513                     itemMainSpace, content, accumulateOffset + GetItemMainOffset(itemMainSpace), content.crossLength_);
514                 break;
515             }
516             default: {
517                 LOGE("Wrap::mainAlignment setting error. Now using START");
518                 PositionedItem(0.0, content, accumulateOffset, content.crossLength_);
519                 break;
520             }
521         }
522         auto contentSpace = NormalizeToPx(contentSpace_);
523         accumulateOffset += betweenPosition;
524         accumulateOffset += (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE)
525                                 ? Offset(0.0, content.crossLength_ + contentSpace)
526                                 : Offset(content.crossLength_ + contentSpace, 0.0);
527     }
528 }
529 
GetItemMainOffset(double mainSpace) const530 Offset RenderWrap::GetItemMainOffset(double mainSpace) const
531 {
532     // calculate the offset of each item in content
533     if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
534         return Offset(mainSpace, 0.0);
535     } else {
536         return Offset(0.0, mainSpace);
537     }
538 }
539 
PositionedItem(double betweenSpace,const ContentInfo & content,const Offset & position,double totalCrossSpace) const540 void RenderWrap::PositionedItem(
541     double betweenSpace, const ContentInfo& content, const Offset& position, double totalCrossSpace) const
542 {
543     Offset itemPositionOffset;
544     // iterate every item in content
545     for (const auto& item : content.itemList_) {
546         switch (crossAlignment_) {
547             case WrapAlignment::START: {
548                 if ((direction_ == WrapDirection::VERTICAL && !isLeftToRight_) ||
549                     (direction_ == WrapDirection::VERTICAL_REVERSE && !isLeftToRight_)) {
550                     HandleEndAlignment(totalCrossSpace, item, position, betweenSpace, itemPositionOffset);
551                 } else {
552                     HandleStartAlignment(item, position, betweenSpace, itemPositionOffset);
553                 }
554                 break;
555             }
556             case WrapAlignment::STRETCH: {
557                 PlaceItemAndLog(item, position + itemPositionOffset, "STRETCH");
558                 // stretch the component in wrap
559                 LayoutParam layoutParam;
560                 auto spacing = NormalizeToPx(spacing_);
561                 if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
562                     itemPositionOffset += Offset(item->GetLayoutSize().Width() + betweenSpace + spacing, 0.0);
563                     layoutParam.SetFixedSize(Size(item->GetLayoutSize().Width(), totalCrossSpace));
564                 } else {
565                     itemPositionOffset += Offset(0.0, item->GetLayoutSize().Height() + betweenSpace + spacing);
566                     layoutParam.SetFixedSize(Size(totalCrossSpace, item->GetLayoutSize().Height()));
567                 }
568                 item->Layout(layoutParam);
569                 break;
570             }
571             case WrapAlignment::END: {
572                 if ((direction_ == WrapDirection::VERTICAL && !isLeftToRight_) ||
573                     (direction_ == WrapDirection::VERTICAL_REVERSE && !isLeftToRight_)) {
574                     HandleStartAlignment(item, position, betweenSpace, itemPositionOffset);
575                 } else {
576                     HandleEndAlignment(totalCrossSpace, item, position, betweenSpace, itemPositionOffset);
577                 }
578                 break;
579             }
580             case WrapAlignment::CENTER: {
581                 // divide the space by two
582                 HandleCenterAlignment(totalCrossSpace, item, position, betweenSpace, itemPositionOffset);
583                 break;
584             }
585             case WrapAlignment::BASELINE: {
586                 if (direction_ == WrapDirection::VERTICAL || direction_ == WrapDirection::VERTICAL_REVERSE) {
587                     if (isLeftToRight_) {
588                         HandleStartAlignment(item, position, betweenSpace, itemPositionOffset);
589                     } else {
590                         HandleEndAlignment(totalCrossSpace, item, position, betweenSpace, itemPositionOffset);
591                     }
592                 } else {
593                     HandleBaselineAlignment(
594                         content.maxBaselineDistance, item, position, betweenSpace, itemPositionOffset);
595                 }
596                 break;
597             }
598             default: {
599                 LOGW("Wrap::crossAlignment setting error. Now using START");
600                 if ((direction_ == WrapDirection::VERTICAL && !isLeftToRight_) ||
601                     (direction_ == WrapDirection::VERTICAL_REVERSE && !isLeftToRight_)) {
602                     HandleEndAlignment(totalCrossSpace, item, position, betweenSpace, itemPositionOffset);
603                 } else {
604                     HandleStartAlignment(item, position, betweenSpace, itemPositionOffset);
605                 }
606                 break;
607             }
608         }
609     }
610 }
611 
PlaceItemAndLog(const RefPtr<RenderNode> & node,const Offset & position,const std::string & align) const612 void RenderWrap::PlaceItemAndLog(const RefPtr<RenderNode>& node, const Offset& position, const std::string& align) const
613 {
614     node->SetPosition(position);
615 }
616 
HandleCenterAlignment(double totalCrossSpace,const RefPtr<RenderNode> & item,const Offset & position,double betweenSpace,Offset & itemPositionOffset) const617 void RenderWrap::HandleCenterAlignment(double totalCrossSpace, const RefPtr<RenderNode>& item, const Offset& position,
618     double betweenSpace, Offset& itemPositionOffset) const
619 {
620     // itemPositionOffset will change in this function
621     Offset crossOffset;
622     auto spacing = NormalizeToPx(spacing_);
623     if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
624         crossOffset = Offset(0.0, (totalCrossSpace - item->GetLayoutSize().Height()) / 2.0);
625         PlaceItemAndLog(item, position + itemPositionOffset + crossOffset, "CENTER");
626         itemPositionOffset += Offset(item->GetLayoutSize().Width() + betweenSpace + spacing, 0.0);
627     } else {
628         crossOffset = Offset((totalCrossSpace - item->GetLayoutSize().Width()) / 2, 0.0);
629         PlaceItemAndLog(item, position + itemPositionOffset + crossOffset, "CENTER");
630         itemPositionOffset += Offset(0.0, item->GetLayoutSize().Height() + betweenSpace + spacing);
631     }
632 }
633 
HandleEndAlignment(double totalCrossSpace,const RefPtr<RenderNode> & item,const Offset & position,double betweenSpace,Offset & itemPositionOffset) const634 void RenderWrap::HandleEndAlignment(double totalCrossSpace, const RefPtr<RenderNode>& item, const Offset& position,
635     double betweenSpace, Offset& itemPositionOffset) const
636 {
637     // itemPositionOffset will change in this function
638     Offset crossOffset;
639     auto spacing = NormalizeToPx(spacing_);
640     if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
641         crossOffset = Offset(0.0, totalCrossSpace - item->GetLayoutSize().Height());
642         PlaceItemAndLog(item, position + itemPositionOffset + crossOffset, "END");
643         itemPositionOffset += Offset(item->GetLayoutSize().Width() + betweenSpace + spacing, 0.0);
644     } else {
645         crossOffset = Offset(totalCrossSpace - item->GetLayoutSize().Width(), 0.0);
646         PlaceItemAndLog(item, position + itemPositionOffset + crossOffset, "END");
647         itemPositionOffset += Offset(0.0, item->GetLayoutSize().Height() + betweenSpace + spacing);
648     }
649 }
650 
HandleBaselineAlignment(double totalCrossSpace,const RefPtr<RenderNode> & item,const Offset & position,double betweenSpace,Offset & itemPositionOffset) const651 void RenderWrap::HandleBaselineAlignment(double totalCrossSpace, const RefPtr<RenderNode>& item, const Offset& position,
652     double betweenSpace, Offset& itemPositionOffset) const
653 {
654     Offset crossOffset;
655     auto spacing = NormalizeToPx(spacing_);
656     crossOffset = Offset(0.0, totalCrossSpace - item->GetBaselineDistance(TextBaseline::ALPHABETIC));
657     PlaceItemAndLog(item, position + itemPositionOffset + crossOffset, "Baseline");
658     itemPositionOffset += Offset(item->GetLayoutSize().Width() + betweenSpace + spacing, 0.0);
659 }
660 
HandleStartAlignment(const RefPtr<RenderNode> & item,const Offset & position,double betweenSpace,Offset & itemPositionOffset) const661 void RenderWrap::HandleStartAlignment(
662     const RefPtr<RenderNode>& item, const Offset& position, double betweenSpace, Offset& itemPositionOffset) const
663 {
664     PlaceItemAndLog(item, position + itemPositionOffset, "START");
665     // Decide content offset position
666     auto spacing = NormalizeToPx(spacing_);
667     bool isHorizontal = direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE;
668     itemPositionOffset += Offset(isHorizontal ? item->GetLayoutSize().Width() + betweenSpace + spacing : 0.0,
669         isHorizontal ? 0.0 : item->GetLayoutSize().Height() + betweenSpace + spacing);
670 }
671 
ClearRenderObject()672 void RenderWrap::ClearRenderObject()
673 {
674     RenderNode::ClearRenderObject();
675     direction_ = WrapDirection::VERTICAL;
676     alignment_ = WrapAlignment::START;
677     mainAlignment_ = WrapAlignment::START;
678     crossAlignment_ = WrapAlignment::START;
679     spacing_ = Dimension();
680     contentSpace_ = Dimension();
681     mainLengthLimit_ = 0.0;
682     crossLengthLimit_ = 0.0;
683     totalMainLength_ = 0.0;
684     totalCrossLength_ = 0.0;
685 
686     dialogDirection_ = WrapDirection::HORIZONTAL;
687     dialogStretch_ = false;
688     isLeftToRight_ = true;
689 }
690 
MaybeRelease()691 bool RenderWrap::MaybeRelease()
692 {
693     auto context = GetContext().Upgrade();
694     if (context && context->GetRenderFactory() && context->GetRenderFactory()->GetRenderWrapFactory()->Recycle(this)) {
695         ClearRenderObject();
696         return false;
697     }
698     return true;
699 }
700 
701 } // namespace OHOS::Ace