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