Coverage Report

Created: 2021-08-22 09:07

/src/skia/modules/sksg/src/SkSGColorFilter.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2018 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/SkSGColorFilter.h"
9
10
#include "include/core/SkColorFilter.h"
11
#include "include/effects/SkTableColorFilter.h"
12
#include "include/private/SkColorData.h"
13
#include "modules/sksg/include/SkSGPaint.h"
14
15
#include <cmath>
16
17
namespace sksg {
18
19
ColorFilter::ColorFilter(sk_sp<RenderNode> child)
20
10.1k
    : INHERITED(std::move(child)) {}
21
22
1.49k
void ColorFilter::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
23
1.49k
    const auto local_ctx = ScopedRenderContext(canvas, ctx).modulateColorFilter(fColorFilter);
24
25
1.49k
    this->INHERITED::onRender(canvas, local_ctx);
26
1.49k
}
27
28
0
const RenderNode* ColorFilter::onNodeAt(const SkPoint& p) const {
29
    // TODO: we likely need to do something more sophisticated than delegate to descendants here.
30
0
    return this->INHERITED::onNodeAt(p);
31
0
}
32
33
10.0k
SkRect ColorFilter::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
34
10.0k
    SkASSERT(this->hasInval());
35
36
10.0k
    fColorFilter = this->onRevalidateFilter();
37
38
10.0k
    return this->INHERITED::onRevalidate(ic, ctm);
39
10.0k
}
40
41
6.84k
sk_sp<ExternalColorFilter> ExternalColorFilter::Make(sk_sp<RenderNode> child) {
42
6.84k
    return child ? sk_sp<ExternalColorFilter>(new ExternalColorFilter(std::move(child)))
43
0
                 : nullptr;
44
6.84k
}
45
46
6.84k
ExternalColorFilter::ExternalColorFilter(sk_sp<RenderNode> child) : INHERITED(std::move(child)) {}
47
48
6.84k
ExternalColorFilter::~ExternalColorFilter() = default;
49
50
567
void ExternalColorFilter::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
51
567
    const auto local_ctx = ScopedRenderContext(canvas, ctx).modulateColorFilter(fColorFilter);
52
53
567
    this->INHERITED::onRender(canvas, local_ctx);
54
567
}
55
56
sk_sp<ModeColorFilter> ModeColorFilter::Make(sk_sp<RenderNode> child, sk_sp<Color> color,
57
739
                                             SkBlendMode mode) {
58
739
    return (child && color) ? sk_sp<ModeColorFilter>(new ModeColorFilter(std::move(child),
59
739
                                                                         std::move(color), mode))
60
0
                            : nullptr;
61
739
}
62
63
ModeColorFilter::ModeColorFilter(sk_sp<RenderNode> child, sk_sp<Color> color, SkBlendMode mode)
64
    : INHERITED(std::move(child))
65
    , fColor(std::move(color))
66
739
    , fMode(mode) {
67
739
    this->observeInval(fColor);
68
739
}
69
70
739
ModeColorFilter::~ModeColorFilter() {
71
739
    this->unobserveInval(fColor);
72
739
}
73
74
707
sk_sp<SkColorFilter> ModeColorFilter::onRevalidateFilter() {
75
707
    fColor->revalidate(nullptr, SkMatrix::I());
76
707
    return SkColorFilters::Blend(fColor->getColor(), fMode);
77
707
}
78
79
sk_sp<GradientColorFilter> GradientColorFilter::Make(sk_sp<RenderNode> child,
80
6.18k
                                                     sk_sp<Color> c0, sk_sp<Color> c1) {
81
6.18k
    return Make(std::move(child), { std::move(c0), std::move(c1) });
82
6.18k
}
83
84
sk_sp<GradientColorFilter> GradientColorFilter::Make(sk_sp<RenderNode> child,
85
9.36k
                                                     std::vector<sk_sp<Color>> colors) {
86
9.36k
    return (child && colors.size() > 1)
87
9.36k
        ? sk_sp<GradientColorFilter>(new GradientColorFilter(std::move(child), std::move(colors)))
88
0
        : nullptr;
89
9.36k
}
90
91
GradientColorFilter::GradientColorFilter(sk_sp<RenderNode> child, std::vector<sk_sp<Color>> colors)
92
    : INHERITED(std::move(child))
