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