1 /*
2 * Copyright (c) 2021 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 <algorithm>
19
20 #include "core/components/wrap/wrap_component.h"
21
22 namespace OHOS::Ace {
23 namespace {
24
25 constexpr int32_t MIN_COMPATIBLE_VERSION = 6;
26
27 }
28
Create()29 RefPtr<RenderNode> RenderWrap::Create()
30 {
31 return AceType::MakeRefPtr<RenderWrap>();
32 }
33
Update(const RefPtr<Component> & component)34 void RenderWrap::Update(const RefPtr<Component>& component)
35 {
36 const RefPtr<WrapComponent> wrap = AceType::DynamicCast<WrapComponent>(component);
37 if (!wrap) {
38 LOGE("Wrap::RenderWrap update dynamicCast to nullptr error");
39 return;
40 }
41 direction_ = wrap->GetDirection();
42 // Whole alignment
43 alignment_ = wrap->GetAlignment();
44 // content main alignment
45 mainAlignment_ = wrap->GetMainAlignment();
46 // content cross alignment
47 crossAlignment_ = wrap->GetCrossAlignment();
48 spacing_ = wrap->GetSpacing();
49 contentSpace_ = wrap->GetContentSpacing();
50 dialogStretch_ = wrap->GetDialogStretch();
51 horizontalMeasure_ = wrap->GetHorizontalMeasure();
52 verticalMeasure_ = wrap->GetVerticalMeasure();
53 SetTextDirection(wrap->GetTextDirection());
54 isLeftToRight_ = (wrap->GetTextDirection() == TextDirection::LTR);
55 contentList_.clear();
56 MarkNeedLayout();
57 }
58
PerformLayout()59 void RenderWrap::PerformLayout()
60 {
61 if (GetChildren().empty()) {
62 // no child will set current to empty and return
63 SetLayoutSize(Size(0.0, 0.0));
64 return;
65 }
66
67 PerformLayoutInitialize();
68
69 // overall size including space
70 totalMainLength_ = 0.0;
71 totalCrossLength_ = 0.0;
72
73 LayoutParam layoutParam;
74 layoutParam.SetMinSize(Size(0.0, 0.0));
75 layoutParam.SetMaxSize(GetLeftSize(0.0, mainLengthLimit_, crossLengthLimit_));
76 if (dialogStretch_) {
77 HandleDialogStretch(layoutParam);
78 } else {
79 auto spacing = NormalizeToPx(spacing_);
80 auto contentSpace = NormalizeToPx(contentSpace_);
81 // content size
82 double currentMainLength = 0.0;
83 // the cross length is without space
84 double currentCrossLength = 0.0;
85 // number of item in content
86 int32_t count = 0;
87 // max baseline of each line
88 double baselineDistance = 0.0;
89 std::list<RefPtr<RenderNode>> itemsList;
90 for (auto& item : GetChildren()) {
91 item->Layout(layoutParam);
92
93 if (mainLengthLimit_ >= currentMainLength + GetMainItemLength(item)) {
94 currentMainLength += GetMainItemLength(item);
95 currentMainLength += spacing;
96 currentCrossLength = std::max(currentCrossLength, GetCrossItemLength(item));
97 if (crossAlignment_ == WrapAlignment::BASELINE) {
98 baselineDistance = std::max(baselineDistance, item->GetBaselineDistance(TextBaseline::ALPHABETIC));
99 }
100 itemsList.push_back(item);
101 count += 1;
102 } else {
103 currentMainLength -= spacing;
104 if ((direction_ == WrapDirection::HORIZONTAL && !isLeftToRight_) ||
105 (direction_ == WrapDirection::HORIZONTAL_REVERSE && isLeftToRight_) ||
106 direction_ == WrapDirection::VERTICAL_REVERSE) {
107 itemsList.reverse();
108 }
109 auto contentInfo = ContentInfo(currentMainLength, currentCrossLength, count, itemsList);
110 contentInfo.maxBaselineDistance = baselineDistance;
111 contentList_.emplace_back(contentInfo);
112 itemsList.clear();
113 totalMainLength_ = std::max(currentMainLength, totalMainLength_);
114 totalCrossLength_ += currentCrossLength + contentSpace;
115 currentMainLength = GetMainItemLength(item) + spacing;
116 currentCrossLength = GetCrossItemLength(item);
117 if (crossAlignment_ == WrapAlignment::BASELINE) {
118 baselineDistance = item->GetBaselineDistance(TextBaseline::ALPHABETIC);
119 }
120 itemsList.push_back(item);
121 count = 1;
122 }
123 }
124 // Add last content into list
125 currentMainLength -= spacing;
126 if ((direction_ == WrapDirection::HORIZONTAL && !isLeftToRight_) ||
127 (direction_ == WrapDirection::HORIZONTAL_REVERSE && isLeftToRight_) ||
128 (direction_ == WrapDirection::VERTICAL_REVERSE)) {
129 itemsList.reverse();
130 }
131 auto contentInfo = ContentInfo(currentMainLength, currentCrossLength, count, itemsList);
132 contentInfo.maxBaselineDistance = baselineDistance;
133 contentList_.emplace_back(contentInfo);
134 if ((direction_ == WrapDirection::VERTICAL || direction_ == WrapDirection::VERTICAL_REVERSE) &&
135 !isLeftToRight_) {
136 contentList_.reverse();
137 }
138 totalMainLength_ = std::max(currentMainLength, totalMainLength_);
139 // n contents has n - 1 space
140 totalCrossLength_ += currentCrossLength;
141 }
142 LayoutWholeWrap();
143 SetWrapLayoutSize(mainLengthLimit_, totalCrossLength_);
144 contentList_.clear();
145 }
146
HandleDialogStretch(const LayoutParam & layoutParam)147 void RenderWrap::HandleDialogStretch(const LayoutParam& layoutParam)
148 {
149 int32_t dialogButtonNum = 0;
150 double totalLength = 0.0;
151 auto spacing = NormalizeToPx(spacing_);
152 auto contentSpace = NormalizeToPx(contentSpace_);
153 // whether the btn in the wrap needs wrap
154 for (const auto& item : GetChildren()) {
155 dialogButtonNum += 1;
156 item->Layout(layoutParam);
157 totalLength += GetMainItemLength(item) + spacing;
158 if (totalLength - spacing > mainLengthLimit_) {
159 dialogDirection_ = WrapDirection::VERTICAL;
160 }
161 }
162 if (dialogButtonNum == 0) {
163 LOGW("dialog button number is 0");
164 return;
165 }
166
167 double buttonSize = (mainLengthLimit_ - spacing * (dialogButtonNum - 1)) / dialogButtonNum;
168 std::list<RefPtr<RenderNode>> itemsList;
169 for (const auto& item : GetChildren()) {
170 LayoutParam newParam;
171 // if dialog is vertical, stretch each button equally to fill max length, otherwise stretch equally in same line
172 double stretchSize = dialogDirection_ == WrapDirection::VERTICAL ? mainLengthLimit_ : buttonSize;
173 newParam.SetFixedSize(
174 (direction_ == WrapDirection::HORIZONTAL ? Size(stretchSize, item->GetLayoutSize().Height())
175 : Size(item->GetLayoutSize().Width(), stretchSize)));
176 item->Layout(newParam);
177 itemsList.push_back(item);
178 totalMainLength_ = mainLengthLimit_;
179
180 if (dialogDirection_ == WrapDirection::VERTICAL) {
181 // stretch each button equally to fill max length
182
183 totalCrossLength_ += direction_ == WrapDirection::HORIZONTAL ? item->GetLayoutSize().Height()
184 : item->GetLayoutSize().Width();
185 totalCrossLength_ += contentSpace;
186 contentList_.emplace_back(
187 ContentInfo(newParam.GetMaxSize().Width(), newParam.GetMaxSize().Height(), 1, itemsList));
188 itemsList.clear();
189 } else {
190 // stretch each button equally in same line
191 totalCrossLength_ = std::max(direction_ == WrapDirection::HORIZONTAL ? item->GetLayoutSize().Height()
192 : item->GetLayoutSize().Width(),
193 totalCrossLength_);
194 }
195 }
196 // if wrap direction is vertical, item has already added into content list
197 if (dialogDirection_ == WrapDirection::VERTICAL) {
198 totalCrossLength_ -= contentSpace;
199 return;
200 }
201 if (!isLeftToRight_) {
202 itemsList.reverse();
203 }
204 if (direction_ == WrapDirection::HORIZONTAL) {
205 contentList_.emplace_back(ContentInfo(mainLengthLimit_, totalCrossLength_, dialogButtonNum, itemsList));
206 } else {
207 contentList_.emplace_back(ContentInfo(totalCrossLength_, mainLengthLimit_, dialogButtonNum, itemsList));
208 }
209 }
210
GetMainItemLength(const RefPtr<RenderNode> & item) const211 double RenderWrap::GetMainItemLength(const RefPtr<RenderNode>& item) const
212 {
213 return direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE
214 ? item->GetLayoutSize().Width()
215 : item->GetLayoutSize().Height();
216 }
217
GetCrossItemLength(const RefPtr<RenderNode> & item) const218 double RenderWrap::GetCrossItemLength(const RefPtr<RenderNode>& item) const
219 {
220 return direction_ == WrapDirection::VERTICAL || direction_ == WrapDirection::VERTICAL_REVERSE
221 ? item->GetLayoutSize().Width()
222 : item->GetLayoutSize().Height();
223 }
224
PerformLayoutInitialize()225 void RenderWrap::PerformLayoutInitialize()
226 {
227 if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
228 mainLengthLimit_ = GetLayoutParam().GetMaxSize().Width();
229 crossLengthLimit_ = GetLayoutParam().GetMaxSize().Height();
230 } else {
231 mainLengthLimit_ =
232 GetLayoutParam().GetMaxSize().IsInfinite() ? viewPort_.Height() : GetLayoutParam().GetMaxSize().Height();
233 crossLengthLimit_ = GetLayoutParam().GetMaxSize().Width();
234 }
235 }
236
GetLeftSize(double crossLength,double mainLeftLength,double crossLeftLength) const237 Size RenderWrap::GetLeftSize(double crossLength, double mainLeftLength, double crossLeftLength) const
238 {
239 if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
240 return Size(mainLeftLength, crossLeftLength - crossLength);
241 } else {
242 return Size(crossLeftLength - crossLength, mainLeftLength);
243 }
244 }
245
LayoutWholeWrap()246 void RenderWrap::LayoutWholeWrap()
247 {
248 int32_t contentNum = static_cast<int32_t>(contentList_.size());
249 if (contentNum == 0) {
250 LOGW("no content in wrap");
251 return;
252 }
253 Offset startPosition;
254 Offset betweenPosition;
255 bool isHorizontal = direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE;
256
257 switch (alignment_) {
258 case WrapAlignment::START: {
259 startPosition = Offset(0.0, 0.0);
260 betweenPosition = Offset();
261 break;
262 }
263 case WrapAlignment::END: {
264 startPosition = GetContentOffset(totalCrossLength_);
265 betweenPosition = Offset();
266 break;
267 }
268 case WrapAlignment::CENTER: {
269 // divided the space by two
270 startPosition = GetContentOffset(totalCrossLength_) / 2;
271 betweenPosition = Offset();
272 break;
273 }
274 case WrapAlignment::SPACE_BETWEEN: {
275 startPosition = Offset(0.0, 0.0);
276 double crossSpace =
277 contentNum > 1 ? (crossLengthLimit_ - totalCrossLength_) / static_cast<double>(contentNum - 1) : 0.0;
278 betweenPosition = isHorizontal ? Offset(0.0, crossSpace) : Offset(crossSpace, 0.0);
279 break;
280 }
281 case WrapAlignment::SPACE_EVENLY: {
282 double leftSpace = crossLengthLimit_ - totalCrossLength_;
283 double crossSpace = leftSpace / static_cast<double>(contentNum + 1);
284 startPosition = isHorizontal ? Offset(0.0, crossSpace) : Offset(crossSpace, 0.0);
285 betweenPosition = isHorizontal ? Offset(0.0, crossSpace) : Offset(crossSpace, 0.0);
286 break;
287 }
288 case WrapAlignment::SPACE_AROUND: {
289 double leftSpace = crossLengthLimit_ - totalCrossLength_;
290 double crossSpace = leftSpace / static_cast<double>(contentNum);
291 startPosition = isHorizontal ? Offset(0.0, crossSpace / 2) : Offset(crossSpace / 2, 0.0);
292 betweenPosition = isHorizontal ? Offset(0.0, crossSpace) : Offset(crossSpace, 0.0);
293 break;
294 }
295 default: {
296 LOGE("Wrap::alignment setting error.");
297 startPosition = Offset(0.0, 0.0);
298 betweenPosition = Offset();
299 break;
300 }
301 }
302 auto context = context_.Upgrade();
303 bool applyNewOffset = context ? context->GetMinPlatformVersion() >= MIN_COMPATIBLE_VERSION : false;
304 if (applyNewOffset) {
305 // In content type, wrap is as large as children, no need to set alignment_.
306 if ((!isHorizontal && horizontalMeasure_ == MeasureType::CONTENT) ||
307 (isHorizontal && verticalMeasure_ == MeasureType::CONTENT)) {
308 startPosition = Offset();
309 betweenPosition = Offset();
310 }
311 }
312 TraverseContent(startPosition, betweenPosition);
313 }
314
GetContentOffset(double totalCrossLength) const315 Offset RenderWrap::GetContentOffset(double totalCrossLength) const
316 {
317 if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
318 return Offset(0.0, crossLengthLimit_ - totalCrossLength);
319 } else {
320 return Offset(crossLengthLimit_ - totalCrossLength, 0.0);
321 }
322 }
323
TraverseContent(const Offset & startPosition,const Offset & betweenPosition) const324 void RenderWrap::TraverseContent(const Offset& startPosition, const Offset& betweenPosition) const
325 {
326 // determine the content start position by main axis
327 Offset accumulateOffset = startPosition;
328 int32_t startItemIndex = 0;
329 double currentMainSpaceLength = 0.0;
330 for (const auto& content : contentList_) {
331 // dfs positioned item in each content
332 currentMainSpaceLength = mainLengthLimit_ - content.mainLength_;
333 int32_t itemNum = content.count_;
334 if (itemNum == 0) {
335 LOGE("fail to TraverseContent due to item num is zero");
336 return;
337 }
338
339 switch (mainAlignment_) {
340 case WrapAlignment::START: {
341 if ((direction_ == WrapDirection::HORIZONTAL && !isLeftToRight_) ||
342 (direction_ == WrapDirection::HORIZONTAL_REVERSE && isLeftToRight_) ||
343 (direction_ == WrapDirection::VERTICAL_REVERSE)) {
344 PositionedItem(0.0, content, accumulateOffset + GetItemMainOffset(currentMainSpaceLength),
345 content.crossLength_);
346 } else {
347 PositionedItem(0.0, content, accumulateOffset, content.crossLength_);
348 }
349 break;
350 }
351 case WrapAlignment::END: {
352 if ((direction_ == WrapDirection::HORIZONTAL && !isLeftToRight_) ||
353 (direction_ == WrapDirection::HORIZONTAL_REVERSE && isLeftToRight_) ||
354 direction_ == WrapDirection::VERTICAL_REVERSE) {
355 PositionedItem(0.0, content, accumulateOffset, content.crossLength_);
356 } else {
357 PositionedItem(0.0, content, accumulateOffset + GetItemMainOffset(currentMainSpaceLength),
358 content.crossLength_);
359 }
360 break;
361 }
362 case WrapAlignment::CENTER: {
363 // divided the space by two
364 PositionedItem(0.0, content, accumulateOffset + GetItemMainOffset(currentMainSpaceLength / 2),
365 content.crossLength_);
366 break;
367 }
368 case WrapAlignment::SPACE_BETWEEN: {
369 double betweenSpace = (itemNum - 1 == 0) ? 0.0 : currentMainSpaceLength / (itemNum - 1);
370 PositionedItem(betweenSpace, content, accumulateOffset, content.crossLength_);
371 break;
372 }
373 case WrapAlignment::SPACE_AROUND: {
374 double itemMainSpace = currentMainSpaceLength / itemNum;
375 PositionedItem(itemMainSpace, content, accumulateOffset + GetItemMainOffset(itemMainSpace / 2),
376 content.crossLength_);
377 break;
378 }
379 case WrapAlignment::SPACE_EVENLY: {
380 double itemMainSpace = currentMainSpaceLength / (itemNum + 1);
381 PositionedItem(
382 itemMainSpace, content, accumulateOffset + GetItemMainOffset(itemMainSpace), content.crossLength_);
383 break;
384 }
385 default: {
386 LOGE("Wrap::mainAlignment setting error. Now using START");
387 PositionedItem(0.0, content, accumulateOffset, content.crossLength_);
388 break;
389 }
390 }
391 auto contentSpace = NormalizeToPx(contentSpace_);
392 startItemIndex += itemNum;
393 accumulateOffset += betweenPosition;
394 accumulateOffset += (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE)
395 ? Offset(0.0, content.crossLength_ + contentSpace)
396 : Offset(content.crossLength_ + contentSpace, 0.0);
397 }
398 }
399
GetItemMainOffset(double mainSpace) const400 Offset RenderWrap::GetItemMainOffset(double mainSpace) const
401 {
402 // calculate the offset of each item in content
403 if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
404 return Offset(mainSpace, 0.0);
405 } else {
406 return Offset(0.0, mainSpace);
407 }
408 }
409
PositionedItem(double betweenSpace,const ContentInfo & content,const Offset & position,double totalCrossSpace) const410 void RenderWrap::PositionedItem(
411 double betweenSpace, const ContentInfo& content, const Offset& position, double totalCrossSpace) const
412 {
413 Offset itemPositionOffset;
414 // iterate every item in content
415 for (const auto& item : content.itemList_) {
416 switch (crossAlignment_) {
417 case WrapAlignment::START: {
418 if ((direction_ == WrapDirection::VERTICAL && !isLeftToRight_) ||
419 (direction_ == WrapDirection::VERTICAL_REVERSE && !isLeftToRight_)) {
420 HandleEndAlignment(totalCrossSpace, item, position, betweenSpace, itemPositionOffset);
421 } else {
422 HandleStartAlignment(item, position, betweenSpace, itemPositionOffset);
423 }
424 break;
425 }
426 case WrapAlignment::STRETCH: {
427 PlaceItemAndLog(item, position + itemPositionOffset, "STRETCH");
428 // stretch the component in wrap
429 LayoutParam layoutParam;
430 auto spacing = NormalizeToPx(spacing_);
431 if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
432 itemPositionOffset += Offset(item->GetLayoutSize().Width() + betweenSpace + spacing, 0.0);
433 layoutParam.SetFixedSize(Size(item->GetLayoutSize().Width(), totalCrossSpace));
434 } else {
435 itemPositionOffset += Offset(0.0, item->GetLayoutSize().Height() + betweenSpace + spacing);
436 layoutParam.SetFixedSize(Size(totalCrossSpace, item->GetLayoutSize().Height()));
437 }
438 item->Layout(layoutParam);
439 break;
440 }
441 case WrapAlignment::END: {
442 if ((direction_ == WrapDirection::VERTICAL && !isLeftToRight_) ||
443 (direction_ == WrapDirection::VERTICAL_REVERSE && !isLeftToRight_)) {
444 HandleStartAlignment(item, position, betweenSpace, itemPositionOffset);
445 } else {
446 HandleEndAlignment(totalCrossSpace, item, position, betweenSpace, itemPositionOffset);
447 }
448 break;
449 }
450 case WrapAlignment::CENTER: {
451 // divide the space by two
452 HandleCenterAlignment(totalCrossSpace, item, position, betweenSpace, itemPositionOffset);
453 break;
454 }
455 case WrapAlignment::BASELINE: {
456 if (direction_ == WrapDirection::VERTICAL || direction_ == WrapDirection::VERTICAL_REVERSE) {
457 if (isLeftToRight_) {
458 HandleStartAlignment(item, position, betweenSpace, itemPositionOffset);
459 } else {
460 HandleEndAlignment(totalCrossSpace, item, position, betweenSpace, itemPositionOffset);
461 }
462 } else {
463 HandleBaselineAlignment(
464 content.maxBaselineDistance, item, position, betweenSpace, itemPositionOffset);
465 }
466 break;
467 }
468 default: {
469 LOGW("Wrap::crossAlignment setting error. Now using START");
470 if ((direction_ == WrapDirection::VERTICAL && !isLeftToRight_) ||
471 (direction_ == WrapDirection::VERTICAL_REVERSE && !isLeftToRight_)) {
472 HandleEndAlignment(totalCrossSpace, item, position, betweenSpace, itemPositionOffset);
473 } else {
474 HandleStartAlignment(item, position, betweenSpace, itemPositionOffset);
475 }
476 break;
477 }
478 }
479 }
480 }
481
PlaceItemAndLog(const RefPtr<RenderNode> & node,const Offset & position,const std::string & align) const482 void RenderWrap::PlaceItemAndLog(const RefPtr<RenderNode>& node, const Offset& position, const std::string& align) const
483 {
484 node->SetPosition(position);
485 LOGD("Wrap::PositionedItem %s item position x:%lf, y:%lf", align.c_str(), position.GetX(), position.GetY());
486 }
487
HandleCenterAlignment(double totalCrossSpace,const RefPtr<RenderNode> & item,const Offset & position,double betweenSpace,Offset & itemPositionOffset) const488 void RenderWrap::HandleCenterAlignment(double totalCrossSpace, const RefPtr<RenderNode>& item, const Offset& position,
489 double betweenSpace, Offset& itemPositionOffset) const
490 {
491 // itemPositionOffset will change in this function
492 Offset crossOffset;
493 auto spacing = NormalizeToPx(spacing_);
494 if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
495 crossOffset = Offset(0.0, (totalCrossSpace - item->GetLayoutSize().Height()) / 2.0);
496 PlaceItemAndLog(item, position + itemPositionOffset + crossOffset, "CENTER");
497 itemPositionOffset += Offset(item->GetLayoutSize().Width() + betweenSpace + spacing, 0.0);
498 } else {
499 crossOffset = Offset((totalCrossSpace - item->GetLayoutSize().Width()) / 2, 0.0);
500 PlaceItemAndLog(item, position + itemPositionOffset + crossOffset, "CENTER");
501 itemPositionOffset += Offset(0.0, item->GetLayoutSize().Height() + betweenSpace + spacing);
502 }
503 }
504
HandleEndAlignment(double totalCrossSpace,const RefPtr<RenderNode> & item,const Offset & position,double betweenSpace,Offset & itemPositionOffset) const505 void RenderWrap::HandleEndAlignment(double totalCrossSpace, const RefPtr<RenderNode>& item, const Offset& position,
506 double betweenSpace, Offset& itemPositionOffset) const
507 {
508 // itemPositionOffset will change in this function
509 Offset crossOffset;
510 auto spacing = NormalizeToPx(spacing_);
511 if (direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE) {
512 crossOffset = Offset(0.0, totalCrossSpace - item->GetLayoutSize().Height());
513 PlaceItemAndLog(item, position + itemPositionOffset + crossOffset, "END");
514 itemPositionOffset += Offset(item->GetLayoutSize().Width() + betweenSpace + spacing, 0.0);
515 } else {
516 crossOffset = Offset(totalCrossSpace - item->GetLayoutSize().Width(), 0.0);
517 PlaceItemAndLog(item, position + itemPositionOffset + crossOffset, "END");
518 itemPositionOffset += Offset(0.0, item->GetLayoutSize().Height() + betweenSpace + spacing);
519 }
520 }
521
HandleBaselineAlignment(double totalCrossSpace,const RefPtr<RenderNode> & item,const Offset & position,double betweenSpace,Offset & itemPositionOffset) const522 void RenderWrap::HandleBaselineAlignment(double totalCrossSpace, const RefPtr<RenderNode>& item, const Offset& position,
523 double betweenSpace, Offset& itemPositionOffset) const
524 {
525 Offset crossOffset;
526 auto spacing = NormalizeToPx(spacing_);
527 crossOffset = Offset(0.0, totalCrossSpace - item->GetBaselineDistance(TextBaseline::ALPHABETIC));
528 PlaceItemAndLog(item, position + itemPositionOffset + crossOffset, "Baseline");
529 itemPositionOffset += Offset(item->GetLayoutSize().Width() + betweenSpace + spacing, 0.0);
530 }
531
HandleStartAlignment(const RefPtr<RenderNode> & item,const Offset & position,double betweenSpace,Offset & itemPositionOffset) const532 void RenderWrap::HandleStartAlignment(
533 const RefPtr<RenderNode>& item, const Offset& position, double betweenSpace, Offset& itemPositionOffset) const
534 {
535 PlaceItemAndLog(item, position + itemPositionOffset, "START");
536 // Decide content offset position
537 auto spacing = NormalizeToPx(spacing_);
538 bool isHorizontal = direction_ == WrapDirection::HORIZONTAL || direction_ == WrapDirection::HORIZONTAL_REVERSE;
539 itemPositionOffset += Offset(isHorizontal ? item->GetLayoutSize().Width() + betweenSpace + spacing : 0.0,
540 isHorizontal ? 0.0 : item->GetLayoutSize().Height() + betweenSpace + spacing);
541 }
542
ClearRenderObject()543 void RenderWrap::ClearRenderObject()
544 {
545 RenderNode::ClearRenderObject();
546 direction_ = WrapDirection::VERTICAL;
547 alignment_ = WrapAlignment::START;
548 mainAlignment_ = WrapAlignment::START;
549 crossAlignment_ = WrapAlignment::START;
550 spacing_ = Dimension();
551 contentSpace_ = Dimension();
552 mainLengthLimit_ = 0.0;
553 crossLengthLimit_ = 0.0;
554 totalMainLength_ = 0.0;
555 totalCrossLength_ = 0.0;
556
557 dialogDirection_ = WrapDirection::HORIZONTAL;
558 dialogStretch_ = false;
559 isLeftToRight_ = true;
560 }
561
MaybeRelease()562 bool RenderWrap::MaybeRelease()
563 {
564 auto context = GetContext().Upgrade();
565 if (context && context->GetRenderFactory() && context->GetRenderFactory()->GetRenderWrapFactory()->Recycle(this)) {
566 ClearRenderObject();
567 return false;
568 }
569 return true;
570 }
571
572 } // namespace OHOS::Ace