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()->removeAllElementReferencesForTarget(this);
89 bool SVGElement::willRecalcStyle(StyleChange change)
91 if (!hasSVGRareData() || styleChangeType() == SyntheticStyleChange)
93 // If the style changes because of a regular property change (not induced by SMIL animations themselves)
94 // reset the "computed style without SMIL style properties", so the base value change gets reflected.
95 if (change > NoChange || needsStyleRecalc())
96 svgRareData()->setNeedsOverrideComputedStyleUpdate();
100 SVGElementRareData* SVGElement::svgRareData() const
102 ASSERT(hasSVGRareData());
103 return SVGElementRareData::rareDataFromMap(this);
106 SVGElementRareData* SVGElement::ensureSVGRareData()
108 if (hasSVGRareData())
109 return svgRareData();
111 ASSERT(!SVGElementRareData::rareDataMap().contains(this));
112 SVGElementRareData* data = new SVGElementRareData;
113 SVGElementRareData::rareDataMap().set(this, data);
118 bool SVGElement::isOutermostSVGSVGElement() const
120 if (!hasTagName(SVGNames::svgTag))
123 // If we're living in a shadow tree, we're a <svg> element that got created as replacement
124 // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case
125 // we're always an inner <svg> element.
126 if (isInShadowTree() && parentOrHostElement() && parentOrHostElement()->isSVGElement())
129 // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
133 // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
134 if (parentNode()->hasTagName(SVGNames::foreignObjectTag))
137 // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
138 return !parentNode()->isSVGElement();
141 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value)
143 if (error == NoError)
146 String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
147 SVGDocumentExtensions* extensions = document()->accessSVGExtensions();
149 if (error == NegativeValueForbiddenError) {
150 extensions->reportError("Invalid negative value for " + errorString);
154 if (error == ParsingAttributeFailedError) {
155 extensions->reportError("Invalid value for " + errorString);
159 ASSERT_NOT_REACHED();
163 bool SVGElement::isSupported(StringImpl* feature, StringImpl* version) const
165 return DOMImplementation::hasFeature(feature, version);
168 String SVGElement::xmlbase() const
170 return fastGetAttribute(XMLNames::baseAttr);
173 void SVGElement::setXmlbase(const String& value, ExceptionCode&)
175 setAttribute(XMLNames::baseAttr, value);
178 void SVGElement::removedFrom(ContainerNode* rootParent)
180 bool wasInDocument = rootParent->inDocument();
182 StyledElement::removedFrom(rootParent);
185 document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this);
186 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
190 SVGSVGElement* SVGElement::ownerSVGElement() const
192 ContainerNode* n = parentOrHostNode();
194 if (n->hasTagName(SVGNames::svgTag))
195 return static_cast<SVGSVGElement*>(n);
197 n = n->parentOrHostNode();
203 SVGElement* SVGElement::viewportElement() const
205 // This function needs shadow tree support - as RenderSVGContainer uses this function
206 // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
207 ContainerNode* n = parentOrHostNode();
209 if (n->hasTagName(SVGNames::svgTag) || n->hasTagName(SVGNames::imageTag) || n->hasTagName(SVGNames::symbolTag))
210 return static_cast<SVGElement*>(n);
212 n = n->parentOrHostNode();
218 SVGDocumentExtensions* SVGElement::accessDocumentSVGExtensions()
220 // This function is provided for use by SVGAnimatedProperty to avoid
221 // global inclusion of Document.h in SVG code.
222 return document() ? document()->accessSVGExtensions() : 0;
225 void SVGElement::mapInstanceToElement(SVGElementInstance* instance)
229 HashSet<SVGElementInstance*>& instances = ensureSVGRareData()->elementInstances();
230 ASSERT(!instances.contains(instance));
232 instances.add(instance);
235 void SVGElement::removeInstanceMapping(SVGElementInstance* instance)
238 ASSERT(hasSVGRareData());
240 HashSet<SVGElementInstance*>& instances = svgRareData()->elementInstances();
241 ASSERT(instances.contains(instance));
243 instances.remove(instance);
246 const HashSet<SVGElementInstance*>& SVGElement::instancesForElement() const
248 if (!hasSVGRareData()) {
249 DEFINE_STATIC_LOCAL(HashSet<SVGElementInstance*>, emptyInstances, ());
250 return emptyInstances;
252 return svgRareData()->elementInstances();
255 bool SVGElement::getBoundingBox(FloatRect& rect, SVGLocatable::StyleUpdateStrategy styleUpdateStrategy)
257 if (isStyledLocatable()) {
258 rect = static_cast<SVGStyledLocatableElement*>(this)->getBBox(styleUpdateStrategy);
261 if (hasTagName(SVGNames::textTag)) {
262 rect = static_cast<SVGTextElement*>(this)->getBBox(styleUpdateStrategy);
268 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
270 SVGElementRareData* rareData = ensureSVGRareData();
271 if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) {
272 if (cursorElement == oldCursorElement)
274 oldCursorElement->removeReferencedElement(this);
276 rareData->setCursorElement(cursorElement);
279 void SVGElement::cursorElementRemoved()
281 ASSERT(hasSVGRareData());
282 svgRareData()->setCursorElement(0);
285 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
287 SVGElementRareData* rareData = ensureSVGRareData();
288 if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) {
289 if (cursorImageValue == oldCursorImageValue)
291 oldCursorImageValue->removeReferencedElement(this);
293 rareData->setCursorImageValue(cursorImageValue);
296 void SVGElement::cursorImageValueRemoved()
298 ASSERT(hasSVGRareData());
299 svgRareData()->setCursorImageValue(0);
302 SVGElement* SVGElement::correspondingElement()
304 ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || shadowRoot());
305 return hasSVGRareData() ? svgRareData()->correspondingElement() : 0;
308 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
310 ensureSVGRareData()->setCorrespondingElement(correspondingElement);
313 void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
316 if (name == onloadAttr)
317 setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, name, value));
318 else if (name == onclickAttr)
319 setAttributeEventListener(eventNames().clickEvent, createAttributeEventListener(this, name, value));
320 else if (name == onmousedownAttr)
321 setAttributeEventListener(eventNames().mousedownEvent, createAttributeEventListener(this, name, value));
322 else if (name == onmousemoveAttr)
323 setAttributeEventListener(eventNames().mousemoveEvent, createAttributeEventListener(this, name, value));
324 else if (name == onmouseoutAttr)
325 setAttributeEventListener(eventNames().mouseoutEvent, createAttributeEventListener(this, name, value));
326 else if (name == onmouseoverAttr)
327 setAttributeEventListener(eventNames().mouseoverEvent, createAttributeEventListener(this, name, value));
328 else if (name == onmouseupAttr)
329 setAttributeEventListener(eventNames().mouseupEvent, createAttributeEventListener(this, name, value));
330 else if (name == SVGNames::onfocusinAttr)
331 setAttributeEventListener(eventNames().focusinEvent, createAttributeEventListener(this, name, value));
332 else if (name == SVGNames::onfocusoutAttr)
333 setAttributeEventListener(eventNames().focusoutEvent, createAttributeEventListener(this, name, value));
334 else if (name == SVGNames::onactivateAttr)
335 setAttributeEventListener(eventNames().DOMActivateEvent, createAttributeEventListener(this, name, value));
337 StyledElement::parseAttribute(name, value);
340 void SVGElement::animatedPropertyTypeForAttribute(const QualifiedName& attributeName, Vector<AnimatedPropertyType>& propertyTypes)
342 localAttributeToPropertyMap().animatedPropertyTypeForAttribute(attributeName, propertyTypes);
345 bool SVGElement::haveLoadedRequiredResources()
347 Node* child = firstChild();
349 if (child->isSVGElement() && !static_cast<SVGElement*>(child)->haveLoadedRequiredResources())
351 child = child->nextSibling();
356 static inline void collectInstancesForSVGElement(SVGElement* element, HashSet<SVGElementInstance*>& instances)
359 if (element->shadowRoot())
362 if (!element->isStyled())
365 SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(element);
366 ASSERT(!styledElement->instanceUpdatesBlocked());
368 instances = styledElement->instancesForElement();
371 bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
373 RefPtr<EventListener> listener = prpListener;
375 // Add event listener to regular DOM element
376 if (!Node::addEventListener(eventType, listener, useCapture))
379 // Add event listener to all shadow tree DOM element instances
380 HashSet<SVGElementInstance*> instances;
381 collectInstancesForSVGElement(this, instances);
382 const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
383 for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
384 ASSERT((*it)->shadowTreeElement());
385 ASSERT((*it)->correspondingElement() == this);
387 bool result = (*it)->shadowTreeElement()->Node::addEventListener(eventType, listener, useCapture);
388 ASSERT_UNUSED(result, result);
394 bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
396 HashSet<SVGElementInstance*> instances;
397 collectInstancesForSVGElement(this, instances);
398 if (instances.isEmpty())
399 return Node::removeEventListener(eventType, listener, useCapture);
401 // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener
402 // object when creating a temporary RegisteredEventListener object used to look up the
403 // event listener in a cache. If we want to be able to call removeEventListener() multiple
404 // times on different nodes, we have to delay its immediate destruction, which would happen
405 // after the first call below.
406 RefPtr<EventListener> protector(listener);
408 // Remove event listener from regular DOM element
409 if (!Node::removeEventListener(eventType, listener, useCapture))
412 // Remove event listener from all shadow tree DOM element instances
413 const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
414 for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
415 ASSERT((*it)->correspondingElement() == this);
417 SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
418 ASSERT(shadowTreeElement);
420 if (shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture))
423 // This case can only be hit for event listeners created from markup
424 ASSERT(listener->wasCreatedFromMarkup());
426 // If the event listener 'listener' has been created from markup and has been fired before
427 // then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener
428 // has been created (read: it's not 0 anymore). During shadow tree creation, the event
429 // listener DOM attribute has been cloned, and another event listener has been setup in
430 // the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0,
431 // and tryRemoveEventListener() above will fail. Work around that very seldom problem.
432 EventTargetData* data = shadowTreeElement->eventTargetData();
435 data->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
441 static bool hasLoadListener(Element* element)
443 if (element->hasEventListeners(eventNames().loadEvent))
446 for (element = element->parentOrHostElement(); element; element = element->parentOrHostElement()) {
447 const EventListenerVector& entry = element->getEventListeners(eventNames().loadEvent);
448 for (size_t i = 0; i < entry.size(); ++i) {
449 if (entry[i].useCapture)
457 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
459 RefPtr<SVGElement> currentTarget = this;
460 while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
461 RefPtr<Element> parent;
462 if (sendParentLoadEvents)
463 parent = currentTarget->parentOrHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree
464 if (hasLoadListener(currentTarget.get()))
465 currentTarget->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
466 currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>();
467 SVGElement* element = static_cast<SVGElement*>(currentTarget.get());
468 if (!element || !element->isOutermostSVGSVGElement())
471 // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>.
472 // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through
473 // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded.
474 ASSERT(sendParentLoadEvents);
476 // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example
477 // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document
478 // to be "ready to render", first.
479 if (!document()->loadEventFinished())
484 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
486 svgLoadEventTimer()->startOneShot(0);
489 void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*)
491 sendSVGLoadEventIfPossible();
494 Timer<SVGElement>* SVGElement::svgLoadEventTimer()
496 ASSERT_NOT_REACHED();
500 void SVGElement::finishParsingChildren()
502 StyledElement::finishParsingChildren();
504 // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent.
505 if (isOutermostSVGSVGElement())
508 // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
509 // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
510 sendSVGLoadEventIfPossible();
513 bool SVGElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
515 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, invalidTextContent, ());
517 if (invalidTextContent.isEmpty()) {
518 invalidTextContent.add(SVGNames::textPathTag);
519 #if ENABLE(SVG_FONTS)
520 invalidTextContent.add(SVGNames::altGlyphTag);
522 invalidTextContent.add(SVGNames::trefTag);
523 invalidTextContent.add(SVGNames::tspanTag);
525 if (childContext.node()->isSVGElement()) {
526 if (invalidTextContent.contains(static_cast<SVGElement*>(childContext.node())->tagQName()))
529 return static_cast<SVGElement*>(childContext.node())->isValid();
534 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue)
536 StyledElement::attributeChanged(name, newValue);
538 if (isIdAttributeName(name))
539 document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this);
541 // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
542 // so we don't want changes to the style attribute to result in extra work here.
543 if (name != HTMLNames::styleAttr)
544 svgAttributeChanged(name);
547 bool SVGElement::hasPendingResources() const
549 return hasSVGRareData() && svgRareData()->hasPendingResources();
552 void SVGElement::setHasPendingResources()
554 ensureSVGRareData()->setHasPendingResources(true);
557 void SVGElement::clearHasPendingResourcesIfPossible()
559 if (!document()->accessSVGExtensions()->isElementPendingResources(this))
560 ensureSVGRareData()->setHasPendingResources(false);
563 void SVGElement::updateAnimatedSVGAttribute(const QualifiedName& name) const
565 if (!attributeData() || !attributeData()->m_animatedSVGAttributesAreDirty)
568 SVGElement* nonConstThis = const_cast<SVGElement*>(this);
569 if (name == anyQName()) {
570 nonConstThis->localAttributeToPropertyMap().synchronizeProperties(nonConstThis);
571 attributeData()->m_animatedSVGAttributesAreDirty = false;
573 nonConstThis->localAttributeToPropertyMap().synchronizeProperty(nonConstThis, name);
576 SVGAttributeToPropertyMap& SVGElement::localAttributeToPropertyMap()
578 DEFINE_STATIC_LOCAL(SVGAttributeToPropertyMap, emptyMap, ());
582 void SVGElement::synchronizeRequiredFeatures(void* contextElement)
584 ASSERT(contextElement);
585 static_cast<SVGElement*>(contextElement)->synchronizeRequiredFeatures();
588 void SVGElement::synchronizeRequiredExtensions(void* contextElement)
590 ASSERT(contextElement);
591 static_cast<SVGElement*>(contextElement)->synchronizeRequiredExtensions();
594 void SVGElement::synchronizeSystemLanguage(void* contextElement)
596 ASSERT(contextElement);
597 static_cast<SVGElement*>(contextElement)->synchronizeSystemLanguage();
600 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
602 if (!correspondingElement())
603 return document()->styleResolver()->styleForElement(this);
605 RenderStyle* style = 0;
606 if (Element* parent = parentOrHostElement()) {
607 if (RenderObject* renderer = parent->renderer())
608 style = renderer->style();
611 return document()->styleResolver()->styleForElement(correspondingElement(), style, DisallowStyleSharing);
614 StylePropertySet* SVGElement::animatedSMILStyleProperties() const
616 if (hasSVGRareData())
617 return svgRareData()->animatedSMILStyleProperties();
621 StylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties()
623 return ensureSVGRareData()->ensureAnimatedSMILStyleProperties();
626 void SVGElement::setUseOverrideComputedStyle(bool value)
628 if (hasSVGRareData())
629 svgRareData()->setUseOverrideComputedStyle(value);
632 RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
634 if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle())
635 return Element::computedStyle(pseudoElementSpecifier);
637 RenderStyle* parentStyle = 0;
638 if (Element* parent = parentOrHostElement()) {
639 if (RenderObject* renderer = parent->renderer())
640 parentStyle = renderer->style();
643 return svgRareData()->overrideComputedStyle(this, parentStyle);
647 bool SVGElement::isAnimatableAttribute(const QualifiedName& name)
649 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ());
651 if (animatableAttributes.isEmpty()) {
652 animatableAttributes.add(classAttr);
653 animatableAttributes.add(XLinkNames::hrefAttr);
654 animatableAttributes.add(SVGNames::amplitudeAttr);
655 animatableAttributes.add(SVGNames::azimuthAttr);
656 animatableAttributes.add(SVGNames::baseFrequencyAttr);
657 animatableAttributes.add(SVGNames::biasAttr);
658 animatableAttributes.add(SVGNames::clipPathUnitsAttr);
659 animatableAttributes.add(SVGNames::cxAttr);
660 animatableAttributes.add(SVGNames::cyAttr);
661 animatableAttributes.add(SVGNames::diffuseConstantAttr);
662 animatableAttributes.add(SVGNames::divisorAttr);
663 animatableAttributes.add(SVGNames::dxAttr);
664 animatableAttributes.add(SVGNames::dyAttr);
665 animatableAttributes.add(SVGNames::edgeModeAttr);
666 animatableAttributes.add(SVGNames::elevationAttr);
667 animatableAttributes.add(SVGNames::exponentAttr);
668 animatableAttributes.add(SVGNames::externalResourcesRequiredAttr);
669 animatableAttributes.add(SVGNames::filterResAttr);
670 animatableAttributes.add(SVGNames::filterUnitsAttr);
671 animatableAttributes.add(SVGNames::fxAttr);
672 animatableAttributes.add(SVGNames::fyAttr);
673 animatableAttributes.add(SVGNames::gradientTransformAttr);
674 animatableAttributes.add(SVGNames::gradientUnitsAttr);
675 animatableAttributes.add(SVGNames::heightAttr);
676 animatableAttributes.add(SVGNames::in2Attr);
677 animatableAttributes.add(SVGNames::inAttr);
678 animatableAttributes.add(SVGNames::interceptAttr);
679 animatableAttributes.add(SVGNames::k1Attr);
680 animatableAttributes.add(SVGNames::k2Attr);
681 animatableAttributes.add(SVGNames::k3Attr);
682 animatableAttributes.add(SVGNames::k4Attr);
683 animatableAttributes.add(SVGNames::kernelMatrixAttr);
684 animatableAttributes.add(SVGNames::kernelUnitLengthAttr);
685 animatableAttributes.add(SVGNames::lengthAdjustAttr);
686 animatableAttributes.add(SVGNames::limitingConeAngleAttr);
687 animatableAttributes.add(SVGNames::markerHeightAttr);
688 animatableAttributes.add(SVGNames::markerUnitsAttr);
689 animatableAttributes.add(SVGNames::markerWidthAttr);
690 animatableAttributes.add(SVGNames::maskContentUnitsAttr);
691 animatableAttributes.add(SVGNames::maskUnitsAttr);
692 animatableAttributes.add(SVGNames::methodAttr);
693 animatableAttributes.add(SVGNames::modeAttr);
694 animatableAttributes.add(SVGNames::numOctavesAttr);
695 animatableAttributes.add(SVGNames::offsetAttr);
696 animatableAttributes.add(SVGNames::operatorAttr);
697 animatableAttributes.add(SVGNames::orderAttr);
698 animatableAttributes.add(SVGNames::orientAttr);
699 animatableAttributes.add(SVGNames::pathLengthAttr);
700 animatableAttributes.add(SVGNames::patternContentUnitsAttr);
701 animatableAttributes.add(SVGNames::patternTransformAttr);
702 animatableAttributes.add(SVGNames::patternUnitsAttr);
703 animatableAttributes.add(SVGNames::pointsAtXAttr);
704 animatableAttributes.add(SVGNames::pointsAtYAttr);
705 animatableAttributes.add(SVGNames::pointsAtZAttr);
706 animatableAttributes.add(SVGNames::preserveAlphaAttr);
707 animatableAttributes.add(SVGNames::preserveAspectRatioAttr);
708 animatableAttributes.add(SVGNames::primitiveUnitsAttr);
709 animatableAttributes.add(SVGNames::radiusAttr);
710 animatableAttributes.add(SVGNames::rAttr);
711 animatableAttributes.add(SVGNames::refXAttr);
712 animatableAttributes.add(SVGNames::refYAttr);
713 animatableAttributes.add(SVGNames::resultAttr);
714 animatableAttributes.add(SVGNames::rotateAttr);
715 animatableAttributes.add(SVGNames::rxAttr);
716 animatableAttributes.add(SVGNames::ryAttr);
717 animatableAttributes.add(SVGNames::scaleAttr);
718 animatableAttributes.add(SVGNames::seedAttr);
719 animatableAttributes.add(SVGNames::slopeAttr);
720 animatableAttributes.add(SVGNames::spacingAttr);
721 animatableAttributes.add(SVGNames::specularConstantAttr);
722 animatableAttributes.add(SVGNames::specularExponentAttr);
723 animatableAttributes.add(SVGNames::spreadMethodAttr);
724 animatableAttributes.add(SVGNames::startOffsetAttr);
725 animatableAttributes.add(SVGNames::stdDeviationAttr);
726 animatableAttributes.add(SVGNames::stitchTilesAttr);
727 animatableAttributes.add(SVGNames::surfaceScaleAttr);
728 animatableAttributes.add(SVGNames::tableValuesAttr);
729 animatableAttributes.add(SVGNames::targetAttr);
730 animatableAttributes.add(SVGNames::targetXAttr);
731 animatableAttributes.add(SVGNames::targetYAttr);
732 animatableAttributes.add(SVGNames::transformAttr);
733 animatableAttributes.add(SVGNames::typeAttr);
734 animatableAttributes.add(SVGNames::valuesAttr);
735 animatableAttributes.add(SVGNames::viewBoxAttr);
736 animatableAttributes.add(SVGNames::widthAttr);
737 animatableAttributes.add(SVGNames::x1Attr);
738 animatableAttributes.add(SVGNames::x2Attr);
739 animatableAttributes.add(SVGNames::xAttr);
740 animatableAttributes.add(SVGNames::xChannelSelectorAttr);
741 animatableAttributes.add(SVGNames::y1Attr);
742 animatableAttributes.add(SVGNames::y2Attr);
743 animatableAttributes.add(SVGNames::yAttr);
744 animatableAttributes.add(SVGNames::yChannelSelectorAttr);
745 animatableAttributes.add(SVGNames::zAttr);
747 return animatableAttributes.contains(name);
753 #endif // ENABLE(SVG)