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