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