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