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