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