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