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