• 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 
IsDeclarativePara()540 bool RenderBoxBase::IsDeclarativePara()
541 {
542     auto context = context_.Upgrade();
543     if (!context) {
544         return false;
545     }
546 
547     return context->GetIsDeclarative();
548 }
549 
ConvertPaddingForLayoutInBox()550 void RenderBoxBase::ConvertPaddingForLayoutInBox()
551 {
552     if (!layoutInBox_) {
553         return;
554     }
555 
556     Size layoutParmMax = selfLayoutParam_.GetMaxSize();
557     Size borderSize = GetBorderSize();
558     double diameter = std::min(layoutParmMax.Width() - margin_.GetLayoutSize().Width() - borderSize.Width(),
559         layoutParmMax.Height() - margin_.GetLayoutSize().Height() - borderSize.Height());
560 
561     double circlePadding = diameter * (1.0 - CIRCLE_LAYOUT_IN_BOX_SCALE) / BOX_DIAMETER_TO_RADIUS;
562 
563     padding_.SetLeft(Dimension(std::max(padding_.LeftPx(), circlePadding)));
564     padding_.SetTop(Dimension(std::max(padding_.TopPx(), circlePadding)));
565     padding_.SetRight(Dimension(std::max(padding_.RightPx(), circlePadding)));
566     padding_.SetBottom(Dimension(std::max(padding_.BottomPx(), circlePadding)));
567 }
568 
CalculateSelfLayoutSize()569 void RenderBoxBase::CalculateSelfLayoutSize()
570 {
571     Size borderSize = GetBorderSize();
572 
573     const LayoutParam& layoutSetByParent = GetLayoutParam();
574     Size selfMax = selfLayoutParam_.GetMaxSize() - margin_.GetLayoutSize();
575     if (!GetChildren().empty()) {
576         childSize_ = GetChildren().front()->GetLayoutSize();
577         childWidth_ = childSize_.Width();
578         childHeight_ = childSize_.Height();
579     }
580     // calculate width
581     double width = 0.0;
582     double childWidth = childSize_.Width() + padding_.GetLayoutSize().Width() + borderSize.Width();
583     if (selfDefineWidth_) {
584         if (boxSizing_ == BoxSizing::BORDER_BOX) {
585             width = selfMax.Width();
586         } else {
587             width = selfMax.Width() + padding_.GetLayoutSize().Width() + borderSize.Width();
588         }
589     } else if (useFlexWidth_) {
590         if (layoutSetByParent.GetMaxSize().IsWidthInfinite() && viewPort_.Width() < childWidth) {
591             width = childWidth;
592         } else {
593             double flexWidth = layoutSetByParent.GetMaxSize().IsWidthInfinite() && !viewPort_.IsWidthInfinite()
594                                    ? viewPort_.Width()
595                                    : layoutSetByParent.GetMaxSize().Width();
596             width = flexWidth - margin_.GetLayoutSize().Width();
597         }
598     } else {
599         width = childWidth;
600         if (gridColumnInfo_) {
601             auto columnWidth = gridColumnInfo_->GetWidth();
602             if (NearEqual(columnWidth, gridColumnInfo_->GetMaxWidth()) && !NearEqual(columnWidth, 0.0)) {
603                 width = columnWidth;
604             }
605         }
606     }
607     // calculate height
608     double height = 0.0;
609     double childHeight = childSize_.Height() + padding_.GetLayoutSize().Height() + borderSize.Height();
610     if (selfDefineHeight_) {
611         if (boxSizing_ == BoxSizing::BORDER_BOX) {
612             height = selfMax.Height();
613         } else {
614             height = selfMax.Height() + padding_.GetLayoutSize().Height() + borderSize.Height();
615         }
616     } else if (useFlexHeight_) {
617         if (layoutSetByParent.GetMaxSize().IsHeightInfinite() && viewPort_.Height() < childHeight) {
618             height = childHeight;
619         } else {
620             double flexHeight = layoutSetByParent.GetMaxSize().IsHeightInfinite() && !viewPort_.IsHeightInfinite()
621                                     ? viewPort_.Height()
622                                     : layoutSetByParent.GetMaxSize().Height();
623             height = flexHeight - margin_.GetLayoutSize().Height();
624         }
625     } else {
626         height = childSize_.Height() + padding_.GetLayoutSize().Height() + borderSize.Height();
627         if (IsDeclarativePara()) {
628             if (height < selfMinHeight_) {
629                 height = selfMinHeight_;
630             }
631         }
632     }
633 
634     const static int32_t PLATFORM_VERSION_SIX = 6;
635     auto context = GetContext().Upgrade();
636     if (context && context->GetMinPlatformVersion() >= PLATFORM_VERSION_SIX) {
637         double minWidth = padding_.GetLayoutSize().Width() + borderSize.Width();
638         double minHeight = padding_.GetLayoutSize().Height() + borderSize.Height();
639         width = width > minWidth ? width : minWidth;
640         height = height > minHeight ? height : minHeight;
641     }
642     // allow force layoutsize for parent
643 
644     if (layoutSetByParent.GetMaxSize().Width() == layoutSetByParent.GetMinSize().Width()) {
645         width = layoutSetByParent.GetMinSize().Width() - margin_.GetLayoutSize().Width();
646     }
647     if (layoutSetByParent.GetMaxSize().Height() == layoutSetByParent.GetMinSize().Height()) {
648         height = layoutSetByParent.GetMinSize().Height() - margin_.GetLayoutSize().Height();
649     }
650     paintSize_ = Size(width, height);
651     if (context && context->GetIsDeclarative()) {
652         // box layout size = paint size + margin size
653         if (LessNotEqual(margin_.LeftPx(), 0.0)) {
654             positionParam_.left = std::make_pair(margin_.Left(), true);
655             margin_.SetLeft(Dimension(0.0, margin_.Left().Unit()));
656         }
657         if (LessNotEqual(margin_.TopPx(), 0.0)) {
658             positionParam_.top = std::make_pair(margin_.Top(), true);
659             margin_.SetTop(Dimension(0.0, margin_.Top().Unit()));
660         }
661         selfLayoutSize_ = paintSize_ + margin_.GetLayoutSize();
662     } else {
663         selfLayoutSize_ = GetLayoutParam().Constrain(paintSize_ + margin_.GetLayoutSize());
664     }
665 
666     paintSize_ = selfLayoutSize_ - margin_.GetLayoutSize();
667     touchArea_.SetOffset(margin_.GetOffset());
668     touchArea_.SetSize(paintSize_);
669     SetLayoutSize(selfLayoutSize_);
670     isChildOverflow_ = childSize_.Width() > GetLayoutSize().Width() || childSize_.Height() > GetLayoutSize().Height();
671 }
672 
CalculateChildPosition()673 void RenderBoxBase::CalculateChildPosition()
674 {
675     Offset borderOffset = GetBorderOffset();
676     Size parentSize = selfLayoutSize_ - margin_.GetLayoutSize() - padding_.GetLayoutSize();
677     parentSize -= GetBorderSize();
678 
679     if (!GetChildren().empty()) {
680         const auto& child = GetChildren().front();
681         childPosition_ = margin_.GetOffset() + borderOffset + padding_.GetOffset() +
682                          Alignment::GetAlignPosition(parentSize, child->GetLayoutSize(), align_);
683         child->SetPosition(childPosition_);
684     }
685 }
686 
PerformLayout()687 void RenderBoxBase::PerformLayout()
688 {
689     // update scale for margin, padding
690     auto context = context_.Upgrade();
691     if (!context) {
692         LOGE("[BOX][Dep:%{public}d][LAYOUT]Call Context Upgrade failed. PerformLayout failed.", this->GetDepth());
693         return;
694     }
695     if (isUseAlign_) {
696         context->AddAlignDeclarationNode(AceType::Claim(this));
697     }
698 
699     CalculateGridLayoutSize();
700     // first. calculate self layout param
701     CalculateSelfLayoutParam();
702     // second. set layout param of child to calculate layout size
703     SetChildLayoutParam();
704     // third. using layout size of child, calculate layout size of box
705     CalculateSelfLayoutSize();
706 
707     if (needReCalc_) {
708         needReCalc_ = false;
709         CalculateSelfLayoutParam();
710         SetChildLayoutParam();
711         CalculateSelfLayoutSize();
712     }
713     // forth. calculate position of child
714     CalculateChildPosition();
715 
716     if (isUseAlign_) {
717         CalculateAlignDeclaration();
718     }
719 
720     if (layoutCallback_) {
721         layoutCallback_();
722     }
723 }
724 
Update(const RefPtr<Component> & component)725 void RenderBoxBase::Update(const RefPtr<Component>& component)
726 {
727     const RefPtr<BoxBaseComponent> box = AceType::DynamicCast<BoxBaseComponent>(component);
728     if (box) {
729         scrollPage_ = box->GetScrollPage();
730 
731         displayType_ = box->GetDisplayType();
732         paddingOrigin_ = box->GetPadding();
733         marginOrigin_ = box->GetMargin();
734         additionalPadding_ = box->GetAdditionalPadding();
735         flex_ = box->GetFlex();
736         boxSizing_ = box->GetBoxSizing();
737         constraints_ = box->GetConstraints();
738         align_ = box->GetAlignment();
739         overflow_ = box->GetOverflow();
740         clipPath_ = box->GetClipPath();
741         deliverMinToChild_ = box->GetDeliverMinToChild();
742         width_ = box->GetWidthDimension();
743         height_ = box->GetHeightDimension();
744         auto context = context_.Upgrade();
745         if (context && scrollPage_) {
746             height_ = AnimatableDimension(context->GetStageRect().Height(), DimensionUnit::PX);
747         }
748         percentFlag_ = box->GetPercentFlag();
749         layoutInBox_ = box->GetLayoutInBoxFlag();
750         aspectRatio_ = box->GetAspectRatio();
751         minWidth_ = box->GetMinWidth();
752         minHeight_ = box->GetMinHeight();
753         maxWidth_ = box->GetMaxWidth();
754         maxHeight_ = box->GetMaxHeight();
755         if (aspectRatio_.IsValid()) {
756             if (GreatNotEqual(minWidth_.Value(), 0.0) && NearZero(minHeight_.Value())) {
757                 minHeight_ = minWidth_ / aspectRatio_.Value();
758             }
759             if (GreatNotEqual(minHeight_.Value(), 0.0) && NearZero(minWidth_.Value())) {
760                 minWidth_ = minHeight_ * aspectRatio_.Value();
761             }
762         }
763         useLiteStyle_ = box->UseLiteStyle();
764         mask_ = box->GetMask();
765         auto gridLayoutInfo = box->GetGridLayoutInfo();
766         auto gridColumnInfo = AceType::DynamicCast<GridColumnInfo>(gridLayoutInfo);
767         if (gridColumnInfo) {
768             gridColumnInfo_ = gridColumnInfo;
769         } else {
770             auto gridContainerInfo = AceType::DynamicCast<GridContainerInfo>(gridLayoutInfo);
771             if (gridContainerInfo) {
772                 gridContainerInfo_ = gridContainerInfo;
773             }
774         }
775         isUseAlign_ = box->IsUseAlign();
776         if (isUseAlign_) {
777             alignPtr_ = box->GetAlignDeclarationPtr();
778             alignSide_ = box->GetUseAlignSide();
779             alignItemOffset_ = box->GetUseAlignOffset();
780         }
781         boxClipFlag_ = box->GetBoxClipFlag();
782         pixelMap_ = box->GetPixelMap();
783 
784         MarkNeedLayout();
785     }
786 }
787 
GetPaintPosition() const788 Offset RenderBoxBase::GetPaintPosition() const
789 {
790     return margin_.GetOffset();
791 }
792 
GetPaintSize() const793 const Size& RenderBoxBase::GetPaintSize() const
794 {
795     return paintSize_;
796 }
797 
SetPaintSize(const Size & paintSize)798 void RenderBoxBase::SetPaintSize(const Size& paintSize)
799 {
800     paintSize_ = paintSize;
801 }
802 
Dump()803 void RenderBoxBase::Dump()
804 {
805     double dipScale = 1.0;
806     auto context = context_.Upgrade();
807     if (context) {
808         dipScale = context->GetDipScale();
809     }
810     Size borderSize = GetBorderSize();
811     Radius radius = GetBorderRadius();
812     DumpLog::GetInstance().AddDesc(std::string("WH: ")
813                                        .append(Size(width_.Value(), height_.Value()).ToString())
814                                        .append(", Margin: ")
815                                        .append(margin_.GetLayoutSizeInPx(dipScale).ToString())
816                                        .append(", Padding: ")
817                                        .append(padding_.GetLayoutSizeInPx(dipScale).ToString())
818                                        .append(", Border: ")
819                                        .append(borderSize.ToString())
820                                        .append(", Radius: ")
821                                        .append(radius.GetX().ToString())
822                                        .append(", Constraints: ")
823                                        .append(constraints_.ToString())
824                                        .append(", BGcolor: ")
825                                        .append(std::to_string(GetColor().GetValue())));
826     DumpLog::GetInstance().AddDesc(std::string("SelfSize: ")
827                                        .append(selfLayoutSize_.ToString())
828                                        .append(", ChildSize: ")
829                                        .append(childSize_.ToString())
830                                        .append(", ChildPos: ")
831                                        .append(childPosition_.ToString()));
832     if (gridColumnInfo_) {
833         DumpLog::GetInstance().AddDesc(std::string("GridColumnInfo"));
834     }
835     if (gridContainerInfo_) {
836         DumpLog::GetInstance().AddDesc(std::string("GridContainerInfo"));
837     }
838 }
839 
ClearRenderObject()840 void RenderBoxBase::ClearRenderObject()
841 {
842     RenderNode::ClearRenderObject();
843     width_ = Dimension(-1.0);
844     height_ = Dimension(-1.0);
845     flex_ = BoxFlex::FLEX_NO;
846 
847     constraints_ = LayoutParam(Size(), Size());
848     padding_ = EdgePx();
849     margin_ = EdgePx();
850     align_ = Alignment();
851     paintSize_ = Size();
852     touchArea_ = Rect();
853 
854     deliverMinToChild_ = true;
855     scrollPage_ = false;
856     percentFlag_ = 0;
857     layoutInBox_ = false;
858 
859     displayType_ = DisplayType::NO_SETTING;
860     paddingOrigin_ = Edge();
861     marginOrigin_ = Edge();
862     additionalPadding_ = Edge();
863 
864     useFlexWidth_ = false;
865     useFlexHeight_ = false;
866     selfDefineWidth_ = false;
867     selfDefineHeight_ = false;
868     selfMaxWidth_ = Size::INFINITE_SIZE;
869     selfMinWidth_ = 0.0;
870     selfMaxHeight_ = Size::INFINITE_SIZE;
871     selfMinHeight_ = 0.0;
872 
873     aspectRatio_ = AnimatableDimension();
874     minWidth_ = Dimension();
875     minHeight_ = Dimension();
876     maxWidth_ = Dimension();
877     maxHeight_ = Dimension();
878 
879     selfLayoutParam_ = LayoutParam();
880     selfLayoutSize_ = Size();
881     childLayoutParam_ = LayoutParam();
882     childSize_ = Size();
883     childPosition_ = Offset();
884 
885     layoutCallback_ = nullptr;
886     gridColumnInfo_ = nullptr;
887     gridContainerInfo_ = nullptr;
888 
889     isUseAlign_ = false;
890     alignPtr_ = nullptr;
891     alignSide_ = AlignDeclaration::Edge::AUTO;
892     alignItemOffset_ = Dimension();
893     alignOffset_.Reset();
894 }
895 
GetFloatPropertySetterMap()896 FloatPropertyAnimatable::SetterMap RenderBoxBase::GetFloatPropertySetterMap()
897 {
898     FloatPropertyAnimatable::SetterMap map;
899     auto weak = AceType::WeakClaim(this);
900     map[PropertyAnimatableType::PROPERTY_WIDTH] = [weak](float value) {
901         auto box = weak.Upgrade();
902         if (!box) {
903             LOGE("Set width failed. box is null.");
904             return;
905         }
906         box->SetWidth(value);
907     };
908     const RefPtr<RenderTextField> renderTextField = AceType::DynamicCast<RenderTextField>(GetFirstChild());
909     if (renderTextField) {
910         WeakPtr<RenderTextField> textWeak = renderTextField;
911         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [textWeak](float value) {
912             auto renderTextField = textWeak.Upgrade();
913             if (!renderTextField) {
914                 LOGE("Set height failed. text is null.");
915                 return;
916             }
917             return renderTextField->SetHeight(value);
918         };
919     } else {
920         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [weak](float value) {
921             auto box = weak.Upgrade();
922             if (!box) {
923                 LOGE("Set height failed. box is null.");
924                 return;
925             }
926             box->SetHeight(value);
927         };
928     }
929     return map;
930 };
931 
GetFloatPropertyGetterMap()932 FloatPropertyAnimatable::GetterMap RenderBoxBase::GetFloatPropertyGetterMap()
933 {
934     FloatPropertyAnimatable::GetterMap map;
935     auto weak = AceType::WeakClaim(this);
936     map[PropertyAnimatableType::PROPERTY_WIDTH] = [weak]() -> float {
937         auto box = weak.Upgrade();
938         if (!box) {
939             LOGE("Get width failed. box is null.");
940             return 0.0;
941         }
942         return box->GetWidth();
943     };
944     const RefPtr<RenderTextField> renderTextField = AceType::DynamicCast<RenderTextField>(GetFirstChild());
945     if (renderTextField) {
946         WeakPtr<RenderTextField> textWeak = renderTextField;
947         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [textWeak]() -> float {
948             auto renderTextField = textWeak.Upgrade();
949             if (!renderTextField) {
950                 LOGE("Get height failed. text is null.");
951                 return 0.0;
952             }
953             return renderTextField->GetHeight();
954         };
955     } else {
956         map[PropertyAnimatableType::PROPERTY_HEIGHT] = [weak]() -> float {
957             auto box = weak.Upgrade();
958             if (!box) {
959                 LOGE("Get height failed. box is null.");
960                 return 0.0;
961             }
962             return box->GetHeight();
963         };
964     }
965     return map;
966 }
967 
CalculateAlignDeclaration()968 void RenderBoxBase::CalculateAlignDeclaration()
969 {
970     alignOffset_.Reset();
971     if (!GetAlignDeclarationOffset(alignPtr_, alignOffset_)) {
972         alignOffset_.Reset();
973         return;
974     }
975 
976     double itemAlignOffset = 0.0;
977     auto context = GetContext().Upgrade();
978     if (context) {
979         itemAlignOffset = context->NormalizeToPx(alignItemOffset_);
980     }
981 
982     switch (alignSide_) {
983         case AlignDeclaration::Edge::TOP:
984             alignOffset_ = alignOffset_ + Offset(0, itemAlignOffset);
985             break;
986         case AlignDeclaration::Edge::CENTER:
987             alignOffset_ = alignOffset_ - Offset(0, GetLayoutSize().Height() / 2 - itemAlignOffset);
988             break;
989         case AlignDeclaration::Edge::BOTTOM:
990             alignOffset_ = alignOffset_ - Offset(0, GetLayoutSize().Height() - itemAlignOffset);
991             break;
992         case AlignDeclaration::Edge::BASELINE:
993             alignOffset_ = alignOffset_ - Offset(0, GetBaselineDistance(TextBaseline::ALPHABETIC) - itemAlignOffset);
994             break;
995         case AlignDeclaration::Edge::START:
996             alignOffset_ = alignOffset_ + Offset(itemAlignOffset, 0);
997             break;
998         case AlignDeclaration::Edge::MIDDLE:
999             alignOffset_ = alignOffset_ - Offset(GetLayoutSize().Width() / 2 - itemAlignOffset, 0);
1000             break;
1001         case AlignDeclaration::Edge::END:
1002             alignOffset_ = alignOffset_ - Offset(GetLayoutSize().Width() - itemAlignOffset, 0);
1003             break;
1004         default:
1005             alignOffset_.Reset();
1006             break;
1007     }
1008 }
1009 
1010 } // namespace OHOS::Ace
1011