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