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