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