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