• 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 
SetAutoMargin(FlexDirection flexDir,double freeSpace,bool isFirst)223 Edge RenderBoxBase::SetAutoMargin(FlexDirection flexDir, double freeSpace, bool isFirst)
224 {
225     Edge margin;
226     if (isFirst) {
227         margin = marginOrigin_;
228     } else {
229         margin = marginBackup_;
230     }
231 
232     if (flexDir == FlexDirection::COLUMN) {
233         if (margin.Left().Unit() == DimensionUnit::AUTO && margin.Right().Unit() == DimensionUnit::AUTO) {
234             marginOrigin_.SetLeft(Dimension(freeSpace / TWO_SIDES, DimensionUnit::PX));
235             marginOrigin_.SetRight(Dimension(freeSpace / TWO_SIDES, DimensionUnit::PX));
236         } else if (margin.Left().Unit() == DimensionUnit::AUTO) {
237             marginOrigin_.SetRight(Dimension(ConvertMarginToPx(margin.Right(), false, false)));
238             marginOrigin_.SetLeft(Dimension((freeSpace - marginOrigin_.Right().Value()), DimensionUnit::PX));
239         } else if (margin.Right().Unit() == DimensionUnit::AUTO) {
240             marginOrigin_.SetLeft(Dimension(ConvertMarginToPx(margin.Left(), false, false)));
241             marginOrigin_.SetRight(Dimension((freeSpace - marginOrigin_.Left().Value()), DimensionUnit::PX));
242         }
243     } else {
244         if (margin.Top().Unit() == DimensionUnit::AUTO && margin.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 (margin.Top().Unit() == DimensionUnit::AUTO) {
248             marginOrigin_.SetBottom(Dimension(ConvertMarginToPx(margin.Bottom(), true, false)));
249             marginOrigin_.SetTop(Dimension((freeSpace - marginOrigin_.Bottom().Value()), DimensionUnit::PX));
250         } else if (margin.Bottom().Unit() == DimensionUnit::AUTO) {
251             marginOrigin_.SetTop(Dimension(ConvertMarginToPx(margin.Top(), true, false)));
252             marginOrigin_.SetBottom(Dimension((freeSpace - marginOrigin_.Top().Value()), DimensionUnit::PX));
253         }
254     }
255     return marginOrigin_;
256 }
257 
CalculateAutoMargin()258 void RenderBoxBase::CalculateAutoMargin()
259 {
260     double freeSpace = 0.0, width = 0.0, height = 0.0;
261     FlexDirection flexDir = FlexDirection::ROW;
262     if (marginOrigin_.Left().Unit() == DimensionUnit::AUTO || marginOrigin_.Right().Unit() == DimensionUnit::AUTO ||
263         marginOrigin_.Top().Unit() == DimensionUnit::AUTO || marginOrigin_.Bottom().Unit() == DimensionUnit::AUTO ||
264         marginBackup_.Left().Unit() == DimensionUnit::AUTO || marginBackup_.Right().Unit() == DimensionUnit::AUTO ||
265         marginBackup_.Top().Unit() == DimensionUnit::AUTO || marginBackup_.Bottom().Unit() == DimensionUnit::AUTO) {
266         auto parent = GetParent().Upgrade();
267         while (parent) {
268             RefPtr<RenderFlex> flexFather = AceType::DynamicCast<RenderFlex>(parent);
269             if (flexFather) {
270                 flexDir = flexFather->GetDirection();
271                 break;
272             }
273             parent = parent->GetParent().Upgrade();
274         }
275         LayoutParam param = GetLayoutParam();
276         if ((flexDir == FlexDirection::COLUMN ||
277                 (flexDir == FlexDirection::ROW && displayType_ == DisplayType::BLOCK)) &&
278             width_.Value() == -1.0) {
279             if (childWidth_ != 0.0) {
280                 width = childWidth_;
281                 freeSpace = param.GetMaxSize().Width() - width;
282                 SetAutoMargin(FlexDirection::COLUMN, freeSpace, false);
283             } else {
284                 marginBackup_ = marginOrigin_;
285                 marginOrigin_.SetLeft(Dimension(0.0, DimensionUnit::PX));
286                 marginOrigin_.SetRight(Dimension(0.0, DimensionUnit::PX));
287                 needReCalc_ = true;
288             }
289         } else if ((flexDir == FlexDirection::COLUMN ||
290                        (flexDir == FlexDirection::ROW && displayType_ == DisplayType::BLOCK)) &&
291                    width_.Value() != -1.0) {
292             width = width_.Value();
293             freeSpace = param.GetMaxSize().Width() - width;
294             SetAutoMargin(FlexDirection::COLUMN, freeSpace, true);
295         } else if (flexDir == FlexDirection::ROW && height_.Value() == -1.0) {
296             if (childHeight_ != 0.0) {
297                 height = childHeight_;
298                 freeSpace = param.GetMaxSize().Height() - height;
299                 SetAutoMargin(flexDir, freeSpace, false);
300             } else {
301                 marginBackup_ = marginOrigin_;
302                 marginOrigin_.SetTop(Dimension(0.0, DimensionUnit::PX));
303                 marginOrigin_.SetBottom(Dimension(0.0, DimensionUnit::PX));
304                 needReCalc_ = true;
305             }
306         } else if (flexDir == FlexDirection::ROW && height_.Value() != -1.0) {
307             height = height_.Value();
308             freeSpace = param.GetMaxSize().Height() - height;
309             SetAutoMargin(flexDir, freeSpace, true);
310         }
311     }
312 }
313 
ConvertMarginPaddingToPx()314 void RenderBoxBase::ConvertMarginPaddingToPx()
315 {
316     padding_ = ConvertEdgeToPx(paddingOrigin_, false) + ConvertEdgeToPx(additionalPadding_, true);
317     CalculateAutoMargin();
318     margin_ = ConvertEdgeToPx(marginOrigin_, false);
319 }
320 
ConvertConstraintsToPx()321 void RenderBoxBase::ConvertConstraintsToPx()
322 {
323     // constraints is set from two ways, one is from BoxComponent::SetConstraints, the other is from DomNode.
324     // BoxComponent::SetConstraints is higher priority than DOMNode.
325     if (GetLayoutParam().HasUsedConstraints() || constraints_.IsWidthValid() || constraints_.IsHeightValid()) {
326         return;
327     }
328     double minWidth = ConvertHorizontalDimensionToPx(minWidth_, true);
329     double minHeight = ConvertVerticalDimensionToPx(minHeight_, true);
330     double maxWidth = ConvertHorizontalDimensionToPx(maxWidth_, true);
331     double maxHeight = ConvertVerticalDimensionToPx(maxHeight_, true);
332     if (LessOrEqual(minWidth, 0.0) && LessOrEqual(minHeight, 0.0) && LessOrEqual(maxWidth, 0.0) &&
333         LessOrEqual(maxHeight, 0.0)) {
334         return;
335     }
336     if (GreatNotEqual(minWidth, 0.0) && NearZero(maxWidth)) {
337         maxWidth = Size::INFINITE_SIZE;
338     }
339     if (GreatNotEqual(minHeight, 0.0) && NearZero(maxHeight)) {
340         maxHeight = Size::INFINITE_SIZE;
341     }
342     if (LessNotEqual(maxWidth, minWidth)) {
343         maxWidth = minWidth;
344     }
345     if (LessNotEqual(maxHeight, minHeight)) {
346         maxHeight = minHeight;
347     }
348     if (GreatNotEqual(minWidth, 0.0) || GreatNotEqual(minHeight, 0.0)) {
349         deliverMinToChild_ = true;
350     }
351     Size minSize = Size(minWidth, minHeight);
352     Size maxSize = Size(maxWidth, maxHeight);
353     constraints_ = LayoutParam(maxSize, minSize);
354 }
355 
CalculateGridLayoutSize()356 void RenderBoxBase::CalculateGridLayoutSize()
357 {
358     if (!gridColumnInfo_) {
359         return;
360     }
361 
362     auto offset = gridColumnInfo_->GetOffset();
363     if (offset != UNDEFINED_DIMENSION) {
364         if (IsHeadRenderNode()) {
365             auto context = context_.Upgrade();
366             positionParam_.type =
367                 (context && context->GetIsDeclarative()) ? PositionType::PTSEMI_RELATIVE : PositionType::PTABSOLUTE;
368             std::pair<AnimatableDimension, bool>& edge =
369                 (GetTextDirection() == TextDirection::RTL) ? positionParam_.right : positionParam_.left;
370             edge.first = offset;
371             edge.second = true;
372         } else {
373             auto headRenderNode = GetHeadRenderNode();
374             if (headRenderNode) {
375                 auto context = headRenderNode->GetContext().Upgrade();
376                 headRenderNode->SetPositionType(
377                     (context && context->GetIsDeclarative()) ? PositionType::PTSEMI_RELATIVE :
378                         PositionType::PTABSOLUTE);
379                 headRenderNode->GetTextDirection() == TextDirection::RTL ? headRenderNode->SetRight(offset)
380                                                                          : headRenderNode->SetLeft(offset);
381             }
382         }
383         // the above two cases will only work on rosen, so using below to support on preview.
384 #ifndef ENABLE_ROSEN_BACKEND
385         auto context = context_.Upgrade();
386         positionParam_.type =
387             (context && context->GetIsDeclarative()) ? PositionType::PTSEMI_RELATIVE : PositionType::PTABSOLUTE;
388         std::pair<AnimatableDimension, bool>& edge =
389             (GetTextDirection() == TextDirection::RTL) ? positionParam_.right : positionParam_.left;
390         edge.first = offset;
391         edge.second = true;
392 #endif
393     }
394 
395     double defaultWidth = gridColumnInfo_->GetWidth();
396     if (NearEqual(defaultWidth, 0.0)) {
397         return;
398     }
399     double maxWidth = gridColumnInfo_->GetMaxWidth();
400     if (!NearEqual(defaultWidth, maxWidth)) {
401         constraints_.SetMinWidth(defaultWidth);
402         constraints_.SetMaxWidth(maxWidth);
403     } else {
404         width_ = AnimatableDimension(gridColumnInfo_->GetWidth(), DimensionUnit::PX);
405         LayoutParam gridLayoutParam = GetLayoutParam();
406         gridLayoutParam.SetMaxSize(Size(width_.Value(), gridLayoutParam.GetMaxSize().Height()));
407         gridLayoutParam.SetMinSize(Size(width_.Value(), gridLayoutParam.GetMinSize().Height()));
408         SetLayoutParam(gridLayoutParam);
409     }
410 }
411 
CalculateSelfLayoutParam()412 void RenderBoxBase::CalculateSelfLayoutParam()
413 {
414     // first. Calculate width and height with the parameter that user set in box component
415     ConvertConstraintsToPx();
416     CalculateWidth();
417     CalculateHeight();
418 
419     if (gridContainerInfo_ && gridContainerInfo_->GetColumnType() == GridColumnType::NONE) {
420         marginOrigin_ = Edge(gridContainerInfo_->GetMarginLeft(), marginOrigin_.Top(),
421             gridContainerInfo_->GetMarginRight(), marginOrigin_.Bottom());
422     }
423     ConvertMarginPaddingToPx();
424     if (GreatNotEqual(aspectRatio_.Value(), 0.0)) {
425         AdjustSizeByAspectRatio();
426     }
427 
428     Size selfMax = Size(selfMaxWidth_, selfMaxHeight_);
429     Size selfMin = Size(selfMinWidth_, selfMinHeight_);
430 
431     // second. constrain parameter with LayoutParam
432     const LayoutParam& layoutSetByParent = GetLayoutParam();
433     Size constrainMax = selfMax;
434     Size constrainMin = selfMin;
435 
436     if (minPlatformVersion_ != COMPATIBLE_VERSION || width_.Unit() != DimensionUnit::PERCENT) {
437         constrainMax.SetWidth(constrainMax.Width() + margin_.GetLayoutSize().Width());
438         constrainMin.SetWidth(constrainMin.Width() + margin_.GetLayoutSize().Width());
439     }
440     if (minPlatformVersion_ != COMPATIBLE_VERSION || height_.Unit() != DimensionUnit::PERCENT) {
441         constrainMax.SetHeight(constrainMax.Height() + margin_.GetLayoutSize().Height());
442         constrainMin.SetHeight(constrainMin.Height() + margin_.GetLayoutSize().Height());
443     }
444 
445     selfMax = layoutSetByParent.Constrain(constrainMax);
446     selfMin = layoutSetByParent.Constrain(constrainMin);
447     auto context = context_.Upgrade();
448     // allow overflow parent when set height or width, except when set flexgrow or flexshrink
449     if (context->GetIsDeclarative()) {
450         if (selfDefineWidth_ && layoutSetByParent.GetMinSize().Width() != layoutSetByParent.GetMaxSize().Width()) {
451             selfMax.SetWidth(constrainMax.Width());
452         }
453         if (selfDefineHeight_ && layoutSetByParent.GetMinSize().Height() != layoutSetByParent.GetMaxSize().Height()) {
454             selfMax.SetHeight(constrainMax.Height());
455         }
456     }
457 
458     selfLayoutParam_.SetMaxSize(selfMax);
459     selfLayoutParam_.SetMinSize(selfMin);
460 
461     if (gridContainerInfo_) {
462         double width = selfMax.Width();
463         gridContainerInfo_->BuildColumnWidth(width);
464     }
465 
466     ConvertPaddingForLayoutInBox();
467 }
468 
AdjustSizeByAspectRatio()469 void RenderBoxBase::AdjustSizeByAspectRatio()
470 {
471     const LayoutParam& layoutSetByParent = GetLayoutParam();
472     LayoutParam selfLayout = layoutSetByParent;
473     if (!layoutSetByParent.HasUsedConstraints() && constraints_.IsWidthValid() && constraints_.IsHeightValid()) {
474         selfLayout = layoutSetByParent.Enforce(constraints_);
475     }
476     auto maxWidth = selfLayout.GetMaxSize().Width();
477     auto minWidth = selfLayout.GetMinSize().Width();
478     auto maxHeight = selfLayout.GetMaxSize().Height();
479     auto minHeight = selfLayout.GetMinSize().Height();
480     // Adjust by aspect ratio, firstly pick height based on width. It means that when width, height and aspectRatio are
481     // all set, the height is not used.
482     if (selfDefineWidth_) {
483         selfMaxHeight_ = selfMaxWidth_ / aspectRatio_.Value();
484     } else if (selfDefineHeight_) {
485         selfMaxWidth_ = selfMaxHeight_ * aspectRatio_.Value();
486     } else if (NearEqual(selfMaxWidth_, Size::INFINITE_SIZE)) {
487         selfMaxWidth_ = selfMaxHeight_ * aspectRatio_.Value();
488     } else {
489         selfMaxHeight_ = selfMaxWidth_ / aspectRatio_.Value();
490     }
491     if (selfMaxWidth_ > maxWidth) {
492         selfMaxWidth_ = maxWidth;
493         selfMaxHeight_ = selfMaxWidth_ / aspectRatio_.Value();
494     }
495     if (selfMaxHeight_ > maxHeight) {
496         selfMaxHeight_ = maxHeight;
497         selfMaxWidth_ = selfMaxHeight_ * aspectRatio_.Value();
498     }
499     if (selfMaxWidth_ < minWidth) {
500         selfMaxWidth_ = minWidth;
501         selfMaxHeight_ = selfMaxWidth_ / aspectRatio_.Value();
502     }
503     if (selfMaxHeight_ < minHeight) {
504         selfMaxHeight_ = minHeight;
505         selfMaxWidth_ = selfMaxHeight_ * aspectRatio_.Value();
506     }
507     if (!NearEqual(selfMaxWidth_, Size::INFINITE_SIZE) && !NearEqual(selfMaxHeight_, Size::INFINITE_SIZE)) {
508         selfDefineWidth_ = true;
509         selfDefineHeight_ = true;
510     }
511 }
512 
SetChildLayoutParam()513 void RenderBoxBase::SetChildLayoutParam()
514 {
515     Size deflate;
516     if (boxSizing_ == BoxSizing::BORDER_BOX) {
517         deflate += padding_.GetLayoutSize();
518         deflate += GetBorderSize();
519     }
520     deflate += margin_.GetLayoutSize();
521 
522     if (deliverMinToChild_) {
523         double minWidth = std::max(selfLayoutParam_.GetMinSize().Width() - deflate.Width(), 0.0);
524         double minHeight = std::max(selfLayoutParam_.GetMinSize().Height() - deflate.Height(), 0.0);
525         childLayoutParam_.SetMinSize(Size(minWidth, minHeight));
526     } else {
527         childLayoutParam_.SetMinSize(Size(0.0, 0.0));
528     }
529 
530     double maxWidth = std::max(selfLayoutParam_.GetMaxSize().Width() - deflate.Width(), 0.0);
531     double maxHeight = std::max(selfLayoutParam_.GetMaxSize().Height() - deflate.Height(), 0.0);
532     childLayoutParam_.SetMaxSize(Size(maxWidth, maxHeight));
533 
534     // First time layout all children
535     for (const auto& item : GetChildren()) {
536         item->Layout(childLayoutParam_);
537     }
538 }
539 
ConvertPaddingForLayoutInBox()540 void RenderBoxBase::ConvertPaddingForLayoutInBox()
541 {
542     if (!layoutInBox_) {
543         return;
544     }
545 
546     Size layoutParmMax = selfLayoutParam_.GetMaxSize();
547     Size borderSize = GetBorderSize();
548     double diameter = std::min(layoutParmMax.Width() - margin_.GetLayoutSize().Width() - borderSize.Width(),
549         layoutParmMax.Height() - margin_.GetLayoutSize().Height() - borderSize.Height());
550 
551     double circlePadding = diameter * (1.0 - CIRCLE_LAYOUT_IN_BOX_SCALE) / BOX_DIAMETER_TO_RADIUS;
552 
553     padding_.SetLeft(Dimension(std::max(padding_.LeftPx(), circlePadding)));
554     padding_.SetTop(Dimension(std::max(padding_.TopPx(), circlePadding)));
555     padding_.SetRight(Dimension(std::max(padding_.RightPx(), circlePadding)));
556     padding_.SetBottom(Dimension(std::max(padding_.BottomPx(), circlePadding)));
557 }
558 
CalculateSelfLayoutSize()559 void RenderBoxBase::CalculateSelfLayoutSize()
560 {
561     Size borderSize = GetBorderSize();
562 
563     const LayoutParam& layoutSetByParent = GetLayoutParam();
564     Size selfMax = selfLayoutParam_.GetMaxSize() - margin_.GetLayoutSize();
565     if (!GetChildren().empty()) {
566         childSize_ = GetChildren().front()->GetLayoutSize();
567         childWidth_ = childSize_.Width();
568         childHeight_ = childSize_.Height();
569     }
570     // calculate width
571     double width = 0.0;
572     double childWidth = childSize_.Width() + padding_.GetLayoutSize().Width() + borderSize.Width();
573     if (selfDefineWidth_) {
574         if (boxSizing_ == BoxSizing::BORDER_BOX) {
575             width = selfMax.Width();
576         } else {
577             width = selfMax.Width() + padding_.GetLayoutSize().Width() + borderSize.Width();
578         }
579     } else if (useFlexWidth_) {
580         if (layoutSetByParent.GetMaxSize().IsWidthInfinite() && viewPort_.Width() < childWidth) {
581             width = childWidth;
582         } else {
583             double flexWidth = layoutSetByParent.GetMaxSize().IsWidthInfinite() && !viewPort_.IsWidthInfinite()
584                                    ? viewPort_.Width()
585                                    : layoutSetByParent.GetMaxSize().Width();
586             width = flexWidth - margin_.GetLayoutSize().Width();
587         }
588     } else {
589         width = childWidth;
590         if (gridColumnInfo_) {
591             auto columnWidth = gridColumnInfo_->GetWidth();
592             if (NearEqual(columnWidth, gridColumnInfo_->GetMaxWidth()) && !NearEqual(columnWidth, 0.0)) {
593                 width = columnWidth;
594             }
595         }
596     }
597     // calculate height
598     double height = 0.0;
599     double childHeight = childSize_.Height() + padding_.GetLayoutSize().Height() + borderSize.Height();
600     if (selfDefineHeight_) {
601         if (boxSizing_ == BoxSizing::BORDER_BOX) {
602             height = selfMax.Height();
603         } else {
604             height = selfMax.Height() + padding_.GetLayoutSize().Height() + borderSize.Height();
605         }
606     } else if (useFlexHeight_) {
607         if (layoutSetByParent.GetMaxSize().IsHeightInfinite() && viewPort_.Height() < childHeight) {
608             height = childHeight;
609         } else {
610             double flexHeight = layoutSetByParent.GetMaxSize().IsHeightInfinite() && !viewPort_.IsHeightInfinite()
611                                     ? viewPort_.Height()
612                                     : layoutSetByParent.GetMaxSize().Height();
613             height = flexHeight - margin_.GetLayoutSize().Height();
614         }
615     } else {
616         height = childSize_.Height() + padding_.GetLayoutSize().Height() + borderSize.Height();
617     }
618 
619     const static int32_t PLATFORM_VERSION_SIX = 6;
620     auto context = GetContext().Upgrade();
621     if (context && context->GetMinPlatformVersion() >= PLATFORM_VERSION_SIX) {
622         double minWidth = padding_.GetLayoutSize().Width() + borderSize.Width();
623         double minHeight = padding_.GetLayoutSize().Height() + borderSize.Height();
624         width = width > minWidth ? width : minWidth;
625         height = height > minHeight ? height : minHeight;
626     }
627     // allow force layoutsize for parent
628 
629     if (layoutSetByParent.GetMaxSize().Width() == layoutSetByParent.GetMinSize().Width()) {
630         width = layoutSetByParent.GetMinSize().Width() - margin_.GetLayoutSize().Width();
631     }
632     if (layoutSetByParent.GetMaxSize().Height() == layoutSetByParent.GetMinSize().Height()) {
633         height = layoutSetByParent.GetMinSize().Height() - margin_.GetLayoutSize().Height();
634     }
635     paintSize_ = Size(width, height);
636     if (context && context->GetIsDeclarative()) {
637         // box layout size = paint size + margin size
638         if (LessNotEqual(margin_.LeftPx(), 0.0)) {
639             positionParam_.left = std::make_pair(margin_.Left(), true);
640             margin_.SetLeft(Dimension(0.0, margin_.Left().Unit()));
641         }
642         if (LessNotEqual(margin_.TopPx(), 0.0)) {
643             positionParam_.top = std::make_pair(margin_.Top(), true);
644             margin_.SetTop(Dimension(0.0, margin_.Top().Unit()));
645         }
646         selfLayoutSize_ = paintSize_ + margin_.GetLayoutSize();
647     } else {
648         selfLayoutSize_ = GetLayoutParam().Constrain(paintSize_ + margin_.GetLayoutSize());
649     }
650 
651     paintSize_ = selfLayoutSize_ - margin_.GetLayoutSize();
652     touchArea_.SetOffset(margin_.GetOffset());
653     touchArea_.SetSize(paintSize_);
654     SetLayoutSize(selfLayoutSize_);
655     isChildOverflow_ = childSize_.Width() > GetLayoutSize().Width() || childSize_.Height() > GetLayoutSize().Height();
656 }
657 
CalculateChildPosition()658 void RenderBoxBase::CalculateChildPosition()
659 {
660     Offset borderOffset = GetBorderOffset();
661     Size parentSize = selfLayoutSize_ - margin_.GetLayoutSize() - padding_.GetLayoutSize();
662     parentSize -= GetBorderSize();
663 
664     if (!GetChildren().empty()) {
665         const auto& child = GetChildren().front();
666         childPosition_ = margin_.GetOffset() + borderOffset + padding_.GetOffset() +
667                          Alignment::GetAlignPosition(parentSize, child->GetLayoutSize(), align_);
668         child->SetPosition(childPosition_);
669     }
670 }
671 
PerformLayout()672 void RenderBoxBase::PerformLayout()
673 {
674     // update scale for margin, padding
675     auto context = context_.Upgrade();
676     if (!context) {
677         LOGE("[BOX][Dep:%{public}d][LAYOUT]Call Context Upgrade failed. PerformLayout failed.", this->GetDepth());
678         return;
679     }
680     if (isUseAlign_) {
681         context->AddAlignDeclarationNode(AceType::Claim(this));
682     }
683 
684     CalculateGridLayoutSize();
685     // first. calculate self layout param
686     CalculateSelfLayoutParam();
687     // second. set layout param of child to calculate layout size
688     SetChildLayoutParam();
689     // third. using layout size of child, calculate layout size of box
690     CalculateSelfLayoutSize();
691 
692     if (needReCalc_) {
693         needReCalc_ = false;
694         CalculateSelfLayoutParam();
695         SetChildLayoutParam();
696         CalculateSelfLayoutSize();
697     }
698     // forth. calculate position of child
699     CalculateChildPosition();
700 
701     if (isUseAlign_) {
702         CalculateAlignDeclaration();
703     }
704 
705     if (layoutCallback_) {
706         layoutCallback_();
707     }
708 }
709 
Update(const RefPtr<Component> & component)710 void RenderBoxBase::Update(const RefPtr<Component>& component)
711 {
712     const RefPtr<BoxBaseComponent> box = AceType::DynamicCast<BoxBaseComponent>(component);
713     if (box) {
714         scrollPage_ = box->GetScrollPage();
715 
716         displayType_ = box->GetDisplayType();
717         paddingOrigin_ = box->GetPadding();
718         marginOrigin_ = box->GetMargin();
719         additionalPadding_ = box->GetAdditionalPadding();
720         flex_ = box->GetFlex();
721         boxSizing_ = box->GetBoxSizing();
722         constraints_ = box->GetConstraints();
723         align_ = box->GetAlignment();
724         overflow_ = box->GetOverflow();
725         clipPath_ = box->GetClipPath();
726         deliverMinToChild_ = box->GetDeliverMinToChild();
727         width_ = box->GetWidthDimension();
728         height_ = box->GetHeightDimension();
729         auto context = context_.Upgrade();
730         if (context && scrollPage_) {
731             height_ = AnimatableDimension(context->GetStageRect().Height(), DimensionUnit::PX);
732         }
733         percentFlag_ = box->GetPercentFlag();
734         layoutInBox_ = box->GetLayoutInBoxFlag();
735         aspectRatio_ = box->GetAspectRatio();
736         minWidth_ = box->GetMinWidth();
737         minHeight_ = box->GetMinHeight();
738         maxWidth_ = box->GetMaxWidth();
739         maxHeight_ = box->GetMaxHeight();
740         if (aspectRatio_.IsValid()) {
741             if (GreatNotEqual(minWidth_.Value(), 0.0) && NearZero(minHeight_.Value())) {
742                 minHeight_ = minWidth_ / aspectRatio_.Value();
743             }
744             if (GreatNotEqual(minHeight_.Value(), 0.0) && NearZero(minWidth_.Value())) {
745                 minWidth_ = minHeight_ * aspectRatio_.Value();
746             }
747         }
748         useLiteStyle_ = box->UseLiteStyle();
749         mask_ = box->GetMask();
750         auto gridLayoutInfo = box->GetGridLayoutInfo();
751         auto gridColumnInfo = AceType::DynamicCast<GridColumnInfo>(gridLayoutInfo);
752         if (gridColumnInfo) {
753             gridColumnInfo_ = gridColumnInfo;
754         } else {
755             auto gridContainerInfo = AceType::DynamicCast<GridContainerInfo>(gridLayoutInfo);
756             if (gridContainerInfo) {
757                 gridContainerInfo_ = gridContainerInfo;
758             }
759         }
760         isUseAlign_ = box->IsUseAlign();
761         if (isUseAlign_) {
762             alignPtr_ = box->GetAlignDeclarationPtr();
763             alignSide_ = box->GetUseAlignSide();
764             alignItemOffset_ = box->GetUseAlignOffset();
765         }
766         boxClipFlag_ = box->GetBoxClipFlag();
767         pixelMap_ = box->GetPixelMap();
768 
769         MarkNeedLayout();
770     }
771 }
772 
GetPaintPosition() const773 Offset RenderBoxBase::GetPaintPosition() const
774 {
775     return margin_.GetOffset();
776 }
777 
GetPaintSize() const778 const Size& RenderBoxBase::GetPaintSize() const
779 {
780     return paintSize_;
781 }
782 
SetPaintSize(const Size & paintSize)783 void RenderBoxBase::SetPaintSize(const Size& paintSize)
784 {
785     paintSize_ = paintSize;
786 }
787 
Dump()788 void RenderBoxBase::Dump()
789 {
790     double dipScale = 1.0;
791     auto context = context_.Upgrade();
792     if (context) {
793         dipScale = context->GetDipScale();
794     }
795     Size borderSize = GetBorderSize();
796     Radius radius = GetBorderRadius();
797     DumpLog::GetInstance().AddDesc(std::string("WH: ")
798                                        .append(Size(width_.Value(), height_.Value()).ToString())
799                                        .append(", Margin: ")
800                                        .append(margin_.GetLayoutSizeInPx(dipScale).ToString())
801                                        .append(", Padding: ")
802                                        .append(padding_.GetLayoutSizeInPx(dipScale).ToString())
803                                        .append(", Border: ")
804                                        .append(borderSize.ToString())
805                                        .append(", Radius: ")
806                                        .append(radius.GetX().ToString())
807                                        .append(", Constraints: ")
808                                        .append(constraints_.ToString())
809                                        .append(", BGcolor: ")
810                                        .append(std::to_string(GetColor().GetValue())));
811     DumpLog::GetInstance().AddDesc(std::string("SelfSize: ")
812                                        .append(selfLayoutSize_.ToString())
813                                        .append(", ChildSize: ")
814                                        .append(childSize_.ToString())
815                                        .append(", ChildPos: ")
816                                        .append(childPosition_.ToString()));
817     if (gridColumnInfo_) {
818         DumpLog::GetInstance().AddDesc(std::string("GridColumnInfo"));
819     }
820     if (gridContainerInfo_) {
821         DumpLog::GetInstance().AddDesc(std::string("GridContainerInfo"));
822     }
823 }
824 
ClearRenderObject()825 void RenderBoxBase::ClearRenderObject()
826 {
827     RenderNode::ClearRenderObject();
828     width_ = Dimension(-1.0);
829     height_ = Dimension(-1.0);
830     flex_ = BoxFlex::FLEX_NO;
831 
832     constraints_ = LayoutParam(Size(), Size());
833     padding_ = EdgePx();
834     margin_ = EdgePx();
835     align_ = Alignment();
836     paintSize_ = Size();
837     touchArea_ = Rect();
838 
839     deliverMinToChild_ = true;
840     scrollPage_ = false;
841     percentFlag_ = 0;
842     layoutInBox_ = false;
843 
844     displayType_ = DisplayType::NO_SETTING;
845     paddingOrigin_ = Edge();
846     marginOrigin_ = Edge();
847     additionalPadding_ = Edge();
848 
849     useFlexWidth_ = false;
850     useFlexHeight_ = false;
851     selfDefineWidth_ = false;
852     selfDefineHeight_ = false;
853     selfMaxWidth_ = Size::INFINITE_SIZE;
854     selfMinWidth_ = 0.0;
855     selfMaxHeight_ = Size::INFINITE_SIZE;
856     selfMinHeight_ = 0.0;
857 
858     aspectRatio_ = AnimatableDimension();
859     minWidth_ = Dimension();
860     minHeight_ = Dimension();
861     maxWidth_ = Dimension();
862     maxHeight_ = Dimension();
863 
864     selfLayoutParam_ = LayoutParam();
865     selfLayoutSize_ = Size();
866     childLayoutParam_ = LayoutParam();
867     childSize_ = Size();
868     childPosition_ = Offset();
869 
870     layoutCallback_ = nullptr;
871     gridColumnInfo_ = nullptr;
872     gridContainerInfo_ = nullptr;
873 
874     isUseAlign_ = false;
875     alignPtr_ = nullptr;
876     alignSide_ = AlignDeclaration::Edge::AUTO;
877     alignItemOffset_ = Dimension();
878     alignOffset_.Reset();
879 }
880 
GetFloatPropertySetterMap()881 FloatPropertyAnimatable::SetterMap RenderBoxBase::GetFloatPropertySetterMap()
882 {
883     FloatPropertyAnimatable::SetterMap map;
884     auto weak = AceType::WeakClaim(this);
885     map[PropertyAnimatableType::PROPERTY_WIDTH] = [weak](float value) {
886         auto box = weak.Upgrade();
887         if (!box) {
888             LOGE("Set width failed. box is null.");
889             return;
890         }
891         box->SetWidth(value);
892     };
893     const RefPtr<RenderTextField> renderTextField = AceType::DynamicCast<RenderTextField>(GetFirstChild());
894     if (renderTextField) {
895         WeakPtr<RenderTextField> textWeak = renderTextField;
896         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [textWeak](float value) {
897             auto renderTextField = textWeak.Upgrade();
898             if (!renderTextField) {
899                 LOGE("Set height failed. text is null.");
900                 return;
901             }
902             return renderTextField->SetHeight(value);
903         };
904     } else {
905         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [weak](float value) {
906             auto box = weak.Upgrade();
907             if (!box) {
908                 LOGE("Set height failed. box is null.");
909                 return;
910             }
911             box->SetHeight(value);
912         };
913     }
914     return map;
915 };
916 
GetFloatPropertyGetterMap()917 FloatPropertyAnimatable::GetterMap RenderBoxBase::GetFloatPropertyGetterMap()
918 {
919     FloatPropertyAnimatable::GetterMap map;
920     auto weak = AceType::WeakClaim(this);
921     map[PropertyAnimatableType::PROPERTY_WIDTH] = [weak]() -> float {
922         auto box = weak.Upgrade();
923         if (!box) {
924             LOGE("Get width failed. box is null.");
925             return 0.0;
926         }
927         return box->GetWidth();
928     };
929     const RefPtr<RenderTextField> renderTextField = AceType::DynamicCast<RenderTextField>(GetFirstChild());
930     if (renderTextField) {
931         WeakPtr<RenderTextField> textWeak = renderTextField;
932         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [textWeak]() -> float {
933             auto renderTextField = textWeak.Upgrade();
934             if (!renderTextField) {
935                 LOGE("Get height failed. text is null.");
936                 return 0.0;
937             }
938             return renderTextField->GetHeight();
939         };
940     } else {
941         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [weak]() -> float {
942             auto box = weak.Upgrade();
943             if (!box) {
944                 LOGE("Get height failed. box is null.");
945                 return 0.0;
946             }
947             return box->GetHeight();
948         };
949     }
950     return map;
951 }
952 
CalculateAlignDeclaration()953 void RenderBoxBase::CalculateAlignDeclaration()
954 {
955     alignOffset_.Reset();
956     if (!GetAlignDeclarationOffset(alignPtr_, alignOffset_)) {
957         alignOffset_.Reset();
958         return;
959     }
960 
961     double itemAlignOffset = 0.0;
962     auto context = GetContext().Upgrade();
963     if (context) {
964         itemAlignOffset = context->NormalizeToPx(alignItemOffset_);
965     }
966 
967     switch (alignSide_) {
968         case AlignDeclaration::Edge::TOP:
969             alignOffset_ = alignOffset_ + Offset(0, itemAlignOffset);
970             break;
971         case AlignDeclaration::Edge::CENTER:
972             alignOffset_ = alignOffset_ - Offset(0, GetLayoutSize().Height() / 2 - itemAlignOffset);
973             break;
974         case AlignDeclaration::Edge::BOTTOM:
975             alignOffset_ = alignOffset_ - Offset(0, GetLayoutSize().Height() - itemAlignOffset);
976             break;
977         case AlignDeclaration::Edge::BASELINE:
978             alignOffset_ = alignOffset_ - Offset(0, GetBaselineDistance(TextBaseline::ALPHABETIC) - itemAlignOffset);
979             break;
980         case AlignDeclaration::Edge::START:
981             alignOffset_ = alignOffset_ + Offset(itemAlignOffset, 0);
982             break;
983         case AlignDeclaration::Edge::MIDDLE:
984             alignOffset_ = alignOffset_ - Offset(GetLayoutSize().Width() / 2 - itemAlignOffset, 0);
985             break;
986         case AlignDeclaration::Edge::END:
987             alignOffset_ = alignOffset_ - Offset(GetLayoutSize().Width() - itemAlignOffset, 0);
988             break;
989         default:
990             alignOffset_.Reset();
991             break;
992     }
993 }
994 
995 } // namespace OHOS::Ace
996