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