GrShape.cpp revision fb08327e592a1dd19a0c3107243ccd01f6b7f848
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 10GrShape& 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 40int 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 62void 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 86void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply) { 87 SkASSERT(!fInheritedKey.count()); 88 // If the output shape turns out to be simple, then we will just use its geometric key 89 if (Type::kPath == fType) { 90 // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key as 91 // ApplyFullStyle(shape). 92 // The full key is structured as (geo,path_effect,stroke). 93 // If we do ApplyPathEffect we get get,path_effect as the inherited key. If we then 94 // do ApplyFullStyle we'll memcpy geo,path_effect into the new inherited key 95 // and then append the style key (which should now be stroke only) at the end. 96 int parentCnt = parent.fInheritedKey.count(); 97 bool useParentGeoKey = !parentCnt; 98 if (useParentGeoKey) { 99 parentCnt = parent.unstyledKeySize(); 100 if (parentCnt < 0) { 101 // The parent's geometry has no key so we will have no key. 102 fPath.get()->setIsVolatile(true); 103 return; 104 } 105 } 106 int styleCnt = GrStyle::KeySize(parent.fStyle, apply); 107 if (styleCnt < 0) { 108 // The style doesn't allow a key, set the path to volatile so that we fail when 109 // we try to get a key for the shape. 110 fPath.get()->setIsVolatile(true); 111 return; 112 } 113 fInheritedKey.reset(parentCnt + styleCnt); 114 if (useParentGeoKey) { 115 // This will be the geo key. 116 parent.writeUnstyledKey(fInheritedKey.get()); 117 } else { 118 // This should be (geo,path_effect). 119 memcpy(fInheritedKey.get(), parent.fInheritedKey.get(), 120 parentCnt * sizeof(uint32_t)); 121 } 122 // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke) 123 GrStyle::WriteKey(fInheritedKey.get() + parentCnt, parent.fStyle, apply); 124 } 125} 126 127GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) { 128 switch (fType) { 129 case Type::kEmpty: 130 return; 131 case Type::kRRect: 132 fRRect = that.fRRect; 133 return; 134 case Type::kPath: 135 fPath.set(*that.fPath.get()); 136 return; 137 } 138 fInheritedKey.reset(that.fInheritedKey.count()); 139 memcpy(fInheritedKey.get(), that.fInheritedKey.get(), 140 sizeof(uint32_t) * fInheritedKey.count()); 141} 142 143GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply) { 144 if (!parent.style().applies() || 145 (GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect())) { 146 fType = Type::kEmpty; 147 *this = parent; 148 return; 149 } 150 151 SkPathEffect* pe = parent.fStyle.pathEffect(); 152 SkTLazy<SkPath> tmpPath; 153 const GrShape* parentForKey = &parent; 154 SkTLazy<GrShape> tmpParent; 155 fType = Type::kPath; 156 fPath.init(); 157 if (pe) { 158 SkPath* srcForPathEffect; 159 if (parent.fType == Type::kPath) { 160 srcForPathEffect = parent.fPath.get(); 161 } else { 162 srcForPathEffect = tmpPath.init(); 163 parent.asPath(tmpPath.get()); 164 } 165 // Should we consider bounds? Would have to include in key, but it'd be nice to know 166 // if the bounds actually modified anything before including in key. 167 SkStrokeRec strokeRec = parent.fStyle.strokeRec(); 168 if (!pe->filterPath(fPath.get(), *srcForPathEffect, &strokeRec, nullptr)) { 169 // Make an empty unstyled shape if filtering fails. 170 fType = Type::kEmpty; 171 fStyle = GrStyle(); 172 fPath.reset(); 173 return; 174 } 175 if (GrStyle::Apply::kPathEffectAndStrokeRec == apply) { 176 if (strokeRec.needToApply()) { 177 // The intermediate shape may not be a general path. If we we're just applying 178 // the path effect then attemptToReduceFromPath would catch it. This means that 179 // when we subsequently applied the remaining strokeRec we would have a non-path 180 // parent shape that would be used to determine the the stroked path's key. 181 // We detect that case here and change parentForKey to a temporary that represents 182 // the simpler shape so that applying both path effect and the strokerec all at 183 // once produces the same key. 184 SkRRect rrect; 185 Type parentType = AttemptToReduceFromPathImpl(*fPath.get(), &rrect, nullptr, 186 strokeRec); 187 switch (parentType) { 188 case Type::kEmpty: 189 tmpParent.init(); 190 parentForKey = tmpParent.get(); 191 break; 192 case Type::kRRect: 193 tmpParent.init(rrect, GrStyle(strokeRec, nullptr)); 194 parentForKey = tmpParent.get(); 195 case Type::kPath: 196 break; 197 } 198 SkAssertResult(strokeRec.applyToPath(fPath.get(), *fPath.get())); 199 } else { 200 fStyle = GrStyle(strokeRec, nullptr); 201 } 202 } else { 203 fStyle = GrStyle(strokeRec, nullptr); 204 } 205 } else { 206 const SkPath* srcForStrokeRec; 207 if (parent.fType == Type::kPath) { 208 srcForStrokeRec = parent.fPath.get(); 209 } else { 210 srcForStrokeRec = tmpPath.init(); 211 parent.asPath(tmpPath.get()); 212 } 213 SkASSERT(parent.fStyle.strokeRec().needToApply()); 214 SkAssertResult(parent.fStyle.strokeRec().applyToPath(fPath.get(), *srcForStrokeRec)); 215 fStyle.resetToInitStyle(SkStrokeRec::kFill_InitStyle); 216 } 217 this->attemptToReduceFromPath(); 218 this->setInheritedKey(*parentForKey, apply); 219} 220