Coverage Report

Created: 2024-05-20 07:14

/src/skia/include/core/SkPathBuilder.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2015 Google Inc.
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 SkPathBuilder_DEFINED
9
#define SkPathBuilder_DEFINED
10
11
#include "include/core/SkPath.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/SkPathRef.h"
19
#include "include/private/base/SkTo.h"
20
21
#include <initializer_list>
22
23
class SkRRect;
24
25
class SK_API SkPathBuilder {
26
public:
27
    SkPathBuilder();
28
    SkPathBuilder(SkPathFillType);
29
    SkPathBuilder(const SkPath&);
30
    SkPathBuilder(const SkPathBuilder&) = default;
31
    ~SkPathBuilder();
32
33
    SkPathBuilder& operator=(const SkPath&);
34
    SkPathBuilder& operator=(const SkPathBuilder&) = default;
35
36
0
    SkPathFillType fillType() const { return fFillType; }
37
    SkRect computeBounds() const;
38
39
    SkPath snapshot() const;  // the builder is unchanged after returning this path
40
    SkPath detach();    // the builder is reset to empty after returning this path
41
42
61.8k
    SkPathBuilder& setFillType(SkPathFillType ft) { fFillType = ft; return *this; }
43
695
    SkPathBuilder& setIsVolatile(bool isVolatile) { fIsVolatile = isVolatile; return *this; }
44
45
    SkPathBuilder& reset();
46
47
    SkPathBuilder& moveTo(SkPoint pt);
48
126k
    SkPathBuilder& moveTo(SkScalar x, SkScalar y) { return this->moveTo(SkPoint::Make(x, y)); }
49
50
    SkPathBuilder& lineTo(SkPoint pt);
51
121k
    SkPathBuilder& lineTo(SkScalar x, SkScalar y) { return this->lineTo(SkPoint::Make(x, y)); }
52
53
    SkPathBuilder& quadTo(SkPoint pt1, SkPoint pt2);
54
281k
    SkPathBuilder& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
55
281k
        return this->quadTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2));
56
281k
    }
57
0
    SkPathBuilder& quadTo(const SkPoint pts[2]) { return this->quadTo(pts[0], pts[1]); }
58
59
    SkPathBuilder& conicTo(SkPoint pt1, SkPoint pt2, SkScalar w);
60
0
    SkPathBuilder& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) {
61
0
        return this->conicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), w);
62
0
    }
63
0
    SkPathBuilder& conicTo(const SkPoint pts[2], SkScalar w) {
64
0
        return this->conicTo(pts[0], pts[1], w);
65
0
    }
66
67
    SkPathBuilder& cubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3);
68
11.9k
    SkPathBuilder& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) {
69
11.9k
        return this->cubicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), SkPoint::Make(x3, y3));
70
11.9k
    }
71
0
    SkPathBuilder& cubicTo(const SkPoint pts[3]) {
72
0
        return this->cubicTo(pts[0], pts[1], pts[2]);
73
0
    }
74
75
    SkPathBuilder& close();
76
77
    // Append a series of lineTo(...)
78
    SkPathBuilder& polylineTo(const SkPoint pts[], int count);
79
0
    SkPathBuilder& polylineTo(const std::initializer_list<SkPoint>& list) {
80
0
        return this->polylineTo(list.begin(), SkToInt(list.size()));
81
0
    }
82
83
    // Relative versions of segments, relative to the previous position.
84
85
    SkPathBuilder& rLineTo(SkPoint pt);
86
0
    SkPathBuilder& rLineTo(SkScalar x, SkScalar y) { return this->rLineTo({x, y}); }
87
    SkPathBuilder& rQuadTo(SkPoint pt1, SkPoint pt2);
88
0
    SkPathBuilder& rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
89
0
        return this->rQuadTo({x1, y1}, {x2, y2});
90
0
    }
91
    SkPathBuilder& rConicTo(SkPoint p1, SkPoint p2, SkScalar w);
92
0
    SkPathBuilder& rConicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) {
93
0
        return this->rConicTo({x1, y1}, {x2, y2}, w);
94
0
    }
