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