1 :
2 : /*
3 : * Copyright 2006 The Android Open Source Project
4 : *
5 : * Use of this source code is governed by a BSD-style license that can be
6 : * found in the LICENSE file.
7 : */
8 :
9 :
10 : #ifndef SkPath_DEFINED
11 : #define SkPath_DEFINED
12 :
13 : #include "SkMatrix.h"
14 : #include "SkTDArray.h"
15 :
16 : #ifdef SK_BUILD_FOR_ANDROID
17 : #define GEN_ID_INC fGenerationID++
18 : #define GEN_ID_PTR_INC(ptr) ptr->fGenerationID++
19 : #else
20 : #define GEN_ID_INC
21 : #define GEN_ID_PTR_INC(ptr)
22 : #endif
23 :
24 : class SkReader32;
25 : class SkWriter32;
26 : class SkAutoPathBoundsUpdate;
27 : class SkString;
28 :
29 : /** \class SkPath
30 :
31 : The SkPath class encapsulates compound (multiple contour) geometric paths
32 : consisting of straight line segments, quadratic curves, and cubic curves.
33 : */
34 : class SK_API SkPath {
35 : public:
36 : SkPath();
37 : SkPath(const SkPath&);
38 : ~SkPath();
39 :
40 : SkPath& operator=(const SkPath&);
41 :
42 : friend bool operator==(const SkPath&, const SkPath&);
43 : friend bool operator!=(const SkPath& a, const SkPath& b) {
44 : return !(a == b);
45 : }
46 :
47 : enum FillType {
48 : /** Specifies that "inside" is computed by a non-zero sum of signed
49 : edge crossings
50 : */
51 : kWinding_FillType,
52 : /** Specifies that "inside" is computed by an odd number of edge
53 : crossings
54 : */
55 : kEvenOdd_FillType,
56 : /** Same as Winding, but draws outside of the path, rather than inside
57 : */
58 : kInverseWinding_FillType,
59 : /** Same as EvenOdd, but draws outside of the path, rather than inside
60 : */
61 : kInverseEvenOdd_FillType
62 : };
63 :
64 : /** Return the path's fill type. This is used to define how "inside" is
65 : computed. The default value is kWinding_FillType.
66 :
67 : @return the path's fill type
68 : */
69 0 : FillType getFillType() const { return (FillType)fFillType; }
70 :
71 : /** Set the path's fill type. This is used to define how "inside" is
72 : computed. The default value is kWinding_FillType.
73 :
74 : @param ft The new fill type for this path
75 : */
76 0 : void setFillType(FillType ft) {
77 0 : fFillType = SkToU8(ft);
78 : GEN_ID_INC;
79 0 : }
80 :
81 : /** Returns true if the filltype is one of the Inverse variants */
82 0 : bool isInverseFillType() const { return (fFillType & 2) != 0; }
83 :
84 : /**
85 : * Toggle between inverse and normal filltypes. This reverse the return
86 : * value of isInverseFillType()
87 : */
88 0 : void toggleInverseFillType() {
89 0 : fFillType ^= 2;
90 : GEN_ID_INC;
91 0 : }
92 :
93 : enum Convexity {
94 : kUnknown_Convexity,
95 : kConvex_Convexity,
96 : kConcave_Convexity
97 : };
98 :
99 : /**
100 : * Return the path's convexity, as stored in the path. If it is currently
101 : * unknown, and the computeIfUnknown bool is true, then this will first
102 : * call ComputeConvexity() and then return that (cached) value.
103 : */
104 0 : Convexity getConvexity() const {
105 0 : if (kUnknown_Convexity == fConvexity) {
106 0 : fConvexity = (uint8_t)ComputeConvexity(*this);
107 : }
108 0 : return (Convexity)fConvexity;
109 : }
110 :
111 : /**
112 : * Return the currently cached value for convexity, even if that is set to
113 : * kUnknown_Convexity. Note: getConvexity() will automatically call
114 : * ComputeConvexity and cache its return value if the current setting is
115 : * kUnknown.
116 : */
117 : Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; }
118 :
119 : /**
120 : * Store a convexity setting in the path. There is no automatic check to
121 : * see if this value actually agress with the return value from
122 : * ComputeConvexity().
123 : *
124 : * Note: even if this is set to a "known" value, if the path is later
125 : * changed (e.g. lineTo(), addRect(), etc.) then the cached value will be
126 : * reset to kUnknown_Convexity.
127 : */
128 : void setConvexity(Convexity);
129 :
130 : /**
131 : * Compute the convexity of the specified path. This does not look at the
132 : * value stored in the path, but computes it directly from the path's data.
133 : *
134 : * This never returns kUnknown_Convexity.
135 : *
136 : * If there is more than one contour, this returns kConcave_Convexity.
137 : * If the contour is degenerate (e.g. there are fewer than 3 non-degenerate
138 : * segments), then this returns kConvex_Convexity.
139 : * The contour is treated as if it were closed, even if there is no kClose
140 : * verb.
141 : */
142 : static Convexity ComputeConvexity(const SkPath&);
143 :
144 : /**
145 : * DEPRECATED: use getConvexity()
146 : * Returns true if the path is flagged as being convex. This is not a
147 : * confirmed by any analysis, it is just the value set earlier.
148 : */
149 0 : bool isConvex() const {
150 0 : return kConvex_Convexity == this->getConvexity();
151 : }
152 :
153 : /**
154 : * DEPRECATED: use setConvexity()
155 : * Set the isConvex flag to true or false. Convex paths may draw faster if
156 : * this flag is set, though setting this to true on a path that is in fact
157 : * not convex can give undefined results when drawn. Paths default to
158 : * isConvex == false
159 : */
160 0 : void setIsConvex(bool isConvex) {
161 0 : this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity);
162 0 : }
163 :
164 : /** Clear any lines and curves from the path, making it empty. This frees up
165 : internal storage associated with those segments.
166 : This does NOT change the fill-type setting nor isConvex
167 : */
168 : void reset();
169 :
170 : /** Similar to reset(), in that all lines and curves are removed from the
171 : path. However, any internal storage for those lines/curves is retained,
172 : making reuse of the path potentially faster.
173 : This does NOT change the fill-type setting nor isConvex
174 : */
175 : void rewind();
176 :
177 : /** Returns true if the path is empty (contains no lines or curves)
178 :
179 : @return true if the path is empty (contains no lines or curves)
180 : */
181 : bool isEmpty() const;
182 :
183 : /** Test a line for zero length
184 :
185 : @return true if the line is of zero length; otherwise false.
186 : */
187 0 : static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) {
188 0 : return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero);
189 : }
190 :
191 : /** Test a quad for zero length
192 :
193 : @return true if the quad is of zero length; otherwise false.
194 : */
195 0 : static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
196 : const SkPoint& p3) {
197 0 : return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero) &&
198 0 : p2.equalsWithinTolerance(p3, SK_ScalarNearlyZero);
199 : }
200 :
201 : /** Test a cubic curve for zero length
202 :
203 : @return true if the cubic is of zero length; otherwise false.
204 : */
205 0 : static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
206 : const SkPoint& p3, const SkPoint& p4) {
207 0 : return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero) &&
208 0 : p2.equalsWithinTolerance(p3, SK_ScalarNearlyZero) &&
209 0 : p3.equalsWithinTolerance(p4, SK_ScalarNearlyZero);
210 : }
211 :
212 : /** Returns true if the path specifies a rectangle. If so, and if rect is
213 : not null, set rect to the bounds of the path. If the path does not
214 : specify a rectangle, return false and ignore rect.
215 :
216 : @param rect If not null, returns the bounds of the path if it specifies
217 : a rectangle
218 : @return true if the path specifies a rectangle
219 : */
220 : bool isRect(SkRect* rect) const;
221 :
222 : /** Return the number of points in the path
223 : */
224 : int countPoints() const {
225 : return this->getPoints(NULL, 0);
226 : }
227 :
228 : /** Return the point at the specified index. If the index is out of range
229 : (i.e. is not 0 <= index < countPoints()) then the returned coordinates
230 : will be (0,0)
231 : */
232 : SkPoint getPoint(int index) const;
233 :
234 : /** Returns the number of points in the path. Up to max points are copied.
235 :
236 : @param points If not null, receives up to max points
237 : @param max The maximum number of points to copy into points
238 : @return the actual number of points in the path
239 : */
240 : int getPoints(SkPoint points[], int max) const;
241 :
242 : //! Swap contents of this and other. Guaranteed not to throw
243 : void swap(SkPath& other);
244 :
245 : /** Returns the bounds of the path's points. If the path contains 0 or 1
246 : points, the bounds is set to (0,0,0,0), and isEmpty() will return true.
247 : Note: this bounds may be larger than the actual shape, since curves
248 : do not extend as far as their control points.
249 : */
250 0 : const SkRect& getBounds() const {
251 0 : if (fBoundsIsDirty) {
252 0 : this->computeBounds();
253 : }
254 0 : return fBounds;
255 : }
256 :
257 : /** Calling this will, if the internal cache of the bounds is out of date,
258 : update it so that subsequent calls to getBounds will be instanteous.
259 : This also means that any copies or simple transformations of the path
260 : will inherit the cached bounds.
261 : */
262 0 : void updateBoundsCache() const {
263 : // for now, just calling getBounds() is sufficient
264 0 : this->getBounds();
265 0 : }
266 :
267 : // Construction methods
268 :
269 : /** Hint to the path to prepare for adding more points. This can allow the
270 : path to more efficiently grow its storage.
271 :
272 : @param extraPtCount The number of extra points the path should
273 : preallocate for.
274 : */
275 : void incReserve(unsigned extraPtCount);
276 :
277 : /** Set the beginning of the next contour to the point (x,y).
278 :
279 : @param x The x-coordinate of the start of a new contour
280 : @param y The y-coordinate of the start of a new contour
281 : */
282 : void moveTo(SkScalar x, SkScalar y);
283 :
284 : /** Set the beginning of the next contour to the point
285 :
286 : @param p The start of a new contour
287 : */
288 0 : void moveTo(const SkPoint& p) {
289 0 : this->moveTo(p.fX, p.fY);
290 0 : }
291 :
292 : /** Set the beginning of the next contour relative to the last point on the
293 : previous contour. If there is no previous contour, this is treated the
294 : same as moveTo().
295 :
296 : @param dx The amount to add to the x-coordinate of the end of the
297 : previous contour, to specify the start of a new contour
298 : @param dy The amount to add to the y-coordinate of the end of the
299 : previous contour, to specify the start of a new contour
300 : */
301 : void rMoveTo(SkScalar dx, SkScalar dy);
302 :
303 : /** Add a line from the last point to the specified point (x,y). If no
304 : moveTo() call has been made for this contour, the first point is
305 : automatically set to (0,0).
306 :
307 : @param x The x-coordinate of the end of a line
308 : @param y The y-coordinate of the end of a line
309 : */
310 : void lineTo(SkScalar x, SkScalar y);
311 :
312 : /** Add a line from the last point to the specified point. If no moveTo()
313 : call has been made for this contour, the first point is automatically
314 : set to (0,0).
315 :
316 : @param p The end of a line
317 : */
318 0 : void lineTo(const SkPoint& p) {
319 0 : this->lineTo(p.fX, p.fY);
320 0 : }
321 :
322 : /** Same as lineTo, but the coordinates are considered relative to the last
323 : point on this contour. If there is no previous point, then a moveTo(0,0)
324 : is inserted automatically.
325 :
326 : @param dx The amount to add to the x-coordinate of the previous point
327 : on this contour, to specify a line
328 : @param dy The amount to add to the y-coordinate of the previous point
329 : on this contour, to specify a line
330 : */
331 : void rLineTo(SkScalar dx, SkScalar dy);
332 :
333 : /** Add a quadratic bezier from the last point, approaching control point
334 : (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
335 : this contour, the first point is automatically set to (0,0).
336 :
337 : @param x1 The x-coordinate of the control point on a quadratic curve
338 : @param y1 The y-coordinate of the control point on a quadratic curve
339 : @param x2 The x-coordinate of the end point on a quadratic curve
340 : @param y2 The y-coordinate of the end point on a quadratic curve
341 : */
342 : void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
343 :
344 : /** Add a quadratic bezier from the last point, approaching control point
345 : p1, and ending at p2. If no moveTo() call has been made for this
346 : contour, the first point is automatically set to (0,0).
347 :
348 : @param p1 The control point on a quadratic curve
349 : @param p2 The end point on a quadratic curve
350 : */
351 0 : void quadTo(const SkPoint& p1, const SkPoint& p2) {
352 0 : this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
353 0 : }
354 :
355 : /** Same as quadTo, but the coordinates are considered relative to the last
356 : point on this contour. If there is no previous point, then a moveTo(0,0)
357 : is inserted automatically.
358 :
359 : @param dx1 The amount to add to the x-coordinate of the last point on
360 : this contour, to specify the control point of a quadratic curve
361 : @param dy1 The amount to add to the y-coordinate of the last point on
362 : this contour, to specify the control point of a quadratic curve
363 : @param dx2 The amount to add to the x-coordinate of the last point on
364 : this contour, to specify the end point of a quadratic curve
365 : @param dy2 The amount to add to the y-coordinate of the last point on
366 : this contour, to specify the end point of a quadratic curve
367 : */
368 : void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
369 :
370 : /** Add a cubic bezier from the last point, approaching control points
371 : (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
372 : made for this contour, the first point is automatically set to (0,0).
373 :
374 : @param x1 The x-coordinate of the 1st control point on a cubic curve
375 : @param y1 The y-coordinate of the 1st control point on a cubic curve
376 : @param x2 The x-coordinate of the 2nd control point on a cubic curve
377 : @param y2 The y-coordinate of the 2nd control point on a cubic curve
378 : @param x3 The x-coordinate of the end point on a cubic curve
379 : @param y3 The y-coordinate of the end point on a cubic curve
380 : */
381 : void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
382 : SkScalar x3, SkScalar y3);
383 :
384 : /** Add a cubic bezier from the last point, approaching control points p1
385 : and p2, and ending at p3. If no moveTo() call has been made for this
386 : contour, the first point is automatically set to (0,0).
387 :
388 : @param p1 The 1st control point on a cubic curve
389 : @param p2 The 2nd control point on a cubic curve
390 : @param p3 The end point on a cubic curve
391 : */
392 0 : void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
393 0 : this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
394 0 : }
395 :
396 : /** Same as cubicTo, but the coordinates are considered relative to the
397 : current point on this contour. If there is no previous point, then a
398 : moveTo(0,0) is inserted automatically.
399 :
400 : @param dx1 The amount to add to the x-coordinate of the last point on
401 : this contour, to specify the 1st control point of a cubic curve
402 : @param dy1 The amount to add to the y-coordinate of the last point on
403 : this contour, to specify the 1st control point of a cubic curve
404 : @param dx2 The amount to add to the x-coordinate of the last point on
405 : this contour, to specify the 2nd control point of a cubic curve
406 : @param dy2 The amount to add to the y-coordinate of the last point on
407 : this contour, to specify the 2nd control point of a cubic curve
408 : @param dx3 The amount to add to the x-coordinate of the last point on
409 : this contour, to specify the end point of a cubic curve
410 : @param dy3 The amount to add to the y-coordinate of the last point on
411 : this contour, to specify the end point of a cubic curve
412 : */
413 : void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
414 : SkScalar x3, SkScalar y3);
415 :
416 : /** Append the specified arc to the path as a new contour. If the start of
417 : the path is different from the path's current last point, then an
418 : automatic lineTo() is added to connect the current contour to the start
419 : of the arc. However, if the path is empty, then we call moveTo() with
420 : the first point of the arc. The sweep angle is treated mod 360.
421 :
422 : @param oval The bounding oval defining the shape and size of the arc
423 : @param startAngle Starting angle (in degrees) where the arc begins
424 : @param sweepAngle Sweep angle (in degrees) measured clockwise. This is
425 : treated mod 360.
426 : @param forceMoveTo If true, always begin a new contour with the arc
427 : */
428 : void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
429 : bool forceMoveTo);
430 :
431 : /** Append a line and arc to the current path. This is the same as the
432 : PostScript call "arct".
433 : */
434 : void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
435 : SkScalar radius);
436 :
437 : /** Append a line and arc to the current path. This is the same as the
438 : PostScript call "arct".
439 : */
440 : void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
441 : this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
442 : }
443 :
444 : /** Close the current contour. If the current point is not equal to the
445 : first point of the contour, a line segment is automatically added.
446 : */
447 : void close();
448 :
449 : enum Direction {
450 : /** clockwise direction for adding closed contours */
451 : kCW_Direction,
452 : /** counter-clockwise direction for adding closed contours */
453 : kCCW_Direction
454 : };
455 :
456 : /** Add a closed rectangle contour to the path
457 : @param rect The rectangle to add as a closed contour to the path
458 : @param dir The direction to wind the rectangle's contour
459 : */
460 : void addRect(const SkRect& rect, Direction dir = kCW_Direction);
461 :
462 : /** Add a closed rectangle contour to the path
463 :
464 : @param left The left side of a rectangle to add as a closed contour
465 : to the path
466 : @param top The top of a rectangle to add as a closed contour to the
467 : path
468 : @param right The right side of a rectangle to add as a closed contour
469 : to the path
470 : @param bottom The bottom of a rectangle to add as a closed contour to
471 : the path
472 : @param dir The direction to wind the rectangle's contour
473 : */
474 : void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
475 : Direction dir = kCW_Direction);
476 :
477 : /** Add a closed oval contour to the path
478 :
479 : @param oval The bounding oval to add as a closed contour to the path
480 : @param dir The direction to wind the oval's contour
481 : */
482 : void addOval(const SkRect& oval, Direction dir = kCW_Direction);
483 :
484 : /** Add a closed circle contour to the path
485 :
486 : @param x The x-coordinate of the center of a circle to add as a
487 : closed contour to the path
488 : @param y The y-coordinate of the center of a circle to add as a
489 : closed contour to the path
490 : @param radius The radius of a circle to add as a closed contour to the
491 : path
492 : @param dir The direction to wind the circle's contour
493 : */
494 : void addCircle(SkScalar x, SkScalar y, SkScalar radius,
495 : Direction dir = kCW_Direction);
496 :
497 : /** Add the specified arc to the path as a new contour.
498 :
499 : @param oval The bounds of oval used to define the size of the arc
500 : @param startAngle Starting angle (in degrees) where the arc begins
501 : @param sweepAngle Sweep angle (in degrees) measured clockwise
502 : */
503 : void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
504 :
505 : /** Add a closed round-rectangle contour to the path
506 : @param rect The bounds of a round-rectangle to add as a closed contour
507 : @param rx The x-radius of the rounded corners on the round-rectangle
508 : @param ry The y-radius of the rounded corners on the round-rectangle
509 : @param dir The direction to wind the round-rectangle's contour
510 : */
511 : void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
512 : Direction dir = kCW_Direction);
513 :
514 : /** Add a closed round-rectangle contour to the path. Each corner receives
515 : two radius values [X, Y]. The corners are ordered top-left, top-right,
516 : bottom-right, bottom-left.
517 : @param rect The bounds of a round-rectangle to add as a closed contour
518 : @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner
519 : @param dir The direction to wind the round-rectangle's contour
520 : */
521 : void addRoundRect(const SkRect& rect, const SkScalar radii[],
522 : Direction dir = kCW_Direction);
523 :
524 : /** Add a copy of src to the path, offset by (dx,dy)
525 : @param src The path to add as a new contour
526 : @param dx The amount to translate the path in X as it is added
527 : @param dx The amount to translate the path in Y as it is added
528 : */
529 : void addPath(const SkPath& src, SkScalar dx, SkScalar dy);
530 :
531 : /** Add a copy of src to the path
532 : */
533 0 : void addPath(const SkPath& src) {
534 : SkMatrix m;
535 0 : m.reset();
536 0 : this->addPath(src, m);
537 0 : }
538 :
539 : /** Add a copy of src to the path, transformed by matrix
540 : @param src The path to add as a new contour
541 : */
542 : void addPath(const SkPath& src, const SkMatrix& matrix);
543 :
544 : /** Offset the path by (dx,dy), returning true on success
545 :
546 : @param dx The amount in the X direction to offset the entire path
547 : @param dy The amount in the Y direction to offset the entire path
548 : @param dst The translated path is written here
549 : */
550 : void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
551 :
552 : /** Offset the path by (dx,dy), returning true on success
553 :
554 : @param dx The amount in the X direction to offset the entire path
555 : @param dy The amount in the Y direction to offset the entire path
556 : */
557 0 : void offset(SkScalar dx, SkScalar dy) {
558 0 : this->offset(dx, dy, this);
559 0 : }
560 :
561 : /** Transform the points in this path by matrix, and write the answer into
562 : dst.
563 :
564 : @param matrix The matrix to apply to the path
565 : @param dst The transformed path is written here
566 : */
567 : void transform(const SkMatrix& matrix, SkPath* dst) const;
568 :
569 : /** Transform the points in this path by matrix
570 :
571 : @param matrix The matrix to apply to the path
572 : */
573 : void transform(const SkMatrix& matrix) {
574 : this->transform(matrix, this);
575 : }
576 :
577 : /** Return the last point on the path. If no points have been added, (0,0)
578 : is returned. If there are no points, this returns false, otherwise it
579 : returns true.
580 :
581 : @param lastPt The last point on the path is returned here
582 : */
583 : bool getLastPt(SkPoint* lastPt) const;
584 :
585 : /** Set the last point on the path. If no points have been added,
586 : moveTo(x,y) is automatically called.
587 :
588 : @param x The new x-coordinate for the last point
589 : @param y The new y-coordinate for the last point
590 : */
591 : void setLastPt(SkScalar x, SkScalar y);
592 :
593 : /** Set the last point on the path. If no points have been added, moveTo(p)
594 : is automatically called.
595 :
596 : @param p The new location for the last point
597 : */
598 : void setLastPt(const SkPoint& p) {
599 : this->setLastPt(p.fX, p.fY);
600 : }
601 :
602 : enum SegmentMask {
603 : kLine_SegmentMask = 1 << 0,
604 : kQuad_SegmentMask = 1 << 1,
605 : kCubic_SegmentMask = 1 << 2
606 : };
607 :
608 : /**
609 : * Returns a mask, where each bit corresponding to a SegmentMask is
610 : * set if the path contains 1 or more segments of that type.
611 : * Returns 0 for an empty path (no segments).
612 : */
613 : uint32_t getSegmentMasks() const { return fSegmentMask; }
614 :
615 : enum Verb {
616 : kMove_Verb, //!< iter.next returns 1 point
617 : kLine_Verb, //!< iter.next returns 2 points
618 : kQuad_Verb, //!< iter.next returns 3 points
619 : kCubic_Verb, //!< iter.next returns 4 points
620 : kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt)
621 : kDone_Verb //!< iter.next returns 0 points
622 : };
623 :
624 : /** Iterate through all of the segments (lines, quadratics, cubics) of
625 : each contours in a path.
626 :
627 : The iterator cleans up the segments along the way, removing degenerate
628 : segments and adding close verbs where necessary. When the forceClose
629 : argument is provided, each contour (as defined by a new starting
630 : move command) will be completed with a close verb regardless of the
631 : contour's contents.
632 : */
633 : class SK_API Iter {
634 : public:
635 : Iter();
636 : Iter(const SkPath&, bool forceClose);
637 :
638 : void setPath(const SkPath&, bool forceClose);
639 :
640 : /** Return the next verb in this iteration of the path. When all
641 : segments have been visited, return kDone_Verb.
642 :
643 : @param pts The points representing the current verb and/or segment
644 : @return The verb for the current segment
645 : */
646 : Verb next(SkPoint pts[4]);
647 :
648 : /** If next() returns kLine_Verb, then this query returns true if the
649 : line was the result of a close() command (i.e. the end point is the
650 : initial moveto for this contour). If next() returned a different
651 : verb, this returns an undefined value.
652 :
653 : @return If the last call to next() returned kLine_Verb, return true
654 : if it was the result of an explicit close command.
655 : */
656 0 : bool isCloseLine() const { return SkToBool(fCloseLine); }
657 :
658 : /** Returns true if the current contour is closed (has a kClose_Verb)
659 : @return true if the current contour is closed (has a kClose_Verb)
660 : */
661 : bool isClosedContour() const;
662 :
663 : private:
664 : const SkPoint* fPts;
665 : const uint8_t* fVerbs;
666 : const uint8_t* fVerbStop;
667 : SkPoint fMoveTo;
668 : SkPoint fLastPt;
669 : SkBool8 fForceClose;
670 : SkBool8 fNeedClose;
671 : SkBool8 fCloseLine;
672 : SkBool8 fSegmentState;
673 :
674 : bool cons_moveTo(SkPoint pts[1]);
675 : Verb autoClose(SkPoint pts[2]);
676 : void consumeDegenerateSegments();
677 : };
678 :
679 : /** Iterate through the verbs in the path, providing the associated points.
680 : */
681 : class SK_API RawIter {
682 : public:
683 : RawIter();
684 : RawIter(const SkPath&);
685 :
686 : void setPath(const SkPath&);
687 :
688 : /** Return the next verb in this iteration of the path. When all
689 : segments have been visited, return kDone_Verb.
690 :
691 : @param pts The points representing the current verb and/or segment
692 : @return The verb for the current segment
693 : */
694 : Verb next(SkPoint pts[4]);
695 :
696 : private:
697 : const SkPoint* fPts;
698 : const uint8_t* fVerbs;
699 : const uint8_t* fVerbStop;
700 : SkPoint fMoveTo;
701 : SkPoint fLastPt;
702 : };
703 :
704 : void dump(bool forceClose, const char title[] = NULL) const;
705 : void dump() const;
706 :
707 : void flatten(SkWriter32&) const;
708 : void unflatten(SkReader32&);
709 :
710 : #ifdef SK_BUILD_FOR_ANDROID
711 : uint32_t getGenerationID() const;
712 : #endif
713 :
714 : SkDEBUGCODE(void validate() const;)
715 :
716 : private:
717 : SkTDArray<SkPoint> fPts;
718 : SkTDArray<uint8_t> fVerbs;
719 : mutable SkRect fBounds;
720 : uint8_t fFillType;
721 : uint8_t fSegmentMask;
722 : mutable uint8_t fBoundsIsDirty;
723 : mutable uint8_t fConvexity;
724 : #ifdef SK_BUILD_FOR_ANDROID
725 : uint32_t fGenerationID;
726 : #endif
727 :
728 : // called, if dirty, by getBounds()
729 : void computeBounds() const;
730 :
731 : friend class Iter;
732 : void cons_moveto();
733 :
734 : friend class SkPathStroker;
735 : /* Append the first contour of path, ignoring path's initial point. If no
736 : moveTo() call has been made for this contour, the first point is
737 : automatically set to (0,0).
738 : */
739 : void pathTo(const SkPath& path);
740 :
741 : /* Append, in reverse order, the first contour of path, ignoring path's
742 : last point. If no moveTo() call has been made for this contour, the
743 : first point is automatically set to (0,0).
744 : */
745 : void reversePathTo(const SkPath&);
746 :
747 : friend const SkPoint* sk_get_path_points(const SkPath&, int index);
748 : friend class SkAutoPathBoundsUpdate;
749 : };
750 :
751 : #endif
|