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