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