Flutter Engine
The Flutter Engine
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
27struct SkArc;
29class SkPaint;
30struct SkPoint;
31
32/**
33 * Represents a geometric shape (rrect or path) and the GrStyle that it should be rendered with.
34 * It is possible to apply the style to the GrStyledShape to produce a new GrStyledShape where the
35 * geometry reflects the styling information (e.g. is stroked). It is also possible to apply just
36 * the path effect from the style. In this case the resulting shape will include any remaining
37 * stroking information that is to be applied after the path effect.
38 *
39 * Shapes can produce keys that represent only the geometry information, not the style. Note that
40 * when styling information is applied to produce a new shape then the style has been converted
41 * to geometric information and is included in the new shape's key. When the same style is applied
42 * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes
43 * will be the same.
44 *
45 * Currently this can only be constructed from a path, rect, or rrect though it can become a path
46 * applying style to the geometry. The idea is to expand this to cover most or all of the geometries
47 * that have fast paths in the GPU backend.
48 */
50public:
51 // Keys for paths may be extracted from the path data for small paths. Clients aren't supposed
52 // to have to worry about this. This value is exposed for unit tests.
53 inline static constexpr int kMaxKeyFromDataVerbCnt = 10;
54
56
57 enum class DoSimplify : bool { kNo = false, kYes };
58
59 explicit GrStyledShape(const SkPath& path, DoSimplify doSimplify = DoSimplify::kYes)
60 : GrStyledShape(path, GrStyle::SimpleFill(), doSimplify) {}
61
62 explicit GrStyledShape(const SkRRect& rrect, DoSimplify doSimplify = DoSimplify::kYes)
63 : GrStyledShape(rrect, GrStyle::SimpleFill(), doSimplify) {}
64
65 explicit GrStyledShape(const SkRect& rect, DoSimplify doSimplify = DoSimplify::kYes)
66 : GrStyledShape(rect, GrStyle::SimpleFill(), doSimplify) {}
67
69 DoSimplify doSimplify = DoSimplify::kYes)
70 : GrStyledShape(path, GrStyle(paint), doSimplify) {}
71
73 DoSimplify doSimplify = DoSimplify::kYes)
74 : GrStyledShape(rrect, GrStyle(paint), doSimplify) {}
75
77 DoSimplify doSimplify = DoSimplify::kYes)
78 : GrStyledShape(rect, GrStyle(paint), doSimplify) {}
79
81 DoSimplify doSimplify = DoSimplify::kYes)
82 : fShape(path), fStyle(style) {
83 if (doSimplify == DoSimplify::kYes) {
84 this->simplify();
85 }
86 }
87
89 DoSimplify doSimplify = DoSimplify::kYes)
90 // Preserve legacy indices (6 for CW), see SkPathBuilder::addRRect().
91 : GrStyledShape(rrect, SkPathDirection::kCW, 6, false, style, doSimplify) {}
92
93 GrStyledShape(const SkRRect& rrect, SkPathDirection dir, unsigned start, bool inverted,
94 const GrStyle& style, DoSimplify doSimplify = DoSimplify::kYes)
95 : fShape(rrect)
96 , fStyle(style) {
98 fShape.setInverted(inverted);
99 if (doSimplify == DoSimplify::kYes) {
100 this->simplify();
101 }
102 }
103
105 DoSimplify doSimplify = DoSimplify::kYes)
106 : fShape(rect), fStyle(style) {
107 if (doSimplify == DoSimplify::kYes) {
108 this->simplify();
109 }
110 }
111
113
114 static GrStyledShape MakeArc(const SkArc& arc,
115 const GrStyle& style,
117
119
120 /**
121 * Informs MakeFilled on how to modify that shape's fill rule when making a simple filled
122 * version of the shape.
123 */
124 enum class FillInversion {
125 kPreserve,
126 kFlip,
127 kForceNoninverted,
128 kForceInverted
129 };
130 /**
131 * Makes a filled shape from the pre-styled original shape and optionally modifies whether
132 * the fill is inverted or not. It's important to note that the original shape's geometry
133 * may already have been modified if doing so was neutral with respect to its style
134 * (e.g. filled paths are always closed when stored in a shape and dashed paths are always
135 * made non-inverted since dashing ignores inverseness).
136 */
137 static GrStyledShape MakeFilled(const GrStyledShape& original,
139
140 const GrStyle& style() const { return fStyle; }
141
142 // True if the shape and/or style were modified into a simpler, equivalent pairing
143 bool simplified() const { return fSimplified; }
144
145 /**
146 * Returns a shape that has either applied the path effect or path effect and stroking
147 * information from this shape's style to its geometry. Scale is used when approximating the
148 * output geometry and typically is computed from the view matrix
149 */
151 return GrStyledShape(*this, apply, scale);
152 }
153
154 bool isRect() const {
155 // Should have simplified a rrect to a rect if possible already.
156 SkASSERT(!fShape.isRRect() || !fShape.rrect().isRect());
157 return fShape.isRect();
158 }
159
160 /** Returns the unstyled geometry as a rrect if possible. */
161 bool asRRect(SkRRect* rrect, bool* inverted) const;
162
163 /**
164 * If the unstyled shape is a straight line segment, returns true and sets pts to the endpoints.
165 * An inverse filled line path is still considered a line.
166 */
167 bool asLine(SkPoint pts[2], bool* inverted) const;
168
169 // Can this shape be drawn as a pair of filled nested rectangles?
170 bool asNestedRects(SkRect rects[2]) const;
171
172 /** Returns the unstyled geometry as a path. */
173 void asPath(SkPath* out) const {
174 fShape.asPath(out, fStyle.isSimpleFill());
175 }
176
177 /**
178 * Returns whether the geometry is empty. Note that applying the style could produce a
179 * non-empty shape. It also may have an inverse fill.
180 */
181 bool isEmpty() const { return fShape.isEmpty(); }
182
183 /**
184 * Gets the bounds of the geometry without reflecting the shape's styling. This ignores
185 * the inverse fill nature of the geometry.
186 */
187 SkRect bounds() const { return fShape.bounds(); }
188
189 /**
190 * Gets the bounds of the geometry reflecting the shape's styling (ignoring inverse fill
191 * status).
192 */
193 SkRect styledBounds() const;
194
195 /**
196 * Is this shape known to be convex, before styling is applied. An unclosed but otherwise
197 * convex path is considered to be closed if they styling reflects a fill and not otherwise.
198 * This is because filling closes all contours in the path.
199 */
200 bool knownToBeConvex() const {
201 return fShape.convex(fStyle.isSimpleFill());
202 }
203
204 /**
205 * Does the shape have a known winding direction. Some degenerate convex shapes may not have
206 * a computable direction, but this is not always a requirement for path renderers so it is
207 * kept separate from knownToBeConvex().
208 */
209 bool knownDirection() const {
210 // Assuming this is called after knownToBeConvex(), this should just be relying on
211 // cached convexity and direction and will be cheap.
212 return !fShape.isPath() ||
214 }
215
216 /** Is the pre-styled geometry inverse filled? */
217 bool inverseFilled() const {
218 // Since the path tracks inverted-fillness itself, it should match what was recorded.
219 SkASSERT(!fShape.isPath() || fShape.inverted() == fShape.path().isInverseFillType());
220 // Dashing ignores inverseness. We should have caught this earlier. skbug.com/5421
221 SkASSERT(!(fShape.inverted() && this->style().isDashed()));
222 return fShape.inverted();
223 }
224
225 /**
226 * Might applying the styling to the geometry produce an inverse fill. The "may" part comes in
227 * because an arbitrary path effect could produce an inverse filled path. In other cases this
228 * can be thought of as "inverseFilledAfterStyling()".
229 */
231 // An arbitrary path effect can produce an arbitrary output path, which may be inverse
232 // filled.
233 if (this->style().hasNonDashPathEffect()) {
234 return true;
235 }
236 return this->inverseFilled();
237 }
238
239 /**
240 * Is it known that the unstyled geometry has no unclosed contours. This means that it will
241 * not have any caps if stroked (modulo the effect of any path effect).
242 */
243 bool knownToBeClosed() const {
244 // This refers to the base shape and does not depend on invertedness.
245 return fShape.closed();
246 }
247
248 uint32_t segmentMask() const {
249 // This refers to the base shape and does not depend on invertedness.
250 return fShape.segmentMask();
251 }
252
253 /**
254 * Gets the size of the key for the shape represented by this GrStyledShape (ignoring its
255 * styling). A negative value is returned if the shape has no key (shouldn't be cached).
256 */
257 int unstyledKeySize() const;
258
259 bool hasUnstyledKey() const { return this->unstyledKeySize() >= 0; }
260
261 /**
262 * Writes unstyledKeySize() bytes into the provided pointer. Assumes that there is enough
263 * space allocated for the key and that unstyledKeySize() does not return a negative value
264 * for this shape.
265 */
266 void writeUnstyledKey(uint32_t* key) const;
267
268 /**
269 * Adds a listener to the *original* path. Typically used to invalidate cached resources when
270 * a path is no longer in-use. If the shape started out as something other than a path, this
271 * does nothing.
272 */
274
275 /**
276 * Helpers that are only exposed for unit tests, to determine if the shape is a path, and get
277 * the generation ID of the *original* path. This is the path that will receive
278 * GenIDChangeListeners added to this shape.
279 */
281 bool testingOnly_isPath() const;
283
284 /**
285 * Similar to GrShape::simplify but also takes into account style and stroking, possibly
286 * applying the style explicitly to produce a new analytic shape with a simpler style.
287 * Unless "doSimplify" is kNo, this method gets called automatically during construction.
288 */
289 void simplify();
290
291private:
292 /** Constructor used by the applyStyle() function */
294
295 /**
296 * Determines the key we should inherit from the input shape's geometry and style when
297 * we are applying the style to create a new shape.
298 */
299 void setInheritedKey(const GrStyledShape& parentShape, GrStyle::Apply, SkScalar scale);
300
301 /**
302 * As part of the simplification process, some shapes can have stroking trivially evaluated
303 * and form a new geometry with just a fill.
304 */
305 void simplifyStroke();
306
307 /** Gets the path that gen id listeners should be added to. */
308 const SkPath* originalPathForListeners() const;
309
310 GrShape fShape;
311 GrStyle fStyle;
312 // Gen ID of the original path (path may be modified or simplified away).
313 int32_t fGenID = 0;
314 bool fClosed = false;
315 bool fSimplified = false;
316
317 SkTLazy<SkPath> fInheritedPathForListeners;
319};
320#endif
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kYes
Do pre-clip the geometry before applying the (perspective) matrix.
@ kNo
Don't pre-clip the geometry before applying the (perspective) matrix.
SkPathDirection
Definition: SkPathTypes.h:34
static bool apply(Pass *pass, SkRecord *record)
bool closed() const
Definition: GrShape.cpp:330
bool isPath() const
Definition: GrShape.h:88
uint32_t segmentMask() const
Definition: GrShape.cpp:393
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:367
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:423
bool convex(bool simpleFill=true) const
Definition: GrShape.cpp:348
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)
Definition: GrStyledShape.h:68
int unstyledKeySize() const
static GrStyledShape MakeArc(const SkArc &arc, const GrStyle &style, DoSimplify=DoSimplify::kYes)
bool asLine(SkPoint pts[2], bool *inverted) const
bool asRRect(SkRRect *rrect, 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)
Definition: GrStyledShape.h:72
GrStyledShape(const SkRect &rect, const SkPaint &paint, DoSimplify doSimplify=DoSimplify::kYes)
Definition: GrStyledShape.h:76
GrStyledShape(const SkRRect &rrect, SkPathDirection dir, unsigned start, bool inverted, const GrStyle &style, DoSimplify doSimplify=DoSimplify::kYes)
Definition: GrStyledShape.h:93
bool knownDirection() const
bool knownToBeConvex() const
bool hasUnstyledKey() const
bool inverseFilled() const
const GrStyle & style() const
GrStyledShape(const SkPath &path, DoSimplify doSimplify=DoSimplify::kYes)
Definition: GrStyledShape.h:59
GrStyledShape(const SkRRect &rrect, DoSimplify doSimplify=DoSimplify::kYes)
Definition: GrStyledShape.h:62
GrStyledShape(const SkPath &path, const GrStyle &style, DoSimplify doSimplify=DoSimplify::kYes)
Definition: GrStyledShape.h:80
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)
Definition: GrStyledShape.h:88
bool mayBeInverseFilledAfterStyling() const
bool testingOnly_isPath() const
bool testingOnly_isNonVolatilePath() const
uint32_t segmentMask() const
static constexpr int kMaxKeyFromDataVerbCnt
Definition: GrStyledShape.h:53
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)
GrStyledShape(const SkRect &rect, DoSimplify doSimplify=DoSimplify::kYes)
Definition: GrStyledShape.h:65
static SkPathFirstDirection ComputeFirstDirection(const SkPath &)
Definition: SkPath.cpp:2627
Definition: SkPath.h:59
bool isInverseFillType() const
Definition: SkPath.h:244
bool isRect() const
Definition: SkRRect.h:84
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
SkRRect rrect
Definition: SkRecords.h:232
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
const Scalar scale
Definition: SkArc.h:15