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