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