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