• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkMatrix.h"
14 #include "SkTDArray.h"
15 
16 #ifdef SK_BUILD_FOR_ANDROID
17 #define GEN_ID_INC              fGenerationID++
18 #define GEN_ID_PTR_INC(ptr)     ptr->fGenerationID++
19 #else
20 #define GEN_ID_INC
21 #define GEN_ID_PTR_INC(ptr)
22 #endif
23 
24 class SkReader32;
25 class SkWriter32;
26 class SkAutoPathBoundsUpdate;
27 class SkString;
28 
29 /** \class SkPath
30 
31     The SkPath class encapsulates compound (multiple contour) geometric paths
32     consisting of straight line segments, quadratic curves, and cubic curves.
33 */
34 class SK_API SkPath {
35 public:
36     SkPath();
37     SkPath(const SkPath&);
38     ~SkPath();
39 
40     SkPath& operator=(const SkPath&);
41 
42     friend bool operator==(const SkPath&, const SkPath&);
43     friend bool operator!=(const SkPath& a, const SkPath& b) {
44         return !(a == b);
45     }
46 
47     enum FillType {
48         /** Specifies that "inside" is computed by a non-zero sum of signed
49             edge crossings
50         */
51         kWinding_FillType,
52         /** Specifies that "inside" is computed by an odd number of edge
53             crossings
54         */
55         kEvenOdd_FillType,
56         /** Same as Winding, but draws outside of the path, rather than inside
57         */
58         kInverseWinding_FillType,
59         /** Same as EvenOdd, but draws outside of the path, rather than inside
60          */
61         kInverseEvenOdd_FillType
62     };
63 
64     /** Return the path's fill type. This is used to define how "inside" is
65         computed. The default value is kWinding_FillType.
66 
67         @return the path's fill type
68     */
getFillType()69     FillType getFillType() const { return (FillType)fFillType; }
70 
71     /** Set the path's fill type. This is used to define how "inside" is
72         computed. The default value is kWinding_FillType.
73 
74         @param ft The new fill type for this path
75     */
setFillType(FillType ft)76     void setFillType(FillType ft) {
77         fFillType = SkToU8(ft);
78         GEN_ID_INC;
79     }
80 
81     /** Returns true if the filltype is one of the Inverse variants */
isInverseFillType()82     bool isInverseFillType() const { return (fFillType & 2) != 0; }
83 
84     /**
85      *  Toggle between inverse and normal filltypes. This reverse the return
86      *  value of isInverseFillType()
87      */
toggleInverseFillType()88     void toggleInverseFillType() {
89         fFillType ^= 2;
90         GEN_ID_INC;
91      }
92 
93     enum Convexity {
94         kUnknown_Convexity,
95         kConvex_Convexity,
96         kConcave_Convexity
97     };
98 
99     /**
100      *  Return the path's convexity, as stored in the path. If it is currently
101      *  unknown, and the computeIfUnknown bool is true, then this will first
102      *  call ComputeConvexity() and then return that (cached) value.
103      */
getConvexity()104     Convexity getConvexity() const {
105         if (kUnknown_Convexity == fConvexity) {
106             fConvexity = (uint8_t)ComputeConvexity(*this);
107         }
108         return (Convexity)fConvexity;
109     }
110 
111     /**
112      *  Return the currently cached value for convexity, even if that is set to
113      *  kUnknown_Convexity. Note: getConvexity() will automatically call
114      *  ComputeConvexity and cache its return value if the current setting is
115      *  kUnknown.
116      */
getConvexityOrUnknown()117     Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; }
118 
119     /**
120      *  Store a convexity setting in the path. There is no automatic check to
121      *  see if this value actually agress with the return value from
122      *  ComputeConvexity().
123      *
124      *  Note: even if this is set to a "known" value, if the path is later
125      *  changed (e.g. lineTo(), addRect(), etc.) then the cached value will be
126      *  reset to kUnknown_Convexity.
127      */
128     void setConvexity(Convexity);
129 
130     /**
131      *  Compute the convexity of the specified path. This does not look at the
132      *  value stored in the path, but computes it directly from the path's data.
133      *
134      *  This never returns kUnknown_Convexity.
135      *
136      *  If there is more than one contour, this returns kConcave_Convexity.
137      *  If the contour is degenerate (e.g. there are fewer than 3 non-degenerate
138      *  segments), then this returns kConvex_Convexity.
139      *  The contour is treated as if it were closed, even if there is no kClose
140      *  verb.
141      */
142     static Convexity ComputeConvexity(const SkPath&);
143 
144     /**
145      *  DEPRECATED: use getConvexity()
146      *  Returns true if the path is flagged as being convex. This is not a
147      *  confirmed by any analysis, it is just the value set earlier.
148      */
isConvex()149     bool isConvex() const {
150         return kConvex_Convexity == this->getConvexity();
151     }
152 
153     /**
154      *  DEPRECATED: use setConvexity()
155      *  Set the isConvex flag to true or false. Convex paths may draw faster if
156      *  this flag is set, though setting this to true on a path that is in fact
157      *  not convex can give undefined results when drawn. Paths default to
158      *  isConvex == false
159      */
setIsConvex(bool isConvex)160     void setIsConvex(bool isConvex) {
161         this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity);
162     }
163 
164     /** Clear any lines and curves from the path, making it empty. This frees up
165         internal storage associated with those segments.
166         This does NOT change the fill-type setting nor isConvex
167     */
168     void reset();
169 
170     /** Similar to reset(), in that all lines and curves are removed from the
171         path. However, any internal storage for those lines/curves is retained,
172         making reuse of the path potentially faster.
173         This does NOT change the fill-type setting nor isConvex
174     */
175     void rewind();
176 
177     /** Returns true if the path is empty (contains no lines or curves)
178 
179         @return true if the path is empty (contains no lines or curves)
180     */
181     bool isEmpty() const;
182 
183     /** Test a line for zero length
184 
185         @return true if the line is of zero length; otherwise false.
186     */
IsLineDegenerate(const SkPoint & p1,const SkPoint & p2)187     static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) {
188         return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero);
189     }
190 
191     /** Test a quad for zero length
192 
193         @return true if the quad is of zero length; otherwise false.
194     */
IsQuadDegenerate(const SkPoint & p1,const SkPoint & p2,const SkPoint & p3)195     static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
196                                  const SkPoint& p3) {
197         return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero) &&
198                p2.equalsWithinTolerance(p3, SK_ScalarNearlyZero);
199     }
200 
201     /** Test a cubic curve for zero length
202 
203         @return true if the cubic is of zero length; otherwise false.
204     */
IsCubicDegenerate(const SkPoint & p1,const SkPoint & p2,const SkPoint & p3,const SkPoint & p4)205     static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
206                                   const SkPoint& p3, const SkPoint& p4) {
207         return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero) &&
208                p2.equalsWithinTolerance(p3, SK_ScalarNearlyZero) &&
209                p3.equalsWithinTolerance(p4, SK_ScalarNearlyZero);
210     }
211 
212     /** Returns true if the path specifies a rectangle. If so, and if rect is
213         not null, set rect to the bounds of the path. If the path does not
214         specify a rectangle, return false and ignore rect.
215 
216         @param rect If not null, returns the bounds of the path if it specifies
217                     a rectangle
218         @return true if the path specifies a rectangle
219     */
220     bool isRect(SkRect* rect) const;
221 
222     /** Return the number of points in the path
223      */
countPoints()224     int countPoints() const {
225         return this->getPoints(NULL, 0);
226     }
227 
228     /** Return the point at the specified index. If the index is out of range
229          (i.e. is not 0 <= index < countPoints()) then the returned coordinates
230          will be (0,0)
231      */
232     SkPoint getPoint(int index) const;
233 
234     /** Returns the number of points in the path. Up to max points are copied.
235 
236         @param points If not null, receives up to max points
237         @param max The maximum number of points to copy into points
238         @return the actual number of points in the path
239     */
240     int getPoints(SkPoint points[], int max) const;
241 
242     //! Swap contents of this and other. Guaranteed not to throw
243     void swap(SkPath& other);
244 
245     /** Returns the bounds of the path's points. If the path contains 0 or 1
246         points, the bounds is set to (0,0,0,0), and isEmpty() will return true.
247         Note: this bounds may be larger than the actual shape, since curves
248         do not extend as far as their control points.
249     */
getBounds()250     const SkRect& getBounds() const {
251         if (fBoundsIsDirty) {
252             this->computeBounds();
253         }
254         return fBounds;
255     }
256 
257     /** Calling this will, if the internal cache of the bounds is out of date,
258         update it so that subsequent calls to getBounds will be instanteous.
259         This also means that any copies or simple transformations of the path
260         will inherit the cached bounds.
261      */
updateBoundsCache()262     void updateBoundsCache() const {
263         // for now, just calling getBounds() is sufficient
264         this->getBounds();
265     }
266 
267     //  Construction methods
268 
269     /** Hint to the path to prepare for adding more points. This can allow the
270         path to more efficiently grow its storage.
271 
272         @param extraPtCount The number of extra points the path should
273                             preallocate for.
274     */
275     void incReserve(unsigned extraPtCount);
276 
277     /** Set the beginning of the next contour to the point (x,y).
278 
279         @param x    The x-coordinate of the start of a new contour
280         @param y    The y-coordinate of the start of a new contour
281     */
282     void moveTo(SkScalar x, SkScalar y);
283 
284     /** Set the beginning of the next contour to the point
285 
286         @param p    The start of a new contour
287     */
moveTo(const SkPoint & p)288     void moveTo(const SkPoint& p) {
289         this->moveTo(p.fX, p.fY);
290     }
291 
292     /** Set the beginning of the next contour relative to the last point on the
293         previous contour. If there is no previous contour, this is treated the
294         same as moveTo().
295 
296         @param dx   The amount to add to the x-coordinate of the end of the
297                     previous contour, to specify the start of a new contour
298         @param dy   The amount to add to the y-coordinate of the end of the
299                     previous contour, to specify the start of a new contour
300     */
301     void rMoveTo(SkScalar dx, SkScalar dy);
302 
303     /** Add a line from the last point to the specified point (x,y). If no
304         moveTo() call has been made for this contour, the first point is
305         automatically set to (0,0).
306 
307         @param x    The x-coordinate of the end of a line
308         @param y    The y-coordinate of the end of a line
309     */
310     void lineTo(SkScalar x, SkScalar y);
311 
312     /** Add a line from the last point to the specified point. If no moveTo()
313         call has been made for this contour, the first point is automatically
314         set to (0,0).
315 
316         @param p    The end of a line
317     */
lineTo(const SkPoint & p)318     void lineTo(const SkPoint& p) {
319         this->lineTo(p.fX, p.fY);
320     }
321 
322     /** Same as lineTo, but the coordinates are considered relative to the last
323         point on this contour. If there is no previous point, then a moveTo(0,0)
324         is inserted automatically.
325 
326         @param dx   The amount to add to the x-coordinate of the previous point
327                     on this contour, to specify a line
328         @param dy   The amount to add to the y-coordinate of the previous point
329                     on this contour, to specify a line
330     */
331     void rLineTo(SkScalar dx, SkScalar dy);
332 
333     /** Add a quadratic bezier from the last point, approaching control point
334         (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
335         this contour, the first point is automatically set to (0,0).
336 
337         @param x1   The x-coordinate of the control point on a quadratic curve
338         @param y1   The y-coordinate of the control point on a quadratic curve
339         @param x2   The x-coordinate of the end point on a quadratic curve
340         @param y2   The y-coordinate of the end point on a quadratic curve
341     */
342     void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
343 
344     /** Add a quadratic bezier from the last point, approaching control point
345         p1, and ending at p2. If no moveTo() call has been made for this
346         contour, the first point is automatically set to (0,0).
347 
348         @param p1   The control point on a quadratic curve
349         @param p2   The end point on a quadratic curve
350     */
quadTo(const SkPoint & p1,const SkPoint & p2)351     void quadTo(const SkPoint& p1, const SkPoint& p2) {
352         this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
353     }
354 
355     /** Same as quadTo, but the coordinates are considered relative to the last
356         point on this contour. If there is no previous point, then a moveTo(0,0)
357         is inserted automatically.
358 
359         @param dx1   The amount to add to the x-coordinate of the last point on
360                 this contour, to specify the control point of a quadratic curve
361         @param dy1   The amount to add to the y-coordinate of the last point on
362                 this contour, to specify the control point of a quadratic curve
363         @param dx2   The amount to add to the x-coordinate of the last point on
364                      this contour, to specify the end point of a quadratic curve
365         @param dy2   The amount to add to the y-coordinate of the last point on
366                      this contour, to specify the end point of a quadratic curve
367     */
368     void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
369 
370     /** Add a cubic bezier from the last point, approaching control points
371         (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
372         made for this contour, the first point is automatically set to (0,0).
373 
374         @param x1   The x-coordinate of the 1st control point on a cubic curve
375         @param y1   The y-coordinate of the 1st control point on a cubic curve
376         @param x2   The x-coordinate of the 2nd control point on a cubic curve
377         @param y2   The y-coordinate of the 2nd control point on a cubic curve
378         @param x3   The x-coordinate of the end point on a cubic curve
379         @param y3   The y-coordinate of the end point on a cubic curve
380     */
381     void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
382                  SkScalar x3, SkScalar y3);
383 
384     /** Add a cubic bezier from the last point, approaching control points p1
385         and p2, and ending at p3. If no moveTo() call has been made for this
386         contour, the first point is automatically set to (0,0).
387 
388         @param p1   The 1st control point on a cubic curve
389         @param p2   The 2nd control point on a cubic curve
390         @param p3   The end point on a cubic curve
391     */
cubicTo(const SkPoint & p1,const SkPoint & p2,const SkPoint & p3)392     void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
393         this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
394     }
395 
396     /** Same as cubicTo, but the coordinates are considered relative to the
397         current point on this contour. If there is no previous point, then a
398         moveTo(0,0) is inserted automatically.
399 
400         @param dx1   The amount to add to the x-coordinate of the last point on
401                 this contour, to specify the 1st control point of a cubic curve
402         @param dy1   The amount to add to the y-coordinate of the last point on
403                 this contour, to specify the 1st control point of a cubic curve
404         @param dx2   The amount to add to the x-coordinate of the last point on
405                 this contour, to specify the 2nd control point of a cubic curve
406         @param dy2   The amount to add to the y-coordinate of the last point on
407                 this contour, to specify the 2nd control point of a cubic curve
408         @param dx3   The amount to add to the x-coordinate of the last point on
409                      this contour, to specify the end point of a cubic curve
410         @param dy3   The amount to add to the y-coordinate of the last point on
411                      this contour, to specify the end point of a cubic curve
412     */
413     void    rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
414                      SkScalar x3, SkScalar y3);
415 
416     /** Append the specified arc to the path as a new contour. If the start of
417         the path is different from the path's current last point, then an
418         automatic lineTo() is added to connect the current contour to the start
419         of the arc. However, if the path is empty, then we call moveTo() with
420         the first point of the arc. The sweep angle is treated mod 360.
421 
422         @param oval The bounding oval defining the shape and size of the arc
423         @param startAngle Starting angle (in degrees) where the arc begins
424         @param sweepAngle Sweep angle (in degrees) measured clockwise. This is
425                           treated mod 360.
426         @param forceMoveTo If true, always begin a new contour with the arc
427     */
428     void    arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
429                   bool forceMoveTo);
430 
431     /** Append a line and arc to the current path. This is the same as the
432         PostScript call "arct".
433     */
434     void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
435                SkScalar radius);
436 
437     /** Append a line and arc to the current path. This is the same as the
438         PostScript call "arct".
439     */
arcTo(const SkPoint p1,const SkPoint p2,SkScalar radius)440     void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
441         this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
442     }
443 
444     /** Close the current contour. If the current point is not equal to the
445         first point of the contour, a line segment is automatically added.
446     */
447     void close();
448 
449     enum Direction {
450         /** clockwise direction for adding closed contours */
451         kCW_Direction,
452         /** counter-clockwise direction for adding closed contours */
453         kCCW_Direction
454     };
455 
456     /**
457      *  Tries to quickly compute the direction of the first non-degenerate
458      *  contour. If it can be computed, return true and set dir to that
459      *  direction. If it cannot be (quickly) determined, return false and ignore
460      *  the dir parameter.
461      */
462     bool cheapComputeDirection(Direction* dir) const;
463 
464     /**
465      *  Returns true if the path's direction can be computed via
466      *  cheapComputDirection() and if that computed direction matches the
467      *  specified direction.
468      */
cheapIsDirection(Direction dir)469     bool cheapIsDirection(Direction dir) const {
470         Direction computedDir;
471         return this->cheapComputeDirection(&computedDir) && computedDir == dir;
472     }
473 
474     /** Add a closed rectangle contour to the path
475         @param rect The rectangle to add as a closed contour to the path
476         @param dir  The direction to wind the rectangle's contour
477     */
478     void    addRect(const SkRect& rect, Direction dir = kCW_Direction);
479 
480     /** Add a closed rectangle contour to the path
481 
482         @param left     The left side of a rectangle to add as a closed contour
483                         to the path
484         @param top      The top of a rectangle to add as a closed contour to the
485                         path
486         @param right    The right side of a rectangle to add as a closed contour
487                         to the path
488         @param bottom   The bottom of a rectangle to add as a closed contour to
489                         the path
490         @param dir      The direction to wind the rectangle's contour
491     */
492     void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
493                  Direction dir = kCW_Direction);
494 
495     /** Add a closed oval contour to the path
496 
497         @param oval The bounding oval to add as a closed contour to the path
498         @param dir  The direction to wind the oval's contour
499     */
500     void addOval(const SkRect& oval, Direction dir = kCW_Direction);
501 
502     /** Add a closed circle contour to the path
503 
504         @param x        The x-coordinate of the center of a circle to add as a
505                         closed contour to the path
506         @param y        The y-coordinate of the center of a circle to add as a
507                         closed contour to the path
508         @param radius   The radius of a circle to add as a closed contour to the
509                         path
510         @param dir      The direction to wind the circle's contour
511     */
512     void addCircle(SkScalar x, SkScalar y, SkScalar radius,
513                    Direction dir = kCW_Direction);
514 
515     /** Add the specified arc to the path as a new contour.
516 
517         @param oval The bounds of oval used to define the size of the arc
518         @param startAngle Starting angle (in degrees) where the arc begins
519         @param sweepAngle Sweep angle (in degrees) measured clockwise
520     */
521     void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
522 
523     /** Add a closed round-rectangle contour to the path
524         @param rect The bounds of a round-rectangle to add as a closed contour
525         @param rx   The x-radius of the rounded corners on the round-rectangle
526         @param ry   The y-radius of the rounded corners on the round-rectangle
527         @param dir  The direction to wind the round-rectangle's contour
528     */
529     void    addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
530                          Direction dir = kCW_Direction);
531 
532     /** Add a closed round-rectangle contour to the path. Each corner receives
533         two radius values [X, Y]. The corners are ordered top-left, top-right,
534         bottom-right, bottom-left.
535         @param rect The bounds of a round-rectangle to add as a closed contour
536         @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner
537         @param dir  The direction to wind the round-rectangle's contour
538         */
539     void addRoundRect(const SkRect& rect, const SkScalar radii[],
540                       Direction dir = kCW_Direction);
541 
542     /** Add a copy of src to the path, offset by (dx,dy)
543         @param src  The path to add as a new contour
544         @param dx   The amount to translate the path in X as it is added
545         @param dx   The amount to translate the path in Y as it is added
546     */
547     void addPath(const SkPath& src, SkScalar dx, SkScalar dy);
548 
549     /** Add a copy of src to the path
550     */
addPath(const SkPath & src)551     void addPath(const SkPath& src) {
552         SkMatrix m;
553         m.reset();
554         this->addPath(src, m);
555     }
556 
557     /** Add a copy of src to the path, transformed by matrix
558         @param src  The path to add as a new contour
559     */
560     void addPath(const SkPath& src, const SkMatrix& matrix);
561 
562     /**
563      *  Same as addPath(), but reverses the src input
564      */
565     void reverseAddPath(const SkPath& src);
566 
567     /** Offset the path by (dx,dy), returning true on success
568 
569         @param dx   The amount in the X direction to offset the entire path
570         @param dy   The amount in the Y direction to offset the entire path
571         @param dst  The translated path is written here
572     */
573     void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
574 
575     /** Offset the path by (dx,dy), returning true on success
576 
577         @param dx   The amount in the X direction to offset the entire path
578         @param dy   The amount in the Y direction to offset the entire path
579     */
offset(SkScalar dx,SkScalar dy)580     void offset(SkScalar dx, SkScalar dy) {
581         this->offset(dx, dy, this);
582     }
583 
584     /** Transform the points in this path by matrix, and write the answer into
585         dst.
586 
587         @param matrix   The matrix to apply to the path
588         @param dst      The transformed path is written here
589     */
590     void transform(const SkMatrix& matrix, SkPath* dst) const;
591 
592     /** Transform the points in this path by matrix
593 
594         @param matrix The matrix to apply to the path
595     */
transform(const SkMatrix & matrix)596     void transform(const SkMatrix& matrix) {
597         this->transform(matrix, this);
598     }
599 
600     /** Return the last point on the path. If no points have been added, (0,0)
601         is returned. If there are no points, this returns false, otherwise it
602         returns true.
603 
604         @param lastPt   The last point on the path is returned here
605     */
606     bool getLastPt(SkPoint* lastPt) const;
607 
608     /** Set the last point on the path. If no points have been added,
609         moveTo(x,y) is automatically called.
610 
611         @param x    The new x-coordinate for the last point
612         @param y    The new y-coordinate for the last point
613     */
614     void setLastPt(SkScalar x, SkScalar y);
615 
616     /** Set the last point on the path. If no points have been added, moveTo(p)
617         is automatically called.
618 
619         @param p    The new location for the last point
620     */
setLastPt(const SkPoint & p)621     void setLastPt(const SkPoint& p) {
622         this->setLastPt(p.fX, p.fY);
623     }
624 
625     enum SegmentMask {
626         kLine_SegmentMask   = 1 << 0,
627         kQuad_SegmentMask   = 1 << 1,
628         kCubic_SegmentMask  = 1 << 2
629     };
630 
631     /**
632      *  Returns a mask, where each bit corresponding to a SegmentMask is
633      *  set if the path contains 1 or more segments of that type.
634      *  Returns 0 for an empty path (no segments).
635      */
getSegmentMasks()636     uint32_t getSegmentMasks() const { return fSegmentMask; }
637 
638     enum Verb {
639         kMove_Verb,     //!< iter.next returns 1 point
640         kLine_Verb,     //!< iter.next returns 2 points
641         kQuad_Verb,     //!< iter.next returns 3 points
642         kCubic_Verb,    //!< iter.next returns 4 points
643         kClose_Verb,    //!< iter.next returns 1 point (contour's moveTo pt)
644         kDone_Verb      //!< iter.next returns 0 points
645     };
646 
647     /** Iterate through all of the segments (lines, quadratics, cubics) of
648         each contours in a path.
649 
650         The iterator cleans up the segments along the way, removing degenerate
651         segments and adding close verbs where necessary. When the forceClose
652         argument is provided, each contour (as defined by a new starting
653         move command) will be completed with a close verb regardless of the
654         contour's contents.
655     */
656     class SK_API Iter {
657     public:
658         Iter();
659         Iter(const SkPath&, bool forceClose);
660 
661         void setPath(const SkPath&, bool forceClose);
662 
663         /** Return the next verb in this iteration of the path. When all
664             segments have been visited, return kDone_Verb.
665 
666             @param  pts The points representing the current verb and/or segment
667             @return The verb for the current segment
668         */
669         Verb next(SkPoint pts[4]);
670 
671         /** If next() returns kLine_Verb, then this query returns true if the
672             line was the result of a close() command (i.e. the end point is the
673             initial moveto for this contour). If next() returned a different
674             verb, this returns an undefined value.
675 
676             @return If the last call to next() returned kLine_Verb, return true
677                     if it was the result of an explicit close command.
678         */
isCloseLine()679         bool isCloseLine() const { return SkToBool(fCloseLine); }
680 
681         /** Returns true if the current contour is closed (has a kClose_Verb)
682             @return true if the current contour is closed (has a kClose_Verb)
683         */
684         bool isClosedContour() const;
685 
686     private:
687         const SkPoint*  fPts;
688         const uint8_t*  fVerbs;
689         const uint8_t*  fVerbStop;
690         SkPoint         fMoveTo;
691         SkPoint         fLastPt;
692         SkBool8         fForceClose;
693         SkBool8         fNeedClose;
694         SkBool8         fCloseLine;
695         SkBool8         fSegmentState;
696 
697         bool cons_moveTo(SkPoint pts[1]);
698         Verb autoClose(SkPoint pts[2]);
699         void consumeDegenerateSegments();
700     };
701 
702     /** Iterate through the verbs in the path, providing the associated points.
703     */
704     class SK_API RawIter {
705     public:
706         RawIter();
707         RawIter(const SkPath&);
708 
709         void setPath(const SkPath&);
710 
711         /** Return the next verb in this iteration of the path. When all
712             segments have been visited, return kDone_Verb.
713 
714             @param  pts The points representing the current verb and/or segment
715             @return The verb for the current segment
716         */
717         Verb next(SkPoint pts[4]);
718 
719     private:
720         const SkPoint*  fPts;
721         const uint8_t*  fVerbs;
722         const uint8_t*  fVerbStop;
723         SkPoint         fMoveTo;
724         SkPoint         fLastPt;
725     };
726 
727     void dump(bool forceClose, const char title[] = NULL) const;
728     void dump() const;
729 
730     void flatten(SkWriter32&) const;
731     void unflatten(SkReader32&);
732 
733 #ifdef SK_BUILD_FOR_ANDROID
734     uint32_t getGenerationID() const;
735     const SkPath* getSourcePath() const;
736     void setSourcePath(const SkPath* path);
737 #endif
738 
739     SkDEBUGCODE(void validate() const;)
740 
741 private:
742     SkTDArray<SkPoint>  fPts;
743     SkTDArray<uint8_t>  fVerbs;
744     mutable SkRect      fBounds;
745     int                 fLastMoveToIndex;
746     uint8_t             fFillType;
747     uint8_t             fSegmentMask;
748     mutable uint8_t     fBoundsIsDirty;
749     mutable uint8_t     fConvexity;
750 #ifdef SK_BUILD_FOR_ANDROID
751     uint32_t            fGenerationID;
752     const SkPath*       fSourcePath;
753 #endif
754 
755     // called, if dirty, by getBounds()
756     void computeBounds() const;
757 
758     friend class Iter;
759 
760     friend class SkPathStroker;
761     /*  Append the first contour of path, ignoring path's initial point. If no
762         moveTo() call has been made for this contour, the first point is
763         automatically set to (0,0).
764     */
765     void pathTo(const SkPath& path);
766 
767     /*  Append, in reverse order, the first contour of path, ignoring path's
768         last point. If no moveTo() call has been made for this contour, the
769         first point is automatically set to (0,0).
770     */
771     void reversePathTo(const SkPath&);
772 
773     // called before we add points for lineTo, quadTo, cubicTo, checking to see
774     // if we need to inject a leading moveTo first
775     //
776     //  SkPath path; path.lineTo(...);   <--- need a leading moveTo(0, 0)
777     // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo)
778     //
779     inline void injectMoveToIfNeeded();
780 
781     friend class SkAutoPathBoundsUpdate;
782 };
783 
784 #endif
785