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