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