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