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