Chromium Code Reviews| 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 |