Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/effects/Sk2DPathEffect.cpp
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
#include "include/core/SkPath.h"
9
#include "include/core/SkRegion.h"
10
#include "include/core/SkStrokeRec.h"
11
#include "include/effects/Sk2DPathEffect.h"
12
#include "src/core/SkPathEffectBase.h"
13
#include "src/core/SkReadBuffer.h"
14
#include "src/core/SkWriteBuffer.h"
15
16
class Sk2DPathEffect : public SkPathEffectBase {
17
public:
18
20.9k
    Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
19
        // Calling invert will set the type mask on both matrices, making them thread safe.
20
20.9k
        fMatrixIsInvertible = fMatrix.invert(&fInverse);
21
20.9k
    }
22
23
protected:
24
    /** New virtual, to be overridden by subclasses.
25
        This is called once from filterPath, and provides the
26
        uv parameter bounds for the path. Subsequent calls to
27
        next() will receive u and v values within these bounds,
28
        and then a call to end() will signal the end of processing.
29
    */
30
10.7k
    virtual void begin(const SkIRect& uvBounds, SkPath* dst) const {}
31
0
    virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const {}
32
10.7k
    virtual void end(SkPath* dst) const {}
33
34
    /** Low-level virtual called per span of locations in the u-direction.
35
        The default implementation calls next() repeatedly with each
36
        location.
37
    */
38
2.91M
    virtual void nextSpan(int x, int y, int ucount, SkPath* path) const {
39
2.91M
        if (!fMatrixIsInvertible) {
40
0
            return;
41
0
        }
42
    #if defined(SK_BUILD_FOR_FUZZER)
43
        if (count > 100) {
44
            return;
45
        }
46
    #endif
47
48
2.91M
        const SkMatrix& mat = this->getMatrix();
49
2.91M
        SkPoint src, dst;
50
51
2.91M
        src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
52
90.9M
        do {
53
90.9M
            mat.mapPoints(&dst, &src, 1);
54
90.9M
            this->next(dst, x++, y, path);
55
90.9M
            src.fX += SK_Scalar1;
56
90.9M
        } while (--ucount > 0);
57
2.91M
    }
58
59
7.20M
    const SkMatrix& getMatrix() const { return fMatrix; }
60
61
0
    void flatten(SkWriteBuffer& buffer) const override {
62
0
        this->INHERITED::flatten(buffer);
63
0
        buffer.writeMatrix(fMatrix);
64
0
    }
65
66
    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
67
27.5k
                      const SkRect* cullRect, const SkMatrix&) const override {
68
27.5k
        if (!fMatrixIsInvertible) {
69
11.7k
            return false;
70
11.7k
        }
71
72
15.8k
        SkPath  tmp;
73
15.8k
        SkIRect ir;
74
75
15.8k
        src.transform(fInverse, &tmp);
76
15.8k
        tmp.getBounds().round(&ir);
77
15.8k
        if (!ir.isEmpty()) {
78
10.7k
            this->begin(ir, dst);
79
80
10.7k
            SkRegion rgn;
81
10.7k
            rgn.setPath(tmp, SkRegion(ir));
82
10.7k
            SkRegion::Iterator iter(rgn);
83
8.46M
            for (; !iter.done(); iter.next()) {
84
8.45M
                const SkIRect& rect = iter.rect();
85
19.4M
                for (int y = rect.fTop; y < rect.fBottom; ++y) {
86
11.0M
                    this->nextSpan(rect.fLeft, y, rect.width(), dst);
87
11.0M
                }
88
8.45M
            }
89
90
10.7k
            this->end(dst);
91
10.7k
        }
92
15.8k
        return true;
93
15.8k
    }
94
95
private:
96
    SkMatrix    fMatrix, fInverse;
97
    bool        fMatrixIsInvertible;
98
99
    // For simplicity, assume fast bounds cannot be computed
100
1.13k
    bool computeFastBounds(SkRect*) const override { return false; }
101
102
    friend class Sk2DPathEffectBlitter;
103
    using INHERITED = SkPathEffect;
