| Flutter Impeller |

round_rect.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/impeller/geometry/round_rect.h"
6
7 namespace impeller {
8
9 RoundRect RoundRect::MakeRectRadii(const Rect& in_bounds,
10 const RoundingRadii& in_radii) {
11 if (!in_bounds.IsFinite()) {
12 return {};
13 }
14 Rect bounds = in_bounds.GetPositive();
15 // RoundingRadii::Scaled might return an empty radii if bounds or in_radii is
16 // empty, which is expected. Pass along the bounds even if the radii is empty
17 // as it would still have a valid location and/or 1-dimensional size which
18 // might appear when stroked
19 return RoundRect(bounds, in_radii.Scaled(bounds));
20 }
21
22 // Determine if p is inside the elliptical corner curve defined by the
23 // indicated corner point and the indicated radii.
24 // p - is the test point in absolute coordinates
25 // corner - is the location of the associated corner in absolute coordinates
26 // direction - is the sign of (corner - center), or the sign of coordinates
27 // as they move in the direction of the corner from inside the
28 // rect ((-1,-1) for the upper left corner for instance)
29 // radii - the non-negative X and Y size of the corner's radii.
30 static bool CornerContains(const Point& p,
31 const Point& corner,
32 const Point& direction,
33 const Size& radii) {
34 FML_DCHECK(radii.width >= 0.0f && radii.height >= 0.0f);
35 if (radii.IsEmpty()) {
36 // This corner is not curved, therefore the containment is the same as
37 // the previously checked bounds containment.
38 return true;
39 }
40
41 // The positive X,Y distance between the corner and the point.
42 Point corner_relative = (corner - p) * direction;
43
44 // The distance from the "center" of the corner's elliptical curve.
45 // If both numbers are positive then we need to do an elliptical distance
46 // check to determine if it is inside the curve.
47 // If either number is negative, then the point is outside this quadrant
48 // and is governed by inclusion in the bounds and inclusion within other
49 // corners of this round rect. In that case, we return true here to allow
50 // further evaluation within other quadrants.
51 Point quadrant_relative = radii - corner_relative;
52 if (quadrant_relative.x <= 0.0f || quadrant_relative.y <= 0.0f) {
53 // Not within the curved quadrant of this corner, therefore "inside"
54 // relative to this one corner.
55 return true;
56 }
57
58 // Dividing the quadrant_relative point by the radii gives a corresponding
59 // location within a unit circle which can be more easily tested for
60 // containment. We can use x^2 + y^2 and compare it against the radius
61 // squared (1.0) to avoid the sqrt.
62 Point quadrant_unit_circle_point = quadrant_relative / radii;
63 return quadrant_unit_circle_point.GetLengthSquared() <= 1.0;
64 }
65
66 // The sign of the direction that points move as they approach the indicated
67 // corner from within the rectangle.
68 static constexpr Point kUpperLeftDirection(-1.0f, -1.0f);
69 static constexpr Point kUpperRightDirection(1.0f, -1.0f);
70 static constexpr Point kLowerLeftDirection(-1.0f, 1.0f);
71 static constexpr Point kLowerRightDirection(1.0f, 1.0f);
72
73 [[nodiscard]] bool RoundRect::Contains(const Point& p) const {
74 if (!bounds_.Contains(p)) {
75 return false;
76 }
77 if (!CornerContains(p, bounds_.GetLeftTop(), kUpperLeftDirection,
78 radii_.top_left) ||
79 !CornerContains(p, bounds_.GetRightTop(), kUpperRightDirection,
80 radii_.top_right) ||
81 !CornerContains(p, bounds_.GetLeftBottom(), kLowerLeftDirection,
82 radii_.bottom_left) ||
83 !CornerContains(p, bounds_.GetRightBottom(), kLowerRightDirection,
84 radii_.bottom_right)) {
85 return false;
86 }
87 return true;
88 }
89
90 void RoundRect::Dispatch(PathReceiver& receiver) const {
91 Scalar left = bounds_.GetLeft();
92 Scalar top = bounds_.GetTop();
93 Scalar right = bounds_.GetRight();
94 Scalar bottom = bounds_.GetBottom();
95
96 receiver.MoveTo(Point(left + radii_.top_left.width, top), true);
97 receiver.LineTo(Point(right - radii_.top_right.width, top));
98
99 receiver.ConicTo(Point(right, top),
100 Point(right, top + radii_.top_right.height), //
101 kSqrt2Over2);
102
103 receiver.LineTo(Point(right, bottom - radii_.bottom_right.height));
104
105 receiver.ConicTo(Point(right, bottom),
106 Point(right - radii_.bottom_right.width, bottom), //
107 kSqrt2Over2);
108
109 receiver.LineTo(Point(left + radii_.bottom_left.width, bottom));
110
111 receiver.ConicTo(Point(left, bottom),
112 Point(left, bottom - radii_.bottom_left.height), //
113 kSqrt2Over2);
114
115 receiver.LineTo(Point(left, top + radii_.top_left.height));
116
117 receiver.ConicTo(Point(left, top),
118 Point(left + radii_.top_left.width, top), //
119 kSqrt2Over2);
120
121 receiver.Close();
122 }
123
124 RoundRectPathSource::RoundRectPathSource(const RoundRect& round_rect)
125 : round_rect_(round_rect) {}
126
127 RoundRectPathSource::~RoundRectPathSource() = default;
128
129 FillType RoundRectPathSource::GetFillType() const {
130 return FillType::kNonZero;
131 }
132
133 Rect RoundRectPathSource::GetBounds() const {
134 return round_rect_.GetBounds();
135 }
136
137 bool RoundRectPathSource::IsConvex() const {
138 return true;
139 }
140
141 void RoundRectPathSource::Dispatch(PathReceiver& receiver) const {
142 round_rect_.Dispatch(receiver);
143 }
144
145 DiffRoundRectPathSource::DiffRoundRectPathSource(const RoundRect& outer,
146 const RoundRect& inner)
147 : outer_(outer), inner_(inner) {}
148
149 DiffRoundRectPathSource::~DiffRoundRectPathSource() = default;
150
151 FillType DiffRoundRectPathSource::GetFillType() const {
152 return FillType::kOdd;
153 }
154
155 Rect DiffRoundRectPathSource::GetBounds() const {
156 return outer_.GetBounds();
157 }
158
159 bool DiffRoundRectPathSource::IsConvex() const {
160 return false;
161 }
162
163 void DiffRoundRectPathSource::Dispatch(PathReceiver& receiver) const {
164 outer_.Dispatch(receiver);
165 inner_.Dispatch(receiver);
166 }
167
168 } // namespace impeller
impeller::DiffRoundRectPathSource::DiffRoundRectPathSource
DiffRoundRectPathSource(const RoundRect &outer, const RoundRect &inner)
Definition: round_rect.cc:145
impeller::DiffRoundRectPathSource::~DiffRoundRectPathSource
~DiffRoundRectPathSource()
impeller::DiffRoundRectPathSource::GetBounds
Rect GetBounds() const override
Definition: round_rect.cc:155
impeller::DiffRoundRectPathSource::IsConvex
bool IsConvex() const override
Definition: round_rect.cc:159
impeller::DiffRoundRectPathSource::Dispatch
void Dispatch(PathReceiver &receiver) const override
Definition: round_rect.cc:163
impeller::DiffRoundRectPathSource::GetFillType
FillType GetFillType() const override
Definition: round_rect.cc:151
impeller::PathReceiver
Collection of functions to receive path segments from the underlying path representation via the DlPa...
Definition: path_source.h:42
impeller::PathReceiver::LineTo
virtual void LineTo(const Point &p2)=0
impeller::PathReceiver::Close
virtual void Close()=0
impeller::PathReceiver::MoveTo
virtual void MoveTo(const Point &p2, bool will_be_closed)=0
impeller::PathReceiver::ConicTo
virtual bool ConicTo(const Point &cp, const Point &p2, Scalar weight)
Definition: path_source.h:48
impeller::RoundRectPathSource::~RoundRectPathSource
~RoundRectPathSource()
impeller::RoundRectPathSource::RoundRectPathSource
RoundRectPathSource(const RoundRect &round_rect)
Definition: round_rect.cc:124
impeller::RoundRectPathSource::GetBounds
Rect GetBounds() const override
Definition: round_rect.cc:133
impeller::RoundRectPathSource::IsConvex
bool IsConvex() const override
Definition: round_rect.cc:137
impeller::RoundRectPathSource::Dispatch
void Dispatch(PathReceiver &receiver) const override
Definition: round_rect.cc:141
impeller::RoundRectPathSource::GetFillType
FillType GetFillType() const override
Definition: round_rect.cc:129
impeller
Definition: allocation.cc:12
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::kSqrt2Over2
constexpr float kSqrt2Over2
Definition: constants.h:51
impeller::CornerContains
static bool CornerContains(const Point &p, const Point &corner, const Point &direction, const Size &radii)
Definition: round_rect.cc:30
impeller::FillType
FillType
Definition: path_source.h:13
impeller::FillType::kOdd
@ kOdd
impeller::FillType::kNonZero
@ kNonZero
impeller::Point
TPoint< Scalar > Point
Definition: point.h:425
impeller::kUpperLeftDirection
static constexpr Point kUpperLeftDirection(-1.0f, -1.0f)
impeller::kLowerRightDirection
static constexpr Point kLowerRightDirection(1.0f, 1.0f)
impeller::kUpperRightDirection
static constexpr Point kUpperRightDirection(1.0f, -1.0f)
impeller::kLowerLeftDirection
static constexpr Point kLowerLeftDirection(-1.0f, 1.0f)
round_rect.h
impeller::RoundRect
Definition: round_rect.h:16
impeller::RoundRect::MakeRectRadii
static RoundRect MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
Definition: round_rect.cc:9
impeller::RoundRect::RoundRect
RoundRect()=default
impeller::RoundRect::Contains
bool Contains(const Point &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
Definition: round_rect.cc:73
impeller::RoundRect::GetBounds
constexpr const Rect & GetBounds() const
Definition: round_rect.h:53
impeller::RoundingRadii
Definition: rounding_radii.h:14
impeller::RoundingRadii::top_right
Size top_right
Definition: rounding_radii.h:16
impeller::RoundingRadii::bottom_left
Size bottom_left
Definition: rounding_radii.h:17
impeller::RoundingRadii::bottom_right
Size bottom_right
Definition: rounding_radii.h:18
impeller::RoundingRadii::top_left
Size top_left
Definition: rounding_radii.h:15
impeller::RoundingRadii::Scaled
RoundingRadii Scaled(const Rect &bounds) const
Returns a scaled copy of this object, ensuring that the sum of the corner radii on each side does not...
Definition: rounding_radii.cc:26
impeller::TPoint< Scalar >
impeller::TPoint::GetLengthSquared
constexpr Type GetLengthSquared() const
Definition: point.h:205
impeller::TPoint::y
Type y
Definition: point.h:32
impeller::TPoint::x
Type x
Definition: point.h:31
impeller::TRect< Scalar >
impeller::TRect::GetBottom
constexpr auto GetBottom() const
Definition: rect.h:357
impeller::TRect::GetTop
constexpr auto GetTop() const
Definition: rect.h:353
impeller::TRect::Contains
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
Definition: rect.h:231
impeller::TRect::GetLeft
constexpr auto GetLeft() const
Definition: rect.h:351
impeller::TRect::GetPositive
constexpr TRect GetPositive() const
Get a version of this rectangle that has a non-negative size.
Definition: rect.h:398
impeller::TRect::GetRight
constexpr auto GetRight() const
Definition: rect.h:355
impeller::TRect::IsFinite
IsFinite() const
Returns true if all of the fields of this floating point rectangle are finite.
Definition: rect.h:288
impeller::TRect::GetLeftBottom
constexpr TPoint< T > GetLeftBottom() const
Definition: rect.h:367
impeller::TRect::GetRightTop
constexpr TPoint< T > GetRightTop() const
Definition: rect.h:363
impeller::TRect::GetRightBottom
constexpr TPoint< T > GetRightBottom() const
Definition: rect.h:371
impeller::TRect::GetLeftTop
constexpr TPoint< T > GetLeftTop() const
Definition: rect.h:359
impeller::TSize< Scalar >
impeller::TSize::height
Type height
Definition: size.h:29
impeller::TSize::width
Type width
Definition: size.h:28
impeller::TSize::IsEmpty
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: size.h:123