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