OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2012 Google Inc. | 3 * Copyright 2012 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #ifndef SkPathRef_DEFINED | 9 #ifndef SkPathRef_DEFINED |
10 #define SkPathRef_DEFINED | 10 #define SkPathRef_DEFINED |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 */ | 122 */ |
123 static SkPathRef* CreateEmpty() { | 123 static SkPathRef* CreateEmpty() { |
124 static SkPathRef* gEmptyPathRef; | 124 static SkPathRef* gEmptyPathRef; |
125 if (!gEmptyPathRef) { | 125 if (!gEmptyPathRef) { |
126 gEmptyPathRef = SkNEW(SkPathRef); // leak! | 126 gEmptyPathRef = SkNEW(SkPathRef); // leak! |
127 } | 127 } |
128 return SkRef(gEmptyPathRef); | 128 return SkRef(gEmptyPathRef); |
129 } | 129 } |
130 | 130 |
131 /** | 131 /** |
| 132 * Returns true if all of the points in this path are finite, meaning there |
| 133 * are no infinities and no NaNs. |
| 134 */ |
| 135 bool isFinite() const { |
| 136 if (fBoundsIsDirty) { |
| 137 this->computeBounds(); |
| 138 } |
| 139 return SkToBool(fIsFinite); |
| 140 } |
| 141 |
| 142 bool hasComputedBounds() const { |
| 143 return !fBoundsIsDirty; |
| 144 } |
| 145 |
| 146 /** Returns the bounds of the path's points. If the path contains 0 or 1 |
| 147 points, the bounds is set to (0,0,0,0), and isEmpty() will return true. |
| 148 Note: this bounds may be larger than the actual shape, since curves |
| 149 do not extend as far as their control points. |
| 150 */ |
| 151 const SkRect& getBounds() const { |
| 152 if (fBoundsIsDirty) { |
| 153 this->computeBounds(); |
| 154 } |
| 155 return fBounds; |
| 156 } |
| 157 |
| 158 void setBounds(const SkRect& rect) { |
| 159 SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom); |
| 160 fBounds = rect; |
| 161 fBoundsIsDirty = false; |
| 162 fIsFinite = fBounds.isFinite(); |
| 163 } |
| 164 |
| 165 /** |
132 * Transforms a path ref by a matrix, allocating a new one only if necessary
. | 166 * Transforms a path ref by a matrix, allocating a new one only if necessary
. |
133 */ | 167 */ |
134 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, | 168 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, |
135 const SkPathRef& src, | 169 const SkPathRef& src, |
136 const SkMatrix& matrix) { | 170 const SkMatrix& matrix) { |
137 src.validate(); | 171 src.validate(); |
138 if (matrix.isIdentity()) { | 172 if (matrix.isIdentity()) { |
139 if (*dst != &src) { | 173 if (*dst != &src) { |
140 src.ref(); | 174 src.ref(); |
141 dst->reset(const_cast<SkPathRef*>(&src)); | 175 dst->reset(const_cast<SkPathRef*>(&src)); |
142 (*dst)->validate(); | 176 (*dst)->validate(); |
143 } | 177 } |
144 return; | 178 return; |
145 } | 179 } |
| 180 |
146 bool dstUnique = (*dst)->unique(); | 181 bool dstUnique = (*dst)->unique(); |
147 if (&src == *dst && dstUnique) { | 182 if (!dstUnique) { |
148 matrix.mapPoints((*dst)->fPoints, (*dst)->fPointCnt); | |
149 return; | |
150 } else if (!dstUnique) { | |
151 dst->reset(SkNEW(SkPathRef)); | 183 dst->reset(SkNEW(SkPathRef)); |
| 184 (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.c
ount()); |
| 185 memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt
* sizeof(uint8_t)); |
| 186 (*dst)->fConicWeights = src.fConicWeights; |
152 } | 187 } |
153 (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count
()); | 188 |
154 memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * s
izeof(uint8_t)); | 189 // Need to check this here in case (&src == dst) |
| 190 bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && s
rc.countPoints() > 1; |
| 191 |
155 matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt); | 192 matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt); |
156 (*dst)->fConicWeights = src.fConicWeights; | 193 |
| 194 /* |
| 195 * Here we optimize the bounds computation, by noting if the bounds are |
| 196 * already known, and if so, we just transform those as well and mark |
| 197 * them as "known", rather than force the transformed path to have to |
| 198 * recompute them. |
| 199 * |
| 200 * Special gotchas if the path is effectively empty (<= 1 point) or |
| 201 * if it is non-finite. In those cases bounds need to stay empty, |
| 202 * regardless of the matrix. |
| 203 */ |
| 204 if (canXformBounds) { |
| 205 (*dst)->fBoundsIsDirty = false; |
| 206 if (src.fIsFinite) { |
| 207 matrix.mapRect(&(*dst)->fBounds, src.fBounds); |
| 208 if (!((*dst)->fIsFinite = (*dst)->fBounds.isFinite())) { |
| 209 (*dst)->fBounds.setEmpty(); |
| 210 } |
| 211 } else { |
| 212 (*dst)->fIsFinite = false; |
| 213 (*dst)->fBounds.setEmpty(); |
| 214 } |
| 215 } else { |
| 216 (*dst)->fBoundsIsDirty = true; |
| 217 } |
| 218 |
157 (*dst)->validate(); | 219 (*dst)->validate(); |
158 } | 220 } |
159 | 221 |
160 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer) { | 222 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer |
| 223 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
| 224 , bool newFormat, int32_t oldPacked |
| 225 #endif |
| 226 ) { |
161 SkPathRef* ref = SkNEW(SkPathRef); | 227 SkPathRef* ref = SkNEW(SkPathRef); |
| 228 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
| 229 if (newFormat) { |
| 230 #endif |
| 231 int32_t packed = buffer->readU32(); |
| 232 |
| 233 ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1; |
| 234 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
| 235 } else { |
| 236 ref->fIsFinite = (oldPacked >> SkPath::kOldIsFinite_SerializationShi
ft) & 1; |
| 237 } |
| 238 #endif |
| 239 |
162 ref->fGenerationID = buffer->readU32(); | 240 ref->fGenerationID = buffer->readU32(); |
163 int32_t verbCount = buffer->readS32(); | 241 int32_t verbCount = buffer->readS32(); |
164 int32_t pointCount = buffer->readS32(); | 242 int32_t pointCount = buffer->readS32(); |
165 int32_t conicCount = buffer->readS32(); | 243 int32_t conicCount = buffer->readS32(); |
166 ref->resetToSize(verbCount, pointCount, conicCount); | 244 ref->resetToSize(verbCount, pointCount, conicCount); |
167 | 245 |
168 SkASSERT(verbCount == ref->countVerbs()); | 246 SkASSERT(verbCount == ref->countVerbs()); |
169 SkASSERT(pointCount == ref->countPoints()); | 247 SkASSERT(pointCount == ref->countPoints()); |
170 SkASSERT(conicCount == ref->fConicWeights.count()); | 248 SkASSERT(conicCount == ref->fConicWeights.count()); |
171 buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t)); | 249 buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t)); |
172 buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)); | 250 buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)); |
173 buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)); | 251 buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)); |
| 252 buffer->read(&ref->fBounds, sizeof(SkRect)); |
| 253 ref->fBoundsIsDirty = false; |
174 return ref; | 254 return ref; |
175 } | 255 } |
176 | 256 |
177 /** | 257 /** |
178 * Rollsback a path ref to zero verbs and points with the assumption that th
e path ref will be | 258 * 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 | 259 * repopulated with approximately the same number of verbs and points. A new
path ref is created |
180 * only if necessary. | 260 * only if necessary. |
181 */ | 261 */ |
182 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef) { | 262 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef) { |
183 if ((*pathRef)->unique()) { | 263 if ((*pathRef)->unique()) { |
184 (*pathRef)->validate(); | 264 (*pathRef)->validate(); |
| 265 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFini
te |
185 (*pathRef)->fVerbCnt = 0; | 266 (*pathRef)->fVerbCnt = 0; |
186 (*pathRef)->fPointCnt = 0; | 267 (*pathRef)->fPointCnt = 0; |
187 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); | 268 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); |
188 (*pathRef)->fGenerationID = 0; | 269 (*pathRef)->fGenerationID = 0; |
189 (*pathRef)->fConicWeights.rewind(); | 270 (*pathRef)->fConicWeights.rewind(); |
190 (*pathRef)->validate(); | 271 (*pathRef)->validate(); |
191 } else { | 272 } else { |
192 int oldVCnt = (*pathRef)->countVerbs(); | 273 int oldVCnt = (*pathRef)->countVerbs(); |
193 int oldPCnt = (*pathRef)->countPoints(); | 274 int oldPCnt = (*pathRef)->countPoints(); |
194 pathRef->reset(SkNEW(SkPathRef)); | 275 pathRef->reset(SkNEW(SkPathRef)); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 return true; | 368 return true; |
288 } | 369 } |
289 | 370 |
290 /** | 371 /** |
291 * Writes the path points and verbs to a buffer. | 372 * Writes the path points and verbs to a buffer. |
292 */ | 373 */ |
293 void writeToBuffer(SkWBuffer* buffer) { | 374 void writeToBuffer(SkWBuffer* buffer) { |
294 this->validate(); | 375 this->validate(); |
295 SkDEBUGCODE(size_t beforePos = buffer->pos();) | 376 SkDEBUGCODE(size_t beforePos = buffer->pos();) |
296 | 377 |
| 378 // Call getBounds() to ensure (as a side-effect) that fBounds |
| 379 // and fIsFinite are computed. |
| 380 const SkRect& bounds = this->getBounds(); |
| 381 |
| 382 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift); |
| 383 buffer->write32(packed); |
| 384 |
297 // TODO: write gen ID here. Problem: We don't know if we're cross proces
s or not from | 385 // 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. | 386 // SkWBuffer. Until this is fixed we write 0. |
299 buffer->write32(0); | 387 buffer->write32(0); |
300 buffer->write32(fVerbCnt); | 388 buffer->write32(fVerbCnt); |
301 buffer->write32(fPointCnt); | 389 buffer->write32(fPointCnt); |
302 buffer->write32(fConicWeights.count()); | 390 buffer->write32(fConicWeights.count()); |
303 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); | 391 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); |
304 buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); | 392 buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); |
305 buffer->write(fConicWeights.begin(), fConicWeights.bytes()); | 393 buffer->write(fConicWeights.begin(), fConicWeights.bytes()); |
| 394 buffer->write(&bounds, sizeof(bounds)); |
306 | 395 |
307 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize()); | 396 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize()); |
308 } | 397 } |
309 | 398 |
310 /** | 399 /** |
311 * Gets the number of bytes that would be written in writeBuffer() | 400 * Gets the number of bytes that would be written in writeBuffer() |
312 */ | 401 */ |
313 uint32_t writeSize() { | 402 uint32_t writeSize() { |
314 return 4 * sizeof(uint32_t) + | 403 return 5 * sizeof(uint32_t) + |
315 fVerbCnt * sizeof(uint8_t) + | 404 fVerbCnt * sizeof(uint8_t) + |
316 fPointCnt * sizeof(SkPoint) + | 405 fPointCnt * sizeof(SkPoint) + |
317 fConicWeights.bytes(); | 406 fConicWeights.bytes() + |
| 407 sizeof(SkRect); |
318 } | 408 } |
319 | 409 |
320 private: | 410 private: |
| 411 enum SerializationOffsets { |
| 412 kIsFinite_SerializationShift = 25, // requires 1 bit |
| 413 }; |
| 414 |
321 SkPathRef() { | 415 SkPathRef() { |
| 416 fBoundsIsDirty = true; // this also invalidates fIsFinite |
322 fPointCnt = 0; | 417 fPointCnt = 0; |
323 fVerbCnt = 0; | 418 fVerbCnt = 0; |
324 fVerbs = NULL; | 419 fVerbs = NULL; |
325 fPoints = NULL; | 420 fPoints = NULL; |
326 fFreeSpace = 0; | 421 fFreeSpace = 0; |
327 fGenerationID = kEmptyGenID; | 422 fGenerationID = kEmptyGenID; |
328 SkDEBUGCODE(fEditorsAttached = 0;) | 423 SkDEBUGCODE(fEditorsAttached = 0;) |
329 this->validate(); | 424 this->validate(); |
330 } | 425 } |
331 | 426 |
332 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe
servePoints) { | 427 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe
servePoints) { |
333 this->validate(); | 428 this->validate(); |
334 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count()
, | 429 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count()
, |
335 additionalReserveVerbs, additionalReservePoints); | 430 additionalReserveVerbs, additionalReservePoints); |
336 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * siz
eof(uint8_t)); | 431 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * siz
eof(uint8_t)); |
337 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); | 432 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); |
338 fConicWeights = ref.fConicWeights; | 433 fConicWeights = ref.fConicWeights; |
339 // We could call genID() here to force a real ID (instead of 0). However
, if we're making | 434 // 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. | 435 // a copy then presumably we intend to make a modification immediately a
fterwards. |
341 fGenerationID = ref.fGenerationID; | 436 fGenerationID = ref.fGenerationID; |
| 437 fBoundsIsDirty = ref.fBoundsIsDirty; |
| 438 if (!fBoundsIsDirty) { |
| 439 fBounds = ref.fBounds; |
| 440 fIsFinite = ref.fIsFinite; |
| 441 } |
342 this->validate(); | 442 this->validate(); |
343 } | 443 } |
344 | 444 |
| 445 // Return true if the computed bounds are finite. |
| 446 static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { |
| 447 int count = ref.countPoints(); |
| 448 if (count <= 1) { // we ignore just 1 point (moveto) |
| 449 bounds->setEmpty(); |
| 450 return count ? ref.points()->isFinite() : true; |
| 451 } else { |
| 452 return bounds->setBoundsCheck(ref.points(), count); |
| 453 } |
| 454 } |
| 455 |
| 456 // called, if dirty, by getBounds() |
| 457 void computeBounds() const { |
| 458 SkDEBUGCODE(this->validate();) |
| 459 SkASSERT(fBoundsIsDirty); |
| 460 |
| 461 fIsFinite = ComputePtBounds(&fBounds, *this); |
| 462 fBoundsIsDirty = false; |
| 463 } |
| 464 |
345 /** Makes additional room but does not change the counts or change the genID
*/ | 465 /** Makes additional room but does not change the counts or change the genID
*/ |
346 void incReserve(int additionalVerbs, int additionalPoints) { | 466 void incReserve(int additionalVerbs, int additionalPoints) { |
347 this->validate(); | 467 this->validate(); |
348 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si
zeof (SkPoint); | 468 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si
zeof (SkPoint); |
349 this->makeSpace(space); | 469 this->makeSpace(space); |
350 this->validate(); | 470 this->validate(); |
351 } | 471 } |
352 | 472 |
353 /** Resets the path ref with verbCount verbs and pointCount points, all unit
ialized. Also | 473 /** 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.*/ | 474 * allocates space for reserveVerb additional verbs and reservePoints addit
ional points.*/ |
355 void resetToSize(int verbCount, int pointCount, int conicCount, | 475 void resetToSize(int verbCount, int pointCount, int conicCount, |
356 int reserveVerbs = 0, int reservePoints = 0) { | 476 int reserveVerbs = 0, int reservePoints = 0) { |
357 this->validate(); | 477 this->validate(); |
| 478 fBoundsIsDirty = true; // this also invalidates fIsFinite |
358 fGenerationID = 0; | 479 fGenerationID = 0; |
359 | 480 |
360 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCo
unt; | 481 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCo
unt; |
361 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * r
eservePoints; | 482 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * r
eservePoints; |
362 size_t minSize = newSize + newReserve; | 483 size_t minSize = newSize + newReserve; |
363 | 484 |
364 ptrdiff_t sizeDelta = this->currSize() - minSize; | 485 ptrdiff_t sizeDelta = this->currSize() - minSize; |
365 | 486 |
366 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) { | 487 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) { |
367 sk_free(fPoints); | 488 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 | 508 * Increases the verb count by newVerbs and the point count be newPoints. Ne
w verbs and points |
388 * are uninitialized. | 509 * are uninitialized. |
389 */ | 510 */ |
390 void grow(int newVerbs, int newPoints) { | 511 void grow(int newVerbs, int newPoints) { |
391 this->validate(); | 512 this->validate(); |
392 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint)
; | 513 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint)
; |
393 this->makeSpace(space); | 514 this->makeSpace(space); |
394 fVerbCnt += newVerbs; | 515 fVerbCnt += newVerbs; |
395 fPointCnt += newPoints; | 516 fPointCnt += newPoints; |
396 fFreeSpace -= space; | 517 fFreeSpace -= space; |
| 518 fBoundsIsDirty = true; // this also invalidates fIsFinite |
397 this->validate(); | 519 this->validate(); |
398 } | 520 } |
399 | 521 |
400 /** | 522 /** |
401 * Increases the verb count 1, records the new verb, and creates room for th
e requisite number | 523 * 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 | 524 * of additional points. A pointer to the first point is returned. Any new p
oints are |
403 * uninitialized. | 525 * uninitialized. |
404 */ | 526 */ |
405 SkPoint* growForVerb(SkPath::Verb verb) { | 527 SkPoint* growForVerb(SkPath::Verb verb) { |
406 this->validate(); | 528 this->validate(); |
(...skipping 23 matching lines...) Expand all Loading... |
430 SkDEBUGFAIL("default is not reached"); | 552 SkDEBUGFAIL("default is not reached"); |
431 pCnt = 0; | 553 pCnt = 0; |
432 } | 554 } |
433 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint); | 555 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint); |
434 this->makeSpace(space); | 556 this->makeSpace(space); |
435 this->fVerbs[~fVerbCnt] = verb; | 557 this->fVerbs[~fVerbCnt] = verb; |
436 SkPoint* ret = fPoints + fPointCnt; | 558 SkPoint* ret = fPoints + fPointCnt; |
437 fVerbCnt += 1; | 559 fVerbCnt += 1; |
438 fPointCnt += pCnt; | 560 fPointCnt += pCnt; |
439 fFreeSpace -= space; | 561 fFreeSpace -= space; |
| 562 fBoundsIsDirty = true; // this also invalidates fIsFinite |
440 this->validate(); | 563 this->validate(); |
441 return ret; | 564 return ret; |
442 } | 565 } |
443 | 566 |
444 /** | 567 /** |
445 * Ensures that the free space available in the path ref is >= size. The ver
b and point counts | 568 * Ensures that the free space available in the path ref is >= size. The ver
b and point counts |
446 * are not changed. | 569 * are not changed. |
447 */ | 570 */ |
448 void makeSpace(size_t size) { | 571 void makeSpace(size_t size) { |
449 this->validate(); | 572 this->validate(); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 void validate() const { | 640 void validate() const { |
518 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0); | 641 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0); |
519 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>
(fPoints) >= 0); | 642 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>
(fPoints) >= 0); |
520 SkASSERT((NULL == fPoints) == (NULL == fVerbs)); | 643 SkASSERT((NULL == fPoints) == (NULL == fVerbs)); |
521 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); | 644 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); |
522 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); | 645 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); |
523 SkASSERT(!(NULL == fPoints && fPointCnt)); | 646 SkASSERT(!(NULL == fPoints && fPointCnt)); |
524 SkASSERT(!(NULL == fVerbs && fVerbCnt)); | 647 SkASSERT(!(NULL == fVerbs && fVerbCnt)); |
525 SkASSERT(this->currSize() == | 648 SkASSERT(this->currSize() == |
526 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fV
erbCnt); | 649 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fV
erbCnt); |
| 650 |
| 651 #ifdef SK_DEBUG |
| 652 if (!fBoundsIsDirty && !fBounds.isEmpty()) { |
| 653 bool isFinite = true; |
| 654 for (int i = 0; i < fPointCnt; ++i) { |
| 655 SkASSERT(fPoints[i].fX >= fBounds.fLeft && fPoints[i].fX <= fBou
nds.fRight && |
| 656 fPoints[i].fY >= fBounds.fTop && fPoints[i].fY <= fBoun
ds.fBottom); |
| 657 if (!fPoints[i].isFinite()) { |
| 658 isFinite = false; |
| 659 } |
| 660 } |
| 661 SkASSERT(SkToBool(fIsFinite) == isFinite); |
| 662 } |
| 663 #endif |
527 } | 664 } |
528 | 665 |
529 enum { | 666 enum { |
530 kMinSize = 256, | 667 kMinSize = 256, |
531 }; | 668 }; |
532 | 669 |
| 670 mutable SkRect fBounds; |
| 671 mutable uint8_t fBoundsIsDirty; |
| 672 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid |
| 673 |
533 SkPoint* fPoints; // points to begining of the allocation | 674 SkPoint* fPoints; // points to begining of the allocation |
534 uint8_t* fVerbs; // points just past the end of the allocation (v
erbs grow backwards) | 675 uint8_t* fVerbs; // points just past the end of the allocation (v
erbs grow backwards) |
535 int fVerbCnt; | 676 int fVerbCnt; |
536 int fPointCnt; | 677 int fPointCnt; |
537 size_t fFreeSpace; // redundant but saves computation | 678 size_t fFreeSpace; // redundant but saves computation |
538 SkTDArray<SkScalar> fConicWeights; | 679 SkTDArray<SkScalar> fConicWeights; |
539 | 680 |
540 enum { | 681 enum { |
541 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer
o verbs. | 682 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer
o verbs. |
542 }; | 683 }; |
543 mutable int32_t fGenerationID; | 684 mutable int32_t fGenerationID; |
544 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use
at any time. | 685 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use
at any time. |
545 | 686 |
546 typedef SkRefCnt INHERITED; | 687 typedef SkRefCnt INHERITED; |
547 }; | 688 }; |
548 | 689 |
549 SK_DEFINE_INST_COUNT(SkPathRef); | 690 SK_DEFINE_INST_COUNT(SkPathRef); |
550 | 691 |
551 #endif | 692 #endif |
OLD | NEW |