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