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

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: Add missing file 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
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
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
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
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
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
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
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
OLDNEW
« include/core/SkPath.h ('K') | « include/core/SkPath.h ('k') | include/core/SkPicture.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698