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