1/*
2 * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4 * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
5 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB.  If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25
26#include "core/svg/SVGFilterElement.h"
27
28#include "XLinkNames.h"
29#include "core/rendering/svg/RenderSVGResourceFilter.h"
30#include "core/svg/SVGElementInstance.h"
31#include "core/svg/SVGParserUtilities.h"
32
33namespace WebCore {
34
35// Animated property definitions
36DEFINE_ANIMATED_ENUMERATION(SVGFilterElement, SVGNames::filterUnitsAttr, FilterUnits, filterUnits, SVGUnitTypes::SVGUnitType)
37DEFINE_ANIMATED_ENUMERATION(SVGFilterElement, SVGNames::primitiveUnitsAttr, PrimitiveUnits, primitiveUnits, SVGUnitTypes::SVGUnitType)
38DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::xAttr, X, x)
39DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::yAttr, Y, y)
40DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::widthAttr, Width, width)
41DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::heightAttr, Height, height)
42DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFilterElement, SVGNames::filterResAttr, filterResXIdentifier(), FilterResX, filterResX)
43DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFilterElement, SVGNames::filterResAttr, filterResYIdentifier(), FilterResY, filterResY)
44DEFINE_ANIMATED_STRING(SVGFilterElement, XLinkNames::hrefAttr, Href, href)
45DEFINE_ANIMATED_BOOLEAN(SVGFilterElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
46
47BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFilterElement)
48    REGISTER_LOCAL_ANIMATED_PROPERTY(filterUnits)
49    REGISTER_LOCAL_ANIMATED_PROPERTY(primitiveUnits)
50    REGISTER_LOCAL_ANIMATED_PROPERTY(x)
51    REGISTER_LOCAL_ANIMATED_PROPERTY(y)
52    REGISTER_LOCAL_ANIMATED_PROPERTY(width)
53    REGISTER_LOCAL_ANIMATED_PROPERTY(height)
54    REGISTER_LOCAL_ANIMATED_PROPERTY(filterResX)
55    REGISTER_LOCAL_ANIMATED_PROPERTY(filterResY)
56    REGISTER_LOCAL_ANIMATED_PROPERTY(href)
57    REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
58END_REGISTER_ANIMATED_PROPERTIES
59
60inline SVGFilterElement::SVGFilterElement(Document& document)
61    : SVGElement(SVGNames::filterTag, document)
62    , m_filterUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
63    , m_primitiveUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
64    , m_x(LengthModeWidth, "-10%")
65    , m_y(LengthModeHeight, "-10%")
66    , m_width(LengthModeWidth, "120%")
67    , m_height(LengthModeHeight, "120%")
68{
69    // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
70    // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
71    ScriptWrappable::init(this);
72    registerAnimatedPropertiesForSVGFilterElement();
73}
74
75PassRefPtr<SVGFilterElement> SVGFilterElement::create(Document& document)
76{
77    return adoptRef(new SVGFilterElement(document));
78}
79
80const AtomicString& SVGFilterElement::filterResXIdentifier()
81{
82    DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGFilterResX", AtomicString::ConstructFromLiteral));
83    return s_identifier;
84}
85
86const AtomicString& SVGFilterElement::filterResYIdentifier()
87{
88    DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGFilterResY", AtomicString::ConstructFromLiteral));
89    return s_identifier;
90}
91
92void SVGFilterElement::setFilterRes(unsigned filterResX, unsigned filterResY)
93{
94    setFilterResXBaseValue(filterResX);
95    setFilterResYBaseValue(filterResY);
96
97    RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
98    if (renderer)
99        renderer->invalidateCacheAndMarkForLayout();
100}
101
102bool SVGFilterElement::isSupportedAttribute(const QualifiedName& attrName)
103{
104    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
105    if (supportedAttributes.isEmpty()) {
106        SVGURIReference::addSupportedAttributes(supportedAttributes);
107        SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
108        supportedAttributes.add(SVGNames::filterUnitsAttr);
109        supportedAttributes.add(SVGNames::primitiveUnitsAttr);
110        supportedAttributes.add(SVGNames::xAttr);
111        supportedAttributes.add(SVGNames::yAttr);
112        supportedAttributes.add(SVGNames::widthAttr);
113        supportedAttributes.add(SVGNames::heightAttr);
114        supportedAttributes.add(SVGNames::filterResAttr);
115    }
116    return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
117}
118
119void SVGFilterElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
120{
121    SVGParsingError parseError = NoError;
122
123    if (!isSupportedAttribute(name))
124        SVGElement::parseAttribute(name, value);
125    else if (name == SVGNames::filterUnitsAttr) {
126        SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
127        if (propertyValue > 0)
128            setFilterUnitsBaseValue(propertyValue);
129    } else if (name == SVGNames::primitiveUnitsAttr) {
130        SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
131        if (propertyValue > 0)
132            setPrimitiveUnitsBaseValue(propertyValue);
133    } else if (name == SVGNames::xAttr)
134        setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
135    else if (name == SVGNames::yAttr)
136        setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
137    else if (name == SVGNames::widthAttr)
138        setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
139    else if (name == SVGNames::heightAttr)
140        setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
141    else if (name == SVGNames::filterResAttr) {
142        float x, y;
143        if (parseNumberOptionalNumber(value, x, y)) {
144            setFilterResXBaseValue(x);
145            setFilterResYBaseValue(y);
146        }
147    } else if (SVGURIReference::parseAttribute(name, value)
148             || SVGExternalResourcesRequired::parseAttribute(name, value)) {
149    } else
150        ASSERT_NOT_REACHED();
151
152    reportAttributeParsingError(parseError, name, value);
153}
154
155void SVGFilterElement::svgAttributeChanged(const QualifiedName& attrName)
156{
157    if (!isSupportedAttribute(attrName)) {
158        SVGElement::svgAttributeChanged(attrName);
159        return;
160    }
161
162    SVGElementInstance::InvalidationGuard invalidationGuard(this);
163
164    if (attrName == SVGNames::xAttr
165        || attrName == SVGNames::yAttr
166        || attrName == SVGNames::widthAttr
167        || attrName == SVGNames::heightAttr)
168        updateRelativeLengthsInformation();
169
170    RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
171    if (renderer)
172        renderer->invalidateCacheAndMarkForLayout();
173}
174
175void SVGFilterElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
176{
177    SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
178
179    if (changedByParser)
180        return;
181
182    if (RenderObject* object = renderer())
183        object->setNeedsLayout();
184}
185
186RenderObject* SVGFilterElement::createRenderer(RenderStyle*)
187{
188    RenderSVGResourceFilter* renderer = new RenderSVGResourceFilter(this);
189
190    HashSet<RefPtr<Node> >::iterator layerEnd = m_clientsToAdd.end();
191    for (HashSet<RefPtr<Node> >::iterator it = m_clientsToAdd.begin(); it != layerEnd; ++it)
192        renderer->addClientRenderLayer((*it).get());
193    m_clientsToAdd.clear();
194
195    return renderer;
196}
197
198bool SVGFilterElement::childShouldCreateRenderer(const Node& child) const
199{
200    if (!child.isSVGElement())
201        return false;
202
203    const SVGElement* svgElement = toSVGElement(&child);
204
205    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, allowedChildElementTags, ());
206    if (allowedChildElementTags.isEmpty()) {
207        allowedChildElementTags.add(SVGNames::feBlendTag);
208        allowedChildElementTags.add(SVGNames::feColorMatrixTag);
209        allowedChildElementTags.add(SVGNames::feComponentTransferTag);
210        allowedChildElementTags.add(SVGNames::feCompositeTag);
211        allowedChildElementTags.add(SVGNames::feConvolveMatrixTag);
212        allowedChildElementTags.add(SVGNames::feDiffuseLightingTag);
213        allowedChildElementTags.add(SVGNames::feDisplacementMapTag);
214        allowedChildElementTags.add(SVGNames::feDistantLightTag);
215        allowedChildElementTags.add(SVGNames::feDropShadowTag);
216        allowedChildElementTags.add(SVGNames::feFloodTag);
217        allowedChildElementTags.add(SVGNames::feFuncATag);
218        allowedChildElementTags.add(SVGNames::feFuncBTag);
219        allowedChildElementTags.add(SVGNames::feFuncGTag);
220        allowedChildElementTags.add(SVGNames::feFuncRTag);
221        allowedChildElementTags.add(SVGNames::feGaussianBlurTag);
222        allowedChildElementTags.add(SVGNames::feImageTag);
223        allowedChildElementTags.add(SVGNames::feMergeTag);
224        allowedChildElementTags.add(SVGNames::feMergeNodeTag);
225        allowedChildElementTags.add(SVGNames::feMorphologyTag);
226        allowedChildElementTags.add(SVGNames::feOffsetTag);
227        allowedChildElementTags.add(SVGNames::fePointLightTag);
228        allowedChildElementTags.add(SVGNames::feSpecularLightingTag);
229        allowedChildElementTags.add(SVGNames::feSpotLightTag);
230        allowedChildElementTags.add(SVGNames::feTileTag);
231        allowedChildElementTags.add(SVGNames::feTurbulenceTag);
232    }
233
234    return allowedChildElementTags.contains<SVGAttributeHashTranslator>(svgElement->tagQName());
235}
236
237bool SVGFilterElement::selfHasRelativeLengths() const
238{
239    return xCurrentValue().isRelative()
240        || yCurrentValue().isRelative()
241        || widthCurrentValue().isRelative()
242        || heightCurrentValue().isRelative();
243}
244
245void SVGFilterElement::addClient(Node* client)
246{
247    ASSERT(client);
248    m_clientsToAdd.add(client);
249}
250
251void SVGFilterElement::removeClient(Node* client)
252{
253    ASSERT(client);
254    m_clientsToAdd.remove(client);
255}
256
257}
258