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