/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 | } |