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#if ENABLE(FILTERS)
27#include "SVGFilterElement.h"
28
29#include "Attr.h"
30#include "RenderSVGResourceFilter.h"
31#include "SVGElementInstance.h"
32#include "SVGFilterBuilder.h"
33#include "SVGFilterPrimitiveStandardAttributes.h"
34#include "SVGNames.h"
35#include "SVGParserUtilities.h"
36#include "XLinkNames.h"
37#include <wtf/NeverDestroyed.h>
38
39namespace WebCore {
40
41// Animated property definitions
42DEFINE_ANIMATED_ENUMERATION(SVGFilterElement, SVGNames::filterUnitsAttr, FilterUnits, filterUnits, SVGUnitTypes::SVGUnitType)
43DEFINE_ANIMATED_ENUMERATION(SVGFilterElement, SVGNames::primitiveUnitsAttr, PrimitiveUnits, primitiveUnits, SVGUnitTypes::SVGUnitType)
44DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::xAttr, X, x)
45DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::yAttr, Y, y)
46DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::widthAttr, Width, width)
47DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::heightAttr, Height, height)
48DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFilterElement, SVGNames::filterResAttr, filterResXIdentifier(), FilterResX, filterResX)
49DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFilterElement, SVGNames::filterResAttr, filterResYIdentifier(), FilterResY, filterResY)
50DEFINE_ANIMATED_STRING(SVGFilterElement, XLinkNames::hrefAttr, Href, href)
51DEFINE_ANIMATED_BOOLEAN(SVGFilterElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
52
53BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFilterElement)
54    REGISTER_LOCAL_ANIMATED_PROPERTY(filterUnits)
55    REGISTER_LOCAL_ANIMATED_PROPERTY(primitiveUnits)
56    REGISTER_LOCAL_ANIMATED_PROPERTY(x)
57    REGISTER_LOCAL_ANIMATED_PROPERTY(y)
58    REGISTER_LOCAL_ANIMATED_PROPERTY(width)
59    REGISTER_LOCAL_ANIMATED_PROPERTY(height)
60    REGISTER_LOCAL_ANIMATED_PROPERTY(filterResX)
61    REGISTER_LOCAL_ANIMATED_PROPERTY(filterResY)
62    REGISTER_LOCAL_ANIMATED_PROPERTY(href)
63    REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
64END_REGISTER_ANIMATED_PROPERTIES
65
66inline SVGFilterElement::SVGFilterElement(const QualifiedName& tagName, Document& document)
67    : SVGElement(tagName, document)
68    , m_filterUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
69    , m_primitiveUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
70    , m_x(LengthModeWidth, "-10%")
71    , m_y(LengthModeHeight, "-10%")
72    , m_width(LengthModeWidth, "120%")
73    , m_height(LengthModeHeight, "120%")
74{
75    // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
76    // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
77    ASSERT(hasTagName(SVGNames::filterTag));
78    registerAnimatedPropertiesForSVGFilterElement();
79}
80
81PassRefPtr<SVGFilterElement> SVGFilterElement::create(const QualifiedName& tagName, Document& document)
82{
83    return adoptRef(new SVGFilterElement(tagName, document));
84}
85
86const AtomicString& SVGFilterElement::filterResXIdentifier()
87{
88    DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGFilterResX", AtomicString::ConstructFromLiteral));
89    return s_identifier;
90}
91
92const AtomicString& SVGFilterElement::filterResYIdentifier()
93{
94    DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGFilterResY", AtomicString::ConstructFromLiteral));
95    return s_identifier;
96}
97
98void SVGFilterElement::setFilterRes(unsigned filterResX, unsigned filterResY)
99{
100    setFilterResXBaseValue(filterResX);
101    setFilterResYBaseValue(filterResY);
102
103    if (RenderObject* object = renderer())
104        object->setNeedsLayout();
105}
106
107bool SVGFilterElement::isSupportedAttribute(const QualifiedName& attrName)
108{
109    static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes;
110    if (supportedAttributes.get().isEmpty()) {
111        SVGURIReference::addSupportedAttributes(supportedAttributes);
112        SVGLangSpace::addSupportedAttributes(supportedAttributes);
113        SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
114        supportedAttributes.get().add(SVGNames::filterUnitsAttr);
115        supportedAttributes.get().add(SVGNames::primitiveUnitsAttr);
116        supportedAttributes.get().add(SVGNames::xAttr);
117        supportedAttributes.get().add(SVGNames::yAttr);
118        supportedAttributes.get().add(SVGNames::widthAttr);
119        supportedAttributes.get().add(SVGNames::heightAttr);
120        supportedAttributes.get().add(SVGNames::filterResAttr);
121    }
122    return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName);
123}
124
125void SVGFilterElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
126{
127    SVGParsingError parseError = NoError;
128
129    if (!isSupportedAttribute(name))
130        SVGElement::parseAttribute(name, value);
131    else if (name == SVGNames::filterUnitsAttr) {
132        SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
133        if (propertyValue > 0)
134            setFilterUnitsBaseValue(propertyValue);
135    } else if (name == SVGNames::primitiveUnitsAttr) {
136        SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
137        if (propertyValue > 0)
138            setPrimitiveUnitsBaseValue(propertyValue);
139    } else if (name == SVGNames::xAttr)
140        setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
141    else if (name == SVGNames::yAttr)
142        setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
143    else if (name == SVGNames::widthAttr)
144        setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
145    else if (name == SVGNames::heightAttr)
146        setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
147    else if (name == SVGNames::filterResAttr) {
148        float x, y;
149        if (parseNumberOptionalNumber(value, x, y)) {
150            setFilterResXBaseValue(x);
151            setFilterResYBaseValue(y);
152        }
153    } else if (SVGURIReference::parseAttribute(name, value)
154             || SVGLangSpace::parseAttribute(name, value)
155             || SVGExternalResourcesRequired::parseAttribute(name, value)) {
156    } else
157        ASSERT_NOT_REACHED();
158
159    reportAttributeParsingError(parseError, name, value);
160}
161
162void SVGFilterElement::svgAttributeChanged(const QualifiedName& attrName)
163{
164    if (!isSupportedAttribute(attrName)) {
165        SVGElement::svgAttributeChanged(attrName);
166        return;
167    }
168
169    SVGElementInstance::InvalidationGuard invalidationGuard(this);
170
171    if (attrName == SVGNames::xAttr
172        || attrName == SVGNames::yAttr
173        || attrName == SVGNames::widthAttr
174        || attrName == SVGNames::heightAttr)
175        updateRelativeLengthsInformation();
176
177    if (RenderObject* object = renderer())
178        object->setNeedsLayout();
179}
180
181void SVGFilterElement::childrenChanged(const ChildChange& change)
182{
183    SVGElement::childrenChanged(change);
184
185    if (change.source == ChildChangeSourceParser)
186        return;
187
188    if (RenderObject* object = renderer())
189        object->setNeedsLayout();
190}
191
192RenderPtr<RenderElement> SVGFilterElement::createElementRenderer(PassRef<RenderStyle> style)
193{
194    return createRenderer<RenderSVGResourceFilter>(*this, WTF::move(style));
195}
196
197bool SVGFilterElement::childShouldCreateRenderer(const Node& child) const
198{
199    if (!child.isSVGElement())
200        return false;
201
202    const SVGElement& svgElement = toSVGElement(child);
203
204    static NeverDestroyed<HashSet<QualifiedName>> allowedChildElementTags;
205    if (allowedChildElementTags.get().isEmpty()) {
206        allowedChildElementTags.get().add(SVGNames::feBlendTag);
207        allowedChildElementTags.get().add(SVGNames::feColorMatrixTag);
208        allowedChildElementTags.get().add(SVGNames::feComponentTransferTag);
209        allowedChildElementTags.get().add(SVGNames::feCompositeTag);
210        allowedChildElementTags.get().add(SVGNames::feConvolveMatrixTag);
211        allowedChildElementTags.get().add(SVGNames::feDiffuseLightingTag);
212        allowedChildElementTags.get().add(SVGNames::feDisplacementMapTag);
213        allowedChildElementTags.get().add(SVGNames::feDistantLightTag);
214        allowedChildElementTags.get().add(SVGNames::feDropShadowTag);
215        allowedChildElementTags.get().add(SVGNames::feFloodTag);
216        allowedChildElementTags.get().add(SVGNames::feFuncATag);
217        allowedChildElementTags.get().add(SVGNames::feFuncBTag);
218        allowedChildElementTags.get().add(SVGNames::feFuncGTag);
219        allowedChildElementTags.get().add(SVGNames::feFuncRTag);
220        allowedChildElementTags.get().add(SVGNames::feGaussianBlurTag);
221        allowedChildElementTags.get().add(SVGNames::feImageTag);
222        allowedChildElementTags.get().add(SVGNames::feMergeTag);
223        allowedChildElementTags.get().add(SVGNames::feMergeNodeTag);
224        allowedChildElementTags.get().add(SVGNames::feMorphologyTag);
225        allowedChildElementTags.get().add(SVGNames::feOffsetTag);
226        allowedChildElementTags.get().add(SVGNames::fePointLightTag);
227        allowedChildElementTags.get().add(SVGNames::feSpecularLightingTag);
228        allowedChildElementTags.get().add(SVGNames::feSpotLightTag);
229        allowedChildElementTags.get().add(SVGNames::feTileTag);
230        allowedChildElementTags.get().add(SVGNames::feTurbulenceTag);
231    }
232
233    return allowedChildElementTags.get().contains<SVGAttributeHashTranslator>(svgElement.tagQName());
234}
235
236bool SVGFilterElement::selfHasRelativeLengths() const
237{
238    return x().isRelative()
239        || y().isRelative()
240        || width().isRelative()
241        || height().isRelative();
242}
243
244}
245
246#endif
247