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) { |
90 SkASSERT(NULL != verbs); | 79 SkASSERT(NULL != verbs); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 fBounds = rect; | 148 fBounds = rect; |
160 fBoundsIsDirty = false; | 149 fBoundsIsDirty = false; |
161 fIsFinite = fBounds.isFinite(); | 150 fIsFinite = fBounds.isFinite(); |
162 } | 151 } |
163 | 152 |
164 /** | 153 /** |
165 * Transforms a path ref by a matrix, allocating a new one only if necessary
. | 154 * Transforms a path ref by a matrix, allocating a new one only if necessary
. |
166 */ | 155 */ |
167 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, | 156 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, |
168 const SkPathRef& src, | 157 const SkPathRef& src, |
169 const SkMatrix& matrix) { | 158 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 | 159 |
221 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer | 160 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer |
222 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O | 161 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
223 , bool newFormat, int32_t oldPacked | 162 , bool newFormat, int32_t oldPacked |
224 #endif | 163 #endif |
225 ); | 164 ); |
226 | 165 |
227 /** | 166 /** |
228 * Rollsback a path ref to zero verbs and points with the assumption that th
e path ref will be | 167 * 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 | 168 * repopulated with approximately the same number of verbs and points. A new
path ref is created |
230 * only if necessary. | 169 * only if necessary. |
231 */ | 170 */ |
232 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef) { | 171 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 | 172 |
250 virtual ~SkPathRef() { | 173 virtual ~SkPathRef() { |
251 this->validate(); | 174 this->validate(); |
252 sk_free(fPoints); | 175 sk_free(fPoints); |
253 | 176 |
254 SkDEBUGCODE(fPoints = NULL;) | 177 SkDEBUGCODE(fPoints = NULL;) |
255 SkDEBUGCODE(fVerbs = NULL;) | 178 SkDEBUGCODE(fVerbs = NULL;) |
256 SkDEBUGCODE(fVerbCnt = 0x9999999;) | 179 SkDEBUGCODE(fVerbCnt = 0x9999999;) |
257 SkDEBUGCODE(fPointCnt = 0xAAAAAAA;) | 180 SkDEBUGCODE(fPointCnt = 0xAAAAAAA;) |
258 SkDEBUGCODE(fPointCnt = 0xBBBBBBB;) | 181 SkDEBUGCODE(fPointCnt = 0xBBBBBBB;) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 */ | 214 */ |
292 uint8_t atVerb(int index) { | 215 uint8_t atVerb(int index) { |
293 SkASSERT((unsigned) index < (unsigned) fVerbCnt); | 216 SkASSERT((unsigned) index < (unsigned) fVerbCnt); |
294 return this->verbs()[~index]; | 217 return this->verbs()[~index]; |
295 } | 218 } |
296 const SkPoint& atPoint(int index) const { | 219 const SkPoint& atPoint(int index) const { |
297 SkASSERT((unsigned) index < (unsigned) fPointCnt); | 220 SkASSERT((unsigned) index < (unsigned) fPointCnt); |
298 return this->points()[index]; | 221 return this->points()[index]; |
299 } | 222 } |
300 | 223 |
301 bool operator== (const SkPathRef& ref) const { | 224 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 | 225 |
341 /** | 226 /** |
342 * Writes the path points and verbs to a buffer. | 227 * Writes the path points and verbs to a buffer. |
343 */ | 228 */ |
344 void writeToBuffer(SkWBuffer* buffer); | 229 void writeToBuffer(SkWBuffer* buffer); |
345 | 230 |
346 /** | 231 /** |
347 * Gets the number of bytes that would be written in writeBuffer() | 232 * Gets the number of bytes that would be written in writeBuffer() |
348 */ | 233 */ |
349 uint32_t writeSize() { | 234 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 | 235 |
357 private: | 236 private: |
358 enum SerializationOffsets { | 237 enum SerializationOffsets { |
359 kIsFinite_SerializationShift = 25, // requires 1 bit | 238 kIsFinite_SerializationShift = 25, // requires 1 bit |
360 }; | 239 }; |
361 | 240 |
362 SkPathRef() { | 241 SkPathRef() { |
363 fBoundsIsDirty = true; // this also invalidates fIsFinite | 242 fBoundsIsDirty = true; // this also invalidates fIsFinite |
364 fPointCnt = 0; | 243 fPointCnt = 0; |
365 fVerbCnt = 0; | 244 fVerbCnt = 0; |
366 fVerbs = NULL; | 245 fVerbs = NULL; |
367 fPoints = NULL; | 246 fPoints = NULL; |
368 fFreeSpace = 0; | 247 fFreeSpace = 0; |
369 fGenerationID = kEmptyGenID; | 248 fGenerationID = kEmptyGenID; |
370 SkDEBUGCODE(fEditorsAttached = 0;) | 249 SkDEBUGCODE(fEditorsAttached = 0;) |
371 this->validate(); | 250 this->validate(); |
372 } | 251 } |
373 | 252 |
374 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe
servePoints) { | 253 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 | 254 |
392 // Return true if the computed bounds are finite. | 255 // Return true if the computed bounds are finite. |
393 static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { | 256 static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { |
394 int count = ref.countPoints(); | 257 int count = ref.countPoints(); |
395 if (count <= 1) { // we ignore just 1 point (moveto) | 258 if (count <= 1) { // we ignore just 1 point (moveto) |
396 bounds->setEmpty(); | 259 bounds->setEmpty(); |
397 return count ? ref.points()->isFinite() : true; | 260 return count ? ref.points()->isFinite() : true; |
398 } else { | 261 } else { |
399 return bounds->setBoundsCheck(ref.points(), count); | 262 return bounds->setBoundsCheck(ref.points(), count); |
400 } | 263 } |
(...skipping 12 matching lines...) Expand all Loading... |
413 void incReserve(int additionalVerbs, int additionalPoints) { | 276 void incReserve(int additionalVerbs, int additionalPoints) { |
414 this->validate(); | 277 this->validate(); |
415 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si
zeof (SkPoint); | 278 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si
zeof (SkPoint); |
416 this->makeSpace(space); | 279 this->makeSpace(space); |
417 this->validate(); | 280 this->validate(); |
418 } | 281 } |
419 | 282 |
420 /** Resets the path ref with verbCount verbs and pointCount points, all unin
itialized. Also | 283 /** 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.*/ | 284 * allocates space for reserveVerb additional verbs and reservePoints addit
ional points.*/ |
422 void resetToSize(int verbCount, int pointCount, int conicCount, | 285 void resetToSize(int verbCount, int pointCount, int conicCount, |
423 int reserveVerbs = 0, int reservePoints = 0) { | 286 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 | 287 |
454 /** | 288 /** |
455 * Increases the verb count by newVerbs and the point count be newPoints. Ne
w verbs and points | 289 * Increases the verb count by newVerbs and the point count be newPoints. Ne
w verbs and points |
456 * are uninitialized. | 290 * are uninitialized. |
457 */ | 291 */ |
458 void grow(int newVerbs, int newPoints) { | 292 void grow(int newVerbs, int newPoints) { |
459 this->validate(); | 293 this->validate(); |
460 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint)
; | 294 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint)
; |
461 this->makeSpace(space); | 295 this->makeSpace(space); |
462 fVerbCnt += newVerbs; | 296 fVerbCnt += newVerbs; |
463 fPointCnt += newPoints; | 297 fPointCnt += newPoints; |
464 fFreeSpace -= space; | 298 fFreeSpace -= space; |
465 fBoundsIsDirty = true; // this also invalidates fIsFinite | 299 fBoundsIsDirty = true; // this also invalidates fIsFinite |
466 this->validate(); | 300 this->validate(); |
467 } | 301 } |
468 | 302 |
469 /** | 303 /** |
470 * Increases the verb count 1, records the new verb, and creates room for th
e requisite number | 304 * 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 | 305 * of additional points. A pointer to the first point is returned. Any new p
oints are |
472 * uninitialized. | 306 * uninitialized. |
473 */ | 307 */ |
474 SkPoint* growForVerb(int /*SkPath::Verb*/ verb); | 308 SkPoint* growForVerb(int /*SkPath::Verb*/ verb); |
475 | 309 |
476 /** | 310 /** |
477 * Ensures that the free space available in the path ref is >= size. The ver
b and point counts | 311 * Ensures that the free space available in the path ref is >= size. The ver
b and point counts |
478 * are not changed. | 312 * are not changed. |
479 */ | 313 */ |
480 void makeSpace(size_t size) { | 314 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 | 315 |
511 /** | 316 /** |
512 * Private, non-const-ptr version of the public function verbsMemBegin(). | 317 * Private, non-const-ptr version of the public function verbsMemBegin(). |
513 */ | 318 */ |
514 uint8_t* verbsMemWritable() { | 319 uint8_t* verbsMemWritable() { |
515 this->validate(); | 320 this->validate(); |
516 return fVerbs - fVerbCnt; | 321 return fVerbs - fVerbCnt; |
517 } | 322 } |
518 | 323 |
519 /** | 324 /** |
520 * Gets the total amount of space allocated for verbs, points, and reserve. | 325 * Gets the total amount of space allocated for verbs, points, and reserve. |
521 */ | 326 */ |
522 size_t currSize() const { | 327 size_t currSize() const { |
523 return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(f
Points); | 328 return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(f
Points); |
524 } | 329 } |
525 | 330 |
526 /** | 331 /** |
527 * Gets an ID that uniquely identifies the contents of the path ref. If two
path refs have the | 332 * 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 | 333 * 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 | 334 * contents but different genIDs. Zero is reserved and means an ID has not y
et been determined |
530 * for the path ref. | 335 * for the path ref. |
531 */ | 336 */ |
532 int32_t genID() const { | 337 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 | 338 |
549 void validate() const { | 339 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 | 340 |
575 enum { | 341 enum { |
576 kMinSize = 256, | 342 kMinSize = 256, |
577 }; | 343 }; |
578 | 344 |
579 mutable SkRect fBounds; | 345 mutable SkRect fBounds; |
580 mutable uint8_t fBoundsIsDirty; | 346 mutable uint8_t fBoundsIsDirty; |
581 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid | 347 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid |
582 | 348 |
583 SkPoint* fPoints; // points to begining of the allocation | 349 SkPoint* fPoints; // points to begining of the allocation |
584 uint8_t* fVerbs; // points just past the end of the allocation (v
erbs grow backwards) | 350 uint8_t* fVerbs; // points just past the end of the allocation (v
erbs grow backwards) |
585 int fVerbCnt; | 351 int fVerbCnt; |
586 int fPointCnt; | 352 int fPointCnt; |
587 size_t fFreeSpace; // redundant but saves computation | 353 size_t fFreeSpace; // redundant but saves computation |
588 SkTDArray<SkScalar> fConicWeights; | 354 SkTDArray<SkScalar> fConicWeights; |
589 | 355 |
590 enum { | 356 enum { |
591 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer
o verbs. | 357 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer
o verbs. |
592 }; | 358 }; |
593 mutable int32_t fGenerationID; | 359 mutable int32_t fGenerationID; |
594 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use
at any time. | 360 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use
at any time. |
595 | 361 |
596 typedef SkRefCnt INHERITED; | 362 typedef SkRefCnt INHERITED; |
597 }; | 363 }; |
598 | 364 |
599 #endif | 365 #endif |
OLD | NEW |