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 |