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