• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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