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