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