Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2012 Google Inc. | 3 * Copyright 2012 Google Inc. |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #ifndef SkPathRef_DEFINED | 9 #ifndef SkPathRef_DEFINED |
| 10 #define SkPathRef_DEFINED | 10 #define SkPathRef_DEFINED |
| 11 | 11 |
| 12 #include "SkMatrix.h" | 12 #include "SkMatrix.h" |
| 13 #include "SkPoint.h" | 13 #include "SkPoint.h" |
| 14 #include "SkRect.h" | 14 #include "SkRect.h" |
| 15 #include "SkRefCnt.h" | 15 #include "SkRefCnt.h" |
| 16 #include "SkTDArray.h" | 16 #include "SkTDArray.h" |
| 17 #include <stddef.h> // ptrdiff_t | 17 #include <stddef.h> // ptrdiff_t |
| 18 | 18 |
| 19 class SkRBuffer; | 19 class SkRBuffer; |
| 20 class SkWBuffer; | 20 class SkWBuffer; |
| 21 | 21 |
| 22 // TODO: refactor this header to move more of the implementation into the .cpp | |
| 23 | |
| 24 /** | 22 /** |
| 25 * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods | 23 * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods |
| 26 * modify the contents. To modify or append to the verbs/points wrap the SkPathR ef in an | 24 * modify the contents. To modify or append to the verbs/points wrap the SkPathR ef in an |
| 27 * SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs | 25 * SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs |
| 28 * copy-on-write if the SkPathRef is shared by multipls SkPaths. The caller pass es the Editor's | 26 * copy-on-write if the SkPathRef is shared by multipls SkPaths. The caller pass es the Editor's |
| 29 * constructor a SkAutoTUnref, which may be updated to point to a new SkPathRef after the editor's | 27 * constructor a SkAutoTUnref, which may be updated to point to a new SkPathRef after the editor's |
| 30 * constructor returns. | 28 * constructor returns. |
| 31 * | 29 * |
| 32 * The points and verbs are stored in a single allocation. The points are at the begining of the | 30 * The points and verbs are stored in a single allocation. The points are at the begining of the |
| 33 * allocation while the verbs are stored at end of the allocation, in reverse or der. Thus the points | 31 * allocation while the verbs are stored at end of the allocation, in reverse or der. Thus the points |
| 34 * and verbs both grow into the middle of the allocation until the meet. To acce ss verb i in the | 32 * and verbs both grow into the middle of the allocation until the meet. To acce ss verb i in the |
| 35 * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first | 33 * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first |
| 36 * logical verb or the last verb in memory). | 34 * logical verb or the last verb in memory). |
| 37 */ | 35 */ |
| 38 | 36 |
| 39 class SkPathRef : public ::SkRefCnt { | 37 class SkPathRef : public ::SkRefCnt { |
| 40 public: | 38 public: |
| 41 SK_DECLARE_INST_COUNT(SkPathRef); | 39 SK_DECLARE_INST_COUNT(SkPathRef); |
| 42 | 40 |
| 43 class Editor { | 41 class Editor { |
| 44 public: | 42 public: |
| 45 Editor(SkAutoTUnref<SkPathRef>* pathRef, | 43 Editor(SkAutoTUnref<SkPathRef>* pathRef, |
| 46 int incReserveVerbs = 0, | 44 int incReserveVerbs = 0, |
| 47 int incReservePoints = 0) | 45 int incReservePoints = 0); |
| 48 { | |
| 49 if ((*pathRef)->unique()) { | |
| 50 (*pathRef)->incReserve(incReserveVerbs, incReservePoints); | |
| 51 } else { | |
| 52 SkPathRef* copy = SkNEW(SkPathRef); | |
| 53 copy->copy(**pathRef, incReserveVerbs, incReservePoints); | |
| 54 pathRef->reset(copy); | |
| 55 } | |
| 56 fPathRef = *pathRef; | |
| 57 fPathRef->fGenerationID = 0; | |
| 58 SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);) | |
| 59 } | |
| 60 | 46 |
| 61 ~Editor() { SkDEBUGCODE(sk_atomic_dec(&fPathRef->fEditorsAttached);) } | 47 ~Editor() { SkDEBUGCODE(sk_atomic_dec(&fPathRef->fEditorsAttached);) } |
| 62 | 48 |
| 63 /** | 49 /** |
| 64 * Returns the array of points. | 50 * Returns the array of points. |
| 65 */ | 51 */ |
| 66 SkPoint* points() { return fPathRef->fPoints; } | 52 SkPoint* points() { return fPathRef->fPoints; } |
| 67 | 53 |
| 68 /** | 54 /** |
| 69 * Gets the ith point. Shortcut for this->points() + i | 55 * Gets the ith point. Shortcut for this->points() + i |
| 70 */ | 56 */ |
| 71 SkPoint* atPoint(int i) { | 57 SkPoint* atPoint(int i) { |
| 72 SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); | 58 SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); |
| 73 return this->points() + i; | 59 return this->points() + i; |
| 74 }; | 60 }; |
| 75 | 61 |
| 76 /** | 62 /** |
| 77 * Adds the verb and allocates space for the number of points indicated by the verb. The | 63 * Adds the verb and allocates space for the number of points indicated by the verb. The |
| 78 * return value is a pointer to where the points for the verb should be written. | 64 * return value is a pointer to where the points for the verb should be written. |
| 79 */ | 65 */ |
| 80 SkPoint* growForVerb(int /*SkPath::Verb*/ verb); | 66 SkPoint* growForVerb(int /*SkPath::Verb*/ verb) { |
| 67 fPathRef->validate(); | |
| 68 return fPathRef->growForVerb(verb); | |
| 69 } | |
| 81 | 70 |
| 82 SkPoint* growForConic(SkScalar w); | 71 SkPoint* growForConic(SkScalar w); |
| 83 | 72 |
| 84 /** | 73 /** |
| 85 * Allocates space for additional verbs and points and returns pointers to the new verbs and | 74 * Allocates space for additional verbs and points and returns pointers to the new verbs and |
| 86 * points. verbs will point one beyond the first new verb (index it usin g [~<i>]). pts points | 75 * points. verbs will point one beyond the first new verb (index it usin g [~<i>]). pts points |
| 87 * at the first new point (indexed normally [<i>]). | 76 * at the first new point (indexed normally [<i>]). |
| 88 */ | 77 */ |
| 89 void grow(int newVerbs, int newPts, uint8_t** verbs, SkPoint** pts) { | 78 void grow(int newVerbs, int newPts, uint8_t** verbs, SkPoint** pts); |
|
bsalomon
2013/09/27 15:58:51
I somewhat question this one. In release build thi
robertphillips
2013/09/27 16:13:30
Done.
| |
| 90 SkASSERT(NULL != verbs); | |
| 91 SkASSERT(NULL != pts); | |
| 92 fPathRef->validate(); | |
| 93 int oldVerbCnt = fPathRef->fVerbCnt; | |
| 94 int oldPointCnt = fPathRef->fPointCnt; | |
| 95 SkASSERT(verbs && pts); | |
| 96 fPathRef->grow(newVerbs, newPts); | |
| 97 *verbs = fPathRef->fVerbs - oldVerbCnt; | |
| 98 *pts = fPathRef->fPoints + oldPointCnt; | |
| 99 fPathRef->validate(); | |
| 100 } | |
| 101 | 79 |
| 102 /** | 80 /** |
| 103 * Resets the path ref to a new verb and point count. The new verbs and points are | 81 * Resets the path ref to a new verb and point count. The new verbs and points are |
| 104 * uninitialized. | 82 * uninitialized. |
| 105 */ | 83 */ |
| 106 void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { | 84 void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { |
| 107 fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); | 85 fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); |
| 108 } | 86 } |
| 109 /** | 87 /** |
| 110 * Gets the path ref that is wrapped in the Editor. | 88 * Gets the path ref that is wrapped in the Editor. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 159 fBounds = rect; | 137 fBounds = rect; |
| 160 fBoundsIsDirty = false; | 138 fBoundsIsDirty = false; |
| 161 fIsFinite = fBounds.isFinite(); | 139 fIsFinite = fBounds.isFinite(); |
| 162 } | 140 } |
| 163 | 141 |
| 164 /** | 142 /** |
| 165 * Transforms a path ref by a matrix, allocating a new one only if necessary . | 143 * Transforms a path ref by a matrix, allocating a new one only if necessary . |
| 166 */ | 144 */ |
| 167 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, | 145 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, |
| 168 const SkPathRef& src, | 146 const SkPathRef& src, |
| 169 const SkMatrix& matrix) { | 147 const SkMatrix& matrix); |
| 170 src.validate(); | |
| 171 if (matrix.isIdentity()) { | |
| 172 if (*dst != &src) { | |
| 173 src.ref(); | |
| 174 dst->reset(const_cast<SkPathRef*>(&src)); | |
| 175 (*dst)->validate(); | |
| 176 } | |
| 177 return; | |
| 178 } | |
| 179 | |
| 180 bool dstUnique = (*dst)->unique(); | |
| 181 if (!dstUnique) { | |
| 182 dst->reset(SkNEW(SkPathRef)); | |
| 183 (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.c ount()); | |
| 184 memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * sizeof(uint8_t)); | |
| 185 (*dst)->fConicWeights = src.fConicWeights; | |
| 186 } | |
| 187 | |
| 188 // Need to check this here in case (&src == dst) | |
| 189 bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && s rc.countPoints() > 1; | |
| 190 | |
| 191 matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt); | |
| 192 | |
| 193 /* | |
| 194 * Here we optimize the bounds computation, by noting if the bounds are | |
| 195 * already known, and if so, we just transform those as well and mark | |
| 196 * them as "known", rather than force the transformed path to have to | |
| 197 * recompute them. | |
| 198 * | |
| 199 * Special gotchas if the path is effectively empty (<= 1 point) or | |
| 200 * if it is non-finite. In those cases bounds need to stay empty, | |
| 201 * regardless of the matrix. | |
| 202 */ | |
| 203 if (canXformBounds) { | |
| 204 (*dst)->fBoundsIsDirty = false; | |
| 205 if (src.fIsFinite) { | |
| 206 matrix.mapRect(&(*dst)->fBounds, src.fBounds); | |
| 207 if (!((*dst)->fIsFinite = (*dst)->fBounds.isFinite())) { | |
| 208 (*dst)->fBounds.setEmpty(); | |
| 209 } | |
| 210 } else { | |
| 211 (*dst)->fIsFinite = false; | |
| 212 (*dst)->fBounds.setEmpty(); | |
| 213 } | |
| 214 } else { | |
| 215 (*dst)->fBoundsIsDirty = true; | |
| 216 } | |
| 217 | |
| 218 (*dst)->validate(); | |
| 219 } | |
| 220 | 148 |
| 221 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer | 149 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer |
| 222 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O | 150 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O |
| 223 , bool newFormat, int32_t oldPacked | 151 , bool newFormat, int32_t oldPacked |
| 224 #endif | 152 #endif |
| 225 ); | 153 ); |
| 226 | 154 |
| 227 /** | 155 /** |
| 228 * Rollsback a path ref to zero verbs and points with the assumption that th e path ref will be | 156 * Rollsback a path ref to zero verbs and points with the assumption that th e path ref will be |
| 229 * repopulated with approximately the same number of verbs and points. A new path ref is created | 157 * repopulated with approximately the same number of verbs and points. A new path ref is created |
| 230 * only if necessary. | 158 * only if necessary. |
| 231 */ | 159 */ |
| 232 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef) { | 160 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef); |
| 233 if ((*pathRef)->unique()) { | |
| 234 (*pathRef)->validate(); | |
| 235 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFini te | |
| 236 (*pathRef)->fVerbCnt = 0; | |
| 237 (*pathRef)->fPointCnt = 0; | |
| 238 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); | |
| 239 (*pathRef)->fGenerationID = 0; | |
| 240 (*pathRef)->fConicWeights.rewind(); | |
| 241 (*pathRef)->validate(); | |
| 242 } else { | |
| 243 int oldVCnt = (*pathRef)->countVerbs(); | |
| 244 int oldPCnt = (*pathRef)->countPoints(); | |
| 245 pathRef->reset(SkNEW(SkPathRef)); | |
| 246 (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt); | |
| 247 } | |
| 248 } | |
| 249 | 161 |
| 250 virtual ~SkPathRef() { | 162 virtual ~SkPathRef() { |
| 251 this->validate(); | 163 this->validate(); |
| 252 sk_free(fPoints); | 164 sk_free(fPoints); |
| 253 | 165 |
| 254 SkDEBUGCODE(fPoints = NULL;) | 166 SkDEBUGCODE(fPoints = NULL;) |
| 255 SkDEBUGCODE(fVerbs = NULL;) | 167 SkDEBUGCODE(fVerbs = NULL;) |
| 256 SkDEBUGCODE(fVerbCnt = 0x9999999;) | 168 SkDEBUGCODE(fVerbCnt = 0x9999999;) |
| 257 SkDEBUGCODE(fPointCnt = 0xAAAAAAA;) | 169 SkDEBUGCODE(fPointCnt = 0xAAAAAAA;) |
| 258 SkDEBUGCODE(fPointCnt = 0xBBBBBBB;) | 170 SkDEBUGCODE(fPointCnt = 0xBBBBBBB;) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 291 */ | 203 */ |
| 292 uint8_t atVerb(int index) { | 204 uint8_t atVerb(int index) { |
| 293 SkASSERT((unsigned) index < (unsigned) fVerbCnt); | 205 SkASSERT((unsigned) index < (unsigned) fVerbCnt); |
| 294 return this->verbs()[~index]; | 206 return this->verbs()[~index]; |
| 295 } | 207 } |
| 296 const SkPoint& atPoint(int index) const { | 208 const SkPoint& atPoint(int index) const { |
| 297 SkASSERT((unsigned) index < (unsigned) fPointCnt); | 209 SkASSERT((unsigned) index < (unsigned) fPointCnt); |
| 298 return this->points()[index]; | 210 return this->points()[index]; |
| 299 } | 211 } |
| 300 | 212 |
| 301 bool operator== (const SkPathRef& ref) const { | 213 bool operator== (const SkPathRef& ref) const; |
| 302 this->validate(); | |
| 303 ref.validate(); | |
| 304 bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID; | |
| 305 #ifdef SK_RELEASE | |
| 306 if (genIDMatch) { | |
| 307 return true; | |
| 308 } | |
| 309 #endif | |
| 310 if (fPointCnt != ref.fPointCnt || | |
| 311 fVerbCnt != ref.fVerbCnt) { | |
| 312 SkASSERT(!genIDMatch); | |
| 313 return false; | |
| 314 } | |
| 315 if (0 != memcmp(this->verbsMemBegin(), | |
| 316 ref.verbsMemBegin(), | |
| 317 ref.fVerbCnt * sizeof(uint8_t))) { | |
| 318 SkASSERT(!genIDMatch); | |
| 319 return false; | |
| 320 } | |
| 321 if (0 != memcmp(this->points(), | |
| 322 ref.points(), | |
| 323 ref.fPointCnt * sizeof(SkPoint))) { | |
| 324 SkASSERT(!genIDMatch); | |
| 325 return false; | |
| 326 } | |
| 327 if (fConicWeights != ref.fConicWeights) { | |
| 328 SkASSERT(!genIDMatch); | |
| 329 return false; | |
| 330 } | |
| 331 // We've done the work to determine that these are equal. If either has a zero genID, copy | |
| 332 // the other's. If both are 0 then genID() will compute the next ID. | |
| 333 if (0 == fGenerationID) { | |
| 334 fGenerationID = ref.genID(); | |
| 335 } else if (0 == ref.fGenerationID) { | |
| 336 ref.fGenerationID = this->genID(); | |
| 337 } | |
| 338 return true; | |
| 339 } | |
| 340 | 214 |
| 341 /** | 215 /** |
| 342 * Writes the path points and verbs to a buffer. | 216 * Writes the path points and verbs to a buffer. |
| 343 */ | 217 */ |
| 344 void writeToBuffer(SkWBuffer* buffer); | 218 void writeToBuffer(SkWBuffer* buffer); |
| 345 | 219 |
| 346 /** | 220 /** |
| 347 * Gets the number of bytes that would be written in writeBuffer() | 221 * Gets the number of bytes that would be written in writeBuffer() |
| 348 */ | 222 */ |
| 349 uint32_t writeSize() { | 223 uint32_t writeSize(); |
| 350 return uint32_t(5 * sizeof(uint32_t) + | |
| 351 fVerbCnt * sizeof(uint8_t) + | |
| 352 fPointCnt * sizeof(SkPoint) + | |
| 353 fConicWeights.bytes() + | |
| 354 sizeof(SkRect)); | |
| 355 } | |
| 356 | 224 |
| 357 private: | 225 private: |
| 358 enum SerializationOffsets { | 226 enum SerializationOffsets { |
| 359 kIsFinite_SerializationShift = 25, // requires 1 bit | 227 kIsFinite_SerializationShift = 25, // requires 1 bit |
| 360 }; | 228 }; |
| 361 | 229 |
| 362 SkPathRef() { | 230 SkPathRef() { |
| 363 fBoundsIsDirty = true; // this also invalidates fIsFinite | 231 fBoundsIsDirty = true; // this also invalidates fIsFinite |
| 364 fPointCnt = 0; | 232 fPointCnt = 0; |
| 365 fVerbCnt = 0; | 233 fVerbCnt = 0; |
| 366 fVerbs = NULL; | 234 fVerbs = NULL; |
| 367 fPoints = NULL; | 235 fPoints = NULL; |
| 368 fFreeSpace = 0; | 236 fFreeSpace = 0; |
| 369 fGenerationID = kEmptyGenID; | 237 fGenerationID = kEmptyGenID; |
| 370 SkDEBUGCODE(fEditorsAttached = 0;) | 238 SkDEBUGCODE(fEditorsAttached = 0;) |
| 371 this->validate(); | 239 this->validate(); |
| 372 } | 240 } |
| 373 | 241 |
| 374 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe servePoints) { | 242 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe servePoints); |
| 375 this->validate(); | |
| 376 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count() , | |
| 377 additionalReserveVerbs, additionalReservePoints); | |
| 378 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * siz eof(uint8_t)); | |
| 379 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); | |
| 380 fConicWeights = ref.fConicWeights; | |
| 381 // We could call genID() here to force a real ID (instead of 0). However , if we're making | |
| 382 // a copy then presumably we intend to make a modification immediately a fterwards. | |
| 383 fGenerationID = ref.fGenerationID; | |
| 384 fBoundsIsDirty = ref.fBoundsIsDirty; | |
| 385 if (!fBoundsIsDirty) { | |
| 386 fBounds = ref.fBounds; | |
| 387 fIsFinite = ref.fIsFinite; | |
| 388 } | |
| 389 this->validate(); | |
| 390 } | |
| 391 | 243 |
| 392 // Return true if the computed bounds are finite. | 244 // Return true if the computed bounds are finite. |
| 393 static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { | 245 static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { |
| 394 int count = ref.countPoints(); | 246 int count = ref.countPoints(); |
| 395 if (count <= 1) { // we ignore just 1 point (moveto) | 247 if (count <= 1) { // we ignore just 1 point (moveto) |
| 396 bounds->setEmpty(); | 248 bounds->setEmpty(); |
| 397 return count ? ref.points()->isFinite() : true; | 249 return count ? ref.points()->isFinite() : true; |
| 398 } else { | 250 } else { |
| 399 return bounds->setBoundsCheck(ref.points(), count); | 251 return bounds->setBoundsCheck(ref.points(), count); |
| 400 } | 252 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 413 void incReserve(int additionalVerbs, int additionalPoints) { | 265 void incReserve(int additionalVerbs, int additionalPoints) { |
| 414 this->validate(); | 266 this->validate(); |
| 415 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si zeof (SkPoint); | 267 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si zeof (SkPoint); |
| 416 this->makeSpace(space); | 268 this->makeSpace(space); |
| 417 this->validate(); | 269 this->validate(); |
| 418 } | 270 } |
| 419 | 271 |
| 420 /** Resets the path ref with verbCount verbs and pointCount points, all unin itialized. Also | 272 /** Resets the path ref with verbCount verbs and pointCount points, all unin itialized. Also |
| 421 * allocates space for reserveVerb additional verbs and reservePoints addit ional points.*/ | 273 * allocates space for reserveVerb additional verbs and reservePoints addit ional points.*/ |
| 422 void resetToSize(int verbCount, int pointCount, int conicCount, | 274 void resetToSize(int verbCount, int pointCount, int conicCount, |
| 423 int reserveVerbs = 0, int reservePoints = 0) { | 275 int reserveVerbs = 0, int reservePoints = 0); |
| 424 this->validate(); | |
| 425 fBoundsIsDirty = true; // this also invalidates fIsFinite | |
| 426 fGenerationID = 0; | |
| 427 | |
| 428 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCo unt; | |
| 429 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * r eservePoints; | |
| 430 size_t minSize = newSize + newReserve; | |
| 431 | |
| 432 ptrdiff_t sizeDelta = this->currSize() - minSize; | |
| 433 | |
| 434 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) { | |
| 435 sk_free(fPoints); | |
| 436 fPoints = NULL; | |
| 437 fVerbs = NULL; | |
| 438 fFreeSpace = 0; | |
| 439 fVerbCnt = 0; | |
| 440 fPointCnt = 0; | |
| 441 this->makeSpace(minSize); | |
| 442 fVerbCnt = verbCount; | |
| 443 fPointCnt = pointCount; | |
| 444 fFreeSpace -= newSize; | |
| 445 } else { | |
| 446 fPointCnt = pointCount; | |
| 447 fVerbCnt = verbCount; | |
| 448 fFreeSpace = this->currSize() - minSize; | |
| 449 } | |
| 450 fConicWeights.setCount(conicCount); | |
| 451 this->validate(); | |
| 452 } | |
| 453 | 276 |
| 454 /** | 277 /** |
| 455 * Increases the verb count by newVerbs and the point count be newPoints. Ne w verbs and points | 278 * Increases the verb count by newVerbs and the point count be newPoints. Ne w verbs and points |
| 456 * are uninitialized. | 279 * are uninitialized. |
| 457 */ | 280 */ |
| 458 void grow(int newVerbs, int newPoints) { | 281 void grow(int newVerbs, int newPoints); |
| 459 this->validate(); | |
| 460 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint) ; | |
|
bsalomon
2013/09/27 15:58:51
also wondering about this one.
robertphillips
2013/09/27 16:13:30
Done.
| |
| 461 this->makeSpace(space); | |
| 462 fVerbCnt += newVerbs; | |
| 463 fPointCnt += newPoints; | |
| 464 fFreeSpace -= space; | |
| 465 fBoundsIsDirty = true; // this also invalidates fIsFinite | |
| 466 this->validate(); | |
| 467 } | |
| 468 | 282 |
| 469 /** | 283 /** |
| 470 * Increases the verb count 1, records the new verb, and creates room for th e requisite number | 284 * Increases the verb count 1, records the new verb, and creates room for th e requisite number |
| 471 * of additional points. A pointer to the first point is returned. Any new p oints are | 285 * of additional points. A pointer to the first point is returned. Any new p oints are |
| 472 * uninitialized. | 286 * uninitialized. |
| 473 */ | 287 */ |
| 474 SkPoint* growForVerb(int /*SkPath::Verb*/ verb); | 288 SkPoint* growForVerb(int /*SkPath::Verb*/ verb); |
| 475 | 289 |
| 476 /** | 290 /** |
| 477 * Ensures that the free space available in the path ref is >= size. The ver b and point counts | 291 * Ensures that the free space available in the path ref is >= size. The ver b and point counts |
| 478 * are not changed. | 292 * are not changed. |
| 479 */ | 293 */ |
| 480 void makeSpace(size_t size) { | 294 void makeSpace(size_t size); |
| 481 this->validate(); | |
| 482 ptrdiff_t growSize = size - fFreeSpace; | |
| 483 if (growSize <= 0) { | |
| 484 return; | |
| 485 } | |
| 486 size_t oldSize = this->currSize(); | |
| 487 // round to next multiple of 8 bytes | |
| 488 growSize = (growSize + 7) & ~static_cast<size_t>(7); | |
| 489 // we always at least double the allocation | |
| 490 if (static_cast<size_t>(growSize) < oldSize) { | |
| 491 growSize = oldSize; | |
| 492 } | |
| 493 if (growSize < kMinSize) { | |
| 494 growSize = kMinSize; | |
| 495 } | |
| 496 size_t newSize = oldSize + growSize; | |
| 497 // Note that realloc could memcpy more than we need. It seems to be a wi n anyway. TODO: | |
| 498 // encapsulate this. | |
| 499 fPoints = reinterpret_cast<SkPoint*>(sk_realloc_throw(fPoints, newSize)) ; | |
| 500 size_t oldVerbSize = fVerbCnt * sizeof(uint8_t); | |
| 501 void* newVerbsDst = reinterpret_cast<void*>( | |
| 502 reinterpret_cast<intptr_t>(fPoints) + newSize - oldVerbSize); | |
| 503 void* oldVerbsSrc = reinterpret_cast<void*>( | |
| 504 reinterpret_cast<intptr_t>(fPoints) + oldSize - oldVerbSize); | |
| 505 memmove(newVerbsDst, oldVerbsSrc, oldVerbSize); | |
| 506 fVerbs = reinterpret_cast<uint8_t*>(reinterpret_cast<intptr_t>(fPoints) + newSize); | |
| 507 fFreeSpace += growSize; | |
| 508 this->validate(); | |
| 509 } | |
| 510 | 295 |
| 511 /** | 296 /** |
| 512 * Private, non-const-ptr version of the public function verbsMemBegin(). | 297 * Private, non-const-ptr version of the public function verbsMemBegin(). |
| 513 */ | 298 */ |
| 514 uint8_t* verbsMemWritable() { | 299 uint8_t* verbsMemWritable() { |
| 515 this->validate(); | 300 this->validate(); |
| 516 return fVerbs - fVerbCnt; | 301 return fVerbs - fVerbCnt; |
| 517 } | 302 } |
| 518 | 303 |
| 519 /** | 304 /** |
| 520 * Gets the total amount of space allocated for verbs, points, and reserve. | 305 * Gets the total amount of space allocated for verbs, points, and reserve. |
| 521 */ | 306 */ |
| 522 size_t currSize() const { | 307 size_t currSize() const { |
| 523 return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(f Points); | 308 return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(f Points); |
| 524 } | 309 } |
| 525 | 310 |
| 526 /** | 311 /** |
| 527 * Gets an ID that uniquely identifies the contents of the path ref. If two path refs have the | 312 * Gets an ID that uniquely identifies the contents of the path ref. If two path refs have the |
| 528 * same ID then they have the same verbs and points. However, two path refs may have the same | 313 * same ID then they have the same verbs and points. However, two path refs may have the same |
| 529 * contents but different genIDs. Zero is reserved and means an ID has not y et been determined | 314 * contents but different genIDs. Zero is reserved and means an ID has not y et been determined |
| 530 * for the path ref. | 315 * for the path ref. |
| 531 */ | 316 */ |
| 532 int32_t genID() const { | 317 int32_t genID() const; |
| 533 SkASSERT(!fEditorsAttached); | |
| 534 if (!fGenerationID) { | |
| 535 if (0 == fPointCnt && 0 == fVerbCnt) { | |
| 536 fGenerationID = kEmptyGenID; | |
| 537 } else { | |
| 538 static int32_t gPathRefGenerationID; | |
| 539 // do a loop in case our global wraps around, as we never want t o return a 0 or the | |
| 540 // empty ID | |
| 541 do { | |
| 542 fGenerationID = sk_atomic_inc(&gPathRefGenerationID) + 1; | |
| 543 } while (fGenerationID <= kEmptyGenID); | |
| 544 } | |
| 545 } | |
| 546 return fGenerationID; | |
| 547 } | |
| 548 | 318 |
| 549 void validate() const { | 319 void validate() const; |
| 550 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0); | |
| 551 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t> (fPoints) >= 0); | |
| 552 SkASSERT((NULL == fPoints) == (NULL == fVerbs)); | |
| 553 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); | |
| 554 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); | |
| 555 SkASSERT(!(NULL == fPoints && fPointCnt)); | |
| 556 SkASSERT(!(NULL == fVerbs && fVerbCnt)); | |
| 557 SkASSERT(this->currSize() == | |
| 558 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fV erbCnt); | |
| 559 | |
| 560 #ifdef SK_DEBUG | |
| 561 if (!fBoundsIsDirty && !fBounds.isEmpty()) { | |
| 562 bool isFinite = true; | |
| 563 for (int i = 0; i < fPointCnt; ++i) { | |
| 564 SkASSERT(fPoints[i].fX >= fBounds.fLeft && fPoints[i].fX <= fBou nds.fRight && | |
| 565 fPoints[i].fY >= fBounds.fTop && fPoints[i].fY <= fBoun ds.fBottom); | |
| 566 if (!fPoints[i].isFinite()) { | |
| 567 isFinite = false; | |
| 568 } | |
| 569 } | |
| 570 SkASSERT(SkToBool(fIsFinite) == isFinite); | |
| 571 } | |
| 572 #endif | |
| 573 } | |
| 574 | 320 |
| 575 enum { | 321 enum { |
| 576 kMinSize = 256, | 322 kMinSize = 256, |
| 577 }; | 323 }; |
| 578 | 324 |
| 579 mutable SkRect fBounds; | 325 mutable SkRect fBounds; |
| 580 mutable uint8_t fBoundsIsDirty; | 326 mutable uint8_t fBoundsIsDirty; |
| 581 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid | 327 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid |
| 582 | 328 |
| 583 SkPoint* fPoints; // points to begining of the allocation | 329 SkPoint* fPoints; // points to begining of the allocation |
| 584 uint8_t* fVerbs; // points just past the end of the allocation (v erbs grow backwards) | 330 uint8_t* fVerbs; // points just past the end of the allocation (v erbs grow backwards) |
| 585 int fVerbCnt; | 331 int fVerbCnt; |
| 586 int fPointCnt; | 332 int fPointCnt; |
| 587 size_t fFreeSpace; // redundant but saves computation | 333 size_t fFreeSpace; // redundant but saves computation |
| 588 SkTDArray<SkScalar> fConicWeights; | 334 SkTDArray<SkScalar> fConicWeights; |
| 589 | 335 |
| 590 enum { | 336 enum { |
| 591 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer o verbs. | 337 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer o verbs. |
| 592 }; | 338 }; |
| 593 mutable int32_t fGenerationID; | 339 mutable int32_t fGenerationID; |
| 594 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time. | 340 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time. |
| 595 | 341 |
| 596 typedef SkRefCnt INHERITED; | 342 typedef SkRefCnt INHERITED; |
| 597 }; | 343 }; |
| 598 | 344 |
| 599 #endif | 345 #endif |
| OLD | NEW |