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