| 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 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 * | 22 * |
| 23 * The points and verbs are stored in a single allocation. The points are at the
begining of the | 23 * The points and verbs are stored in a single allocation. The points are at the
begining of the |
| 24 * allocation while the verbs are stored at end of the allocation, in reverse or
der. Thus the points | 24 * allocation while the verbs are stored at end of the allocation, in reverse or
der. Thus the points |
| 25 * and verbs both grow into the middle of the allocation until the meet. To acce
ss verb i in the | 25 * and verbs both grow into the middle of the allocation until the meet. To acce
ss verb i in the |
| 26 * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond
the first | 26 * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond
the first |
| 27 * logical verb or the last verb in memory). | 27 * logical verb or the last verb in memory). |
| 28 */ | 28 */ |
| 29 | 29 |
| 30 class SkPathRef; | 30 class SkPathRef; |
| 31 | 31 |
| 32 // This path ref should never be deleted once it is created. It should not be gl
obal but was made | |
| 33 // so for checks when SK_DEBUG_PATH_REF is enabled. It we be re-hidden when the
debugging code is | |
| 34 // reverted. | |
| 35 SkPathRef* gEmptyPathRef; | |
| 36 | |
| 37 // Temporary hackery to try to nail down http://code.google.com/p/chromium/issue
s/detail?id=148637 | |
| 38 #if SK_DEBUG_PATH_REF | |
| 39 #define PR_CONTAINER SkPath::PathRefDebugRef | |
| 40 #define SkDEBUGCODE_X(code) code | |
| 41 #define SkASSERT_X(cond) SK_DEBUGBREAK(cond) | |
| 42 // We put the mutex in a factory function to protect against static-initiali
zion order | |
| 43 // fiasco when SkPaths are created before main(). | |
| 44 static SkMutex* owners_mutex() { | |
| 45 static SkMutex* gOwnersMutex; | |
| 46 if (!gOwnersMutex) { | |
| 47 gOwnersMutex = new SkMutex(); // leak! | |
| 48 } | |
| 49 return gOwnersMutex; | |
| 50 } | |
| 51 // We have a static initializer that calls owners_mutex before main() so tha
t | |
| 52 // hopefully that we only wind up with one mutex (assuming no threads create
d | |
| 53 // before static initialization is finished.) | |
| 54 static const SkMutex* gOwnersMutexForce = owners_mutex(); | |
| 55 #else | |
| 56 #define PR_CONTAINER SkAutoTUnref<SkPathRef> | |
| 57 #define SkDEBUGCODE_X(code) SkDEBUGCODE(code) | |
| 58 #define SkASSERT_X(cond) SkASSERT(cond) | |
| 59 #endif | |
| 60 | |
| 61 class SkPathRef : public ::SkRefCnt { | 32 class SkPathRef : public ::SkRefCnt { |
| 62 public: | 33 public: |
| 63 SK_DECLARE_INST_COUNT(SkPathRef); | 34 SK_DECLARE_INST_COUNT(SkPathRef); |
| 64 | 35 |
| 65 class Editor { | 36 class Editor { |
| 66 public: | 37 public: |
| 67 Editor(PR_CONTAINER* pathRef, | 38 Editor(SkAutoTUnref<SkPathRef>* pathRef, |
| 68 int incReserveVerbs = 0, | 39 int incReserveVerbs = 0, |
| 69 int incReservePoints = 0) { | 40 int incReservePoints = 0) { |
| 70 if (pathRef->get()->getRefCnt() > 1) { | 41 if (pathRef->get()->getRefCnt() > 1) { |
| 71 SkPathRef* copy = SkNEW(SkPathRef); | 42 SkPathRef* copy = SkNEW(SkPathRef); |
| 72 copy->copy(*pathRef->get(), incReserveVerbs, incReservePoints); | 43 copy->copy(*pathRef->get(), incReserveVerbs, incReservePoints); |
| 73 pathRef->reset(copy); | 44 pathRef->reset(copy); |
| 74 } else { | 45 } else { |
| 75 (*pathRef)->incReserve(incReserveVerbs, incReservePoints); | 46 (*pathRef)->incReserve(incReserveVerbs, incReservePoints); |
| 76 } | 47 } |
| 77 fPathRef = pathRef->get(); | 48 fPathRef = pathRef->get(); |
| 78 fPathRef->fGenerationID = 0; | 49 fPathRef->fGenerationID = 0; |
| 79 SkDEBUGCODE_X(sk_atomic_inc(&fPathRef->fEditorsAttached);) | 50 SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);) |
| 80 } | 51 } |
| 81 | 52 |
| 82 ~Editor() { SkDEBUGCODE_X(sk_atomic_dec(&fPathRef->fEditorsAttached);) } | 53 ~Editor() { SkDEBUGCODE(sk_atomic_dec(&fPathRef->fEditorsAttached);) } |
| 83 | 54 |
| 84 /** | 55 /** |
| 85 * Returns the array of points. | 56 * Returns the array of points. |
| 86 */ | 57 */ |
| 87 SkPoint* points() { return fPathRef->fPoints; } | 58 SkPoint* points() { return fPathRef->fPoints; } |
| 88 | 59 |
| 89 /** | 60 /** |
| 90 * Gets the ith point. Shortcut for this->points() + i | 61 * Gets the ith point. Shortcut for this->points() + i |
| 91 */ | 62 */ |
| 92 SkPoint* atPoint(int i) { | 63 SkPoint* atPoint(int i) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 138 /** | 109 /** |
| 139 * Gets the path ref that is wrapped in the Editor. | 110 * Gets the path ref that is wrapped in the Editor. |
| 140 */ | 111 */ |
| 141 SkPathRef* pathRef() { return fPathRef; } | 112 SkPathRef* pathRef() { return fPathRef; } |
| 142 | 113 |
| 143 private: | 114 private: |
| 144 SkPathRef* fPathRef; | 115 SkPathRef* fPathRef; |
| 145 }; | 116 }; |
| 146 | 117 |
| 147 public: | 118 public: |
| 148 #if SK_DEBUG_PATH_REF | |
| 149 void addOwner(SkPath* owner) { | |
| 150 SkAutoMutexAcquire ac(owners_mutex()); | |
| 151 for (int i = 0; i < fOwners.count(); ++i) { | |
| 152 SkASSERT_X(fOwners[i] != owner); | |
| 153 } | |
| 154 *fOwners.append() = owner; | |
| 155 SkASSERT_X((this->getRefCnt() == fOwners.count()) || | |
| 156 (this == gEmptyPathRef && this->getRefCnt() == fOwners.count(
) + 1)); | |
| 157 } | |
| 158 | |
| 159 void removeOwner(SkPath* owner) { | |
| 160 SkAutoMutexAcquire ac(owners_mutex()); | |
| 161 SkASSERT_X((this->getRefCnt() == fOwners.count()) || | |
| 162 (this == gEmptyPathRef && this->getRefCnt() == fOwners.count(
) + 1)); | |
| 163 bool found = false; | |
| 164 for (int i = 0; !found && i < fOwners.count(); ++i) { | |
| 165 found = (owner == fOwners[i]); | |
| 166 if (found) { | |
| 167 fOwners.remove(i); | |
| 168 } | |
| 169 } | |
| 170 SkASSERT_X(found); | |
| 171 } | |
| 172 #endif | |
| 173 | |
| 174 /** | 119 /** |
| 175 * Gets a path ref with no verbs or points. | 120 * Gets a path ref with no verbs or points. |
| 176 */ | 121 */ |
| 177 static SkPathRef* CreateEmpty() { | 122 static SkPathRef* CreateEmpty() { |
| 123 static SkPathRef* gEmptyPathRef; |
| 178 if (!gEmptyPathRef) { | 124 if (!gEmptyPathRef) { |
| 179 gEmptyPathRef = SkNEW(SkPathRef); // leak! | 125 gEmptyPathRef = SkNEW(SkPathRef); // leak! |
| 180 } | 126 } |
| 181 return SkRef(gEmptyPathRef); | 127 return SkRef(gEmptyPathRef); |
| 182 } | 128 } |
| 183 | 129 |
| 184 /** | 130 /** |
| 185 * Transforms a path ref by a matrix, allocating a new one only if necessary
. | 131 * Transforms a path ref by a matrix, allocating a new one only if necessary
. |
| 186 */ | 132 */ |
| 187 static void CreateTransformedCopy(PR_CONTAINER* dst, | 133 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, |
| 188 const SkPathRef& src, | 134 const SkPathRef& src, |
| 189 const SkMatrix& matrix) { | 135 const SkMatrix& matrix) { |
| 190 src.validate(); | 136 src.validate(); |
| 191 if (matrix.isIdentity()) { | 137 if (matrix.isIdentity()) { |
| 192 if (dst->get() != &src) { | 138 if (dst->get() != &src) { |
| 193 src.ref(); | 139 src.ref(); |
| 194 dst->reset(const_cast<SkPathRef*>(&src)); | 140 dst->reset(const_cast<SkPathRef*>(&src)); |
| 195 (*dst)->validate(); | 141 (*dst)->validate(); |
| 196 } | 142 } |
| 197 return; | 143 return; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 225 buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)); | 171 buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)); |
| 226 buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)); | 172 buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)); |
| 227 return ref; | 173 return ref; |
| 228 } | 174 } |
| 229 | 175 |
| 230 /** | 176 /** |
| 231 * Rollsback a path ref to zero verbs and points with the assumption that th
e path ref will be | 177 * Rollsback a path ref to zero verbs and points with the assumption that th
e path ref will be |
| 232 * repopulated with approximately the same number of verbs and points. A new
path ref is created | 178 * repopulated with approximately the same number of verbs and points. A new
path ref is created |
| 233 * only if necessary. | 179 * only if necessary. |
| 234 */ | 180 */ |
| 235 static void Rewind(PR_CONTAINER* pathRef) { | 181 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef) { |
| 236 if (1 == (*pathRef)->getRefCnt()) { | 182 if (1 == (*pathRef)->getRefCnt()) { |
| 237 (*pathRef)->validate(); | 183 (*pathRef)->validate(); |
| 238 (*pathRef)->fVerbCnt = 0; | 184 (*pathRef)->fVerbCnt = 0; |
| 239 (*pathRef)->fPointCnt = 0; | 185 (*pathRef)->fPointCnt = 0; |
| 240 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); | 186 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); |
| 241 (*pathRef)->fGenerationID = 0; | 187 (*pathRef)->fGenerationID = 0; |
| 242 (*pathRef)->fConicWeights.rewind(); | 188 (*pathRef)->fConicWeights.rewind(); |
| 243 (*pathRef)->validate(); | 189 (*pathRef)->validate(); |
| 244 } else { | 190 } else { |
| 245 int oldVCnt = (*pathRef)->countVerbs(); | 191 int oldVCnt = (*pathRef)->countVerbs(); |
| 246 int oldPCnt = (*pathRef)->countPoints(); | 192 int oldPCnt = (*pathRef)->countPoints(); |
| 247 pathRef->reset(SkNEW(SkPathRef)); | 193 pathRef->reset(SkNEW(SkPathRef)); |
| 248 (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt); | 194 (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt); |
| 249 } | 195 } |
| 250 } | 196 } |
| 251 | 197 |
| 252 virtual ~SkPathRef() { | 198 virtual ~SkPathRef() { |
| 253 SkASSERT_X(this != gEmptyPathRef); | |
| 254 #if SK_DEBUG_PATH_REF | |
| 255 SkASSERT_X(!fOwners.count()); | |
| 256 #endif | |
| 257 | |
| 258 this->validate(); | 199 this->validate(); |
| 259 sk_free(fPoints); | 200 sk_free(fPoints); |
| 260 | 201 |
| 261 SkDEBUGCODE_X(fPoints = NULL;) | 202 SkDEBUGCODE(fPoints = NULL;) |
| 262 SkDEBUGCODE_X(fVerbs = NULL;) | 203 SkDEBUGCODE(fVerbs = NULL;) |
| 263 SkDEBUGCODE_X(fVerbCnt = 0x9999999;) | 204 SkDEBUGCODE(fVerbCnt = 0x9999999;) |
| 264 SkDEBUGCODE_X(fPointCnt = 0xAAAAAAA;) | 205 SkDEBUGCODE(fPointCnt = 0xAAAAAAA;) |
| 265 SkDEBUGCODE_X(fPointCnt = 0xBBBBBBB;) | 206 SkDEBUGCODE(fPointCnt = 0xBBBBBBB;) |
| 266 SkDEBUGCODE_X(fGenerationID = 0xEEEEEEEE;) | 207 SkDEBUGCODE(fGenerationID = 0xEEEEEEEE;) |
| 267 SkDEBUGCODE_X(fEditorsAttached = 0x7777777;) | 208 SkDEBUGCODE(fEditorsAttached = 0x7777777;) |
| 268 } | 209 } |
| 269 | 210 |
| 270 int countPoints() const { this->validate(); return fPointCnt; } | 211 int countPoints() const { this->validate(); return fPointCnt; } |
| 271 int countVerbs() const { this->validate(); return fVerbCnt; } | 212 int countVerbs() const { this->validate(); return fVerbCnt; } |
| 272 | 213 |
| 273 /** | 214 /** |
| 274 * Returns a pointer one beyond the first logical verb (last verb in memory
order). | 215 * Returns a pointer one beyond the first logical verb (last verb in memory
order). |
| 275 */ | 216 */ |
| 276 const uint8_t* verbs() const { this->validate(); return fVerbs; } | 217 const uint8_t* verbs() const { this->validate(); return fVerbs; } |
| 277 | 218 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 ref.fGenerationID = this->genID(); | 284 ref.fGenerationID = this->genID(); |
| 344 } | 285 } |
| 345 return true; | 286 return true; |
| 346 } | 287 } |
| 347 | 288 |
| 348 /** | 289 /** |
| 349 * Writes the path points and verbs to a buffer. | 290 * Writes the path points and verbs to a buffer. |
| 350 */ | 291 */ |
| 351 void writeToBuffer(SkWBuffer* buffer) { | 292 void writeToBuffer(SkWBuffer* buffer) { |
| 352 this->validate(); | 293 this->validate(); |
| 353 SkDEBUGCODE_X(size_t beforePos = buffer->pos();) | 294 SkDEBUGCODE(size_t beforePos = buffer->pos();) |
| 354 | 295 |
| 355 // TODO: write gen ID here. Problem: We don't know if we're cross proces
s or not from | 296 // TODO: write gen ID here. Problem: We don't know if we're cross proces
s or not from |
| 356 // SkWBuffer. Until this is fixed we write 0. | 297 // SkWBuffer. Until this is fixed we write 0. |
| 357 buffer->write32(0); | 298 buffer->write32(0); |
| 358 buffer->write32(fVerbCnt); | 299 buffer->write32(fVerbCnt); |
| 359 buffer->write32(fPointCnt); | 300 buffer->write32(fPointCnt); |
| 360 buffer->write32(fConicWeights.count()); | 301 buffer->write32(fConicWeights.count()); |
| 361 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); | 302 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); |
| 362 buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); | 303 buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); |
| 363 buffer->write(fConicWeights.begin(), fConicWeights.bytes()); | 304 buffer->write(fConicWeights.begin(), fConicWeights.bytes()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 376 } | 317 } |
| 377 | 318 |
| 378 private: | 319 private: |
| 379 SkPathRef() { | 320 SkPathRef() { |
| 380 fPointCnt = 0; | 321 fPointCnt = 0; |
| 381 fVerbCnt = 0; | 322 fVerbCnt = 0; |
| 382 fVerbs = NULL; | 323 fVerbs = NULL; |
| 383 fPoints = NULL; | 324 fPoints = NULL; |
| 384 fFreeSpace = 0; | 325 fFreeSpace = 0; |
| 385 fGenerationID = kEmptyGenID; | 326 fGenerationID = kEmptyGenID; |
| 386 SkDEBUGCODE_X(fEditorsAttached = 0;) | 327 SkDEBUGCODE(fEditorsAttached = 0;) |
| 387 this->validate(); | 328 this->validate(); |
| 388 } | 329 } |
| 389 | 330 |
| 390 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe
servePoints) { | 331 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe
servePoints) { |
| 391 this->validate(); | 332 this->validate(); |
| 392 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count()
, | 333 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count()
, |
| 393 additionalReserveVerbs, additionalReservePoints); | 334 additionalReserveVerbs, additionalReservePoints); |
| 394 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * siz
eof(uint8_t)); | 335 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * siz
eof(uint8_t)); |
| 395 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); | 336 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); |
| 396 fConicWeights = ref.fConicWeights; | 337 fConicWeights = ref.fConicWeights; |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(f
Points); | 485 return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(f
Points); |
| 545 } | 486 } |
| 546 | 487 |
| 547 /** | 488 /** |
| 548 * Gets an ID that uniquely identifies the contents of the path ref. If two
path refs have the | 489 * Gets an ID that uniquely identifies the contents of the path ref. If two
path refs have the |
| 549 * same ID then they have the same verbs and points. However, two path refs
may have the same | 490 * same ID then they have the same verbs and points. However, two path refs
may have the same |
| 550 * contents but different genIDs. Zero is reserved and means an ID has not y
et been determined | 491 * contents but different genIDs. Zero is reserved and means an ID has not y
et been determined |
| 551 * for the path ref. | 492 * for the path ref. |
| 552 */ | 493 */ |
| 553 int32_t genID() const { | 494 int32_t genID() const { |
| 554 SkASSERT_X(!fEditorsAttached); | 495 SkASSERT(!fEditorsAttached); |
| 555 if (!fGenerationID) { | 496 if (!fGenerationID) { |
| 556 if (0 == fPointCnt && 0 == fVerbCnt) { | 497 if (0 == fPointCnt && 0 == fVerbCnt) { |
| 557 fGenerationID = kEmptyGenID; | 498 fGenerationID = kEmptyGenID; |
| 558 } else { | 499 } else { |
| 559 static int32_t gPathRefGenerationID; | 500 static int32_t gPathRefGenerationID; |
| 560 // do a loop in case our global wraps around, as we never want t
o return a 0 or the | 501 // do a loop in case our global wraps around, as we never want t
o return a 0 or the |
| 561 // empty ID | 502 // empty ID |
| 562 do { | 503 do { |
| 563 fGenerationID = sk_atomic_inc(&gPathRefGenerationID) + 1; | 504 fGenerationID = sk_atomic_inc(&gPathRefGenerationID) + 1; |
| 564 } while (fGenerationID <= kEmptyGenID); | 505 } while (fGenerationID <= kEmptyGenID); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 587 uint8_t* fVerbs; // points just past the end of the allocation (v
erbs grow backwards) | 528 uint8_t* fVerbs; // points just past the end of the allocation (v
erbs grow backwards) |
| 588 int fVerbCnt; | 529 int fVerbCnt; |
| 589 int fPointCnt; | 530 int fPointCnt; |
| 590 size_t fFreeSpace; // redundant but saves computation | 531 size_t fFreeSpace; // redundant but saves computation |
| 591 SkTDArray<SkScalar> fConicWeights; | 532 SkTDArray<SkScalar> fConicWeights; |
| 592 | 533 |
| 593 enum { | 534 enum { |
| 594 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer
o verbs. | 535 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer
o verbs. |
| 595 }; | 536 }; |
| 596 mutable int32_t fGenerationID; | 537 mutable int32_t fGenerationID; |
| 597 SkDEBUGCODE_X(int32_t fEditorsAttached;) // assert that only one editor in u
se at any time. | 538 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use
at any time. |
| 598 | |
| 599 #if SK_DEBUG_PATH_REF | |
| 600 SkTDArray<SkPath*> fOwners; | |
| 601 #endif | |
| 602 | 539 |
| 603 typedef SkRefCnt INHERITED; | 540 typedef SkRefCnt INHERITED; |
| 604 }; | 541 }; |
| 605 | 542 |
| 606 SK_DEFINE_INST_COUNT(SkPathRef); | 543 SK_DEFINE_INST_COUNT(SkPathRef); |
| 607 | 544 |
| 608 #endif | 545 #endif |
| OLD | NEW |