95
    SkPathBuilder& rCubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3);
96
0
    SkPathBuilder& rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) {
97
0
        return this->rCubicTo({x1, y1}, {x2, y2}, {x3, y3});
98
0
    }
99
100
    // Arcs
101
102
    /** Appends arc to the builder. Arc added is part of ellipse
103
        bounded by oval, from startAngle through sweepAngle. Both startAngle and
104
        sweepAngle are measured in degrees, where zero degrees is aligned with the
105
        positive x-axis, and positive sweeps extends arc clockwise.
106
107
        arcTo() adds line connecting the builder's last point to initial arc point if forceMoveTo
108
        is false and the builder is not empty. Otherwise, added contour begins with first point
109
        of arc. Angles greater than -360 and less than 360 are treated modulo 360.
110
111
        @param oval          bounds of ellipse containing arc
112
        @param startAngleDeg starting angle of arc in degrees
113
        @param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360
114
        @param forceMoveTo   true to start a new contour with arc
115
        @return              reference to the builder
116
    */
117
    SkPathBuilder& arcTo(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg,
118
                         bool forceMoveTo);
119
120
    /** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic
121
        weighted to describe part of circle. Arc is contained by tangent from
122
        last SkPath point to p1, and tangent from p1 to p2. Arc
123
        is part of circle sized to radius, positioned so it touches both tangent lines.
124
125
        If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath.
126
        The length of vector from p1 to p2 does not affect arc.
127
128
        Arc sweep is always less than 180 degrees. If radius is zero, or if
129
        tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1.
130
131
        arcTo() appends at most one line and one conic.
132
        arcTo() implements the functionality of PostScript arct and HTML Canvas arcTo.
133
134
        @param p1      SkPoint common to pair of tangents
135
        @param p2      end of second tangent
136
        @param radius  distance from arc to circle center
137
        @return        reference to SkPath
138
    */
139
    SkPathBuilder& arcTo(SkPoint p1, SkPoint p2, SkScalar radius);
140
141
    enum ArcSize {
142
        kSmall_ArcSize, //!< smaller of arc pair
143
        kLarge_ArcSize, //!< larger of arc pair
144
    };
145
146
    /** Appends arc to SkPath. Arc is implemented by one or more conic weighted to describe
147
        part of oval with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves
148
        from last SkPath SkPoint to (xy.fX, xy.fY), choosing one of four possible routes:
149
        clockwise or counterclockwise,
150
        and smaller or larger.
151
152
        Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either
153
        radii are zero, or if last SkPath SkPoint equals (xy.fX, xy.fY). arcTo() scales radii r to
154
        fit last SkPath SkPoint and xy if both are greater than zero but too small to describe
155
        an arc.
156
157
        arcTo() appends up to four conic curves.
158
        arcTo() implements the functionality of SVG arc, although SVG sweep-flag value is
159
        opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise, while
160
        kCW_Direction cast to int is zero.
161
162
        @param r            radii on axes before x-axis rotation
163
        @param xAxisRotate  x-axis rotation in degrees; positive values are clockwise
164
        @param largeArc     chooses smaller or larger arc
165
        @param sweep        chooses clockwise or counterclockwise arc
166
        @param xy           end of arc
167
        @return             reference to SkPath
168
    */
169
    SkPathBuilder& arcTo(SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, SkPathDirection sweep,
170
                         SkPoint xy);
171
172
    /** Appends arc to the builder, as the start of new contour. Arc added is part of ellipse
173
        bounded by oval, from startAngle through sweepAngle. Both startAngle and
174
        sweepAngle are measured in degrees, where zero degrees is aligned with the
175
        positive x-axis, and positive sweeps extends arc clockwise.
176
177
        If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
178
        zero, append oval instead of arc. Otherwise, sweepAngle values are treated
179
        modulo 360, and arc may or may not draw depending on numeric rounding.
180
181
        @param oval          bounds of ellipse containing arc
182
        @param startAngleDeg starting angle of arc in degrees
183
        @param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360
184
        @return              reference to this builder
185
    */
