bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 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 GrShape_DEFINED |
| 9 | #define GrShape_DEFINED |
| 10 | |
| 11 | #include "GrStyle.h" |
| 12 | #include "SkPath.h" |
| 13 | #include "SkRRect.h" |
| 14 | #include "SkTemplates.h" |
| 15 | #include "SkTLazy.h" |
| 16 | |
| 17 | /** |
| 18 | * Represents a geometric shape (rrect or path) and the GrStyle that it should be rendered with. |
| 19 | * It is possible to apply the style to the GrShape to produce a new GrShape where the geometry |
| 20 | * reflects the styling information (e.g. is stroked). It is also possible to apply just the |
| 21 | * 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 | * |
| 24 | * 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 | * to geometric information and is included in the new shape's key. When the same style is applied |
| 27 | * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes |
| 28 | * will be the same. |
| 29 | * |
| 30 | * Currently this can only be constructed from a rrect, though it can become a path by applying |
| 31 | * style to the geometry. The idea is to expand this to cover most or all of the geometries that |
| 32 | * have SkCanvas::draw APIs. |
| 33 | */ |
| 34 | class GrShape { |
| 35 | public: |
bsalomon | 5e410b4 | 2016-04-28 09:30:46 -0700 | [diff] [blame] | 36 | GrShape() : fType(Type::kEmpty) {} |
| 37 | |
| 38 | explicit GrShape(const SkPath& path) |
bsalomon | 72dc51c | 2016-04-27 06:46:23 -0700 | [diff] [blame] | 39 | : fType(Type::kPath) |
| 40 | , fPath(&path) { |
| 41 | this->attemptToReduceFromPath(); |
| 42 | } |
| 43 | |
bsalomon | 5e410b4 | 2016-04-28 09:30:46 -0700 | [diff] [blame] | 44 | explicit GrShape(const SkRRect& rrect) |
| 45 | : fType(Type::kRRect) |
| 46 | , fRRect(rrect) { |
| 47 | this->attemptToReduceFromRRect(); |
| 48 | } |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 49 | |
bsalomon | 5e410b4 | 2016-04-28 09:30:46 -0700 | [diff] [blame] | 50 | explicit GrShape(const SkRect& rect) |
| 51 | : fType(Type::kRRect) |
| 52 | , fRRect(SkRRect::MakeRect(rect)) { |
| 53 | this->attemptToReduceFromRRect(); |
| 54 | } |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 55 | |
bsalomon | 72dc51c | 2016-04-27 06:46:23 -0700 | [diff] [blame] | 56 | GrShape(const SkPath& path, const GrStyle& style) |
| 57 | : fType(Type::kPath) |
| 58 | , fPath(&path) |
| 59 | , fStyle(style) { |
| 60 | this->attemptToReduceFromPath(); |
| 61 | } |
| 62 | |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 63 | GrShape(const SkRRect& rrect, const GrStyle& style) |
| 64 | : fType(Type::kRRect) |
| 65 | , fRRect(rrect) |
bsalomon | 5e410b4 | 2016-04-28 09:30:46 -0700 | [diff] [blame] | 66 | , fStyle(style) { |
| 67 | this->attemptToReduceFromRRect(); |
| 68 | } |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 69 | |
| 70 | GrShape(const SkRect& rect, const GrStyle& style) |
| 71 | : fType(Type::kRRect) |
| 72 | , fRRect(SkRRect::MakeRect(rect)) |
bsalomon | 5e410b4 | 2016-04-28 09:30:46 -0700 | [diff] [blame] | 73 | , fStyle(style) { |
| 74 | this->attemptToReduceFromRRect(); |
| 75 | } |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 76 | |
bsalomon | 72dc51c | 2016-04-27 06:46:23 -0700 | [diff] [blame] | 77 | GrShape(const SkPath& path, const SkPaint& paint) |
| 78 | : fType(Type::kPath) |
| 79 | , fPath(&path) |
| 80 | , fStyle(paint) { |
| 81 | this->attemptToReduceFromPath(); |
| 82 | } |
| 83 | |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 84 | GrShape(const SkRRect& rrect, const SkPaint& paint) |
| 85 | : fType(Type::kRRect) |
| 86 | , fRRect(rrect) |
bsalomon | 5e410b4 | 2016-04-28 09:30:46 -0700 | [diff] [blame] | 87 | , fStyle(paint) { |
| 88 | this->attemptToReduceFromRRect(); |
| 89 | } |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 90 | |
| 91 | GrShape(const SkRect& rect, const SkPaint& paint) |
| 92 | : fType(Type::kRRect) |
| 93 | , fRRect(SkRRect::MakeRect(rect)) |
bsalomon | 5e410b4 | 2016-04-28 09:30:46 -0700 | [diff] [blame] | 94 | , fStyle(paint) { |
| 95 | this->attemptToReduceFromRRect(); |
| 96 | } |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 97 | |
| 98 | GrShape(const GrShape&); |
| 99 | GrShape& operator=(const GrShape& that); |
| 100 | |
| 101 | ~GrShape() { |
| 102 | if (Type::kPath == fType) { |
| 103 | fPath.reset(); |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | const GrStyle& style() const { return fStyle; } |
| 108 | |
bsalomon | 97fd2d4 | 2016-05-09 13:02:01 -0700 | [diff] [blame] | 109 | /** |
| 110 | * Returns a shape that has either applied the path effect or path effect and stroking |
| 111 | * information from this shape's style to its geometry. Scale is used when approximating the |
| 112 | * output geometry and typically is computed from the view matrix |
| 113 | */ |
| 114 | GrShape applyStyle(GrStyle::Apply apply, SkScalar scale) { |
| 115 | return GrShape(*this, apply, scale); |
| 116 | } |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 117 | |
| 118 | bool asRRect(SkRRect* rrect) const { |
| 119 | if (Type::kRRect != fType) { |
| 120 | return false; |
| 121 | } |
| 122 | if (rrect) { |
| 123 | *rrect = fRRect; |
| 124 | } |
| 125 | return true; |
| 126 | } |
| 127 | |
| 128 | void asPath(SkPath* out) const { |
| 129 | switch (fType) { |
bsalomon | 0607756 | 2016-05-04 13:50:29 -0700 | [diff] [blame] | 130 | case Type::kEmpty: |
| 131 | out->reset(); |
| 132 | break; |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 133 | case Type::kRRect: |
| 134 | out->reset(); |
| 135 | out->addRRect(fRRect); |
| 136 | break; |
| 137 | case Type::kPath: |
| 138 | *out = *fPath.get(); |
| 139 | break; |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 140 | } |
| 141 | } |
| 142 | |
| 143 | /** |
bsalomon | 0607756 | 2016-05-04 13:50:29 -0700 | [diff] [blame] | 144 | * Is it known that the shape has no unclosed contours. This means that it will not have |
| 145 | * any caps if stroked (modulo the effect of any path effect). |
| 146 | */ |
| 147 | bool knownToBeClosed() const { |
| 148 | switch (fType) { |
| 149 | case Type::kEmpty: |
| 150 | return true; |
| 151 | case Type::kRRect: |
| 152 | return true; |
| 153 | case Type::kPath: |
| 154 | return false; |
| 155 | } |
| 156 | return false; |
| 157 | } |
| 158 | |
| 159 | /** |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 160 | * Gets the size of the key for the shape represented by this GrShape (ignoring its styling). |
| 161 | * A negative value is returned if the shape has no key (shouldn't be cached). |
| 162 | */ |
| 163 | int unstyledKeySize() const; |
| 164 | |
| 165 | /** |
| 166 | * Writes unstyledKeySize() bytes into the provided pointer. Assumes that there is enough |
| 167 | * space allocated for the key and that unstyledKeySize() does not return a negative value |
| 168 | * for this shape. |
| 169 | */ |
| 170 | void writeUnstyledKey(uint32_t* key) const; |
| 171 | |
| 172 | private: |
bsalomon | 72dc51c | 2016-04-27 06:46:23 -0700 | [diff] [blame] | 173 | enum class Type { |
| 174 | kEmpty, |
| 175 | kRRect, |
| 176 | kPath, |
| 177 | }; |
| 178 | |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 179 | |
bsalomon | 97fd2d4 | 2016-05-09 13:02:01 -0700 | [diff] [blame] | 180 | /** Constructor used by the applyStyle() function */ |
| 181 | GrShape(const GrShape& parentShape, GrStyle::Apply, SkScalar scale); |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 182 | |
| 183 | /** |
| 184 | * Determines the key we should inherit from the input shape's geometry and style when |
| 185 | * we are applying the style to create a new shape. |
| 186 | */ |
bsalomon | 97fd2d4 | 2016-05-09 13:02:01 -0700 | [diff] [blame] | 187 | void setInheritedKey(const GrShape& parentShape, GrStyle::Apply, SkScalar scale); |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 188 | |
bsalomon | 72dc51c | 2016-04-27 06:46:23 -0700 | [diff] [blame] | 189 | void attemptToReduceFromPath() { |
| 190 | SkASSERT(Type::kPath == fType); |
| 191 | fType = AttemptToReduceFromPathImpl(*fPath.get(), &fRRect, fStyle.pathEffect(), |
| 192 | fStyle.strokeRec()); |
| 193 | if (Type::kPath != fType) { |
| 194 | fPath.reset(); |
| 195 | fInheritedKey.reset(0); |
| 196 | } |
| 197 | } |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 198 | |
bsalomon | 5e410b4 | 2016-04-28 09:30:46 -0700 | [diff] [blame] | 199 | void attemptToReduceFromRRect() { |
| 200 | SkASSERT(Type::kRRect == fType); |
| 201 | SkASSERT(!fInheritedKey.count()); |
| 202 | if (fRRect.isEmpty()) { |
| 203 | fType = Type::kEmpty; |
| 204 | } |
| 205 | } |
| 206 | |
bsalomon | 72dc51c | 2016-04-27 06:46:23 -0700 | [diff] [blame] | 207 | static Type AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect, |
| 208 | const SkPathEffect* pe, const SkStrokeRec& strokeRec) { |
| 209 | if (path.isEmpty()) { |
| 210 | return Type::kEmpty; |
| 211 | } |
| 212 | if (path.isRRect(rrect)) { |
bsalomon | 5e410b4 | 2016-04-28 09:30:46 -0700 | [diff] [blame] | 213 | SkASSERT(!rrect->isEmpty()); |
bsalomon | 72dc51c | 2016-04-27 06:46:23 -0700 | [diff] [blame] | 214 | return Type::kRRect; |
| 215 | } |
| 216 | SkRect rect; |
| 217 | if (path.isOval(&rect)) { |
| 218 | rrect->setOval(rect); |
| 219 | return Type::kRRect; |
| 220 | } |
| 221 | bool closed; |
| 222 | if (path.isRect(&rect, &closed, nullptr)) { |
| 223 | if (closed || (!pe && strokeRec.isFillStyle())) { |
| 224 | rrect->setRect(rect); |
| 225 | return Type::kRRect; |
| 226 | } |
| 227 | } |
| 228 | return Type::kPath; |
| 229 | } |
| 230 | |
| 231 | Type fType; |
bsalomon | 47cc769 | 2016-04-26 12:56:00 -0700 | [diff] [blame] | 232 | SkRRect fRRect; |
| 233 | SkTLazy<SkPath> fPath; |
| 234 | GrStyle fStyle; |
| 235 | SkAutoSTArray<8, uint32_t> fInheritedKey; |
| 236 | }; |
| 237 | #endif |