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