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