SkPath.h revision f6d3c5aa5f93e4c3cc7a7aebf014e960cf837783
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 //! Swap contents of this and other. Guaranteed not to throw 263 void swap(SkPath& other); 264 265 /** Returns the bounds of the path's points. If the path contains 0 or 1 266 points, the bounds is set to (0,0,0,0), and isEmpty() will return true. 267 Note: this bounds may be larger than the actual shape, since curves 268 do not extend as far as their control points. 269 */ 270 const SkRect& getBounds() const { 271 if (fBoundsIsDirty) { 272 this->computeBounds(); 273 } 274 return fBounds; 275 } 276 277 /** Calling this will, if the internal cache of the bounds is out of date, 278 update it so that subsequent calls to getBounds will be instanteous. 279 This also means that any copies or simple transformations of the path 280 will inherit the cached bounds. 281 */ 282 void updateBoundsCache() const { 283 // for now, just calling getBounds() is sufficient 284 this->getBounds(); 285 } 286 287 // Construction methods 288 289 /** Hint to the path to prepare for adding more points. This can allow the 290 path to more efficiently grow its storage. 291 292 @param extraPtCount The number of extra points the path should 293 preallocate for. 294 */ 295 void incReserve(unsigned extraPtCount); 296 297 /** Set the beginning of the next contour to the point (x,y). 298 299 @param x The x-coordinate of the start of a new contour 300 @param y The y-coordinate of the start of a new contour 301 */ 302 void moveTo(SkScalar x, SkScalar y); 303 304 /** Set the beginning of the next contour to the point 305 306 @param p The start of a new contour 307 */ 308 void moveTo(const SkPoint& p) { 309 this->moveTo(p.fX, p.fY); 310 } 311 312 /** Set the beginning of the next contour relative to the last point on the 313 previous contour. If there is no previous contour, this is treated the 314 same as moveTo(). 315 316 @param dx The amount to add to the x-coordinate of the end of the 317 previous contour, to specify the start of a new contour 318 @param dy The amount to add to the y-coordinate of the end of the 319 previous contour, to specify the start of a new contour 320 */ 321 void rMoveTo(SkScalar dx, SkScalar dy); 322 323 /** Add a line from the last point to the specified point (x,y). If no 324 moveTo() call has been made for this contour, the first point is 325 automatically set to (0,0). 326 327 @param x The x-coordinate of the end of a line 328 @param y The y-coordinate of the end of a line 329 */ 330 void lineTo(SkScalar x, SkScalar y); 331 332 /** Add a line from the last point to the specified point. If no moveTo() 333 call has been made for this contour, the first point is automatically 334 set to (0,0). 335 336 @param p The end of a line 337 */ 338 void lineTo(const SkPoint& p) { 339 this->lineTo(p.fX, p.fY); 340 } 341 342 /** Same as lineTo, but the coordinates are considered relative to the last 343 point on this contour. If there is no previous point, then a moveTo(0,0) 344 is inserted automatically. 345 346 @param dx The amount to add to the x-coordinate of the previous point 347 on this contour, to specify a line 348 @param dy The amount to add to the y-coordinate of the previous point 349 on this contour, to specify a line 350 */ 351 void rLineTo(SkScalar dx, SkScalar dy); 352 353 /** Add a quadratic bezier from the last point, approaching control point 354 (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for 355 this contour, the first point is automatically set to (0,0). 356 357 @param x1 The x-coordinate of the control point on a quadratic curve 358 @param y1 The y-coordinate of the control point on a quadratic curve 359 @param x2 The x-coordinate of the end point on a quadratic curve 360 @param y2 The y-coordinate of the end point on a quadratic curve 361 */ 362 void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2); 363 364 /** Add a quadratic bezier from the last point, approaching control point 365 p1, and ending at p2. If no moveTo() call has been made for this 366 contour, the first point is automatically set to (0,0). 367 368 @param p1 The control point on a quadratic curve 369 @param p2 The end point on a quadratic curve 370 */ 371 void quadTo(const SkPoint& p1, const SkPoint& p2) { 372 this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY); 373 } 374 375 /** Same as quadTo, but the coordinates are considered relative to the last 376 point on this contour. If there is no previous point, then a moveTo(0,0) 377 is inserted automatically. 378 379 @param dx1 The amount to add to the x-coordinate of the last point on 380 this contour, to specify the control point of a quadratic curve 381 @param dy1 The amount to add to the y-coordinate of the last point on 382 this contour, to specify the control point of a quadratic curve 383 @param dx2 The amount to add to the x-coordinate of the last point on 384 this contour, to specify the end point of a quadratic curve 385 @param dy2 The amount to add to the y-coordinate of the last point on 386 this contour, to specify the end point of a quadratic curve 387 */ 388 void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2); 389 390 /** Add a cubic bezier from the last point, approaching control points 391 (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been 392 made for this contour, the first point is automatically set to (0,0). 393 394 @param x1 The x-coordinate of the 1st control point on a cubic curve 395 @param y1 The y-coordinate of the 1st control point on a cubic curve 396 @param x2 The x-coordinate of the 2nd control point on a cubic curve 397 @param y2 The y-coordinate of the 2nd control point on a cubic curve 398 @param x3 The x-coordinate of the end point on a cubic curve 399 @param y3 The y-coordinate of the end point on a cubic curve 400 */ 401 void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 402 SkScalar x3, SkScalar y3); 403 404 /** Add a cubic bezier from the last point, approaching control points p1 405 and p2, and ending at p3. If no moveTo() call has been made for this 406 contour, the first point is automatically set to (0,0). 407 408 @param p1 The 1st control point on a cubic curve 409 @param p2 The 2nd control point on a cubic curve 410 @param p3 The end point on a cubic curve 411 */ 412 void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) { 413 this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY); 414 } 415 416 /** Same as cubicTo, but the coordinates are considered relative to the 417 current point on this contour. If there is no previous point, then a 418 moveTo(0,0) is inserted automatically. 419 420 @param dx1 The amount to add to the x-coordinate of the last point on 421 this contour, to specify the 1st control point of a cubic curve 422 @param dy1 The amount to add to the y-coordinate of the last point on 423 this contour, to specify the 1st control point of a cubic curve 424 @param dx2 The amount to add to the x-coordinate of the last point on 425 this contour, to specify the 2nd control point of a cubic curve 426 @param dy2 The amount to add to the y-coordinate of the last point on 427 this contour, to specify the 2nd control point of a cubic curve 428 @param dx3 The amount to add to the x-coordinate of the last point on 429 this contour, to specify the end point of a cubic curve 430 @param dy3 The amount to add to the y-coordinate of the last point on 431 this contour, to specify the end point of a cubic curve 432 */ 433 void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 434 SkScalar x3, SkScalar y3); 435 436 /** Append the specified arc to the path as a new contour. If the start of 437 the path is different from the path's current last point, then an 438 automatic lineTo() is added to connect the current contour to the start 439 of the arc. However, if the path is empty, then we call moveTo() with 440 the first point of the arc. The sweep angle is treated mod 360. 441 442 @param oval The bounding oval defining the shape and size of the arc 443 @param startAngle Starting angle (in degrees) where the arc begins 444 @param sweepAngle Sweep angle (in degrees) measured clockwise. This is 445 treated mod 360. 446 @param forceMoveTo If true, always begin a new contour with the arc 447 */ 448 void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 449 bool forceMoveTo); 450 451 /** Append a line and arc to the current path. This is the same as the 452 PostScript call "arct". 453 */ 454 void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 455 SkScalar radius); 456 457 /** Append a line and arc to the current path. This is the same as the 458 PostScript call "arct". 459 */ 460 void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) { 461 this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius); 462 } 463 464 /** Close the current contour. If the current point is not equal to the 465 first point of the contour, a line segment is automatically added. 466 */ 467 void close(); 468 469 enum Direction { 470 /** clockwise direction for adding closed contours */ 471 kCW_Direction, 472 /** counter-clockwise direction for adding closed contours */ 473 kCCW_Direction 474 }; 475 476 /** 477 * Tries to quickly compute the direction of the first non-degenerate 478 * contour. If it can be computed, return true and set dir to that 479 * direction. If it cannot be (quickly) determined, return false and ignore 480 * the dir parameter. 481 */ 482 bool cheapComputeDirection(Direction* dir) const; 483 484 /** 485 * Returns true if the path's direction can be computed via 486 * cheapComputDirection() and if that computed direction matches the 487 * specified direction. 488 */ 489 bool cheapIsDirection(Direction dir) const { 490 Direction computedDir; 491 return this->cheapComputeDirection(&computedDir) && computedDir == dir; 492 } 493 494 /** Add a closed rectangle contour to the path 495 @param rect The rectangle to add as a closed contour to the path 496 @param dir The direction to wind the rectangle's contour 497 */ 498 void addRect(const SkRect& rect, Direction dir = kCW_Direction); 499 500 /** Add a closed rectangle contour to the path 501 502 @param left The left side of a rectangle to add as a closed contour 503 to the path 504 @param top The top of a rectangle to add as a closed contour to the 505 path 506 @param right The right side of a rectangle to add as a closed contour 507 to the path 508 @param bottom The bottom of a rectangle to add as a closed contour to 509 the path 510 @param dir The direction to wind the rectangle's contour 511 */ 512 void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, 513 Direction dir = kCW_Direction); 514 515 /** Add a closed oval contour to the path 516 517 @param oval The bounding oval to add as a closed contour to the path 518 @param dir The direction to wind the oval's contour 519 */ 520 void addOval(const SkRect& oval, Direction dir = kCW_Direction); 521 522 /** Add a closed circle contour to the path 523 524 @param x The x-coordinate of the center of a circle to add as a 525 closed contour to the path 526 @param y The y-coordinate of the center of a circle to add as a 527 closed contour to the path 528 @param radius The radius of a circle to add as a closed contour to the 529 path 530 @param dir The direction to wind the circle's contour 531 */ 532 void addCircle(SkScalar x, SkScalar y, SkScalar radius, 533 Direction dir = kCW_Direction); 534 535 /** Add the specified arc to the path as a new contour. 536 537 @param oval The bounds of oval used to define the size of the arc 538 @param startAngle Starting angle (in degrees) where the arc begins 539 @param sweepAngle Sweep angle (in degrees) measured clockwise 540 */ 541 void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle); 542 543 /** Add a closed round-rectangle contour to the path 544 @param rect The bounds of a round-rectangle to add as a closed contour 545 @param rx The x-radius of the rounded corners on the round-rectangle 546 @param ry The y-radius of the rounded corners on the round-rectangle 547 @param dir The direction to wind the round-rectangle's contour 548 */ 549 void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, 550 Direction dir = kCW_Direction); 551 552 /** Add a closed round-rectangle contour to the path. Each corner receives 553 two radius values [X, Y]. The corners are ordered top-left, top-right, 554 bottom-right, bottom-left. 555 @param rect The bounds of a round-rectangle to add as a closed contour 556 @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner 557 @param dir The direction to wind the round-rectangle's contour 558 */ 559 void addRoundRect(const SkRect& rect, const SkScalar radii[], 560 Direction dir = kCW_Direction); 561 562 /** 563 * Add a new contour made of just lines. This is just a fast version of 564 * the following: 565 * this->moveTo(pts[0]); 566 * for (int i = 1; i < count; ++i) { 567 * this->lineTo(pts[i]); 568 * } 569 * if (close) { 570 * this->close(); 571 * } 572 */ 573 void addPoly(const SkPoint pts[], int count, bool close); 574 575 /** Add a copy of src to the path, offset by (dx,dy) 576 @param src The path to add as a new contour 577 @param dx The amount to translate the path in X as it is added 578 @param dx The amount to translate the path in Y as it is added 579 */ 580 void addPath(const SkPath& src, SkScalar dx, SkScalar dy); 581 582 /** Add a copy of src to the path 583 */ 584 void addPath(const SkPath& src) { 585 SkMatrix m; 586 m.reset(); 587 this->addPath(src, m); 588 } 589 590 /** Add a copy of src to the path, transformed by matrix 591 @param src The path to add as a new contour 592 */ 593 void addPath(const SkPath& src, const SkMatrix& matrix); 594 595 /** 596 * Same as addPath(), but reverses the src input 597 */ 598 void reverseAddPath(const SkPath& src); 599 600 /** Offset the path by (dx,dy), returning true on success 601 602 @param dx The amount in the X direction to offset the entire path 603 @param dy The amount in the Y direction to offset the entire path 604 @param dst The translated path is written here 605 */ 606 void offset(SkScalar dx, SkScalar dy, SkPath* dst) const; 607 608 /** Offset the path by (dx,dy), returning true on success 609 610 @param dx The amount in the X direction to offset the entire path 611 @param dy The amount in the Y direction to offset the entire path 612 */ 613 void offset(SkScalar dx, SkScalar dy) { 614 this->offset(dx, dy, this); 615 } 616 617 /** Transform the points in this path by matrix, and write the answer into 618 dst. 619 620 @param matrix The matrix to apply to the path 621 @param dst The transformed path is written here 622 */ 623 void transform(const SkMatrix& matrix, SkPath* dst) const; 624 625 /** Transform the points in this path by matrix 626 627 @param matrix The matrix to apply to the path 628 */ 629 void transform(const SkMatrix& matrix) { 630 this->transform(matrix, this); 631 } 632 633 /** Return the last point on the path. If no points have been added, (0,0) 634 is returned. If there are no points, this returns false, otherwise it 635 returns true. 636 637 @param lastPt The last point on the path is returned here 638 */ 639 bool getLastPt(SkPoint* lastPt) const; 640 641 /** Set the last point on the path. If no points have been added, 642 moveTo(x,y) is automatically called. 643 644 @param x The new x-coordinate for the last point 645 @param y The new y-coordinate for the last point 646 */ 647 void setLastPt(SkScalar x, SkScalar y); 648 649 /** Set the last point on the path. If no points have been added, moveTo(p) 650 is automatically called. 651 652 @param p The new location for the last point 653 */ 654 void setLastPt(const SkPoint& p) { 655 this->setLastPt(p.fX, p.fY); 656 } 657 658 enum SegmentMask { 659 kLine_SegmentMask = 1 << 0, 660 kQuad_SegmentMask = 1 << 1, 661 kCubic_SegmentMask = 1 << 2 662 }; 663 664 /** 665 * Returns a mask, where each bit corresponding to a SegmentMask is 666 * set if the path contains 1 or more segments of that type. 667 * Returns 0 for an empty path (no segments). 668 */ 669 uint32_t getSegmentMasks() const { return fSegmentMask; } 670 671 enum Verb { 672 kMove_Verb, //!< iter.next returns 1 point 673 kLine_Verb, //!< iter.next returns 2 points 674 kQuad_Verb, //!< iter.next returns 3 points 675 kCubic_Verb, //!< iter.next returns 4 points 676 kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt) 677 kDone_Verb //!< iter.next returns 0 points 678 }; 679 680 /** Iterate through all of the segments (lines, quadratics, cubics) of 681 each contours in a path. 682 683 The iterator cleans up the segments along the way, removing degenerate 684 segments and adding close verbs where necessary. When the forceClose 685 argument is provided, each contour (as defined by a new starting 686 move command) will be completed with a close verb regardless of the 687 contour's contents. 688 */ 689 class SK_API Iter { 690 public: 691 Iter(); 692 Iter(const SkPath&, bool forceClose); 693 694 void setPath(const SkPath&, bool forceClose); 695 696 /** Return the next verb in this iteration of the path. When all 697 segments have been visited, return kDone_Verb. 698 699 @param pts The points representing the current verb and/or segment 700 @param doConsumeDegerates If true, first scan for segments that are 701 deemed degenerate (too short) and skip those. 702 @return The verb for the current segment 703 */ 704 Verb next(SkPoint pts[4], bool doConsumeDegerates = true) { 705 if (doConsumeDegerates) { 706 this->consumeDegenerateSegments(); 707 } 708 return this->doNext(pts); 709 } 710 711 /** If next() returns kLine_Verb, then this query returns true if the 712 line was the result of a close() command (i.e. the end point is the 713 initial moveto for this contour). If next() returned a different 714 verb, this returns an undefined value. 715 716 @return If the last call to next() returned kLine_Verb, return true 717 if it was the result of an explicit close command. 718 */ 719 bool isCloseLine() const { return SkToBool(fCloseLine); } 720 721 /** Returns true if the current contour is closed (has a kClose_Verb) 722 @return true if the current contour is closed (has a kClose_Verb) 723 */ 724 bool isClosedContour() const; 725 726 private: 727 const SkPoint* fPts; 728 const uint8_t* fVerbs; 729 const uint8_t* fVerbStop; 730 SkPoint fMoveTo; 731 SkPoint fLastPt; 732 SkBool8 fForceClose; 733 SkBool8 fNeedClose; 734 SkBool8 fCloseLine; 735 SkBool8 fSegmentState; 736 737 inline const SkPoint& cons_moveTo(); 738 Verb autoClose(SkPoint pts[2]); 739 void consumeDegenerateSegments(); 740 Verb doNext(SkPoint pts[4]); 741 }; 742 743 /** Iterate through the verbs in the path, providing the associated points. 744 */ 745 class SK_API RawIter { 746 public: 747 RawIter(); 748 RawIter(const SkPath&); 749 750 void setPath(const SkPath&); 751 752 /** Return the next verb in this iteration of the path. When all 753 segments have been visited, return kDone_Verb. 754 755 @param pts The points representing the current verb and/or segment 756 This must not be NULL. 757 @return The verb for the current segment 758 */ 759 Verb next(SkPoint pts[4]); 760 761 private: 762 const SkPoint* fPts; 763 const uint8_t* fVerbs; 764 const uint8_t* fVerbStop; 765 SkPoint fMoveTo; 766 SkPoint fLastPt; 767 }; 768 769 void dump(bool forceClose, const char title[] = NULL) const; 770 void dump() const; 771 772 void flatten(SkWriter32&) const; 773 void unflatten(SkReader32&); 774 775#ifdef SK_BUILD_FOR_ANDROID 776 uint32_t getGenerationID() const; 777 const SkPath* getSourcePath() const; 778 void setSourcePath(const SkPath* path); 779#endif 780 781 SkDEBUGCODE(void validate() const;) 782 783private: 784 SkTDArray<SkPoint> fPts; 785 SkTDArray<uint8_t> fVerbs; 786 mutable SkRect fBounds; 787 int fLastMoveToIndex; 788 uint8_t fFillType; 789 uint8_t fSegmentMask; 790 mutable uint8_t fBoundsIsDirty; 791 mutable uint8_t fConvexity; 792 793 mutable SkBool8 fIsOval; 794#ifdef SK_BUILD_FOR_ANDROID 795 uint32_t fGenerationID; 796 const SkPath* fSourcePath; 797#endif 798 799 // called, if dirty, by getBounds() 800 void computeBounds() const; 801 802 friend class Iter; 803 804 friend class SkPathStroker; 805 /* Append the first contour of path, ignoring path's initial point. If no 806 moveTo() call has been made for this contour, the first point is 807 automatically set to (0,0). 808 */ 809 void pathTo(const SkPath& path); 810 811 /* Append, in reverse order, the first contour of path, ignoring path's 812 last point. If no moveTo() call has been made for this contour, the 813 first point is automatically set to (0,0). 814 */ 815 void reversePathTo(const SkPath&); 816 817 // called before we add points for lineTo, quadTo, cubicTo, checking to see 818 // if we need to inject a leading moveTo first 819 // 820 // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0) 821 // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo) 822 // 823 inline void injectMoveToIfNeeded(); 824 825 inline bool hasOnlyMoveTos() const; 826 827 friend class SkAutoPathBoundsUpdate; 828 friend class SkAutoDisableOvalCheck; 829}; 830 831#endif 832