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