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