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(SVG) && ENABLE(FILTERS)
27 #include "SVGFilterElement.h"
28
29 #include "Attr.h"
30 #include "RenderSVGResourceFilter.h"
31 #include "SVGFilterBuilder.h"
32 #include "SVGFilterPrimitiveStandardAttributes.h"
33 #include "SVGNames.h"
34 #include "SVGParserUtilities.h"
35 #include "SVGUnitTypes.h"
36
37 namespace WebCore {
38
39 // Animated property definitions
DEFINE_ANIMATED_ENUMERATION(SVGFilterElement,SVGNames::filterUnitsAttr,FilterUnits,filterUnits)40 DEFINE_ANIMATED_ENUMERATION(SVGFilterElement, SVGNames::filterUnitsAttr, FilterUnits, filterUnits)
41 DEFINE_ANIMATED_ENUMERATION(SVGFilterElement, SVGNames::primitiveUnitsAttr, PrimitiveUnits, primitiveUnits)
42 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::xAttr, X, x)
43 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::yAttr, Y, y)
44 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::widthAttr, Width, width)
45 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::heightAttr, Height, height)
46 DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFilterElement, SVGNames::filterResAttr, filterResXIdentifier(), FilterResX, filterResX)
47 DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFilterElement, SVGNames::filterResAttr, filterResYIdentifier(), FilterResY, filterResY)
48 DEFINE_ANIMATED_STRING(SVGFilterElement, XLinkNames::hrefAttr, Href, href)
49 DEFINE_ANIMATED_BOOLEAN(SVGFilterElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
50
51 inline SVGFilterElement::SVGFilterElement(const QualifiedName& tagName, Document* document)
52 : SVGStyledElement(tagName, document)
53 , SVGURIReference()
54 , SVGLangSpace()
55 , SVGExternalResourcesRequired()
56 , m_filterUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
57 , m_primitiveUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
58 , m_x(LengthModeWidth, "-10%")
59 , m_y(LengthModeHeight, "-10%")
60 , m_width(LengthModeWidth, "120%")
61 , m_height(LengthModeHeight, "120%")
62 {
63 // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
64 // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
65 }
66
create(const QualifiedName & tagName,Document * document)67 PassRefPtr<SVGFilterElement> SVGFilterElement::create(const QualifiedName& tagName, Document* document)
68 {
69 return adoptRef(new SVGFilterElement(tagName, document));
70 }
71
filterResXIdentifier()72 const AtomicString& SVGFilterElement::filterResXIdentifier()
73 {
74 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGFilterResX"));
75 return s_identifier;
76 }
77
filterResYIdentifier()78 const AtomicString& SVGFilterElement::filterResYIdentifier()
79 {
80 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGFilterResY"));
81 return s_identifier;
82 }
83
setFilterRes(unsigned long filterResX,unsigned long filterResY)84 void SVGFilterElement::setFilterRes(unsigned long filterResX, unsigned long filterResY)
85 {
86 setFilterResXBaseValue(filterResX);
87 setFilterResYBaseValue(filterResY);
88
89 if (RenderObject* object = renderer())
90 object->setNeedsLayout(true);
91 }
92
parseMappedAttribute(Attribute * attr)93 void SVGFilterElement::parseMappedAttribute(Attribute* attr)
94 {
95 const String& value = attr->value();
96 if (attr->name() == SVGNames::filterUnitsAttr) {
97 if (value == "userSpaceOnUse")
98 setFilterUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
99 else if (value == "objectBoundingBox")
100 setFilterUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
101 } else if (attr->name() == SVGNames::primitiveUnitsAttr) {
102 if (value == "userSpaceOnUse")
103 setPrimitiveUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
104 else if (value == "objectBoundingBox")
105 setPrimitiveUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
106 } else if (attr->name() == SVGNames::xAttr)
107 setXBaseValue(SVGLength(LengthModeWidth, value));
108 else if (attr->name() == SVGNames::yAttr)
109 setYBaseValue(SVGLength(LengthModeHeight, value));
110 else if (attr->name() == SVGNames::widthAttr)
111 setWidthBaseValue(SVGLength(LengthModeWidth, value));
112 else if (attr->name() == SVGNames::heightAttr)
113 setHeightBaseValue(SVGLength(LengthModeHeight, value));
114 else if (attr->name() == SVGNames::filterResAttr) {
115 float x, y;
116 if (parseNumberOptionalNumber(value, x, y)) {
117 setFilterResXBaseValue(x);
118 setFilterResYBaseValue(y);
119 }
120 } else {
121 if (SVGURIReference::parseMappedAttribute(attr))
122 return;
123 if (SVGLangSpace::parseMappedAttribute(attr))
124 return;
125 if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
126 return;
127
128 SVGStyledElement::parseMappedAttribute(attr);
129 }
130 }
131
svgAttributeChanged(const QualifiedName & attrName)132 void SVGFilterElement::svgAttributeChanged(const QualifiedName& attrName)
133 {
134 SVGStyledElement::svgAttributeChanged(attrName);
135
136 bool invalidateClients = false;
137 if (attrName == SVGNames::xAttr
138 || attrName == SVGNames::yAttr
139 || attrName == SVGNames::widthAttr
140 || attrName == SVGNames::heightAttr) {
141 invalidateClients = true;
142 updateRelativeLengthsInformation();
143 }
144
145 RenderObject* object = renderer();
146 if (!object)
147 return;
148
149 if (invalidateClients
150 || attrName == SVGNames::filterUnitsAttr
151 || attrName == SVGNames::primitiveUnitsAttr
152 || attrName == SVGNames::filterResAttr
153 || SVGStyledElement::isKnownAttribute(attrName)
154 || SVGURIReference::isKnownAttribute(attrName)
155 || SVGLangSpace::isKnownAttribute(attrName)
156 || SVGExternalResourcesRequired::isKnownAttribute(attrName))
157 object->setNeedsLayout(true);
158 }
159
synchronizeProperty(const QualifiedName & attrName)160 void SVGFilterElement::synchronizeProperty(const QualifiedName& attrName)
161 {
162 SVGStyledElement::synchronizeProperty(attrName);
163
164 if (attrName == anyQName()) {
165 synchronizeX();
166 synchronizeY();
167 synchronizeWidth();
168 synchronizeHeight();
169 synchronizeFilterUnits();
170 synchronizePrimitiveUnits();
171 synchronizeFilterResX();
172 synchronizeFilterResY();
173 synchronizeExternalResourcesRequired();
174 synchronizeHref();
175 return;
176 }
177
178 if (attrName == SVGNames::xAttr)
179 synchronizeX();
180 else if (attrName == SVGNames::yAttr)
181 synchronizeY();
182 else if (attrName == SVGNames::widthAttr)
183 synchronizeWidth();
184 else if (attrName == SVGNames::heightAttr)
185 synchronizeHeight();
186 else if (attrName == SVGNames::filterUnitsAttr)
187 synchronizeFilterUnits();
188 else if (attrName == SVGNames::primitiveUnitsAttr)
189 synchronizePrimitiveUnits();
190 else if (attrName == SVGNames::filterResAttr) {
191 synchronizeFilterResX();
192 synchronizeFilterResY();
193 } else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
194 synchronizeExternalResourcesRequired();
195 else if (SVGURIReference::isKnownAttribute(attrName))
196 synchronizeHref();
197 }
198
attributeToPropertyTypeMap()199 AttributeToPropertyTypeMap& SVGFilterElement::attributeToPropertyTypeMap()
200 {
201 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
202 return s_attributeToPropertyTypeMap;
203 }
204
fillAttributeToPropertyTypeMap()205 void SVGFilterElement::fillAttributeToPropertyTypeMap()
206 {
207 AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap();
208
209 SVGStyledElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap);
210 attributeToPropertyTypeMap.set(SVGNames::filterUnitsAttr, AnimatedEnumeration);
211 attributeToPropertyTypeMap.set(SVGNames::primitiveUnitsAttr, AnimatedEnumeration);
212 attributeToPropertyTypeMap.set(SVGNames::xAttr, AnimatedLength);
213 attributeToPropertyTypeMap.set(SVGNames::yAttr, AnimatedLength);
214 attributeToPropertyTypeMap.set(SVGNames::widthAttr, AnimatedLength);
215 attributeToPropertyTypeMap.set(SVGNames::heightAttr, AnimatedLength);
216 attributeToPropertyTypeMap.set(SVGNames::filterResAttr, AnimatedNumberOptionalNumber);
217 attributeToPropertyTypeMap.set(XLinkNames::hrefAttr, AnimatedString);
218 }
219
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)220 void SVGFilterElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
221 {
222 SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
223
224 if (changedByParser)
225 return;
226
227 if (RenderObject* object = renderer())
228 object->setNeedsLayout(true);
229 }
230
filterBoundingBox(const FloatRect & objectBoundingBox) const231 FloatRect SVGFilterElement::filterBoundingBox(const FloatRect& objectBoundingBox) const
232 {
233 FloatRect filterBBox;
234 if (filterUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
235 filterBBox = FloatRect(x().valueAsPercentage() * objectBoundingBox.width() + objectBoundingBox.x(),
236 y().valueAsPercentage() * objectBoundingBox.height() + objectBoundingBox.y(),
237 width().valueAsPercentage() * objectBoundingBox.width(),
238 height().valueAsPercentage() * objectBoundingBox.height());
239 else
240 filterBBox = FloatRect(x().value(this),
241 y().value(this),
242 width().value(this),
243 height().value(this));
244
245 return filterBBox;
246 }
247
createRenderer(RenderArena * arena,RenderStyle *)248 RenderObject* SVGFilterElement::createRenderer(RenderArena* arena, RenderStyle*)
249 {
250 return new (arena) RenderSVGResourceFilter(this);
251 }
252
selfHasRelativeLengths() const253 bool SVGFilterElement::selfHasRelativeLengths() const
254 {
255 return x().isRelative()
256 || y().isRelative()
257 || width().isRelative()
258 || height().isRelative();
259 }
260
261 }
262
263 #endif
264