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