• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkPath_DEFINED
9 #define SkPath_DEFINED
10 
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkPathTypes.h"
13 #include "include/core/SkPoint.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkRefCnt.h"
16 #include "include/core/SkScalar.h"
17 #include "include/core/SkTypes.h"
18 #include "include/private/base/SkDebug.h"
19 #include "include/private/base/SkTo.h"
20 #include "include/private/base/SkTypeTraits.h"
21 
22 #include <atomic>
23 #include <cstddef>
24 #include <cstdint>
25 #include <initializer_list>
26 #include <tuple>
27 #include <type_traits>
28 
29 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     /** Experimental, subject to change or removal.
1143 
1144         Adds an "open" oval to SkPath. This follows canvas2D semantics: The oval is not
1145         a separate contour. If the path was empty, then kMove_Verb is appended. Otherwise,
1146         kLine_Verb is appended. Four kConic_Verbs are appended. kClose_Verb is not appended.
1147     */
1148     SkPath& addOpenOval(const SkRect& oval, SkPathDirection dir, unsigned start);
1149 
1150     /** Adds circle centered at (x, y) of size radius to SkPath, appending kMove_Verb,
1151         four kConic_Verb, and kClose_Verb. Circle begins at: (x + radius, y), continuing
1152         clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
1153 
1154         Has no effect if radius is zero or negative.
1155 
1156         @param x       center of circle
1157         @param y       center of circle
1158         @param radius  distance from center to edge
1159         @param dir     SkPath::Direction to wind circle
1160         @return        reference to SkPath
1161     */
1162     SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius,
1163                       SkPathDirection dir = SkPathDirection::kCW);
1164 
1165     /** Appends arc to SkPath, as the start of new contour. Arc added is part of ellipse
1166         bounded by oval, from startAngle through sweepAngle. Both startAngle and
1167         sweepAngle are measured in degrees, where zero degrees is aligned with the
1168         positive x-axis, and positive sweeps extends arc clockwise.
1169 
1170         If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
1171         zero, append oval instead of arc. Otherwise, sweepAngle values are treated
1172         modulo 360, and arc may or may not draw depending on numeric rounding.
1173 
1174         @param oval        bounds of ellipse containing arc
1175         @param startAngle  starting angle of arc in degrees
1176         @param sweepAngle  sweep, in degrees. Positive is clockwise; treated modulo 360
1177         @return            reference to SkPath
1178 
1179         example: https://fiddle.skia.org/c/@Path_addArc
1180     */
1181     SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
1182 
1183     /** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds
1184         equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
1185         dir is kCW_Direction, SkRRect starts at top-left of the lower-left corner and
1186         winds clockwise. If dir is kCCW_Direction, SkRRect starts at the bottom-left
1187         of the upper-left corner and winds counterclockwise.
1188 
1189         If either rx or ry is too large, rx and ry are scaled uniformly until the
1190         corners fit. If rx or ry is less than or equal to zero, addRoundRect() appends
1191         SkRect rect to SkPath.
1192 
1193         After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect.
1194 
1195         @param rect  bounds of SkRRect
1196         @param rx    x-axis radius of rounded corners on the SkRRect
1197         @param ry    y-axis radius of rounded corners on the SkRRect
1198         @param dir   SkPath::Direction to wind SkRRect
1199         @return      reference to SkPath
1200     */
1201     SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
1202                          SkPathDirection dir = SkPathDirection::kCW);
1203 
1204     /** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds
1205         equal to rect; each corner is 90 degrees of an ellipse with radii from the
1206         array.
1207 
1208         @param rect   bounds of SkRRect
1209         @param radii  array of 8 SkScalar values, a radius pair for each corner
1210         @param dir    SkPath::Direction to wind SkRRect
1211         @return       reference to SkPath
1212     */
1213     SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[],
1214                          SkPathDirection dir = SkPathDirection::kCW);
1215 
1216     /** Adds rrect to SkPath, creating a new closed contour. If
1217         dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
1218         winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
1219         of the upper-left corner and winds counterclockwise.
1220 
1221         After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect.
1222 
1223         @param rrect  bounds and radii of rounded rectangle
1224         @param dir    SkPath::Direction to wind SkRRect
1225         @return       reference to SkPath
1226 
1227         example: https://fiddle.skia.org/c/@Path_addRRect
1228     */
1229     SkPath& addRRect(const SkRRect& rrect, SkPathDirection dir = SkPathDirection::kCW);
1230 
1231     /** Adds rrect to SkPath, creating a new closed contour. If dir is kCW_Direction, rrect
1232         winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
1233         start determines the first point of rrect to add.
1234 
1235         @param rrect  bounds and radii of rounded rectangle
1236         @param dir    SkPath::Direction to wind SkRRect
1237         @param start  index of initial point of SkRRect
1238         @return       reference to SkPath
1239 
1240         example: https://fiddle.skia.org/c/@Path_addRRect_2
1241     */
1242     SkPath& addRRect(const SkRRect& rrect, SkPathDirection dir, unsigned start);
1243 
1244     /** Adds contour created from line array, adding (count - 1) line segments.
1245         Contour added starts at pts[0], then adds a line for every additional SkPoint
1246         in pts array. If close is true, appends kClose_Verb to SkPath, connecting
1247         pts[count - 1] and pts[0].
1248 
1249         If count is zero, append kMove_Verb to path.
1250         Has no effect if count is less than one.
1251 
1252         @param pts    array of line sharing end and start SkPoint
1253         @param count  length of SkPoint array
1254         @param close  true to add line connecting contour end and start
1255         @return       reference to SkPath
1256 
1257         example: https://fiddle.skia.org/c/@Path_addPoly
1258     */
1259     SkPath& addPoly(const SkPoint pts[], int count, bool close);
1260 
1261     /** Adds contour created from list. Contour added starts at list[0], then adds a line
1262         for every additional SkPoint in list. If close is true, appends kClose_Verb to SkPath,
1263         connecting last and first SkPoint in list.
1264 
1265         If list is empty, append kMove_Verb to path.
1266 
1267         @param list   array of SkPoint
1268         @param close  true to add line connecting contour end and start
1269         @return       reference to SkPath
1270     */
addPoly(const std::initializer_list<SkPoint> & list,bool close)1271     SkPath& addPoly(const std::initializer_list<SkPoint>& list, bool close) {
1272         return this->addPoly(list.begin(), SkToInt(list.size()), close);
1273     }
1274 
1275 #ifdef SK_HIDE_PATH_EDIT_METHODS
1276 public:
1277 #endif
1278 
1279     /** \enum SkPath::AddPathMode
1280         AddPathMode chooses how addPath() appends. Adding one SkPath to another can extend
1281         the last contour or start a new contour.
1282     */
1283     enum AddPathMode {
1284         /** Contours are appended to the destination path as new contours.
1285         */
1286         kAppend_AddPathMode,
1287         /** Extends the last contour of the destination path with the first countour
1288             of the source path, connecting them with a line.  If the last contour is
1289             closed, a new empty contour starting at its start point is extended instead.
1290             If the destination path is empty, the result is the source path.
1291             The last path of the result is closed only if the last path of the source is.
1292         */
1293         kExtend_AddPathMode,
1294     };
1295 
1296     /** Appends src to SkPath, offset by (dx, dy).
1297 
1298         If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
1299         added unaltered. If mode is kExtend_AddPathMode, add line before appending
1300         verbs, SkPoint, and conic weights.
1301 
1302         @param src   SkPath verbs, SkPoint, and conic weights to add
1303         @param dx    offset added to src SkPoint array x-axis coordinates
1304         @param dy    offset added to src SkPoint array y-axis coordinates
1305         @param mode  kAppend_AddPathMode or kExtend_AddPathMode
1306         @return      reference to SkPath
1307     */
1308     SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy,
1309                     AddPathMode mode = kAppend_AddPathMode);
1310 
1311     /** Appends src to SkPath.
1312 
1313         If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
1314         added unaltered. If mode is kExtend_AddPathMode, add line before appending
1315         verbs, SkPoint, and conic weights.
1316 
1317         @param src   SkPath verbs, SkPoint, and conic weights to add
1318         @param mode  kAppend_AddPathMode or kExtend_AddPathMode
1319         @return      reference to SkPath
1320     */
1321     SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) {
1322         SkMatrix m;
1323         m.reset();
1324         return this->addPath(src, m, mode);
1325     }
1326 
1327     /** Appends src to SkPath, transformed by matrix. Transformed curves may have different
1328         verbs, SkPoint, and conic weights.
1329 
1330         If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
1331         added unaltered. If mode is kExtend_AddPathMode, add line before appending
1332         verbs, SkPoint, and conic weights.
1333 
1334         @param src     SkPath verbs, SkPoint, and conic weights to add
1335         @param matrix  transform applied to src
1336         @param mode    kAppend_AddPathMode or kExtend_AddPathMode
1337         @return        reference to SkPath
1338     */
1339     SkPath& addPath(const SkPath& src, const SkMatrix& matrix,
1340                     AddPathMode mode = kAppend_AddPathMode);
1341 
1342     /** Appends src to SkPath, from back to front.
1343         Reversed src always appends a new contour to SkPath.
1344 
1345         @param src  SkPath verbs, SkPoint, and conic weights to add
1346         @return     reference to SkPath
1347 
1348         example: https://fiddle.skia.org/c/@Path_reverseAddPath
1349     */
1350     SkPath& reverseAddPath(const SkPath& src);
1351 
1352     /** Offsets SkPoint array by (dx, dy). Offset SkPath replaces dst.
1353         If dst is nullptr, SkPath is replaced by offset data.
1354 
1355         @param dx   offset added to SkPoint array x-axis coordinates
1356         @param dy   offset added to SkPoint array y-axis coordinates
1357         @param dst  overwritten, translated copy of SkPath; may be nullptr
1358 
1359         example: https://fiddle.skia.org/c/@Path_offset
1360     */
1361     void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
1362 
1363     /** Offsets SkPoint array by (dx, dy). SkPath is replaced by offset data.
1364 
1365         @param dx  offset added to SkPoint array x-axis coordinates
1366         @param dy  offset added to SkPoint array y-axis coordinates
1367     */
offset(SkScalar dx,SkScalar dy)1368     SkPath& offset(SkScalar dx, SkScalar dy) {
1369         this->offset(dx, dy, this);
1370         return *this;
1371     }
1372 
1373     /** Transforms verb array, SkPoint array, and weight by matrix.
1374         transform may change verbs and increase their number.
1375         Transformed SkPath replaces dst; if dst is nullptr, original data
1376         is replaced.
1377 
1378         @param matrix  SkMatrix to apply to SkPath
1379         @param dst     overwritten, transformed copy of SkPath; may be nullptr
1380         @param pc      whether to apply perspective clipping
1381 
1382         example: https://fiddle.skia.org/c/@Path_transform
1383     */
1384     void transform(const SkMatrix& matrix, SkPath* dst,
1385                    SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const;
1386 
1387     /** Transforms verb array, SkPoint array, and weight by matrix.
1388         transform may change verbs and increase their number.
1389         SkPath is replaced by transformed data.
1390 
1391         @param matrix  SkMatrix to apply to SkPath
1392         @param pc      whether to apply perspective clipping
1393     */
1394     SkPath& transform(const SkMatrix& matrix,
1395                    SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) {
1396         this->transform(matrix, this, pc);
1397         return *this;
1398     }
1399 
1400     SkPath makeTransform(const SkMatrix& m,
1401                          SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const {
1402         SkPath dst;
1403         this->transform(m, &dst, pc);
1404         return dst;
1405     }
1406 
makeScale(SkScalar sx,SkScalar sy)1407     SkPath makeScale(SkScalar sx, SkScalar sy) {
1408         return this->makeTransform(SkMatrix::Scale(sx, sy), SkApplyPerspectiveClip::kNo);
1409     }
1410 
1411     /** Returns last point on SkPath in lastPt. Returns false if SkPoint array is empty,
1412         storing (0, 0) if lastPt is not nullptr.
1413 
1414         @param lastPt  storage for final SkPoint in SkPoint array; may be nullptr
1415         @return        true if SkPoint array contains one or more SkPoint
1416 
1417         example: https://fiddle.skia.org/c/@Path_getLastPt
1418     */
1419     bool getLastPt(SkPoint* lastPt) const;
1420 
1421     /** Sets last point to (x, y). If SkPoint array is empty, append kMove_Verb to
1422         verb array and append (x, y) to SkPoint array.
1423 
1424         @param x  set x-axis value of last point
1425         @param y  set y-axis value of last point
1426 
1427         example: https://fiddle.skia.org/c/@Path_setLastPt
1428     */
1429     void setLastPt(SkScalar x, SkScalar y);
1430 
1431     /** Sets the last point on the path. If SkPoint array is empty, append kMove_Verb to
1432         verb array and append p to SkPoint array.
1433 
1434         @param p  set value of last point
1435     */
setLastPt(const SkPoint & p)1436     void setLastPt(const SkPoint& p) {
1437         this->setLastPt(p.fX, p.fY);
1438     }
1439 
1440     /** \enum SkPath::SegmentMask
1441         SegmentMask constants correspond to each drawing Verb type in SkPath; for
1442         instance, if SkPath only contains lines, only the kLine_SegmentMask bit is set.
1443     */
1444     enum SegmentMask {
1445         kLine_SegmentMask  = kLine_SkPathSegmentMask,
1446         kQuad_SegmentMask  = kQuad_SkPathSegmentMask,
1447         kConic_SegmentMask = kConic_SkPathSegmentMask,
1448         kCubic_SegmentMask = kCubic_SkPathSegmentMask,
1449     };
1450 
1451     /** Returns a mask, where each set bit corresponds to a SegmentMask constant
1452         if SkPath contains one or more verbs of that type.
1453         Returns zero if SkPath contains no lines, or curves: quads, conics, or cubics.
1454 
1455         getSegmentMasks() returns a cached result; it is very fast.
1456 
1457         @return  SegmentMask bits or zero
1458     */
1459     uint32_t getSegmentMasks() const;
1460 
1461     /** \enum SkPath::Verb
1462         Verb instructs SkPath how to interpret one or more SkPoint and optional conic weight;
1463         manage contour, and terminate SkPath.
1464     */
1465     enum Verb {
1466         kMove_Verb  = static_cast<int>(SkPathVerb::kMove),
1467         kLine_Verb  = static_cast<int>(SkPathVerb::kLine),
1468         kQuad_Verb  = static_cast<int>(SkPathVerb::kQuad),
1469         kConic_Verb = static_cast<int>(SkPathVerb::kConic),
1470         kCubic_Verb = static_cast<int>(SkPathVerb::kCubic),
1471         kClose_Verb = static_cast<int>(SkPathVerb::kClose),
1472         kDone_Verb  = kClose_Verb + 1
1473     };
1474 
1475     /** \class SkPath::Iter
1476         Iterates through verb array, and associated SkPoint array and conic weight.
1477         Provides options to treat open contours as closed, and to ignore
1478         degenerate data.
1479     */
1480     class SK_API Iter {
1481     public:
1482 
1483         /** Initializes SkPath::Iter with an empty SkPath. next() on SkPath::Iter returns
1484             kDone_Verb.
1485             Call setPath to initialize SkPath::Iter at a later time.
1486 
1487             @return  SkPath::Iter of empty SkPath
1488 
1489         example: https://fiddle.skia.org/c/@Path_Iter_Iter
1490         */
1491         Iter();
1492 
1493         /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in
1494             path. If forceClose is true, SkPath::Iter will add kLine_Verb and kClose_Verb after each
1495             open contour. path is not altered.
1496 
1497             @param path        SkPath to iterate
1498             @param forceClose  true if open contours generate kClose_Verb
1499             @return            SkPath::Iter of path
1500 
1501         example: https://fiddle.skia.org/c/@Path_Iter_const_SkPath
1502         */
1503         Iter(const SkPath& path, bool forceClose);
1504 
1505         /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in
1506             path. If forceClose is true, SkPath::Iter will add kLine_Verb and kClose_Verb after each
1507             open contour. path is not altered.
1508 
1509             @param path        SkPath to iterate
1510             @param forceClose  true if open contours generate kClose_Verb
1511 
1512         example: https://fiddle.skia.org/c/@Path_Iter_setPath
1513         */
1514         void setPath(const SkPath& path, bool forceClose);
1515 
1516         /** Returns next SkPath::Verb in verb array, and advances SkPath::Iter.
1517             When verb array is exhausted, returns kDone_Verb.
1518 
1519             Zero to four SkPoint are stored in pts, depending on the returned SkPath::Verb.
1520 
1521             @param pts  storage for SkPoint data describing returned SkPath::Verb
1522             @return     next SkPath::Verb from verb array
1523 
1524         example: https://fiddle.skia.org/c/@Path_RawIter_next
1525         */
1526         Verb next(SkPoint pts[4]);
1527 
1528         /** Returns conic weight if next() returned kConic_Verb.
1529 
1530             If next() has not been called, or next() did not return kConic_Verb,
1531             result is undefined.
1532 
1533             @return  conic weight for conic SkPoint returned by next()
1534         */
conicWeight()1535         SkScalar conicWeight() const { return *fConicWeights; }
1536 
1537         /** Returns true if last kLine_Verb returned by next() was generated
1538             by kClose_Verb. When true, the end point returned by next() is
1539             also the start point of contour.
1540 
1541             If next() has not been called, or next() did not return kLine_Verb,
1542             result is undefined.
1543 
1544             @return  true if last kLine_Verb was generated by kClose_Verb
1545         */
isCloseLine()1546         bool isCloseLine() const { return SkToBool(fCloseLine); }
1547 
1548         /** Returns true if subsequent calls to next() return kClose_Verb before returning
1549             kMove_Verb. if true, contour SkPath::Iter is processing may end with kClose_Verb, or
1550             SkPath::Iter may have been initialized with force close set to true.
1551 
1552             @return  true if contour is closed
1553 
1554         example: https://fiddle.skia.org/c/@Path_Iter_isClosedContour
1555         */
1556         bool isClosedContour() const;
1557 
1558     private:
1559         const SkPoint*  fPts;
1560         const uint8_t*  fVerbs;
1561         const uint8_t*  fVerbStop;
1562         const SkScalar* fConicWeights;
1563         SkPoint         fMoveTo;
1564         SkPoint         fLastPt;
1565         bool            fForceClose;
1566         bool            fNeedClose;
1567         bool            fCloseLine;
1568 
1569         Verb autoClose(SkPoint pts[2]);
1570     };
1571 
1572 private:
1573     /** \class SkPath::RangeIter
1574         Iterates through a raw range of path verbs, points, and conics. All values are returned
1575         unaltered.
1576 
1577         NOTE: This class will be moved into SkPathPriv once RangeIter is removed.
1578     */
1579     class RangeIter {
1580     public:
1581         RangeIter() = default;
RangeIter(const uint8_t * verbs,const SkPoint * points,const SkScalar * weights)1582         RangeIter(const uint8_t* verbs, const SkPoint* points, const SkScalar* weights)
1583                 : fVerb(verbs), fPoints(points), fWeights(weights) {
1584             SkDEBUGCODE(fInitialPoints = fPoints;)
1585         }
1586         bool operator!=(const RangeIter& that) const {
1587             return fVerb != that.fVerb;
1588         }
1589         bool operator==(const RangeIter& that) const {
1590             return fVerb == that.fVerb;
1591         }
1592         RangeIter& operator++() {
1593             auto verb = static_cast<SkPathVerb>(*fVerb++);
1594             fPoints += pts_advance_after_verb(verb);
1595             if (verb == SkPathVerb::kConic) {
1596                 ++fWeights;
1597             }
1598             return *this;
1599         }
1600         RangeIter operator++(int) {
1601             RangeIter copy = *this;
1602             this->operator++();
1603             return copy;
1604         }
peekVerb()1605         SkPathVerb peekVerb() const {
1606             return static_cast<SkPathVerb>(*fVerb);
1607         }
1608         std::tuple<SkPathVerb, const SkPoint*, const SkScalar*> operator*() const {
1609             SkPathVerb verb = this->peekVerb();
1610             // We provide the starting point for beziers by peeking backwards from the current
1611             // point, which works fine as long as there is always a kMove before any geometry.
1612             // (SkPath::injectMoveToIfNeeded should have guaranteed this to be the case.)
1613             int backset = pts_backset_for_verb(verb);
1614             SkASSERT(fPoints + backset >= fInitialPoints);
1615             return {verb, fPoints + backset, fWeights};
1616         }
1617     private:
pts_advance_after_verb(SkPathVerb verb)1618         constexpr static int pts_advance_after_verb(SkPathVerb verb) {
1619             switch (verb) {
1620                 case SkPathVerb::kMove: return 1;
1621                 case SkPathVerb::kLine: return 1;
1622                 case SkPathVerb::kQuad: return 2;
1623                 case SkPathVerb::kConic: return 2;
1624                 case SkPathVerb::kCubic: return 3;
1625                 case SkPathVerb::kClose: return 0;
1626             }
1627             SkUNREACHABLE;
1628         }
pts_backset_for_verb(SkPathVerb verb)1629         constexpr static int pts_backset_for_verb(SkPathVerb verb) {
1630             switch (verb) {
1631                 case SkPathVerb::kMove: return 0;
1632                 case SkPathVerb::kLine: return -1;
1633                 case SkPathVerb::kQuad: return -1;
1634                 case SkPathVerb::kConic: return -1;
1635                 case SkPathVerb::kCubic: return -1;
1636                 case SkPathVerb::kClose: return -1;
1637             }
1638             SkUNREACHABLE;
1639         }
1640         const uint8_t* fVerb = nullptr;
1641         const SkPoint* fPoints = nullptr;
1642         const SkScalar* fWeights = nullptr;
1643         SkDEBUGCODE(const SkPoint* fInitialPoints = nullptr;)
1644     };
1645 public:
1646 
1647     /** \class SkPath::RawIter
1648         Use Iter instead. This class will soon be removed and RangeIter will be made private.
1649     */
1650     class SK_API RawIter {
1651     public:
1652 
1653         /** Initializes RawIter with an empty SkPath. next() on RawIter returns kDone_Verb.
1654             Call setPath to initialize SkPath::Iter at a later time.
1655 
1656             @return  RawIter of empty SkPath
1657         */
RawIter()1658         RawIter() {}
1659 
1660         /** Sets RawIter to return elements of verb array, SkPoint array, and conic weight in path.
1661 
1662             @param path  SkPath to iterate
1663             @return      RawIter of path
1664         */
RawIter(const SkPath & path)1665         RawIter(const SkPath& path) {
1666             setPath(path);
1667         }
1668 
1669         /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in
1670             path.
1671 
1672             @param path  SkPath to iterate
1673         */
1674         void setPath(const SkPath&);
1675 
1676         /** Returns next SkPath::Verb in verb array, and advances RawIter.
1677             When verb array is exhausted, returns kDone_Verb.
1678             Zero to four SkPoint are stored in pts, depending on the returned SkPath::Verb.
1679 
1680             @param pts  storage for SkPoint data describing returned SkPath::Verb
1681             @return     next SkPath::Verb from verb array
1682         */
1683         Verb next(SkPoint[4]);
1684 
1685         /** Returns next SkPath::Verb, but does not advance RawIter.
1686 
1687             @return  next SkPath::Verb from verb array
1688         */
peek()1689         Verb peek() const {
1690             return (fIter != fEnd) ? static_cast<Verb>(std::get<0>(*fIter)) : kDone_Verb;
1691         }
1692 
1693         /** Returns conic weight if next() returned kConic_Verb.
1694 
1695             If next() has not been called, or next() did not return kConic_Verb,
1696             result is undefined.
1697 
1698             @return  conic weight for conic SkPoint returned by next()
1699         */
conicWeight()1700         SkScalar conicWeight() const {
1701             return fConicWeight;
1702         }
1703 
1704     private:
1705         RangeIter fIter;
1706         RangeIter fEnd;
1707         SkScalar fConicWeight = 0;
1708         friend class SkPath;
1709 
1710     };
1711 
1712     /** Returns true if the point (x, y) is contained by SkPath, taking into
1713         account FillType.
1714 
1715         @param x  x-axis value of containment test
1716         @param y  y-axis value of containment test
1717         @return   true if SkPoint is in SkPath
1718 
1719         example: https://fiddle.skia.org/c/@Path_contains
1720     */
1721     bool contains(SkScalar x, SkScalar y) const;
1722 
1723     /** Writes text representation of SkPath to stream. If stream is nullptr, writes to
1724         standard output. Set dumpAsHex true to generate exact binary representations
1725         of floating point numbers used in SkPoint array and conic weights.
1726 
1727         @param stream      writable SkWStream receiving SkPath text representation; may be nullptr
1728         @param dumpAsHex   true if SkScalar values are written as hexadecimal
1729 
1730         example: https://fiddle.skia.org/c/@Path_dump
1731     */
1732     void dump(SkWStream* stream, bool dumpAsHex) const;
1733 
dump()1734     void dump() const { this->dump(nullptr, false); }
dumpHex()1735     void dumpHex() const { this->dump(nullptr, true); }
1736 
1737     // Like dump(), but outputs for the SkPath::Make() factory
1738     void dumpArrays(SkWStream* stream, bool dumpAsHex) const;
dumpArrays()1739     void dumpArrays() const { this->dumpArrays(nullptr, false); }
1740 
1741     /** Writes SkPath to buffer, returning the number of bytes written.
1742         Pass nullptr to obtain the storage size.
1743 
1744         Writes SkPath::FillType, verb array, SkPoint array, conic weight, and
1745         additionally writes computed information like SkPath::Convexity and bounds.
1746 
1747         Use only be used in concert with readFromMemory();
1748         the format used for SkPath in memory is not guaranteed.
1749 
1750         @param buffer  storage for SkPath; may be nullptr
1751         @return        size of storage required for SkPath; always a multiple of 4
1752 
1753         example: https://fiddle.skia.org/c/@Path_writeToMemory
1754     */
1755     size_t writeToMemory(void* buffer) const;
1756 
1757     /** Writes SkPath to buffer, returning the buffer written to, wrapped in SkData.
1758 
1759         serialize() writes SkPath::FillType, verb array, SkPoint array, conic weight, and
1760         additionally writes computed information like SkPath::Convexity and bounds.
1761 
1762         serialize() should only be used in concert with readFromMemory().
1763         The format used for SkPath in memory is not guaranteed.
1764 
1765         @return  SkPath data wrapped in SkData buffer
1766 
1767         example: https://fiddle.skia.org/c/@Path_serialize
1768     */
1769     sk_sp<SkData> serialize() const;
1770 
1771     /** Initializes SkPath from buffer of size length. Returns zero if the buffer is
1772         data is inconsistent, or the length is too small.
1773 
1774         Reads SkPath::FillType, verb array, SkPoint array, conic weight, and
1775         additionally reads computed information like SkPath::Convexity and bounds.
1776 
1777         Used only in concert with writeToMemory();
1778         the format used for SkPath in memory is not guaranteed.
1779 
1780         @param buffer  storage for SkPath
1781         @param length  buffer size in bytes; must be multiple of 4
1782         @return        number of bytes read, or zero on failure
1783 
1784         example: https://fiddle.skia.org/c/@Path_readFromMemory
1785     */
1786     size_t readFromMemory(const void* buffer, size_t length);
1787 
1788     /** (See Skia bug 1762.)
1789         Returns a non-zero, globally unique value. A different value is returned
1790         if verb array, SkPoint array, or conic weight changes.
1791 
1792         Setting SkPath::FillType does not change generation identifier.
1793 
1794         Each time the path is modified, a different generation identifier will be returned.
1795         SkPath::FillType does affect generation identifier on Android framework.
1796 
1797         @return  non-zero, globally unique value
1798 
1799         example: https://fiddle.skia.org/c/@Path_getGenerationID
1800     */
1801     uint32_t getGenerationID() const;
1802 
1803     /** Returns if SkPath data is consistent. Corrupt SkPath data is detected if
1804         internal values are out of range or internal storage does not match
1805         array dimensions.
1806 
1807         @return  true if SkPath data is consistent
1808     */
1809     bool isValid() const;
1810 
1811     using sk_is_trivially_relocatable = std::true_type;
1812 
1813 private:
1814     SkPath(sk_sp<SkPathRef>, SkPathFillType, bool isVolatile, SkPathConvexity,
1815            SkPathFirstDirection firstDirection);
1816 
1817     sk_sp<SkPathRef>               fPathRef;
1818     int                            fLastMoveToIndex;
1819     mutable std::atomic<uint8_t>   fConvexity;      // SkPathConvexity
1820     mutable std::atomic<uint8_t>   fFirstDirection; // SkPathFirstDirection
1821     uint8_t                        fFillType    : 2;
1822     uint8_t                        fIsVolatile  : 1;
1823 
1824     static_assert(::sk_is_trivially_relocatable<decltype(fPathRef)>::value);
1825 
1826     /** Resets all fields other than fPathRef to their initial 'empty' values.
1827      *  Assumes the caller has already emptied fPathRef.
1828      */
1829     void resetFields();
1830 
1831     /** Sets all fields other than fPathRef to the values in 'that'.
1832      *  Assumes the caller has already set fPathRef.
1833      *  Doesn't change fGenerationID or fSourcePath on Android.
1834      */
1835     void copyFields(const SkPath& that);
1836 
1837     size_t writeToMemoryAsRRect(void* buffer) const;
1838     size_t readAsRRect(const void*, size_t);
1839 
1840     friend class Iter;
1841     friend class SkPathPriv;
1842     friend class SkPathStroker;
1843 
1844     /*  Append, in reverse order, the first contour of path, ignoring path's
1845         last point. If no moveTo() call has been made for this contour, the
1846         first point is automatically set to (0,0).
1847     */
1848     SkPath& reversePathTo(const SkPath&);
1849 
1850     // called before we add points for lineTo, quadTo, cubicTo, checking to see
1851     // if we need to inject a leading moveTo first
1852     //
1853     //  SkPath path; path.lineTo(...);   <--- need a leading moveTo(0, 0)
1854     // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo)
1855     //
1856     inline void injectMoveToIfNeeded();
1857 
1858     inline bool hasOnlyMoveTos() const;
1859 
1860     SkPathConvexity computeConvexity() const;
1861 
1862     bool isValidImpl() const;
1863     /** Asserts if SkPath data is inconsistent.
1864         Debugging check intended for internal use only.
1865      */
1866 #ifdef SK_DEBUG
1867     void validate() const;
1868     void validateRef() const;
1869 #endif
1870 
1871     // called by stroker to see if all points (in the last contour) are equal and worthy of a cap
1872     bool isZeroLengthSincePoint(int startPtIndex) const;
1873 
1874     /** Returns if the path can return a bound at no cost (true) or will have to
1875         perform some computation (false).
1876      */
1877     bool hasComputedBounds() const;
1878 
1879     // 'rect' needs to be sorted
1880     void setBounds(const SkRect& rect);
1881 
1882     void setPt(int index, SkScalar x, SkScalar y);
1883 
1884     SkPath& dirtyAfterEdit();
1885 
1886     // Bottlenecks for working with fConvexity and fFirstDirection.
1887     // Notice the setters are const... these are mutable atomic fields.
1888     void  setConvexity(SkPathConvexity) const;
1889 
1890     void setFirstDirection(SkPathFirstDirection) const;
1891     SkPathFirstDirection getFirstDirection() const;
1892 
1893     /** Returns the comvexity type, computing if needed. Never returns kUnknown.
1894         @return  path's convexity type (convex or concave)
1895     */
1896     SkPathConvexity getConvexity() const;
1897 
1898     SkPathConvexity getConvexityOrUnknown() const;
1899 
1900     // Compares the cached value with a freshly computed one (computeConvexity())
1901     bool isConvexityAccurate() const;
1902 
1903     /** Stores a convexity type for this path. This is what will be returned if
1904      *  getConvexityOrUnknown() is called. If you pass kUnknown, then if getContexityType()
1905      *  is called, the real convexity will be computed.
1906      *
1907      *  example: https://fiddle.skia.org/c/@Path_setConvexity
1908      */
1909     void setConvexity(SkPathConvexity convexity);
1910 
1911     /** Shrinks SkPath verb array and SkPoint array storage to discard unused capacity.
1912      *  May reduce the heap overhead for SkPath known to be fully constructed.
1913      *
1914      *  NOTE: This may relocate the underlying buffers, and thus any Iterators referencing
1915      *        this path should be discarded after calling shrinkToFit().
1916      */
1917     void shrinkToFit();
1918 
1919     // Creates a new Path after the supplied arguments have been validated by
1920     // sk_path_analyze_verbs().
1921     static SkPath MakeInternal(const SkPathVerbAnalysis& analsis,
1922                                const SkPoint points[],
1923                                const uint8_t verbs[],
1924                                int verbCount,
1925                                const SkScalar conics[],
1926                                SkPathFillType fillType,
1927                                bool isVolatile);
1928 
1929     friend class SkAutoPathBoundsUpdate;
1930     friend class SkAutoDisableOvalCheck;
1931     friend class SkAutoDisableDirectionCheck;
1932     friend class SkPathBuilder;
1933     friend class SkPathEdgeIter;
1934     friend class SkPathWriter;
1935     friend class SkOpBuilder;
1936     friend class SkBench_AddPathTest; // perf test reversePathTo
1937     friend class PathTest_Private; // unit test reversePathTo
1938     friend class ForceIsRRect_Private; // unit test isRRect
1939     friend class FuzzPath; // for legacy access to validateRef
1940 };
1941 
1942 #endif
1943