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