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 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB.  If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22#include "config.h"
23
24#include "core/svg/SVGFESpecularLightingElement.h"
25
26#include "platform/graphics/filters/FilterEffect.h"
27#include "core/rendering/style/RenderStyle.h"
28#include "core/svg/SVGElementInstance.h"
29#include "core/svg/SVGParserUtilities.h"
30#include "core/svg/graphics/filters/SVGFilterBuilder.h"
31
32namespace WebCore {
33
34// Animated property definitions
35DEFINE_ANIMATED_STRING(SVGFESpecularLightingElement, SVGNames::inAttr, In1, in1)
36DEFINE_ANIMATED_NUMBER(SVGFESpecularLightingElement, SVGNames::specularConstantAttr, SpecularConstant, specularConstant)
37DEFINE_ANIMATED_NUMBER(SVGFESpecularLightingElement, SVGNames::specularExponentAttr, SpecularExponent, specularExponent)
38DEFINE_ANIMATED_NUMBER(SVGFESpecularLightingElement, SVGNames::surfaceScaleAttr, SurfaceScale, surfaceScale)
39DEFINE_ANIMATED_NUMBER_MULTIPLE_WRAPPERS(SVGFESpecularLightingElement, SVGNames::kernelUnitLengthAttr, kernelUnitLengthXIdentifier(), KernelUnitLengthX, kernelUnitLengthX)
40DEFINE_ANIMATED_NUMBER_MULTIPLE_WRAPPERS(SVGFESpecularLightingElement, SVGNames::kernelUnitLengthAttr, kernelUnitLengthYIdentifier(), KernelUnitLengthY, kernelUnitLengthY)
41
42BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFESpecularLightingElement)
43    REGISTER_LOCAL_ANIMATED_PROPERTY(in1)
44    REGISTER_LOCAL_ANIMATED_PROPERTY(specularConstant)
45    REGISTER_LOCAL_ANIMATED_PROPERTY(specularExponent)
46    REGISTER_LOCAL_ANIMATED_PROPERTY(surfaceScale)
47    REGISTER_LOCAL_ANIMATED_PROPERTY(kernelUnitLengthX)
48    REGISTER_LOCAL_ANIMATED_PROPERTY(kernelUnitLengthY)
49    REGISTER_PARENT_ANIMATED_PROPERTIES(SVGFilterPrimitiveStandardAttributes)
50END_REGISTER_ANIMATED_PROPERTIES
51
52inline SVGFESpecularLightingElement::SVGFESpecularLightingElement(Document& document)
53    : SVGFilterPrimitiveStandardAttributes(SVGNames::feSpecularLightingTag, document)
54    , m_specularConstant(1)
55    , m_specularExponent(1)
56    , m_surfaceScale(1)
57{
58    ScriptWrappable::init(this);
59    registerAnimatedPropertiesForSVGFESpecularLightingElement();
60}
61
62PassRefPtr<SVGFESpecularLightingElement> SVGFESpecularLightingElement::create(Document& document)
63{
64    return adoptRef(new SVGFESpecularLightingElement(document));
65}
66
67const AtomicString& SVGFESpecularLightingElement::kernelUnitLengthXIdentifier()
68{
69    DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGKernelUnitLengthX", AtomicString::ConstructFromLiteral));
70    return s_identifier;
71}
72
73const AtomicString& SVGFESpecularLightingElement::kernelUnitLengthYIdentifier()
74{
75    DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGKernelUnitLengthY", AtomicString::ConstructFromLiteral));
76    return s_identifier;
77}
78
79bool SVGFESpecularLightingElement::isSupportedAttribute(const QualifiedName& attrName)
80{
81    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
82    if (supportedAttributes.isEmpty()) {
83        supportedAttributes.add(SVGNames::inAttr);
84        supportedAttributes.add(SVGNames::specularConstantAttr);
85        supportedAttributes.add(SVGNames::specularExponentAttr);
86        supportedAttributes.add(SVGNames::surfaceScaleAttr);
87        supportedAttributes.add(SVGNames::kernelUnitLengthAttr);
88    }
89    return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
90}
91
92void SVGFESpecularLightingElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
93{
94    if (!isSupportedAttribute(name)) {
95        SVGFilterPrimitiveStandardAttributes::parseAttribute(name, value);
96        return;
97    }
98
99    if (name == SVGNames::inAttr) {
100        setIn1BaseValue(value);
101        return;
102    }
103
104    if (name == SVGNames::surfaceScaleAttr) {
105        setSurfaceScaleBaseValue(value.toFloat());
106        return;
107    }
108
109    if (name == SVGNames::specularConstantAttr) {
110        setSpecularConstantBaseValue(value.toFloat());
111        return;
112    }
113
114    if (name == SVGNames::specularExponentAttr) {
115        setSpecularExponentBaseValue(value.toFloat());
116        return;
117    }
118
119    if (name == SVGNames::kernelUnitLengthAttr) {
120        float x, y;
121        if (parseNumberOptionalNumber(value, x, y)) {
122            setKernelUnitLengthXBaseValue(x);
123            setKernelUnitLengthYBaseValue(y);
124        }
125        return;
126    }
127
128    ASSERT_NOT_REACHED();
129}
130
131bool SVGFESpecularLightingElement::setFilterEffectAttribute(FilterEffect* effect, const QualifiedName& attrName)
132{
133    FESpecularLighting* specularLighting = static_cast<FESpecularLighting*>(effect);
134
135    if (attrName == SVGNames::lighting_colorAttr) {
136        RenderObject* renderer = this->renderer();
137        ASSERT(renderer);
138        ASSERT(renderer->style());
139        return specularLighting->setLightingColor(renderer->style()->svgStyle()->lightingColor());
140    }
141    if (attrName == SVGNames::surfaceScaleAttr)
142        return specularLighting->setSurfaceScale(surfaceScaleCurrentValue());
143    if (attrName == SVGNames::specularConstantAttr)
144        return specularLighting->setSpecularConstant(specularConstantCurrentValue());
145    if (attrName == SVGNames::specularExponentAttr)
146        return specularLighting->setSpecularExponent(specularExponentCurrentValue());
147
148    LightSource* lightSource = const_cast<LightSource*>(specularLighting->lightSource());
149    const SVGFELightElement* lightElement = SVGFELightElement::findLightElement(this);
150    ASSERT(lightSource);
151    ASSERT(lightElement);
152
153    if (attrName == SVGNames::azimuthAttr)
154        return lightSource->setAzimuth(lightElement->azimuthCurrentValue());
155    if (attrName == SVGNames::elevationAttr)
156        return lightSource->setElevation(lightElement->elevationCurrentValue());
157    if (attrName == SVGNames::xAttr)
158        return lightSource->setX(lightElement->xCurrentValue());
159    if (attrName == SVGNames::yAttr)
160        return lightSource->setY(lightElement->yCurrentValue());
161    if (attrName == SVGNames::zAttr)
162        return lightSource->setZ(lightElement->zCurrentValue());
163    if (attrName == SVGNames::pointsAtXAttr)
164        return lightSource->setPointsAtX(lightElement->pointsAtXCurrentValue());
165    if (attrName == SVGNames::pointsAtYAttr)
166        return lightSource->setPointsAtY(lightElement->pointsAtYCurrentValue());
167    if (attrName == SVGNames::pointsAtZAttr)
168        return lightSource->setPointsAtZ(lightElement->pointsAtZCurrentValue());
169    if (attrName == SVGNames::specularExponentAttr)
170        return lightSource->setSpecularExponent(lightElement->specularExponentCurrentValue());
171    if (attrName == SVGNames::limitingConeAngleAttr)
172        return lightSource->setLimitingConeAngle(lightElement->limitingConeAngleCurrentValue());
173
174    ASSERT_NOT_REACHED();
175    return false;
176}
177
178void SVGFESpecularLightingElement::svgAttributeChanged(const QualifiedName& attrName)
179{
180    if (!isSupportedAttribute(attrName)) {
181        SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(attrName);
182        return;
183    }
184
185    SVGElementInstance::InvalidationGuard invalidationGuard(this);
186
187    if (attrName == SVGNames::surfaceScaleAttr
188        || attrName == SVGNames::specularConstantAttr
189        || attrName == SVGNames::specularExponentAttr
190        || attrName == SVGNames::kernelUnitLengthAttr) {
191        primitiveAttributeChanged(attrName);
192        return;
193    }
194
195    if (attrName == SVGNames::inAttr) {
196        invalidate();
197        return;
198    }
199
200    ASSERT_NOT_REACHED();
201}
202
203void SVGFESpecularLightingElement::lightElementAttributeChanged(const SVGFELightElement* lightElement, const QualifiedName& attrName)
204{
205    if (SVGFELightElement::findLightElement(this) != lightElement)
206        return;
207
208    // The light element has different attribute names so attrName can identify the requested attribute.
209    primitiveAttributeChanged(attrName);
210}
211
212PassRefPtr<FilterEffect> SVGFESpecularLightingElement::build(SVGFilterBuilder* filterBuilder, Filter* filter)
213{
214    FilterEffect* input1 = filterBuilder->getEffectById(in1CurrentValue());
215
216    if (!input1)
217        return 0;
218
219    RefPtr<LightSource> lightSource = SVGFELightElement::findLightSource(this);
220    if (!lightSource)
221        return 0;
222
223    RenderObject* renderer = this->renderer();
224    if (!renderer)
225        return 0;
226
227    ASSERT(renderer->style());
228    Color color = renderer->style()->svgStyle()->lightingColor();
229
230    RefPtr<FilterEffect> effect = FESpecularLighting::create(filter, color, surfaceScaleCurrentValue(), specularConstantCurrentValue(),
231        specularExponentCurrentValue(), kernelUnitLengthXCurrentValue(), kernelUnitLengthYCurrentValue(), lightSource.release());
232    effect->inputEffects().append(input1);
233    return effect.release();
234}
235
236}
237