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