Coverage Report

Created: 2024-09-14 07:19

/src/skia/modules/svg/src/SkSVGFeComponentTransfer.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2024 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/svg/include/SkSVGFeComponentTransfer.h"
9
10
#include "include/core/SkColorFilter.h"
11
#include "include/core/SkImageFilter.h"
12
#include "include/core/SkRect.h"
13
#include "include/effects/SkImageFilters.h"
14
#include "include/private/base/SkAssert.h"
15
#include "include/private/base/SkFloatingPoint.h"
16
#include "include/private/base/SkTArray.h"
17
#include "include/private/base/SkTPin.h"
18
#include "include/private/base/SkTo.h"
19
#include "modules/svg/include/SkSVGAttributeParser.h"
20
#include "modules/svg/include/SkSVGFilterContext.h"
21
#include "modules/svg/include/SkSVGTypes.h"
22
23
#include <cmath>
24
#include <cstddef>
25
#include <cstdint>
26
#include <tuple>
27
#include <utility>
28
29
class SkSVGRenderContext;
30
31
sk_sp<SkImageFilter> SkSVGFeComponentTransfer::onMakeImageFilter(
32
        const SkSVGRenderContext& ctx,
33
0
        const SkSVGFilterContext& fctx) const {
34
0
    std::vector<uint8_t> a_tbl, b_tbl, g_tbl, r_tbl;
35
36
0
    for (const auto& child : fChildren) {
37
0
        switch (child->tag()) {
38
0
            case SkSVGTag::kFeFuncA:
39
0
                a_tbl = static_cast<const SkSVGFeFunc*>(child.get())->getTable();
40
0
                break;
41
0
            case SkSVGTag::kFeFuncB:
42
0
                b_tbl = static_cast<const SkSVGFeFunc*>(child.get())->getTable();
43
0
                break;
44
0
            case SkSVGTag::kFeFuncG:
45
0
                g_tbl = static_cast<const SkSVGFeFunc*>(child.get())->getTable();
46
0
                break;
47
0
            case SkSVGTag::kFeFuncR:
48
0
                r_tbl = static_cast<const SkSVGFeFunc*>(child.get())->getTable();
49
0
                break;
50
0
            default:
51
0
                break;
52
0
        }
53
0
    }
54
0
    SkASSERT(a_tbl.empty() || a_tbl.size() == 256);
55
0
    SkASSERT(b_tbl.empty() || b_tbl.size() == 256);
56
0
    SkASSERT(g_tbl.empty() || g_tbl.size() == 256);
57
0
    SkASSERT(r_tbl.empty() || r_tbl.size() == 256);
58
59
0
    const SkRect cropRect = this->resolveFilterSubregion(ctx, fctx);
60
0
    const sk_sp<SkImageFilter> input = fctx.resolveInput(ctx,
61
0
                                                         this->getIn(),
62
0
                                                         this->resolveColorspace(ctx, fctx));
63
64
0
    const auto cf =  SkColorFilters::TableARGB(a_tbl.empty() ? nullptr : a_tbl.data(),
65
0
                                               r_tbl.empty() ? nullptr : r_tbl.data(),
66
0
                                               g_tbl.empty() ? nullptr : g_tbl.data(),
67
0
                                               b_tbl.empty() ? nullptr : b_tbl.data());
68
69
0
    return SkImageFilters::ColorFilter(std::move(cf), std::move(input), cropRect);
70
0
}
Unexecuted instantiation: SkSVGFeComponentTransfer::onMakeImageFilter(SkSVGRenderContext const&, SkSVGFilterContext const&) const
Unexecuted instantiation: SkSVGFeComponentTransfer::onMakeImageFilter(SkSVGRenderContext const&, SkSVGFilterContext const&) const
71
72
0
std::vector<uint8_t> SkSVGFeFunc::getTable() const {
73
    // https://www.w3.org/TR/SVG11/filters.html#feComponentTransferTypeAttribute
74
0
    const auto make_linear = [this]() -> std::vector<uint8_t> {
75
0
        std::vector<uint8_t> tbl(256);
76
0
        const float slope = this->getSlope(),
77
0
             intercept255 = this->getIntercept() * 255;
78
79
0
        for (size_t i = 0; i < 256; ++i) {
80
0
            tbl[i] = SkTPin<int>(sk_float_round2int(intercept255 + i * slope), 0, 255);
81
0
        }
82
83
0
        return tbl;
84
0
    };
85
86
0
    const auto make_gamma = [this]() -> std::vector<uint8_t> {
87
0
        std::vector<uint8_t> tbl(256);
88
0
        const float exponent = this->getExponent(),
89
0
                      offset = this->getOffset();
90
91
0
        for (size_t i = 0; i < 256; ++i) {
92
0
            const float component = offset + std::pow(i * (1 / 255.f), exponent);
93
0
            tbl[i] = SkTPin<int>(sk_float_round2int(component * 255), 0, 255);
94
0
        }
95
96
0
        return tbl;
97
0
    };
98
99
0
    const auto lerp_from_table_values = [this](auto lerp_func) -> std::vector<uint8_t> {
100
0
        const auto& vals = this->getTableValues();
101
0
        if (vals.size() < 2 || vals.size() > 255) {
102
0
            return {};
103
0
        }
104
105
        // number of interpolation intervals
106
0
        const size_t n = vals.size() - 1;
107
108
0
        std::vector<uint8_t> tbl(256);
109
0
        for (size_t k = 0; k < n; ++k) {
110
            // interpolation values
111
0
            const SkSVGNumberType v0 = SkTPin(vals[k + 0], 0.f, 1.f),
112
0
                                  v1 = SkTPin(vals[k + 1], 0.f, 1.f);
113
114
            // start/end component table indices
115
0
            const size_t c_start = k * 255 / n,
116
0
                         c_end   = (k + 1) * 255 / n;
117
0
            SkASSERT(c_end <= 255);
118
119
0
            for (size_t ci = c_start; ci < c_end; ++ci) {
120
0
                const float lerp_t = static_cast<float>(ci - c_start) / (c_end - c_start),
121
0
                         component = lerp_func(v0, v1, lerp_t);
122
0
                SkASSERT(component >= 0 && component <= 1);
123
124
0
                tbl[ci] = SkToU8(sk_float_round2int(component * 255));
125
0
            }
126
0
        }
127
128
0
        tbl.back() = SkToU8(sk_float_round2int(255 * SkTPin(vals.back(), 0.f, 1.f)));
129
130
0
        return tbl;
131
0
    };
Unexecuted instantiation: SkSVGFeComponentTransfer.cpp:std::__1::vector<unsigned char, SkSVGFeFunc::getTable() const::$_3::operator()() const::{lambda(float, float, float)#1}::allocator<unsigned char> > SkSVGFeFunc::getTable() const::$_2::operator()<SkSVGFeFunc::getTable() const::$_3::operator()() const::{lambda(float, float, float)#1}>(SkSVGFeFunc::getTable() const::$_3::operator()() const::{lambda(float, float, float)#1}) const
Unexecuted instantiation: SkSVGFeComponentTransfer.cpp:std::__1::vector<unsigned char, SkSVGFeFunc::getTable() const::$_4::operator()() const::{lambda(float, float, float)#1}::allocator<unsigned char> > SkSVGFeFunc::getTable() const::$_2::operator()<SkSVGFeFunc::getTable() const::$_4::operator()() const::{lambda(float, float, float)#1}>(SkSVGFeFunc::getTable() const::$_4::operator()() const::{lambda(float, float, float)#1}) const
Unexecuted instantiation: SkSVGFeComponentTransfer.cpp:std::__1::vector<unsigned char, SkSVGFeFunc::getTable() const::$_3::operator()() const::{lambda(float, float, float)#1}::allocator<unsigned char> > SkSVGFeFunc::getTable() const::$_2::operator()<SkSVGFeFunc::getTable() const::$_3::operator()() const::{lambda(float, float, float)#1}>(SkSVGFeFunc::getTable() const::$_3::operator()() const::{lambda(float, float, float)#1}) const
Unexecuted instantiation: SkSVGFeComponentTransfer.cpp:std::__1::vector<unsigned char, SkSVGFeFunc::getTable() const::$_4::operator()() const::{lambda(float, float, float)#1}::allocator<unsigned char> > SkSVGFeFunc::getTable() const::$_2::operator()<SkSVGFeFunc::getTable() const::$_4::operator()() const::{lambda(float, float, float)#1}>(SkSVGFeFunc::getTable() const::$_4::operator()() const::{lambda(float, float, float)#1}) const
132
133
0
    const auto make_table = [&]() -> std::vector<uint8_t> {
134
0
        return lerp_from_table_values([](float v0, float v1, float t) {
135
0
            return v0 + (v1 - v0) * t;
136
0
        });
137
0
    };
138
139
0
    const auto make_discrete = [&]() -> std::vector<uint8_t> {
140
0
        return lerp_from_table_values([](float v0, float v1, float t) {
141
0
            return v0;
142
0
        });
143
0
    };
144
145
0
    switch (this->getType()) {
146
0
        case SkSVGFeFuncType::kIdentity: return {};
147
0
        case SkSVGFeFuncType::kTable:    return make_table();
148
0
        case SkSVGFeFuncType::kDiscrete: return make_discrete();
149
0
        case SkSVGFeFuncType::kLinear:   return make_linear();
150
0
        case SkSVGFeFuncType::kGamma:    return make_gamma();
151
0
    }
152
153
0
    SkUNREACHABLE;
154
0
}
155
156
0
bool SkSVGFeFunc::parseAndSetAttribute(const char* name, const char* val) {
157
0
    return INHERITED::parseAndSetAttribute(name, val) ||
158
0
      this->setAmplitude(SkSVGAttributeParser::parse<SkSVGNumberType>("amplitude", name, val)) ||
159
0
      this->setExponent(SkSVGAttributeParser::parse<SkSVGNumberType>("exponent", name, val)) ||
160
0
      this->setIntercept(SkSVGAttributeParser::parse<SkSVGNumberType>("intercept", name, val)) ||
161
0
      this->setOffset(SkSVGAttributeParser::parse<SkSVGNumberType>("offset", name, val)) ||
162
0
      this->setSlope(SkSVGAttributeParser::parse<SkSVGNumberType>("slope", name, val)) ||
163
0
      this->setTableValues(SkSVGAttributeParser::parse<std::vector<SkSVGNumberType>>("tableValues",
164
0
                                                                                     name, val)) ||
165
0
      this->setType(SkSVGAttributeParser::parse<SkSVGFeFuncType>("type", name, val));
166
0
}
167
168
template <>
169
0
bool SkSVGAttributeParser::parse(SkSVGFeFuncType* type) {
170
0
    static constexpr std::tuple<const char*, SkSVGFeFuncType> gTypeMap[] = {
171
0
            { "identity", SkSVGFeFuncType::kIdentity },
172
0
            { "table"   , SkSVGFeFuncType::kTable    },
173
0
            { "discrete", SkSVGFeFuncType::kDiscrete },
174
0
            { "linear"  , SkSVGFeFuncType::kLinear   },
175
0
            { "gamma"   , SkSVGFeFuncType::kGamma    },
176
0
    };
177
178
0
    return this->parseEnumMap(gTypeMap, type) && this->parseEOSToken();
179
0
}