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