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    /** 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    */
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    */
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    */
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     */
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    */
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     */
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    */
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    */
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    */
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    */
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    */
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     */
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    */
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    */
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    */
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    */
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     */
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        */
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
741private:
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