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