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