| /* | |
| * Copyright 2006 The Android Open Source Project | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef SkPath_DEFINED | |
| #define SkPath_DEFINED | |
| #include "SkInstCnt.h" | |
| #include "SkMatrix.h" | |
| #include "SkPathRef.h" | |
| #include "SkTDArray.h" | |
| #include "SkRefCnt.h" | |
| class SkReader32; | |
| class SkWriter32; | |
| class SkAutoPathBoundsUpdate; | |
| class SkString; | |
| class SkRRect; | |
| class SkWStream; | |
| /** \class SkPath | |
| The SkPath class encapsulates compound (multiple contour) geometric paths | |
| consisting of straight line segments, quadratic curves, and cubic curves. | |
| */ | |
| class SK_API SkPath { | |
| public: | |
| SK_DECLARE_INST_COUNT_ROOT(SkPath); | |
| SkPath(); | |
| SkPath(const SkPath&); | |
| ~SkPath(); | |
| SkPath& operator=(const SkPath&); | |
| friend SK_API bool operator==(const SkPath&, const SkPath&); | |
| friend bool operator!=(const SkPath& a, const SkPath& b) { | |
| return !(a == b); | |
| } | |
| enum FillType { | |
| /** Specifies that "inside" is computed by a non-zero sum of signed | |
| edge crossings | |
| */ | |
| kWinding_FillType, | |
| /** Specifies that "inside" is computed by an odd number of edge | |
| crossings | |
| */ | |
| kEvenOdd_FillType, | |
| /** Same as Winding, but draws outside of the path, rather than inside | |
| */ | |
| kInverseWinding_FillType, | |
| /** Same as EvenOdd, but draws outside of the path, rather than inside | |
| */ | |
| kInverseEvenOdd_FillType | |
| }; | |
| /** Return the path's fill type. This is used to define how "inside" is | |
| computed. The default value is kWinding_FillType. | |
| @return the path's fill type | |
| */ | |
| FillType getFillType() const { return (FillType)fFillType; } | |
| /** Set the path's fill type. This is used to define how "inside" is | |
| computed. The default value is kWinding_FillType. | |
| @param ft The new fill type for this path | |
| */ | |
| void setFillType(FillType ft) { | |
| fFillType = SkToU8(ft); | |
| } | |
| /** Returns true if the filltype is one of the Inverse variants */ | |
| bool isInverseFillType() const { return IsInverseFillType((FillType)fFillType); } | |
| /** | |
| * Toggle between inverse and normal filltypes. This reverse the return | |
| * value of isInverseFillType() | |
| */ | |
| void toggleInverseFillType() { | |
| fFillType ^= 2; | |
| } | |
| enum Convexity { | |
| kUnknown_Convexity, | |
| kConvex_Convexity, | |
| kConcave_Convexity | |
| }; | |
| /** | |
| * Return the path's convexity, as stored in the path. If it is currently unknown, | |
| * then this function will attempt to compute the convexity (and cache the result). | |
| */ | |
| Convexity getConvexity() const { | |
| if (kUnknown_Convexity != fConvexity) { | |
| return static_cast<Convexity>(fConvexity); | |
| } else { | |
| return this->internalGetConvexity(); | |
| } | |
| } | |
| /** | |
| * Return the currently cached value for convexity, even if that is set to | |
| * kUnknown_Convexity. Note: getConvexity() will automatically call | |
| * ComputeConvexity and cache its return value if the current setting is | |
| * kUnknown. | |
| */ | |
| Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; } | |
| /** | |
| * Store a convexity setting in the path. There is no automatic check to | |
| * see if this value actually agrees with the return value that would be | |
| * computed by getConvexity(). | |
| * | |
| * Note: even if this is set to a "known" value, if the path is later | |
| * changed (e.g. lineTo(), addRect(), etc.) then the cached value will be | |
| * reset to kUnknown_Convexity. | |
| */ | |
| void setConvexity(Convexity); | |
| /** | |
| * Returns true if the path is flagged as being convex. This is not a | |
| * confirmed by any analysis, it is just the value set earlier. | |
| */ | |
| bool isConvex() const { | |
| return kConvex_Convexity == this->getConvexity(); | |
| } | |
| /** | |
| * Set the isConvex flag to true or false. Convex paths may draw faster if | |
| * this flag is set, though setting this to true on a path that is in fact | |
| * not convex can give undefined results when drawn. Paths default to | |
| * isConvex == false | |
| */ | |
| SK_ATTR_DEPRECATED("use setConvexity") | |
| void setIsConvex(bool isConvex) { | |
| this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity); | |
| } | |
| /** Returns true if the path is an oval. | |
| * | |
| * @param rect returns the bounding rect of this oval. It's a circle | |
| * if the height and width are the same. | |
| * | |
| * @return true if this path is an oval. | |
| * Tracking whether a path is an oval is considered an | |
| * optimization for performance and so some paths that are in | |
| * fact ovals can report false. | |
| */ | |
| bool isOval(SkRect* rect) const { return fPathRef->isOval(rect); } | |
| /** Clear any lines and curves from the path, making it empty. This frees up | |
| internal storage associated with those segments. | |
| On Android, does not change fSourcePath. | |
| */ | |
| void reset(); | |
| /** Similar to reset(), in that all lines and curves are removed from the | |
| path. However, any internal storage for those lines/curves is retained, | |
| making reuse of the path potentially faster. | |
| On Android, does not change fSourcePath. | |
| */ | |
| void rewind(); | |
| /** Returns true if the path is empty (contains no lines or curves) | |
| @return true if the path is empty (contains no lines or curves) | |
| */ | |
| bool isEmpty() const { | |
| SkDEBUGCODE(this->validate();) | |
| return 0 == fPathRef->countVerbs(); | |
| } | |
| /** | |
| * Returns true if all of the points in this path are finite, meaning there | |
| * are no infinities and no NaNs. | |
| */ | |
| bool isFinite() const { | |
| SkDEBUGCODE(this->validate();) | |
| return fPathRef->isFinite(); | |
| } | |
| /** Returns true if the path is volatile (i.e. should not be cached by devices.) | |
| */ | |
| bool isVolatile() const { | |
| return SkToBool(fIsVolatile); | |
| } | |
| /** Specify whether this path is volatile. Paths are not volatile by | |
| default. Temporary paths that are discarded or modified after use should be | |
| marked as volatile. This provides a hint to the device that the path | |
| should not be cached. Providing this hint when appropriate can | |
| improve performance by avoiding unnecessary overhead and resource | |
| consumption on the device. | |
| */ | |
| void setIsVolatile(bool isVolatile) { | |
| fIsVolatile = isVolatile; | |
| } | |
| /** Test a line for zero length | |
| @return true if the line is of zero length; otherwise false. | |
| */ | |
| static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) { | |
| return p1.equalsWithinTolerance(p2); | |
| } | |
| /** Test a quad for zero length | |
| @return true if the quad is of zero length; otherwise false. | |
| */ | |
| static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2, | |
| const SkPoint& p3) { | |
| return p1.equalsWithinTolerance(p2) && | |
| p2.equalsWithinTolerance(p3); | |
| } | |
| /** Test a cubic curve for zero length | |
| @return true if the cubic is of zero length; otherwise false. | |
| */ | |
| static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, | |
| const SkPoint& p3, const SkPoint& p4) { | |
| return p1.equalsWithinTolerance(p2) && | |
| p2.equalsWithinTolerance(p3) && | |
| p3.equalsWithinTolerance(p4); | |
| } | |
| /** | |
| * Returns true if the path specifies a single line (i.e. it contains just | |
| * a moveTo and a lineTo). If so, and line[] is not null, it sets the 2 | |
| * points in line[] to the end-points of the line. If the path is not a | |
| * line, returns false and ignores line[]. | |
| */ | |
| bool isLine(SkPoint line[2]) const; | |
| /** Return the number of points in the path | |
| */ | |
| int countPoints() const; | |
| /** Return the point at the specified index. If the index is out of range | |
| (i.e. is not 0 <= index < countPoints()) then the returned coordinates | |
| will be (0,0) | |
| */ | |
| SkPoint getPoint(int index) const; | |
| /** Returns the number of points in the path. Up to max points are copied. | |
| @param points If not null, receives up to max points | |
| @param max The maximum number of points to copy into points | |
| @return the actual number of points in the path | |
| */ | |
| int getPoints(SkPoint points[], int max) const; | |
| /** Return the number of verbs in the path | |
| */ | |
| int countVerbs() const; | |
| /** Returns the number of verbs in the path. Up to max verbs are copied. The | |
| verbs are copied as one byte per verb. | |
| @param verbs If not null, receives up to max verbs | |
| @param max The maximum number of verbs to copy into verbs | |
| @return the actual number of verbs in the path | |
| */ | |
| int getVerbs(uint8_t verbs[], int max) const; | |
| //! Swap contents of this and other. Guaranteed not to throw | |
| void swap(SkPath& other); | |
| /** Returns the bounds of the path's points. If the path contains 0 or 1 | |
| points, the bounds is set to (0,0,0,0), and isEmpty() will return true. | |
| Note: this bounds may be larger than the actual shape, since curves | |
| do not extend as far as their control points. Additionally this bound | |
| can contain trailing MoveTo points (cf. isRect). | |
| */ | |
| const SkRect& getBounds() const { | |
| return fPathRef->getBounds(); | |
| } | |
| /** Calling this will, if the internal cache of the bounds is out of date, | |
| update it so that subsequent calls to getBounds will be instantaneous. | |
| This also means that any copies or simple transformations of the path | |
| will inherit the cached bounds. | |
| */ | |
| void updateBoundsCache() const { | |
| // for now, just calling getBounds() is sufficient | |
| this->getBounds(); | |
| } | |
| /** | |
| * Does a conservative test to see whether a rectangle is inside a path. Currently it only | |
| * will ever return true for single convex contour paths. The empty-status of the rect is not | |
| * considered (e.g. a rect that is a point can be inside a path). Points or line segments where | |
| * the rect edge touches the path border are not considered containment violations. | |
| */ | |
| bool conservativelyContainsRect(const SkRect& rect) const; | |
| // Construction methods | |
| /** Hint to the path to prepare for adding more points. This can allow the | |
| path to more efficiently grow its storage. | |
| @param extraPtCount The number of extra points the path should | |
| preallocate for. | |
| */ | |
| void incReserve(unsigned extraPtCount); | |
| /** Set the beginning of the next contour to the point (x,y). | |
| @param x The x-coordinate of the start of a new contour | |
| @param y The y-coordinate of the start of a new contour | |
| */ | |
| void moveTo(SkScalar x, SkScalar y); | |
| /** Set the beginning of the next contour to the point | |
| @param p The start of a new contour | |
| */ | |
| void moveTo(const SkPoint& p) { | |
| this->moveTo(p.fX, p.fY); | |
| } | |
| /** Set the beginning of the next contour relative to the last point on the | |
| previous contour. If there is no previous contour, this is treated the | |
| same as moveTo(). | |
| @param dx The amount to add to the x-coordinate of the end of the | |
| previous contour, to specify the start of a new contour | |
| @param dy The amount to add to the y-coordinate of the end of the | |
| previous contour, to specify the start of a new contour | |
| */ | |
| void rMoveTo(SkScalar dx, SkScalar dy); | |
| /** Add a line from the last point to the specified point (x,y). If no | |
| moveTo() call has been made for this contour, the first point is | |
| automatically set to (0,0). | |
| @param x The x-coordinate of the end of a line | |
| @param y The y-coordinate of the end of a line | |
| */ | |
| void lineTo(SkScalar x, SkScalar y); | |
| /** Add a line from the last point to the specified point. If no moveTo() | |
| call has been made for this contour, the first point is automatically | |
| set to (0,0). | |
| @param p The end of a line | |
| */ | |
| void lineTo(const SkPoint& p) { | |
| this->lineTo(p.fX, p.fY); | |
| } | |
| /** Same as lineTo, but the coordinates are considered relative to the last | |
| point on this contour. If there is no previous point, then a moveTo(0,0) | |
| is inserted automatically. | |
| @param dx The amount to add to the x-coordinate of the previous point | |
| on this contour, to specify a line | |
| @param dy The amount to add to the y-coordinate of the previous point | |
| on this contour, to specify a line | |
| */ | |
| void rLineTo(SkScalar dx, SkScalar dy); | |
| /** Add a quadratic bezier from the last point, approaching control point | |
| (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for | |
| this contour, the first point is automatically set to (0,0). | |
| @param x1 The x-coordinate of the control point on a quadratic curve | |
| @param y1 The y-coordinate of the control point on a quadratic curve | |
| @param x2 The x-coordinate of the end point on a quadratic curve | |
| @param y2 The y-coordinate of the end point on a quadratic curve | |
| */ | |
| void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2); | |
| /** Add a quadratic bezier from the last point, approaching control point | |
| p1, and ending at p2. If no moveTo() call has been made for this | |
| contour, the first point is automatically set to (0,0). | |
| @param p1 The control point on a quadratic curve | |
| @param p2 The end point on a quadratic curve | |
| */ | |
| void quadTo(const SkPoint& p1, const SkPoint& p2) { | |
| this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY); | |
| } | |
| /** Same as quadTo, but the coordinates are considered relative to the last | |
| point on this contour. If there is no previous point, then a moveTo(0,0) | |
| is inserted automatically. | |
| @param dx1 The amount to add to the x-coordinate of the last point on | |
| this contour, to specify the control point of a quadratic curve | |
| @param dy1 The amount to add to the y-coordinate of the last point on | |
| this contour, to specify the control point of a quadratic curve | |
| @param dx2 The amount to add to the x-coordinate of the last point on | |
| this contour, to specify the end point of a quadratic curve | |
| @param dy2 The amount to add to the y-coordinate of the last point on | |
| this contour, to specify the end point of a quadratic curve | |
| */ | |
| void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2); | |
| void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | |
| SkScalar w); | |
| void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) { | |
| this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w); | |
| } | |
| void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, | |
| SkScalar w); | |
| /** Add a cubic bezier from the last point, approaching control points | |
| (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been | |
| made for this contour, the first point is automatically set to (0,0). | |
| @param x1 The x-coordinate of the 1st control point on a cubic curve | |
| @param y1 The y-coordinate of the 1st control point on a cubic curve | |
| @param x2 The x-coordinate of the 2nd control point on a cubic curve | |
| @param y2 The y-coordinate of the 2nd control point on a cubic curve | |
| @param x3 The x-coordinate of the end point on a cubic curve | |
| @param y3 The y-coordinate of the end point on a cubic curve | |
| */ | |
| void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | |
| SkScalar x3, SkScalar y3); | |
| /** Add a cubic bezier from the last point, approaching control points p1 | |
| and p2, and ending at p3. If no moveTo() call has been made for this | |
| contour, the first point is automatically set to (0,0). | |
| @param p1 The 1st control point on a cubic curve | |
| @param p2 The 2nd control point on a cubic curve | |
| @param p3 The end point on a cubic curve | |
| */ | |
| void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) { | |
| this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY); | |
| } | |
| /** Same as cubicTo, but the coordinates are considered relative to the | |
| current point on this contour. If there is no previous point, then a | |
| moveTo(0,0) is inserted automatically. | |
| @param dx1 The amount to add to the x-coordinate of the last point on | |
| this contour, to specify the 1st control point of a cubic curve | |
| @param dy1 The amount to add to the y-coordinate of the last point on | |
| this contour, to specify the 1st control point of a cubic curve | |
| @param dx2 The amount to add to the x-coordinate of the last point on | |
| this contour, to specify the 2nd control point of a cubic curve | |
| @param dy2 The amount to add to the y-coordinate of the last point on | |
| this contour, to specify the 2nd control point of a cubic curve | |
| @param dx3 The amount to add to the x-coordinate of the last point on | |
| this contour, to specify the end point of a cubic curve | |
| @param dy3 The amount to add to the y-coordinate of the last point on | |
| this contour, to specify the end point of a cubic curve | |
| */ | |
| void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | |
| SkScalar x3, SkScalar y3); | |
| /** Append the specified arc to the path as a new contour. If the start of | |
| the path is different from the path's current last point, then an | |
| automatic lineTo() is added to connect the current contour to the start | |
| of the arc. However, if the path is empty, then we call moveTo() with | |
| the first point of the arc. The sweep angle is treated mod 360. | |
| @param oval The bounding oval defining the shape and size of the arc | |
| @param startAngle Starting angle (in degrees) where the arc begins | |
| @param sweepAngle Sweep angle (in degrees) measured clockwise. This is | |
| treated mod 360. | |
| @param forceMoveTo If true, always begin a new contour with the arc | |
| */ | |
| void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, | |
| bool forceMoveTo); | |
| /** Append a line and arc to the current path. This is the same as the | |
| PostScript call "arct". | |
| */ | |
| void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | |
| SkScalar radius); | |
| /** Append a line and arc to the current path. This is the same as the | |
| PostScript call "arct". | |
| */ | |
| void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) { | |
| this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius); | |
| } | |
| /** Close the current contour. If the current point is not equal to the | |
| first point of the contour, a line segment is automatically added. | |
| */ | |
| void close(); | |
| enum Direction { | |
| /** Direction either has not been or could not be computed */ | |
| kUnknown_Direction, | |
| /** clockwise direction for adding closed contours */ | |
| kCW_Direction, | |
| /** counter-clockwise direction for adding closed contours */ | |
| kCCW_Direction, | |
| }; | |
| /** | |
| * Return the opposite of the specified direction. kUnknown is its own | |
| * opposite. | |
| */ | |
| static Direction OppositeDirection(Direction dir) { | |
| static const Direction gOppositeDir[] = { | |
| kUnknown_Direction, kCCW_Direction, kCW_Direction | |
| }; | |
| return gOppositeDir[dir]; | |
| } | |
| /** | |
| * Returns whether or not a fill type is inverted | |
| * | |
| * kWinding_FillType -> false | |
| * kEvenOdd_FillType -> false | |
| * kInverseWinding_FillType -> true | |
| * kInverseEvenOdd_FillType -> true | |
| */ | |
| static bool IsInverseFillType(FillType fill) { | |
| SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch); | |
| SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch); | |
| SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch); | |
| SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch); | |
| return (fill & 2) != 0; | |
| } | |
| /** | |
| * Returns the equivalent non-inverted fill type to the given fill type | |
| * | |
| * kWinding_FillType -> kWinding_FillType | |
| * kEvenOdd_FillType -> kEvenOdd_FillType | |
| * kInverseWinding_FillType -> kWinding_FillType | |
| * kInverseEvenOdd_FillType -> kEvenOdd_FillType | |
| */ | |
| static FillType ConvertToNonInverseFillType(FillType fill) { | |
| SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch); | |
| SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch); | |
| SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch); | |
| SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch); | |
| return (FillType)(fill & 1); | |
| } | |
| /** | |
| * Tries to quickly compute the direction of the first non-degenerate | |
| * contour. If it can be computed, return true and set dir to that | |
| * direction. If it cannot be (quickly) determined, return false and ignore | |
| * the dir parameter. If the direction was determined, it is cached to make | |
| * subsequent calls return quickly. | |
| */ | |
| bool cheapComputeDirection(Direction* dir) const; | |
| /** | |
| * Returns true if the path's direction can be computed via | |
| * cheapComputDirection() and if that computed direction matches the | |
| * specified direction. If dir is kUnknown, returns true if the direction | |
| * cannot be computed. | |
| */ | |
| bool cheapIsDirection(Direction dir) const { | |
| Direction computedDir = kUnknown_Direction; | |
| (void)this->cheapComputeDirection(&computedDir); | |
| return computedDir == dir; | |
| } | |
| /** | |
| * Returns true if the path specifies a rectangle. | |
| * | |
| * If this returns false, then all output parameters are ignored, and left | |
| * unchanged. If this returns true, then each of the output parameters | |
| * are checked for NULL. If they are not, they return their value. | |
| * | |
| * @param rect If not null, set to the bounds of the rectangle. | |
| * Note : this bounds may be smaller than the path's bounds, since it is just | |
| * the bounds of the "drawable" parts of the path. e.g. a trailing MoveTo would | |
| * be ignored in this rect, but not by the path's bounds | |
| * @param isClosed If not null, set to true if the path is closed | |
| * @param direction If not null, set to the rectangle's direction | |
| * @return true if the path specifies a rectangle | |
| */ | |
| bool isRect(SkRect* rect, bool* isClosed = NULL, Direction* direction = NULL) const; | |
| /** Returns true if the path specifies a pair of nested rectangles. If so, and if | |
| rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner | |
| rectangle. If so, and dirs is not null, set dirs[0] to the direction of | |
| the outer rectangle and dirs[1] to the direction of the inner rectangle. If | |
| the path does not specify a pair of nested rectangles, return | |
| false and ignore rect and dirs. | |
| @param rect If not null, returns the path as a pair of nested rectangles | |
| @param dirs If not null, returns the direction of the rects | |
| @return true if the path describes a pair of nested rectangles | |
| */ | |
| bool isNestedRects(SkRect rect[2], Direction dirs[2] = NULL) const; | |
| /** | |
| * Add a closed rectangle contour to the path | |
| * @param rect The rectangle to add as a closed contour to the path | |
| * @param dir The direction to wind the rectangle's contour. Cannot be | |
| * kUnknown_Direction. | |
| */ | |
| void addRect(const SkRect& rect, Direction dir = kCW_Direction); | |
| /** | |
| * Add a closed rectangle contour to the path | |
| * | |
| * @param left The left side of a rectangle to add as a closed contour | |
| * to the path | |
| * @param top The top of a rectangle to add as a closed contour to the | |
| * path | |
| * @param right The right side of a rectangle to add as a closed contour | |
| * to the path | |
| * @param bottom The bottom of a rectangle to add as a closed contour to | |
| * the path | |
| * @param dir The direction to wind the rectangle's contour. Cannot be | |
| * kUnknown_Direction. | |
| */ | |
| void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, | |
| Direction dir = kCW_Direction); | |
| /** | |
| * Add a closed oval contour to the path | |
| * | |
| * @param oval The bounding oval to add as a closed contour to the path | |
| * @param dir The direction to wind the oval's contour. Cannot be | |
| * kUnknown_Direction. | |
| */ | |
| void addOval(const SkRect& oval, Direction dir = kCW_Direction); | |
| /** | |
| * Add a closed circle contour to the path | |
| * | |
| * @param x The x-coordinate of the center of a circle to add as a | |
| * closed contour to the path | |
| * @param y The y-coordinate of the center of a circle to add as a | |
| * closed contour to the path | |
| * @param radius The radius of a circle to add as a closed contour to the | |
| * path | |
| * @param dir The direction to wind the circle's contour. Cannot be | |
| * kUnknown_Direction. | |
| */ | |
| void addCircle(SkScalar x, SkScalar y, SkScalar radius, | |
| Direction dir = kCW_Direction); | |
| /** Add the specified arc to the path as a new contour. | |
| @param oval The bounds of oval used to define the size of the arc | |
| @param startAngle Starting angle (in degrees) where the arc begins | |
| @param sweepAngle Sweep angle (in degrees) measured clockwise | |
| */ | |
| void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle); | |
| /** | |
| * Add a closed round-rectangle contour to the path | |
| * @param rect The bounds of a round-rectangle to add as a closed contour | |
| * @param rx The x-radius of the rounded corners on the round-rectangle | |
| * @param ry The y-radius of the rounded corners on the round-rectangle | |
| * @param dir The direction to wind the rectangle's contour. Cannot be | |
| * kUnknown_Direction. | |
| */ | |
| void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, | |
| Direction dir = kCW_Direction); | |
| /** | |
| * Add a closed round-rectangle contour to the path. Each corner receives | |
| * two radius values [X, Y]. The corners are ordered top-left, top-right, | |
| * bottom-right, bottom-left. | |
| * @param rect The bounds of a round-rectangle to add as a closed contour | |
| * @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner | |
| * @param dir The direction to wind the rectangle's contour. Cannot be | |
| * kUnknown_Direction. | |
| * Note: The radii here now go through the same constraint handling as the | |
| * SkRRect radii (i.e., either radii at a corner being 0 implies a | |
| * sqaure corner and oversized radii are proportionally scaled down). | |
| */ | |
| void addRoundRect(const SkRect& rect, const SkScalar radii[], | |
| Direction dir = kCW_Direction); | |
| /** | |
| * Add an SkRRect contour to the path | |
| * @param rrect The rounded rect to add as a closed contour | |
| * @param dir The winding direction for the new contour. Cannot be | |
| * kUnknown_Direction. | |
| */ | |
| void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction); | |
| /** | |
| * Add a new contour made of just lines. This is just a fast version of | |
| * the following: | |
| * this->moveTo(pts[0]); | |
| * for (int i = 1; i < count; ++i) { | |
| * this->lineTo(pts[i]); | |
| * } | |
| * if (close) { | |
| * this->close(); | |
| * } | |
| */ | |
| void addPoly(const SkPoint pts[], int count, bool close); | |
| enum AddPathMode { | |
| /** Source path contours are added as new contours. | |
| */ | |
| kAppend_AddPathMode, | |
| /** Path is added by extending the last contour of the destination path | |
| with the first contour of the source path. If the last contour of | |
| the destination path is closed, then it will not be extended. | |
| Instead, the start of source path will be extended by a straight | |
| line to the end point of the destination path. | |
| */ | |
| kExtend_AddPathMode | |
| }; | |
| /** Add a copy of src to the path, offset by (dx,dy) | |
| @param src The path to add as a new contour | |
| @param dx The amount to translate the path in X as it is added | |
| @param dx The amount to translate the path in Y as it is added | |
| */ | |
| void addPath(const SkPath& src, SkScalar dx, SkScalar dy, | |
| AddPathMode mode = kAppend_AddPathMode); | |
| /** Add a copy of src to the path | |
| */ | |
| void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) { | |
| SkMatrix m; | |
| m.reset(); | |
| this->addPath(src, m, mode); | |
| } | |
| /** Add a copy of src to the path, transformed by matrix | |
| @param src The path to add as a new contour | |
| @param matrix Transform applied to src | |
| @param mode Determines how path is added | |
| */ | |
| void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode); | |
| /** | |
| * Same as addPath(), but reverses the src input | |
| */ | |
| void reverseAddPath(const SkPath& src); | |
| /** Offset the path by (dx,dy), returning true on success | |
| @param dx The amount in the X direction to offset the entire path | |
| @param dy The amount in the Y direction to offset the entire path | |
| @param dst The translated path is written here | |
| */ | |
| void offset(SkScalar dx, SkScalar dy, SkPath* dst) const; | |
| /** Offset the path by (dx,dy), returning true on success | |
| @param dx The amount in the X direction to offset the entire path | |
| @param dy The amount in the Y direction to offset the entire path | |
| */ | |
| void offset(SkScalar dx, SkScalar dy) { | |
| this->offset(dx, dy, this); | |
| } | |
| /** Transform the points in this path by matrix, and write the answer into | |
| dst. | |
| @param matrix The matrix to apply to the path | |
| @param dst The transformed path is written here | |
| */ | |
| void transform(const SkMatrix& matrix, SkPath* dst) const; | |
| /** Transform the points in this path by matrix | |
| @param matrix The matrix to apply to the path | |
| */ | |
| void transform(const SkMatrix& matrix) { | |
| this->transform(matrix, this); | |
| } | |
| /** Return the last point on the path. If no points have been added, (0,0) | |
| is returned. If there are no points, this returns false, otherwise it | |
| returns true. | |
| @param lastPt The last point on the path is returned here | |
| */ | |
| bool getLastPt(SkPoint* lastPt) const; | |
| /** Set the last point on the path. If no points have been added, | |
| moveTo(x,y) is automatically called. | |
| @param x The new x-coordinate for the last point | |
| @param y The new y-coordinate for the last point | |
| */ | |
| void setLastPt(SkScalar x, SkScalar y); | |
| /** Set the last point on the path. If no points have been added, moveTo(p) | |
| is automatically called. | |
| @param p The new location for the last point | |
| */ | |
| void setLastPt(const SkPoint& p) { | |
| this->setLastPt(p.fX, p.fY); | |
| } | |
| enum SegmentMask { | |
| kLine_SegmentMask = 1 << 0, | |
| kQuad_SegmentMask = 1 << 1, | |
| kConic_SegmentMask = 1 << 2, | |
| kCubic_SegmentMask = 1 << 3, | |
| }; | |
| /** | |
| * Returns a mask, where each bit corresponding to a SegmentMask is | |
| * set if the path contains 1 or more segments of that type. | |
| * Returns 0 for an empty path (no segments). | |
| */ | |
| uint32_t getSegmentMasks() const { return fPathRef->getSegmentMasks(); } | |
| enum Verb { | |
| kMove_Verb, //!< iter.next returns 1 point | |
| kLine_Verb, //!< iter.next returns 2 points | |
| kQuad_Verb, //!< iter.next returns 3 points | |
| kConic_Verb, //!< iter.next returns 3 points + iter.conicWeight() | |
| kCubic_Verb, //!< iter.next returns 4 points | |
| kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt) | |
| kDone_Verb, //!< iter.next returns 0 points | |
| }; | |
| /** Iterate through all of the segments (lines, quadratics, cubics) of | |
| each contours in a path. | |
| The iterator cleans up the segments along the way, removing degenerate | |
| segments and adding close verbs where necessary. When the forceClose | |
| argument is provided, each contour (as defined by a new starting | |
| move command) will be completed with a close verb regardless of the | |
| contour's contents. | |
| */ | |
| class SK_API Iter { | |
| public: | |
| Iter(); | |
| Iter(const SkPath&, bool forceClose); | |
| void setPath(const SkPath&, bool forceClose); | |
| /** Return the next verb in this iteration of the path. When all | |
| segments have been visited, return kDone_Verb. | |
| @param pts The points representing the current verb and/or segment | |
| @param doConsumeDegerates If true, first scan for segments that are | |
| deemed degenerate (too short) and skip those. | |
| @return The verb for the current segment | |
| */ | |
| Verb next(SkPoint pts[4], bool doConsumeDegerates = true) { | |
| if (doConsumeDegerates) { | |
| this->consumeDegenerateSegments(); | |
| } | |
| return this->doNext(pts); | |
| } | |
| /** | |
| * Return the weight for the current conic. Only valid if the current | |
| * segment return by next() was a conic. | |
| */ | |
| SkScalar conicWeight() const { return *fConicWeights; } | |
| /** If next() returns kLine_Verb, then this query returns true if the | |
| line was the result of a close() command (i.e. the end point is the | |
| initial moveto for this contour). If next() returned a different | |
| verb, this returns an undefined value. | |
| @return If the last call to next() returned kLine_Verb, return true | |
| if it was the result of an explicit close command. | |
| */ | |
| bool isCloseLine() const { return SkToBool(fCloseLine); } | |
| /** Returns true if the current contour is closed (has a kClose_Verb) | |
| @return true if the current contour is closed (has a kClose_Verb) | |
| */ | |
| bool isClosedContour() const; | |
| private: | |
| const SkPoint* fPts; | |
| const uint8_t* fVerbs; | |
| const uint8_t* fVerbStop; | |
| const SkScalar* fConicWeights; | |
| SkPoint fMoveTo; | |
| SkPoint fLastPt; | |
| SkBool8 fForceClose; | |
| SkBool8 fNeedClose; | |
| SkBool8 fCloseLine; | |
| SkBool8 fSegmentState; | |
| inline const SkPoint& cons_moveTo(); | |
| Verb autoClose(SkPoint pts[2]); | |
| void consumeDegenerateSegments(); | |
| Verb doNext(SkPoint pts[4]); | |
| }; | |
| /** Iterate through the verbs in the path, providing the associated points. | |
| */ | |
| class SK_API RawIter { | |
| public: | |
| RawIter(); | |
| RawIter(const SkPath&); | |
| void setPath(const SkPath&); | |
| /** Return the next verb in this iteration of the path. When all | |
| segments have been visited, return kDone_Verb. | |
| @param pts The points representing the current verb and/or segment | |
| This must not be NULL. | |
| @return The verb for the current segment | |
| */ | |
| Verb next(SkPoint pts[4]); | |
| SkScalar conicWeight() const { return *fConicWeights; } | |
| private: | |
| const SkPoint* fPts; | |
| const uint8_t* fVerbs; | |
| const uint8_t* fVerbStop; | |
| const SkScalar* fConicWeights; | |
| SkPoint fMoveTo; | |
| SkPoint fLastPt; | |
| }; | |
| /** | |
| * Returns true if the point { x, y } is contained by the path, taking into | |
| * account the FillType. | |
| */ | |
| bool contains(SkScalar x, SkScalar y) const; | |
| void dump(SkWStream* , bool forceClose, bool dumpAsHex) const; | |
| void dump() const; | |
| void dumpHex() const; | |
| /** | |
| * Write the path to the buffer, and return the number of bytes written. | |
| * If buffer is NULL, it still returns the number of bytes. | |
| */ | |
| size_t writeToMemory(void* buffer) const; | |
| /** | |
| * Initializes the path from the buffer | |
| * | |
| * @param buffer Memory to read from | |
| * @param length Amount of memory available in the buffer | |
| * @return number of bytes read (must be a multiple of 4) or | |
| * 0 if there was not enough memory available | |
| */ | |
| size_t readFromMemory(const void* buffer, size_t length); | |
| /** Returns a non-zero, globally unique value corresponding to the set of verbs | |
| and points in the path (but not the fill type [except on Android skbug.com/1762]). | |
| Each time the path is modified, a different generation ID will be returned. | |
| */ | |
| uint32_t getGenerationID() const; | |
| #ifdef SK_BUILD_FOR_ANDROID | |
| static const int kPathRefGenIDBitCnt = 30; // leave room for the fill type (skbug.com/1762) | |
| const SkPath* getSourcePath() const; | |
| void setSourcePath(const SkPath* path); | |
| #else | |
| static const int kPathRefGenIDBitCnt = 32; | |
| #endif | |
| SkDEBUGCODE(void validate() const;) | |
| private: | |
| enum SerializationOffsets { | |
| // 1 free bit at 29 | |
| kUnused1_SerializationShift = 28, // 1 free bit | |
| kDirection_SerializationShift = 26, // requires 2 bits | |
| kIsVolatile_SerializationShift = 25, // requires 1 bit | |
| // 1 free bit at 24 | |
| kConvexity_SerializationShift = 16, // requires 8 bits | |
| kFillType_SerializationShift = 8, // requires 8 bits | |
| // 8 free bits at 0 | |
| }; | |
| SkAutoTUnref<SkPathRef> fPathRef; | |
| int fLastMoveToIndex; | |
| uint8_t fFillType; | |
| mutable uint8_t fConvexity; | |
| mutable uint8_t fDirection; | |
| mutable SkBool8 fIsVolatile; | |
| #ifdef SK_BUILD_FOR_ANDROID | |
| const SkPath* fSourcePath; | |
| #endif | |
| /** Resets all fields other than fPathRef to their initial 'empty' values. | |
| * Assumes the caller has already emptied fPathRef. | |
| * On Android increments fGenerationID without reseting it. | |
| */ | |
| void resetFields(); | |
| /** Sets all fields other than fPathRef to the values in 'that'. | |
| * Assumes the caller has already set fPathRef. | |
| * Doesn't change fGenerationID or fSourcePath on Android. | |
| */ | |
| void copyFields(const SkPath& that); | |
| friend class Iter; | |
| friend class SkPathStroker; | |
| /* Append, in reverse order, the first contour of path, ignoring path's | |
| last point. If no moveTo() call has been made for this contour, the | |
| first point is automatically set to (0,0). | |
| */ | |
| void reversePathTo(const SkPath&); | |
| // called before we add points for lineTo, quadTo, cubicTo, checking to see | |
| // if we need to inject a leading moveTo first | |
| // | |
| // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0) | |
| // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo) | |
| // | |
| inline void injectMoveToIfNeeded(); | |
| inline bool hasOnlyMoveTos() const; | |
| Convexity internalGetConvexity() const; | |
| bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts, | |
| bool* isClosed, Direction* direction) const; | |
| /** Returns if the path can return a bound at no cost (true) or will have to | |
| perform some computation (false). | |
| */ | |
| bool hasComputedBounds() const { | |
| SkDEBUGCODE(this->validate();) | |
| return fPathRef->hasComputedBounds(); | |
| } | |
| // 'rect' needs to be sorted | |
| void setBounds(const SkRect& rect) { | |
| SkPathRef::Editor ed(&fPathRef); | |
| ed.setBounds(rect); | |
| } | |
| friend class SkAutoPathBoundsUpdate; | |
| friend class SkAutoDisableOvalCheck; | |
| friend class SkAutoDisableDirectionCheck; | |
| friend class SkBench_AddPathTest; // perf test reversePathTo | |
| friend class PathTest_Private; // unit test reversePathTo | |
| }; | |
| #endif |