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