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>
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.
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.
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.
27 #include "SVGElement.h"
29 #include "CSSCursorImageValue.h"
30 #include "DOMImplementation.h"
33 #include "HTMLNames.h"
34 #include "NodeRenderingContext.h"
35 #include "RenderObject.h"
36 #include "SVGCursorElement.h"
37 #include "SVGDocumentExtensions.h"
38 #include "SVGElementInstance.h"
39 #include "SVGElementRareData.h"
41 #include "SVGSVGElement.h"
42 #include "SVGStyledLocatableElement.h"
43 #include "SVGTextElement.h"
44 #include "ScriptEventListener.h"
49 using namespace HTMLNames;
51 SVGElement::SVGElement(const QualifiedName& tagName, Document* document, ConstructionType constructionType)
52 : StyledElement(tagName, document, constructionType)
54 setHasCustomCallbacks();
57 PassRefPtr<SVGElement> SVGElement::create(const QualifiedName& tagName, Document* document)
59 return adoptRef(new SVGElement(tagName, document));
62 SVGElement::~SVGElement()
64 if (!hasSVGRareData())
65 ASSERT(!SVGElementRareData::rareDataMap().contains(this));
68 if (hasPendingResources())
69 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
70 ASSERT(!hasPendingResources());
71 SVGElementRareData::SVGElementRareDataMap& rareDataMap = SVGElementRareData::rareDataMap();
72 SVGElementRareData::SVGElementRareDataMap::iterator it = rareDataMap.find(this);
73 ASSERT(it != rareDataMap.end());
75 SVGElementRareData* rareData = it->value;
76 rareData->destroyAnimatedSMILStyleProperties();
77 if (SVGCursorElement* cursorElement = rareData->cursorElement())
78 cursorElement->removeClient(this);
79 if (CSSCursorImageValue* cursorImageValue = rareData->cursorImageValue())
80 cursorImageValue->removeReferencedElement(this);
83 rareDataMap.remove(it);
86 document()->accessSVGExtensions()->removeAllAnimationElementsFromTarget(this);
87 document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this);
90 bool SVGElement::willRecalcStyle(StyleChange change)
92 if (!hasSVGRareData() || styleChangeType() == SyntheticStyleChange)
94 // If the style changes because of a regular property change (not induced by SMIL animations themselves)
95 // reset the "computed style without SMIL style properties", so the base value change gets reflected.
96 if (change > NoChange || needsStyleRecalc())
97 svgRareData()->setNeedsOverrideComputedStyleUpdate();
101 SVGElementRareData* SVGElement::svgRareData() const
103 ASSERT(hasSVGRareData());
104 return SVGElementRareData::rareDataFromMap(this);
107 SVGElementRareData* SVGElement::ensureSVGRareData()
109 if (hasSVGRareData())
110 return svgRareData();
112 ASSERT(!SVGElementRareData::rareDataMap().contains(this));
113 SVGElementRareData* data = new SVGElementRareData;
114 SVGElementRareData::rareDataMap().set(this, data);
119 bool SVGElement::isOutermostSVGSVGElement() const
121 if (!hasTagName(SVGNames::svgTag))
124 // If we're living in a shadow tree, we're a <svg> element that got created as replacement
125 // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case
126 // we're always an inner <svg> element.
127 if (isInShadowTree() && parentOrHostElement() && parentOrHostElement()->isSVGElement())
130 // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
134 // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
135 if (parentNode()->hasTagName(SVGNames::foreignObjectTag))
138 // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
139 return !parentNode()->isSVGElement();
142 void SVGElement::reportAttributeParsingError(SVGParsingError error, const Attribute& attribute)
144 if (error == NoError)
147 String errorString = "<" + tagName() + "> attribute " + attribute.name().toString() + "=\"" + attribute.value() + "\"";
148 SVGDocumentExtensions* extensions = document()->accessSVGExtensions();
150 if (error == NegativeValueForbiddenError) {
151 extensions->reportError("Invalid negative value for " + errorString);
155 if (error == ParsingAttributeFailedError) {
156 extensions->reportError("Invalid value for " + errorString);
160 ASSERT_NOT_REACHED();
164 bool SVGElement::isSupported(StringImpl* feature, StringImpl* version) const
166 return DOMImplementation::hasFeature(feature, version);
169 String SVGElement::xmlbase() const
171 return fastGetAttribute(XMLNames::baseAttr);
174 void SVGElement::setXmlbase(const String& value, ExceptionCode&)
176 setAttribute(XMLNames::baseAttr, value);
179 void SVGElement::removedFrom(ContainerNode* rootParent)
181 bool wasInDocument = rootParent->inDocument();
183 StyledElement::removedFrom(rootParent);
186 document()->accessSVGExtensions()->removeAllAnimationElementsFromTarget(this);
187 document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this);
188 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
192 SVGSVGElement* SVGElement::ownerSVGElement() const
194 ContainerNode* n = parentOrHostNode();
196 if (n->hasTagName(SVGNames::svgTag))
197 return static_cast<SVGSVGElement*>(n);
199 n = n->parentOrHostNode();
205 SVGElement* SVGElement::viewportElement() const
207 // This function needs shadow tree support - as RenderSVGContainer uses this function
208 // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
209 ContainerNode* n = parentOrHostNode();
211 if (n->hasTagName(SVGNames::svgTag) || n->hasTagName(SVGNames::imageTag) || n->hasTagName(SVGNames::symbolTag))
212 return static_cast<SVGElement*>(n);
214 n = n->parentOrHostNode();
220 SVGDocumentExtensions* SVGElement::accessDocumentSVGExtensions()
222 // This function is provided for use by SVGAnimatedProperty to avoid
223 // global inclusion of Document.h in SVG code.
224 return document() ? document()->accessSVGExtensions() : 0;
227 void SVGElement::mapInstanceToElement(SVGElementInstance* instance)
231 HashSet<SVGElementInstance*>& instances = ensureSVGRareData()->elementInstances();
232 ASSERT(!instances.contains(instance));
234 instances.add(instance);
237 void SVGElement::removeInstanceMapping(SVGElementInstance* instance)
240 ASSERT(hasSVGRareData());
242 HashSet<SVGElementInstance*>& instances = svgRareData()->elementInstances();
243 ASSERT(instances.contains(instance));
245 instances.remove(instance);
248 const HashSet<SVGElementInstance*>& SVGElement::instancesForElement() const
250 if (!hasSVGRareData()) {
251 DEFINE_STATIC_LOCAL(HashSet<SVGElementInstance*>, emptyInstances, ());
252 return emptyInstances;
254 return svgRareData()->elementInstances();
257 bool SVGElement::getBoundingBox(FloatRect& rect, SVGLocatable::StyleUpdateStrategy styleUpdateStrategy)
259 if (isStyledLocatable()) {
260 rect = static_cast<SVGStyledLocatableElement*>(this)->getBBox(styleUpdateStrategy);
263 if (hasTagName(SVGNames::textTag)) {
264 rect = static_cast<SVGTextElement*>(this)->getBBox(styleUpdateStrategy);
270 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
272 SVGElementRareData* rareData = ensureSVGRareData();
273 if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) {
274 if (cursorElement == oldCursorElement)
276 oldCursorElement->removeReferencedElement(this);
278 rareData->setCursorElement(cursorElement);
281 void SVGElement::cursorElementRemoved()
283 ASSERT(hasSVGRareData());
284 svgRareData()->setCursorElement(0);
287 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
289 SVGElementRareData* rareData = ensureSVGRareData();
290 if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) {
291 if (cursorImageValue == oldCursorImageValue)
293 oldCursorImageValue->removeReferencedElement(this);
295 rareData->setCursorImageValue(cursorImageValue);
298 void SVGElement::cursorImageValueRemoved()
300 ASSERT(hasSVGRareData());
301 svgRareData()->setCursorImageValue(0);
304 SVGElement* SVGElement::correspondingElement()
306 ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || shadowRoot());
307 return hasSVGRareData() ? svgRareData()->correspondingElement() : 0;
310 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
312 ensureSVGRareData()->setCorrespondingElement(correspondingElement);
315 void SVGElement::parseAttribute(const Attribute& attribute)
318 if (attribute.name() == onloadAttr)
319 setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attribute));
320 else if (attribute.name() == onclickAttr)
321 setAttributeEventListener(eventNames().clickEvent, createAttributeEventListener(this, attribute));
322 else if (attribute.name() == onmousedownAttr)
323 setAttributeEventListener(eventNames().mousedownEvent, createAttributeEventListener(this, attribute));
324 else if (attribute.name() == onmousemoveAttr)
325 setAttributeEventListener(eventNames().mousemoveEvent, createAttributeEventListener(this, attribute));
326 else if (attribute.name() == onmouseoutAttr)
327 setAttributeEventListener(eventNames().mouseoutEvent, createAttributeEventListener(this, attribute));
328 else if (attribute.name() == onmouseoverAttr)
329 setAttributeEventListener(eventNames().mouseoverEvent, createAttributeEventListener(this, attribute));
330 else if (attribute.name() == onmouseupAttr)
331 setAttributeEventListener(eventNames().mouseupEvent, createAttributeEventListener(this, attribute));
332 else if (attribute.name() == SVGNames::onfocusinAttr)
333 setAttributeEventListener(eventNames().focusinEvent, createAttributeEventListener(this, attribute));
334 else if (attribute.name() == SVGNames::onfocusoutAttr)
335 setAttributeEventListener(eventNames().focusoutEvent, createAttributeEventListener(this, attribute));
336 else if (attribute.name() == SVGNames::onactivateAttr)
337 setAttributeEventListener(eventNames().DOMActivateEvent, createAttributeEventListener(this, attribute));
339 StyledElement::parseAttribute(attribute);
342 void SVGElement::animatedPropertyTypeForAttribute(const QualifiedName& attributeName, Vector<AnimatedPropertyType>& propertyTypes)
344 localAttributeToPropertyMap().animatedPropertyTypeForAttribute(attributeName, propertyTypes);
347 bool SVGElement::haveLoadedRequiredResources()
349 Node* child = firstChild();
351 if (child->isSVGElement() && !static_cast<SVGElement*>(child)->haveLoadedRequiredResources())
353 child = child->nextSibling();
358 static inline void collectInstancesForSVGElement(SVGElement* element, HashSet<SVGElementInstance*>& instances)
361 if (element->shadowRoot())
364 if (!element->isStyled())
367 SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(element);
368 ASSERT(!styledElement->instanceUpdatesBlocked());
370 instances = styledElement->instancesForElement();
373 bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
375 RefPtr<EventListener> listener = prpListener;
377 // Add event listener to regular DOM element
378 if (!Node::addEventListener(eventType, listener, useCapture))
381 // Add event listener to all shadow tree DOM element instances
382 HashSet<SVGElementInstance*> instances;
383 collectInstancesForSVGElement(this, instances);
384 const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
385 for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
386 ASSERT((*it)->shadowTreeElement());
387 ASSERT((*it)->correspondingElement() == this);
389 bool result = (*it)->shadowTreeElement()->Node::addEventListener(eventType, listener, useCapture);
390 ASSERT_UNUSED(result, result);
396 bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
398 HashSet<SVGElementInstance*> instances;
399 collectInstancesForSVGElement(this, instances);
400 if (instances.isEmpty())
401 return Node::removeEventListener(eventType, listener, useCapture);
403 // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener
404 // object when creating a temporary RegisteredEventListener object used to look up the
405 // event listener in a cache. If we want to be able to call removeEventListener() multiple
406 // times on different nodes, we have to delay its immediate destruction, which would happen
407 // after the first call below.
408 RefPtr<EventListener> protector(listener);
410 // Remove event listener from regular DOM element
411 if (!Node::removeEventListener(eventType, listener, useCapture))
414 // Remove event listener from all shadow tree DOM element instances
415 const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
416 for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
417 ASSERT((*it)->correspondingElement() == this);
419 SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
420 ASSERT(shadowTreeElement);
422 if (shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture))
425 // This case can only be hit for event listeners created from markup
426 ASSERT(listener->wasCreatedFromMarkup());
428 // If the event listener 'listener' has been created from markup and has been fired before
429 // then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener
430 // has been created (read: it's not 0 anymore). During shadow tree creation, the event
431 // listener DOM attribute has been cloned, and another event listener has been setup in
432 // the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0,
433 // and tryRemoveEventListener() above will fail. Work around that very seldom problem.
434 EventTargetData* data = shadowTreeElement->eventTargetData();
437 data->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
443 static bool hasLoadListener(Element* element)
445 if (element->hasEventListeners(eventNames().loadEvent))
448 for (element = element->parentOrHostElement(); element; element = element->parentOrHostElement()) {
449 const EventListenerVector& entry = element->getEventListeners(eventNames().loadEvent);
450 for (size_t i = 0; i < entry.size(); ++i) {
451 if (entry[i].useCapture)
459 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
461 RefPtr<SVGElement> currentTarget = this;
462 while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
463 RefPtr<Element> parent;
464 if (sendParentLoadEvents)
465 parent = currentTarget->parentOrHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree
466 if (hasLoadListener(currentTarget.get()))
467 currentTarget->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
468 currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>();
469 SVGElement* element = static_cast<SVGElement*>(currentTarget.get());
470 if (!element || !element->isOutermostSVGSVGElement())
473 // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>.
474 // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through
475 // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded.
476 ASSERT(sendParentLoadEvents);
478 // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example
479 // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document
480 // to be "ready to render", first.
481 if (!document()->loadEventFinished())
486 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
488 svgLoadEventTimer()->startOneShot(0);
491 void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*)
493 sendSVGLoadEventIfPossible();
496 Timer<SVGElement>* SVGElement::svgLoadEventTimer()
498 ASSERT_NOT_REACHED();
502 void SVGElement::finishParsingChildren()
504 StyledElement::finishParsingChildren();
506 // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent.
507 if (isOutermostSVGSVGElement())
510 // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
511 // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
512 sendSVGLoadEventIfPossible();
515 bool SVGElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
517 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, invalidTextContent, ());
519 if (invalidTextContent.isEmpty()) {
520 invalidTextContent.add(SVGNames::textPathTag);
521 #if ENABLE(SVG_FONTS)
522 invalidTextContent.add(SVGNames::altGlyphTag);
524 invalidTextContent.add(SVGNames::trefTag);
525 invalidTextContent.add(SVGNames::tspanTag);
527 if (childContext.node()->isSVGElement()) {
528 if (invalidTextContent.contains(static_cast<SVGElement*>(childContext.node())->tagQName()))
531 return static_cast<SVGElement*>(childContext.node())->isValid();
536 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue)
538 StyledElement::attributeChanged(name, newValue);
540 // When an animated SVG property changes through SVG DOM, svgAttributeChanged() is called, not attributeChanged().
541 // Next time someone tries to access the XML attributes, the synchronization code starts. During that synchronization
542 // SVGAnimatedPropertySynchronizer may call ElementAttributeData::removeAttribute(), which in turn calls attributeChanged().
543 // At this point we're not allowed to call svgAttributeChanged() again - it may lead to extra work being done, or crashes
544 // see bug https://bugs.webkit.org/show_bug.cgi?id=40994.
545 if (isSynchronizingSVGAttributes())
548 if (isIdAttributeName(name)) {
549 document()->accessSVGExtensions()->removeAllAnimationElementsFromTarget(this);
550 document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this);
553 // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
554 // so we don't want changes to the style attribute to result in extra work here.
555 if (name != HTMLNames::styleAttr)
556 svgAttributeChanged(name);
559 bool SVGElement::hasPendingResources() const
561 return hasSVGRareData() && svgRareData()->hasPendingResources();
564 void SVGElement::setHasPendingResources()
566 ensureSVGRareData()->setHasPendingResources(true);
569 void SVGElement::clearHasPendingResourcesIfPossible()
571 if (!document()->accessSVGExtensions()->isElementPendingResources(this))
572 ensureSVGRareData()->setHasPendingResources(false);
575 void SVGElement::updateAnimatedSVGAttribute(const QualifiedName& name) const
577 if (isSynchronizingSVGAttributes() || areSVGAttributesValid())
580 setIsSynchronizingSVGAttributes();
582 SVGElement* nonConstThis = const_cast<SVGElement*>(this);
583 if (name == anyQName()) {
584 nonConstThis->localAttributeToPropertyMap().synchronizeProperties(nonConstThis);
585 setAreSVGAttributesValid();
587 nonConstThis->localAttributeToPropertyMap().synchronizeProperty(nonConstThis, name);
589 clearIsSynchronizingSVGAttributes();
592 SVGAttributeToPropertyMap& SVGElement::localAttributeToPropertyMap()
594 DEFINE_STATIC_LOCAL(SVGAttributeToPropertyMap, emptyMap, ());
598 void SVGElement::synchronizeRequiredFeatures(void* contextElement)
600 ASSERT(contextElement);
601 static_cast<SVGElement*>(contextElement)->synchronizeRequiredFeatures();
604 void SVGElement::synchronizeRequiredExtensions(void* contextElement)
606 ASSERT(contextElement);
607 static_cast<SVGElement*>(contextElement)->synchronizeRequiredExtensions();
610 void SVGElement::synchronizeSystemLanguage(void* contextElement)
612 ASSERT(contextElement);
613 static_cast<SVGElement*>(contextElement)->synchronizeSystemLanguage();
616 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
618 if (!correspondingElement())
619 return document()->styleResolver()->styleForElement(this);
621 RenderStyle* style = 0;
622 if (Element* parent = parentOrHostElement()) {
623 if (RenderObject* renderer = parent->renderer())
624 style = renderer->style();
627 return document()->styleResolver()->styleForElement(correspondingElement(), style, DisallowStyleSharing);
630 StylePropertySet* SVGElement::animatedSMILStyleProperties() const
632 if (hasSVGRareData())
633 return svgRareData()->animatedSMILStyleProperties();
637 StylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties()
639 return ensureSVGRareData()->ensureAnimatedSMILStyleProperties();
642 void SVGElement::setUseOverrideComputedStyle(bool value)
644 if (hasSVGRareData())
645 svgRareData()->setUseOverrideComputedStyle(value);
648 RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
650 if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle())
651 return Element::computedStyle(pseudoElementSpecifier);
653 RenderStyle* parentStyle = 0;
654 if (Element* parent = parentOrHostElement()) {
655 if (RenderObject* renderer = parent->renderer())
656 parentStyle = renderer->style();
659 return svgRareData()->overrideComputedStyle(this, parentStyle);
663 bool SVGElement::isAnimatableAttribute(const QualifiedName& name)
665 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ());
667 if (animatableAttributes.isEmpty()) {
668 animatableAttributes.add(classAttr);
669 animatableAttributes.add(XLinkNames::hrefAttr);
670 animatableAttributes.add(SVGNames::amplitudeAttr);
671 animatableAttributes.add(SVGNames::azimuthAttr);
672 animatableAttributes.add(SVGNames::baseFrequencyAttr);
673 animatableAttributes.add(SVGNames::biasAttr);
674 animatableAttributes.add(SVGNames::clipPathUnitsAttr);
675 animatableAttributes.add(SVGNames::cxAttr);
676 animatableAttributes.add(SVGNames::cyAttr);
677 animatableAttributes.add(SVGNames::diffuseConstantAttr);
678 animatableAttributes.add(SVGNames::divisorAttr);
679 animatableAttributes.add(SVGNames::dxAttr);
680 animatableAttributes.add(SVGNames::dyAttr);
681 animatableAttributes.add(SVGNames::edgeModeAttr);
682 animatableAttributes.add(SVGNames::elevationAttr);
683 animatableAttributes.add(SVGNames::exponentAttr);
684 animatableAttributes.add(SVGNames::externalResourcesRequiredAttr);
685 animatableAttributes.add(SVGNames::filterResAttr);
686 animatableAttributes.add(SVGNames::filterUnitsAttr);
687 animatableAttributes.add(SVGNames::fxAttr);
688 animatableAttributes.add(SVGNames::fyAttr);
689 animatableAttributes.add(SVGNames::gradientTransformAttr);
690 animatableAttributes.add(SVGNames::gradientUnitsAttr);
691 animatableAttributes.add(SVGNames::heightAttr);
692 animatableAttributes.add(SVGNames::in2Attr);
693 animatableAttributes.add(SVGNames::inAttr);
694 animatableAttributes.add(SVGNames::interceptAttr);
695 animatableAttributes.add(SVGNames::k1Attr);
696 animatableAttributes.add(SVGNames::k2Attr);
697 animatableAttributes.add(SVGNames::k3Attr);
698 animatableAttributes.add(SVGNames::k4Attr);
699 animatableAttributes.add(SVGNames::kernelMatrixAttr);
700 animatableAttributes.add(SVGNames::kernelUnitLengthAttr);
701 animatableAttributes.add(SVGNames::lengthAdjustAttr);
702 animatableAttributes.add(SVGNames::limitingConeAngleAttr);
703 animatableAttributes.add(SVGNames::markerHeightAttr);
704 animatableAttributes.add(SVGNames::markerUnitsAttr);
705 animatableAttributes.add(SVGNames::markerWidthAttr);
706 animatableAttributes.add(SVGNames::maskContentUnitsAttr);
707 animatableAttributes.add(SVGNames::maskUnitsAttr);
708 animatableAttributes.add(SVGNames::methodAttr);
709 animatableAttributes.add(SVGNames::modeAttr);
710 animatableAttributes.add(SVGNames::numOctavesAttr);
711 animatableAttributes.add(SVGNames::offsetAttr);
712 animatableAttributes.add(SVGNames::operatorAttr);
713 animatableAttributes.add(SVGNames::orderAttr);
714 animatableAttributes.add(SVGNames::orientAttr);
715 animatableAttributes.add(SVGNames::pathLengthAttr);
716 animatableAttributes.add(SVGNames::patternContentUnitsAttr);
717 animatableAttributes.add(SVGNames::patternTransformAttr);
718 animatableAttributes.add(SVGNames::patternUnitsAttr);
719 animatableAttributes.add(SVGNames::pointsAtXAttr);
720 animatableAttributes.add(SVGNames::pointsAtYAttr);
721 animatableAttributes.add(SVGNames::pointsAtZAttr);
722 animatableAttributes.add(SVGNames::preserveAlphaAttr);
723 animatableAttributes.add(SVGNames::preserveAspectRatioAttr);
724 animatableAttributes.add(SVGNames::primitiveUnitsAttr);
725 animatableAttributes.add(SVGNames::radiusAttr);
726 animatableAttributes.add(SVGNames::rAttr);
727 animatableAttributes.add(SVGNames::refXAttr);
728 animatableAttributes.add(SVGNames::refYAttr);
729 animatableAttributes.add(SVGNames::resultAttr);
730 animatableAttributes.add(SVGNames::rotateAttr);
731 animatableAttributes.add(SVGNames::rxAttr);
732 animatableAttributes.add(SVGNames::ryAttr);
733 animatableAttributes.add(SVGNames::scaleAttr);
734 animatableAttributes.add(SVGNames::seedAttr);
735 animatableAttributes.add(SVGNames::slopeAttr);
736 animatableAttributes.add(SVGNames::spacingAttr);
737 animatableAttributes.add(SVGNames::specularConstantAttr);
738 animatableAttributes.add(SVGNames::specularExponentAttr);
739 animatableAttributes.add(SVGNames::spreadMethodAttr);
740 animatableAttributes.add(SVGNames::startOffsetAttr);
741 animatableAttributes.add(SVGNames::stdDeviationAttr);
742 animatableAttributes.add(SVGNames::stitchTilesAttr);
743 animatableAttributes.add(SVGNames::surfaceScaleAttr);
744 animatableAttributes.add(SVGNames::tableValuesAttr);
745 animatableAttributes.add(SVGNames::targetAttr);
746 animatableAttributes.add(SVGNames::targetXAttr);
747 animatableAttributes.add(SVGNames::targetYAttr);
748 animatableAttributes.add(SVGNames::transformAttr);
749 animatableAttributes.add(SVGNames::typeAttr);
750 animatableAttributes.add(SVGNames::valuesAttr);
751 animatableAttributes.add(SVGNames::viewBoxAttr);
752 animatableAttributes.add(SVGNames::widthAttr);
753 animatableAttributes.add(SVGNames::x1Attr);
754 animatableAttributes.add(SVGNames::x2Attr);
755 animatableAttributes.add(SVGNames::xAttr);
756 animatableAttributes.add(SVGNames::xChannelSelectorAttr);
757 animatableAttributes.add(SVGNames::y1Attr);
758 animatableAttributes.add(SVGNames::y2Attr);
759 animatableAttributes.add(SVGNames::yAttr);
760 animatableAttributes.add(SVGNames::yChannelSelectorAttr);
761 animatableAttributes.add(SVGNames::zAttr);
763 return animatableAttributes.contains(name);
769 #endif // ENABLE(SVG)