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