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