| // Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_H_ |
| #define FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_H_ |
| |
| #include "flutter/impeller/geometry/path_source.h" |
| #include "flutter/impeller/geometry/point.h" |
| #include "flutter/impeller/geometry/rect.h" |
| #include "flutter/impeller/geometry/rounding_radii.h" |
| #include "flutter/impeller/geometry/size.h" |
| |
| namespace impeller { |
| |
| struct RoundRect; |
| |
| struct RoundSuperellipse { |
| RoundSuperellipse() = default; |
| |
| inline static RoundSuperellipse MakeRect(const Rect& rect) { |
| return MakeRectRadii(rect, RoundingRadii()); |
| } |
| |
| inline static RoundSuperellipse MakeOval(const Rect& rect) { |
| return MakeRectRadii(rect, RoundingRadii::MakeRadii(rect.GetSize() * 0.5f)); |
| } |
| |
| inline static RoundSuperellipse MakeRectRadius(const Rect& rect, |
| Scalar radius) { |
| return MakeRectRadii(rect, RoundingRadii::MakeRadius(radius)); |
| } |
| |
| inline static RoundSuperellipse MakeRectXY(const Rect& rect, |
| Scalar x_radius, |
| Scalar y_radius) { |
| return MakeRectRadii(rect, |
| RoundingRadii::MakeRadii(Size(x_radius, y_radius))); |
| } |
| |
| inline static RoundSuperellipse MakeRectXY(const Rect& rect, |
| Size corner_radii) { |
| return MakeRectRadii(rect, RoundingRadii::MakeRadii(corner_radii)); |
| } |
| |
| static RoundSuperellipse MakeRectRadii(const Rect& rect, |
| const RoundingRadii& radii); |
| |
| constexpr const Rect& GetBounds() const { return bounds_; } |
| constexpr const RoundingRadii& GetRadii() const { return radii_; } |
| |
| [[nodiscard]] constexpr bool IsFinite() const { |
| return bounds_.IsFinite() && // |
| radii_.top_left.IsFinite() && // |
| radii_.top_right.IsFinite() && // |
| radii_.bottom_left.IsFinite() && // |
| radii_.bottom_right.IsFinite(); |
| } |
| |
| [[nodiscard]] constexpr bool IsEmpty() const { return bounds_.IsEmpty(); } |
| |
| [[nodiscard]] constexpr bool IsRect() const { |
| return !bounds_.IsEmpty() && radii_.AreAllCornersEmpty(); |
| } |
| |
| [[nodiscard]] constexpr bool IsOval() const { |
| return !bounds_.IsEmpty() && radii_.AreAllCornersSame() && |
| ScalarNearlyEqual(radii_.top_left.width, |
| bounds_.GetWidth() * 0.5f) && |
| ScalarNearlyEqual(radii_.top_left.height, |
| bounds_.GetHeight() * 0.5f); |
| } |
| |
| /// @brief Returns true iff the provided point |p| is inside the |
| /// half-open interior of this rectangle. |
| /// |
| /// For purposes of containment, a rectangle contains points |
| /// along the top and left edges but not points along the |
| /// right and bottom edges so that a point is only ever |
| /// considered inside one of two abutting rectangles. |
| [[nodiscard]] bool Contains(const Point& p) const; |
| |
| /// @brief Returns a new round rectangle translated by the given offset. |
| [[nodiscard]] inline RoundSuperellipse Shift(Scalar dx, Scalar dy) const { |
| // Just in case, use the factory rather than the internal constructor |
| // as shifting the rectangle may increase/decrease its bit precision |
| // so we should re-validate the radii to the newly located rectangle. |
| return MakeRectRadii(bounds_.Shift(dx, dy), radii_); |
| } |
| |
| /// @brief Returns a round rectangle with expanded edges. Negative expansion |
| /// results in shrinking. |
| [[nodiscard]] inline RoundSuperellipse Expand(Scalar left, |
| Scalar top, |
| Scalar right, |
| Scalar bottom) const { |
| // Use the factory rather than the internal constructor as the changing |
| // size of the rectangle requires that we re-validate the radii to the |
| // newly sized rectangle. |
| return MakeRectRadii(bounds_.Expand(left, top, right, bottom), radii_); |
| } |
| |
| /// @brief Returns a round rectangle with expanded edges. Negative expansion |
| /// results in shrinking. |
| [[nodiscard]] inline RoundSuperellipse Expand(Scalar horizontal, |
| Scalar vertical) const { |
| // Use the factory rather than the internal constructor as the changing |
| // size of the rectangle requires that we re-validate the radii to the |
| // newly sized rectangle. |
| return MakeRectRadii(bounds_.Expand(horizontal, vertical), radii_); |
| } |
| |
| /// @brief Returns a round rectangle with expanded edges. Negative expansion |
| /// results in shrinking. |
| [[nodiscard]] inline RoundSuperellipse Expand(Scalar amount) const { |
| // Use the factory rather than the internal constructor as the changing |
| // size of the rectangle requires that we re-validate the radii to the |
| // newly sized rectangle. |
| return MakeRectRadii(bounds_.Expand(amount), radii_); |
| } |
| |
| [[nodiscard]] constexpr bool operator==(const RoundSuperellipse& rr) const { |
| return bounds_ == rr.bounds_ && radii_ == rr.radii_; |
| } |
| |
| // Approximates a rounded superellipse with a round rectangle to the |
| // best practical accuracy. |
| // |
| // This is used for Skia backends, which does not support rounded |
| // superellipses directly, so rendering rounded superellipses |
| // falls back to RRect. |
| [[nodiscard]] RoundRect ToApproximateRoundRect() const; |
| |
| private: |
| constexpr RoundSuperellipse(const Rect& bounds, const RoundingRadii& radii) |
| : bounds_(bounds), radii_(radii) {} |
| |
| Rect bounds_; |
| RoundingRadii radii_; |
| }; |
| |
| class RoundSuperellipsePathSource : public PathSource { |
| public: |
| explicit RoundSuperellipsePathSource( |
| const RoundSuperellipse& round_superellipse); |
| |
| ~RoundSuperellipsePathSource(); |
| |
| const RoundSuperellipse& GetRoundSuperellipse() const { |
| return round_superellipse_; |
| } |
| |
| // |PathSource| |
| FillType GetFillType() const override; |
| |
| // |PathSource| |
| Rect GetBounds() const override; |
| |
| // |PathSource| |
| bool IsConvex() const override; |
| |
| // |PathSource| |
| void Dispatch(PathReceiver& receiver) const override; |
| |
| private: |
| const RoundSuperellipse round_superellipse_; |
| }; |
| |
| } // namespace impeller |
| |
| namespace std { |
| |
| inline std::ostream& operator<<(std::ostream& out, |
| const impeller::RoundSuperellipse& rr) { |
| out << "(" // |
| << "rect: " << rr.GetBounds() << ", " // |
| << "radii: " << rr.GetRadii(); |
| out << ")"; |
| return out; |
| } |
| |
| } // namespace std |
| |
| #endif // FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_H_ |