Coverage Report

Created: 2021-08-22 09:07

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