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