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