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 #ifndef FOUNDATION_ACE_FRAMEWORKS_BASE_GEOMETRY_DIMENSION_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BASE_GEOMETRY_DIMENSION_H
18
19 #include <string>
20
21 #include "base/utils/macros.h"
22 #include "base/utils/system_properties.h"
23 #include "base/utils/utils.h"
24
25 #define NEAR_ZERO(value) ((value > 0.0) ? ((value - 0.0) <= 0.000001f) : ((0.0 - value) <= 0.000001f))
26
27 namespace OHOS::Ace {
28 enum class DimensionUnit {
29 /*
30 * Unit is invalid.
31 */
32 INVALID = -2,
33 /*
34 * Unit is empty.
35 */
36 NONE = -1,
37 /*
38 * Logical pixel used in Ace1.0. It's based on frontend design width.
39 * For example, when a frontend with 750px design width running on a
40 * device with 1080 pixels width, 1px represents 1.44 pixels.
41 */
42 PX = 0,
43 /*
44 * Density independent pixels, one vp is one pixel on a 160 dpi screen.
45 */
46 VP,
47 /*
48 * Scale independent pixels. This is like VP but will be scaled by
49 * user's font size preference.
50 */
51 FP,
52 /*
53 * The percentage of either a value from the element's parent or from
54 * another property of the element itself.
55 */
56 PERCENT,
57 /*
58 * logic pixels used in ACE2.0 instead of PX, and PX is the physical pixels in ACE2.0
59 */
60 LPX,
61 /*
62 * The value is calculated from the element's parent and another property of the element itself.
63 */
64 AUTO,
65 /*
66 * The value is expression.
67 */
68 CALC,
69 };
70
71 /*
72 * Dimension contains a value and an unit to represent different
73 * scales in one class.
74 */
75 class ACE_FORCE_EXPORT Dimension {
76 public:
77 constexpr Dimension() = default;
78 ~Dimension() = default;
Dimension(double value, DimensionUnit unit = DimensionUnit::PX)79 constexpr explicit Dimension(double value, DimensionUnit unit = DimensionUnit::PX) : value_(value), unit_(unit) {}
80
Reset()81 void Reset()
82 {
83 value_ = 0.0;
84 unit_ = DimensionUnit::PX;
85 }
86
ResetInvalidValue()87 void ResetInvalidValue()
88 {
89 if (std::isnan(value_)) {
90 Reset();
91 }
92 }
93
Value() const94 constexpr double Value() const
95 {
96 return value_;
97 }
98
SetValue(double value)99 void SetValue(double value)
100 {
101 value_ = value;
102 }
103
Unit() const104 constexpr DimensionUnit Unit() const
105 {
106 return unit_;
107 }
108
SetUnit(DimensionUnit unit)109 void SetUnit(DimensionUnit unit)
110 {
111 unit_ = unit;
112 }
113
IsValid() const114 bool IsValid() const
115 {
116 return GreatNotEqual(value_, 0.0);
117 }
118
IsNonNegative() const119 bool IsNonNegative() const
120 {
121 return NonNegative(value_);
122 }
123
IsNonPositive() const124 bool IsNonPositive() const
125 {
126 return NonPositive(value_);
127 }
128
IsNegative() const129 bool IsNegative() const
130 {
131 return !NonNegative(value_);
132 }
133
134 // Deprecated: don't use this to covert to px.
ConvertToPx(double dipScale) const135 double ConvertToPx(double dipScale) const
136 {
137 if (unit_ == DimensionUnit::VP || unit_ == DimensionUnit::FP) {
138 return value_ * dipScale;
139 }
140 return value_;
141 }
142
143 // Percentage unit conversion is not supported.
144 double ConvertToVp() const;
145
146 // Percentage unit conversion is not supported.
147 double ConvertToPx() const;
148
149 // Percentage unit conversion is not supported.
150 double ConvertToFp() const;
151
152 DimensionUnit GetAdaptDimensionUnit(const Dimension& dimension);
153
154 double ConvertToPxDistribute(
155 std::optional<float> minOptional, std::optional<float> maxOptional, bool allowScale = true) const;
156
157 double ConvertToPxByCustomFontScale(float minFontScale, float maxFontScale) const;
158
159 double ConvertToPxByAppFontScale(float minFontScale) const;
160
161 double ConvertToVpByAppFontScale() const;
162
GetNativeValue(DimensionUnit unit) const163 double GetNativeValue(DimensionUnit unit) const
164 {
165 if (unit_ == unit || unit == DimensionUnit::PERCENT) {
166 return value_;
167 } else if (unit == DimensionUnit::PX) {
168 return ConvertToPx();
169 } else if (unit == DimensionUnit::FP) {
170 return ConvertToFp();
171 } else {
172 return ConvertToVp();
173 }
174 }
175
176 // support percentage unit conversion
177 double ConvertToPxWithSize(double size) const;
178
179 bool NormalizeToPx(double vpScale, double fpScale, double lpxScale, double parentLength, double& result) const;
180
operator *(double value) const181 constexpr Dimension operator*(double value) const
182 {
183 return Dimension(value_ * value, unit_);
184 }
185
operator /(double value) const186 constexpr Dimension operator/(double value) const
187 {
188 // NearZero cannot be used in a constant expression
189 if (NEAR_ZERO(value)) {
190 return {};
191 }
192 return Dimension(value_ / value, unit_);
193 }
194
operator ==(const Dimension& dimension) const195 bool operator==(const Dimension& dimension) const
196 {
197 return (unit_ == dimension.unit_) && NearEqual(value_, dimension.value_);
198 }
199
operator !=(const Dimension& dimension) const200 bool operator!=(const Dimension& dimension) const
201 {
202 return !operator==(dimension);
203 }
204
205 /*
206 * Add two dimensions using the same unit.
207 */
operator +(const Dimension& dimension) const208 constexpr Dimension operator+(const Dimension& dimension) const
209 {
210 if (NEAR_ZERO(dimension.Value())) {
211 return *this;
212 }
213 ACE_DCHECK(unit_ == dimension.unit_);
214 return Dimension(value_ + dimension.value_, unit_);
215 }
216
217 /*
218 * Add a new dimension to itself using same unit.
219 */
operator +=(const Dimension& dimension)220 Dimension& operator+=(const Dimension& dimension)
221 {
222 ACE_DCHECK(unit_ == dimension.unit_);
223 value_ += dimension.value_;
224 return *this;
225 }
226
227 /*
228 * Minus a dimension using the same unit.
229 */
operator -(const Dimension& dimension) const230 constexpr Dimension operator-(const Dimension& dimension) const
231 {
232 if (NEAR_ZERO(dimension.Value())) {
233 return *this;
234 }
235 ACE_DCHECK(unit_ == dimension.unit_);
236 return Dimension(value_ - dimension.value_, unit_);
237 }
238
239 /*
240 * The opposite of dimension.
241 */
operator -() const242 constexpr Dimension operator-() const
243 {
244 return Dimension(-value_, unit_);
245 }
246
247 /*
248 * Minus a dimension to itself using the same unit.
249 */
operator -=(const Dimension& dimension)250 Dimension& operator-=(const Dimension& dimension)
251 {
252 ACE_DCHECK(unit_ == dimension.unit_);
253 value_ -= dimension.value_;
254 return *this;
255 }
256
operator >(const Dimension& dimension) const257 bool operator>(const Dimension& dimension) const
258 {
259 ACE_DCHECK(unit_ == dimension.unit_);
260 return (value_ > dimension.value_);
261 }
262
operator <(const Dimension& dimension) const263 bool operator<(const Dimension& dimension) const
264 {
265 ACE_DCHECK(unit_ == dimension.unit_);
266 return (value_ < dimension.value_);
267 }
268
269 std::string ToString() const;
270
271 static Dimension FromString(const std::string& str);
272
273 private:
274 double value_ = 0.0;
275 DimensionUnit unit_ = DimensionUnit::PX;
276 };
277
278 // literal operators for dimension
_vp(long double value)279 inline constexpr Dimension operator""_vp(long double value)
280 {
281 return Dimension(static_cast<double>(value), DimensionUnit::VP);
282 }
283
_px(long double value)284 inline constexpr Dimension operator""_px(long double value)
285 {
286 return Dimension(static_cast<double>(value), DimensionUnit::PX);
287 }
288
_fp(long double value)289 inline constexpr Dimension operator""_fp(long double value)
290 {
291 return Dimension(static_cast<double>(value), DimensionUnit::FP);
292 }
293
_pct(long double value)294 inline constexpr Dimension operator""_pct(long double value)
295 {
296 return Dimension(static_cast<double>(value), DimensionUnit::PERCENT);
297 }
298
299 } // namespace OHOS::Ace
300
301 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_GEOMETRY_DIMENSION_H
302