104
};
105
106
///////////////////////////////////////////////////////////////////////////////
107
108
class SkLine2DPathEffectImpl : public Sk2DPathEffect {
109
public:
110
    SkLine2DPathEffectImpl(SkScalar width, const SkMatrix& matrix)
111
        : Sk2DPathEffect(matrix)
112
        , fWidth(width)
113
8.60k
    {
114
8.60k
        SkASSERT(width >= 0);
115
8.60k
    }
116
117
    bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
118
10.4k
                      const SkRect* cullRect, const SkMatrix& ctm) const override {
119
10.4k
        if (this->INHERITED::onFilterPath(dst, src, rec, cullRect, ctm)) {
120
8.16k
            rec->setStrokeStyle(fWidth);
121
8.16k
            return true;
122
8.16k
        }
123
2.26k
        return false;
124
2.26k
    }
125
126
8.12M
    void nextSpan(int u, int v, int ucount, SkPath* dst) const override {
127
8.12M
        if (ucount > 1) {
128
4.28M
            SkPoint    src[2], dstP[2];
129
130
4.28M
            src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
131
4.28M
            src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
132
4.28M
            this->getMatrix().mapPoints(dstP, src, 2);
133
134
4.28M
            dst->moveTo(dstP[0]);
135
4.28M
            dst->lineTo(dstP[1]);
136
4.28M
        }
137
8.12M
    }
138
139
0
    static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
140
0
        SkMatrix matrix;
141
0
        buffer.readMatrix(&matrix);
142
0
        SkScalar width = buffer.readScalar();
143
0
        return SkLine2DPathEffect::Make(width, matrix);
144
0
    }
145
146
1.60k
    void flatten(SkWriteBuffer &buffer) const override {
147
1.60k
        buffer.writeMatrix(this->getMatrix());
148
1.60k
        buffer.writeScalar(fWidth);
149
1.60k
    }
150
151
1.60k
    Factory getFactory() const override { return CreateProc; }
152
1.60k
    const char* getTypeName() const override { return "SkLine2DPathEffect"; }
153
154
private:
155
    SkScalar fWidth;
156
157
    using INHERITED = Sk2DPathEffect;
158
};
159
160
/////////////////////////////////////////////////////////////////////////////////////////////////
161
162
class SK_API SkPath2DPathEffectImpl : public Sk2DPathEffect {
163
public:
164
12.3k
    SkPath2DPathEffectImpl(const SkMatrix& m, const SkPath& p) : INHERITED(m), fPath(p) {}
165
166
90.9M
    void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
167
90.9M
        dst->addPath(fPath, loc.fX, loc.fY);
168
90.9M
    }
169
170
0
    static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
171
0
        SkMatrix matrix;
172
0
        buffer.readMatrix(&matrix);
173
0
        SkPath path;
174
0
        buffer.readPath(&path);
175
0
        return SkPath2DPathEffect::Make(matrix, path);
176
0
    }
177
178
1.81k
    void flatten(SkWriteBuffer& buffer) const override {
179
1.81k
        buffer.writeMatrix(this->getMatrix());
180
1.81k
        buffer.writePath(fPath);
181
1.81k
    }
182
183
1.81k
    Factory getFactory() const override { return CreateProc; }
184
1.81k
    const char* getTypeName() const override { return "SkPath2DPathEffect"; }
185
186
private:
187
    SkPath  fPath;
188
189
    using INHERITED = Sk2DPathEffect;
190
};
191
192
//////////////////////////////////////////////////////////////////////////////////////////////////
193
194
9.16k
sk_sp<SkPathEffect> SkLine2DPathEffect::Make(SkScalar width, const SkMatrix& matrix) {
195
9.16k
    if (!(width >= 0)) {
196
562
        return nullptr;
197
562
    }
198
8.60k
    return sk_sp<SkPathEffect>(new SkLine2DPathEffectImpl(width, matrix));
199
8.60k
}
200
201
12.3k
sk_sp<SkPathEffect> SkPath2DPathEffect::Make(const SkMatrix& matrix, const SkPath& path) {
202
12.3k
    return sk_sp<SkPathEffect>(new SkPath2DPathEffectImpl(matrix, path));
203
12.3k
}
204
205
3
void SkLine2DPathEffect::RegisterFlattenables() {
206
3
    SK_REGISTER_FLATTENABLE(SkLine2DPathEffectImpl);
207
3
}
208
209
3
void SkPath2DPathEffect::RegisterFlattenables() {
210
3
    SK_REGISTER_FLATTENABLE(SkPath2DPathEffectImpl);
211
3
}