93
9.36k
    , fColors(std::move(colors)) {
94
21.9k
    for (const auto& color : fColors) {
95
21.9k
        this->observeInval(color);
96
21.9k
    }
97
9.36k
}
98
99
9.36k
GradientColorFilter::~GradientColorFilter() {
100
21.9k
    for (const auto& color : fColors) {
101
21.9k
        this->unobserveInval(color);
102
21.9k
    }
103
9.36k
}
104
105
namespace  {
106
107
4.12k
sk_sp<SkColorFilter> Make2ColorGradient(const sk_sp<Color>& color0, const sk_sp<Color>& color1) {
108
4.12k
    const auto c0 = SkColor4f::FromColor(color0->getColor()),
109
4.12k
               c1 = SkColor4f::FromColor(color1->getColor());
110
111
4.12k
    const auto dR = c1.fR - c0.fR,
112
4.12k
               dG = c1.fG - c0.fG,
113
4.12k
               dB = c1.fB - c0.fB;
114
115
    // A 2-color gradient can be expressed as a color matrix (and combined with the luminance
116
    // calculation).  First, the luminance:
117
    //
118
    //   L = [r,g,b] . [kR,kG,kB]
119
    //
120
    // We can compute it using a color matrix (result stored in R):
121
    //
122
    //   | kR, kG, kB,  0,  0 |    r' = L
123
    //   |  0,  0,  0,  0,  0 |    g' = 0
124
    //   |  0,  0,  0,  0,  0 |    b' = 0
125
    //   |  0,  0,  0,  1,  0 |    a' = a
126
    //
127
    // Then we want to interpolate component-wise, based on L:
128
    //
129
    //   r' = c0.r + (c1.r - c0.r) * L = c0.r + dR*L
130
    //   g' = c0.g + (c1.g - c0.g) * L = c0.g + dG*L
131
    //   b' = c0.b + (c1.b - c0.b) * L = c0.b + dB*L
132
    //   a' = a
133
    //
134
    // This can be expressed as another color matrix (when L is stored in R):
135
    //
136
    //  | dR,  0,  0,  0, c0.r |
137
    //  | dG,  0,  0,  0, c0.g |
138
    //  | dB,  0,  0,  0, c0.b |
139
    //  |  0,  0,  0,  1,    0 |
140
    //
141
    // Composing these two, we get the total tint matrix:
142
143
4.12k
    const float tint_matrix[] = {
144
4.12k
        dR*SK_LUM_COEFF_R, dR*SK_LUM_COEFF_G, dR*SK_LUM_COEFF_B, 0, c0.fR,
145
4.12k
        dG*SK_LUM_COEFF_R, dG*SK_LUM_COEFF_G, dG*SK_LUM_COEFF_B, 0, c0.fG,
146
4.12k
        dB*SK_LUM_COEFF_R, dB*SK_LUM_COEFF_G, dB*SK_LUM_COEFF_B, 0, c0.fB,
147
4.12k
        0,                 0,                 0,                 1, 0,
148
4.12k
    };
149
150
4.12k
    return SkColorFilters::Matrix(tint_matrix);
151
4.12k
}
152
153
3.17k
sk_sp<SkColorFilter> MakeNColorGradient(const std::vector<sk_sp<Color>>& colors) {
154
    // For N colors, we build a gradient color table.
155
3.17k
    uint8_t rTable[256], gTable[256], bTable[256];
156
157
3.17k
    SkASSERT(colors.size() > 2);
158
3.17k
    const auto span_count = colors.size() - 1;
159
160
3.17k
    size_t span_start = 0;
161
9.53k
    for (size_t i = 0; i < span_count; ++i) {
162
6.35k
        const auto span_stop = static_cast<size_t>(std::round((i + 1) * 255.0f / span_count)),
163
6.35k
                   span_size = span_stop - span_start;
164
6.35k
        if (span_start > span_stop) {
165
            // Degenerate case.
166
0
            continue;
167
0
        }
168
6.35k
        SkASSERT(span_stop <= 255);
169
170
        // Fill the gradient in [span_start,span_stop] -> [c0,c1]
171
6.35k
        const SkColor c0 = colors[i    ]->getColor(),
172
6.35k
                      c1 = colors[i + 1]->getColor();
173
6.35k
        float r = SkColorGetR(c0),
174
6.35k
              g = SkColorGetG(c0),
175
6.35k
              b = SkColorGetB(c0);
176
6.35k
        const float dR = (SkColorGetR(c1) - r) / span_size,
177
6.35k
                    dG = (SkColorGetG(c1) - g) / span_size,
178
6.35k
                    dB = (SkColorGetB(c1) - b) / span_size;
179
180
819k
        for (size_t j = span_start; j <= span_stop; ++j) {
181
813k
            rTable[j] = static_cast<uint8_t>(std::round(r));
182
813k
            gTable[j] = static_cast<uint8_t>(std::round(g));
183
813k
            bTable[j] = static_cast<uint8_t>(std::round(b));
184
813k
            r += dR;
185
813k
            g += dG;
186
813k
            b += dB;
187
813k
        }
188
189
        // Ensure we always advance.
190
6.35k
        span_start = span_stop + 1;
191
6.35k
    }
192
3.17k
    SkASSERT(span_start == 256);
193
194
3.17k
    const float luminance_matrix[] = {
195
3.17k
        SK_LUM_COEFF_R, SK_LUM_COEFF_G, SK_LUM_COEFF_B,  0,  0,  // r' = L
196
3.17k
        SK_LUM_COEFF_R, SK_LUM_COEFF_G, SK_LUM_COEFF_B,  0,  0,  // g' = L
197
3.17k
        SK_LUM_COEFF_R, SK_LUM_COEFF_G, SK_LUM_COEFF_B,  0,  0,  // b' = L
198
3.17k
                     0,              0,              0,  1,  0,  // a' = a
199
3.17k
    };
200
201
3.17k
    return SkTableColorFilter::MakeARGB(nullptr, rTable, gTable, bTable)
202
3.17k
            ->makeComposed(SkColorFilters::Matrix(luminance_matrix));
203
3.17k
}
204
205
} // namespace
206
207
9.33k
sk_sp<SkColorFilter> GradientColorFilter::onRevalidateFilter() {
208
21.8k
    for (const auto& color : fColors) {
209
21.8k
        color->revalidate(nullptr, SkMatrix::I());
210
21.8k
    }
211
212
9.33k
    if (fWeight <= 0) {
213
2.03k
        return nullptr;
214
2.03k
    }
215
216
7.29k
    SkASSERT(fColors.size() > 1);
217
3.17k
    auto gradientCF = (fColors.size() > 2) ? MakeNColorGradient(fColors)
218
4.12k
                                           : Make2ColorGradient(fColors[0], fColors[1]);
219
220
7.29k
    return SkColorFilters::Lerp(fWeight, nullptr, std::move(gradientCF));
221
7.29k
}
222
223
} // namespace sksg