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, 2007, 2008 Rob Buis <buis (at) kde.org>
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  */
     20 
     21 #include "config.h"
     22 
     23 #if ENABLE(SVG)
     24 #include "SVGStyledElement.h"
     25 
     26 #include "Attr.h"
     27 #include "CSSParser.h"
     28 #include "CSSStyleSelector.h"
     29 #include "Document.h"
     30 #include "HTMLNames.h"
     31 #include "PlatformString.h"
     32 #include "RenderObject.h"
     33 #include "RenderSVGResource.h"
     34 #include "RenderSVGResourceClipper.h"
     35 #include "RenderSVGResourceFilter.h"
     36 #include "RenderSVGResourceMasker.h"
     37 #include "SVGElement.h"
     38 #include "SVGElementInstance.h"
     39 #include "SVGElementRareData.h"
     40 #include "SVGNames.h"
     41 #include "SVGRenderStyle.h"
     42 #include "SVGRenderSupport.h"
     43 #include "SVGSVGElement.h"
     44 #include "SVGUseElement.h"
     45 #include <wtf/Assertions.h>
     46 #include <wtf/HashMap.h>
     47 
     48 namespace WebCore {
     49 
     50 // Animated property definitions
     51 DEFINE_ANIMATED_STRING(SVGStyledElement, HTMLNames::classAttr, ClassName, className)
     52 
     53 using namespace SVGNames;
     54 
     55 void mapAttributeToCSSProperty(HashMap<AtomicStringImpl*, int>* propertyNameToIdMap, const QualifiedName& attrName)
     56 {
     57     int propertyId = cssPropertyID(attrName.localName());
     58     ASSERT(propertyId > 0);
     59     propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
     60 }
     61 
     62 SVGStyledElement::SVGStyledElement(const QualifiedName& tagName, Document* document)
     63     : SVGElement(tagName, document)
     64 {
     65 }
     66 
     67 SVGStyledElement::~SVGStyledElement()
     68 {
     69 }
     70 
     71 String SVGStyledElement::title() const
     72 {
     73     // According to spec, we should not return titles when hovering over root <svg> elements (those
     74     // <title> elements are the title of the document, not a tooltip) so we instantly return.
     75     if (hasTagName(SVGNames::svgTag)) {
     76         const SVGSVGElement* svg = static_cast<const SVGSVGElement*>(this);
     77         if (svg->isOutermostSVG())
     78             return String();
     79     }
     80 
     81     // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title.
     82     Node* parent = const_cast<SVGStyledElement*>(this);
     83     while (parent) {
     84         if (!parent->isSVGShadowRoot()) {
     85             parent = parent->parentNodeGuaranteedHostFree();
     86             continue;
     87         }
     88 
     89         // Get the <use> element.
     90         Element* shadowParent = parent->svgShadowHost();
     91         if (shadowParent && shadowParent->isSVGElement() && shadowParent->hasTagName(SVGNames::useTag)) {
     92             SVGUseElement* useElement = static_cast<SVGUseElement*>(shadowParent);
     93             // If the <use> title is not empty we found the title to use.
     94             String useTitle(useElement->title());
     95             if (useTitle.isEmpty())
     96                 break;
     97             return useTitle;
     98         }
     99         parent = parent->parentNode();
    100     }
    101 
    102     // If we aren't an instance in a <use> or the <use> title was not found, then find the first
    103     // <title> child of this element.
    104     Element* titleElement = firstElementChild();
    105     for (; titleElement; titleElement = titleElement->nextElementSibling()) {
    106         if (titleElement->hasTagName(SVGNames::titleTag) && titleElement->isSVGElement())
    107             break;
    108     }
    109 
    110     // If a title child was found, return the text contents.
    111     if (titleElement)
    112         return titleElement->innerText();
    113 
    114     // Otherwise return a null/empty string.
    115     return String();
    116 }
    117 
    118 bool SVGStyledElement::rendererIsNeeded(RenderStyle* style)
    119 {
    120     // http://www.w3.org/TR/SVG/extend.html#PrivateData
    121     // Prevent anything other than SVG renderers from appearing in our render tree
    122     // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
    123     // with the SVG content. In general, the SVG user agent will include the unknown
    124     // elements in the DOM but will otherwise ignore unknown elements.
    125     if (!parentNode() || parentNode()->isSVGElement())
    126         return StyledElement::rendererIsNeeded(style);
    127 
    128     return false;
    129 }
    130 
    131 int SVGStyledElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
    132 {
    133     if (!attrName.namespaceURI().isNull())
    134         return 0;
    135 
    136     static HashMap<AtomicStringImpl*, int>* propertyNameToIdMap = 0;
    137     if (!propertyNameToIdMap) {
    138         propertyNameToIdMap = new HashMap<AtomicStringImpl*, int>;
    139         // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
    140         mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr);
    141         mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr);
    142         mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr);
    143         mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr);
    144         mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr);
    145         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::colorAttr);
    146         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr);
    147         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr);
    148         mapAttributeToCSSProperty(propertyNameToIdMap, color_profileAttr);
    149         mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr);
    150         mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr);
    151         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::directionAttr);
    152         mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr);
    153         mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr);
    154         mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr);
    155         mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr);
    156         mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr);
    157         mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr);
    158         mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr);
    159         mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr);
    160         mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr);
    161         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
    162         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
    163         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
    164         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
    165         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
    166         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
    167         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr);
    168         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr);
    169         mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr);
    170         mapAttributeToCSSProperty(propertyNameToIdMap, kerningAttr);
    171         mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr);
    172         mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr);
    173         mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr);
    174         mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr);
    175         mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr);
    176         mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr);
    177         mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr);
    178         mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr);
    179         mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr);
    180         mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr);
    181         mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr);
    182         mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr);
    183         mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr);
    184         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr);
    185         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr);
    186         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr);
    187         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr);
    188         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr);
    189         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr);
    190         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr);
    191         mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr);
    192         mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr);
    193         mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr);
    194         mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr);
    195         mapAttributeToCSSProperty(propertyNameToIdMap, vector_effectAttr);
    196         mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr);
    197         mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr);
    198         mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr);
    199     }
    200 
    201     return propertyNameToIdMap->get(attrName.localName().impl());
    202 }
    203 
    204 static inline AttributeToPropertyTypeMap& cssPropertyToTypeMap()
    205 {
    206     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_cssPropertyMap, ());
    207 
    208     if (!s_cssPropertyMap.isEmpty())
    209         return s_cssPropertyMap;
    210 
    211     // Fill the map for the first use.
    212     s_cssPropertyMap.set(alignment_baselineAttr, AnimatedString);
    213     s_cssPropertyMap.set(baseline_shiftAttr, AnimatedString);
    214     s_cssPropertyMap.set(clipAttr, AnimatedRect);
    215     s_cssPropertyMap.set(clip_pathAttr, AnimatedString);
    216     s_cssPropertyMap.set(clip_ruleAttr, AnimatedString);
    217     s_cssPropertyMap.set(SVGNames::colorAttr, AnimatedColor);
    218     s_cssPropertyMap.set(color_interpolationAttr, AnimatedString);
    219     s_cssPropertyMap.set(color_interpolation_filtersAttr, AnimatedString);
    220     s_cssPropertyMap.set(color_profileAttr, AnimatedString);
    221     s_cssPropertyMap.set(color_renderingAttr, AnimatedString);
    222     s_cssPropertyMap.set(cursorAttr, AnimatedString);
    223     s_cssPropertyMap.set(displayAttr, AnimatedString);
    224     s_cssPropertyMap.set(dominant_baselineAttr, AnimatedString);
    225     s_cssPropertyMap.set(fillAttr, AnimatedColor);
    226     s_cssPropertyMap.set(fill_opacityAttr, AnimatedNumber);
    227     s_cssPropertyMap.set(fill_ruleAttr, AnimatedString);
    228     s_cssPropertyMap.set(filterAttr, AnimatedString);
    229     s_cssPropertyMap.set(flood_colorAttr, AnimatedColor);
    230     s_cssPropertyMap.set(flood_opacityAttr, AnimatedNumber);
    231     s_cssPropertyMap.set(font_familyAttr, AnimatedString);
    232     s_cssPropertyMap.set(font_sizeAttr, AnimatedLength);
    233     s_cssPropertyMap.set(font_stretchAttr, AnimatedString);
    234     s_cssPropertyMap.set(font_styleAttr, AnimatedString);
    235     s_cssPropertyMap.set(font_variantAttr, AnimatedString);
    236     s_cssPropertyMap.set(font_weightAttr, AnimatedString);
    237     s_cssPropertyMap.set(image_renderingAttr, AnimatedString);
    238     s_cssPropertyMap.set(kerningAttr, AnimatedLength);
    239     s_cssPropertyMap.set(letter_spacingAttr, AnimatedLength);
    240     s_cssPropertyMap.set(lighting_colorAttr, AnimatedColor);
    241     s_cssPropertyMap.set(marker_endAttr, AnimatedString);
    242     s_cssPropertyMap.set(marker_midAttr, AnimatedString);
    243     s_cssPropertyMap.set(marker_startAttr, AnimatedString);
    244     s_cssPropertyMap.set(maskAttr, AnimatedString);
    245     s_cssPropertyMap.set(opacityAttr, AnimatedNumber);
    246     s_cssPropertyMap.set(overflowAttr, AnimatedString);
    247     s_cssPropertyMap.set(pointer_eventsAttr, AnimatedString);
    248     s_cssPropertyMap.set(shape_renderingAttr, AnimatedString);
    249     s_cssPropertyMap.set(stop_colorAttr, AnimatedColor);
    250     s_cssPropertyMap.set(stop_opacityAttr, AnimatedNumber);
    251     s_cssPropertyMap.set(strokeAttr, AnimatedColor);
    252     s_cssPropertyMap.set(stroke_dasharrayAttr, AnimatedLengthList);
    253     s_cssPropertyMap.set(stroke_dashoffsetAttr, AnimatedLength);
    254     s_cssPropertyMap.set(stroke_linecapAttr, AnimatedString);
    255     s_cssPropertyMap.set(stroke_linejoinAttr, AnimatedString);
    256     s_cssPropertyMap.set(stroke_miterlimitAttr, AnimatedNumber);
    257     s_cssPropertyMap.set(stroke_opacityAttr, AnimatedNumber);
    258     s_cssPropertyMap.set(stroke_widthAttr, AnimatedLength);
    259     s_cssPropertyMap.set(text_anchorAttr, AnimatedString);
    260     s_cssPropertyMap.set(text_decorationAttr, AnimatedString);
    261     s_cssPropertyMap.set(text_renderingAttr, AnimatedString);
    262     s_cssPropertyMap.set(vector_effectAttr, AnimatedString);
    263     s_cssPropertyMap.set(visibilityAttr, AnimatedString);
    264     s_cssPropertyMap.set(word_spacingAttr, AnimatedLength);
    265     return s_cssPropertyMap;
    266 }
    267 
    268 AnimatedAttributeType SVGStyledElement::animatedPropertyTypeForCSSProperty(const QualifiedName& attrName)
    269 {
    270     AttributeToPropertyTypeMap& cssPropertyTypeMap = cssPropertyToTypeMap();
    271     if (cssPropertyTypeMap.contains(attrName))
    272         return cssPropertyTypeMap.get(attrName);
    273     return AnimatedUnknown;
    274 }
    275 
    276 bool SVGStyledElement::isAnimatableCSSProperty(const QualifiedName& attrName)
    277 {
    278     return cssPropertyToTypeMap().contains(attrName);
    279 }
    280 
    281 void SVGStyledElement::fillPassedAttributeToPropertyTypeMap(AttributeToPropertyTypeMap& attributeToPropertyTypeMap)
    282 {
    283     attributeToPropertyTypeMap.set(HTMLNames::classAttr, AnimatedString);
    284 }
    285 
    286 bool SVGStyledElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
    287 {
    288     if (SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName) > 0) {
    289         result = eSVG;
    290         return false;
    291     }
    292     return SVGElement::mapToEntry(attrName, result);
    293 }
    294 
    295 void SVGStyledElement::parseMappedAttribute(Attribute* attr)
    296 {
    297     const QualifiedName& attrName = attr->name();
    298     // NOTE: Any subclass which overrides parseMappedAttribute for a property handled by
    299     // cssPropertyIdForSVGAttributeName will also have to override mapToEntry to disable the default eSVG mapping
    300     int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName);
    301     if (propId > 0) {
    302         addCSSProperty(attr, propId, attr->value());
    303         setNeedsStyleRecalc();
    304         return;
    305     }
    306 
    307     // SVG animation has currently requires special storage of values so we set
    308     // the className here.  svgAttributeChanged actually causes the resulting
    309     // style updates (instead of StyledElement::parseMappedAttribute). We don't
    310     // tell StyledElement about the change to avoid parsing the class list twice
    311     if (attrName.matches(HTMLNames::classAttr))
    312         setClassNameBaseValue(attr->value());
    313     else
    314         // id is handled by StyledElement which SVGElement inherits from
    315         SVGElement::parseMappedAttribute(attr);
    316 }
    317 
    318 bool SVGStyledElement::isKnownAttribute(const QualifiedName& attrName)
    319 {
    320     return isIdAttributeName(attrName);
    321 }
    322 
    323 void SVGStyledElement::svgAttributeChanged(const QualifiedName& attrName)
    324 {
    325     SVGElement::svgAttributeChanged(attrName);
    326 
    327     if (attrName.matches(HTMLNames::classAttr))
    328         classAttributeChanged(className());
    329 
    330     RenderObject* object = renderer();
    331 
    332     if (isIdAttributeName(attrName)) {
    333         // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
    334         if (object && object->isSVGResourceContainer())
    335             object->toRenderSVGResourceContainer()->idChanged();
    336     }
    337 
    338     // Invalidate all SVGElementInstances associated with us
    339     SVGElementInstance::invalidateAllInstancesOfElement(this);
    340 }
    341 
    342 void SVGStyledElement::synchronizeProperty(const QualifiedName& attrName)
    343 {
    344     SVGElement::synchronizeProperty(attrName);
    345 
    346     if (attrName == anyQName() || attrName.matches(HTMLNames::classAttr))
    347         synchronizeClassName();
    348 }
    349 
    350 void SVGStyledElement::attach()
    351 {
    352     SVGElement::attach();
    353 
    354     if (RenderObject* object = renderer())
    355         object->updateFromElement();
    356 }
    357 
    358 void SVGStyledElement::insertedIntoDocument()
    359 {
    360     SVGElement::insertedIntoDocument();
    361     updateRelativeLengthsInformation();
    362 }
    363 
    364 void SVGStyledElement::removedFromDocument()
    365 {
    366     updateRelativeLengthsInformation(false, this);
    367     SVGElement::removedFromDocument();
    368 }
    369 
    370 void SVGStyledElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    371 {
    372     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    373 
    374     // Invalidate all SVGElementInstances associated with us
    375     if (!changedByParser)
    376         SVGElementInstance::invalidateAllInstancesOfElement(this);
    377 }
    378 
    379 PassRefPtr<RenderStyle> SVGStyledElement::resolveStyle(RenderStyle* parentStyle)
    380 {
    381     if (renderer())
    382         return renderer()->style();
    383     return document()->styleSelector()->styleForElement(this, parentStyle);
    384 }
    385 
    386 PassRefPtr<CSSValue> SVGStyledElement::getPresentationAttribute(const String& name)
    387 {
    388     if (!attributeMap())
    389         return 0;
    390 
    391     QualifiedName attributeName(nullAtom, name, nullAtom);
    392     Attribute* attr = attributeMap()->getAttributeItem(attributeName);
    393     if (!attr || !attr->isMappedAttribute() || !attr->style())
    394         return 0;
    395 
    396     Attribute* cssSVGAttr = attr;
    397     // This function returns a pointer to a CSSValue which can be mutated from JavaScript.
    398     // If the associated MappedAttribute uses the same CSSMappedAttributeDeclaration
    399     // as StyledElement's mappedAttributeDecls cache, create a new CSSMappedAttributeDeclaration
    400     // before returning so that any modifications to the CSSValue will not affect other attributes.
    401     MappedAttributeEntry entry;
    402     mapToEntry(attributeName, entry);
    403     if (getMappedAttributeDecl(entry, cssSVGAttr) == cssSVGAttr->decl()) {
    404         cssSVGAttr->setDecl(0);
    405         int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(cssSVGAttr->name());
    406         addCSSProperty(cssSVGAttr, propId, cssSVGAttr->value());
    407     }
    408     return cssSVGAttr->style()->getPropertyCSSValue(name);
    409 }
    410 
    411 bool SVGStyledElement::instanceUpdatesBlocked() const
    412 {
    413     return hasRareSVGData() && rareSVGData()->instanceUpdatesBlocked();
    414 }
    415 
    416 void SVGStyledElement::setInstanceUpdatesBlocked(bool value)
    417 {
    418     if (hasRareSVGData())
    419         rareSVGData()->setInstanceUpdatesBlocked(value);
    420 }
    421 
    422 AffineTransform SVGStyledElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope) const
    423 {
    424     // To be overriden by SVGStyledLocatableElement/SVGStyledTransformableElement (or as special case SVGTextElement)
    425     ASSERT_NOT_REACHED();
    426     return AffineTransform();
    427 }
    428 
    429 void SVGStyledElement::updateRelativeLengthsInformation(bool hasRelativeLengths, SVGStyledElement* element)
    430 {
    431     // If we're not yet in a document, this function will be called again from insertedIntoDocument(). Do nothing now.
    432     if (!inDocument())
    433         return;
    434 
    435     // An element wants to notify us that its own relative lengths state changed.
    436     // Register it in the relative length map, and register us in the parent relative length map.
    437     // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.
    438 
    439     if (hasRelativeLengths)
    440         m_elementsWithRelativeLengths.add(element);
    441     else {
    442         if (!m_elementsWithRelativeLengths.contains(element)) {
    443             // We were never registered. Do nothing.
    444             return;
    445         }
    446 
    447         m_elementsWithRelativeLengths.remove(element);
    448     }
    449 
    450     // Find first styled parent node, and notify it that we've changed our relative length state.
    451     ContainerNode* node = parentNode();
    452     while (node) {
    453         if (!node->isSVGElement())
    454             break;
    455 
    456         SVGElement* element = static_cast<SVGElement*>(node);
    457         if (!element->isStyled()) {
    458             node = node->parentNode();
    459             continue;
    460         }
    461 
    462         // Register us in the parent element map.
    463         static_cast<SVGStyledElement*>(element)->updateRelativeLengthsInformation(hasRelativeLengths, this);
    464         break;
    465     }
    466 }
    467 
    468 }
    469 
    470 #endif // ENABLE(SVG)
    471