Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/gpu/geometry/GrAAConvexTessellator.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 GrAAConvexTessellator_DEFINED
9
#define GrAAConvexTessellator_DEFINED
10
11
#include "include/core/SkColor.h"
12
#include "include/core/SkPaint.h"
13
#include "include/core/SkScalar.h"
14
#include "include/core/SkStrokeRec.h"
15
#include "include/private/SkTDArray.h"
16
#include "src/core/SkPointPriv.h"
17
18
class SkCanvas;
19
class SkMatrix;
20
class SkPath;
21
22
//#define GR_AA_CONVEX_TESSELLATOR_VIZ 1
23
24
// device space distance which we inset / outset points in order to create the soft antialiased edge
25
static const SkScalar kAntialiasingRadius = 0.5f;
26
27
class GrAAConvexTessellator;
28
29
// The AAConvexTessellator holds the global pool of points and the triangulation
30
// that connects them. It also drives the tessellation process.
31
// The outward facing normals of the original polygon are stored (in 'fNorms') to service
32
// computeDepthFromEdge requests.
33
class GrAAConvexTessellator {
34
public:
35
    GrAAConvexTessellator(SkStrokeRec::Style style = SkStrokeRec::kFill_Style,
36
                          SkScalar strokeWidth = -1.0f,
37
                          SkPaint::Join join = SkPaint::Join::kBevel_Join,
38
                          SkScalar miterLimit = 0.0f)
39
        : fSide(SkPointPriv::kOn_Side)
40
        , fStrokeWidth(strokeWidth)
41
        , fStyle(style)
42
        , fJoin(join)
43
157
        , fMiterLimit(miterLimit) {
44
157
    }
45
46
1.78k
    SkPointPriv::Side side() const { return fSide; }
47
48
    bool tessellate(const SkMatrix& m, const SkPath& path);
49
50
    // The next five should only be called after tessellate to extract the result
51
18.4k
    int numPts() const { return fPts.count(); }
52
31.2k
    int numIndices() const { return fIndices.count(); }
53
54
6.58k
    const SkPoint& lastPoint() const { return fPts.top(); }
55
22.9k
    const SkPoint& point(int index) const { return fPts[index]; }
56
31.2k
    int index(int index) const { return fIndices[index]; }
57
6.68k
    SkScalar coverage(int index) const { return fCoverages[index]; }
58
59
#if GR_AA_CONVEX_TESSELLATOR_VIZ
60
    void draw(SkCanvas* canvas) const;
61
#endif
62
63
    // The tessellator can be reused for multiple paths by rewinding in between
64
    void rewind();
65
66
private:
67
    // CandidateVerts holds the vertices for the next ring while they are
68
    // being generated. Its main function is to de-dup the points.
69
    class CandidateVerts {
70
    public:
71
7
        void setReserve(int numPts) { fPts.setReserve(numPts); }
72
17
        void rewind() { fPts.rewind(); }
73
74
1.78k
        int numPts() const { return fPts.count(); }
75
76
1.95k
        const SkPoint& lastPoint() const { return fPts.top().fPt; }
77
4
        const SkPoint& firstPoint() const { return fPts[0].fPt; }
78
1.78k
        const SkPoint& point(int index) const { return fPts[index].fPt; }
79
80
1.78k
        int originatingIdx(int index) const { return fPts[index].fOriginatingIdx; }
81
1.78k
        int origEdge(int index) const { return fPts[index].fOrigEdgeId; }
82
1.78k
        bool needsToBeNew(int index) const { return fPts[index].fNeedsToBeNew; }
83
84
1.95k
        int addNewPt(const SkPoint& newPt, int originatingIdx, int origEdge, bool needsToBeNew) {
85
1.95k
            struct PointData* pt = fPts.push();
86
1.95k
            pt->fPt = newPt;
87
1.95k
            pt->fOrigEdgeId = origEdge;
88
1.95k
            pt->fOriginatingIdx = originatingIdx;
89
1.95k
            pt->fNeedsToBeNew = needsToBeNew;
90
1.95k
            return fPts.count() - 1;
91
1.95k
        }
92
93
1
        int fuseWithPrior(int origEdgeId) {
94
1
            fPts.top().fOrigEdgeId = origEdgeId;
95
1
            fPts.top().fOriginatingIdx = -1;
96
1
            fPts.top().fNeedsToBeNew = true;
97
1
            return fPts.count() - 1;
98
1
        }
99
100
2
        int fuseWithNext() {
101
2
            fPts[0].fOriginatingIdx = -1;
102
2
            fPts[0].fNeedsToBeNew = true;
103
2
            return 0;
104
2
        }
105
106
0
        int fuseWithBoth() {
107
0
            if (fPts.count() > 1) {
108
0
                fPts.pop();
109
0
            }
110
111
0
            fPts[0].fOriginatingIdx = -1;
112
0
            fPts[0].fNeedsToBeNew = true;
113
0
            return 0;
114
0
        }
115
116
    private:
117
        struct PointData {
118
            SkPoint fPt;
119
            int     fOriginatingIdx;
120
            int     fOrigEdgeId;
121
            bool    fNeedsToBeNew;
122
        };
123
124
        SkTDArray<struct PointData> fPts;
125
    };
126
127
    // The Ring holds a set of indices into the global pool that together define
128
    // a single polygon inset.
129
    class Ring {
130
    public:
131
24
        void setReserve(int numPts) { fPts.setReserve(numPts); }
132
17
        void rewind() { fPts.rewind(); }
133
134
13.0k
        int numPts() const { return fPts.count(); }
135
136
6.68k
        void addIdx(int index, int origEdgeId) {
137
6.68k
            struct PointData* pt = fPts.push();
138
6.68k
            pt->fIndex = index;
139
6.68k
            pt->fOrigEdgeId = origEdgeId;
140
6.68k
        }
141
142
        // Upgrade this ring so that it can behave like an originating ring
143
0
        void makeOriginalRing() {
144
0
            for (int i = 0; i < fPts.count(); ++i) {
145
0
                fPts[i].fOrigEdgeId = fPts[i].fIndex;
146
0
            }
147
0
        }
148
149
        // init should be called after all the indices have been added (via addIdx)
150
        void init(const GrAAConvexTessellator& tess);
151
        void init(const SkTDArray<SkVector>& norms, const SkTDArray<SkVector>& bisectors);
152
153
4.93k
        const SkPoint& norm(int index) const { return fPts[index].fNorm; }
154
9.51k
        const SkPoint& bisector(int index) const { return fPts[index].fBisector; }
155
29.3k
        int index(int index) const { return fPts[index].fIndex; }
156
3.92k
        int origEdgeID(int index) const { return fPts[index].fOrigEdgeId; }
157
0
        void setOrigEdgeId(int index, int id) { fPts[index].fOrigEdgeId = id; }
158
159
    #if GR_AA_CONVEX_TESSELLATOR_VIZ
160
        void draw(SkCanvas* canvas, const GrAAConvexTessellator& tess) const;
161
    #endif
162
163
    private:
164
        void computeNormals(const GrAAConvexTessellator& result);
165
        void computeBisectors(const GrAAConvexTessellator& tess);
166
167
        SkDEBUGCODE(bool isConvex(const GrAAConvexTessellator& tess) const;)
168
169
        struct PointData {
170
            SkPoint fNorm;
171
            SkPoint fBisector;
172
            int     fIndex;
173
            int     fOrigEdgeId;
174
        };
175
176
        SkTDArray<PointData> fPts;
177
    };
178
179
    // Represents whether a given point is within a curve. A point is inside a curve only if it is
180
    // an interior point within a quad, cubic, or conic, or if it is the endpoint of a quad, cubic,
181
    // or conic with another curve meeting it at (more or less) the same angle.
182
    enum CurveState {
183
        // point is a sharp vertex
184
        kSharp_CurveState,
185
        // endpoint of a curve with the other side's curvature not yet determined
186
        kIndeterminate_CurveState,
187
        // point is in the interior of a curve
188
        kCurve_CurveState
189
    };
190
191
1.95k
    bool movable(int index) const { return fMovable[index]; }
192
193
    // Movable points are those that can be slid along their bisector.
194
    // Basically, a point is immovable if it is part of the original
195
    // polygon or it results from the fusing of two bisectors.
196
    int addPt(const SkPoint& pt, SkScalar depth, SkScalar coverage, bool movable, CurveState curve);
197
    void popLastPt();
198
    void popFirstPtShuffle();
199
200
    void updatePt(int index, const SkPoint& pt, SkScalar depth, SkScalar coverage);
201
202
    void addTri(int i0, int i1, int i2);
203
204
157
    void reservePts(int count) {
205
157
        fPts.setReserve(count);
206
157
        fCoverages.setReserve(count);
207
157
        fMovable.setReserve(count);
208
157
    }
209
210
    SkScalar computeDepthFromEdge(int edgeIdx, const SkPoint& p) const;
211
212
    bool computePtAlongBisector(int startIdx, const SkPoint& bisector,
213
                                int edgeIdx, SkScalar desiredDepth,
214
                                SkPoint* result) const;
215
216
    void lineTo(const SkPoint& p, CurveState curve);
217
218
    void lineTo(const SkMatrix& m, const SkPoint& p, CurveState curve);
219
220
    void quadTo(const SkPoint pts[3]);
221
222
    void quadTo(const SkMatrix& m, const SkPoint pts[3]);
223
224
    void cubicTo(const SkMatrix& m, const SkPoint pts[4]);
225
226
    void conicTo(const SkMatrix& m, const SkPoint pts[3], SkScalar w);
227
228
    void terminate(const Ring& lastRing);
229
230
    // return false on failure/degenerate path
231
    bool extractFromPath(const SkMatrix& m, const SkPath& path);
232
    void computeBisectors();
233
    void computeNormals();
234
235
    void fanRing(const Ring& ring);
236
237
    Ring* getNextRing(Ring* lastRing);
238
239
    void createOuterRing(const Ring& previousRing, SkScalar outset, SkScalar coverage,
240
                         Ring* nextRing);
241
242
    bool createInsetRings(Ring& previousRing, SkScalar initialDepth, SkScalar initialCoverage,
243
                          SkScalar targetDepth, SkScalar targetCoverage, Ring** finalRing);
244
245
    bool createInsetRing(const Ring& lastRing, Ring* nextRing,
246
                         SkScalar initialDepth, SkScalar initialCoverage, SkScalar targetDepth,
247
                         SkScalar targetCoverage, bool forceNew);
248
249
    void validate() const;
250
251
    // fPts, fCoverages, fMovable & fCurveState should always have the same # of elements
252
    SkTDArray<SkPoint>    fPts;
253
    SkTDArray<SkScalar>   fCoverages;
254
    // movable points are those that can be slid further along their bisector
255
    SkTDArray<bool>       fMovable;
256
    // Tracks whether a given point is interior to a curve. Such points are
257
    // assumed to have shallow curvature.
258
    SkTDArray<CurveState> fCurveState;
259
260
    // The outward facing normals for the original polygon
261
    SkTDArray<SkVector>   fNorms;
262
    // The inward facing bisector at each point in the original polygon. Only
263
    // needed for exterior ring creation and then handed off to the initial ring.
264
    SkTDArray<SkVector>   fBisectors;
265
266
    SkPointPriv::Side     fSide;    // winding of the original polygon
267
268
    // The triangulation of the points
269
    SkTDArray<int>        fIndices;
270
271
    Ring                  fInitialRing;
272
#if GR_AA_CONVEX_TESSELLATOR_VIZ
273
    // When visualizing save all the rings
274
    SkTDArray<Ring*>      fRings;
275
#else
276
    Ring                  fRings[2];
277
#endif
278
    CandidateVerts        fCandidateVerts;
279
280
    // the stroke width is only used for stroke or stroke-and-fill styles
281
    SkScalar              fStrokeWidth;
282
    SkStrokeRec::Style    fStyle;
283
284
    SkPaint::Join         fJoin;
285
286
    SkScalar              fMiterLimit;
287
288
    // accumulated error when removing near colinear points to prevent an
289
    // overly greedy simplification
290
    SkScalar              fAccumLinearError;
291
292
    SkTDArray<SkPoint>    fPointBuffer;
293
};
294
295
296
#endif