• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SkPath_DEFINED
18 #define SkPath_DEFINED
19 
20 #include "SkMatrix.h"
21 #include "SkTDArray.h"
22 
23 class SkFlattenableReadBuffer;
24 class SkFlattenableWriteBuffer;
25 class SkAutoPathBoundsUpdate;
26 class SkString;
27 
28 /** \class SkPath
29 
30     The SkPath class encapsulates compound (multiple contour) geometric paths
31     consisting of straight line segments, quadratic curves, and cubic curves.
32 */
33 class SkPath {
34 public:
35     SkPath();
36     SkPath(const SkPath&);
37     ~SkPath();
38 
39     SkPath& operator=(const SkPath&);
40 
41     friend bool operator==(const SkPath&, const SkPath&);
42     friend bool operator!=(const SkPath& a, const SkPath& b) {
43         return !(a == b);
44     }
45 
46     enum FillType {
47         /** Specifies that "inside" is computed by a non-zero sum of signed
48             edge crossings
49         */
50         kWinding_FillType,
51         /** Specifies that "inside" is computed by an odd number of edge
52             crossings
53         */
54         kEvenOdd_FillType,
55         /** Same as Winding, but draws outside of the path, rather than inside
56         */
57         kInverseWinding_FillType,
58         /** Same as EvenOdd, but draws outside of the path, rather than inside
59          */
60         kInverseEvenOdd_FillType
61     };
62 
63     /** Return the path's fill type. This is used to define how "inside" is
64         computed. The default value is kWinding_FillType.
65 
66         @return the path's fill type
67     */
getFillType()68     FillType getFillType() const { return (FillType)fFillType; }
69 
70     /** Set the path's fill type. This is used to define how "inside" is
71         computed. The default value is kWinding_FillType.
72 
73         @param ft The new fill type for this path
74     */
setFillType(FillType ft)75     void setFillType(FillType ft) { fFillType = SkToU8(ft); }
76 
77     /** Returns true if the filltype is one of the Inverse variants */
isInverseFillType()78     bool isInverseFillType() const { return (fFillType & 2) != 0; }
79 
80     /** Toggle between inverse and normal filltypes. This reverse the return
81         value of isInverseFillType()
82     */
toggleInverseFillType()83     void toggleInverseFillType() { fFillType ^= 2; }
84 
85     /** Clear any lines and curves from the path, making it empty. This frees up
86         internal storage associated with those segments.
87         This does NOT change the fill-type setting.
88     */
89     void reset();
90 
91     /** Similar to reset(), in that all lines and curves are removed from the
92         path. However, any internal storage for those lines/curves is retained,
93         making reuse of the path potentially faster.
94         This does NOT change the fill-type setting.
95     */
96     void rewind();
97 
98     /** Returns true if the path is empty (contains no lines or curves)
99 
100         @return true if the path is empty (contains no lines or curves)
101     */
102     bool isEmpty() const;
103 
104     /** Returns true if the path specifies a rectangle. If so, and if rect is
105         not null, set rect to the bounds of the path. If the path does not
106         specify a rectangle, return false and ignore rect.
107 
108         @param rect If not null, returns the bounds of the path if it specifies
109                     a rectangle
110         @return true if the path specifies a rectangle
111     */
112     bool isRect(SkRect* rect) const;
113 
114     /** Returns the number of points in the path. Up to max points are copied.
115 
116         @param points If not null, receives up to max points
117         @param max The maximum number of points to copy into points
118         @return the actual number of points in the path
119     */
120     int getPoints(SkPoint points[], int max) const;
121 
122     //! Swap contents of this and other. Guaranteed not to throw
123     void swap(SkPath& other);
124 
125     enum BoundsType {
126         /** compute the bounds of the path's control points, may be larger than
127             with kExact_BoundsType, but may be faster to compute
128         */
129         kFast_BoundsType,
130         /** compute the exact bounds of the path, may be smaller than with
131             kFast_BoundsType, but may be slower to compute
132         */
133         kExact_BoundsType
134     };
135 
136     /** Compute the bounds of the path, and write the answer into bounds. If the
137         path contains 0 or 1 points, the bounds is set to (0,0,0,0)
138 
139         @param bounds   Returns the computed bounds of the path
140         @param btype    Specifies if the computed bounds should be exact
141                         (slower) or approximate (faster)
142     */
143     void computeBounds(SkRect* bounds, BoundsType btype) const;
144 
145     /** Calling this will, if the internal cache of the bounds is out of date,
146         update it so that subsequent calls to computeBounds will be instanteous.
147         This also means that any copies or simple transformations of the path
148         will inherit the cached bounds.
149     */
150     void updateBoundsCache() const;
151 
152     //  Construction methods
153 
154     /** Hint to the path to prepare for adding more points. This can allow the
155         path to more efficiently grow its storage.
156 
157         @param extraPtCount The number of extra points the path should
158                             preallocate for.
159     */
160     void incReserve(unsigned extraPtCount);
161 
162     /** Set the beginning of the next contour to the point (x,y).
163 
164         @param x    The x-coordinate of the start of a new contour
165         @param y    The y-coordinate of the start of a new contour
166     */
167     void moveTo(SkScalar x, SkScalar y);
168 
169     /** Set the beginning of the next contour to the point
170 
171         @param p    The start of a new contour
172     */
moveTo(const SkPoint & p)173     void moveTo(const SkPoint& p) {
174         this->moveTo(p.fX, p.fY);
175     }
176 
177     /** Set the beginning of the next contour relative to the last point on the
178         previous contour. If there is no previous contour, this is treated the
179         same as moveTo().
180 
181         @param dx   The amount to add to the x-coordinate of the end of the
182                     previous contour, to specify the start of a new contour
183         @param dy   The amount to add to the y-coordinate of the end of the
184                     previous contour, to specify the start of a new contour
185     */
186     void rMoveTo(SkScalar dx, SkScalar dy);
187 
188     /** Add a line from the last point to the specified point (x,y). If no
189         moveTo() call has been made for this contour, the first point is
190         automatically set to (0,0).
191 
192         @param x    The x-coordinate of the end of a line
193         @param y    The y-coordinate of the end of a line
194     */
195     void lineTo(SkScalar x, SkScalar y);
196 
197     /** Add a line from the last point to the specified point. If no moveTo()
198         call has been made for this contour, the first point is automatically
199         set to (0,0).
200 
201         @param p    The end of a line
202     */
lineTo(const SkPoint & p)203     void lineTo(const SkPoint& p) {
204         this->lineTo(p.fX, p.fY);
205     }
206 
207     /** Same as lineTo, but the coordinates are considered relative to the last
208         point on this contour. If there is no previous point, then a moveTo(0,0)
209         is inserted automatically.
210 
211         @param dx   The amount to add to the x-coordinate of the previous point
212                     on this contour, to specify a line
213         @param dy   The amount to add to the y-coordinate of the previous point
214                     on this contour, to specify a line
215     */
216     void rLineTo(SkScalar dx, SkScalar dy);
217 
218     /** Add a quadratic bezier from the last point, approaching control point
219         (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
220         this contour, the first point is automatically set to (0,0).
221 
222         @param x1   The x-coordinate of the control point on a quadratic curve
223         @param y1   The y-coordinate of the control point on a quadratic curve
224         @param x2   The x-coordinate of the end point on a quadratic curve
225         @param y2   The y-coordinate of the end point on a quadratic curve
226     */
227     void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
228 
229     /** Add a quadratic bezier from the last point, approaching control point
230         p1, and ending at p2. If no moveTo() call has been made for this
231         contour, the first point is automatically set to (0,0).
232 
233         @param p1   The control point on a quadratic curve
234         @param p2   The end point on a quadratic curve
235     */
quadTo(const SkPoint & p1,const SkPoint & p2)236     void quadTo(const SkPoint& p1, const SkPoint& p2) {
237         this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
238     }
239 
240     /** Same as quadTo, but the coordinates are considered relative to the last
241         point on this contour. If there is no previous point, then a moveTo(0,0)
242         is inserted automatically.
243 
244         @param dx1   The amount to add to the x-coordinate of the last point on
245                 this contour, to specify the control point of a quadratic curve
246         @param dy1   The amount to add to the y-coordinate of the last point on
247                 this contour, to specify the control point of a quadratic curve
248         @param dx2   The amount to add to the x-coordinate of the last point on
249                      this contour, to specify the end point of a quadratic curve
250         @param dy2   The amount to add to the y-coordinate of the last point on
251                      this contour, to specify the end point of a quadratic curve
252     */
253     void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
254 
255     /** Add a cubic bezier from the last point, approaching control points
256         (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
257         made for this contour, the first point is automatically set to (0,0).
258 
259         @param x1   The x-coordinate of the 1st control point on a cubic curve
260         @param y1   The y-coordinate of the 1st control point on a cubic curve
261         @param x2   The x-coordinate of the 2nd control point on a cubic curve
262         @param y2   The y-coordinate of the 2nd control point on a cubic curve
263         @param x3   The x-coordinate of the end point on a cubic curve
264         @param y3   The y-coordinate of the end point on a cubic curve
265     */
266     void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
267                  SkScalar x3, SkScalar y3);
268 
269     /** Add a cubic bezier from the last point, approaching control points p1
270         and p2, and ending at p3. If no moveTo() call has been made for this
271         contour, the first point is automatically set to (0,0).
272 
273         @param p1   The 1st control point on a cubic curve
274         @param p2   The 2nd control point on a cubic curve
275         @param p3   The end point on a cubic curve
276     */
cubicTo(const SkPoint & p1,const SkPoint & p2,const SkPoint & p3)277     void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
278         this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
279     }
280 
281     /** Same as cubicTo, but the coordinates are considered relative to the
282         current point on this contour. If there is no previous point, then a
283         moveTo(0,0) is inserted automatically.
284 
285         @param dx1   The amount to add to the x-coordinate of the last point on
286                 this contour, to specify the 1st control point of a cubic curve
287         @param dy1   The amount to add to the y-coordinate of the last point on
288                 this contour, to specify the 1st control point of a cubic curve
289         @param dx2   The amount to add to the x-coordinate of the last point on
290                 this contour, to specify the 2nd control point of a cubic curve
291         @param dy2   The amount to add to the y-coordinate of the last point on
292                 this contour, to specify the 2nd control point of a cubic curve
293         @param dx3   The amount to add to the x-coordinate of the last point on
294                      this contour, to specify the end point of a cubic curve
295         @param dy3   The amount to add to the y-coordinate of the last point on
296                      this contour, to specify the end point of a cubic curve
297     */
298     void    rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
299                      SkScalar x3, SkScalar y3);
300 
301     /** Append the specified arc to the path as a new contour. If the start of
302         the path is different from the path's current last point, then an
303         automatic lineTo() is added to connect the current contour to the start
304         of the arc. However, if the path is empty, then we call moveTo() with
305         the first point of the arc. The sweep angle is treated mod 360.
306 
307         @param oval The bounding oval defining the shape and size of the arc
308         @param startAngle Starting angle (in degrees) where the arc begins
309         @param sweepAngle Sweep angle (in degrees) measured clockwise. This is
310                           treated mod 360.
311         @param forceMoveTo If true, always begin a new contour with the arc
312     */
313     void    arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
314                   bool forceMoveTo);
315 
316     /** Append a line and arc to the current path. This is the same as the
317         PostScript call "arct".
318     */
319     void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
320                SkScalar radius);
321 
322     /** Append a line and arc to the current path. This is the same as the
323         PostScript call "arct".
324     */
arcTo(const SkPoint p1,const SkPoint p2,SkScalar radius)325     void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
326         this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
327     }
328 
329     /** Close the current contour. If the current point is not equal to the
330         first point of the contour, a line segment is automatically added.
331     */
332     void close();
333 
334     enum Direction {
335         /** clockwise direction for adding closed contours */
336         kCW_Direction,
337         /** counter-clockwise direction for adding closed contours */
338         kCCW_Direction
339     };
340 
341     /** Add a closed rectangle contour to the path
342         @param rect The rectangle to add as a closed contour to the path
343         @param dir  The direction to wind the rectangle's contour
344     */
345     void    addRect(const SkRect& rect, Direction dir = kCW_Direction);
346 
347     /** Add a closed rectangle contour to the path
348 
349         @param left     The left side of a rectangle to add as a closed contour
350                         to the path
351         @param top      The top of a rectangle to add as a closed contour to the
352                         path
353         @param right    The right side of a rectangle to add as a closed contour
354                         to the path
355         @param bottom   The bottom of a rectangle to add as a closed contour to
356                         the path
357         @param dir      The direction to wind the rectangle's contour
358     */
359     void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
360                  Direction dir = kCW_Direction);
361 
362     /** Add a closed oval contour to the path
363 
364         @param oval The bounding oval to add as a closed contour to the path
365         @param dir  The direction to wind the oval's contour
366     */
367     void addOval(const SkRect& oval, Direction dir = kCW_Direction);
368 
369     /** Add a closed circle contour to the path
370 
371         @param x        The x-coordinate of the center of a circle to add as a
372                         closed contour to the path
373         @param y        The y-coordinate of the center of a circle to add as a
374                         closed contour to the path
375         @param radius   The radius of a circle to add as a closed contour to the
376                         path
377         @param dir      The direction to wind the circle's contour
378     */
379     void addCircle(SkScalar x, SkScalar y, SkScalar radius,
380                    Direction dir = kCW_Direction);
381 
382     /** Add the specified arc to the path as a new contour.
383 
384         @param oval The bounds of oval used to define the size of the arc
385         @param startAngle Starting angle (in degrees) where the arc begins
386         @param sweepAngle Sweep angle (in degrees) measured clockwise
387     */
388     void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
389 
390     /** Add a closed round-rectangle contour to the path
391         @param rect The bounds of a round-rectangle to add as a closed contour
392         @param rx   The x-radius of the rounded corners on the round-rectangle
393         @param ry   The y-radius of the rounded corners on the round-rectangle
394         @param dir  The direction to wind the round-rectangle's contour
395     */
396     void    addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
397                          Direction dir = kCW_Direction);
398 
399     /** Add a closed round-rectangle contour to the path. Each corner receives
400         two radius values [X, Y]. The corners are ordered top-left, top-right,
401         bottom-right, bottom-left.
402         @param rect The bounds of a round-rectangle to add as a closed contour
403         @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner
404         @param dir  The direction to wind the round-rectangle's contour
405         */
406     void addRoundRect(const SkRect& rect, const SkScalar radii[],
407                       Direction dir = kCW_Direction);
408 
409     /** Add a copy of src to the path, offset by (dx,dy)
410         @param src  The path to add as a new contour
411         @param dx   The amount to translate the path in X as it is added
412         @param dx   The amount to translate the path in Y as it is added
413     */
414     void    addPath(const SkPath& src, SkScalar dx, SkScalar dy);
415 
416     /** Add a copy of src to the path
417     */
addPath(const SkPath & src)418     void addPath(const SkPath& src) {
419         SkMatrix m;
420         m.reset();
421         this->addPath(src, m);
422     }
423 
424     /** Add a copy of src to the path, transformed by matrix
425         @param src  The path to add as a new contour
426     */
427     void addPath(const SkPath& src, const SkMatrix& matrix);
428 
429     /** Offset the path by (dx,dy), returning true on success
430 
431         @param dx   The amount in the X direction to offset the entire path
432         @param dy   The amount in the Y direction to offset the entire path
433         @param dst  The translated path is written here
434     */
435     void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
436 
437     /** Offset the path by (dx,dy), returning true on success
438 
439         @param dx   The amount in the X direction to offset the entire path
440         @param dy   The amount in the Y direction to offset the entire path
441     */
offset(SkScalar dx,SkScalar dy)442     void offset(SkScalar dx, SkScalar dy) {
443         this->offset(dx, dy, this);
444     }
445 
446     /** Transform the points in this path by matrix, and write the answer into
447         dst.
448 
449         @param matrix   The matrix to apply to the path
450         @param dst      The transformed path is written here
451     */
452     void transform(const SkMatrix& matrix, SkPath* dst) const;
453 
454     /** Transform the points in this path by matrix
455 
456         @param matrix The matrix to apply to the path
457     */
transform(const SkMatrix & matrix)458     void transform(const SkMatrix& matrix) {
459         this->transform(matrix, this);
460     }
461 
462     /** Return the last point on the path. If no points have been added, (0,0)
463         is returned.
464 
465         @param lastPt   The last point on the path is returned here
466     */
467     void getLastPt(SkPoint* lastPt) const;
468 
469     /** Set the last point on the path. If no points have been added,
470         moveTo(x,y) is automatically called.
471 
472         @param x    The new x-coordinate for the last point
473         @param y    The new y-coordinate for the last point
474     */
475     void setLastPt(SkScalar x, SkScalar y);
476 
477     /** Set the last point on the path. If no points have been added, moveTo(p)
478         is automatically called.
479 
480         @param p    The new location for the last point
481     */
setLastPt(const SkPoint & p)482     void setLastPt(const SkPoint& p) {
483         this->setLastPt(p.fX, p.fY);
484     }
485 
486     enum Verb {
487         kMove_Verb,     //!< iter.next returns 1 point
488         kLine_Verb,     //!< iter.next returns 2 points
489         kQuad_Verb,     //!< iter.next returns 3 points
490         kCubic_Verb,    //!< iter.next returns 4 points
491         kClose_Verb,    //!< iter.next returns 1 point (the last point)
492         kDone_Verb      //!< iter.next returns 0 points
493     };
494 
495     /** Iterate through all of the segments (lines, quadratics, cubics) of
496         each contours in a path.
497     */
498     class Iter {
499     public:
500                 Iter();
501                 Iter(const SkPath&, bool forceClose);
502 
503         void setPath(const SkPath&, bool forceClose);
504 
505         /** Return the next verb in this iteration of the path. When all
506             segments have been visited, return kDone_Verb.
507 
508             @param  pts The points representing the current verb and/or segment
509             @return The verb for the current segment
510         */
511         Verb next(SkPoint pts[4]);
512 
513         /** If next() returns kLine_Verb, then this query returns true if the
514             line was the result of a close() command (i.e. the end point is the
515             initial moveto for this contour). If next() returned a different
516             verb, this returns an undefined value.
517 
518             @return If the last call to next() returned kLine_Verb, return true
519                     if it was the result of an explicit close command.
520         */
isCloseLine()521         bool isCloseLine() const { return SkToBool(fCloseLine); }
522 
523         /** Returns true if the current contour is closed (has a kClose_Verb)
524             @return true if the current contour is closed (has a kClose_Verb)
525         */
526         bool isClosedContour() const;
527 
528     private:
529         const SkPoint*  fPts;
530         const uint8_t*  fVerbs;
531         const uint8_t*  fVerbStop;
532         SkPoint         fMoveTo;
533         SkPoint         fLastPt;
534         SkBool8         fForceClose;
535         SkBool8         fNeedClose;
536         SkBool8         fNeedMoveTo;
537         SkBool8         fCloseLine;
538 
539         bool cons_moveTo(SkPoint pts[1]);
540         Verb autoClose(SkPoint pts[2]);
541     };
542 
543 #ifdef SK_DEBUG
544   /** @cond UNIT_TEST */
545     void dump(bool forceClose, const char title[] = NULL) const;
546   /** @endcond */
547 #endif
548 
549     void flatten(SkFlattenableWriteBuffer&) const;
550     void unflatten(SkFlattenableReadBuffer&);
551 
552     /** Subdivide the path so that no segment is longer that dist.
553         If bendLines is true, then turn all line segments into curves.
554         If dst == null, then the original path itself is modified (not const!)
555     */
556     void subdivide(SkScalar dist, bool bendLines, SkPath* dst = NULL) const;
557 
558     /** Return an SVG-compatible string of the path.
559     */
560     void toString(SkString*) const;
561 
562     SkDEBUGCODE(void validate() const;)
563 
564 private:
565     SkTDArray<SkPoint>  fPts;
566     SkTDArray<uint8_t>  fVerbs;
567     mutable SkRect      fFastBounds;
568     mutable uint8_t     fFastBoundsIsDirty;
569     uint8_t             fFillType;
570 
571     friend class Iter;
572     void cons_moveto();
573 
574     friend class SkPathStroker;
575     /*  Append the first contour of path, ignoring path's initial point. If no
576         moveTo() call has been made for this contour, the first point is
577         automatically set to (0,0).
578     */
579     void pathTo(const SkPath& path);
580 
581     /*  Append, in reverse order, the first contour of path, ignoring path's
582         last point. If no moveTo() call has been made for this contour, the
583         first point is automatically set to (0,0).
584     */
585     void reversePathTo(const SkPath&);
586 
587     friend const SkPoint* sk_get_path_points(const SkPath&, int index);
588     friend class SkAutoPathBoundsUpdate;
589 };
590 
591 #endif
592 
593