SkPath.h revision dd68f4533b6ba7310ebec82e2442efb00c583e73
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 IsInverseFillType((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 /** Return the number of points in the path 250 */ 251 int countPoints() const; 252 253 /** Return the point at the specified index. If the index is out of range 254 (i.e. is not 0 <= index < countPoints()) then the returned coordinates 255 will be (0,0) 256 */ 257 SkPoint getPoint(int index) const; 258 259 /** Returns the number of points in the path. Up to max points are copied. 260 261 @param points If not null, receives up to max points 262 @param max The maximum number of points to copy into points 263 @return the actual number of points in the path 264 */ 265 int getPoints(SkPoint points[], int max) const; 266 267 /** Return the number of verbs in the path 268 */ 269 int countVerbs() const; 270 271 /** Returns the number of verbs in the path. Up to max verbs are copied. The 272 verbs are copied as one byte per verb. 273 274 @param verbs If not null, receives up to max verbs 275 @param max The maximum number of verbs to copy into verbs 276 @return the actual number of verbs in the path 277 */ 278 int getVerbs(uint8_t verbs[], int max) const; 279 280 //! Swap contents of this and other. Guaranteed not to throw 281 void swap(SkPath& other); 282 283 /** Returns the bounds of the path's points. If the path contains 0 or 1 284 points, the bounds is set to (0,0,0,0), and isEmpty() will return true. 285 Note: this bounds may be larger than the actual shape, since curves 286 do not extend as far as their control points. 287 */ 288 const SkRect& getBounds() const { 289 if (fBoundsIsDirty) { 290 this->computeBounds(); 291 } 292 return fBounds; 293 } 294 295 /** Calling this will, if the internal cache of the bounds is out of date, 296 update it so that subsequent calls to getBounds will be instantaneous. 297 This also means that any copies or simple transformations of the path 298 will inherit the cached bounds. 299 */ 300 void updateBoundsCache() const { 301 // for now, just calling getBounds() is sufficient 302 this->getBounds(); 303 } 304 305 /** 306 * Does a conservative test to see whether a rectangle is inside a path. Currently it only 307 * will ever return true for single convex contour paths. The empty-status of the rect is not 308 * considered (e.g. a rect that is a point can be inside a path). Points or line segments where 309 * the rect edge touches the path border are not considered containment violations. 310 */ 311 bool conservativelyContainsRect(const SkRect& rect) const; 312 313 // Construction methods 314 315 /** Hint to the path to prepare for adding more points. This can allow the 316 path to more efficiently grow its storage. 317 318 @param extraPtCount The number of extra points the path should 319 preallocate for. 320 */ 321 void incReserve(unsigned extraPtCount); 322 323 /** Set the beginning of the next contour to the point (x,y). 324 325 @param x The x-coordinate of the start of a new contour 326 @param y The y-coordinate of the start of a new contour 327 */ 328 void moveTo(SkScalar x, SkScalar y); 329 330 /** Set the beginning of the next contour to the point 331 332 @param p The start of a new contour 333 */ 334 void moveTo(const SkPoint& p) { 335 this->moveTo(p.fX, p.fY); 336 } 337 338 /** Set the beginning of the next contour relative to the last point on the 339 previous contour. If there is no previous contour, this is treated the 340 same as moveTo(). 341 342 @param dx The amount to add to the x-coordinate of the end of the 343 previous contour, to specify the start of a new contour 344 @param dy The amount to add to the y-coordinate of the end of the 345 previous contour, to specify the start of a new contour 346 */ 347 void rMoveTo(SkScalar dx, SkScalar dy); 348 349 /** Add a line from the last point to the specified point (x,y). If no 350 moveTo() call has been made for this contour, the first point is 351 automatically set to (0,0). 352 353 @param x The x-coordinate of the end of a line 354 @param y The y-coordinate of the end of a line 355 */ 356 void lineTo(SkScalar x, SkScalar y); 357 358 /** Add a line from the last point to the specified point. If no moveTo() 359 call has been made for this contour, the first point is automatically 360 set to (0,0). 361 362 @param p The end of a line 363 */ 364 void lineTo(const SkPoint& p) { 365 this->lineTo(p.fX, p.fY); 366 } 367 368 /** Same as lineTo, but the coordinates are considered relative to the last 369 point on this contour. If there is no previous point, then a moveTo(0,0) 370 is inserted automatically. 371 372 @param dx The amount to add to the x-coordinate of the previous point 373 on this contour, to specify a line 374 @param dy The amount to add to the y-coordinate of the previous point 375 on this contour, to specify a line 376 */ 377 void rLineTo(SkScalar dx, SkScalar dy); 378 379 /** Add a quadratic bezier from the last point, approaching control point 380 (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for 381 this contour, the first point is automatically set to (0,0). 382 383 @param x1 The x-coordinate of the control point on a quadratic curve 384 @param y1 The y-coordinate of the control point on a quadratic curve 385 @param x2 The x-coordinate of the end point on a quadratic curve 386 @param y2 The y-coordinate of the end point on a quadratic curve 387 */ 388 void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2); 389 390 /** Add a quadratic bezier from the last point, approaching control point 391 p1, and ending at p2. If no moveTo() call has been made for this 392 contour, the first point is automatically set to (0,0). 393 394 @param p1 The control point on a quadratic curve 395 @param p2 The end point on a quadratic curve 396 */ 397 void quadTo(const SkPoint& p1, const SkPoint& p2) { 398 this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY); 399 } 400 401 /** Same as quadTo, but the coordinates are considered relative to the last 402 point on this contour. If there is no previous point, then a moveTo(0,0) 403 is inserted automatically. 404 405 @param dx1 The amount to add to the x-coordinate of the last point on 406 this contour, to specify the control point of a quadratic curve 407 @param dy1 The amount to add to the y-coordinate of the last point on 408 this contour, to specify the control point of a quadratic curve 409 @param dx2 The amount to add to the x-coordinate of the last point on 410 this contour, to specify the end point of a quadratic curve 411 @param dy2 The amount to add to the y-coordinate of the last point on 412 this contour, to specify the end point of a quadratic curve 413 */ 414 void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2); 415 416 void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 417 SkScalar w); 418 void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) { 419 this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w); 420 } 421 void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, 422 SkScalar w); 423 424 /** Add a cubic bezier from the last point, approaching control points 425 (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been 426 made for this contour, the first point is automatically set to (0,0). 427 428 @param x1 The x-coordinate of the 1st control point on a cubic curve 429 @param y1 The y-coordinate of the 1st control point on a cubic curve 430 @param x2 The x-coordinate of the 2nd control point on a cubic curve 431 @param y2 The y-coordinate of the 2nd control point on a cubic curve 432 @param x3 The x-coordinate of the end point on a cubic curve 433 @param y3 The y-coordinate of the end point on a cubic curve 434 */ 435 void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 436 SkScalar x3, SkScalar y3); 437 438 /** Add a cubic bezier from the last point, approaching control points p1 439 and p2, and ending at p3. If no moveTo() call has been made for this 440 contour, the first point is automatically set to (0,0). 441 442 @param p1 The 1st control point on a cubic curve 443 @param p2 The 2nd control point on a cubic curve 444 @param p3 The end point on a cubic curve 445 */ 446 void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) { 447 this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY); 448 } 449 450 /** Same as cubicTo, but the coordinates are considered relative to the 451 current point on this contour. If there is no previous point, then a 452 moveTo(0,0) is inserted automatically. 453 454 @param dx1 The amount to add to the x-coordinate of the last point on 455 this contour, to specify the 1st control point of a cubic curve 456 @param dy1 The amount to add to the y-coordinate of the last point on 457 this contour, to specify the 1st control point of a cubic curve 458 @param dx2 The amount to add to the x-coordinate of the last point on 459 this contour, to specify the 2nd control point of a cubic curve 460 @param dy2 The amount to add to the y-coordinate of the last point on 461 this contour, to specify the 2nd control point of a cubic curve 462 @param dx3 The amount to add to the x-coordinate of the last point on 463 this contour, to specify the end point of a cubic curve 464 @param dy3 The amount to add to the y-coordinate of the last point on 465 this contour, to specify the end point of a cubic curve 466 */ 467 void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 468 SkScalar x3, SkScalar y3); 469 470 /** Append the specified arc to the path as a new contour. If the start of 471 the path is different from the path's current last point, then an 472 automatic lineTo() is added to connect the current contour to the start 473 of the arc. However, if the path is empty, then we call moveTo() with 474 the first point of the arc. The sweep angle is treated mod 360. 475 476 @param oval The bounding oval defining the shape and size of the arc 477 @param startAngle Starting angle (in degrees) where the arc begins 478 @param sweepAngle Sweep angle (in degrees) measured clockwise. This is 479 treated mod 360. 480 @param forceMoveTo If true, always begin a new contour with the arc 481 */ 482 void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 483 bool forceMoveTo); 484 485 /** Append a line and arc to the current path. This is the same as the 486 PostScript call "arct". 487 */ 488 void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 489 SkScalar radius); 490 491 /** Append a line and arc to the current path. This is the same as the 492 PostScript call "arct". 493 */ 494 void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) { 495 this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius); 496 } 497 498 /** Close the current contour. If the current point is not equal to the 499 first point of the contour, a line segment is automatically added. 500 */ 501 void close(); 502 503 enum Direction { 504 /** Direction either has not been or could not be computed */ 505 kUnknown_Direction, 506 /** clockwise direction for adding closed contours */ 507 kCW_Direction, 508 /** counter-clockwise direction for adding closed contours */ 509 kCCW_Direction, 510 }; 511 512 /** 513 * Return the opposite of the specified direction. kUnknown is its own 514 * opposite. 515 */ 516 static Direction OppositeDirection(Direction dir) { 517 static const Direction gOppositeDir[] = { 518 kUnknown_Direction, kCCW_Direction, kCW_Direction 519 }; 520 return gOppositeDir[dir]; 521 } 522 523 /** 524 * Returns whether or not a fill type is inverted 525 * 526 * kWinding_FillType -> false 527 * kEvenOdd_FillType -> false 528 * kInverseWinding_FillType -> true 529 * kInverseEvenOdd_FillType -> true 530 */ 531 static bool IsInverseFillType(FillType fill) { 532 SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch); 533 SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch); 534 SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch); 535 SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch); 536 return (fill & 2) != 0; 537 } 538 539 /** 540 * Returns the equivalent non-inverted fill type to the given fill type 541 * 542 * kWinding_FillType -> kWinding_FillType 543 * kEvenOdd_FillType -> kEvenOdd_FillType 544 * kInverseWinding_FillType -> kWinding_FillType 545 * kInverseEvenOdd_FillType -> kEvenOdd_FillType 546 */ 547 static FillType ConvertToNonInverseFillType(FillType fill) { 548 SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch); 549 SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch); 550 SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch); 551 SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch); 552 return (FillType)(fill & 1); 553 } 554 555 /** 556 * Tries to quickly compute the direction of the first non-degenerate 557 * contour. If it can be computed, return true and set dir to that 558 * direction. If it cannot be (quickly) determined, return false and ignore 559 * the dir parameter. If the direction was determined, it is cached to make 560 * subsequent calls return quickly. 561 */ 562 bool cheapComputeDirection(Direction* dir) const; 563 564 /** 565 * Returns true if the path's direction can be computed via 566 * cheapComputDirection() and if that computed direction matches the 567 * specified direction. If dir is kUnknown, returns true if the direction 568 * cannot be computed. 569 */ 570 bool cheapIsDirection(Direction dir) const { 571 Direction computedDir = kUnknown_Direction; 572 (void)this->cheapComputeDirection(&computedDir); 573 return computedDir == dir; 574 } 575 576 /** Returns true if the path specifies a rectangle. If so, and if isClosed is 577 not null, set isClosed to true if the path is closed. Also, if returning true 578 and direction is not null, return the rect direction. If the path does not 579 specify a rectangle, return false and ignore isClosed and direction. 580 581 @param isClosed If not null, set to true if the path is closed 582 @param direction If not null, set to the rectangle's direction 583 @return true if the path specifies a rectangle 584 */ 585 bool isRect(bool* isClosed, Direction* direction) const; 586 587 /** Returns true if the path specifies a pair of nested rectangles. If so, and if 588 rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner 589 rectangle. If so, and dirs is not null, set dirs[0] to the direction of 590 the outer rectangle and dirs[1] to the direction of the inner rectangle. If 591 the path does not specify a pair of nested rectangles, return 592 false and ignore rect and dirs. 593 594 @param rect If not null, returns the path as a pair of nested rectangles 595 @param dirs If not null, returns the direction of the rects 596 @return true if the path describes a pair of nested rectangles 597 */ 598 bool isNestedRects(SkRect rect[2], Direction dirs[2] = NULL) const; 599 600 /** 601 * Add a closed rectangle contour to the path 602 * @param rect The rectangle to add as a closed contour to the path 603 * @param dir The direction to wind the rectangle's contour. Cannot be 604 * kUnknown_Direction. 605 */ 606 void addRect(const SkRect& rect, Direction dir = kCW_Direction); 607 608 /** 609 * Add a closed rectangle contour to the path 610 * 611 * @param left The left side of a rectangle to add as a closed contour 612 * to the path 613 * @param top The top of a rectangle to add as a closed contour to the 614 * path 615 * @param right The right side of a rectangle to add as a closed contour 616 * to the path 617 * @param bottom The bottom of a rectangle to add as a closed contour to 618 * the path 619 * @param dir The direction to wind the rectangle's contour. Cannot be 620 * kUnknown_Direction. 621 */ 622 void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, 623 Direction dir = kCW_Direction); 624 625 /** 626 * Add a closed oval contour to the path 627 * 628 * @param oval The bounding oval to add as a closed contour to the path 629 * @param dir The direction to wind the oval's contour. Cannot be 630 * kUnknown_Direction. 631 */ 632 void addOval(const SkRect& oval, Direction dir = kCW_Direction); 633 634 /** 635 * Add a closed circle contour to the path 636 * 637 * @param x The x-coordinate of the center of a circle to add as a 638 * closed contour to the path 639 * @param y The y-coordinate of the center of a circle to add as a 640 * closed contour to the path 641 * @param radius The radius of a circle to add as a closed contour to the 642 * path 643 * @param dir The direction to wind the circle's contour. Cannot be 644 * kUnknown_Direction. 645 */ 646 void addCircle(SkScalar x, SkScalar y, SkScalar radius, 647 Direction dir = kCW_Direction); 648 649 /** Add the specified arc to the path as a new contour. 650 651 @param oval The bounds of oval used to define the size of the arc 652 @param startAngle Starting angle (in degrees) where the arc begins 653 @param sweepAngle Sweep angle (in degrees) measured clockwise 654 */ 655 void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle); 656 657 /** 658 * Add a closed round-rectangle contour to the path 659 * @param rect The bounds of a round-rectangle to add as a closed contour 660 * @param rx The x-radius of the rounded corners on the round-rectangle 661 * @param ry The y-radius of the rounded corners on the round-rectangle 662 * @param dir The direction to wind the rectangle's contour. Cannot be 663 * kUnknown_Direction. 664 */ 665 void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, 666 Direction dir = kCW_Direction); 667 668 /** 669 * Add a closed round-rectangle contour to the path. Each corner receives 670 * two radius values [X, Y]. The corners are ordered top-left, top-right, 671 * bottom-right, bottom-left. 672 * @param rect The bounds of a round-rectangle to add as a closed contour 673 * @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner 674 * @param dir The direction to wind the rectangle's contour. Cannot be 675 * kUnknown_Direction. 676 * Note: The radii here now go through the same constraint handling as the 677 * SkRRect radii (i.e., either radii at a corner being 0 implies a 678 * sqaure corner and oversized radii are proportionally scaled down). 679 */ 680 void addRoundRect(const SkRect& rect, const SkScalar radii[], 681 Direction dir = kCW_Direction); 682 683 /** 684 * Add an SkRRect contour to the path 685 * @param rrect The rounded rect to add as a closed contour 686 * @param dir The winding direction for the new contour. Cannot be 687 * kUnknown_Direction. 688 */ 689 void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction); 690 691 /** 692 * Add a new contour made of just lines. This is just a fast version of 693 * the following: 694 * this->moveTo(pts[0]); 695 * for (int i = 1; i < count; ++i) { 696 * this->lineTo(pts[i]); 697 * } 698 * if (close) { 699 * this->close(); 700 * } 701 */ 702 void addPoly(const SkPoint pts[], int count, bool close); 703 704 /** Add a copy of src to the path, offset by (dx,dy) 705 @param src The path to add as a new contour 706 @param dx The amount to translate the path in X as it is added 707 @param dx The amount to translate the path in Y as it is added 708 */ 709 void addPath(const SkPath& src, SkScalar dx, SkScalar dy); 710 711 /** Add a copy of src to the path 712 */ 713 void addPath(const SkPath& src) { 714 SkMatrix m; 715 m.reset(); 716 this->addPath(src, m); 717 } 718 719 /** Add a copy of src to the path, transformed by matrix 720 @param src The path to add as a new contour 721 */ 722 void addPath(const SkPath& src, const SkMatrix& matrix); 723 724 /** 725 * Same as addPath(), but reverses the src input 726 */ 727 void reverseAddPath(const SkPath& src); 728 729 /** Offset the path by (dx,dy), returning true on success 730 731 @param dx The amount in the X direction to offset the entire path 732 @param dy The amount in the Y direction to offset the entire path 733 @param dst The translated path is written here 734 */ 735 void offset(SkScalar dx, SkScalar dy, SkPath* dst) const; 736 737 /** Offset the path by (dx,dy), returning true on success 738 739 @param dx The amount in the X direction to offset the entire path 740 @param dy The amount in the Y direction to offset the entire path 741 */ 742 void offset(SkScalar dx, SkScalar dy) { 743 this->offset(dx, dy, this); 744 } 745 746 /** Transform the points in this path by matrix, and write the answer into 747 dst. 748 749 @param matrix The matrix to apply to the path 750 @param dst The transformed path is written here 751 */ 752 void transform(const SkMatrix& matrix, SkPath* dst) const; 753 754 /** Transform the points in this path by matrix 755 756 @param matrix The matrix to apply to the path 757 */ 758 void transform(const SkMatrix& matrix) { 759 this->transform(matrix, this); 760 } 761 762 /** Return the last point on the path. If no points have been added, (0,0) 763 is returned. If there are no points, this returns false, otherwise it 764 returns true. 765 766 @param lastPt The last point on the path is returned here 767 */ 768 bool getLastPt(SkPoint* lastPt) const; 769 770 /** Set the last point on the path. If no points have been added, 771 moveTo(x,y) is automatically called. 772 773 @param x The new x-coordinate for the last point 774 @param y The new y-coordinate for the last point 775 */ 776 void setLastPt(SkScalar x, SkScalar y); 777 778 /** Set the last point on the path. If no points have been added, moveTo(p) 779 is automatically called. 780 781 @param p The new location for the last point 782 */ 783 void setLastPt(const SkPoint& p) { 784 this->setLastPt(p.fX, p.fY); 785 } 786 787 enum SegmentMask { 788 kLine_SegmentMask = 1 << 0, 789 kQuad_SegmentMask = 1 << 1, 790 kConic_SegmentMask = 1 << 2, 791 kCubic_SegmentMask = 1 << 3, 792 }; 793 794 /** 795 * Returns a mask, where each bit corresponding to a SegmentMask is 796 * set if the path contains 1 or more segments of that type. 797 * Returns 0 for an empty path (no segments). 798 */ 799 uint32_t getSegmentMasks() const { return fSegmentMask; } 800 801 enum Verb { 802 kMove_Verb, //!< iter.next returns 1 point 803 kLine_Verb, //!< iter.next returns 2 points 804 kQuad_Verb, //!< iter.next returns 3 points 805 kConic_Verb, //!< iter.next returns 3 points + iter.conicWeight() 806 kCubic_Verb, //!< iter.next returns 4 points 807 kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt) 808 kDone_Verb, //!< iter.next returns 0 points 809 }; 810 811 /** Iterate through all of the segments (lines, quadratics, cubics) of 812 each contours in a path. 813 814 The iterator cleans up the segments along the way, removing degenerate 815 segments and adding close verbs where necessary. When the forceClose 816 argument is provided, each contour (as defined by a new starting 817 move command) will be completed with a close verb regardless of the 818 contour's contents. 819 */ 820 class SK_API Iter { 821 public: 822 Iter(); 823 Iter(const SkPath&, bool forceClose); 824 825 void setPath(const SkPath&, bool forceClose); 826 827 /** Return the next verb in this iteration of the path. When all 828 segments have been visited, return kDone_Verb. 829 830 @param pts The points representing the current verb and/or segment 831 @param doConsumeDegerates If true, first scan for segments that are 832 deemed degenerate (too short) and skip those. 833 @return The verb for the current segment 834 */ 835 Verb next(SkPoint pts[4], bool doConsumeDegerates = true) { 836 if (doConsumeDegerates) { 837 this->consumeDegenerateSegments(); 838 } 839 return this->doNext(pts); 840 } 841 842 /** 843 * Return the weight for the current conic. Only valid if the current 844 * segment return by next() was a conic. 845 */ 846 SkScalar conicWeight() const { return *fConicWeights; } 847 848 /** If next() returns kLine_Verb, then this query returns true if the 849 line was the result of a close() command (i.e. the end point is the 850 initial moveto for this contour). If next() returned a different 851 verb, this returns an undefined value. 852 853 @return If the last call to next() returned kLine_Verb, return true 854 if it was the result of an explicit close command. 855 */ 856 bool isCloseLine() const { return SkToBool(fCloseLine); } 857 858 /** Returns true if the current contour is closed (has a kClose_Verb) 859 @return true if the current contour is closed (has a kClose_Verb) 860 */ 861 bool isClosedContour() const; 862 863 private: 864 const SkPoint* fPts; 865 const uint8_t* fVerbs; 866 const uint8_t* fVerbStop; 867 const SkScalar* fConicWeights; 868 SkPoint fMoveTo; 869 SkPoint fLastPt; 870 SkBool8 fForceClose; 871 SkBool8 fNeedClose; 872 SkBool8 fCloseLine; 873 SkBool8 fSegmentState; 874 875 inline const SkPoint& cons_moveTo(); 876 Verb autoClose(SkPoint pts[2]); 877 void consumeDegenerateSegments(); 878 Verb doNext(SkPoint pts[4]); 879 }; 880 881 /** Iterate through the verbs in the path, providing the associated points. 882 */ 883 class SK_API RawIter { 884 public: 885 RawIter(); 886 RawIter(const SkPath&); 887 888 void setPath(const SkPath&); 889 890 /** Return the next verb in this iteration of the path. When all 891 segments have been visited, return kDone_Verb. 892 893 @param pts The points representing the current verb and/or segment 894 This must not be NULL. 895 @return The verb for the current segment 896 */ 897 Verb next(SkPoint pts[4]); 898 899 SkScalar conicWeight() const { return *fConicWeights; } 900 901 private: 902 const SkPoint* fPts; 903 const uint8_t* fVerbs; 904 const uint8_t* fVerbStop; 905 const SkScalar* fConicWeights; 906 SkPoint fMoveTo; 907 SkPoint fLastPt; 908 }; 909 910 /** 911 * Returns true if the point { x, y } is contained by the path, taking into 912 * account the FillType. 913 */ 914 bool contains(SkScalar x, SkScalar y) const; 915 916 void dump(bool forceClose, const char title[] = NULL) const; 917 void dump() const; 918 919 /** 920 * Write the region to the buffer, and return the number of bytes written. 921 * If buffer is NULL, it still returns the number of bytes. 922 */ 923 uint32_t writeToMemory(void* buffer) const; 924 /** 925 * Initialized the region from the buffer, returning the number 926 * of bytes actually read. 927 */ 928 uint32_t readFromMemory(const void* buffer); 929 930#ifdef SK_BUILD_FOR_ANDROID 931 uint32_t getGenerationID() const; 932 const SkPath* getSourcePath() const; 933 void setSourcePath(const SkPath* path); 934#endif 935 936 SkDEBUGCODE(void validate() const;) 937 938private: 939 enum SerializationOffsets { 940 kDirection_SerializationShift = 26, // requires 2 bits 941 kIsFinite_SerializationShift = 25, // requires 1 bit 942 kIsOval_SerializationShift = 24, // requires 1 bit 943 kConvexity_SerializationShift = 16, // requires 2 bits 944 kFillType_SerializationShift = 8, // requires 2 bits 945 kSegmentMask_SerializationShift = 0 // requires 4 bits 946 }; 947 948#if SK_DEBUG_PATH_REF 949public: 950 /** Debugging wrapper for SkAutoTUnref<SkPathRef> used to track owners (SkPaths) 951 of SkPathRefs */ 952 class PathRefDebugRef { 953 public: 954 PathRefDebugRef(SkPathRef* pr, SkPath* owner); 955 ~PathRefDebugRef(); 956 void reset(SkPathRef* ref); 957 void swap(PathRefDebugRef* other); 958 SkPathRef* get() const; 959 SkAutoTUnref<SkPathRef>::BlockRefType *operator->() const; 960 operator SkPathRef*(); 961 private: 962 SkAutoTUnref<SkPathRef> fPathRef; 963 SkPath* fOwner; 964 }; 965 966private: 967 PathRefDebugRef fPathRef; 968#else 969 SkAutoTUnref<SkPathRef> fPathRef; 970#endif 971 972 mutable SkRect fBounds; 973 int fLastMoveToIndex; 974 uint8_t fFillType; 975 uint8_t fSegmentMask; 976 mutable uint8_t fBoundsIsDirty; 977 mutable uint8_t fConvexity; 978 mutable uint8_t fDirection; 979 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid 980 mutable SkBool8 fIsOval; 981#ifdef SK_BUILD_FOR_ANDROID 982 uint32_t fGenerationID; 983 const SkPath* fSourcePath; 984#endif 985 986 /** Resets all fields other than fPathRef to their initial 'empty' values. 987 * Assumes the caller has already emptied fPathRef. 988 * On Android increments fGenerationID without reseting it. 989 */ 990 void resetFields(); 991 992 /** Sets all fields other than fPathRef to the values in 'that'. 993 * Assumes the caller has already set fPathRef. 994 * On Android increments fGenerationID without copying it. 995 * On Android sets fSourcePath to NULL. 996 */ 997 void copyFields(const SkPath& that); 998 999 // called, if dirty, by getBounds() 1000 void computeBounds() const; 1001 1002 friend class Iter; 1003 1004 friend class SkPathStroker; 1005 /* Append the first contour of path, ignoring path's initial point. If no 1006 moveTo() call has been made for this contour, the first point is 1007 automatically set to (0,0). 1008 */ 1009 void pathTo(const SkPath& path); 1010 1011 /* Append, in reverse order, the first contour of path, ignoring path's 1012 last point. If no moveTo() call has been made for this contour, the 1013 first point is automatically set to (0,0). 1014 */ 1015 void reversePathTo(const SkPath&); 1016 1017 // called before we add points for lineTo, quadTo, cubicTo, checking to see 1018 // if we need to inject a leading moveTo first 1019 // 1020 // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0) 1021 // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo) 1022 // 1023 inline void injectMoveToIfNeeded(); 1024 1025 inline bool hasOnlyMoveTos() const; 1026 1027 Convexity internalGetConvexity() const; 1028 1029 bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts, 1030 bool* isClosed, Direction* direction) const; 1031 1032 friend class SkAutoPathBoundsUpdate; 1033 friend class SkAutoDisableOvalCheck; 1034 friend class SkAutoDisableDirectionCheck; 1035 friend class SkBench_AddPathTest; // perf test pathTo/reversePathTo 1036}; 1037 1038#endif 1039