/* * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RECT_H #define RECT_H #include #include #include "utils/drawing_macros.h" #include "utils/scalar.h" namespace OHOS { namespace Rosen { namespace Drawing { class RectF; typedef RectF Rect; #define DRAWING_MAX_S32_FITS_IN_FLOAT 2147483520 #define DRAWING_MIN_S32_FITS_IN_FLOAT (-DRAWING_MAX_S32_FITS_IN_FLOAT) static inline int32_t DrawingFloatSaturate2Int(float x) { x = x < DRAWING_MAX_S32_FITS_IN_FLOAT ? x : DRAWING_MAX_S32_FITS_IN_FLOAT; x = x > DRAWING_MIN_S32_FITS_IN_FLOAT ? x : DRAWING_MIN_S32_FITS_IN_FLOAT; return (int32_t)x; } class DRAWING_API RectI { public: inline RectI() noexcept; inline RectI(const RectI& r) noexcept; inline RectI(const int32_t l, const int32_t t, const int32_t r, const int32_t b) noexcept; ~RectI() {} inline bool IsValid() const; inline bool IsEmpty() const; inline int32_t GetLeft() const; inline int32_t GetTop() const; inline int32_t GetRight() const; inline int32_t GetBottom() const; inline int32_t GetWidth() const; inline int32_t GetHeight() const; inline void SetLeft(int32_t pos); inline void SetTop(int32_t pos); inline void SetRight(int32_t pos); inline void SetBottom(int32_t pos); /** * @brief Offsets RectI by adding dx to left, right; and by adding dy to top, bottom. * If dx is negative, moves RectI returned to the left. * If dx is positive, moves RectI returned to the right. * If dy is negative, moves RectI returned upward. * If dy is positive, moves RectI returned downward. * @param dx offset added to left and right * @param dy offset added to top and bottom */ inline void Offset(int32_t dx, int32_t dy); /** * @brief outset by (dx, dy). * If dx is negative, RectI is narrower. * If dx is positive, RectI is wider. * If dy is negative, RectI is shorter. * If dy is positive, RectI is taller. * @param dx offset subtracted to left and added from right * @param dy offset subtracted to top and added from bottom */ inline void MakeOutset(int32_t dx, int32_t dy); /** * @brief Returns true if RectI contains other. * Returns false if RectI is empty or other is empty. * RectI contains other when RectI area completely includes other area. * @param other RectI contained * @return true if all sides of RectI are outside other */ inline bool Contains(const RectI& other) const; /** * @brief If RectI intersects other, sets RectI to intersection. * @param other limit of result. * @return true if other and RectI have area in common. */ inline bool Intersect(const RectI& other); /** * @brief If other is valid, sets RectI to the union of itself and other. * @param other expansion RectI. * @return true if other is valid. */ inline bool Join(const RectI& other); inline std::string ToString() const; friend inline bool operator==(const RectI& r1, const RectI& r2); friend inline bool operator!=(const RectI& r1, const RectI& r2); int32_t left_; int32_t top_; int32_t right_; int32_t bottom_; }; inline RectI::RectI() noexcept : left_(0), top_(0), right_(0), bottom_(0) {} inline RectI::RectI(const RectI& r) noexcept : left_(r.GetLeft()), top_(r.GetTop()), right_(r.GetRight()), bottom_(r.GetBottom()) {} inline RectI::RectI(const int l, const int t, const int r, const int b) noexcept : left_(l), top_(t), right_(r), bottom_(b) {} inline bool RectI::IsValid() const { return !IsEmpty(); } inline bool RectI::IsEmpty() const { int64_t w = (int64_t)right_ - (int64_t)left_; int64_t h = (int64_t)bottom_ - (int64_t)top_; if (w <= 0 || h <= 0) { return true; } // Return true if either exceeds int32_t int32_t int32test = (w | h) & 0xFFFFFFFF; return int32test < 0; } inline int32_t RectI::GetLeft() const { return left_; } inline int32_t RectI::GetTop() const { return top_; } inline int32_t RectI::GetRight() const { return right_; } inline int32_t RectI::GetBottom() const { return bottom_; } inline int32_t RectI::GetWidth() const { return right_ - left_; } inline int32_t RectI::GetHeight() const { return bottom_ - top_; } inline void RectI::SetLeft(int32_t pos) { left_ = pos; } inline void RectI::SetTop(int32_t pos) { top_ = pos; } inline void RectI::SetRight(int32_t pos) { right_ = pos; } inline void RectI::SetBottom(int32_t pos) { bottom_ = pos; } inline void RectI::Offset(int32_t dx, int32_t dy) { left_ += dx; right_ += dx; top_ += dy; bottom_ += dy; } inline void RectI::MakeOutset(int32_t dx, int32_t dy) { left_ -= dx; right_ += dx; top_ -= dy; bottom_ += dy; } inline bool RectI::Intersect(const RectI& other) { RectI rectI(left_ > other.left_ ? left_ : other.left_, top_ > other.top_ ? top_ : other.top_, right_ < other.right_ ? right_ : other.right_, bottom_ < other.bottom_ ? bottom_ : other.bottom_); if (!rectI.IsValid()) { return false; } *this = rectI; return true; } inline bool RectI::Join(const RectI& other) { if (!other.IsValid()) { return false; } if (!IsValid()) { *this = other; } else { *this = RectI(left_ < other.left_ ? left_ : other.left_, top_ < other.top_ ? top_ : other.top_, right_ > other.right_ ? right_ : other.right_, bottom_ > other.bottom_ ? bottom_ : other.bottom_); } return true; } inline bool RectI::Contains(const RectI& other) const { return !other.IsEmpty() && !this->IsEmpty() && left_ <= other.left_ && top_ <= other.top_ && right_ >= other.right_ && bottom_ >= other.bottom_; } inline std::string RectI::ToString() const { return std::string("(") + std::to_string(left_) + ", " + std::to_string(top_) + ", " + std::to_string(right_ - left_) + ", " + std::to_string(bottom_ - top_) + ")"; } inline bool operator==(const RectI& r1, const RectI& r2) { return r1.left_ == r2.left_ && r1.right_ == r2.right_ && r1.top_ == r2.top_ && r1.bottom_ == r2.bottom_; } inline bool operator!=(const RectI& r1, const RectI& r2) { return r1.left_ != r2.left_ || r1.right_ != r2.right_ || r1.top_ != r2.top_ || r1.bottom_ != r2.bottom_; } class DRAWING_API RectF { public: inline RectF() noexcept; inline RectF(const RectF& r) noexcept; inline RectF(const RectI& r) noexcept; inline RectF(const scalar l, const scalar t, const scalar r, const scalar b) noexcept; ~RectF() {} inline bool IsValid() const; inline bool IsEmpty() const; inline scalar GetLeft() const; inline scalar GetTop() const; inline scalar GetRight() const; inline scalar GetBottom() const; inline scalar GetWidth() const; inline scalar GetHeight() const; inline void SetLeft(scalar pos); inline void SetTop(scalar pos); inline void SetRight(scalar pos); inline void SetBottom(scalar pos); inline void Offset(scalar dx, scalar dy); inline void MakeOutset(scalar dx, scalar dy); inline void Round(); inline RectI RoundOut(); inline std::string ToString() const; /* * @brief If RectF intersects other, sets RectF to intersection. * @param other limit of result. * @return true if other and RectF have area in common. */ inline bool Intersect(const RectF& other); /* * @brief If other is valid, sets RectF to the union of itself and other. * @param other expansion RectF. * @return true if other is valid. */ inline bool Join(const RectF& other); friend inline bool operator==(const RectF& r1, const RectF& r2); friend inline bool operator!=(const RectF& r1, const RectF& r2); scalar left_; scalar top_; scalar right_; scalar bottom_; }; inline RectF::RectF() noexcept : left_(0.0), top_(0.0), right_(0.0), bottom_(0.0) {} inline RectF::RectF(const RectF& r) noexcept : left_(r.GetLeft()), top_(r.GetTop()), right_(r.GetRight()), bottom_(r.GetBottom()) {} inline RectF::RectF(const RectI& r) noexcept : left_(r.GetLeft()), top_(r.GetTop()), right_(r.GetRight()), bottom_(r.GetBottom()) {} inline RectF::RectF(const scalar l, const scalar t, const scalar r, const scalar b) noexcept : left_(l), top_(t), right_(r), bottom_(b) {} inline bool RectF::IsValid() const { return left_ < right_ && top_ < bottom_; } inline bool RectF::IsEmpty() const { return !(left_ < right_ && top_ < bottom_); } inline scalar RectF::GetLeft() const { return left_; } inline scalar RectF::GetTop() const { return top_; } inline scalar RectF::GetRight() const { return right_; } inline scalar RectF::GetBottom() const { return bottom_; } inline scalar RectF::GetWidth() const { return right_ - left_; } inline scalar RectF::GetHeight() const { return bottom_ - top_; } inline void RectF::SetLeft(scalar pos) { left_ = pos; } inline void RectF::SetTop(scalar pos) { top_ = pos; } inline void RectF::SetRight(scalar pos) { right_ = pos; } inline void RectF::SetBottom(scalar pos) { bottom_ = pos; } inline void RectF::Offset(scalar dx, scalar dy) { left_ += dx; right_ += dx; top_ += dy; bottom_ += dy; } inline void RectF::MakeOutset(scalar dx, scalar dy) { left_ -= dx; right_ += dx; top_ -= dy; bottom_ += dy; } inline void RectF::Round() { left_ = DrawingFloatSaturate2Int(left_ + 0.5f); right_ = DrawingFloatSaturate2Int(right_ + 0.5f); top_ = DrawingFloatSaturate2Int(top_ + 0.5f); bottom_ = DrawingFloatSaturate2Int(bottom_ + 0.5f); } inline RectI RectF::RoundOut() { int32_t left = DrawingFloatSaturate2Int(floorf(left_)); int32_t right = DrawingFloatSaturate2Int(ceilf(right_)); int32_t top = DrawingFloatSaturate2Int(floorf(top_)); int32_t bottom = DrawingFloatSaturate2Int(ceilf(bottom_)); return RectI(left, top, right, bottom); } inline bool RectF::Intersect(const RectF& other) { RectF rectF(left_ > other.left_ ? left_ : other.left_, top_ > other.top_ ? top_ : other.top_, right_ < other.right_ ? right_ : other.right_, bottom_ < other.bottom_ ? bottom_ : other.bottom_); if (!rectF.IsValid()) { return false; } *this = rectF; return true; } inline bool RectF::Join(const RectF& other) { if (!other.IsValid()) { return false; } if (!IsValid()) { *this = other; } else { *this = RectF(left_ < other.left_ ? left_ : other.left_, top_ < other.top_ ? top_ : other.top_, right_ > other.right_ ? right_ : other.right_, bottom_ > other.bottom_ ? bottom_ : other.bottom_); } return true; } inline std::string RectF::ToString() const { return std::string("(") + std::to_string(left_) + ", " + std::to_string(top_) + ", " + std::to_string(right_ - left_) + ", " + std::to_string(bottom_ - top_) + ")"; } inline bool operator==(const RectF& r1, const RectF& r2) { return IsScalarAlmostEqual(r1.left_, r2.left_) && IsScalarAlmostEqual(r1.right_, r2.right_) && IsScalarAlmostEqual(r1.top_, r2.top_) && IsScalarAlmostEqual(r1.bottom_, r2.bottom_); } inline bool operator!=(const RectF& r1, const RectF& r2) { return !IsScalarAlmostEqual(r1.left_, r2.left_) || !IsScalarAlmostEqual(r1.right_, r2.right_) || !IsScalarAlmostEqual(r1.top_, r2.top_) || !IsScalarAlmostEqual(r1.bottom_, r2.bottom_); } } // namespace Drawing } // namespace Rosen } // namespace OHOS #endif