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