Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrStyledShape.h
Go to the documentation of this file.
1/*
2 * Copyright 2016 Google Inc.
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 GrStyledShape_DEFINED
9#define GrStyledShape_DEFINED
10
11#include "include/core/SkPath.h"
14#include "include/core/SkRect.h"
19#include "src/base/SkTLazy.h"
21#include "src/core/SkPathPriv.h"
24
25#include <cstdint>
26
28class SkPaint;
29struct SkPoint;
30
31/**
32 * Represents a geometric shape (rrect or path) and the GrStyle that it should be rendered with.
33 * It is possible to apply the style to the GrStyledShape to produce a new GrStyledShape where the
34 * geometry reflects the styling information (e.g. is stroked). It is also possible to apply just
35 * the path effect from the style. In this case the resulting shape will include any remaining
36 * stroking information that is to be applied after the path effect.
37 *
38 * Shapes can produce keys that represent only the geometry information, not the style. Note that
39 * when styling information is applied to produce a new shape then the style has been converted
40 * to geometric information and is included in the new shape's key. When the same style is applied
41 * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes
42 * will be the same.
43 *
44 * Currently this can only be constructed from a path, rect, or rrect though it can become a path
45 * applying style to the geometry. The idea is to expand this to cover most or all of the geometries
46 * that have fast paths in the GPU backend.
47 */
49public:
50 // Keys for paths may be extracted from the path data for small paths. Clients aren't supposed
51 // to have to worry about this. This value is exposed for unit tests.
52 inline static constexpr int kMaxKeyFromDataVerbCnt = 10;
53
55
56 enum class DoSimplify : bool { kNo = false, kYes };
57
58 explicit GrStyledShape(const SkPath& path, DoSimplify doSimplify = DoSimplify::kYes)
59 : GrStyledShape(path, GrStyle::SimpleFill(), doSimplify) {}
60
61 explicit GrStyledShape(const SkRRect& rrect, DoSimplify doSimplify = DoSimplify::kYes)
62 : GrStyledShape(rrect, GrStyle::SimpleFill(), doSimplify) {}
63
64 explicit GrStyledShape(const SkRect& rect, DoSimplify doSimplify = DoSimplify::kYes)
65 : GrStyledShape(rect, GrStyle::SimpleFill(), doSimplify) {}
66
67 GrStyledShape(const SkPath& path, const SkPaint& paint,
68 DoSimplify doSimplify = DoSimplify::kYes)
69 : GrStyledShape(path, GrStyle(paint), doSimplify) {}
70
71 GrStyledShape(const SkRRect& rrect, const SkPaint& paint,
72 DoSimplify doSimplify = DoSimplify::kYes)
73 : GrStyledShape(rrect, GrStyle(paint), doSimplify) {}
74
75 GrStyledShape(const SkRect& rect, const SkPaint& paint,
76 DoSimplify doSimplify = DoSimplify::kYes)
77 : GrStyledShape(rect, GrStyle(paint), doSimplify) {}
78
79 GrStyledShape(const SkPath& path, const GrStyle& style,
80 DoSimplify doSimplify = DoSimplify::kYes)
81 : fShape(path), fStyle(style) {
82 if (doSimplify == DoSimplify::kYes) {
83 this->simplify();
84 }
85 }
86
87 GrStyledShape(const SkRRect& rrect, const GrStyle& style,
88 DoSimplify doSimplify = DoSimplify::kYes)
89 // Preserve legacy indices (6 for CW), see SkPathBuilder::addRRect().
90 : GrStyledShape(rrect, SkPathDirection::kCW, 6, false, style, doSimplify) {}
91
92 GrStyledShape(const SkRRect& rrect, SkPathDirection dir, unsigned start, bool inverted,
93 const GrStyle& style, DoSimplify doSimplify = DoSimplify::kYes)
94 : fShape(rrect)
95 , fStyle(style) {
96 fShape.setPathWindingParams(dir, start);
97 fShape.setInverted(inverted);
98 if (doSimplify == DoSimplify::kYes) {
99 this->simplify();
100 }
101 }
102
103 GrStyledShape(const SkRect& rect, const GrStyle& style,
104 DoSimplify doSimplify = DoSimplify::kYes)
105 : fShape(rect), fStyle(style) {
106 if (doSimplify == DoSimplify::kYes) {
107 this->simplify();
108 }
109 }
110
112
113 static GrStyledShape MakeArc(const SkRect& oval, SkScalar startAngleDegrees,
114 SkScalar sweepAngleDegrees, bool useCenter, const GrStyle& style,
116
118
119 /**
120 * Informs MakeFilled on how to modify that shape's fill rule when making a simple filled
121 * version of the shape.
122 */
123 enum class FillInversion {
124 kPreserve,
125 kFlip,
128 };
129 /**
130 * Makes a filled shape from the pre-styled original shape and optionally modifies whether
131 * the fill is inverted or not. It's important to note that the original shape's geometry
132 * may already have been modified if doing so was neutral with respect to its style
133 * (e.g. filled paths are always closed when stored in a shape and dashed paths are always
134 * made non-inverted since dashing ignores inverseness).
135 */
136 static GrStyledShape MakeFilled(const GrStyledShape& original,
138
139 const GrStyle& style() const { return fStyle; }
140
141 // True if the shape and/or style were modified into a simpler, equivalent pairing
142 bool simplified() const { return fSimplified; }
143
144 /**
145 * Returns a shape that has either applied the path effect or path effect and stroking
146 * information from this shape's style to its geometry. Scale is used when approximating the
147 * output geometry and typically is computed from the view matrix
148 */
152
153 bool isRect() const {
154 // Should have simplified a rrect to a rect if possible already.
155 SkASSERT(!fShape.isRRect() || !fShape.rrect().isRect());
156 return fShape.isRect();
157 }
158
159 /** Returns the unstyled geometry as a rrect if possible. */
160 bool asRRect(SkRRect* rrect, SkPathDirection* dir, unsigned* start, bool* inverted) const;
161
162 /**
163 * If the unstyled shape is a straight line segment, returns true and sets pts to the endpoints.
164 * An inverse filled line path is still considered a line.
165 */
166 bool asLine(SkPoint pts[2], bool* inverted) const;
167
168 // Can this shape be drawn as a pair of filled nested rectangles?
169 bool asNestedRects(SkRect rects[2]) const;
170
171 /** Returns the unstyled geometry as a path. */
172 void asPath(SkPath* out) const {
173 fShape.asPath(out, fStyle.isSimpleFill());
174 }
175
176 /**
177 * Returns whether the geometry is empty. Note that applying the style could produce a
178 * non-empty shape. It also may have an inverse fill.
179 */
180 bool isEmpty() const { return fShape.isEmpty(); }
181
182 /**
183 * Gets the bounds of the geometry without reflecting the shape's styling. This ignores
184 * the inverse fill nature of the geometry.
185 */
186 SkRect bounds() const { return fShape.bounds(); }
187
188 /**
189 * Gets the bounds of the geometry reflecting the shape's styling (ignoring inverse fill
190 * status).
191 */
192 SkRect styledBounds() const;
193
194 /**
195 * Is this shape known to be convex, before styling is applied. An unclosed but otherwise
196 * convex path is considered to be closed if they styling reflects a fill and not otherwise.
197 * This is because filling closes all contours in the path.
198 */
199 bool knownToBeConvex() const {
200 return fShape.convex(fStyle.isSimpleFill());
201 }
202
203 /**
204 * Does the shape have a known winding direction. Some degenerate convex shapes may not have
205 * a computable direction, but this is not always a requirement for path renderers so it is
206 * kept separate from knownToBeConvex().
207 */
208 bool knownDirection() const {
209 // Assuming this is called after knownToBeConvex(), this should just be relying on
210 // cached convexity and direction and will be cheap.
211 return !fShape.isPath() ||
213 }
214
215 /** Is the pre-styled geometry inverse filled? */
216 bool inverseFilled() const {
217 // Since the path tracks inverted-fillness itself, it should match what was recorded.
218 SkASSERT(!fShape.isPath() || fShape.inverted() == fShape.path().isInverseFillType());
219 // Dashing ignores inverseness. We should have caught this earlier. skbug.com/5421
220 SkASSERT(!(fShape.inverted() && this->style().isDashed()));
221 return fShape.inverted();
222 }
223
224 /**
225 * Might applying the styling to the geometry produce an inverse fill. The "may" part comes in
226 * because an arbitrary path effect could produce an inverse filled path. In other cases this
227 * can be thought of as "inverseFilledAfterStyling()".
228 */
230 // An arbitrary path effect can produce an arbitrary output path, which may be inverse
231 // filled.
232 if (this->style().hasNonDashPathEffect()) {
233 return true;
234 }
235 return this->inverseFilled();
236 }
237
238 /**
239 * Is it known that the unstyled geometry has no unclosed contours. This means that it will
240 * not have any caps if stroked (modulo the effect of any path effect).
241 */
242 bool knownToBeClosed() const {
243 // This refers to the base shape and does not depend on invertedness.
244 return fShape.closed();
245 }
246
247 uint32_t segmentMask() const {
248 // This refers to the base shape and does not depend on invertedness.
249 return fShape.segmentMask();
250 }
251
252 /**
253 * Gets the size of the key for the shape represented by this GrStyledShape (ignoring its
254 * styling). A negative value is returned if the shape has no key (shouldn't be cached).
255 */
256 int unstyledKeySize() const;
257
258 bool hasUnstyledKey() const { return this->unstyledKeySize() >= 0; }
259
260 /**
261 * Writes unstyledKeySize() bytes into the provided pointer. Assumes that there is enough
262 * space allocated for the key and that unstyledKeySize() does not return a negative value
263 * for this shape.
264 */
265 void writeUnstyledKey(uint32_t* key) const;
266
267 /**
268 * Adds a listener to the *original* path. Typically used to invalidate cached resources when
269 * a path is no longer in-use. If the shape started out as something other than a path, this
270 * does nothing.
271 */
273
274 /**
275 * Helpers that are only exposed for unit tests, to determine if the shape is a path, and get
276 * the generation ID of the *original* path. This is the path that will receive
277 * GenIDChangeListeners added to this shape.
278 */
280 bool testingOnly_isPath() const;
282
283 /**
284 * Similar to GrShape::simplify but also takes into account style and stroking, possibly
285 * applying the style explicitly to produce a new analytic shape with a simpler style.
286 * Unless "doSimplify" is kNo, this method gets called automatically during construction.
287 */
288 void simplify();
289
290private:
291 /** Constructor used by the applyStyle() function */
293
294 /**
295 * Determines the key we should inherit from the input shape's geometry and style when
296 * we are applying the style to create a new shape.
297 */
298 void setInheritedKey(const GrStyledShape& parentShape, GrStyle::Apply, SkScalar scale);
299
300 /**
301 * As part of the simplification process, some shapes can have stroking trivially evaluated
302 * and form a new geometry with just a fill.
303 */
304 void simplifyStroke();
305
306 /** Gets the path that gen id listeners should be added to. */
307 const SkPath* originalPathForListeners() const;
308
309 GrShape fShape;
310 GrStyle fStyle;
311 // Gen ID of the original path (path may be modified or simplified away).
312 int32_t fGenID = 0;
313 bool fClosed = false;
314 bool fSimplified = false;
315
316 SkTLazy<SkPath> fInheritedPathForListeners;
318};
319#endif
#define SkASSERT(cond)
Definition SkAssert.h:116
SkPathDirection
Definition SkPathTypes.h:34
static bool apply(Pass *pass, SkRecord *record)
bool closed() const
Definition GrShape.cpp:328
bool isPath() const
Definition GrShape.h:88
uint32_t segmentMask() const
Definition GrShape.cpp:391
bool isRRect() const
Definition GrShape.h:87
SkPath & path()
Definition GrShape.h:140
SkRRect & rrect()
Definition GrShape.h:137
bool isRect() const
Definition GrShape.h:86
SkRect bounds() const
Definition GrShape.cpp:365
void setPathWindingParams(SkPathDirection dir, unsigned start)
Definition GrShape.h:112
bool inverted() const
Definition GrShape.h:99
void setInverted(bool inverted)
Definition GrShape.h:119
void asPath(SkPath *out, bool simpleFill=true) const
Definition GrShape.cpp:421
bool convex(bool simpleFill=true) const
Definition GrShape.cpp:346
bool isEmpty() const
Definition GrShape.h:84
bool isSimpleFill() const
Definition GrStyle.h:114
bool knownToBeClosed() const
void asPath(SkPath *out) const
void writeUnstyledKey(uint32_t *key) const
bool isEmpty() const
GrStyledShape(const SkPath &path, const SkPaint &paint, DoSimplify doSimplify=DoSimplify::kYes)
int unstyledKeySize() const
bool asLine(SkPoint pts[2], bool *inverted) const
bool simplified() const
GrStyledShape(const SkRect &rect, const GrStyle &style, DoSimplify doSimplify=DoSimplify::kYes)
GrStyledShape(const SkRRect &rrect, const SkPaint &paint, DoSimplify doSimplify=DoSimplify::kYes)
GrStyledShape(const SkRect &rect, const SkPaint &paint, DoSimplify doSimplify=DoSimplify::kYes)
GrStyledShape(const SkRRect &rrect, SkPathDirection dir, unsigned start, bool inverted, const GrStyle &style, DoSimplify doSimplify=DoSimplify::kYes)
bool knownDirection() const
bool knownToBeConvex() const
bool hasUnstyledKey() const
bool inverseFilled() const
const GrStyle & style() const
GrStyledShape(const SkPath &path, DoSimplify doSimplify=DoSimplify::kYes)
GrStyledShape(const SkRRect &rrect, DoSimplify doSimplify=DoSimplify::kYes)
static GrStyledShape MakeArc(const SkRect &oval, SkScalar startAngleDegrees, SkScalar sweepAngleDegrees, bool useCenter, const GrStyle &style, DoSimplify=DoSimplify::kYes)
GrStyledShape(const SkPath &path, const GrStyle &style, DoSimplify doSimplify=DoSimplify::kYes)
SkRect styledBounds() const
SkRect bounds() const
bool asNestedRects(SkRect rects[2]) const
void addGenIDChangeListener(sk_sp< SkIDChangeListener >) const
GrStyledShape(const SkRRect &rrect, const GrStyle &style, DoSimplify doSimplify=DoSimplify::kYes)
bool mayBeInverseFilledAfterStyling() const
bool testingOnly_isPath() const
bool testingOnly_isNonVolatilePath() const
uint32_t segmentMask() const
static constexpr int kMaxKeyFromDataVerbCnt
uint32_t testingOnly_getOriginalGenerationID() const
bool isRect() const
static GrStyledShape MakeFilled(const GrStyledShape &original, FillInversion=FillInversion::kPreserve)
GrStyledShape applyStyle(GrStyle::Apply apply, SkScalar scale) const
GrStyledShape & operator=(const GrStyledShape &that)
bool asRRect(SkRRect *rrect, SkPathDirection *dir, unsigned *start, bool *inverted) const
GrStyledShape(const SkRect &rect, DoSimplify doSimplify=DoSimplify::kYes)
static SkPathFirstDirection ComputeFirstDirection(const SkPath &)
Definition SkPath.cpp:2563
bool isInverseFillType() const
Definition SkPath.h:244
bool isRect() const
Definition SkRRect.h:84
const Paint & paint
float SkScalar
Definition extension.cpp:12
const Scalar scale