OLD | NEW |
(Empty) | |
| 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 #include "GrShape.h" |
| 9 |
| 10 GrShape& GrShape::operator=(const GrShape& that) { |
| 11 bool wasPath = Type::kPath == fType; |
| 12 fStyle = that.fStyle; |
| 13 fType = that.fType; |
| 14 switch (fType) { |
| 15 case Type::kEmpty: |
| 16 if (wasPath) { |
| 17 fPath.reset(); |
| 18 } |
| 19 break; |
| 20 case Type::kRRect: |
| 21 if (wasPath) { |
| 22 fPath.reset(); |
| 23 } |
| 24 fRRect = that.fRRect; |
| 25 break; |
| 26 case Type::kPath: |
| 27 if (wasPath) { |
| 28 *fPath.get() = *that.fPath.get(); |
| 29 } else { |
| 30 fPath.set(*that.fPath.get()); |
| 31 } |
| 32 break; |
| 33 } |
| 34 fInheritedKey.reset(that.fInheritedKey.count()); |
| 35 memcpy(fInheritedKey.get(), that.fInheritedKey.get(), |
| 36 sizeof(uint32_t) * fInheritedKey.count()); |
| 37 return *this; |
| 38 } |
| 39 |
| 40 int GrShape::unstyledKeySize() const { |
| 41 if (fInheritedKey.count()) { |
| 42 return fInheritedKey.count(); |
| 43 } |
| 44 switch (fType) { |
| 45 case Type::kEmpty: |
| 46 return 1; |
| 47 case Type::kRRect: |
| 48 SkASSERT(!fInheritedKey.count()); |
| 49 SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t)); |
| 50 return SkRRect::kSizeInMemory / sizeof(uint32_t); |
| 51 case Type::kPath: |
| 52 if (fPath.get()->isVolatile()) { |
| 53 return -1; |
| 54 } else { |
| 55 return 1; |
| 56 } |
| 57 } |
| 58 SkFAIL("Should never get here."); |
| 59 return 0; |
| 60 } |
| 61 |
| 62 void GrShape::writeUnstyledKey(uint32_t* key) const { |
| 63 SkASSERT(this->unstyledKeySize()); |
| 64 SkDEBUGCODE(uint32_t* origKey = key;) |
| 65 if (fInheritedKey.count()) { |
| 66 memcpy(key, fInheritedKey.get(), sizeof(uint32_t) * fInheritedKey.count(
)); |
| 67 SkDEBUGCODE(key += fInheritedKey.count();) |
| 68 } else { |
| 69 switch (fType) { |
| 70 case Type::kEmpty: |
| 71 *key++ = 1; |
| 72 break; |
| 73 case Type::kRRect: |
| 74 fRRect.writeToMemory(key); |
| 75 key += SkRRect::kSizeInMemory / sizeof(uint32_t); |
| 76 break; |
| 77 case Type::kPath: |
| 78 SkASSERT(!fPath.get()->isVolatile()); |
| 79 *key++ = fPath.get()->getGenerationID(); |
| 80 break; |
| 81 } |
| 82 } |
| 83 SkASSERT(key - origKey == this->unstyledKeySize()); |
| 84 } |
| 85 |
| 86 int GrShape::StyleKeySize(const GrStyle& style, bool stopAfterPE) { |
| 87 GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar)); |
| 88 int size = 0; |
| 89 if (style.isDashed()) { |
| 90 // One scalar for dash phase and one for each dash value. |
| 91 size += 1 + style.dashIntervalCnt(); |
| 92 } else if (style.pathEffect()) { |
| 93 // No key for a generic path effect. |
| 94 return -1; |
| 95 } |
| 96 |
| 97 if (stopAfterPE) { |
| 98 return size; |
| 99 } |
| 100 |
| 101 if (style.strokeRec().needToApply()) { |
| 102 // One for style/cap/join, 2 for miter and width. |
| 103 size += 3; |
| 104 } |
| 105 return size; |
| 106 } |
| 107 |
| 108 void GrShape::StyleKey(uint32_t* key, const GrStyle& style, bool stopAfterPE) { |
| 109 SkASSERT(key); |
| 110 SkASSERT(StyleKeySize(style, stopAfterPE) >= 0); |
| 111 GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar)); |
| 112 |
| 113 int i = 0; |
| 114 if (style.isDashed()) { |
| 115 GR_STATIC_ASSERT(sizeof(style.dashPhase()) == sizeof(uint32_t)); |
| 116 SkScalar phase = style.dashPhase(); |
| 117 memcpy(&key[i++], &phase, sizeof(SkScalar)); |
| 118 |
| 119 int32_t count = style.dashIntervalCnt(); |
| 120 // Dash count should always be even. |
| 121 SkASSERT(0 == (count & 0x1)); |
| 122 const SkScalar* intervals = style.dashIntervals(); |
| 123 int intervalByteCnt = count * sizeof(SkScalar); |
| 124 memcpy(&key[i], intervals, intervalByteCnt); |
| 125 i += count; |
| 126 } else { |
| 127 SkASSERT(!style.pathEffect()); |
| 128 } |
| 129 |
| 130 if (!stopAfterPE && style.strokeRec().needToApply()) { |
| 131 enum { |
| 132 kStyleBits = 2, |
| 133 kJoinBits = 2, |
| 134 kCapBits = 32 - kStyleBits - kJoinBits, |
| 135 |
| 136 kJoinShift = kStyleBits, |
| 137 kCapShift = kJoinShift + kJoinBits, |
| 138 }; |
| 139 GR_STATIC_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits)); |
| 140 GR_STATIC_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits)); |
| 141 GR_STATIC_ASSERT(SkPaint::kCapCount <= (1 << kCapBits)); |
| 142 key[i++] = style.strokeRec().getStyle() | |
| 143 style.strokeRec().getJoin() << kJoinShift | |
| 144 style.strokeRec().getCap() << kCapShift; |
| 145 |
| 146 SkScalar scalar; |
| 147 // Miter limit only affects miter joins |
| 148 scalar = SkPaint::kMiter_Join == style.strokeRec().getJoin() |
| 149 ? style.strokeRec().getMiter() |
| 150 : -1.f; |
| 151 memcpy(&key[i++], &scalar, sizeof(scalar)); |
| 152 |
| 153 scalar = style.strokeRec().getWidth(); |
| 154 memcpy(&key[i++], &scalar, sizeof(scalar)); |
| 155 } |
| 156 SkASSERT(StyleKeySize(style, stopAfterPE) == i); |
| 157 } |
| 158 |
| 159 void GrShape::setInheritedKey(const GrShape &parent, bool stopAfterPE){ |
| 160 SkASSERT(!fInheritedKey.count()); |
| 161 // If the output shape turns out to be simple, then we will just use its geo
metric key |
| 162 if (Type::kPath == fType) { |
| 163 // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key a
s |
| 164 // ApplyFullStyle(shape). |
| 165 // The full key is structured as (geo,path_effect,stroke). |
| 166 // If we do ApplyPathEffect we get get,path_effect as the inherited key.
If we then |
| 167 // do ApplyFullStyle we'll memcpy geo,path_effect into the new inherited
key |
| 168 // and then append the style key (which should now be stroke only) at th
e end. |
| 169 int parentCnt = parent.fInheritedKey.count(); |
| 170 bool useParentGeoKey = !parentCnt; |
| 171 if (useParentGeoKey) { |
| 172 parentCnt = parent.unstyledKeySize(); |
| 173 } |
| 174 int styleCnt = StyleKeySize(parent.fStyle, stopAfterPE); |
| 175 if (styleCnt < 0) { |
| 176 // The style doesn't allow a key, set the path to volatile so that w
e fail when |
| 177 // we try to get a key for the shape. |
| 178 fPath.get()->setIsVolatile(true); |
| 179 } else { |
| 180 fInheritedKey.reset(parentCnt + styleCnt); |
| 181 if (useParentGeoKey) { |
| 182 // This will be the geo key. |
| 183 parent.writeUnstyledKey(fInheritedKey.get()); |
| 184 } else { |
| 185 // This should be geo,path_effect |
| 186 memcpy(fInheritedKey.get(), parent.fInheritedKey.get(), |
| 187 parentCnt * sizeof(uint32_t)); |
| 188 } |
| 189 // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke) |
| 190 StyleKey(fInheritedKey.get() + parentCnt, parent.fStyle, stopAfterPE
); |
| 191 } |
| 192 } |
| 193 } |
| 194 |
| 195 GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) { |
| 196 switch (fType) { |
| 197 case Type::kEmpty: |
| 198 return; |
| 199 case Type::kRRect: |
| 200 fRRect = that.fRRect; |
| 201 return; |
| 202 case Type::kPath: |
| 203 fPath.set(*that.fPath.get()); |
| 204 return; |
| 205 } |
| 206 fInheritedKey.reset(that.fInheritedKey.count()); |
| 207 memcpy(fInheritedKey.get(), that.fInheritedKey.get(), |
| 208 sizeof(uint32_t) * fInheritedKey.count()); |
| 209 } |
| 210 |
| 211 GrShape::GrShape(const GrShape& parent, bool stopAfterPE) { |
| 212 fType = Type::kEmpty; |
| 213 SkPathEffect* pe = parent.fStyle.pathEffect(); |
| 214 const SkPath* inPath; |
| 215 SkStrokeRec strokeRec = parent.fStyle.strokeRec(); |
| 216 if (pe) { |
| 217 fType = Type::kPath; |
| 218 fPath.init(); |
| 219 if (parent.fType == Type::kPath) { |
| 220 inPath = parent.fPath.get(); |
| 221 } else { |
| 222 inPath = fPath.get(); |
| 223 parent.asPath(fPath.get()); |
| 224 } |
| 225 // Should we consider bounds? Would have to include in key, but it'd be
nice to know |
| 226 // if the bounds actually modified anything before including in key. |
| 227 if (!pe->filterPath(fPath.get(), *inPath, &strokeRec, nullptr)) { |
| 228 // Make an empty unstyled shape if filtering fails. |
| 229 fType = Type::kEmpty; |
| 230 fStyle = GrStyle(); |
| 231 fPath.reset(); |
| 232 return; |
| 233 } |
| 234 inPath = fPath.get(); |
| 235 } else if (stopAfterPE || !strokeRec.needToApply()) { |
| 236 *this = parent; |
| 237 return; |
| 238 } else { |
| 239 fType = Type::kPath; |
| 240 fPath.init(); |
| 241 if (parent.fType == Type::kPath) { |
| 242 inPath = parent.fPath.get(); |
| 243 } else { |
| 244 inPath = fPath.get(); |
| 245 parent.asPath(fPath.get()); |
| 246 } |
| 247 } |
| 248 if (!stopAfterPE) { |
| 249 strokeRec.applyToPath(fPath.get(), *inPath); |
| 250 } else { |
| 251 fStyle = GrStyle(strokeRec, nullptr); |
| 252 } |
| 253 this->setInheritedKey(parent, stopAfterPE); |
| 254 } |
OLD | NEW |