• 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/box/render_box_base.h"
17 
18 #include <algorithm>
19 
20 #include "base/geometry/offset.h"
21 #include "base/log/dump_log.h"
22 #include "base/utils/string_expression.h"
23 #include "core/animation/property_animatable_helper.h"
24 #include "core/components/box/box_base_component.h"
25 #include "core/components/common/properties/radius.h"
26 #include "core/components/flex/render_flex.h"
27 #include "core/components/text_field/render_text_field.h"
28 
29 namespace OHOS::Ace {
30 namespace {
31 
32 const double CIRCLE_LAYOUT_IN_BOX_SCALE = sin(M_PI_4);
33 constexpr double BOX_DIAMETER_TO_RADIUS = 2.0;
34 constexpr int32_t COMPATIBLE_VERSION = 5;
35 constexpr double TWO_SIDES = 2.0;
36 
37 } // namespace
38 
GetBorderSize() const39 Size RenderBoxBase::GetBorderSize() const
40 {
41     return Size(0.0, 0.0);
42 }
43 
GetBorderOffset() const44 Offset RenderBoxBase::GetBorderOffset() const
45 {
46     return Offset(0.0, 0.0);
47 }
48 
GetBorderRadius() const49 Radius RenderBoxBase::GetBorderRadius() const
50 {
51     return Radius();
52 }
53 
IsSizeValid(const Dimension & value,double maxLimit)54 bool RenderBoxBase::IsSizeValid(const Dimension& value, double maxLimit)
55 {
56     if (NearZero(value.Value())) {
57         return false;
58     }
59     if ((value.Unit() == DimensionUnit::PERCENT) && (NearEqual(maxLimit, Size::INFINITE_SIZE))) {
60         // When maxLimit is INFINITE, percent value is invalid, except PERCENT_FLAG_USE_VIEW_PORT is set.
61         return percentFlag_ == PERCENT_FLAG_USE_VIEW_PORT;
62     }
63     return true;
64 }
65 
OnAnimationCallback()66 void RenderBoxBase::OnAnimationCallback()
67 {
68     MarkNeedLayout();
69 }
70 
CalculateHeightPercent(double percent) const71 double RenderBoxBase::CalculateHeightPercent(double percent) const
72 {
73     return ConvertVerticalDimensionToPx(Dimension(percent, DimensionUnit::PERCENT));
74 }
75 
ConvertMarginToPx(CalcDimension dimension,bool vertical,bool additional) const76 double RenderBoxBase::ConvertMarginToPx(CalcDimension dimension, bool vertical, bool additional) const
77 {
78     if (dimension.Unit() == DimensionUnit::CALC) {
79         std::string value = dimension.CalcValue();
80         auto node = AceType::Claim(const_cast<RenderBoxBase*>(this));
81         return StringExpression::CalculateExp(value, [vertical, node](const Dimension& dim) -> double {
82                 return node->NormalizePercentToPx(dim, vertical, false);
83             });
84     } else if (dimension.Unit() == DimensionUnit::PERCENT) {
85         double parentLimit = 0.0;
86         if (vertical) {
87             parentLimit = GetLayoutParam().GetMaxSize().Height();
88             if (NearEqual(parentLimit, Size::INFINITE_SIZE) && !NearEqual(selfMaxHeight_, Size::INFINITE_SIZE)) {
89                 parentLimit = selfMaxHeight_;
90             }
91         } else {
92             parentLimit = GetLayoutParam().GetMaxSize().Width();
93             if (NearEqual(parentLimit, Size::INFINITE_SIZE) && !NearEqual(selfMaxWidth_, Size::INFINITE_SIZE)) {
94                 parentLimit = selfMaxWidth_;
95             }
96         }
97         if (NearEqual(parentLimit, Size::INFINITE_SIZE)) {
98             if (additional || percentFlag_ != PERCENT_FLAG_USE_VIEW_PORT) {
99                 return 0.0; // Additional(from theme) set to 0.0 when INFINITE_SIZE.
100             }
101             parentLimit = vertical ? viewPort_.Height() : viewPort_.Width();
102         }
103         return parentLimit * dimension.Value();
104     } else if (dimension.Unit() == DimensionUnit::PX) {
105         return dimension.Value();
106     } else {
107         auto context = context_.Upgrade();
108         if (!context) {
109             return dimension.Value();
110         }
111         return context->NormalizeToPx(dimension);
112     }
113 }
114 
ConvertDimensionToPx(CalcDimension dimension,bool vertical,bool defaultZero) const115 double RenderBoxBase::ConvertDimensionToPx(CalcDimension dimension, bool vertical, bool defaultZero) const
116 {
117     if (dimension.Unit() == DimensionUnit::CALC) {
118         std::string value = dimension.CalcValue();
119         auto node = AceType::Claim(const_cast<RenderBoxBase*>(this));
120         return StringExpression::CalculateExp(value, [vertical, node](const Dimension& dim) -> double {
121                 return node->NormalizePercentToPx(dim, vertical, false);
122             });
123     } else if (dimension.Unit() == DimensionUnit::PERCENT) {
124         double parentLimit = GetLayoutParam().GetMaxSize().Width();
125         if (vertical) {
126             parentLimit = GetLayoutParam().GetMaxSize().Height();
127         }
128         if (NearEqual(parentLimit, Size::INFINITE_SIZE)) {
129             if (percentFlag_ != PERCENT_FLAG_USE_VIEW_PORT) {
130                 return defaultZero ? 0.0 : Size::INFINITE_SIZE;
131             } else {
132                 parentLimit = vertical ? viewPort_.Height() : viewPort_.Width();
133             }
134         }
135         return parentLimit * dimension.Value();
136     } else if (dimension.Unit() == DimensionUnit::PX) {
137         return dimension.Value();
138     } else {
139         auto context = context_.Upgrade();
140         if (!context) {
141             return dimension.Value();
142         }
143         return context->NormalizeToPx(dimension);
144     }
145 }
146 
ConvertHorizontalDimensionToPx(CalcDimension dimension,bool defaultZero) const147 double RenderBoxBase::ConvertHorizontalDimensionToPx(CalcDimension dimension, bool defaultZero) const
148 {
149     return ConvertDimensionToPx(dimension, false, defaultZero);
150 }
151 
ConvertVerticalDimensionToPx(CalcDimension dimension,bool defaultZero) const152 double RenderBoxBase::ConvertVerticalDimensionToPx(CalcDimension dimension, bool defaultZero) const
153 {
154     return ConvertDimensionToPx(dimension, true, defaultZero);
155 }
156 
CalculateWidth()157 void RenderBoxBase::CalculateWidth()
158 {
159     useFlexWidth_ = true;
160     selfDefineWidth_ = false;
161     selfMaxWidth_ = ConvertHorizontalDimensionToPx(width_, false);
162     selfMinWidth_ = 0.0;
163     if (GreatOrEqual(selfMaxWidth_, 0.0) && !NearEqual(selfMaxWidth_, Size::INFINITE_SIZE)) {
164         selfMinWidth_ = 0.0;
165         selfDefineWidth_ = true;
166         useFlexWidth_ = false;
167     } else if (constraints_.IsWidthValid()) {
168         selfMaxWidth_ = constraints_.GetMaxSize().Width();
169         selfMinWidth_ = constraints_.GetMinSize().Width();
170         useFlexWidth_ = false;
171     } else if (flex_ != BoxFlex::FLEX_X && flex_ != BoxFlex::FLEX_XY) {
172         selfMaxWidth_ = Size::INFINITE_SIZE;
173         useFlexWidth_ = false;
174     } else {
175         // No width, no constrain, no flex, use default min and max, reset selfMaxWidth_ here.
176         selfMaxWidth_ = Size::INFINITE_SIZE;
177     }
178     if (!GetLayoutParam().HasUsedConstraints() && constraints_.IsWidthValid()) {
179         selfMaxWidth_ = std::clamp(selfMaxWidth_, constraints_.GetMinSize().Width(), constraints_.GetMaxSize().Width());
180         selfMinWidth_ = std::clamp(selfMinWidth_, constraints_.GetMinSize().Width(), constraints_.GetMaxSize().Width());
181     }
182 }
183 
CalculateHeight()184 void RenderBoxBase::CalculateHeight()
185 {
186     useFlexHeight_ = true;
187     selfDefineHeight_ = false;
188     selfMaxHeight_ = ConvertVerticalDimensionToPx(height_, false);
189     selfMinHeight_ = 0.0;
190     if (GreatOrEqual(selfMaxHeight_, 0.0) && !NearEqual(selfMaxHeight_, Size::INFINITE_SIZE)) {
191         selfMinHeight_ = 0.0;
192         selfDefineHeight_ = true;
193         useFlexHeight_ = false;
194     } else if (constraints_.IsHeightValid()) {
195         selfMaxHeight_ = constraints_.GetMaxSize().Height();
196         selfMinHeight_ = constraints_.GetMinSize().Height();
197         useFlexHeight_ = false;
198     } else if (flex_ != BoxFlex::FLEX_Y && flex_ != BoxFlex::FLEX_XY) {
199         selfMaxHeight_ = Size::INFINITE_SIZE;
200         useFlexHeight_ = false;
201     } else {
202         // No height, no constrain, no flex, use default min and max, reset selfMaxHeight_ here.
203         selfMaxHeight_ = Size::INFINITE_SIZE;
204     }
205     if (!GetLayoutParam().HasUsedConstraints() && constraints_.IsHeightValid()) {
206         selfMaxHeight_ =
207             std::clamp(selfMaxHeight_, constraints_.GetMinSize().Height(), constraints_.GetMaxSize().Height());
208         selfMinHeight_ =
209             std::clamp(selfMinHeight_, constraints_.GetMinSize().Height(), constraints_.GetMaxSize().Height());
210     }
211 }
212 
ConvertEdgeToPx(const Edge & edge,bool additional)213 EdgePx RenderBoxBase::ConvertEdgeToPx(const Edge& edge, bool additional)
214 {
215     EdgePx edgePx;
216     edgePx.SetLeft(Dimension(ConvertMarginToPx(edge.Left(), false, additional)));
217     edgePx.SetRight(Dimension(ConvertMarginToPx(edge.Right(), false, additional)));
218     edgePx.SetTop(Dimension(ConvertMarginToPx(edge.Top(), true, additional)));
219     edgePx.SetBottom(Dimension(ConvertMarginToPx(edge.Bottom(), true, additional)));
220     return edgePx;
221 }
222 
CalculateAutoMargin()223 void RenderBoxBase::CalculateAutoMargin()
224 {
225     double freeSpace = 0.0;
226     FlexDirection flexDir = FlexDirection::ROW;
227     if (marginOrigin_.Left().Unit() == DimensionUnit::AUTO || marginOrigin_.Right().Unit() == DimensionUnit::AUTO
228         || marginOrigin_.Top().Unit() == DimensionUnit::AUTO
229         || marginOrigin_.Bottom().Unit() == DimensionUnit::AUTO) {
230         RefPtr<RenderFlex> flexFather;
231         auto parent = GetParent().Upgrade();
232         while (parent) {
233             flexFather = AceType::DynamicCast<RenderFlex>(parent);
234             if (flexFather) {
235                 flexDir = flexFather->GetDirection();
236                 break;
237             }
238             parent = parent->GetParent().Upgrade();
239         }
240         LayoutParam param = GetLayoutParam();
241         if (flexDir == FlexDirection::ROW) {
242             freeSpace = param.GetMaxSize().Height() - height_.Value();
243             if (marginOrigin_.Top().Unit() == DimensionUnit::AUTO
244                 && marginOrigin_.Bottom().Unit() == DimensionUnit::AUTO) {
245                 marginOrigin_.SetTop(Dimension(freeSpace / TWO_SIDES, DimensionUnit::PX));
246                 marginOrigin_.SetBottom(Dimension(freeSpace / TWO_SIDES, DimensionUnit::PX));
247             } else if (marginOrigin_.Top().Unit() == DimensionUnit::AUTO) {
248                 marginOrigin_.SetBottom(Dimension(ConvertMarginToPx(marginOrigin_.Bottom(), true, false)));
249                 marginOrigin_.SetTop(Dimension((freeSpace - marginOrigin_.Bottom().Value()), DimensionUnit::PX));
250             } else if (marginOrigin_.Bottom().Unit() == DimensionUnit::AUTO) {
251                 marginOrigin_.SetTop(Dimension(ConvertMarginToPx(marginOrigin_.Top(), true, false)));
252                 marginOrigin_.SetBottom(Dimension((freeSpace - marginOrigin_.Top().Value()), DimensionUnit::PX));
253             }
254         } else if (flexDir == FlexDirection::COLUMN) {
255             freeSpace = param.GetMaxSize().Width() - width_.Value();
256             if (marginOrigin_.Left().Unit() == DimensionUnit::AUTO
257                 && marginOrigin_.Right().Unit() == DimensionUnit::AUTO) {
258                 marginOrigin_.SetLeft(Dimension(freeSpace / TWO_SIDES, DimensionUnit::PX));
259                 marginOrigin_.SetRight(Dimension(freeSpace / TWO_SIDES, DimensionUnit::PX));
260             } else if (marginOrigin_.Left().Unit() == DimensionUnit::AUTO) {
261                 marginOrigin_.SetRight(Dimension(ConvertMarginToPx(marginOrigin_.Right(), false, false)));
262                 marginOrigin_.SetLeft(Dimension((freeSpace - marginOrigin_.Right().Value()), DimensionUnit::PX));
263             } else if (marginOrigin_.Right().Unit() == DimensionUnit::AUTO) {
264                 marginOrigin_.SetLeft(Dimension(ConvertMarginToPx(marginOrigin_.Left(), false, false)));
265                 marginOrigin_.SetRight(Dimension((freeSpace - marginOrigin_.Left().Value()), DimensionUnit::PX));
266             }
267         }
268     }
269 }
270 
ConvertMarginPaddingToPx()271 void RenderBoxBase::ConvertMarginPaddingToPx()
272 {
273     padding_ = ConvertEdgeToPx(paddingOrigin_, false) + ConvertEdgeToPx(additionalPadding_, true);
274     CalculateAutoMargin();
275     margin_ = ConvertEdgeToPx(marginOrigin_, false);
276 }
277 
ConvertConstraintsToPx()278 void RenderBoxBase::ConvertConstraintsToPx()
279 {
280     // constraints is set from two ways, one is from BoxComponent::SetConstraints, the other is from DomNode.
281     // BoxComponent::SetConstraints is higher priority than DOMNode.
282     if (GetLayoutParam().HasUsedConstraints() || constraints_.IsWidthValid() || constraints_.IsHeightValid()) {
283         return;
284     }
285     double minWidth = ConvertHorizontalDimensionToPx(minWidth_, true);
286     double minHeight = ConvertVerticalDimensionToPx(minHeight_, true);
287     double maxWidth = ConvertHorizontalDimensionToPx(maxWidth_, true);
288     double maxHeight = ConvertVerticalDimensionToPx(maxHeight_, true);
289     if (LessOrEqual(minWidth, 0.0) && LessOrEqual(minHeight, 0.0) && LessOrEqual(maxWidth, 0.0) &&
290         LessOrEqual(maxHeight, 0.0)) {
291         return;
292     }
293     if (GreatNotEqual(minWidth, 0.0) && NearZero(maxWidth)) {
294         maxWidth = Size::INFINITE_SIZE;
295     }
296     if (GreatNotEqual(minHeight, 0.0) && NearZero(maxHeight)) {
297         maxHeight = Size::INFINITE_SIZE;
298     }
299     if (LessNotEqual(maxWidth, minWidth)) {
300         maxWidth = minWidth;
301     }
302     if (LessNotEqual(maxHeight, minHeight)) {
303         maxHeight = minHeight;
304     }
305     if (GreatNotEqual(minWidth, 0.0) || GreatNotEqual(minHeight, 0.0)) {
306         deliverMinToChild_ = true;
307     }
308     Size minSize = Size(minWidth, minHeight);
309     Size maxSize = Size(maxWidth, maxHeight);
310     constraints_ = LayoutParam(maxSize, minSize);
311 }
312 
CalculateGridLayoutSize()313 void RenderBoxBase::CalculateGridLayoutSize()
314 {
315     if (!gridColumnInfo_) {
316         return;
317     }
318 
319     auto offset = gridColumnInfo_->GetOffset();
320     if (offset != UNDEFINED_DIMENSION) {
321         auto context = context_.Upgrade();
322         positionParam_.type =
323             (context && context->GetIsDeclarative()) ? PositionType::SEMI_RELATIVE : PositionType::ABSOLUTE;
324         std::pair<AnimatableDimension, bool>& edge =
325             (GetTextDirection() == TextDirection::RTL) ? positionParam_.right : positionParam_.left;
326         edge.first = offset;
327         edge.second = true;
328     }
329 
330     double defaultWidth = gridColumnInfo_->GetWidth();
331     if (NearEqual(defaultWidth, 0.0)) {
332         return;
333     }
334     double maxWidth = gridColumnInfo_->GetMaxWidth();
335     if (!NearEqual(defaultWidth, maxWidth)) {
336         constraints_.SetMinWidth(defaultWidth);
337         constraints_.SetMaxWidth(maxWidth);
338     } else {
339         width_ = AnimatableDimension(gridColumnInfo_->GetWidth(), DimensionUnit::PX);
340         LayoutParam gridLayoutParam = GetLayoutParam();
341         gridLayoutParam.SetMaxSize(Size(width_.Value(), gridLayoutParam.GetMaxSize().Height()));
342         gridLayoutParam.SetMinSize(Size(width_.Value(), gridLayoutParam.GetMinSize().Height()));
343         SetLayoutParam(gridLayoutParam);
344     }
345 }
346 
CalculateSelfLayoutParam()347 void RenderBoxBase::CalculateSelfLayoutParam()
348 {
349     // first. Calculate width and height with the parameter that user set in box component
350     ConvertConstraintsToPx();
351     CalculateWidth();
352     CalculateHeight();
353 
354     if (gridContainerInfo_ && gridContainerInfo_->GetColumnType() == GridColumnType::NONE) {
355         marginOrigin_ = Edge(gridContainerInfo_->GetMarginLeft(), marginOrigin_.Top(),
356             gridContainerInfo_->GetMarginRight(), marginOrigin_.Bottom());
357     }
358     ConvertMarginPaddingToPx();
359     if (GreatNotEqual(aspectRatio_.Value(), 0.0)) {
360         AdjustSizeByAspectRatio();
361     }
362 
363     Size selfMax = Size(selfMaxWidth_, selfMaxHeight_);
364     Size selfMin = Size(selfMinWidth_, selfMinHeight_);
365 
366     // second. constrain parameter with LayoutParam
367     const LayoutParam& layoutSetByParent = GetLayoutParam();
368     Size constrainMax = selfMax;
369     Size constrainMin = selfMin;
370 
371     if (minPlatformVersion_ != COMPATIBLE_VERSION || width_.Unit() != DimensionUnit::PERCENT) {
372         constrainMax.SetWidth(constrainMax.Width() + margin_.GetLayoutSize().Width());
373         constrainMin.SetWidth(constrainMin.Width() + margin_.GetLayoutSize().Width());
374     }
375     if (minPlatformVersion_ != COMPATIBLE_VERSION || height_.Unit() != DimensionUnit::PERCENT) {
376         constrainMax.SetHeight(constrainMax.Height() + margin_.GetLayoutSize().Height());
377         constrainMin.SetHeight(constrainMin.Height() + margin_.GetLayoutSize().Height());
378     }
379 
380     selfMax = layoutSetByParent.Constrain(constrainMax);
381     selfMin = layoutSetByParent.Constrain(constrainMin);
382     auto context = context_.Upgrade();
383     // allow overflow parent when set height or width, except when set flexgrow or flexshrink
384     if (context->GetIsDeclarative()) {
385         if (selfDefineWidth_ && layoutSetByParent.GetMinSize().Width() != layoutSetByParent.GetMaxSize().Width()) {
386             selfMax.SetWidth(constrainMax.Width());
387         }
388         if (selfDefineHeight_ && layoutSetByParent.GetMinSize().Height() != layoutSetByParent.GetMaxSize().Height()) {
389             selfMax.SetHeight(constrainMax.Height());
390         }
391     }
392 
393     selfLayoutParam_.SetMaxSize(selfMax);
394     selfLayoutParam_.SetMinSize(selfMin);
395 
396     if (gridContainerInfo_) {
397         double width = selfMax.Width();
398         gridContainerInfo_->BuildColumnWidth(width);
399     }
400 
401     ConvertPaddingForLayoutInBox();
402 }
403 
AdjustSizeByAspectRatio()404 void RenderBoxBase::AdjustSizeByAspectRatio()
405 {
406     const LayoutParam& layoutSetByParent = GetLayoutParam();
407     LayoutParam selfLayout = layoutSetByParent;
408     if (!layoutSetByParent.HasUsedConstraints() && constraints_.IsWidthValid() && constraints_.IsHeightValid()) {
409         selfLayout = layoutSetByParent.Enforce(constraints_);
410     }
411     auto maxWidth = selfLayout.GetMaxSize().Width();
412     auto minWidth = selfLayout.GetMinSize().Width();
413     auto maxHeight = selfLayout.GetMaxSize().Height();
414     auto minHeight = selfLayout.GetMinSize().Height();
415     // Adjust by aspect ratio, firstly pick height based on width. It means that when width, height and aspectRatio are
416     // all set, the height is not used.
417     if (selfDefineWidth_) {
418         selfMaxHeight_ = selfMaxWidth_ / aspectRatio_.Value();
419     } else if (selfDefineHeight_) {
420         selfMaxWidth_ = selfMaxHeight_ * aspectRatio_.Value();
421     } else if (NearEqual(selfMaxWidth_, Size::INFINITE_SIZE)) {
422         selfMaxWidth_ = selfMaxHeight_ * aspectRatio_.Value();
423     } else {
424         selfMaxHeight_ = selfMaxWidth_ / aspectRatio_.Value();
425     }
426     if (selfMaxWidth_ > maxWidth) {
427         selfMaxWidth_ = maxWidth;
428         selfMaxHeight_ = selfMaxWidth_ / aspectRatio_.Value();
429     }
430     if (selfMaxHeight_ > maxHeight) {
431         selfMaxHeight_ = maxHeight;
432         selfMaxWidth_ = selfMaxHeight_ * aspectRatio_.Value();
433     }
434     if (selfMaxWidth_ < minWidth) {
435         selfMaxWidth_ = minWidth;
436         selfMaxHeight_ = selfMaxWidth_ / aspectRatio_.Value();
437     }
438     if (selfMaxHeight_ < minHeight) {
439         selfMaxHeight_ = minHeight;
440         selfMaxWidth_ = selfMaxHeight_ * aspectRatio_.Value();
441     }
442     if (!NearEqual(selfMaxWidth_, Size::INFINITE_SIZE) && !NearEqual(selfMaxHeight_, Size::INFINITE_SIZE)) {
443         selfDefineWidth_ = true;
444         selfDefineHeight_ = true;
445     }
446 }
447 
SetChildLayoutParam()448 void RenderBoxBase::SetChildLayoutParam()
449 {
450     Size deflate;
451     if (boxSizing_ == BoxSizing::BORDER_BOX) {
452         deflate += padding_.GetLayoutSize();
453         deflate += GetBorderSize();
454     }
455     deflate += margin_.GetLayoutSize();
456 
457     if (deliverMinToChild_) {
458         double minWidth = std::max(selfLayoutParam_.GetMinSize().Width() - deflate.Width(), 0.0);
459         double minHeight = std::max(selfLayoutParam_.GetMinSize().Height() - deflate.Height(), 0.0);
460         childLayoutParam_.SetMinSize(Size(minWidth, minHeight));
461     } else {
462         childLayoutParam_.SetMinSize(Size(0.0, 0.0));
463     }
464 
465     double maxWidth = std::max(selfLayoutParam_.GetMaxSize().Width() - deflate.Width(), 0.0);
466     double maxHeight = std::max(selfLayoutParam_.GetMaxSize().Height() - deflate.Height(), 0.0);
467     childLayoutParam_.SetMaxSize(Size(maxWidth, maxHeight));
468 
469     // First time layout all children
470     for (const auto& item : GetChildren()) {
471         item->Layout(childLayoutParam_);
472     }
473 }
474 
ConvertPaddingForLayoutInBox()475 void RenderBoxBase::ConvertPaddingForLayoutInBox()
476 {
477     if (!layoutInBox_) {
478         return;
479     }
480 
481     Size layoutParmMax = selfLayoutParam_.GetMaxSize();
482     Size borderSize = GetBorderSize();
483     double diameter = std::min(layoutParmMax.Width() - margin_.GetLayoutSize().Width() - borderSize.Width(),
484         layoutParmMax.Height() - margin_.GetLayoutSize().Height() - borderSize.Height());
485 
486     double circlePadding = diameter * (1.0 - CIRCLE_LAYOUT_IN_BOX_SCALE) / BOX_DIAMETER_TO_RADIUS;
487 
488     padding_.SetLeft(Dimension(std::max(padding_.LeftPx(), circlePadding)));
489     padding_.SetTop(Dimension(std::max(padding_.TopPx(), circlePadding)));
490     padding_.SetRight(Dimension(std::max(padding_.RightPx(), circlePadding)));
491     padding_.SetBottom(Dimension(std::max(padding_.BottomPx(), circlePadding)));
492 }
493 
CalculateSelfLayoutSize()494 void RenderBoxBase::CalculateSelfLayoutSize()
495 {
496     Size borderSize = GetBorderSize();
497 
498     const LayoutParam& layoutSetByParent = GetLayoutParam();
499     Size selfMax = selfLayoutParam_.GetMaxSize() - margin_.GetLayoutSize();
500     if (!GetChildren().empty()) {
501         childSize_ = GetChildren().front()->GetLayoutSize();
502     }
503     // calculate width
504     double width = 0.0;
505     double childWidth = childSize_.Width() + padding_.GetLayoutSize().Width() + borderSize.Width();
506     if (selfDefineWidth_) {
507         if (boxSizing_ == BoxSizing::BORDER_BOX) {
508             width = selfMax.Width();
509         } else {
510             width = selfMax.Width() + padding_.GetLayoutSize().Width() + borderSize.Width();
511         }
512     } else if (useFlexWidth_) {
513         if (layoutSetByParent.GetMaxSize().IsWidthInfinite() && viewPort_.Width() < childWidth) {
514             width = childWidth;
515         } else {
516             double flexWidth = layoutSetByParent.GetMaxSize().IsWidthInfinite() && !viewPort_.IsWidthInfinite()
517                                    ? viewPort_.Width()
518                                    : layoutSetByParent.GetMaxSize().Width();
519             width = flexWidth - margin_.GetLayoutSize().Width();
520         }
521     } else {
522         width = childWidth;
523         if (gridColumnInfo_) {
524             auto columnWidth = gridColumnInfo_->GetWidth();
525             if (NearEqual(columnWidth, gridColumnInfo_->GetMaxWidth()) && !NearEqual(columnWidth, 0.0)) {
526                 width = columnWidth;
527             }
528         }
529     }
530     // calculate height
531     double height = 0.0;
532     double childHeight = childSize_.Height() + padding_.GetLayoutSize().Height() + borderSize.Height();
533     if (selfDefineHeight_) {
534         if (boxSizing_ == BoxSizing::BORDER_BOX) {
535             height = selfMax.Height();
536         } else {
537             height = selfMax.Height() + padding_.GetLayoutSize().Height() + borderSize.Height();
538         }
539     } else if (useFlexHeight_) {
540         if (layoutSetByParent.GetMaxSize().IsHeightInfinite() && viewPort_.Height() < childHeight) {
541             height = childHeight;
542         } else {
543             double flexHeight = layoutSetByParent.GetMaxSize().IsHeightInfinite() && !viewPort_.IsHeightInfinite()
544                                     ? viewPort_.Height()
545                                     : layoutSetByParent.GetMaxSize().Height();
546             height = flexHeight - margin_.GetLayoutSize().Height();
547         }
548     } else {
549         height = childSize_.Height() + padding_.GetLayoutSize().Height() + borderSize.Height();
550     }
551 
552     const static int32_t PLATFORM_VERSION_SIX = 6;
553     auto context = GetContext().Upgrade();
554     if (context && context->GetMinPlatformVersion() >= PLATFORM_VERSION_SIX) {
555         double minWidth = padding_.GetLayoutSize().Width() + borderSize.Width();
556         double minHeight = padding_.GetLayoutSize().Height() + borderSize.Height();
557         width = width > minWidth ? width : minWidth;
558         height = height > minHeight ? height : minHeight;
559     }
560     // allow force layoutsize for parend
561     if (layoutSetByParent.GetMaxSize().Width() == layoutSetByParent.GetMinSize().Width()) {
562         width = layoutSetByParent.GetMinSize().Width();
563     }
564     if (layoutSetByParent.GetMaxSize().Height() == layoutSetByParent.GetMinSize().Height()) {
565         height = layoutSetByParent.GetMinSize().Height();
566     }
567     paintSize_ = Size(width, height);
568 
569     if (context && context->GetIsDeclarative()) {
570         // box layout size = paint size + margin size
571         if (LessNotEqual(margin_.LeftPx(), 0.0)) {
572             positionParam_.left = std::make_pair(margin_.Left(), true);
573             margin_.SetLeft(Dimension(0.0, margin_.Left().Unit()));
574         }
575         if (LessNotEqual(margin_.TopPx(), 0.0)) {
576             positionParam_.top = std::make_pair(margin_.Top(), true);
577             margin_.SetTop(Dimension(0.0, margin_.Top().Unit()));
578         }
579         selfLayoutSize_ = paintSize_ + margin_.GetLayoutSize();
580     } else {
581         selfLayoutSize_ = GetLayoutParam().Constrain(paintSize_ + margin_.GetLayoutSize());
582     }
583 
584     paintSize_ = selfLayoutSize_ - margin_.GetLayoutSize();
585     touchArea_.SetOffset(margin_.GetOffset());
586     touchArea_.SetSize(paintSize_);
587     SetLayoutSize(selfLayoutSize_);
588     isChildOverflow_ = childSize_.Width() > GetLayoutSize().Width() || childSize_.Height() > GetLayoutSize().Height();
589 }
590 
CalculateChildPosition()591 void RenderBoxBase::CalculateChildPosition()
592 {
593     Offset borderOffset = GetBorderOffset();
594     Size parentSize = selfLayoutSize_ - margin_.GetLayoutSize() - padding_.GetLayoutSize();
595     parentSize -= GetBorderSize();
596 
597     if (!GetChildren().empty()) {
598         const auto& child = GetChildren().front();
599         childPosition_ = margin_.GetOffset() + borderOffset + padding_.GetOffset() +
600                          Alignment::GetAlignPosition(parentSize, child->GetLayoutSize(), align_);
601         child->SetPosition(childPosition_);
602     }
603 }
604 
PerformLayout()605 void RenderBoxBase::PerformLayout()
606 {
607     // update scale for margin, padding
608     auto context = context_.Upgrade();
609     if (!context) {
610         LOGE("[BOX][Dep:%{public}d][LAYOUT]Call Context Upgrade failed. PerformLayout failed.", this->GetDepth());
611         return;
612     }
613     if (isUseAlign_) {
614         context->AddAlignDeclarationNode(AceType::Claim(this));
615     }
616 
617     CalculateGridLayoutSize();
618     // first. calculate self layout param
619     CalculateSelfLayoutParam();
620     // second. set layout param of child to calculate layout size
621     SetChildLayoutParam();
622     // third. using layout size of child, calculate layout size of box
623     CalculateSelfLayoutSize();
624     // forth. calculate position of child
625     CalculateChildPosition();
626 
627     if (isUseAlign_) {
628         CalculateAlignDeclaration();
629     }
630 
631     if (layoutCallback_) {
632         layoutCallback_();
633     }
634 }
635 
PerformLayoutInLiteMode()636 void RenderBoxBase::PerformLayoutInLiteMode()
637 {
638     // Lite must has width and height
639     CalculateWidth();
640     CalculateHeight();
641     ConvertMarginPaddingToPx();
642     if (NearEqual(selfMaxWidth_, Size::INFINITE_SIZE) && !selfDefineWidth_) {
643         selfMaxWidth_ = GetLayoutParam().GetMaxSize().Width();
644     }
645     if (NearEqual(selfMaxHeight_, Size::INFINITE_SIZE) && !selfDefineHeight_) {
646         selfMaxHeight_ = GetLayoutParam().GetMaxSize().Height();
647     }
648     Size selfMax = Size(selfMaxWidth_, selfMaxHeight_) + margin_.GetLayoutSize();
649     Size selfMin = Size(selfMinWidth_, selfMinHeight_) + margin_.GetLayoutSize();
650     // Do not constrain param in lite mode
651     selfLayoutParam_.SetMaxSize(selfMax);
652     selfLayoutParam_.SetMinSize(selfMin);
653     SetChildLayoutParam();
654     double width = 0.0;
655     double height = 0.0;
656     Size borderSize = GetBorderSize();
657     childSize_ = GetChildren().front()->GetLayoutSize();
658     if (selfDefineWidth_) {
659         width = selfMax.Width() - margin_.GetLayoutSize().Width();
660     } else {
661         width = childSize_.Width() + padding_.GetLayoutSize().Width() + borderSize.Width();
662     }
663     if (selfDefineHeight_) {
664         height = selfMax.Height() - margin_.GetLayoutSize().Height();
665     } else {
666         height = childSize_.Height() + padding_.GetLayoutSize().Height() + borderSize.Height();
667     }
668     double targetHeight = padding_.GetLayoutSize().Height() + borderSize.Height();
669     targetHeight = targetHeight > height ? targetHeight : height;
670     double targetWidth = padding_.GetLayoutSize().Width() + borderSize.Width();
671     targetHeight = targetWidth > width ? targetWidth : width;
672     // Determine self size, not use constrain.
673     paintSize_ = Size(targetWidth, targetHeight);
674     selfLayoutSize_ = paintSize_ + margin_.GetLayoutSize();
675     touchArea_.SetOffset(margin_.GetOffset());
676     touchArea_.SetSize(paintSize_);
677     SetLayoutSize(selfLayoutSize_);
678     CalculateChildPosition();
679 }
680 
Update(const RefPtr<Component> & component)681 void RenderBoxBase::Update(const RefPtr<Component>& component)
682 {
683     const RefPtr<BoxBaseComponent> box = AceType::DynamicCast<BoxBaseComponent>(component);
684     if (box) {
685         scrollPage_ = box->GetScrollPage();
686 
687         paddingOrigin_ = box->GetPadding();
688         marginOrigin_ = box->GetMargin();
689         additionalPadding_ = box->GetAdditionalPadding();
690         flex_ = box->GetFlex();
691         boxSizing_ = box->GetBoxSizing();
692         constraints_ = box->GetConstraints();
693         align_ = box->GetAlignment();
694         overflow_ = box->GetOverflow();
695         clipPath_ = box->GetClipPath();
696         deliverMinToChild_ = box->GetDeliverMinToChild();
697         width_ = box->GetWidthDimension();
698         height_ = box->GetHeightDimension();
699         auto context = context_.Upgrade();
700         if (context && scrollPage_) {
701             height_ = AnimatableDimension(context->GetStageRect().Height(), DimensionUnit::PX);
702         }
703         percentFlag_ = box->GetPercentFlag();
704         layoutInBox_ = box->GetLayoutInBoxFlag();
705         aspectRatio_ = box->GetAspectRatio();
706         minWidth_ = box->GetMinWidth();
707         minHeight_ = box->GetMinHeight();
708         maxWidth_ = box->GetMaxWidth();
709         maxHeight_ = box->GetMaxHeight();
710         useLiteStyle_ = box->UseLiteStyle();
711         mask_ = box->GetMask();
712         auto gridLayoutInfo = box->GetGridLayoutInfo();
713         auto gridColumnInfo = AceType::DynamicCast<GridColumnInfo>(gridLayoutInfo);
714         if (gridColumnInfo) {
715             gridColumnInfo_ = gridColumnInfo;
716         } else {
717             auto gridContainerInfo = AceType::DynamicCast<GridContainerInfo>(gridLayoutInfo);
718             if (gridContainerInfo) {
719                 gridContainerInfo_ = gridContainerInfo;
720             }
721         }
722         isUseAlign_ = box->IsUseAlign();
723         if (isUseAlign_) {
724             alignPtr_ = box->GetAlignDeclarationPtr();
725             alignSide_ = box->GetUseAlignSide();
726             alignItemOffset_ = box->GetUseAlignOffset();
727         }
728         boxClipFlag_ = box->GetBoxClipFlag();
729         pixelMap_ = box->GetPixelMap();
730 
731         MarkNeedLayout();
732     }
733 }
734 
GetPaintPosition() const735 Offset RenderBoxBase::GetPaintPosition() const
736 {
737     return margin_.GetOffset();
738 }
739 
GetPaintSize() const740 const Size& RenderBoxBase::GetPaintSize() const
741 {
742     return paintSize_;
743 }
744 
SetPaintSize(const Size & paintSize)745 void RenderBoxBase::SetPaintSize(const Size& paintSize)
746 {
747     paintSize_ = paintSize;
748 }
749 
Dump()750 void RenderBoxBase::Dump()
751 {
752     double dipScale = 1.0;
753     auto context = context_.Upgrade();
754     if (context) {
755         dipScale = context->GetDipScale();
756     }
757     Size borderSize = GetBorderSize();
758     Radius radius = GetBorderRadius();
759     DumpLog::GetInstance().AddDesc("BoxFlex: " + std::to_string(static_cast<int32_t>(flex_)) +
760                                    ", BGcolor: " + std::to_string(GetColor().GetValue()) + ", BoxSizing: " +
761                                    std::to_string(static_cast<int32_t>(boxSizing_)) + ", Align: " + align_.ToString());
762     DumpLog::GetInstance().AddDesc(std::string("WH: ")
763                                        .append(Size(width_.Value(), height_.Value()).ToString())
764                                        .append(", Margin: ")
765                                        .append(margin_.GetLayoutSizeInPx(dipScale).ToString())
766                                        .append(", Padding: ")
767                                        .append(padding_.GetLayoutSizeInPx(dipScale).ToString())
768                                        .append(", Border: ")
769                                        .append(borderSize.ToString())
770                                        .append(", Radius: ")
771                                        .append(radius.GetX().ToString()));
772     DumpLog::GetInstance().AddDesc(std::string("Constraints: ")
773                                        .append(constraints_.ToString())
774                                        .append(", ChildLayout: ")
775                                        .append(childLayoutParam_.ToString()));
776     DumpLog::GetInstance().AddDesc(std::string("PaintSize: ")
777                                        .append(paintSize_.ToString())
778                                        .append(", TouchArea: ")
779                                        .append(touchArea_.ToString()));
780     DumpLog::GetInstance().AddDesc(std::string("SelfSize: ")
781                                        .append(selfLayoutSize_.ToString())
782                                        .append(", ChildSize: ")
783                                        .append(childSize_.ToString())
784                                        .append(", ChildPos: ")
785                                        .append(childPosition_.ToString()));
786     DumpLog::GetInstance().AddDesc(std::string("alignOffset: ")
787                                        .append(alignOffset_.ToString()));
788     if (gridColumnInfo_) {
789         DumpLog::GetInstance().AddDesc(std::string("GridColumnInfo"));
790     }
791     if (gridContainerInfo_) {
792         DumpLog::GetInstance().AddDesc(std::string("GridContainerInfo"));
793     }
794 }
795 
ClearRenderObject()796 void RenderBoxBase::ClearRenderObject()
797 {
798     RenderNode::ClearRenderObject();
799     width_ = Dimension(-1.0);
800     height_ = Dimension(-1.0);
801     flex_ = BoxFlex::FLEX_NO;
802 
803     constraints_ = LayoutParam(Size(), Size());
804     padding_ = EdgePx();
805     margin_ = EdgePx();
806     align_ = Alignment();
807     paintSize_ = Size();
808     touchArea_ = Rect();
809 
810     deliverMinToChild_ = true;
811     scrollPage_ = false;
812     percentFlag_ = 0;
813     layoutInBox_ = false;
814 
815     paddingOrigin_ = Edge();
816     marginOrigin_ = Edge();
817     additionalPadding_ = Edge();
818 
819     useFlexWidth_ = false;
820     useFlexHeight_ = false;
821     selfDefineWidth_ = false;
822     selfDefineHeight_ = false;
823     selfMaxWidth_ = Size::INFINITE_SIZE;
824     selfMinWidth_ = 0.0;
825     selfMaxHeight_ = Size::INFINITE_SIZE;
826     selfMinHeight_ = 0.0;
827 
828     aspectRatio_ = AnimatableDimension();
829     minWidth_ = Dimension();
830     minHeight_ = Dimension();
831     maxWidth_ = Dimension();
832     maxHeight_ = Dimension();
833 
834     selfLayoutParam_ = LayoutParam();
835     selfLayoutSize_ = Size();
836     childLayoutParam_ = LayoutParam();
837     childSize_ = Size();
838     childPosition_ = Offset();
839 
840     layoutCallback_ = nullptr;
841     gridColumnInfo_ = nullptr;
842     gridContainerInfo_ = nullptr;
843 
844     isUseAlign_ = false;
845     alignPtr_ = nullptr;
846     alignSide_ = AlignDeclaration::Edge::AUTO;
847     alignItemOffset_ = Dimension();
848     alignOffset_.Reset();
849 }
850 
GetFloatPropertySetterMap()851 FloatPropertyAnimatable::SetterMap RenderBoxBase::GetFloatPropertySetterMap()
852 {
853     FloatPropertyAnimatable::SetterMap map;
854     auto weak = AceType::WeakClaim(this);
855     map[PropertyAnimatableType::PROPERTY_WIDTH] = [weak](float value) {
856         auto box = weak.Upgrade();
857         if (!box) {
858             LOGE("Set width failed. box is null.");
859             return;
860         }
861         box->SetWidth(value);
862     };
863     const RefPtr<RenderTextField> renderTextField = AceType::DynamicCast<RenderTextField>(GetFirstChild());
864     if (renderTextField) {
865         WeakPtr<RenderTextField> textWeak = renderTextField;
866         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [textWeak](float value) {
867             auto renderTextField = textWeak.Upgrade();
868             if (!renderTextField) {
869                 LOGE("Set height failed. text is null.");
870                 return;
871             }
872             return renderTextField->SetHeight(value);
873         };
874     } else {
875         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [weak](float value) {
876             auto box = weak.Upgrade();
877             if (!box) {
878                 LOGE("Set height failed. box is null.");
879                 return;
880             }
881             box->SetHeight(value);
882         };
883     }
884     return map;
885 };
886 
GetFloatPropertyGetterMap()887 FloatPropertyAnimatable::GetterMap RenderBoxBase::GetFloatPropertyGetterMap()
888 {
889     FloatPropertyAnimatable::GetterMap map;
890     auto weak = AceType::WeakClaim(this);
891     map[PropertyAnimatableType::PROPERTY_WIDTH] = [weak]() -> float {
892         auto box = weak.Upgrade();
893         if (!box) {
894             LOGE("Get width failed. box is null.");
895             return 0.0;
896         }
897         return box->GetWidth();
898     };
899     const RefPtr<RenderTextField> renderTextField = AceType::DynamicCast<RenderTextField>(GetFirstChild());
900     if (renderTextField) {
901         WeakPtr<RenderTextField> textWeak = renderTextField;
902         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [textWeak]() -> float {
903             auto renderTextField = textWeak.Upgrade();
904             if (!renderTextField) {
905                 LOGE("Get height failed. text is null.");
906                 return 0.0;
907             }
908             return renderTextField->GetHeight();
909         };
910     } else {
911         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [weak]() -> float {
912             auto box = weak.Upgrade();
913             if (!box) {
914                 LOGE("Get height failed. box is null.");
915                 return 0.0;
916             }
917             return box->GetHeight();
918         };
919     }
920     return map;
921 }
922 
CalculateAlignDeclaration()923 void RenderBoxBase::CalculateAlignDeclaration()
924 {
925     alignOffset_.Reset();
926     if (!GetAlignDeclarationOffset(alignPtr_, alignOffset_)) {
927         alignOffset_.Reset();
928         return;
929     }
930 
931     double itemAlignOffset = 0.0;
932     auto context = GetContext().Upgrade();
933     if (context) {
934         itemAlignOffset = context->NormalizeToPx(alignItemOffset_);
935     }
936 
937     switch (alignSide_) {
938         case AlignDeclaration::Edge::TOP:
939             alignOffset_ = alignOffset_ + Offset(0, itemAlignOffset);
940             break;
941         case AlignDeclaration::Edge::CENTER:
942             alignOffset_ = alignOffset_ - Offset(0, GetLayoutSize().Height() / 2 - itemAlignOffset);
943             break;
944         case AlignDeclaration::Edge::BOTTOM:
945             alignOffset_ = alignOffset_ - Offset(0, GetLayoutSize().Height() - itemAlignOffset);
946             break;
947         case AlignDeclaration::Edge::BASELINE:
948             alignOffset_ = alignOffset_ - Offset(0, GetBaselineDistance(TextBaseline::ALPHABETIC) - itemAlignOffset);
949             break;
950         case AlignDeclaration::Edge::START:
951             alignOffset_ = alignOffset_ + Offset(itemAlignOffset, 0);
952             break;
953         case AlignDeclaration::Edge::MIDDLE:
954             alignOffset_ = alignOffset_ - Offset(GetLayoutSize().Width() / 2 - itemAlignOffset, 0);
955             break;
956         case AlignDeclaration::Edge::END:
957             alignOffset_ = alignOffset_ - Offset(GetLayoutSize().Width() - itemAlignOffset, 0);
958             break;
959         default:
960             alignOffset_.Reset();
961             break;
962     }
963 }
964 
965 } // namespace OHOS::Ace
966