Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: include/core/SkPathRef.h

Issue 24350006: Move bound and isFinite into pathref (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Added TODO Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « include/core/SkPath.h ('k') | include/core/SkPicture.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
14 18
19 class SkRBuffer;
20 class SkWBuffer;
21
22 // TODO: refactor this header to move more of the implementation into the .cpp
23
15 /** 24 /**
16 * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods 25 * 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 26 * 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 27 * 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 28 * 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 29 * constructor a SkAutoTUnref, which may be updated to point to a new SkPathRef after the editor's
21 * constructor returns. 30 * constructor returns.
22 * 31 *
23 * The points and verbs are stored in a single allocation. The points are at the begining of the 32 * 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 33 * 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 34 * 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 35 * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first
27 * logical verb or the last verb in memory). 36 * logical verb or the last verb in memory).
28 */ 37 */
29 38
30 class SkPathRef;
31
32 class SkPathRef : public ::SkRefCnt { 39 class SkPathRef : public ::SkRefCnt {
33 public: 40 public:
34 SK_DECLARE_INST_COUNT(SkPathRef); 41 SK_DECLARE_INST_COUNT(SkPathRef);
35 42
36 class Editor { 43 class Editor {
37 public: 44 public:
38 Editor(SkAutoTUnref<SkPathRef>* pathRef, 45 Editor(SkAutoTUnref<SkPathRef>* pathRef,
39 int incReserveVerbs = 0, 46 int incReserveVerbs = 0,
40 int incReservePoints = 0) 47 int incReservePoints = 0)
41 { 48 {
(...skipping 21 matching lines...) Expand all
63 */ 70 */
64 SkPoint* atPoint(int i) { 71 SkPoint* atPoint(int i) {
65 SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); 72 SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt);
66 return this->points() + i; 73 return this->points() + i;
67 }; 74 };
68 75
69 /** 76 /**
70 * Adds the verb and allocates space for the number of points indicated by the verb. The 77 * 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. 78 * return value is a pointer to where the points for the verb should be written.
72 */ 79 */
73 SkPoint* growForVerb(SkPath::Verb verb) { 80 SkPoint* growForVerb(int /*SkPath::Verb*/ verb);
74 fPathRef->validate();
75 return fPathRef->growForVerb(verb);
76 }
77 81
78 SkPoint* growForConic(SkScalar w) { 82 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 83
85 /** 84 /**
86 * Allocates space for additional verbs and points and returns pointers to the new verbs and 85 * 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 86 * 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>]). 87 * at the first new point (indexed normally [<i>]).
89 */ 88 */
90 void grow(int newVerbs, int newPts, uint8_t** verbs, SkPoint** pts) { 89 void grow(int newVerbs, int newPts, uint8_t** verbs, SkPoint** pts) {
91 SkASSERT(NULL != verbs); 90 SkASSERT(NULL != verbs);
92 SkASSERT(NULL != pts); 91 SkASSERT(NULL != pts);
93 fPathRef->validate(); 92 fPathRef->validate();
(...skipping 28 matching lines...) Expand all
122 */ 121 */
123 static SkPathRef* CreateEmpty() { 122 static SkPathRef* CreateEmpty() {
124 static SkPathRef* gEmptyPathRef; 123 static SkPathRef* gEmptyPathRef;
125 if (!gEmptyPathRef) { 124 if (!gEmptyPathRef) {
126 gEmptyPathRef = SkNEW(SkPathRef); // leak! 125 gEmptyPathRef = SkNEW(SkPathRef); // leak!
127 } 126 }
128 return SkRef(gEmptyPathRef); 127 return SkRef(gEmptyPathRef);
129 } 128 }
130 129
131 /** 130 /**
131 * Returns true if all of the points in this path are finite, meaning there
132 * are no infinities and no NaNs.
133 */
134 bool isFinite() const {
135 if (fBoundsIsDirty) {
136 this->computeBounds();
137 }
138 return SkToBool(fIsFinite);
139 }
140
141 bool hasComputedBounds() const {
142 return !fBoundsIsDirty;
143 }
144
145 /** Returns the bounds of the path's points. If the path contains 0 or 1
146 points, the bounds is set to (0,0,0,0), and isEmpty() will return true.
147 Note: this bounds may be larger than the actual shape, since curves
148 do not extend as far as their control points.
149 */
150 const SkRect& getBounds() const {
151 if (fBoundsIsDirty) {
152 this->computeBounds();
153 }
154 return fBounds;
155 }
156
157 void setBounds(const SkRect& rect) {
158 SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom);
159 fBounds = rect;
160 fBoundsIsDirty = false;
161 fIsFinite = fBounds.isFinite();
162 }
163
164 /**
132 * Transforms a path ref by a matrix, allocating a new one only if necessary . 165 * Transforms a path ref by a matrix, allocating a new one only if necessary .
133 */ 166 */
134 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, 167 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
135 const SkPathRef& src, 168 const SkPathRef& src,
136 const SkMatrix& matrix) { 169 const SkMatrix& matrix) {
137 src.validate(); 170 src.validate();
138 if (matrix.isIdentity()) { 171 if (matrix.isIdentity()) {
139 if (*dst != &src) { 172 if (*dst != &src) {
140 src.ref(); 173 src.ref();
141 dst->reset(const_cast<SkPathRef*>(&src)); 174 dst->reset(const_cast<SkPathRef*>(&src));
142 (*dst)->validate(); 175 (*dst)->validate();
143 } 176 }
144 return; 177 return;
145 } 178 }
179
146 bool dstUnique = (*dst)->unique(); 180 bool dstUnique = (*dst)->unique();
147 if (&src == *dst && dstUnique) { 181 if (!dstUnique) {
148 matrix.mapPoints((*dst)->fPoints, (*dst)->fPointCnt);
149 return;
150 } else if (!dstUnique) {
151 dst->reset(SkNEW(SkPathRef)); 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;
152 } 186 }
153 (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count ()); 187
154 memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * s izeof(uint8_t)); 188 // Need to check this here in case (&src == dst)
189 bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && s rc.countPoints() > 1;
190
155 matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt); 191 matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt);
156 (*dst)->fConicWeights = src.fConicWeights; 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
157 (*dst)->validate(); 218 (*dst)->validate();
158 } 219 }
159 220
160 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer) { 221 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer
161 SkPathRef* ref = SkNEW(SkPathRef); 222 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
162 ref->fGenerationID = buffer->readU32(); 223 , bool newFormat, int32_t oldPacked
163 int32_t verbCount = buffer->readS32(); 224 #endif
164 int32_t pointCount = buffer->readS32(); 225 );
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 226
177 /** 227 /**
178 * Rollsback a path ref to zero verbs and points with the assumption that th e path ref will be 228 * 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 229 * repopulated with approximately the same number of verbs and points. A new path ref is created
180 * only if necessary. 230 * only if necessary.
181 */ 231 */
182 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef) { 232 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef) {
183 if ((*pathRef)->unique()) { 233 if ((*pathRef)->unique()) {
184 (*pathRef)->validate(); 234 (*pathRef)->validate();
235 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFini te
185 (*pathRef)->fVerbCnt = 0; 236 (*pathRef)->fVerbCnt = 0;
186 (*pathRef)->fPointCnt = 0; 237 (*pathRef)->fPointCnt = 0;
187 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); 238 (*pathRef)->fFreeSpace = (*pathRef)->currSize();
188 (*pathRef)->fGenerationID = 0; 239 (*pathRef)->fGenerationID = 0;
189 (*pathRef)->fConicWeights.rewind(); 240 (*pathRef)->fConicWeights.rewind();
190 (*pathRef)->validate(); 241 (*pathRef)->validate();
191 } else { 242 } else {
192 int oldVCnt = (*pathRef)->countVerbs(); 243 int oldVCnt = (*pathRef)->countVerbs();
193 int oldPCnt = (*pathRef)->countPoints(); 244 int oldPCnt = (*pathRef)->countPoints();
194 pathRef->reset(SkNEW(SkPathRef)); 245 pathRef->reset(SkNEW(SkPathRef));
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 fGenerationID = ref.genID(); 334 fGenerationID = ref.genID();
284 } else if (0 == ref.fGenerationID) { 335 } else if (0 == ref.fGenerationID) {
285 ref.fGenerationID = this->genID(); 336 ref.fGenerationID = this->genID();
286 } 337 }
287 return true; 338 return true;
288 } 339 }
289 340
290 /** 341 /**
291 * Writes the path points and verbs to a buffer. 342 * Writes the path points and verbs to a buffer.
292 */ 343 */
293 void writeToBuffer(SkWBuffer* buffer) { 344 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 345
310 /** 346 /**
311 * Gets the number of bytes that would be written in writeBuffer() 347 * Gets the number of bytes that would be written in writeBuffer()
312 */ 348 */
313 uint32_t writeSize() { 349 uint32_t writeSize() {
314 return 4 * sizeof(uint32_t) + 350 return 5 * sizeof(uint32_t) +
315 fVerbCnt * sizeof(uint8_t) + 351 fVerbCnt * sizeof(uint8_t) +
316 fPointCnt * sizeof(SkPoint) + 352 fPointCnt * sizeof(SkPoint) +
317 fConicWeights.bytes(); 353 fConicWeights.bytes() +
354 sizeof(SkRect);
318 } 355 }
319 356
320 private: 357 private:
358 enum SerializationOffsets {
359 kIsFinite_SerializationShift = 25, // requires 1 bit
360 };
361
321 SkPathRef() { 362 SkPathRef() {
363 fBoundsIsDirty = true; // this also invalidates fIsFinite
322 fPointCnt = 0; 364 fPointCnt = 0;
323 fVerbCnt = 0; 365 fVerbCnt = 0;
324 fVerbs = NULL; 366 fVerbs = NULL;
325 fPoints = NULL; 367 fPoints = NULL;
326 fFreeSpace = 0; 368 fFreeSpace = 0;
327 fGenerationID = kEmptyGenID; 369 fGenerationID = kEmptyGenID;
328 SkDEBUGCODE(fEditorsAttached = 0;) 370 SkDEBUGCODE(fEditorsAttached = 0;)
329 this->validate(); 371 this->validate();
330 } 372 }
331 373
332 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe servePoints) { 374 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe servePoints) {
333 this->validate(); 375 this->validate();
334 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count() , 376 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count() ,
335 additionalReserveVerbs, additionalReservePoints); 377 additionalReserveVerbs, additionalReservePoints);
336 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * siz eof(uint8_t)); 378 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * siz eof(uint8_t));
337 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); 379 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
338 fConicWeights = ref.fConicWeights; 380 fConicWeights = ref.fConicWeights;
339 // We could call genID() here to force a real ID (instead of 0). However , if we're making 381 // 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. 382 // a copy then presumably we intend to make a modification immediately a fterwards.
341 fGenerationID = ref.fGenerationID; 383 fGenerationID = ref.fGenerationID;
384 fBoundsIsDirty = ref.fBoundsIsDirty;
385 if (!fBoundsIsDirty) {
386 fBounds = ref.fBounds;
387 fIsFinite = ref.fIsFinite;
388 }
342 this->validate(); 389 this->validate();
343 } 390 }
344 391
392 // Return true if the computed bounds are finite.
393 static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) {
394 int count = ref.countPoints();
395 if (count <= 1) { // we ignore just 1 point (moveto)
396 bounds->setEmpty();
397 return count ? ref.points()->isFinite() : true;
398 } else {
399 return bounds->setBoundsCheck(ref.points(), count);
400 }
401 }
402
403 // called, if dirty, by getBounds()
404 void computeBounds() const {
405 SkDEBUGCODE(this->validate();)
406 SkASSERT(fBoundsIsDirty);
407
408 fIsFinite = ComputePtBounds(&fBounds, *this);
409 fBoundsIsDirty = false;
410 }
411
345 /** Makes additional room but does not change the counts or change the genID */ 412 /** Makes additional room but does not change the counts or change the genID */
346 void incReserve(int additionalVerbs, int additionalPoints) { 413 void incReserve(int additionalVerbs, int additionalPoints) {
347 this->validate(); 414 this->validate();
348 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si zeof (SkPoint); 415 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si zeof (SkPoint);
349 this->makeSpace(space); 416 this->makeSpace(space);
350 this->validate(); 417 this->validate();
351 } 418 }
352 419
353 /** Resets the path ref with verbCount verbs and pointCount points, all unit ialized. Also 420 /** 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.*/ 421 * allocates space for reserveVerb additional verbs and reservePoints addit ional points.*/
355 void resetToSize(int verbCount, int pointCount, int conicCount, 422 void resetToSize(int verbCount, int pointCount, int conicCount,
356 int reserveVerbs = 0, int reservePoints = 0) { 423 int reserveVerbs = 0, int reservePoints = 0) {
357 this->validate(); 424 this->validate();
425 fBoundsIsDirty = true; // this also invalidates fIsFinite
358 fGenerationID = 0; 426 fGenerationID = 0;
359 427
360 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCo unt; 428 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCo unt;
361 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * r eservePoints; 429 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * r eservePoints;
362 size_t minSize = newSize + newReserve; 430 size_t minSize = newSize + newReserve;
363 431
364 ptrdiff_t sizeDelta = this->currSize() - minSize; 432 ptrdiff_t sizeDelta = this->currSize() - minSize;
365 433
366 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) { 434 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) {
367 sk_free(fPoints); 435 sk_free(fPoints);
(...skipping 19 matching lines...) Expand all
387 * Increases the verb count by newVerbs and the point count be newPoints. Ne w verbs and points 455 * Increases the verb count by newVerbs and the point count be newPoints. Ne w verbs and points
388 * are uninitialized. 456 * are uninitialized.
389 */ 457 */
390 void grow(int newVerbs, int newPoints) { 458 void grow(int newVerbs, int newPoints) {
391 this->validate(); 459 this->validate();
392 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint) ; 460 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint) ;
393 this->makeSpace(space); 461 this->makeSpace(space);
394 fVerbCnt += newVerbs; 462 fVerbCnt += newVerbs;
395 fPointCnt += newPoints; 463 fPointCnt += newPoints;
396 fFreeSpace -= space; 464 fFreeSpace -= space;
465 fBoundsIsDirty = true; // this also invalidates fIsFinite
397 this->validate(); 466 this->validate();
398 } 467 }
399 468
400 /** 469 /**
401 * Increases the verb count 1, records the new verb, and creates room for th e requisite number 470 * 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 471 * of additional points. A pointer to the first point is returned. Any new p oints are
403 * uninitialized. 472 * uninitialized.
404 */ 473 */
405 SkPoint* growForVerb(SkPath::Verb verb) { 474 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 475
444 /** 476 /**
445 * Ensures that the free space available in the path ref is >= size. The ver b and point counts 477 * Ensures that the free space available in the path ref is >= size. The ver b and point counts
446 * are not changed. 478 * are not changed.
447 */ 479 */
448 void makeSpace(size_t size) { 480 void makeSpace(size_t size) {
449 this->validate(); 481 this->validate();
450 ptrdiff_t growSize = size - fFreeSpace; 482 ptrdiff_t growSize = size - fFreeSpace;
451 if (growSize <= 0) { 483 if (growSize <= 0) {
452 return; 484 return;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 void validate() const { 549 void validate() const {
518 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0); 550 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0);
519 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t> (fPoints) >= 0); 551 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t> (fPoints) >= 0);
520 SkASSERT((NULL == fPoints) == (NULL == fVerbs)); 552 SkASSERT((NULL == fPoints) == (NULL == fVerbs));
521 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); 553 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
522 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); 554 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
523 SkASSERT(!(NULL == fPoints && fPointCnt)); 555 SkASSERT(!(NULL == fPoints && fPointCnt));
524 SkASSERT(!(NULL == fVerbs && fVerbCnt)); 556 SkASSERT(!(NULL == fVerbs && fVerbCnt));
525 SkASSERT(this->currSize() == 557 SkASSERT(this->currSize() ==
526 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fV erbCnt); 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
527 } 573 }
528 574
529 enum { 575 enum {
530 kMinSize = 256, 576 kMinSize = 256,
531 }; 577 };
532 578
579 mutable SkRect fBounds;
580 mutable uint8_t fBoundsIsDirty;
581 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid
582
533 SkPoint* fPoints; // points to begining of the allocation 583 SkPoint* fPoints; // points to begining of the allocation
534 uint8_t* fVerbs; // points just past the end of the allocation (v erbs grow backwards) 584 uint8_t* fVerbs; // points just past the end of the allocation (v erbs grow backwards)
535 int fVerbCnt; 585 int fVerbCnt;
536 int fPointCnt; 586 int fPointCnt;
537 size_t fFreeSpace; // redundant but saves computation 587 size_t fFreeSpace; // redundant but saves computation
538 SkTDArray<SkScalar> fConicWeights; 588 SkTDArray<SkScalar> fConicWeights;
539 589
540 enum { 590 enum {
541 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer o verbs. 591 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer o verbs.
542 }; 592 };
543 mutable int32_t fGenerationID; 593 mutable int32_t fGenerationID;
544 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time. 594 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time.
545 595
546 typedef SkRefCnt INHERITED; 596 typedef SkRefCnt INHERITED;
547 }; 597 };
548 598
549 SK_DEFINE_INST_COUNT(SkPathRef);
550
551 #endif 599 #endif
OLDNEW
« no previous file with comments | « include/core/SkPath.h ('k') | include/core/SkPicture.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698