Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / svg / SVGElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006, 2008 Rob Buis <buis@kde.org>
4  * Copyright (C) 2008 Apple Inc. All rights reserved.
5  * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6  * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
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/SVGElement.h"
27
28 #include "HTMLNames.h"
29 #include "SVGNames.h"
30 #include "XLinkNames.h"
31 #include "XMLNames.h"
32 #include "bindings/v8/ScriptEventListener.h"
33 #include "core/css/CSSCursorImageValue.h"
34 #include "core/css/parser/BisonCSSParser.h"
35 #include "core/dom/Document.h"
36 #include "core/dom/ElementTraversal.h"
37 #include "core/dom/shadow/ShadowRoot.h"
38 #include "core/events/Event.h"
39 #include "core/frame/Settings.h"
40 #include "core/html/HTMLElement.h"
41 #include "core/rendering/RenderObject.h"
42 #include "core/rendering/svg/RenderSVGResourceContainer.h"
43 #include "core/svg/SVGCursorElement.h"
44 #include "core/svg/SVGDocumentExtensions.h"
45 #include "core/svg/SVGElementRareData.h"
46 #include "core/svg/SVGGraphicsElement.h"
47 #include "core/svg/SVGSVGElement.h"
48 #include "core/svg/SVGTitleElement.h"
49 #include "core/svg/SVGUseElement.h"
50
51 #include "wtf/TemporaryChange.h"
52
53 namespace WebCore {
54
55 using namespace HTMLNames;
56 using namespace SVGNames;
57
58 void mapAttributeToCSSProperty(HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap, const QualifiedName& attrName)
59 {
60     // FIXME: when CSS supports "transform-origin" the special case for transform_originAttr can be removed.
61     // FIXME: It's not clear the above is strictly true, as -webkit-transform-origin has non-standard behavior.
62     CSSPropertyID propertyId = cssPropertyID(attrName.localName());
63     if (!propertyId && attrName == transform_originAttr) {
64         propertyId = CSSPropertyWebkitTransformOrigin; // cssPropertyID("-webkit-transform-origin")
65     } else if (propertyId == CSSPropertyTransformOrigin) {
66         propertyId = CSSPropertyWebkitTransformOrigin;
67     }
68     ASSERT(propertyId > 0);
69     propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
70 }
71
72 SVGElement::SVGElement(const QualifiedName& tagName, Document& document, ConstructionType constructionType)
73     : Element(tagName, &document, constructionType)
74 #if !ASSERT_DISABLED
75     , m_inRelativeLengthClientsInvalidation(false)
76 #endif
77     // |m_isContextElement| must be initialized before |m_className|, as SVGAnimatedString tear-off c-tor currently set this to true.
78     , m_isContextElement(false)
79     , m_hasSVGRareData(false)
80     , m_className(SVGAnimatedString::create(this, HTMLNames::classAttr, SVGString::create()))
81 {
82     ScriptWrappable::init(this);
83     addToPropertyMap(m_className);
84     setHasCustomStyleCallbacks();
85 }
86
87 SVGElement::~SVGElement()
88 {
89     ASSERT(inDocument() || !hasRelativeLengths());
90
91     // The below teardown is all handled by weak pointer processing in oilpan.
92 #if !ENABLE(OILPAN)
93     if (!hasSVGRareData())
94         ASSERT(!SVGElementRareData::rareDataMap().contains(this));
95     else {
96         SVGElementRareData::SVGElementRareDataMap& rareDataMap = SVGElementRareData::rareDataMap();
97         SVGElementRareData::SVGElementRareDataMap::iterator it = rareDataMap.find(this);
98         ASSERT_WITH_SECURITY_IMPLICATION(it != rareDataMap.end());
99
100         SVGElementRareData* rareData = it->value;
101         if (SVGCursorElement* cursorElement = rareData->cursorElement())
102             cursorElement->removeReferencedElement(this);
103         if (CSSCursorImageValue* cursorImageValue = rareData->cursorImageValue())
104             cursorImageValue->removeReferencedElement(this);
105
106         delete rareData;
107
108         // The rare data cleanup may have caused other SVG nodes to be deleted,
109         // modifying the rare data map. Do not rely on the existing iterator.
110         ASSERT(rareDataMap.contains(this));
111         rareDataMap.remove(this);
112         // Clear HasSVGRareData flag now so that we are in a consistent state when
113         // calling rebuildAllElementReferencesForTarget() and
114         // removeAllElementReferencesForTarget() below.
115         clearHasSVGRareData();
116     }
117
118     // With Oilpan, either removedFrom has been called or the document is dead
119     // as well and there is no reason to clear out the extensions.
120     document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this);
121     document().accessSVGExtensions().removeAllElementReferencesForTarget(this);
122 #endif
123 }
124
125 short SVGElement::tabIndex() const
126 {
127     if (supportsFocus())
128         return Element::tabIndex();
129     return -1;
130 }
131
132 void SVGElement::willRecalcStyle(StyleRecalcChange change)
133 {
134     if (!hasSVGRareData())
135         return;
136     // If the style changes because of a regular property change (not induced by SMIL animations themselves)
137     // reset the "computed style without SMIL style properties", so the base value change gets reflected.
138     if (change > NoChange || needsStyleRecalc())
139         svgRareData()->setNeedsOverrideComputedStyleUpdate();
140 }
141
142 void SVGElement::buildPendingResourcesIfNeeded()
143 {
144     Document& document = this->document();
145     if (!needsPendingResourceHandling() || !inDocument() || inUseShadowTree())
146         return;
147
148     SVGDocumentExtensions& extensions = document.accessSVGExtensions();
149     AtomicString resourceId = getIdAttribute();
150     if (!extensions.hasPendingResource(resourceId))
151         return;
152
153     // Mark pending resources as pending for removal.
154     extensions.markPendingResourcesForRemoval(resourceId);
155
156     // Rebuild pending resources for each client of a pending resource that is being removed.
157     while (Element* clientElement = extensions.removeElementFromPendingResourcesForRemoval(resourceId)) {
158         ASSERT(clientElement->hasPendingResources());
159         if (clientElement->hasPendingResources()) {
160             clientElement->buildPendingResource();
161             extensions.clearHasPendingResourcesIfPossible(clientElement);
162         }
163     }
164 }
165
166 bool SVGElement::rendererIsNeeded(const RenderStyle& style)
167 {
168     // http://www.w3.org/TR/SVG/extend.html#PrivateData
169     // Prevent anything other than SVG renderers from appearing in our render tree
170     // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
171     // with the SVG content. In general, the SVG user agent will include the unknown
172     // elements in the DOM but will otherwise ignore unknown elements.
173     if (!parentOrShadowHostElement() || parentOrShadowHostElement()->isSVGElement())
174         return Element::rendererIsNeeded(style);
175
176     return false;
177 }
178
179 SVGElementRareData* SVGElement::svgRareData() const
180 {
181     ASSERT(hasSVGRareData());
182     return SVGElementRareData::rareDataFromMap(this);
183 }
184
185 SVGElementRareData* SVGElement::ensureSVGRareData()
186 {
187     if (hasSVGRareData())
188         return svgRareData();
189
190     ASSERT(!SVGElementRareData::rareDataMap().contains(this));
191     SVGElementRareData* data = new SVGElementRareData(this);
192     SVGElementRareData::rareDataMap().set(this, data);
193     setHasSVGRareData();
194     return data;
195 }
196
197 bool SVGElement::isOutermostSVGSVGElement() const
198 {
199     if (!isSVGSVGElement(*this))
200         return false;
201
202     // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
203     if (!parentNode())
204         return true;
205
206     // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
207     if (isSVGForeignObjectElement(*parentNode()))
208         return true;
209
210     // If we're living in a shadow tree, we're a <svg> element that got created as replacement
211     // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case
212     // we're always an inner <svg> element.
213     if (inUseShadowTree() && parentOrShadowHostElement() && parentOrShadowHostElement()->isSVGElement())
214         return false;
215
216     // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
217     return !parentNode()->isSVGElement();
218 }
219
220 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value)
221 {
222     if (error == NoError)
223         return;
224
225     String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
226     SVGDocumentExtensions& extensions = document().accessSVGExtensions();
227
228     if (error == NegativeValueForbiddenError) {
229         extensions.reportError("Invalid negative value for " + errorString);
230         return;
231     }
232
233     if (error == ParsingAttributeFailedError) {
234         extensions.reportError("Invalid value for " + errorString);
235         return;
236     }
237
238     ASSERT_NOT_REACHED();
239 }
240
241 String SVGElement::title() const
242 {
243     // According to spec, we should not return titles when hovering over root <svg> elements (those
244     // <title> elements are the title of the document, not a tooltip) so we instantly return.
245     if (isOutermostSVGSVGElement())
246         return String();
247
248     if (inUseShadowTree()) {
249         String useTitle(shadowHost()->title());
250         if (!useTitle.isEmpty())
251             return useTitle;
252     }
253
254     // If we aren't an instance in a <use> or the <use> title was not found, then find the first
255     // <title> child of this element.
256     // If a title child was found, return the text contents.
257     if (Element* titleElement = Traversal<SVGTitleElement>::firstChild(*this))
258         return titleElement->innerText();
259
260     // Otherwise return a null/empty string.
261     return String();
262 }
263
264 bool SVGElement::instanceUpdatesBlocked() const
265 {
266     return hasSVGRareData() && svgRareData()->instanceUpdatesBlocked();
267 }
268
269 void SVGElement::setInstanceUpdatesBlocked(bool value)
270 {
271     if (hasSVGRareData())
272         svgRareData()->setInstanceUpdatesBlocked(value);
273 }
274
275 AffineTransform SVGElement::localCoordinateSpaceTransform(CTMScope) const
276 {
277     // To be overriden by SVGGraphicsElement (or as special case SVGTextElement and SVGPatternElement)
278     return AffineTransform();
279 }
280
281 const AtomicString& SVGElement::xmlbase() const
282 {
283     return fastGetAttribute(XMLNames::baseAttr);
284 }
285
286 void SVGElement::setXMLbase(const AtomicString& value)
287 {
288     setAttribute(XMLNames::baseAttr, value);
289 }
290
291 const AtomicString& SVGElement::xmllang() const
292 {
293     return fastGetAttribute(XMLNames::langAttr);
294 }
295
296 void SVGElement::setXMLlang(const AtomicString& value)
297 {
298     setAttribute(XMLNames::langAttr, value);
299 }
300
301 const AtomicString& SVGElement::xmlspace() const
302 {
303     return fastGetAttribute(XMLNames::spaceAttr);
304 }
305
306 void SVGElement::setXMLspace(const AtomicString& value)
307 {
308     setAttribute(XMLNames::spaceAttr, value);
309 }
310
311 Node::InsertionNotificationRequest SVGElement::insertedInto(ContainerNode* rootParent)
312 {
313     Element::insertedInto(rootParent);
314     updateRelativeLengthsInformation();
315     buildPendingResourcesIfNeeded();
316     return InsertionDone;
317 }
318
319 void SVGElement::removedFrom(ContainerNode* rootParent)
320 {
321     bool wasInDocument = rootParent->inDocument();
322
323     if (wasInDocument && hasRelativeLengths()) {
324         // The root of the subtree being removed should take itself out from its parent's relative
325         // length set. For the other nodes in the subtree we don't need to do anything: they will
326         // get their own removedFrom() notification and just clear their sets.
327         if (rootParent->isSVGElement() && !parentNode()) {
328             ASSERT(toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this));
329             toSVGElement(rootParent)->updateRelativeLengthsInformation(false, this);
330         }
331
332         m_elementsWithRelativeLengths.clear();
333     }
334
335     ASSERT_WITH_SECURITY_IMPLICATION(!rootParent->isSVGElement() || !toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this));
336
337     Element::removedFrom(rootParent);
338
339     if (wasInDocument) {
340         document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this);
341         document().accessSVGExtensions().removeAllElementReferencesForTarget(this);
342     }
343
344     invalidateInstances();
345 }
346
347 void SVGElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
348 {
349     Element::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
350
351     // Invalidate all SVGElementInstances associated with us.
352     if (!changedByParser)
353         invalidateInstances();
354 }
355
356 CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
357 {
358     if (!attrName.namespaceURI().isNull())
359         return CSSPropertyInvalid;
360
361     static HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap = 0;
362     if (!propertyNameToIdMap) {
363         propertyNameToIdMap = new HashMap<StringImpl*, CSSPropertyID>;
364         // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
365         mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr);
366         mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr);
367         mapAttributeToCSSProperty(propertyNameToIdMap, buffered_renderingAttr);
368         mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr);
369         mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr);
370         mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr);
371         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::colorAttr);
372         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr);
373         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr);
374         mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr);
375         mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr);
376         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::directionAttr);
377         mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr);
378         mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr);
379         mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr);
380         mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr);
381         mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr);
382         mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr);
383         mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr);
384         mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr);
385         mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr);
386         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
387         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
388         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
389         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
390         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
391         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
392         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr);
393         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr);
394         mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr);
395         mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr);
396         mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr);
397         mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr);
398         mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr);
399         mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr);
400         mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr);
401         mapAttributeToCSSProperty(propertyNameToIdMap, mask_typeAttr);
402         mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr);
403         mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr);
404         mapAttributeToCSSProperty(propertyNameToIdMap, paint_orderAttr);
405         mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr);
406         mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr);
407         mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr);
408         mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr);
409         mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr);
410         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr);
411         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr);
412         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr);
413         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr);
414         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr);
415         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr);
416         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr);
417         mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr);
418         mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr);
419         mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr);
420         mapAttributeToCSSProperty(propertyNameToIdMap, transform_originAttr);
421         mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr);
422         mapAttributeToCSSProperty(propertyNameToIdMap, vector_effectAttr);
423         mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr);
424         mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr);
425         mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr);
426     }
427
428     return propertyNameToIdMap->get(attrName.localName().impl());
429 }
430
431 void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement)
432 {
433     ASSERT(clientElement);
434
435     // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now.
436     if (!inDocument())
437         return;
438
439     // An element wants to notify us that its own relative lengths state changed.
440     // Register it in the relative length map, and register us in the parent relative length map.
441     // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.
442     for (ContainerNode* currentNode = this; currentNode && currentNode->isSVGElement(); currentNode = currentNode->parentNode()) {
443         SVGElement* currentElement = toSVGElement(currentNode);
444         ASSERT(!currentElement->m_inRelativeLengthClientsInvalidation);
445
446         bool hadRelativeLengths = currentElement->hasRelativeLengths();
447         if (clientHasRelativeLengths)
448             currentElement->m_elementsWithRelativeLengths.add(clientElement);
449         else
450             currentElement->m_elementsWithRelativeLengths.remove(clientElement);
451
452         // If the relative length state hasn't changed, we can stop propagating the notification.
453         if (hadRelativeLengths == currentElement->hasRelativeLengths())
454             return;
455
456         clientElement = currentElement;
457         clientHasRelativeLengths = clientElement->hasRelativeLengths();
458     }
459
460     // Register root SVG elements for top level viewport change notifications.
461     if (isSVGSVGElement(*clientElement)) {
462         SVGDocumentExtensions& svgExtensions = accessDocumentSVGExtensions();
463         if (clientElement->hasRelativeLengths())
464             svgExtensions.addSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
465         else
466             svgExtensions.removeSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
467     }
468 }
469
470 void SVGElement::invalidateRelativeLengthClients(SubtreeLayoutScope* layoutScope)
471 {
472     if (!inDocument())
473         return;
474
475     ASSERT(!m_inRelativeLengthClientsInvalidation);
476 #if !ASSERT_DISABLED
477     TemporaryChange<bool> inRelativeLengthClientsInvalidationChange(m_inRelativeLengthClientsInvalidation, true);
478 #endif
479
480     RenderObject* renderer = this->renderer();
481     if (renderer && selfHasRelativeLengths()) {
482         if (renderer->isSVGResourceContainer())
483             toRenderSVGResourceContainer(renderer)->invalidateCacheAndMarkForLayout(layoutScope);
484         else
485             renderer->setNeedsLayout(MarkContainingBlockChain, layoutScope);
486     }
487
488     HashSet<SVGElement*>::iterator end = m_elementsWithRelativeLengths.end();
489     for (HashSet<SVGElement*>::iterator it = m_elementsWithRelativeLengths.begin(); it != end; ++it) {
490         if (*it != this)
491             (*it)->invalidateRelativeLengthClients(layoutScope);
492     }
493 }
494
495 SVGSVGElement* SVGElement::ownerSVGElement() const
496 {
497     ContainerNode* n = parentOrShadowHostNode();
498     while (n) {
499         if (isSVGSVGElement(*n))
500             return toSVGSVGElement(n);
501
502         n = n->parentOrShadowHostNode();
503     }
504
505     return 0;
506 }
507
508 SVGElement* SVGElement::viewportElement() const
509 {
510     // This function needs shadow tree support - as RenderSVGContainer uses this function
511     // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
512     ContainerNode* n = parentOrShadowHostNode();
513     while (n) {
514         if (isSVGSVGElement(*n) || isSVGImageElement(*n) || isSVGSymbolElement(*n))
515             return toSVGElement(n);
516
517         n = n->parentOrShadowHostNode();
518     }
519
520     return 0;
521 }
522
523 SVGDocumentExtensions& SVGElement::accessDocumentSVGExtensions()
524 {
525     // This function is provided for use by SVGAnimatedProperty to avoid
526     // global inclusion of core/dom/Document.h in SVG code.
527     return document().accessSVGExtensions();
528 }
529
530 void SVGElement::mapInstanceToElement(SVGElement* instance)
531 {
532     ASSERT(instance);
533     ASSERT(instance->inUseShadowTree());
534
535     WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = ensureSVGRareData()->elementInstances();
536     ASSERT(!instances.contains(instance));
537
538     instances.add(instance);
539 }
540
541 void SVGElement::removeInstanceMapping(SVGElement* instance)
542 {
543     ASSERT(instance);
544     ASSERT(instance->inUseShadowTree());
545     ASSERT(hasSVGRareData());
546
547     WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = svgRareData()->elementInstances();
548     ASSERT(instances.contains(instance));
549
550     instances.remove(instance);
551 }
552
553 static WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& emptyInstances()
554 {
555 #if ENABLE(OILPAN)
556     DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<WeakMember<SVGElement> > >, emptyInstances, (new HeapHashSet<WeakMember<SVGElement> >));
557     return *emptyInstances;
558 #else
559     DEFINE_STATIC_LOCAL(HashSet<RawPtr<SVGElement> >, emptyInstances, ());
560     return emptyInstances;
561 #endif
562 }
563
564 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& SVGElement::instancesForElement() const
565 {
566     if (!hasSVGRareData())
567         return emptyInstances();
568     return svgRareData()->elementInstances();
569 }
570
571 bool SVGElement::getBoundingBox(FloatRect& rect)
572 {
573     if (!isSVGGraphicsElement())
574         return false;
575
576     rect = toSVGGraphicsElement(this)->getBBox();
577     return true;
578 }
579
580 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
581 {
582     SVGElementRareData* rareData = ensureSVGRareData();
583     if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) {
584         if (cursorElement == oldCursorElement)
585             return;
586         oldCursorElement->removeReferencedElement(this);
587     }
588     rareData->setCursorElement(cursorElement);
589 }
590
591 #if !ENABLE(OILPAN)
592 void SVGElement::cursorElementRemoved()
593 {
594     ASSERT(hasSVGRareData());
595     svgRareData()->setCursorElement(0);
596 }
597 #endif
598
599 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
600 {
601     SVGElementRareData* rareData = ensureSVGRareData();
602 #if !ENABLE(OILPAN)
603     if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) {
604         if (cursorImageValue == oldCursorImageValue)
605             return;
606         oldCursorImageValue->removeReferencedElement(this);
607     }
608 #endif
609     rareData->setCursorImageValue(cursorImageValue);
610 }
611
612 #if !ENABLE(OILPAN)
613 void SVGElement::cursorImageValueRemoved()
614 {
615     ASSERT(hasSVGRareData());
616     svgRareData()->setCursorImageValue(0);
617 }
618 #endif
619
620 SVGElement* SVGElement::correspondingElement()
621 {
622     ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || containingShadowRoot());
623     return hasSVGRareData() ? svgRareData()->correspondingElement() : 0;
624 }
625
626 SVGUseElement* SVGElement::correspondingUseElement() const
627 {
628     if (ShadowRoot* root = containingShadowRoot()) {
629         if (isSVGUseElement(root->host()) && (root->type() == ShadowRoot::UserAgentShadowRoot))
630             return toSVGUseElement(root->host());
631     }
632     return 0;
633 }
634
635 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
636 {
637     ensureSVGRareData()->setCorrespondingElement(correspondingElement);
638 }
639
640 bool SVGElement::inUseShadowTree() const
641 {
642     return correspondingUseElement();
643 }
644
645 bool SVGElement::supportsSpatialNavigationFocus() const
646 {
647     // This function checks whether the element satisfies the extended criteria
648     // for the element to be focusable, introduced by spatial navigation feature,
649     // i.e. checks if click or keyboard event handler is specified.
650     // This is the way to make it possible to navigate to (focus) elements
651     // which web designer meant for being active (made them respond to click events).
652
653     if (!document().settings() || !document().settings()->spatialNavigationEnabled())
654         return false;
655     return hasEventListeners(EventTypeNames::click)
656         || hasEventListeners(EventTypeNames::keydown)
657         || hasEventListeners(EventTypeNames::keypress)
658         || hasEventListeners(EventTypeNames::keyup)
659         || hasEventListeners(EventTypeNames::focus)
660         || hasEventListeners(EventTypeNames::blur)
661         || hasEventListeners(EventTypeNames::focusin)
662         || hasEventListeners(EventTypeNames::focusout);
663 }
664
665 void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
666 {
667     if (name == HTMLNames::classAttr) {
668         // SVG animation has currently requires special storage of values so we set
669         // the className here. svgAttributeChanged actually causes the resulting
670         // style updates (instead of Element::parseAttribute). We don't
671         // tell Element about the change to avoid parsing the class list twice
672         SVGParsingError parseError = NoError;
673         m_className->setBaseValueAsString(value, parseError);
674         reportAttributeParsingError(parseError, name, value);
675     } else if (name.matches(XMLNames::langAttr) || name.matches(XMLNames::spaceAttr)) {
676     } else if (name == tabindexAttr) {
677         Element::parseAttribute(name, value);
678     } else {
679         // standard events
680         const AtomicString& eventName = HTMLElement::eventNameForAttributeName(name);
681         if (!eventName.isNull())
682             setAttributeEventListener(eventName, createAttributeEventListener(this, name, value));
683         else
684             Element::parseAttribute(name, value);
685     }
686 }
687
688 typedef HashMap<QualifiedName, AnimatedPropertyType> AttributeToPropertyTypeMap;
689 AnimatedPropertyType SVGElement::animatedPropertyTypeForCSSAttribute(const QualifiedName& attributeName)
690 {
691     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, cssPropertyMap, ());
692
693     if (cssPropertyMap.isEmpty()) {
694         // Fill the map for the first use.
695         cssPropertyMap.set(alignment_baselineAttr, AnimatedString);
696         cssPropertyMap.set(baseline_shiftAttr, AnimatedString);
697         cssPropertyMap.set(buffered_renderingAttr, AnimatedString);
698         cssPropertyMap.set(clipAttr, AnimatedRect);
699         cssPropertyMap.set(clip_pathAttr, AnimatedString);
700         cssPropertyMap.set(clip_ruleAttr, AnimatedString);
701         cssPropertyMap.set(SVGNames::colorAttr, AnimatedColor);
702         cssPropertyMap.set(color_interpolationAttr, AnimatedString);
703         cssPropertyMap.set(color_interpolation_filtersAttr, AnimatedString);
704         cssPropertyMap.set(color_renderingAttr, AnimatedString);
705         cssPropertyMap.set(cursorAttr, AnimatedString);
706         cssPropertyMap.set(displayAttr, AnimatedString);
707         cssPropertyMap.set(dominant_baselineAttr, AnimatedString);
708         cssPropertyMap.set(fillAttr, AnimatedColor);
709         cssPropertyMap.set(fill_opacityAttr, AnimatedNumber);
710         cssPropertyMap.set(fill_ruleAttr, AnimatedString);
711         cssPropertyMap.set(filterAttr, AnimatedString);
712         cssPropertyMap.set(flood_colorAttr, AnimatedColor);
713         cssPropertyMap.set(flood_opacityAttr, AnimatedNumber);
714         cssPropertyMap.set(font_familyAttr, AnimatedString);
715         cssPropertyMap.set(font_sizeAttr, AnimatedLength);
716         cssPropertyMap.set(font_stretchAttr, AnimatedString);
717         cssPropertyMap.set(font_styleAttr, AnimatedString);
718         cssPropertyMap.set(font_variantAttr, AnimatedString);
719         cssPropertyMap.set(font_weightAttr, AnimatedString);
720         cssPropertyMap.set(image_renderingAttr, AnimatedString);
721         cssPropertyMap.set(letter_spacingAttr, AnimatedLength);
722         cssPropertyMap.set(lighting_colorAttr, AnimatedColor);
723         cssPropertyMap.set(marker_endAttr, AnimatedString);
724         cssPropertyMap.set(marker_midAttr, AnimatedString);
725         cssPropertyMap.set(marker_startAttr, AnimatedString);
726         cssPropertyMap.set(maskAttr, AnimatedString);
727         cssPropertyMap.set(mask_typeAttr, AnimatedString);
728         cssPropertyMap.set(opacityAttr, AnimatedNumber);
729         cssPropertyMap.set(overflowAttr, AnimatedString);
730         cssPropertyMap.set(paint_orderAttr, AnimatedString);
731         cssPropertyMap.set(pointer_eventsAttr, AnimatedString);
732         cssPropertyMap.set(shape_renderingAttr, AnimatedString);
733         cssPropertyMap.set(stop_colorAttr, AnimatedColor);
734         cssPropertyMap.set(stop_opacityAttr, AnimatedNumber);
735         cssPropertyMap.set(strokeAttr, AnimatedColor);
736         cssPropertyMap.set(stroke_dasharrayAttr, AnimatedLengthList);
737         cssPropertyMap.set(stroke_dashoffsetAttr, AnimatedLength);
738         cssPropertyMap.set(stroke_linecapAttr, AnimatedString);
739         cssPropertyMap.set(stroke_linejoinAttr, AnimatedString);
740         cssPropertyMap.set(stroke_miterlimitAttr, AnimatedNumber);
741         cssPropertyMap.set(stroke_opacityAttr, AnimatedNumber);
742         cssPropertyMap.set(stroke_widthAttr, AnimatedLength);
743         cssPropertyMap.set(text_anchorAttr, AnimatedString);
744         cssPropertyMap.set(text_decorationAttr, AnimatedString);
745         cssPropertyMap.set(text_renderingAttr, AnimatedString);
746         cssPropertyMap.set(vector_effectAttr, AnimatedString);
747         cssPropertyMap.set(visibilityAttr, AnimatedString);
748         cssPropertyMap.set(word_spacingAttr, AnimatedLength);
749     }
750
751     if (cssPropertyMap.contains(attributeName))
752         return cssPropertyMap.get(attributeName);
753
754     return AnimatedUnknown;
755 }
756
757 void SVGElement::addToPropertyMap(PassRefPtr<SVGAnimatedPropertyBase> passProperty)
758 {
759     RefPtr<SVGAnimatedPropertyBase> property(passProperty);
760     QualifiedName attributeName = property->attributeName();
761     m_newAttributeToPropertyMap.set(attributeName, property.release());
762 }
763
764 PassRefPtr<SVGAnimatedPropertyBase> SVGElement::propertyFromAttribute(const QualifiedName& attributeName)
765 {
766     return m_newAttributeToPropertyMap.get(attributeName);
767 }
768
769 bool SVGElement::isAnimatableCSSProperty(const QualifiedName& attrName)
770 {
771     return animatedPropertyTypeForCSSAttribute(attrName) != AnimatedUnknown;
772 }
773
774 bool SVGElement::isPresentationAttribute(const QualifiedName& name) const
775 {
776     return cssPropertyIdForSVGAttributeName(name) > 0;
777 }
778
779 void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
780 {
781     CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(name);
782     if (propertyID > 0)
783         addPropertyToPresentationAttributeStyle(style, propertyID, value);
784 }
785
786 bool SVGElement::haveLoadedRequiredResources()
787 {
788     for (SVGElement* child = Traversal<SVGElement>::firstChild(*this); child; child = Traversal<SVGElement>::nextSibling(*child)) {
789         if (!child->haveLoadedRequiredResources())
790             return false;
791     }
792     return true;
793 }
794
795 static inline void collectInstancesForSVGElement(SVGElement* element, WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances)
796 {
797     ASSERT(element);
798     if (element->containingShadowRoot())
799         return;
800
801     ASSERT(!element->instanceUpdatesBlocked());
802
803     instances = element->instancesForElement();
804 }
805
806 bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
807 {
808     RefPtr<EventListener> listener = prpListener;
809
810     // Add event listener to regular DOM element
811     if (!Node::addEventListener(eventType, listener, useCapture))
812         return false;
813
814     // Add event listener to all shadow tree DOM element instances
815     WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > instances;
816     collectInstancesForSVGElement(this, instances);
817     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
818     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
819         bool result = (*it)->Node::addEventListener(eventType, listener, useCapture);
820         ASSERT_UNUSED(result, result);
821     }
822
823     return true;
824 }
825
826 bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
827 {
828     WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > instances;
829     collectInstancesForSVGElement(this, instances);
830     if (instances.isEmpty())
831         return Node::removeEventListener(eventType, listener, useCapture);
832
833     // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener
834     // object when creating a temporary RegisteredEventListener object used to look up the
835     // event listener in a cache. If we want to be able to call removeEventListener() multiple
836     // times on different nodes, we have to delay its immediate destruction, which would happen
837     // after the first call below.
838     RefPtr<EventListener> protector(listener);
839
840     // Remove event listener from regular DOM element
841     if (!Node::removeEventListener(eventType, listener, useCapture))
842         return false;
843
844     // Remove event listener from all shadow tree DOM element instances
845     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
846     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
847         SVGElement* shadowTreeElement = *it;
848         ASSERT(shadowTreeElement);
849
850         if (shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture))
851             continue;
852
853         // This case can only be hit for event listeners created from markup
854         ASSERT(listener->wasCreatedFromMarkup());
855
856         // If the event listener 'listener' has been created from markup and has been fired before
857         // then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener
858         // has been created (read: it's not 0 anymore). During shadow tree creation, the event
859         // listener DOM attribute has been cloned, and another event listener has been setup in
860         // the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0,
861         // and tryRemoveEventListener() above will fail. Work around that very seldom problem.
862         EventTargetData* data = shadowTreeElement->eventTargetData();
863         ASSERT(data);
864
865         data->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
866     }
867
868     return true;
869 }
870
871 static bool hasLoadListener(Element* element)
872 {
873     if (element->hasEventListeners(EventTypeNames::load))
874         return true;
875
876     for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) {
877         const EventListenerVector& entry = element->getEventListeners(EventTypeNames::load);
878         for (size_t i = 0; i < entry.size(); ++i) {
879             if (entry[i].useCapture)
880                 return true;
881         }
882     }
883
884     return false;
885 }
886
887 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
888 {
889     RefPtr<SVGElement> currentTarget = this;
890     while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
891         RefPtr<Element> parent;
892         if (sendParentLoadEvents)
893             parent = currentTarget->parentOrShadowHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree
894         if (hasLoadListener(currentTarget.get())
895             && (currentTarget->isStructurallyExternal() || isSVGSVGElement(*currentTarget)))
896             currentTarget->dispatchEvent(Event::create(EventTypeNames::load));
897         currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>();
898         SVGElement* element = currentTarget.get();
899         if (!element || !element->isOutermostSVGSVGElement())
900             continue;
901
902         // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>.
903         // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through
904         // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded.
905         ASSERT(sendParentLoadEvents);
906
907         // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example
908         // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document
909         // to be "ready to render", first.
910         if (!document().loadEventFinished())
911             break;
912     }
913 }
914
915 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
916 {
917     svgLoadEventTimer()->startOneShot(0, FROM_HERE);
918 }
919
920 void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*)
921 {
922     sendSVGLoadEventIfPossible();
923 }
924
925 Timer<SVGElement>* SVGElement::svgLoadEventTimer()
926 {
927     ASSERT_NOT_REACHED();
928     return 0;
929 }
930
931 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason)
932 {
933     Element::attributeChanged(name, newValue);
934
935     if (isIdAttributeName(name))
936         document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this);
937
938     // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
939     // so we don't want changes to the style attribute to result in extra work here.
940     if (name != HTMLNames::styleAttr)
941         svgAttributeChanged(name);
942 }
943
944 void SVGElement::svgAttributeChanged(const QualifiedName& attrName)
945 {
946     CSSPropertyID propId = SVGElement::cssPropertyIdForSVGAttributeName(attrName);
947     if (propId > 0) {
948         invalidateInstances();
949         return;
950     }
951
952     if (attrName == HTMLNames::classAttr) {
953         classAttributeChanged(AtomicString(m_className->currentValue()->value()));
954         invalidateInstances();
955         return;
956     }
957
958     if (isIdAttributeName(attrName)) {
959         RenderObject* object = renderer();
960         // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
961         if (object && object->isSVGResourceContainer())
962             toRenderSVGResourceContainer(object)->idChanged();
963         if (inDocument())
964             buildPendingResourcesIfNeeded();
965         invalidateInstances();
966         return;
967     }
968 }
969
970 void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const
971 {
972     if (!elementData() || !elementData()->m_animatedSVGAttributesAreDirty)
973         return;
974
975     if (name == anyQName()) {
976         AttributeToPropertyMap::const_iterator::Values it = m_newAttributeToPropertyMap.values().begin();
977         AttributeToPropertyMap::const_iterator::Values end = m_newAttributeToPropertyMap.values().end();
978         for (; it != end; ++it) {
979             if ((*it)->needsSynchronizeAttribute())
980                 (*it)->synchronizeAttribute();
981         }
982
983         elementData()->m_animatedSVGAttributesAreDirty = false;
984     } else {
985         RefPtr<SVGAnimatedPropertyBase> property = m_newAttributeToPropertyMap.get(name);
986         if (property && property->needsSynchronizeAttribute())
987             property->synchronizeAttribute();
988     }
989 }
990
991 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
992 {
993     if (!correspondingElement())
994         return document().ensureStyleResolver().styleForElement(this);
995
996     RenderStyle* style = 0;
997     if (Element* parent = parentOrShadowHostElement()) {
998         if (RenderObject* renderer = parent->renderer())
999             style = renderer->style();
1000     }
1001
1002     return document().ensureStyleResolver().styleForElement(correspondingElement(), style, DisallowStyleSharing);
1003 }
1004
1005 MutableStylePropertySet* SVGElement::animatedSMILStyleProperties() const
1006 {
1007     if (hasSVGRareData())
1008         return svgRareData()->animatedSMILStyleProperties();
1009     return 0;
1010 }
1011
1012 MutableStylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties()
1013 {
1014     return ensureSVGRareData()->ensureAnimatedSMILStyleProperties();
1015 }
1016
1017 void SVGElement::setUseOverrideComputedStyle(bool value)
1018 {
1019     if (hasSVGRareData())
1020         svgRareData()->setUseOverrideComputedStyle(value);
1021 }
1022
1023 RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
1024 {
1025     if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle())
1026         return Element::computedStyle(pseudoElementSpecifier);
1027
1028     RenderStyle* parentStyle = 0;
1029     if (Element* parent = parentOrShadowHostElement()) {
1030         if (RenderObject* renderer = parent->renderer())
1031             parentStyle = renderer->style();
1032     }
1033
1034     return svgRareData()->overrideComputedStyle(this, parentStyle);
1035 }
1036
1037 bool SVGElement::hasFocusEventListeners() const
1038 {
1039     return hasEventListeners(EventTypeNames::focusin) || hasEventListeners(EventTypeNames::focusout)
1040         || hasEventListeners(EventTypeNames::focus) || hasEventListeners(EventTypeNames::blur);
1041 }
1042
1043 void SVGElement::invalidateInstances()
1044 {
1045     if (!inDocument())
1046         return;
1047
1048     if (instanceUpdatesBlocked())
1049         return;
1050
1051     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& set = instancesForElement();
1052     if (set.isEmpty())
1053         return;
1054
1055     // Mark all use elements referencing 'element' for rebuilding
1056     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = set.end();
1057     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = set.begin(); it != end; ++it) {
1058         (*it)->setCorrespondingElement(0);
1059
1060         if (SVGUseElement* element = (*it)->correspondingUseElement()) {
1061             ASSERT(element->inDocument());
1062             element->invalidateShadowTree();
1063         }
1064     }
1065
1066     document().updateRenderTreeIfNeeded();
1067 }
1068
1069 SVGElement::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement* targetElement)
1070     : m_targetElement(targetElement)
1071 {
1072     if (m_targetElement)
1073         m_targetElement->setInstanceUpdatesBlocked(true);
1074 }
1075
1076 SVGElement::InstanceUpdateBlocker::~InstanceUpdateBlocker()
1077 {
1078     if (m_targetElement)
1079         m_targetElement->setInstanceUpdatesBlocked(false);
1080 }
1081
1082 #ifndef NDEBUG
1083 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
1084 {
1085     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ());
1086
1087     if (animatableAttributes.isEmpty()) {
1088         animatableAttributes.add(XLinkNames::hrefAttr);
1089         animatableAttributes.add(SVGNames::amplitudeAttr);
1090         animatableAttributes.add(SVGNames::azimuthAttr);
1091         animatableAttributes.add(SVGNames::baseFrequencyAttr);
1092         animatableAttributes.add(SVGNames::biasAttr);
1093         animatableAttributes.add(SVGNames::clipPathUnitsAttr);
1094         animatableAttributes.add(SVGNames::cxAttr);
1095         animatableAttributes.add(SVGNames::cyAttr);
1096         animatableAttributes.add(SVGNames::diffuseConstantAttr);
1097         animatableAttributes.add(SVGNames::divisorAttr);
1098         animatableAttributes.add(SVGNames::dxAttr);
1099         animatableAttributes.add(SVGNames::dyAttr);
1100         animatableAttributes.add(SVGNames::edgeModeAttr);
1101         animatableAttributes.add(SVGNames::elevationAttr);
1102         animatableAttributes.add(SVGNames::exponentAttr);
1103         animatableAttributes.add(SVGNames::filterResAttr);
1104         animatableAttributes.add(SVGNames::filterUnitsAttr);
1105         animatableAttributes.add(SVGNames::fxAttr);
1106         animatableAttributes.add(SVGNames::fyAttr);
1107         animatableAttributes.add(SVGNames::gradientTransformAttr);
1108         animatableAttributes.add(SVGNames::gradientUnitsAttr);
1109         animatableAttributes.add(SVGNames::heightAttr);
1110         animatableAttributes.add(SVGNames::in2Attr);
1111         animatableAttributes.add(SVGNames::inAttr);
1112         animatableAttributes.add(SVGNames::interceptAttr);
1113         animatableAttributes.add(SVGNames::k1Attr);
1114         animatableAttributes.add(SVGNames::k2Attr);
1115         animatableAttributes.add(SVGNames::k3Attr);
1116         animatableAttributes.add(SVGNames::k4Attr);
1117         animatableAttributes.add(SVGNames::kernelMatrixAttr);
1118         animatableAttributes.add(SVGNames::kernelUnitLengthAttr);
1119         animatableAttributes.add(SVGNames::lengthAdjustAttr);
1120         animatableAttributes.add(SVGNames::limitingConeAngleAttr);
1121         animatableAttributes.add(SVGNames::markerHeightAttr);
1122         animatableAttributes.add(SVGNames::markerUnitsAttr);
1123         animatableAttributes.add(SVGNames::markerWidthAttr);
1124         animatableAttributes.add(SVGNames::maskContentUnitsAttr);
1125         animatableAttributes.add(SVGNames::maskUnitsAttr);
1126         animatableAttributes.add(SVGNames::methodAttr);
1127         animatableAttributes.add(SVGNames::modeAttr);
1128         animatableAttributes.add(SVGNames::numOctavesAttr);
1129         animatableAttributes.add(SVGNames::offsetAttr);
1130         animatableAttributes.add(SVGNames::operatorAttr);
1131         animatableAttributes.add(SVGNames::orderAttr);
1132         animatableAttributes.add(SVGNames::orientAttr);
1133         animatableAttributes.add(SVGNames::pathLengthAttr);
1134         animatableAttributes.add(SVGNames::patternContentUnitsAttr);
1135         animatableAttributes.add(SVGNames::patternTransformAttr);
1136         animatableAttributes.add(SVGNames::patternUnitsAttr);
1137         animatableAttributes.add(SVGNames::pointsAtXAttr);
1138         animatableAttributes.add(SVGNames::pointsAtYAttr);
1139         animatableAttributes.add(SVGNames::pointsAtZAttr);
1140         animatableAttributes.add(SVGNames::preserveAlphaAttr);
1141         animatableAttributes.add(SVGNames::preserveAspectRatioAttr);
1142         animatableAttributes.add(SVGNames::primitiveUnitsAttr);
1143         animatableAttributes.add(SVGNames::radiusAttr);
1144         animatableAttributes.add(SVGNames::rAttr);
1145         animatableAttributes.add(SVGNames::refXAttr);
1146         animatableAttributes.add(SVGNames::refYAttr);
1147         animatableAttributes.add(SVGNames::resultAttr);
1148         animatableAttributes.add(SVGNames::rotateAttr);
1149         animatableAttributes.add(SVGNames::rxAttr);
1150         animatableAttributes.add(SVGNames::ryAttr);
1151         animatableAttributes.add(SVGNames::scaleAttr);
1152         animatableAttributes.add(SVGNames::seedAttr);
1153         animatableAttributes.add(SVGNames::slopeAttr);
1154         animatableAttributes.add(SVGNames::spacingAttr);
1155         animatableAttributes.add(SVGNames::specularConstantAttr);
1156         animatableAttributes.add(SVGNames::specularExponentAttr);
1157         animatableAttributes.add(SVGNames::spreadMethodAttr);
1158         animatableAttributes.add(SVGNames::startOffsetAttr);
1159         animatableAttributes.add(SVGNames::stdDeviationAttr);
1160         animatableAttributes.add(SVGNames::stitchTilesAttr);
1161         animatableAttributes.add(SVGNames::surfaceScaleAttr);
1162         animatableAttributes.add(SVGNames::tableValuesAttr);
1163         animatableAttributes.add(SVGNames::targetAttr);
1164         animatableAttributes.add(SVGNames::targetXAttr);
1165         animatableAttributes.add(SVGNames::targetYAttr);
1166         animatableAttributes.add(SVGNames::transformAttr);
1167         animatableAttributes.add(SVGNames::typeAttr);
1168         animatableAttributes.add(SVGNames::valuesAttr);
1169         animatableAttributes.add(SVGNames::viewBoxAttr);
1170         animatableAttributes.add(SVGNames::widthAttr);
1171         animatableAttributes.add(SVGNames::x1Attr);
1172         animatableAttributes.add(SVGNames::x2Attr);
1173         animatableAttributes.add(SVGNames::xAttr);
1174         animatableAttributes.add(SVGNames::xChannelSelectorAttr);
1175         animatableAttributes.add(SVGNames::y1Attr);
1176         animatableAttributes.add(SVGNames::y2Attr);
1177         animatableAttributes.add(SVGNames::yAttr);
1178         animatableAttributes.add(SVGNames::yChannelSelectorAttr);
1179         animatableAttributes.add(SVGNames::zAttr);
1180     }
1181
1182     if (name == classAttr)
1183         return true;
1184
1185     return animatableAttributes.contains(name);
1186 }
1187 #endif
1188 }