1/*
2 * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4 * Copyright (C) 2005 Oliver Hunt <oliver@nerget.com>
5 * Copyright (C) 2018 Apple Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#include "config.h"
24#include "SVGFESpecularLightingElement.h"
25
26#include "FilterEffect.h"
27#include "RenderStyle.h"
28#include "SVGFELightElement.h"
29#include "SVGFilterBuilder.h"
30#include "SVGNames.h"
31#include "SVGParserUtilities.h"
32#include <wtf/IsoMallocInlines.h>
33
34namespace WebCore {
35
36WTF_MAKE_ISO_ALLOCATED_IMPL(SVGFESpecularLightingElement);
37
38inline SVGFESpecularLightingElement::SVGFESpecularLightingElement(const QualifiedName& tagName, Document& document)
39 : SVGFilterPrimitiveStandardAttributes(tagName, document)
40{
41 ASSERT(hasTagName(SVGNames::feSpecularLightingTag));
42
43 static std::once_flag onceFlag;
44 std::call_once(onceFlag, [] {
45 PropertyRegistry::registerProperty<SVGNames::inAttr, &SVGFESpecularLightingElement::m_in1>();
46 PropertyRegistry::registerProperty<SVGNames::specularConstantAttr, &SVGFESpecularLightingElement::m_specularConstant>();
47 PropertyRegistry::registerProperty<SVGNames::specularExponentAttr, &SVGFESpecularLightingElement::m_specularExponent>();
48 PropertyRegistry::registerProperty<SVGNames::surfaceScaleAttr, &SVGFESpecularLightingElement::m_surfaceScale>();
49 PropertyRegistry::registerProperty<SVGNames::kernelUnitLengthAttr, &SVGFESpecularLightingElement::m_kernelUnitLengthX, &SVGFESpecularLightingElement::m_kernelUnitLengthY>();
50 });
51}
52
53Ref<SVGFESpecularLightingElement> SVGFESpecularLightingElement::create(const QualifiedName& tagName, Document& document)
54{
55 return adoptRef(*new SVGFESpecularLightingElement(tagName, document));
56}
57
58void SVGFESpecularLightingElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
59{
60 if (name == SVGNames::inAttr) {
61 m_in1->setBaseValInternal(value);
62 return;
63 }
64
65 if (name == SVGNames::surfaceScaleAttr) {
66 m_surfaceScale->setBaseValInternal(value.toFloat());
67 return;
68 }
69
70 if (name == SVGNames::specularConstantAttr) {
71 m_specularConstant->setBaseValInternal(value.toFloat());
72 return;
73 }
74
75 if (name == SVGNames::specularExponentAttr) {
76 m_specularExponent->setBaseValInternal(value.toFloat());
77 return;
78 }
79
80 if (name == SVGNames::kernelUnitLengthAttr) {
81 float x, y;
82 if (parseNumberOptionalNumber(value, x, y)) {
83 m_kernelUnitLengthX->setBaseValInternal(x);
84 m_kernelUnitLengthY->setBaseValInternal(y);
85 }
86 return;
87 }
88
89 SVGFilterPrimitiveStandardAttributes::parseAttribute(name, value);
90}
91
92bool SVGFESpecularLightingElement::setFilterEffectAttribute(FilterEffect* effect, const QualifiedName& attrName)
93{
94 FESpecularLighting* specularLighting = static_cast<FESpecularLighting*>(effect);
95
96 if (attrName == SVGNames::lighting_colorAttr) {
97 RenderObject* renderer = this->renderer();
98 ASSERT(renderer);
99 Color color = renderer->style().colorByApplyingColorFilter(renderer->style().svgStyle().lightingColor());
100 return specularLighting->setLightingColor(color);
101 }
102 if (attrName == SVGNames::surfaceScaleAttr)
103 return specularLighting->setSurfaceScale(surfaceScale());
104 if (attrName == SVGNames::specularConstantAttr)
105 return specularLighting->setSpecularConstant(specularConstant());
106 if (attrName == SVGNames::specularExponentAttr)
107 return specularLighting->setSpecularExponent(specularExponent());
108
109 auto& lightSource = const_cast<LightSource&>(specularLighting->lightSource());
110 const SVGFELightElement* lightElement = SVGFELightElement::findLightElement(this);
111 ASSERT(lightElement);
112
113 if (attrName == SVGNames::azimuthAttr)
114 return lightSource.setAzimuth(lightElement->azimuth());
115 if (attrName == SVGNames::elevationAttr)
116 return lightSource.setElevation(lightElement->elevation());
117 if (attrName == SVGNames::xAttr)
118 return lightSource.setX(lightElement->x());
119 if (attrName == SVGNames::yAttr)
120 return lightSource.setY(lightElement->y());
121 if (attrName == SVGNames::zAttr)
122 return lightSource.setZ(lightElement->z());
123 if (attrName == SVGNames::pointsAtXAttr)
124 return lightSource.setPointsAtX(lightElement->pointsAtX());
125 if (attrName == SVGNames::pointsAtYAttr)
126 return lightSource.setPointsAtY(lightElement->pointsAtY());
127 if (attrName == SVGNames::pointsAtZAttr)
128 return lightSource.setPointsAtZ(lightElement->pointsAtZ());
129 if (attrName == SVGNames::specularExponentAttr)
130 return lightSource.setSpecularExponent(lightElement->specularExponent());
131 if (attrName == SVGNames::limitingConeAngleAttr)
132 return lightSource.setLimitingConeAngle(lightElement->limitingConeAngle());
133
134 ASSERT_NOT_REACHED();
135 return false;
136}
137
138void SVGFESpecularLightingElement::svgAttributeChanged(const QualifiedName& attrName)
139{
140 if (attrName == SVGNames::surfaceScaleAttr || attrName == SVGNames::specularConstantAttr || attrName == SVGNames::specularExponentAttr || attrName == SVGNames::kernelUnitLengthAttr) {
141 InstanceInvalidationGuard guard(*this);
142 primitiveAttributeChanged(attrName);
143 return;
144 }
145
146 if (attrName == SVGNames::inAttr) {
147 InstanceInvalidationGuard guard(*this);
148 invalidate();
149 return;
150 }
151
152 SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(attrName);
153}
154
155void SVGFESpecularLightingElement::lightElementAttributeChanged(const SVGFELightElement* lightElement, const QualifiedName& attrName)
156{
157 if (SVGFELightElement::findLightElement(this) != lightElement)
158 return;
159
160 // The light element has different attribute names so attrName can identify the requested attribute.
161 primitiveAttributeChanged(attrName);
162}
163
164RefPtr<FilterEffect> SVGFESpecularLightingElement::build(SVGFilterBuilder* filterBuilder, Filter& filter) const
165{
166 auto input1 = filterBuilder->getEffectById(in1());
167
168 if (!input1)
169 return nullptr;
170
171 auto lightElement = makeRefPtr(SVGFELightElement::findLightElement(this));
172 if (!lightElement)
173 return nullptr;
174
175 auto lightSource = lightElement->lightSource(*filterBuilder);
176
177 RenderObject* renderer = this->renderer();
178 if (!renderer)
179 return nullptr;
180
181 Color color = renderer->style().colorByApplyingColorFilter(renderer->style().svgStyle().lightingColor());
182
183 auto effect = FESpecularLighting::create(filter, color, surfaceScale(), specularConstant(), specularExponent(), kernelUnitLengthX(), kernelUnitLengthY(), WTFMove(lightSource));
184 effect->inputEffects().append(input1);
185 return effect;
186}
187
188}
189