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/events/Event.h"
38 #include "core/dom/shadow/ShadowRoot.h"
39 #include "core/rendering/RenderObject.h"
40 #include "core/rendering/svg/RenderSVGResourceContainer.h"
41 #include "core/svg/SVGCursorElement.h"
42 #include "core/svg/SVGDocumentExtensions.h"
43 #include "core/svg/SVGElementInstance.h"
44 #include "core/svg/SVGElementRareData.h"
45 #include "core/svg/SVGGraphicsElement.h"
46 #include "core/svg/SVGSVGElement.h"
47 #include "core/svg/SVGUseElement.h"
49 #include "wtf/TemporaryChange.h"
53 // Animated property definitions
54 DEFINE_ANIMATED_STRING(SVGElement, HTMLNames::classAttr, ClassName, className)
56 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGElement)
57 REGISTER_LOCAL_ANIMATED_PROPERTY(className)
58 END_REGISTER_ANIMATED_PROPERTIES
60 using namespace HTMLNames;
61 using namespace SVGNames;
63 void mapAttributeToCSSProperty(HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap, const QualifiedName& attrName)
65 // FIXME: when CSS supports "transform-origin" the special case for transform_originAttr can be removed.
66 CSSPropertyID propertyId = cssPropertyID(attrName.localName());
67 if (!propertyId && attrName == transform_originAttr)
68 propertyId = CSSPropertyWebkitTransformOrigin; // cssPropertyID("-webkit-transform-origin")
69 ASSERT(propertyId > 0);
70 propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
73 SVGElement::SVGElement(const QualifiedName& tagName, Document& document, ConstructionType constructionType)
74 : Element(tagName, &document, constructionType)
76 , m_inRelativeLengthClientsInvalidation(false)
78 , m_animatedPropertiesDestructed(false)
79 , m_isContextElement(false)
80 , m_hasSVGRareData(false)
82 ScriptWrappable::init(this);
83 registerAnimatedPropertiesForSVGElement();
84 setHasCustomStyleCallbacks();
87 SVGElement::~SVGElement()
89 ASSERT(inDocument() || !hasRelativeLengths());
93 SVGElement::cleanupAnimatedProperties()
95 if (m_animatedPropertiesDestructed)
97 m_animatedPropertiesDestructed = true;
99 if (!hasSVGRareData())
100 ASSERT(!SVGElementRareData::rareDataMap().contains(this));
102 SVGElementRareData::SVGElementRareDataMap& rareDataMap = SVGElementRareData::rareDataMap();
103 SVGElementRareData::SVGElementRareDataMap::iterator it = rareDataMap.find(this);
104 ASSERT_WITH_SECURITY_IMPLICATION(it != rareDataMap.end());
106 SVGElementRareData* rareData = it->value;
107 rareData->destroyAnimatedSMILStyleProperties();
108 if (SVGCursorElement* cursorElement = rareData->cursorElement())
109 cursorElement->removeClient(this);
110 if (CSSCursorImageValue* cursorImageValue = rareData->cursorImageValue())
111 cursorImageValue->removeReferencedElement(this);
115 // The rare data cleanup may have caused other SVG nodes to be deleted,
116 // modifying the rare data map. Do not rely on the existing iterator.
117 ASSERT(rareDataMap.contains(this));
118 rareDataMap.remove(this);
119 // Clear HasSVGRareData flag now so that we are in a consistent state when
120 // calling rebuildAllElementReferencesForTarget() and
121 // removeAllElementReferencesForTarget() below.
122 clearHasSVGRareData();
124 document().accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
125 document().accessSVGExtensions()->removeAllElementReferencesForTarget(this);
126 SVGAnimatedProperty::detachAnimatedPropertiesForElement(this);
129 void SVGElement::willRecalcStyle(StyleRecalcChange change)
131 // FIXME: This assumes that when shouldNotifyRendererWithIdenticalStyles() is true
132 // the change came from a SMIL animation, but what if there were non-SMIL changes
133 // since then? I think we should remove the shouldNotifyRendererWithIdenticalStyles
135 if (!hasSVGRareData() || shouldNotifyRendererWithIdenticalStyles())
137 // If the style changes because of a regular property change (not induced by SMIL animations themselves)
138 // reset the "computed style without SMIL style properties", so the base value change gets reflected.
139 if (change > NoChange || needsStyleRecalc())
140 svgRareData()->setNeedsOverrideComputedStyleUpdate();
143 void SVGElement::buildPendingResourcesIfNeeded()
145 Document& document = this->document();
146 if (!needsPendingResourceHandling() || !inDocument() || isInShadowTree())
149 SVGDocumentExtensions* extensions = document.accessSVGExtensions();
150 AtomicString resourceId = getIdAttribute();
151 if (!extensions->hasPendingResource(resourceId))
154 // Mark pending resources as pending for removal.
155 extensions->markPendingResourcesForRemoval(resourceId);
157 // Rebuild pending resources for each client of a pending resource that is being removed.
158 while (Element* clientElement = extensions->removeElementFromPendingResourcesForRemoval(resourceId)) {
159 ASSERT(clientElement->hasPendingResources());
160 if (clientElement->hasPendingResources()) {
161 clientElement->buildPendingResource();
162 extensions->clearHasPendingResourcesIfPossible(clientElement);
167 bool SVGElement::rendererIsNeeded(const RenderStyle& style)
169 // http://www.w3.org/TR/SVG/extend.html#PrivateData
170 // Prevent anything other than SVG renderers from appearing in our render tree
171 // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
172 // with the SVG content. In general, the SVG user agent will include the unknown
173 // elements in the DOM but will otherwise ignore unknown elements.
174 if (!parentOrShadowHostElement() || parentOrShadowHostElement()->isSVGElement())
175 return Element::rendererIsNeeded(style);
180 SVGElementRareData* SVGElement::svgRareData() const
182 ASSERT(hasSVGRareData());
183 return SVGElementRareData::rareDataFromMap(this);
186 SVGElementRareData* SVGElement::ensureSVGRareData()
188 if (hasSVGRareData())
189 return svgRareData();
191 ASSERT(!SVGElementRareData::rareDataMap().contains(this));
192 SVGElementRareData* data = new SVGElementRareData;
193 SVGElementRareData::rareDataMap().set(this, data);
198 bool SVGElement::isOutermostSVGSVGElement() const
200 if (!hasTagName(SVGNames::svgTag))
203 // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
207 // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
208 if (parentNode()->hasTagName(SVGNames::foreignObjectTag))
211 // If we're living in a shadow tree, we're a <svg> element that got created as replacement
212 // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case
213 // we're always an inner <svg> element.
214 if (isInShadowTree() && parentOrShadowHostElement() && parentOrShadowHostElement()->isSVGElement())
217 // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
218 return !parentNode()->isSVGElement();
221 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value)
223 if (error == NoError)
226 String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
227 SVGDocumentExtensions* extensions = document().accessSVGExtensions();
229 if (error == NegativeValueForbiddenError) {
230 extensions->reportError("Invalid negative value for " + errorString);
234 if (error == ParsingAttributeFailedError) {
235 extensions->reportError("Invalid value for " + errorString);
239 ASSERT_NOT_REACHED();
242 String SVGElement::title() const
244 // According to spec, we should not return titles when hovering over root <svg> elements (those
245 // <title> elements are the title of the document, not a tooltip) so we instantly return.
246 if (isOutermostSVGSVGElement())
249 // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title.
250 if (isInShadowTree()) {
251 Element* shadowHostElement = toShadowRoot(treeScope().rootNode()).host();
252 // At this time, SVG nodes are not allowed in non-<use> shadow trees, so any shadow root we do
253 // have should be a use. The assert and following test is here to catch future shadow DOM changes
254 // that do enable SVG in a shadow tree.
255 ASSERT(!shadowHostElement || shadowHostElement->hasTagName(SVGNames::useTag));
256 if (shadowHostElement && shadowHostElement->hasTagName(SVGNames::useTag)) {
257 SVGUseElement* useElement = toSVGUseElement(shadowHostElement);
259 // If the <use> title is not empty we found the title to use.
260 String useTitle(useElement->title());
261 if (!useTitle.isEmpty())
266 // If we aren't an instance in a <use> or the <use> title was not found, then find the first
267 // <title> child of this element.
268 Element* titleElement = ElementTraversal::firstWithin(*this);
269 for (; titleElement; titleElement = ElementTraversal::nextSkippingChildren(*titleElement, this)) {
270 if (titleElement->hasTagName(SVGNames::titleTag) && titleElement->isSVGElement())
274 // If a title child was found, return the text contents.
276 return titleElement->innerText();
278 // Otherwise return a null/empty string.
282 PassRefPtr<CSSValue> SVGElement::getPresentationAttribute(const AtomicString& name)
284 if (!hasAttributesWithoutUpdate())
287 QualifiedName attributeName(nullAtom, name, nullAtom);
288 const Attribute* attr = getAttributeItem(attributeName);
292 RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create(SVGAttributeMode);
293 CSSPropertyID propertyID = SVGElement::cssPropertyIdForSVGAttributeName(attr->name());
294 style->setProperty(propertyID, attr->value());
295 RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(propertyID);
296 return cssValue ? cssValue->cloneForCSSOM() : 0;
300 bool SVGElement::instanceUpdatesBlocked() const
302 return hasSVGRareData() && svgRareData()->instanceUpdatesBlocked();
305 void SVGElement::setInstanceUpdatesBlocked(bool value)
307 if (hasSVGRareData())
308 svgRareData()->setInstanceUpdatesBlocked(value);
311 AffineTransform SVGElement::localCoordinateSpaceTransform(CTMScope) const
313 // To be overriden by SVGGraphicsElement (or as special case SVGTextElement and SVGPatternElement)
314 return AffineTransform();
317 const AtomicString& SVGElement::xmlbase() const
319 return fastGetAttribute(XMLNames::baseAttr);
322 void SVGElement::setXMLbase(const AtomicString& value)
324 setAttribute(XMLNames::baseAttr, value);
327 const AtomicString& SVGElement::xmllang() const
329 return fastGetAttribute(XMLNames::langAttr);
332 void SVGElement::setXMLlang(const AtomicString& value)
334 setAttribute(XMLNames::langAttr, value);
337 const AtomicString& SVGElement::xmlspace() const
339 return fastGetAttribute(XMLNames::spaceAttr);
342 void SVGElement::setXMLspace(const AtomicString& value)
344 setAttribute(XMLNames::spaceAttr, value);
347 Node::InsertionNotificationRequest SVGElement::insertedInto(ContainerNode* rootParent)
349 Element::insertedInto(rootParent);
350 updateRelativeLengthsInformation();
351 buildPendingResourcesIfNeeded();
352 return InsertionDone;
355 void SVGElement::removedFrom(ContainerNode* rootParent)
357 bool wasInDocument = rootParent->inDocument();
359 if (wasInDocument && hasRelativeLengths()) {
360 // The root of the subtree being removed should take itself out from its parent's relative
361 // length set. For the other nodes in the subtree we don't need to do anything: they will
362 // get their own removedFrom() notification and just clear their sets.
363 if (rootParent->isSVGElement() && !parentNode()) {
364 ASSERT(toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this));
365 toSVGElement(rootParent)->updateRelativeLengthsInformation(false, this);
368 m_elementsWithRelativeLengths.clear();
371 ASSERT_WITH_SECURITY_IMPLICATION(!rootParent->isSVGElement() || !toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this));
373 Element::removedFrom(rootParent);
376 document().accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
377 document().accessSVGExtensions()->removeAllElementReferencesForTarget(this);
380 SVGElementInstance::invalidateAllInstancesOfElement(this);
383 void SVGElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
385 Element::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
387 // Invalidate all SVGElementInstances associated with us.
388 if (!changedByParser)
389 SVGElementInstance::invalidateAllInstancesOfElement(this);
392 CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
394 if (!attrName.namespaceURI().isNull())
395 return CSSPropertyInvalid;
397 static HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap = 0;
398 if (!propertyNameToIdMap) {
399 propertyNameToIdMap = new HashMap<StringImpl*, CSSPropertyID>;
400 // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
401 mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr);
402 mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr);
403 mapAttributeToCSSProperty(propertyNameToIdMap, buffered_renderingAttr);
404 mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr);
405 mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr);
406 mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr);
407 mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::colorAttr);
408 mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr);
409 mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr);
410 mapAttributeToCSSProperty(propertyNameToIdMap, color_profileAttr);
411 mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr);
412 mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr);
413 mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::directionAttr);
414 mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr);
415 mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr);
416 mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr);
417 mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr);
418 mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr);
419 mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr);
420 mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr);
421 mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr);
422 mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr);
423 mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
424 mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
425 mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
426 mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
427 mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
428 mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
429 mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr);
430 mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr);
431 mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr);
432 mapAttributeToCSSProperty(propertyNameToIdMap, kerningAttr);
433 mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr);
434 mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr);
435 mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr);
436 mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr);
437 mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr);
438 mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr);
439 mapAttributeToCSSProperty(propertyNameToIdMap, mask_typeAttr);
440 mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr);
441 mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr);
442 mapAttributeToCSSProperty(propertyNameToIdMap, paint_orderAttr);
443 mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr);
444 mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr);
445 mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr);
446 mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr);
447 mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr);
448 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr);
449 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr);
450 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr);
451 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr);
452 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr);
453 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr);
454 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr);
455 mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr);
456 mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr);
457 mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr);
458 mapAttributeToCSSProperty(propertyNameToIdMap, transform_originAttr);
459 mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr);
460 mapAttributeToCSSProperty(propertyNameToIdMap, vector_effectAttr);
461 mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr);
462 mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr);
463 mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr);
466 return propertyNameToIdMap->get(attrName.localName().impl());
469 void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement)
471 ASSERT(clientElement);
473 // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now.
477 // An element wants to notify us that its own relative lengths state changed.
478 // Register it in the relative length map, and register us in the parent relative length map.
479 // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.
480 for (ContainerNode* currentNode = this; currentNode && currentNode->isSVGElement(); currentNode = currentNode->parentNode()) {
481 SVGElement* currentElement = toSVGElement(currentNode);
482 ASSERT(!currentElement->m_inRelativeLengthClientsInvalidation);
484 bool hadRelativeLengths = currentElement->hasRelativeLengths();
485 if (clientHasRelativeLengths)
486 currentElement->m_elementsWithRelativeLengths.add(clientElement);
488 currentElement->m_elementsWithRelativeLengths.remove(clientElement);
490 // If the relative length state hasn't changed, we can stop propagating the notification.
491 if (hadRelativeLengths == currentElement->hasRelativeLengths())
494 clientElement = currentElement;
495 clientHasRelativeLengths = clientElement->hasRelativeLengths();
498 // Register root SVG elements for top level viewport change notifications.
499 if (clientElement->isSVGSVGElement()) {
500 SVGDocumentExtensions* svgExtensions = accessDocumentSVGExtensions();
501 if (clientElement->hasRelativeLengths())
502 svgExtensions->addSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
504 svgExtensions->removeSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
508 void SVGElement::invalidateRelativeLengthClients(SubtreeLayoutScope* layoutScope)
513 ASSERT(!m_inRelativeLengthClientsInvalidation);
515 TemporaryChange<bool> inRelativeLengthClientsInvalidationChange(m_inRelativeLengthClientsInvalidation, true);
518 RenderObject* renderer = this->renderer();
519 if (renderer && selfHasRelativeLengths()) {
520 if (renderer->isSVGResourceContainer())
521 toRenderSVGResourceContainer(renderer)->invalidateCacheAndMarkForLayout(layoutScope);
523 renderer->setNeedsLayout(MarkContainingBlockChain, layoutScope);
526 HashSet<SVGElement*>::iterator end = m_elementsWithRelativeLengths.end();
527 for (HashSet<SVGElement*>::iterator it = m_elementsWithRelativeLengths.begin(); it != end; ++it) {
529 (*it)->invalidateRelativeLengthClients(layoutScope);
533 SVGSVGElement* SVGElement::ownerSVGElement() const
535 ContainerNode* n = parentOrShadowHostNode();
537 if (n->hasTagName(SVGNames::svgTag))
538 return toSVGSVGElement(n);
540 n = n->parentOrShadowHostNode();
546 SVGElement* SVGElement::viewportElement() const
548 // This function needs shadow tree support - as RenderSVGContainer uses this function
549 // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
550 ContainerNode* n = parentOrShadowHostNode();
552 if (n->hasTagName(SVGNames::svgTag) || n->hasTagName(SVGNames::imageTag) || n->hasTagName(SVGNames::symbolTag))
553 return toSVGElement(n);
555 n = n->parentOrShadowHostNode();
561 SVGDocumentExtensions* SVGElement::accessDocumentSVGExtensions()
563 // This function is provided for use by SVGAnimatedProperty to avoid
564 // global inclusion of core/dom/Document.h in SVG code.
565 return document().accessSVGExtensions();
568 void SVGElement::mapInstanceToElement(SVGElementInstance* instance)
572 HashSet<SVGElementInstance*>& instances = ensureSVGRareData()->elementInstances();
573 ASSERT(!instances.contains(instance));
575 instances.add(instance);
578 void SVGElement::removeInstanceMapping(SVGElementInstance* instance)
581 ASSERT(hasSVGRareData());
583 HashSet<SVGElementInstance*>& instances = svgRareData()->elementInstances();
584 ASSERT(instances.contains(instance));
586 instances.remove(instance);
589 const HashSet<SVGElementInstance*>& SVGElement::instancesForElement() const
591 if (!hasSVGRareData()) {
592 DEFINE_STATIC_LOCAL(HashSet<SVGElementInstance*>, emptyInstances, ());
593 return emptyInstances;
595 return svgRareData()->elementInstances();
598 bool SVGElement::getBoundingBox(FloatRect& rect)
600 if (!isSVGGraphicsElement())
603 rect = toSVGGraphicsElement(this)->getBBox();
607 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
609 SVGElementRareData* rareData = ensureSVGRareData();
610 if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) {
611 if (cursorElement == oldCursorElement)
613 oldCursorElement->removeReferencedElement(this);
615 rareData->setCursorElement(cursorElement);
618 void SVGElement::cursorElementRemoved()
620 ASSERT(hasSVGRareData());
621 svgRareData()->setCursorElement(0);
624 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
626 SVGElementRareData* rareData = ensureSVGRareData();
627 if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) {
628 if (cursorImageValue == oldCursorImageValue)
630 oldCursorImageValue->removeReferencedElement(this);
632 rareData->setCursorImageValue(cursorImageValue);
635 void SVGElement::cursorImageValueRemoved()
637 ASSERT(hasSVGRareData());
638 svgRareData()->setCursorImageValue(0);
641 SVGElement* SVGElement::correspondingElement()
643 ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || containingShadowRoot());
644 return hasSVGRareData() ? svgRareData()->correspondingElement() : 0;
647 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
649 ensureSVGRareData()->setCorrespondingElement(correspondingElement);
652 void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
655 if (name == onloadAttr)
656 setAttributeEventListener(EventTypeNames::load, createAttributeEventListener(this, name, value));
657 else if (name == onclickAttr)
658 setAttributeEventListener(EventTypeNames::click, createAttributeEventListener(this, name, value));
659 else if (name == onmousedownAttr)
660 setAttributeEventListener(EventTypeNames::mousedown, createAttributeEventListener(this, name, value));
661 else if (name == onmouseenterAttr)
662 setAttributeEventListener(EventTypeNames::mouseenter, createAttributeEventListener(this, name, value));
663 else if (name == onmouseleaveAttr)
664 setAttributeEventListener(EventTypeNames::mouseleave, createAttributeEventListener(this, name, value));
665 else if (name == onmousemoveAttr)
666 setAttributeEventListener(EventTypeNames::mousemove, createAttributeEventListener(this, name, value));
667 else if (name == onmouseoutAttr)
668 setAttributeEventListener(EventTypeNames::mouseout, createAttributeEventListener(this, name, value));
669 else if (name == onmouseoverAttr)
670 setAttributeEventListener(EventTypeNames::mouseover, createAttributeEventListener(this, name, value));
671 else if (name == onmouseupAttr)
672 setAttributeEventListener(EventTypeNames::mouseup, createAttributeEventListener(this, name, value));
673 else if (name == SVGNames::onfocusinAttr)
674 setAttributeEventListener(EventTypeNames::focusin, createAttributeEventListener(this, name, value));
675 else if (name == SVGNames::onfocusoutAttr)
676 setAttributeEventListener(EventTypeNames::focusout, createAttributeEventListener(this, name, value));
677 else if (name == SVGNames::onactivateAttr)
678 setAttributeEventListener(EventTypeNames::DOMActivate, createAttributeEventListener(this, name, value));
679 else if (name == HTMLNames::classAttr) {
680 // SVG animation has currently requires special storage of values so we set
681 // the className here. svgAttributeChanged actually causes the resulting
682 // style updates (instead of Element::parseAttribute). We don't
683 // tell Element about the change to avoid parsing the class list twice
684 setClassNameBaseValue(value);
685 } else if (name == ontouchstartAttr) {
686 setAttributeEventListener(EventTypeNames::touchstart, createAttributeEventListener(this, name, value));
687 } else if (name == ontouchmoveAttr) {
688 setAttributeEventListener(EventTypeNames::touchmove, createAttributeEventListener(this, name, value));
689 } else if (name == ontouchendAttr) {
690 setAttributeEventListener(EventTypeNames::touchend, createAttributeEventListener(this, name, value));
691 } else if (name == ontouchcancelAttr) {
692 setAttributeEventListener(EventTypeNames::touchcancel, createAttributeEventListener(this, name, value));
693 } else if (name.matches(XMLNames::langAttr) || name.matches(XMLNames::spaceAttr)) {
695 Element::parseAttribute(name, value);
699 typedef HashMap<QualifiedName, AnimatedPropertyType> AttributeToPropertyTypeMap;
700 static inline AttributeToPropertyTypeMap& cssPropertyToTypeMap()
702 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_cssPropertyMap, ());
704 if (!s_cssPropertyMap.isEmpty())
705 return s_cssPropertyMap;
707 // Fill the map for the first use.
708 s_cssPropertyMap.set(alignment_baselineAttr, AnimatedString);
709 s_cssPropertyMap.set(baseline_shiftAttr, AnimatedString);
710 s_cssPropertyMap.set(buffered_renderingAttr, AnimatedString);
711 s_cssPropertyMap.set(clipAttr, AnimatedRect);
712 s_cssPropertyMap.set(clip_pathAttr, AnimatedString);
713 s_cssPropertyMap.set(clip_ruleAttr, AnimatedString);
714 s_cssPropertyMap.set(SVGNames::colorAttr, AnimatedColor);
715 s_cssPropertyMap.set(color_interpolationAttr, AnimatedString);
716 s_cssPropertyMap.set(color_interpolation_filtersAttr, AnimatedString);
717 s_cssPropertyMap.set(color_profileAttr, AnimatedString);
718 s_cssPropertyMap.set(color_renderingAttr, AnimatedString);
719 s_cssPropertyMap.set(cursorAttr, AnimatedString);
720 s_cssPropertyMap.set(displayAttr, AnimatedString);
721 s_cssPropertyMap.set(dominant_baselineAttr, AnimatedString);
722 s_cssPropertyMap.set(fillAttr, AnimatedColor);
723 s_cssPropertyMap.set(fill_opacityAttr, AnimatedNumber);
724 s_cssPropertyMap.set(fill_ruleAttr, AnimatedString);
725 s_cssPropertyMap.set(filterAttr, AnimatedString);
726 s_cssPropertyMap.set(flood_colorAttr, AnimatedColor);
727 s_cssPropertyMap.set(flood_opacityAttr, AnimatedNumber);
728 s_cssPropertyMap.set(font_familyAttr, AnimatedString);
729 s_cssPropertyMap.set(font_sizeAttr, AnimatedLength);
730 s_cssPropertyMap.set(font_stretchAttr, AnimatedString);
731 s_cssPropertyMap.set(font_styleAttr, AnimatedString);
732 s_cssPropertyMap.set(font_variantAttr, AnimatedString);
733 s_cssPropertyMap.set(font_weightAttr, AnimatedString);
734 s_cssPropertyMap.set(image_renderingAttr, AnimatedString);
735 s_cssPropertyMap.set(kerningAttr, AnimatedLength);
736 s_cssPropertyMap.set(letter_spacingAttr, AnimatedLength);
737 s_cssPropertyMap.set(lighting_colorAttr, AnimatedColor);
738 s_cssPropertyMap.set(marker_endAttr, AnimatedString);
739 s_cssPropertyMap.set(marker_midAttr, AnimatedString);
740 s_cssPropertyMap.set(marker_startAttr, AnimatedString);
741 s_cssPropertyMap.set(maskAttr, AnimatedString);
742 s_cssPropertyMap.set(mask_typeAttr, AnimatedString);
743 s_cssPropertyMap.set(opacityAttr, AnimatedNumber);
744 s_cssPropertyMap.set(overflowAttr, AnimatedString);
745 s_cssPropertyMap.set(paint_orderAttr, AnimatedString);
746 s_cssPropertyMap.set(pointer_eventsAttr, AnimatedString);
747 s_cssPropertyMap.set(shape_renderingAttr, AnimatedString);
748 s_cssPropertyMap.set(stop_colorAttr, AnimatedColor);
749 s_cssPropertyMap.set(stop_opacityAttr, AnimatedNumber);
750 s_cssPropertyMap.set(strokeAttr, AnimatedColor);
751 s_cssPropertyMap.set(stroke_dasharrayAttr, AnimatedLengthList);
752 s_cssPropertyMap.set(stroke_dashoffsetAttr, AnimatedLength);
753 s_cssPropertyMap.set(stroke_linecapAttr, AnimatedString);
754 s_cssPropertyMap.set(stroke_linejoinAttr, AnimatedString);
755 s_cssPropertyMap.set(stroke_miterlimitAttr, AnimatedNumber);
756 s_cssPropertyMap.set(stroke_opacityAttr, AnimatedNumber);
757 s_cssPropertyMap.set(stroke_widthAttr, AnimatedLength);
758 s_cssPropertyMap.set(text_anchorAttr, AnimatedString);
759 s_cssPropertyMap.set(text_decorationAttr, AnimatedString);
760 s_cssPropertyMap.set(text_renderingAttr, AnimatedString);
761 s_cssPropertyMap.set(vector_effectAttr, AnimatedString);
762 s_cssPropertyMap.set(visibilityAttr, AnimatedString);
763 s_cssPropertyMap.set(word_spacingAttr, AnimatedLength);
764 return s_cssPropertyMap;
767 void SVGElement::animatedPropertyTypeForAttribute(const QualifiedName& attributeName, Vector<AnimatedPropertyType>& propertyTypes)
769 localAttributeToPropertyMap().animatedPropertyTypeForAttribute(attributeName, propertyTypes);
770 if (!propertyTypes.isEmpty())
773 RefPtr<NewSVGAnimatedPropertyBase> animatedProperty = m_newAttributeToPropertyMap.get(attributeName);
774 if (animatedProperty)
775 propertyTypes.append(animatedProperty->type());
777 AttributeToPropertyTypeMap& cssPropertyTypeMap = cssPropertyToTypeMap();
778 if (cssPropertyTypeMap.contains(attributeName))
779 propertyTypes.append(cssPropertyTypeMap.get(attributeName));
782 void SVGElement::addToPropertyMap(PassRefPtr<NewSVGAnimatedPropertyBase> passProperty)
784 RefPtr<NewSVGAnimatedPropertyBase> property(passProperty);
785 QualifiedName attributeName = property->attributeName();
786 m_newAttributeToPropertyMap.set(attributeName, property.release());
789 PassRefPtr<NewSVGAnimatedPropertyBase> SVGElement::propertyFromAttribute(const QualifiedName& attributeName)
791 return m_newAttributeToPropertyMap.get(attributeName);
794 bool SVGElement::isAnimatableCSSProperty(const QualifiedName& attrName)
796 return cssPropertyToTypeMap().contains(attrName);
799 bool SVGElement::isPresentationAttribute(const QualifiedName& name) const
801 return cssPropertyIdForSVGAttributeName(name) > 0;
804 void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
806 CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(name);
808 addPropertyToPresentationAttributeStyle(style, propertyID, value);
811 bool SVGElement::haveLoadedRequiredResources()
813 Node* child = firstChild();
815 if (child->isSVGElement() && !toSVGElement(child)->haveLoadedRequiredResources())
817 child = child->nextSibling();
822 static inline void collectInstancesForSVGElement(SVGElement* element, HashSet<SVGElementInstance*>& instances)
825 if (element->containingShadowRoot())
828 ASSERT(!element->instanceUpdatesBlocked());
830 instances = element->instancesForElement();
833 bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
835 RefPtr<EventListener> listener = prpListener;
837 // Add event listener to regular DOM element
838 if (!Node::addEventListener(eventType, listener, useCapture))
841 // Add event listener to all shadow tree DOM element instances
842 HashSet<SVGElementInstance*> instances;
843 collectInstancesForSVGElement(this, instances);
844 const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
845 for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
846 ASSERT((*it)->shadowTreeElement());
847 ASSERT((*it)->correspondingElement() == this);
849 bool result = (*it)->shadowTreeElement()->Node::addEventListener(eventType, listener, useCapture);
850 ASSERT_UNUSED(result, result);
856 bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
858 HashSet<SVGElementInstance*> instances;
859 collectInstancesForSVGElement(this, instances);
860 if (instances.isEmpty())
861 return Node::removeEventListener(eventType, listener, useCapture);
863 // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener
864 // object when creating a temporary RegisteredEventListener object used to look up the
865 // event listener in a cache. If we want to be able to call removeEventListener() multiple
866 // times on different nodes, we have to delay its immediate destruction, which would happen
867 // after the first call below.
868 RefPtr<EventListener> protector(listener);
870 // Remove event listener from regular DOM element
871 if (!Node::removeEventListener(eventType, listener, useCapture))
874 // Remove event listener from all shadow tree DOM element instances
875 const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
876 for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
877 ASSERT((*it)->correspondingElement() == this);
879 SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
880 ASSERT(shadowTreeElement);
882 if (shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture))
885 // This case can only be hit for event listeners created from markup
886 ASSERT(listener->wasCreatedFromMarkup());
888 // If the event listener 'listener' has been created from markup and has been fired before
889 // then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener
890 // has been created (read: it's not 0 anymore). During shadow tree creation, the event
891 // listener DOM attribute has been cloned, and another event listener has been setup in
892 // the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0,
893 // and tryRemoveEventListener() above will fail. Work around that very seldom problem.
894 EventTargetData* data = shadowTreeElement->eventTargetData();
897 data->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
903 static bool hasLoadListener(Element* element)
905 if (element->hasEventListeners(EventTypeNames::load))
908 for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) {
909 const EventListenerVector& entry = element->getEventListeners(EventTypeNames::load);
910 for (size_t i = 0; i < entry.size(); ++i) {
911 if (entry[i].useCapture)
919 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
921 RefPtr<SVGElement> currentTarget = this;
922 while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
923 RefPtr<Element> parent;
924 if (sendParentLoadEvents)
925 parent = currentTarget->parentOrShadowHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree
926 if (hasLoadListener(currentTarget.get())
927 && (currentTarget->isStructurallyExternal() || currentTarget->isSVGSVGElement()))
928 currentTarget->dispatchEvent(Event::create(EventTypeNames::load));
929 currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>();
930 SVGElement* element = currentTarget.get();
931 if (!element || !element->isOutermostSVGSVGElement())
934 // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>.
935 // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through
936 // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded.
937 ASSERT(sendParentLoadEvents);
939 // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example
940 // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document
941 // to be "ready to render", first.
942 if (!document().loadEventFinished())
947 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
949 svgLoadEventTimer()->startOneShot(0);
952 void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*)
954 sendSVGLoadEventIfPossible();
957 Timer<SVGElement>* SVGElement::svgLoadEventTimer()
959 ASSERT_NOT_REACHED();
963 void SVGElement::finishParsingChildren()
965 Element::finishParsingChildren();
967 // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent.
968 if (isOutermostSVGSVGElement())
971 // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
972 // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
973 if (isSVGSVGElement())
974 sendSVGLoadEventIfPossible();
977 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason)
979 Element::attributeChanged(name, newValue);
981 if (isIdAttributeName(name))
982 document().accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
984 // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
985 // so we don't want changes to the style attribute to result in extra work here.
986 if (name != HTMLNames::styleAttr)
987 svgAttributeChanged(name);
990 void SVGElement::svgAttributeChanged(const QualifiedName& attrName)
992 CSSPropertyID propId = SVGElement::cssPropertyIdForSVGAttributeName(attrName);
994 SVGElementInstance::invalidateAllInstancesOfElement(this);
998 if (attrName == HTMLNames::classAttr) {
999 classAttributeChanged(AtomicString(classNameCurrentValue()));
1000 SVGElementInstance::invalidateAllInstancesOfElement(this);
1004 if (isIdAttributeName(attrName)) {
1005 RenderObject* object = renderer();
1006 // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
1007 if (object && object->isSVGResourceContainer())
1008 toRenderSVGResourceContainer(object)->idChanged();
1010 buildPendingResourcesIfNeeded();
1011 SVGElementInstance::invalidateAllInstancesOfElement(this);
1016 void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const
1018 if (!elementData() || !elementData()->m_animatedSVGAttributesAreDirty)
1021 SVGElement* nonConstThis = const_cast<SVGElement*>(this);
1022 if (name == anyQName()) {
1023 nonConstThis->localAttributeToPropertyMap().synchronizeProperties(nonConstThis);
1025 AttributeToPropertyMap::const_iterator::Values it = m_newAttributeToPropertyMap.values().begin();
1026 AttributeToPropertyMap::const_iterator::Values end = m_newAttributeToPropertyMap.values().end();
1027 for (; it != end; ++it) {
1028 if ((*it)->needsSynchronizeAttribute())
1029 (*it)->synchronizeAttribute();
1032 elementData()->m_animatedSVGAttributesAreDirty = false;
1034 nonConstThis->localAttributeToPropertyMap().synchronizeProperty(nonConstThis, name);
1036 RefPtr<NewSVGAnimatedPropertyBase> property = m_newAttributeToPropertyMap.get(name);
1037 if (property && property->needsSynchronizeAttribute())
1038 property->synchronizeAttribute();
1042 void SVGElement::synchronizeRequiredFeatures(SVGElement* contextElement)
1044 ASSERT(contextElement);
1045 contextElement->synchronizeRequiredFeatures();
1048 void SVGElement::synchronizeRequiredExtensions(SVGElement* contextElement)
1050 ASSERT(contextElement);
1051 contextElement->synchronizeRequiredExtensions();
1054 void SVGElement::synchronizeSystemLanguage(SVGElement* contextElement)
1056 ASSERT(contextElement);
1057 contextElement->synchronizeSystemLanguage();
1060 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
1062 if (!correspondingElement())
1063 return document().ensureStyleResolver().styleForElement(this);
1065 RenderStyle* style = 0;
1066 if (Element* parent = parentOrShadowHostElement()) {
1067 if (RenderObject* renderer = parent->renderer())
1068 style = renderer->style();
1071 return document().ensureStyleResolver().styleForElement(correspondingElement(), style, DisallowStyleSharing);
1074 MutableStylePropertySet* SVGElement::animatedSMILStyleProperties() const
1076 if (hasSVGRareData())
1077 return svgRareData()->animatedSMILStyleProperties();
1081 MutableStylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties()
1083 return ensureSVGRareData()->ensureAnimatedSMILStyleProperties();
1086 void SVGElement::setUseOverrideComputedStyle(bool value)
1088 if (hasSVGRareData())
1089 svgRareData()->setUseOverrideComputedStyle(value);
1092 RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
1094 if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle())
1095 return Element::computedStyle(pseudoElementSpecifier);
1097 RenderStyle* parentStyle = 0;
1098 if (Element* parent = parentOrShadowHostElement()) {
1099 if (RenderObject* renderer = parent->renderer())
1100 parentStyle = renderer->style();
1103 return svgRareData()->overrideComputedStyle(this, parentStyle);
1106 bool SVGElement::hasFocusEventListeners() const
1108 return hasEventListeners(EventTypeNames::focusin) || hasEventListeners(EventTypeNames::focusout);
1111 bool SVGElement::isKeyboardFocusable() const
1113 return isFocusable();
1117 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
1119 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ());
1121 if (animatableAttributes.isEmpty()) {
1122 animatableAttributes.add(XLinkNames::hrefAttr);
1123 animatableAttributes.add(SVGNames::amplitudeAttr);
1124 animatableAttributes.add(SVGNames::azimuthAttr);
1125 animatableAttributes.add(SVGNames::baseFrequencyAttr);
1126 animatableAttributes.add(SVGNames::biasAttr);
1127 animatableAttributes.add(SVGNames::clipPathUnitsAttr);
1128 animatableAttributes.add(SVGNames::cxAttr);
1129 animatableAttributes.add(SVGNames::cyAttr);
1130 animatableAttributes.add(SVGNames::diffuseConstantAttr);
1131 animatableAttributes.add(SVGNames::divisorAttr);
1132 animatableAttributes.add(SVGNames::dxAttr);
1133 animatableAttributes.add(SVGNames::dyAttr);
1134 animatableAttributes.add(SVGNames::edgeModeAttr);
1135 animatableAttributes.add(SVGNames::elevationAttr);
1136 animatableAttributes.add(SVGNames::exponentAttr);
1137 animatableAttributes.add(SVGNames::filterResAttr);
1138 animatableAttributes.add(SVGNames::filterUnitsAttr);
1139 animatableAttributes.add(SVGNames::fxAttr);
1140 animatableAttributes.add(SVGNames::fyAttr);
1141 animatableAttributes.add(SVGNames::gradientTransformAttr);
1142 animatableAttributes.add(SVGNames::gradientUnitsAttr);
1143 animatableAttributes.add(SVGNames::heightAttr);
1144 animatableAttributes.add(SVGNames::in2Attr);
1145 animatableAttributes.add(SVGNames::inAttr);
1146 animatableAttributes.add(SVGNames::interceptAttr);
1147 animatableAttributes.add(SVGNames::k1Attr);
1148 animatableAttributes.add(SVGNames::k2Attr);
1149 animatableAttributes.add(SVGNames::k3Attr);
1150 animatableAttributes.add(SVGNames::k4Attr);
1151 animatableAttributes.add(SVGNames::kernelMatrixAttr);
1152 animatableAttributes.add(SVGNames::kernelUnitLengthAttr);
1153 animatableAttributes.add(SVGNames::lengthAdjustAttr);
1154 animatableAttributes.add(SVGNames::limitingConeAngleAttr);
1155 animatableAttributes.add(SVGNames::markerHeightAttr);
1156 animatableAttributes.add(SVGNames::markerUnitsAttr);
1157 animatableAttributes.add(SVGNames::markerWidthAttr);
1158 animatableAttributes.add(SVGNames::maskContentUnitsAttr);
1159 animatableAttributes.add(SVGNames::maskUnitsAttr);
1160 animatableAttributes.add(SVGNames::methodAttr);
1161 animatableAttributes.add(SVGNames::modeAttr);
1162 animatableAttributes.add(SVGNames::numOctavesAttr);
1163 animatableAttributes.add(SVGNames::offsetAttr);
1164 animatableAttributes.add(SVGNames::operatorAttr);
1165 animatableAttributes.add(SVGNames::orderAttr);
1166 animatableAttributes.add(SVGNames::orientAttr);
1167 animatableAttributes.add(SVGNames::pathLengthAttr);
1168 animatableAttributes.add(SVGNames::patternContentUnitsAttr);
1169 animatableAttributes.add(SVGNames::patternTransformAttr);
1170 animatableAttributes.add(SVGNames::patternUnitsAttr);
1171 animatableAttributes.add(SVGNames::pointsAtXAttr);
1172 animatableAttributes.add(SVGNames::pointsAtYAttr);
1173 animatableAttributes.add(SVGNames::pointsAtZAttr);
1174 animatableAttributes.add(SVGNames::preserveAlphaAttr);
1175 animatableAttributes.add(SVGNames::preserveAspectRatioAttr);
1176 animatableAttributes.add(SVGNames::primitiveUnitsAttr);
1177 animatableAttributes.add(SVGNames::radiusAttr);
1178 animatableAttributes.add(SVGNames::rAttr);
1179 animatableAttributes.add(SVGNames::refXAttr);
1180 animatableAttributes.add(SVGNames::refYAttr);
1181 animatableAttributes.add(SVGNames::resultAttr);
1182 animatableAttributes.add(SVGNames::rotateAttr);
1183 animatableAttributes.add(SVGNames::rxAttr);
1184 animatableAttributes.add(SVGNames::ryAttr);
1185 animatableAttributes.add(SVGNames::scaleAttr);
1186 animatableAttributes.add(SVGNames::seedAttr);
1187 animatableAttributes.add(SVGNames::slopeAttr);
1188 animatableAttributes.add(SVGNames::spacingAttr);
1189 animatableAttributes.add(SVGNames::specularConstantAttr);
1190 animatableAttributes.add(SVGNames::specularExponentAttr);
1191 animatableAttributes.add(SVGNames::spreadMethodAttr);
1192 animatableAttributes.add(SVGNames::startOffsetAttr);
1193 animatableAttributes.add(SVGNames::stdDeviationAttr);
1194 animatableAttributes.add(SVGNames::stitchTilesAttr);
1195 animatableAttributes.add(SVGNames::surfaceScaleAttr);
1196 animatableAttributes.add(SVGNames::tableValuesAttr);
1197 animatableAttributes.add(SVGNames::targetAttr);
1198 animatableAttributes.add(SVGNames::targetXAttr);
1199 animatableAttributes.add(SVGNames::targetYAttr);
1200 animatableAttributes.add(SVGNames::transformAttr);
1201 animatableAttributes.add(SVGNames::typeAttr);
1202 animatableAttributes.add(SVGNames::valuesAttr);
1203 animatableAttributes.add(SVGNames::viewBoxAttr);
1204 animatableAttributes.add(SVGNames::widthAttr);
1205 animatableAttributes.add(SVGNames::x1Attr);
1206 animatableAttributes.add(SVGNames::x2Attr);
1207 animatableAttributes.add(SVGNames::xAttr);
1208 animatableAttributes.add(SVGNames::xChannelSelectorAttr);
1209 animatableAttributes.add(SVGNames::y1Attr);
1210 animatableAttributes.add(SVGNames::y2Attr);
1211 animatableAttributes.add(SVGNames::yAttr);
1212 animatableAttributes.add(SVGNames::yChannelSelectorAttr);
1213 animatableAttributes.add(SVGNames::zAttr);
1216 if (name == classAttr)
1219 return animatableAttributes.contains(name);