1 /*
2 * Copyright (c) 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_ng/property/measure_utils.h"
17
18 #include <memory>
19 #include <optional>
20
21 #include "base/geometry/ng/size_t.h"
22 #include "base/geometry/size.h"
23 #include "base/log/log.h"
24 #include "base/utils/utils.h"
25 #include "core/components_ng/property/measure_property.h"
26 #include "core/pipeline/pipeline_base.h"
27
28 namespace OHOS::Ace::NG {
29 namespace {
30 const static int32_t PLATFORM_VERSION_TEN = 10;
31 }
32
ConvertToSize(const CalcSize & size,const ScaleProperty & scaleProperty,const SizeF & percentReference)33 SizeF ConvertToSize(const CalcSize& size, const ScaleProperty& scaleProperty, const SizeF& percentReference)
34 {
35 auto width = ConvertToPx(size.Width(), scaleProperty, percentReference.Width());
36 auto height = ConvertToPx(size.Height(), scaleProperty, percentReference.Height());
37 return { width.value_or(-1.0f), height.value_or(-1.0f) };
38 }
39
ConvertToOptionalSize(const CalcSize & size,const ScaleProperty & scaleProperty,const SizeF & percentReference)40 OptionalSizeF ConvertToOptionalSize(
41 const CalcSize& size, const ScaleProperty& scaleProperty, const SizeF& percentReference)
42 {
43 auto width = ConvertToPx(size.Width(), scaleProperty, percentReference.Width());
44 auto height = ConvertToPx(size.Height(), scaleProperty, percentReference.Height());
45 return { width, height };
46 }
47
ConvertToPx(const CalcLength & value,const ScaleProperty & scaleProperty,float percentReference)48 std::optional<float> ConvertToPx(const CalcLength& value, const ScaleProperty& scaleProperty, float percentReference)
49 {
50 double result = -1.0;
51 if (!value.NormalizeToPx(
52 scaleProperty.vpScale, scaleProperty.fpScale, scaleProperty.lpxScale, percentReference, result)) {
53 LOGE("fail to Convert CalcDimension To Px: %{public}f, %{public}f, %{public}f, %{public}f",
54 scaleProperty.vpScale, scaleProperty.fpScale, scaleProperty.lpxScale, percentReference);
55 return std::nullopt;
56 }
57 return static_cast<float>(result);
58 }
59
ConvertToPx(const std::optional<CalcLength> & value,const ScaleProperty & scaleProperty,float percentReference)60 std::optional<float> ConvertToPx(
61 const std::optional<CalcLength>& value, const ScaleProperty& scaleProperty, float percentReference)
62 {
63 if (!value) {
64 return std::nullopt;
65 }
66 double result = -1.0;
67 if (!value.value().NormalizeToPx(
68 scaleProperty.vpScale, scaleProperty.fpScale, scaleProperty.lpxScale, percentReference, result)) {
69 LOGE("optional: fail to Convert CalcDimension To Px: %{public}f, %{public}f, %{public}f, %{public}f",
70 scaleProperty.vpScale, scaleProperty.fpScale, scaleProperty.lpxScale, percentReference);
71 return std::nullopt;
72 }
73 return static_cast<float>(result);
74 }
75
ConvertToPx(const Dimension & dimension,const ScaleProperty & scaleProperty,float percentReference)76 std::optional<float> ConvertToPx(const Dimension& dimension, const ScaleProperty& scaleProperty, float percentReference)
77 {
78 double result = -1.0;
79 if (!dimension.NormalizeToPx(
80 scaleProperty.vpScale, scaleProperty.fpScale, scaleProperty.lpxScale, percentReference, result)) {
81 LOGE("fail to Convert dimension To Px: %{public}f, %{public}f, %{public}f, %{public}f", scaleProperty.vpScale,
82 scaleProperty.fpScale, scaleProperty.lpxScale, percentReference);
83 return std::nullopt;
84 }
85 return static_cast<float>(result);
86 }
87
ConvertToPx(const std::optional<Dimension> & dimension,const ScaleProperty & scaleProperty,float percentReference)88 std::optional<float> ConvertToPx(
89 const std::optional<Dimension>& dimension, const ScaleProperty& scaleProperty, float percentReference)
90 {
91 if (!dimension) {
92 return std::nullopt;
93 }
94 double result = -1.0;
95 if (!dimension.value().NormalizeToPx(
96 scaleProperty.vpScale, scaleProperty.fpScale, scaleProperty.lpxScale, percentReference, result)) {
97 LOGE("fail to Convert dimension To Px: %{public}f, %{public}f, %{public}f, %{public}f", scaleProperty.vpScale,
98 scaleProperty.fpScale, scaleProperty.lpxScale, percentReference);
99 return std::nullopt;
100 }
101 return static_cast<float>(result);
102 }
103
ConstrainSize(const SizeF & size,const SizeF & minSize,const SizeF & maxSize)104 SizeF ConstrainSize(const SizeF& size, const SizeF& minSize, const SizeF& maxSize)
105 {
106 float height = std::max(minSize.Height(), size.Height());
107 if (maxSize.Height() > 0) {
108 height = std::min(maxSize.Height(), height);
109 }
110 float width = std::max(minSize.Width(), size.Width());
111 if (maxSize.Width() > 0) {
112 width = std::min(maxSize.Width(), width);
113 }
114 return { width, height };
115 }
116
ConvertToPaddingPropertyF(const std::unique_ptr<PaddingProperty> & padding,const ScaleProperty & scaleProperty,float percentReference)117 PaddingPropertyF ConvertToPaddingPropertyF(
118 const std::unique_ptr<PaddingProperty>& padding, const ScaleProperty& scaleProperty, float percentReference)
119 {
120 if (!padding) {
121 return {};
122 }
123 return ConvertToPaddingPropertyF(*padding, scaleProperty, percentReference);
124 }
125
ConvertToPaddingPropertyF(const PaddingProperty & padding,const ScaleProperty & scaleProperty,float percentReference)126 PaddingPropertyF ConvertToPaddingPropertyF(
127 const PaddingProperty& padding, const ScaleProperty& scaleProperty, float percentReference)
128 {
129 auto left = ConvertToPx(padding.left, scaleProperty, percentReference);
130 auto right = ConvertToPx(padding.right, scaleProperty, percentReference);
131 auto top = ConvertToPx(padding.top, scaleProperty, percentReference);
132 auto bottom = ConvertToPx(padding.bottom, scaleProperty, percentReference);
133 return PaddingPropertyF { left, right, top, bottom };
134 }
135
ConvertToMarginPropertyF(const std::unique_ptr<MarginProperty> & margin,const ScaleProperty & scaleProperty,float percentReference)136 MarginPropertyF ConvertToMarginPropertyF(
137 const std::unique_ptr<MarginProperty>& margin, const ScaleProperty& scaleProperty, float percentReference)
138 {
139 return ConvertToPaddingPropertyF(margin, scaleProperty, percentReference);
140 }
141
ConvertToMarginPropertyF(const MarginProperty & margin,const ScaleProperty & scaleProperty,float percentReference)142 MarginPropertyF ConvertToMarginPropertyF(
143 const MarginProperty& margin, const ScaleProperty& scaleProperty, float percentReference)
144 {
145 return ConvertToPaddingPropertyF(margin, scaleProperty, percentReference);
146 }
147
ConvertToBorderWidthPropertyF(const std::unique_ptr<BorderWidthProperty> & borderWidth,const ScaleProperty & scaleProperty,float percentReference)148 BorderWidthPropertyF ConvertToBorderWidthPropertyF(
149 const std::unique_ptr<BorderWidthProperty>& borderWidth, const ScaleProperty& scaleProperty, float percentReference)
150 {
151 if (!borderWidth) {
152 return {};
153 }
154 return ConvertToBorderWidthPropertyF(*borderWidth, scaleProperty, percentReference);
155 }
156
ConvertToBorderWidthPropertyF(const BorderWidthProperty & borderWidth,const ScaleProperty & scaleProperty,float percentReference)157 BorderWidthPropertyF ConvertToBorderWidthPropertyF(
158 const BorderWidthProperty& borderWidth, const ScaleProperty& scaleProperty, float percentReference)
159 {
160 auto left = ConvertToPx(borderWidth.leftDimen, scaleProperty, percentReference);
161 auto right = ConvertToPx(borderWidth.rightDimen, scaleProperty, percentReference);
162 auto top = ConvertToPx(borderWidth.topDimen, scaleProperty, percentReference);
163 auto bottom = ConvertToPx(borderWidth.bottomDimen, scaleProperty, percentReference);
164 if (left.has_value()) {
165 left = floor(left.value());
166 }
167 if (right.has_value()) {
168 right = floor(right.value());
169 }
170 if (top.has_value()) {
171 top = floor(top.value());
172 }
173 if (bottom.has_value()) {
174 bottom = floor(bottom.value());
175 }
176 return BorderWidthPropertyF { left, top, right, bottom };
177 }
178
UpdatePaddingPropertyF(const PaddingProperty & padding,const ScaleProperty & scaleProperty,const SizeF & selfSize,PaddingPropertyF & paddingValue)179 void UpdatePaddingPropertyF(const PaddingProperty& padding, const ScaleProperty& scaleProperty, const SizeF& selfSize,
180 PaddingPropertyF& paddingValue)
181 {
182 auto left = ConvertToPx(padding.left, scaleProperty, selfSize.Width());
183 auto right = ConvertToPx(padding.right, scaleProperty, selfSize.Width());
184 auto top = ConvertToPx(padding.top, scaleProperty, selfSize.Height());
185 auto bottom = ConvertToPx(padding.bottom, scaleProperty, selfSize.Height());
186 if (left.has_value()) {
187 paddingValue.left = left;
188 }
189 if (right.has_value()) {
190 paddingValue.right = right;
191 }
192 if (top.has_value()) {
193 paddingValue.top = top;
194 }
195 if (bottom.has_value()) {
196 paddingValue.bottom = bottom;
197 }
198 }
199
AddPaddingToSize(const PaddingPropertyF & padding,SizeF & size)200 void AddPaddingToSize(const PaddingPropertyF& padding, SizeF& size)
201 {
202 size.AddPadding(padding.left, padding.right, padding.top, padding.bottom);
203 }
204
MinusPaddingToSize(const PaddingPropertyF & padding,SizeF & size)205 void MinusPaddingToSize(const PaddingPropertyF& padding, SizeF& size)
206 {
207 size.MinusPadding(padding.left, padding.right, padding.top, padding.bottom);
208 }
209
MinusPaddingToNonNegativeSize(const PaddingPropertyF & padding,SizeF & size)210 void MinusPaddingToNonNegativeSize(const PaddingPropertyF& padding, SizeF& size)
211 {
212 size.MinusPaddingToNonNegative(padding.left, padding.right, padding.top, padding.bottom);
213 }
214
AddPaddingToSize(const PaddingPropertyF & padding,OptionalSizeF & size)215 void AddPaddingToSize(const PaddingPropertyF& padding, OptionalSizeF& size)
216 {
217 size.AddPadding(padding.left, padding.right, padding.top, padding.bottom);
218 }
219
MinusPaddingToSize(const PaddingPropertyF & padding,OptionalSizeF & size)220 void MinusPaddingToSize(const PaddingPropertyF& padding, OptionalSizeF& size)
221 {
222 size.MinusPadding(padding.left, padding.right, padding.top, padding.bottom);
223 }
224
GetMainAxisOffset(const OffsetF & offset,Axis axis)225 float GetMainAxisOffset(const OffsetF& offset, Axis axis)
226 {
227 return axis == Axis::HORIZONTAL ? offset.GetX() : offset.GetY();
228 }
229
GetMainAxisSize(const SizeF & size,Axis axis)230 float GetMainAxisSize(const SizeF& size, Axis axis)
231 {
232 return axis == Axis::HORIZONTAL ? size.Width() : size.Height();
233 }
234
GetCrossAxisSize(const SizeF & size,Axis axis)235 float GetCrossAxisSize(const SizeF& size, Axis axis)
236 {
237 return axis == Axis::HORIZONTAL ? size.Height() : size.Width();
238 }
239
SetCrossAxisSize(float value,Axis axis,SizeF & size)240 void SetCrossAxisSize(float value, Axis axis, SizeF& size)
241 {
242 if (axis == Axis::VERTICAL) {
243 size.SetWidth(value);
244 return;
245 }
246 size.SetHeight(value);
247 }
248
GetMainAxisSize(const OptionalSizeF & size,Axis axis)249 std::optional<float> GetMainAxisSize(const OptionalSizeF& size, Axis axis)
250 {
251 return axis == Axis::HORIZONTAL ? size.Width() : size.Height();
252 }
253
GetCrossAxisSize(const OptionalSizeF & size,Axis axis)254 std::optional<float> GetCrossAxisSize(const OptionalSizeF& size, Axis axis)
255 {
256 return axis == Axis::HORIZONTAL ? size.Height() : size.Width();
257 }
258
SetCrossAxisSize(float value,Axis axis,OptionalSizeF & size)259 void SetCrossAxisSize(float value, Axis axis, OptionalSizeF& size)
260 {
261 if (axis == Axis::VERTICAL) {
262 size.SetWidth(value);
263 return;
264 }
265 size.SetHeight(value);
266 }
267
SetMainAxisSize(float value,Axis axis,OptionalSizeF & size)268 void SetMainAxisSize(float value, Axis axis, OptionalSizeF& size)
269 {
270 if (axis == Axis::VERTICAL) {
271 size.SetHeight(value);
272 return;
273 }
274 size.SetWidth(value);
275 }
276
CreateIdealSize(const LayoutConstraintF & layoutConstraint,Axis axis,MeasureType measureType,bool usingMaxSize)277 SizeF CreateIdealSize(const LayoutConstraintF& layoutConstraint, Axis axis, MeasureType measureType, bool usingMaxSize)
278 {
279 auto optional = CreateIdealSize(layoutConstraint, axis, measureType);
280 if (usingMaxSize) {
281 optional.UpdateIllegalSizeWithCheck(layoutConstraint.maxSize);
282 } else {
283 optional.UpdateIllegalSizeWithCheck(layoutConstraint.minSize);
284 }
285 return optional.ConvertToSizeT();
286 }
287
CreateIdealSize(const LayoutConstraintF & layoutConstraint,Axis axis,MeasureType measureType)288 OptionalSizeF CreateIdealSize(const LayoutConstraintF& layoutConstraint, Axis axis, MeasureType measureType)
289 {
290 OptionalSizeF idealSize;
291 do {
292 // Use idea size first if it is valid.
293 idealSize.UpdateSizeWithCheck(layoutConstraint.selfIdealSize);
294 if (idealSize.IsValid()) {
295 break;
296 }
297
298 if (measureType == MeasureType::MATCH_PARENT) {
299 idealSize.UpdateIllegalSizeWithCheck(layoutConstraint.parentIdealSize);
300 idealSize.UpdateIllegalSizeWithCheck(layoutConstraint.maxSize);
301 break;
302 }
303
304 if (measureType == MeasureType::MATCH_PARENT_CROSS_AXIS) {
305 auto selfSize = GetCrossAxisSize(idealSize, axis);
306 if (!selfSize) {
307 auto parentCrossSize = GetCrossAxisSize(layoutConstraint.parentIdealSize, axis);
308 if (parentCrossSize) {
309 SetCrossAxisSize(parentCrossSize.value(), axis, idealSize);
310 } else {
311 parentCrossSize = GetCrossAxisSize(layoutConstraint.maxSize, axis);
312 SetCrossAxisSize(parentCrossSize.value(), axis, idealSize);
313 }
314 }
315 break;
316 }
317
318 if (measureType == MeasureType::MATCH_PARENT_MAIN_AXIS) {
319 auto selfSize = GetMainAxisSize(idealSize, axis);
320 auto parentMainSize = GetMainAxisSize(layoutConstraint.parentIdealSize, axis);
321 if (!selfSize) {
322 if (parentMainSize) {
323 SetMainAxisSize(parentMainSize.value(), axis, idealSize);
324 } else {
325 parentMainSize = GetMainAxisSize(layoutConstraint.maxSize, axis);
326 SetMainAxisSize(parentMainSize.value(), axis, idealSize);
327 }
328 }
329 break;
330 }
331 } while (false);
332 return idealSize;
333 }
334
UpdateOptionSizeByCalcLayoutConstraint(const OptionalSize<float> & frameSize,const std::unique_ptr<MeasureProperty> & calcLayoutConstraint,const SizeT<float> percentReference)335 OptionalSizeF UpdateOptionSizeByCalcLayoutConstraint(const OptionalSize<float>& frameSize,
336 const std::unique_ptr<MeasureProperty>& calcLayoutConstraint, const SizeT<float> percentReference)
337 {
338 OptionalSizeF finalSize(frameSize.Width(), frameSize.Height());
339 if (!calcLayoutConstraint) {
340 return finalSize;
341 } else {
342 UpdateOptionSizeByMaxOrMinCalcLayoutConstraint(
343 finalSize, calcLayoutConstraint->maxSize, percentReference, true);
344 UpdateOptionSizeByMaxOrMinCalcLayoutConstraint(
345 finalSize, calcLayoutConstraint->minSize, percentReference, false);
346 }
347 return finalSize;
348 }
349
UpdateOptionSizeByMaxOrMinCalcLayoutConstraint(OptionalSizeF & frameSize,const std::optional<CalcSize> & calcLayoutConstraintMaxMinSize,const SizeT<float> percentReference,bool IsMaxSize)350 void UpdateOptionSizeByMaxOrMinCalcLayoutConstraint(OptionalSizeF& frameSize,
351 const std::optional<CalcSize>& calcLayoutConstraintMaxMinSize, const SizeT<float> percentReference, bool IsMaxSize)
352 {
353 auto scaleProperty = ScaleProperty::CreateScaleProperty();
354 if (!calcLayoutConstraintMaxMinSize.has_value()) {
355 return;
356 }
357 if (calcLayoutConstraintMaxMinSize->Width().has_value()) {
358 auto maxWidthPx = ConvertToPx(calcLayoutConstraintMaxMinSize->Width(), scaleProperty, percentReference.Width());
359 if (IsMaxSize) {
360 frameSize.SetWidth(std::min(maxWidthPx.value(), frameSize.Width().value_or(maxWidthPx.value())));
361 } else {
362 frameSize.SetWidth(std::max(maxWidthPx.value(), frameSize.Width().value_or(maxWidthPx.value())));
363 }
364 }
365 if (calcLayoutConstraintMaxMinSize->Height().has_value()) {
366 auto maxHeightPx =
367 ConvertToPx(calcLayoutConstraintMaxMinSize->Height(), scaleProperty, percentReference.Height());
368 if (IsMaxSize) {
369 frameSize.SetHeight(std::min(maxHeightPx.value(), frameSize.Height().value_or(maxHeightPx.value())));
370 } else {
371 frameSize.SetHeight(std::max(maxHeightPx.value(), frameSize.Height().value_or(maxHeightPx.value())));
372 }
373 }
374 }
375
CreateIdealSizeByPercentRef(const LayoutConstraintF & layoutConstraint,Axis axis,MeasureType measureType,bool needToConstrain)376 OptionalSizeF CreateIdealSizeByPercentRef(
377 const LayoutConstraintF& layoutConstraint, Axis axis, MeasureType measureType, bool needToConstrain)
378 {
379 OptionalSizeF idealSize;
380 do {
381 // Use idea size first if it is valid.
382 idealSize.UpdateSizeWithCheck(layoutConstraint.selfIdealSize);
383 if (idealSize.IsValid()) {
384 break;
385 }
386
387 if (measureType == MeasureType::MATCH_PARENT) {
388 idealSize.UpdateIllegalSizeWithCheck(layoutConstraint.parentIdealSize);
389 idealSize.UpdateIllegalSizeWithCheck(layoutConstraint.percentReference);
390 break;
391 }
392
393 if (measureType == MeasureType::MATCH_PARENT_CROSS_AXIS) {
394 auto selfSize = GetCrossAxisSize(idealSize, axis);
395 if (!selfSize) {
396 auto parentCrossSize = GetCrossAxisSize(layoutConstraint.parentIdealSize, axis);
397 if (parentCrossSize) {
398 SetCrossAxisSize(parentCrossSize.value(), axis, idealSize);
399 } else {
400 parentCrossSize = GetCrossAxisSize(layoutConstraint.percentReference, axis);
401 SetCrossAxisSize(parentCrossSize.value(), axis, idealSize);
402 }
403 }
404 break;
405 }
406
407 if (measureType == MeasureType::MATCH_PARENT_MAIN_AXIS) {
408 auto selfSize = GetMainAxisSize(idealSize, axis);
409 auto parentMainSize = GetMainAxisSize(layoutConstraint.parentIdealSize, axis);
410 if (!selfSize) {
411 if (parentMainSize) {
412 SetMainAxisSize(parentMainSize.value(), axis, idealSize);
413 } else {
414 parentMainSize = GetMainAxisSize(layoutConstraint.percentReference, axis);
415 SetMainAxisSize(parentMainSize.value(), axis, idealSize);
416 }
417 }
418 break;
419 }
420 } while (false);
421 if (needToConstrain) {
422 idealSize.Constrain(layoutConstraint.minSize, layoutConstraint.maxSize,
423 PipelineBase::GetCurrentContext() &&
424 PipelineBase::GetCurrentContext()->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN);
425 }
426 return idealSize;
427 }
428
CreateChildrenConstraint(SizeF & size,const PaddingPropertyF & padding)429 void CreateChildrenConstraint(SizeF& size, const PaddingPropertyF& padding)
430 {
431 float width = 0;
432 float height = 0;
433
434 float paddingLeft = padding.left.has_value() ? padding.left.value() : 0;
435 float paddingRight = padding.right.has_value() ? padding.right.value() : 0;
436 float paddingTop = padding.top.has_value() ? padding.top.value() : 0;
437 float paddingBottom = padding.bottom.has_value() ? padding.bottom.value() : 0;
438 width += (paddingLeft + paddingRight);
439 height += (paddingTop + paddingBottom);
440
441 size.SetHeight(size.Height() - height);
442 size.SetWidth(size.Width() - width);
443 }
444
ConvertToCalcPaddingProperty(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)445 PaddingProperty ConvertToCalcPaddingProperty(const std::optional<CalcDimension>& top,
446 const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
447 const std::optional<CalcDimension>& right)
448 {
449 PaddingProperty paddings;
450 if (top.has_value()) {
451 if (top.value().Unit() == DimensionUnit::CALC) {
452 paddings.top =
453 NG::CalcLength(top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue());
454 } else {
455 paddings.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension());
456 }
457 }
458 if (bottom.has_value()) {
459 if (bottom.value().Unit() == DimensionUnit::CALC) {
460 paddings.bottom = NG::CalcLength(
461 bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue());
462 } else {
463 paddings.bottom = NG::CalcLength(bottom.value().IsNonNegative() ? bottom.value() : CalcDimension());
464 }
465 }
466 if (left.has_value()) {
467 if (left.value().Unit() == DimensionUnit::CALC) {
468 paddings.left =
469 NG::CalcLength(left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue());
470 } else {
471 paddings.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension());
472 }
473 }
474 if (right.has_value()) {
475 if (right.value().Unit() == DimensionUnit::CALC) {
476 paddings.right =
477 NG::CalcLength(right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue());
478 } else {
479 paddings.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension());
480 }
481 }
482 return paddings;
483 }
484 } // namespace OHOS::Ace::NG
485