Coverage Report

Created: 2024-09-14 07:19

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