Coverage Report

Created: 2024-09-14 07:19

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