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