186
    SkPathBuilder& addArc(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg);
187
188
    // Add a new contour
189
190
    SkPathBuilder& addRect(const SkRect&, SkPathDirection, unsigned startIndex);
191
    SkPathBuilder& addOval(const SkRect&, SkPathDirection, unsigned startIndex);
192
    SkPathBuilder& addRRect(const SkRRect&, SkPathDirection, unsigned startIndex);
193
194
2
    SkPathBuilder& addRect(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) {
195
2
        return this->addRect(rect, dir, 0);
196
2
    }
197
1.86k
    SkPathBuilder& addOval(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) {
198
        // legacy start index: 1
199
1.86k
        return this->addOval(rect, dir, 1);
200
1.86k
    }
201
2.80k
    SkPathBuilder& addRRect(const SkRRect& rrect, SkPathDirection dir = SkPathDirection::kCW) {
202
        // legacy start indices: 6 (CW) and 7 (CCW)
203
2.80k
        return this->addRRect(rrect, dir, dir == SkPathDirection::kCW ? 6 : 7);
204
2.80k
    }
205
206
    SkPathBuilder& addCircle(SkScalar center_x, SkScalar center_y, SkScalar radius,
207
                             SkPathDirection dir = SkPathDirection::kCW);
208
209
    SkPathBuilder& addPolygon(const SkPoint pts[], int count, bool isClosed);
210
0
    SkPathBuilder& addPolygon(const std::initializer_list<SkPoint>& list, bool isClosed) {
211
0
        return this->addPolygon(list.begin(), SkToInt(list.size()), isClosed);
212
0
    }
213
214
    SkPathBuilder& addPath(const SkPath&);
215
216
    // Performance hint, to reserve extra storage for subsequent calls to lineTo, quadTo, etc.
217
218
    void incReserve(int extraPtCount, int extraVerbCount);
219
93.1k
    void incReserve(int extraPtCount) {
220
93.1k
        this->incReserve(extraPtCount, extraPtCount);
221
93.1k
    }
222
223
    SkPathBuilder& offset(SkScalar dx, SkScalar dy);
224
225
0
    SkPathBuilder& toggleInverseFillType() {
226
0
        fFillType = (SkPathFillType)((unsigned)fFillType ^ 2);
227
0
        return *this;
228
0
    }
229
230
private:
231
    SkPathRef::PointsArray fPts;
232
    SkPathRef::VerbsArray fVerbs;
233
    SkPathRef::ConicWeightsArray fConicWeights;
234
235
    SkPathFillType      fFillType;
236
    bool                fIsVolatile;
237
238
    unsigned    fSegmentMask;
239
    SkPoint     fLastMovePoint;
240
    int         fLastMoveIndex; // only needed until SkPath is immutable
241
    bool        fNeedsMoveVerb;
242
243
    enum IsA {
244
        kIsA_JustMoves,     // we only have 0 or more moves
245
        kIsA_MoreThanMoves, // we have verbs other than just move
246
        kIsA_Oval,          // we are 0 or more moves followed by an oval
247
        kIsA_RRect,         // we are 0 or more moves followed by a rrect
248
    };
249
    IsA fIsA      = kIsA_JustMoves;
250
    int fIsAStart = -1;     // tracks direction iff fIsA is not unknown
251
    bool fIsACCW  = false;  // tracks direction iff fIsA is not unknown
252
253
0
    int countVerbs() const { return fVerbs.size(); }
254
255
    // called right before we add a (non-move) verb
256
6.27M
    void ensureMove() {
257
6.27M
        fIsA = kIsA_MoreThanMoves;
258
6.27M
        if (fNeedsMoveVerb) {
259
12.8k
            this->moveTo(fLastMovePoint);
260
12.8k
        }
261
6.27M
    }
262
263
    SkPath make(sk_sp<SkPathRef>) const;
264
265
    SkPathBuilder& privateReverseAddPath(const SkPath&);
266
267
    friend class SkPathPriv;
268
};
269
270
#endif
271