1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkPath_DEFINED
9 #define SkPath_DEFINED
10 
11 #include "SkMatrix.h"
12 #include "SkPathRef.h"
13 #include "SkRefCnt.h"
14 
15 class SkReader32;
16 class SkWriter32;
17 class SkAutoPathBoundsUpdate;
18 class SkString;
19 class SkRRect;
20 class SkWStream;
21 
22 /** \class SkPath
23 
24     The SkPath class encapsulates compound (multiple contour) geometric paths
25     consisting of straight line segments, quadratic curves, and cubic curves.
26 */
27 class SK_API SkPath {
28 public:
29     enum Direction {
30         /** clockwise direction for adding closed contours */
31         kCW_Direction,
32         /** counter-clockwise direction for adding closed contours */
33         kCCW_Direction,
34     };
35 
36     SkPath();
37     SkPath(const SkPath&);
38     ~SkPath();
39 
40     SkPath& operator=(const SkPath&);
41     friend  SK_API bool operator==(const SkPath&, const SkPath&);
42     friend bool operator!=(const SkPath& a, const SkPath& b) {
43         return !(a == b);
44     }
45 
46     /** Return true if the paths contain an equal array of verbs and weights. Paths
47      *  with equal verb counts can be readily interpolated. If the paths contain one
48      *  or more conics, the conics' weights must also match.
49      *
50      *  @param compare  The path to compare.
51      *
52      *  @return true if the paths have the same verbs and weights.
53      */
54     bool isInterpolatable(const SkPath& compare) const;
55 
56     /** Interpolate between two paths with same-sized point arrays.
57      *  The out path contains the verbs and weights of this path.
58      *  The out points are a weighted average of this path and the ending path.
59      *
60      *  @param ending  The path to interpolate between.
61      *  @param weight  The weight, from 0 to 1. The output points are set to
62      *                 (this->points * weight) + ending->points * (1 - weight).
63      *  @return true if the paths could be interpolated.
64      */
65     bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const;
66 
67 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
68     /** Returns true if the caller is the only owner of the underlying path data */
unique()69     bool unique() const { return fPathRef->unique(); }
70 #endif
71 
72     enum FillType {
73         /** Specifies that "inside" is computed by a non-zero sum of signed
74             edge crossings
75         */
76         kWinding_FillType,
77         /** Specifies that "inside" is computed by an odd number of edge
78             crossings
79         */
80         kEvenOdd_FillType,
81         /** Same as Winding, but draws outside of the path, rather than inside
82         */
83         kInverseWinding_FillType,
84         /** Same as EvenOdd, but draws outside of the path, rather than inside
85          */
86         kInverseEvenOdd_FillType
87     };
88 
89     /** Return the path's fill type. This is used to define how "inside" is
90         computed. The default value is kWinding_FillType.
91 
92         @return the path's fill type
93     */
getFillType()94     FillType getFillType() const { return (FillType)fFillType; }
95 
96     /** Set the path's fill type. This is used to define how "inside" is
97         computed. The default value is kWinding_FillType.
98 
99         @param ft The new fill type for this path
100     */
setFillType(FillType ft)101     void setFillType(FillType ft) {
102         fFillType = SkToU8(ft);
103     }
104 
105     /** Returns true if the filltype is one of the Inverse variants */
isInverseFillType()106     bool isInverseFillType() const { return IsInverseFillType((FillType)fFillType); }
107 
108     /**
109      *  Toggle between inverse and normal filltypes. This reverse the return
110      *  value of isInverseFillType()
111      */
toggleInverseFillType()112     void toggleInverseFillType() {
113         fFillType ^= 2;
114     }
115 
116     enum Convexity {
117         kUnknown_Convexity,
118         kConvex_Convexity,
119         kConcave_Convexity
120     };
121 
122     /**
123      *  Return the path's convexity, as stored in the path. If it is currently unknown,
124      *  then this function will attempt to compute the convexity (and cache the result).
125      */
getConvexity()126     Convexity getConvexity() const {
127         if (kUnknown_Convexity != fConvexity) {
128             return static_cast<Convexity>(fConvexity);
129         } else {
130             return this->internalGetConvexity();
131         }
132     }
133 
134     /**
135      *  Return the currently cached value for convexity, even if that is set to
136      *  kUnknown_Convexity. Note: getConvexity() will automatically call
137      *  ComputeConvexity and cache its return value if the current setting is
138      *  kUnknown.
139      */
getConvexityOrUnknown()140     Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; }
141 
142     /**
143      *  Store a convexity setting in the path. There is no automatic check to
144      *  see if this value actually agrees with the return value that would be
145      *  computed by getConvexity().
146      *
147      *  Note: even if this is set to a "known" value, if the path is later
148      *  changed (e.g. lineTo(), addRect(), etc.) then the cached value will be
149      *  reset to kUnknown_Convexity.
150      */
151     void setConvexity(Convexity);
152 
153     /**
154      *  Returns true if the path is flagged as being convex. This is not a
155      *  confirmed by any analysis, it is just the value set earlier.
156      */
isConvex()157     bool isConvex() const {
158         return kConvex_Convexity == this->getConvexity();
159     }
160 
161     /**
162      *  Set the isConvex flag to true or false. Convex paths may draw faster if
163      *  this flag is set, though setting this to true on a path that is in fact
164      *  not convex can give undefined results when drawn. Paths default to
165      *  isConvex == false
166      */
167     SK_ATTR_DEPRECATED("use setConvexity")
setIsConvex(bool isConvex)168     void setIsConvex(bool isConvex) {
169         this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity);
170     }
171 
172     /** Returns true if the path is an oval.
173      *
174      * @param rect      returns the bounding rect of this oval. It's a circle
175      *                  if the height and width are the same.
176      * @param dir       is the oval CCW (or CW if false).
177      * @param start     indicates where the contour starts on the oval (see
178      *                  SkPath::addOval for intepretation of the index).
179      * @return true if this path is an oval.
180      *              Tracking whether a path is an oval is considered an
181      *              optimization for performance and so some paths that are in
182      *              fact ovals can report false.
183      */
184     bool isOval(SkRect* rect, Direction* dir = nullptr,
185                 unsigned* start = nullptr) const {
186         bool isCCW = false;
187         bool result = fPathRef->isOval(rect, &isCCW, start);
188         if (dir && result) {
189             *dir = isCCW ? kCCW_Direction : kCW_Direction;
190         }
191         return result;
192     }
193 
194     /** Returns true if the path is a round rect.
195      *
196      * @param rrect  Returns the bounding rect and radii of this round rect.
197      * @param dir    is the rrect CCW (or CW if false).
198      * @param start  indicates where the contour starts on the rrect (see
199      *               SkPath::addRRect for intepretation of the index).
200      *
201      * @return true if this path is a round rect.
202      *              Tracking whether a path is a round rect is considered an
203      *              optimization for performance and so some paths that are in
204      *              fact round rects can report false.
205      */
206     bool isRRect(SkRRect* rrect, Direction* dir = nullptr,
207                  unsigned* start = nullptr) const {
208         bool isCCW = false;
209         bool result = fPathRef->isRRect(rrect, &isCCW, start);
210         if (dir && result) {
211             *dir = isCCW ? kCCW_Direction : kCW_Direction;
212         }
213         return result;
214     }
215 
216     /** Clear any lines and curves from the path, making it empty. This frees up
217         internal storage associated with those segments.
218         On Android, does not change fSourcePath.
219     */
220     void reset();
221 
222     /** Similar to reset(), in that all lines and curves are removed from the
223         path. However, any internal storage for those lines/curves is retained,
224         making reuse of the path potentially faster.
225         On Android, does not change fSourcePath.
226     */
227     void rewind();
228 
229     /** Returns true if the path is empty (contains no lines or curves)
230 
231         @return true if the path is empty (contains no lines or curves)
232     */
isEmpty()233     bool isEmpty() const {
234         SkDEBUGCODE(this->validate();)
235         return 0 == fPathRef->countVerbs();
236     }
237 
238     /** Return true if the last contour of this path ends with a close verb.
239      */
240     bool isLastContourClosed() const;
241 
242     /**
243      *  Returns true if all of the points in this path are finite, meaning there
244      *  are no infinities and no NaNs.
245      */
isFinite()246     bool isFinite() const {
247         SkDEBUGCODE(this->validate();)
248         return fPathRef->isFinite();
249     }
250 
251     /** Returns true if the path is volatile (i.e. should not be cached by devices.)
252      */
isVolatile()253     bool isVolatile() const {
254         return SkToBool(fIsVolatile);
255     }
256 
257     /** Specify whether this path is volatile. Paths are not volatile by
258      default. Temporary paths that are discarded or modified after use should be
259      marked as volatile. This provides a hint to the device that the path
260      should not be cached. Providing this hint when appropriate can
261      improve performance by avoiding unnecessary overhead and resource
262      consumption on the device.
263      */
setIsVolatile(bool isVolatile)264     void setIsVolatile(bool isVolatile) {
265         fIsVolatile = isVolatile;
266     }
267 
268     /** Test a line for zero length
269 
270         @return true if the line is of zero length; otherwise false.
271     */
IsLineDegenerate(const SkPoint & p1,const SkPoint & p2,bool exact)272     static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact) {
273         return exact ? p1 == p2 : p1.equalsWithinTolerance(p2);
274     }
275 
276     /** Test a quad for zero length
277 
278         @return true if the quad is of zero length; otherwise false.
279     */
IsQuadDegenerate(const SkPoint & p1,const SkPoint & p2,const SkPoint & p3,bool exact)280     static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
281                                  const SkPoint& p3, bool exact) {
282         return exact ? p1 == p2 && p2 == p3 : p1.equalsWithinTolerance(p2) &&
283                p2.equalsWithinTolerance(p3);
284     }
285 
286     /** Test a cubic curve for zero length
287 
288         @return true if the cubic is of zero length; otherwise false.
289     */
IsCubicDegenerate(const SkPoint & p1,const SkPoint & p2,const SkPoint & p3,const SkPoint & p4,bool exact)290     static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
291                                   const SkPoint& p3, const SkPoint& p4, bool exact) {
292         return exact ? p1 == p2 && p2 == p3 && p3 == p4 : p1.equalsWithinTolerance(p2) &&
293                p2.equalsWithinTolerance(p3) &&
294                p3.equalsWithinTolerance(p4);
295     }
296 
297     /**
298      *  Returns true if the path specifies a single line (i.e. it contains just
299      *  a moveTo and a lineTo). If so, and line[] is not null, it sets the 2
300      *  points in line[] to the end-points of the line. If the path is not a
301      *  line, returns false and ignores line[].
302      */
303     bool isLine(SkPoint line[2]) const;
304 
305     /** Return the number of points in the path
306      */
307     int countPoints() const;
308 
309     /** Return the point at the specified index. If the index is out of range
310          (i.e. is not 0 <= index < countPoints()) then the returned coordinates
311          will be (0,0)
312      */
313     SkPoint getPoint(int index) const;
314 
315     /** Returns the number of points in the path. Up to max points are copied.
316 
317         @param points If not null, receives up to max points
318         @param max The maximum number of points to copy into points
319         @return the actual number of points in the path
320     */
321     int getPoints(SkPoint points[], int max) const;
322 
323     /** Return the number of verbs in the path
324      */
325     int countVerbs() const;
326 
327     /** Returns the number of verbs in the path. Up to max verbs are copied. The
328         verbs are copied as one byte per verb.
329 
330         @param verbs If not null, receives up to max verbs
331         @param max The maximum number of verbs to copy into verbs
332         @return the actual number of verbs in the path
333     */
334     int getVerbs(uint8_t verbs[], int max) const;
335 
336     //! Swap contents of this and other. Guaranteed not to throw
337     void swap(SkPath& other);
338 
339     /**
340      *  Returns the bounds of the path's points. If the path contains zero points/verbs, this
341      *  will return the "empty" rect [0, 0, 0, 0].
342      *  Note: this bounds may be larger than the actual shape, since curves
343      *  do not extend as far as their control points. Additionally this bound encompases all points,
344      *  even isolated moveTos either preceeding or following the last non-degenerate contour.
345     */
getBounds()346     const SkRect& getBounds() const {
347         return fPathRef->getBounds();
348     }
349 
350     /** Calling this will, if the internal cache of the bounds is out of date,
351         update it so that subsequent calls to getBounds will be instantaneous.
352         This also means that any copies or simple transformations of the path
353         will inherit the cached bounds.
354      */
updateBoundsCache()355     void updateBoundsCache() const {
356         // for now, just calling getBounds() is sufficient
357         this->getBounds();
358     }
359 
360     /**
361      * Does a conservative test to see whether a rectangle is inside a path. Currently it only
362      * will ever return true for single convex contour paths. The empty-status of the rect is not
363      * considered (e.g. a rect that is a point can be inside a path). Points or line segments where
364      * the rect edge touches the path border are not considered containment violations.
365      */
366     bool conservativelyContainsRect(const SkRect& rect) const;
367 
368     //  Construction methods
369 
370     /** Hint to the path to prepare for adding more points. This can allow the
371         path to more efficiently grow its storage.
372 
373         @param extraPtCount The number of extra points the path should
374                             preallocate for.
375     */
376     void incReserve(unsigned extraPtCount);
377 
378     /** Set the beginning of the next contour to the point (x,y).
379 
380         @param x    The x-coordinate of the start of a new contour
381         @param y    The y-coordinate of the start of a new contour
382     */
383     void moveTo(SkScalar x, SkScalar y);
384 
385     /** Set the beginning of the next contour to the point
386 
387         @param p    The start of a new contour
388     */
moveTo(const SkPoint & p)389     void moveTo(const SkPoint& p) {
390         this->moveTo(p.fX, p.fY);
391     }
392 
393     /** Set the beginning of the next contour relative to the last point on the
394         previous contour. If there is no previous contour, this is treated the
395         same as moveTo().
396 
397         @param dx   The amount to add to the x-coordinate of the end of the
398                     previous contour, to specify the start of a new contour
399         @param dy   The amount to add to the y-coordinate of the end of the
400                     previous contour, to specify the start of a new contour
401     */
402     void rMoveTo(SkScalar dx, SkScalar dy);
403 
404     /** Add a line from the last point to the specified point (x,y). If no
405         moveTo() call has been made for this contour, the first point is
406         automatically set to (0,0).
407 
408         @param x    The x-coordinate of the end of a line
409         @param y    The y-coordinate of the end of a line
410     */
411     void lineTo(SkScalar x, SkScalar y);
412 
413     /** Add a line from the last point to the specified point. If no moveTo()
414         call has been made for this contour, the first point is automatically
415         set to (0,0).
416 
417         @param p    The end of a line
418     */
lineTo(const SkPoint & p)419     void lineTo(const SkPoint& p) {
420         this->lineTo(p.fX, p.fY);
421     }
422 
423     /** Same as lineTo, but the coordinates are considered relative to the last
424         point on this contour. If there is no previous point, then a moveTo(0,0)
425         is inserted automatically.
426 
427         @param dx   The amount to add to the x-coordinate of the previous point
428                     on this contour, to specify a line
429         @param dy   The amount to add to the y-coordinate of the previous point
430                     on this contour, to specify a line
431     */
432     void rLineTo(SkScalar dx, SkScalar dy);
433 
434     /** Add a quadratic bezier from the last point, approaching control point
435         (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
436         this contour, the first point is automatically set to (0,0).
437 
438         @param x1   The x-coordinate of the control point on a quadratic curve
439         @param y1   The y-coordinate of the control point on a quadratic curve
440         @param x2   The x-coordinate of the end point on a quadratic curve
441         @param y2   The y-coordinate of the end point on a quadratic curve
442     */
443     void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
444 
445     /** Add a quadratic bezier from the last point, approaching control point
446         p1, and ending at p2. If no moveTo() call has been made for this
447         contour, the first point is automatically set to (0,0).
448 
449         @param p1   The control point on a quadratic curve
450         @param p2   The end point on a quadratic curve
451     */
quadTo(const SkPoint & p1,const SkPoint & p2)452     void quadTo(const SkPoint& p1, const SkPoint& p2) {
453         this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
454     }
455 
456     /** Same as quadTo, but the coordinates are considered relative to the last
457         point on this contour. If there is no previous point, then a moveTo(0,0)
458         is inserted automatically.
459 
460         @param dx1   The amount to add to the x-coordinate of the last point on
461                 this contour, to specify the control point of a quadratic curve
462         @param dy1   The amount to add to the y-coordinate of the last point on
463                 this contour, to specify the control point of a quadratic curve
464         @param dx2   The amount to add to the x-coordinate of the last point on
465                      this contour, to specify the end point of a quadratic curve
466         @param dy2   The amount to add to the y-coordinate of the last point on
467                      this contour, to specify the end point of a quadratic curve
468     */
469     void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
470 
471     void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
472                  SkScalar w);
conicTo(const SkPoint & p1,const SkPoint & p2,SkScalar w)473     void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) {
474         this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w);
475     }
476     void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
477                   SkScalar w);
478 
479     /** Add a cubic bezier from the last point, approaching control points
480         (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
481         made for this contour, the first point is automatically set to (0,0).
482 
483         @param x1   The x-coordinate of the 1st control point on a cubic curve
484         @param y1   The y-coordinate of the 1st control point on a cubic curve
485         @param x2   The x-coordinate of the 2nd control point on a cubic curve
486         @param y2   The y-coordinate of the 2nd control point on a cubic curve
487         @param x3   The x-coordinate of the end point on a cubic curve
488         @param y3   The y-coordinate of the end point on a cubic curve
489     */
490     void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
491                  SkScalar x3, SkScalar y3);
492 
493     /** Add a cubic bezier from the last point, approaching control points p1
494         and p2, and ending at p3. If no moveTo() call has been made for this
495         contour, the first point is automatically set to (0,0).
496 
497         @param p1   The 1st control point on a cubic curve
498         @param p2   The 2nd control point on a cubic curve
499         @param p3   The end point on a cubic curve
500     */
cubicTo(const SkPoint & p1,const SkPoint & p2,const SkPoint & p3)501     void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
502         this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
503     }
504 
505     /** Same as cubicTo, but the coordinates are considered relative to the
506         current point on this contour. If there is no previous point, then a
507         moveTo(0,0) is inserted automatically.
508 
509         @param dx1   The amount to add to the x-coordinate of the last point on
510                 this contour, to specify the 1st control point of a cubic curve
511         @param dy1   The amount to add to the y-coordinate of the last point on
512                 this contour, to specify the 1st control point of a cubic curve
513         @param dx2   The amount to add to the x-coordinate of the last point on
514                 this contour, to specify the 2nd control point of a cubic curve
515         @param dy2   The amount to add to the y-coordinate of the last point on
516                 this contour, to specify the 2nd control point of a cubic curve
517         @param dx3   The amount to add to the x-coordinate of the last point on
518                      this contour, to specify the end point of a cubic curve
519         @param dy3   The amount to add to the y-coordinate of the last point on
520                      this contour, to specify the end point of a cubic curve
521     */
522     void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
523                   SkScalar x3, SkScalar y3);
524 
525     /**
526      *  Append the specified arc to the path. If the start of the arc is different from the path's
527      *  current last point, then an automatic lineTo() is added to connect the current contour
528      *  to the start of the arc. However, if the path is empty, then we call moveTo() with
529      *  the first point of the arc. The sweep angle is treated mod 360.
530      *
531      *  @param oval The bounding oval defining the shape and size of the arc
532      *  @param startAngle Starting angle (in degrees) where the arc begins
533      *  @param sweepAngle Sweep angle (in degrees) measured clockwise. This is treated mod 360.
534      *  @param forceMoveTo If true, always begin a new contour with the arc
535      */
536     void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo);
537 
538     /**
539      *  Append a line and arc to the current path. This is the same as the PostScript call "arct".
540      */
541     void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius);
542 
543     /** Append a line and arc to the current path. This is the same as the
544         PostScript call "arct".
545     */
arcTo(const SkPoint p1,const SkPoint p2,SkScalar radius)546     void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
547         this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
548     }
549 
550     enum ArcSize {
551         /** the smaller of the two possible SVG arcs. */
552         kSmall_ArcSize,
553         /** the larger of the two possible SVG arcs. */
554         kLarge_ArcSize,
555     };
556 
557     /**
558      *  Append an elliptical arc from the current point in the format used by SVG.
559      *  The center of the ellipse is computed to satisfy the constraints below.
560      *
561      *  @param rx,ry The radii in the x and y directions respectively.
562      *  @param xAxisRotate The angle in degrees relative to the x-axis.
563      *  @param largeArc Determines whether the smallest or largest arc possible
564      *         is drawn.
565      *  @param sweep Determines if the arc should be swept in an anti-clockwise or
566      *         clockwise direction. Note that this enum value is opposite the SVG
567      *         arc sweep value.
568      *  @param x,y The destination coordinates.
569      */
570     void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
571                Direction sweep, SkScalar x, SkScalar y);
572 
arcTo(const SkPoint r,SkScalar xAxisRotate,ArcSize largeArc,Direction sweep,const SkPoint xy)573     void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
574                const SkPoint xy) {
575         this->arcTo(r.fX, r.fY, xAxisRotate, largeArc, sweep, xy.fX, xy.fY);
576     }
577 
578     /** Same as arcTo format used by SVG, but the destination coordinate is relative to the
579      *  last point on this contour. If there is no previous point, then a
580      *  moveTo(0,0) is inserted automatically.
581      *
582      *  @param rx,ry The radii in the x and y directions respectively.
583      *  @param xAxisRotate The angle in degrees relative to the x-axis.
584      *  @param largeArc Determines whether the smallest or largest arc possible
585      *         is drawn.
586      *  @param sweep Determines if the arc should be swept in an anti-clockwise or
587      *         clockwise direction. Note that this enum value is opposite the SVG
588      *         arc sweep value.
589      *  @param dx,dy The destination coordinates relative to the last point.
590      */
591     void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
592                 Direction sweep, SkScalar dx, SkScalar dy);
593 
594     /** Close the current contour. If the current point is not equal to the
595         first point of the contour, a line segment is automatically added.
596     */
597     void close();
598 
599     /**
600      *  Returns whether or not a fill type is inverted
601      *
602      *  kWinding_FillType        -> false
603      *  kEvenOdd_FillType        -> false
604      *  kInverseWinding_FillType -> true
605      *  kInverseEvenOdd_FillType -> true
606      */
IsInverseFillType(FillType fill)607     static bool IsInverseFillType(FillType fill) {
608         static_assert(0 == kWinding_FillType, "fill_type_mismatch");
609         static_assert(1 == kEvenOdd_FillType, "fill_type_mismatch");
610         static_assert(2 == kInverseWinding_FillType, "fill_type_mismatch");
611         static_assert(3 == kInverseEvenOdd_FillType, "fill_type_mismatch");
612         return (fill & 2) != 0;
613     }
614 
615     /**
616      *  Returns the equivalent non-inverted fill type to the given fill type
617      *
618      *  kWinding_FillType        -> kWinding_FillType
619      *  kEvenOdd_FillType        -> kEvenOdd_FillType
620      *  kInverseWinding_FillType -> kWinding_FillType
621      *  kInverseEvenOdd_FillType -> kEvenOdd_FillType
622      */
ConvertToNonInverseFillType(FillType fill)623     static FillType ConvertToNonInverseFillType(FillType fill) {
624         static_assert(0 == kWinding_FillType, "fill_type_mismatch");
625         static_assert(1 == kEvenOdd_FillType, "fill_type_mismatch");
626         static_assert(2 == kInverseWinding_FillType, "fill_type_mismatch");
627         static_assert(3 == kInverseEvenOdd_FillType, "fill_type_mismatch");
628         return (FillType)(fill & 1);
629     }
630 
631     /**
632      *  Chop a conic into N quads, stored continguously in pts[], where
633      *  N = 1 << pow2. The amount of storage needed is (1 + 2 * N)
634      */
635     static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
636                                    SkScalar w, SkPoint pts[], int pow2);
637 
638     /**
639      *  Returns true if the path specifies a rectangle.
640      *
641      *  If this returns false, then all output parameters are ignored, and left
642      *  unchanged. If this returns true, then each of the output parameters
643      *  are checked for NULL. If they are not, they return their value.
644      *
645      *  @param rect If not null, set to the bounds of the rectangle.
646      *              Note : this bounds may be smaller than the path's bounds, since it is just
647      *              the bounds of the "drawable" parts of the path. e.g. a trailing MoveTo would
648      *              be ignored in this rect, but not by the path's bounds
649      *  @param isClosed If not null, set to true if the path is closed
650      *  @param direction If not null, set to the rectangle's direction
651      *  @return true if the path specifies a rectangle
652      */
653     bool isRect(SkRect* rect, bool* isClosed = NULL, Direction* direction = NULL) const;
654 
655     /** Returns true if the path specifies a pair of nested rectangles, or would draw a
656         pair of nested rectangles when filled. If so, and if
657         rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner
658         rectangle. If so, and dirs is not null, set dirs[0] to the direction of
659         the outer rectangle and dirs[1] to the direction of the inner rectangle. If
660         the path does not specify a pair of nested rectangles, return
661         false and ignore rect and dirs.
662 
663         @param rect If not null, returns the path as a pair of nested rectangles
664         @param dirs If not null, returns the direction of the rects
665         @return true if the path describes a pair of nested rectangles
666     */
667     bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = NULL) const;
668 
669     /**
670      *  Add a closed rectangle contour to the path
671      *  @param rect The rectangle to add as a closed contour to the path
672      *  @param dir  The direction to wind the rectangle's contour.
673      *
674      *  Note: the contour initial point index is 0 (as defined below).
675      */
676     void addRect(const SkRect& rect, Direction dir = kCW_Direction);
677 
678     /**
679      *  Add a closed rectangle contour to the path
680      *  @param rect  The rectangle to add as a closed contour to the path
681      *  @param dir   The direction to wind the rectangle's contour.
682      *  @param start Initial point of the contour (initial moveTo), expressed as
683      *               a corner index, starting in the upper-left position, clock-wise:
684      *
685      *  0         1
686      *   *-------*
687      *   |       |
688      *   *-------*
689      *  3         2
690      */
691     void addRect(const SkRect& rect, Direction dir, unsigned start);
692 
693     /**
694      *  Add a closed rectangle contour to the path
695      *
696      *  @param left     The left side of a rectangle to add as a closed contour
697      *                  to the path
698      *  @param top      The top of a rectangle to add as a closed contour to the
699      *                  path
700      *  @param right    The right side of a rectangle to add as a closed contour
701      *                  to the path
702      *  @param bottom   The bottom of a rectangle to add as a closed contour to
703      *                  the path
704      *  @param dir  The direction to wind the rectangle's contour.
705      *
706      *  Note: the contour initial point index is 0 (as defined above).
707      */
708     void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
709                  Direction dir = kCW_Direction);
710 
711     /**
712      *  Add a closed oval contour to the path
713      *
714      *  @param oval The bounding oval to add as a closed contour to the path
715      *  @param dir  The direction to wind the oval's contour.
716      *
717      *  Note: the contour initial point index is 1 (as defined below).
718      */
719     void addOval(const SkRect& oval, Direction dir = kCW_Direction);
720 
721     /**
722      *  Add a closed oval contour to the path
723      *
724      *  @param oval  The bounding oval to add as a closed contour to the path
725      *  @param dir   The direction to wind the oval's contour.
726      *  @param start Initial point of the contour (initial moveTo), expressed
727      *               as an ellipse vertex index, starting at the top, clock-wise
728      *               (90/0/270/180deg order):
729      *
730      *        0
731      *       -*-
732      *     |     |
733      *   3 *     * 1
734      *     |     |
735      *       -*-
736      *        2
737      */
738     void addOval(const SkRect& oval, Direction dir, unsigned start);
739 
740     /**
741      *  Add a closed circle contour to the path. The circle contour begins at
742      *  the right-most point (as though 1 were passed to addOval's 'start' param).
743      *
744      *  @param x        The x-coordinate of the center of a circle to add as a
745      *                  closed contour to the path
746      *  @param y        The y-coordinate of the center of a circle to add as a
747      *                  closed contour to the path
748      *  @param radius   The radius of a circle to add as a closed contour to the
749      *                  path
750      *  @param dir  The direction to wind the circle's contour.
751      */
752     void addCircle(SkScalar x, SkScalar y, SkScalar radius,
753                    Direction dir = kCW_Direction);
754 
755     /** Add the specified arc to the path as a new contour.
756 
757         @param oval The bounds of oval used to define the size of the arc
758         @param startAngle Starting angle (in degrees) where the arc begins
759         @param sweepAngle Sweep angle (in degrees) measured clockwise
760     */
761     void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
762 
763     /**
764      *  Add a closed round-rectangle contour to the path
765      *  @param rect The bounds of a round-rectangle to add as a closed contour
766      *  @param rx   The x-radius of the rounded corners on the round-rectangle
767      *  @param ry   The y-radius of the rounded corners on the round-rectangle
768      *  @param dir  The direction to wind the rectangle's contour.
769      */
770     void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
771                       Direction dir = kCW_Direction);
772 
773     /**
774      *  Add a closed round-rectangle contour to the path. Each corner receives
775      *  two radius values [X, Y]. The corners are ordered top-left, top-right,
776      *  bottom-right, bottom-left.
777      *  @param rect The bounds of a round-rectangle to add as a closed contour
778      *  @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner
779      *  @param dir  The direction to wind the rectangle's contour.
780      * Note: The radii here now go through the same constraint handling as the
781      *       SkRRect radii (i.e., either radii at a corner being 0 implies a
782      *       sqaure corner and oversized radii are proportionally scaled down).
783      */
784     void addRoundRect(const SkRect& rect, const SkScalar radii[],
785                       Direction dir = kCW_Direction);
786 
787     /**
788      *  Add an SkRRect contour to the path
789      *  @param rrect The rounded rect to add as a closed contour
790      *  @param dir   The winding direction for the new contour.
791      *
792      *  Note: the contour initial point index is either 6 (for dir == kCW_Direction)
793      *        or 7 (for dir == kCCW_Direction), as defined below.
794      *
795      */
796     void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction);
797 
798     /**
799      *  Add an SkRRect contour to the path
800      *  @param rrect The rounded rect to add as a closed contour
801      *  @param dir   The winding direction for the new contour.
802      *  @param start Initial point of the contour (initial moveTo), expressed as
803      *               an index of the radii minor/major points, ordered clock-wise:
804      *
805      *      0    1
806      *      *----*
807      *   7 *      * 2
808      *     |      |
809      *   6 *      * 3
810      *      *----*
811      *      5    4
812      */
813     void addRRect(const SkRRect& rrect, Direction dir, unsigned start);
814 
815     /**
816      *  Add a new contour made of just lines. This is just a fast version of
817      *  the following:
818      *      this->moveTo(pts[0]);
819      *      for (int i = 1; i < count; ++i) {
820      *          this->lineTo(pts[i]);
821      *      }
822      *      if (close) {
823      *          this->close();
824      *      }
825      */
826     void addPoly(const SkPoint pts[], int count, bool close);
827 
828     enum AddPathMode {
829         /** Source path contours are added as new contours.
830         */
831         kAppend_AddPathMode,
832         /** Path is added by extending the last contour of the destination path
833             with the first contour of the source path. If the last contour of
834             the destination path is closed, then it will not be extended.
835             Instead, the start of source path will be extended by a straight
836             line to the end point of the destination path.
837         */
838         kExtend_AddPathMode
839     };
840 
841     /** Add a copy of src to the path, offset by (dx,dy)
842         @param src  The path to add as a new contour
843         @param dx   The amount to translate the path in X as it is added
844         @param dx   The amount to translate the path in Y as it is added
845     */
846     void addPath(const SkPath& src, SkScalar dx, SkScalar dy,
847                  AddPathMode mode = kAppend_AddPathMode);
848 
849     /** Add a copy of src to the path
850     */
851     void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) {
852         SkMatrix m;
853         m.reset();
854         this->addPath(src, m, mode);
855     }
856 
857     /** Add a copy of src to the path, transformed by matrix
858         @param src  The path to add as a new contour
859         @param matrix  Transform applied to src
860         @param mode  Determines how path is added
861     */
862     void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode);
863 
864     /**
865      *  Same as addPath(), but reverses the src input
866      */
867     void reverseAddPath(const SkPath& src);
868 
869     /** Offset the path by (dx,dy), returning true on success
870 
871         @param dx   The amount in the X direction to offset the entire path
872         @param dy   The amount in the Y direction to offset the entire path
873         @param dst  The translated path is written here
874     */
875     void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
876 
877     /** Offset the path by (dx,dy), returning true on success
878 
879         @param dx   The amount in the X direction to offset the entire path
880         @param dy   The amount in the Y direction to offset the entire path
881     */
offset(SkScalar dx,SkScalar dy)882     void offset(SkScalar dx, SkScalar dy) {
883         this->offset(dx, dy, this);
884     }
885 
886     /** Transform the points in this path by matrix, and write the answer into
887         dst.
888 
889         @param matrix   The matrix to apply to the path
890         @param dst      The transformed path is written here
891     */
892     void transform(const SkMatrix& matrix, SkPath* dst) const;
893 
894     /** Transform the points in this path by matrix
895 
896         @param matrix The matrix to apply to the path
897     */
transform(const SkMatrix & matrix)898     void transform(const SkMatrix& matrix) {
899         this->transform(matrix, this);
900     }
901 
902     /** Return the last point on the path. If no points have been added, (0,0)
903         is returned. If there are no points, this returns false, otherwise it
904         returns true.
905 
906         @param lastPt   The last point on the path is returned here
907     */
908     bool getLastPt(SkPoint* lastPt) const;
909 
910     /** Set the last point on the path. If no points have been added,
911         moveTo(x,y) is automatically called.
912 
913         @param x    The new x-coordinate for the last point
914         @param y    The new y-coordinate for the last point
915     */
916     void setLastPt(SkScalar x, SkScalar y);
917 
918     /** Set the last point on the path. If no points have been added, moveTo(p)
919         is automatically called.
920 
921         @param p    The new location for the last point
922     */
setLastPt(const SkPoint & p)923     void setLastPt(const SkPoint& p) {
924         this->setLastPt(p.fX, p.fY);
925     }
926 
927     enum SegmentMask {
928         kLine_SegmentMask   = 1 << 0,
929         kQuad_SegmentMask   = 1 << 1,
930         kConic_SegmentMask  = 1 << 2,
931         kCubic_SegmentMask  = 1 << 3,
932     };
933 
934     /**
935      *  Returns a mask, where each bit corresponding to a SegmentMask is
936      *  set if the path contains 1 or more segments of that type.
937      *  Returns 0 for an empty path (no segments).
938      */
getSegmentMasks()939     uint32_t getSegmentMasks() const { return fPathRef->getSegmentMasks(); }
940 
941     enum Verb {
942         kMove_Verb,     //!< iter.next returns 1 point
943         kLine_Verb,     //!< iter.next returns 2 points
944         kQuad_Verb,     //!< iter.next returns 3 points
945         kConic_Verb,    //!< iter.next returns 3 points + iter.conicWeight()
946         kCubic_Verb,    //!< iter.next returns 4 points
947         kClose_Verb,    //!< iter.next returns 0 points
948         kDone_Verb,     //!< iter.next returns 0 points
949     };
950 
951     /** Iterate through all of the segments (lines, quadratics, cubics) of
952         each contours in a path.
953 
954         The iterator cleans up the segments along the way, removing degenerate
955         segments and adding close verbs where necessary. When the forceClose
956         argument is provided, each contour (as defined by a new starting
957         move command) will be completed with a close verb regardless of the
958         contour's contents.
959     */
960     class SK_API Iter {
961     public:
962         Iter();
963         Iter(const SkPath&, bool forceClose);
964 
965         void setPath(const SkPath&, bool forceClose);
966 
967         /** Return the next verb in this iteration of the path. When all
968             segments have been visited, return kDone_Verb.
969 
970             @param  pts The points representing the current verb and/or segment
971             @param doConsumeDegerates If true, first scan for segments that are
972                    deemed degenerate (too short) and skip those.
973             @param exact if doConsumeDegenerates is true and exact is true, skip only
974                    degenerate elements with lengths exactly equal to zero. If exact
975                    is false, skip degenerate elements with lengths close to zero. If
976                    doConsumeDegenerates is false, exact has no effect.
977             @return The verb for the current segment
978         */
979         Verb next(SkPoint pts[4], bool doConsumeDegerates = true, bool exact = false) {
980             if (doConsumeDegerates) {
981                 this->consumeDegenerateSegments(exact);
982             }
983             return this->doNext(pts);
984         }
985 
986         /**
987          *  Return the weight for the current conic. Only valid if the current
988          *  segment return by next() was a conic.
989          */
conicWeight()990         SkScalar conicWeight() const { return *fConicWeights; }
991 
992         /** If next() returns kLine_Verb, then this query returns true if the
993             line was the result of a close() command (i.e. the end point is the
994             initial moveto for this contour). If next() returned a different
995             verb, this returns an undefined value.
996 
997             @return If the last call to next() returned kLine_Verb, return true
998                     if it was the result of an explicit close command.
999         */
isCloseLine()1000         bool isCloseLine() const { return SkToBool(fCloseLine); }
1001 
1002         /** Returns true if the current contour is closed (has a kClose_Verb)
1003             @return true if the current contour is closed (has a kClose_Verb)
1004         */
1005         bool isClosedContour() const;
1006 
1007     private:
1008         const SkPoint*  fPts;
1009         const uint8_t*  fVerbs;
1010         const uint8_t*  fVerbStop;
1011         const SkScalar* fConicWeights;
1012         SkPoint         fMoveTo;
1013         SkPoint         fLastPt;
1014         SkBool8         fForceClose;
1015         SkBool8         fNeedClose;
1016         SkBool8         fCloseLine;
1017         SkBool8         fSegmentState;
1018 
1019         inline const SkPoint& cons_moveTo();
1020         Verb autoClose(SkPoint pts[2]);
1021         void consumeDegenerateSegments(bool exact);
1022         Verb doNext(SkPoint pts[4]);
1023     };
1024 
1025     /** Iterate through the verbs in the path, providing the associated points.
1026     */
1027     class SK_API RawIter {
1028     public:
RawIter()1029         RawIter() {}
RawIter(const SkPath & path)1030         RawIter(const SkPath& path) {
1031             setPath(path);
1032         }
1033 
setPath(const SkPath & path)1034         void setPath(const SkPath& path) {
1035             fRawIter.setPathRef(*path.fPathRef.get());
1036         }
1037 
1038         /** Return the next verb in this iteration of the path. When all
1039             segments have been visited, return kDone_Verb.
1040 
1041             @param  pts The points representing the current verb and/or segment
1042                         This must not be NULL.
1043             @return The verb for the current segment
1044         */
next(SkPoint pts[4])1045         Verb next(SkPoint pts[4]) {
1046             return (Verb) fRawIter.next(pts);
1047         }
1048 
1049         /** Return what the next verb will be, but do not visit the next segment.
1050 
1051             @return The verb for the next segment
1052         */
peek()1053         Verb peek() const {
1054             return (Verb) fRawIter.peek();
1055         }
1056 
conicWeight()1057         SkScalar conicWeight() const {
1058             return fRawIter.conicWeight();
1059         }
1060 
1061     private:
1062         SkPathRef::Iter fRawIter;
1063         friend class SkPath;
1064     };
1065 
1066     /**
1067      *  Returns true if the point { x, y } is contained by the path, taking into
1068      *  account the FillType.
1069      */
1070     bool contains(SkScalar x, SkScalar y) const;
1071 
1072     void dump(SkWStream* , bool forceClose, bool dumpAsHex) const;
1073     void dump() const;
1074     void dumpHex() const;
1075 
1076     /**
1077      *  Write the path to the buffer, and return the number of bytes written.
1078      *  If buffer is NULL, it still returns the number of bytes.
1079      */
1080     size_t writeToMemory(void* buffer) const;
1081     /**
1082      * Initializes the path from the buffer
1083      *
1084      * @param buffer Memory to read from
1085      * @param length Amount of memory available in the buffer
1086      * @return number of bytes read (must be a multiple of 4) or
1087      *         0 if there was not enough memory available
1088      */
1089     size_t readFromMemory(const void* buffer, size_t length);
1090 
1091     /** Returns a non-zero, globally unique value corresponding to the set of verbs
1092         and points in the path (but not the fill type [except on Android skbug.com/1762]).
1093         Each time the path is modified, a different generation ID will be returned.
1094     */
1095     uint32_t getGenerationID() const;
1096 
1097 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1098     static const int kPathRefGenIDBitCnt = 30; // leave room for the fill type (skbug.com/1762)
1099 #else
1100     static const int kPathRefGenIDBitCnt = 32;
1101 #endif
1102 
1103     SkDEBUGCODE(void validate() const;)
1104     SkDEBUGCODE(void experimentalValidateRef() const { fPathRef->validate(); } )
1105 
1106 private:
1107     enum SerializationOffsets {
1108         // 1 free bit at 29
1109         kUnused1_SerializationShift = 28,    // 1 free bit
1110         kDirection_SerializationShift = 26, // requires 2 bits
1111         kIsVolatile_SerializationShift = 25, // requires 1 bit
1112         // 1 free bit at 24
1113         kConvexity_SerializationShift = 16, // requires 8 bits
1114         kFillType_SerializationShift = 8,   // requires 8 bits
1115         // low-8-bits are version
1116     };
1117 
1118     enum SerializationVersions {
1119         kPathPrivFirstDirection_Version = 1,
1120         kPathPrivLastMoveToIndex_Version = 2,
1121         kCurrent_Version = 2
1122     };
1123 
1124     SkAutoTUnref<SkPathRef>                            fPathRef;
1125     int                                                fLastMoveToIndex;
1126     uint8_t                                            fFillType;
1127     mutable uint8_t                                    fConvexity;
1128     mutable SkAtomic<uint8_t, sk_memory_order_relaxed> fFirstDirection;// SkPathPriv::FirstDirection
1129     mutable SkBool8                                    fIsVolatile;
1130 
1131     /** Resets all fields other than fPathRef to their initial 'empty' values.
1132      *  Assumes the caller has already emptied fPathRef.
1133      *  On Android increments fGenerationID without reseting it.
1134      */
1135     void resetFields();
1136 
1137     /** Sets all fields other than fPathRef to the values in 'that'.
1138      *  Assumes the caller has already set fPathRef.
1139      *  Doesn't change fGenerationID or fSourcePath on Android.
1140      */
1141     void copyFields(const SkPath& that);
1142 
1143     friend class Iter;
1144     friend class SkPathPriv;
1145     friend class SkPathStroker;
1146 
1147     /*  Append, in reverse order, the first contour of path, ignoring path's
1148         last point. If no moveTo() call has been made for this contour, the
1149         first point is automatically set to (0,0).
1150     */
1151     void reversePathTo(const SkPath&);
1152 
1153     // called before we add points for lineTo, quadTo, cubicTo, checking to see
1154     // if we need to inject a leading moveTo first
1155     //
1156     //  SkPath path; path.lineTo(...);   <--- need a leading moveTo(0, 0)
1157     // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo)
1158     //
1159     inline void injectMoveToIfNeeded();
1160 
1161     inline bool hasOnlyMoveTos() const;
1162 
1163     Convexity internalGetConvexity() const;
1164 
1165     bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts,
1166                        bool* isClosed, Direction* direction) const;
1167 
1168     // called by stroker to see if all points are equal and worthy of a cap
1169     // equivalent to a short-circuit version of getBounds().isEmpty()
1170     bool isZeroLength() const;
1171 
1172     /** Returns if the path can return a bound at no cost (true) or will have to
1173         perform some computation (false).
1174      */
hasComputedBounds()1175     bool hasComputedBounds() const {
1176         SkDEBUGCODE(this->validate();)
1177         return fPathRef->hasComputedBounds();
1178     }
1179 
1180 
1181     // 'rect' needs to be sorted
setBounds(const SkRect & rect)1182     void setBounds(const SkRect& rect) {
1183         SkPathRef::Editor ed(&fPathRef);
1184 
1185         ed.setBounds(rect);
1186     }
1187 
1188     void setPt(int index, SkScalar x, SkScalar y);
1189 
1190     friend class SkAutoPathBoundsUpdate;
1191     friend class SkAutoDisableOvalCheck;
1192     friend class SkAutoDisableDirectionCheck;
1193     friend class SkBench_AddPathTest; // perf test reversePathTo
1194     friend class PathTest_Private; // unit test reversePathTo
1195     friend class ForceIsRRect_Private; // unit test isRRect
1196 };
1197 
1198 #endif
1199