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