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