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