SkPath.h revision 0c3137c4f45ffbf09a41526e5eb96e12cc6f35ae
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 "../private/SkPathRef.h" 13 14class SkAutoPathBoundsUpdate; 15class SkData; 16class SkRRect; 17class SkWStream; 18 19/** \class SkPath 20 Paths contain geometry. Paths may be empty, or contain one or more verbs that 21 outline a figure. SkPath always starts with a move verb to a Cartesian_Coordinate, 22 and may be followed by additional verbs that add lines or curves. 23 Adding a close verb makes the geometry into a continuous loop, a closed contour. 24 Paths may contain any number of contours, each beginning with a move verb. 25 26 SkPath contours may contain only a move verb, or may also contain lines, 27 quadratic beziers, conics, and cubic beziers. SkPath contours may be open or 28 closed. 29 30 When used to draw a filled area, SkPath describes whether the fill is inside or 31 outside the geometry. SkPath also describes the winding rule used to fill 32 overlapping contours. 33 34 Internally, SkPath lazily computes metrics likes bounds and convexity. Call 35 SkPath::updateBoundsCache to make SkPath thread safe. 36*/ 37class SK_API SkPath { 38public: 39 40 /** \enum SkPath::Direction 41 Direction describes whether contour is clockwise or counterclockwise. 42 When SkPath contains multiple overlapping contours, Direction together with 43 FillType determines whether overlaps are filled or form holes. 44 45 Direction also determines how contour is measured. For instance, dashing 46 measures along SkPath to determine where to start and stop stroke; Direction 47 will change dashed results as it steps clockwise or counterclockwise. 48 49 Closed contours like SkRect, SkRRect, circle, and oval added with 50 kCW_Direction travel clockwise; the same added with kCCW_Direction 51 travel counterclockwise. 52 */ 53 enum Direction { 54 kCW_Direction, //!< Contour travels in a clockwise direction 55 kCCW_Direction, //!< Contour travels in a counterclockwise direction 56 }; 57 58 /** By default, SkPath has no verbs, no points, and no weights. 59 SkPath::FillType is set to kWinding_FillType. 60 61 @return empty SkPath 62 */ 63 SkPath(); 64 65 /** Copy constructor makes two paths identical by value. Internally, path and 66 the returned result share pointer values. The underlying verb array, SkPoint array 67 and weights are copied when modified. 68 69 Creating a SkPath copy is very efficient and never allocates memory. 70 Paths are always copied by value from the interface; the underlying shared 71 pointers are not exposed. 72 73 @param path SkPath to copy by value 74 @return copy of SkPath 75 */ 76 SkPath(const SkPath& path); 77 78 /** Releases ownership of any shared data and deletes data if SkPath is sole owner. 79 */ 80 ~SkPath(); 81 82 /** SkPath assignment makes two paths identical by value. Internally, assignment 83 shares pointer values. The underlying verb array, SkPoint array and weights 84 are copied when modified. 85 86 Copying paths by assignment is very efficient and never allocates memory. 87 Paths are always copied by value from the interface; the underlying shared 88 pointers are not exposed. 89 90 @param path verb array, SkPoint array, weights, and SkPath::FillType to copy 91 @return SkPath copied by value 92 */ 93 SkPath& operator=(const SkPath& path); 94 95 /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint array, and weights 96 are equivalent. 97 98 @param a SkPath to compare 99 @param b SkPath to compare 100 @return true if SkPath pair are equivalent 101 */ 102 friend SK_API bool operator==(const SkPath& a, const SkPath& b); 103 104 /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint array, and weights 105 are not equivalent. 106 107 @param a SkPath to compare 108 @param b SkPath to compare 109 @return true if SkPath pair are not equivalent 110 */ 111 friend bool operator!=(const SkPath& a, const SkPath& b) { 112 return !(a == b); 113 } 114 115 /** Return true if paths contain equal verbs and equal weights. 116 If paths contain one or more conics, the weights must match. 117 118 conicTo() may add different verbs depending on conic weight, so it is not 119 trivial to interpolate a pair of paths containing conics with different 120 conic weight values. 121 122 @param compare SkPath to compare 123 @return true if paths verb array and weights are equivalent 124 */ 125 bool isInterpolatable(const SkPath& compare) const; 126 127 /** Interpolate between paths with SkPoint array of equal size. 128 Copy verb array and weights to out, and set out SkPoint array to a weighted 129 average of this SkPoint array and ending SkPoint array, using the formula: (this->points * weight) + ending->points * (1 - weight). 130 131 weight is most useful when between zero (ending SkPoint array) and 132 one (this Point_Array); will work with values outside of this 133 range. 134 135 interpolate() returns false and leaves out unchanged if SkPoint array is not 136 the same size as ending SkPoint array. Call isInterpolatable() to check SkPath 137 compatibility prior to calling interpolate(). 138 139 @param ending SkPoint array averaged with this SkPoint array 140 @param weight contribution of this SkPoint array, and 141 one minus contribution of ending SkPoint array 142 @param out SkPath replaced by interpolated averages 143 @return true if paths contain same number of points 144 */ 145 bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const; 146 147#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 148 /** To be deprecated; only valid for Android framework. 149 150 @return true if SkPath has one owner 151 */ 152 bool unique() const { return fPathRef->unique(); } 153#endif 154 155 /** \enum SkPath::FillType 156 FillType selects the rule used to fill SkPath. SkPath set to kWinding_FillType 157 fills if the sum of contour edges is not zero, where clockwise edges add one, and 158 counterclockwise edges subtract one. SkPath set to kEvenOdd_FillType fills if the 159 number of contour edges is odd. Each FillType has an inverse variant that 160 reverses the rule: 161 kInverseWinding_FillType fills where the sum of contour edges is zero; 162 kInverseEvenOdd_FillType fills where the number of contour edges is even. 163 */ 164 enum FillType { 165 /** Specifies fill as area is enclosed by a non-zero sum of contour directions. */ 166 kWinding_FillType, 167 168 /** Specifies fill as area enclosed by an odd number of contours. */ 169 kEvenOdd_FillType, 170 171 /** Specifies fill as area is enclosed by a zero sum of contour directions. */ 172 kInverseWinding_FillType, 173 174 /** Specifies fill as area enclosed by an even number of contours. */ 175 kInverseEvenOdd_FillType, 176 }; 177 178 /** Returns FillType, the rule used to fill SkPath. FillType of a new SkPath is 179 kWinding_FillType. 180 181 @return one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType, 182 kInverseEvenOdd_FillType 183 */ 184 FillType getFillType() const { return (FillType)fFillType; } 185 186 /** Sets FillType, the rule used to fill SkPath. While there is no check 187 that ft is legal, values outside of FillType are not supported. 188 189 @param ft one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType, 190 kInverseEvenOdd_FillType 191 */ 192 void setFillType(FillType ft) { 193 fFillType = SkToU8(ft); 194 } 195 196 /** Returns if FillType describes area outside SkPath geometry. The inverse fill area 197 extends indefinitely. 198 199 @return true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType 200 */ 201 bool isInverseFillType() const { return IsInverseFillType((FillType)fFillType); } 202 203 /** Replace FillType with its inverse. The inverse of FillType describes the area 204 unmodified by the original FillType. 205 */ 206 void toggleInverseFillType() { 207 fFillType ^= 2; 208 } 209 210 /** \enum SkPath::Convexity 211 SkPath is convex if it contains one contour and contour loops no more than 212 360 degrees, and contour angles all have same Direction. Convex SkPath 213 may have better performance and require fewer resources on GPU surface. 214 215 SkPath is concave when either at least one Direction change is clockwise and 216 another is counterclockwise, or the sum of the changes in Direction is not 360 217 degrees. 218 219 Initially SkPath Convexity is kUnknown_Convexity. SkPath Convexity is computed 220 if needed by destination SkSurface. 221 */ 222 enum Convexity : uint8_t { 223 kUnknown_Convexity, //!< Indicates Convexity has not been determined. 224 225 /** SkPath has one contour made of a simple geometry without indentations. */ 226 kConvex_Convexity, 227 kConcave_Convexity, //!< SkPath has more than one contour, or a geometry with indentations. 228 }; 229 230 /** Computes SkPath::Convexity if required, and returns stored value. 231 SkPath::Convexity is computed if stored value is kUnknown_Convexity, 232 or if SkPath has been altered since SkPath::Convexity was computed or set. 233 234 @return computed or stored SkPath::Convexity 235 */ 236 Convexity getConvexity() const { 237 for (Convexity convexity = fConvexity.load(); kUnknown_Convexity != convexity; ) { 238 return convexity; 239 } 240 return this->internalGetConvexity(); 241 } 242 243 /** Returns last computed SkPath::Convexity, or kUnknown_Convexity if 244 SkPath has been altered since SkPath::Convexity was computed or set. 245 246 @return stored SkPath::Convexity 247 */ 248 Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; } 249 250 /** Stores convexity so that it is later returned by getConvexity() or getConvexityOrUnknown(). 251 convexity may differ from getConvexity(), although setting an incorrect value may 252 cause incorrect or inefficient drawing. 253 254 If convexity is kUnknown_Convexity: getConvexity() will 255 compute SkPath::Convexity, and getConvexityOrUnknown() will return kUnknown_Convexity. 256 257 If convexity is kConvex_Convexity or kConcave_Convexity, getConvexity() 258 and getConvexityOrUnknown() will return convexity until the path is 259 altered. 260 261 @param convexity one of: kUnknown_Convexity, kConvex_Convexity, or kConcave_Convexity 262 */ 263 void setConvexity(Convexity convexity); 264 265 /** Computes SkPath::Convexity if required, and returns true if value is kConvex_Convexity. 266 If setConvexity() was called with kConvex_Convexity or kConcave_Convexity, and 267 the path has not been altered, SkPath::Convexity is not recomputed. 268 269 @return true if SkPath::Convexity stored or computed is kConvex_Convexity 270 */ 271 bool isConvex() const { 272 return kConvex_Convexity == this->getConvexity(); 273 } 274 275 /** Deprecated. Use setConvexity(). 276 */ 277 SK_ATTR_DEPRECATED("use setConvexity") 278 void setIsConvex(bool isConvex) { 279 this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity); 280 } 281 282 /** 283 * Returns true if this path is recognized as an oval or circle. 284 * 285 * @param bounds If this returns true and bounds is not null, then it is set to the 286 * bounds of the oval that matches this path. If this returns false, 287 * then this parameter is ignored. 288 */ 289 bool isOval(SkRect* bounds) const; 290 291 /** 292 * Returns true if this path is recognized as a SkRRect (but not an oval/circle or rect). 293 * 294 * @param rrect If this returns true and rrect is not null, then it is set to the 295 * SkRRect that matches this path. If this returns false, then this parameter 296 * is ignored. 297 */ 298 bool isRRect(SkRRect* rrect) const; 299 300 /** Sets SkPath to its initial state. 301 Removes verb array, SkPoint array, and weights, and sets FillType to kWinding_FillType. 302 Internal storage associated with SkPath is released. 303 */ 304 void reset(); 305 306 /** Sets SkPath to its initial state, preserving internal storage. 307 Removes verb array, SkPoint array, and weights, and sets FillType to kWinding_FillType. 308 Internal storage associated with SkPath is retained. 309 310 Use rewind() instead of reset() if SkPath storage will be reused and performance 311 is critical. 312 */ 313 void rewind(); 314 315 /** Empty SkPath may have FillType but has no SkPoint, SkPath::Verb, or conic weight. 316 SkPath() constructs empty SkPath; reset() and (rewind) make SkPath empty. 317 318 @return true if the path contains no SkPath::Verb array 319 */ 320 bool isEmpty() const { 321 SkDEBUGCODE(this->validate();) 322 return 0 == fPathRef->countVerbs(); 323 } 324 325 /** Contour is closed if SkPath SkPath::Verb array was last modified by close(). When stroked, 326 closed contour draws SkPaint::Join instead of SkPaint::Cap at first and last SkPoint. 327 328 @return true if the last contour ends with a kClose_Verb 329 */ 330 bool isLastContourClosed() const; 331 332 /** Returns true for finite SkPoint array values between negative SK_ScalarMax and 333 positive SK_ScalarMax. Returns false for any SkPoint array value of 334 SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN. 335 336 @return true if all SkPoint values are finite 337 */ 338 bool isFinite() const { 339 SkDEBUGCODE(this->validate();) 340 return fPathRef->isFinite(); 341 } 342 343 /** Returns true if the path is volatile; it will not be altered or discarded 344 by the caller after it is drawn. Paths by default have volatile set false, allowing 345 SkSurface to attach a cache of data which speeds repeated drawing. If true, SkSurface 346 may not speed repeated drawing. 347 348 @return true if caller will alter SkPath after drawing 349 */ 350 bool isVolatile() const { 351 return SkToBool(fIsVolatile); 352 } 353 354 /** Specify whether SkPath is volatile; whether it will be altered or discarded 355 by the caller after it is drawn. Paths by default have volatile set false, allowing 356 SkBaseDevice to attach a cache of data which speeds repeated drawing. 357 358 Mark temporary paths, discarded or modified after use, as volatile 359 to inform SkBaseDevice that the path need not be cached. 360 361 Mark animating SkPath volatile to improve performance. 362 Mark unchanging SkPath non-volatile to improve repeated rendering. 363 364 raster surface SkPath draws are affected by volatile for some shadows. 365 GPU surface SkPath draws are affected by volatile for some shadows and concave geometries. 366 367 @param isVolatile true if caller will alter SkPath after drawing 368 */ 369 void setIsVolatile(bool isVolatile) { 370 fIsVolatile = isVolatile; 371 } 372 373 /** Test if line between SkPoint pair is degenerate. 374 Line with no length or that moves a very short distance is degenerate; it is 375 treated as a point. 376 377 exact changes the equality test. If true, returns true only if p1 equals p2. 378 If false, returns true if p1 equals or nearly equals p2. 379 380 @param p1 line start point 381 @param p2 line end point 382 @param exact if false, allow nearly equals 383 @return true if line is degenerate; its length is effectively zero 384 */ 385 static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact); 386 387 /** Test if quad is degenerate. 388 Quad with no length or that moves a very short distance is degenerate; it is 389 treated as a point. 390 391 @param p1 quad start point 392 @param p2 quad control point 393 @param p3 quad end point 394 @param exact if true, returns true only if p1, p2, and p3 are equal; 395 if false, returns true if p1, p2, and p3 are equal or nearly equal 396 @return true if quad is degenerate; its length is effectively zero 397 */ 398 static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2, 399 const SkPoint& p3, bool exact); 400 401 /** Test if cubic is degenerate. 402 Cubic with no length or that moves a very short distance is degenerate; it is 403 treated as a point. 404 405 @param p1 cubic start point 406 @param p2 cubic control point 1 407 @param p3 cubic control point 2 408 @param p4 cubic end point 409 @param exact if true, returns true only if p1, p2, p3, and p4 are equal; 410 if false, returns true if p1, p2, p3, and p4 are equal or nearly equal 411 @return true if cubic is degenerate; its length is effectively zero 412 */ 413 static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, 414 const SkPoint& p3, const SkPoint& p4, bool exact); 415 416 /** Returns true if SkPath contains only one line; 417 SkPath::Verb array has two entries: kMove_Verb, kLine_Verb. 418 If SkPath contains one line and line is not nullptr, line is set to 419 line start point and line end point. 420 Returns false if SkPath is not one line; line is unaltered. 421 422 @param line storage for line. May be nullptr 423 @return true if SkPath contains exactly one line 424 */ 425 bool isLine(SkPoint line[2]) const; 426 427 /** Returns the number of points in SkPath. 428 SkPoint count is initially zero. 429 430 @return SkPath SkPoint array length 431 */ 432 int countPoints() const; 433 434 /** Returns SkPoint at index in SkPoint array. Valid range for index is 435 0 to countPoints() - 1. 436 Returns (0, 0) if index is out of range. 437 438 @param index SkPoint array element selector 439 @return SkPoint array value or (0, 0) 440 */ 441 SkPoint getPoint(int index) const; 442 443 /** Returns number of points in SkPath. Up to max points are copied. 444 points may be nullptr; then, max must be zero. 445 If max is greater than number of points, excess points storage is unaltered. 446 447 @param points storage for SkPath SkPoint array. May be nullptr 448 @param max maximum to copy; must be greater than or equal to zero 449 @return SkPath SkPoint array length 450 */ 451 int getPoints(SkPoint points[], int max) const; 452 453 /** Returns the number of verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb, 454 kCubic_Verb, and kClose_Verb; added to SkPath. 455 456 @return length of verb array 457 */ 458 int countVerbs() const; 459 460 /** Returns the number of verbs in the path. Up to max verbs are copied. The 461 verbs are copied as one byte per verb. 462 463 @param verbs storage for verbs, may be nullptr 464 @param max maximum number to copy into verbs 465 @return the actual number of verbs in the path 466 */ 467 int getVerbs(uint8_t verbs[], int max) const; 468 469 /** Exchanges the verb array, SkPoint array, weights, and SkPath::FillType with other. 470 Cached state is also exchanged. swap() internally exchanges pointers, so 471 it is lightweight and does not allocate memory. 472 473 swap() usage has largely been replaced by operator=(const SkPath& path). 474 Paths do not copy their content on assignment until they are written to, 475 making assignment as efficient as swap(). 476 477 @param other SkPath exchanged by value 478 */ 479 void swap(SkPath& other); 480 481 /** Returns minimum and maximum x and y values of SkPoint array. 482 Returns (0, 0, 0, 0) if SkPath contains no points. Returned bounds width and height may 483 be larger or smaller than area affected when SkPath is drawn. 484 485 SkRect returned includes all points added to SkPath, including points associated with 486 kMove_Verb that define empty contours. 487 488 @return bounds of all points in SkPoint array 489 */ 490 const SkRect& getBounds() const { 491 return fPathRef->getBounds(); 492 } 493 494 /** Update internal bounds so that subsequent calls to getBounds() are instantaneous. 495 Unaltered copies of SkPath may also access cached bounds through getBounds(). 496 497 For now, identical to calling getBounds() and ignoring the returned value. 498 499 Call to prepare SkPath subsequently drawn from multiple threads, 500 to avoid a race condition where each draw separately computes the bounds. 501 */ 502 void updateBoundsCache() const { 503 // for now, just calling getBounds() is sufficient 504 this->getBounds(); 505 } 506 507 /** Returns minimum and maximum x and y values of the lines and curves in SkPath. 508 Returns (0, 0, 0, 0) if SkPath contains no points. 509 Returned bounds width and height may be larger or smaller than area affected 510 when SkPath is drawn. 511 512 Includes points associated with kMove_Verb that define empty 513 contours. 514 515 Behaves identically to getBounds() when SkPath contains 516 only lines. If SkPath contains curves, computed bounds includes 517 the maximum extent of the quad, conic, or cubic; is slower than getBounds(); 518 and unlike getBounds(), does not cache the result. 519 520 @return tight bounds of curves in SkPath 521 */ 522 SkRect computeTightBounds() const; 523 524 /** Returns true if rect is contained by SkPath. 525 May return false when rect is contained by SkPath. 526 527 For now, only returns true if SkPath has one contour and is convex. 528 rect may share points and edges with SkPath and be contained. 529 Returns true if rect is empty, that is, it has zero width or height; and 530 the SkPoint or line described by rect is contained by SkPath. 531 532 @param rect SkRect, line, or SkPoint checked for containment 533 @return true if rect is contained 534 */ 535 bool conservativelyContainsRect(const SkRect& rect) const; 536 537 /** grows SkPath verb array and SkPoint array to contain extraPtCount additional points. 538 May improve performance and use less memory by 539 reducing the number and size of allocations when creating SkPath. 540 541 @param extraPtCount number of additional points to allocate 542 */ 543 void incReserve(unsigned extraPtCount); 544 545 /** Adds beginning of contour at SkPoint (x, y). 546 547 @param x x-coordinate of contour start 548 @param y y-coordinate of contour start 549 */ 550 void moveTo(SkScalar x, SkScalar y); 551 552 /** Adds beginning of contour at SkPoint p. 553 554 @param p contour start 555 */ 556 void moveTo(const SkPoint& p) { 557 this->moveTo(p.fX, p.fY); 558 } 559 560 /** Adds beginning of contour relative to last point. 561 If SkPath is empty, starts contour at (dx, dy). 562 Otherwise, start contour at last point offset by (dx, dy). 563 Function name stands for "relative move to". 564 565 @param dx offset from last point x to contour start x 566 @param dy offset from last point y to contour start y 567 */ 568 void rMoveTo(SkScalar dx, SkScalar dy); 569 570 /** Adds line from last point to (x, y). If SkPath is empty, or last SkPath::Verb is 571 kClose_Verb, last point is set to (0, 0) before adding line. 572 573 lineTo() appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. 574 lineTo() then appends kLine_Verb to verb array and (x, y) to SkPoint array. 575 576 @param x end of added line in x 577 @param y end of added line in y 578 */ 579 void lineTo(SkScalar x, SkScalar y); 580 581 /** Adds line from last point to SkPoint p. If SkPath is empty, or last SkPath::Verb is 582 kClose_Verb, last point is set to (0, 0) before adding line. 583 584 lineTo() first appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. 585 lineTo() then appends kLine_Verb to verb array and SkPoint p to SkPoint array. 586 587 @param p end SkPoint of added line 588 */ 589 void lineTo(const SkPoint& p) { 590 this->lineTo(p.fX, p.fY); 591 } 592 593 /** Adds line from last point to vector (dx, dy). If SkPath is empty, or last SkPath::Verb is 594 kClose_Verb, last point is set to (0, 0) before adding line. 595 596 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; 597 then appends kLine_Verb to verb array and line end to SkPoint array. 598 Line end is last point plus vector (dx, dy). 599 Function name stands for "relative line to". 600 601 @param dx offset from last point x to line end x 602 @param dy offset from last point y to line end y 603 */ 604 void rLineTo(SkScalar dx, SkScalar dy); 605 606 /** Adds quad from last point towards (x1, y1), to (x2, y2). 607 If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) 608 before adding quad. 609 610 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; 611 then appends kQuad_Verb to verb array; and (x1, y1), (x2, y2) 612 to SkPoint array. 613 614 @param x1 control SkPoint of quad in x 615 @param y1 control SkPoint of quad in y 616 @param x2 end SkPoint of quad in x 617 @param y2 end SkPoint of quad in y 618 */ 619 void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2); 620 621 /** Adds quad from last point towards SkPoint p1, to SkPoint p2. 622 If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) 623 before adding quad. 624 625 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; 626 then appends kQuad_Verb to verb array; and points p1, p2 627 to SkPoint array. 628 629 @param p1 control SkPoint of added quad 630 @param p2 end SkPoint of added quad 631 */ 632 void quadTo(const SkPoint& p1, const SkPoint& p2) { 633 this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY); 634 } 635 636 /** Adds quad from last point towards vector (dx1, dy1), to vector (dx2, dy2). 637 If SkPath is empty, or last SkPath::Verb 638 is kClose_Verb, last point is set to (0, 0) before adding quad. 639 640 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, 641 if needed; then appends kQuad_Verb to verb array; and appends quad 642 control and quad end to SkPoint array. 643 Quad control is last point plus vector (dx1, dy1). 644 Quad end is last point plus vector (dx2, dy2). 645 Function name stands for "relative quad to". 646 647 @param dx1 offset from last point x to quad control x 648 @param dy1 offset from last point x to quad control y 649 @param dx2 offset from last point x to quad end x 650 @param dy2 offset from last point x to quad end y 651 */ 652 void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2); 653 654 /** Adds conic from last point towards (x1, y1), to (x2, y2), weighted by w. 655 If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) 656 before adding conic. 657 658 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. 659 660 If w is finite and not one, appends kConic_Verb to verb array; 661 and (x1, y1), (x2, y2) to SkPoint array; and w to conic weights. 662 663 If w is one, appends kQuad_Verb to verb array, and 664 (x1, y1), (x2, y2) to SkPoint array. 665 666 If w is not finite, appends kLine_Verb twice to verb array, and 667 (x1, y1), (x2, y2) to SkPoint array. 668 669 @param x1 control SkPoint of conic in x 670 @param y1 control SkPoint of conic in y 671 @param x2 end SkPoint of conic in x 672 @param y2 end SkPoint of conic in y 673 @param w weight of added conic 674 */ 675 void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 676 SkScalar w); 677 678 /** Adds conic from last point towards SkPoint p1, to SkPoint p2, weighted by w. 679 If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) 680 before adding conic. 681 682 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. 683 684 If w is finite and not one, appends kConic_Verb to verb array; 685 and points p1, p2 to SkPoint array; and w to conic weights. 686 687 If w is one, appends kQuad_Verb to verb array, and points p1, p2 688 to SkPoint array. 689 690 If w is not finite, appends kLine_Verb twice to verb array, and 691 points p1, p2 to SkPoint array. 692 693 @param p1 control SkPoint of added conic 694 @param p2 end SkPoint of added conic 695 @param w weight of added conic 696 */ 697 void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) { 698 this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w); 699 } 700 701 /** Adds conic from last point towards vector (dx1, dy1), to vector (dx2, dy2), 702 weighted by w. If SkPath is empty, or last SkPath::Verb 703 is kClose_Verb, last point is set to (0, 0) before adding conic. 704 705 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, 706 if needed. 707 708 If w is finite and not one, next appends kConic_Verb to verb array, 709 and w is recorded as conic weight; otherwise, if w is one, appends 710 kQuad_Verb to verb array; or if w is not finite, appends kLine_Verb 711 twice to verb array. 712 713 In all cases appends points control and end to SkPoint array. 714 control is last point plus vector (dx1, dy1). 715 end is last point plus vector (dx2, dy2). 716 717 Function name stands for "relative conic to". 718 719 @param dx1 offset from last point x to conic control x 720 @param dy1 offset from last point x to conic control y 721 @param dx2 offset from last point x to conic end x 722 @param dy2 offset from last point x to conic end y 723 @param w weight of added conic 724 */ 725 void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, 726 SkScalar w); 727 728 /** Adds cubic from last point towards (x1, y1), then towards (x2, y2), ending at 729 (x3, y3). If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to 730 (0, 0) before adding cubic. 731 732 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; 733 then appends kCubic_Verb to verb array; and (x1, y1), (x2, y2), (x3, y3) 734 to SkPoint array. 735 736 @param x1 first control SkPoint of cubic in x 737 @param y1 first control SkPoint of cubic in y 738 @param x2 second control SkPoint of cubic in x 739 @param y2 second control SkPoint of cubic in y 740 @param x3 end SkPoint of cubic in x 741 @param y3 end SkPoint of cubic in y 742 */ 743 void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 744 SkScalar x3, SkScalar y3); 745 746 /** Adds cubic from last point towards SkPoint p1, then towards SkPoint p2, ending at 747 SkPoint p3. If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to 748 (0, 0) before adding cubic. 749 750 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; 751 then appends kCubic_Verb to verb array; and points p1, p2, p3 752 to SkPoint array. 753 754 @param p1 first control SkPoint of cubic 755 @param p2 second control SkPoint of cubic 756 @param p3 end SkPoint of cubic 757 */ 758 void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) { 759 this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY); 760 } 761 762 /** Adds cubic from last point towards vector (dx1, dy1), then towards 763 vector (dx2, dy2), to vector (dx3, dy3). 764 If SkPath is empty, or last SkPath::Verb 765 is kClose_Verb, last point is set to (0, 0) before adding cubic. 766 767 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, 768 if needed; then appends kCubic_Verb to verb array; and appends cubic 769 control and cubic end to SkPoint array. 770 Cubic control is last point plus vector (dx1, dy1). 771 Cubic end is last point plus vector (dx2, dy2). 772 Function name stands for "relative cubic to". 773 774 @param x1 offset from last point x to first cubic control x 775 @param y1 offset from last point x to first cubic control y 776 @param x2 offset from last point x to second cubic control x 777 @param y2 offset from last point x to second cubic control y 778 @param x3 offset from last point x to cubic end x 779 @param y3 offset from last point x to cubic end y 780 */ 781 void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 782 SkScalar x3, SkScalar y3); 783 784 /** Append arc to SkPath. Arc added is part of ellipse 785 bounded by oval, from startAngle through sweepAngle. Both startAngle and 786 sweepAngle are measured in degrees, where zero degrees is aligned with the 787 positive x-axis, and positive sweeps extends arc clockwise. 788 789 arcTo() adds line connecting SkPath last SkPoint to initial arc SkPoint if forceMoveTo 790 is false and SkPath is not empty. Otherwise, added contour begins with first point 791 of arc. Angles greater than -360 and less than 360 are treated modulo 360. 792 793 @param oval bounds of ellipse containing arc 794 @param startAngle starting angle of arc in degrees 795 @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 796 @param forceMoveTo true to start a new contour with arc 797 */ 798 void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo); 799 800 /** Append arc to SkPath, after appending line if needed. Arc is implemented by conic 801 weighted to describe part of circle. Arc is contained by tangent from 802 last SkPath point (x0, y0) to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc 803 is part of circle sized to radius, positioned so it touches both tangent lines. 804 805 @param x1 x common to pair of tangents 806 @param y1 y common to pair of tangents 807 @param x2 x end of second tangent 808 @param y2 y end of second tangent 809 @param radius distance from arc to circle center 810 */ 811 void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius); 812 813 /** Append arc to SkPath, after appending line if needed. Arc is implemented by conic 814 weighted to describe part of circle. Arc is contained by tangent from 815 last SkPath point to p1, and tangent from p1 to p2. Arc 816 is part of circle sized to radius, positioned so it touches both tangent lines. 817 818 If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath. 819 The length of vector from p1 to p2 does not affect arc. 820 821 Arc sweep is always less than 180 degrees. If radius is zero, or if 822 tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1. 823 824 arcTo() appends at most one line and one conic. 825 arcTo() implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo. 826 827 @param p1 SkPoint common to pair of tangents 828 @param p2 end of second tangent 829 @param radius distance from arc to circle center 830 */ 831 void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) { 832 this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius); 833 } 834 835 /** \enum SkPath::ArcSize 836 Four oval parts with radii (rx, ry) start at last SkPath SkPoint and ends at (x, y). 837 ArcSize and Direction select one of the four oval parts. 838 */ 839 enum ArcSize { 840 kSmall_ArcSize, //!< smaller of arc pair 841 kLarge_ArcSize, //!< larger of arc pair 842 }; 843 844 /** Append arc to SkPath. Arc is implemented by one or more conics weighted to 845 describe part of oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc 846 curves from last SkPath SkPoint to (x, y), choosing one of four possible routes: 847 clockwise or counterclockwise, and smaller or larger. 848 849 Arc sweep is always less than 360 degrees. arcTo() appends line to (x, y) if 850 either radii are zero, or if last SkPath SkPoint equals (x, y). arcTo() scales radii 851 (rx, ry) to fit last SkPath SkPoint and (x, y) if both are greater than zero but 852 too small. 853 854 arcTo() appends up to four conic curves. 855 arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value 856 is opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, 857 while kCW_Direction cast to int is zero. 858 859 @param rx radius in x before x-axis rotation 860 @param ry radius in y before x-axis rotation 861 @param xAxisRotate x-axis rotation in degrees; positive values are clockwise 862 @param largeArc chooses smaller or larger arc 863 @param sweep chooses clockwise or counterclockwise arc 864 @param x end of arc 865 @param y end of arc 866 */ 867 void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, 868 Direction sweep, SkScalar x, SkScalar y); 869 870 /** Append arc to SkPath. Arc is implemented by one or more conic weighted to describe part of oval 871 with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves from last SkPath SkPoint to 872 (xy.fX, xy.fY), choosing one of four possible routes: clockwise or counterclockwise, 873 and smaller or larger. 874 875 Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either radii are zero, 876 or if last SkPath SkPoint equals (x, y). arcTo() scales radii r to fit last SkPath SkPoint and 877 xy if both are greater than zero but too small to describe an arc. 878 879 arcTo() appends up to four conic curves. 880 arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value is 881 opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while 882 kCW_Direction cast to int is zero. 883 884 @param r radii in x and y before x-axis rotation 885 @param xAxisRotate x-axis rotation in degrees; positive values are clockwise 886 @param largeArc chooses smaller or larger arc 887 @param sweep chooses clockwise or counterclockwise arc 888 @param xy end of arc 889 */ 890 void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep, 891 const SkPoint xy) { 892 this->arcTo(r.fX, r.fY, xAxisRotate, largeArc, sweep, xy.fX, xy.fY); 893 } 894 895 /** Append arc to SkPath, relative to last SkPath SkPoint. Arc is implemented by one or 896 more conic, weighted to describe part of oval with radii (rx, ry) rotated by 897 xAxisRotate degrees. Arc curves from last SkPath SkPoint (x0, y0) to end SkPoint: 898 (x0 + dx, y0 + dy), choosing one of four possible routes: clockwise or 899 counterclockwise, and smaller or larger. If SkPath is empty, the start arc SkPoint 900 is (0, 0). 901 902 Arc sweep is always less than 360 degrees. arcTo() appends line to end SkPoint 903 if either radii are zero, or if last SkPath SkPoint equals end SkPoint. 904 arcTo() scales radii (rx, ry) to fit last SkPath SkPoint and end SkPoint if both are 905 greater than zero but too small to describe an arc. 906 907 arcTo() appends up to four conic curves. 908 arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value is 909 opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while 910 kCW_Direction cast to int is zero. 911 912 @param rx radius in x before x-axis rotation 913 @param ry radius in y before x-axis rotation 914 @param xAxisRotate x-axis rotation in degrees; positive values are clockwise 915 @param largeArc chooses smaller or larger arc 916 @param sweep chooses clockwise or counterclockwise arc 917 @param dx x offset end of arc from last SkPath SkPoint 918 @param dy y offset end of arc from last SkPath SkPoint 919 */ 920 void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, 921 Direction sweep, SkScalar dx, SkScalar dy); 922 923 /** Append kClose_Verb to SkPath. A closed contour connects the first and last SkPoint 924 with line, forming a continuous loop. Open and closed contour draw the same 925 with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open contour draws 926 SkPaint::Cap at contour start and end; closed contour draws 927 SkPaint::Join at contour start and end. 928 929 close() has no effect if SkPath is empty or last SkPath SkPath::Verb is kClose_Verb. 930 */ 931 void close(); 932 933 /** Returns true if fill is inverted and SkPath with fill represents area outside 934 of its geometric bounds. 935 936 @param fill one of: kWinding_FillType, kEvenOdd_FillType, 937 kInverseWinding_FillType, kInverseEvenOdd_FillType 938 @return true if SkPath fills outside its bounds 939 */ 940 static bool IsInverseFillType(FillType fill) { 941 static_assert(0 == kWinding_FillType, "fill_type_mismatch"); 942 static_assert(1 == kEvenOdd_FillType, "fill_type_mismatch"); 943 static_assert(2 == kInverseWinding_FillType, "fill_type_mismatch"); 944 static_assert(3 == kInverseEvenOdd_FillType, "fill_type_mismatch"); 945 return (fill & 2) != 0; 946 } 947 948 /** Returns equivalent SkPath::FillType representing SkPath fill inside its bounds. 949 . 950 951 @param fill one of: kWinding_FillType, kEvenOdd_FillType, 952 kInverseWinding_FillType, kInverseEvenOdd_FillType 953 @return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted 954 */ 955 static FillType ConvertToNonInverseFillType(FillType fill) { 956 static_assert(0 == kWinding_FillType, "fill_type_mismatch"); 957 static_assert(1 == kEvenOdd_FillType, "fill_type_mismatch"); 958 static_assert(2 == kInverseWinding_FillType, "fill_type_mismatch"); 959 static_assert(3 == kInverseEvenOdd_FillType, "fill_type_mismatch"); 960 return (FillType)(fill & 1); 961 } 962 963 /** Approximates conic with quad array. Conic is constructed from start SkPoint p0, 964 control SkPoint p1, end SkPoint p2, and weight w. 965 Quad array is stored in pts; this storage is supplied by caller. 966 Maximum quad count is 2 to the pow2. 967 Every third point in array shares last SkPoint of previous quad and first SkPoint of 968 next quad. Maximum pts storage size is given by: (1 + 2 * (1 << pow2)) * sizeof(SkPoint). 969 970 Returns quad count used the approximation, which may be smaller 971 than the number requested. 972 973 conic weight determines the amount of influence conic control point has on the curve. 974 w less than one represents an elliptical section. w greater than one represents 975 a hyperbolic section. w equal to one represents a parabolic section. 976 977 Two quad curves are sufficient to approximate an elliptical conic with a sweep 978 of up to 90 degrees; in this case, set pow2 to one. 979 980 @param p0 conic start SkPoint 981 @param p1 conic control SkPoint 982 @param p2 conic end SkPoint 983 @param w conic weight 984 @param pts storage for quad array 985 @param pow2 quad count, as power of two, normally 0 to 5 (1 to 32 quad curves) 986 @return number of quad curves written to pts 987 */ 988 static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2, 989 SkScalar w, SkPoint pts[], int pow2); 990 991 /** Returns true if SkPath is equivalent to SkRect when filled. 992 If false: rect, isClosed, and direction are unchanged. 993 If true: rect, isClosed, and direction are written to if not nullptr. 994 995 rect may be smaller than the SkPath bounds. SkPath bounds may include kMove_Verb points 996 that do not alter the area drawn by the returned rect. 997 998 @param rect storage for bounds of SkRect; may be nullptr 999 @param isClosed storage set to true if SkPath is closed; may be nullptr 1000 @param direction storage set to SkRect direction; may be nullptr 1001 @return true if SkPath contains SkRect 1002 */ 1003 bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const; 1004 1005 /** Returns true if SkPath is equivalent to nested SkRect pair when filled. 1006 If false, rect and dirs are unchanged. 1007 If true, rect and dirs are written to if not nullptr: 1008 setting rect[0] to outer SkRect, and rect[1] to inner SkRect; 1009 setting dirs[0] to SkPath::Direction of outer SkRect, and dirs[1] to SkPath::Direction of inner 1010 SkRect. 1011 1012 @param rect storage for SkRect pair; may be nullptr 1013 @param dirs storage for SkPath::Direction pair; may be nullptr 1014 @return true if SkPath contains nested SkRect pair 1015 */ 1016 bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const; 1017 1018 /** Add SkRect to SkPath, appending kMove_Verb, three kLine_Verb, and kClose_Verb, 1019 starting with top-left corner of SkRect; followed by top-right, bottom-right, 1020 and bottom-left if dir is kCW_Direction; or followed by bottom-left, 1021 bottom-right, and top-right if dir is kCCW_Direction. 1022 1023 @param rect SkRect to add as a closed contour 1024 @param dir SkPath::Direction to wind added contour 1025 */ 1026 void addRect(const SkRect& rect, Direction dir = kCW_Direction); 1027 1028 /** Add SkRect to SkPath, appending kMove_Verb, three kLine_Verb, and kClose_Verb. 1029 If dir is kCW_Direction, SkRect corners are added clockwise; if dir is 1030 kCCW_Direction, SkRect corners are added counterclockwise. 1031 start determines the first corner added. 1032 1033 @param rect SkRect to add as a closed contour 1034 @param dir SkPath::Direction to wind added contour 1035 @param start initial corner of SkRect to add 1036 */ 1037 void addRect(const SkRect& rect, Direction dir, unsigned start); 1038 1039 /** Add SkRect (left, top, right, bottom) to SkPath, 1040 appending kMove_Verb, three kLine_Verb, and kClose_Verb, 1041 starting with top-left corner of SkRect; followed by top-right, bottom-right, 1042 and bottom-left if dir is kCW_Direction; or followed by bottom-left, 1043 bottom-right, and top-right if dir is kCCW_Direction. 1044 1045 @param left smaller x of SkRect 1046 @param top smaller y of SkRect 1047 @param right larger x of SkRect 1048 @param bottom larger y of SkRect 1049 @param dir SkPath::Direction to wind added contour 1050 */ 1051 void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, 1052 Direction dir = kCW_Direction); 1053 1054 /** Add oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb. 1055 Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width 1056 and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues 1057 clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction. 1058 1059 This form is identical to addOval(oval, dir, 1). 1060 1061 @param oval bounds of ellipse added 1062 @param dir SkPath::Direction to wind ellipse 1063 */ 1064 void addOval(const SkRect& oval, Direction dir = kCW_Direction); 1065 1066 /** Add oval to SkPath, appending kMove_Verb, four kConic_Verb, and kClose_Verb. 1067 Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width 1068 and half oval height. Oval begins at start and continues 1069 clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction. 1070 1071 @param oval bounds of ellipse added 1072 @param dir SkPath::Direction to wind ellipse 1073 @param start index of initial point of ellipse 1074 */ 1075 void addOval(const SkRect& oval, Direction dir, unsigned start); 1076 1077 /** Add circle centered at (x, y) of size radius to SkPath, appending kMove_Verb, 1078 four kConic_Verb, and kClose_Verb. Circle begins at: (x + radius, y), continuing 1079 clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction. 1080 1081 Has no effect if radius is zero or negative. 1082 1083 @param x center of circle 1084 @param y center of circle 1085 @param radius distance from center to edge 1086 @param dir SkPath::Direction to wind circle 1087 */ 1088 void addCircle(SkScalar x, SkScalar y, SkScalar radius, 1089 Direction dir = kCW_Direction); 1090 1091 /** Append arc to SkPath, as the start of new contour. Arc added is part of ellipse 1092 bounded by oval, from startAngle through sweepAngle. Both startAngle and 1093 sweepAngle are measured in degrees, where zero degrees is aligned with the 1094 positive x-axis, and positive sweeps extends arc clockwise. 1095 1096 If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly 1097 zero, append oval instead of arc. Otherwise, sweepAngle values are treated 1098 modulo 360, and arc may or may not draw depending on numeric rounding. 1099 1100 @param oval bounds of ellipse containing arc 1101 @param startAngle starting angle of arc in degrees 1102 @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 1103 */ 1104 void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle); 1105 1106 /** Append SkRRect to SkPath, creating a new closed contour. SkRRect has bounds 1107 equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If 1108 dir is kCW_Direction, SkRRect starts at top-left of the lower-left corner and 1109 winds clockwise. If dir is kCCW_Direction, SkRRect starts at the bottom-left 1110 of the upper-left corner and winds counterclockwise. 1111 1112 If either rx or ry is too large, rx and ry are scaled uniformly until the 1113 corners fit. If rx or ry is less than or equal to zero, addRoundRect() appends 1114 SkRect rect to SkPath. 1115 1116 After appending, SkPath may be empty, or may contain: SkRect, oval, or RoundRect. 1117 1118 @param rect bounds of SkRRect 1119 @param rx x-radius of rounded corners on the SkRRect 1120 @param ry y-radius of rounded corners on the SkRRect 1121 @param dir SkPath::Direction to wind SkRRect 1122 */ 1123 void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, 1124 Direction dir = kCW_Direction); 1125 1126 /** Append SkRRect to SkPath, creating a new closed contour. SkRRect has bounds 1127 equal to rect; each corner is 90 degrees of an ellipse with radii from the 1128 array. 1129 1130 @param rect bounds of SkRRect 1131 @param radii array of 8 SkScalar values, a radius pair for each corner 1132 @param dir SkPath::Direction to wind SkRRect 1133 */ 1134 void addRoundRect(const SkRect& rect, const SkScalar radii[], 1135 Direction dir = kCW_Direction); 1136 1137 /** Add rrect to SkPath, creating a new closed contour. If 1138 dir is kCW_Direction, rrect starts at top-left of the lower-left corner and 1139 winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left 1140 of the upper-left corner and winds counterclockwise. 1141 1142 After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect. 1143 1144 @param rrect bounds and radii of rounded rectangle 1145 @param dir SkPath::Direction to wind SkRRect 1146 */ 1147 void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction); 1148 1149 /** Add rrect to SkPath, creating a new closed contour. If dir is kCW_Direction, rrect 1150 winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise. 1151 start determines the first point of rrect to add. 1152 1153 @param rrect bounds and radii of rounded rectangle 1154 @param dir SkPath::Direction to wind SkRRect 1155 @param start index of initial point of SkRRect 1156 */ 1157 void addRRect(const SkRRect& rrect, Direction dir, unsigned start); 1158 1159 /** Add contour created from line array, adding (count - 1) line segments. 1160 Contour added starts at pts[0], then adds a line for every additional SkPoint 1161 in pts array. If close is true,appends kClose_Verb to SkPath, connecting 1162 pts[count - 1] and pts[0]. 1163 1164 If count is zero, append kMove_Verb to path. 1165 Has no effect if count is less than one. 1166 1167 @param pts array of line sharing end and start SkPoint 1168 @param count length of SkPoint array 1169 @param close true to add line connecting contour end and start 1170 */ 1171 void addPoly(const SkPoint pts[], int count, bool close); 1172 1173 /** \enum SkPath::AddPathMode 1174 AddPathMode chooses how addPath() appends. Adding one SkPath to another can extend 1175 the last contour or start a new contour. 1176 */ 1177 enum AddPathMode { 1178 /** Since SkPath verb array begins with kMove_Verb if src is not empty, this 1179 starts a new contour. 1180 */ 1181 kAppend_AddPathMode, 1182 1183 /** is not empty, add line from last point to added SkPath first SkPoint. Skip added 1184 SkPath initial kMove_Verb, then append remining verbs, points, and conic weights. 1185 */ 1186 kExtend_AddPathMode, 1187 }; 1188 1189 /** Append src to SkPath, offset by (dx, dy). 1190 1191 If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are 1192 added unaltered. If mode is kExtend_AddPathMode, add line before appending 1193 verbs, points, and conic weights. 1194 1195 @param src SkPath verbs, points, and conic weights to add 1196 @param dx offset added to src SkPoint array x coordinates 1197 @param dy offset added to src SkPoint array y coordinates 1198 @param mode kAppend_AddPathMode or kExtend_AddPathMode 1199 */ 1200 void addPath(const SkPath& src, SkScalar dx, SkScalar dy, 1201 AddPathMode mode = kAppend_AddPathMode); 1202 1203 /** Append src to SkPath. 1204 1205 If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are 1206 added unaltered. If mode is kExtend_AddPathMode, add line before appending 1207 verbs, points, and conic weights. 1208 1209 @param src SkPath verbs, points, and conic weights to add 1210 @param mode kAppend_AddPathMode or kExtend_AddPathMode 1211 */ 1212 void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) { 1213 SkMatrix m; 1214 m.reset(); 1215 this->addPath(src, m, mode); 1216 } 1217 1218 /** Append src to SkPath, transformed by matrix. Transformed curves may have different 1219 verbs, points, and conic weights. 1220 1221 If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are 1222 added unaltered. If mode is kExtend_AddPathMode, add line before appending 1223 verbs, points, and conic weights. 1224 1225 @param src SkPath verbs, points, and conic weights to add 1226 @param matrix transform applied to src 1227 @param mode kAppend_AddPathMode or kExtend_AddPathMode 1228 */ 1229 void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode); 1230 1231 /** Append src to SkPath, from back to front. 1232 Reversed src always appends a new contour to SkPath. 1233 1234 @param src SkPath verbs, points, and conic weights to add 1235 */ 1236 void reverseAddPath(const SkPath& src); 1237 1238 /** Offset SkPoint array by (dx, dy). Offset SkPath replaces dst. 1239 If dst is nullptr, SkPath is replaced by offset data. 1240 1241 @param dx offset added to SkPoint array x coordinates 1242 @param dy offset added to SkPoint array y coordinates 1243 @param dst overwritten, translated copy of SkPath; may be nullptr 1244 */ 1245 void offset(SkScalar dx, SkScalar dy, SkPath* dst) const; 1246 1247 /** Offset SkPoint array by (dx, dy). SkPath is replaced by offset data. 1248 1249 @param dx offset added to SkPoint array x coordinates 1250 @param dy offset added to SkPoint array y coordinates 1251 */ 1252 void offset(SkScalar dx, SkScalar dy) { 1253 this->offset(dx, dy, this); 1254 } 1255 1256 /** Transform verb array, SkPoint array, and weight by matrix. 1257 transform may change verbs and increase their number. 1258 Transformed SkPath replaces dst; if dst is nullptr, original data 1259 is replaced. 1260 1261 @param matrix SkMatrix to apply to SkPath 1262 @param dst overwritten, transformed copy of SkPath; may be nullptr 1263 */ 1264 void transform(const SkMatrix& matrix, SkPath* dst) const; 1265 1266 /** Transform verb array, SkPoint array, and weight by matrix. 1267 transform may change verbs and increase their number. 1268 SkPath is replaced by transformed data. 1269 1270 @param matrix SkMatrix to apply to SkPath 1271 */ 1272 void transform(const SkMatrix& matrix) { 1273 this->transform(matrix, this); 1274 } 1275 1276 /** Returns last point on SkPath in lastPt. Returns false if SkPoint array is empty, 1277 storing (0, 0) if lastPt is not nullptr. 1278 1279 @param lastPt storage for final SkPoint in SkPoint array; may be nullptr 1280 @return true if SkPoint array contains one or more points 1281 */ 1282 bool getLastPt(SkPoint* lastPt) const; 1283 1284 /** Set last point to (x, y). If SkPoint array is empty, append kMove_Verb to 1285 verb array and (x, y) to SkPoint array. 1286 1287 @param x set x-coordinate of last point 1288 @param y set y-coordinate of last point 1289 */ 1290 void setLastPt(SkScalar x, SkScalar y); 1291 1292 /** Set the last point on the path. If no points have been added, moveTo(p) 1293 is automatically called. 1294 1295 @param p set value of last point 1296 */ 1297 void setLastPt(const SkPoint& p) { 1298 this->setLastPt(p.fX, p.fY); 1299 } 1300 1301 /** \enum SkPath::SegmentMask 1302 SegmentMask constants correspond to each drawing Verb type in SkPath; for 1303 instance, if SkPath only contains lines, only the kLine_SegmentMask bit is set. 1304 */ 1305 enum SegmentMask { 1306 kLine_SegmentMask = 1 << 0, //!< Set if verb array contains kLine_Verb. 1307 1308 /** Set if verb array contains kQuad_Verb. Note that conicTo() may add a quad. */ 1309 kQuad_SegmentMask = 1 << 1, 1310 kConic_SegmentMask = 1 << 2, //!< Set if verb array contains kConic_Verb. 1311 kCubic_SegmentMask = 1 << 3, //!< Set if verb array contains kCubic_Verb. 1312 }; 1313 1314 /** Returns a mask, where each set bit corresponds to a SegmentMask constant 1315 if SkPath contains one or more verbs of that type. 1316 Returns zero if SkPath contains no lines, or curves: quads, conics, or cubics. 1317 1318 getSegmentMasks() returns a cached result; it is very fast. 1319 1320 @return SegmentMask bits or zero 1321 */ 1322 uint32_t getSegmentMasks() const { return fPathRef->getSegmentMasks(); } 1323 1324 /** \enum SkPath::Verb 1325 Verb instructs SkPath how to interpret one or more SkPoint and optional conic weight; 1326 manage contour, and terminate SkPath. 1327 */ 1328 enum Verb { 1329 kMove_Verb, //!< Starts new contour at next SkPoint. 1330 1331 /** Adds line from last point to next SkPoint. 1332 Line is a straight segment from SkPoint to SkPoint. 1333 */ 1334 kLine_Verb, 1335 1336 /** Adds quad from last point, using control SkPoint, and end SkPoint. 1337 Quad is a parabolic section within tangents from last point to control SkPoint, 1338 and control SkPoint to end SkPoint. 1339 */ 1340 kQuad_Verb, 1341 1342 /** Adds conic from last point, using control SkPoint, end SkPoint, and conic weight. 1343 Conic is a elliptical, parabolic, or hyperbolic section within tangents 1344 from last point to control SkPoint, and control SkPoint to end SkPoint, constrained 1345 by conic weight. conic weight less than one is elliptical; equal to one is 1346 parabolic (and identical to Quad); greater than one hyperbolic. 1347 */ 1348 kConic_Verb, 1349 1350 /** Adds cubic from last point, using two control points, and end SkPoint. 1351 Cubic is a third-order Bezier_Curve section within tangents from last point 1352 to first control SkPoint, and from second control SkPoint to end SkPoint. 1353 */ 1354 kCubic_Verb, 1355 kClose_Verb, //!< Closes contour, connecting last point to kMove_Verb SkPoint. 1356 kDone_Verb, //!< Terminates SkPath. Not in verb array, but returned by SkPath iterator. 1357 }; 1358 1359 /** \class SkPath::Iter 1360 */ 1361 class SK_API Iter { 1362 public: 1363 1364 /** Initializes iter with an empty SkPath. next() on iter returns kDone_Verb. 1365 Call setPath to initialize iter at a later time. 1366 1367 @return iter of empty SkPath 1368 */ 1369 Iter(); 1370 1371 /** Sets iter to return elements of verb array, SkPoint array, and conic weight in path. 1372 If forceClose is true, iter will add kLine_Verb and kClose_Verb after each 1373 open contour. path is not altered. 1374 1375 @param path SkPath to iterate 1376 @param forceClose true if open contours generate kClose_Verb 1377 @return iter of path 1378 */ 1379 Iter(const SkPath& path, bool forceClose); 1380 1381 /** Sets iter to return elements of verb array, SkPoint array, and conic weight in path. 1382 If forceClose is true, iter will add kLine_Verb and kClose_Verb after each 1383 open contour. path is not altered. 1384 1385 @param path SkPath to iterate 1386 @param forceClose true if open contours generate kClose_Verb 1387 */ 1388 void setPath(const SkPath& path, bool forceClose); 1389 1390 /** Returns next SkPath::Verb in verb array, and advances iter. 1391 When verb array is exhausted, returns kDone_Verb. 1392 1393 Zero to four points are stored in pts, depending on the returned SkPath::Verb. 1394 1395 If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning 1396 only the last in the series; and skip very small lines, quads, and conics; and 1397 skip kClose_Verb following kMove_Verb. 1398 if doConsumeDegenerates is true and exact is true, only skip lines, quads, and 1399 conics with zero lengths. 1400 1401 @param pts storage for SkPoint data describing returned SkPath::Verb 1402 @param doConsumeDegenerates if true, skip degenerate verbs 1403 @param exact skip zero length curves 1404 @return next SkPath::Verb from verb array 1405 */ 1406 Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false) { 1407 if (doConsumeDegenerates) { 1408 this->consumeDegenerateSegments(exact); 1409 } 1410 return this->doNext(pts); 1411 } 1412 1413 /** Returns conic weight if next() returned kConic_Verb. 1414 1415 If next() has not been called, or next() did not return kConic_Verb, 1416 result is undefined. 1417 1418 @return conic weight for conic points returned by next() 1419 */ 1420 SkScalar conicWeight() const { return *fConicWeights; } 1421 1422 /** Returns true if last kLine_Verb returned by next() was generated 1423 by kClose_Verb. When true, the end point returned by next() is 1424 also the start point of contour. 1425 1426 If next() has not been called, or next() did not return kLine_Verb, 1427 result is undefined. 1428 1429 @return true if last kLine_Verb was generated by kClose_Verb 1430 */ 1431 bool isCloseLine() const { return SkToBool(fCloseLine); } 1432 1433 /** Returns true if subsequent calls to next() return kClose_Verb before returning 1434 kMove_Verb. if true, contour iter is processing may end with kClose_Verb, or 1435 iter may have been initialized with force close set to true. 1436 1437 @return true if contour is closed 1438 */ 1439 bool isClosedContour() const; 1440 1441 private: 1442 const SkPoint* fPts; 1443 const uint8_t* fVerbs; 1444 const uint8_t* fVerbStop; 1445 const SkScalar* fConicWeights; 1446 SkPoint fMoveTo; 1447 SkPoint fLastPt; 1448 SkBool8 fForceClose; 1449 SkBool8 fNeedClose; 1450 SkBool8 fCloseLine; 1451 SkBool8 fSegmentState; 1452 1453 inline const SkPoint& cons_moveTo(); 1454 Verb autoClose(SkPoint pts[2]); 1455 void consumeDegenerateSegments(bool exact); 1456 Verb doNext(SkPoint pts[4]); 1457 1458 }; 1459 1460 /** \class SkPath::RawIter 1461 */ 1462 class SK_API RawIter { 1463 public: 1464 1465 /** Initializes RawIter with an empty SkPath. next() on RawIter returns kDone_Verb. 1466 Call setPath to initialize iter at a later time. 1467 1468 @return RawIter of empty SkPath 1469 */ 1470 RawIter() {} 1471 1472 /** Sets RawIter to return elements of verb array, SkPoint array, and conic weight in path. 1473 1474 @param path SkPath to iterate 1475 @return RawIter of path 1476 */ 1477 RawIter(const SkPath& path) { 1478 setPath(path); 1479 } 1480 1481 /** Sets iter to return elements of verb array, SkPoint array, and conic weight in path. 1482 1483 @param path SkPath to iterate 1484 */ 1485 void setPath(const SkPath& path) { 1486 fRawIter.setPathRef(*path.fPathRef.get()); 1487 } 1488 1489 /** Returns next SkPath::Verb in verb array, and advances RawIter. 1490 When verb array is exhausted, returns kDone_Verb. 1491 Zero to four points are stored in pts, depending on the returned SkPath::Verb. 1492 1493 @param pts storage for SkPoint data describing returned SkPath::Verb 1494 @return next SkPath::Verb from verb array 1495 */ 1496 Verb next(SkPoint pts[4]) { 1497 return (Verb) fRawIter.next(pts); 1498 } 1499 1500 /** Returns next SkPath::Verb, but does not advance RawIter. 1501 1502 @return next SkPath::Verb from verb array 1503 */ 1504 Verb peek() const { 1505 return (Verb) fRawIter.peek(); 1506 } 1507 1508 /** Returns conic weight if next() returned kConic_Verb. 1509 1510 If next() has not been called, or next() did not return kConic_Verb, 1511 result is undefined. 1512 1513 @return conic weight for conic points returned by next() 1514 */ 1515 SkScalar conicWeight() const { 1516 return fRawIter.conicWeight(); 1517 } 1518 1519 private: 1520 SkPathRef::Iter fRawIter; 1521 friend class SkPath; 1522 1523 }; 1524 1525 /** Returns true if the point (x, y) is contained by SkPath, taking into 1526 account FillType. 1527 1528 @param x x-coordinate of containment test 1529 @param y y-coordinate of containment test 1530 @return true if SkPoint is in SkPath 1531 */ 1532 bool contains(SkScalar x, SkScalar y) const; 1533 1534 /** Writes text representation of SkPath to stream. If stream is nullptr, writes to 1535 standard output. Set forceClose to true to get edges used to fill SkPath. 1536 Set dumpAsHex true to generate exact binary representations 1537 of floating point numbers used in SkPoint array and conic weights. 1538 1539 @param stream writable SkStream receiving SkPath text representation; may be nullptr 1540 @param forceClose true if missing kClose_Verb is output 1541 @param dumpAsHex true if SkScalar values are written as hexadecimal 1542 */ 1543 void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const; 1544 1545 /** Writes text representation of SkPath to standard output. The representation may be 1546 directly compiled as C++ code. Floating point values are written 1547 with limited precision; it may not be possible to reconstruct original SkPath 1548 from output. 1549 */ 1550 void dump() const; 1551 1552 /** Writes text representation of SkPath to standard output. The representation may be 1553 directly compiled as C++ code. Floating point values are written 1554 in hexadecimal to preserve their exact bit pattern. The output reconstructs the 1555 original SkPath. 1556 1557 Use instead of dump() when submitting 1558 */ 1559 void dumpHex() const; 1560 1561 /** Writes SkPath to buffer, returning the number of bytes written. 1562 Pass nullptr to obtain the storage size. 1563 1564 Writes SkPath::FillType, verb array, SkPoint array, conic weight, and 1565 additionally writes computed information like SkPath::Convexity and bounds. 1566 1567 Use only be used in concert with readFromMemory(); 1568 the format used for SkPath in memory is not guaranteed. 1569 1570 @param buffer storage for SkPath; may be nullptr 1571 @return size of storage required for SkPath; always a multiple of 4 1572 */ 1573 size_t writeToMemory(void* buffer) const; 1574 1575 /** Write SkPath to buffer, returning the buffer written to, wrapped in SkData. 1576 1577 serialize() writes SkPath::FillType, verb array, SkPoint array, conic weight, and 1578 additionally writes computed information like SkPath::Convexity and bounds. 1579 1580 serialize() should only be used in concert with readFromMemory(). 1581 The format used for SkPath in memory is not guaranteed. 1582 1583 @return SkPath data wrapped in SkData buffer 1584 */ 1585 sk_sp<SkData> serialize() const; 1586 1587 /** Initializes SkPath from buffer of size length. Returns zero if the buffer is 1588 data is inconsistent, or the length is too small. 1589 1590 Reads SkPath::FillType, verb array, SkPoint array, conic weight, and 1591 additionally reads computed information like SkPath::Convexity and bounds. 1592 1593 Used only in concert with writeToMemory(); 1594 the format used for SkPath in memory is not guaranteed. 1595 1596 @param buffer storage for SkPath 1597 @param length buffer size in bytes; must be multiple of 4 1598 @return number of bytes read, or zero on failure 1599 */ 1600 size_t readFromMemory(const void* buffer, size_t length); 1601 1602 /** Returns a non-zero, globally unique value. A different value is returned 1603 if verb array, SkPoint array, or conic weight changes. 1604 1605 Setting SkPath::FillType does not change generation id. 1606 1607 Each time the path is modified, a different generation id will be returned. 1608 1609 @return non-zero, globally unique value 1610 */ 1611 uint32_t getGenerationID() const; 1612 1613#ifdef SK_SUPPORT_DIRECT_PATHREF_VALIDATION 1614 /** Returns if SkPath data is consistent. Corrupt SkPath data is detected if 1615 internal values are out of range or internal storage does not match 1616 array dimensions. 1617 1618 @return true if SkPath data is consistent 1619 */ 1620 bool isValid() const { return this->isValidImpl() && fPathRef->isValid(); } 1621#else 1622 bool isValid() const { return this->isValidImpl(); } 1623 bool pathRefIsValid() const { return fPathRef->isValid(); } 1624#endif 1625 1626private: 1627 enum SerializationOffsets { 1628 kType_SerializationShift = 28, // requires 4 bits 1629 kDirection_SerializationShift = 26, // requires 2 bits, could be reused - ignored on read. 1630 kIsVolatile_SerializationShift = 25, // requires 1 bit 1631 // 1 free bit at 24 1632 kConvexity_SerializationShift = 16, // requires 8 bits, could be reused - ignored on read. 1633 kFillType_SerializationShift = 8, // requires 8 bits 1634 // low-8-bits are version 1635 }; 1636 1637 enum SerializationVersions { 1638 // kPathPrivFirstDirection_Version = 1, 1639 kPathPrivLastMoveToIndex_Version = 2, 1640 kPathPrivTypeEnumVersion = 3, 1641 kCurrent_Version = 3 1642 }; 1643 1644 enum SerializationType { 1645 kGeneral = 0, 1646 kRRect = 1 1647 }; 1648 1649 sk_sp<SkPathRef> fPathRef; 1650 int fLastMoveToIndex; 1651 uint8_t fFillType; 1652 mutable SkAtomic<Convexity, sk_memory_order_relaxed> fConvexity; 1653 mutable SkAtomic<uint8_t, sk_memory_order_relaxed> fFirstDirection;// SkPathPriv::FirstDirection 1654 SkBool8 fIsVolatile; 1655 1656 /** Resets all fields other than fPathRef to their initial 'empty' values. 1657 * Assumes the caller has already emptied fPathRef. 1658 * On Android increments fGenerationID without reseting it. 1659 */ 1660 void resetFields(); 1661 1662 /** Sets all fields other than fPathRef to the values in 'that'. 1663 * Assumes the caller has already set fPathRef. 1664 * Doesn't change fGenerationID or fSourcePath on Android. 1665 */ 1666 void copyFields(const SkPath& that); 1667 1668 size_t writeToMemoryAsRRect(int32_t packedHeader, void* buffer) const; 1669 size_t readFromMemoryAsRRect(const void* buffer) const; 1670 1671 friend class Iter; 1672 friend class SkPathPriv; 1673 friend class SkPathStroker; 1674 1675 /* Append, in reverse order, the first contour of path, ignoring path's 1676 last point. If no moveTo() call has been made for this contour, the 1677 first point is automatically set to (0,0). 1678 */ 1679 void reversePathTo(const SkPath&); 1680 1681 // called before we add points for lineTo, quadTo, cubicTo, checking to see 1682 // if we need to inject a leading moveTo first 1683 // 1684 // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0) 1685 // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo) 1686 // 1687 inline void injectMoveToIfNeeded(); 1688 1689 inline bool hasOnlyMoveTos() const; 1690 1691 Convexity internalGetConvexity() const; 1692 1693 /** Asserts if SkPath data is inconsistent. 1694 Debugging check intended for internal use only. 1695 */ 1696 SkDEBUGCODE(void validate() const { SkASSERT(this->isValidImpl()); } ) 1697 bool isValidImpl() const; 1698 SkDEBUGCODE(void validateRef() const { fPathRef->validate(); } ) 1699 1700 bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts, 1701 bool* isClosed, Direction* direction) const; 1702 1703 // called by stroker to see if all points (in the last contour) are equal and worthy of a cap 1704 bool isZeroLengthSincePoint(int startPtIndex) const; 1705 1706 /** Returns if the path can return a bound at no cost (true) or will have to 1707 perform some computation (false). 1708 */ 1709 bool hasComputedBounds() const { 1710 SkDEBUGCODE(this->validate();) 1711 return fPathRef->hasComputedBounds(); 1712 } 1713 1714 1715 // 'rect' needs to be sorted 1716 void setBounds(const SkRect& rect) { 1717 SkPathRef::Editor ed(&fPathRef); 1718 1719 ed.setBounds(rect); 1720 } 1721 1722 void setPt(int index, SkScalar x, SkScalar y); 1723 1724 friend class SkAutoPathBoundsUpdate; 1725 friend class SkAutoDisableOvalCheck; 1726 friend class SkAutoDisableDirectionCheck; 1727 friend class SkPathWriter; 1728 friend class SkOpBuilder; 1729 friend class SkBench_AddPathTest; // perf test reversePathTo 1730 friend class PathTest_Private; // unit test reversePathTo 1731 friend class ForceIsRRect_Private; // unit test isRRect 1732 friend class FuzzPath; // for legacy access to validateRef 1733}; 1734 1735#endif 1736