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