| 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" | 12 #include "SkMatrix.h" |
| 13 #include "SkPoint.h" | 13 #include "SkPoint.h" |
| 14 #include "SkRect.h" | 14 #include "SkRect.h" |
| 15 #include "SkRefCnt.h" | 15 #include "SkRefCnt.h" |
| 16 #include "SkTDArray.h" | 16 #include "SkTDArray.h" |
| 17 #include <stddef.h> // ptrdiff_t | 17 #include <stddef.h> // ptrdiff_t |
| 18 | 18 |
| 19 class SkRBuffer; | 19 class SkRBuffer; |
| 20 class SkWBuffer; | 20 class SkWBuffer; |
| 21 | 21 |
| 22 /** | 22 /** |
| 23 * 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 |
| 24 * 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 |
| 25 * 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 |
| 26 * 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 multiple SkPaths. The caller pass
es the Editor's |
| 27 * 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 |
| 28 * constructor returns. | 28 * constructor returns. |
| 29 * | 29 * |
| 30 * 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 |
| 31 * 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 |
| 32 * 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 |
| 33 * 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 |
| 34 * logical verb or the last verb in memory). | 34 * logical verb or the last verb in memory). |
| 35 */ | 35 */ |
| 36 | 36 |
| 37 class SK_API SkPathRef : public ::SkRefCnt { | 37 class SK_API SkPathRef : public ::SkRefCnt { |
| 38 public: | 38 public: |
| 39 SK_DECLARE_INST_COUNT(SkPathRef); | 39 SK_DECLARE_INST_COUNT(SkPathRef); |
| 40 | 40 |
| 41 enum Verb { |
| 42 kMove_Verb, //!< iter.next returns 1 point |
| 43 kLine_Verb, //!< iter.next returns 2 points |
| 44 kQuad_Verb, //!< iter.next returns 3 points |
| 45 kConic_Verb, //!< iter.next returns 3 points + iter.conicWeight() |
| 46 kCubic_Verb, //!< iter.next returns 4 points |
| 47 kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt) |
| 48 kDone_Verb, //!< iter.next returns 0 points |
| 49 }; |
| 50 |
| 41 class Editor { | 51 class Editor { |
| 42 public: | 52 public: |
| 43 Editor(SkAutoTUnref<SkPathRef>* pathRef, | 53 Editor(SkAutoTUnref<SkPathRef>* pathRef, |
| 44 int incReserveVerbs = 0, | 54 int incReserveVerbs = 0, |
| 45 int incReservePoints = 0); | 55 int incReservePoints = 0); |
| 46 | 56 |
| 47 ~Editor() { SkDEBUGCODE(sk_atomic_dec(&fPathRef->fEditorsAttached);) } | 57 ~Editor() { SkDEBUGCODE(sk_atomic_dec(&fPathRef->fEditorsAttached);) } |
| 48 | 58 |
| 49 /** | 59 /** |
| 50 * Returns the array of points. | 60 * Returns the array of points. |
| 51 */ | 61 */ |
| 52 SkPoint* points() { return fPathRef->fPoints; } | 62 SkPoint* points() { return fPathRef->fPoints; } |
| 53 | 63 |
| 54 /** | 64 /** |
| 55 * Gets the ith point. Shortcut for this->points() + i | 65 * Gets the ith point. Shortcut for this->points() + i |
| 56 */ | 66 */ |
| 57 SkPoint* atPoint(int i) { | 67 SkPoint* atPoint(int i) { |
| 58 SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); | 68 SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); |
| 59 return this->points() + i; | 69 return this->points() + i; |
| 60 }; | 70 }; |
| 61 | 71 |
| 62 /** | 72 /** |
| 63 * Adds the verb and allocates space for the number of points indicated
by the verb. The | 73 * Adds the verb and allocates space for the number of points indicated
by the verb. The |
| 64 * return value is a pointer to where the points for the verb should be
written. | 74 * return value is a pointer to where the points for the verb should be
written. |
| 65 */ | 75 */ |
| 66 SkPoint* growForVerb(int /*SkPath::Verb*/ verb) { | 76 SkPoint* growForVerb(Verb verb) { |
| 67 SkDEBUGCODE(fPathRef->validate();) | 77 SkDEBUGCODE(fPathRef->validate();) |
| 68 return fPathRef->growForVerb(verb); | 78 return fPathRef->growForVerb(verb); |
| 69 } | 79 } |
| 70 | 80 |
| 71 SkPoint* growForConic(SkScalar w); | 81 SkPoint* growForConic(SkScalar w) { |
| 72 | 82 SkDEBUGCODE(fPathRef->validate();) |
| 83 SkPoint* pts = fPathRef->growForVerb(kConic_Verb); |
| 84 *fPathRef->fConicWeights.append() = w; |
| 85 return pts; |
| 86 } |
| 73 /** | 87 /** |
| 74 * Allocates space for additional verbs and points and returns pointers
to the new verbs and | 88 * Allocates space for additional lines and returns a pointer to the new |
| 75 * points. verbs will point one beyond the first new verb (index it usin
g [~<i>]). pts points | 89 * points. The return pointer points at the first new point (indexed nor
mally [<i>]). |
| 76 * at the first new point (indexed normally [<i>]). | |
| 77 */ | 90 */ |
| 78 void grow(int newVerbs, int newPts, uint8_t** verbs, SkPoint** pts) { | 91 SkPoint* growForLines(int numLines) { |
| 79 SkASSERT(NULL != verbs); | |
| 80 SkASSERT(NULL != pts); | |
| 81 SkDEBUGCODE(fPathRef->validate();) | 92 SkDEBUGCODE(fPathRef->validate();) |
| 82 int oldVerbCnt = fPathRef->fVerbCnt; | 93 return fPathRef->growForLines(numLines); |
| 83 int oldPointCnt = fPathRef->fPointCnt; | |
| 84 SkASSERT(verbs && pts); | |
| 85 fPathRef->grow(newVerbs, newPts); | |
| 86 *verbs = fPathRef->fVerbs - oldVerbCnt; | |
| 87 *pts = fPathRef->fPoints + oldPointCnt; | |
| 88 SkDEBUGCODE(fPathRef->validate();) | |
| 89 } | 94 } |
| 90 | 95 |
| 91 /** | 96 /** |
| 92 * Resets the path ref to a new verb and point count. The new verbs and
points are | 97 * Resets the path ref to a new verb and point count. The new verbs and
points are |
| 93 * uninitialized. | 98 * uninitialized. |
| 94 */ | 99 */ |
| 95 void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { | 100 void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { |
| 96 fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); | 101 fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); |
| 97 } | 102 } |
| 103 |
| 98 /** | 104 /** |
| 99 * Gets the path ref that is wrapped in the Editor. | 105 * Gets the path ref that is wrapped in the Editor. |
| 100 */ | 106 */ |
| 101 SkPathRef* pathRef() { return fPathRef; } | 107 SkPathRef* pathRef() { return fPathRef; } |
| 102 | 108 |
| 103 private: | 109 private: |
| 104 SkPathRef* fPathRef; | 110 SkPathRef* fPathRef; |
| 105 }; | 111 }; |
| 106 | 112 |
| 107 public: | 113 public: |
| 108 /** | 114 /** |
| 109 * Gets a path ref with no verbs or points. | 115 * Gets a path ref with no verbs or points. |
| 110 */ | 116 */ |
| 111 static SkPathRef* CreateEmpty() { | 117 static SkPathRef* CreateEmpty() { |
| 112 static SkPathRef* gEmptyPathRef; | 118 static SkPathRef* gEmptyPathRef; |
| 113 if (!gEmptyPathRef) { | 119 if (!gEmptyPathRef) { |
| 114 gEmptyPathRef = SkNEW(SkPathRef); // leak! | 120 gEmptyPathRef = SkNEW(SkPathRef); // leak! |
| 115 gEmptyPathRef->computeBounds(); // Premptively avoid a race to cle
ar fBoundsIsDirty. | 121 gEmptyPathRef->computeBounds(); // Premptively avoid a race to cle
ar fBoundsIsDirty. |
| 116 } | 122 } |
| 117 return SkRef(gEmptyPathRef); | 123 return SkRef(gEmptyPathRef); |
| 118 } | 124 } |
| 119 | 125 |
| 126 enum Direction { |
| 127 /** Direction either has not been or could not be computed */ |
| 128 kUnknown_Direction, |
| 129 /** clockwise direction for adding closed contours */ |
| 130 kCW_Direction, |
| 131 /** counter-clockwise direction for adding closed contours */ |
| 132 kCCW_Direction, |
| 133 }; |
| 134 |
| 135 /** |
| 136 * Return the opposite of the specified direction. kUnknown is its own |
| 137 * opposite. |
| 138 */ |
| 139 static Direction OppositeDirection(Direction dir) { |
| 140 static const Direction gOppositeDir[] = { |
| 141 kUnknown_Direction, |
| 142 kCCW_Direction, |
| 143 kCW_Direction |
| 144 }; |
| 145 return gOppositeDir[dir]; |
| 146 } |
| 147 |
| 148 Direction getDirection() const { return (Direction) fDirection; } |
| 149 |
| 150 enum Convexity { |
| 151 kUnknown_Convexity, |
| 152 kConvex_Convexity, |
| 153 kConcave_Convexity |
| 154 }; |
| 155 |
| 156 /** |
| 157 * Return the path's convexity, as stored in the path. If it is currently u
nknown, |
| 158 * then this function will attempt to compute the convexity (and cache the
result). |
| 159 */ |
| 160 Convexity getConvexity() const { |
| 161 if (kUnknown_Convexity != fConvexity) { |
| 162 return static_cast<Convexity>(fConvexity); |
| 163 } else { |
| 164 return this->internalGetConvexity(); |
| 165 } |
| 166 } |
| 167 |
| 168 /** |
| 169 * Return the currently cached value for convexity, even if that is set to |
| 170 * kUnknown_Convexity. Note: getConvexity() will automatically call |
| 171 * ComputeConvexity and cache its return value if the current setting is |
| 172 * kUnknown. |
| 173 */ |
| 174 Convexity getConvexityOrUnknown() const { |
| 175 return (Convexity) fConvexity; |
| 176 } |
| 177 |
| 178 /** |
| 179 * Store a convexity setting in the path. There is no automatic check to |
| 180 * see if this value actually agrees with the return value that would be |
| 181 * computed by getConvexity(). |
| 182 * |
| 183 * Note: even if this is set to a "known" value, if the path is later |
| 184 * changed (e.g. lineTo(), addRect(), etc.) then the cached value will be |
| 185 * reset to kUnknown_Convexity. |
| 186 */ |
| 187 void setConvexity(Convexity convexity) { |
| 188 fConvexity = convexity; |
| 189 } |
| 190 |
| 191 /** Returns true if the path is an oval. |
| 192 * |
| 193 * @param rect returns the bounding rect of this oval. It's a circle |
| 194 * if the height and width are the same. |
| 195 * |
| 196 * @return true if this path is an oval. |
| 197 * Tracking whether a path is an oval is considered an |
| 198 * optimization for performance and so some paths that are in |
| 199 * fact ovals can report false. |
| 200 */ |
| 201 bool isOval(SkRect* rect) const { |
| 202 if (fIsOval && NULL != rect) { |
| 203 *rect = this->getBounds(); |
| 204 } |
| 205 return SkToBool(fIsOval); |
| 206 } |
| 207 |
| 120 /** | 208 /** |
| 121 * Returns true if all of the points in this path are finite, meaning there | 209 * Returns true if all of the points in this path are finite, meaning there |
| 122 * are no infinities and no NaNs. | 210 * are no infinities and no NaNs. |
| 123 */ | 211 */ |
| 124 bool isFinite() const { | 212 bool isFinite() const { |
| 125 if (fBoundsIsDirty) { | 213 if (fBoundsIsDirty) { |
| 126 this->computeBounds(); | 214 this->computeBounds(); |
| 127 } | 215 } |
| 128 return SkToBool(fIsFinite); | 216 return SkToBool(fIsFinite); |
| 129 } | 217 } |
| 130 | 218 |
| 219 enum SegmentMask { |
| 220 kLine_SegmentMask = 1 << 0, |
| 221 kQuad_SegmentMask = 1 << 1, |
| 222 kConic_SegmentMask = 1 << 2, |
| 223 kCubic_SegmentMask = 1 << 3, |
| 224 }; |
| 225 |
| 226 /** |
| 227 * Returns a mask, where each bit corresponding to a SegmentMask is |
| 228 * set if the path contains 1 or more segments of that type. |
| 229 * Returns 0 for an empty path (no segments). |
| 230 */ |
| 231 uint32_t getSegmentMasks() const { return fSegmentMask; } |
| 232 |
| 131 bool hasComputedBounds() const { | 233 bool hasComputedBounds() const { |
| 132 return !fBoundsIsDirty; | 234 return !fBoundsIsDirty; |
| 133 } | 235 } |
| 134 | 236 |
| 135 /** Returns the bounds of the path's points. If the path contains 0 or 1 | 237 /** Returns the bounds of the path's points. If the path contains 0 or 1 |
| 136 points, the bounds is set to (0,0,0,0), and isEmpty() will return true. | 238 points, the bounds is set to (0,0,0,0), and isEmpty() will return true. |
| 137 Note: this bounds may be larger than the actual shape, since curves | 239 Note: this bounds may be larger than the actual shape, since curves |
| 138 do not extend as far as their control points. | 240 do not extend as far as their control points. |
| 139 */ | 241 */ |
| 140 const SkRect& getBounds() const { | 242 const SkRect& getBounds() const { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 */ | 331 */ |
| 230 void writeToBuffer(SkWBuffer* buffer); | 332 void writeToBuffer(SkWBuffer* buffer); |
| 231 | 333 |
| 232 /** | 334 /** |
| 233 * Gets the number of bytes that would be written in writeBuffer() | 335 * Gets the number of bytes that would be written in writeBuffer() |
| 234 */ | 336 */ |
| 235 uint32_t writeSize(); | 337 uint32_t writeSize(); |
| 236 | 338 |
| 237 private: | 339 private: |
| 238 enum SerializationOffsets { | 340 enum SerializationOffsets { |
| 341 kDirection_SerializationShift = 26, // requires 2 bits |
| 239 kIsFinite_SerializationShift = 25, // requires 1 bit | 342 kIsFinite_SerializationShift = 25, // requires 1 bit |
| 343 kIsOval_SerializationShift = 24, // requires 1 bit |
| 344 kConvexity_SerializationShift = 16, // requires 8 bits |
| 345 // FillType (in SkPath) takes up 8 |
| 346 kSegmentMask_SerializationShift = 0 // requires 4 bits |
| 240 }; | 347 }; |
| 241 | 348 |
| 349 // flag to require a moveTo if we begin with something else, like lineTo etc
. |
| 350 static const int kINITIAL_LASTMOVETOINDEX_VALUE = ~0; |
| 351 |
| 242 SkPathRef() { | 352 SkPathRef() { |
| 243 fBoundsIsDirty = true; // this also invalidates fIsFinite | 353 fBoundsIsDirty = true; // this also invalidates fIsFinite |
| 244 fPointCnt = 0; | 354 fPointCnt = 0; |
| 245 fVerbCnt = 0; | 355 fVerbCnt = 0; |
| 246 fVerbs = NULL; | 356 fVerbs = NULL; |
| 247 fPoints = NULL; | 357 fPoints = NULL; |
| 248 fFreeSpace = 0; | 358 fFreeSpace = 0; |
| 249 fGenerationID = kEmptyGenID; | 359 fGenerationID = kEmptyGenID; |
| 250 SkDEBUGCODE(fEditorsAttached = 0;) | 360 SkDEBUGCODE(fEditorsAttached = 0;) |
| 361 fLastMoveToIndex = kINITIAL_LASTMOVETOINDEX_VALUE; |
| 362 fSegmentMask = 0; |
| 363 fConvexity = kUnknown_Convexity; |
| 364 fDirection = kUnknown_Direction; |
| 365 fIsOval = false; |
| 251 SkDEBUGCODE(this->validate();) | 366 SkDEBUGCODE(this->validate();) |
| 252 } | 367 } |
| 253 | 368 |
| 254 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe
servePoints); | 369 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalRe
servePoints); |
| 255 | 370 |
| 256 // Return true if the computed bounds are finite. | 371 // Return true if the computed bounds are finite. |
| 257 static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { | 372 static bool ComputePtBounds(SkRect* bounds, const SkPoint* points, int count
) { |
| 258 int count = ref.countPoints(); | |
| 259 if (count <= 1) { // we ignore just 1 point (moveto) | 373 if (count <= 1) { // we ignore just 1 point (moveto) |
| 260 bounds->setEmpty(); | 374 bounds->setEmpty(); |
| 261 return count ? ref.points()->isFinite() : true; | 375 return count ? points->isFinite() : true; |
| 262 } else { | 376 } else { |
| 263 return bounds->setBoundsCheck(ref.points(), count); | 377 return bounds->setBoundsCheck(points, count); |
| 264 } | 378 } |
| 265 } | 379 } |
| 266 | 380 |
| 267 // called, if dirty, by getBounds() | 381 // called, if dirty, by getBounds() |
| 268 void computeBounds() const { | 382 void computeBounds() const { |
| 269 SkDEBUGCODE(this->validate();) | 383 SkDEBUGCODE(this->validate();) |
| 270 SkASSERT(fBoundsIsDirty); | 384 SkASSERT(fBoundsIsDirty); |
| 271 | 385 |
| 272 fIsFinite = ComputePtBounds(&fBounds, *this); | 386 fIsFinite = ComputePtBounds(&fBounds, this->points(), this->countPoints(
)); |
| 273 fBoundsIsDirty = false; | 387 fBoundsIsDirty = false; |
| 274 } | 388 } |
| 275 | 389 |
| 276 /** Makes additional room but does not change the counts or change the genID
*/ | 390 /** Makes additional room but does not change the counts or change the genID
*/ |
| 277 void incReserve(int additionalVerbs, int additionalPoints) { | 391 void incReserve(int additionalVerbs, int additionalPoints) { |
| 278 SkDEBUGCODE(this->validate();) | 392 SkDEBUGCODE(this->validate();) |
| 279 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si
zeof (SkPoint); | 393 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * si
zeof (SkPoint); |
| 280 this->makeSpace(space); | 394 this->makeSpace(space); |
| 281 SkDEBUGCODE(this->validate();) | 395 SkDEBUGCODE(this->validate();) |
| 282 } | 396 } |
| 283 | 397 |
| 284 /** Resets the path ref with verbCount verbs and pointCount points, all unin
itialized. Also | 398 /** Resets the path ref with verbCount verbs and pointCount points, all unin
itialized. Also |
| 285 * allocates space for reserveVerb additional verbs and reservePoints addit
ional points.*/ | 399 * allocates space for reserveVerb additional verbs and reservePoints addit
ional points.*/ |
| 286 void resetToSize(int verbCount, int pointCount, int conicCount, | 400 void resetToSize(int verbCount, int pointCount, int conicCount, |
| 287 int reserveVerbs = 0, int reservePoints = 0) { | 401 int reserveVerbs = 0, int reservePoints = 0) { |
| 288 SkDEBUGCODE(this->validate();) | 402 SkDEBUGCODE(this->validate();) |
| 289 fBoundsIsDirty = true; // this also invalidates fIsFinite | 403 fBoundsIsDirty = true; // this also invalidates fIsFinite |
| 290 fGenerationID = 0; | 404 fGenerationID = 0; |
| 291 | 405 |
| 406 fLastMoveToIndex = kINITIAL_LASTMOVETOINDEX_VALUE; |
| 407 fSegmentMask = 0; |
| 408 fConvexity = kUnknown_Convexity; |
| 409 fDirection = kUnknown_Direction; |
| 410 fIsOval = false; |
| 411 |
| 292 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCo
unt; | 412 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCo
unt; |
| 293 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * r
eservePoints; | 413 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * r
eservePoints; |
| 294 size_t minSize = newSize + newReserve; | 414 size_t minSize = newSize + newReserve; |
| 295 | 415 |
| 296 ptrdiff_t sizeDelta = this->currSize() - minSize; | 416 ptrdiff_t sizeDelta = this->currSize() - minSize; |
| 297 | 417 |
| 298 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) { | 418 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) { |
| 299 sk_free(fPoints); | 419 sk_free(fPoints); |
| 300 fPoints = NULL; | 420 fPoints = NULL; |
| 301 fVerbs = NULL; | 421 fVerbs = NULL; |
| 302 fFreeSpace = 0; | 422 fFreeSpace = 0; |
| 303 fVerbCnt = 0; | 423 fVerbCnt = 0; |
| 304 fPointCnt = 0; | 424 fPointCnt = 0; |
| 305 this->makeSpace(minSize); | 425 this->makeSpace(minSize); |
| 306 fVerbCnt = verbCount; | 426 fVerbCnt = verbCount; |
| 307 fPointCnt = pointCount; | 427 fPointCnt = pointCount; |
| 308 fFreeSpace -= newSize; | 428 fFreeSpace -= newSize; |
| 309 } else { | 429 } else { |
| 310 fPointCnt = pointCount; | 430 fPointCnt = pointCount; |
| 311 fVerbCnt = verbCount; | 431 fVerbCnt = verbCount; |
| 312 fFreeSpace = this->currSize() - minSize; | 432 fFreeSpace = this->currSize() - minSize; |
| 313 } | 433 } |
| 314 fConicWeights.setCount(conicCount); | 434 fConicWeights.setCount(conicCount); |
| 315 SkDEBUGCODE(this->validate();) | 435 SkDEBUGCODE(this->validate();) |
| 316 } | 436 } |
| 317 | 437 |
| 438 // This method assumes space has already been allocated for the new |
| 439 // verb and point. |
| 440 void injectMove() { |
| 441 SkScalar x, y; |
| 442 if (this->countVerbs() == 0) { |
| 443 x = y = 0; |
| 444 } else { |
| 445 const SkPoint& pt = this->atPoint(~fLastMoveToIndex); |
| 446 x = pt.fX; |
| 447 y = pt.fY; |
| 448 } |
| 449 fPoints[fPointCnt].set(x, y); |
| 450 fLastMoveToIndex = fPointCnt; |
| 451 ++fPointCnt; |
| 452 fVerbs[~fVerbCnt] = kMove_Verb; |
| 453 ++fVerbCnt; |
| 454 } |
| 455 |
| 456 |
| 318 /** | 457 /** |
| 319 * Increases the verb count by newVerbs and the point count be newPoints. Ne
w verbs and points | 458 * Increases the verb and point count by numLines. The new points |
| 320 * are uninitialized. | 459 * are uninitialized. All the new verbs are set to kLine_SegmentMask. |
| 321 */ | 460 */ |
| 322 void grow(int newVerbs, int newPoints) { | 461 SkPoint* growForLines(int numLines) { |
| 462 // This value is just made-up for now. When numLines is 3, calling memse
t was much |
| 463 // slower than just writing the loop. This seems odd, and hopefully in t
he |
| 464 // future this will appear to have been a fluke... |
| 465 static const unsigned int kMIN_COUNT_FOR_MEMSET_TO_BE_FAST = 16; |
| 466 |
| 467 // TODO: The following isn't hyper-optimized for the lines case since |
| 468 // it should be expanded to handle quads, conics and cubics |
| 323 SkDEBUGCODE(this->validate();) | 469 SkDEBUGCODE(this->validate();) |
| 324 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint)
; | 470 bool dirtyAfterEdit = true; |
| 471 bool moveInjectionNeeded = false; |
| 472 |
| 473 moveInjectionNeeded = fLastMoveToIndex < 0; |
| 474 |
| 475 size_t space = numLines * sizeof(uint8_t) + numLines * sizeof (SkPoint); |
| 476 if (moveInjectionNeeded) { |
| 477 space += sizeof(uint8_t) + sizeof(SkPoint); |
| 478 } |
| 325 this->makeSpace(space); | 479 this->makeSpace(space); |
| 326 fVerbCnt += newVerbs; | 480 if (moveInjectionNeeded) { |
| 327 fPointCnt += newPoints; | 481 SkASSERT(dirtyAfterEdit); |
| 482 this->injectMove(); |
| 483 } |
| 484 SkPoint* ret = fPoints + fPointCnt; |
| 485 uint8_t* vb = fVerbs - fVerbCnt; |
| 486 |
| 487 // cast to unsigned, so if MIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to |
| 488 // be 0, the compiler will remove the test/branch entirely. |
| 489 if ((unsigned)numLines >= kMIN_COUNT_FOR_MEMSET_TO_BE_FAST) { |
| 490 memset(vb - numLines, kLine_Verb, numLines); |
| 491 } else { |
| 492 for (int i = 0; i < numLines; ++i) { |
| 493 vb[~i] = kLine_Verb; |
| 494 } |
| 495 } |
| 496 fSegmentMask |= kLine_SegmentMask; |
| 497 |
| 498 fVerbCnt += numLines; |
| 499 fPointCnt += numLines; |
| 328 fFreeSpace -= space; | 500 fFreeSpace -= space; |
| 329 fBoundsIsDirty = true; // this also invalidates fIsFinite | 501 fBoundsIsDirty = true; // this also invalidates fIsFinite |
| 502 |
| 503 if (dirtyAfterEdit) { |
| 504 fConvexity = kUnknown_Convexity; |
| 505 fDirection = kUnknown_Direction; |
| 506 fIsOval = false; |
| 507 } |
| 508 |
| 330 SkDEBUGCODE(this->validate();) | 509 SkDEBUGCODE(this->validate();) |
| 510 return ret; |
| 331 } | 511 } |
| 332 | 512 |
| 333 /** | 513 /** |
| 334 * Increases the verb count 1, records the new verb, and creates room for th
e requisite number | 514 * Increases the verb count 1, records the new verb, and creates room for th
e requisite number |
| 335 * of additional points. A pointer to the first point is returned. Any new p
oints are | 515 * of additional points. A pointer to the first point is returned. Any new p
oints are |
| 336 * uninitialized. | 516 * uninitialized. |
| 337 */ | 517 */ |
| 338 SkPoint* growForVerb(int /*SkPath::Verb*/ verb); | 518 SkPoint* growForVerb(Verb verb); |
| 339 | 519 |
| 340 /** | 520 /** |
| 341 * Ensures that the free space available in the path ref is >= size. The ver
b and point counts | 521 * Ensures that the free space available in the path ref is >= size. The ver
b and point counts |
| 342 * are not changed. | 522 * are not changed. |
| 343 */ | 523 */ |
| 344 void makeSpace(size_t size) { | 524 void makeSpace(size_t size) { |
| 345 SkDEBUGCODE(this->validate();) | 525 SkDEBUGCODE(this->validate();) |
| 346 ptrdiff_t growSize = size - fFreeSpace; | 526 ptrdiff_t growSize = size - fFreeSpace; |
| 347 if (growSize <= 0) { | 527 if (growSize <= 0) { |
| 348 return; | 528 return; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 /** | 570 /** |
| 391 * Gets an ID that uniquely identifies the contents of the path ref. If two
path refs have the | 571 * Gets an ID that uniquely identifies the contents of the path ref. If two
path refs have the |
| 392 * same ID then they have the same verbs and points. However, two path refs
may have the same | 572 * same ID then they have the same verbs and points. However, two path refs
may have the same |
| 393 * contents but different genIDs. Zero is reserved and means an ID has not y
et been determined | 573 * contents but different genIDs. Zero is reserved and means an ID has not y
et been determined |
| 394 * for the path ref. | 574 * for the path ref. |
| 395 */ | 575 */ |
| 396 int32_t genID() const; | 576 int32_t genID() const; |
| 397 | 577 |
| 398 SkDEBUGCODE(void validate() const;) | 578 SkDEBUGCODE(void validate() const;) |
| 399 | 579 |
| 580 Convexity internalGetConvexity() const; |
| 581 |
| 582 void setIsOval(bool isOval) { fIsOval = isOval; } |
| 583 void setDirection(Direction direction) { fDirection = direction; } |
| 584 |
| 585 /** |
| 586 * Tries to quickly compute the direction of the first non-degenerate |
| 587 * contour. If it can be computed, return true and set dir to that |
| 588 * direction. If it cannot be (quickly) determined, return false and ignore |
| 589 * the dir parameter. If the direction was determined, it is cached to make |
| 590 * subsequent calls return quickly. |
| 591 */ |
| 592 bool cheapComputeDirection(Direction* dir) const; |
| 593 |
| 400 enum { | 594 enum { |
| 401 kMinSize = 256, | 595 kMinSize = 256, |
| 402 }; | 596 }; |
| 403 | 597 |
| 404 mutable SkRect fBounds; | 598 mutable SkRect fBounds; |
| 599 int fLastMoveToIndex; |
| 600 |
| 601 uint8_t fSegmentMask; |
| 405 mutable uint8_t fBoundsIsDirty; | 602 mutable uint8_t fBoundsIsDirty; |
| 603 mutable uint8_t fConvexity; |
| 604 mutable uint8_t fDirection; |
| 406 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid | 605 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid |
| 606 mutable SkBool8 fIsOval; |
| 407 | 607 |
| 408 SkPoint* fPoints; // points to begining of the allocation | 608 SkPoint* fPoints; // points to begining of the allocation |
| 409 uint8_t* fVerbs; // points just past the end of the allocation (v
erbs grow backwards) | 609 uint8_t* fVerbs; // points just past the end of the allocation (v
erbs grow backwards) |
| 410 int fVerbCnt; | 610 int fVerbCnt; |
| 411 int fPointCnt; | 611 int fPointCnt; |
| 412 size_t fFreeSpace; // redundant but saves computation | 612 size_t fFreeSpace; // redundant but saves computation |
| 413 SkTDArray<SkScalar> fConicWeights; | 613 SkTDArray<SkScalar> fConicWeights; |
| 414 | 614 |
| 415 enum { | 615 enum { |
| 416 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer
o verbs. | 616 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zer
o verbs. |
| 417 }; | 617 }; |
| 418 mutable int32_t fGenerationID; | 618 mutable int32_t fGenerationID; |
| 419 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use
at any time. | 619 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use
at any time. |
| 420 | 620 |
| 621 friend class SkPath; |
| 622 |
| 421 typedef SkRefCnt INHERITED; | 623 typedef SkRefCnt INHERITED; |
| 422 }; | 624 }; |
| 423 | 625 |
| 424 #endif | 626 #endif |
| OLD | NEW |