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     inline void Dump(std::string& out) const;
116 
117     int32_t left_;
118     int32_t top_;
119     int32_t right_;
120     int32_t bottom_;
121 };
122 
123 inline RectI::RectI() noexcept : left_(0), top_(0), right_(0), bottom_(0) {}
124 
125 inline RectI::RectI(const RectI& r) noexcept
bottom_(r.GetBottom())126     : left_(r.GetLeft()), top_(r.GetTop()), right_(r.GetRight()), bottom_(r.GetBottom())
127 {}
128 
129 inline RectI::RectI(const int l, const int t, const int r, const int b) noexcept
bottom_(b)130     : left_(l), top_(t), right_(r), bottom_(b)
131 {}
132 
IsValid() const133 inline bool RectI::IsValid() const
134 {
135     return !IsEmpty();
136 }
137 
IsEmpty() const138 inline bool RectI::IsEmpty() const
139 {
140     int64_t w = (int64_t)right_ - (int64_t)left_;
141     int64_t h = (int64_t)bottom_ - (int64_t)top_;
142     if (w <= 0 || h <= 0) {
143         return true;
144     }
145     // Return true if either exceeds int32_t
146     int32_t int32test = (w | h) & 0xFFFFFFFF;
147     return int32test < 0;
148 }
149 
GetLeft() const150 inline int32_t RectI::GetLeft() const
151 {
152     return left_;
153 }
154 
GetTop() const155 inline int32_t RectI::GetTop() const
156 {
157     return top_;
158 }
159 
GetRight() const160 inline int32_t RectI::GetRight() const
161 {
162     return right_;
163 }
164 
GetBottom() const165 inline int32_t RectI::GetBottom() const
166 {
167     return bottom_;
168 }
169 
GetWidth() const170 inline int32_t RectI::GetWidth() const
171 {
172     return right_ - left_;
173 }
174 
GetHeight() const175 inline int32_t RectI::GetHeight() const
176 {
177     return bottom_ - top_;
178 }
179 
SetLeft(int32_t pos)180 inline void RectI::SetLeft(int32_t pos)
181 {
182     left_ = pos;
183 }
184 
SetTop(int32_t pos)185 inline void RectI::SetTop(int32_t pos)
186 {
187     top_ = pos;
188 }
189 
SetRight(int32_t pos)190 inline void RectI::SetRight(int32_t pos)
191 {
192     right_ = pos;
193 }
194 
SetBottom(int32_t pos)195 inline void RectI::SetBottom(int32_t pos)
196 {
197     bottom_ = pos;
198 }
199 
Offset(int32_t dx, int32_t dy)200 inline void RectI::Offset(int32_t dx, int32_t dy)
201 {
202     left_ += dx;
203     right_ += dx;
204     top_ += dy;
205     bottom_ += dy;
206 }
207 
MakeOutset(int32_t dx, int32_t dy)208 inline void RectI::MakeOutset(int32_t dx, int32_t dy)
209 {
210     left_ -= dx;
211     right_ += dx;
212     top_ -= dy;
213     bottom_ += dy;
214 }
215 
Intersect(const RectI& other)216 inline bool RectI::Intersect(const RectI& other)
217 {
218     RectI rectI(left_ > other.left_ ? left_ : other.left_, top_ > other.top_ ? top_ : other.top_,
219         right_ < other.right_ ? right_ : other.right_, bottom_ < other.bottom_ ? bottom_ : other.bottom_);
220     if (!rectI.IsValid()) {
221         return false;
222     }
223     *this = rectI;
224     return true;
225 }
226 
Join(const RectI& other)227 inline bool RectI::Join(const RectI& other)
228 {
229     if (!other.IsValid()) {
230         return false;
231     }
232     if (!IsValid()) {
233         *this = other;
234     } else {
235         *this = RectI(left_ < other.left_ ? left_ : other.left_, top_ < other.top_ ? top_ : other.top_,
236             right_ > other.right_ ? right_ : other.right_, bottom_ > other.bottom_ ? bottom_ : other.bottom_);
237     }
238     return true;
239 }
240 
Contains(const RectI& other) const241 inline bool RectI::Contains(const RectI& other) const
242 {
243     return !other.IsEmpty() && !this->IsEmpty() &&
244         left_ <= other.left_ && top_ <= other.top_ &&
245         right_ >= other.right_ && bottom_ >= other.bottom_;
246 }
247 
ToString() const248 inline std::string RectI::ToString() const
249 {
250     return std::string("(") + std::to_string(left_) + ", " + std::to_string(top_) + ", " +
251         std::to_string(right_ - left_) + ", " + std::to_string(bottom_ - top_) + ")";
252 }
253 
Dump(std::string& out) const254 inline void RectI::Dump(std::string& out) const
255 {
256     out += "[left:" + std::to_string(left_);
257     out += " top:" + std::to_string(top_);
258     out += " right:" + std::to_string(right_);
259     out += " bottom:" + std::to_string(bottom_);
260     out += "]";
261 }
262 
operator ==(const RectI& r1, const RectI& r2)263 inline bool operator==(const RectI& r1, const RectI& r2)
264 {
265     return r1.left_ == r2.left_ && r1.right_ == r2.right_ && r1.top_ == r2.top_ && r1.bottom_ == r2.bottom_;
266 }
267 
operator !=(const RectI& r1, const RectI& r2)268 inline bool operator!=(const RectI& r1, const RectI& r2)
269 {
270     return r1.left_ != r2.left_ || r1.right_ != r2.right_ || r1.top_ != r2.top_ || r1.bottom_ != r2.bottom_;
271 }
272 
273 class DRAWING_API RectF {
274 public:
275     inline RectF() noexcept;
276     inline RectF(const RectF& r) noexcept;
277     inline RectF(const RectI& r) noexcept;
278     inline RectF(const scalar l, const scalar t, const scalar r, const scalar b) noexcept;
279 
~RectF()280     ~RectF() {}
281 
282     inline bool IsValid() const;
283     inline bool IsEmpty() const;
284 
285     inline scalar GetLeft() const;
286     inline scalar GetTop() const;
287     inline scalar GetRight() const;
288     inline scalar GetBottom() const;
289 
290     inline scalar GetWidth() const;
291     inline scalar GetHeight() const;
292 
293     inline void SetLeft(scalar pos);
294     inline void SetTop(scalar pos);
295     inline void SetRight(scalar pos);
296     inline void SetBottom(scalar pos);
297 
298     inline void Offset(scalar dx, scalar dy);
299     inline void MakeOutset(scalar dx, scalar dy);
300     inline void Round();
301     inline RectI RoundOut();
302     inline std::string ToString() const;
303 
304     /*
305      * @brief        If RectF intersects other, sets RectF to intersection.
306      * @param other  limit of result.
307      * @return       true if other and RectF have area in common.
308      */
309     inline bool Intersect(const RectF& other);
310 
311     /*
312      * @brief        If other is valid, sets RectF to the union of itself and other.
313      * @param other  expansion RectF.
314      * @return       true if other is valid.
315      */
316     inline bool Join(const RectF& other);
317 
318     friend inline bool operator==(const RectF& r1, const RectF& r2);
319     friend inline bool operator!=(const RectF& r1, const RectF& r2);
320 
321     inline void Dump(std::string& out) const;
322 
323     scalar left_;
324     scalar top_;
325     scalar right_;
326     scalar bottom_;
327 };
328 
329 inline RectF::RectF() noexcept : left_(0.0), top_(0.0), right_(0.0), bottom_(0.0) {}
330 
331 inline RectF::RectF(const RectF& r) noexcept
bottom_(r.GetBottom())332     : left_(r.GetLeft()), top_(r.GetTop()), right_(r.GetRight()), bottom_(r.GetBottom())
333 {}
334 
335 inline RectF::RectF(const RectI& r) noexcept
bottom_(r.GetBottom())336     : left_(r.GetLeft()), top_(r.GetTop()), right_(r.GetRight()), bottom_(r.GetBottom())
337 {}
338 
339 inline RectF::RectF(const scalar l, const scalar t, const scalar r, const scalar b) noexcept
bottom_(b)340     : left_(l), top_(t), right_(r), bottom_(b)
341 {}
342 
IsValid() const343 inline bool RectF::IsValid() const
344 {
345     return left_ < right_ && top_ < bottom_;
346 }
347 
IsEmpty() const348 inline bool RectF::IsEmpty() const
349 {
350     return !(left_ < right_ && top_ < bottom_);
351 }
352 
GetLeft() const353 inline scalar RectF::GetLeft() const
354 {
355     return left_;
356 }
357 
GetTop() const358 inline scalar RectF::GetTop() const
359 {
360     return top_;
361 }
362 
GetRight() const363 inline scalar RectF::GetRight() const
364 {
365     return right_;
366 }
367 
GetBottom() const368 inline scalar RectF::GetBottom() const
369 {
370     return bottom_;
371 }
372 
GetWidth() const373 inline scalar RectF::GetWidth() const
374 {
375     return right_ - left_;
376 }
377 
GetHeight() const378 inline scalar RectF::GetHeight() const
379 {
380     return bottom_ - top_;
381 }
382 
SetLeft(scalar pos)383 inline void RectF::SetLeft(scalar pos)
384 {
385     left_ = pos;
386 }
387 
SetTop(scalar pos)388 inline void RectF::SetTop(scalar pos)
389 {
390     top_ = pos;
391 }
392 
SetRight(scalar pos)393 inline void RectF::SetRight(scalar pos)
394 {
395     right_ = pos;
396 }
397 
SetBottom(scalar pos)398 inline void RectF::SetBottom(scalar pos)
399 {
400     bottom_ = pos;
401 }
402 
Offset(scalar dx, scalar dy)403 inline void RectF::Offset(scalar dx, scalar dy)
404 {
405     left_ += dx;
406     right_ += dx;
407     top_ += dy;
408     bottom_ += dy;
409 }
410 
MakeOutset(scalar dx, scalar dy)411 inline void RectF::MakeOutset(scalar dx, scalar dy)
412 {
413     left_ -= dx;
414     right_ += dx;
415     top_ -= dy;
416     bottom_ += dy;
417 }
418 
Round()419 inline void RectF::Round()
420 {
421     left_ = DrawingFloatSaturate2Int(left_ + 0.5f);
422     right_ = DrawingFloatSaturate2Int(right_ + 0.5f);
423     top_ = DrawingFloatSaturate2Int(top_ + 0.5f);
424     bottom_ = DrawingFloatSaturate2Int(bottom_ + 0.5f);
425 }
426 
RoundOut()427 inline RectI RectF::RoundOut()
428 {
429     int32_t left = DrawingFloatSaturate2Int(floorf(left_));
430     int32_t right = DrawingFloatSaturate2Int(ceilf(right_));
431     int32_t top = DrawingFloatSaturate2Int(floorf(top_));
432     int32_t bottom = DrawingFloatSaturate2Int(ceilf(bottom_));
433     return RectI(left, top, right, bottom);
434 }
435 
Intersect(const RectF& other)436 inline bool RectF::Intersect(const RectF& other)
437 {
438     RectF rectF(left_ > other.left_ ? left_ : other.left_, top_ > other.top_ ? top_ : other.top_,
439                 right_ < other.right_ ? right_ : other.right_, bottom_ < other.bottom_ ? bottom_ : other.bottom_);
440     if (!rectF.IsValid()) {
441         return false;
442     }
443     *this = rectF;
444     return true;
445 }
446 
Join(const RectF& other)447 inline bool RectF::Join(const RectF& other)
448 {
449     if (!other.IsValid()) {
450         return false;
451     }
452     if (!IsValid()) {
453         *this = other;
454     } else {
455         *this = RectF(left_ < other.left_ ? left_ : other.left_, top_ < other.top_ ? top_ : other.top_,
456             right_ > other.right_ ? right_ : other.right_, bottom_ > other.bottom_ ? bottom_ : other.bottom_);
457     }
458     return true;
459 }
460 
ToString() const461 inline std::string RectF::ToString() const
462 {
463     return std::string("(") + std::to_string(left_) + ", " + std::to_string(top_) + ", " +
464         std::to_string(right_ - left_) + ", " + std::to_string(bottom_ - top_) + ")";
465 }
466 
Dump(std::string& out) const467 inline void RectF::Dump(std::string& out) const
468 {
469     out += "[left:" + std::to_string(left_);
470     out += " top:" + std::to_string(top_);
471     out += " right:" + std::to_string(right_);
472     out += " bottom:" + std::to_string(bottom_);
473     out += ']';
474 }
475 
operator ==(const RectF& r1, const RectF& r2)476 inline bool operator==(const RectF& r1, const RectF& r2)
477 {
478     return IsScalarAlmostEqual(r1.left_, r2.left_) && IsScalarAlmostEqual(r1.right_, r2.right_) &&
479         IsScalarAlmostEqual(r1.top_, r2.top_) && IsScalarAlmostEqual(r1.bottom_, r2.bottom_);
480 }
481 
operator !=(const RectF& r1, const RectF& r2)482 inline bool operator!=(const RectF& r1, const RectF& r2)
483 {
484     return !IsScalarAlmostEqual(r1.left_, r2.left_) || !IsScalarAlmostEqual(r1.right_, r2.right_) ||
485         !IsScalarAlmostEqual(r1.top_, r2.top_) || !IsScalarAlmostEqual(r1.bottom_, r2.bottom_);
486 }
487 } // namespace Drawing
488 } // namespace Rosen
489 } // namespace OHOS
490 #endif
491