Coverage Report

Created: 2024-05-20 07:14

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