1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkPath_DEFINED
9#define SkPath_DEFINED
10
11#include "include/core/SkMatrix.h"
12#include "include/core/SkPathTypes.h"
13#include "include/private/SkPathRef.h"
14#include "include/private/SkTo.h"
15
16#include <initializer_list>
17
18class SkAutoPathBoundsUpdate;
19class SkData;
20class SkRRect;
21class SkWStream;
22
23/** \class SkPath
24 SkPath contain geometry. SkPath may be empty, or contain one or more verbs that
25 outline a figure. SkPath always starts with a move verb to a Cartesian coordinate,
26 and may be followed by additional verbs that add lines or curves.
27 Adding a close verb makes the geometry into a continuous loop, a closed contour.
28 SkPath may contain any number of contours, each beginning with a move verb.
29
30 SkPath contours may contain only a move verb, or may also contain lines,
31 quadratic beziers, conics, and cubic beziers. SkPath contours may be open or
32 closed.
33
34 When used to draw a filled area, SkPath describes whether the fill is inside or
35 outside the geometry. SkPath also describes the winding rule used to fill
36 overlapping contours.
37
38 Internally, SkPath lazily computes metrics likes bounds and convexity. Call
39 SkPath::updateBoundsCache to make SkPath thread safe.
40*/
41class SK_API SkPath {
42public:
43
44 /** Constructs an empty SkPath. By default, SkPath has no verbs, no SkPoint, and no weights.
45 FillType is set to kWinding.
46
47 @return empty SkPath
48
49 example: https://fiddle.skia.org/c/@Path_empty_constructor
50 */
51 SkPath();
52
53 /** Constructs a copy of an existing path.
54 Copy constructor makes two paths identical by value. Internally, path and
55 the returned result share pointer values. The underlying verb array, SkPoint array
56 and weights are copied when modified.
57
58 Creating a SkPath copy is very efficient and never allocates memory.
59 SkPath are always copied by value from the interface; the underlying shared
60 pointers are not exposed.
61
62 @param path SkPath to copy by value
63 @return copy of SkPath
64
65 example: https://fiddle.skia.org/c/@Path_copy_const_SkPath
66 */
67 SkPath(const SkPath& path);
68
69 /** Releases ownership of any shared data and deletes data if SkPath is sole owner.
70
71 example: https://fiddle.skia.org/c/@Path_destructor
72 */
73 ~SkPath();
74
75 /** Constructs a copy of an existing path.
76 SkPath assignment makes two paths identical by value. Internally, assignment
77 shares pointer values. The underlying verb array, SkPoint array and weights
78 are copied when modified.
79
80 Copying SkPath by assignment is very efficient and never allocates memory.
81 SkPath are always copied by value from the interface; the underlying shared
82 pointers are not exposed.
83
84 @param path verb array, SkPoint array, weights, and SkPath::FillType to copy
85 @return SkPath copied by value
86
87 example: https://fiddle.skia.org/c/@Path_copy_operator
88 */
89 SkPath& operator=(const SkPath& path);
90
91 /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint array, and weights
92 are equivalent.
93
94 @param a SkPath to compare
95 @param b SkPath to compare
96 @return true if SkPath pair are equivalent
97 */
98 friend SK_API bool operator==(const SkPath& a, const SkPath& b);
99
100 /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint array, and weights
101 are not equivalent.
102
103 @param a SkPath to compare
104 @param b SkPath to compare
105 @return true if SkPath pair are not equivalent
106 */
107 friend bool operator!=(const SkPath& a, const SkPath& b) {
108 return !(a == b);
109 }
110
111 /** Returns true if SkPath contain equal verbs and equal weights.
112 If SkPath contain one or more conics, the weights must match.
113
114 conicTo() may add different verbs depending on conic weight, so it is not
115 trivial to interpolate a pair of SkPath containing conics with different
116 conic weight values.
117
118 @param compare SkPath to compare
119 @return true if SkPath verb array and weights are equivalent
120
121 example: https://fiddle.skia.org/c/@Path_isInterpolatable
122 */
123 bool isInterpolatable(const SkPath& compare) const;
124
125 /** Interpolates between SkPath with SkPoint array of equal size.
126 Copy verb array and weights to out, and set out SkPoint array to a weighted
127 average of this SkPoint array and ending SkPoint array, using the formula:
128 (Path Point * weight) + ending Point * (1 - weight).
129
130 weight is most useful when between zero (ending SkPoint array) and
131 one (this Point_Array); will work with values outside of this
132 range.
133
134 interpolate() returns false and leaves out unchanged if SkPoint array is not
135 the same size as ending SkPoint array. Call isInterpolatable() to check SkPath
136 compatibility prior to calling interpolate().
137
138 @param ending SkPoint array averaged with this SkPoint array
139 @param weight contribution of this SkPoint array, and
140 one minus contribution of ending SkPoint array
141 @param out SkPath replaced by interpolated averages
142 @return true if SkPath contain same number of SkPoint
143
144 example: https://fiddle.skia.org/c/@Path_interpolate
145 */
146 bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const;
147
148 /** Returns SkPathFillType, the rule used to fill SkPath.
149
150 @return current SkPathFillType setting
151 */
152 SkPathFillType getFillType() const { return (SkPathFillType)fFillType; }
153
154 /** Sets FillType, the rule used to fill SkPath. While there is no check
155 that ft is legal, values outside of FillType are not supported.
156 */
157 void setFillType(SkPathFillType ft) {
158 fFillType = SkToU8(ft);
159 }
160
161 /** Returns if FillType describes area outside SkPath geometry. The inverse fill area
162 extends indefinitely.
163
164 @return true if FillType is kInverseWinding or kInverseEvenOdd
165 */
166 bool isInverseFillType() const { return SkPathFillType_IsInverse(this->getFillType()); }
167
168 /** Replaces FillType with its inverse. The inverse of FillType describes the area
169 unmodified by the original FillType.
170 */
171 void toggleInverseFillType() {
172 fFillType ^= 2;
173 }
174
175 /** Returns the comvexity type, computing if needed. Never returns kUnknown.
176 @return path's convexity type (convex or concave)
177 */
178 SkPathConvexityType getConvexityType() const {
179 SkPathConvexityType convexity = this->getConvexityTypeOrUnknown();
180 if (convexity != SkPathConvexityType::kUnknown) {
181 return convexity;
182 }
183 return this->internalGetConvexity();
184 }
185
186 /** If the path's convexity is already known, return it, else return kUnknown.
187 * If you always want to know the convexity, even if that means having to compute it,
188 * call getConvexitytype().
189 *
190 * @return known convexity, or kUnknown
191 */
192 SkPathConvexityType getConvexityTypeOrUnknown() const {
193 return (SkPathConvexityType)fConvexity.load(std::memory_order_relaxed);
194 }
195
196 /** Stores a convexity type for this path. This is what will be returned if
197 * getConvexityTypeOrUnknown() is called. If you pass kUnknown, then if getContexityType()
198 * is called, the real convexity will be computed.
199 *
200 * example: https://fiddle.skia.org/c/@Path_setConvexity
201 */
202 void setConvexityType(SkPathConvexityType convexity);
203
204 /** Returns true if the path is convex. If necessary, it will first compute the convexity.
205 */
206 bool isConvex() const {
207 return SkPathConvexityType::kConvex == this->getConvexityType();
208 }
209
210 /** Returns true if this path is recognized as an oval or circle.
211
212 bounds receives bounds of oval.
213
214 bounds is unmodified if oval is not found.
215
216 @param bounds storage for bounding SkRect of oval; may be nullptr
217 @return true if SkPath is recognized as an oval or circle
218
219 example: https://fiddle.skia.org/c/@Path_isOval
220 */
221 bool isOval(SkRect* bounds) const;
222
223 /** Returns true if path is representable as SkRRect.
224 Returns false if path is representable as oval, circle, or SkRect.
225
226 rrect receives bounds of SkRRect.
227
228 rrect is unmodified if SkRRect is not found.
229
230 @param rrect storage for bounding SkRect of SkRRect; may be nullptr
231 @return true if SkPath contains only SkRRect
232
233 example: https://fiddle.skia.org/c/@Path_isRRect
234 */
235 bool isRRect(SkRRect* rrect) const;
236
237 /** Sets SkPath to its initial state.
238 Removes verb array, SkPoint array, and weights, and sets FillType to kWinding.
239 Internal storage associated with SkPath is released.
240
241 @return reference to SkPath
242
243 example: https://fiddle.skia.org/c/@Path_reset
244 */
245 SkPath& reset();
246
247 /** Sets SkPath to its initial state, preserving internal storage.
248 Removes verb array, SkPoint array, and weights, and sets FillType to kWinding.
249 Internal storage associated with SkPath is retained.
250
251 Use rewind() instead of reset() if SkPath storage will be reused and performance
252 is critical.
253
254 @return reference to SkPath
255
256 example: https://fiddle.skia.org/c/@Path_rewind
257 */
258 SkPath& rewind();
259
260 /** Returns if SkPath is empty.
261 Empty SkPath may have FillType but has no SkPoint, SkPath::Verb, or conic weight.
262 SkPath() constructs empty SkPath; reset() and rewind() make SkPath empty.
263
264 @return true if the path contains no SkPath::Verb array
265 */
266 bool isEmpty() const {
267 SkDEBUGCODE(this->validate();)
268 return 0 == fPathRef->countVerbs();
269 }
270
271 /** Returns if contour is closed.
272 Contour is closed if SkPath SkPath::Verb array was last modified by close(). When stroked,
273 closed contour draws SkPaint::Join instead of SkPaint::Cap at first and last SkPoint.
274
275 @return true if the last contour ends with a kClose_Verb
276
277 example: https://fiddle.skia.org/c/@Path_isLastContourClosed
278 */
279 bool isLastContourClosed() const;
280
281 /** Returns true for finite SkPoint array values between negative SK_ScalarMax and
282 positive SK_ScalarMax. Returns false for any SkPoint array value of
283 SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN.
284
285 @return true if all SkPoint values are finite
286 */
287 bool isFinite() const {
288 SkDEBUGCODE(this->validate();)
289 return fPathRef->isFinite();
290 }
291
292 /** Returns true if the path is volatile; it will not be altered or discarded
293 by the caller after it is drawn. SkPath by default have volatile set false, allowing
294 SkSurface to attach a cache of data which speeds repeated drawing. If true, SkSurface
295 may not speed repeated drawing.
296
297 @return true if caller will alter SkPath after drawing
298 */
299 bool isVolatile() const {
300 return SkToBool(fIsVolatile);
301 }
302
303 /** Specifies whether SkPath is volatile; whether it will be altered or discarded
304 by the caller after it is drawn. SkPath by default have volatile set false, allowing
305 SkBaseDevice to attach a cache of data which speeds repeated drawing.
306
307 Mark temporary paths, discarded or modified after use, as volatile
308 to inform SkBaseDevice that the path need not be cached.
309
310 Mark animating SkPath volatile to improve performance.
311 Mark unchanging SkPath non-volatile to improve repeated rendering.
312
313 raster surface SkPath draws are affected by volatile for some shadows.
314 GPU surface SkPath draws are affected by volatile for some shadows and concave geometries.
315
316 @param isVolatile true if caller will alter SkPath after drawing
317 */
318 void setIsVolatile(bool isVolatile) {
319 fIsVolatile = isVolatile;
320 }
321
322 /** Tests if line between SkPoint pair is degenerate.
323 Line with no length or that moves a very short distance is degenerate; it is
324 treated as a point.
325
326 exact changes the equality test. If true, returns true only if p1 equals p2.
327 If false, returns true if p1 equals or nearly equals p2.
328
329 @param p1 line start point
330 @param p2 line end point
331 @param exact if false, allow nearly equals
332 @return true if line is degenerate; its length is effectively zero
333
334 example: https://fiddle.skia.org/c/@Path_IsLineDegenerate
335 */
336 static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact);
337
338 /** Tests if quad is degenerate.
339 Quad with no length or that moves a very short distance is degenerate; it is
340 treated as a point.
341
342 @param p1 quad start point
343 @param p2 quad control point
344 @param p3 quad end point
345 @param exact if true, returns true only if p1, p2, and p3 are equal;
346 if false, returns true if p1, p2, and p3 are equal or nearly equal
347 @return true if quad is degenerate; its length is effectively zero
348 */
349 static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
350 const SkPoint& p3, bool exact);
351
352 /** Tests if cubic is degenerate.
353 Cubic with no length or that moves a very short distance is degenerate; it is
354 treated as a point.
355
356 @param p1 cubic start point
357 @param p2 cubic control point 1
358 @param p3 cubic control point 2
359 @param p4 cubic end point
360 @param exact if true, returns true only if p1, p2, p3, and p4 are equal;
361 if false, returns true if p1, p2, p3, and p4 are equal or nearly equal
362 @return true if cubic is degenerate; its length is effectively zero
363 */
364 static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
365 const SkPoint& p3, const SkPoint& p4, bool exact);
366
367 /** Returns true if SkPath contains only one line;
368 SkPath::Verb array has two entries: kMove_Verb, kLine_Verb.
369 If SkPath contains one line and line is not nullptr, line is set to
370 line start point and line end point.
371 Returns false if SkPath is not one line; line is unaltered.
372
373 @param line storage for line. May be nullptr
374 @return true if SkPath contains exactly one line
375
376 example: https://fiddle.skia.org/c/@Path_isLine
377 */
378 bool isLine(SkPoint line[2]) const;
379
380 /** Returns the number of points in SkPath.
381 SkPoint count is initially zero.
382
383 @return SkPath SkPoint array length
384
385 example: https://fiddle.skia.org/c/@Path_countPoints
386 */
387 int countPoints() const;
388
389 /** Returns SkPoint at index in SkPoint array. Valid range for index is
390 0 to countPoints() - 1.
391 Returns (0, 0) if index is out of range.
392
393 @param index SkPoint array element selector
394 @return SkPoint array value or (0, 0)
395
396 example: https://fiddle.skia.org/c/@Path_getPoint
397 */
398 SkPoint getPoint(int index) const;
399
400 /** Returns number of points in SkPath. Up to max points are copied.
401 points may be nullptr; then, max must be zero.
402 If max is greater than number of points, excess points storage is unaltered.
403
404 @param points storage for SkPath SkPoint array. May be nullptr
405 @param max maximum to copy; must be greater than or equal to zero
406 @return SkPath SkPoint array length
407
408 example: https://fiddle.skia.org/c/@Path_getPoints
409 */
410 int getPoints(SkPoint points[], int max) const;
411
412 /** Returns the number of verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
413 kCubic_Verb, and kClose_Verb; added to SkPath.
414
415 @return length of verb array
416
417 example: https://fiddle.skia.org/c/@Path_countVerbs
418 */
419 int countVerbs() const;
420
421 /** Returns the number of verbs in the path. Up to max verbs are copied. The
422 verbs are copied as one byte per verb.
423
424 @param verbs storage for verbs, may be nullptr
425 @param max maximum number to copy into verbs
426 @return the actual number of verbs in the path
427
428 example: https://fiddle.skia.org/c/@Path_getVerbs
429 */
430 int getVerbs(uint8_t verbs[], int max) const;
431
432 /** Returns the approximate byte size of the SkPath in memory.
433
434 @return approximate size
435 */
436 size_t approximateBytesUsed() const;
437
438 /** Exchanges the verb array, SkPoint array, weights, and SkPath::FillType with other.
439 Cached state is also exchanged. swap() internally exchanges pointers, so
440 it is lightweight and does not allocate memory.
441
442 swap() usage has largely been replaced by operator=(const SkPath& path).
443 SkPath do not copy their content on assignment until they are written to,
444 making assignment as efficient as swap().
445
446 @param other SkPath exchanged by value
447
448 example: https://fiddle.skia.org/c/@Path_swap
449 */
450 void swap(SkPath& other);
451
452 /** Returns minimum and maximum axes values of SkPoint array.
453 Returns (0, 0, 0, 0) if SkPath contains no points. Returned bounds width and height may
454 be larger or smaller than area affected when SkPath is drawn.
455
456 SkRect returned includes all SkPoint added to SkPath, including SkPoint associated with
457 kMove_Verb that define empty contours.
458
459 @return bounds of all SkPoint in SkPoint array
460 */
461 const SkRect& getBounds() const {
462 return fPathRef->getBounds();
463 }
464
465 /** Updates internal bounds so that subsequent calls to getBounds() are instantaneous.
466 Unaltered copies of SkPath may also access cached bounds through getBounds().
467
468 For now, identical to calling getBounds() and ignoring the returned value.
469
470 Call to prepare SkPath subsequently drawn from multiple threads,
471 to avoid a race condition where each draw separately computes the bounds.
472 */
473 void updateBoundsCache() const {
474 // for now, just calling getBounds() is sufficient
475 this->getBounds();
476 }
477
478 /** Returns minimum and maximum axes values of the lines and curves in SkPath.
479 Returns (0, 0, 0, 0) if SkPath contains no points.
480 Returned bounds width and height may be larger or smaller than area affected
481 when SkPath is drawn.
482
483 Includes SkPoint associated with kMove_Verb that define empty
484 contours.
485
486 Behaves identically to getBounds() when SkPath contains
487 only lines. If SkPath contains curves, computed bounds includes
488 the maximum extent of the quad, conic, or cubic; is slower than getBounds();
489 and unlike getBounds(), does not cache the result.
490
491 @return tight bounds of curves in SkPath
492
493 example: https://fiddle.skia.org/c/@Path_computeTightBounds
494 */
495 SkRect computeTightBounds() const;
496
497 /** Returns true if rect is contained by SkPath.
498 May return false when rect is contained by SkPath.
499
500 For now, only returns true if SkPath has one contour and is convex.
501 rect may share points and edges with SkPath and be contained.
502 Returns true if rect is empty, that is, it has zero width or height; and
503 the SkPoint or line described by rect is contained by SkPath.
504
505 @param rect SkRect, line, or SkPoint checked for containment
506 @return true if rect is contained
507
508 example: https://fiddle.skia.org/c/@Path_conservativelyContainsRect
509 */
510 bool conservativelyContainsRect(const SkRect& rect) const;
511
512 /** Grows SkPath verb array and SkPoint array to contain extraPtCount additional SkPoint.
513 May improve performance and use less memory by
514 reducing the number and size of allocations when creating SkPath.
515
516 @param extraPtCount number of additional SkPoint to allocate
517
518 example: https://fiddle.skia.org/c/@Path_incReserve
519 */
520 void incReserve(int extraPtCount);
521
522 /** Shrinks SkPath verb array and SkPoint array storage to discard unused capacity.
523 May reduce the heap overhead for SkPath known to be fully constructed.
524 */
525 void shrinkToFit();
526
527 /** Adds beginning of contour at SkPoint (x, y).
528
529 @param x x-axis value of contour start
530 @param y y-axis value of contour start
531 @return reference to SkPath
532
533 example: https://fiddle.skia.org/c/@Path_moveTo
534 */
535 SkPath& moveTo(SkScalar x, SkScalar y);
536
537 /** Adds beginning of contour at SkPoint p.
538
539 @param p contour start
540 @return reference to SkPath
541 */
542 SkPath& moveTo(const SkPoint& p) {
543 return this->moveTo(p.fX, p.fY);
544 }
545
546 /** Adds beginning of contour relative to last point.
547 If SkPath is empty, starts contour at (dx, dy).
548 Otherwise, start contour at last point offset by (dx, dy).
549 Function name stands for "relative move to".
550
551 @param dx offset from last point to contour start on x-axis
552 @param dy offset from last point to contour start on y-axis
553 @return reference to SkPath
554
555 example: https://fiddle.skia.org/c/@Path_rMoveTo
556 */
557 SkPath& rMoveTo(SkScalar dx, SkScalar dy);
558
559 /** Adds line from last point to (x, y). If SkPath is empty, or last SkPath::Verb is
560 kClose_Verb, last point is set to (0, 0) before adding line.
561
562 lineTo() appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
563 lineTo() then appends kLine_Verb to verb array and (x, y) to SkPoint array.
564
565 @param x end of added line on x-axis
566 @param y end of added line on y-axis
567 @return reference to SkPath
568
569 example: https://fiddle.skia.org/c/@Path_lineTo
570 */
571 SkPath& lineTo(SkScalar x, SkScalar y);
572
573 /** Adds line from last point to SkPoint p. If SkPath is empty, or last SkPath::Verb is
574 kClose_Verb, last point is set to (0, 0) before adding line.
575
576 lineTo() first appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
577 lineTo() then appends kLine_Verb to verb array and SkPoint p to SkPoint array.
578
579 @param p end SkPoint of added line
580 @return reference to SkPath
581 */
582 SkPath& lineTo(const SkPoint& p) {
583 return this->lineTo(p.fX, p.fY);
584 }
585
586 /** Adds line from last point to vector (dx, dy). If SkPath is empty, or last SkPath::Verb is
587 kClose_Verb, last point is set to (0, 0) before adding line.
588
589 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
590 then appends kLine_Verb to verb array and line end to SkPoint array.
591 Line end is last point plus vector (dx, dy).
592 Function name stands for "relative line to".
593
594 @param dx offset from last point to line end on x-axis
595 @param dy offset from last point to line end on y-axis
596 @return reference to SkPath
597
598 example: https://fiddle.skia.org/c/@Path_rLineTo
599 example: https://fiddle.skia.org/c/@Quad_a
600 example: https://fiddle.skia.org/c/@Quad_b
601 */
602 SkPath& rLineTo(SkScalar dx, SkScalar dy);
603
604 /** Adds quad from last point towards (x1, y1), to (x2, y2).
605 If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
606 before adding quad.
607
608 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
609 then appends kQuad_Verb to verb array; and (x1, y1), (x2, y2)
610 to SkPoint array.
611
612 @param x1 control SkPoint of quad on x-axis
613 @param y1 control SkPoint of quad on y-axis
614 @param x2 end SkPoint of quad on x-axis
615 @param y2 end SkPoint of quad on y-axis
616 @return reference to SkPath
617
618 example: https://fiddle.skia.org/c/@Path_quadTo
619 */
620 SkPath& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
621
622 /** Adds quad from last point towards SkPoint p1, to SkPoint p2.
623 If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
624 before adding quad.
625
626 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
627 then appends kQuad_Verb to verb array; and SkPoint p1, p2
628 to SkPoint array.
629
630 @param p1 control SkPoint of added quad
631 @param p2 end SkPoint of added quad
632 @return reference to SkPath
633 */
634 SkPath& quadTo(const SkPoint& p1, const SkPoint& p2) {
635 return this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
636 }
637
638 /** Adds quad from last point towards vector (dx1, dy1), to vector (dx2, dy2).
639 If SkPath is empty, or last SkPath::Verb
640 is kClose_Verb, last point is set to (0, 0) before adding quad.
641
642 Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
643 if needed; then appends kQuad_Verb to verb array; and appends quad
644 control and quad end to SkPoint array.
645 Quad control is last point plus vector (dx1, dy1).
646 Quad end is last point plus vector (dx2, dy2).
647 Function name stands for "relative quad to".
648
649 @param dx1 offset from last point to quad control on x-axis
650 @param dy1 offset from last point to quad control on y-axis
651 @param dx2 offset from last point to quad end on x-axis
652 @param dy2 offset from last point to quad end on y-axis
653 @return reference to SkPath
654
655 example: https://fiddle.skia.org/c/@Conic_Weight_a
656 example: https://fiddle.skia.org/c/@Conic_Weight_b
657 example: https://fiddle.skia.org/c/@Conic_Weight_c
658 example: https://fiddle.skia.org/c/@Path_rQuadTo
659 */
660 SkPath& rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
661
662 /** Adds conic from last point towards (x1, y1), to (x2, y2), weighted by w.
663 If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
664 before adding conic.
665
666 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
667
668 If w is finite and not one, appends kConic_Verb to verb array;
669 and (x1, y1), (x2, y2) to SkPoint array; and w to conic weights.
670
671 If w is one, appends kQuad_Verb to verb array, and
672 (x1, y1), (x2, y2) to SkPoint array.
673
674 If w is not finite, appends kLine_Verb twice to verb array, and
675 (x1, y1), (x2, y2) to SkPoint array.
676
677 @param x1 control SkPoint of conic on x-axis
678 @param y1 control SkPoint of conic on y-axis
679 @param x2 end SkPoint of conic on x-axis
680 @param y2 end SkPoint of conic on y-axis
681 @param w weight of added conic
682 @return reference to SkPath
683 */
684 SkPath& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
685 SkScalar w);
686
687 /** Adds conic from last point towards SkPoint p1, to SkPoint p2, weighted by w.
688 If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
689 before adding conic.
690
691 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
692
693 If w is finite and not one, appends kConic_Verb to verb array;
694 and SkPoint p1, p2 to SkPoint array; and w to conic weights.
695
696 If w is one, appends kQuad_Verb to verb array, and SkPoint p1, p2
697 to SkPoint array.
698
699 If w is not finite, appends kLine_Verb twice to verb array, and
700 SkPoint p1, p2 to SkPoint array.
701
702 @param p1 control SkPoint of added conic
703 @param p2 end SkPoint of added conic
704 @param w weight of added conic
705 @return reference to SkPath
706 */
707 SkPath& conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) {
708 return this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w);
709 }
710
711 /** Adds conic from last point towards vector (dx1, dy1), to vector (dx2, dy2),
712 weighted by w. If SkPath is empty, or last SkPath::Verb
713 is kClose_Verb, last point is set to (0, 0) before adding conic.
714
715 Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
716 if needed.
717
718 If w is finite and not one, next appends kConic_Verb to verb array,
719 and w is recorded as conic weight; otherwise, if w is one, appends
720 kQuad_Verb to verb array; or if w is not finite, appends kLine_Verb
721 twice to verb array.
722
723 In all cases appends SkPoint control and end to SkPoint array.
724 control is last point plus vector (dx1, dy1).
725 end is last point plus vector (dx2, dy2).
726
727 Function name stands for "relative conic to".
728
729 @param dx1 offset from last point to conic control on x-axis
730 @param dy1 offset from last point to conic control on y-axis
731 @param dx2 offset from last point to conic end on x-axis
732 @param dy2 offset from last point to conic end on y-axis
733 @param w weight of added conic
734 @return reference to SkPath
735 */
736 SkPath& rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
737 SkScalar w);
738
739 /** Adds cubic from last point towards (x1, y1), then towards (x2, y2), ending at
740 (x3, y3). If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to
741 (0, 0) before adding cubic.
742
743 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
744 then appends kCubic_Verb to verb array; and (x1, y1), (x2, y2), (x3, y3)
745 to SkPoint array.
746
747 @param x1 first control SkPoint of cubic on x-axis
748 @param y1 first control SkPoint of cubic on y-axis
749 @param x2 second control SkPoint of cubic on x-axis
750 @param y2 second control SkPoint of cubic on y-axis
751 @param x3 end SkPoint of cubic on x-axis
752 @param y3 end SkPoint of cubic on y-axis
753 @return reference to SkPath
754 */
755 SkPath& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
756 SkScalar x3, SkScalar y3);
757
758 /** Adds cubic from last point towards SkPoint p1, then towards SkPoint p2, ending at
759 SkPoint p3. If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to
760 (0, 0) before adding cubic.
761
762 Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
763 then appends kCubic_Verb to verb array; and SkPoint p1, p2, p3
764 to SkPoint array.
765
766 @param p1 first control SkPoint of cubic
767 @param p2 second control SkPoint of cubic
768 @param p3 end SkPoint of cubic
769 @return reference to SkPath
770 */
771 SkPath& cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
772 return this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
773 }
774
775 /** Adds cubic from last point towards vector (dx1, dy1), then towards
776 vector (dx2, dy2), to vector (dx3, dy3).
777 If SkPath is empty, or last SkPath::Verb
778 is kClose_Verb, last point is set to (0, 0) before adding cubic.
779
780 Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
781 if needed; then appends kCubic_Verb to verb array; and appends cubic
782 control and cubic end to SkPoint array.
783 Cubic control is last point plus vector (dx1, dy1).
784 Cubic end is last point plus vector (dx2, dy2).
785 Function name stands for "relative cubic to".
786
787 @param dx1 offset from last point to first cubic control on x-axis
788 @param dy1 offset from last point to first cubic control on y-axis
789 @param dx2 offset from last point to second cubic control on x-axis
790 @param dy2 offset from last point to second cubic control on y-axis
791 @param dx3 offset from last point to cubic end on x-axis
792 @param dy3 offset from last point to cubic end on y-axis
793 @return reference to SkPath
794 */
795 SkPath& rCubicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
796 SkScalar dx3, SkScalar dy3);
797
798 /** Appends arc to SkPath. Arc added is part of ellipse
799 bounded by oval, from startAngle through sweepAngle. Both startAngle and
800 sweepAngle are measured in degrees, where zero degrees is aligned with the
801 positive x-axis, and positive sweeps extends arc clockwise.
802
803 arcTo() adds line connecting SkPath last SkPoint to initial arc SkPoint if forceMoveTo
804 is false and SkPath is not empty. Otherwise, added contour begins with first point
805 of arc. Angles greater than -360 and less than 360 are treated modulo 360.
806
807 @param oval bounds of ellipse containing arc
808 @param startAngle starting angle of arc in degrees
809 @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360
810 @param forceMoveTo true to start a new contour with arc
811 @return reference to SkPath
812
813 example: https://fiddle.skia.org/c/@Path_arcTo
814 */
815 SkPath& arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo);
816
817 /** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic
818 weighted to describe part of circle. Arc is contained by tangent from
819 last SkPath point to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
820 is part of circle sized to radius, positioned so it touches both tangent lines.
821
822 If last Path Point does not start Arc, arcTo appends connecting Line to Path.
823 The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
824
825 Arc sweep is always less than 180 degrees. If radius is zero, or if
826 tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
827
828 arcTo appends at most one Line and one conic.
829 arcTo implements the functionality of PostScript arct and HTML Canvas arcTo.
830
831 @param x1 x-axis value common to pair of tangents
832 @param y1 y-axis value common to pair of tangents
833 @param x2 x-axis value end of second tangent
834 @param y2 y-axis value end of second tangent
835 @param radius distance from arc to circle center
836 @return reference to SkPath
837
838 example: https://fiddle.skia.org/c/@Path_arcTo_2_a
839 example: https://fiddle.skia.org/c/@Path_arcTo_2_b
840 example: https://fiddle.skia.org/c/@Path_arcTo_2_c
841 */
842 SkPath& arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius);
843
844 /** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic
845 weighted to describe part of circle. Arc is contained by tangent from
846 last SkPath point to p1, and tangent from p1 to p2. Arc
847 is part of circle sized to radius, positioned so it touches both tangent lines.
848
849 If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath.
850 The length of vector from p1 to p2 does not affect arc.
851
852 Arc sweep is always less than 180 degrees. If radius is zero, or if
853 tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1.
854
855 arcTo() appends at most one line and one conic.
856 arcTo() implements the functionality of PostScript arct and HTML Canvas arcTo.
857
858 @param p1 SkPoint common to pair of tangents
859 @param p2 end of second tangent
860 @param radius distance from arc to circle center
861 @return reference to SkPath
862 */
863 SkPath& arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
864 return this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
865 }
866
867 /** \enum SkPath::ArcSize
868 Four oval parts with radii (rx, ry) start at last SkPath SkPoint and ends at (x, y).
869 ArcSize and Direction select one of the four oval parts.
870 */
871 enum ArcSize {
872 kSmall_ArcSize, //!< smaller of arc pair
873 kLarge_ArcSize, //!< larger of arc pair
874 };
875
876 /** Appends arc to SkPath. Arc is implemented by one or more conics weighted to
877 describe part of oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
878 curves from last SkPath SkPoint to (x, y), choosing one of four possible routes:
879 clockwise or counterclockwise, and smaller or larger.
880
881 Arc sweep is always less than 360 degrees. arcTo() appends line to (x, y) if
882 either radii are zero, or if last SkPath SkPoint equals (x, y). arcTo() scales radii
883 (rx, ry) to fit last SkPath SkPoint and (x, y) if both are greater than zero but
884 too small.
885
886 arcTo() appends up to four conic curves.
887 arcTo() implements the functionality of SVG arc, although SVG sweep-flag value
888 is opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise,
889 while kCW_Direction cast to int is zero.
890
891 @param rx radius on x-axis before x-axis rotation
892 @param ry radius on y-axis before x-axis rotation
893 @param xAxisRotate x-axis rotation in degrees; positive values are clockwise
894 @param largeArc chooses smaller or larger arc
895 @param sweep chooses clockwise or counterclockwise arc
896 @param x end of arc
897 @param y end of arc
898 @return reference to SkPath
899 */
900 SkPath& arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
901 SkPathDirection sweep, SkScalar x, SkScalar y);
902
903 /** Appends arc to SkPath. Arc is implemented by one or more conic weighted to describe
904 part of oval with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves
905 from last SkPath SkPoint to (xy.fX, xy.fY), choosing one of four possible routes:
906 clockwise or counterclockwise,
907 and smaller or larger.
908
909 Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either
910 radii are zero, or if last SkPath SkPoint equals (xy.fX, xy.fY). arcTo() scales radii r to
911 fit last SkPath SkPoint and xy if both are greater than zero but too small to describe
912 an arc.
913
914 arcTo() appends up to four conic curves.
915 arcTo() implements the functionality of SVG arc, although SVG sweep-flag value is
916 opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise, while
917 kCW_Direction cast to int is zero.
918
919 @param r radii on axes before x-axis rotation
920 @param xAxisRotate x-axis rotation in degrees; positive values are clockwise
921 @param largeArc chooses smaller or larger arc
922 @param sweep chooses clockwise or counterclockwise arc
923 @param xy end of arc
924 @return reference to SkPath
925 */
926 SkPath& arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, SkPathDirection sweep,
927 const SkPoint xy) {
928 return this->arcTo(r.fX, r.fY, xAxisRotate, largeArc, sweep, xy.fX, xy.fY);
929 }
930
931 /** Appends arc to SkPath, relative to last SkPath SkPoint. Arc is implemented by one or
932 more conic, weighted to describe part of oval with radii (rx, ry) rotated by
933 xAxisRotate degrees. Arc curves from last SkPath SkPoint to relative end SkPoint:
934 (dx, dy), choosing one of four possible routes: clockwise or
935 counterclockwise, and smaller or larger. If SkPath is empty, the start arc SkPoint
936 is (0, 0).
937
938 Arc sweep is always less than 360 degrees. arcTo() appends line to end SkPoint
939 if either radii are zero, or if last SkPath SkPoint equals end SkPoint.
940 arcTo() scales radii (rx, ry) to fit last SkPath SkPoint and end SkPoint if both are
941 greater than zero but too small to describe an arc.
942
943 arcTo() appends up to four conic curves.
944 arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value is
945 opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
946 kCW_Direction cast to int is zero.
947
948 @param rx radius before x-axis rotation
949 @param ry radius before x-axis rotation
950 @param xAxisRotate x-axis rotation in degrees; positive values are clockwise
951 @param largeArc chooses smaller or larger arc
952 @param sweep chooses clockwise or counterclockwise arc
953 @param dx x-axis offset end of arc from last SkPath SkPoint
954 @param dy y-axis offset end of arc from last SkPath SkPoint
955 @return reference to SkPath
956 */
957 SkPath& rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
958 SkPathDirection sweep, SkScalar dx, SkScalar dy);
959
960 /** Appends kClose_Verb to SkPath. A closed contour connects the first and last SkPoint
961 with line, forming a continuous loop. Open and closed contour draw the same
962 with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open contour draws
963 SkPaint::Cap at contour start and end; closed contour draws
964 SkPaint::Join at contour start and end.
965
966 close() has no effect if SkPath is empty or last SkPath SkPath::Verb is kClose_Verb.
967
968 @return reference to SkPath
969
970 example: https://fiddle.skia.org/c/@Path_close
971 */
972 SkPath& close();
973
974 /** Approximates conic with quad array. Conic is constructed from start SkPoint p0,
975 control SkPoint p1, end SkPoint p2, and weight w.
976 Quad array is stored in pts; this storage is supplied by caller.
977 Maximum quad count is 2 to the pow2.
978 Every third point in array shares last SkPoint of previous quad and first SkPoint of
979 next quad. Maximum pts storage size is given by:
980 (1 + 2 * (1 << pow2)) * sizeof(SkPoint).
981
982 Returns quad count used the approximation, which may be smaller
983 than the number requested.
984
985 conic weight determines the amount of influence conic control point has on the curve.
986 w less than one represents an elliptical section. w greater than one represents
987 a hyperbolic section. w equal to one represents a parabolic section.
988
989 Two quad curves are sufficient to approximate an elliptical conic with a sweep
990 of up to 90 degrees; in this case, set pow2 to one.
991
992 @param p0 conic start SkPoint
993 @param p1 conic control SkPoint
994 @param p2 conic end SkPoint
995 @param w conic weight
996 @param pts storage for quad array
997 @param pow2 quad count, as power of two, normally 0 to 5 (1 to 32 quad curves)
998 @return number of quad curves written to pts
999 */
1000 static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
1001 SkScalar w, SkPoint pts[], int pow2);
1002
1003 /** Returns true if SkPath is equivalent to SkRect when filled.
1004 If false: rect, isClosed, and direction are unchanged.
1005 If true: rect, isClosed, and direction are written to if not nullptr.
1006
1007 rect may be smaller than the SkPath bounds. SkPath bounds may include kMove_Verb points
1008 that do not alter the area drawn by the returned rect.
1009
1010 @param rect storage for bounds of SkRect; may be nullptr
1011 @param isClosed storage set to true if SkPath is closed; may be nullptr
1012 @param direction storage set to SkRect direction; may be nullptr
1013 @return true if SkPath contains SkRect
1014
1015 example: https://fiddle.skia.org/c/@Path_isRect
1016 */
1017 bool isRect(SkRect* rect, bool* isClosed = nullptr, SkPathDirection* direction = nullptr) const;
1018
1019 /** Adds SkRect to SkPath, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
1020 starting with top-left corner of SkRect; followed by top-right, bottom-right,
1021 and bottom-left if dir is kCW_Direction; or followed by bottom-left,
1022 bottom-right, and top-right if dir is kCCW_Direction.
1023
1024 @param rect SkRect to add as a closed contour
1025 @param dir SkPath::Direction to wind added contour
1026 @return reference to SkPath
1027
1028 example: https://fiddle.skia.org/c/@Path_addRect
1029 */
1030 SkPath& addRect(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW);
1031
1032 /** Adds SkRect to SkPath, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
1033 If dir is kCW_Direction, SkRect corners are added clockwise; if dir is
1034 kCCW_Direction, SkRect corners are added counterclockwise.
1035 start determines the first corner added.
1036
1037 @param rect SkRect to add as a closed contour
1038 @param dir SkPath::Direction to wind added contour
1039 @param start initial corner of SkRect to add
1040 @return reference to SkPath
1041
1042 example: https://fiddle.skia.org/c/@Path_addRect_2
1043 */
1044 SkPath& addRect(const SkRect& rect, SkPathDirection dir, unsigned start);
1045
1046 /** Adds SkRect (left, top, right, bottom) to SkPath,
1047 appending kMove_Verb, three kLine_Verb, and kClose_Verb,
1048 starting with top-left corner of SkRect; followed by top-right, bottom-right,
1049 and bottom-left if dir is kCW_Direction; or followed by bottom-left,
1050 bottom-right, and top-right if dir is kCCW_Direction.
1051
1052 @param left smaller x-axis value of SkRect
1053 @param top smaller y-axis value of SkRect
1054 @param right larger x-axis value of SkRect
1055 @param bottom larger y-axis value of SkRect
1056 @param dir SkPath::Direction to wind added contour
1057 @return reference to SkPath
1058 */
1059 SkPath& addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
1060 SkPathDirection dir = SkPathDirection::kCW);
1061
1062 /** Adds oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
1063 Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width
1064 and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
1065 clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
1066
1067 @param oval bounds of ellipse added
1068 @param dir SkPath::Direction to wind ellipse
1069 @return reference to SkPath
1070
1071 example: https://fiddle.skia.org/c/@Path_addOval
1072 */
1073 SkPath& addOval(const SkRect& oval, SkPathDirection dir = SkPathDirection::kCW);
1074
1075 /** Adds oval to SkPath, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
1076 Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width
1077 and half oval height. Oval begins at start and continues
1078 clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
1079
1080 @param oval bounds of ellipse added
1081 @param dir SkPath::Direction to wind ellipse
1082 @param start index of initial point of ellipse
1083 @return reference to SkPath
1084
1085 example: https://fiddle.skia.org/c/@Path_addOval_2
1086 */
1087 SkPath& addOval(const SkRect& oval, SkPathDirection dir, unsigned start);
1088
1089 /** Adds circle centered at (x, y) of size radius to SkPath, appending kMove_Verb,
1090 four kConic_Verb, and kClose_Verb. Circle begins at: (x + radius, y), continuing
1091 clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
1092
1093 Has no effect if radius is zero or negative.
1094
1095 @param x center of circle
1096 @param y center of circle
1097 @param radius distance from center to edge
1098 @param dir SkPath::Direction to wind circle
1099 @return reference to SkPath
1100 */
1101 SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius,
1102 SkPathDirection dir = SkPathDirection::kCW);
1103
1104 /** Appends arc to SkPath, as the start of new contour. Arc added is part of ellipse
1105 bounded by oval, from startAngle through sweepAngle. Both startAngle and
1106 sweepAngle are measured in degrees, where zero degrees is aligned with the
1107 positive x-axis, and positive sweeps extends arc clockwise.
1108
1109 If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
1110 zero, append oval instead of arc. Otherwise, sweepAngle values are treated
1111 modulo 360, and arc may or may not draw depending on numeric rounding.
1112
1113 @param oval bounds of ellipse containing arc
1114 @param startAngle starting angle of arc in degrees
1115 @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360
1116 @return reference to SkPath
1117
1118 example: https://fiddle.skia.org/c/@Path_addArc
1119 */
1120 SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
1121
1122 /** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds
1123 equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
1124 dir is kCW_Direction, SkRRect starts at top-left of the lower-left corner and
1125 winds clockwise. If dir is kCCW_Direction, SkRRect starts at the bottom-left
1126 of the upper-left corner and winds counterclockwise.
1127
1128 If either rx or ry is too large, rx and ry are scaled uniformly until the
1129 corners fit. If rx or ry is less than or equal to zero, addRoundRect() appends
1130 SkRect rect to SkPath.
1131
1132 After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect.
1133
1134 @param rect bounds of SkRRect
1135 @param rx x-axis radius of rounded corners on the SkRRect
1136 @param ry y-axis radius of rounded corners on the SkRRect
1137 @param dir SkPath::Direction to wind SkRRect
1138 @return reference to SkPath
1139 */
1140 SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
1141 SkPathDirection dir = SkPathDirection::kCW);
1142
1143 /** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds
1144 equal to rect; each corner is 90 degrees of an ellipse with radii from the
1145 array.
1146
1147 @param rect bounds of SkRRect
1148 @param radii array of 8 SkScalar values, a radius pair for each corner
1149 @param dir SkPath::Direction to wind SkRRect
1150 @return reference to SkPath
1151 */
1152 SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[],
1153 SkPathDirection dir = SkPathDirection::kCW);
1154
1155 /** Adds rrect to SkPath, creating a new closed contour. If
1156 dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
1157 winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
1158 of the upper-left corner and winds counterclockwise.
1159
1160 After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect.
1161
1162 @param rrect bounds and radii of rounded rectangle
1163 @param dir SkPath::Direction to wind SkRRect
1164 @return reference to SkPath
1165
1166 example: https://fiddle.skia.org/c/@Path_addRRect
1167 */
1168 SkPath& addRRect(const SkRRect& rrect, SkPathDirection dir = SkPathDirection::kCW);
1169
1170 /** Adds rrect to SkPath, creating a new closed contour. If dir is kCW_Direction, rrect
1171 winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
1172 start determines the first point of rrect to add.
1173
1174 @param rrect bounds and radii of rounded rectangle
1175 @param dir SkPath::Direction to wind SkRRect
1176 @param start index of initial point of SkRRect
1177 @return reference to SkPath
1178
1179 example: https://fiddle.skia.org/c/@Path_addRRect_2
1180 */
1181 SkPath& addRRect(const SkRRect& rrect, SkPathDirection dir, unsigned start);
1182
1183 /** Adds contour created from line array, adding (count - 1) line segments.
1184 Contour added starts at pts[0], then adds a line for every additional SkPoint
1185 in pts array. If close is true, appends kClose_Verb to SkPath, connecting
1186 pts[count - 1] and pts[0].
1187
1188 If count is zero, append kMove_Verb to path.
1189 Has no effect if count is less than one.
1190
1191 @param pts array of line sharing end and start SkPoint
1192 @param count length of SkPoint array
1193 @param close true to add line connecting contour end and start
1194 @return reference to SkPath
1195
1196 example: https://fiddle.skia.org/c/@Path_addPoly
1197 */
1198 SkPath& addPoly(const SkPoint pts[], int count, bool close);
1199
1200 /** Adds contour created from list. Contour added starts at list[0], then adds a line
1201 for every additional SkPoint in list. If close is true, appends kClose_Verb to SkPath,
1202 connecting last and first SkPoint in list.
1203
1204 If list is empty, append kMove_Verb to path.
1205
1206 @param list array of SkPoint
1207 @param close true to add line connecting contour end and start
1208 @return reference to SkPath
1209 */
1210 SkPath& addPoly(const std::initializer_list<SkPoint>& list, bool close) {
1211 return this->addPoly(list.begin(), SkToInt(list.size()), close);
1212 }
1213
1214 /** \enum SkPath::AddPathMode
1215 AddPathMode chooses how addPath() appends. Adding one SkPath to another can extend
1216 the last contour or start a new contour.
1217 */
1218 enum AddPathMode {
1219 kAppend_AddPathMode, //!< appended to destination unaltered
1220 kExtend_AddPathMode, //!< add line if prior contour is not closed
1221 };
1222
1223 /** Appends src to SkPath, offset by (dx, dy).
1224
1225 If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
1226 added unaltered. If mode is kExtend_AddPathMode, add line before appending
1227 verbs, SkPoint, and conic weights.
1228
1229 @param src SkPath verbs, SkPoint, and conic weights to add
1230 @param dx offset added to src SkPoint array x-axis coordinates
1231 @param dy offset added to src SkPoint array y-axis coordinates
1232 @param mode kAppend_AddPathMode or kExtend_AddPathMode
1233 @return reference to SkPath
1234 */
1235 SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy,
1236 AddPathMode mode = kAppend_AddPathMode);
1237
1238 /** Appends src to SkPath.
1239
1240 If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
1241 added unaltered. If mode is kExtend_AddPathMode, add line before appending
1242 verbs, SkPoint, and conic weights.
1243
1244 @param src SkPath verbs, SkPoint, and conic weights to add
1245 @param mode kAppend_AddPathMode or kExtend_AddPathMode
1246 @return reference to SkPath
1247 */
1248 SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) {
1249 SkMatrix m;
1250 m.reset();
1251 return this->addPath(src, m, mode);
1252 }
1253
1254 /** Appends src to SkPath, transformed by matrix. Transformed curves may have different
1255 verbs, SkPoint, and conic weights.
1256
1257 If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
1258 added unaltered. If mode is kExtend_AddPathMode, add line before appending
1259 verbs, SkPoint, and conic weights.
1260
1261 @param src SkPath verbs, SkPoint, and conic weights to add
1262 @param matrix transform applied to src
1263 @param mode kAppend_AddPathMode or kExtend_AddPathMode
1264 @return reference to SkPath
1265 */
1266 SkPath& addPath(const SkPath& src, const SkMatrix& matrix,
1267 AddPathMode mode = kAppend_AddPathMode);
1268
1269 /** Appends src to SkPath, from back to front.
1270 Reversed src always appends a new contour to SkPath.
1271
1272 @param src SkPath verbs, SkPoint, and conic weights to add
1273 @return reference to SkPath
1274
1275 example: https://fiddle.skia.org/c/@Path_reverseAddPath
1276 */
1277 SkPath& reverseAddPath(const SkPath& src);
1278
1279 /** Offsets SkPoint array by (dx, dy). Offset SkPath replaces dst.
1280 If dst is nullptr, SkPath is replaced by offset data.
1281
1282 @param dx offset added to SkPoint array x-axis coordinates
1283 @param dy offset added to SkPoint array y-axis coordinates
1284 @param dst overwritten, translated copy of SkPath; may be nullptr
1285
1286 example: https://fiddle.skia.org/c/@Path_offset
1287 */
1288 void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
1289
1290 /** Offsets SkPoint array by (dx, dy). SkPath is replaced by offset data.
1291
1292 @param dx offset added to SkPoint array x-axis coordinates
1293 @param dy offset added to SkPoint array y-axis coordinates
1294 */
1295 void offset(SkScalar dx, SkScalar dy) {
1296 this->offset(dx, dy, this);
1297 }
1298
1299 /** Transforms verb array, SkPoint array, and weight by matrix.
1300 transform may change verbs and increase their number.
1301 Transformed SkPath replaces dst; if dst is nullptr, original data
1302 is replaced.
1303
1304 @param matrix SkMatrix to apply to SkPath
1305 @param dst overwritten, transformed copy of SkPath; may be nullptr
1306 @param pc whether to apply perspective clipping
1307
1308 example: https://fiddle.skia.org/c/@Path_transform
1309 */
1310 void transform(const SkMatrix& matrix, SkPath* dst,
1311 SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const;
1312
1313 /** Transforms verb array, SkPoint array, and weight by matrix.
1314 transform may change verbs and increase their number.
1315 SkPath is replaced by transformed data.
1316
1317 @param matrix SkMatrix to apply to SkPath
1318 @param pc whether to apply perspective clipping
1319 */
1320 void transform(const SkMatrix& matrix,
1321 SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) {
1322 this->transform(matrix, this, pc);
1323 }
1324
1325 /** Returns last point on SkPath in lastPt. Returns false if SkPoint array is empty,
1326 storing (0, 0) if lastPt is not nullptr.
1327
1328 @param lastPt storage for final SkPoint in SkPoint array; may be nullptr
1329 @return true if SkPoint array contains one or more SkPoint
1330
1331 example: https://fiddle.skia.org/c/@Path_getLastPt
1332 */
1333 bool getLastPt(SkPoint* lastPt) const;
1334
1335 /** Sets last point to (x, y). If SkPoint array is empty, append kMove_Verb to
1336 verb array and append (x, y) to SkPoint array.
1337
1338 @param x set x-axis value of last point
1339 @param y set y-axis value of last point
1340
1341 example: https://fiddle.skia.org/c/@Path_setLastPt
1342 */
1343 void setLastPt(SkScalar x, SkScalar y);
1344
1345 /** Sets the last point on the path. If SkPoint array is empty, append kMove_Verb to
1346 verb array and append p to SkPoint array.
1347
1348 @param p set value of last point
1349 */
1350 void setLastPt(const SkPoint& p) {
1351 this->setLastPt(p.fX, p.fY);
1352 }
1353
1354 /** \enum SkPath::SegmentMask
1355 SegmentMask constants correspond to each drawing Verb type in SkPath; for
1356 instance, if SkPath only contains lines, only the kLine_SegmentMask bit is set.
1357 */
1358 enum SegmentMask {
1359 kLine_SegmentMask = kLine_SkPathSegmentMask,
1360 kQuad_SegmentMask = kQuad_SkPathSegmentMask,
1361 kConic_SegmentMask = kConic_SkPathSegmentMask,
1362 kCubic_SegmentMask = kCubic_SkPathSegmentMask,
1363 };
1364
1365 /** Returns a mask, where each set bit corresponds to a SegmentMask constant
1366 if SkPath contains one or more verbs of that type.
1367 Returns zero if SkPath contains no lines, or curves: quads, conics, or cubics.
1368
1369 getSegmentMasks() returns a cached result; it is very fast.
1370
1371 @return SegmentMask bits or zero
1372 */
1373 uint32_t getSegmentMasks() const { return fPathRef->getSegmentMasks(); }
1374
1375 /** \enum SkPath::Verb
1376 Verb instructs SkPath how to interpret one or more SkPoint and optional conic weight;
1377 manage contour, and terminate SkPath.
1378 */
1379 enum Verb {
1380 kMove_Verb = static_cast<int>(SkPathVerb::kMove),
1381 kLine_Verb = static_cast<int>(SkPathVerb::kLine),
1382 kQuad_Verb = static_cast<int>(SkPathVerb::kQuad),
1383 kConic_Verb = static_cast<int>(SkPathVerb::kConic),
1384 kCubic_Verb = static_cast<int>(SkPathVerb::kCubic),
1385 kClose_Verb = static_cast<int>(SkPathVerb::kClose),
1386 kDone_Verb = static_cast<int>(SkPathVerb::kDone),
1387 };
1388
1389 /** \class SkPath::Iter
1390 Iterates through verb array, and associated SkPoint array and conic weight.
1391 Provides options to treat open contours as closed, and to ignore
1392 degenerate data.
1393 */
1394 class SK_API Iter {
1395 public:
1396
1397 /** Initializes SkPath::Iter with an empty SkPath. next() on SkPath::Iter returns
1398 kDone_Verb.
1399 Call setPath to initialize SkPath::Iter at a later time.
1400
1401 @return SkPath::Iter of empty SkPath
1402
1403 example: https://fiddle.skia.org/c/@Path_Iter_Iter
1404 */
1405 Iter();
1406
1407 /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in
1408 path. If forceClose is true, SkPath::Iter will add kLine_Verb and kClose_Verb after each
1409 open contour. path is not altered.
1410
1411 @param path SkPath to iterate
1412 @param forceClose true if open contours generate kClose_Verb
1413 @return SkPath::Iter of path
1414
1415 example: https://fiddle.skia.org/c/@Path_Iter_const_SkPath
1416 */
1417 Iter(const SkPath& path, bool forceClose);
1418
1419 /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in
1420 path. If forceClose is true, SkPath::Iter will add kLine_Verb and kClose_Verb after each
1421 open contour. path is not altered.
1422
1423 @param path SkPath to iterate
1424 @param forceClose true if open contours generate kClose_Verb
1425
1426 example: https://fiddle.skia.org/c/@Path_Iter_setPath
1427 */
1428 void setPath(const SkPath& path, bool forceClose);
1429
1430 /** Returns next SkPath::Verb in verb array, and advances SkPath::Iter.
1431 When verb array is exhausted, returns kDone_Verb.
1432
1433 Zero to four SkPoint are stored in pts, depending on the returned SkPath::Verb.
1434
1435 @param pts storage for SkPoint data describing returned SkPath::Verb
1436 @return next SkPath::Verb from verb array
1437
1438 example: https://fiddle.skia.org/c/@Path_RawIter_next
1439 */
1440 Verb next(SkPoint pts[4]);
1441
1442 /** Returns conic weight if next() returned kConic_Verb.
1443
1444 If next() has not been called, or next() did not return kConic_Verb,
1445 result is undefined.
1446
1447 @return conic weight for conic SkPoint returned by next()
1448 */
1449 SkScalar conicWeight() const { return *fConicWeights; }
1450
1451 /** Returns true if last kLine_Verb returned by next() was generated
1452 by kClose_Verb. When true, the end point returned by next() is
1453 also the start point of contour.
1454
1455 If next() has not been called, or next() did not return kLine_Verb,
1456 result is undefined.
1457
1458 @return true if last kLine_Verb was generated by kClose_Verb
1459 */
1460 bool isCloseLine() const { return SkToBool(fCloseLine); }
1461
1462 /** Returns true if subsequent calls to next() return kClose_Verb before returning
1463 kMove_Verb. if true, contour SkPath::Iter is processing may end with kClose_Verb, or
1464 SkPath::Iter may have been initialized with force close set to true.
1465
1466 @return true if contour is closed
1467
1468 example: https://fiddle.skia.org/c/@Path_Iter_isClosedContour
1469 */
1470 bool isClosedContour() const;
1471
1472 private:
1473 const SkPoint* fPts;
1474 const uint8_t* fVerbs;
1475 const uint8_t* fVerbStop;
1476 const SkScalar* fConicWeights;
1477 SkPoint fMoveTo;
1478 SkPoint fLastPt;
1479 bool fForceClose;
1480 bool fNeedClose;
1481 bool fCloseLine;
1482 enum SegmentState : uint8_t {
1483 /** The current contour is empty. Starting processing or have just closed a contour. */
1484 kEmptyContour_SegmentState,
1485 /** Have seen a move, but nothing else. */
1486 kAfterMove_SegmentState,
1487 /** Have seen a primitive but not yet closed the path. Also the initial state. */
1488 kAfterPrimitive_SegmentState
1489 };
1490 SegmentState fSegmentState;
1491
1492 inline const SkPoint& cons_moveTo();
1493 Verb autoClose(SkPoint pts[2]);
1494 };
1495
1496 /** \class SkPath::RawIter
1497 Iterates through verb array, and associated SkPoint array and conic weight.
1498 verb array, SkPoint array, and conic weight are returned unaltered.
1499 */
1500 class SK_API RawIter {
1501 public:
1502
1503 /** Initializes RawIter with an empty SkPath. next() on RawIter returns kDone_Verb.
1504 Call setPath to initialize SkPath::Iter at a later time.
1505
1506 @return RawIter of empty SkPath
1507 */
1508 RawIter() {}
1509
1510 /** Sets RawIter to return elements of verb array, SkPoint array, and conic weight in path.
1511
1512 @param path SkPath to iterate
1513 @return RawIter of path
1514 */
1515 RawIter(const SkPath& path) {
1516 setPath(path);
1517 }
1518
1519 /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in
1520 path.
1521
1522 @param path SkPath to iterate
1523 */
1524 void setPath(const SkPath& path) {
1525 fRawIter.setPathRef(*path.fPathRef.get());
1526 }
1527
1528 /** Returns next SkPath::Verb in verb array, and advances RawIter.
1529 When verb array is exhausted, returns kDone_Verb.
1530 Zero to four SkPoint are stored in pts, depending on the returned SkPath::Verb.
1531
1532 @param pts storage for SkPoint data describing returned SkPath::Verb
1533 @return next SkPath::Verb from verb array
1534 */
1535 Verb next(SkPoint pts[4]) {
1536 return (Verb) fRawIter.next(pts);
1537 }
1538
1539 /** Returns next SkPath::Verb, but does not advance RawIter.
1540
1541 @return next SkPath::Verb from verb array
1542 */
1543 Verb peek() const {
1544 return (Verb) fRawIter.peek();
1545 }
1546
1547 /** Returns conic weight if next() returned kConic_Verb.
1548
1549 If next() has not been called, or next() did not return kConic_Verb,
1550 result is undefined.
1551
1552 @return conic weight for conic SkPoint returned by next()
1553 */
1554 SkScalar conicWeight() const {
1555 return fRawIter.conicWeight();
1556 }
1557
1558 private:
1559 SkPathRef::Iter fRawIter;
1560 friend class SkPath;
1561
1562 };
1563
1564 /** Returns true if the point (x, y) is contained by SkPath, taking into
1565 account FillType.
1566
1567 @param x x-axis value of containment test
1568 @param y y-axis value of containment test
1569 @return true if SkPoint is in SkPath
1570
1571 example: https://fiddle.skia.org/c/@Path_contains
1572 */
1573 bool contains(SkScalar x, SkScalar y) const;
1574
1575 /** Writes text representation of SkPath to stream. If stream is nullptr, writes to
1576 standard output. Set forceClose to true to get edges used to fill SkPath.
1577 Set dumpAsHex true to generate exact binary representations
1578 of floating point numbers used in SkPoint array and conic weights.
1579
1580 @param stream writable SkWStream receiving SkPath text representation; may be nullptr
1581 @param forceClose true if missing kClose_Verb is output
1582 @param dumpAsHex true if SkScalar values are written as hexadecimal
1583
1584 example: https://fiddle.skia.org/c/@Path_dump
1585 */
1586 void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const;
1587
1588 /** Writes text representation of SkPath to standard output. The representation may be
1589 directly compiled as C++ code. Floating point values are written
1590 with limited precision; it may not be possible to reconstruct original SkPath
1591 from output.
1592
1593 example: https://fiddle.skia.org/c/@Path_dump_2
1594 */
1595 void dump() const;
1596
1597 /** Writes text representation of SkPath to standard output. The representation may be
1598 directly compiled as C++ code. Floating point values are written
1599 in hexadecimal to preserve their exact bit pattern. The output reconstructs the
1600 original SkPath.
1601
1602 Use instead of dump() when submitting
1603
1604 example: https://fiddle.skia.org/c/@Path_dumpHex
1605 */
1606 void dumpHex() const;
1607
1608 /** Writes SkPath to buffer, returning the number of bytes written.
1609 Pass nullptr to obtain the storage size.
1610
1611 Writes SkPath::FillType, verb array, SkPoint array, conic weight, and
1612 additionally writes computed information like SkPath::Convexity and bounds.
1613
1614 Use only be used in concert with readFromMemory();
1615 the format used for SkPath in memory is not guaranteed.
1616
1617 @param buffer storage for SkPath; may be nullptr
1618 @return size of storage required for SkPath; always a multiple of 4
1619
1620 example: https://fiddle.skia.org/c/@Path_writeToMemory
1621 */
1622 size_t writeToMemory(void* buffer) const;
1623
1624 /** Writes SkPath to buffer, returning the buffer written to, wrapped in SkData.
1625
1626 serialize() writes SkPath::FillType, verb array, SkPoint array, conic weight, and
1627 additionally writes computed information like SkPath::Convexity and bounds.
1628
1629 serialize() should only be used in concert with readFromMemory().
1630 The format used for SkPath in memory is not guaranteed.
1631
1632 @return SkPath data wrapped in SkData buffer
1633
1634 example: https://fiddle.skia.org/c/@Path_serialize
1635 */
1636 sk_sp<SkData> serialize() const;
1637
1638 /** Initializes SkPath from buffer of size length. Returns zero if the buffer is
1639 data is inconsistent, or the length is too small.
1640
1641 Reads SkPath::FillType, verb array, SkPoint array, conic weight, and
1642 additionally reads computed information like SkPath::Convexity and bounds.
1643
1644 Used only in concert with writeToMemory();
1645 the format used for SkPath in memory is not guaranteed.
1646
1647 @param buffer storage for SkPath
1648 @param length buffer size in bytes; must be multiple of 4
1649 @return number of bytes read, or zero on failure
1650
1651 example: https://fiddle.skia.org/c/@Path_readFromMemory
1652 */
1653 size_t readFromMemory(const void* buffer, size_t length);
1654
1655 /** (See Skia bug 1762.)
1656 Returns a non-zero, globally unique value. A different value is returned
1657 if verb array, SkPoint array, or conic weight changes.
1658
1659 Setting SkPath::FillType does not change generation identifier.
1660
1661 Each time the path is modified, a different generation identifier will be returned.
1662 SkPath::FillType does affect generation identifier on Android framework.
1663
1664 @return non-zero, globally unique value
1665
1666 example: https://fiddle.skia.org/c/@Path_getGenerationID
1667 */
1668 uint32_t getGenerationID() const;
1669
1670 /** Returns if SkPath data is consistent. Corrupt SkPath data is detected if
1671 internal values are out of range or internal storage does not match
1672 array dimensions.
1673
1674 @return true if SkPath data is consistent
1675 */
1676 bool isValid() const { return this->isValidImpl() && fPathRef->isValid(); }
1677
1678private:
1679 sk_sp<SkPathRef> fPathRef;
1680 int fLastMoveToIndex;
1681 mutable std::atomic<uint8_t> fConvexity; // SkPathConvexityType
1682 mutable std::atomic<uint8_t> fFirstDirection; // really an SkPathPriv::FirstDirection
1683 uint8_t fFillType : 2;
1684 uint8_t fIsVolatile : 1;
1685
1686 /** Resets all fields other than fPathRef to their initial 'empty' values.
1687 * Assumes the caller has already emptied fPathRef.
1688 * On Android increments fGenerationID without reseting it.
1689 */
1690 void resetFields();
1691
1692 /** Sets all fields other than fPathRef to the values in 'that'.
1693 * Assumes the caller has already set fPathRef.
1694 * Doesn't change fGenerationID or fSourcePath on Android.
1695 */
1696 void copyFields(const SkPath& that);
1697
1698 size_t writeToMemoryAsRRect(void* buffer) const;
1699 size_t readAsRRect(const void*, size_t);
1700 size_t readFromMemory_EQ4Or5(const void*, size_t);
1701
1702 friend class Iter;
1703 friend class SkPathPriv;
1704 friend class SkPathStroker;
1705
1706 /* Append, in reverse order, the first contour of path, ignoring path's
1707 last point. If no moveTo() call has been made for this contour, the
1708 first point is automatically set to (0,0).
1709 */
1710 SkPath& reversePathTo(const SkPath&);
1711
1712 // called before we add points for lineTo, quadTo, cubicTo, checking to see
1713 // if we need to inject a leading moveTo first
1714 //
1715 // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0)
1716 // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo)
1717 //
1718 inline void injectMoveToIfNeeded();
1719
1720 inline bool hasOnlyMoveTos() const;
1721
1722 SkPathConvexityType internalGetConvexity() const;
1723
1724 /** Asserts if SkPath data is inconsistent.
1725 Debugging check intended for internal use only.
1726 */
1727 SkDEBUGCODE(void validate() const { SkASSERT(this->isValidImpl()); } )
1728 bool isValidImpl() const;
1729 SkDEBUGCODE(void validateRef() const { fPathRef->validate(); } )
1730
1731 // called by stroker to see if all points (in the last contour) are equal and worthy of a cap
1732 bool isZeroLengthSincePoint(int startPtIndex) const;
1733
1734 /** Returns if the path can return a bound at no cost (true) or will have to
1735 perform some computation (false).
1736 */
1737 bool hasComputedBounds() const {
1738 SkDEBUGCODE(this->validate();)
1739 return fPathRef->hasComputedBounds();
1740 }
1741
1742
1743 // 'rect' needs to be sorted
1744 void setBounds(const SkRect& rect) {
1745 SkPathRef::Editor ed(&fPathRef);
1746
1747 ed.setBounds(rect);
1748 }
1749
1750 void setPt(int index, SkScalar x, SkScalar y);
1751
1752 SkPath& dirtyAfterEdit();
1753
1754 // Bottlenecks for working with fConvexity and fFirstDirection.
1755 // Notice the setters are const... these are mutable atomic fields.
1756 void setConvexityType(SkPathConvexityType) const;
1757 void setFirstDirection(uint8_t) const;
1758 uint8_t getFirstDirection() const;
1759
1760 friend class SkAutoPathBoundsUpdate;
1761 friend class SkAutoDisableOvalCheck;
1762 friend class SkAutoDisableDirectionCheck;
1763 friend class SkPathEdgeIter;
1764 friend class SkPathWriter;
1765 friend class SkOpBuilder;
1766 friend class SkBench_AddPathTest; // perf test reversePathTo
1767 friend class PathTest_Private; // unit test reversePathTo
1768 friend class ForceIsRRect_Private; // unit test isRRect
1769 friend class FuzzPath; // for legacy access to validateRef
1770};
1771
1772#endif
1773