Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2006, 2008 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2008 Apple Inc. All rights reserved.
      5  * Copyright (C) 2008 Alp Toker <alp (at) atoker.com>
      6  * Copyright (C) 2009 Cameron McCormack <cam (at) 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 #include "core/svg/SVGElement.h"
     27 
     28 #include "HTMLNames.h"
     29 #include "SVGNames.h"
     30 #include "XLinkNames.h"
     31 #include "XMLNames.h"
     32 #include "bindings/v8/ScriptEventListener.h"
     33 #include "core/css/CSSCursorImageValue.h"
     34 #include "core/css/CSSParser.h"
     35 #include "core/dom/Document.h"
     36 #include "core/dom/ElementTraversal.h"
     37 #include "core/events/Event.h"
     38 #include "core/dom/shadow/ShadowRoot.h"
     39 #include "core/rendering/RenderObject.h"
     40 #include "core/rendering/svg/RenderSVGResourceContainer.h"
     41 #include "core/svg/SVGCursorElement.h"
     42 #include "core/svg/SVGDocumentExtensions.h"
     43 #include "core/svg/SVGElementInstance.h"
     44 #include "core/svg/SVGElementRareData.h"
     45 #include "core/svg/SVGGraphicsElement.h"
     46 #include "core/svg/SVGSVGElement.h"
     47 #include "core/svg/SVGUseElement.h"
     48 
     49 #include "wtf/TemporaryChange.h"
     50 
     51 namespace WebCore {
     52 
     53 // Animated property definitions
     54 DEFINE_ANIMATED_STRING(SVGElement, HTMLNames::classAttr, ClassName, className)
     55 
     56 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGElement)
     57     REGISTER_LOCAL_ANIMATED_PROPERTY(className)
     58 END_REGISTER_ANIMATED_PROPERTIES
     59 
     60 using namespace HTMLNames;
     61 using namespace SVGNames;
     62 
     63 void mapAttributeToCSSProperty(HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap, const QualifiedName& attrName)
     64 {
     65     // FIXME: when CSS supports "transform-origin" the special case for transform_originAttr can be removed.
     66     CSSPropertyID propertyId = cssPropertyID(attrName.localName());
     67     if (!propertyId && attrName == transform_originAttr)
     68         propertyId = CSSPropertyWebkitTransformOrigin; // cssPropertyID("-webkit-transform-origin")
     69     ASSERT(propertyId > 0);
     70     propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
     71 }
     72 
     73 SVGElement::SVGElement(const QualifiedName& tagName, Document& document, ConstructionType constructionType)
     74     : Element(tagName, &document, constructionType)
     75 #if !ASSERT_DISABLED
     76     , m_inRelativeLengthClientsInvalidation(false)
     77 #endif
     78     , m_animatedPropertiesDestructed(false)
     79     , m_isContextElement(false)
     80 {
     81     ScriptWrappable::init(this);
     82     registerAnimatedPropertiesForSVGElement();
     83     setHasCustomStyleCallbacks();
     84 }
     85 
     86 SVGElement::~SVGElement()
     87 {
     88     ASSERT(inDocument() || !hasRelativeLengths());
     89 }
     90 
     91 void
     92 SVGElement::cleanupAnimatedProperties()
     93 {
     94     if (m_animatedPropertiesDestructed)
     95         return;
     96     m_animatedPropertiesDestructed = true;
     97 
     98     if (!hasSVGRareData())
     99         ASSERT(!SVGElementRareData::rareDataMap().contains(this));
    100     else {
    101         SVGElementRareData::SVGElementRareDataMap& rareDataMap = SVGElementRareData::rareDataMap();
    102         SVGElementRareData::SVGElementRareDataMap::iterator it = rareDataMap.find(this);
    103         ASSERT_WITH_SECURITY_IMPLICATION(it != rareDataMap.end());
    104 
    105         SVGElementRareData* rareData = it->value;
    106         rareData->destroyAnimatedSMILStyleProperties();
    107         if (SVGCursorElement* cursorElement = rareData->cursorElement())
    108             cursorElement->removeClient(this);
    109         if (CSSCursorImageValue* cursorImageValue = rareData->cursorImageValue())
    110             cursorImageValue->removeReferencedElement(this);
    111 
    112         delete rareData;
    113 
    114         // The rare data cleanup may have caused other SVG nodes to be deleted,
    115         // modifying the rare data map. Do not rely on the existing iterator.
    116         ASSERT(rareDataMap.contains(this));
    117         rareDataMap.remove(this);
    118         // Clear HasSVGRareData flag now so that we are in a consistent state when
    119         // calling rebuildAllElementReferencesForTarget() and
    120         // removeAllElementReferencesForTarget() below.
    121         clearHasSVGRareData();
    122     }
    123     document().accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
    124     document().accessSVGExtensions()->removeAllElementReferencesForTarget(this);
    125     SVGAnimatedProperty::detachAnimatedPropertiesForElement(this);
    126 }
    127 
    128 void SVGElement::willRecalcStyle(StyleRecalcChange change)
    129 {
    130     // FIXME: This assumes that when shouldNotifyRendererWithIdenticalStyles() is true
    131     // the change came from a SMIL animation, but what if there were non-SMIL changes
    132     // since then? I think we should remove the shouldNotifyRendererWithIdenticalStyles
    133     // check.
    134     if (!hasSVGRareData() || shouldNotifyRendererWithIdenticalStyles())
    135         return;
    136     // If the style changes because of a regular property change (not induced by SMIL animations themselves)
    137     // reset the "computed style without SMIL style properties", so the base value change gets reflected.
    138     if (change > NoChange || needsStyleRecalc())
    139         svgRareData()->setNeedsOverrideComputedStyleUpdate();
    140 }
    141 
    142 void SVGElement::buildPendingResourcesIfNeeded()
    143 {
    144     Document& document = this->document();
    145     if (!needsPendingResourceHandling() || !inDocument() || isInShadowTree())
    146         return;
    147 
    148     SVGDocumentExtensions* extensions = document.accessSVGExtensions();
    149     String resourceId = getIdAttribute();
    150     if (!extensions->hasPendingResource(resourceId))
    151         return;
    152 
    153     // Mark pending resources as pending for removal.
    154     extensions->markPendingResourcesForRemoval(resourceId);
    155 
    156     // Rebuild pending resources for each client of a pending resource that is being removed.
    157     while (Element* clientElement = extensions->removeElementFromPendingResourcesForRemoval(resourceId)) {
    158         ASSERT(clientElement->hasPendingResources());
    159         if (clientElement->hasPendingResources()) {
    160             clientElement->buildPendingResource();
    161             extensions->clearHasPendingResourcesIfPossible(clientElement);
    162         }
    163     }
    164 }
    165 
    166 bool SVGElement::rendererIsNeeded(const RenderStyle& style)
    167 {
    168     // http://www.w3.org/TR/SVG/extend.html#PrivateData
    169     // Prevent anything other than SVG renderers from appearing in our render tree
    170     // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
    171     // with the SVG content. In general, the SVG user agent will include the unknown
    172     // elements in the DOM but will otherwise ignore unknown elements.
    173     if (!parentOrShadowHostElement() || parentOrShadowHostElement()->isSVGElement())
    174         return Element::rendererIsNeeded(style);
    175 
    176     return false;
    177 }
    178 
    179 SVGElementRareData* SVGElement::svgRareData() const
    180 {
    181     ASSERT(hasSVGRareData());
    182     return SVGElementRareData::rareDataFromMap(this);
    183 }
    184 
    185 SVGElementRareData* SVGElement::ensureSVGRareData()
    186 {
    187     if (hasSVGRareData())
    188         return svgRareData();
    189 
    190     ASSERT(!SVGElementRareData::rareDataMap().contains(this));
    191     SVGElementRareData* data = new SVGElementRareData;
    192     SVGElementRareData::rareDataMap().set(this, data);
    193     setHasSVGRareData();
    194     return data;
    195 }
    196 
    197 bool SVGElement::isOutermostSVGSVGElement() const
    198 {
    199     if (!hasTagName(SVGNames::svgTag))
    200         return false;
    201 
    202     // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
    203     if (!parentNode())
    204         return true;
    205 
    206     // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
    207     if (parentNode()->hasTagName(SVGNames::foreignObjectTag))
    208         return true;
    209 
    210     // If we're living in a shadow tree, we're a <svg> element that got created as replacement
    211     // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case
    212     // we're always an inner <svg> element.
    213     if (isInShadowTree() && parentOrShadowHostElement() && parentOrShadowHostElement()->isSVGElement())
    214         return false;
    215 
    216     // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
    217     return !parentNode()->isSVGElement();
    218 }
    219 
    220 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value)
    221 {
    222     if (error == NoError)
    223         return;
    224 
    225     String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
    226     SVGDocumentExtensions* extensions = document().accessSVGExtensions();
    227 
    228     if (error == NegativeValueForbiddenError) {
    229         extensions->reportError("Invalid negative value for " + errorString);
    230         return;
    231     }
    232 
    233     if (error == ParsingAttributeFailedError) {
    234         extensions->reportError("Invalid value for " + errorString);
    235         return;
    236     }
    237 
    238     ASSERT_NOT_REACHED();
    239 }
    240 
    241 String SVGElement::title() const
    242 {
    243     // According to spec, we should not return titles when hovering over root <svg> elements (those
    244     // <title> elements are the title of the document, not a tooltip) so we instantly return.
    245     if (isOutermostSVGSVGElement())
    246         return String();
    247 
    248     // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title.
    249     if (isInShadowTree()) {
    250         Element* shadowHostElement = toShadowRoot(treeScope().rootNode())->host();
    251         // At this time, SVG nodes are not allowed in non-<use> shadow trees, so any shadow root we do
    252         // have should be a use. The assert and following test is here to catch future shadow DOM changes
    253         // that do enable SVG in a shadow tree.
    254         ASSERT(!shadowHostElement || shadowHostElement->hasTagName(SVGNames::useTag));
    255         if (shadowHostElement && shadowHostElement->hasTagName(SVGNames::useTag)) {
    256             SVGUseElement* useElement = toSVGUseElement(shadowHostElement);
    257 
    258             // If the <use> title is not empty we found the title to use.
    259             String useTitle(useElement->title());
    260             if (!useTitle.isEmpty())
    261                 return useTitle;
    262         }
    263     }
    264 
    265     // If we aren't an instance in a <use> or the <use> title was not found, then find the first
    266     // <title> child of this element.
    267     Element* titleElement = ElementTraversal::firstWithin(*this);
    268     for (; titleElement; titleElement = ElementTraversal::nextSkippingChildren(*titleElement, this)) {
    269         if (titleElement->hasTagName(SVGNames::titleTag) && titleElement->isSVGElement())
    270             break;
    271     }
    272 
    273     // If a title child was found, return the text contents.
    274     if (titleElement)
    275         return titleElement->innerText();
    276 
    277     // Otherwise return a null/empty string.
    278     return String();
    279 }
    280 
    281 PassRefPtr<CSSValue> SVGElement::getPresentationAttribute(const String& name)
    282 {
    283     if (!hasAttributesWithoutUpdate())
    284         return 0;
    285 
    286     QualifiedName attributeName(nullAtom, name, nullAtom);
    287     const Attribute* attr = getAttributeItem(attributeName);
    288     if (!attr)
    289         return 0;
    290 
    291     RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create(SVGAttributeMode);
    292     CSSPropertyID propertyID = SVGElement::cssPropertyIdForSVGAttributeName(attr->name());
    293     style->setProperty(propertyID, attr->value());
    294     RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(propertyID);
    295     return cssValue ? cssValue->cloneForCSSOM() : 0;
    296 }
    297 
    298 
    299 bool SVGElement::instanceUpdatesBlocked() const
    300 {
    301     return hasSVGRareData() && svgRareData()->instanceUpdatesBlocked();
    302 }
    303 
    304 void SVGElement::setInstanceUpdatesBlocked(bool value)
    305 {
    306     if (hasSVGRareData())
    307         svgRareData()->setInstanceUpdatesBlocked(value);
    308 }
    309 
    310 AffineTransform SVGElement::localCoordinateSpaceTransform(CTMScope) const
    311 {
    312     // To be overriden by SVGGraphicsElement (or as special case SVGTextElement and SVGPatternElement)
    313     return AffineTransform();
    314 }
    315 
    316 String SVGElement::xmlbase() const
    317 {
    318     return fastGetAttribute(XMLNames::baseAttr);
    319 }
    320 
    321 void SVGElement::setXMLbase(const String& value)
    322 {
    323     setAttribute(XMLNames::baseAttr, value);
    324 }
    325 
    326 String SVGElement::xmllang() const
    327 {
    328     return fastGetAttribute(XMLNames::langAttr);
    329 }
    330 
    331 void SVGElement::setXMLlang(const String& value)
    332 {
    333     setAttribute(XMLNames::langAttr, value);
    334 }
    335 
    336 String SVGElement::xmlspace() const
    337 {
    338     return fastGetAttribute(XMLNames::spaceAttr);
    339 }
    340 
    341 void SVGElement::setXMLspace(const String& value)
    342 {
    343     setAttribute(XMLNames::spaceAttr, value);
    344 }
    345 
    346 Node::InsertionNotificationRequest SVGElement::insertedInto(ContainerNode* rootParent)
    347 {
    348     Element::insertedInto(rootParent);
    349     updateRelativeLengthsInformation();
    350     buildPendingResourcesIfNeeded();
    351     return InsertionDone;
    352 }
    353 
    354 void SVGElement::removedFrom(ContainerNode* rootParent)
    355 {
    356     bool wasInDocument = rootParent->inDocument();
    357 
    358     if (wasInDocument && hasRelativeLengths()) {
    359         // The root of the subtree being removed should take itself out from its parent's relative
    360         // length set. For the other nodes in the subtree we don't need to do anything: they will
    361         // get their own removedFrom() notification and just clear their sets.
    362         if (rootParent->isSVGElement() && !parentNode()) {
    363             ASSERT(toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this));
    364             toSVGElement(rootParent)->updateRelativeLengthsInformation(false, this);
    365         }
    366 
    367         m_elementsWithRelativeLengths.clear();
    368     }
    369 
    370     ASSERT_WITH_SECURITY_IMPLICATION(!rootParent->isSVGElement() || !toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this));
    371 
    372     Element::removedFrom(rootParent);
    373 
    374     if (wasInDocument) {
    375         document().accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
    376         document().accessSVGExtensions()->removeAllElementReferencesForTarget(this);
    377     }
    378 
    379     SVGElementInstance::invalidateAllInstancesOfElement(this);
    380 }
    381 
    382 void SVGElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    383 {
    384     Element::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    385 
    386     // Invalidate all SVGElementInstances associated with us.
    387     if (!changedByParser)
    388         SVGElementInstance::invalidateAllInstancesOfElement(this);
    389 }
    390 
    391 CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
    392 {
    393     if (!attrName.namespaceURI().isNull())
    394         return CSSPropertyInvalid;
    395 
    396     static HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap = 0;
    397     if (!propertyNameToIdMap) {
    398         propertyNameToIdMap = new HashMap<StringImpl*, CSSPropertyID>;
    399         // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
    400         mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr);
    401         mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr);
    402         mapAttributeToCSSProperty(propertyNameToIdMap, buffered_renderingAttr);
    403         mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr);
    404         mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr);
    405         mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr);
    406         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::colorAttr);
    407         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr);
    408         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr);
    409         mapAttributeToCSSProperty(propertyNameToIdMap, color_profileAttr);
    410         mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr);
    411         mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr);
    412         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::directionAttr);
    413         mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr);
    414         mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr);
    415         mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr);
    416         mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr);
    417         mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr);
    418         mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr);
    419         mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr);
    420         mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr);
    421         mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr);
    422         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
    423         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
    424         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
    425         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
    426         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
    427         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
    428         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr);
    429         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr);
    430         mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr);
    431         mapAttributeToCSSProperty(propertyNameToIdMap, kerningAttr);
    432         mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr);
    433         mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr);
    434         mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr);
    435         mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr);
    436         mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr);
    437         mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr);
    438         mapAttributeToCSSProperty(propertyNameToIdMap, mask_typeAttr);
    439         mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr);
    440         mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr);
    441         mapAttributeToCSSProperty(propertyNameToIdMap, paint_orderAttr);
    442         mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr);
    443         mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr);
    444         mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr);
    445         mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr);
    446         mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr);
    447         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr);
    448         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr);
    449         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr);
    450         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr);
    451         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr);
    452         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr);
    453         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr);
    454         mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr);
    455         mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr);
    456         mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr);
    457         mapAttributeToCSSProperty(propertyNameToIdMap, transform_originAttr);
    458         mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr);
    459         mapAttributeToCSSProperty(propertyNameToIdMap, vector_effectAttr);
    460         mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr);
    461         mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr);
    462         mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr);
    463     }
    464 
    465     return propertyNameToIdMap->get(attrName.localName().impl());
    466 }
    467 
    468 void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement)
    469 {
    470     ASSERT(clientElement);
    471 
    472     // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now.
    473     if (!inDocument())
    474         return;
    475 
    476     // An element wants to notify us that its own relative lengths state changed.
    477     // Register it in the relative length map, and register us in the parent relative length map.
    478     // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.
    479     for (ContainerNode* currentNode = this; currentNode && currentNode->isSVGElement(); currentNode = currentNode->parentNode()) {
    480         SVGElement* currentElement = toSVGElement(currentNode);
    481         ASSERT(!currentElement->m_inRelativeLengthClientsInvalidation);
    482 
    483         bool hadRelativeLengths = currentElement->hasRelativeLengths();
    484         if (clientHasRelativeLengths)
    485             currentElement->m_elementsWithRelativeLengths.add(clientElement);
    486         else
    487             currentElement->m_elementsWithRelativeLengths.remove(clientElement);
    488 
    489         // If the relative length state hasn't changed, we can stop propagating the notification.
    490         if (hadRelativeLengths == currentElement->hasRelativeLengths())
    491             return;
    492 
    493         clientElement = currentElement;
    494         clientHasRelativeLengths = clientElement->hasRelativeLengths();
    495     }
    496 
    497     // Register root SVG elements for top level viewport change notifications.
    498     if (clientElement->isSVGSVGElement()) {
    499         SVGDocumentExtensions* svgExtensions = accessDocumentSVGExtensions();
    500         if (clientElement->hasRelativeLengths())
    501             svgExtensions->addSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
    502         else
    503             svgExtensions->removeSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
    504     }
    505 }
    506 
    507 void SVGElement::invalidateRelativeLengthClients(SubtreeLayoutScope* layoutScope)
    508 {
    509     if (!inDocument())
    510         return;
    511 
    512     ASSERT(!m_inRelativeLengthClientsInvalidation);
    513 #if !ASSERT_DISABLED
    514     TemporaryChange<bool> inRelativeLengthClientsInvalidationChange(m_inRelativeLengthClientsInvalidation, true);
    515 #endif
    516 
    517     RenderObject* renderer = this->renderer();
    518     if (renderer && selfHasRelativeLengths()) {
    519         if (renderer->isSVGResourceContainer())
    520             toRenderSVGResourceContainer(renderer)->invalidateCacheAndMarkForLayout(layoutScope);
    521         else
    522             renderer->setNeedsLayout(MarkContainingBlockChain, layoutScope);
    523     }
    524 
    525     HashSet<SVGElement*>::iterator end = m_elementsWithRelativeLengths.end();
    526     for (HashSet<SVGElement*>::iterator it = m_elementsWithRelativeLengths.begin(); it != end; ++it) {
    527         if (*it != this)
    528             (*it)->invalidateRelativeLengthClients(layoutScope);
    529     }
    530 }
    531 
    532 SVGSVGElement* SVGElement::ownerSVGElement() const
    533 {
    534     ContainerNode* n = parentOrShadowHostNode();
    535     while (n) {
    536         if (n->hasTagName(SVGNames::svgTag))
    537             return toSVGSVGElement(n);
    538 
    539         n = n->parentOrShadowHostNode();
    540     }
    541 
    542     return 0;
    543 }
    544 
    545 SVGElement* SVGElement::viewportElement() const
    546 {
    547     // This function needs shadow tree support - as RenderSVGContainer uses this function
    548     // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
    549     ContainerNode* n = parentOrShadowHostNode();
    550     while (n) {
    551         if (n->hasTagName(SVGNames::svgTag) || n->hasTagName(SVGNames::imageTag) || n->hasTagName(SVGNames::symbolTag))
    552             return toSVGElement(n);
    553 
    554         n = n->parentOrShadowHostNode();
    555     }
    556 
    557     return 0;
    558 }
    559 
    560 SVGDocumentExtensions* SVGElement::accessDocumentSVGExtensions()
    561 {
    562     // This function is provided for use by SVGAnimatedProperty to avoid
    563     // global inclusion of core/dom/Document.h in SVG code.
    564     return document().accessSVGExtensions();
    565 }
    566 
    567 void SVGElement::mapInstanceToElement(SVGElementInstance* instance)
    568 {
    569     ASSERT(instance);
    570 
    571     HashSet<SVGElementInstance*>& instances = ensureSVGRareData()->elementInstances();
    572     ASSERT(!instances.contains(instance));
    573 
    574     instances.add(instance);
    575 }
    576 
    577 void SVGElement::removeInstanceMapping(SVGElementInstance* instance)
    578 {
    579     ASSERT(instance);
    580     ASSERT(hasSVGRareData());
    581 
    582     HashSet<SVGElementInstance*>& instances = svgRareData()->elementInstances();
    583     ASSERT(instances.contains(instance));
    584 
    585     instances.remove(instance);
    586 }
    587 
    588 const HashSet<SVGElementInstance*>& SVGElement::instancesForElement() const
    589 {
    590     if (!hasSVGRareData()) {
    591         DEFINE_STATIC_LOCAL(HashSet<SVGElementInstance*>, emptyInstances, ());
    592         return emptyInstances;
    593     }
    594     return svgRareData()->elementInstances();
    595 }
    596 
    597 bool SVGElement::getBoundingBox(FloatRect& rect)
    598 {
    599     if (!isSVGGraphicsElement())
    600         return false;
    601 
    602     rect = toSVGGraphicsElement(this)->getBBox();
    603     return true;
    604 }
    605 
    606 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
    607 {
    608     SVGElementRareData* rareData = ensureSVGRareData();
    609     if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) {
    610         if (cursorElement == oldCursorElement)
    611             return;
    612         oldCursorElement->removeReferencedElement(this);
    613     }
    614     rareData->setCursorElement(cursorElement);
    615 }
    616 
    617 void SVGElement::cursorElementRemoved()
    618 {
    619     ASSERT(hasSVGRareData());
    620     svgRareData()->setCursorElement(0);
    621 }
    622 
    623 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
    624 {
    625     SVGElementRareData* rareData = ensureSVGRareData();
    626     if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) {
    627         if (cursorImageValue == oldCursorImageValue)
    628             return;
    629         oldCursorImageValue->removeReferencedElement(this);
    630     }
    631     rareData->setCursorImageValue(cursorImageValue);
    632 }
    633 
    634 void SVGElement::cursorImageValueRemoved()
    635 {
    636     ASSERT(hasSVGRareData());
    637     svgRareData()->setCursorImageValue(0);
    638 }
    639 
    640 SVGElement* SVGElement::correspondingElement()
    641 {
    642     ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || containingShadowRoot());
    643     return hasSVGRareData() ? svgRareData()->correspondingElement() : 0;
    644 }
    645 
    646 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
    647 {
    648     ensureSVGRareData()->setCorrespondingElement(correspondingElement);
    649 }
    650 
    651 void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    652 {
    653     // standard events
    654     if (name == onloadAttr)
    655         setAttributeEventListener(EventTypeNames::load, createAttributeEventListener(this, name, value));
    656     else if (name == onbeginAttr)
    657         setAttributeEventListener(EventTypeNames::beginEvent, createAttributeEventListener(this, name, value));
    658     else if (name == onendAttr)
    659         setAttributeEventListener(EventTypeNames::endEvent, createAttributeEventListener(this, name, value));
    660     else if (name == onrepeatAttr)
    661         setAttributeEventListener(EventTypeNames::repeatEvent, createAttributeEventListener(this, name, value));
    662     else if (name == onclickAttr)
    663         setAttributeEventListener(EventTypeNames::click, createAttributeEventListener(this, name, value));
    664     else if (name == onmousedownAttr)
    665         setAttributeEventListener(EventTypeNames::mousedown, createAttributeEventListener(this, name, value));
    666     else if (name == onmouseenterAttr)
    667         setAttributeEventListener(EventTypeNames::mouseenter, createAttributeEventListener(this, name, value));
    668     else if (name == onmouseleaveAttr)
    669         setAttributeEventListener(EventTypeNames::mouseleave, createAttributeEventListener(this, name, value));
    670     else if (name == onmousemoveAttr)
    671         setAttributeEventListener(EventTypeNames::mousemove, createAttributeEventListener(this, name, value));
    672     else if (name == onmouseoutAttr)
    673         setAttributeEventListener(EventTypeNames::mouseout, createAttributeEventListener(this, name, value));
    674     else if (name == onmouseoverAttr)
    675         setAttributeEventListener(EventTypeNames::mouseover, createAttributeEventListener(this, name, value));
    676     else if (name == onmouseupAttr)
    677         setAttributeEventListener(EventTypeNames::mouseup, createAttributeEventListener(this, name, value));
    678     else if (name == SVGNames::onfocusinAttr)
    679         setAttributeEventListener(EventTypeNames::focusin, createAttributeEventListener(this, name, value));
    680     else if (name == SVGNames::onfocusoutAttr)
    681         setAttributeEventListener(EventTypeNames::focusout, createAttributeEventListener(this, name, value));
    682     else if (name == SVGNames::onactivateAttr)
    683         setAttributeEventListener(EventTypeNames::DOMActivate, createAttributeEventListener(this, name, value));
    684     else if (name == HTMLNames::classAttr) {
    685         // SVG animation has currently requires special storage of values so we set
    686         // the className here. svgAttributeChanged actually causes the resulting
    687         // style updates (instead of Element::parseAttribute). We don't
    688         // tell Element about the change to avoid parsing the class list twice
    689         setClassNameBaseValue(value);
    690     } else if (name.matches(XMLNames::langAttr) || name.matches(XMLNames::spaceAttr)) {
    691     } else
    692         Element::parseAttribute(name, value);
    693 }
    694 
    695 typedef HashMap<QualifiedName, AnimatedPropertyType> AttributeToPropertyTypeMap;
    696 static inline AttributeToPropertyTypeMap& cssPropertyToTypeMap()
    697 {
    698     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_cssPropertyMap, ());
    699 
    700     if (!s_cssPropertyMap.isEmpty())
    701         return s_cssPropertyMap;
    702 
    703     // Fill the map for the first use.
    704     s_cssPropertyMap.set(alignment_baselineAttr, AnimatedString);
    705     s_cssPropertyMap.set(baseline_shiftAttr, AnimatedString);
    706     s_cssPropertyMap.set(buffered_renderingAttr, AnimatedString);
    707     s_cssPropertyMap.set(clipAttr, AnimatedRect);
    708     s_cssPropertyMap.set(clip_pathAttr, AnimatedString);
    709     s_cssPropertyMap.set(clip_ruleAttr, AnimatedString);
    710     s_cssPropertyMap.set(SVGNames::colorAttr, AnimatedColor);
    711     s_cssPropertyMap.set(color_interpolationAttr, AnimatedString);
    712     s_cssPropertyMap.set(color_interpolation_filtersAttr, AnimatedString);
    713     s_cssPropertyMap.set(color_profileAttr, AnimatedString);
    714     s_cssPropertyMap.set(color_renderingAttr, AnimatedString);
    715     s_cssPropertyMap.set(cursorAttr, AnimatedString);
    716     s_cssPropertyMap.set(displayAttr, AnimatedString);
    717     s_cssPropertyMap.set(dominant_baselineAttr, AnimatedString);
    718     s_cssPropertyMap.set(fillAttr, AnimatedColor);
    719     s_cssPropertyMap.set(fill_opacityAttr, AnimatedNumber);
    720     s_cssPropertyMap.set(fill_ruleAttr, AnimatedString);
    721     s_cssPropertyMap.set(filterAttr, AnimatedString);
    722     s_cssPropertyMap.set(flood_colorAttr, AnimatedColor);
    723     s_cssPropertyMap.set(flood_opacityAttr, AnimatedNumber);
    724     s_cssPropertyMap.set(font_familyAttr, AnimatedString);
    725     s_cssPropertyMap.set(font_sizeAttr, AnimatedLength);
    726     s_cssPropertyMap.set(font_stretchAttr, AnimatedString);
    727     s_cssPropertyMap.set(font_styleAttr, AnimatedString);
    728     s_cssPropertyMap.set(font_variantAttr, AnimatedString);
    729     s_cssPropertyMap.set(font_weightAttr, AnimatedString);
    730     s_cssPropertyMap.set(image_renderingAttr, AnimatedString);
    731     s_cssPropertyMap.set(kerningAttr, AnimatedLength);
    732     s_cssPropertyMap.set(letter_spacingAttr, AnimatedLength);
    733     s_cssPropertyMap.set(lighting_colorAttr, AnimatedColor);
    734     s_cssPropertyMap.set(marker_endAttr, AnimatedString);
    735     s_cssPropertyMap.set(marker_midAttr, AnimatedString);
    736     s_cssPropertyMap.set(marker_startAttr, AnimatedString);
    737     s_cssPropertyMap.set(maskAttr, AnimatedString);
    738     s_cssPropertyMap.set(mask_typeAttr, AnimatedString);
    739     s_cssPropertyMap.set(opacityAttr, AnimatedNumber);
    740     s_cssPropertyMap.set(overflowAttr, AnimatedString);
    741     s_cssPropertyMap.set(paint_orderAttr, AnimatedString);
    742     s_cssPropertyMap.set(pointer_eventsAttr, AnimatedString);
    743     s_cssPropertyMap.set(shape_renderingAttr, AnimatedString);
    744     s_cssPropertyMap.set(stop_colorAttr, AnimatedColor);
    745     s_cssPropertyMap.set(stop_opacityAttr, AnimatedNumber);
    746     s_cssPropertyMap.set(strokeAttr, AnimatedColor);
    747     s_cssPropertyMap.set(stroke_dasharrayAttr, AnimatedLengthList);
    748     s_cssPropertyMap.set(stroke_dashoffsetAttr, AnimatedLength);
    749     s_cssPropertyMap.set(stroke_linecapAttr, AnimatedString);
    750     s_cssPropertyMap.set(stroke_linejoinAttr, AnimatedString);
    751     s_cssPropertyMap.set(stroke_miterlimitAttr, AnimatedNumber);
    752     s_cssPropertyMap.set(stroke_opacityAttr, AnimatedNumber);
    753     s_cssPropertyMap.set(stroke_widthAttr, AnimatedLength);
    754     s_cssPropertyMap.set(text_anchorAttr, AnimatedString);
    755     s_cssPropertyMap.set(text_decorationAttr, AnimatedString);
    756     s_cssPropertyMap.set(text_renderingAttr, AnimatedString);
    757     s_cssPropertyMap.set(vector_effectAttr, AnimatedString);
    758     s_cssPropertyMap.set(visibilityAttr, AnimatedString);
    759     s_cssPropertyMap.set(word_spacingAttr, AnimatedLength);
    760     return s_cssPropertyMap;
    761 }
    762 
    763 void SVGElement::animatedPropertyTypeForAttribute(const QualifiedName& attributeName, Vector<AnimatedPropertyType>& propertyTypes)
    764 {
    765     localAttributeToPropertyMap().animatedPropertyTypeForAttribute(attributeName, propertyTypes);
    766     if (!propertyTypes.isEmpty())
    767         return;
    768 
    769     AttributeToPropertyTypeMap& cssPropertyTypeMap = cssPropertyToTypeMap();
    770     if (cssPropertyTypeMap.contains(attributeName))
    771         propertyTypes.append(cssPropertyTypeMap.get(attributeName));
    772 }
    773 
    774 bool SVGElement::isAnimatableCSSProperty(const QualifiedName& attrName)
    775 {
    776     return cssPropertyToTypeMap().contains(attrName);
    777 }
    778 
    779 bool SVGElement::isPresentationAttribute(const QualifiedName& name) const
    780 {
    781     return cssPropertyIdForSVGAttributeName(name) > 0;
    782 }
    783 
    784 void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
    785 {
    786     CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(name);
    787     if (propertyID > 0)
    788         addPropertyToPresentationAttributeStyle(style, propertyID, value);
    789 }
    790 
    791 bool SVGElement::haveLoadedRequiredResources()
    792 {
    793     Node* child = firstChild();
    794     while (child) {
    795         if (child->isSVGElement() && !toSVGElement(child)->haveLoadedRequiredResources())
    796             return false;
    797         child = child->nextSibling();
    798     }
    799     return true;
    800 }
    801 
    802 static inline void collectInstancesForSVGElement(SVGElement* element, HashSet<SVGElementInstance*>& instances)
    803 {
    804     ASSERT(element);
    805     if (element->containingShadowRoot())
    806         return;
    807 
    808     ASSERT(!element->instanceUpdatesBlocked());
    809 
    810     instances = element->instancesForElement();
    811 }
    812 
    813 bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
    814 {
    815     RefPtr<EventListener> listener = prpListener;
    816 
    817     // Add event listener to regular DOM element
    818     if (!Node::addEventListener(eventType, listener, useCapture))
    819         return false;
    820 
    821     // Add event listener to all shadow tree DOM element instances
    822     HashSet<SVGElementInstance*> instances;
    823     collectInstancesForSVGElement(this, instances);
    824     const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
    825     for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
    826         ASSERT((*it)->shadowTreeElement());
    827         ASSERT((*it)->correspondingElement() == this);
    828 
    829         bool result = (*it)->shadowTreeElement()->Node::addEventListener(eventType, listener, useCapture);
    830         ASSERT_UNUSED(result, result);
    831     }
    832 
    833     return true;
    834 }
    835 
    836 bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
    837 {
    838     HashSet<SVGElementInstance*> instances;
    839     collectInstancesForSVGElement(this, instances);
    840     if (instances.isEmpty())
    841         return Node::removeEventListener(eventType, listener, useCapture);
    842 
    843     // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener
    844     // object when creating a temporary RegisteredEventListener object used to look up the
    845     // event listener in a cache. If we want to be able to call removeEventListener() multiple
    846     // times on different nodes, we have to delay its immediate destruction, which would happen
    847     // after the first call below.
    848     RefPtr<EventListener> protector(listener);
    849 
    850     // Remove event listener from regular DOM element
    851     if (!Node::removeEventListener(eventType, listener, useCapture))
    852         return false;
    853 
    854     // Remove event listener from all shadow tree DOM element instances
    855     const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
    856     for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
    857         ASSERT((*it)->correspondingElement() == this);
    858 
    859         SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
    860         ASSERT(shadowTreeElement);
    861 
    862         if (shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture))
    863             continue;
    864 
    865         // This case can only be hit for event listeners created from markup
    866         ASSERT(listener->wasCreatedFromMarkup());
    867 
    868         // If the event listener 'listener' has been created from markup and has been fired before
    869         // then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener
    870         // has been created (read: it's not 0 anymore). During shadow tree creation, the event
    871         // listener DOM attribute has been cloned, and another event listener has been setup in
    872         // the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0,
    873         // and tryRemoveEventListener() above will fail. Work around that very seldom problem.
    874         EventTargetData* data = shadowTreeElement->eventTargetData();
    875         ASSERT(data);
    876 
    877         data->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
    878     }
    879 
    880     return true;
    881 }
    882 
    883 static bool hasLoadListener(Element* element)
    884 {
    885     if (element->hasEventListeners(EventTypeNames::load))
    886         return true;
    887 
    888     for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) {
    889         const EventListenerVector& entry = element->getEventListeners(EventTypeNames::load);
    890         for (size_t i = 0; i < entry.size(); ++i) {
    891             if (entry[i].useCapture)
    892                 return true;
    893         }
    894     }
    895 
    896     return false;
    897 }
    898 
    899 bool SVGElement::shouldMoveToFlowThread(RenderStyle* styleToUse) const
    900 {
    901     // Allow only svg root elements to be directly collected by a render flow thread.
    902     return parentNode() && !parentNode()->isSVGElement() && hasTagName(SVGNames::svgTag) && Element::shouldMoveToFlowThread(styleToUse);
    903 }
    904 
    905 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
    906 {
    907     RefPtr<SVGElement> currentTarget = this;
    908     while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
    909         RefPtr<Element> parent;
    910         if (sendParentLoadEvents)
    911             parent = currentTarget->parentOrShadowHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree
    912         if (hasLoadListener(currentTarget.get()))
    913             currentTarget->dispatchEvent(Event::create(EventTypeNames::load));
    914         currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>();
    915         SVGElement* element = currentTarget.get();
    916         if (!element || !element->isOutermostSVGSVGElement())
    917             continue;
    918 
    919         // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>.
    920         // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through
    921         // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded.
    922         ASSERT(sendParentLoadEvents);
    923 
    924         // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example
    925         // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document
    926         // to be "ready to render", first.
    927         if (!document().loadEventFinished())
    928             break;
    929     }
    930 }
    931 
    932 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
    933 {
    934     svgLoadEventTimer()->startOneShot(0);
    935 }
    936 
    937 void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*)
    938 {
    939     sendSVGLoadEventIfPossible();
    940 }
    941 
    942 Timer<SVGElement>* SVGElement::svgLoadEventTimer()
    943 {
    944     ASSERT_NOT_REACHED();
    945     return 0;
    946 }
    947 
    948 void SVGElement::finishParsingChildren()
    949 {
    950     Element::finishParsingChildren();
    951 
    952     // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent.
    953     if (isOutermostSVGSVGElement())
    954         return;
    955 
    956     // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
    957     // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
    958     sendSVGLoadEventIfPossible();
    959 }
    960 
    961 bool SVGElement::childShouldCreateRenderer(const Node& child) const
    962 {
    963     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, invalidTextContent, ());
    964 
    965     if (invalidTextContent.isEmpty()) {
    966         invalidTextContent.add(SVGNames::textPathTag);
    967 #if ENABLE(SVG_FONTS)
    968         invalidTextContent.add(SVGNames::altGlyphTag);
    969 #endif
    970         invalidTextContent.add(SVGNames::tspanTag);
    971     }
    972     if (child.isSVGElement()) {
    973         const SVGElement* svgChild = toSVGElement(&child);
    974         if (invalidTextContent.contains(svgChild->tagQName()))
    975             return false;
    976 
    977         return svgChild->isValid();
    978     }
    979     return false;
    980 }
    981 
    982 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason)
    983 {
    984     Element::attributeChanged(name, newValue);
    985 
    986     if (isIdAttributeName(name))
    987         document().accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
    988 
    989     // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
    990     // so we don't want changes to the style attribute to result in extra work here.
    991     if (name != HTMLNames::styleAttr)
    992         svgAttributeChanged(name);
    993 }
    994 
    995 void SVGElement::svgAttributeChanged(const QualifiedName& attrName)
    996 {
    997     CSSPropertyID propId = SVGElement::cssPropertyIdForSVGAttributeName(attrName);
    998     if (propId > 0) {
    999         SVGElementInstance::invalidateAllInstancesOfElement(this);
   1000         return;
   1001     }
   1002 
   1003     if (attrName == HTMLNames::classAttr) {
   1004         classAttributeChanged(classNameCurrentValue());
   1005         SVGElementInstance::invalidateAllInstancesOfElement(this);
   1006         return;
   1007     }
   1008 
   1009     if (isIdAttributeName(attrName)) {
   1010         RenderObject* object = renderer();
   1011         // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
   1012         if (object && object->isSVGResourceContainer())
   1013             toRenderSVGResourceContainer(object)->idChanged();
   1014         if (inDocument())
   1015             buildPendingResourcesIfNeeded();
   1016         SVGElementInstance::invalidateAllInstancesOfElement(this);
   1017         return;
   1018     }
   1019 }
   1020 
   1021 void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const
   1022 {
   1023     if (!elementData() || !elementData()->m_animatedSVGAttributesAreDirty)
   1024         return;
   1025 
   1026     SVGElement* nonConstThis = const_cast<SVGElement*>(this);
   1027     if (name == anyQName()) {
   1028         nonConstThis->localAttributeToPropertyMap().synchronizeProperties(nonConstThis);
   1029         elementData()->m_animatedSVGAttributesAreDirty = false;
   1030     } else
   1031         nonConstThis->localAttributeToPropertyMap().synchronizeProperty(nonConstThis, name);
   1032 }
   1033 
   1034 void SVGElement::synchronizeRequiredFeatures(SVGElement* contextElement)
   1035 {
   1036     ASSERT(contextElement);
   1037     contextElement->synchronizeRequiredFeatures();
   1038 }
   1039 
   1040 void SVGElement::synchronizeRequiredExtensions(SVGElement* contextElement)
   1041 {
   1042     ASSERT(contextElement);
   1043     contextElement->synchronizeRequiredExtensions();
   1044 }
   1045 
   1046 void SVGElement::synchronizeSystemLanguage(SVGElement* contextElement)
   1047 {
   1048     ASSERT(contextElement);
   1049     contextElement->synchronizeSystemLanguage();
   1050 }
   1051 
   1052 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
   1053 {
   1054     if (!correspondingElement())
   1055         return document().ensureStyleResolver().styleForElement(this);
   1056 
   1057     RenderStyle* style = 0;
   1058     if (Element* parent = parentOrShadowHostElement()) {
   1059         if (RenderObject* renderer = parent->renderer())
   1060             style = renderer->style();
   1061     }
   1062 
   1063     return document().ensureStyleResolver().styleForElement(correspondingElement(), style, DisallowStyleSharing);
   1064 }
   1065 
   1066 MutableStylePropertySet* SVGElement::animatedSMILStyleProperties() const
   1067 {
   1068     if (hasSVGRareData())
   1069         return svgRareData()->animatedSMILStyleProperties();
   1070     return 0;
   1071 }
   1072 
   1073 MutableStylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties()
   1074 {
   1075     return ensureSVGRareData()->ensureAnimatedSMILStyleProperties();
   1076 }
   1077 
   1078 void SVGElement::setUseOverrideComputedStyle(bool value)
   1079 {
   1080     if (hasSVGRareData())
   1081         svgRareData()->setUseOverrideComputedStyle(value);
   1082 }
   1083 
   1084 RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
   1085 {
   1086     if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle())
   1087         return Element::computedStyle(pseudoElementSpecifier);
   1088 
   1089     RenderStyle* parentStyle = 0;
   1090     if (Element* parent = parentOrShadowHostElement()) {
   1091         if (RenderObject* renderer = parent->renderer())
   1092             parentStyle = renderer->style();
   1093     }
   1094 
   1095     return svgRareData()->overrideComputedStyle(this, parentStyle);
   1096 }
   1097 
   1098 bool SVGElement::hasFocusEventListeners() const
   1099 {
   1100     return hasEventListeners(EventTypeNames::focusin) || hasEventListeners(EventTypeNames::focusout);
   1101 }
   1102 
   1103 bool SVGElement::isKeyboardFocusable() const
   1104 {
   1105     return isFocusable();
   1106 }
   1107 
   1108 #ifndef NDEBUG
   1109 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
   1110 {
   1111     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ());
   1112 
   1113     if (animatableAttributes.isEmpty()) {
   1114         animatableAttributes.add(XLinkNames::hrefAttr);
   1115         animatableAttributes.add(SVGNames::amplitudeAttr);
   1116         animatableAttributes.add(SVGNames::azimuthAttr);
   1117         animatableAttributes.add(SVGNames::baseFrequencyAttr);
   1118         animatableAttributes.add(SVGNames::biasAttr);
   1119         animatableAttributes.add(SVGNames::clipPathUnitsAttr);
   1120         animatableAttributes.add(SVGNames::cxAttr);
   1121         animatableAttributes.add(SVGNames::cyAttr);
   1122         animatableAttributes.add(SVGNames::diffuseConstantAttr);
   1123         animatableAttributes.add(SVGNames::divisorAttr);
   1124         animatableAttributes.add(SVGNames::dxAttr);
   1125         animatableAttributes.add(SVGNames::dyAttr);
   1126         animatableAttributes.add(SVGNames::edgeModeAttr);
   1127         animatableAttributes.add(SVGNames::elevationAttr);
   1128         animatableAttributes.add(SVGNames::exponentAttr);
   1129         animatableAttributes.add(SVGNames::externalResourcesRequiredAttr);
   1130         animatableAttributes.add(SVGNames::filterResAttr);
   1131         animatableAttributes.add(SVGNames::filterUnitsAttr);
   1132         animatableAttributes.add(SVGNames::fxAttr);
   1133         animatableAttributes.add(SVGNames::fyAttr);
   1134         animatableAttributes.add(SVGNames::gradientTransformAttr);
   1135         animatableAttributes.add(SVGNames::gradientUnitsAttr);
   1136         animatableAttributes.add(SVGNames::heightAttr);
   1137         animatableAttributes.add(SVGNames::in2Attr);
   1138         animatableAttributes.add(SVGNames::inAttr);
   1139         animatableAttributes.add(SVGNames::interceptAttr);
   1140         animatableAttributes.add(SVGNames::k1Attr);
   1141         animatableAttributes.add(SVGNames::k2Attr);
   1142         animatableAttributes.add(SVGNames::k3Attr);
   1143         animatableAttributes.add(SVGNames::k4Attr);
   1144         animatableAttributes.add(SVGNames::kernelMatrixAttr);
   1145         animatableAttributes.add(SVGNames::kernelUnitLengthAttr);
   1146         animatableAttributes.add(SVGNames::lengthAdjustAttr);
   1147         animatableAttributes.add(SVGNames::limitingConeAngleAttr);
   1148         animatableAttributes.add(SVGNames::markerHeightAttr);
   1149         animatableAttributes.add(SVGNames::markerUnitsAttr);
   1150         animatableAttributes.add(SVGNames::markerWidthAttr);
   1151         animatableAttributes.add(SVGNames::maskContentUnitsAttr);
   1152         animatableAttributes.add(SVGNames::maskUnitsAttr);
   1153         animatableAttributes.add(SVGNames::methodAttr);
   1154         animatableAttributes.add(SVGNames::modeAttr);
   1155         animatableAttributes.add(SVGNames::numOctavesAttr);
   1156         animatableAttributes.add(SVGNames::offsetAttr);
   1157         animatableAttributes.add(SVGNames::operatorAttr);
   1158         animatableAttributes.add(SVGNames::orderAttr);
   1159         animatableAttributes.add(SVGNames::orientAttr);
   1160         animatableAttributes.add(SVGNames::pathLengthAttr);
   1161         animatableAttributes.add(SVGNames::patternContentUnitsAttr);
   1162         animatableAttributes.add(SVGNames::patternTransformAttr);
   1163         animatableAttributes.add(SVGNames::patternUnitsAttr);
   1164         animatableAttributes.add(SVGNames::pointsAtXAttr);
   1165         animatableAttributes.add(SVGNames::pointsAtYAttr);
   1166         animatableAttributes.add(SVGNames::pointsAtZAttr);
   1167         animatableAttributes.add(SVGNames::preserveAlphaAttr);
   1168         animatableAttributes.add(SVGNames::preserveAspectRatioAttr);
   1169         animatableAttributes.add(SVGNames::primitiveUnitsAttr);
   1170         animatableAttributes.add(SVGNames::radiusAttr);
   1171         animatableAttributes.add(SVGNames::rAttr);
   1172         animatableAttributes.add(SVGNames::refXAttr);
   1173         animatableAttributes.add(SVGNames::refYAttr);
   1174         animatableAttributes.add(SVGNames::resultAttr);
   1175         animatableAttributes.add(SVGNames::rotateAttr);
   1176         animatableAttributes.add(SVGNames::rxAttr);
   1177         animatableAttributes.add(SVGNames::ryAttr);
   1178         animatableAttributes.add(SVGNames::scaleAttr);
   1179         animatableAttributes.add(SVGNames::seedAttr);
   1180         animatableAttributes.add(SVGNames::slopeAttr);
   1181         animatableAttributes.add(SVGNames::spacingAttr);
   1182         animatableAttributes.add(SVGNames::specularConstantAttr);
   1183         animatableAttributes.add(SVGNames::specularExponentAttr);
   1184         animatableAttributes.add(SVGNames::spreadMethodAttr);
   1185         animatableAttributes.add(SVGNames::startOffsetAttr);
   1186         animatableAttributes.add(SVGNames::stdDeviationAttr);
   1187         animatableAttributes.add(SVGNames::stitchTilesAttr);
   1188         animatableAttributes.add(SVGNames::surfaceScaleAttr);
   1189         animatableAttributes.add(SVGNames::tableValuesAttr);
   1190         animatableAttributes.add(SVGNames::targetAttr);
   1191         animatableAttributes.add(SVGNames::targetXAttr);
   1192         animatableAttributes.add(SVGNames::targetYAttr);
   1193         animatableAttributes.add(SVGNames::transformAttr);
   1194         animatableAttributes.add(SVGNames::typeAttr);
   1195         animatableAttributes.add(SVGNames::valuesAttr);
   1196         animatableAttributes.add(SVGNames::viewBoxAttr);
   1197         animatableAttributes.add(SVGNames::widthAttr);
   1198         animatableAttributes.add(SVGNames::x1Attr);
   1199         animatableAttributes.add(SVGNames::x2Attr);
   1200         animatableAttributes.add(SVGNames::xAttr);
   1201         animatableAttributes.add(SVGNames::xChannelSelectorAttr);
   1202         animatableAttributes.add(SVGNames::y1Attr);
   1203         animatableAttributes.add(SVGNames::y2Attr);
   1204         animatableAttributes.add(SVGNames::yAttr);
   1205         animatableAttributes.add(SVGNames::yChannelSelectorAttr);
   1206         animatableAttributes.add(SVGNames::zAttr);
   1207     }
   1208 
   1209     if (name == classAttr)
   1210         return true;
   1211 
   1212     return animatableAttributes.contains(name);
   1213 }
   1214 #endif
   1215 
   1216 }
   1217