SkPath.h revision f6d3c5aa5f93e4c3cc7a7aebf014e960cf837783
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
24class SkReader32;
25class SkWriter32;
26class SkAutoPathBoundsUpdate;
27class 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*/
34class SK_API SkPath {
35public:
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    */
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    */
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 */
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     */
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     */
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     */
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     */
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     */
160    void setIsConvex(bool isConvex) {
161        this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity);
162    }
163
164    /** Returns true if the path is an oval.
165     *
166     * @param rect      returns the bounding rect of this oval. It's a circle
167     *                  if the height and width are the same.
168     *
169     * @return true if this path is an oval.
170     *              Tracking whether a path is an oval is considered an
171     *              optimization for performance and so some paths that are in
172     *              fact ovals can report false.
173     */
174    bool isOval(SkRect* rect) const;
175
176    /** Clear any lines and curves from the path, making it empty. This frees up
177        internal storage associated with those segments.
178        This does NOT change the fill-type setting nor isConvex
179    */
180    void reset();
181
182    /** Similar to reset(), in that all lines and curves are removed from the
183        path. However, any internal storage for those lines/curves is retained,
184        making reuse of the path potentially faster.
185        This does NOT change the fill-type setting nor isConvex
186    */
187    void rewind();
188
189    /** Returns true if the path is empty (contains no lines or curves)
190
191        @return true if the path is empty (contains no lines or curves)
192    */
193    bool isEmpty() const;
194
195    /** Test a line for zero length
196
197        @return true if the line is of zero length; otherwise false.
198    */
199    static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) {
200        return p1.equalsWithinTolerance(p2);
201    }
202
203    /** Test a quad for zero length
204
205        @return true if the quad is of zero length; otherwise false.
206    */
207    static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
208                                 const SkPoint& p3) {
209        return p1.equalsWithinTolerance(p2) &&
210               p2.equalsWithinTolerance(p3);
211    }
212
213    /** Test a cubic curve for zero length
214
215        @return true if the cubic is of zero length; otherwise false.
216    */
217    static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
218                                  const SkPoint& p3, const SkPoint& p4) {
219        return p1.equalsWithinTolerance(p2) &&
220               p2.equalsWithinTolerance(p3) &&
221               p3.equalsWithinTolerance(p4);
222    }
223
224    /**
225     *  Returns true if the path specifies a single line (i.e. it contains just
226     *  a moveTo and a lineTo). If so, and line[] is not null, it sets the 2
227     *  points in line[] to the end-points of the line. If the path is not a
228     *  line, returns false and ignores line[].
229     */
230    bool isLine(SkPoint line[2]) const;
231
232    /** Returns true if the path specifies a rectangle. If so, and if rect is
233        not null, set rect to the bounds of the path. If the path does not
234        specify a rectangle, return false and ignore rect.
235
236        @param rect If not null, returns the bounds of the path if it specifies
237                    a rectangle
238        @return true if the path specifies a rectangle
239    */
240    bool isRect(SkRect* rect) const;
241
242    /** Return the number of points in the path
243     */
244    int countPoints() const {
245        return this->getPoints(NULL, 0);
246    }
247
248    /** Return the point at the specified index. If the index is out of range
249         (i.e. is not 0 <= index < countPoints()) then the returned coordinates
250         will be (0,0)
251     */
252    SkPoint getPoint(int index) const;
253
254    /** Returns the number of points in the path. Up to max points are copied.
255
256        @param points If not null, receives up to max points
257        @param max The maximum number of points to copy into points
258        @return the actual number of points in the path
259    */
260    int getPoints(SkPoint points[], int max) const;
261
262    //! Swap contents of this and other. Guaranteed not to throw
263    void swap(SkPath& other);
264
265    /** Returns the bounds of the path's points. If the path contains 0 or 1
266        points, the bounds is set to (0,0,0,0), and isEmpty() will return true.
267        Note: this bounds may be larger than the actual shape, since curves
268        do not extend as far as their control points.
269    */
270    const SkRect& getBounds() const {
271        if (fBoundsIsDirty) {
272            this->computeBounds();
273        }
274        return fBounds;
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 instanteous.
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    //  Construction methods
288
289    /** Hint to the path to prepare for adding more points. This can allow the
290        path to more efficiently grow its storage.
291
292        @param extraPtCount The number of extra points the path should
293                            preallocate for.
294    */
295    void incReserve(unsigned extraPtCount);
296
297    /** Set the beginning of the next contour to the point (x,y).
298
299        @param x    The x-coordinate of the start of a new contour
300        @param y    The y-coordinate of the start of a new contour
301    */
302    void moveTo(SkScalar x, SkScalar y);
303
304    /** Set the beginning of the next contour to the point
305
306        @param p    The start of a new contour
307    */
308    void moveTo(const SkPoint& p) {
309        this->moveTo(p.fX, p.fY);
310    }
311
312    /** Set the beginning of the next contour relative to the last point on the
313        previous contour. If there is no previous contour, this is treated the
314        same as moveTo().
315
316        @param dx   The amount to add to the x-coordinate of the end of the
317                    previous contour, to specify the start of a new contour
318        @param dy   The amount to add to the y-coordinate of the end of the
319                    previous contour, to specify the start of a new contour
320    */
321    void rMoveTo(SkScalar dx, SkScalar dy);
322
323    /** Add a line from the last point to the specified point (x,y). If no
324        moveTo() call has been made for this contour, the first point is
325        automatically set to (0,0).
326
327        @param x    The x-coordinate of the end of a line
328        @param y    The y-coordinate of the end of a line
329    */
330    void lineTo(SkScalar x, SkScalar y);
331
332    /** Add a line from the last point to the specified point. If no moveTo()
333        call has been made for this contour, the first point is automatically
334        set to (0,0).
335
336        @param p    The end of a line
337    */
338    void lineTo(const SkPoint& p) {
339        this->lineTo(p.fX, p.fY);
340    }
341
342    /** Same as lineTo, but the coordinates are considered relative to the last
343        point on this contour. If there is no previous point, then a moveTo(0,0)
344        is inserted automatically.
345
346        @param dx   The amount to add to the x-coordinate of the previous point
347                    on this contour, to specify a line
348        @param dy   The amount to add to the y-coordinate of the previous point
349                    on this contour, to specify a line
350    */
351    void rLineTo(SkScalar dx, SkScalar dy);
352
353    /** Add a quadratic bezier from the last point, approaching control point
354        (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
355        this contour, the first point is automatically set to (0,0).
356
357        @param x1   The x-coordinate of the control point on a quadratic curve
358        @param y1   The y-coordinate of the control point on a quadratic curve
359        @param x2   The x-coordinate of the end point on a quadratic curve
360        @param y2   The y-coordinate of the end point on a quadratic curve
361    */
362    void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
363
364    /** Add a quadratic bezier from the last point, approaching control point
365        p1, and ending at p2. If no moveTo() call has been made for this
366        contour, the first point is automatically set to (0,0).
367
368        @param p1   The control point on a quadratic curve
369        @param p2   The end point on a quadratic curve
370    */
371    void quadTo(const SkPoint& p1, const SkPoint& p2) {
372        this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
373    }
374
375    /** Same as quadTo, but the coordinates are considered relative to the last
376        point on this contour. If there is no previous point, then a moveTo(0,0)
377        is inserted automatically.
378
379        @param dx1   The amount to add to the x-coordinate of the last point on
380                this contour, to specify the control point of a quadratic curve
381        @param dy1   The amount to add to the y-coordinate of the last point on
382                this contour, to specify the control point of a quadratic curve
383        @param dx2   The amount to add to the x-coordinate of the last point on
384                     this contour, to specify the end point of a quadratic curve
385        @param dy2   The amount to add to the y-coordinate of the last point on
386                     this contour, to specify the end point of a quadratic curve
387    */
388    void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
389
390    /** Add a cubic bezier from the last point, approaching control points
391        (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
392        made for this contour, the first point is automatically set to (0,0).
393
394        @param x1   The x-coordinate of the 1st control point on a cubic curve
395        @param y1   The y-coordinate of the 1st control point on a cubic curve
396        @param x2   The x-coordinate of the 2nd control point on a cubic curve
397        @param y2   The y-coordinate of the 2nd control point on a cubic curve
398        @param x3   The x-coordinate of the end point on a cubic curve
399        @param y3   The y-coordinate of the end point on a cubic curve
400    */
401    void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
402                 SkScalar x3, SkScalar y3);
403
404    /** Add a cubic bezier from the last point, approaching control points p1
405        and p2, and ending at p3. If no moveTo() call has been made for this
406        contour, the first point is automatically set to (0,0).
407
408        @param p1   The 1st control point on a cubic curve
409        @param p2   The 2nd control point on a cubic curve
410        @param p3   The end point on a cubic curve
411    */
412    void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
413        this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
414    }
415
416    /** Same as cubicTo, but the coordinates are considered relative to the
417        current point on this contour. If there is no previous point, then a
418        moveTo(0,0) is inserted automatically.
419
420        @param dx1   The amount to add to the x-coordinate of the last point on
421                this contour, to specify the 1st control point of a cubic curve
422        @param dy1   The amount to add to the y-coordinate of the last point on
423                this contour, to specify the 1st control point of a cubic curve
424        @param dx2   The amount to add to the x-coordinate of the last point on
425                this contour, to specify the 2nd control point of a cubic curve
426        @param dy2   The amount to add to the y-coordinate of the last point on
427                this contour, to specify the 2nd control point of a cubic curve
428        @param dx3   The amount to add to the x-coordinate of the last point on
429                     this contour, to specify the end point of a cubic curve
430        @param dy3   The amount to add to the y-coordinate of the last point on
431                     this contour, to specify the end point of a cubic curve
432    */
433    void    rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
434                     SkScalar x3, SkScalar y3);
435
436    /** Append the specified arc to the path as a new contour. If the start of
437        the path is different from the path's current last point, then an
438        automatic lineTo() is added to connect the current contour to the start
439        of the arc. However, if the path is empty, then we call moveTo() with
440        the first point of the arc. The sweep angle is treated mod 360.
441
442        @param oval The bounding oval defining the shape and size of the arc
443        @param startAngle Starting angle (in degrees) where the arc begins
444        @param sweepAngle Sweep angle (in degrees) measured clockwise. This is
445                          treated mod 360.
446        @param forceMoveTo If true, always begin a new contour with the arc
447    */
448    void    arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
449                  bool forceMoveTo);
450
451    /** Append a line and arc to the current path. This is the same as the
452        PostScript call "arct".
453    */
454    void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
455               SkScalar radius);
456
457    /** Append a line and arc to the current path. This is the same as the
458        PostScript call "arct".
459    */
460    void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
461        this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
462    }
463
464    /** Close the current contour. If the current point is not equal to the
465        first point of the contour, a line segment is automatically added.
466    */
467    void close();
468
469    enum Direction {
470        /** clockwise direction for adding closed contours */
471        kCW_Direction,
472        /** counter-clockwise direction for adding closed contours */
473        kCCW_Direction
474    };
475
476    /**
477     *  Tries to quickly compute the direction of the first non-degenerate
478     *  contour. If it can be computed, return true and set dir to that
479     *  direction. If it cannot be (quickly) determined, return false and ignore
480     *  the dir parameter.
481     */
482    bool cheapComputeDirection(Direction* dir) const;
483
484    /**
485     *  Returns true if the path's direction can be computed via
486     *  cheapComputDirection() and if that computed direction matches the
487     *  specified direction.
488     */
489    bool cheapIsDirection(Direction dir) const {
490        Direction computedDir;
491        return this->cheapComputeDirection(&computedDir) && computedDir == dir;
492    }
493
494    /** Add a closed rectangle contour to the path
495        @param rect The rectangle to add as a closed contour to the path
496        @param dir  The direction to wind the rectangle's contour
497    */
498    void    addRect(const SkRect& rect, Direction dir = kCW_Direction);
499
500    /** Add a closed rectangle contour to the path
501
502        @param left     The left side of a rectangle to add as a closed contour
503                        to the path
504        @param top      The top of a rectangle to add as a closed contour to the
505                        path
506        @param right    The right side of a rectangle to add as a closed contour
507                        to the path
508        @param bottom   The bottom of a rectangle to add as a closed contour to
509                        the path
510        @param dir      The direction to wind the rectangle's contour
511    */
512    void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
513                 Direction dir = kCW_Direction);
514
515    /** Add a closed oval contour to the path
516
517        @param oval The bounding oval to add as a closed contour to the path
518        @param dir  The direction to wind the oval's contour
519    */
520    void addOval(const SkRect& oval, Direction dir = kCW_Direction);
521
522    /** Add a closed circle contour to the path
523
524        @param x        The x-coordinate of the center of a circle to add as a
525                        closed contour to the path
526        @param y        The y-coordinate of the center of a circle to add as a
527                        closed contour to the path
528        @param radius   The radius of a circle to add as a closed contour to the
529                        path
530        @param dir      The direction to wind the circle's contour
531    */
532    void addCircle(SkScalar x, SkScalar y, SkScalar radius,
533                   Direction dir = kCW_Direction);
534
535    /** Add the specified arc to the path as a new contour.
536
537        @param oval The bounds of oval used to define the size of the arc
538        @param startAngle Starting angle (in degrees) where the arc begins
539        @param sweepAngle Sweep angle (in degrees) measured clockwise
540    */
541    void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
542
543    /** Add a closed round-rectangle contour to the path
544        @param rect The bounds of a round-rectangle to add as a closed contour
545        @param rx   The x-radius of the rounded corners on the round-rectangle
546        @param ry   The y-radius of the rounded corners on the round-rectangle
547        @param dir  The direction to wind the round-rectangle's contour
548    */
549    void    addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
550                         Direction dir = kCW_Direction);
551
552    /** Add a closed round-rectangle contour to the path. Each corner receives
553        two radius values [X, Y]. The corners are ordered top-left, top-right,
554        bottom-right, bottom-left.
555        @param rect The bounds of a round-rectangle to add as a closed contour
556        @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner
557        @param dir  The direction to wind the round-rectangle's contour
558        */
559    void addRoundRect(const SkRect& rect, const SkScalar radii[],
560                      Direction dir = kCW_Direction);
561
562    /**
563     *  Add a new contour made of just lines. This is just a fast version of
564     *  the following:
565     *      this->moveTo(pts[0]);
566     *      for (int i = 1; i < count; ++i) {
567     *          this->lineTo(pts[i]);
568     *      }
569     *      if (close) {
570     *          this->close();
571     *      }
572     */
573    void addPoly(const SkPoint pts[], int count, bool close);
574
575    /** Add a copy of src to the path, offset by (dx,dy)
576        @param src  The path to add as a new contour
577        @param dx   The amount to translate the path in X as it is added
578        @param dx   The amount to translate the path in Y as it is added
579    */
580    void addPath(const SkPath& src, SkScalar dx, SkScalar dy);
581
582    /** Add a copy of src to the path
583    */
584    void addPath(const SkPath& src) {
585        SkMatrix m;
586        m.reset();
587        this->addPath(src, m);
588    }
589
590    /** Add a copy of src to the path, transformed by matrix
591        @param src  The path to add as a new contour
592    */
593    void addPath(const SkPath& src, const SkMatrix& matrix);
594
595    /**
596     *  Same as addPath(), but reverses the src input
597     */
598    void reverseAddPath(const SkPath& src);
599
600    /** Offset the path by (dx,dy), returning true on success
601
602        @param dx   The amount in the X direction to offset the entire path
603        @param dy   The amount in the Y direction to offset the entire path
604        @param dst  The translated path is written here
605    */
606    void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
607
608    /** Offset the path by (dx,dy), returning true on success
609
610        @param dx   The amount in the X direction to offset the entire path
611        @param dy   The amount in the Y direction to offset the entire path
612    */
613    void offset(SkScalar dx, SkScalar dy) {
614        this->offset(dx, dy, this);
615    }
616
617    /** Transform the points in this path by matrix, and write the answer into
618        dst.
619
620        @param matrix   The matrix to apply to the path
621        @param dst      The transformed path is written here
622    */
623    void transform(const SkMatrix& matrix, SkPath* dst) const;
624
625    /** Transform the points in this path by matrix
626
627        @param matrix The matrix to apply to the path
628    */
629    void transform(const SkMatrix& matrix) {
630        this->transform(matrix, this);
631    }
632
633    /** Return the last point on the path. If no points have been added, (0,0)
634        is returned. If there are no points, this returns false, otherwise it
635        returns true.
636
637        @param lastPt   The last point on the path is returned here
638    */
639    bool getLastPt(SkPoint* lastPt) const;
640
641    /** Set the last point on the path. If no points have been added,
642        moveTo(x,y) is automatically called.
643
644        @param x    The new x-coordinate for the last point
645        @param y    The new y-coordinate for the last point
646    */
647    void setLastPt(SkScalar x, SkScalar y);
648
649    /** Set the last point on the path. If no points have been added, moveTo(p)
650        is automatically called.
651
652        @param p    The new location for the last point
653    */
654    void setLastPt(const SkPoint& p) {
655        this->setLastPt(p.fX, p.fY);
656    }
657
658    enum SegmentMask {
659        kLine_SegmentMask   = 1 << 0,
660        kQuad_SegmentMask   = 1 << 1,
661        kCubic_SegmentMask  = 1 << 2
662    };
663
664    /**
665     *  Returns a mask, where each bit corresponding to a SegmentMask is
666     *  set if the path contains 1 or more segments of that type.
667     *  Returns 0 for an empty path (no segments).
668     */
669    uint32_t getSegmentMasks() const { return fSegmentMask; }
670
671    enum Verb {
672        kMove_Verb,     //!< iter.next returns 1 point
673        kLine_Verb,     //!< iter.next returns 2 points
674        kQuad_Verb,     //!< iter.next returns 3 points
675        kCubic_Verb,    //!< iter.next returns 4 points
676        kClose_Verb,    //!< iter.next returns 1 point (contour's moveTo pt)
677        kDone_Verb      //!< iter.next returns 0 points
678    };
679
680    /** Iterate through all of the segments (lines, quadratics, cubics) of
681        each contours in a path.
682
683        The iterator cleans up the segments along the way, removing degenerate
684        segments and adding close verbs where necessary. When the forceClose
685        argument is provided, each contour (as defined by a new starting
686        move command) will be completed with a close verb regardless of the
687        contour's contents.
688    */
689    class SK_API Iter {
690    public:
691        Iter();
692        Iter(const SkPath&, bool forceClose);
693
694        void setPath(const SkPath&, bool forceClose);
695
696        /** Return the next verb in this iteration of the path. When all
697            segments have been visited, return kDone_Verb.
698
699            @param  pts The points representing the current verb and/or segment
700            @param doConsumeDegerates If true, first scan for segments that are
701                   deemed degenerate (too short) and skip those.
702            @return The verb for the current segment
703        */
704        Verb next(SkPoint pts[4], bool doConsumeDegerates = true) {
705            if (doConsumeDegerates) {
706                this->consumeDegenerateSegments();
707            }
708            return this->doNext(pts);
709        }
710
711        /** If next() returns kLine_Verb, then this query returns true if the
712            line was the result of a close() command (i.e. the end point is the
713            initial moveto for this contour). If next() returned a different
714            verb, this returns an undefined value.
715
716            @return If the last call to next() returned kLine_Verb, return true
717                    if it was the result of an explicit close command.
718        */
719        bool isCloseLine() const { return SkToBool(fCloseLine); }
720
721        /** Returns true if the current contour is closed (has a kClose_Verb)
722            @return true if the current contour is closed (has a kClose_Verb)
723        */
724        bool isClosedContour() const;
725
726    private:
727        const SkPoint*  fPts;
728        const uint8_t*  fVerbs;
729        const uint8_t*  fVerbStop;
730        SkPoint         fMoveTo;
731        SkPoint         fLastPt;
732        SkBool8         fForceClose;
733        SkBool8         fNeedClose;
734        SkBool8         fCloseLine;
735        SkBool8         fSegmentState;
736
737        inline const SkPoint& cons_moveTo();
738        Verb autoClose(SkPoint pts[2]);
739        void consumeDegenerateSegments();
740        Verb doNext(SkPoint pts[4]);
741    };
742
743    /** Iterate through the verbs in the path, providing the associated points.
744    */
745    class SK_API RawIter {
746    public:
747        RawIter();
748        RawIter(const SkPath&);
749
750        void setPath(const SkPath&);
751
752        /** Return the next verb in this iteration of the path. When all
753            segments have been visited, return kDone_Verb.
754
755            @param  pts The points representing the current verb and/or segment
756                        This must not be NULL.
757            @return The verb for the current segment
758        */
759        Verb next(SkPoint pts[4]);
760
761    private:
762        const SkPoint*  fPts;
763        const uint8_t*  fVerbs;
764        const uint8_t*  fVerbStop;
765        SkPoint         fMoveTo;
766        SkPoint         fLastPt;
767    };
768
769    void dump(bool forceClose, const char title[] = NULL) const;
770    void dump() const;
771
772    void flatten(SkWriter32&) const;
773    void unflatten(SkReader32&);
774
775#ifdef SK_BUILD_FOR_ANDROID
776    uint32_t getGenerationID() const;
777    const SkPath* getSourcePath() const;
778    void setSourcePath(const SkPath* path);
779#endif
780
781    SkDEBUGCODE(void validate() const;)
782
783private:
784    SkTDArray<SkPoint>  fPts;
785    SkTDArray<uint8_t>  fVerbs;
786    mutable SkRect      fBounds;
787    int                 fLastMoveToIndex;
788    uint8_t             fFillType;
789    uint8_t             fSegmentMask;
790    mutable uint8_t     fBoundsIsDirty;
791    mutable uint8_t     fConvexity;
792
793    mutable SkBool8     fIsOval;
794#ifdef SK_BUILD_FOR_ANDROID
795    uint32_t            fGenerationID;
796    const SkPath*       fSourcePath;
797#endif
798
799    // called, if dirty, by getBounds()
800    void computeBounds() const;
801
802    friend class Iter;
803
804    friend class SkPathStroker;
805    /*  Append the first contour of path, ignoring path's initial point. If no
806        moveTo() call has been made for this contour, the first point is
807        automatically set to (0,0).
808    */
809    void pathTo(const SkPath& path);
810
811    /*  Append, in reverse order, the first contour of path, ignoring path's
812        last point. If no moveTo() call has been made for this contour, the
813        first point is automatically set to (0,0).
814    */
815    void reversePathTo(const SkPath&);
816
817    // called before we add points for lineTo, quadTo, cubicTo, checking to see
818    // if we need to inject a leading moveTo first
819    //
820    //  SkPath path; path.lineTo(...);   <--- need a leading moveTo(0, 0)
821    // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo)
822    //
823    inline void injectMoveToIfNeeded();
824
825    inline bool hasOnlyMoveTos() const;
826
827    friend class SkAutoPathBoundsUpdate;
828    friend class SkAutoDisableOvalCheck;
829};
830
831#endif
832