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.
26 #include "core/svg/SVGElement.h"
28 #include "HTMLNames.h"
30 #include "XLinkNames.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"
51 #include "wtf/TemporaryChange.h"
55 using namespace HTMLNames;
56 using namespace SVGNames;
58 void mapAttributeToCSSProperty(HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap, const QualifiedName& attrName)
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;
68 ASSERT(propertyId > 0);
69 propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
72 SVGElement::SVGElement(const QualifiedName& tagName, Document& document, ConstructionType constructionType)
73 : Element(tagName, &document, constructionType)
75 , m_inRelativeLengthClientsInvalidation(false)
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()))
82 ScriptWrappable::init(this);
83 addToPropertyMap(m_className);
84 setHasCustomStyleCallbacks();
87 SVGElement::~SVGElement()
89 ASSERT(inDocument() || !hasRelativeLengths());
91 // The below teardown is all handled by weak pointer processing in oilpan.
93 if (!hasSVGRareData())
94 ASSERT(!SVGElementRareData::rareDataMap().contains(this));
96 SVGElementRareData::SVGElementRareDataMap& rareDataMap = SVGElementRareData::rareDataMap();
97 SVGElementRareData::SVGElementRareDataMap::iterator it = rareDataMap.find(this);
98 ASSERT_WITH_SECURITY_IMPLICATION(it != rareDataMap.end());
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);
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();
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);
125 short SVGElement::tabIndex() const
128 return Element::tabIndex();
132 void SVGElement::willRecalcStyle(StyleRecalcChange change)
134 if (!hasSVGRareData())
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();
142 void SVGElement::buildPendingResourcesIfNeeded()
144 Document& document = this->document();
145 if (!needsPendingResourceHandling() || !inDocument() || inUseShadowTree())
148 SVGDocumentExtensions& extensions = document.accessSVGExtensions();
149 AtomicString resourceId = getIdAttribute();
150 if (!extensions.hasPendingResource(resourceId))
153 // Mark pending resources as pending for removal.
154 extensions.markPendingResourcesForRemoval(resourceId);
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);
166 bool SVGElement::rendererIsNeeded(const RenderStyle& style)
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);
179 SVGElementRareData* SVGElement::svgRareData() const
181 ASSERT(hasSVGRareData());
182 return SVGElementRareData::rareDataFromMap(this);
185 SVGElementRareData* SVGElement::ensureSVGRareData()
187 if (hasSVGRareData())
188 return svgRareData();
190 ASSERT(!SVGElementRareData::rareDataMap().contains(this));
191 SVGElementRareData* data = new SVGElementRareData(this);
192 SVGElementRareData::rareDataMap().set(this, data);
197 bool SVGElement::isOutermostSVGSVGElement() const
199 if (!isSVGSVGElement(*this))
202 // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
206 // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
207 if (isSVGForeignObjectElement(*parentNode()))
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())
216 // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
217 return !parentNode()->isSVGElement();
220 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value)
222 if (error == NoError)
225 String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
226 SVGDocumentExtensions& extensions = document().accessSVGExtensions();
228 if (error == NegativeValueForbiddenError) {
229 extensions.reportError("Invalid negative value for " + errorString);
233 if (error == ParsingAttributeFailedError) {
234 extensions.reportError("Invalid value for " + errorString);
238 ASSERT_NOT_REACHED();
241 String SVGElement::title() const
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())
248 if (inUseShadowTree()) {
249 String useTitle(shadowHost()->title());
250 if (!useTitle.isEmpty())
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();
260 // Otherwise return a null/empty string.
264 bool SVGElement::instanceUpdatesBlocked() const
266 return hasSVGRareData() && svgRareData()->instanceUpdatesBlocked();
269 void SVGElement::setInstanceUpdatesBlocked(bool value)
271 if (hasSVGRareData())
272 svgRareData()->setInstanceUpdatesBlocked(value);
275 AffineTransform SVGElement::localCoordinateSpaceTransform(CTMScope) const
277 // To be overriden by SVGGraphicsElement (or as special case SVGTextElement and SVGPatternElement)
278 return AffineTransform();
281 const AtomicString& SVGElement::xmlbase() const
283 return fastGetAttribute(XMLNames::baseAttr);
286 void SVGElement::setXMLbase(const AtomicString& value)
288 setAttribute(XMLNames::baseAttr, value);
291 const AtomicString& SVGElement::xmllang() const
293 return fastGetAttribute(XMLNames::langAttr);
296 void SVGElement::setXMLlang(const AtomicString& value)
298 setAttribute(XMLNames::langAttr, value);
301 const AtomicString& SVGElement::xmlspace() const
303 return fastGetAttribute(XMLNames::spaceAttr);
306 void SVGElement::setXMLspace(const AtomicString& value)
308 setAttribute(XMLNames::spaceAttr, value);
311 Node::InsertionNotificationRequest SVGElement::insertedInto(ContainerNode* rootParent)
313 Element::insertedInto(rootParent);
314 updateRelativeLengthsInformation();
315 buildPendingResourcesIfNeeded();
316 return InsertionDone;
319 void SVGElement::removedFrom(ContainerNode* rootParent)
321 bool wasInDocument = rootParent->inDocument();
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);
332 m_elementsWithRelativeLengths.clear();
335 ASSERT_WITH_SECURITY_IMPLICATION(!rootParent->isSVGElement() || !toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this));
337 Element::removedFrom(rootParent);
340 document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this);
341 document().accessSVGExtensions().removeAllElementReferencesForTarget(this);
344 invalidateInstances();
347 void SVGElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
349 Element::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
351 // Invalidate all SVGElementInstances associated with us.
352 if (!changedByParser)
353 invalidateInstances();
356 CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
358 if (!attrName.namespaceURI().isNull())
359 return CSSPropertyInvalid;
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);
428 return propertyNameToIdMap->get(attrName.localName().impl());
431 void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement)
433 ASSERT(clientElement);
435 // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now.
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);
446 bool hadRelativeLengths = currentElement->hasRelativeLengths();
447 if (clientHasRelativeLengths)
448 currentElement->m_elementsWithRelativeLengths.add(clientElement);
450 currentElement->m_elementsWithRelativeLengths.remove(clientElement);
452 // If the relative length state hasn't changed, we can stop propagating the notification.
453 if (hadRelativeLengths == currentElement->hasRelativeLengths())
456 clientElement = currentElement;
457 clientHasRelativeLengths = clientElement->hasRelativeLengths();
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));
466 svgExtensions.removeSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
470 void SVGElement::invalidateRelativeLengthClients(SubtreeLayoutScope* layoutScope)
475 ASSERT(!m_inRelativeLengthClientsInvalidation);
477 TemporaryChange<bool> inRelativeLengthClientsInvalidationChange(m_inRelativeLengthClientsInvalidation, true);
480 RenderObject* renderer = this->renderer();
481 if (renderer && selfHasRelativeLengths()) {
482 if (renderer->isSVGResourceContainer())
483 toRenderSVGResourceContainer(renderer)->invalidateCacheAndMarkForLayout(layoutScope);
485 renderer->setNeedsLayout(MarkContainingBlockChain, layoutScope);
488 HashSet<SVGElement*>::iterator end = m_elementsWithRelativeLengths.end();
489 for (HashSet<SVGElement*>::iterator it = m_elementsWithRelativeLengths.begin(); it != end; ++it) {
491 (*it)->invalidateRelativeLengthClients(layoutScope);
495 SVGSVGElement* SVGElement::ownerSVGElement() const
497 ContainerNode* n = parentOrShadowHostNode();
499 if (isSVGSVGElement(*n))
500 return toSVGSVGElement(n);
502 n = n->parentOrShadowHostNode();
508 SVGElement* SVGElement::viewportElement() const
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();
514 if (isSVGSVGElement(*n) || isSVGImageElement(*n) || isSVGSymbolElement(*n))
515 return toSVGElement(n);
517 n = n->parentOrShadowHostNode();
523 SVGDocumentExtensions& SVGElement::accessDocumentSVGExtensions()
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();
530 void SVGElement::mapInstanceToElement(SVGElement* instance)
533 ASSERT(instance->inUseShadowTree());
535 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = ensureSVGRareData()->elementInstances();
536 ASSERT(!instances.contains(instance));
538 instances.add(instance);
541 void SVGElement::removeInstanceMapping(SVGElement* instance)
544 ASSERT(instance->inUseShadowTree());
545 ASSERT(hasSVGRareData());
547 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = svgRareData()->elementInstances();
548 ASSERT(instances.contains(instance));
550 instances.remove(instance);
553 static WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& emptyInstances()
556 DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<WeakMember<SVGElement> > >, emptyInstances, (new HeapHashSet<WeakMember<SVGElement> >));
557 return *emptyInstances;
559 DEFINE_STATIC_LOCAL(HashSet<RawPtr<SVGElement> >, emptyInstances, ());
560 return emptyInstances;
564 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& SVGElement::instancesForElement() const
566 if (!hasSVGRareData())
567 return emptyInstances();
568 return svgRareData()->elementInstances();
571 bool SVGElement::getBoundingBox(FloatRect& rect)
573 if (!isSVGGraphicsElement())
576 rect = toSVGGraphicsElement(this)->getBBox();
580 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
582 SVGElementRareData* rareData = ensureSVGRareData();
583 if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) {
584 if (cursorElement == oldCursorElement)
586 oldCursorElement->removeReferencedElement(this);
588 rareData->setCursorElement(cursorElement);
592 void SVGElement::cursorElementRemoved()
594 ASSERT(hasSVGRareData());
595 svgRareData()->setCursorElement(0);
599 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
601 SVGElementRareData* rareData = ensureSVGRareData();
603 if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) {
604 if (cursorImageValue == oldCursorImageValue)
606 oldCursorImageValue->removeReferencedElement(this);
609 rareData->setCursorImageValue(cursorImageValue);
613 void SVGElement::cursorImageValueRemoved()
615 ASSERT(hasSVGRareData());
616 svgRareData()->setCursorImageValue(0);
620 SVGElement* SVGElement::correspondingElement()
622 ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || containingShadowRoot());
623 return hasSVGRareData() ? svgRareData()->correspondingElement() : 0;
626 SVGUseElement* SVGElement::correspondingUseElement() const
628 if (ShadowRoot* root = containingShadowRoot()) {
629 if (isSVGUseElement(root->host()) && (root->type() == ShadowRoot::UserAgentShadowRoot))
630 return toSVGUseElement(root->host());
635 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
637 ensureSVGRareData()->setCorrespondingElement(correspondingElement);
640 bool SVGElement::inUseShadowTree() const
642 return correspondingUseElement();
645 bool SVGElement::supportsSpatialNavigationFocus() const
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).
653 if (!document().settings() || !document().settings()->spatialNavigationEnabled())
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);
665 void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
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);
680 const AtomicString& eventName = HTMLElement::eventNameForAttributeName(name);
681 if (!eventName.isNull())
682 setAttributeEventListener(eventName, createAttributeEventListener(this, name, value));
684 Element::parseAttribute(name, value);
688 typedef HashMap<QualifiedName, AnimatedPropertyType> AttributeToPropertyTypeMap;
689 AnimatedPropertyType SVGElement::animatedPropertyTypeForCSSAttribute(const QualifiedName& attributeName)
691 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, cssPropertyMap, ());
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);
751 if (cssPropertyMap.contains(attributeName))
752 return cssPropertyMap.get(attributeName);
754 return AnimatedUnknown;
757 void SVGElement::addToPropertyMap(PassRefPtr<SVGAnimatedPropertyBase> passProperty)
759 RefPtr<SVGAnimatedPropertyBase> property(passProperty);
760 QualifiedName attributeName = property->attributeName();
761 m_newAttributeToPropertyMap.set(attributeName, property.release());
764 PassRefPtr<SVGAnimatedPropertyBase> SVGElement::propertyFromAttribute(const QualifiedName& attributeName)
766 return m_newAttributeToPropertyMap.get(attributeName);
769 bool SVGElement::isAnimatableCSSProperty(const QualifiedName& attrName)
771 return animatedPropertyTypeForCSSAttribute(attrName) != AnimatedUnknown;
774 bool SVGElement::isPresentationAttribute(const QualifiedName& name) const
776 return cssPropertyIdForSVGAttributeName(name) > 0;
779 void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
781 CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(name);
783 addPropertyToPresentationAttributeStyle(style, propertyID, value);
786 bool SVGElement::haveLoadedRequiredResources()
788 for (SVGElement* child = Traversal<SVGElement>::firstChild(*this); child; child = Traversal<SVGElement>::nextSibling(*child)) {
789 if (!child->haveLoadedRequiredResources())
795 static inline void collectInstancesForSVGElement(SVGElement* element, WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances)
798 if (element->containingShadowRoot())
801 ASSERT(!element->instanceUpdatesBlocked());
803 instances = element->instancesForElement();
806 bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
808 RefPtr<EventListener> listener = prpListener;
810 // Add event listener to regular DOM element
811 if (!Node::addEventListener(eventType, listener, useCapture))
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);
826 bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
828 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > instances;
829 collectInstancesForSVGElement(this, instances);
830 if (instances.isEmpty())
831 return Node::removeEventListener(eventType, listener, useCapture);
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);
840 // Remove event listener from regular DOM element
841 if (!Node::removeEventListener(eventType, listener, useCapture))
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);
850 if (shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture))
853 // This case can only be hit for event listeners created from markup
854 ASSERT(listener->wasCreatedFromMarkup());
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();
865 data->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
871 static bool hasLoadListener(Element* element)
873 if (element->hasEventListeners(EventTypeNames::load))
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)
887 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
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())
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);
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())
915 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
917 svgLoadEventTimer()->startOneShot(0, FROM_HERE);
920 void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*)
922 sendSVGLoadEventIfPossible();
925 Timer<SVGElement>* SVGElement::svgLoadEventTimer()
927 ASSERT_NOT_REACHED();
931 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason)
933 Element::attributeChanged(name, newValue);
935 if (isIdAttributeName(name))
936 document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this);
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);
944 void SVGElement::svgAttributeChanged(const QualifiedName& attrName)
946 CSSPropertyID propId = SVGElement::cssPropertyIdForSVGAttributeName(attrName);
948 invalidateInstances();
952 if (attrName == HTMLNames::classAttr) {
953 classAttributeChanged(AtomicString(m_className->currentValue()->value()));
954 invalidateInstances();
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();
964 buildPendingResourcesIfNeeded();
965 invalidateInstances();
970 void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const
972 if (!elementData() || !elementData()->m_animatedSVGAttributesAreDirty)
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();
983 elementData()->m_animatedSVGAttributesAreDirty = false;
985 RefPtr<SVGAnimatedPropertyBase> property = m_newAttributeToPropertyMap.get(name);
986 if (property && property->needsSynchronizeAttribute())
987 property->synchronizeAttribute();
991 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
993 if (!correspondingElement())
994 return document().ensureStyleResolver().styleForElement(this);
996 RenderStyle* style = 0;
997 if (Element* parent = parentOrShadowHostElement()) {
998 if (RenderObject* renderer = parent->renderer())
999 style = renderer->style();
1002 return document().ensureStyleResolver().styleForElement(correspondingElement(), style, DisallowStyleSharing);
1005 MutableStylePropertySet* SVGElement::animatedSMILStyleProperties() const
1007 if (hasSVGRareData())
1008 return svgRareData()->animatedSMILStyleProperties();
1012 MutableStylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties()
1014 return ensureSVGRareData()->ensureAnimatedSMILStyleProperties();
1017 void SVGElement::setUseOverrideComputedStyle(bool value)
1019 if (hasSVGRareData())
1020 svgRareData()->setUseOverrideComputedStyle(value);
1023 RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
1025 if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle())
1026 return Element::computedStyle(pseudoElementSpecifier);
1028 RenderStyle* parentStyle = 0;
1029 if (Element* parent = parentOrShadowHostElement()) {
1030 if (RenderObject* renderer = parent->renderer())
1031 parentStyle = renderer->style();
1034 return svgRareData()->overrideComputedStyle(this, parentStyle);
1037 bool SVGElement::hasFocusEventListeners() const
1039 return hasEventListeners(EventTypeNames::focusin) || hasEventListeners(EventTypeNames::focusout)
1040 || hasEventListeners(EventTypeNames::focus) || hasEventListeners(EventTypeNames::blur);
1043 void SVGElement::invalidateInstances()
1048 if (instanceUpdatesBlocked())
1051 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& set = instancesForElement();
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);
1060 if (SVGUseElement* element = (*it)->correspondingUseElement()) {
1061 ASSERT(element->inDocument());
1062 element->invalidateShadowTree();
1066 document().updateRenderTreeIfNeeded();
1069 SVGElement::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement* targetElement)
1070 : m_targetElement(targetElement)
1072 if (m_targetElement)
1073 m_targetElement->setInstanceUpdatesBlocked(true);
1076 SVGElement::InstanceUpdateBlocker::~InstanceUpdateBlocker()
1078 if (m_targetElement)
1079 m_targetElement->setInstanceUpdatesBlocked(false);
1083 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
1085 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ());
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);
1182 if (name == classAttr)
1185 return animatableAttributes.contains(name);