SkPath.h revision b3eb687f8a89eb1eacd1afb4016401eb392f66ab
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    /** Returns true if the path specifies a rectangle. If so, and if rect is
243        not null, set rect to the bounds of the path. If the path does not
244        specify a rectangle, return false and ignore rect.
245
246        @param rect If not null, returns the bounds of the path if it specifies
247                    a rectangle
248        @return true if the path specifies a rectangle
249    */
250    bool isRect(SkRect* rect) const;
251
252    /** Return the number of points in the path
253     */
254    int countPoints() const;
255
256    /** Return the point at the specified index. If the index is out of range
257         (i.e. is not 0 <= index < countPoints()) then the returned coordinates
258         will be (0,0)
259     */
260    SkPoint getPoint(int index) const;
261
262    /** Returns the number of points in the path. Up to max points are copied.
263
264        @param points If not null, receives up to max points
265        @param max The maximum number of points to copy into points
266        @return the actual number of points in the path
267    */
268    int getPoints(SkPoint points[], int max) const;
269
270    /** Return the number of verbs in the path
271     */
272    int countVerbs() const;
273
274    /** Returns the number of verbs in the path. Up to max verbs are copied. The
275        verbs are copied as one byte per verb.
276
277        @param verbs If not null, receives up to max verbs
278        @param max The maximum number of verbs to copy into verbs
279        @return the actual number of verbs in the path
280    */
281    int getVerbs(uint8_t verbs[], int max) const;
282
283    //! Swap contents of this and other. Guaranteed not to throw
284    void swap(SkPath& other);
285
286    /** Returns the bounds of the path's points. If the path contains 0 or 1
287        points, the bounds is set to (0,0,0,0), and isEmpty() will return true.
288        Note: this bounds may be larger than the actual shape, since curves
289        do not extend as far as their control points.
290    */
291    const SkRect& getBounds() const {
292        return fPathRef->getBounds();
293    }
294
295    /** Calling this will, if the internal cache of the bounds is out of date,
296        update it so that subsequent calls to getBounds will be instantaneous.
297        This also means that any copies or simple transformations of the path
298        will inherit the cached bounds.
299     */
300    void updateBoundsCache() const {
301        // for now, just calling getBounds() is sufficient
302        this->getBounds();
303    }
304
305    /**
306     * Does a conservative test to see whether a rectangle is inside a path. Currently it only
307     * will ever return true for single convex contour paths. The empty-status of the rect is not
308     * considered (e.g. a rect that is a point can be inside a path). Points or line segments where
309     * the rect edge touches the path border are not considered containment violations.
310     */
311    bool conservativelyContainsRect(const SkRect& rect) const;
312
313    //  Construction methods
314
315    /** Hint to the path to prepare for adding more points. This can allow the
316        path to more efficiently grow its storage.
317
318        @param extraPtCount The number of extra points the path should
319                            preallocate for.
320    */
321    void incReserve(unsigned extraPtCount);
322
323    /** Set the beginning of the next contour to the point (x,y).
324
325        @param x    The x-coordinate of the start of a new contour
326        @param y    The y-coordinate of the start of a new contour
327    */
328    void moveTo(SkScalar x, SkScalar y);
329
330    /** Set the beginning of the next contour to the point
331
332        @param p    The start of a new contour
333    */
334    void moveTo(const SkPoint& p) {
335        this->moveTo(p.fX, p.fY);
336    }
337
338    /** Set the beginning of the next contour relative to the last point on the
339        previous contour. If there is no previous contour, this is treated the
340        same as moveTo().
341
342        @param dx   The amount to add to the x-coordinate of the end of the
343                    previous contour, to specify the start of a new contour
344        @param dy   The amount to add to the y-coordinate of the end of the
345                    previous contour, to specify the start of a new contour
346    */
347    void rMoveTo(SkScalar dx, SkScalar dy);
348
349    /** Add a line from the last point to the specified point (x,y). If no
350        moveTo() call has been made for this contour, the first point is
351        automatically set to (0,0).
352
353        @param x    The x-coordinate of the end of a line
354        @param y    The y-coordinate of the end of a line
355    */
356    void lineTo(SkScalar x, SkScalar y);
357
358    /** Add a line from the last point to the specified point. If no moveTo()
359        call has been made for this contour, the first point is automatically
360        set to (0,0).
361
362        @param p    The end of a line
363    */
364    void lineTo(const SkPoint& p) {
365        this->lineTo(p.fX, p.fY);
366    }
367
368    /** Same as lineTo, but the coordinates are considered relative to the last
369        point on this contour. If there is no previous point, then a moveTo(0,0)
370        is inserted automatically.
371
372        @param dx   The amount to add to the x-coordinate of the previous point
373                    on this contour, to specify a line
374        @param dy   The amount to add to the y-coordinate of the previous point
375                    on this contour, to specify a line
376    */
377    void rLineTo(SkScalar dx, SkScalar dy);
378
379    /** Add a quadratic bezier from the last point, approaching control point
380        (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
381        this contour, the first point is automatically set to (0,0).
382
383        @param x1   The x-coordinate of the control point on a quadratic curve
384        @param y1   The y-coordinate of the control point on a quadratic curve
385        @param x2   The x-coordinate of the end point on a quadratic curve
386        @param y2   The y-coordinate of the end point on a quadratic curve
387    */
388    void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
389
390    /** Add a quadratic bezier from the last point, approaching control point
391        p1, and ending at p2. If no moveTo() call has been made for this
392        contour, the first point is automatically set to (0,0).
393
394        @param p1   The control point on a quadratic curve
395        @param p2   The end point on a quadratic curve
396    */
397    void quadTo(const SkPoint& p1, const SkPoint& p2) {
398        this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
399    }
400
401    /** Same as quadTo, but the coordinates are considered relative to the last
402        point on this contour. If there is no previous point, then a moveTo(0,0)
403        is inserted automatically.
404
405        @param dx1   The amount to add to the x-coordinate of the last point on
406                this contour, to specify the control point of a quadratic curve
407        @param dy1   The amount to add to the y-coordinate of the last point on
408                this contour, to specify the control point of a quadratic curve
409        @param dx2   The amount to add to the x-coordinate of the last point on
410                     this contour, to specify the end point of a quadratic curve
411        @param dy2   The amount to add to the y-coordinate of the last point on
412                     this contour, to specify the end point of a quadratic curve
413    */
414    void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
415
416    void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
417                 SkScalar w);
418    void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) {
419        this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w);
420    }
421    void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
422                  SkScalar w);
423
424    /** Add a cubic bezier from the last point, approaching control points
425        (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
426        made for this contour, the first point is automatically set to (0,0).
427
428        @param x1   The x-coordinate of the 1st control point on a cubic curve
429        @param y1   The y-coordinate of the 1st control point on a cubic curve
430        @param x2   The x-coordinate of the 2nd control point on a cubic curve
431        @param y2   The y-coordinate of the 2nd control point on a cubic curve
432        @param x3   The x-coordinate of the end point on a cubic curve
433        @param y3   The y-coordinate of the end point on a cubic curve
434    */
435    void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
436                 SkScalar x3, SkScalar y3);
437
438    /** Add a cubic bezier from the last point, approaching control points p1
439        and p2, and ending at p3. If no moveTo() call has been made for this
440        contour, the first point is automatically set to (0,0).
441
442        @param p1   The 1st control point on a cubic curve
443        @param p2   The 2nd control point on a cubic curve
444        @param p3   The end point on a cubic curve
445    */
446    void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
447        this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
448    }
449
450    /** Same as cubicTo, but the coordinates are considered relative to the
451        current point on this contour. If there is no previous point, then a
452        moveTo(0,0) is inserted automatically.
453
454        @param dx1   The amount to add to the x-coordinate of the last point on
455                this contour, to specify the 1st control point of a cubic curve
456        @param dy1   The amount to add to the y-coordinate of the last point on
457                this contour, to specify the 1st control point of a cubic curve
458        @param dx2   The amount to add to the x-coordinate of the last point on
459                this contour, to specify the 2nd control point of a cubic curve
460        @param dy2   The amount to add to the y-coordinate of the last point on
461                this contour, to specify the 2nd control point of a cubic curve
462        @param dx3   The amount to add to the x-coordinate of the last point on
463                     this contour, to specify the end point of a cubic curve
464        @param dy3   The amount to add to the y-coordinate of the last point on
465                     this contour, to specify the end point of a cubic curve
466    */
467    void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
468                  SkScalar x3, SkScalar y3);
469
470    /** Append the specified arc to the path as a new contour. If the start of
471        the path is different from the path's current last point, then an
472        automatic lineTo() is added to connect the current contour to the start
473        of the arc. However, if the path is empty, then we call moveTo() with
474        the first point of the arc. The sweep angle is treated mod 360.
475
476        @param oval The bounding oval defining the shape and size of the arc
477        @param startAngle Starting angle (in degrees) where the arc begins
478        @param sweepAngle Sweep angle (in degrees) measured clockwise. This is
479                          treated mod 360.
480        @param forceMoveTo If true, always begin a new contour with the arc
481    */
482    void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
483               bool forceMoveTo);
484
485    /** Append a line and arc to the current path. This is the same as the
486        PostScript call "arct".
487    */
488    void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
489               SkScalar radius);
490
491    /** Append a line and arc to the current path. This is the same as the
492        PostScript call "arct".
493    */
494    void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
495        this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
496    }
497
498    /** Close the current contour. If the current point is not equal to the
499        first point of the contour, a line segment is automatically added.
500    */
501    void close();
502
503    enum Direction {
504        /** Direction either has not been or could not be computed */
505        kUnknown_Direction,
506        /** clockwise direction for adding closed contours */
507        kCW_Direction,
508        /** counter-clockwise direction for adding closed contours */
509        kCCW_Direction,
510    };
511
512    /**
513     *  Return the opposite of the specified direction. kUnknown is its own
514     *  opposite.
515     */
516    static Direction OppositeDirection(Direction dir) {
517        static const Direction gOppositeDir[] = {
518            kUnknown_Direction, kCCW_Direction, kCW_Direction
519        };
520        return gOppositeDir[dir];
521    }
522
523    /**
524     *  Returns whether or not a fill type is inverted
525     *
526     *  kWinding_FillType        -> false
527     *  kEvenOdd_FillType        -> false
528     *  kInverseWinding_FillType -> true
529     *  kInverseEvenOdd_FillType -> true
530     */
531    static bool IsInverseFillType(FillType fill) {
532        SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch);
533        SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch);
534        SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch);
535        SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch);
536        return (fill & 2) != 0;
537    }
538
539    /**
540     *  Returns the equivalent non-inverted fill type to the given fill type
541     *
542     *  kWinding_FillType        -> kWinding_FillType
543     *  kEvenOdd_FillType        -> kEvenOdd_FillType
544     *  kInverseWinding_FillType -> kWinding_FillType
545     *  kInverseEvenOdd_FillType -> kEvenOdd_FillType
546     */
547    static FillType ConvertToNonInverseFillType(FillType fill) {
548        SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch);
549        SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch);
550        SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch);
551        SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch);
552        return (FillType)(fill & 1);
553    }
554
555    /**
556     *  Tries to quickly compute the direction of the first non-degenerate
557     *  contour. If it can be computed, return true and set dir to that
558     *  direction. If it cannot be (quickly) determined, return false and ignore
559     *  the dir parameter. If the direction was determined, it is cached to make
560     *  subsequent calls return quickly.
561     */
562    bool cheapComputeDirection(Direction* dir) const;
563
564    /**
565     *  Returns true if the path's direction can be computed via
566     *  cheapComputDirection() and if that computed direction matches the
567     *  specified direction. If dir is kUnknown, returns true if the direction
568     *  cannot be computed.
569     */
570    bool cheapIsDirection(Direction dir) const {
571        Direction computedDir = kUnknown_Direction;
572        (void)this->cheapComputeDirection(&computedDir);
573        return computedDir == dir;
574    }
575
576    enum PathAsRect {
577        /** The path can not draw the same as its bounds. */
578        kNone_PathAsRect,
579        /** The path draws the same as its bounds when filled. */
580        kFill_PathAsRect,
581        /** The path draws the same as its bounds when stroked or filled. */
582        kStroke_PathAsRect,
583    };
584
585    /** Returns kFill_PathAsRect or kStroke_PathAsRect if drawing the path (either filled or
586        stroked) will be equivalent to filling/stroking the path's bounding rect. If
587        either is true, and direction is not null, sets the direction of the contour. If the
588        path is not drawn equivalent to a rect, returns kNone_PathAsRect and ignores direction.
589
590        @param direction If not null, set to the contour's direction when it is drawn as a rect
591        @return the path's PathAsRect type
592     */
593    PathAsRect asRect(Direction* direction = NULL) const;
594
595    /** Returns true if the path specifies a rectangle. If so, and if isClosed is
596        not null, set isClosed to true if the path is closed. Also, if returning true
597        and direction is not null, return the rect direction. If the path does not
598        specify a rectangle, return false and ignore isClosed and direction.
599
600        @param isClosed If not null, set to true if the path is closed
601        @param direction If not null, set to the rectangle's direction
602        @return true if the path specifies a rectangle
603    */
604    bool isRect(bool* isClosed, Direction* direction) const;
605
606    /** Returns true if the path specifies a pair of nested rectangles. If so, and if
607        rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner
608        rectangle. If so, and dirs is not null, set dirs[0] to the direction of
609        the outer rectangle and dirs[1] to the direction of the inner rectangle. If
610        the path does not specify a pair of nested rectangles, return
611        false and ignore rect and dirs.
612
613        @param rect If not null, returns the path as a pair of nested rectangles
614        @param dirs If not null, returns the direction of the rects
615        @return true if the path describes a pair of nested rectangles
616    */
617    bool isNestedRects(SkRect rect[2], Direction dirs[2] = NULL) const;
618
619    /**
620     *  Add a closed rectangle contour to the path
621     *  @param rect The rectangle to add as a closed contour to the path
622     *  @param dir  The direction to wind the rectangle's contour. Cannot be
623     *              kUnknown_Direction.
624     */
625    void addRect(const SkRect& rect, Direction dir = kCW_Direction);
626
627    /**
628     *  Add a closed rectangle contour to the path
629     *
630     *  @param left     The left side of a rectangle to add as a closed contour
631     *                  to the path
632     *  @param top      The top of a rectangle to add as a closed contour to the
633     *                  path
634     *  @param right    The right side of a rectangle to add as a closed contour
635     *                  to the path
636     *  @param bottom   The bottom of a rectangle to add as a closed contour to
637     *                  the path
638     *  @param dir  The direction to wind the rectangle's contour. Cannot be
639     *              kUnknown_Direction.
640     */
641    void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
642                 Direction dir = kCW_Direction);
643
644    /**
645     *  Add a closed oval contour to the path
646     *
647     *  @param oval The bounding oval to add as a closed contour to the path
648     *  @param dir  The direction to wind the oval's contour. Cannot be
649     *              kUnknown_Direction.
650     */
651    void addOval(const SkRect& oval, Direction dir = kCW_Direction);
652
653    /**
654     *  Add a closed circle contour to the path
655     *
656     *  @param x        The x-coordinate of the center of a circle to add as a
657     *                  closed contour to the path
658     *  @param y        The y-coordinate of the center of a circle to add as a
659     *                  closed contour to the path
660     *  @param radius   The radius of a circle to add as a closed contour to the
661     *                  path
662     *  @param dir  The direction to wind the circle's contour. Cannot be
663     *              kUnknown_Direction.
664     */
665    void addCircle(SkScalar x, SkScalar y, SkScalar radius,
666                   Direction dir = kCW_Direction);
667
668    /** Add the specified arc to the path as a new contour.
669
670        @param oval The bounds of oval used to define the size of the arc
671        @param startAngle Starting angle (in degrees) where the arc begins
672        @param sweepAngle Sweep angle (in degrees) measured clockwise
673    */
674    void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
675
676    /**
677     *  Add a closed round-rectangle contour to the path
678     *  @param rect The bounds of a round-rectangle to add as a closed contour
679     *  @param rx   The x-radius of the rounded corners on the round-rectangle
680     *  @param ry   The y-radius of the rounded corners on the round-rectangle
681     *  @param dir  The direction to wind the rectangle's contour. Cannot be
682     *              kUnknown_Direction.
683     */
684    void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
685                      Direction dir = kCW_Direction);
686
687    /**
688     *  Add a closed round-rectangle contour to the path. Each corner receives
689     *  two radius values [X, Y]. The corners are ordered top-left, top-right,
690     *  bottom-right, bottom-left.
691     *  @param rect The bounds of a round-rectangle to add as a closed contour
692     *  @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner
693     *  @param dir  The direction to wind the rectangle's contour. Cannot be
694     *              kUnknown_Direction.
695     * Note: The radii here now go through the same constraint handling as the
696     *       SkRRect radii (i.e., either radii at a corner being 0 implies a
697     *       sqaure corner and oversized radii are proportionally scaled down).
698     */
699    void addRoundRect(const SkRect& rect, const SkScalar radii[],
700                      Direction dir = kCW_Direction);
701
702    /**
703     *  Add an SkRRect contour to the path
704     *  @param rrect The rounded rect to add as a closed contour
705     *  @param dir   The winding direction for the new contour. Cannot be
706     *               kUnknown_Direction.
707     */
708    void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction);
709
710    /**
711     *  Add a new contour made of just lines. This is just a fast version of
712     *  the following:
713     *      this->moveTo(pts[0]);
714     *      for (int i = 1; i < count; ++i) {
715     *          this->lineTo(pts[i]);
716     *      }
717     *      if (close) {
718     *          this->close();
719     *      }
720     */
721    void addPoly(const SkPoint pts[], int count, bool close);
722
723    enum AddPathMode {
724        /** Source path contours are added as new contours.
725        */
726        kAppend_AddPathMode,
727        /** Path is added by extending the last contour of the destination path
728            with the first contour of the source path. If the last contour of
729            the destination path is closed, then it will not be extended.
730            Instead, the start of source path will be extended by a straight
731            line to the end point of the destination path.
732        */
733        kExtend_AddPathMode
734    };
735
736    /** Add a copy of src to the path, offset by (dx,dy)
737        @param src  The path to add as a new contour
738        @param dx   The amount to translate the path in X as it is added
739        @param dx   The amount to translate the path in Y as it is added
740    */
741    void addPath(const SkPath& src, SkScalar dx, SkScalar dy,
742                 AddPathMode mode = kAppend_AddPathMode);
743
744    /** Add a copy of src to the path
745    */
746    void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) {
747        SkMatrix m;
748        m.reset();
749        this->addPath(src, m, mode);
750    }
751
752    /** Add a copy of src to the path, transformed by matrix
753        @param src  The path to add as a new contour
754        @param matrix  Transform applied to src
755        @param mode  Determines how path is added
756    */
757    void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode);
758
759    /**
760     *  Same as addPath(), but reverses the src input
761     */
762    void reverseAddPath(const SkPath& src);
763
764    /** Offset the path by (dx,dy), returning true on success
765
766        @param dx   The amount in the X direction to offset the entire path
767        @param dy   The amount in the Y direction to offset the entire path
768        @param dst  The translated path is written here
769    */
770    void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
771
772    /** Offset the path by (dx,dy), returning true on success
773
774        @param dx   The amount in the X direction to offset the entire path
775        @param dy   The amount in the Y direction to offset the entire path
776    */
777    void offset(SkScalar dx, SkScalar dy) {
778        this->offset(dx, dy, this);
779    }
780
781    /** Transform the points in this path by matrix, and write the answer into
782        dst.
783
784        @param matrix   The matrix to apply to the path
785        @param dst      The transformed path is written here
786    */
787    void transform(const SkMatrix& matrix, SkPath* dst) const;
788
789    /** Transform the points in this path by matrix
790
791        @param matrix The matrix to apply to the path
792    */
793    void transform(const SkMatrix& matrix) {
794        this->transform(matrix, this);
795    }
796
797    /** Return the last point on the path. If no points have been added, (0,0)
798        is returned. If there are no points, this returns false, otherwise it
799        returns true.
800
801        @param lastPt   The last point on the path is returned here
802    */
803    bool getLastPt(SkPoint* lastPt) const;
804
805    /** Set the last point on the path. If no points have been added,
806        moveTo(x,y) is automatically called.
807
808        @param x    The new x-coordinate for the last point
809        @param y    The new y-coordinate for the last point
810    */
811    void setLastPt(SkScalar x, SkScalar y);
812
813    /** Set the last point on the path. If no points have been added, moveTo(p)
814        is automatically called.
815
816        @param p    The new location for the last point
817    */
818    void setLastPt(const SkPoint& p) {
819        this->setLastPt(p.fX, p.fY);
820    }
821
822    enum SegmentMask {
823        kLine_SegmentMask   = 1 << 0,
824        kQuad_SegmentMask   = 1 << 1,
825        kConic_SegmentMask  = 1 << 2,
826        kCubic_SegmentMask  = 1 << 3,
827    };
828
829    /**
830     *  Returns a mask, where each bit corresponding to a SegmentMask is
831     *  set if the path contains 1 or more segments of that type.
832     *  Returns 0 for an empty path (no segments).
833     */
834    uint32_t getSegmentMasks() const { return fPathRef->getSegmentMasks(); }
835
836    enum Verb {
837        kMove_Verb,     //!< iter.next returns 1 point
838        kLine_Verb,     //!< iter.next returns 2 points
839        kQuad_Verb,     //!< iter.next returns 3 points
840        kConic_Verb,    //!< iter.next returns 3 points + iter.conicWeight()
841        kCubic_Verb,    //!< iter.next returns 4 points
842        kClose_Verb,    //!< iter.next returns 1 point (contour's moveTo pt)
843        kDone_Verb,     //!< iter.next returns 0 points
844    };
845
846    /** Iterate through all of the segments (lines, quadratics, cubics) of
847        each contours in a path.
848
849        The iterator cleans up the segments along the way, removing degenerate
850        segments and adding close verbs where necessary. When the forceClose
851        argument is provided, each contour (as defined by a new starting
852        move command) will be completed with a close verb regardless of the
853        contour's contents.
854    */
855    class SK_API Iter {
856    public:
857        Iter();
858        Iter(const SkPath&, bool forceClose);
859
860        void setPath(const SkPath&, bool forceClose);
861
862        /** Return the next verb in this iteration of the path. When all
863            segments have been visited, return kDone_Verb.
864
865            @param  pts The points representing the current verb and/or segment
866            @param doConsumeDegerates If true, first scan for segments that are
867                   deemed degenerate (too short) and skip those.
868            @return The verb for the current segment
869        */
870        Verb next(SkPoint pts[4], bool doConsumeDegerates = true) {
871            if (doConsumeDegerates) {
872                this->consumeDegenerateSegments();
873            }
874            return this->doNext(pts);
875        }
876
877        /**
878         *  Return the weight for the current conic. Only valid if the current
879         *  segment return by next() was a conic.
880         */
881        SkScalar conicWeight() const { return *fConicWeights; }
882
883        /** If next() returns kLine_Verb, then this query returns true if the
884            line was the result of a close() command (i.e. the end point is the
885            initial moveto for this contour). If next() returned a different
886            verb, this returns an undefined value.
887
888            @return If the last call to next() returned kLine_Verb, return true
889                    if it was the result of an explicit close command.
890        */
891        bool isCloseLine() const { return SkToBool(fCloseLine); }
892
893        /** Returns true if the current contour is closed (has a kClose_Verb)
894            @return true if the current contour is closed (has a kClose_Verb)
895        */
896        bool isClosedContour() const;
897
898    private:
899        const SkPoint*  fPts;
900        const uint8_t*  fVerbs;
901        const uint8_t*  fVerbStop;
902        const SkScalar* fConicWeights;
903        SkPoint         fMoveTo;
904        SkPoint         fLastPt;
905        SkBool8         fForceClose;
906        SkBool8         fNeedClose;
907        SkBool8         fCloseLine;
908        SkBool8         fSegmentState;
909
910        inline const SkPoint& cons_moveTo();
911        Verb autoClose(SkPoint pts[2]);
912        void consumeDegenerateSegments();
913        Verb doNext(SkPoint pts[4]);
914    };
915
916    /** Iterate through the verbs in the path, providing the associated points.
917    */
918    class SK_API RawIter {
919    public:
920        RawIter();
921        RawIter(const SkPath&);
922
923        void setPath(const SkPath&);
924
925        /** Return the next verb in this iteration of the path. When all
926            segments have been visited, return kDone_Verb.
927
928            @param  pts The points representing the current verb and/or segment
929                        This must not be NULL.
930            @return The verb for the current segment
931        */
932        Verb next(SkPoint pts[4]);
933
934        SkScalar conicWeight() const { return *fConicWeights; }
935
936    private:
937        const SkPoint*  fPts;
938        const uint8_t*  fVerbs;
939        const uint8_t*  fVerbStop;
940        const SkScalar* fConicWeights;
941        SkPoint         fMoveTo;
942        SkPoint         fLastPt;
943    };
944
945    /**
946     *  Returns true if the point { x, y } is contained by the path, taking into
947     *  account the FillType.
948     */
949    bool contains(SkScalar x, SkScalar y) const;
950
951    void dump(SkWStream* , bool forceClose, bool dumpAsHex) const;
952    void dump() const;
953    void dumpHex() const;
954
955    /**
956     *  Write the path to the buffer, and return the number of bytes written.
957     *  If buffer is NULL, it still returns the number of bytes.
958     */
959    size_t writeToMemory(void* buffer) const;
960    /**
961     * Initializes the path from the buffer
962     *
963     * @param buffer Memory to read from
964     * @param length Amount of memory available in the buffer
965     * @return number of bytes read (must be a multiple of 4) or
966     *         0 if there was not enough memory available
967     */
968    size_t readFromMemory(const void* buffer, size_t length);
969
970    /** Returns a non-zero, globally unique value corresponding to the set of verbs
971        and points in the path (but not the fill type [except on Android skbug.com/1762]).
972        Each time the path is modified, a different generation ID will be returned.
973    */
974    uint32_t getGenerationID() const;
975
976#ifdef SK_BUILD_FOR_ANDROID
977    static const int kPathRefGenIDBitCnt = 30; // leave room for the fill type (skbug.com/1762)
978    const SkPath* getSourcePath() const;
979    void setSourcePath(const SkPath* path);
980#else
981    static const int kPathRefGenIDBitCnt = 32;
982#endif
983
984    SkDEBUGCODE(void validate() const;)
985
986private:
987    enum SerializationOffsets {
988        // 1 free bit at 29
989        kUnused1_SerializationShift = 28,    // 1 free bit
990        kDirection_SerializationShift = 26, // requires 2 bits
991        kIsVolatile_SerializationShift = 25, // requires 1 bit
992        // 1 free bit at 24
993        kConvexity_SerializationShift = 16, // requires 8 bits
994        kFillType_SerializationShift = 8,   // requires 8 bits
995        // 8 free bits at 0
996    };
997
998    SkAutoTUnref<SkPathRef> fPathRef;
999
1000    int                 fLastMoveToIndex;
1001    uint8_t             fFillType;
1002    mutable uint8_t     fConvexity;
1003    mutable uint8_t     fDirection;
1004    mutable SkBool8     fIsVolatile;
1005#ifdef SK_BUILD_FOR_ANDROID
1006    const SkPath*       fSourcePath;
1007#endif
1008
1009    /** Resets all fields other than fPathRef to their initial 'empty' values.
1010     *  Assumes the caller has already emptied fPathRef.
1011     *  On Android increments fGenerationID without reseting it.
1012     */
1013    void resetFields();
1014
1015    /** Sets all fields other than fPathRef to the values in 'that'.
1016     *  Assumes the caller has already set fPathRef.
1017     *  Doesn't change fGenerationID or fSourcePath on Android.
1018     */
1019    void copyFields(const SkPath& that);
1020
1021    friend class Iter;
1022
1023    friend class SkPathStroker;
1024
1025    /*  Append, in reverse order, the first contour of path, ignoring path's
1026        last point. If no moveTo() call has been made for this contour, the
1027        first point is automatically set to (0,0).
1028    */
1029    void reversePathTo(const SkPath&);
1030
1031    // called before we add points for lineTo, quadTo, cubicTo, checking to see
1032    // if we need to inject a leading moveTo first
1033    //
1034    //  SkPath path; path.lineTo(...);   <--- need a leading moveTo(0, 0)
1035    // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo)
1036    //
1037    inline void injectMoveToIfNeeded();
1038
1039    inline bool hasOnlyMoveTos() const;
1040
1041    Convexity internalGetConvexity() const;
1042
1043    bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts,
1044                       bool* isClosed, Direction* direction) const;
1045
1046    /** Returns if the path can return a bound at no cost (true) or will have to
1047        perform some computation (false).
1048     */
1049    bool hasComputedBounds() const {
1050        SkDEBUGCODE(this->validate();)
1051        return fPathRef->hasComputedBounds();
1052    }
1053
1054
1055    // 'rect' needs to be sorted
1056    void setBounds(const SkRect& rect) {
1057        SkPathRef::Editor ed(&fPathRef);
1058
1059        ed.setBounds(rect);
1060    }
1061
1062    friend class SkAutoPathBoundsUpdate;
1063    friend class SkAutoDisableOvalCheck;
1064    friend class SkAutoDisableDirectionCheck;
1065    friend class SkBench_AddPathTest; // perf test reversePathTo
1066    friend class PathTest_Private; // unit test reversePathTo
1067};
1068
1069#endif
1070