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