OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef GrShape_DEFINED | 8 #ifndef GrShape_DEFINED |
9 #define GrShape_DEFINED | 9 #define GrShape_DEFINED |
10 | 10 |
(...skipping 26 matching lines...) Expand all Loading... |
37 GrShape() : fType(Type::kEmpty) {} | 37 GrShape() : fType(Type::kEmpty) {} |
38 | 38 |
39 explicit GrShape(const SkPath& path) | 39 explicit GrShape(const SkPath& path) |
40 : fType(Type::kPath) | 40 : fType(Type::kPath) |
41 , fPath(&path) { | 41 , fPath(&path) { |
42 this->attemptToReduceFromPath(); | 42 this->attemptToReduceFromPath(); |
43 } | 43 } |
44 | 44 |
45 explicit GrShape(const SkRRect& rrect) | 45 explicit GrShape(const SkRRect& rrect) |
46 : fType(Type::kRRect) | 46 : fType(Type::kRRect) |
47 , fRRect(rrect) { | 47 , fRRect(rrect) |
| 48 , fRRectIsInverted(false) { |
48 fRRectStart = DefaultRRectDirAndStartIndex(rrect, false, &fRRectDir); | 49 fRRectStart = DefaultRRectDirAndStartIndex(rrect, false, &fRRectDir); |
49 this->attemptToReduceFromRRect(); | 50 this->attemptToReduceFromRRect(); |
50 } | 51 } |
51 | 52 |
52 explicit GrShape(const SkRect& rect) | 53 explicit GrShape(const SkRect& rect) |
53 : fType(Type::kRRect) | 54 : fType(Type::kRRect) |
54 , fRRect(SkRRect::MakeRect(rect)) { | 55 , fRRect(SkRRect::MakeRect(rect)) |
| 56 , fRRectIsInverted(false) { |
55 fRRectStart = DefaultRectDirAndStartIndex(rect, false, &fRRectDir); | 57 fRRectStart = DefaultRectDirAndStartIndex(rect, false, &fRRectDir); |
56 this->attemptToReduceFromRRect(); | 58 this->attemptToReduceFromRRect(); |
57 } | 59 } |
58 | 60 |
59 GrShape(const SkPath& path, const GrStyle& style) | 61 GrShape(const SkPath& path, const GrStyle& style) |
60 : fType(Type::kPath) | 62 : fType(Type::kPath) |
61 , fPath(&path) | 63 , fPath(&path) |
62 , fStyle(style) { | 64 , fStyle(style) { |
63 this->attemptToReduceFromPath(); | 65 this->attemptToReduceFromPath(); |
64 } | 66 } |
65 | 67 |
66 GrShape(const SkRRect& rrect, const GrStyle& style) | 68 GrShape(const SkRRect& rrect, const GrStyle& style) |
67 : fType(Type::kRRect) | 69 : fType(Type::kRRect) |
68 , fRRect(rrect) | 70 , fRRect(rrect) |
| 71 , fRRectIsInverted(false) |
69 , fStyle(style) { | 72 , fStyle(style) { |
70 fRRectStart = DefaultRRectDirAndStartIndex(rrect, style.hasPathEffect(),
&fRRectDir); | 73 fRRectStart = DefaultRRectDirAndStartIndex(rrect, style.hasPathEffect(),
&fRRectDir); |
71 this->attemptToReduceFromRRect(); | 74 this->attemptToReduceFromRRect(); |
72 } | 75 } |
73 | 76 |
74 GrShape(const SkRRect& rrect, SkPath::Direction dir, unsigned start, const G
rStyle& style) | 77 GrShape(const SkRRect& rrect, SkPath::Direction dir, unsigned start, bool in
verted, |
| 78 const GrStyle& style) |
75 : fType(Type::kRRect) | 79 : fType(Type::kRRect) |
76 , fRRect(rrect) | 80 , fRRect(rrect) |
| 81 , fRRectIsInverted(inverted) |
77 , fStyle(style) { | 82 , fStyle(style) { |
78 if (style.pathEffect()) { | 83 if (style.pathEffect()) { |
79 fRRectDir = dir; | 84 fRRectDir = dir; |
80 fRRectStart = start; | 85 fRRectStart = start; |
| 86 if (fRRect.getType() == SkRRect::kRect_Type) { |
| 87 fRRectStart = (fRRectStart + 1) & 0b110; |
| 88 } else if (fRRect.getType() == SkRRect::kOval_Type) { |
| 89 fRRectStart &= 0b110; |
| 90 } |
81 } else { | 91 } else { |
82 fRRectStart = DefaultRRectDirAndStartIndex(rrect, false, &fRRectDir)
; | 92 fRRectStart = DefaultRRectDirAndStartIndex(rrect, false, &fRRectDir)
; |
83 } | 93 } |
84 this->attemptToReduceFromRRect(); | 94 this->attemptToReduceFromRRect(); |
85 } | 95 } |
86 | 96 |
87 GrShape(const SkRect& rect, const GrStyle& style) | 97 GrShape(const SkRect& rect, const GrStyle& style) |
88 : fType(Type::kRRect) | 98 : fType(Type::kRRect) |
89 , fRRect(SkRRect::MakeRect(rect)) | 99 , fRRect(SkRRect::MakeRect(rect)) |
| 100 , fRRectIsInverted(false) |
90 , fStyle(style) { | 101 , fStyle(style) { |
91 fRRectStart = DefaultRectDirAndStartIndex(rect, style.hasPathEffect(), &
fRRectDir); | 102 fRRectStart = DefaultRectDirAndStartIndex(rect, style.hasPathEffect(), &
fRRectDir); |
92 this->attemptToReduceFromRRect(); | 103 this->attemptToReduceFromRRect(); |
93 } | 104 } |
94 | 105 |
95 GrShape(const SkPath& path, const SkPaint& paint) | 106 GrShape(const SkPath& path, const SkPaint& paint) |
96 : fType(Type::kPath) | 107 : fType(Type::kPath) |
97 , fPath(&path) | 108 , fPath(&path) |
98 , fStyle(paint) { | 109 , fStyle(paint) { |
99 this->attemptToReduceFromPath(); | 110 this->attemptToReduceFromPath(); |
100 } | 111 } |
101 | 112 |
102 GrShape(const SkRRect& rrect, const SkPaint& paint) | 113 GrShape(const SkRRect& rrect, const SkPaint& paint) |
103 : fType(Type::kRRect) | 114 : fType(Type::kRRect) |
104 , fRRect(rrect) | 115 , fRRect(rrect) |
| 116 , fRRectIsInverted(false) |
105 , fStyle(paint) { | 117 , fStyle(paint) { |
106 fRRectStart = DefaultRRectDirAndStartIndex(rrect, fStyle.hasPathEffect()
, &fRRectDir); | 118 fRRectStart = DefaultRRectDirAndStartIndex(rrect, fStyle.hasPathEffect()
, &fRRectDir); |
107 this->attemptToReduceFromRRect(); | 119 this->attemptToReduceFromRRect(); |
108 } | 120 } |
109 | 121 |
110 GrShape(const SkRect& rect, const SkPaint& paint) | 122 GrShape(const SkRect& rect, const SkPaint& paint) |
111 : fType(Type::kRRect) | 123 : fType(Type::kRRect) |
112 , fRRect(SkRRect::MakeRect(rect)) | 124 , fRRect(SkRRect::MakeRect(rect)) |
| 125 , fRRectIsInverted(false) |
113 , fStyle(paint) { | 126 , fStyle(paint) { |
114 fRRectStart = DefaultRectDirAndStartIndex(rect, fStyle.hasPathEffect(),
&fRRectDir); | 127 fRRectStart = DefaultRectDirAndStartIndex(rect, fStyle.hasPathEffect(),
&fRRectDir); |
115 this->attemptToReduceFromRRect(); | 128 this->attemptToReduceFromRRect(); |
116 } | 129 } |
117 | 130 |
118 GrShape(const GrShape&); | 131 GrShape(const GrShape&); |
119 GrShape& operator=(const GrShape& that); | 132 GrShape& operator=(const GrShape& that); |
120 | 133 |
121 ~GrShape() { | 134 ~GrShape() { |
122 if (Type::kPath == fType) { | 135 if (Type::kPath == fType) { |
123 fPath.reset(); | 136 fPath.reset(); |
124 } | 137 } |
125 } | 138 } |
126 | 139 |
127 const GrStyle& style() const { return fStyle; } | 140 const GrStyle& style() const { return fStyle; } |
128 | 141 |
129 /** | 142 /** |
130 * Returns a shape that has either applied the path effect or path effect an
d stroking | 143 * Returns a shape that has either applied the path effect or path effect an
d stroking |
131 * information from this shape's style to its geometry. Scale is used when a
pproximating the | 144 * information from this shape's style to its geometry. Scale is used when a
pproximating the |
132 * output geometry and typically is computed from the view matrix | 145 * output geometry and typically is computed from the view matrix |
133 */ | 146 */ |
134 GrShape applyStyle(GrStyle::Apply apply, SkScalar scale) { | 147 GrShape applyStyle(GrStyle::Apply apply, SkScalar scale) { |
135 return GrShape(*this, apply, scale); | 148 return GrShape(*this, apply, scale); |
136 } | 149 } |
137 | 150 |
138 /** Returns the unstyled geometry as a rrect if possible. */ | 151 /** Returns the unstyled geometry as a rrect if possible. */ |
139 bool asRRect(SkRRect* rrect, SkPath::Direction* dir, unsigned* start) const
{ | 152 bool asRRect(SkRRect* rrect, SkPath::Direction* dir, unsigned* start, bool*
inverted) const { |
140 if (Type::kRRect != fType) { | 153 if (Type::kRRect != fType) { |
141 return false; | 154 return false; |
142 } | 155 } |
143 if (rrect) { | 156 if (rrect) { |
144 *rrect = fRRect; | 157 *rrect = fRRect; |
145 } | 158 } |
146 if (dir) { | 159 if (dir) { |
147 *dir = fRRectDir; | 160 *dir = fRRectDir; |
148 } | 161 } |
149 if (start) { | 162 if (start) { |
150 *start = fRRectStart; | 163 *start = fRRectStart; |
151 } | 164 } |
| 165 if (inverted) { |
| 166 *inverted = fRRectIsInverted; |
| 167 } |
152 return true; | 168 return true; |
153 } | 169 } |
154 | 170 |
155 /** Returns the unstyled geometry as a path. */ | 171 /** Returns the unstyled geometry as a path. */ |
156 void asPath(SkPath* out) const { | 172 void asPath(SkPath* out) const { |
157 switch (fType) { | 173 switch (fType) { |
158 case Type::kEmpty: | 174 case Type::kEmpty: |
159 out->reset(); | 175 out->reset(); |
160 break; | 176 break; |
161 case Type::kRRect: | 177 case Type::kRRect: |
162 out->reset(); | 178 out->reset(); |
163 out->addRRect(fRRect, fRRectDir, fRRectStart); | 179 out->addRRect(fRRect, fRRectDir, fRRectStart); |
| 180 if (fRRectIsInverted) { |
| 181 out->setFillType(SkPath::kInverseWinding_FillType); |
| 182 } |
164 break; | 183 break; |
165 case Type::kPath: | 184 case Type::kPath: |
166 *out = *fPath.get(); | 185 *out = *fPath.get(); |
167 break; | 186 break; |
168 } | 187 } |
169 } | 188 } |
170 | 189 |
171 /** | 190 /** |
172 * Returns whether the geometry is empty. Note that applying the style could
produce a | 191 * Returns whether the geometry is empty. Note that applying the style could
produce a |
173 * non-empty shape. | 192 * non-empty shape. |
174 */ | 193 */ |
175 bool isEmpty() const { return Type::kEmpty == fType; } | 194 bool isEmpty() const { return Type::kEmpty == fType; } |
176 | 195 |
177 /** Gets the bounds of the geometry without reflecting the shape's styling.
*/ | 196 /** |
| 197 * Gets the bounds of the geometry without reflecting the shape's styling. T
his ignores |
| 198 * the inverse fill nature of the geometry. |
| 199 */ |
178 const SkRect& bounds() const; | 200 const SkRect& bounds() const; |
179 | 201 |
180 /** Gets the bounds of the geometry reflecting the shape's styling. */ | 202 /** |
| 203 * Gets the bounds of the geometry reflecting the shape's styling (ignoring
inverse fill |
| 204 * status). |
| 205 */ |
181 void styledBounds(SkRect* bounds) const; | 206 void styledBounds(SkRect* bounds) const; |
182 | 207 |
183 /** | 208 /** |
184 * Is it known that the unstyled geometry has no unclosed contours. This mea
ns that it will | 209 * Is it known that the unstyled geometry has no unclosed contours. This mea
ns that it will |
185 * not have any caps if stroked (modulo the effect of any path effect). | 210 * not have any caps if stroked (modulo the effect of any path effect). |
186 */ | 211 */ |
187 bool knownToBeClosed() const { | 212 bool knownToBeClosed() const { |
188 switch (fType) { | 213 switch (fType) { |
189 case Type::kEmpty: | 214 case Type::kEmpty: |
190 return true; | 215 return true; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 | 263 |
239 /** | 264 /** |
240 * Determines the key we should inherit from the input shape's geometry and
style when | 265 * Determines the key we should inherit from the input shape's geometry and
style when |
241 * we are applying the style to create a new shape. | 266 * we are applying the style to create a new shape. |
242 */ | 267 */ |
243 void setInheritedKey(const GrShape& parentShape, GrStyle::Apply, SkScalar sc
ale); | 268 void setInheritedKey(const GrShape& parentShape, GrStyle::Apply, SkScalar sc
ale); |
244 | 269 |
245 void attemptToReduceFromPath() { | 270 void attemptToReduceFromPath() { |
246 SkASSERT(Type::kPath == fType); | 271 SkASSERT(Type::kPath == fType); |
247 fType = AttemptToReduceFromPathImpl(*fPath.get(), &fRRect, &fRRectDir, &
fRRectStart, | 272 fType = AttemptToReduceFromPathImpl(*fPath.get(), &fRRect, &fRRectDir, &
fRRectStart, |
248 fStyle.pathEffect(), fStyle.strokeRe
c()); | 273 &fRRectIsInverted, fStyle.pathEffect
(), |
| 274 fStyle.strokeRec()); |
249 if (Type::kPath != fType) { | 275 if (Type::kPath != fType) { |
250 fPath.reset(); | 276 fPath.reset(); |
251 fInheritedKey.reset(0); | 277 fInheritedKey.reset(0); |
252 } | 278 } |
253 } | 279 } |
254 | 280 |
255 void attemptToReduceFromRRect() { | 281 void attemptToReduceFromRRect() { |
256 SkASSERT(Type::kRRect == fType); | 282 SkASSERT(Type::kRRect == fType); |
257 SkASSERT(!fInheritedKey.count()); | 283 SkASSERT(!fInheritedKey.count()); |
258 if (fRRect.isEmpty()) { | 284 if (fRRectIsInverted) { |
| 285 if (!fStyle.hasNonDashPathEffect()) { |
| 286 SkStrokeRec::Style recStyle = fStyle.strokeRec().getStyle(); |
| 287 if (SkStrokeRec::kStroke_Style == recStyle || |
| 288 SkStrokeRec::kHairline_Style == recStyle) { |
| 289 // stroking ignores the path fill rule. |
| 290 fRRectIsInverted = false; |
| 291 } |
| 292 } |
| 293 } else if (fRRect.isEmpty()) { |
259 fType = Type::kEmpty; | 294 fType = Type::kEmpty; |
260 } | 295 } |
261 } | 296 } |
262 | 297 |
263 static Type AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect, | 298 static Type AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect, |
264 SkPath::Direction* rrectDir, unsigne
d* rrectStart, | 299 SkPath::Direction* rrectDir, unsigne
d* rrectStart, |
265 const SkPathEffect* pe, const SkStro
keRec& strokeRec); | 300 bool* rrectIsInverted, const SkPathE
ffect* pe, |
| 301 const SkStrokeRec& strokeRec); |
266 | 302 |
267 static constexpr SkPath::Direction kDefaultRRectDir = SkPath::kCW_Direction; | 303 static constexpr SkPath::Direction kDefaultRRectDir = SkPath::kCW_Direction; |
268 static constexpr unsigned kDefaultRRectStart = 0; | 304 static constexpr unsigned kDefaultRRectStart = 0; |
269 | 305 |
270 static unsigned DefaultRectDirAndStartIndex(const SkRect& rect, bool hasPath
Effect, | 306 static unsigned DefaultRectDirAndStartIndex(const SkRect& rect, bool hasPath
Effect, |
271 SkPath::Direction* dir) { | 307 SkPath::Direction* dir) { |
272 *dir = kDefaultRRectDir; | 308 *dir = kDefaultRRectDir; |
273 // This comes from SkPath's interface. The default for adding a SkRect i
s counter clockwise | 309 // This comes from SkPath's interface. The default for adding a SkRect i
s counter clockwise |
274 // beginning at index 0 (which happens to correspond to rrect index 0 or
7). | 310 // beginning at index 0 (which happens to correspond to rrect index 0 or
7). |
275 if (!hasPathEffect) { | 311 if (!hasPathEffect) { |
(...skipping 30 matching lines...) Expand all Loading... |
306 // It doesn't matter what start we use, just be consistent to avoid
redundant keys. | 342 // It doesn't matter what start we use, just be consistent to avoid
redundant keys. |
307 return kDefaultRRectStart; | 343 return kDefaultRRectStart; |
308 } | 344 } |
309 return kPathRRectStartIdx; | 345 return kPathRRectStartIdx; |
310 } | 346 } |
311 | 347 |
312 Type fType; | 348 Type fType; |
313 SkRRect fRRect; | 349 SkRRect fRRect; |
314 SkPath::Direction fRRectDir; | 350 SkPath::Direction fRRectDir; |
315 unsigned fRRectStart; | 351 unsigned fRRectStart; |
| 352 bool fRRectIsInverted; |
316 SkTLazy<SkPath> fPath; | 353 SkTLazy<SkPath> fPath; |
317 GrStyle fStyle; | 354 GrStyle fStyle; |
318 SkAutoSTArray<8, uint32_t> fInheritedKey; | 355 SkAutoSTArray<8, uint32_t> fInheritedKey; |
319 }; | 356 }; |
320 #endif | 357 #endif |
OLD | NEW |