blob: 074278cd863eb18391b14bb001352eb009a624a0 [file] [log] [blame]
bsalomon47cc7692016-04-26 12:56:00 -07001/*
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 GrShape_DEFINED
9#define GrShape_DEFINED
10
11#include "GrStyle.h"
12#include "SkPath.h"
bsalomonee295642016-06-06 14:01:25 -070013#include "SkPathPriv.h"
bsalomon47cc7692016-04-26 12:56:00 -070014#include "SkRRect.h"
15#include "SkTemplates.h"
16#include "SkTLazy.h"
17
18/**
19 * Represents a geometric shape (rrect or path) and the GrStyle that it should be rendered with.
20 * It is possible to apply the style to the GrShape to produce a new GrShape where the geometry
21 * reflects the styling information (e.g. is stroked). It is also possible to apply just the
22 * path effect from the style. In this case the resulting shape will include any remaining
23 * stroking information that is to be applied after the path effect.
24 *
25 * Shapes can produce keys that represent only the geometry information, not the style. Note that
26 * when styling information is applied to produce a new shape then the style has been converted
27 * to geometric information and is included in the new shape's key. When the same style is applied
28 * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes
29 * will be the same.
30 *
bsalomonee295642016-06-06 14:01:25 -070031 * Currently this can only be constructed from a path, rect, or rrect though it can become a path
32 * applying style to the geometry. The idea is to expand this to cover most or all of the geometries
33 * that have SkCanvas::draw APIs.
bsalomon47cc7692016-04-26 12:56:00 -070034 */
35class GrShape {
36public:
bsalomon67fa4e32016-09-21 08:26:57 -070037 // Keys for paths may be extracted from the path data for small paths. Clients aren't supposed
38 // to have to worry about this. This value is exposed for unit tests.
39 static constexpr int kMaxKeyFromDataVerbCnt = 10;
40
bsalomon728b0f72016-06-27 10:00:19 -070041 GrShape() { this->initType(Type::kEmpty); }
bsalomon5e410b42016-04-28 09:30:46 -070042
bsalomon728b0f72016-06-27 10:00:19 -070043 explicit GrShape(const SkPath& path) : GrShape(path, GrStyle::SimpleFill()) {}
bsalomon72dc51c2016-04-27 06:46:23 -070044
bsalomon728b0f72016-06-27 10:00:19 -070045 explicit GrShape(const SkRRect& rrect) : GrShape(rrect, GrStyle::SimpleFill()) {}
bsalomon47cc7692016-04-26 12:56:00 -070046
bsalomon728b0f72016-06-27 10:00:19 -070047 explicit GrShape(const SkRect& rect) : GrShape(rect, GrStyle::SimpleFill()) {}
bsalomon47cc7692016-04-26 12:56:00 -070048
bsalomon728b0f72016-06-27 10:00:19 -070049 GrShape(const SkPath& path, const GrStyle& style) : fStyle(style) {
50 this->initType(Type::kPath, &path);
bsalomon1b28c1a2016-06-20 12:28:17 -070051 this->attemptToSimplifyPath();
bsalomon72dc51c2016-04-27 06:46:23 -070052 }
53
bsalomon47cc7692016-04-26 12:56:00 -070054 GrShape(const SkRRect& rrect, const GrStyle& style)
bsalomon728b0f72016-06-27 10:00:19 -070055 : fStyle(style) {
56 this->initType(Type::kRRect);
57 fRRectData.fRRect = rrect;
58 fRRectData.fInverted = false;
59 fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, style.hasPathEffect(),
60 &fRRectData.fDir);
bsalomon1b28c1a2016-06-20 12:28:17 -070061 this->attemptToSimplifyRRect();
bsalomonee295642016-06-06 14:01:25 -070062 }
63
bsalomon70493962016-06-10 08:05:14 -070064 GrShape(const SkRRect& rrect, SkPath::Direction dir, unsigned start, bool inverted,
65 const GrStyle& style)
bsalomon728b0f72016-06-27 10:00:19 -070066 : fStyle(style) {
67 this->initType(Type::kRRect);
68 fRRectData.fRRect = rrect;
69 fRRectData.fInverted = inverted;
bsalomonee295642016-06-06 14:01:25 -070070 if (style.pathEffect()) {
bsalomon728b0f72016-06-27 10:00:19 -070071 fRRectData.fDir = dir;
72 fRRectData.fStart = start;
73 if (fRRectData.fRRect.getType() == SkRRect::kRect_Type) {
74 fRRectData.fStart = (fRRectData.fStart + 1) & 0b110;
75 } else if (fRRectData.fRRect.getType() == SkRRect::kOval_Type) {
76 fRRectData.fStart &= 0b110;
bsalomon70493962016-06-10 08:05:14 -070077 }
bsalomonee295642016-06-06 14:01:25 -070078 } else {
bsalomon728b0f72016-06-27 10:00:19 -070079 fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, false, &fRRectData.fDir);
bsalomonee295642016-06-06 14:01:25 -070080 }
bsalomon1b28c1a2016-06-20 12:28:17 -070081 this->attemptToSimplifyRRect();
bsalomon5e410b42016-04-28 09:30:46 -070082 }
bsalomon47cc7692016-04-26 12:56:00 -070083
84 GrShape(const SkRect& rect, const GrStyle& style)
bsalomon728b0f72016-06-27 10:00:19 -070085 : fStyle(style) {
86 this->initType(Type::kRRect);
87 fRRectData.fRRect = SkRRect::MakeRect(rect);
88 fRRectData.fInverted = false;
89 fRRectData.fStart = DefaultRectDirAndStartIndex(rect, style.hasPathEffect(),
90 &fRRectData.fDir);
bsalomon1b28c1a2016-06-20 12:28:17 -070091 this->attemptToSimplifyRRect();
bsalomon5e410b42016-04-28 09:30:46 -070092 }
bsalomon47cc7692016-04-26 12:56:00 -070093
bsalomon728b0f72016-06-27 10:00:19 -070094 GrShape(const SkPath& path, const SkPaint& paint) : fStyle(paint) {
95 this->initType(Type::kPath, &path);
bsalomon1b28c1a2016-06-20 12:28:17 -070096 this->attemptToSimplifyPath();
bsalomon72dc51c2016-04-27 06:46:23 -070097 }
98
bsalomon47cc7692016-04-26 12:56:00 -070099 GrShape(const SkRRect& rrect, const SkPaint& paint)
bsalomon728b0f72016-06-27 10:00:19 -0700100 : fStyle(paint) {
101 this->initType(Type::kRRect);
102 fRRectData.fRRect = rrect;
103 fRRectData.fInverted = false;
104 fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, fStyle.hasPathEffect(),
105 &fRRectData.fDir);
bsalomon1b28c1a2016-06-20 12:28:17 -0700106 this->attemptToSimplifyRRect();
bsalomon5e410b42016-04-28 09:30:46 -0700107 }
bsalomon47cc7692016-04-26 12:56:00 -0700108
109 GrShape(const SkRect& rect, const SkPaint& paint)
bsalomon728b0f72016-06-27 10:00:19 -0700110 : fStyle(paint) {
111 this->initType(Type::kRRect);
112 fRRectData.fRRect = SkRRect::MakeRect(rect);
113 fRRectData.fInverted = false;
114 fRRectData.fStart = DefaultRectDirAndStartIndex(rect, fStyle.hasPathEffect(),
115 &fRRectData.fDir);
bsalomon1b28c1a2016-06-20 12:28:17 -0700116 this->attemptToSimplifyRRect();
bsalomon5e410b42016-04-28 09:30:46 -0700117 }
bsalomon47cc7692016-04-26 12:56:00 -0700118
119 GrShape(const GrShape&);
120 GrShape& operator=(const GrShape& that);
121
bsalomon728b0f72016-06-27 10:00:19 -0700122 ~GrShape() { this->changeType(Type::kEmpty); }
bsalomon47cc7692016-04-26 12:56:00 -0700123
124 const GrStyle& style() const { return fStyle; }
125
bsalomon97fd2d42016-05-09 13:02:01 -0700126 /**
127 * Returns a shape that has either applied the path effect or path effect and stroking
128 * information from this shape's style to its geometry. Scale is used when approximating the
129 * output geometry and typically is computed from the view matrix
130 */
bsalomon425c27f2016-06-23 13:18:45 -0700131 GrShape applyStyle(GrStyle::Apply apply, SkScalar scale) const {
bsalomon97fd2d42016-05-09 13:02:01 -0700132 return GrShape(*this, apply, scale);
133 }
bsalomon47cc7692016-04-26 12:56:00 -0700134
bsalomon7c73a532016-05-11 15:15:56 -0700135 /** Returns the unstyled geometry as a rrect if possible. */
bsalomon70493962016-06-10 08:05:14 -0700136 bool asRRect(SkRRect* rrect, SkPath::Direction* dir, unsigned* start, bool* inverted) const {
bsalomon47cc7692016-04-26 12:56:00 -0700137 if (Type::kRRect != fType) {
138 return false;
139 }
140 if (rrect) {
bsalomon728b0f72016-06-27 10:00:19 -0700141 *rrect = fRRectData.fRRect;
bsalomon47cc7692016-04-26 12:56:00 -0700142 }
bsalomonee295642016-06-06 14:01:25 -0700143 if (dir) {
bsalomon728b0f72016-06-27 10:00:19 -0700144 *dir = fRRectData.fDir;
bsalomonee295642016-06-06 14:01:25 -0700145 }
146 if (start) {
bsalomon728b0f72016-06-27 10:00:19 -0700147 *start = fRRectData.fStart;
bsalomonee295642016-06-06 14:01:25 -0700148 }
bsalomon70493962016-06-10 08:05:14 -0700149 if (inverted) {
bsalomon728b0f72016-06-27 10:00:19 -0700150 *inverted = fRRectData.fInverted;
bsalomon70493962016-06-10 08:05:14 -0700151 }
bsalomon47cc7692016-04-26 12:56:00 -0700152 return true;
153 }
154
bsalomon398e3f42016-06-13 10:22:48 -0700155 /**
156 * If the unstyled shape is a straight line segment, returns true and sets pts to the endpoints.
157 * An inverse filled line path is still considered a line.
158 */
bsalomon0a0f67e2016-06-28 11:56:42 -0700159 bool asLine(SkPoint pts[2], bool* inverted) const {
160 if (fType != Type::kLine) {
161 return false;
162 }
163 if (pts) {
164 pts[0] = fLineData.fPts[0];
165 pts[1] = fLineData.fPts[1];
166 }
167 if (inverted) {
168 *inverted = fLineData.fInverted;
169 }
170 return true;
171 }
bsalomon398e3f42016-06-13 10:22:48 -0700172
bsalomon7c73a532016-05-11 15:15:56 -0700173 /** Returns the unstyled geometry as a path. */
bsalomon47cc7692016-04-26 12:56:00 -0700174 void asPath(SkPath* out) const {
175 switch (fType) {
bsalomon06077562016-05-04 13:50:29 -0700176 case Type::kEmpty:
177 out->reset();
178 break;
bsalomon47cc7692016-04-26 12:56:00 -0700179 case Type::kRRect:
180 out->reset();
bsalomon728b0f72016-06-27 10:00:19 -0700181 out->addRRect(fRRectData.fRRect, fRRectData.fDir, fRRectData.fStart);
bsalomon93f66bc2016-06-21 08:35:49 -0700182 // Below matches the fill type that attemptToSimplifyPath uses.
bsalomon728b0f72016-06-27 10:00:19 -0700183 if (fRRectData.fInverted) {
bsalomona4817af2016-06-23 11:48:26 -0700184 out->setFillType(kDefaultPathInverseFillType);
bsalomon93f66bc2016-06-21 08:35:49 -0700185 } else {
bsalomona4817af2016-06-23 11:48:26 -0700186 out->setFillType(kDefaultPathFillType);
bsalomon70493962016-06-10 08:05:14 -0700187 }
bsalomon47cc7692016-04-26 12:56:00 -0700188 break;
bsalomon0a0f67e2016-06-28 11:56:42 -0700189 case Type::kLine:
190 out->reset();
191 out->moveTo(fLineData.fPts[0]);
192 out->lineTo(fLineData.fPts[1]);
193 if (fLineData.fInverted) {
194 out->setFillType(kDefaultPathInverseFillType);
195 } else {
196 out->setFillType(kDefaultPathFillType);
197 }
198 break;
bsalomon47cc7692016-04-26 12:56:00 -0700199 case Type::kPath:
bsalomon728b0f72016-06-27 10:00:19 -0700200 *out = this->path();
bsalomon47cc7692016-04-26 12:56:00 -0700201 break;
bsalomon47cc7692016-04-26 12:56:00 -0700202 }
203 }
204
205 /**
bsalomon7c73a532016-05-11 15:15:56 -0700206 * Returns whether the geometry is empty. Note that applying the style could produce a
207 * non-empty shape.
208 */
209 bool isEmpty() const { return Type::kEmpty == fType; }
210
bsalomon70493962016-06-10 08:05:14 -0700211 /**
212 * Gets the bounds of the geometry without reflecting the shape's styling. This ignores
213 * the inverse fill nature of the geometry.
214 */
bsalomon0a0f67e2016-06-28 11:56:42 -0700215 SkRect bounds() const;
bsalomon9fb42032016-05-13 09:23:38 -0700216
bsalomon70493962016-06-10 08:05:14 -0700217 /**
218 * Gets the bounds of the geometry reflecting the shape's styling (ignoring inverse fill
219 * status).
220 */
bsalomon0a0f67e2016-06-28 11:56:42 -0700221 SkRect styledBounds() const;
bsalomon9fb42032016-05-13 09:23:38 -0700222
bsalomon7c73a532016-05-11 15:15:56 -0700223 /**
bsalomon425c27f2016-06-23 13:18:45 -0700224 * Is this shape known to be convex, before styling is applied. An unclosed but otherwise
225 * convex path is considered to be closed if they styling reflects a fill and not otherwise.
226 * This is because filling closes all contours in the path.
227 */
228 bool knownToBeConvex() const {
229 switch (fType) {
230 case Type::kEmpty:
231 return true;
232 case Type::kRRect:
233 return true;
bsalomon0a0f67e2016-06-28 11:56:42 -0700234 case Type::kLine:
235 return true;
bsalomon425c27f2016-06-23 13:18:45 -0700236 case Type::kPath:
237 // SkPath.isConvex() really means "is this path convex were it to be closed" and
238 // thus doesn't give the correct answer for stroked paths, hence we also check
239 // whether the path is either filled or closed. Convex paths may only have one
240 // contour hence isLastContourClosed() is a sufficient for a convex path.
bsalomon728b0f72016-06-27 10:00:19 -0700241 return (this->style().isSimpleFill() || this->path().isLastContourClosed()) &&
242 this->path().isConvex();
bsalomon425c27f2016-06-23 13:18:45 -0700243 }
244 return false;
245 }
246
247 /** Is the pre-styled geometry inverse filled? */
248 bool inverseFilled() const {
249 bool ret = false;
250 switch (fType) {
251 case Type::kEmpty:
252 ret = false;
253 break;
254 case Type::kRRect:
bsalomon728b0f72016-06-27 10:00:19 -0700255 ret = fRRectData.fInverted;
bsalomon425c27f2016-06-23 13:18:45 -0700256 break;
bsalomon0a0f67e2016-06-28 11:56:42 -0700257 case Type::kLine:
258 ret = fLineData.fInverted;
259 break;
bsalomon425c27f2016-06-23 13:18:45 -0700260 case Type::kPath:
bsalomon728b0f72016-06-27 10:00:19 -0700261 ret = this->path().isInverseFillType();
bsalomon425c27f2016-06-23 13:18:45 -0700262 break;
263 }
264 // Dashing ignores inverseness. We should have caught this earlier. skbug.com/5421
265 SkASSERT(!(ret && this->style().isDashed()));
266 return ret;
267 }
268
269 /**
270 * Might applying the styling to the geometry produce an inverse fill. The "may" part comes in
271 * because an arbitrary path effect could produce an inverse filled path. In other cases this
272 * can be thought of as "inverseFilledAfterStyling()".
273 */
274 bool mayBeInverseFilledAfterStyling() const {
275 // An arbitrary path effect can produce an arbitrary output path, which may be inverse
276 // filled.
277 if (this->style().hasNonDashPathEffect()) {
278 return true;
279 }
280 return this->inverseFilled();
281 }
282
283 /**
bsalomon7c73a532016-05-11 15:15:56 -0700284 * Is it known that the unstyled geometry has no unclosed contours. This means that it will
285 * not have any caps if stroked (modulo the effect of any path effect).
bsalomon06077562016-05-04 13:50:29 -0700286 */
287 bool knownToBeClosed() const {
288 switch (fType) {
289 case Type::kEmpty:
290 return true;
291 case Type::kRRect:
292 return true;
bsalomon0a0f67e2016-06-28 11:56:42 -0700293 case Type::kLine:
294 return false;
bsalomon06077562016-05-04 13:50:29 -0700295 case Type::kPath:
bsalomon425c27f2016-06-23 13:18:45 -0700296 // SkPath doesn't keep track of the closed status of each contour.
bsalomon728b0f72016-06-27 10:00:19 -0700297 return SkPathPriv::IsClosedSingleContour(this->path());
bsalomon06077562016-05-04 13:50:29 -0700298 }
299 return false;
300 }
301
bsalomon06115ee2016-06-07 06:28:51 -0700302 uint32_t segmentMask() const {
303 switch (fType) {
304 case Type::kEmpty:
305 return 0;
306 case Type::kRRect:
bsalomon728b0f72016-06-27 10:00:19 -0700307 if (fRRectData.fRRect.getType() == SkRRect::kOval_Type) {
bsalomon06115ee2016-06-07 06:28:51 -0700308 return SkPath::kConic_SegmentMask;
bsalomon728b0f72016-06-27 10:00:19 -0700309 } else if (fRRectData.fRRect.getType() == SkRRect::kRect_Type) {
bsalomon06115ee2016-06-07 06:28:51 -0700310 return SkPath::kLine_SegmentMask;
311 }
312 return SkPath::kLine_SegmentMask | SkPath::kConic_SegmentMask;
bsalomon0a0f67e2016-06-28 11:56:42 -0700313 case Type::kLine:
314 return SkPath::kLine_SegmentMask;
bsalomon06115ee2016-06-07 06:28:51 -0700315 case Type::kPath:
bsalomon728b0f72016-06-27 10:00:19 -0700316 return this->path().getSegmentMasks();
bsalomon06115ee2016-06-07 06:28:51 -0700317 }
318 return 0;
319 }
320
bsalomon06077562016-05-04 13:50:29 -0700321 /**
bsalomon47cc7692016-04-26 12:56:00 -0700322 * Gets the size of the key for the shape represented by this GrShape (ignoring its styling).
323 * A negative value is returned if the shape has no key (shouldn't be cached).
324 */
325 int unstyledKeySize() const;
326
bsalomon425c27f2016-06-23 13:18:45 -0700327 bool hasUnstyledKey() const { return this->unstyledKeySize() >= 0; }
328
bsalomon47cc7692016-04-26 12:56:00 -0700329 /**
330 * Writes unstyledKeySize() bytes into the provided pointer. Assumes that there is enough
331 * space allocated for the key and that unstyledKeySize() does not return a negative value
332 * for this shape.
333 */
334 void writeUnstyledKey(uint32_t* key) const;
335
336private:
bsalomon72dc51c2016-04-27 06:46:23 -0700337 enum class Type {
338 kEmpty,
339 kRRect,
bsalomon0a0f67e2016-06-28 11:56:42 -0700340 kLine,
bsalomon72dc51c2016-04-27 06:46:23 -0700341 kPath,
342 };
343
bsalomon728b0f72016-06-27 10:00:19 -0700344 void initType(Type type, const SkPath* path = nullptr) {
345 fType = Type::kEmpty;
346 this->changeType(type, path);
347 }
348
349 void changeType(Type type, const SkPath* path = nullptr) {
350 bool wasPath = Type::kPath == fType;
351 fType = type;
352 bool isPath = Type::kPath == type;
353 SkASSERT(!path || isPath);
354 if (wasPath && !isPath) {
355 fPathData.fPath.~SkPath();
356 } else if (!wasPath && isPath) {
357 if (path) {
358 new (&fPathData.fPath) SkPath(*path);
359 } else {
360 new (&fPathData.fPath) SkPath();
361 }
362 } else if (isPath && path) {
363 fPathData.fPath = *path;
364 }
365 // Whether or not we use the path's gen ID is decided in attemptToSimplifyPath.
366 fPathData.fGenID = 0;
367 }
368
369 SkPath& path() {
370 SkASSERT(Type::kPath == fType);
371 return fPathData.fPath;
372 }
373
374 const SkPath& path() const {
375 SkASSERT(Type::kPath == fType);
376 return fPathData.fPath;
377 }
378
bsalomon97fd2d42016-05-09 13:02:01 -0700379 /** Constructor used by the applyStyle() function */
380 GrShape(const GrShape& parentShape, GrStyle::Apply, SkScalar scale);
bsalomon47cc7692016-04-26 12:56:00 -0700381
382 /**
383 * Determines the key we should inherit from the input shape's geometry and style when
384 * we are applying the style to create a new shape.
385 */
bsalomon97fd2d42016-05-09 13:02:01 -0700386 void setInheritedKey(const GrShape& parentShape, GrStyle::Apply, SkScalar scale);
bsalomon47cc7692016-04-26 12:56:00 -0700387
bsalomon1b28c1a2016-06-20 12:28:17 -0700388 void attemptToSimplifyPath();
bsalomon1b28c1a2016-06-20 12:28:17 -0700389 void attemptToSimplifyRRect();
bsalomon0a0f67e2016-06-28 11:56:42 -0700390 void attemptToSimplifyLine();
bsalomonee295642016-06-06 14:01:25 -0700391
bsalomona4817af2016-06-23 11:48:26 -0700392 // Defaults to use when there is no distinction between even/odd and winding fills.
393 static constexpr SkPath::FillType kDefaultPathFillType = SkPath::kEvenOdd_FillType;
394 static constexpr SkPath::FillType kDefaultPathInverseFillType =
395 SkPath::kInverseEvenOdd_FillType;
396
bsalomonee295642016-06-06 14:01:25 -0700397 static constexpr SkPath::Direction kDefaultRRectDir = SkPath::kCW_Direction;
398 static constexpr unsigned kDefaultRRectStart = 0;
399
400 static unsigned DefaultRectDirAndStartIndex(const SkRect& rect, bool hasPathEffect,
401 SkPath::Direction* dir) {
402 *dir = kDefaultRRectDir;
403 // This comes from SkPath's interface. The default for adding a SkRect is counter clockwise
404 // beginning at index 0 (which happens to correspond to rrect index 0 or 7).
405 if (!hasPathEffect) {
406 // It doesn't matter what start we use, just be consistent to avoid redundant keys.
407 return kDefaultRRectStart;
bsalomon72dc51c2016-04-27 06:46:23 -0700408 }
bsalomonee295642016-06-06 14:01:25 -0700409 // In SkPath a rect starts at index 0 by default. This is the top left corner. However,
410 // we store rects as rrects. RRects don't preserve the invertedness, but rather sort the
411 // rect edges. Thus, we may need to modify the rrect's start index to account for the sort.
412 bool swapX = rect.fLeft > rect.fRight;
413 bool swapY = rect.fTop > rect.fBottom;
414 if (swapX && swapY) {
415 // 0 becomes start index 2 and times 2 to convert from rect the rrect indices.
416 return 2 * 2;
417 } else if (swapX) {
418 *dir = SkPath::kCCW_Direction;
419 // 0 becomes start index 1 and times 2 to convert from rect the rrect indices.
420 return 2 * 1;
421 } else if (swapY) {
422 *dir = SkPath::kCCW_Direction;
423 // 0 becomes start index 3 and times 2 to convert from rect the rrect indices.
424 return 2 * 3;
bsalomon72dc51c2016-04-27 06:46:23 -0700425 }
bsalomonee295642016-06-06 14:01:25 -0700426 return 0;
427 }
428
429 static unsigned DefaultRRectDirAndStartIndex(const SkRRect& rrect, bool hasPathEffect,
430 SkPath::Direction* dir) {
431 // This comes from SkPath's interface. The default for adding a SkRRect to a path is
432 // clockwise beginning at starting index 6.
433 static constexpr unsigned kPathRRectStartIdx = 6;
434 *dir = kDefaultRRectDir;
435 if (!hasPathEffect) {
436 // It doesn't matter what start we use, just be consistent to avoid redundant keys.
437 return kDefaultRRectStart;
bsalomon72dc51c2016-04-27 06:46:23 -0700438 }
bsalomonee295642016-06-06 14:01:25 -0700439 return kPathRRectStartIdx;
bsalomon72dc51c2016-04-27 06:46:23 -0700440 }
441
442 Type fType;
bsalomon728b0f72016-06-27 10:00:19 -0700443 union {
444 struct {
445 SkRRect fRRect;
446 SkPath::Direction fDir;
447 unsigned fStart;
448 bool fInverted;
449 } fRRectData;
450 struct {
451 SkPath fPath;
452 // Gen ID of the original path (fPath may be modified)
453 int32_t fGenID;
454 } fPathData;
bsalomon0a0f67e2016-06-28 11:56:42 -0700455 struct {
456 SkPoint fPts[2];
457 bool fInverted;
458 } fLineData;
bsalomon728b0f72016-06-27 10:00:19 -0700459 };
bsalomon47cc7692016-04-26 12:56:00 -0700460 GrStyle fStyle;
461 SkAutoSTArray<8, uint32_t> fInheritedKey;
462};
463#endif