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 |
11 #include "GrStyle.h" | 11 #include "GrStyle.h" |
12 #include "SkPath.h" | 12 #include "SkPath.h" |
13 #include "SkPathPriv.h" | |
13 #include "SkRRect.h" | 14 #include "SkRRect.h" |
14 #include "SkTemplates.h" | 15 #include "SkTemplates.h" |
15 #include "SkTLazy.h" | 16 #include "SkTLazy.h" |
16 | 17 |
17 /** | 18 /** |
18 * Represents a geometric shape (rrect or path) and the GrStyle that it should b e rendered with. | 19 * Represents a geometric shape (rrect or path) and the GrStyle that it should b e rendered with. |
19 * It is possible to apply the style to the GrShape to produce a new GrShape whe re the geometry | 20 * It is possible to apply the style to the GrShape to produce a new GrShape whe re the geometry |
20 * reflects the styling information (e.g. is stroked). It is also possible to ap ply just the | 21 * reflects the styling information (e.g. is stroked). It is also possible to ap ply just the |
21 * path effect from the style. In this case the resulting shape will include any remaining | 22 * path effect from the style. In this case the resulting shape will include any remaining |
22 * stroking information that is to be applied after the path effect. | 23 * stroking information that is to be applied after the path effect. |
23 * | 24 * |
24 * Shapes can produce keys that represent only the geometry information, not the style. Note that | 25 * Shapes can produce keys that represent only the geometry information, not the style. Note that |
25 * when styling information is applied to produce a new shape then the style has been converted | 26 * when styling information is applied to produce a new shape then the style has been converted |
26 * to geometric information and is included in the new shape's key. When the sam e style is applied | 27 * to geometric information and is included in the new shape's key. When the sam e style is applied |
27 * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes | 28 * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes |
28 * will be the same. | 29 * will be the same. |
29 * | 30 * |
30 * Currently this can only be constructed from a rrect, though it can become a p ath by applying | 31 * Currently this can only be constructed from a path, rect, or rrect though it can become a path |
31 * style to the geometry. The idea is to expand this to cover most or all of the geometries that | 32 * applying style to the geometry. The idea is to expand this to cover most or a ll of the geometries |
32 * have SkCanvas::draw APIs. | 33 * that have SkCanvas::draw APIs. |
33 */ | 34 */ |
34 class GrShape { | 35 class GrShape { |
35 public: | 36 public: |
36 GrShape() : fType(Type::kEmpty) {} | 37 GrShape() : fType(Type::kEmpty) {} |
37 | 38 |
38 explicit GrShape(const SkPath& path) | 39 explicit GrShape(const SkPath& path) |
39 : fType(Type::kPath) | 40 : fType(Type::kPath) |
40 , fPath(&path) { | 41 , fPath(&path) { |
41 this->attemptToReduceFromPath(); | 42 this->attemptToReduceFromPath(); |
42 } | 43 } |
43 | 44 |
44 explicit GrShape(const SkRRect& rrect) | 45 explicit GrShape(const SkRRect& rrect) |
45 : fType(Type::kRRect) | 46 : fType(Type::kRRect) |
46 , fRRect(rrect) { | 47 , fRRect(rrect) |
48 , fRRectDir(SkPath::kCW_Direction) | |
49 , fRRectStart(DefaultRRectStartIndex(rrect, false)) { | |
47 this->attemptToReduceFromRRect(); | 50 this->attemptToReduceFromRRect(); |
48 } | 51 } |
49 | 52 |
50 explicit GrShape(const SkRect& rect) | 53 explicit GrShape(const SkRect& rect) |
51 : fType(Type::kRRect) | 54 : fType(Type::kRRect) |
52 , fRRect(SkRRect::MakeRect(rect)) { | 55 , fRRect(SkRRect::MakeRect(rect)) |
56 , fRRectDir(SkPath::kCW_Direction) | |
57 , fRRectStart(1) { | |
53 this->attemptToReduceFromRRect(); | 58 this->attemptToReduceFromRRect(); |
54 } | 59 } |
55 | 60 |
56 GrShape(const SkPath& path, const GrStyle& style) | 61 GrShape(const SkPath& path, const GrStyle& style) |
57 : fType(Type::kPath) | 62 : fType(Type::kPath) |
58 , fPath(&path) | 63 , fPath(&path) |
59 , fStyle(style) { | 64 , fStyle(style) { |
60 this->attemptToReduceFromPath(); | 65 this->attemptToReduceFromPath(); |
61 } | 66 } |
62 | 67 |
63 GrShape(const SkRRect& rrect, const GrStyle& style) | 68 GrShape(const SkRRect& rrect, const GrStyle& style) |
64 : fType(Type::kRRect) | 69 : fType(Type::kRRect) |
65 , fRRect(rrect) | 70 , fRRect(rrect) |
71 , fRRectDir(SkPath::kCW_Direction) | |
72 , fRRectStart(DefaultRRectStartIndex(rrect, SkToBool(style.pathEffect()) )) | |
66 , fStyle(style) { | 73 , fStyle(style) { |
67 this->attemptToReduceFromRRect(); | 74 this->attemptToReduceFromRRect(); |
68 } | 75 } |
69 | 76 |
77 GrShape(const SkRRect& rrect, SkPath::Direction dir, unsigned start, const G rStyle& style) | |
78 : fType(Type::kRRect) | |
79 , fRRect(rrect) | |
80 , fStyle(style) { | |
81 if (style.pathEffect()) { | |
82 fRRectDir = dir; | |
83 fRRectStart = start; | |
84 } else { | |
85 fRRectDir = SkPath::kCW_Direction; | |
86 fRRectStart = DefaultRRectStartIndex(rrect, false); | |
87 } | |
88 this->attemptToReduceFromRRect(); | |
89 } | |
90 | |
70 GrShape(const SkRect& rect, const GrStyle& style) | 91 GrShape(const SkRect& rect, const GrStyle& style) |
71 : fType(Type::kRRect) | 92 : fType(Type::kRRect) |
72 , fRRect(SkRRect::MakeRect(rect)) | 93 , fRRect(SkRRect::MakeRect(rect)) |
73 , fStyle(style) { | 94 , fStyle(style) { |
95 fRRectStart = DefaultRectDirAndStartIndex(rect, style.pathEffect(), &fRR ectDir); | |
74 this->attemptToReduceFromRRect(); | 96 this->attemptToReduceFromRRect(); |
75 } | 97 } |
76 | 98 |
77 GrShape(const SkPath& path, const SkPaint& paint) | 99 GrShape(const SkPath& path, const SkPaint& paint) |
78 : fType(Type::kPath) | 100 : fType(Type::kPath) |
79 , fPath(&path) | 101 , fPath(&path) |
80 , fStyle(paint) { | 102 , fStyle(paint) { |
81 this->attemptToReduceFromPath(); | 103 this->attemptToReduceFromPath(); |
82 } | 104 } |
83 | 105 |
84 GrShape(const SkRRect& rrect, const SkPaint& paint) | 106 GrShape(const SkRRect& rrect, const SkPaint& paint) |
85 : fType(Type::kRRect) | 107 : fType(Type::kRRect) |
86 , fRRect(rrect) | 108 , fRRect(rrect) |
109 , fRRectDir(SkPath::kCW_Direction) | |
87 , fStyle(paint) { | 110 , fStyle(paint) { |
111 fRRectStart = DefaultRRectStartIndex(rrect, SkToBool(fStyle.pathEffect() )); | |
88 this->attemptToReduceFromRRect(); | 112 this->attemptToReduceFromRRect(); |
89 } | 113 } |
90 | 114 |
91 GrShape(const SkRect& rect, const SkPaint& paint) | 115 GrShape(const SkRect& rect, const SkPaint& paint) |
92 : fType(Type::kRRect) | 116 : fType(Type::kRRect) |
93 , fRRect(SkRRect::MakeRect(rect)) | 117 , fRRect(SkRRect::MakeRect(rect)) |
94 , fStyle(paint) { | 118 , fStyle(paint) { |
119 fRRectStart = DefaultRectDirAndStartIndex(rect, fStyle.pathEffect(), &fR RectDir); | |
95 this->attemptToReduceFromRRect(); | 120 this->attemptToReduceFromRRect(); |
96 } | 121 } |
97 | 122 |
98 GrShape(const GrShape&); | 123 GrShape(const GrShape&); |
99 GrShape& operator=(const GrShape& that); | 124 GrShape& operator=(const GrShape& that); |
100 | 125 |
101 ~GrShape() { | 126 ~GrShape() { |
102 if (Type::kPath == fType) { | 127 if (Type::kPath == fType) { |
103 fPath.reset(); | 128 fPath.reset(); |
104 } | 129 } |
105 } | 130 } |
106 | 131 |
107 const GrStyle& style() const { return fStyle; } | 132 const GrStyle& style() const { return fStyle; } |
108 | 133 |
109 /** | 134 /** |
110 * Returns a shape that has either applied the path effect or path effect an d stroking | 135 * Returns a shape that has either applied the path effect or path effect an d stroking |
111 * information from this shape's style to its geometry. Scale is used when a pproximating the | 136 * information from this shape's style to its geometry. Scale is used when a pproximating the |
112 * output geometry and typically is computed from the view matrix | 137 * output geometry and typically is computed from the view matrix |
113 */ | 138 */ |
114 GrShape applyStyle(GrStyle::Apply apply, SkScalar scale) { | 139 GrShape applyStyle(GrStyle::Apply apply, SkScalar scale) { |
115 return GrShape(*this, apply, scale); | 140 return GrShape(*this, apply, scale); |
116 } | 141 } |
117 | 142 |
118 /** Returns the unstyled geometry as a rrect if possible. */ | 143 /** Returns the unstyled geometry as a rrect if possible. */ |
119 bool asRRect(SkRRect* rrect) const { | 144 bool asRRect(SkRRect* rrect, SkPath::Direction* dir, unsigned* start) const { |
120 if (Type::kRRect != fType) { | 145 if (Type::kRRect != fType) { |
121 return false; | 146 return false; |
122 } | 147 } |
123 if (rrect) { | 148 if (rrect) { |
124 *rrect = fRRect; | 149 *rrect = fRRect; |
125 } | 150 } |
151 if (dir) { | |
152 *dir = fRRectDir; | |
153 } | |
154 if (start) { | |
155 *start = fRRectStart; | |
156 } | |
126 return true; | 157 return true; |
127 } | 158 } |
128 | 159 |
129 /** Returns the unstyled geometry as a path. */ | 160 /** Returns the unstyled geometry as a path. */ |
130 void asPath(SkPath* out) const { | 161 void asPath(SkPath* out) const { |
131 switch (fType) { | 162 switch (fType) { |
132 case Type::kEmpty: | 163 case Type::kEmpty: |
133 out->reset(); | 164 out->reset(); |
134 break; | 165 break; |
135 case Type::kRRect: | 166 case Type::kRRect: |
136 out->reset(); | 167 out->reset(); |
137 out->addRRect(fRRect); | 168 out->addRRect(fRRect, fRRectDir, fRRectStart); |
138 break; | 169 break; |
139 case Type::kPath: | 170 case Type::kPath: |
140 *out = *fPath.get(); | 171 *out = *fPath.get(); |
141 break; | 172 break; |
142 } | 173 } |
143 } | 174 } |
144 | 175 |
145 /** | 176 /** |
146 * Returns whether the geometry is empty. Note that applying the style could produce a | 177 * Returns whether the geometry is empty. Note that applying the style could produce a |
147 * non-empty shape. | 178 * non-empty shape. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
183 */ | 214 */ |
184 void writeUnstyledKey(uint32_t* key) const; | 215 void writeUnstyledKey(uint32_t* key) const; |
185 | 216 |
186 private: | 217 private: |
187 enum class Type { | 218 enum class Type { |
188 kEmpty, | 219 kEmpty, |
189 kRRect, | 220 kRRect, |
190 kPath, | 221 kPath, |
191 }; | 222 }; |
192 | 223 |
193 | |
194 /** Constructor used by the applyStyle() function */ | 224 /** Constructor used by the applyStyle() function */ |
195 GrShape(const GrShape& parentShape, GrStyle::Apply, SkScalar scale); | 225 GrShape(const GrShape& parentShape, GrStyle::Apply, SkScalar scale); |
196 | 226 |
197 /** | 227 /** |
198 * Determines the key we should inherit from the input shape's geometry and style when | 228 * Determines the key we should inherit from the input shape's geometry and style when |
199 * we are applying the style to create a new shape. | 229 * we are applying the style to create a new shape. |
200 */ | 230 */ |
201 void setInheritedKey(const GrShape& parentShape, GrStyle::Apply, SkScalar sc ale); | 231 void setInheritedKey(const GrShape& parentShape, GrStyle::Apply, SkScalar sc ale); |
202 | 232 |
203 void attemptToReduceFromPath() { | 233 void attemptToReduceFromPath() { |
204 SkASSERT(Type::kPath == fType); | 234 SkASSERT(Type::kPath == fType); |
205 fType = AttemptToReduceFromPathImpl(*fPath.get(), &fRRect, fStyle.pathEf fect(), | 235 fType = AttemptToReduceFromPathImpl(*fPath.get(), &fRRect, &fRRectDir, & fRRectStart, |
206 fStyle.strokeRec()); | 236 fStyle.pathEffect(), fStyle.strokeRe c()); |
207 if (Type::kPath != fType) { | 237 if (Type::kPath != fType) { |
208 fPath.reset(); | 238 fPath.reset(); |
209 fInheritedKey.reset(0); | 239 fInheritedKey.reset(0); |
210 } | 240 } |
211 } | 241 } |
212 | 242 |
213 void attemptToReduceFromRRect() { | 243 void attemptToReduceFromRRect() { |
214 SkASSERT(Type::kRRect == fType); | 244 SkASSERT(Type::kRRect == fType); |
215 SkASSERT(!fInheritedKey.count()); | 245 SkASSERT(!fInheritedKey.count()); |
216 if (fRRect.isEmpty()) { | 246 if (fRRect.isEmpty()) { |
217 fType = Type::kEmpty; | 247 fType = Type::kEmpty; |
218 } | 248 } |
219 } | 249 } |
220 | 250 |
221 static Type AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect, | 251 static Type AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect, |
222 const SkPathEffect* pe, const SkStro keRec& strokeRec) { | 252 SkPath::Direction* rrectDir, unsigne d* rrectStart, |
223 if (path.isEmpty()) { | 253 const SkPathEffect* pe, const SkStro keRec& strokeRec); |
224 return Type::kEmpty; | 254 |
255 static unsigned DefaultRectDirAndStartIndex(const SkRect& rect, bool hasPath Effect, | |
256 SkPath::Direction* dir) { | |
257 // This is the default direction when a rect is added to a path. | |
258 *dir = SkPath::kCW_Direction; | |
259 // This comes from SkPath's interface. The default for adding a SkRect i s counter clockwise | |
260 // beginning at index 0 (which happens to correspond to rrect index 0 or 7). | |
261 if (!hasPathEffect) { | |
262 return 0; | |
225 } | 263 } |
226 if (path.isRRect(rrect)) { | 264 // We store rects as rrects. RRects don't preserve the invertedness, but rather sort the |
227 SkASSERT(!rrect->isEmpty()); | 265 // rect edges. Thus, we may need to modify the rrect's start index to ac count for the sort. |
228 return Type::kRRect; | 266 *dir = SkPath::kCW_Direction; |
egdaniel
2016/06/06 15:50:29
This line is repeated above
bsalomon
2016/06/06 16:28:05
Done.
| |
267 bool swapX = rect.fLeft > rect.fRight; | |
268 bool swapY = rect.fTop > rect.fBottom; | |
269 if (swapX && swapY) { | |
270 // 0 becomes start index 2 and times 2 to convert from rect the rrec t indices. | |
271 return 2 * 2; | |
272 } else if (swapX) { | |
273 *dir = SkPath::kCW_Direction; | |
egdaniel
2016/06/06 15:50:29
CCW?
bsalomon
2016/06/06 16:28:04
Done.
| |
274 // 0 becomes start index 1 and times 2 to convert from rect the rrec t indices. | |
275 return 2 * 1; | |
276 } else if (swapY) { | |
277 *dir = SkPath::kCW_Direction; | |
egdaniel
2016/06/06 15:50:29
CCW?
bsalomon
2016/06/06 16:28:05
Done.
| |
278 // 0 becomes start index 3 and times 2 to convert from rect the rrec t indices. | |
279 return 2 * 3; | |
229 } | 280 } |
230 SkRect rect; | 281 return 0; |
231 if (path.isOval(&rect)) { | 282 } |
232 rrect->setOval(rect); | 283 |
233 return Type::kRRect; | 284 static unsigned DefaultRRectStartIndex(const SkRRect& rrect, bool hasPathEff ect) { |
234 } | 285 // This comes from SkPath's interface. The default for adding a SkRRect to a path is |
235 bool closed; | 286 // clockwise beginning at starting index 6. |
236 if (path.isRect(&rect, &closed, nullptr)) { | 287 static constexpr unsigned kDefaultRRectStartIdx = 6; |
237 if (closed || (!pe && strokeRec.isFillStyle())) { | 288 if (!hasPathEffect) { |
238 rrect->setRect(rect); | 289 // Rect and Oval subtypes have their own default/canonical starting index. This agrees |
239 return Type::kRRect; | 290 // with AttemptToReduceFromPathImpl and SkPath's add[Oval Rect] meth ods. |
291 if (rrect.getType() == SkRRect::kRect_Type) { | |
292 // The default rect starting point in SkPath::addRect is 0 which stays 0 | |
293 // in terms of rrect indices. | |
294 return 0; | |
295 } else if (rrect.getType() == SkRRect::kOval_Type) { | |
296 // The default oval starting point in SkPath::addOval is 1 which converts to 2 | |
297 // in terms of rrect indices. | |
298 return 2; | |
240 } | 299 } |
241 } | 300 } |
242 return Type::kPath; | 301 return kDefaultRRectStartIdx; |
243 } | 302 } |
244 | 303 |
245 Type fType; | 304 Type fType; |
246 SkRRect fRRect; | 305 SkRRect fRRect; |
306 SkPath::Direction fRRectDir; | |
307 unsigned fRRectStart; | |
247 SkTLazy<SkPath> fPath; | 308 SkTLazy<SkPath> fPath; |
248 GrStyle fStyle; | 309 GrStyle fStyle; |
249 SkAutoSTArray<8, uint32_t> fInheritedKey; | 310 SkAutoSTArray<8, uint32_t> fInheritedKey; |
250 }; | 311 }; |
251 #endif | 312 #endif |
OLD | NEW |