|
1 |
|
2 /* |
|
3 * Copyright 2006 The Android Open Source Project |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 |
|
10 #ifndef SkPath_DEFINED |
|
11 #define SkPath_DEFINED |
|
12 |
|
13 #include "SkInstCnt.h" |
|
14 #include "SkMatrix.h" |
|
15 #include "SkPathRef.h" |
|
16 #include "SkTDArray.h" |
|
17 #include "SkRefCnt.h" |
|
18 |
|
19 class SkReader32; |
|
20 class SkWriter32; |
|
21 class SkAutoPathBoundsUpdate; |
|
22 class SkString; |
|
23 class SkRRect; |
|
24 |
|
25 /** \class SkPath |
|
26 |
|
27 The SkPath class encapsulates compound (multiple contour) geometric paths |
|
28 consisting of straight line segments, quadratic curves, and cubic curves. |
|
29 */ |
|
30 class SK_API SkPath { |
|
31 public: |
|
32 SK_DECLARE_INST_COUNT_ROOT(SkPath); |
|
33 |
|
34 SkPath(); |
|
35 SkPath(const SkPath&); |
|
36 ~SkPath(); |
|
37 |
|
38 SkPath& operator=(const SkPath&); |
|
39 friend SK_API bool operator==(const SkPath&, const SkPath&); |
|
40 friend bool operator!=(const SkPath& a, const SkPath& b) { |
|
41 return !(a == b); |
|
42 } |
|
43 |
|
44 enum FillType { |
|
45 /** Specifies that "inside" is computed by a non-zero sum of signed |
|
46 edge crossings |
|
47 */ |
|
48 kWinding_FillType, |
|
49 /** Specifies that "inside" is computed by an odd number of edge |
|
50 crossings |
|
51 */ |
|
52 kEvenOdd_FillType, |
|
53 /** Same as Winding, but draws outside of the path, rather than inside |
|
54 */ |
|
55 kInverseWinding_FillType, |
|
56 /** Same as EvenOdd, but draws outside of the path, rather than inside |
|
57 */ |
|
58 kInverseEvenOdd_FillType |
|
59 }; |
|
60 |
|
61 /** Return the path's fill type. This is used to define how "inside" is |
|
62 computed. The default value is kWinding_FillType. |
|
63 |
|
64 @return the path's fill type |
|
65 */ |
|
66 FillType getFillType() const { return (FillType)fFillType; } |
|
67 |
|
68 /** Set the path's fill type. This is used to define how "inside" is |
|
69 computed. The default value is kWinding_FillType. |
|
70 |
|
71 @param ft The new fill type for this path |
|
72 */ |
|
73 void setFillType(FillType ft) { |
|
74 fFillType = SkToU8(ft); |
|
75 } |
|
76 |
|
77 /** Returns true if the filltype is one of the Inverse variants */ |
|
78 bool isInverseFillType() const { return IsInverseFillType((FillType)fFillType); } |
|
79 |
|
80 /** |
|
81 * Toggle between inverse and normal filltypes. This reverse the return |
|
82 * value of isInverseFillType() |
|
83 */ |
|
84 void toggleInverseFillType() { |
|
85 fFillType ^= 2; |
|
86 } |
|
87 |
|
88 enum Convexity { |
|
89 kUnknown_Convexity, |
|
90 kConvex_Convexity, |
|
91 kConcave_Convexity |
|
92 }; |
|
93 |
|
94 /** |
|
95 * Return the path's convexity, as stored in the path. If it is currently unknown, |
|
96 * then this function will attempt to compute the convexity (and cache the result). |
|
97 */ |
|
98 Convexity getConvexity() const { |
|
99 if (kUnknown_Convexity != fConvexity) { |
|
100 return static_cast<Convexity>(fConvexity); |
|
101 } else { |
|
102 return this->internalGetConvexity(); |
|
103 } |
|
104 } |
|
105 |
|
106 /** |
|
107 * Return the currently cached value for convexity, even if that is set to |
|
108 * kUnknown_Convexity. Note: getConvexity() will automatically call |
|
109 * ComputeConvexity and cache its return value if the current setting is |
|
110 * kUnknown. |
|
111 */ |
|
112 Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; } |
|
113 |
|
114 /** |
|
115 * Store a convexity setting in the path. There is no automatic check to |
|
116 * see if this value actually agrees with the return value that would be |
|
117 * computed by getConvexity(). |
|
118 * |
|
119 * Note: even if this is set to a "known" value, if the path is later |
|
120 * changed (e.g. lineTo(), addRect(), etc.) then the cached value will be |
|
121 * reset to kUnknown_Convexity. |
|
122 */ |
|
123 void setConvexity(Convexity); |
|
124 |
|
125 /** |
|
126 * Returns true if the path is flagged as being convex. This is not a |
|
127 * confirmed by any analysis, it is just the value set earlier. |
|
128 */ |
|
129 bool isConvex() const { |
|
130 return kConvex_Convexity == this->getConvexity(); |
|
131 } |
|
132 |
|
133 /** |
|
134 * Set the isConvex flag to true or false. Convex paths may draw faster if |
|
135 * this flag is set, though setting this to true on a path that is in fact |
|
136 * not convex can give undefined results when drawn. Paths default to |
|
137 * isConvex == false |
|
138 */ |
|
139 SK_ATTR_DEPRECATED("use setConvexity") |
|
140 void setIsConvex(bool isConvex) { |
|
141 this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity); |
|
142 } |
|
143 |
|
144 /** Returns true if the path is an oval. |
|
145 * |
|
146 * @param rect returns the bounding rect of this oval. It's a circle |
|
147 * if the height and width are the same. |
|
148 * |
|
149 * @return true if this path is an oval. |
|
150 * Tracking whether a path is an oval is considered an |
|
151 * optimization for performance and so some paths that are in |
|
152 * fact ovals can report false. |
|
153 */ |
|
154 bool isOval(SkRect* rect) const { return fPathRef->isOval(rect); } |
|
155 |
|
156 /** Clear any lines and curves from the path, making it empty. This frees up |
|
157 internal storage associated with those segments. |
|
158 On Android, does not change fSourcePath. |
|
159 */ |
|
160 void reset(); |
|
161 |
|
162 /** Similar to reset(), in that all lines and curves are removed from the |
|
163 path. However, any internal storage for those lines/curves is retained, |
|
164 making reuse of the path potentially faster. |
|
165 On Android, does not change fSourcePath. |
|
166 */ |
|
167 void rewind(); |
|
168 |
|
169 /** Returns true if the path is empty (contains no lines or curves) |
|
170 |
|
171 @return true if the path is empty (contains no lines or curves) |
|
172 */ |
|
173 bool isEmpty() const { |
|
174 SkDEBUGCODE(this->validate();) |
|
175 return 0 == fPathRef->countVerbs(); |
|
176 } |
|
177 |
|
178 /** |
|
179 * Returns true if all of the points in this path are finite, meaning there |
|
180 * are no infinities and no NaNs. |
|
181 */ |
|
182 bool isFinite() const { |
|
183 SkDEBUGCODE(this->validate();) |
|
184 return fPathRef->isFinite(); |
|
185 } |
|
186 |
|
187 /** Test a line for zero length |
|
188 |
|
189 @return true if the line is of zero length; otherwise false. |
|
190 */ |
|
191 static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) { |
|
192 return p1.equalsWithinTolerance(p2); |
|
193 } |
|
194 |
|
195 /** Test a quad for zero length |
|
196 |
|
197 @return true if the quad is of zero length; otherwise false. |
|
198 */ |
|
199 static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2, |
|
200 const SkPoint& p3) { |
|
201 return p1.equalsWithinTolerance(p2) && |
|
202 p2.equalsWithinTolerance(p3); |
|
203 } |
|
204 |
|
205 /** Test a cubic curve for zero length |
|
206 |
|
207 @return true if the cubic is of zero length; otherwise false. |
|
208 */ |
|
209 static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, |
|
210 const SkPoint& p3, const SkPoint& p4) { |
|
211 return p1.equalsWithinTolerance(p2) && |
|
212 p2.equalsWithinTolerance(p3) && |
|
213 p3.equalsWithinTolerance(p4); |
|
214 } |
|
215 |
|
216 /** |
|
217 * Returns true if the path specifies a single line (i.e. it contains just |
|
218 * a moveTo and a lineTo). If so, and line[] is not null, it sets the 2 |
|
219 * points in line[] to the end-points of the line. If the path is not a |
|
220 * line, returns false and ignores line[]. |
|
221 */ |
|
222 bool isLine(SkPoint line[2]) const; |
|
223 |
|
224 /** Returns true if the path specifies a rectangle. If so, and if rect is |
|
225 not null, set rect to the bounds of the path. If the path does not |
|
226 specify a rectangle, return false and ignore rect. |
|
227 |
|
228 @param rect If not null, returns the bounds of the path if it specifies |
|
229 a rectangle |
|
230 @return true if the path specifies a rectangle |
|
231 */ |
|
232 bool isRect(SkRect* rect) const; |
|
233 |
|
234 /** Return the number of points in the path |
|
235 */ |
|
236 int countPoints() const; |
|
237 |
|
238 /** Return the point at the specified index. If the index is out of range |
|
239 (i.e. is not 0 <= index < countPoints()) then the returned coordinates |
|
240 will be (0,0) |
|
241 */ |
|
242 SkPoint getPoint(int index) const; |
|
243 |
|
244 /** Returns the number of points in the path. Up to max points are copied. |
|
245 |
|
246 @param points If not null, receives up to max points |
|
247 @param max The maximum number of points to copy into points |
|
248 @return the actual number of points in the path |
|
249 */ |
|
250 int getPoints(SkPoint points[], int max) const; |
|
251 |
|
252 /** Return the number of verbs in the path |
|
253 */ |
|
254 int countVerbs() const; |
|
255 |
|
256 /** Returns the number of verbs in the path. Up to max verbs are copied. The |
|
257 verbs are copied as one byte per verb. |
|
258 |
|
259 @param verbs If not null, receives up to max verbs |
|
260 @param max The maximum number of verbs to copy into verbs |
|
261 @return the actual number of verbs in the path |
|
262 */ |
|
263 int getVerbs(uint8_t verbs[], int max) const; |
|
264 |
|
265 //! Swap contents of this and other. Guaranteed not to throw |
|
266 void swap(SkPath& other); |
|
267 |
|
268 /** Returns the bounds of the path's points. If the path contains 0 or 1 |
|
269 points, the bounds is set to (0,0,0,0), and isEmpty() will return true. |
|
270 Note: this bounds may be larger than the actual shape, since curves |
|
271 do not extend as far as their control points. |
|
272 */ |
|
273 const SkRect& getBounds() const { |
|
274 return fPathRef->getBounds(); |
|
275 } |
|
276 |
|
277 /** Calling this will, if the internal cache of the bounds is out of date, |
|
278 update it so that subsequent calls to getBounds will be instantaneous. |
|
279 This also means that any copies or simple transformations of the path |
|
280 will inherit the cached bounds. |
|
281 */ |
|
282 void updateBoundsCache() const { |
|
283 // for now, just calling getBounds() is sufficient |
|
284 this->getBounds(); |
|
285 } |
|
286 |
|
287 /** |
|
288 * Does a conservative test to see whether a rectangle is inside a path. Currently it only |
|
289 * will ever return true for single convex contour paths. The empty-status of the rect is not |
|
290 * considered (e.g. a rect that is a point can be inside a path). Points or line segments where |
|
291 * the rect edge touches the path border are not considered containment violations. |
|
292 */ |
|
293 bool conservativelyContainsRect(const SkRect& rect) const; |
|
294 |
|
295 // Construction methods |
|
296 |
|
297 /** Hint to the path to prepare for adding more points. This can allow the |
|
298 path to more efficiently grow its storage. |
|
299 |
|
300 @param extraPtCount The number of extra points the path should |
|
301 preallocate for. |
|
302 */ |
|
303 void incReserve(unsigned extraPtCount); |
|
304 |
|
305 /** Set the beginning of the next contour to the point (x,y). |
|
306 |
|
307 @param x The x-coordinate of the start of a new contour |
|
308 @param y The y-coordinate of the start of a new contour |
|
309 */ |
|
310 void moveTo(SkScalar x, SkScalar y); |
|
311 |
|
312 /** Set the beginning of the next contour to the point |
|
313 |
|
314 @param p The start of a new contour |
|
315 */ |
|
316 void moveTo(const SkPoint& p) { |
|
317 this->moveTo(p.fX, p.fY); |
|
318 } |
|
319 |
|
320 /** Set the beginning of the next contour relative to the last point on the |
|
321 previous contour. If there is no previous contour, this is treated the |
|
322 same as moveTo(). |
|
323 |
|
324 @param dx The amount to add to the x-coordinate of the end of the |
|
325 previous contour, to specify the start of a new contour |
|
326 @param dy The amount to add to the y-coordinate of the end of the |
|
327 previous contour, to specify the start of a new contour |
|
328 */ |
|
329 void rMoveTo(SkScalar dx, SkScalar dy); |
|
330 |
|
331 /** Add a line from the last point to the specified point (x,y). If no |
|
332 moveTo() call has been made for this contour, the first point is |
|
333 automatically set to (0,0). |
|
334 |
|
335 @param x The x-coordinate of the end of a line |
|
336 @param y The y-coordinate of the end of a line |
|
337 */ |
|
338 void lineTo(SkScalar x, SkScalar y); |
|
339 |
|
340 /** Add a line from the last point to the specified point. If no moveTo() |
|
341 call has been made for this contour, the first point is automatically |
|
342 set to (0,0). |
|
343 |
|
344 @param p The end of a line |
|
345 */ |
|
346 void lineTo(const SkPoint& p) { |
|
347 this->lineTo(p.fX, p.fY); |
|
348 } |
|
349 |
|
350 /** Same as lineTo, but the coordinates are considered relative to the last |
|
351 point on this contour. If there is no previous point, then a moveTo(0,0) |
|
352 is inserted automatically. |
|
353 |
|
354 @param dx The amount to add to the x-coordinate of the previous point |
|
355 on this contour, to specify a line |
|
356 @param dy The amount to add to the y-coordinate of the previous point |
|
357 on this contour, to specify a line |
|
358 */ |
|
359 void rLineTo(SkScalar dx, SkScalar dy); |
|
360 |
|
361 /** Add a quadratic bezier from the last point, approaching control point |
|
362 (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for |
|
363 this contour, the first point is automatically set to (0,0). |
|
364 |
|
365 @param x1 The x-coordinate of the control point on a quadratic curve |
|
366 @param y1 The y-coordinate of the control point on a quadratic curve |
|
367 @param x2 The x-coordinate of the end point on a quadratic curve |
|
368 @param y2 The y-coordinate of the end point on a quadratic curve |
|
369 */ |
|
370 void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2); |
|
371 |
|
372 /** Add a quadratic bezier from the last point, approaching control point |
|
373 p1, and ending at p2. If no moveTo() call has been made for this |
|
374 contour, the first point is automatically set to (0,0). |
|
375 |
|
376 @param p1 The control point on a quadratic curve |
|
377 @param p2 The end point on a quadratic curve |
|
378 */ |
|
379 void quadTo(const SkPoint& p1, const SkPoint& p2) { |
|
380 this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY); |
|
381 } |
|
382 |
|
383 /** Same as quadTo, but the coordinates are considered relative to the last |
|
384 point on this contour. If there is no previous point, then a moveTo(0,0) |
|
385 is inserted automatically. |
|
386 |
|
387 @param dx1 The amount to add to the x-coordinate of the last point on |
|
388 this contour, to specify the control point of a quadratic curve |
|
389 @param dy1 The amount to add to the y-coordinate of the last point on |
|
390 this contour, to specify the control point of a quadratic curve |
|
391 @param dx2 The amount to add to the x-coordinate of the last point on |
|
392 this contour, to specify the end point of a quadratic curve |
|
393 @param dy2 The amount to add to the y-coordinate of the last point on |
|
394 this contour, to specify the end point of a quadratic curve |
|
395 */ |
|
396 void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2); |
|
397 |
|
398 void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
|
399 SkScalar w); |
|
400 void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) { |
|
401 this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w); |
|
402 } |
|
403 void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, |
|
404 SkScalar w); |
|
405 |
|
406 /** Add a cubic bezier from the last point, approaching control points |
|
407 (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been |
|
408 made for this contour, the first point is automatically set to (0,0). |
|
409 |
|
410 @param x1 The x-coordinate of the 1st control point on a cubic curve |
|
411 @param y1 The y-coordinate of the 1st control point on a cubic curve |
|
412 @param x2 The x-coordinate of the 2nd control point on a cubic curve |
|
413 @param y2 The y-coordinate of the 2nd control point on a cubic curve |
|
414 @param x3 The x-coordinate of the end point on a cubic curve |
|
415 @param y3 The y-coordinate of the end point on a cubic curve |
|
416 */ |
|
417 void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
|
418 SkScalar x3, SkScalar y3); |
|
419 |
|
420 /** Add a cubic bezier from the last point, approaching control points p1 |
|
421 and p2, and ending at p3. If no moveTo() call has been made for this |
|
422 contour, the first point is automatically set to (0,0). |
|
423 |
|
424 @param p1 The 1st control point on a cubic curve |
|
425 @param p2 The 2nd control point on a cubic curve |
|
426 @param p3 The end point on a cubic curve |
|
427 */ |
|
428 void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) { |
|
429 this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY); |
|
430 } |
|
431 |
|
432 /** Same as cubicTo, but the coordinates are considered relative to the |
|
433 current point on this contour. If there is no previous point, then a |
|
434 moveTo(0,0) is inserted automatically. |
|
435 |
|
436 @param dx1 The amount to add to the x-coordinate of the last point on |
|
437 this contour, to specify the 1st control point of a cubic curve |
|
438 @param dy1 The amount to add to the y-coordinate of the last point on |
|
439 this contour, to specify the 1st control point of a cubic curve |
|
440 @param dx2 The amount to add to the x-coordinate of the last point on |
|
441 this contour, to specify the 2nd control point of a cubic curve |
|
442 @param dy2 The amount to add to the y-coordinate of the last point on |
|
443 this contour, to specify the 2nd control point of a cubic curve |
|
444 @param dx3 The amount to add to the x-coordinate of the last point on |
|
445 this contour, to specify the end point of a cubic curve |
|
446 @param dy3 The amount to add to the y-coordinate of the last point on |
|
447 this contour, to specify the end point of a cubic curve |
|
448 */ |
|
449 void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
|
450 SkScalar x3, SkScalar y3); |
|
451 |
|
452 /** Append the specified arc to the path as a new contour. If the start of |
|
453 the path is different from the path's current last point, then an |
|
454 automatic lineTo() is added to connect the current contour to the start |
|
455 of the arc. However, if the path is empty, then we call moveTo() with |
|
456 the first point of the arc. The sweep angle is treated mod 360. |
|
457 |
|
458 @param oval The bounding oval defining the shape and size of the arc |
|
459 @param startAngle Starting angle (in degrees) where the arc begins |
|
460 @param sweepAngle Sweep angle (in degrees) measured clockwise. This is |
|
461 treated mod 360. |
|
462 @param forceMoveTo If true, always begin a new contour with the arc |
|
463 */ |
|
464 void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, |
|
465 bool forceMoveTo); |
|
466 |
|
467 /** Append a line and arc to the current path. This is the same as the |
|
468 PostScript call "arct". |
|
469 */ |
|
470 void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
|
471 SkScalar radius); |
|
472 |
|
473 /** Append a line and arc to the current path. This is the same as the |
|
474 PostScript call "arct". |
|
475 */ |
|
476 void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) { |
|
477 this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius); |
|
478 } |
|
479 |
|
480 /** Close the current contour. If the current point is not equal to the |
|
481 first point of the contour, a line segment is automatically added. |
|
482 */ |
|
483 void close(); |
|
484 |
|
485 enum Direction { |
|
486 /** Direction either has not been or could not be computed */ |
|
487 kUnknown_Direction, |
|
488 /** clockwise direction for adding closed contours */ |
|
489 kCW_Direction, |
|
490 /** counter-clockwise direction for adding closed contours */ |
|
491 kCCW_Direction, |
|
492 }; |
|
493 |
|
494 /** |
|
495 * Return the opposite of the specified direction. kUnknown is its own |
|
496 * opposite. |
|
497 */ |
|
498 static Direction OppositeDirection(Direction dir) { |
|
499 static const Direction gOppositeDir[] = { |
|
500 kUnknown_Direction, kCCW_Direction, kCW_Direction |
|
501 }; |
|
502 return gOppositeDir[dir]; |
|
503 } |
|
504 |
|
505 /** |
|
506 * Returns whether or not a fill type is inverted |
|
507 * |
|
508 * kWinding_FillType -> false |
|
509 * kEvenOdd_FillType -> false |
|
510 * kInverseWinding_FillType -> true |
|
511 * kInverseEvenOdd_FillType -> true |
|
512 */ |
|
513 static bool IsInverseFillType(FillType fill) { |
|
514 SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch); |
|
515 SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch); |
|
516 SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch); |
|
517 SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch); |
|
518 return (fill & 2) != 0; |
|
519 } |
|
520 |
|
521 /** |
|
522 * Returns the equivalent non-inverted fill type to the given fill type |
|
523 * |
|
524 * kWinding_FillType -> kWinding_FillType |
|
525 * kEvenOdd_FillType -> kEvenOdd_FillType |
|
526 * kInverseWinding_FillType -> kWinding_FillType |
|
527 * kInverseEvenOdd_FillType -> kEvenOdd_FillType |
|
528 */ |
|
529 static FillType ConvertToNonInverseFillType(FillType fill) { |
|
530 SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch); |
|
531 SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch); |
|
532 SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch); |
|
533 SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch); |
|
534 return (FillType)(fill & 1); |
|
535 } |
|
536 |
|
537 /** |
|
538 * Tries to quickly compute the direction of the first non-degenerate |
|
539 * contour. If it can be computed, return true and set dir to that |
|
540 * direction. If it cannot be (quickly) determined, return false and ignore |
|
541 * the dir parameter. If the direction was determined, it is cached to make |
|
542 * subsequent calls return quickly. |
|
543 */ |
|
544 bool cheapComputeDirection(Direction* dir) const; |
|
545 |
|
546 /** |
|
547 * Returns true if the path's direction can be computed via |
|
548 * cheapComputDirection() and if that computed direction matches the |
|
549 * specified direction. If dir is kUnknown, returns true if the direction |
|
550 * cannot be computed. |
|
551 */ |
|
552 bool cheapIsDirection(Direction dir) const { |
|
553 Direction computedDir = kUnknown_Direction; |
|
554 (void)this->cheapComputeDirection(&computedDir); |
|
555 return computedDir == dir; |
|
556 } |
|
557 |
|
558 enum PathAsRect { |
|
559 /** The path can not draw the same as its bounds. */ |
|
560 kNone_PathAsRect, |
|
561 /** The path draws the same as its bounds when filled. */ |
|
562 kFill_PathAsRect, |
|
563 /** The path draws the same as its bounds when stroked or filled. */ |
|
564 kStroke_PathAsRect, |
|
565 }; |
|
566 |
|
567 /** Returns kFill_PathAsRect or kStroke_PathAsRect if drawing the path (either filled or |
|
568 stroked) will be equivalent to filling/stroking the path's bounding rect. If |
|
569 either is true, and direction is not null, sets the direction of the contour. If the |
|
570 path is not drawn equivalent to a rect, returns kNone_PathAsRect and ignores direction. |
|
571 |
|
572 @param direction If not null, set to the contour's direction when it is drawn as a rect |
|
573 @return the path's PathAsRect type |
|
574 */ |
|
575 PathAsRect asRect(Direction* direction = NULL) const; |
|
576 |
|
577 /** Returns true if the path specifies a rectangle. If so, and if isClosed is |
|
578 not null, set isClosed to true if the path is closed. Also, if returning true |
|
579 and direction is not null, return the rect direction. If the path does not |
|
580 specify a rectangle, return false and ignore isClosed and direction. |
|
581 |
|
582 @param isClosed If not null, set to true if the path is closed |
|
583 @param direction If not null, set to the rectangle's direction |
|
584 @return true if the path specifies a rectangle |
|
585 */ |
|
586 bool isRect(bool* isClosed, Direction* direction) const; |
|
587 |
|
588 /** Returns true if the path specifies a pair of nested rectangles. If so, and if |
|
589 rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner |
|
590 rectangle. If so, and dirs is not null, set dirs[0] to the direction of |
|
591 the outer rectangle and dirs[1] to the direction of the inner rectangle. If |
|
592 the path does not specify a pair of nested rectangles, return |
|
593 false and ignore rect and dirs. |
|
594 |
|
595 @param rect If not null, returns the path as a pair of nested rectangles |
|
596 @param dirs If not null, returns the direction of the rects |
|
597 @return true if the path describes a pair of nested rectangles |
|
598 */ |
|
599 bool isNestedRects(SkRect rect[2], Direction dirs[2] = NULL) const; |
|
600 |
|
601 /** |
|
602 * Add a closed rectangle contour to the path |
|
603 * @param rect The rectangle to add as a closed contour to the path |
|
604 * @param dir The direction to wind the rectangle's contour. Cannot be |
|
605 * kUnknown_Direction. |
|
606 */ |
|
607 void addRect(const SkRect& rect, Direction dir = kCW_Direction); |
|
608 |
|
609 /** |
|
610 * Add a closed rectangle contour to the path |
|
611 * |
|
612 * @param left The left side of a rectangle to add as a closed contour |
|
613 * to the path |
|
614 * @param top The top of a rectangle to add as a closed contour to the |
|
615 * path |
|
616 * @param right The right side of a rectangle to add as a closed contour |
|
617 * to the path |
|
618 * @param bottom The bottom of a rectangle to add as a closed contour to |
|
619 * the path |
|
620 * @param dir The direction to wind the rectangle's contour. Cannot be |
|
621 * kUnknown_Direction. |
|
622 */ |
|
623 void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, |
|
624 Direction dir = kCW_Direction); |
|
625 |
|
626 /** |
|
627 * Add a closed oval contour to the path |
|
628 * |
|
629 * @param oval The bounding oval to add as a closed contour to the path |
|
630 * @param dir The direction to wind the oval's contour. Cannot be |
|
631 * kUnknown_Direction. |
|
632 */ |
|
633 void addOval(const SkRect& oval, Direction dir = kCW_Direction); |
|
634 |
|
635 /** |
|
636 * Add a closed circle contour to the path |
|
637 * |
|
638 * @param x The x-coordinate of the center of a circle to add as a |
|
639 * closed contour to the path |
|
640 * @param y The y-coordinate of the center of a circle to add as a |
|
641 * closed contour to the path |
|
642 * @param radius The radius of a circle to add as a closed contour to the |
|
643 * path |
|
644 * @param dir The direction to wind the circle's contour. Cannot be |
|
645 * kUnknown_Direction. |
|
646 */ |
|
647 void addCircle(SkScalar x, SkScalar y, SkScalar radius, |
|
648 Direction dir = kCW_Direction); |
|
649 |
|
650 /** Add the specified arc to the path as a new contour. |
|
651 |
|
652 @param oval The bounds of oval used to define the size of the arc |
|
653 @param startAngle Starting angle (in degrees) where the arc begins |
|
654 @param sweepAngle Sweep angle (in degrees) measured clockwise |
|
655 */ |
|
656 void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle); |
|
657 |
|
658 /** |
|
659 * Add a closed round-rectangle contour to the path |
|
660 * @param rect The bounds of a round-rectangle to add as a closed contour |
|
661 * @param rx The x-radius of the rounded corners on the round-rectangle |
|
662 * @param ry The y-radius of the rounded corners on the round-rectangle |
|
663 * @param dir The direction to wind the rectangle's contour. Cannot be |
|
664 * kUnknown_Direction. |
|
665 */ |
|
666 void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, |
|
667 Direction dir = kCW_Direction); |
|
668 |
|
669 /** |
|
670 * Add a closed round-rectangle contour to the path. Each corner receives |
|
671 * two radius values [X, Y]. The corners are ordered top-left, top-right, |
|
672 * bottom-right, bottom-left. |
|
673 * @param rect The bounds of a round-rectangle to add as a closed contour |
|
674 * @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner |
|
675 * @param dir The direction to wind the rectangle's contour. Cannot be |
|
676 * kUnknown_Direction. |
|
677 * Note: The radii here now go through the same constraint handling as the |
|
678 * SkRRect radii (i.e., either radii at a corner being 0 implies a |
|
679 * sqaure corner and oversized radii are proportionally scaled down). |
|
680 */ |
|
681 void addRoundRect(const SkRect& rect, const SkScalar radii[], |
|
682 Direction dir = kCW_Direction); |
|
683 |
|
684 /** |
|
685 * Add an SkRRect contour to the path |
|
686 * @param rrect The rounded rect to add as a closed contour |
|
687 * @param dir The winding direction for the new contour. Cannot be |
|
688 * kUnknown_Direction. |
|
689 */ |
|
690 void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction); |
|
691 |
|
692 /** |
|
693 * Add a new contour made of just lines. This is just a fast version of |
|
694 * the following: |
|
695 * this->moveTo(pts[0]); |
|
696 * for (int i = 1; i < count; ++i) { |
|
697 * this->lineTo(pts[i]); |
|
698 * } |
|
699 * if (close) { |
|
700 * this->close(); |
|
701 * } |
|
702 */ |
|
703 void addPoly(const SkPoint pts[], int count, bool close); |
|
704 |
|
705 enum AddPathMode { |
|
706 /** Source path contours are added as new contours. |
|
707 */ |
|
708 kAppend_AddPathMode, |
|
709 /** Path is added by extending the last contour of the destination path |
|
710 with the first contour of the source path. If the last contour of |
|
711 the destination path is closed, then it will not be extended. |
|
712 Instead, the start of source path will be extended by a straight |
|
713 line to the end point of the destination path. |
|
714 */ |
|
715 kExtend_AddPathMode |
|
716 }; |
|
717 |
|
718 /** Add a copy of src to the path, offset by (dx,dy) |
|
719 @param src The path to add as a new contour |
|
720 @param dx The amount to translate the path in X as it is added |
|
721 @param dx The amount to translate the path in Y as it is added |
|
722 */ |
|
723 void addPath(const SkPath& src, SkScalar dx, SkScalar dy, |
|
724 AddPathMode mode = kAppend_AddPathMode); |
|
725 |
|
726 /** Add a copy of src to the path |
|
727 */ |
|
728 void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) { |
|
729 SkMatrix m; |
|
730 m.reset(); |
|
731 this->addPath(src, m, mode); |
|
732 } |
|
733 |
|
734 /** Add a copy of src to the path, transformed by matrix |
|
735 @param src The path to add as a new contour |
|
736 @param matrix Transform applied to src |
|
737 @param mode Determines how path is added |
|
738 */ |
|
739 void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode); |
|
740 |
|
741 /** |
|
742 * Same as addPath(), but reverses the src input |
|
743 */ |
|
744 void reverseAddPath(const SkPath& src); |
|
745 |
|
746 /** Offset the path by (dx,dy), returning true on success |
|
747 |
|
748 @param dx The amount in the X direction to offset the entire path |
|
749 @param dy The amount in the Y direction to offset the entire path |
|
750 @param dst The translated path is written here |
|
751 */ |
|
752 void offset(SkScalar dx, SkScalar dy, SkPath* dst) const; |
|
753 |
|
754 /** Offset the path by (dx,dy), returning true on success |
|
755 |
|
756 @param dx The amount in the X direction to offset the entire path |
|
757 @param dy The amount in the Y direction to offset the entire path |
|
758 */ |
|
759 void offset(SkScalar dx, SkScalar dy) { |
|
760 this->offset(dx, dy, this); |
|
761 } |
|
762 |
|
763 /** Transform the points in this path by matrix, and write the answer into |
|
764 dst. |
|
765 |
|
766 @param matrix The matrix to apply to the path |
|
767 @param dst The transformed path is written here |
|
768 */ |
|
769 void transform(const SkMatrix& matrix, SkPath* dst) const; |
|
770 |
|
771 /** Transform the points in this path by matrix |
|
772 |
|
773 @param matrix The matrix to apply to the path |
|
774 */ |
|
775 void transform(const SkMatrix& matrix) { |
|
776 this->transform(matrix, this); |
|
777 } |
|
778 |
|
779 /** Return the last point on the path. If no points have been added, (0,0) |
|
780 is returned. If there are no points, this returns false, otherwise it |
|
781 returns true. |
|
782 |
|
783 @param lastPt The last point on the path is returned here |
|
784 */ |
|
785 bool getLastPt(SkPoint* lastPt) const; |
|
786 |
|
787 /** Set the last point on the path. If no points have been added, |
|
788 moveTo(x,y) is automatically called. |
|
789 |
|
790 @param x The new x-coordinate for the last point |
|
791 @param y The new y-coordinate for the last point |
|
792 */ |
|
793 void setLastPt(SkScalar x, SkScalar y); |
|
794 |
|
795 /** Set the last point on the path. If no points have been added, moveTo(p) |
|
796 is automatically called. |
|
797 |
|
798 @param p The new location for the last point |
|
799 */ |
|
800 void setLastPt(const SkPoint& p) { |
|
801 this->setLastPt(p.fX, p.fY); |
|
802 } |
|
803 |
|
804 enum SegmentMask { |
|
805 kLine_SegmentMask = 1 << 0, |
|
806 kQuad_SegmentMask = 1 << 1, |
|
807 kConic_SegmentMask = 1 << 2, |
|
808 kCubic_SegmentMask = 1 << 3, |
|
809 }; |
|
810 |
|
811 /** |
|
812 * Returns a mask, where each bit corresponding to a SegmentMask is |
|
813 * set if the path contains 1 or more segments of that type. |
|
814 * Returns 0 for an empty path (no segments). |
|
815 */ |
|
816 uint32_t getSegmentMasks() const { return fPathRef->getSegmentMasks(); } |
|
817 |
|
818 enum Verb { |
|
819 kMove_Verb, //!< iter.next returns 1 point |
|
820 kLine_Verb, //!< iter.next returns 2 points |
|
821 kQuad_Verb, //!< iter.next returns 3 points |
|
822 kConic_Verb, //!< iter.next returns 3 points + iter.conicWeight() |
|
823 kCubic_Verb, //!< iter.next returns 4 points |
|
824 kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt) |
|
825 kDone_Verb, //!< iter.next returns 0 points |
|
826 }; |
|
827 |
|
828 /** Iterate through all of the segments (lines, quadratics, cubics) of |
|
829 each contours in a path. |
|
830 |
|
831 The iterator cleans up the segments along the way, removing degenerate |
|
832 segments and adding close verbs where necessary. When the forceClose |
|
833 argument is provided, each contour (as defined by a new starting |
|
834 move command) will be completed with a close verb regardless of the |
|
835 contour's contents. |
|
836 */ |
|
837 class SK_API Iter { |
|
838 public: |
|
839 Iter(); |
|
840 Iter(const SkPath&, bool forceClose); |
|
841 |
|
842 void setPath(const SkPath&, bool forceClose); |
|
843 |
|
844 /** Return the next verb in this iteration of the path. When all |
|
845 segments have been visited, return kDone_Verb. |
|
846 |
|
847 @param pts The points representing the current verb and/or segment |
|
848 @param doConsumeDegerates If true, first scan for segments that are |
|
849 deemed degenerate (too short) and skip those. |
|
850 @return The verb for the current segment |
|
851 */ |
|
852 Verb next(SkPoint pts[4], bool doConsumeDegerates = true) { |
|
853 if (doConsumeDegerates) { |
|
854 this->consumeDegenerateSegments(); |
|
855 } |
|
856 return this->doNext(pts); |
|
857 } |
|
858 |
|
859 /** |
|
860 * Return the weight for the current conic. Only valid if the current |
|
861 * segment return by next() was a conic. |
|
862 */ |
|
863 SkScalar conicWeight() const { return *fConicWeights; } |
|
864 |
|
865 /** If next() returns kLine_Verb, then this query returns true if the |
|
866 line was the result of a close() command (i.e. the end point is the |
|
867 initial moveto for this contour). If next() returned a different |
|
868 verb, this returns an undefined value. |
|
869 |
|
870 @return If the last call to next() returned kLine_Verb, return true |
|
871 if it was the result of an explicit close command. |
|
872 */ |
|
873 bool isCloseLine() const { return SkToBool(fCloseLine); } |
|
874 |
|
875 /** Returns true if the current contour is closed (has a kClose_Verb) |
|
876 @return true if the current contour is closed (has a kClose_Verb) |
|
877 */ |
|
878 bool isClosedContour() const; |
|
879 |
|
880 private: |
|
881 const SkPoint* fPts; |
|
882 const uint8_t* fVerbs; |
|
883 const uint8_t* fVerbStop; |
|
884 const SkScalar* fConicWeights; |
|
885 SkPoint fMoveTo; |
|
886 SkPoint fLastPt; |
|
887 SkBool8 fForceClose; |
|
888 SkBool8 fNeedClose; |
|
889 SkBool8 fCloseLine; |
|
890 SkBool8 fSegmentState; |
|
891 |
|
892 inline const SkPoint& cons_moveTo(); |
|
893 Verb autoClose(SkPoint pts[2]); |
|
894 void consumeDegenerateSegments(); |
|
895 Verb doNext(SkPoint pts[4]); |
|
896 }; |
|
897 |
|
898 /** Iterate through the verbs in the path, providing the associated points. |
|
899 */ |
|
900 class SK_API RawIter { |
|
901 public: |
|
902 RawIter(); |
|
903 RawIter(const SkPath&); |
|
904 |
|
905 void setPath(const SkPath&); |
|
906 |
|
907 /** Return the next verb in this iteration of the path. When all |
|
908 segments have been visited, return kDone_Verb. |
|
909 |
|
910 @param pts The points representing the current verb and/or segment |
|
911 This must not be NULL. |
|
912 @return The verb for the current segment |
|
913 */ |
|
914 Verb next(SkPoint pts[4]); |
|
915 |
|
916 SkScalar conicWeight() const { return *fConicWeights; } |
|
917 |
|
918 private: |
|
919 const SkPoint* fPts; |
|
920 const uint8_t* fVerbs; |
|
921 const uint8_t* fVerbStop; |
|
922 const SkScalar* fConicWeights; |
|
923 SkPoint fMoveTo; |
|
924 SkPoint fLastPt; |
|
925 }; |
|
926 |
|
927 /** |
|
928 * Returns true if the point { x, y } is contained by the path, taking into |
|
929 * account the FillType. |
|
930 */ |
|
931 bool contains(SkScalar x, SkScalar y) const; |
|
932 |
|
933 void dump(bool forceClose, const char title[] = NULL) const; |
|
934 void dump() const; |
|
935 |
|
936 /** |
|
937 * Write the path to the buffer, and return the number of bytes written. |
|
938 * If buffer is NULL, it still returns the number of bytes. |
|
939 */ |
|
940 size_t writeToMemory(void* buffer) const; |
|
941 /** |
|
942 * Initializes the path from the buffer |
|
943 * |
|
944 * @param buffer Memory to read from |
|
945 * @param length Amount of memory available in the buffer |
|
946 * @return number of bytes read (must be a multiple of 4) or |
|
947 * 0 if there was not enough memory available |
|
948 */ |
|
949 size_t readFromMemory(const void* buffer, size_t length); |
|
950 |
|
951 /** Returns a non-zero, globally unique value corresponding to the set of verbs |
|
952 and points in the path (but not the fill type [except on Android skbug.com/1762]). |
|
953 Each time the path is modified, a different generation ID will be returned. |
|
954 */ |
|
955 uint32_t getGenerationID() const; |
|
956 |
|
957 #ifdef SK_BUILD_FOR_ANDROID |
|
958 static const int kPathRefGenIDBitCnt = 30; // leave room for the fill type (skbug.com/1762) |
|
959 const SkPath* getSourcePath() const; |
|
960 void setSourcePath(const SkPath* path); |
|
961 #else |
|
962 static const int kPathRefGenIDBitCnt = 32; |
|
963 #endif |
|
964 |
|
965 SkDEBUGCODE(void validate() const;) |
|
966 |
|
967 private: |
|
968 enum SerializationOffsets { |
|
969 // 1 free bit at 29 |
|
970 kUnused1_SerializationShift = 28, // 1 free bit |
|
971 kDirection_SerializationShift = 26, // requires 2 bits |
|
972 kUnused2_SerializationShift = 25, // 1 free bit |
|
973 // 1 free bit at 24 |
|
974 kConvexity_SerializationShift = 16, // requires 8 bits |
|
975 kFillType_SerializationShift = 8, // requires 8 bits |
|
976 // 8 free bits at 0 |
|
977 }; |
|
978 |
|
979 SkAutoTUnref<SkPathRef> fPathRef; |
|
980 |
|
981 int fLastMoveToIndex; |
|
982 uint8_t fFillType; |
|
983 mutable uint8_t fConvexity; |
|
984 mutable uint8_t fDirection; |
|
985 #ifdef SK_BUILD_FOR_ANDROID |
|
986 const SkPath* fSourcePath; |
|
987 #endif |
|
988 |
|
989 /** Resets all fields other than fPathRef to their initial 'empty' values. |
|
990 * Assumes the caller has already emptied fPathRef. |
|
991 * On Android increments fGenerationID without reseting it. |
|
992 */ |
|
993 void resetFields(); |
|
994 |
|
995 /** Sets all fields other than fPathRef to the values in 'that'. |
|
996 * Assumes the caller has already set fPathRef. |
|
997 * Doesn't change fGenerationID or fSourcePath on Android. |
|
998 */ |
|
999 void copyFields(const SkPath& that); |
|
1000 |
|
1001 friend class Iter; |
|
1002 |
|
1003 friend class SkPathStroker; |
|
1004 |
|
1005 /* Append, in reverse order, the first contour of path, ignoring path's |
|
1006 last point. If no moveTo() call has been made for this contour, the |
|
1007 first point is automatically set to (0,0). |
|
1008 */ |
|
1009 void reversePathTo(const SkPath&); |
|
1010 |
|
1011 // called before we add points for lineTo, quadTo, cubicTo, checking to see |
|
1012 // if we need to inject a leading moveTo first |
|
1013 // |
|
1014 // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0) |
|
1015 // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo) |
|
1016 // |
|
1017 inline void injectMoveToIfNeeded(); |
|
1018 |
|
1019 inline bool hasOnlyMoveTos() const; |
|
1020 |
|
1021 Convexity internalGetConvexity() const; |
|
1022 |
|
1023 bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts, |
|
1024 bool* isClosed, Direction* direction) const; |
|
1025 |
|
1026 /** Returns if the path can return a bound at no cost (true) or will have to |
|
1027 perform some computation (false). |
|
1028 */ |
|
1029 bool hasComputedBounds() const { |
|
1030 SkDEBUGCODE(this->validate();) |
|
1031 return fPathRef->hasComputedBounds(); |
|
1032 } |
|
1033 |
|
1034 |
|
1035 // 'rect' needs to be sorted |
|
1036 void setBounds(const SkRect& rect) { |
|
1037 SkPathRef::Editor ed(&fPathRef); |
|
1038 |
|
1039 ed.setBounds(rect); |
|
1040 } |
|
1041 |
|
1042 friend class SkAutoPathBoundsUpdate; |
|
1043 friend class SkAutoDisableOvalCheck; |
|
1044 friend class SkAutoDisableDirectionCheck; |
|
1045 friend class SkBench_AddPathTest; // perf test reversePathTo |
|
1046 friend class PathTest_Private; // unit test reversePathTo |
|
1047 }; |
|
1048 |
|
1049 #endif |