Merge SVGLangSpace into SVGElement
[WebKit-https.git] / Source / WebCore / svg / SVGElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006, 2008 Rob Buis <buis@kde.org>
4  * Copyright (C) 2008 Apple Inc. All rights reserved.
5  * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6  * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #include "config.h"
25
26 #if ENABLE(SVG)
27 #include "SVGElement.h"
28
29 #include "CSSCursorImageValue.h"
30 #include "DOMImplementation.h"
31 #include "Document.h"
32 #include "Event.h"
33 #include "HTMLNames.h"
34 #include "NodeRenderingContext.h"
35 #include "RenderObject.h"
36 #include "SVGCursorElement.h"
37 #include "SVGDocumentExtensions.h"
38 #include "SVGElementInstance.h"
39 #include "SVGElementRareData.h"
40 #include "SVGNames.h"
41 #include "SVGSVGElement.h"
42 #include "SVGStyledLocatableElement.h"
43 #include "SVGTextElement.h"
44 #include "ScriptEventListener.h"
45 #include "XMLNames.h"
46
47 namespace WebCore {
48
49 using namespace HTMLNames;
50
51 SVGElement::SVGElement(const QualifiedName& tagName, Document* document, ConstructionType constructionType)
52     : StyledElement(tagName, document, constructionType)
53 {
54     setHasCustomStyleCallbacks();
55 }
56
57 PassRefPtr<SVGElement> SVGElement::create(const QualifiedName& tagName, Document* document)
58 {
59     return adoptRef(new SVGElement(tagName, document));
60 }
61
62 SVGElement::~SVGElement()
63 {
64     if (!hasSVGRareData())
65         ASSERT(!SVGElementRareData::rareDataMap().contains(this));
66     else {
67         ASSERT(document());
68         SVGElementRareData::SVGElementRareDataMap& rareDataMap = SVGElementRareData::rareDataMap();
69         SVGElementRareData::SVGElementRareDataMap::iterator it = rareDataMap.find(this);
70         ASSERT(it != rareDataMap.end());
71
72         SVGElementRareData* rareData = it->value;
73         rareData->destroyAnimatedSMILStyleProperties();
74         if (SVGCursorElement* cursorElement = rareData->cursorElement())
75             cursorElement->removeClient(this);
76         if (CSSCursorImageValue* cursorImageValue = rareData->cursorImageValue())
77             cursorImageValue->removeReferencedElement(this);
78
79         delete rareData;
80
81         it = rareDataMap.find(this);
82         ASSERT(it != rareDataMap.end());
83         rareDataMap.remove(it);
84     }
85     ASSERT(document());
86     document()->accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
87     document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this);
88 }
89
90 bool SVGElement::willRecalcStyle(StyleChange change)
91 {
92     if (!hasSVGRareData() || styleChangeType() == SyntheticStyleChange)
93         return true;
94     // If the style changes because of a regular property change (not induced by SMIL animations themselves)
95     // reset the "computed style without SMIL style properties", so the base value change gets reflected.
96     if (change > NoChange || needsStyleRecalc())
97         svgRareData()->setNeedsOverrideComputedStyleUpdate();
98     return true;
99 }
100
101 SVGElementRareData* SVGElement::svgRareData() const
102 {
103     ASSERT(hasSVGRareData());
104     return SVGElementRareData::rareDataFromMap(this);
105 }
106
107 SVGElementRareData* SVGElement::ensureSVGRareData()
108 {
109     if (hasSVGRareData())
110         return svgRareData();
111
112     ASSERT(!SVGElementRareData::rareDataMap().contains(this));
113     SVGElementRareData* data = new SVGElementRareData;
114     SVGElementRareData::rareDataMap().set(this, data);
115     setHasSVGRareData();
116     return data;
117 }
118
119 bool SVGElement::isOutermostSVGSVGElement() const
120 {
121     if (!hasTagName(SVGNames::svgTag))
122         return false;
123
124     // If we're living in a shadow tree, we're a <svg> element that got created as replacement
125     // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case
126     // we're always an inner <svg> element.
127     if (isInShadowTree() && parentOrShadowHostElement() && parentOrShadowHostElement()->isSVGElement())
128         return false;
129
130     // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
131     if (!parentNode())
132         return true;
133
134     // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
135     if (parentNode()->hasTagName(SVGNames::foreignObjectTag))
136         return true;
137
138     // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
139     return !parentNode()->isSVGElement();
140 }
141
142 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value)
143 {
144     if (error == NoError)
145         return;
146
147     String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
148     SVGDocumentExtensions* extensions = document()->accessSVGExtensions();
149
150     if (error == NegativeValueForbiddenError) {
151         extensions->reportError("Invalid negative value for " + errorString);
152         return;
153     }
154
155     if (error == ParsingAttributeFailedError) {
156         extensions->reportError("Invalid value for " + errorString);
157         return;
158     }
159
160     ASSERT_NOT_REACHED();
161 }
162
163
164 bool SVGElement::isSupported(StringImpl* feature, StringImpl* version) const
165 {
166     return DOMImplementation::hasFeature(feature, version);
167 }
168
169 String SVGElement::xmlbase() const
170 {
171     return fastGetAttribute(XMLNames::baseAttr);
172 }
173
174 void SVGElement::setXmlbase(const String& value, ExceptionCode&)
175 {
176     setAttribute(XMLNames::baseAttr, value);
177 }
178
179 void SVGElement::removedFrom(ContainerNode* rootParent)
180 {
181     bool wasInDocument = rootParent->inDocument();
182
183     StyledElement::removedFrom(rootParent);
184
185     if (wasInDocument) {
186         document()->accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
187         document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this);
188     }
189 }
190
191 SVGSVGElement* SVGElement::ownerSVGElement() const
192 {
193     ContainerNode* n = parentOrShadowHostNode();
194     while (n) {
195         if (n->hasTagName(SVGNames::svgTag))
196             return toSVGSVGElement(n);
197
198         n = n->parentOrShadowHostNode();
199     }
200
201     return 0;
202 }
203
204 SVGElement* SVGElement::viewportElement() const
205 {
206     // This function needs shadow tree support - as RenderSVGContainer uses this function
207     // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
208     ContainerNode* n = parentOrShadowHostNode();
209     while (n) {
210         if (n->hasTagName(SVGNames::svgTag) || n->hasTagName(SVGNames::imageTag) || n->hasTagName(SVGNames::symbolTag))
211             return toSVGElement(n);
212
213         n = n->parentOrShadowHostNode();
214     }
215
216     return 0;
217 }
218
219 SVGDocumentExtensions* SVGElement::accessDocumentSVGExtensions()
220 {
221     // This function is provided for use by SVGAnimatedProperty to avoid
222     // global inclusion of Document.h in SVG code.
223     return document() ? document()->accessSVGExtensions() : 0;
224 }
225  
226 void SVGElement::mapInstanceToElement(SVGElementInstance* instance)
227 {
228     ASSERT(instance);
229
230     HashSet<SVGElementInstance*>& instances = ensureSVGRareData()->elementInstances();
231     ASSERT(!instances.contains(instance));
232
233     instances.add(instance);
234 }
235  
236 void SVGElement::removeInstanceMapping(SVGElementInstance* instance)
237 {
238     ASSERT(instance);
239     ASSERT(hasSVGRareData());
240
241     HashSet<SVGElementInstance*>& instances = svgRareData()->elementInstances();
242     ASSERT(instances.contains(instance));
243
244     instances.remove(instance);
245 }
246
247 const HashSet<SVGElementInstance*>& SVGElement::instancesForElement() const
248 {
249     if (!hasSVGRareData()) {
250         DEFINE_STATIC_LOCAL(HashSet<SVGElementInstance*>, emptyInstances, ());
251         return emptyInstances;
252     }
253     return svgRareData()->elementInstances();
254 }
255
256 bool SVGElement::getBoundingBox(FloatRect& rect, SVGLocatable::StyleUpdateStrategy styleUpdateStrategy)
257 {
258     if (isStyledLocatable()) {
259         rect = toSVGStyledLocatableElement(this)->getBBox(styleUpdateStrategy);
260         return true;
261     }
262     if (hasTagName(SVGNames::textTag)) {
263         rect = static_cast<SVGTextElement*>(this)->getBBox(styleUpdateStrategy);
264         return true;
265     }
266     return false;
267 }
268
269 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
270 {
271     SVGElementRareData* rareData = ensureSVGRareData();
272     if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) {
273         if (cursorElement == oldCursorElement)
274             return;
275         oldCursorElement->removeReferencedElement(this);
276     }
277     rareData->setCursorElement(cursorElement);
278 }
279
280 void SVGElement::cursorElementRemoved() 
281 {
282     ASSERT(hasSVGRareData());
283     svgRareData()->setCursorElement(0);
284 }
285
286 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
287 {
288     SVGElementRareData* rareData = ensureSVGRareData();
289     if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) {
290         if (cursorImageValue == oldCursorImageValue)
291             return;
292         oldCursorImageValue->removeReferencedElement(this);
293     }
294     rareData->setCursorImageValue(cursorImageValue);
295 }
296
297 void SVGElement::cursorImageValueRemoved()
298 {
299     ASSERT(hasSVGRareData());
300     svgRareData()->setCursorImageValue(0);
301 }
302
303 SVGElement* SVGElement::correspondingElement()
304 {
305     ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || containingShadowRoot());
306     return hasSVGRareData() ? svgRareData()->correspondingElement() : 0;
307 }
308
309 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
310 {
311     ensureSVGRareData()->setCorrespondingElement(correspondingElement);
312 }
313
314 void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
315 {
316     // standard events
317     if (name == onloadAttr)
318         setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, name, value));
319     else if (name == onclickAttr)
320         setAttributeEventListener(eventNames().clickEvent, createAttributeEventListener(this, name, value));
321     else if (name == onmousedownAttr)
322         setAttributeEventListener(eventNames().mousedownEvent, createAttributeEventListener(this, name, value));
323     else if (name == onmouseenterAttr)
324         setAttributeEventListener(eventNames().mouseenterEvent, createAttributeEventListener(this, name, value));
325     else if (name == onmouseleaveAttr)
326         setAttributeEventListener(eventNames().mouseleaveEvent, createAttributeEventListener(this, name, value));
327     else if (name == onmousemoveAttr)
328         setAttributeEventListener(eventNames().mousemoveEvent, createAttributeEventListener(this, name, value));
329     else if (name == onmouseoutAttr)
330         setAttributeEventListener(eventNames().mouseoutEvent, createAttributeEventListener(this, name, value));
331     else if (name == onmouseoverAttr)
332         setAttributeEventListener(eventNames().mouseoverEvent, createAttributeEventListener(this, name, value));
333     else if (name == onmouseupAttr)
334         setAttributeEventListener(eventNames().mouseupEvent, createAttributeEventListener(this, name, value));
335     else if (name == SVGNames::onfocusinAttr)
336         setAttributeEventListener(eventNames().focusinEvent, createAttributeEventListener(this, name, value));
337     else if (name == SVGNames::onfocusoutAttr)
338         setAttributeEventListener(eventNames().focusoutEvent, createAttributeEventListener(this, name, value));
339     else if (name == SVGNames::onactivateAttr)
340         setAttributeEventListener(eventNames().DOMActivateEvent, createAttributeEventListener(this, name, value));
341     else if (SVGLangSpace::parseAttribute(name, value)) {
342     } else
343         StyledElement::parseAttribute(name, value);
344 }
345
346 void SVGElement::animatedPropertyTypeForAttribute(const QualifiedName& attributeName, Vector<AnimatedPropertyType>& propertyTypes)
347 {
348     localAttributeToPropertyMap().animatedPropertyTypeForAttribute(attributeName, propertyTypes);
349 }
350
351 bool SVGElement::haveLoadedRequiredResources()
352 {
353     Node* child = firstChild();
354     while (child) {
355         if (child->isSVGElement() && !toSVGElement(child)->haveLoadedRequiredResources())
356             return false;
357         child = child->nextSibling();
358     }
359     return true;
360 }
361
362 static inline void collectInstancesForSVGElement(SVGElement* element, HashSet<SVGElementInstance*>& instances)
363 {
364     ASSERT(element);
365     if (element->containingShadowRoot())
366         return;
367
368     if (!element->isSVGStyledElement())
369         return;
370
371     SVGStyledElement* styledElement = toSVGStyledElement(element);
372     ASSERT(!styledElement->instanceUpdatesBlocked());
373
374     instances = styledElement->instancesForElement();
375 }
376
377 bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
378 {
379     RefPtr<EventListener> listener = prpListener;
380     
381     // Add event listener to regular DOM element
382     if (!Node::addEventListener(eventType, listener, useCapture))
383         return false;
384
385     // Add event listener to all shadow tree DOM element instances
386     HashSet<SVGElementInstance*> instances;
387     collectInstancesForSVGElement(this, instances);    
388     const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
389     for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
390         ASSERT((*it)->shadowTreeElement());
391         ASSERT((*it)->correspondingElement() == this);
392
393         bool result = (*it)->shadowTreeElement()->Node::addEventListener(eventType, listener, useCapture);
394         ASSERT_UNUSED(result, result);
395     }
396
397     return true;
398 }
399
400 bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
401 {
402     HashSet<SVGElementInstance*> instances;
403     collectInstancesForSVGElement(this, instances);
404     if (instances.isEmpty())
405         return Node::removeEventListener(eventType, listener, useCapture);
406
407     // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener
408     // object when creating a temporary RegisteredEventListener object used to look up the
409     // event listener in a cache. If we want to be able to call removeEventListener() multiple
410     // times on different nodes, we have to delay its immediate destruction, which would happen
411     // after the first call below.
412     RefPtr<EventListener> protector(listener);
413
414     // Remove event listener from regular DOM element
415     if (!Node::removeEventListener(eventType, listener, useCapture))
416         return false;
417
418     // Remove event listener from all shadow tree DOM element instances
419     const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
420     for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
421         ASSERT((*it)->correspondingElement() == this);
422
423         SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
424         ASSERT(shadowTreeElement);
425
426         if (shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture))
427             continue;
428
429         // This case can only be hit for event listeners created from markup
430         ASSERT(listener->wasCreatedFromMarkup());
431
432         // If the event listener 'listener' has been created from markup and has been fired before
433         // then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener
434         // has been created (read: it's not 0 anymore). During shadow tree creation, the event
435         // listener DOM attribute has been cloned, and another event listener has been setup in
436         // the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0,
437         // and tryRemoveEventListener() above will fail. Work around that very seldom problem.
438         EventTargetData* data = shadowTreeElement->eventTargetData();
439         ASSERT(data);
440
441         data->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
442     }
443
444     return true;
445 }
446
447 static bool hasLoadListener(Element* element)
448 {
449     if (element->hasEventListeners(eventNames().loadEvent))
450         return true;
451
452     for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) {
453         const EventListenerVector& entry = element->getEventListeners(eventNames().loadEvent);
454         for (size_t i = 0; i < entry.size(); ++i) {
455             if (entry[i].useCapture)
456                 return true;
457         }
458     }
459
460     return false;
461 }
462
463 bool SVGElement::moveToFlowThreadIsNeeded(RefPtr<RenderStyle>& cachedStyle)
464 {
465     // Allow only svg root elements to be directly collected by a render flow thread.
466     return parentNode() && !parentNode()->isSVGElement() && hasTagName(SVGNames::svgTag) && Element::moveToFlowThreadIsNeeded(cachedStyle);
467 }
468
469 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
470 {
471     RefPtr<SVGElement> currentTarget = this;
472     while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
473         RefPtr<Element> parent;
474         if (sendParentLoadEvents)
475             parent = currentTarget->parentOrShadowHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree
476         if (hasLoadListener(currentTarget.get()))
477             currentTarget->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
478         currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>();
479         SVGElement* element = toSVGElement(currentTarget.get());
480         if (!element || !element->isOutermostSVGSVGElement())
481             continue;
482
483         // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>.
484         // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through
485         // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded.
486         ASSERT(sendParentLoadEvents);
487
488         // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example
489         // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document
490         // to be "ready to render", first.
491         if (!document()->loadEventFinished())
492             break;
493     }
494 }
495
496 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
497 {
498     svgLoadEventTimer()->startOneShot(0);
499 }
500
501 void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*)
502 {
503     sendSVGLoadEventIfPossible();
504 }
505
506 Timer<SVGElement>* SVGElement::svgLoadEventTimer()
507 {
508     ASSERT_NOT_REACHED();
509     return 0;
510 }
511
512 void SVGElement::finishParsingChildren()
513 {
514     StyledElement::finishParsingChildren();
515
516     // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent.
517     if (isOutermostSVGSVGElement())
518         return;
519
520     // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
521     // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
522     sendSVGLoadEventIfPossible();
523 }
524
525 bool SVGElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
526 {
527     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, invalidTextContent, ());
528
529     if (invalidTextContent.isEmpty()) {
530         invalidTextContent.add(SVGNames::textPathTag);
531 #if ENABLE(SVG_FONTS)
532         invalidTextContent.add(SVGNames::altGlyphTag);
533 #endif
534         invalidTextContent.add(SVGNames::trefTag);
535         invalidTextContent.add(SVGNames::tspanTag);
536     }
537     if (childContext.node()->isSVGElement()) {
538         SVGElement* svgChild = toSVGElement(childContext.node());
539         if (invalidTextContent.contains(svgChild->tagQName()))
540             return false;
541
542         return svgChild->isValid();
543     }
544     return false;
545 }
546
547 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason)
548 {
549     StyledElement::attributeChanged(name, newValue);
550
551     if (isIdAttributeName(name))
552         document()->accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
553
554     // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
555     // so we don't want changes to the style attribute to result in extra work here.
556     if (name != HTMLNames::styleAttr)
557         svgAttributeChanged(name);
558 }
559
560 void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const
561 {
562     if (!elementData() || !elementData()->m_animatedSVGAttributesAreDirty)
563         return;
564
565     SVGElement* nonConstThis = const_cast<SVGElement*>(this);
566     if (name == anyQName()) {
567         nonConstThis->localAttributeToPropertyMap().synchronizeProperties(nonConstThis);
568         elementData()->m_animatedSVGAttributesAreDirty = false;
569     } else
570         nonConstThis->localAttributeToPropertyMap().synchronizeProperty(nonConstThis, name);
571 }
572
573 SVGAttributeToPropertyMap& SVGElement::localAttributeToPropertyMap()
574 {
575     DEFINE_STATIC_LOCAL(SVGAttributeToPropertyMap, emptyMap, ());
576     return emptyMap;
577 }
578
579 void SVGElement::synchronizeRequiredFeatures(SVGElement* contextElement)
580 {
581     ASSERT(contextElement);
582     contextElement->synchronizeRequiredFeatures();
583 }
584
585 void SVGElement::synchronizeRequiredExtensions(SVGElement* contextElement)
586 {
587     ASSERT(contextElement);
588     contextElement->synchronizeRequiredExtensions();
589 }
590
591 void SVGElement::synchronizeSystemLanguage(SVGElement* contextElement)
592 {
593     ASSERT(contextElement);
594     contextElement->synchronizeSystemLanguage();
595 }
596
597 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
598 {
599     if (!correspondingElement())
600         return document()->ensureStyleResolver()->styleForElement(this);
601
602     RenderStyle* style = 0;
603     if (Element* parent = parentOrShadowHostElement()) {
604         if (RenderObject* renderer = parent->renderer())
605             style = renderer->style();
606     }
607
608     return document()->ensureStyleResolver()->styleForElement(correspondingElement(), style, DisallowStyleSharing);
609 }
610
611 MutableStylePropertySet* SVGElement::animatedSMILStyleProperties() const
612 {
613     if (hasSVGRareData())
614         return svgRareData()->animatedSMILStyleProperties();
615     return 0;
616 }
617
618 MutableStylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties()
619 {
620     return ensureSVGRareData()->ensureAnimatedSMILStyleProperties();
621 }
622
623 void SVGElement::setUseOverrideComputedStyle(bool value)
624 {
625     if (hasSVGRareData())
626         svgRareData()->setUseOverrideComputedStyle(value);
627 }
628
629 RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
630 {
631     if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle())
632         return Element::computedStyle(pseudoElementSpecifier);
633
634     RenderStyle* parentStyle = 0;
635     if (Element* parent = parentOrShadowHostElement()) {
636         if (RenderObject* renderer = parent->renderer())
637             parentStyle = renderer->style();
638     }
639
640     return svgRareData()->overrideComputedStyle(this, parentStyle);
641 }
642
643 #ifndef NDEBUG
644 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
645 {
646     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ());
647
648     if (animatableAttributes.isEmpty()) {
649         animatableAttributes.add(XLinkNames::hrefAttr);
650         animatableAttributes.add(SVGNames::amplitudeAttr);
651         animatableAttributes.add(SVGNames::azimuthAttr);
652         animatableAttributes.add(SVGNames::baseFrequencyAttr);
653         animatableAttributes.add(SVGNames::biasAttr);
654         animatableAttributes.add(SVGNames::clipPathUnitsAttr);
655         animatableAttributes.add(SVGNames::cxAttr);
656         animatableAttributes.add(SVGNames::cyAttr);
657         animatableAttributes.add(SVGNames::diffuseConstantAttr);
658         animatableAttributes.add(SVGNames::divisorAttr);
659         animatableAttributes.add(SVGNames::dxAttr);
660         animatableAttributes.add(SVGNames::dyAttr);
661         animatableAttributes.add(SVGNames::edgeModeAttr);
662         animatableAttributes.add(SVGNames::elevationAttr);
663         animatableAttributes.add(SVGNames::exponentAttr);
664         animatableAttributes.add(SVGNames::externalResourcesRequiredAttr);
665         animatableAttributes.add(SVGNames::filterResAttr);
666         animatableAttributes.add(SVGNames::filterUnitsAttr);
667         animatableAttributes.add(SVGNames::fxAttr);
668         animatableAttributes.add(SVGNames::fyAttr);
669         animatableAttributes.add(SVGNames::gradientTransformAttr);
670         animatableAttributes.add(SVGNames::gradientUnitsAttr);
671         animatableAttributes.add(SVGNames::heightAttr);
672         animatableAttributes.add(SVGNames::in2Attr);
673         animatableAttributes.add(SVGNames::inAttr);
674         animatableAttributes.add(SVGNames::interceptAttr);
675         animatableAttributes.add(SVGNames::k1Attr);
676         animatableAttributes.add(SVGNames::k2Attr);
677         animatableAttributes.add(SVGNames::k3Attr);
678         animatableAttributes.add(SVGNames::k4Attr);
679         animatableAttributes.add(SVGNames::kernelMatrixAttr);
680         animatableAttributes.add(SVGNames::kernelUnitLengthAttr);
681         animatableAttributes.add(SVGNames::lengthAdjustAttr);
682         animatableAttributes.add(SVGNames::limitingConeAngleAttr);
683         animatableAttributes.add(SVGNames::markerHeightAttr);
684         animatableAttributes.add(SVGNames::markerUnitsAttr);
685         animatableAttributes.add(SVGNames::markerWidthAttr);
686         animatableAttributes.add(SVGNames::maskContentUnitsAttr);
687         animatableAttributes.add(SVGNames::maskUnitsAttr);
688         animatableAttributes.add(SVGNames::methodAttr);
689         animatableAttributes.add(SVGNames::modeAttr);
690         animatableAttributes.add(SVGNames::numOctavesAttr);
691         animatableAttributes.add(SVGNames::offsetAttr);
692         animatableAttributes.add(SVGNames::operatorAttr);
693         animatableAttributes.add(SVGNames::orderAttr);
694         animatableAttributes.add(SVGNames::orientAttr);
695         animatableAttributes.add(SVGNames::pathLengthAttr);
696         animatableAttributes.add(SVGNames::patternContentUnitsAttr);
697         animatableAttributes.add(SVGNames::patternTransformAttr);
698         animatableAttributes.add(SVGNames::patternUnitsAttr);
699         animatableAttributes.add(SVGNames::pointsAtXAttr);
700         animatableAttributes.add(SVGNames::pointsAtYAttr);
701         animatableAttributes.add(SVGNames::pointsAtZAttr);
702         animatableAttributes.add(SVGNames::preserveAlphaAttr);
703         animatableAttributes.add(SVGNames::preserveAspectRatioAttr);
704         animatableAttributes.add(SVGNames::primitiveUnitsAttr);
705         animatableAttributes.add(SVGNames::radiusAttr);
706         animatableAttributes.add(SVGNames::rAttr);
707         animatableAttributes.add(SVGNames::refXAttr);
708         animatableAttributes.add(SVGNames::refYAttr);
709         animatableAttributes.add(SVGNames::resultAttr);
710         animatableAttributes.add(SVGNames::rotateAttr);
711         animatableAttributes.add(SVGNames::rxAttr);
712         animatableAttributes.add(SVGNames::ryAttr);
713         animatableAttributes.add(SVGNames::scaleAttr);
714         animatableAttributes.add(SVGNames::seedAttr);
715         animatableAttributes.add(SVGNames::slopeAttr);
716         animatableAttributes.add(SVGNames::spacingAttr);
717         animatableAttributes.add(SVGNames::specularConstantAttr);
718         animatableAttributes.add(SVGNames::specularExponentAttr);
719         animatableAttributes.add(SVGNames::spreadMethodAttr);
720         animatableAttributes.add(SVGNames::startOffsetAttr);
721         animatableAttributes.add(SVGNames::stdDeviationAttr);
722         animatableAttributes.add(SVGNames::stitchTilesAttr);
723         animatableAttributes.add(SVGNames::surfaceScaleAttr);
724         animatableAttributes.add(SVGNames::tableValuesAttr);
725         animatableAttributes.add(SVGNames::targetAttr);
726         animatableAttributes.add(SVGNames::targetXAttr);
727         animatableAttributes.add(SVGNames::targetYAttr);
728         animatableAttributes.add(SVGNames::transformAttr);
729         animatableAttributes.add(SVGNames::typeAttr);
730         animatableAttributes.add(SVGNames::valuesAttr);
731         animatableAttributes.add(SVGNames::viewBoxAttr);
732         animatableAttributes.add(SVGNames::widthAttr);
733         animatableAttributes.add(SVGNames::x1Attr);
734         animatableAttributes.add(SVGNames::x2Attr);
735         animatableAttributes.add(SVGNames::xAttr);
736         animatableAttributes.add(SVGNames::xChannelSelectorAttr);
737         animatableAttributes.add(SVGNames::y1Attr);
738         animatableAttributes.add(SVGNames::y2Attr);
739         animatableAttributes.add(SVGNames::yAttr);
740         animatableAttributes.add(SVGNames::yChannelSelectorAttr);
741         animatableAttributes.add(SVGNames::zAttr);
742     }
743
744     if (name == classAttr)
745         return isSVGStyledElement();
746
747     return animatableAttributes.contains(name);
748 }
749 #endif
750
751 }
752
753 #endif // ENABLE(SVG)