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