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