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;
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()94     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()104     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()114     bool IsValid() const
115     {
116         return GreatNotEqual(value_, 0.0);
117     }
118 
IsNonNegative()119     bool IsNonNegative() const
120     {
121         return NonNegative(value_);
122     }
123 
IsNonPositive()124     bool IsNonPositive() const
125     {
126         return NonPositive(value_);
127     }
128 
IsNegative()129     bool IsNegative() const
130     {
131         return !NonNegative(value_);
132     }
133 
134     // Deprecated: don't use this to covert to px.
ConvertToPx(double dipScale)135     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)163     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 
181     constexpr Dimension operator*(double value) const
182     {
183         return Dimension(value_ * value, unit_);
184     }
185 
186     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 
195     bool operator==(const Dimension& dimension) const
196     {
197         return (unit_ == dimension.unit_) && NearEqual(value_, dimension.value_);
198     }
199 
200     bool operator!=(const Dimension& dimension) const
201     {
202         return !operator==(dimension);
203     }
204 
205     /*
206      * Add two dimensions using the same unit.
207      */
208     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      */
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      */
230     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      */
242     constexpr Dimension operator-() const
243     {
244         return Dimension(-value_, unit_);
245     }
246 
247     /*
248      * Minus a dimension to itself using the same unit.
249      */
250     Dimension& operator-=(const Dimension& dimension)
251     {
252         ACE_DCHECK(unit_ == dimension.unit_);
253         value_ -= dimension.value_;
254         return *this;
255     }
256 
257     bool operator>(const Dimension& dimension) const
258     {
259         ACE_DCHECK(unit_ == dimension.unit_);
260         return (value_ > dimension.value_);
261     }
262 
263     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
279 inline constexpr Dimension operator""_vp(long double value)
280 {
281     return Dimension(static_cast<double>(value), DimensionUnit::VP);
282 }
283 
284 inline constexpr Dimension operator""_px(long double value)
285 {
286     return Dimension(static_cast<double>(value), DimensionUnit::PX);
287 }
288 
289 inline constexpr Dimension operator""_fp(long double value)
290 {
291     return Dimension(static_cast<double>(value), DimensionUnit::FP);
292 }
293 
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