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 |