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