1 /*
2  * Copyright (c) 2021-2023 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 RECT_H
17 #define RECT_H
18 
19 #include <cmath>
20 #include <string>
21 #include "utils/drawing_macros.h"
22 #include "utils/scalar.h"
23 
24 namespace OHOS {
25 namespace Rosen {
26 namespace Drawing {
27 class RectF;
28 
29 typedef RectF Rect;
30 
31 #define DRAWING_MAX_S32_FITS_IN_FLOAT    2147483520
32 #define DRAWING_MIN_S32_FITS_IN_FLOAT    (-DRAWING_MAX_S32_FITS_IN_FLOAT)
33 
DrawingFloatSaturate2Int(float x)34 static inline int32_t DrawingFloatSaturate2Int(float x)
35 {
36     x = x < DRAWING_MAX_S32_FITS_IN_FLOAT ? x : DRAWING_MAX_S32_FITS_IN_FLOAT;
37     x = x > DRAWING_MIN_S32_FITS_IN_FLOAT ? x : DRAWING_MIN_S32_FITS_IN_FLOAT;
38     return (int32_t)x;
39 }
40 
41 class DRAWING_API RectI {
42 public:
43     inline RectI() noexcept;
44     inline RectI(const RectI& r) noexcept;
45     inline RectI(const int32_t l, const int32_t t, const int32_t r, const int32_t b) noexcept;
46 
~RectI()47     ~RectI() {}
48 
49     inline bool IsValid() const;
50     inline bool IsEmpty() const;
51 
52     inline int32_t GetLeft() const;
53     inline int32_t GetTop() const;
54     inline int32_t GetRight() const;
55     inline int32_t GetBottom() const;
56 
57     inline int32_t GetWidth() const;
58     inline int32_t GetHeight() const;
59 
60     inline void SetLeft(int32_t pos);
61     inline void SetTop(int32_t pos);
62     inline void SetRight(int32_t pos);
63     inline void SetBottom(int32_t pos);
64 
65     /**
66      * @brief Offsets RectI by adding dx to left, right; and by adding dy to top, bottom.
67      * If dx is negative, moves RectI returned to the left.
68      * If dx is positive, moves RectI returned to the right.
69      * If dy is negative, moves RectI returned upward.
70      * If dy is positive, moves RectI returned downward.
71      * @param dx  offset added to left and right
72      * @param dy  offset added to top and bottom
73      */
74     inline void Offset(int32_t dx, int32_t dy);
75 
76     /**
77      * @brief outset by (dx, dy).
78      * If dx is negative, RectI is narrower.
79      * If dx is positive, RectI is wider.
80      * If dy is negative, RectI is shorter.
81      * If dy is positive, RectI is taller.
82      * @param dx offset subtracted to left and added from right
83      * @param dy offset subtracted to top and added from bottom
84      */
85     inline void MakeOutset(int32_t dx, int32_t dy);
86 
87     /**
88      * @brief Returns true if RectI contains other.
89      * Returns false if RectI is empty or other is empty.
90      * RectI contains other when RectI area completely includes other area.
91      * @param other RectI contained
92      * @return true if all sides of RectI are outside other
93      */
94     inline bool Contains(const RectI& other) const;
95 
96     /**
97      * @brief If RectI intersects other, sets RectI to intersection.
98      * @param other limit of result.
99      * @return true if other and RectI have area in common.
100      */
101     inline bool Intersect(const RectI& other);
102 
103     /**
104      * @brief If other is valid, sets RectI to the union of itself and other.
105      * @param other expansion RectI.
106      * @return true if other is valid.
107      */
108     inline bool Join(const RectI& other);
109 
110     inline std::string ToString() const;
111 
112     friend inline bool operator==(const RectI& r1, const RectI& r2);
113     friend inline bool operator!=(const RectI& r1, const RectI& r2);
114 
115     int32_t left_;
116     int32_t top_;
117     int32_t right_;
118     int32_t bottom_;
119 };
120 
RectI()121 inline RectI::RectI() noexcept : left_(0), top_(0), right_(0), bottom_(0) {}
122 
RectI(const RectI & r)123 inline RectI::RectI(const RectI& r) noexcept
124     : left_(r.GetLeft()), top_(r.GetTop()), right_(r.GetRight()), bottom_(r.GetBottom())
125 {}
126 
RectI(const int l,const int t,const int r,const int b)127 inline RectI::RectI(const int l, const int t, const int r, const int b) noexcept
128     : left_(l), top_(t), right_(r), bottom_(b)
129 {}
130 
IsValid()131 inline bool RectI::IsValid() const
132 {
133     return !IsEmpty();
134 }
135 
IsEmpty()136 inline bool RectI::IsEmpty() const
137 {
138     int64_t w = (int64_t)right_ - (int64_t)left_;
139     int64_t h = (int64_t)bottom_ - (int64_t)top_;
140     if (w <= 0 || h <= 0) {
141         return true;
142     }
143     // Return true if either exceeds int32_t
144     int32_t int32test = (w | h) & 0xFFFFFFFF;
145     return int32test < 0;
146 }
147 
GetLeft()148 inline int32_t RectI::GetLeft() const
149 {
150     return left_;
151 }
152 
GetTop()153 inline int32_t RectI::GetTop() const
154 {
155     return top_;
156 }
157 
GetRight()158 inline int32_t RectI::GetRight() const
159 {
160     return right_;
161 }
162 
GetBottom()163 inline int32_t RectI::GetBottom() const
164 {
165     return bottom_;
166 }
167 
GetWidth()168 inline int32_t RectI::GetWidth() const
169 {
170     return right_ - left_;
171 }
172 
GetHeight()173 inline int32_t RectI::GetHeight() const
174 {
175     return bottom_ - top_;
176 }
177 
SetLeft(int32_t pos)178 inline void RectI::SetLeft(int32_t pos)
179 {
180     left_ = pos;
181 }
182 
SetTop(int32_t pos)183 inline void RectI::SetTop(int32_t pos)
184 {
185     top_ = pos;
186 }
187 
SetRight(int32_t pos)188 inline void RectI::SetRight(int32_t pos)
189 {
190     right_ = pos;
191 }
192 
SetBottom(int32_t pos)193 inline void RectI::SetBottom(int32_t pos)
194 {
195     bottom_ = pos;
196 }
197 
Offset(int32_t dx,int32_t dy)198 inline void RectI::Offset(int32_t dx, int32_t dy)
199 {
200     left_ += dx;
201     right_ += dx;
202     top_ += dy;
203     bottom_ += dy;
204 }
205 
MakeOutset(int32_t dx,int32_t dy)206 inline void RectI::MakeOutset(int32_t dx, int32_t dy)
207 {
208     left_ -= dx;
209     right_ += dx;
210     top_ -= dy;
211     bottom_ += dy;
212 }
213 
Intersect(const RectI & other)214 inline bool RectI::Intersect(const RectI& other)
215 {
216     RectI rectI(left_ > other.left_ ? left_ : other.left_, top_ > other.top_ ? top_ : other.top_,
217         right_ < other.right_ ? right_ : other.right_, bottom_ < other.bottom_ ? bottom_ : other.bottom_);
218     if (!rectI.IsValid()) {
219         return false;
220     }
221     *this = rectI;
222     return true;
223 }
224 
Join(const RectI & other)225 inline bool RectI::Join(const RectI& other)
226 {
227     if (!other.IsValid()) {
228         return false;
229     }
230     if (!IsValid()) {
231         *this = other;
232     } else {
233         *this = RectI(left_ < other.left_ ? left_ : other.left_, top_ < other.top_ ? top_ : other.top_,
234             right_ > other.right_ ? right_ : other.right_, bottom_ > other.bottom_ ? bottom_ : other.bottom_);
235     }
236     return true;
237 }
238 
Contains(const RectI & other)239 inline bool RectI::Contains(const RectI& other) const
240 {
241     return !other.IsEmpty() && !this->IsEmpty() &&
242         left_ <= other.left_ && top_ <= other.top_ &&
243         right_ >= other.right_ && bottom_ >= other.bottom_;
244 }
245 
ToString()246 inline std::string RectI::ToString() const
247 {
248     return std::string("(") + std::to_string(left_) + ", " + std::to_string(top_) + ", " +
249         std::to_string(right_ - left_) + ", " + std::to_string(bottom_ - top_) + ")";
250 }
251 
252 inline bool operator==(const RectI& r1, const RectI& r2)
253 {
254     return r1.left_ == r2.left_ && r1.right_ == r2.right_ && r1.top_ == r2.top_ && r1.bottom_ == r2.bottom_;
255 }
256 
257 inline bool operator!=(const RectI& r1, const RectI& r2)
258 {
259     return r1.left_ != r2.left_ || r1.right_ != r2.right_ || r1.top_ != r2.top_ || r1.bottom_ != r2.bottom_;
260 }
261 
262 class DRAWING_API RectF {
263 public:
264     inline RectF() noexcept;
265     inline RectF(const RectF& r) noexcept;
266     inline RectF(const RectI& r) noexcept;
267     inline RectF(const scalar l, const scalar t, const scalar r, const scalar b) noexcept;
268 
~RectF()269     ~RectF() {}
270 
271     inline bool IsValid() const;
272     inline bool IsEmpty() const;
273 
274     inline scalar GetLeft() const;
275     inline scalar GetTop() const;
276     inline scalar GetRight() const;
277     inline scalar GetBottom() const;
278 
279     inline scalar GetWidth() const;
280     inline scalar GetHeight() const;
281 
282     inline void SetLeft(scalar pos);
283     inline void SetTop(scalar pos);
284     inline void SetRight(scalar pos);
285     inline void SetBottom(scalar pos);
286 
287     inline void Offset(scalar dx, scalar dy);
288     inline void MakeOutset(scalar dx, scalar dy);
289     inline void Round();
290     inline RectI RoundOut();
291     inline std::string ToString() const;
292 
293     /*
294      * @brief        If RectF intersects other, sets RectF to intersection.
295      * @param other  limit of result.
296      * @return       true if other and RectF have area in common.
297      */
298     inline bool Intersect(const RectF& other);
299 
300     /*
301      * @brief        If other is valid, sets RectF to the union of itself and other.
302      * @param other  expansion RectF.
303      * @return       true if other is valid.
304      */
305     inline bool Join(const RectF& other);
306 
307     friend inline bool operator==(const RectF& r1, const RectF& r2);
308     friend inline bool operator!=(const RectF& r1, const RectF& r2);
309 
310     scalar left_;
311     scalar top_;
312     scalar right_;
313     scalar bottom_;
314 };
315 
RectF()316 inline RectF::RectF() noexcept : left_(0.0), top_(0.0), right_(0.0), bottom_(0.0) {}
317 
RectF(const RectF & r)318 inline RectF::RectF(const RectF& r) noexcept
319     : left_(r.GetLeft()), top_(r.GetTop()), right_(r.GetRight()), bottom_(r.GetBottom())
320 {}
321 
RectF(const RectI & r)322 inline RectF::RectF(const RectI& r) noexcept
323     : left_(r.GetLeft()), top_(r.GetTop()), right_(r.GetRight()), bottom_(r.GetBottom())
324 {}
325 
RectF(const scalar l,const scalar t,const scalar r,const scalar b)326 inline RectF::RectF(const scalar l, const scalar t, const scalar r, const scalar b) noexcept
327     : left_(l), top_(t), right_(r), bottom_(b)
328 {}
329 
IsValid()330 inline bool RectF::IsValid() const
331 {
332     return left_ < right_ && top_ < bottom_;
333 }
334 
IsEmpty()335 inline bool RectF::IsEmpty() const
336 {
337     return !(left_ < right_ && top_ < bottom_);
338 }
339 
GetLeft()340 inline scalar RectF::GetLeft() const
341 {
342     return left_;
343 }
344 
GetTop()345 inline scalar RectF::GetTop() const
346 {
347     return top_;
348 }
349 
GetRight()350 inline scalar RectF::GetRight() const
351 {
352     return right_;
353 }
354 
GetBottom()355 inline scalar RectF::GetBottom() const
356 {
357     return bottom_;
358 }
359 
GetWidth()360 inline scalar RectF::GetWidth() const
361 {
362     return right_ - left_;
363 }
364 
GetHeight()365 inline scalar RectF::GetHeight() const
366 {
367     return bottom_ - top_;
368 }
369 
SetLeft(scalar pos)370 inline void RectF::SetLeft(scalar pos)
371 {
372     left_ = pos;
373 }
374 
SetTop(scalar pos)375 inline void RectF::SetTop(scalar pos)
376 {
377     top_ = pos;
378 }
379 
SetRight(scalar pos)380 inline void RectF::SetRight(scalar pos)
381 {
382     right_ = pos;
383 }
384 
SetBottom(scalar pos)385 inline void RectF::SetBottom(scalar pos)
386 {
387     bottom_ = pos;
388 }
389 
Offset(scalar dx,scalar dy)390 inline void RectF::Offset(scalar dx, scalar dy)
391 {
392     left_ += dx;
393     right_ += dx;
394     top_ += dy;
395     bottom_ += dy;
396 }
397 
MakeOutset(scalar dx,scalar dy)398 inline void RectF::MakeOutset(scalar dx, scalar dy)
399 {
400     left_ -= dx;
401     right_ += dx;
402     top_ -= dy;
403     bottom_ += dy;
404 }
405 
Round()406 inline void RectF::Round()
407 {
408     left_ = DrawingFloatSaturate2Int(left_ + 0.5f);
409     right_ = DrawingFloatSaturate2Int(right_ + 0.5f);
410     top_ = DrawingFloatSaturate2Int(top_ + 0.5f);
411     bottom_ = DrawingFloatSaturate2Int(bottom_ + 0.5f);
412 }
413 
RoundOut()414 inline RectI RectF::RoundOut()
415 {
416     int32_t left = DrawingFloatSaturate2Int(floorf(left_));
417     int32_t right = DrawingFloatSaturate2Int(ceilf(right_));
418     int32_t top = DrawingFloatSaturate2Int(floorf(top_));
419     int32_t bottom = DrawingFloatSaturate2Int(ceilf(bottom_));
420     return RectI(left, top, right, bottom);
421 }
422 
Intersect(const RectF & other)423 inline bool RectF::Intersect(const RectF& other)
424 {
425     RectF rectF(left_ > other.left_ ? left_ : other.left_, top_ > other.top_ ? top_ : other.top_,
426                 right_ < other.right_ ? right_ : other.right_, bottom_ < other.bottom_ ? bottom_ : other.bottom_);
427     if (!rectF.IsValid()) {
428         return false;
429     }
430     *this = rectF;
431     return true;
432 }
433 
Join(const RectF & other)434 inline bool RectF::Join(const RectF& other)
435 {
436     if (!other.IsValid()) {
437         return false;
438     }
439     if (!IsValid()) {
440         *this = other;
441     } else {
442         *this = RectF(left_ < other.left_ ? left_ : other.left_, top_ < other.top_ ? top_ : other.top_,
443             right_ > other.right_ ? right_ : other.right_, bottom_ > other.bottom_ ? bottom_ : other.bottom_);
444     }
445     return true;
446 }
447 
ToString()448 inline std::string RectF::ToString() const
449 {
450     return std::string("(") + std::to_string(left_) + ", " + std::to_string(top_) + ", " +
451         std::to_string(right_ - left_) + ", " + std::to_string(bottom_ - top_) + ")";
452 }
453 
454 inline bool operator==(const RectF& r1, const RectF& r2)
455 {
456     return IsScalarAlmostEqual(r1.left_, r2.left_) && IsScalarAlmostEqual(r1.right_, r2.right_) &&
457         IsScalarAlmostEqual(r1.top_, r2.top_) && IsScalarAlmostEqual(r1.bottom_, r2.bottom_);
458 }
459 
460 inline bool operator!=(const RectF& r1, const RectF& r2)
461 {
462     return !IsScalarAlmostEqual(r1.left_, r2.left_) || !IsScalarAlmostEqual(r1.right_, r2.right_) ||
463         !IsScalarAlmostEqual(r1.top_, r2.top_) || !IsScalarAlmostEqual(r1.bottom_, r2.bottom_);
464 }
465 } // namespace Drawing
466 } // namespace Rosen
467 } // namespace OHOS
468 #endif
469