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" | |
13 #include "SkPoint.h" | |
14 #include "SkRect.h" | |
12 #include "SkRefCnt.h" | 15 #include "SkRefCnt.h" |
16 #include "SkTDArray.h" | |
13 #include <stddef.h> // ptrdiff_t | 17 #include <stddef.h> // ptrdiff_t |
reed1
2013/09/24 17:32:17
is it time to put this sucker in SkTypes.h?
robertphillips
2013/09/26 12:18:44
I don't think so - it isn't all that widely used i
| |
14 | 18 |
19 class SkRBuffer; | |
20 class SkWBuffer; | |
21 | |
15 /** | 22 /** |
16 * 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 |
17 * 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 |
18 * 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 |
19 * 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 |
20 * 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 |
21 * constructor returns. | 28 * constructor returns. |
22 * | 29 * |
23 * 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 |
24 * 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 |
25 * 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 |
26 * 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 |
27 * logical verb or the last verb in memory). | 34 * logical verb or the last verb in memory). |
28 */ | 35 */ |
29 | 36 |
30 class SkPathRef; | |
31 | |
32 class SkPathRef : public ::SkRefCnt { | 37 class SkPathRef : public ::SkRefCnt { |
33 public: | 38 public: |
34 SK_DECLARE_INST_COUNT(SkPathRef); | 39 SK_DECLARE_INST_COUNT(SkPathRef); |
35 | 40 |
36 class Editor { | 41 class Editor { |
37 public: | 42 public: |
38 Editor(SkAutoTUnref<SkPathRef>* pathRef, | 43 Editor(SkAutoTUnref<SkPathRef>* pathRef, |
39 int incReserveVerbs = 0, | 44 int incReserveVerbs = 0, |
40 int incReservePoints = 0) | 45 int incReservePoints = 0) |
41 { | 46 { |
(...skipping 21 matching lines...) Expand all Loading... | |
63 */ | 68 */ |
64 SkPoint* atPoint(int i) { | 69 SkPoint* atPoint(int i) { |
65 SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); | 70 SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); |
66 return this->points() + i; | 71 return this->points() + i; |
67 }; | 72 }; |
68 | 73 |
69 /** | 74 /** |
70 * Adds the verb and allocates space for the number of points indicated by the verb. The | 75 * Adds the verb and allocates space for the number of points indicated by the verb. The |
71 * return value is a pointer to where the points for the verb should be written. | 76 * return value is a pointer to where the points for the verb should be written. |
72 */ | 77 */ |
73 SkPoint* growForVerb(SkPath::Verb verb) { | 78 SkPoint* growForVerb(int /*SkPath::Verb*/ verb); |
74 fPathRef->validate(); | |
75 return fPathRef->growForVerb(verb); | |
76 } | |
77 | 79 |
78 SkPoint* growForConic(SkScalar w) { | 80 SkPoint* growForConic(SkScalar w); |
79 fPathRef->validate(); | |
80 SkPoint* pts = fPathRef->growForVerb(SkPath::kConic_Verb); | |
81 *fPathRef->fConicWeights.append() = w; | |
82 return pts; | |
83 } | |
84 | 81 |
85 /** | 82 /** |
86 * Allocates space for additional verbs and points and returns pointers to the new verbs and | 83 * Allocates space for additional verbs and points and returns pointers to the new verbs and |
87 * points. verbs will point one beyond the first new verb (index it usin g [~<i>]). pts points | 84 * points. verbs will point one beyond the first new verb (index it usin g [~<i>]). pts points |
88 * at the first new point (indexed normally [<i>]). | 85 * at the first new point (indexed normally [<i>]). |
89 */ | 86 */ |
90 void grow(int newVerbs, int newPts, uint8_t** verbs, SkPoint** pts) { | 87 void grow(int newVerbs, int newPts, uint8_t** verbs, SkPoint** pts) { |
91 SkASSERT(NULL != verbs); | 88 SkASSERT(NULL != verbs); |
92 SkASSERT(NULL != pts); | 89 SkASSERT(NULL != pts); |
93 fPathRef->validate(); | 90 fPathRef->validate(); |
(...skipping 28 matching lines...) Expand all Loading... | |
122 */ | 119 */ |
123 static SkPathRef* CreateEmpty() { | 120 static SkPathRef* CreateEmpty() { |
124 static SkPathRef* gEmptyPathRef; | 121 static SkPathRef* gEmptyPathRef; |
125 if (!gEmptyPathRef) { | 122 if (!gEmptyPathRef) { |
126 gEmptyPathRef = SkNEW(SkPathRef); // leak! | 123 gEmptyPathRef = SkNEW(SkPathRef); // leak! |
127 } | 124 } |
128 return SkRef(gEmptyPathRef); | 125 return SkRef(gEmptyPathRef); |
129 } | 126 } |
130 | 127 |
131 /** | 128 /** |
129 * Returns true if all of the points in this path are finite, meaning there | |
130 * are no infinities and no NaNs. | |
131 */ | |
132 bool isFinite() const { | |
133 if (fBoundsIsDirty) { | |
134 this->computeBounds(); | |
135 } | |
136 return SkToBool(fIsFinite); | |
137 } | |
138 | |
139 bool hasComputedBounds() const { | |
140 return !fBoundsIsDirty; | |
141 } | |
142 | |
143 /** Returns the bounds of the path's points. If the path contains 0 or 1 | |
144 points, the bounds is set to (0,0,0,0), and isEmpty() will return true. | |
145 Note: this bounds may be larger than the actual shape, since curves | |
146 do not extend as far as their control points. | |
147 */ | |
148 const SkRect& getBounds() const { | |
149 if (fBoundsIsDirty) { | |
150 this->computeBounds(); | |
151 } | |
152 return fBounds; | |
153 } | |
154 | |
155 void setBounds(const SkRect& rect) { | |
156 SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom); | |
157 fBounds = rect; | |
158 fBoundsIsDirty = false; | |
159 fIsFinite = fBounds.isFinite(); | |
160 } | |
161 | |
162 /** | |
132 * Transforms a path ref by a matrix, allocating a new one only if necessary . | 163 * Transforms a path ref by a matrix, allocating a new one only if necessary . |
133 */ | 164 */ |
134 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, | 165 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, |
135 const SkPathRef& src, | 166 const SkPathRef& src, |
136 const SkMatrix& matrix) { | 167 const SkMatrix& matrix) { |
137 src.validate(); | 168 src.validate(); |
138 if (matrix.isIdentity()) { | 169 if (matrix.isIdentity()) { |
139 if (*dst != &src) { | 170 if (*dst != &src) { |
140 src.ref(); | 171 src.ref(); |
141 dst->reset(const_cast<SkPathRef*>(&src)); | 172 dst->reset(const_cast<SkPathRef*>(&src)); |
142 (*dst)->validate(); | 173 (*dst)->validate(); |
143 } | 174 } |
144 return; | 175 return; |
145 } | 176 } |
177 | |
146 bool dstUnique = (*dst)->unique(); | 178 bool dstUnique = (*dst)->unique(); |
147 if (&src == *dst && dstUnique) { | 179 if (!dstUnique) { |
148 matrix.mapPoints((*dst)->fPoints, (*dst)->fPointCnt); | |
149 return; | |
150 } else if (!dstUnique) { | |
151 dst->reset(SkNEW(SkPathRef)); | 180 dst->reset(SkNEW(SkPathRef)); |
181 (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.c ount()); | |
182 memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * sizeof(uint8_t)); | |
183 (*dst)->fConicWeights = src.fConicWeights; | |
152 } | 184 } |
153 (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count ()); | 185 |
154 memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * s izeof(uint8_t)); | 186 // Need to check this here in case (&src == dst) |
187 bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && s rc.countPoints() > 1; | |
188 | |
155 matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt); | 189 matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt); |
156 (*dst)->fConicWeights = src.fConicWeights; | 190 |
191 /* | |
192 * Here we optimize the bounds computation, by noting if the bounds are | |
193 * already known, and if so, we just transform those as well and mark | |
194 * them as "known", rather than force the transformed path to have to | |
195 * recompute them. | |
196 * | |
197 * Special gotchas if the path is effectively empty (<= 1 point) or | |
198 * if it is non-finite. In those cases bounds need to stay empty, | |
199 * regardless of the matrix. | |
200 */ | |
201 if (canXformBounds) { | |
202 (*dst)->fBoundsIsDirty = false; | |
203 if (src.fIsFinite) { | |
204 matrix.mapRect(&(*dst)->fBounds, src.fBounds); | |
205 if (!((*dst)->fIsFinite = (*dst)->fBounds.isFinite())) { | |
206 (*dst)->fBounds.setEmpty(); | |
207 } | |
208 } else { | |
209 (*dst)->fIsFinite = false; | |
210 (*dst)->fBounds.setEmpty(); | |
211 } | |
212 } else { | |
213 (*dst)->fBoundsIsDirty = true; | |
214 } | |
215 | |
157 (*dst)->validate(); | 216 (*dst)->validate(); |
158 } | 217 } |
159 | 218 |
160 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer) { | 219 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer |
161 SkPathRef* ref = SkNEW(SkPathRef); | 220 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O |
162 ref->fGenerationID = buffer->readU32(); | 221 , bool newFormat, int32_t oldPacked |
163 int32_t verbCount = buffer->readS32(); | 222 #endif |
164 int32_t pointCount = buffer->readS32(); | 223 ); |
165 int32_t conicCount = buffer->readS32(); | |
166 ref->resetToSize(verbCount, pointCount, conicCount); | |
167 | |
168 SkASSERT(verbCount == ref->countVerbs()); | |
169 SkASSERT(pointCount == ref->countPoints()); | |
170 SkASSERT(conicCount == ref->fConicWeights.count()); | |
171 buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t)); | |
172 buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)); | |
173 buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)); | |
174 return ref; | |
175 } | |
176 | 224 |
177 /** | 225 /** |
178 * Rollsback a path ref to zero verbs and points with the assumption that th e path ref will be | 226 * Rollsback a path ref to zero verbs and points with the assumption that th e path ref will be |
179 * repopulated with approximately the same number of verbs and points. A new path ref is created | 227 * repopulated with approximately the same number of verbs and points. A new path ref is created |
180 * only if necessary. | 228 * only if necessary. |
181 */ | 229 */ |
182 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef) { | 230 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef) { |
183 if ((*pathRef)->unique()) { | 231 if ((*pathRef)->unique()) { |
184 (*pathRef)->validate(); | 232 (*pathRef)->validate(); |
233 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFini te | |
185 (*pathRef)->fVerbCnt = 0; | 234 (*pathRef)->fVerbCnt = 0; |
186 (*pathRef)->fPointCnt = 0; | 235 (*pathRef)->fPointCnt = 0; |
187 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); | 236 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); |
188 (*pathRef)->fGenerationID = 0; | 237 (*pathRef)->fGenerationID = 0; |
189 (*pathRef)->fConicWeights.rewind(); | 238 (*pathRef)->fConicWeights.rewind(); |
190 (*pathRef)->validate(); | 239 (*pathRef)->validate(); |
191 } else { | 240 } else { |
192 int oldVCnt = (*pathRef)->countVerbs(); | 241 int oldVCnt = (*pathRef)->countVerbs(); |
193 int oldPCnt = (*pathRef)->countPoints(); | 242 int oldPCnt = (*pathRef)->countPoints(); |
194 pathRef->reset(SkNEW(SkPathRef)); | 243 pathRef->reset(SkNEW(SkPathRef)); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
283 fGenerationID = ref.genID(); | 332 fGenerationID = ref.genID(); |
284 } else if (0 == ref.fGenerationID) { | 333 } else if (0 == ref.fGenerationID) { |
285 ref.fGenerationID = this->genID(); | 334 ref.fGenerationID = this->genID(); |
286 } | 335 } |
287 return true; | 336 return true; |
288 } | 337 } |
289 | 338 |
290 /** | 339 /** |
291 * Writes the path points and verbs to a buffer. | 340 * Writes the path points and verbs to a buffer. |
292 */ | 341 */ |
293 void writeToBuffer(SkWBuffer* buffer) { | 342 void writeToBuffer(SkWBuffer* buffer); |
294 this->validate(); | |
295 SkDEBUGCODE(size_t beforePos = buffer->pos();) | |
296 | |
297 // TODO: write gen ID here. Problem: We don't know if we're cross proces s or not from | |
298 // SkWBuffer. Until this is fixed we write 0. | |
299 buffer->write32(0); | |
300 buffer->write32(fVerbCnt); | |
301 buffer->write32(fPointCnt); | |
302 buffer->write32(fConicWeights.count()); | |
303 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); | |
304 buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); | |
305 buffer->write(fConicWeights.begin(), fConicWeights.bytes()); | |
306 | |
307 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize()); | |
308 } | |
309 | 343 |
310 /** | 344 /** |
311 * Gets the number of bytes that would be written in writeBuffer() | 345 * Gets the number of bytes that would be written in writeBuffer() |
312 */ | 346 */ |
313 uint32_t writeSize() { | 347 uint32_t writeSize() { |
314 return 4 * sizeof(uint32_t) + | 348 return 5 * sizeof(uint32_t) + |
315 fVerbCnt * sizeof(uint8_t) + | 349 fVerbCnt * sizeof(uint8_t) + |
316 fPointCnt * sizeof(SkPoint) + | 350 fPointCnt * sizeof(SkPoint) + |
317 fConicWeights.bytes(); | 351 fConicWeights.bytes() + |
352 sizeof(SkRect); | |
318 } | 353 } |
319 | 354 |
320 private: | 355 private: |
356 enum SerializationOffsets { | |
357 kIsFinite_SerializationShift = 25, // requires 1 bit | |
358 }; | |
359 | |
321 SkPathRef() { | 360 SkPathRef() { |
361 fBoundsIsDirty = true; // this also invalidates fIsFinite | |
322 fPointCnt = 0; | 362 fPointCnt = 0; |
323 fVerbCnt = 0; | 363 fVerbCnt = 0; |
324 fVerbs = NULL; | 364 fVerbs = NULL; |
325 fPoints = NULL; | 365 fPoints = NULL; |
326 fFreeSpace = 0; | 366 fFreeSpace = 0; |
327 fGenerationID = kEmptyGenID; | 367 fGenerationID = kEmptyGenID; |
328 SkDEBUGCODE(fEditorsAttached = 0;) | 368 SkDEBUGCODE(fEditorsAttached = 0;) |
329 this->validate(); | 369 this->validate(); |
330 } | 370 } |
331 | 371 |
332 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe servePoints) { | 372 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe servePoints) { |
333 this->validate(); | 373 this->validate(); |
334 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count() , | 374 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count() , |
335 additionalReserveVerbs, additionalReservePoints); | 375 additionalReserveVerbs, additionalReservePoints); |
336 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * siz eof(uint8_t)); | 376 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * siz eof(uint8_t)); |
337 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); | 377 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); |
338 fConicWeights = ref.fConicWeights; | 378 fConicWeights = ref.fConicWeights; |
339 // We could call genID() here to force a real ID (instead of 0). However , if we're making | 379 // We could call genID() here to force a real ID (instead of 0). However , if we're making |
340 // a copy then presumably we intend to make a modification immediately a fterwards. | 380 // a copy then presumably we intend to make a modification immediately a fterwards. |
341 fGenerationID = ref.fGenerationID; | 381 fGenerationID = ref.fGenerationID; |
382 fBoundsIsDirty = ref.fBoundsIsDirty; | |
383 if (!fBoundsIsDirty) { | |
384 fBounds = ref.fBounds; | |
385 fIsFinite = ref.fIsFinite; | |
386 } | |
342 this->validate(); | 387 this->validate(); |
343 } | 388 } |
344 | 389 |
390 // Return true if the computed bounds are finite. | |
391 static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { | |
392 int count = ref.countPoints(); | |
393 if (count <= 1) { // we ignore just 1 point (moveto) | |
394 bounds->setEmpty(); | |
395 return count ? ref.points()->isFinite() : true; | |
396 } else { | |
397 return bounds->setBoundsCheck(ref.points(), count); | |
398 } | |
399 } | |
400 | |
401 // called, if dirty, by getBounds() | |
402 void computeBounds() const { | |
403 SkDEBUGCODE(this->validate();) | |
404 SkASSERT(fBoundsIsDirty); | |
405 | |
406 fIsFinite = ComputePtBounds(&fBounds, *this); | |
407 fBoundsIsDirty = false; | |
408 } | |
409 | |
345 /** Makes additional room but does not change the counts or change the genID */ | 410 /** Makes additional room but does not change the counts or change the genID */ |
346 void incReserve(int additionalVerbs, int additionalPoints) { | 411 void incReserve(int additionalVerbs, int additionalPoints) { |
347 this->validate(); | 412 this->validate(); |
348 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si zeof (SkPoint); | 413 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si zeof (SkPoint); |
349 this->makeSpace(space); | 414 this->makeSpace(space); |
350 this->validate(); | 415 this->validate(); |
351 } | 416 } |
352 | 417 |
353 /** Resets the path ref with verbCount verbs and pointCount points, all unit ialized. Also | 418 /** Resets the path ref with verbCount verbs and pointCount points, all unin itialized. Also |
354 * allocates space for reserveVerb additional verbs and reservePoints addit ional points.*/ | 419 * allocates space for reserveVerb additional verbs and reservePoints addit ional points.*/ |
355 void resetToSize(int verbCount, int pointCount, int conicCount, | 420 void resetToSize(int verbCount, int pointCount, int conicCount, |
356 int reserveVerbs = 0, int reservePoints = 0) { | 421 int reserveVerbs = 0, int reservePoints = 0) { |
357 this->validate(); | 422 this->validate(); |
423 fBoundsIsDirty = true; // this also invalidates fIsFinite | |
358 fGenerationID = 0; | 424 fGenerationID = 0; |
359 | 425 |
360 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCo unt; | 426 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCo unt; |
361 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * r eservePoints; | 427 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * r eservePoints; |
362 size_t minSize = newSize + newReserve; | 428 size_t minSize = newSize + newReserve; |
363 | 429 |
364 ptrdiff_t sizeDelta = this->currSize() - minSize; | 430 ptrdiff_t sizeDelta = this->currSize() - minSize; |
365 | 431 |
366 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) { | 432 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) { |
367 sk_free(fPoints); | 433 sk_free(fPoints); |
(...skipping 19 matching lines...) Expand all Loading... | |
387 * Increases the verb count by newVerbs and the point count be newPoints. Ne w verbs and points | 453 * Increases the verb count by newVerbs and the point count be newPoints. Ne w verbs and points |
388 * are uninitialized. | 454 * are uninitialized. |
389 */ | 455 */ |
390 void grow(int newVerbs, int newPoints) { | 456 void grow(int newVerbs, int newPoints) { |
391 this->validate(); | 457 this->validate(); |
392 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint) ; | 458 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint) ; |
393 this->makeSpace(space); | 459 this->makeSpace(space); |
394 fVerbCnt += newVerbs; | 460 fVerbCnt += newVerbs; |
395 fPointCnt += newPoints; | 461 fPointCnt += newPoints; |
396 fFreeSpace -= space; | 462 fFreeSpace -= space; |
463 fBoundsIsDirty = true; // this also invalidates fIsFinite | |
397 this->validate(); | 464 this->validate(); |
398 } | 465 } |
399 | 466 |
400 /** | 467 /** |
401 * Increases the verb count 1, records the new verb, and creates room for th e requisite number | 468 * Increases the verb count 1, records the new verb, and creates room for th e requisite number |
402 * of additional points. A pointer to the first point is returned. Any new p oints are | 469 * of additional points. A pointer to the first point is returned. Any new p oints are |
403 * uninitialized. | 470 * uninitialized. |
404 */ | 471 */ |
405 SkPoint* growForVerb(SkPath::Verb verb) { | 472 SkPoint* growForVerb(int /*SkPath::Verb*/ verb); |
406 this->validate(); | |
407 int pCnt; | |
408 switch (verb) { | |
409 case SkPath::kMove_Verb: | |
410 pCnt = 1; | |
411 break; | |
412 case SkPath::kLine_Verb: | |
413 pCnt = 1; | |
414 break; | |
415 case SkPath::kQuad_Verb: | |
416 // fall through | |
417 case SkPath::kConic_Verb: | |
418 pCnt = 2; | |
419 break; | |
420 case SkPath::kCubic_Verb: | |
421 pCnt = 3; | |
422 break; | |
423 case SkPath::kClose_Verb: | |
424 pCnt = 0; | |
425 break; | |
426 case SkPath::kDone_Verb: | |
427 SkDEBUGFAIL("growForVerb called for kDone"); | |
428 // fall through | |
429 default: | |
430 SkDEBUGFAIL("default is not reached"); | |
431 pCnt = 0; | |
432 } | |
433 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint); | |
434 this->makeSpace(space); | |
435 this->fVerbs[~fVerbCnt] = verb; | |
436 SkPoint* ret = fPoints + fPointCnt; | |
437 fVerbCnt += 1; | |
438 fPointCnt += pCnt; | |
439 fFreeSpace -= space; | |
440 this->validate(); | |
441 return ret; | |
442 } | |
443 | 473 |
444 /** | 474 /** |
445 * Ensures that the free space available in the path ref is >= size. The ver b and point counts | 475 * Ensures that the free space available in the path ref is >= size. The ver b and point counts |
446 * are not changed. | 476 * are not changed. |
447 */ | 477 */ |
448 void makeSpace(size_t size) { | 478 void makeSpace(size_t size) { |
449 this->validate(); | 479 this->validate(); |
450 ptrdiff_t growSize = size - fFreeSpace; | 480 ptrdiff_t growSize = size - fFreeSpace; |
451 if (growSize <= 0) { | 481 if (growSize <= 0) { |
452 return; | 482 return; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
517 void validate() const { | 547 void validate() const { |
518 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0); | 548 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0); |
519 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t> (fPoints) >= 0); | 549 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t> (fPoints) >= 0); |
520 SkASSERT((NULL == fPoints) == (NULL == fVerbs)); | 550 SkASSERT((NULL == fPoints) == (NULL == fVerbs)); |
521 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); | 551 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); |
522 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); | 552 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); |
523 SkASSERT(!(NULL == fPoints && fPointCnt)); | 553 SkASSERT(!(NULL == fPoints && fPointCnt)); |
524 SkASSERT(!(NULL == fVerbs && fVerbCnt)); | 554 SkASSERT(!(NULL == fVerbs && fVerbCnt)); |
525 SkASSERT(this->currSize() == | 555 SkASSERT(this->currSize() == |
526 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fV erbCnt); | 556 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fV erbCnt); |
557 | |
558 #ifdef SK_DEBUG | |
559 if (!fBoundsIsDirty && !fBounds.isEmpty()) { | |
560 bool isFinite = true; | |
561 for (int i = 0; i < fPointCnt; ++i) { | |
562 SkASSERT(fPoints[i].fX >= fBounds.fLeft && fPoints[i].fX <= fBou nds.fRight && | |
563 fPoints[i].fY >= fBounds.fTop && fPoints[i].fY <= fBoun ds.fBottom); | |
564 if (!fPoints[i].isFinite()) { | |
565 isFinite = false; | |
566 } | |
567 } | |
568 SkASSERT(SkToBool(fIsFinite) == isFinite); | |
569 } | |
570 #endif | |
527 } | 571 } |
528 | 572 |
529 enum { | 573 enum { |
530 kMinSize = 256, | 574 kMinSize = 256, |
531 }; | 575 }; |
532 | 576 |
577 mutable SkRect fBounds; | |
578 mutable uint8_t fBoundsIsDirty; | |
579 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid | |
580 | |
533 SkPoint* fPoints; // points to begining of the allocation | 581 SkPoint* fPoints; // points to begining of the allocation |
534 uint8_t* fVerbs; // points just past the end of the allocation (v erbs grow backwards) | 582 uint8_t* fVerbs; // points just past the end of the allocation (v erbs grow backwards) |
535 int fVerbCnt; | 583 int fVerbCnt; |
536 int fPointCnt; | 584 int fPointCnt; |
537 size_t fFreeSpace; // redundant but saves computation | 585 size_t fFreeSpace; // redundant but saves computation |
538 SkTDArray<SkScalar> fConicWeights; | 586 SkTDArray<SkScalar> fConicWeights; |
539 | 587 |
540 enum { | 588 enum { |
541 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer o verbs. | 589 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer o verbs. |
542 }; | 590 }; |
543 mutable int32_t fGenerationID; | 591 mutable int32_t fGenerationID; |
544 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time. | 592 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time. |
545 | 593 |
546 typedef SkRefCnt INHERITED; | 594 typedef SkRefCnt INHERITED; |
547 }; | 595 }; |
548 | 596 |
549 SK_DEFINE_INST_COUNT(SkPathRef); | |
550 | |
551 #endif | 597 #endif |
OLD | NEW |