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