Coverage Report

Created: 2021-08-22 09:07

/src/skia/modules/svg/src/SkSVGFeLighting.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 "include/core/SkPoint3.h"
9
#include "include/effects/SkImageFilters.h"
10
#include "modules/svg/include/SkSVGAttributeParser.h"
11
#include "modules/svg/include/SkSVGFeLightSource.h"
12
#include "modules/svg/include/SkSVGFeLighting.h"
13
#include "modules/svg/include/SkSVGFilterContext.h"
14
#include "modules/svg/include/SkSVGRenderContext.h"
15
#include "modules/svg/include/SkSVGValue.h"
16
17
0
bool SkSVGFeLighting::parseAndSetAttribute(const char* n, const char* v) {
18
0
    return INHERITED::parseAndSetAttribute(n, v) ||
19
0
           this->setSurfaceScale(
20
0
                   SkSVGAttributeParser::parse<SkSVGNumberType>("surfaceScale", n, v)) ||
21
0
           this->setKernelUnitLength(SkSVGAttributeParser::parse<SkSVGFeLighting::KernelUnitLength>(
22
0
                   "kernelUnitLength", n, v));
23
0
}
24
25
template <>
26
bool SkSVGAttributeParser::parse<SkSVGFeLighting::KernelUnitLength>(
27
0
        SkSVGFeLighting::KernelUnitLength* kernelUnitLength) {
28
0
    std::vector<SkSVGNumberType> values;
29
0
    if (!this->parse(&values)) {
30
0
        return false;
31
0
    }
32
33
0
    kernelUnitLength->fDx = values[0];
34
0
    kernelUnitLength->fDy = values.size() > 1 ? values[1] : values[0];
35
0
    return true;
36
0
}
37
38
sk_sp<SkImageFilter> SkSVGFeLighting::onMakeImageFilter(const SkSVGRenderContext& ctx,
39
0
                                                        const SkSVGFilterContext& fctx) const {
40
0
    for (const auto& child : fChildren) {
41
0
        switch (child->tag()) {
42
0
            case SkSVGTag::kFeDistantLight:
43
0
                return this->makeDistantLight(
44
0
                        ctx, fctx, static_cast<const SkSVGFeDistantLight*>(child.get()));
45
0
            case SkSVGTag::kFePointLight:
46
0
                return this->makePointLight(
47
0
                        ctx, fctx, static_cast<const SkSVGFePointLight*>(child.get()));
48
0
            case SkSVGTag::kFeSpotLight:
49
0
                return this->makeSpotLight(
50
0
                        ctx, fctx, static_cast<const SkSVGFeSpotLight*>(child.get()));
51
0
            default:
52
                // Ignore unknown children, such as <desc> elements
53
0
                break;
54
0
        }
55
0
    }
56
57
0
    SkDebugf("lighting filter effect needs exactly one light source\n");
58
0
    return nullptr;
59
0
}
60
61
0
SkColor SkSVGFeLighting::resolveLightingColor(const SkSVGRenderContext& ctx) const {
62
0
    const auto color = this->getLightingColor();
63
0
    if (!color.isValue()) {
64
        // Uninherited presentation attributes should have a concrete value by now.
65
0
        SkDebugf("unhandled: lighting-color has no value\n");
66
0
        return SK_ColorWHITE;
67
0
    }
68
69
0
    return ctx.resolveSvgColor(*color);
70
0
}
71
72
SkPoint3 SkSVGFeLighting::resolveXYZ(const SkSVGRenderContext& ctx,
73
                                     const SkSVGFilterContext& fctx,
74
                                     SkSVGNumberType x,
75
                                     SkSVGNumberType y,
76
0
                                     SkSVGNumberType z) const {
77
0
    const auto obbt = ctx.transformForCurrentOBB(fctx.primitiveUnits());
78
0
    const auto xy = SkV2{x,y} * obbt.scale + obbt.offset;
79
0
    z = SkSVGLengthContext({obbt.scale.x, obbt.scale.y})
80
0
            .resolve(SkSVGLength(z * 100.f, SkSVGLength::Unit::kPercentage),
81
0
                     SkSVGLengthContext::LengthType::kOther);
82
0
    return SkPoint3::Make(xy.x, xy.y, z);
83
0
}
84
85
0
bool SkSVGFeSpecularLighting::parseAndSetAttribute(const char* n, const char* v) {
86
0
    return INHERITED::parseAndSetAttribute(n, v) ||
87
0
           this->setSpecularConstant(
88
0
                   SkSVGAttributeParser::parse<SkSVGNumberType>("specularConstant", n, v)) ||
89
0
           this->setSpecularExponent(
90
0
                   SkSVGAttributeParser::parse<SkSVGNumberType>("specularExponent", n, v));
91
0
}
92
93
sk_sp<SkImageFilter> SkSVGFeSpecularLighting::makeDistantLight(
94
        const SkSVGRenderContext& ctx,
95
        const SkSVGFilterContext& fctx,
96
0
        const SkSVGFeDistantLight* light) const {
97
0
    const SkPoint3 dir = light->computeDirection();
98
0
    return SkImageFilters::DistantLitSpecular(
99
0
            this->resolveXYZ(ctx, fctx, dir.fX, dir.fY, dir.fZ),
100
0
            this->resolveLightingColor(ctx),
101
0
            this->getSurfaceScale(),
102
0
            fSpecularConstant,
103
0
            fSpecularExponent,
104
0
            fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
105
0
            this->resolveFilterSubregion(ctx, fctx));
106
0
}
107
108
sk_sp<SkImageFilter> SkSVGFeSpecularLighting::makePointLight(const SkSVGRenderContext& ctx,
109
                                                             const SkSVGFilterContext& fctx,
110
0
                                                             const SkSVGFePointLight* light) const {
111
0
    return SkImageFilters::PointLitSpecular(
112
0
            this->resolveXYZ(ctx, fctx, light->getX(), light->getY(), light->getZ()),
113
0
            this->resolveLightingColor(ctx),
114
0
            this->getSurfaceScale(),
115
0
            fSpecularConstant,
116
0
            fSpecularExponent,
117
0
            fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
118
0
            this->resolveFilterSubregion(ctx, fctx));
119
0
}
120
121
sk_sp<SkImageFilter> SkSVGFeSpecularLighting::makeSpotLight(const SkSVGRenderContext& ctx,
122
                                                            const SkSVGFilterContext& fctx,
123
0
                                                            const SkSVGFeSpotLight* light) const {
124
0
    const auto& limitingConeAngle = light->getLimitingConeAngle();
125
0
    const float cutoffAngle = limitingConeAngle.isValid() ? *limitingConeAngle : 180.f;
126
127
0
    return SkImageFilters::SpotLitSpecular(
128
0
            this->resolveXYZ(ctx, fctx, light->getX(), light->getY(), light->getZ()),
129
0
            this->resolveXYZ(
130
0
                    ctx, fctx, light->getPointsAtX(), light->getPointsAtY(), light->getPointsAtZ()),
131
0
            light->getSpecularExponent(),
132
0
            cutoffAngle,
133
0
            this->resolveLightingColor(ctx),
134
0
            this->getSurfaceScale(),
135
0
            fSpecularConstant,
136
0
            fSpecularExponent,
137
0
            fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
138
0
            this->resolveFilterSubregion(ctx, fctx));
139
0
}
140
141
0
bool SkSVGFeDiffuseLighting::parseAndSetAttribute(const char* n, const char* v) {
142
0
    return INHERITED::parseAndSetAttribute(n, v) ||
143
0
           this->setDiffuseConstant(
144
0
                   SkSVGAttributeParser::parse<SkSVGNumberType>("diffuseConstant", n, v));
145
0
}
146
147
sk_sp<SkImageFilter> SkSVGFeDiffuseLighting::makeDistantLight(
148
        const SkSVGRenderContext& ctx,
149
        const SkSVGFilterContext& fctx,
150
0
        const SkSVGFeDistantLight* light) const {
151
0
    const SkPoint3 dir = light->computeDirection();
152
0
    return SkImageFilters::DistantLitDiffuse(
153
0
            this->resolveXYZ(ctx, fctx, dir.fX, dir.fY, dir.fZ),
154
0
            this->resolveLightingColor(ctx),
155
0
            this->getSurfaceScale(),
156
0
            this->getDiffuseConstant(),
157
0
            fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
158
0
            this->resolveFilterSubregion(ctx, fctx));
159
0
}
160
161
sk_sp<SkImageFilter> SkSVGFeDiffuseLighting::makePointLight(const SkSVGRenderContext& ctx,
162
                                                            const SkSVGFilterContext& fctx,
163
0
                                                            const SkSVGFePointLight* light) const {
164
0
    return SkImageFilters::PointLitDiffuse(
165
0
            this->resolveXYZ(ctx, fctx, light->getX(), light->getY(), light->getZ()),
166
0
            this->resolveLightingColor(ctx),
167
0
            this->getSurfaceScale(),
168
0
            this->getDiffuseConstant(),
169
0
            fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
170
0
            this->resolveFilterSubregion(ctx, fctx));
171
0
}
172
173
sk_sp<SkImageFilter> SkSVGFeDiffuseLighting::makeSpotLight(const SkSVGRenderContext& ctx,
174
                                                           const SkSVGFilterContext& fctx,
175
0
                                                           const SkSVGFeSpotLight* light) const {
176
0
    const auto& limitingConeAngle = light->getLimitingConeAngle();
177
0
    const float cutoffAngle = limitingConeAngle.isValid() ? *limitingConeAngle : 180.f;
178
179
0
    return SkImageFilters::SpotLitDiffuse(
180
0
            this->resolveXYZ(ctx, fctx, light->getX(), light->getY(), light->getZ()),
181
0
            this->resolveXYZ(
182
0
                    ctx, fctx, light->getPointsAtX(), light->getPointsAtY(), light->getPointsAtZ()),
183
0
            light->getSpecularExponent(),
184
0
            cutoffAngle,
185
0
            this->resolveLightingColor(ctx),
186
0
            this->getSurfaceScale(),
187
0
            this->getDiffuseConstant(),
188
0
            fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
189
0
            this->resolveFilterSubregion(ctx, fctx));
190
0
}