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