Coverage Report

Created: 2024-05-20 07:14

/src/skia/modules/sksg/src/SkSGGeometryEffect.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2020 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
#include "modules/sksg/include/SkSGGeometryEffect.h"
9
10
#include "include/core/SkCanvas.h"
11
#include "include/core/SkClipOp.h"
12
#include "include/core/SkMatrix.h"
13
#include "include/core/SkPath.h"
14
#include "include/core/SkPathEffect.h"
15
#include "include/core/SkPathUtils.h"
16
#include "include/core/SkStrokeRec.h"
17
#include "include/effects/SkCornerPathEffect.h"
18
#include "include/effects/SkDashPathEffect.h"
19
#include "include/effects/SkTrimPathEffect.h"
20
#include "include/pathops/SkPathOps.h"
21
#include "include/private/base/SkAssert.h"
22
#include "include/private/base/SkPoint_impl.h"
23
#include "include/private/base/SkTArray.h"
24
#include "include/private/base/SkTo.h"
25
#include "modules/sksg/src/SkSGTransformPriv.h"
26
#include "src/core/SkPathPriv.h"
27
28
#include <algorithm>
29
#include <cmath>
30
31
using namespace skia_private;
32
33
namespace sksg {
34
35
GeometryEffect::GeometryEffect(sk_sp<GeometryNode> child)
36
2.00M
    : fChild(std::move(child)) {
37
2.00M
    SkASSERT(fChild);
38
39
2.00M
    this->observeInval(fChild);
40
2.00M
}
41
42
2.00M
GeometryEffect::~GeometryEffect() {
43
2.00M
    this->unobserveInval(fChild);
44
2.00M
}
45
46
0
void GeometryEffect::onClip(SkCanvas* canvas, bool antiAlias) const {
47
0
    canvas->clipPath(fPath, SkClipOp::kIntersect, antiAlias);
48
0
}
49
50
2.62k
void GeometryEffect::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
51
2.62k
    canvas->drawPath(fPath, paint);
52
2.62k
}
53
54
0
bool GeometryEffect::onContains(const SkPoint& p) const {
55
0
    return fPath.contains(p.x(), p.y());
56
0
}
57
58
2.15M
SkPath GeometryEffect::onAsPath() const {
59
2.15M
    return fPath;
60
2.15M
}
61
62
1.97M
SkRect GeometryEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
63
1.97M
    SkASSERT(this->hasInval());
64
65
1.97M
    fChild->revalidate(ic, ctm);
66
67
1.97M
    fPath = this->onRevalidateEffect(fChild);
68
1.97M
    SkPathPriv::ShrinkToFit(&fPath);
69
70
1.97M
    return fPath.computeTightBounds();
71
1.97M
}
72
73
1.04M
SkPath TrimEffect::onRevalidateEffect(const sk_sp<GeometryNode>& child) {
74
1.04M
    SkPath path = child->asPath();
75
76
1.04M
    if (const auto trim = SkTrimPathEffect::Make(fStart, fStop, fMode)) {
77
291k
        SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle);
78
291k
        SkASSERT(!trim->needsCTM());
79
291k
        SkAssertResult(trim->filterPath(&path, path, &rec, nullptr));
80
291k
    }
81
82
1.04M
    return path;
83
1.04M
}
84
85
GeometryTransform::GeometryTransform(sk_sp<GeometryNode> child, sk_sp<Transform> transform)
86
    : INHERITED(std::move(child))
87
16.8k
    , fTransform(std::move(transform)) {
88
16.8k
    SkASSERT(fTransform);
89
16.8k
    this->observeInval(fTransform);
90
16.8k
}
91
92
16.8k
GeometryTransform::~GeometryTransform() {
93
16.8k
    this->unobserveInval(fTransform);
94
16.8k
}
95
96
1.97k
SkPath GeometryTransform::onRevalidateEffect(const sk_sp<GeometryNode>& child) {
97
1.97k
    fTransform->revalidate(nullptr, SkMatrix::I());
98
1.97k
    const auto m = TransformPriv::As<SkMatrix>(fTransform);
99
100
1.97k
    SkPath path = child->asPath();
101
1.97k
    path.transform(m);
102
103
1.97k
    return path;
104
1.97k
}
105
106
namespace  {
107
108
32.1k
sk_sp<SkPathEffect> make_dash(const std::vector<float>& intervals, float phase) {
109
32.1k
    if (intervals.empty()) {
110
0
        return nullptr;
111
0
    }
112
113
32.1k
    const auto* intervals_ptr   = intervals.data();
114
32.1k
    auto        intervals_count = intervals.size();
115
116
32.1k
    STArray<32, float, true> storage;
117
32.1k
    if (intervals_count & 1) {
118
29.2k
        intervals_count *= 2;
119
29.2k
        storage.resize(intervals_count);
120
29.2k
        intervals_ptr = storage.data();
121
122
29.2k
        std::copy(intervals.begin(), intervals.end(), storage.begin());
123
29.2k
        std::copy(intervals.begin(), intervals.end(), storage.begin() + intervals.size());
124
29.2k
    }
125
126
32.1k
    return SkDashPathEffect::Make(intervals_ptr, SkToInt(intervals_count), phase);
127
32.1k
}
128
129
} // namespace
130
131
32.1k
SkPath DashEffect::onRevalidateEffect(const sk_sp<GeometryNode>& child) {
132
32.1k
    SkPath path = child->asPath();
133
134
32.1k
    if (const auto dash_patheffect = make_dash(fIntervals, fPhase)) {
135
29.6k
        SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle);
136
29.6k
        SkASSERT(!dash_patheffect->needsCTM());
137
29.6k
        dash_patheffect->filterPath(&path, path, &rec, nullptr);
138
29.6k
    }
139
140
32.1k
    return path;
141
32.1k
}
142
143
641k
SkPath RoundEffect::onRevalidateEffect(const sk_sp<GeometryNode>& child) {
144
641k
    SkPath path = child->asPath();
145
146
641k
    if (const auto round = SkCornerPathEffect::Make(fRadius)) {
147
273k
        SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle);
148
273k
        SkASSERT(!round->needsCTM());
149
273k
        SkAssertResult(round->filterPath(&path, path, &rec, nullptr));
150
273k
    }
151
152
641k
    return path;
153
641k
}
154
155
188k
SkPath OffsetEffect::onRevalidateEffect(const sk_sp<GeometryNode>& child) {
156
188k
    SkPath path = child->asPath();
157
158
188k
    if (!SkScalarNearlyZero(fOffset)) {
159
181k
        SkPaint paint;
160
181k
        paint.setStyle(SkPaint::kStroke_Style);
161
181k
        paint.setStrokeWidth(std::abs(fOffset) * 2);
162
181k
        paint.setStrokeMiter(fMiterLimit);
163
181k
        paint.setStrokeJoin(fJoin);
164
165
181k
        SkPath fill_path;
166
181k
        skpathutils::FillPathWithPaint(path, paint, &fill_path, nullptr);
167
168
181k
        if (fOffset > 0) {
169
181k
            Op(path, fill_path, kUnion_SkPathOp, &path);
170
181k
        } else {
171
32
            Op(path, fill_path, kDifference_SkPathOp, &path);
172
32
        }
173
174
        // TODO: this seems to break path combining (winding mismatch?)
175
        // Simplify(path, &path);
176
181k
    }
177
178
188k
    return path;
179
188k
}
180
181
}  // namespace sksg