Flutter Engine
The Flutter Engine
GrShape.h
Go to the documentation of this file.
1/*
2 * Copyright 2020 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrShape_DEFINED
9#define GrShape_DEFINED
10
11#include "include/core/SkArc.h"
12#include "include/core/SkPath.h"
16#include "include/core/SkRect.h"
20
21#include <cstdint>
22#include <new>
23#include <type_traits>
24
25// Represents a line segment between two points.
29};
30
31/**
32 * GrShape is a convenience class to represent the many different specialized geometries that
33 * Ganesh can handle, including rects, round rects, lines, as well as paths. It is intended as
34 * a data-only class where any additional complex behavior is handled by an owning type (e.g.
35 * GrStyledShape). However, it does include some basic utilities that unify common functionality
36 * (such as contains()) from the underlying shape types.
37 *
38 * In order to have lossless simplification of the geometry, it also tracks winding direction, start
39 * index, and fill inversion. The direction and index are match the SkPath indexing scheme for
40 * the shape's type (e.g. rect, rrect, or oval).
41 *
42 * Regarding GrShape's empty shape:
43 * - GrShape uses empty to refer to the absence of any geometric data
44 * - SkRect::isEmpty() returns true if the rect is not sorted, even if it has area. GrShape will not
45 * simplify these shapes to an empty GrShape. Rects with actual 0 width and height will simplify
46 * to a point or line, not empty. This is to preserve geometric data for path effects and strokes.
47 * - SkRRect::isEmpty() is true when the bounds have 0 width or height, so GrShape will simplify it
48 * to a point or line, just like a rect. SkRRect does not have the concept of unsorted edges.
49 */
50class GrShape {
51public:
52 // The current set of types GrShape can represent directly
53 enum class Type : uint8_t {
54 kEmpty, kPoint, kRect, kRRect, kPath, kArc, kLine
55 };
56 inline static constexpr int kTypeCount = static_cast<int>(Type::kLine) + 1;
57
58 // The direction and start index used when a shape does not have a representable winding,
59 // or when that information was discarded during simplification (kIgnoreWinding_Flag).
61 inline static constexpr unsigned kDefaultStart = 0;
62 // The fill rule that is used by asPath() for shapes that aren't already a path.
64
66 explicit GrShape(const SkPoint& point) { this->setPoint(point); }
67 explicit GrShape(const SkRect& rect) { this->setRect(rect); }
68 explicit GrShape(const SkRRect& rrect) { this->setRRect(rrect); }
69 explicit GrShape(const SkPath& path) { this->setPath(path); }
70 explicit GrShape(const SkArc& arc) { this->setArc(arc); }
71 explicit GrShape(const GrLineSegment& line){ this->setLine(line); }
72
73 GrShape(const GrShape& shape) { *this = shape; }
74
75 ~GrShape() { this->reset(); }
76
77 // NOTE: None of the geometry types benefit from move semantics, so we don't bother
78 // defining a move assignment operator for GrShape.
79 GrShape& operator=(const GrShape& shape);
80
81 // These type queries reflect the shape type provided when assigned, it does not incorporate
82 // any potential simplification (e.g. if isRRect() is true and rrect().isRect() is true,
83 // isRect() will still be false, until simplify() is called).
84 bool isEmpty() const { return this->type() == Type::kEmpty; }
85 bool isPoint() const { return this->type() == Type::kPoint; }
86 bool isRect() const { return this->type() == Type::kRect; }
87 bool isRRect() const { return this->type() == Type::kRRect; }
88 bool isPath() const { return this->type() == Type::kPath; }
89 bool isArc() const { return this->type() == Type::kArc; }
90 bool isLine() const { return this->type() == Type::kLine; }
91
92 Type type() const { return fType; }
93
94 // Report the shape type, winding direction, start index, and invertedness as a value suitable
95 // for use in a resource key. This does not include any geometry coordinates into the key value.
96 uint32_t stateKey() const;
97
98 // Whether or not the shape is meant to be the inverse of its geometry (i.e. its exterior).
99 bool inverted() const {
100 return this->isPath() ? fPath.isInverseFillType() : SkToBool(fInverted);
101 }
102
103 // Returns the path direction extracted from the path during simplification, if the shape's
104 // type represents a rrect, rect, or oval.
106 // Returns the start index extracted from the path during simplification, if the shape's
107 // type represents a rrect, rect, or oval.
108 unsigned startIndex() const { return fStart; }
109
110 // Override the direction and start parameters for the simplified contour. These are only
111 // meaningful for rects, rrects, and ovals.
113 SkASSERT((this->isRect() && start < 4) || (this->isRRect() && start < 8) ||
115 fCW = dir == SkPathDirection::kCW;
116 fStart = static_cast<uint8_t>(start);
117 }
118
120 if (this->isPath()) {
121 if (inverted != fPath.isInverseFillType()) {
123 }
124 } else {
125 fInverted = inverted;
126 }
127 }
128
129 // Access the actual geometric description of the shape. May only access the appropriate type
130 // based on what was last set. The type may change after simplify() is called.
131 SkPoint& point() { SkASSERT(this->isPoint()); return fPoint; }
132 const SkPoint& point() const { SkASSERT(this->isPoint()); return fPoint; }
133
134 SkRect& rect() { SkASSERT(this->isRect()); return fRect; }
135 const SkRect& rect() const { SkASSERT(this->isRect()); return fRect; }
136
137 SkRRect& rrect() { SkASSERT(this->isRRect()); return fRRect; }
138 const SkRRect& rrect() const { SkASSERT(this->isRRect()); return fRRect; }
139
140 SkPath& path() { SkASSERT(this->isPath()); return fPath; }
141 const SkPath& path() const { SkASSERT(this->isPath()); return fPath; }
142
143 SkArc& arc() { SkASSERT(this->isArc()); return fArc; }
144 const SkArc& arc() const { SkASSERT(this->isArc()); return fArc; }
145
146 GrLineSegment& line() { SkASSERT(this->isLine()); return fLine; }
147 const GrLineSegment& line() const { SkASSERT(this->isLine()); return fLine; }
148
149 // Update the geometry stored in the GrShape and update its associated type to match. This
150 // performs no simplification, so calling setRRect() with a round rect that has isRect() return
151 // true will still be considered an rrect by this shape until simplify() is called.
152 //
153 // These also reset any extracted direction, start, and inverted state from a prior simplified
154 // path, since these functions ared used to describe a new geometry.
155 void setPoint(const SkPoint& point) {
156 this->reset(Type::kPoint);
157 fPoint = point;
158 }
159 void setRect(const SkRect& rect) {
160 this->reset(Type::kRect);
161 fRect = rect;
162 }
163 void setRRect(const SkRRect& rrect) {
164 this->reset(Type::kRRect);
165 fRRect = rrect;
166 }
167 void setArc(const SkArc& arc) {
168 this->reset(Type::kArc);
169 fArc = arc;
170 }
172 this->reset(Type::kLine);
173 fLine = line;
174 }
175 void setPath(const SkPath& path) {
176 if (this->isPath()) {
177 // Assign directly
178 fPath = path;
179 } else {
180 // In-place initialize
181 this->setType(Type::kPath);
182 new (&fPath) SkPath(path);
183 }
184 // Must also set these since we didn't call reset() like other setX functions.
185 this->setPathWindingParams(kDefaultDir, kDefaultStart);
186 fInverted = path.isInverseFillType();
187 }
188 void reset() {
189 this->reset(Type::kEmpty);
190 }
191
192 // Flags that enable more aggressive, "destructive" simplifications to the geometry
193 enum SimplifyFlags : unsigned {
194 // If set, it is assumed the original shape would have been implicitly filled when drawn or
195 // clipped, so simpler shape types that are closed can still be considered. Shapes with
196 // 0 area (i.e. points and lines) can be turned into empty.
198 // If set, simplifications that would impact a directional stroke or path effect can still
199 // be taken (e.g. dir and start are not required, arcs can be converted to ovals).
201 // If set, the geometry will be updated to have sorted coordinates (rects, lines), modulated
202 // sweep angles (arcs).
204
205 kAll_Flags = 0b111
206 };
207 // Returns true if the shape was originally closed based on type (or detected type within a
208 // path), even if the final simplification results in a point, line, or empty.
209 bool simplify(unsigned flags = kAll_Flags);
210
211 // True if the given bounding box is completely inside the shape, if it's conservatively treated
212 // as a filled, closed shape.
213 bool conservativeContains(const SkRect& rect) const;
214 bool conservativeContains(const SkPoint& point) const;
215
216 // True if the underlying geometry represents a closed shape, without the need for an
217 // implicit close (note that if simplified earlier with 'simpleFill' = true, a shape that was
218 // not closed may become closed).
219 bool closed() const;
220
221 // True if the underlying shape is known to be convex, assuming no other styles. If 'simpleFill'
222 // is true, it is assumed the contours will be implicitly closed when drawn or used.
223 bool convex(bool simpleFill = true) const;
224
225 // The bounding box of the shape.
226 SkRect bounds() const;
227
228 // The segment masks that describe the shape, were it to be converted to an SkPath
229 uint32_t segmentMask() const;
230
231 // Convert the shape into a path that describes the same geometry.
232 void asPath(SkPath* out, bool simpleFill = true) const;
233
234 using sk_is_trivially_relocatable = std::true_type;
235
236private:
237
238 void setType(Type type) {
239 if (this->isPath() && type != Type::kPath) {
240 fInverted = fPath.isInverseFillType();
241 fPath.~SkPath();
242 }
243 fType = type;
244 }
245
246 void reset(Type type) {
247 this->setType(type);
248 this->setPathWindingParams(kDefaultDir, kDefaultStart);
249 this->setInverted(false);
250 }
251
252 // Paths and arcs are root shapes, another type will never simplify to them, so they do
253 // not take the geometry to simplify as an argument. Since they are root shapes, they also
254 // return whether or not they were originally closed before being simplified.
255 bool simplifyPath(unsigned flags);
256 bool simplifyArc(unsigned flags);
257
258 // The simpler type classes do take the geometry because it may represent an in-progress
259 // simplification that hasn't been set on the GrShape yet. The simpler types do not report
260 // whether or not they were closed because it's implicit in their type.
261 void simplifyLine(const SkPoint& p1, const SkPoint& p2, unsigned flags);
262 void simplifyPoint(const SkPoint& point, unsigned flags);
263
264 // RRects and rects care about winding for path effects and will set the path winding state
265 // of the shape as well.
266 void simplifyRRect(const SkRRect& rrect, SkPathDirection dir, unsigned start, unsigned flags);
267 void simplifyRect(const SkRect& rect, SkPathDirection dir, unsigned start, unsigned flags);
268
269 union {
276 };
277
278 Type fType = Type::kEmpty;
279 uint8_t fStart; // Restricted to rrects and simpler, so this will be < 8
280 bool fCW;
281 bool fInverted;
282
283 static_assert(::sk_is_trivially_relocatable<decltype(fPoint)>::value);
284 static_assert(::sk_is_trivially_relocatable<decltype(fRect)>::value);
285 static_assert(::sk_is_trivially_relocatable<decltype(fRRect)>::value);
286 static_assert(::sk_is_trivially_relocatable<decltype(fPath)>::value);
287 static_assert(::sk_is_trivially_relocatable<decltype(fArc)>::value);
288 static_assert(::sk_is_trivially_relocatable<decltype(fLine)>::value);
289 static_assert(::sk_is_trivially_relocatable<decltype(fType)>::value);
290};
291
292#endif
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkPathDirection
Definition: SkPathTypes.h:34
SkPathFillType
Definition: SkPathTypes.h:11
@ kRRect
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
bool closed() const
Definition: GrShape.cpp:330
SkRRect fRRect
Definition: GrShape.h:272
GrShape & operator=(const GrShape &shape)
Definition: GrShape.cpp:17
SkRect & rect()
Definition: GrShape.h:134
const SkRect & rect() const
Definition: GrShape.h:135
GrLineSegment fLine
Definition: GrShape.h:275
Type type() const
Definition: GrShape.h:92
uint32_t stateKey() const
Definition: GrShape.cpp:49
bool isPath() const
Definition: GrShape.h:88
void setRRect(const SkRRect &rrect)
Definition: GrShape.h:163
uint32_t segmentMask() const
Definition: GrShape.cpp:393
void reset()
Definition: GrShape.h:188
std::true_type sk_is_trivially_relocatable
Definition: GrShape.h:234
GrShape(const SkPath &path)
Definition: GrShape.h:69
bool isRRect() const
Definition: GrShape.h:87
static constexpr int kTypeCount
Definition: GrShape.h:56
SkPath & path()
Definition: GrShape.h:140
bool isLine() const
Definition: GrShape.h:90
SkRRect & rrect()
Definition: GrShape.h:137
bool isRect() const
Definition: GrShape.h:86
GrLineSegment & line()
Definition: GrShape.h:146
GrShape(const SkPoint &point)
Definition: GrShape.h:66
void setPath(const SkPath &path)
Definition: GrShape.h:175
SkRect bounds() const
Definition: GrShape.cpp:367
const GrLineSegment & line() const
Definition: GrShape.h:147
void setLine(const GrLineSegment &line)
Definition: GrShape.h:171
SimplifyFlags
Definition: GrShape.h:193
@ kMakeCanonical_Flag
Definition: GrShape.h:203
@ kIgnoreWinding_Flag
Definition: GrShape.h:200
@ kSimpleFill_Flag
Definition: GrShape.h:197
@ kAll_Flags
Definition: GrShape.h:205
GrShape(const SkRRect &rrect)
Definition: GrShape.h:68
bool isPoint() const
Definition: GrShape.h:85
SkRect fRect
Definition: GrShape.h:271
SkArc & arc()
Definition: GrShape.h:143
SkPath fPath
Definition: GrShape.h:273
void setPathWindingParams(SkPathDirection dir, unsigned start)
Definition: GrShape.h:112
bool inverted() const
Definition: GrShape.h:99
SkArc fArc
Definition: GrShape.h:274
~GrShape()
Definition: GrShape.h:75
SkPathDirection dir() const
Definition: GrShape.h:105
static constexpr SkPathDirection kDefaultDir
Definition: GrShape.h:60
static constexpr SkPathFillType kDefaultFillType
Definition: GrShape.h:63
bool isArc() const
Definition: GrShape.h:89
void setInverted(bool inverted)
Definition: GrShape.h:119
void setArc(const SkArc &arc)
Definition: GrShape.h:167
const SkPath & path() const
Definition: GrShape.h:141
bool conservativeContains(const SkRect &rect) const
Definition: GrShape.cpp:289
SkPoint fPoint
Definition: GrShape.h:270
GrShape()
Definition: GrShape.h:65
unsigned startIndex() const
Definition: GrShape.h:108
const SkPoint & point() const
Definition: GrShape.h:132
const SkArc & arc() const
Definition: GrShape.h:144
static constexpr unsigned kDefaultStart
Definition: GrShape.h:61
const SkRRect & rrect() const
Definition: GrShape.h:138
void asPath(SkPath *out, bool simpleFill=true) const
Definition: GrShape.cpp:423
SkPoint & point()
Definition: GrShape.h:131
GrShape(const SkRect &rect)
Definition: GrShape.h:67
void setPoint(const SkPoint &point)
Definition: GrShape.h:155
GrShape(const SkArc &arc)
Definition: GrShape.h:70
GrShape(const GrLineSegment &line)
Definition: GrShape.h:71
GrShape(const GrShape &shape)
Definition: GrShape.h:73
bool convex(bool simpleFill=true) const
Definition: GrShape.cpp:348
bool isEmpty() const
Definition: GrShape.h:84
void setRect(const SkRect &rect)
Definition: GrShape.h:159
bool simplify(unsigned flags=kAll_Flags)
Definition: GrShape.cpp:244
Definition: SkPath.h:59
bool isInverseFillType() const
Definition: SkPath.h:244
void toggleInverseFillType()
Definition: SkPath.h:249
~SkPath()
Definition: SkPath.cpp:186
FlutterSemanticsFlag flags
uint8_t value
SkPoint fP2
Definition: GrShape.h:28
SkPoint fP1
Definition: GrShape.h:27
Definition: SkArc.h:15