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