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