| 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 |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |