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