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