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

source code of flutter_engine/third_party/skia/include/core/SkPath.h