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