// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef UI_GFX_RRECT_F_H_ #define UI_GFX_RRECT_F_H_ #include #include #include "third_party/skia/include/core/SkRRect.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/gfx/skia_util.h" namespace gfx { class GEOMETRY_SKIA_EXPORT RRectF { public: RRectF() = default; ~RRectF() = default; RRectF(const RRectF& rect) = default; RRectF& operator=(const RRectF& rect) = default; explicit RRectF(const SkRRect& rect) : skrrect_(rect) {} explicit RRectF(const gfx::RectF& rect) : RRectF(rect, 0.f) {} RRectF(const gfx::RectF& rect, float radius) : RRectF(rect, radius, radius) {} RRectF(const gfx::RectF& rect, float x_rad, float y_rad) : RRectF(rect.x(), rect.y(), rect.width(), rect.height(), x_rad, y_rad) {} // Sets all x and y radii to radius. RRectF(float x, float y, float width, float height, float radius) : RRectF(x, y, width, height, radius, radius) {} // Sets all x radii to x_rad, and all y radii to y_rad. If one of x_rad or // y_rad are zero, sets ALL radii to zero. RRectF(float x, float y, float width, float height, float x_rad, float y_rad); // Directly sets all four corners. RRectF(float x, float y, float width, float height, float upper_left_x, float upper_left_y, float upper_right_x, float upper_right_y, float lower_right_x, float lower_right_y, float lower_left_x, float lower_left_y); RRectF(const gfx::RectF& rect, float upper_left_x, float upper_left_y, float upper_right_x, float upper_right_y, float lower_right_x, float lower_right_y, float lower_left_x, float lower_left_y) : RRectF(rect.x(), rect.y(), rect.width(), rect.height(), upper_left_x, upper_left_y, upper_right_x, upper_right_y, lower_right_x, lower_right_y, lower_left_x, lower_left_y) {} RRectF(const gfx::RectF& rect, const gfx::RoundedCornersF& corners) : RRectF(rect.x(), rect.y(), rect.width(), rect.height(), corners.upper_left(), corners.upper_left(), corners.upper_right(), corners.upper_right(), corners.lower_right(), corners.lower_right(), corners.lower_left(), corners.lower_left()) {} // The rectangular portion of the RRectF, without the corner radii. gfx::RectF rect() const { return gfx::SkRectToRectF(skrrect_.rect()); } // Returns the radii of the all corners. DCHECKs that all corners // have the same radii (the type is <= kOval). gfx::Vector2dF GetSimpleRadii() const; // Returns the radius of all corners. DCHECKs that all corners have the same // radii, and that x_rad == y_rad (the type is <= kSingle). float GetSimpleRadius() const; // Make the RRectF empty. void Clear() { skrrect_.setEmpty(); } bool Equals(const RRectF& other) const { return skrrect_ == other.skrrect_; } // These are all mutually exclusive, and ordered in increasing complexity. The // order is assumed in several functions. enum class Type { kEmpty, // Zero width or height. kRect, // Non-zero width and height, and zeroed radii - a pure rectangle. kSingle, // Non-zero width and height, and a single, non-zero value for all // X and Y radii. kSimple, // Non-zero width and height, X radii all equal and non-zero, Y // radii all equal and non-zero, and x_rad != y_rad. kOval, // Non-zero width and height, X radii all equal to width/2, and Y // radii all equal to height/2, and x_rad != y_rad. kComplex, // Non-zero width and height, and arbitrary (non-equal) radii. }; Type GetType() const; bool IsEmpty() const { return GetType() == Type::kEmpty; } // Enumeration of the corners of a rectangle in clockwise order. Values match // SkRRect::Corner. enum class Corner { kUpperLeft = SkRRect::kUpperLeft_Corner, kUpperRight = SkRRect::kUpperRight_Corner, kLowerRight = SkRRect::kLowerRight_Corner, kLowerLeft = SkRRect::kLowerLeft_Corner, }; // GetCornerRadii may be called for any type of RRect (kRect, kOval, etc.), // and it will return "correct" values. If GetType() is kOval or less, all // corner values will be identical to each other. SetCornerRadii can similarly // be called on any type of RRect, but GetType() may change as a result of the // call. gfx::Vector2dF GetCornerRadii(Corner corner) const; void SetCornerRadii(Corner corner, float x_rad, float y_rad); void SetCornerRadii(Corner corner, const gfx::Vector2dF& radii) { SetCornerRadii(corner, radii.x(), radii.y()); } // Returns true if |rect| is inside the bounds and corner radii of this // RRectF, and if both this RRectF and rect are not empty. bool Contains(const RectF& rect) const { return skrrect_.contains(gfx::RectFToSkRect(rect)); } // Scales the rectangle by |scale|. void Scale(float scale) { Scale(scale, scale); } // Scales the rectangle by |x_scale| and |y_scale|. void Scale(float x_scale, float y_scale); // Move the rectangle by a horizontal and vertical distance. void Offset(float horizontal, float vertical); void Offset(const Vector2dF& distance) { Offset(distance.x(), distance.y()); } const RRectF& operator+=(const gfx::Vector2dF& offset); const RRectF& operator-=(const gfx::Vector2dF& offset); std::string ToString() const; bool ApproximatelyEqual(const RRectF& rect, float tolerance) const; // Insets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may // be positive, negative, or zero. If either corner radius is zero, the corner // has no curvature and is unchanged. Otherwise, if adjusted radius becomes // negative, the radius is pinned to zero. void Inset(float val) { skrrect_.inset(val, val); } void Inset(float dx, float dy) { skrrect_.inset(dx, dy); } // Outsets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may // be positive, negative, or zero. If either corner radius is zero, the corner // has no curvature and is unchanged. Otherwise, if adjusted radius becomes // negative, the radius is pinned to zero. void Outset(float val) { skrrect_.outset(val, val); } void Outset(float dx, float dy) { skrrect_.outset(dx, dy); } explicit operator SkRRect() const { return skrrect_; } private: void GetAllRadii(SkVector radii[4]) const; SkRRect skrrect_; }; inline std::ostream& operator<<(std::ostream& os, const RRectF& rect) { return os << rect.ToString(); } inline bool operator==(const RRectF& a, const RRectF& b) { return a.Equals(b); } inline bool operator!=(const RRectF& a, const RRectF& b) { return !(a == b); } inline RRectF operator+(const RRectF& a, const gfx::Vector2dF& b) { RRectF result = a; result += b; return result; } inline RRectF operator-(const RRectF& a, const Vector2dF& b) { RRectF result = a; result -= b; return result; } } // namespace gfx #endif // UI_GFX_RRECT_F_H_