blob: 2488dd8bf938b404273acb635c16bbd8696f1c32 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#ifndef SkPath_DEFINED
11#define SkPath_DEFINED
12
bsalomon@google.com65a87cc2012-08-14 13:15:44 +000013#include "SkInstCnt.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkMatrix.h"
15#include "SkTDArray.h"
bsalomon@google.com1dfe88e2012-10-03 13:46:20 +000016#include "SkRefCnt.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
djsollen@google.com56c69772011-11-08 19:00:26 +000018#ifdef SK_BUILD_FOR_ANDROID
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +000019#define GEN_ID_INC fGenerationID++
bungeman@google.com28eadc92013-06-21 15:28:54 +000020#define GEN_ID_PTR_INC(ptr) (ptr)->fGenerationID++
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +000021#else
22#define GEN_ID_INC
23#define GEN_ID_PTR_INC(ptr)
24#endif
25
reed@google.com73945652011-04-25 19:04:27 +000026class SkReader32;
27class SkWriter32;
reed@android.com8a1c16f2008-12-17 15:59:43 +000028class SkAutoPathBoundsUpdate;
29class SkString;
bsalomon@google.com1dfe88e2012-10-03 13:46:20 +000030class SkPathRef;
reed@google.com4ed0fb72012-12-12 20:48:18 +000031class SkRRect;
reed@android.com8a1c16f2008-12-17 15:59:43 +000032
bsalomon@google.comae09f2d2012-10-03 19:57:01 +000033#ifndef SK_DEBUG_PATH_REF
bsalomon@google.com7823d9a2012-10-04 17:55:30 +000034 #define SK_DEBUG_PATH_REF 0
bsalomon@google.comae09f2d2012-10-03 19:57:01 +000035#endif
36
reed@android.com8a1c16f2008-12-17 15:59:43 +000037/** \class SkPath
38
39 The SkPath class encapsulates compound (multiple contour) geometric paths
40 consisting of straight line segments, quadratic curves, and cubic curves.
41*/
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +000042class SK_API SkPath {
reed@android.com8a1c16f2008-12-17 15:59:43 +000043public:
bsalomon@google.com65a87cc2012-08-14 13:15:44 +000044 SK_DECLARE_INST_COUNT_ROOT(SkPath);
45
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 SkPath();
47 SkPath(const SkPath&);
48 ~SkPath();
49
50 SkPath& operator=(const SkPath&);
schenney@chromium.orgb0af6da2011-12-21 20:43:13 +000051
bsalomon@google.com5e728452012-09-07 13:32:37 +000052 friend SK_API bool operator==(const SkPath&, const SkPath&);
reed@android.com3abec1d2009-03-02 05:36:20 +000053 friend bool operator!=(const SkPath& a, const SkPath& b) {
54 return !(a == b);
55 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000056
57 enum FillType {
58 /** Specifies that "inside" is computed by a non-zero sum of signed
59 edge crossings
60 */
61 kWinding_FillType,
62 /** Specifies that "inside" is computed by an odd number of edge
63 crossings
64 */
65 kEvenOdd_FillType,
66 /** Same as Winding, but draws outside of the path, rather than inside
67 */
68 kInverseWinding_FillType,
69 /** Same as EvenOdd, but draws outside of the path, rather than inside
70 */
71 kInverseEvenOdd_FillType
72 };
73
74 /** Return the path's fill type. This is used to define how "inside" is
75 computed. The default value is kWinding_FillType.
76
77 @return the path's fill type
78 */
79 FillType getFillType() const { return (FillType)fFillType; }
80
81 /** Set the path's fill type. This is used to define how "inside" is
82 computed. The default value is kWinding_FillType.
schenney@chromium.orgb0af6da2011-12-21 20:43:13 +000083
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 @param ft The new fill type for this path
85 */
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +000086 void setFillType(FillType ft) {
87 fFillType = SkToU8(ft);
88 GEN_ID_INC;
89 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000090
91 /** Returns true if the filltype is one of the Inverse variants */
sugoi@google.com5f74cf82012-12-17 21:16:45 +000092 bool isInverseFillType() const { return IsInverseFillType((FillType)fFillType); }
reed@android.com8a1c16f2008-12-17 15:59:43 +000093
reed@google.comb54455e2011-05-16 14:16:04 +000094 /**
95 * Toggle between inverse and normal filltypes. This reverse the return
96 * value of isInverseFillType()
97 */
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +000098 void toggleInverseFillType() {
99 fFillType ^= 2;
100 GEN_ID_INC;
101 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102
reed@google.com04863fa2011-05-15 04:08:24 +0000103 enum Convexity {
104 kUnknown_Convexity,
105 kConvex_Convexity,
106 kConcave_Convexity
107 };
reed@android.com6b82d1a2009-06-03 02:35:01 +0000108
reed@google.com04863fa2011-05-15 04:08:24 +0000109 /**
bsalomon@google.com30c174b2012-11-13 14:36:42 +0000110 * Return the path's convexity, as stored in the path. If it is currently unknown,
111 * then this function will attempt to compute the convexity (and cache the result).
reed@google.com04863fa2011-05-15 04:08:24 +0000112 */
reed@google.comb54455e2011-05-16 14:16:04 +0000113 Convexity getConvexity() const {
bsalomon@google.com30c174b2012-11-13 14:36:42 +0000114 if (kUnknown_Convexity != fConvexity) {
115 return static_cast<Convexity>(fConvexity);
116 } else {
117 return this->internalGetConvexity();
reed@google.comb54455e2011-05-16 14:16:04 +0000118 }
reed@google.comb54455e2011-05-16 14:16:04 +0000119 }
120
121 /**
122 * Return the currently cached value for convexity, even if that is set to
123 * kUnknown_Convexity. Note: getConvexity() will automatically call
124 * ComputeConvexity and cache its return value if the current setting is
125 * kUnknown.
126 */
127 Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; }
reed@google.com04863fa2011-05-15 04:08:24 +0000128
129 /**
130 * Store a convexity setting in the path. There is no automatic check to
bsalomon@google.com30c174b2012-11-13 14:36:42 +0000131 * see if this value actually agrees with the return value that would be
132 * computed by getConvexity().
reed@google.comb54455e2011-05-16 14:16:04 +0000133 *
134 * Note: even if this is set to a "known" value, if the path is later
135 * changed (e.g. lineTo(), addRect(), etc.) then the cached value will be
136 * reset to kUnknown_Convexity.
reed@google.com04863fa2011-05-15 04:08:24 +0000137 */
138 void setConvexity(Convexity);
139
140 /**
reed@google.com04863fa2011-05-15 04:08:24 +0000141 * DEPRECATED: use getConvexity()
142 * Returns true if the path is flagged as being convex. This is not a
143 * confirmed by any analysis, it is just the value set earlier.
144 */
145 bool isConvex() const {
146 return kConvex_Convexity == this->getConvexity();
147 }
148
149 /**
150 * DEPRECATED: use setConvexity()
151 * Set the isConvex flag to true or false. Convex paths may draw faster if
152 * this flag is set, though setting this to true on a path that is in fact
153 * not convex can give undefined results when drawn. Paths default to
154 * isConvex == false
reed@android.com6b82d1a2009-06-03 02:35:01 +0000155 */
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000156 void setIsConvex(bool isConvex) {
reed@google.com04863fa2011-05-15 04:08:24 +0000157 this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity);
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000158 }
reed@android.com6b82d1a2009-06-03 02:35:01 +0000159
bsalomon@google.com6aa29652012-04-18 13:29:52 +0000160 /** Returns true if the path is an oval.
161 *
162 * @param rect returns the bounding rect of this oval. It's a circle
163 * if the height and width are the same.
164 *
165 * @return true if this path is an oval.
166 * Tracking whether a path is an oval is considered an
167 * optimization for performance and so some paths that are in
168 * fact ovals can report false.
169 */
170 bool isOval(SkRect* rect) const;
171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 /** Clear any lines and curves from the path, making it empty. This frees up
173 internal storage associated with those segments.
reed@android.com6b82d1a2009-06-03 02:35:01 +0000174 This does NOT change the fill-type setting nor isConvex
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 */
176 void reset();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000177
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 /** Similar to reset(), in that all lines and curves are removed from the
179 path. However, any internal storage for those lines/curves is retained,
180 making reuse of the path potentially faster.
reed@android.com6b82d1a2009-06-03 02:35:01 +0000181 This does NOT change the fill-type setting nor isConvex
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 */
183 void rewind();
184
185 /** Returns true if the path is empty (contains no lines or curves)
186
187 @return true if the path is empty (contains no lines or curves)
188 */
189 bool isEmpty() const;
190
reed@google.com0bb18bb2012-07-26 15:20:36 +0000191 /**
192 * Returns true if all of the points in this path are finite, meaning there
193 * are no infinities and no NaNs.
194 */
195 bool isFinite() const {
196 if (fBoundsIsDirty) {
197 this->computeBounds();
198 }
robertphillips@google.comfc91dc72012-07-26 21:18:31 +0000199 return SkToBool(fIsFinite);
reed@google.com0bb18bb2012-07-26 15:20:36 +0000200 }
201
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000202 /** Test a line for zero length
203
204 @return true if the line is of zero length; otherwise false.
205 */
206 static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) {
epoger@google.com94fa43c2012-04-11 17:51:01 +0000207 return p1.equalsWithinTolerance(p2);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000208 }
209
210 /** Test a quad for zero length
211
212 @return true if the quad is of zero length; otherwise false.
213 */
214 static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
215 const SkPoint& p3) {
epoger@google.com94fa43c2012-04-11 17:51:01 +0000216 return p1.equalsWithinTolerance(p2) &&
217 p2.equalsWithinTolerance(p3);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000218 }
219
220 /** Test a cubic curve for zero length
221
222 @return true if the cubic is of zero length; otherwise false.
223 */
224 static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
225 const SkPoint& p3, const SkPoint& p4) {
epoger@google.com94fa43c2012-04-11 17:51:01 +0000226 return p1.equalsWithinTolerance(p2) &&
227 p2.equalsWithinTolerance(p3) &&
228 p3.equalsWithinTolerance(p4);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000229 }
230
reed@google.com7e6c4d12012-05-10 14:05:43 +0000231 /**
232 * Returns true if the path specifies a single line (i.e. it contains just
233 * a moveTo and a lineTo). If so, and line[] is not null, it sets the 2
234 * points in line[] to the end-points of the line. If the path is not a
235 * line, returns false and ignores line[].
236 */
237 bool isLine(SkPoint line[2]) const;
238
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 /** Returns true if the path specifies a rectangle. If so, and if rect is
240 not null, set rect to the bounds of the path. If the path does not
241 specify a rectangle, return false and ignore rect.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000242
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 @param rect If not null, returns the bounds of the path if it specifies
244 a rectangle
245 @return true if the path specifies a rectangle
246 */
robertphillips@google.com8fd16032013-06-25 15:39:58 +0000247 bool isRect(SkRect* rect) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248
reed@android.comd3aa4ff2010-02-09 16:38:45 +0000249 /** Return the number of points in the path
250 */
bsalomon@google.com1dfe88e2012-10-03 13:46:20 +0000251 int countPoints() const;
reed@android.comd3aa4ff2010-02-09 16:38:45 +0000252
253 /** Return the point at the specified index. If the index is out of range
254 (i.e. is not 0 <= index < countPoints()) then the returned coordinates
255 will be (0,0)
256 */
257 SkPoint getPoint(int index) const;
258
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259 /** Returns the number of points in the path. Up to max points are copied.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000260
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 @param points If not null, receives up to max points
262 @param max The maximum number of points to copy into points
263 @return the actual number of points in the path
264 */
265 int getPoints(SkPoint points[], int max) const;
266
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000267 /** Return the number of verbs in the path
268 */
bsalomon@google.com1dfe88e2012-10-03 13:46:20 +0000269 int countVerbs() const;
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000270
271 /** Returns the number of verbs in the path. Up to max verbs are copied. The
272 verbs are copied as one byte per verb.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000273
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000274 @param verbs If not null, receives up to max verbs
275 @param max The maximum number of verbs to copy into verbs
276 @return the actual number of verbs in the path
277 */
278 int getVerbs(uint8_t verbs[], int max) const;
279
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 //! Swap contents of this and other. Guaranteed not to throw
281 void swap(SkPath& other);
282
reed@android.comd252db02009-04-01 18:31:44 +0000283 /** Returns the bounds of the path's points. If the path contains 0 or 1
284 points, the bounds is set to (0,0,0,0), and isEmpty() will return true.
285 Note: this bounds may be larger than the actual shape, since curves
286 do not extend as far as their control points.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287 */
reed@android.comd252db02009-04-01 18:31:44 +0000288 const SkRect& getBounds() const {
289 if (fBoundsIsDirty) {
290 this->computeBounds();
291 }
292 return fBounds;
293 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294
295 /** Calling this will, if the internal cache of the bounds is out of date,
bsalomon@google.com9bee33a2012-11-13 21:51:38 +0000296 update it so that subsequent calls to getBounds will be instantaneous.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 This also means that any copies or simple transformations of the path
298 will inherit the cached bounds.
reed@android.comd252db02009-04-01 18:31:44 +0000299 */
300 void updateBoundsCache() const {
301 // for now, just calling getBounds() is sufficient
302 this->getBounds();
303 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304
bsalomon@google.com9bee33a2012-11-13 21:51:38 +0000305 /**
306 * Does a conservative test to see whether a rectangle is inside a path. Currently it only
307 * will ever return true for single convex contour paths. The empty-status of the rect is not
308 * considered (e.g. a rect that is a point can be inside a path). Points or line segments where
309 * the rect edge touches the path border are not considered containment violations.
310 */
311 bool conservativelyContainsRect(const SkRect& rect) const;
312
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 // Construction methods
314
315 /** Hint to the path to prepare for adding more points. This can allow the
316 path to more efficiently grow its storage.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000317
reed@android.com8a1c16f2008-12-17 15:59:43 +0000318 @param extraPtCount The number of extra points the path should
319 preallocate for.
320 */
321 void incReserve(unsigned extraPtCount);
322
323 /** Set the beginning of the next contour to the point (x,y).
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000324
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 @param x The x-coordinate of the start of a new contour
326 @param y The y-coordinate of the start of a new contour
327 */
328 void moveTo(SkScalar x, SkScalar y);
329
330 /** Set the beginning of the next contour to the point
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000331
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332 @param p The start of a new contour
333 */
334 void moveTo(const SkPoint& p) {
335 this->moveTo(p.fX, p.fY);
336 }
337
338 /** Set the beginning of the next contour relative to the last point on the
339 previous contour. If there is no previous contour, this is treated the
340 same as moveTo().
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000341
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 @param dx The amount to add to the x-coordinate of the end of the
343 previous contour, to specify the start of a new contour
344 @param dy The amount to add to the y-coordinate of the end of the
345 previous contour, to specify the start of a new contour
346 */
347 void rMoveTo(SkScalar dx, SkScalar dy);
348
349 /** Add a line from the last point to the specified point (x,y). If no
350 moveTo() call has been made for this contour, the first point is
351 automatically set to (0,0).
352
353 @param x The x-coordinate of the end of a line
354 @param y The y-coordinate of the end of a line
355 */
356 void lineTo(SkScalar x, SkScalar y);
357
358 /** Add a line from the last point to the specified point. If no moveTo()
359 call has been made for this contour, the first point is automatically
360 set to (0,0).
361
362 @param p The end of a line
363 */
364 void lineTo(const SkPoint& p) {
365 this->lineTo(p.fX, p.fY);
366 }
367
368 /** Same as lineTo, but the coordinates are considered relative to the last
369 point on this contour. If there is no previous point, then a moveTo(0,0)
370 is inserted automatically.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000371
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372 @param dx The amount to add to the x-coordinate of the previous point
373 on this contour, to specify a line
374 @param dy The amount to add to the y-coordinate of the previous point
375 on this contour, to specify a line
376 */
377 void rLineTo(SkScalar dx, SkScalar dy);
378
379 /** Add a quadratic bezier from the last point, approaching control point
380 (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
381 this contour, the first point is automatically set to (0,0).
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000382
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383 @param x1 The x-coordinate of the control point on a quadratic curve
384 @param y1 The y-coordinate of the control point on a quadratic curve
385 @param x2 The x-coordinate of the end point on a quadratic curve
386 @param y2 The y-coordinate of the end point on a quadratic curve
387 */
388 void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
389
390 /** Add a quadratic bezier from the last point, approaching control point
391 p1, and ending at p2. If no moveTo() call has been made for this
392 contour, the first point is automatically set to (0,0).
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000393
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394 @param p1 The control point on a quadratic curve
395 @param p2 The end point on a quadratic curve
396 */
397 void quadTo(const SkPoint& p1, const SkPoint& p2) {
398 this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
399 }
400
401 /** Same as quadTo, but the coordinates are considered relative to the last
402 point on this contour. If there is no previous point, then a moveTo(0,0)
403 is inserted automatically.
404
405 @param dx1 The amount to add to the x-coordinate of the last point on
406 this contour, to specify the control point of a quadratic curve
407 @param dy1 The amount to add to the y-coordinate of the last point on
408 this contour, to specify the control point of a quadratic curve
409 @param dx2 The amount to add to the x-coordinate of the last point on
410 this contour, to specify the end point of a quadratic curve
411 @param dy2 The amount to add to the y-coordinate of the last point on
412 this contour, to specify the end point of a quadratic curve
413 */
414 void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
415
reed@google.com277c3f82013-05-31 15:17:50 +0000416 void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
417 SkScalar w);
418 void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) {
419 this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w);
420 }
421 void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
422 SkScalar w);
skia.committer@gmail.com26da7f02013-06-01 07:01:39 +0000423
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424 /** Add a cubic bezier from the last point, approaching control points
425 (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
426 made for this contour, the first point is automatically set to (0,0).
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000427
reed@android.com8a1c16f2008-12-17 15:59:43 +0000428 @param x1 The x-coordinate of the 1st control point on a cubic curve
429 @param y1 The y-coordinate of the 1st control point on a cubic curve
430 @param x2 The x-coordinate of the 2nd control point on a cubic curve
431 @param y2 The y-coordinate of the 2nd control point on a cubic curve
432 @param x3 The x-coordinate of the end point on a cubic curve
433 @param y3 The y-coordinate of the end point on a cubic curve
434 */
435 void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
436 SkScalar x3, SkScalar y3);
437
438 /** Add a cubic bezier from the last point, approaching control points p1
439 and p2, and ending at p3. If no moveTo() call has been made for this
440 contour, the first point is automatically set to (0,0).
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000441
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442 @param p1 The 1st control point on a cubic curve
443 @param p2 The 2nd control point on a cubic curve
444 @param p3 The end point on a cubic curve
445 */
446 void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
447 this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
448 }
449
450 /** Same as cubicTo, but the coordinates are considered relative to the
451 current point on this contour. If there is no previous point, then a
452 moveTo(0,0) is inserted automatically.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000453
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454 @param dx1 The amount to add to the x-coordinate of the last point on
455 this contour, to specify the 1st control point of a cubic curve
456 @param dy1 The amount to add to the y-coordinate of the last point on
457 this contour, to specify the 1st control point of a cubic curve
458 @param dx2 The amount to add to the x-coordinate of the last point on
459 this contour, to specify the 2nd control point of a cubic curve
460 @param dy2 The amount to add to the y-coordinate of the last point on
461 this contour, to specify the 2nd control point of a cubic curve
462 @param dx3 The amount to add to the x-coordinate of the last point on
463 this contour, to specify the end point of a cubic curve
464 @param dy3 The amount to add to the y-coordinate of the last point on
465 this contour, to specify the end point of a cubic curve
466 */
467 void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
468 SkScalar x3, SkScalar y3);
469
470 /** Append the specified arc to the path as a new contour. If the start of
471 the path is different from the path's current last point, then an
472 automatic lineTo() is added to connect the current contour to the start
473 of the arc. However, if the path is empty, then we call moveTo() with
474 the first point of the arc. The sweep angle is treated mod 360.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000475
reed@android.com8a1c16f2008-12-17 15:59:43 +0000476 @param oval The bounding oval defining the shape and size of the arc
477 @param startAngle Starting angle (in degrees) where the arc begins
478 @param sweepAngle Sweep angle (in degrees) measured clockwise. This is
479 treated mod 360.
480 @param forceMoveTo If true, always begin a new contour with the arc
481 */
482 void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
483 bool forceMoveTo);
484
485 /** Append a line and arc to the current path. This is the same as the
486 PostScript call "arct".
487 */
488 void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
489 SkScalar radius);
490
491 /** Append a line and arc to the current path. This is the same as the
492 PostScript call "arct".
493 */
494 void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
495 this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
496 }
497
498 /** Close the current contour. If the current point is not equal to the
499 first point of the contour, a line segment is automatically added.
500 */
501 void close();
502
robertphillips@google.com8fd16032013-06-25 15:39:58 +0000503 enum Direction {
504 /** Direction either has not been or could not be computed */
505 kUnknown_Direction,
506 /** clockwise direction for adding closed contours */
507 kCW_Direction,
508 /** counter-clockwise direction for adding closed contours */
509 kCCW_Direction,
510 };
511
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000512 /**
513 * Return the opposite of the specified direction. kUnknown is its own
514 * opposite.
515 */
bsalomon@google.com30c174b2012-11-13 14:36:42 +0000516 static Direction OppositeDirection(Direction dir) {
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000517 static const Direction gOppositeDir[] = {
518 kUnknown_Direction, kCCW_Direction, kCW_Direction
519 };
520 return gOppositeDir[dir];
bsalomon@google.com30c174b2012-11-13 14:36:42 +0000521 }
522
reed@google.com69a99432012-01-10 18:00:10 +0000523 /**
sugoi@google.com12b4e272012-12-06 20:13:11 +0000524 * Returns whether or not a fill type is inverted
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000525 *
526 * kWinding_FillType -> false
527 * kEvenOdd_FillType -> false
528 * kInverseWinding_FillType -> true
529 * kInverseEvenOdd_FillType -> true
sugoi@google.com12b4e272012-12-06 20:13:11 +0000530 */
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000531 static bool IsInverseFillType(FillType fill) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000532 SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch);
533 SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch);
534 SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch);
535 SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch);
536 return (fill & 2) != 0;
537 }
538
539 /**
540 * Returns the equivalent non-inverted fill type to the given fill type
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000541 *
542 * kWinding_FillType -> kWinding_FillType
543 * kEvenOdd_FillType -> kEvenOdd_FillType
544 * kInverseWinding_FillType -> kWinding_FillType
545 * kInverseEvenOdd_FillType -> kEvenOdd_FillType
sugoi@google.com12b4e272012-12-06 20:13:11 +0000546 */
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000547 static FillType ConvertToNonInverseFillType(FillType fill) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000548 SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch);
549 SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch);
550 SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch);
551 SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch);
552 return (FillType)(fill & 1);
553 }
554
555 /**
reed@google.com69a99432012-01-10 18:00:10 +0000556 * Tries to quickly compute the direction of the first non-degenerate
557 * contour. If it can be computed, return true and set dir to that
558 * direction. If it cannot be (quickly) determined, return false and ignore
bsalomon@google.com30c174b2012-11-13 14:36:42 +0000559 * the dir parameter. If the direction was determined, it is cached to make
560 * subsequent calls return quickly.
reed@google.com69a99432012-01-10 18:00:10 +0000561 */
562 bool cheapComputeDirection(Direction* dir) const;
563
564 /**
565 * Returns true if the path's direction can be computed via
566 * cheapComputDirection() and if that computed direction matches the
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000567 * specified direction. If dir is kUnknown, returns true if the direction
568 * cannot be computed.
reed@google.com69a99432012-01-10 18:00:10 +0000569 */
570 bool cheapIsDirection(Direction dir) const {
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000571 Direction computedDir = kUnknown_Direction;
572 (void)this->cheapComputeDirection(&computedDir);
573 return computedDir == dir;
reed@google.com69a99432012-01-10 18:00:10 +0000574 }
575
robertphillips@google.com8fd16032013-06-25 15:39:58 +0000576 /** Returns true if the path specifies a rectangle. If so, and if isClosed is
577 not null, set isClosed to true if the path is closed. Also, if returning true
578 and direction is not null, return the rect direction. If the path does not
579 specify a rectangle, return false and ignore isClosed and direction.
580
581 @param isClosed If not null, set to true if the path is closed
582 @param direction If not null, set to the rectangle's direction
583 @return true if the path specifies a rectangle
584 */
585 bool isRect(bool* isClosed, Direction* direction) const;
586
587 /** Returns true if the path specifies a pair of nested rectangles. If so, and if
588 rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner
589 rectangle. If so, and dirs is not null, set dirs[0] to the direction of
590 the outer rectangle and dirs[1] to the direction of the inner rectangle. If
591 the path does not specify a pair of nested rectangles, return
592 false and ignore rect and dirs.
593
594 @param rect If not null, returns the path as a pair of nested rectangles
595 @param dirs If not null, returns the direction of the rects
596 @return true if the path describes a pair of nested rectangles
597 */
598 bool isNestedRects(SkRect rect[2], Direction dirs[2] = NULL) const;
599
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000600 /**
601 * Add a closed rectangle contour to the path
602 * @param rect The rectangle to add as a closed contour to the path
603 * @param dir The direction to wind the rectangle's contour. Cannot be
604 * kUnknown_Direction.
605 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606 void addRect(const SkRect& rect, Direction dir = kCW_Direction);
607
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000608 /**
609 * Add a closed rectangle contour to the path
610 *
611 * @param left The left side of a rectangle to add as a closed contour
612 * to the path
613 * @param top The top of a rectangle to add as a closed contour to the
614 * path
615 * @param right The right side of a rectangle to add as a closed contour
616 * to the path
617 * @param bottom The bottom of a rectangle to add as a closed contour to
618 * the path
619 * @param dir The direction to wind the rectangle's contour. Cannot be
620 * kUnknown_Direction.
621 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622 void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
623 Direction dir = kCW_Direction);
624
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000625 /**
626 * Add a closed oval contour to the path
627 *
628 * @param oval The bounding oval to add as a closed contour to the path
629 * @param dir The direction to wind the oval's contour. Cannot be
630 * kUnknown_Direction.
631 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632 void addOval(const SkRect& oval, Direction dir = kCW_Direction);
633
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000634 /**
635 * Add a closed circle contour to the path
636 *
637 * @param x The x-coordinate of the center of a circle to add as a
638 * closed contour to the path
639 * @param y The y-coordinate of the center of a circle to add as a
640 * closed contour to the path
641 * @param radius The radius of a circle to add as a closed contour to the
642 * path
643 * @param dir The direction to wind the circle's contour. Cannot be
644 * kUnknown_Direction.
645 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646 void addCircle(SkScalar x, SkScalar y, SkScalar radius,
647 Direction dir = kCW_Direction);
648
649 /** Add the specified arc to the path as a new contour.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000650
reed@android.com8a1c16f2008-12-17 15:59:43 +0000651 @param oval The bounds of oval used to define the size of the arc
652 @param startAngle Starting angle (in degrees) where the arc begins
653 @param sweepAngle Sweep angle (in degrees) measured clockwise
654 */
655 void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
656
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000657 /**
658 * Add a closed round-rectangle contour to the path
659 * @param rect The bounds of a round-rectangle to add as a closed contour
660 * @param rx The x-radius of the rounded corners on the round-rectangle
661 * @param ry The y-radius of the rounded corners on the round-rectangle
662 * @param dir The direction to wind the rectangle's contour. Cannot be
663 * kUnknown_Direction.
664 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665 void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
666 Direction dir = kCW_Direction);
667
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000668 /**
669 * Add a closed round-rectangle contour to the path. Each corner receives
670 * two radius values [X, Y]. The corners are ordered top-left, top-right,
671 * bottom-right, bottom-left.
672 * @param rect The bounds of a round-rectangle to add as a closed contour
673 * @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner
674 * @param dir The direction to wind the rectangle's contour. Cannot be
675 * kUnknown_Direction.
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000676 * Note: The radii here now go through the same constraint handling as the
677 * SkRRect radii (i.e., either radii at a corner being 0 implies a
678 * sqaure corner and oversized radii are proportionally scaled down).
reed@google.coma8a3b3d2012-11-26 18:16:27 +0000679 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680 void addRoundRect(const SkRect& rect, const SkScalar radii[],
681 Direction dir = kCW_Direction);
682
reed@google.com744faba2012-05-29 19:54:52 +0000683 /**
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000684 * Add an SkRRect contour to the path
685 * @param rrect The rounded rect to add as a closed contour
686 * @param dir The winding direction for the new contour. Cannot be
687 * kUnknown_Direction.
reed@google.com4ed0fb72012-12-12 20:48:18 +0000688 */
robertphillips@google.com4e18c7a2012-12-17 21:48:19 +0000689 void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000690
691 /**
reed@google.com744faba2012-05-29 19:54:52 +0000692 * Add a new contour made of just lines. This is just a fast version of
693 * the following:
694 * this->moveTo(pts[0]);
695 * for (int i = 1; i < count; ++i) {
696 * this->lineTo(pts[i]);
697 * }
698 * if (close) {
699 * this->close();
700 * }
701 */
702 void addPoly(const SkPoint pts[], int count, bool close);
703
reed@android.com8a1c16f2008-12-17 15:59:43 +0000704 /** Add a copy of src to the path, offset by (dx,dy)
705 @param src The path to add as a new contour
706 @param dx The amount to translate the path in X as it is added
707 @param dx The amount to translate the path in Y as it is added
708 */
reed@google.com63d73742012-01-10 15:33:12 +0000709 void addPath(const SkPath& src, SkScalar dx, SkScalar dy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000710
711 /** Add a copy of src to the path
712 */
713 void addPath(const SkPath& src) {
714 SkMatrix m;
715 m.reset();
716 this->addPath(src, m);
717 }
718
719 /** Add a copy of src to the path, transformed by matrix
720 @param src The path to add as a new contour
721 */
722 void addPath(const SkPath& src, const SkMatrix& matrix);
723
reed@google.com63d73742012-01-10 15:33:12 +0000724 /**
725 * Same as addPath(), but reverses the src input
726 */
727 void reverseAddPath(const SkPath& src);
728
reed@android.com8a1c16f2008-12-17 15:59:43 +0000729 /** Offset the path by (dx,dy), returning true on success
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000730
731 @param dx The amount in the X direction to offset the entire path
732 @param dy The amount in the Y direction to offset the entire path
reed@android.com8a1c16f2008-12-17 15:59:43 +0000733 @param dst The translated path is written here
734 */
735 void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
736
737 /** Offset the path by (dx,dy), returning true on success
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000738
739 @param dx The amount in the X direction to offset the entire path
740 @param dy The amount in the Y direction to offset the entire path
reed@android.com8a1c16f2008-12-17 15:59:43 +0000741 */
742 void offset(SkScalar dx, SkScalar dy) {
743 this->offset(dx, dy, this);
744 }
745
746 /** Transform the points in this path by matrix, and write the answer into
747 dst.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000748
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749 @param matrix The matrix to apply to the path
750 @param dst The transformed path is written here
751 */
752 void transform(const SkMatrix& matrix, SkPath* dst) const;
753
754 /** Transform the points in this path by matrix
755
756 @param matrix The matrix to apply to the path
757 */
758 void transform(const SkMatrix& matrix) {
759 this->transform(matrix, this);
760 }
761
762 /** Return the last point on the path. If no points have been added, (0,0)
reed@google.com294dd7b2011-10-11 11:58:32 +0000763 is returned. If there are no points, this returns false, otherwise it
764 returns true.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000765
reed@android.com8a1c16f2008-12-17 15:59:43 +0000766 @param lastPt The last point on the path is returned here
767 */
reed@google.com294dd7b2011-10-11 11:58:32 +0000768 bool getLastPt(SkPoint* lastPt) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769
770 /** Set the last point on the path. If no points have been added,
771 moveTo(x,y) is automatically called.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000772
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 @param x The new x-coordinate for the last point
774 @param y The new y-coordinate for the last point
775 */
776 void setLastPt(SkScalar x, SkScalar y);
777
778 /** Set the last point on the path. If no points have been added, moveTo(p)
779 is automatically called.
780
781 @param p The new location for the last point
782 */
783 void setLastPt(const SkPoint& p) {
784 this->setLastPt(p.fX, p.fY);
785 }
786
reed@google.com10296cc2011-09-21 12:29:05 +0000787 enum SegmentMask {
788 kLine_SegmentMask = 1 << 0,
789 kQuad_SegmentMask = 1 << 1,
reed@google.com277c3f82013-05-31 15:17:50 +0000790 kConic_SegmentMask = 1 << 2,
791 kCubic_SegmentMask = 1 << 3,
reed@google.com10296cc2011-09-21 12:29:05 +0000792 };
793
794 /**
795 * Returns a mask, where each bit corresponding to a SegmentMask is
796 * set if the path contains 1 or more segments of that type.
797 * Returns 0 for an empty path (no segments).
798 */
799 uint32_t getSegmentMasks() const { return fSegmentMask; }
800
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801 enum Verb {
802 kMove_Verb, //!< iter.next returns 1 point
803 kLine_Verb, //!< iter.next returns 2 points
804 kQuad_Verb, //!< iter.next returns 3 points
reed@google.com277c3f82013-05-31 15:17:50 +0000805 kConic_Verb, //!< iter.next returns 3 points + iter.conicWeight()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806 kCubic_Verb, //!< iter.next returns 4 points
bsalomon@google.comb3b8dfa2011-07-13 17:44:36 +0000807 kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt)
reed@google.com277c3f82013-05-31 15:17:50 +0000808 kDone_Verb, //!< iter.next returns 0 points
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809 };
810
811 /** Iterate through all of the segments (lines, quadratics, cubics) of
812 each contours in a path.
schenney@chromium.org72785c42011-12-29 21:03:28 +0000813
814 The iterator cleans up the segments along the way, removing degenerate
815 segments and adding close verbs where necessary. When the forceClose
816 argument is provided, each contour (as defined by a new starting
817 move command) will be completed with a close verb regardless of the
818 contour's contents.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819 */
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +0000820 class SK_API Iter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821 public:
schenney@chromium.org72785c42011-12-29 21:03:28 +0000822 Iter();
823 Iter(const SkPath&, bool forceClose);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824
825 void setPath(const SkPath&, bool forceClose);
826
827 /** Return the next verb in this iteration of the path. When all
828 segments have been visited, return kDone_Verb.
schenney@chromium.orgb0af6da2011-12-21 20:43:13 +0000829
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830 @param pts The points representing the current verb and/or segment
reed@google.com4a3b7142012-05-16 17:16:46 +0000831 @param doConsumeDegerates If true, first scan for segments that are
832 deemed degenerate (too short) and skip those.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833 @return The verb for the current segment
834 */
reed@google.com4a3b7142012-05-16 17:16:46 +0000835 Verb next(SkPoint pts[4], bool doConsumeDegerates = true) {
836 if (doConsumeDegerates) {
837 this->consumeDegenerateSegments();
838 }
839 return this->doNext(pts);
840 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841
reed@google.com277c3f82013-05-31 15:17:50 +0000842 /**
843 * Return the weight for the current conic. Only valid if the current
844 * segment return by next() was a conic.
845 */
846 SkScalar conicWeight() const { return *fConicWeights; }
847
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848 /** If next() returns kLine_Verb, then this query returns true if the
849 line was the result of a close() command (i.e. the end point is the
850 initial moveto for this contour). If next() returned a different
851 verb, this returns an undefined value.
schenney@chromium.orgb0af6da2011-12-21 20:43:13 +0000852
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853 @return If the last call to next() returned kLine_Verb, return true
854 if it was the result of an explicit close command.
855 */
856 bool isCloseLine() const { return SkToBool(fCloseLine); }
schenney@chromium.orgb0af6da2011-12-21 20:43:13 +0000857
reed@android.com8a1c16f2008-12-17 15:59:43 +0000858 /** Returns true if the current contour is closed (has a kClose_Verb)
859 @return true if the current contour is closed (has a kClose_Verb)
860 */
861 bool isClosedContour() const;
862
863 private:
864 const SkPoint* fPts;
865 const uint8_t* fVerbs;
866 const uint8_t* fVerbStop;
reed@google.com277c3f82013-05-31 15:17:50 +0000867 const SkScalar* fConicWeights;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868 SkPoint fMoveTo;
869 SkPoint fLastPt;
870 SkBool8 fForceClose;
871 SkBool8 fNeedClose;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872 SkBool8 fCloseLine;
schenney@chromium.orgb0af6da2011-12-21 20:43:13 +0000873 SkBool8 fSegmentState;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874
reed@google.com9e25dbf2012-05-15 17:05:38 +0000875 inline const SkPoint& cons_moveTo();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000876 Verb autoClose(SkPoint pts[2]);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000877 void consumeDegenerateSegments();
reed@google.com4a3b7142012-05-16 17:16:46 +0000878 Verb doNext(SkPoint pts[4]);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000879 };
880
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000881 /** Iterate through the verbs in the path, providing the associated points.
882 */
883 class SK_API RawIter {
884 public:
885 RawIter();
886 RawIter(const SkPath&);
887
888 void setPath(const SkPath&);
889
890 /** Return the next verb in this iteration of the path. When all
891 segments have been visited, return kDone_Verb.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000892
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000893 @param pts The points representing the current verb and/or segment
bsalomon@google.comf6d3c5a2012-06-07 17:47:33 +0000894 This must not be NULL.
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000895 @return The verb for the current segment
896 */
897 Verb next(SkPoint pts[4]);
898
reed@google.com277c3f82013-05-31 15:17:50 +0000899 SkScalar conicWeight() const { return *fConicWeights; }
900
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000901 private:
902 const SkPoint* fPts;
903 const uint8_t* fVerbs;
904 const uint8_t* fVerbStop;
reed@google.com277c3f82013-05-31 15:17:50 +0000905 const SkScalar* fConicWeights;
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000906 SkPoint fMoveTo;
907 SkPoint fLastPt;
908 };
909
mike@reedtribe.orgbad1b2f2012-07-11 01:51:33 +0000910 /**
911 * Returns true if the point { x, y } is contained by the path, taking into
912 * account the FillType.
913 */
914 bool contains(SkScalar x, SkScalar y) const;
915
reed@android.com8a1c16f2008-12-17 15:59:43 +0000916 void dump(bool forceClose, const char title[] = NULL) const;
reed@android.come522ca52009-11-23 20:10:41 +0000917 void dump() const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000918
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000919 /**
920 * Write the region to the buffer, and return the number of bytes written.
921 * If buffer is NULL, it still returns the number of bytes.
922 */
923 uint32_t writeToMemory(void* buffer) const;
924 /**
925 * Initialized the region from the buffer, returning the number
926 * of bytes actually read.
927 */
928 uint32_t readFromMemory(const void* buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929
djsollen@google.com56c69772011-11-08 19:00:26 +0000930#ifdef SK_BUILD_FOR_ANDROID
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000931 uint32_t getGenerationID() const;
djsollen@google.come63793a2012-03-21 15:39:03 +0000932 const SkPath* getSourcePath() const;
933 void setSourcePath(const SkPath* path);
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000934#endif
935
reed@android.com8a1c16f2008-12-17 15:59:43 +0000936 SkDEBUGCODE(void validate() const;)
937
938private:
robertphillips@google.com01ec2eb2012-08-17 10:58:49 +0000939 enum SerializationOffsets {
bsalomon@google.com30c174b2012-11-13 14:36:42 +0000940 kDirection_SerializationShift = 26, // requires 2 bits
941 kIsFinite_SerializationShift = 25, // requires 1 bit
942 kIsOval_SerializationShift = 24, // requires 1 bit
943 kConvexity_SerializationShift = 16, // requires 2 bits
944 kFillType_SerializationShift = 8, // requires 2 bits
reed@google.com277c3f82013-05-31 15:17:50 +0000945 kSegmentMask_SerializationShift = 0 // requires 4 bits
robertphillips@google.com01ec2eb2012-08-17 10:58:49 +0000946 };
947
bsalomon@google.comae09f2d2012-10-03 19:57:01 +0000948#if SK_DEBUG_PATH_REF
949public:
950 /** Debugging wrapper for SkAutoTUnref<SkPathRef> used to track owners (SkPaths)
951 of SkPathRefs */
952 class PathRefDebugRef {
953 public:
954 PathRefDebugRef(SkPath* owner);
955 PathRefDebugRef(SkPathRef* pr, SkPath* owner);
956 ~PathRefDebugRef();
skia.committer@gmail.com7cc7f492012-10-04 02:01:34 +0000957 void reset(SkPathRef* ref);
bsalomon@google.comae09f2d2012-10-03 19:57:01 +0000958 void swap(PathRefDebugRef* other);
959 SkPathRef* get() const;
960 SkAutoTUnref<SkPathRef>::BlockRefType *operator->() const;
961 operator SkPathRef*();
962 private:
963 SkAutoTUnref<SkPathRef> fPathRef;
964 SkPath* fOwner;
965 };
966
967private:
968 PathRefDebugRef fPathRef;
969#else
970 SkAutoTUnref<SkPathRef> fPathRef;
971#endif
972
reed@android.comd252db02009-04-01 18:31:44 +0000973 mutable SkRect fBounds;
reed@google.comd335d1d2012-01-12 18:17:11 +0000974 int fLastMoveToIndex;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000975 uint8_t fFillType;
reed@google.com10296cc2011-09-21 12:29:05 +0000976 uint8_t fSegmentMask;
977 mutable uint8_t fBoundsIsDirty;
reed@google.comb54455e2011-05-16 14:16:04 +0000978 mutable uint8_t fConvexity;
bsalomon@google.com30c174b2012-11-13 14:36:42 +0000979 mutable uint8_t fDirection;
reed@google.com0bb18bb2012-07-26 15:20:36 +0000980 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid
bsalomon@google.com6aa29652012-04-18 13:29:52 +0000981 mutable SkBool8 fIsOval;
djsollen@google.com56c69772011-11-08 19:00:26 +0000982#ifdef SK_BUILD_FOR_ANDROID
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000983 uint32_t fGenerationID;
djsollen@google.come63793a2012-03-21 15:39:03 +0000984 const SkPath* fSourcePath;
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000985#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986
bungeman@google.coma5809a32013-06-21 15:13:34 +0000987 /** Resets all fields other than fPathRef to their initial 'empty' values.
988 * Assumes the caller has already emptied fPathRef.
989 * On Android increments fGenerationID without reseting it.
990 */
991 void resetFields();
992
993 /** Sets all fields other than fPathRef to the values in 'that'.
994 * Assumes the caller has already set fPathRef.
995 * On Android increments fGenerationID without copying it.
996 * On Android sets fSourcePath to NULL.
997 */
998 void copyFields(const SkPath& that);
999
reed@android.comd252db02009-04-01 18:31:44 +00001000 // called, if dirty, by getBounds()
1001 void computeBounds() const;
1002
reed@android.com8a1c16f2008-12-17 15:59:43 +00001003 friend class Iter;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004
1005 friend class SkPathStroker;
1006 /* Append the first contour of path, ignoring path's initial point. If no
1007 moveTo() call has been made for this contour, the first point is
1008 automatically set to (0,0).
1009 */
1010 void pathTo(const SkPath& path);
1011
1012 /* Append, in reverse order, the first contour of path, ignoring path's
1013 last point. If no moveTo() call has been made for this contour, the
1014 first point is automatically set to (0,0).
1015 */
1016 void reversePathTo(const SkPath&);
1017
reed@google.comd335d1d2012-01-12 18:17:11 +00001018 // called before we add points for lineTo, quadTo, cubicTo, checking to see
1019 // if we need to inject a leading moveTo first
1020 //
1021 // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0)
1022 // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo)
1023 //
1024 inline void injectMoveToIfNeeded();
1025
bsalomon@google.com6aa29652012-04-18 13:29:52 +00001026 inline bool hasOnlyMoveTos() const;
1027
bsalomon@google.com30c174b2012-11-13 14:36:42 +00001028 Convexity internalGetConvexity() const;
skia.committer@gmail.com34587162012-11-20 02:01:23 +00001029
caryclark@google.comf68154a2012-11-21 15:18:06 +00001030 bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts,
1031 bool* isClosed, Direction* direction) const;
bsalomon@google.com30c174b2012-11-13 14:36:42 +00001032
reed@android.com8a1c16f2008-12-17 15:59:43 +00001033 friend class SkAutoPathBoundsUpdate;
bsalomon@google.com6aa29652012-04-18 13:29:52 +00001034 friend class SkAutoDisableOvalCheck;
bsalomon@google.com30c174b2012-11-13 14:36:42 +00001035 friend class SkAutoDisableDirectionCheck;
bsalomon@google.com30e6d2c2012-08-13 14:03:31 +00001036 friend class SkBench_AddPathTest; // perf test pathTo/reversePathTo
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037};
1038
1039#endif