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