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 #include "GrShape.h" | 8 #include "GrShape.h" |
| 9 | 9 |
| 10 GrShape& GrShape::operator=(const GrShape& that) { | 10 GrShape& GrShape::operator=(const GrShape& that) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 fRRectDir = that.fRRectDir; | 25 fRRectDir = that.fRRectDir; |
| 26 fRRectStart = that.fRRectStart; | 26 fRRectStart = that.fRRectStart; |
| 27 fRRectIsInverted = that.fRRectIsInverted; | 27 fRRectIsInverted = that.fRRectIsInverted; |
| 28 break; | 28 break; |
| 29 case Type::kPath: | 29 case Type::kPath: |
| 30 if (wasPath) { | 30 if (wasPath) { |
| 31 *fPath.get() = *that.fPath.get(); | 31 *fPath.get() = *that.fPath.get(); |
| 32 } else { | 32 } else { |
| 33 fPath.set(*that.fPath.get()); | 33 fPath.set(*that.fPath.get()); |
| 34 } | 34 } |
| 35 fPathGenID = that.fPathGenID; | |
| 35 break; | 36 break; |
| 36 } | 37 } |
| 37 fInheritedKey.reset(that.fInheritedKey.count()); | 38 fInheritedKey.reset(that.fInheritedKey.count()); |
| 38 sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(), | 39 sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(), |
| 39 sizeof(uint32_t) * fInheritedKey.count()); | 40 sizeof(uint32_t) * fInheritedKey.count()); |
| 40 return *this; | 41 return *this; |
| 41 } | 42 } |
| 42 | 43 |
| 43 const SkRect& GrShape::bounds() const { | 44 const SkRect& GrShape::bounds() const { |
| 44 static constexpr SkRect kEmpty = SkRect::MakeEmpty(); | 45 static constexpr SkRect kEmpty = SkRect::MakeEmpty(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 68 } | 69 } |
| 69 switch (fType) { | 70 switch (fType) { |
| 70 case Type::kEmpty: | 71 case Type::kEmpty: |
| 71 return 1; | 72 return 1; |
| 72 case Type::kRRect: | 73 case Type::kRRect: |
| 73 SkASSERT(!fInheritedKey.count()); | 74 SkASSERT(!fInheritedKey.count()); |
| 74 SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t)); | 75 SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t)); |
| 75 // + 1 for the direction, start index, and inverseness. | 76 // + 1 for the direction, start index, and inverseness. |
| 76 return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1; | 77 return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1; |
| 77 case Type::kPath: | 78 case Type::kPath: |
| 78 if (fPath.get()->isVolatile()) { | 79 if (0 == fPathGenID) { |
| 79 return -1; | 80 return -1; |
| 80 } else { | 81 } else { |
| 81 // The key is the path ID and fill type. | 82 // The key is the path ID and fill type. |
| 82 return 2; | 83 return 2; |
| 83 } | 84 } |
| 84 } | 85 } |
| 85 SkFAIL("Should never get here."); | 86 SkFAIL("Should never get here."); |
| 86 return 0; | 87 return 0; |
| 87 } | 88 } |
| 88 | 89 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 99 break; | 100 break; |
| 100 case Type::kRRect: | 101 case Type::kRRect: |
| 101 fRRect.writeToMemory(key); | 102 fRRect.writeToMemory(key); |
| 102 key += SkRRect::kSizeInMemory / sizeof(uint32_t); | 103 key += SkRRect::kSizeInMemory / sizeof(uint32_t); |
| 103 *key = (fRRectDir == SkPath::kCCW_Direction) ? (1 << 31) : 0; | 104 *key = (fRRectDir == SkPath::kCCW_Direction) ? (1 << 31) : 0; |
| 104 *key |= fRRectIsInverted ? (1 << 30) : 0; | 105 *key |= fRRectIsInverted ? (1 << 30) : 0; |
| 105 *key++ |= fRRectStart; | 106 *key++ |= fRRectStart; |
| 106 SkASSERT(fRRectStart < 8); | 107 SkASSERT(fRRectStart < 8); |
| 107 break; | 108 break; |
| 108 case Type::kPath: | 109 case Type::kPath: |
| 109 SkASSERT(!fPath.get()->isVolatile()); | 110 SkASSERT(fPathGenID); |
| 110 *key++ = fPath.get()->getGenerationID(); | 111 *key++ = fPathGenID; |
| 111 // We could canonicalize the fill rule for paths that don't diff erentiate between | 112 // We could canonicalize the fill rule for paths that don't diff erentiate between |
| 112 // even/odd or winding fill (e.g. convex). | 113 // even/odd or winding fill (e.g. convex). |
| 113 *key++ = fPath.get()->getFillType(); | 114 *key++ = fPath.get()->getFillType(); |
| 114 break; | 115 break; |
| 115 } | 116 } |
| 116 } | 117 } |
| 117 SkASSERT(key - origKey == this->unstyledKeySize()); | 118 SkASSERT(key - origKey == this->unstyledKeySize()); |
| 118 } | 119 } |
| 119 | 120 |
| 120 void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkSca lar scale) { | 121 void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkSca lar scale) { |
| 121 SkASSERT(!fInheritedKey.count()); | 122 SkASSERT(!fInheritedKey.count()); |
| 122 // If the output shape turns out to be simple, then we will just use its geo metric key | 123 // If the output shape turns out to be simple, then we will just use its geo metric key |
| 123 if (Type::kPath == fType) { | 124 if (Type::kPath == fType) { |
| 124 // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key a s | 125 // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key a s |
| 125 // ApplyFullStyle(shape). | 126 // ApplyFullStyle(shape). |
| 126 // The full key is structured as (geo,path_effect,stroke). | 127 // The full key is structured as (geo,path_effect,stroke). |
| 127 // If we do ApplyPathEffect we get get,path_effect as the inherited key. If we then | 128 // If we do ApplyPathEffect we get get,path_effect as the inherited key. If we then |
| 128 // do ApplyFullStyle we'll memcpy geo,path_effect into the new inherited key | 129 // do ApplyFullStyle we'll memcpy geo,path_effect into the new inherited key |
| 129 // and then append the style key (which should now be stroke only) at th e end. | 130 // and then append the style key (which should now be stroke only) at th e end. |
| 130 int parentCnt = parent.fInheritedKey.count(); | 131 int parentCnt = parent.fInheritedKey.count(); |
| 131 bool useParentGeoKey = !parentCnt; | 132 bool useParentGeoKey = !parentCnt; |
| 132 if (useParentGeoKey) { | 133 if (useParentGeoKey) { |
| 133 parentCnt = parent.unstyledKeySize(); | 134 parentCnt = parent.unstyledKeySize(); |
| 134 if (parentCnt < 0) { | 135 if (parentCnt < 0) { |
| 135 // The parent's geometry has no key so we will have no key. | 136 // The parent's geometry has no key so we will have no key. |
| 136 fPath.get()->setIsVolatile(true); | 137 fPathGenID = 0; |
| 137 return; | 138 return; |
| 138 } | 139 } |
| 139 } | 140 } |
| 140 uint32_t styleKeyFlags = 0; | 141 uint32_t styleKeyFlags = 0; |
| 141 if (parent.knownToBeClosed()) { | 142 if (parent.knownToBeClosed()) { |
| 142 styleKeyFlags |= GrStyle::kClosed_KeyFlag; | 143 styleKeyFlags |= GrStyle::kClosed_KeyFlag; |
| 143 } | 144 } |
| 144 int styleCnt = GrStyle::KeySize(parent.fStyle, apply, styleKeyFlags); | 145 int styleCnt = GrStyle::KeySize(parent.fStyle, apply, styleKeyFlags); |
| 145 if (styleCnt < 0) { | 146 if (styleCnt < 0) { |
| 146 // The style doesn't allow a key, set the path to volatile so that w e fail when | 147 // The style doesn't allow a key, set the path gen ID to 0 so that w e fail when |
| 147 // we try to get a key for the shape. | 148 // we try to get a key for the shape. |
| 148 fPath.get()->setIsVolatile(true); | 149 fPathGenID = 0; |
| 149 return; | 150 return; |
| 150 } | 151 } |
| 151 fInheritedKey.reset(parentCnt + styleCnt); | 152 fInheritedKey.reset(parentCnt + styleCnt); |
| 152 if (useParentGeoKey) { | 153 if (useParentGeoKey) { |
| 153 // This will be the geo key. | 154 // This will be the geo key. |
| 154 parent.writeUnstyledKey(fInheritedKey.get()); | 155 parent.writeUnstyledKey(fInheritedKey.get()); |
| 155 } else { | 156 } else { |
| 156 // This should be (geo,path_effect). | 157 // This should be (geo,path_effect). |
| 157 memcpy(fInheritedKey.get(), parent.fInheritedKey.get(), | 158 memcpy(fInheritedKey.get(), parent.fInheritedKey.get(), |
| 158 parentCnt * sizeof(uint32_t)); | 159 parentCnt * sizeof(uint32_t)); |
| 159 } | 160 } |
| 160 // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke) | 161 // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke) |
| 161 GrStyle::WriteKey(fInheritedKey.get() + parentCnt, parent.fStyle, apply, scale, | 162 GrStyle::WriteKey(fInheritedKey.get() + parentCnt, parent.fStyle, apply, scale, |
| 162 styleKeyFlags); | 163 styleKeyFlags); |
| 163 } | 164 } |
| 164 } | 165 } |
| 165 | 166 |
| 166 GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) { | 167 GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) { |
| 167 switch (fType) { | 168 switch (fType) { |
| 168 case Type::kEmpty: | 169 case Type::kEmpty: |
| 169 return; | 170 break; |
| 170 case Type::kRRect: | 171 case Type::kRRect: |
| 171 fRRect = that.fRRect; | 172 fRRect = that.fRRect; |
| 172 fRRectDir = that.fRRectDir; | 173 fRRectDir = that.fRRectDir; |
| 173 fRRectStart = that.fRRectStart; | 174 fRRectStart = that.fRRectStart; |
| 174 fRRectIsInverted = that.fRRectIsInverted; | 175 fRRectIsInverted = that.fRRectIsInverted; |
| 175 return; | 176 break; |
| 176 case Type::kPath: | 177 case Type::kPath: |
| 177 fPath.set(*that.fPath.get()); | 178 fPath.set(*that.fPath.get()); |
| 178 return; | 179 fPathGenID = that.fPathGenID; |
| 180 break; | |
| 179 } | 181 } |
| 180 fInheritedKey.reset(that.fInheritedKey.count()); | 182 fInheritedKey.reset(that.fInheritedKey.count()); |
| 181 memcpy(fInheritedKey.get(), that.fInheritedKey.get(), | 183 sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(), |
| 182 sizeof(uint32_t) * fInheritedKey.count()); | 184 sizeof(uint32_t) * fInheritedKey.count()); |
| 183 } | 185 } |
| 184 | 186 |
| 185 GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) { | 187 GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) { |
| 186 // TODO: Add some quantization of scale for better cache performance here or leave that up | 188 // TODO: Add some quantization of scale for better cache performance here or leave that up |
| 187 // to caller? | 189 // to caller? |
| 188 // TODO: For certain shapes and stroke params we could ignore the scale. (e. g. miter or bevel | 190 // TODO: For certain shapes and stroke params we could ignore the scale. (e. g. miter or bevel |
| 189 // stroke of a rect). | 191 // stroke of a rect). |
| 190 if (!parent.style().applies() || | 192 if (!parent.style().applies() || |
| 191 (GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect( ))) { | 193 (GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect( ))) { |
| 192 fType = Type::kEmpty; | 194 fType = Type::kEmpty; |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 308 fType = Type::kRRect; | 310 fType = Type::kRRect; |
| 309 } | 311 } |
| 310 } | 312 } |
| 311 } | 313 } |
| 312 if (Type::kPath != fType) { | 314 if (Type::kPath != fType) { |
| 313 fPath.reset(); | 315 fPath.reset(); |
| 314 fInheritedKey.reset(0); | 316 fInheritedKey.reset(0); |
| 315 if (Type::kRRect == fType) { | 317 if (Type::kRRect == fType) { |
| 316 this->attemptToSimplifyRRect(); | 318 this->attemptToSimplifyRRect(); |
| 317 } | 319 } |
| 320 } else { | |
| 321 if (fInheritedKey.count() || fPath.get()->isVolatile()) { | |
| 322 fPathGenID = 0; | |
| 323 } else { | |
| 324 fPathGenID = fPath.get()->getGenerationID(); | |
| 325 } | |
| 326 if (this->style().isSimpleFill()) { | |
| 327 // Filled paths are treated as though all their contours were closed . | |
| 328 // Since SkPath doesn't track individual contours, this will only cl ose the last. :( | |
| 329 // There is no point in closing lines, though, since they loose thei r line-ness. | |
|
bsalomon
2016/06/20 20:18:58
In the future we'll extract the line during simpli
| |
| 330 if (!fPath.get()->isLine(nullptr)) { | |
| 331 fPath.get()->close(); | |
| 332 fPath.get()->setIsVolatile(true); | |
| 333 } | |
| 334 } | |
| 335 if (fPath.get()->isConvex()) { | |
| 336 // There is no distinction between even/odd and non-zero winding cou nt for convex | |
| 337 // paths. | |
| 338 if (fPath.get()->isInverseFillType()) { | |
| 339 fPath.get()->setFillType(SkPath::kInverseEvenOdd_FillType); | |
| 340 } else { | |
| 341 fPath.get()->setFillType(SkPath::kEvenOdd_FillType); | |
| 342 } | |
| 343 } | |
| 344 if (this->style().isDashed()) { | |
| 345 // Dashing ignores inverseness (skbug.com/5421) | |
| 346 switch (fPath.get()->getFillType()) { | |
| 347 case SkPath::kWinding_FillType: | |
| 348 case SkPath::kEvenOdd_FillType: | |
| 349 break; | |
| 350 case SkPath::kInverseWinding_FillType: | |
| 351 fPath.get()->setFillType(SkPath::kWinding_FillType); | |
| 352 break; | |
| 353 case SkPath::kInverseEvenOdd_FillType: | |
| 354 fPath.get()->setFillType(SkPath::kEvenOdd_FillType); | |
| 355 break; | |
| 356 } | |
| 357 } | |
| 318 } | 358 } |
| 319 } | 359 } |
| 320 | 360 |
| 321 void GrShape::attemptToSimplifyRRect() { | 361 void GrShape::attemptToSimplifyRRect() { |
| 322 SkASSERT(Type::kRRect == fType); | 362 SkASSERT(Type::kRRect == fType); |
| 323 SkASSERT(!fInheritedKey.count()); | 363 SkASSERT(!fInheritedKey.count()); |
| 324 if (fRRect.isEmpty()) { | 364 if (fRRect.isEmpty()) { |
| 325 fType = Type::kEmpty; | 365 fType = Type::kEmpty; |
| 326 return; | 366 return; |
| 327 } | 367 } |
| 328 if (!this->style().hasPathEffect()) { | 368 if (!this->style().hasPathEffect()) { |
| 329 fRRectDir = kDefaultRRectDir; | 369 fRRectDir = kDefaultRRectDir; |
| 330 fRRectStart = kDefaultRRectStart; | 370 fRRectStart = kDefaultRRectStart; |
| 331 } else if (fStyle.isDashed()) { | 371 } else if (fStyle.isDashed()) { |
| 332 // Dashing ignores the inverseness (currently). skbug.com/5421 | 372 // Dashing ignores the inverseness (currently). skbug.com/5421 |
| 333 fRRectIsInverted = false; | 373 fRRectIsInverted = false; |
| 334 } | 374 } |
| 335 } | 375 } |
| OLD | NEW |