1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/include/core/SkPath.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1049 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2006 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#ifndef SkPath_DEFINED 1.14 +#define SkPath_DEFINED 1.15 + 1.16 +#include "SkInstCnt.h" 1.17 +#include "SkMatrix.h" 1.18 +#include "SkPathRef.h" 1.19 +#include "SkTDArray.h" 1.20 +#include "SkRefCnt.h" 1.21 + 1.22 +class SkReader32; 1.23 +class SkWriter32; 1.24 +class SkAutoPathBoundsUpdate; 1.25 +class SkString; 1.26 +class SkRRect; 1.27 + 1.28 +/** \class SkPath 1.29 + 1.30 + The SkPath class encapsulates compound (multiple contour) geometric paths 1.31 + consisting of straight line segments, quadratic curves, and cubic curves. 1.32 +*/ 1.33 +class SK_API SkPath { 1.34 +public: 1.35 + SK_DECLARE_INST_COUNT_ROOT(SkPath); 1.36 + 1.37 + SkPath(); 1.38 + SkPath(const SkPath&); 1.39 + ~SkPath(); 1.40 + 1.41 + SkPath& operator=(const SkPath&); 1.42 + friend SK_API bool operator==(const SkPath&, const SkPath&); 1.43 + friend bool operator!=(const SkPath& a, const SkPath& b) { 1.44 + return !(a == b); 1.45 + } 1.46 + 1.47 + enum FillType { 1.48 + /** Specifies that "inside" is computed by a non-zero sum of signed 1.49 + edge crossings 1.50 + */ 1.51 + kWinding_FillType, 1.52 + /** Specifies that "inside" is computed by an odd number of edge 1.53 + crossings 1.54 + */ 1.55 + kEvenOdd_FillType, 1.56 + /** Same as Winding, but draws outside of the path, rather than inside 1.57 + */ 1.58 + kInverseWinding_FillType, 1.59 + /** Same as EvenOdd, but draws outside of the path, rather than inside 1.60 + */ 1.61 + kInverseEvenOdd_FillType 1.62 + }; 1.63 + 1.64 + /** Return the path's fill type. This is used to define how "inside" is 1.65 + computed. The default value is kWinding_FillType. 1.66 + 1.67 + @return the path's fill type 1.68 + */ 1.69 + FillType getFillType() const { return (FillType)fFillType; } 1.70 + 1.71 + /** Set the path's fill type. This is used to define how "inside" is 1.72 + computed. The default value is kWinding_FillType. 1.73 + 1.74 + @param ft The new fill type for this path 1.75 + */ 1.76 + void setFillType(FillType ft) { 1.77 + fFillType = SkToU8(ft); 1.78 + } 1.79 + 1.80 + /** Returns true if the filltype is one of the Inverse variants */ 1.81 + bool isInverseFillType() const { return IsInverseFillType((FillType)fFillType); } 1.82 + 1.83 + /** 1.84 + * Toggle between inverse and normal filltypes. This reverse the return 1.85 + * value of isInverseFillType() 1.86 + */ 1.87 + void toggleInverseFillType() { 1.88 + fFillType ^= 2; 1.89 + } 1.90 + 1.91 + enum Convexity { 1.92 + kUnknown_Convexity, 1.93 + kConvex_Convexity, 1.94 + kConcave_Convexity 1.95 + }; 1.96 + 1.97 + /** 1.98 + * Return the path's convexity, as stored in the path. If it is currently unknown, 1.99 + * then this function will attempt to compute the convexity (and cache the result). 1.100 + */ 1.101 + Convexity getConvexity() const { 1.102 + if (kUnknown_Convexity != fConvexity) { 1.103 + return static_cast<Convexity>(fConvexity); 1.104 + } else { 1.105 + return this->internalGetConvexity(); 1.106 + } 1.107 + } 1.108 + 1.109 + /** 1.110 + * Return the currently cached value for convexity, even if that is set to 1.111 + * kUnknown_Convexity. Note: getConvexity() will automatically call 1.112 + * ComputeConvexity and cache its return value if the current setting is 1.113 + * kUnknown. 1.114 + */ 1.115 + Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; } 1.116 + 1.117 + /** 1.118 + * Store a convexity setting in the path. There is no automatic check to 1.119 + * see if this value actually agrees with the return value that would be 1.120 + * computed by getConvexity(). 1.121 + * 1.122 + * Note: even if this is set to a "known" value, if the path is later 1.123 + * changed (e.g. lineTo(), addRect(), etc.) then the cached value will be 1.124 + * reset to kUnknown_Convexity. 1.125 + */ 1.126 + void setConvexity(Convexity); 1.127 + 1.128 + /** 1.129 + * Returns true if the path is flagged as being convex. This is not a 1.130 + * confirmed by any analysis, it is just the value set earlier. 1.131 + */ 1.132 + bool isConvex() const { 1.133 + return kConvex_Convexity == this->getConvexity(); 1.134 + } 1.135 + 1.136 + /** 1.137 + * Set the isConvex flag to true or false. Convex paths may draw faster if 1.138 + * this flag is set, though setting this to true on a path that is in fact 1.139 + * not convex can give undefined results when drawn. Paths default to 1.140 + * isConvex == false 1.141 + */ 1.142 + SK_ATTR_DEPRECATED("use setConvexity") 1.143 + void setIsConvex(bool isConvex) { 1.144 + this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity); 1.145 + } 1.146 + 1.147 + /** Returns true if the path is an oval. 1.148 + * 1.149 + * @param rect returns the bounding rect of this oval. It's a circle 1.150 + * if the height and width are the same. 1.151 + * 1.152 + * @return true if this path is an oval. 1.153 + * Tracking whether a path is an oval is considered an 1.154 + * optimization for performance and so some paths that are in 1.155 + * fact ovals can report false. 1.156 + */ 1.157 + bool isOval(SkRect* rect) const { return fPathRef->isOval(rect); } 1.158 + 1.159 + /** Clear any lines and curves from the path, making it empty. This frees up 1.160 + internal storage associated with those segments. 1.161 + On Android, does not change fSourcePath. 1.162 + */ 1.163 + void reset(); 1.164 + 1.165 + /** Similar to reset(), in that all lines and curves are removed from the 1.166 + path. However, any internal storage for those lines/curves is retained, 1.167 + making reuse of the path potentially faster. 1.168 + On Android, does not change fSourcePath. 1.169 + */ 1.170 + void rewind(); 1.171 + 1.172 + /** Returns true if the path is empty (contains no lines or curves) 1.173 + 1.174 + @return true if the path is empty (contains no lines or curves) 1.175 + */ 1.176 + bool isEmpty() const { 1.177 + SkDEBUGCODE(this->validate();) 1.178 + return 0 == fPathRef->countVerbs(); 1.179 + } 1.180 + 1.181 + /** 1.182 + * Returns true if all of the points in this path are finite, meaning there 1.183 + * are no infinities and no NaNs. 1.184 + */ 1.185 + bool isFinite() const { 1.186 + SkDEBUGCODE(this->validate();) 1.187 + return fPathRef->isFinite(); 1.188 + } 1.189 + 1.190 + /** Test a line for zero length 1.191 + 1.192 + @return true if the line is of zero length; otherwise false. 1.193 + */ 1.194 + static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) { 1.195 + return p1.equalsWithinTolerance(p2); 1.196 + } 1.197 + 1.198 + /** Test a quad for zero length 1.199 + 1.200 + @return true if the quad is of zero length; otherwise false. 1.201 + */ 1.202 + static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2, 1.203 + const SkPoint& p3) { 1.204 + return p1.equalsWithinTolerance(p2) && 1.205 + p2.equalsWithinTolerance(p3); 1.206 + } 1.207 + 1.208 + /** Test a cubic curve for zero length 1.209 + 1.210 + @return true if the cubic is of zero length; otherwise false. 1.211 + */ 1.212 + static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, 1.213 + const SkPoint& p3, const SkPoint& p4) { 1.214 + return p1.equalsWithinTolerance(p2) && 1.215 + p2.equalsWithinTolerance(p3) && 1.216 + p3.equalsWithinTolerance(p4); 1.217 + } 1.218 + 1.219 + /** 1.220 + * Returns true if the path specifies a single line (i.e. it contains just 1.221 + * a moveTo and a lineTo). If so, and line[] is not null, it sets the 2 1.222 + * points in line[] to the end-points of the line. If the path is not a 1.223 + * line, returns false and ignores line[]. 1.224 + */ 1.225 + bool isLine(SkPoint line[2]) const; 1.226 + 1.227 + /** Returns true if the path specifies a rectangle. If so, and if rect is 1.228 + not null, set rect to the bounds of the path. If the path does not 1.229 + specify a rectangle, return false and ignore rect. 1.230 + 1.231 + @param rect If not null, returns the bounds of the path if it specifies 1.232 + a rectangle 1.233 + @return true if the path specifies a rectangle 1.234 + */ 1.235 + bool isRect(SkRect* rect) const; 1.236 + 1.237 + /** Return the number of points in the path 1.238 + */ 1.239 + int countPoints() const; 1.240 + 1.241 + /** Return the point at the specified index. If the index is out of range 1.242 + (i.e. is not 0 <= index < countPoints()) then the returned coordinates 1.243 + will be (0,0) 1.244 + */ 1.245 + SkPoint getPoint(int index) const; 1.246 + 1.247 + /** Returns the number of points in the path. Up to max points are copied. 1.248 + 1.249 + @param points If not null, receives up to max points 1.250 + @param max The maximum number of points to copy into points 1.251 + @return the actual number of points in the path 1.252 + */ 1.253 + int getPoints(SkPoint points[], int max) const; 1.254 + 1.255 + /** Return the number of verbs in the path 1.256 + */ 1.257 + int countVerbs() const; 1.258 + 1.259 + /** Returns the number of verbs in the path. Up to max verbs are copied. The 1.260 + verbs are copied as one byte per verb. 1.261 + 1.262 + @param verbs If not null, receives up to max verbs 1.263 + @param max The maximum number of verbs to copy into verbs 1.264 + @return the actual number of verbs in the path 1.265 + */ 1.266 + int getVerbs(uint8_t verbs[], int max) const; 1.267 + 1.268 + //! Swap contents of this and other. Guaranteed not to throw 1.269 + void swap(SkPath& other); 1.270 + 1.271 + /** Returns the bounds of the path's points. If the path contains 0 or 1 1.272 + points, the bounds is set to (0,0,0,0), and isEmpty() will return true. 1.273 + Note: this bounds may be larger than the actual shape, since curves 1.274 + do not extend as far as their control points. 1.275 + */ 1.276 + const SkRect& getBounds() const { 1.277 + return fPathRef->getBounds(); 1.278 + } 1.279 + 1.280 + /** Calling this will, if the internal cache of the bounds is out of date, 1.281 + update it so that subsequent calls to getBounds will be instantaneous. 1.282 + This also means that any copies or simple transformations of the path 1.283 + will inherit the cached bounds. 1.284 + */ 1.285 + void updateBoundsCache() const { 1.286 + // for now, just calling getBounds() is sufficient 1.287 + this->getBounds(); 1.288 + } 1.289 + 1.290 + /** 1.291 + * Does a conservative test to see whether a rectangle is inside a path. Currently it only 1.292 + * will ever return true for single convex contour paths. The empty-status of the rect is not 1.293 + * considered (e.g. a rect that is a point can be inside a path). Points or line segments where 1.294 + * the rect edge touches the path border are not considered containment violations. 1.295 + */ 1.296 + bool conservativelyContainsRect(const SkRect& rect) const; 1.297 + 1.298 + // Construction methods 1.299 + 1.300 + /** Hint to the path to prepare for adding more points. This can allow the 1.301 + path to more efficiently grow its storage. 1.302 + 1.303 + @param extraPtCount The number of extra points the path should 1.304 + preallocate for. 1.305 + */ 1.306 + void incReserve(unsigned extraPtCount); 1.307 + 1.308 + /** Set the beginning of the next contour to the point (x,y). 1.309 + 1.310 + @param x The x-coordinate of the start of a new contour 1.311 + @param y The y-coordinate of the start of a new contour 1.312 + */ 1.313 + void moveTo(SkScalar x, SkScalar y); 1.314 + 1.315 + /** Set the beginning of the next contour to the point 1.316 + 1.317 + @param p The start of a new contour 1.318 + */ 1.319 + void moveTo(const SkPoint& p) { 1.320 + this->moveTo(p.fX, p.fY); 1.321 + } 1.322 + 1.323 + /** Set the beginning of the next contour relative to the last point on the 1.324 + previous contour. If there is no previous contour, this is treated the 1.325 + same as moveTo(). 1.326 + 1.327 + @param dx The amount to add to the x-coordinate of the end of the 1.328 + previous contour, to specify the start of a new contour 1.329 + @param dy The amount to add to the y-coordinate of the end of the 1.330 + previous contour, to specify the start of a new contour 1.331 + */ 1.332 + void rMoveTo(SkScalar dx, SkScalar dy); 1.333 + 1.334 + /** Add a line from the last point to the specified point (x,y). If no 1.335 + moveTo() call has been made for this contour, the first point is 1.336 + automatically set to (0,0). 1.337 + 1.338 + @param x The x-coordinate of the end of a line 1.339 + @param y The y-coordinate of the end of a line 1.340 + */ 1.341 + void lineTo(SkScalar x, SkScalar y); 1.342 + 1.343 + /** Add a line from the last point to the specified point. If no moveTo() 1.344 + call has been made for this contour, the first point is automatically 1.345 + set to (0,0). 1.346 + 1.347 + @param p The end of a line 1.348 + */ 1.349 + void lineTo(const SkPoint& p) { 1.350 + this->lineTo(p.fX, p.fY); 1.351 + } 1.352 + 1.353 + /** Same as lineTo, but the coordinates are considered relative to the last 1.354 + point on this contour. If there is no previous point, then a moveTo(0,0) 1.355 + is inserted automatically. 1.356 + 1.357 + @param dx The amount to add to the x-coordinate of the previous point 1.358 + on this contour, to specify a line 1.359 + @param dy The amount to add to the y-coordinate of the previous point 1.360 + on this contour, to specify a line 1.361 + */ 1.362 + void rLineTo(SkScalar dx, SkScalar dy); 1.363 + 1.364 + /** Add a quadratic bezier from the last point, approaching control point 1.365 + (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for 1.366 + this contour, the first point is automatically set to (0,0). 1.367 + 1.368 + @param x1 The x-coordinate of the control point on a quadratic curve 1.369 + @param y1 The y-coordinate of the control point on a quadratic curve 1.370 + @param x2 The x-coordinate of the end point on a quadratic curve 1.371 + @param y2 The y-coordinate of the end point on a quadratic curve 1.372 + */ 1.373 + void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2); 1.374 + 1.375 + /** Add a quadratic bezier from the last point, approaching control point 1.376 + p1, and ending at p2. If no moveTo() call has been made for this 1.377 + contour, the first point is automatically set to (0,0). 1.378 + 1.379 + @param p1 The control point on a quadratic curve 1.380 + @param p2 The end point on a quadratic curve 1.381 + */ 1.382 + void quadTo(const SkPoint& p1, const SkPoint& p2) { 1.383 + this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY); 1.384 + } 1.385 + 1.386 + /** Same as quadTo, but the coordinates are considered relative to the last 1.387 + point on this contour. If there is no previous point, then a moveTo(0,0) 1.388 + is inserted automatically. 1.389 + 1.390 + @param dx1 The amount to add to the x-coordinate of the last point on 1.391 + this contour, to specify the control point of a quadratic curve 1.392 + @param dy1 The amount to add to the y-coordinate of the last point on 1.393 + this contour, to specify the control point of a quadratic curve 1.394 + @param dx2 The amount to add to the x-coordinate of the last point on 1.395 + this contour, to specify the end point of a quadratic curve 1.396 + @param dy2 The amount to add to the y-coordinate of the last point on 1.397 + this contour, to specify the end point of a quadratic curve 1.398 + */ 1.399 + void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2); 1.400 + 1.401 + void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 1.402 + SkScalar w); 1.403 + void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) { 1.404 + this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w); 1.405 + } 1.406 + void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, 1.407 + SkScalar w); 1.408 + 1.409 + /** Add a cubic bezier from the last point, approaching control points 1.410 + (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been 1.411 + made for this contour, the first point is automatically set to (0,0). 1.412 + 1.413 + @param x1 The x-coordinate of the 1st control point on a cubic curve 1.414 + @param y1 The y-coordinate of the 1st control point on a cubic curve 1.415 + @param x2 The x-coordinate of the 2nd control point on a cubic curve 1.416 + @param y2 The y-coordinate of the 2nd control point on a cubic curve 1.417 + @param x3 The x-coordinate of the end point on a cubic curve 1.418 + @param y3 The y-coordinate of the end point on a cubic curve 1.419 + */ 1.420 + void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 1.421 + SkScalar x3, SkScalar y3); 1.422 + 1.423 + /** Add a cubic bezier from the last point, approaching control points p1 1.424 + and p2, and ending at p3. If no moveTo() call has been made for this 1.425 + contour, the first point is automatically set to (0,0). 1.426 + 1.427 + @param p1 The 1st control point on a cubic curve 1.428 + @param p2 The 2nd control point on a cubic curve 1.429 + @param p3 The end point on a cubic curve 1.430 + */ 1.431 + void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) { 1.432 + this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY); 1.433 + } 1.434 + 1.435 + /** Same as cubicTo, but the coordinates are considered relative to the 1.436 + current point on this contour. If there is no previous point, then a 1.437 + moveTo(0,0) is inserted automatically. 1.438 + 1.439 + @param dx1 The amount to add to the x-coordinate of the last point on 1.440 + this contour, to specify the 1st control point of a cubic curve 1.441 + @param dy1 The amount to add to the y-coordinate of the last point on 1.442 + this contour, to specify the 1st control point of a cubic curve 1.443 + @param dx2 The amount to add to the x-coordinate of the last point on 1.444 + this contour, to specify the 2nd control point of a cubic curve 1.445 + @param dy2 The amount to add to the y-coordinate of the last point on 1.446 + this contour, to specify the 2nd control point of a cubic curve 1.447 + @param dx3 The amount to add to the x-coordinate of the last point on 1.448 + this contour, to specify the end point of a cubic curve 1.449 + @param dy3 The amount to add to the y-coordinate of the last point on 1.450 + this contour, to specify the end point of a cubic curve 1.451 + */ 1.452 + void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 1.453 + SkScalar x3, SkScalar y3); 1.454 + 1.455 + /** Append the specified arc to the path as a new contour. If the start of 1.456 + the path is different from the path's current last point, then an 1.457 + automatic lineTo() is added to connect the current contour to the start 1.458 + of the arc. However, if the path is empty, then we call moveTo() with 1.459 + the first point of the arc. The sweep angle is treated mod 360. 1.460 + 1.461 + @param oval The bounding oval defining the shape and size of the arc 1.462 + @param startAngle Starting angle (in degrees) where the arc begins 1.463 + @param sweepAngle Sweep angle (in degrees) measured clockwise. This is 1.464 + treated mod 360. 1.465 + @param forceMoveTo If true, always begin a new contour with the arc 1.466 + */ 1.467 + void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 1.468 + bool forceMoveTo); 1.469 + 1.470 + /** Append a line and arc to the current path. This is the same as the 1.471 + PostScript call "arct". 1.472 + */ 1.473 + void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 1.474 + SkScalar radius); 1.475 + 1.476 + /** Append a line and arc to the current path. This is the same as the 1.477 + PostScript call "arct". 1.478 + */ 1.479 + void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) { 1.480 + this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius); 1.481 + } 1.482 + 1.483 + /** Close the current contour. If the current point is not equal to the 1.484 + first point of the contour, a line segment is automatically added. 1.485 + */ 1.486 + void close(); 1.487 + 1.488 + enum Direction { 1.489 + /** Direction either has not been or could not be computed */ 1.490 + kUnknown_Direction, 1.491 + /** clockwise direction for adding closed contours */ 1.492 + kCW_Direction, 1.493 + /** counter-clockwise direction for adding closed contours */ 1.494 + kCCW_Direction, 1.495 + }; 1.496 + 1.497 + /** 1.498 + * Return the opposite of the specified direction. kUnknown is its own 1.499 + * opposite. 1.500 + */ 1.501 + static Direction OppositeDirection(Direction dir) { 1.502 + static const Direction gOppositeDir[] = { 1.503 + kUnknown_Direction, kCCW_Direction, kCW_Direction 1.504 + }; 1.505 + return gOppositeDir[dir]; 1.506 + } 1.507 + 1.508 + /** 1.509 + * Returns whether or not a fill type is inverted 1.510 + * 1.511 + * kWinding_FillType -> false 1.512 + * kEvenOdd_FillType -> false 1.513 + * kInverseWinding_FillType -> true 1.514 + * kInverseEvenOdd_FillType -> true 1.515 + */ 1.516 + static bool IsInverseFillType(FillType fill) { 1.517 + SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch); 1.518 + SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch); 1.519 + SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch); 1.520 + SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch); 1.521 + return (fill & 2) != 0; 1.522 + } 1.523 + 1.524 + /** 1.525 + * Returns the equivalent non-inverted fill type to the given fill type 1.526 + * 1.527 + * kWinding_FillType -> kWinding_FillType 1.528 + * kEvenOdd_FillType -> kEvenOdd_FillType 1.529 + * kInverseWinding_FillType -> kWinding_FillType 1.530 + * kInverseEvenOdd_FillType -> kEvenOdd_FillType 1.531 + */ 1.532 + static FillType ConvertToNonInverseFillType(FillType fill) { 1.533 + SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch); 1.534 + SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch); 1.535 + SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch); 1.536 + SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch); 1.537 + return (FillType)(fill & 1); 1.538 + } 1.539 + 1.540 + /** 1.541 + * Tries to quickly compute the direction of the first non-degenerate 1.542 + * contour. If it can be computed, return true and set dir to that 1.543 + * direction. If it cannot be (quickly) determined, return false and ignore 1.544 + * the dir parameter. If the direction was determined, it is cached to make 1.545 + * subsequent calls return quickly. 1.546 + */ 1.547 + bool cheapComputeDirection(Direction* dir) const; 1.548 + 1.549 + /** 1.550 + * Returns true if the path's direction can be computed via 1.551 + * cheapComputDirection() and if that computed direction matches the 1.552 + * specified direction. If dir is kUnknown, returns true if the direction 1.553 + * cannot be computed. 1.554 + */ 1.555 + bool cheapIsDirection(Direction dir) const { 1.556 + Direction computedDir = kUnknown_Direction; 1.557 + (void)this->cheapComputeDirection(&computedDir); 1.558 + return computedDir == dir; 1.559 + } 1.560 + 1.561 + enum PathAsRect { 1.562 + /** The path can not draw the same as its bounds. */ 1.563 + kNone_PathAsRect, 1.564 + /** The path draws the same as its bounds when filled. */ 1.565 + kFill_PathAsRect, 1.566 + /** The path draws the same as its bounds when stroked or filled. */ 1.567 + kStroke_PathAsRect, 1.568 + }; 1.569 + 1.570 + /** Returns kFill_PathAsRect or kStroke_PathAsRect if drawing the path (either filled or 1.571 + stroked) will be equivalent to filling/stroking the path's bounding rect. If 1.572 + either is true, and direction is not null, sets the direction of the contour. If the 1.573 + path is not drawn equivalent to a rect, returns kNone_PathAsRect and ignores direction. 1.574 + 1.575 + @param direction If not null, set to the contour's direction when it is drawn as a rect 1.576 + @return the path's PathAsRect type 1.577 + */ 1.578 + PathAsRect asRect(Direction* direction = NULL) const; 1.579 + 1.580 + /** Returns true if the path specifies a rectangle. If so, and if isClosed is 1.581 + not null, set isClosed to true if the path is closed. Also, if returning true 1.582 + and direction is not null, return the rect direction. If the path does not 1.583 + specify a rectangle, return false and ignore isClosed and direction. 1.584 + 1.585 + @param isClosed If not null, set to true if the path is closed 1.586 + @param direction If not null, set to the rectangle's direction 1.587 + @return true if the path specifies a rectangle 1.588 + */ 1.589 + bool isRect(bool* isClosed, Direction* direction) const; 1.590 + 1.591 + /** Returns true if the path specifies a pair of nested rectangles. If so, and if 1.592 + rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner 1.593 + rectangle. If so, and dirs is not null, set dirs[0] to the direction of 1.594 + the outer rectangle and dirs[1] to the direction of the inner rectangle. If 1.595 + the path does not specify a pair of nested rectangles, return 1.596 + false and ignore rect and dirs. 1.597 + 1.598 + @param rect If not null, returns the path as a pair of nested rectangles 1.599 + @param dirs If not null, returns the direction of the rects 1.600 + @return true if the path describes a pair of nested rectangles 1.601 + */ 1.602 + bool isNestedRects(SkRect rect[2], Direction dirs[2] = NULL) const; 1.603 + 1.604 + /** 1.605 + * Add a closed rectangle contour to the path 1.606 + * @param rect The rectangle to add as a closed contour to the path 1.607 + * @param dir The direction to wind the rectangle's contour. Cannot be 1.608 + * kUnknown_Direction. 1.609 + */ 1.610 + void addRect(const SkRect& rect, Direction dir = kCW_Direction); 1.611 + 1.612 + /** 1.613 + * Add a closed rectangle contour to the path 1.614 + * 1.615 + * @param left The left side of a rectangle to add as a closed contour 1.616 + * to the path 1.617 + * @param top The top of a rectangle to add as a closed contour to the 1.618 + * path 1.619 + * @param right The right side of a rectangle to add as a closed contour 1.620 + * to the path 1.621 + * @param bottom The bottom of a rectangle to add as a closed contour to 1.622 + * the path 1.623 + * @param dir The direction to wind the rectangle's contour. Cannot be 1.624 + * kUnknown_Direction. 1.625 + */ 1.626 + void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, 1.627 + Direction dir = kCW_Direction); 1.628 + 1.629 + /** 1.630 + * Add a closed oval contour to the path 1.631 + * 1.632 + * @param oval The bounding oval to add as a closed contour to the path 1.633 + * @param dir The direction to wind the oval's contour. Cannot be 1.634 + * kUnknown_Direction. 1.635 + */ 1.636 + void addOval(const SkRect& oval, Direction dir = kCW_Direction); 1.637 + 1.638 + /** 1.639 + * Add a closed circle contour to the path 1.640 + * 1.641 + * @param x The x-coordinate of the center of a circle to add as a 1.642 + * closed contour to the path 1.643 + * @param y The y-coordinate of the center of a circle to add as a 1.644 + * closed contour to the path 1.645 + * @param radius The radius of a circle to add as a closed contour to the 1.646 + * path 1.647 + * @param dir The direction to wind the circle's contour. Cannot be 1.648 + * kUnknown_Direction. 1.649 + */ 1.650 + void addCircle(SkScalar x, SkScalar y, SkScalar radius, 1.651 + Direction dir = kCW_Direction); 1.652 + 1.653 + /** Add the specified arc to the path as a new contour. 1.654 + 1.655 + @param oval The bounds of oval used to define the size of the arc 1.656 + @param startAngle Starting angle (in degrees) where the arc begins 1.657 + @param sweepAngle Sweep angle (in degrees) measured clockwise 1.658 + */ 1.659 + void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle); 1.660 + 1.661 + /** 1.662 + * Add a closed round-rectangle contour to the path 1.663 + * @param rect The bounds of a round-rectangle to add as a closed contour 1.664 + * @param rx The x-radius of the rounded corners on the round-rectangle 1.665 + * @param ry The y-radius of the rounded corners on the round-rectangle 1.666 + * @param dir The direction to wind the rectangle's contour. Cannot be 1.667 + * kUnknown_Direction. 1.668 + */ 1.669 + void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, 1.670 + Direction dir = kCW_Direction); 1.671 + 1.672 + /** 1.673 + * Add a closed round-rectangle contour to the path. Each corner receives 1.674 + * two radius values [X, Y]. The corners are ordered top-left, top-right, 1.675 + * bottom-right, bottom-left. 1.676 + * @param rect The bounds of a round-rectangle to add as a closed contour 1.677 + * @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner 1.678 + * @param dir The direction to wind the rectangle's contour. Cannot be 1.679 + * kUnknown_Direction. 1.680 + * Note: The radii here now go through the same constraint handling as the 1.681 + * SkRRect radii (i.e., either radii at a corner being 0 implies a 1.682 + * sqaure corner and oversized radii are proportionally scaled down). 1.683 + */ 1.684 + void addRoundRect(const SkRect& rect, const SkScalar radii[], 1.685 + Direction dir = kCW_Direction); 1.686 + 1.687 + /** 1.688 + * Add an SkRRect contour to the path 1.689 + * @param rrect The rounded rect to add as a closed contour 1.690 + * @param dir The winding direction for the new contour. Cannot be 1.691 + * kUnknown_Direction. 1.692 + */ 1.693 + void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction); 1.694 + 1.695 + /** 1.696 + * Add a new contour made of just lines. This is just a fast version of 1.697 + * the following: 1.698 + * this->moveTo(pts[0]); 1.699 + * for (int i = 1; i < count; ++i) { 1.700 + * this->lineTo(pts[i]); 1.701 + * } 1.702 + * if (close) { 1.703 + * this->close(); 1.704 + * } 1.705 + */ 1.706 + void addPoly(const SkPoint pts[], int count, bool close); 1.707 + 1.708 + enum AddPathMode { 1.709 + /** Source path contours are added as new contours. 1.710 + */ 1.711 + kAppend_AddPathMode, 1.712 + /** Path is added by extending the last contour of the destination path 1.713 + with the first contour of the source path. If the last contour of 1.714 + the destination path is closed, then it will not be extended. 1.715 + Instead, the start of source path will be extended by a straight 1.716 + line to the end point of the destination path. 1.717 + */ 1.718 + kExtend_AddPathMode 1.719 + }; 1.720 + 1.721 + /** Add a copy of src to the path, offset by (dx,dy) 1.722 + @param src The path to add as a new contour 1.723 + @param dx The amount to translate the path in X as it is added 1.724 + @param dx The amount to translate the path in Y as it is added 1.725 + */ 1.726 + void addPath(const SkPath& src, SkScalar dx, SkScalar dy, 1.727 + AddPathMode mode = kAppend_AddPathMode); 1.728 + 1.729 + /** Add a copy of src to the path 1.730 + */ 1.731 + void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) { 1.732 + SkMatrix m; 1.733 + m.reset(); 1.734 + this->addPath(src, m, mode); 1.735 + } 1.736 + 1.737 + /** Add a copy of src to the path, transformed by matrix 1.738 + @param src The path to add as a new contour 1.739 + @param matrix Transform applied to src 1.740 + @param mode Determines how path is added 1.741 + */ 1.742 + void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode); 1.743 + 1.744 + /** 1.745 + * Same as addPath(), but reverses the src input 1.746 + */ 1.747 + void reverseAddPath(const SkPath& src); 1.748 + 1.749 + /** Offset the path by (dx,dy), returning true on success 1.750 + 1.751 + @param dx The amount in the X direction to offset the entire path 1.752 + @param dy The amount in the Y direction to offset the entire path 1.753 + @param dst The translated path is written here 1.754 + */ 1.755 + void offset(SkScalar dx, SkScalar dy, SkPath* dst) const; 1.756 + 1.757 + /** Offset the path by (dx,dy), returning true on success 1.758 + 1.759 + @param dx The amount in the X direction to offset the entire path 1.760 + @param dy The amount in the Y direction to offset the entire path 1.761 + */ 1.762 + void offset(SkScalar dx, SkScalar dy) { 1.763 + this->offset(dx, dy, this); 1.764 + } 1.765 + 1.766 + /** Transform the points in this path by matrix, and write the answer into 1.767 + dst. 1.768 + 1.769 + @param matrix The matrix to apply to the path 1.770 + @param dst The transformed path is written here 1.771 + */ 1.772 + void transform(const SkMatrix& matrix, SkPath* dst) const; 1.773 + 1.774 + /** Transform the points in this path by matrix 1.775 + 1.776 + @param matrix The matrix to apply to the path 1.777 + */ 1.778 + void transform(const SkMatrix& matrix) { 1.779 + this->transform(matrix, this); 1.780 + } 1.781 + 1.782 + /** Return the last point on the path. If no points have been added, (0,0) 1.783 + is returned. If there are no points, this returns false, otherwise it 1.784 + returns true. 1.785 + 1.786 + @param lastPt The last point on the path is returned here 1.787 + */ 1.788 + bool getLastPt(SkPoint* lastPt) const; 1.789 + 1.790 + /** Set the last point on the path. If no points have been added, 1.791 + moveTo(x,y) is automatically called. 1.792 + 1.793 + @param x The new x-coordinate for the last point 1.794 + @param y The new y-coordinate for the last point 1.795 + */ 1.796 + void setLastPt(SkScalar x, SkScalar y); 1.797 + 1.798 + /** Set the last point on the path. If no points have been added, moveTo(p) 1.799 + is automatically called. 1.800 + 1.801 + @param p The new location for the last point 1.802 + */ 1.803 + void setLastPt(const SkPoint& p) { 1.804 + this->setLastPt(p.fX, p.fY); 1.805 + } 1.806 + 1.807 + enum SegmentMask { 1.808 + kLine_SegmentMask = 1 << 0, 1.809 + kQuad_SegmentMask = 1 << 1, 1.810 + kConic_SegmentMask = 1 << 2, 1.811 + kCubic_SegmentMask = 1 << 3, 1.812 + }; 1.813 + 1.814 + /** 1.815 + * Returns a mask, where each bit corresponding to a SegmentMask is 1.816 + * set if the path contains 1 or more segments of that type. 1.817 + * Returns 0 for an empty path (no segments). 1.818 + */ 1.819 + uint32_t getSegmentMasks() const { return fPathRef->getSegmentMasks(); } 1.820 + 1.821 + enum Verb { 1.822 + kMove_Verb, //!< iter.next returns 1 point 1.823 + kLine_Verb, //!< iter.next returns 2 points 1.824 + kQuad_Verb, //!< iter.next returns 3 points 1.825 + kConic_Verb, //!< iter.next returns 3 points + iter.conicWeight() 1.826 + kCubic_Verb, //!< iter.next returns 4 points 1.827 + kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt) 1.828 + kDone_Verb, //!< iter.next returns 0 points 1.829 + }; 1.830 + 1.831 + /** Iterate through all of the segments (lines, quadratics, cubics) of 1.832 + each contours in a path. 1.833 + 1.834 + The iterator cleans up the segments along the way, removing degenerate 1.835 + segments and adding close verbs where necessary. When the forceClose 1.836 + argument is provided, each contour (as defined by a new starting 1.837 + move command) will be completed with a close verb regardless of the 1.838 + contour's contents. 1.839 + */ 1.840 + class SK_API Iter { 1.841 + public: 1.842 + Iter(); 1.843 + Iter(const SkPath&, bool forceClose); 1.844 + 1.845 + void setPath(const SkPath&, bool forceClose); 1.846 + 1.847 + /** Return the next verb in this iteration of the path. When all 1.848 + segments have been visited, return kDone_Verb. 1.849 + 1.850 + @param pts The points representing the current verb and/or segment 1.851 + @param doConsumeDegerates If true, first scan for segments that are 1.852 + deemed degenerate (too short) and skip those. 1.853 + @return The verb for the current segment 1.854 + */ 1.855 + Verb next(SkPoint pts[4], bool doConsumeDegerates = true) { 1.856 + if (doConsumeDegerates) { 1.857 + this->consumeDegenerateSegments(); 1.858 + } 1.859 + return this->doNext(pts); 1.860 + } 1.861 + 1.862 + /** 1.863 + * Return the weight for the current conic. Only valid if the current 1.864 + * segment return by next() was a conic. 1.865 + */ 1.866 + SkScalar conicWeight() const { return *fConicWeights; } 1.867 + 1.868 + /** If next() returns kLine_Verb, then this query returns true if the 1.869 + line was the result of a close() command (i.e. the end point is the 1.870 + initial moveto for this contour). If next() returned a different 1.871 + verb, this returns an undefined value. 1.872 + 1.873 + @return If the last call to next() returned kLine_Verb, return true 1.874 + if it was the result of an explicit close command. 1.875 + */ 1.876 + bool isCloseLine() const { return SkToBool(fCloseLine); } 1.877 + 1.878 + /** Returns true if the current contour is closed (has a kClose_Verb) 1.879 + @return true if the current contour is closed (has a kClose_Verb) 1.880 + */ 1.881 + bool isClosedContour() const; 1.882 + 1.883 + private: 1.884 + const SkPoint* fPts; 1.885 + const uint8_t* fVerbs; 1.886 + const uint8_t* fVerbStop; 1.887 + const SkScalar* fConicWeights; 1.888 + SkPoint fMoveTo; 1.889 + SkPoint fLastPt; 1.890 + SkBool8 fForceClose; 1.891 + SkBool8 fNeedClose; 1.892 + SkBool8 fCloseLine; 1.893 + SkBool8 fSegmentState; 1.894 + 1.895 + inline const SkPoint& cons_moveTo(); 1.896 + Verb autoClose(SkPoint pts[2]); 1.897 + void consumeDegenerateSegments(); 1.898 + Verb doNext(SkPoint pts[4]); 1.899 + }; 1.900 + 1.901 + /** Iterate through the verbs in the path, providing the associated points. 1.902 + */ 1.903 + class SK_API RawIter { 1.904 + public: 1.905 + RawIter(); 1.906 + RawIter(const SkPath&); 1.907 + 1.908 + void setPath(const SkPath&); 1.909 + 1.910 + /** Return the next verb in this iteration of the path. When all 1.911 + segments have been visited, return kDone_Verb. 1.912 + 1.913 + @param pts The points representing the current verb and/or segment 1.914 + This must not be NULL. 1.915 + @return The verb for the current segment 1.916 + */ 1.917 + Verb next(SkPoint pts[4]); 1.918 + 1.919 + SkScalar conicWeight() const { return *fConicWeights; } 1.920 + 1.921 + private: 1.922 + const SkPoint* fPts; 1.923 + const uint8_t* fVerbs; 1.924 + const uint8_t* fVerbStop; 1.925 + const SkScalar* fConicWeights; 1.926 + SkPoint fMoveTo; 1.927 + SkPoint fLastPt; 1.928 + }; 1.929 + 1.930 + /** 1.931 + * Returns true if the point { x, y } is contained by the path, taking into 1.932 + * account the FillType. 1.933 + */ 1.934 + bool contains(SkScalar x, SkScalar y) const; 1.935 + 1.936 + void dump(bool forceClose, const char title[] = NULL) const; 1.937 + void dump() const; 1.938 + 1.939 + /** 1.940 + * Write the path to the buffer, and return the number of bytes written. 1.941 + * If buffer is NULL, it still returns the number of bytes. 1.942 + */ 1.943 + size_t writeToMemory(void* buffer) const; 1.944 + /** 1.945 + * Initializes the path from the buffer 1.946 + * 1.947 + * @param buffer Memory to read from 1.948 + * @param length Amount of memory available in the buffer 1.949 + * @return number of bytes read (must be a multiple of 4) or 1.950 + * 0 if there was not enough memory available 1.951 + */ 1.952 + size_t readFromMemory(const void* buffer, size_t length); 1.953 + 1.954 + /** Returns a non-zero, globally unique value corresponding to the set of verbs 1.955 + and points in the path (but not the fill type [except on Android skbug.com/1762]). 1.956 + Each time the path is modified, a different generation ID will be returned. 1.957 + */ 1.958 + uint32_t getGenerationID() const; 1.959 + 1.960 +#ifdef SK_BUILD_FOR_ANDROID 1.961 + static const int kPathRefGenIDBitCnt = 30; // leave room for the fill type (skbug.com/1762) 1.962 + const SkPath* getSourcePath() const; 1.963 + void setSourcePath(const SkPath* path); 1.964 +#else 1.965 + static const int kPathRefGenIDBitCnt = 32; 1.966 +#endif 1.967 + 1.968 + SkDEBUGCODE(void validate() const;) 1.969 + 1.970 +private: 1.971 + enum SerializationOffsets { 1.972 + // 1 free bit at 29 1.973 + kUnused1_SerializationShift = 28, // 1 free bit 1.974 + kDirection_SerializationShift = 26, // requires 2 bits 1.975 + kUnused2_SerializationShift = 25, // 1 free bit 1.976 + // 1 free bit at 24 1.977 + kConvexity_SerializationShift = 16, // requires 8 bits 1.978 + kFillType_SerializationShift = 8, // requires 8 bits 1.979 + // 8 free bits at 0 1.980 + }; 1.981 + 1.982 + SkAutoTUnref<SkPathRef> fPathRef; 1.983 + 1.984 + int fLastMoveToIndex; 1.985 + uint8_t fFillType; 1.986 + mutable uint8_t fConvexity; 1.987 + mutable uint8_t fDirection; 1.988 +#ifdef SK_BUILD_FOR_ANDROID 1.989 + const SkPath* fSourcePath; 1.990 +#endif 1.991 + 1.992 + /** Resets all fields other than fPathRef to their initial 'empty' values. 1.993 + * Assumes the caller has already emptied fPathRef. 1.994 + * On Android increments fGenerationID without reseting it. 1.995 + */ 1.996 + void resetFields(); 1.997 + 1.998 + /** Sets all fields other than fPathRef to the values in 'that'. 1.999 + * Assumes the caller has already set fPathRef. 1.1000 + * Doesn't change fGenerationID or fSourcePath on Android. 1.1001 + */ 1.1002 + void copyFields(const SkPath& that); 1.1003 + 1.1004 + friend class Iter; 1.1005 + 1.1006 + friend class SkPathStroker; 1.1007 + 1.1008 + /* Append, in reverse order, the first contour of path, ignoring path's 1.1009 + last point. If no moveTo() call has been made for this contour, the 1.1010 + first point is automatically set to (0,0). 1.1011 + */ 1.1012 + void reversePathTo(const SkPath&); 1.1013 + 1.1014 + // called before we add points for lineTo, quadTo, cubicTo, checking to see 1.1015 + // if we need to inject a leading moveTo first 1.1016 + // 1.1017 + // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0) 1.1018 + // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo) 1.1019 + // 1.1020 + inline void injectMoveToIfNeeded(); 1.1021 + 1.1022 + inline bool hasOnlyMoveTos() const; 1.1023 + 1.1024 + Convexity internalGetConvexity() const; 1.1025 + 1.1026 + bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts, 1.1027 + bool* isClosed, Direction* direction) const; 1.1028 + 1.1029 + /** Returns if the path can return a bound at no cost (true) or will have to 1.1030 + perform some computation (false). 1.1031 + */ 1.1032 + bool hasComputedBounds() const { 1.1033 + SkDEBUGCODE(this->validate();) 1.1034 + return fPathRef->hasComputedBounds(); 1.1035 + } 1.1036 + 1.1037 + 1.1038 + // 'rect' needs to be sorted 1.1039 + void setBounds(const SkRect& rect) { 1.1040 + SkPathRef::Editor ed(&fPathRef); 1.1041 + 1.1042 + ed.setBounds(rect); 1.1043 + } 1.1044 + 1.1045 + friend class SkAutoPathBoundsUpdate; 1.1046 + friend class SkAutoDisableOvalCheck; 1.1047 + friend class SkAutoDisableDirectionCheck; 1.1048 + friend class SkBench_AddPathTest; // perf test reversePathTo 1.1049 + friend class PathTest_Private; // unit test reversePathTo 1.1050 +}; 1.1051 + 1.1052 +#endif