Home | History | Annotate | Download | only in svg
      1 /*
      2     Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3                   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 "CString.h"
     30 #include "Document.h"
     31 #include "HTMLNames.h"
     32 #include "MappedAttribute.h"
     33 #include "PlatformString.h"
     34 #include "RenderObject.h"
     35 #include "SVGElement.h"
     36 #include "SVGElementInstance.h"
     37 #include "SVGElementRareData.h"
     38 #include "SVGNames.h"
     39 #include "SVGRenderStyle.h"
     40 #include "SVGResourceClipper.h"
     41 #include "SVGResourceFilter.h"
     42 #include "SVGResourceMasker.h"
     43 #include "SVGSVGElement.h"
     44 #include <wtf/Assertions.h>
     45 
     46 namespace WebCore {
     47 
     48 using namespace SVGNames;
     49 
     50 void mapAttributeToCSSProperty(HashMap<AtomicStringImpl*, int>* propertyNameToIdMap, const QualifiedName& attrName)
     51 {
     52     int propertyId = cssPropertyID(attrName.localName());
     53     ASSERT(propertyId > 0);
     54     propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
     55 }
     56 
     57 SVGStyledElement::SVGStyledElement(const QualifiedName& tagName, Document* doc)
     58     : SVGElement(tagName, doc)
     59 {
     60 }
     61 
     62 SVGStyledElement::~SVGStyledElement()
     63 {
     64     SVGResource::removeClient(this);
     65 }
     66 
     67 bool SVGStyledElement::rendererIsNeeded(RenderStyle* style)
     68 {
     69     // http://www.w3.org/TR/SVG/extend.html#PrivateData
     70     // Prevent anything other than SVG renderers from appearing in our render tree
     71     // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
     72     // with the SVG content. In general, the SVG user agent will include the unknown
     73     // elements in the DOM but will otherwise ignore unknown elements.
     74     if (!parentNode() || parentNode()->isSVGElement())
     75         return StyledElement::rendererIsNeeded(style);
     76 
     77     return false;
     78 }
     79 
     80 int SVGStyledElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
     81 {
     82     if (!attrName.namespaceURI().isNull())
     83         return 0;
     84 
     85     static HashMap<AtomicStringImpl*, int>* propertyNameToIdMap = 0;
     86     if (!propertyNameToIdMap) {
     87         propertyNameToIdMap = new HashMap<AtomicStringImpl*, int>;
     88         // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
     89         mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr);
     90         mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr);
     91         mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr);
     92         mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr);
     93         mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr);
     94         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::colorAttr);
     95         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr);
     96         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr);
     97         mapAttributeToCSSProperty(propertyNameToIdMap, color_profileAttr);
     98         mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr);
     99         mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr);
    100         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::directionAttr);
    101         mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr);
    102         mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr);
    103         mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr);
    104         mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr);
    105         mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr);
    106         mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr);
    107         mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr);
    108         mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr);
    109         mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr);
    110         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
    111         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
    112         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
    113         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
    114         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
    115         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
    116         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr);
    117         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr);
    118         mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr);
    119         mapAttributeToCSSProperty(propertyNameToIdMap, kerningAttr);
    120         mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr);
    121         mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr);
    122         mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr);
    123         mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr);
    124         mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr);
    125         mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr);
    126         mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr);
    127         mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr);
    128         mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr);
    129         mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr);
    130         mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr);
    131         mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr);
    132         mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr);
    133         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr);
    134         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr);
    135         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr);
    136         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr);
    137         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr);
    138         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr);
    139         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr);
    140         mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr);
    141         mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr);
    142         mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr);
    143         mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr);
    144         mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr);
    145         mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr);
    146         mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr);
    147     }
    148 
    149     return propertyNameToIdMap->get(attrName.localName().impl());
    150 }
    151 
    152 bool SVGStyledElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
    153 {
    154     if (SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName) > 0) {
    155         result = eSVG;
    156         return false;
    157     }
    158     return SVGElement::mapToEntry(attrName, result);
    159 }
    160 
    161 void SVGStyledElement::parseMappedAttribute(MappedAttribute* attr)
    162 {
    163     const QualifiedName& attrName = attr->name();
    164     // NOTE: Any subclass which overrides parseMappedAttribute for a property handled by
    165     // cssPropertyIdForSVGAttributeName will also have to override mapToEntry to disable the default eSVG mapping
    166     int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName);
    167     if (propId > 0) {
    168         addCSSProperty(attr, propId, attr->value());
    169         setNeedsStyleRecalc();
    170         return;
    171     }
    172 
    173     // SVG animation has currently requires special storage of values so we set
    174     // the className here.  svgAttributeChanged actually causes the resulting
    175     // style updates (instead of StyledElement::parseMappedAttribute). We don't
    176     // tell StyledElement about the change to avoid parsing the class list twice
    177     if (attrName.matches(HTMLNames::classAttr))
    178         setClassNameBaseValue(attr->value());
    179     else
    180         // id is handled by StyledElement which SVGElement inherits from
    181         SVGElement::parseMappedAttribute(attr);
    182 }
    183 
    184 bool SVGStyledElement::isKnownAttribute(const QualifiedName& attrName)
    185 {
    186     // Recognize all style related SVG CSS properties
    187     int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName);
    188     if (propId > 0)
    189         return true;
    190 
    191     return (attrName == idAttributeName() || attrName == HTMLNames::styleAttr);
    192 }
    193 
    194 void SVGStyledElement::svgAttributeChanged(const QualifiedName& attrName)
    195 {
    196     SVGElement::svgAttributeChanged(attrName);
    197 
    198     if (attrName.matches(HTMLNames::classAttr))
    199         classAttributeChanged(className());
    200 
    201     // If we're the child of a resource element, be sure to invalidate it.
    202     invalidateResourcesInAncestorChain();
    203 
    204     // If the element is using resources, invalidate them.
    205     invalidateResources();
    206 
    207     // Invalidate all SVGElementInstances associated with us
    208     SVGElementInstance::invalidateAllInstancesOfElement(this);
    209 }
    210 
    211 void SVGStyledElement::synchronizeProperty(const QualifiedName& attrName)
    212 {
    213     SVGElement::synchronizeProperty(attrName);
    214 
    215     if (attrName == anyQName() || attrName.matches(HTMLNames::classAttr))
    216         synchronizeClassName();
    217 }
    218 
    219 void SVGStyledElement::invalidateResources()
    220 {
    221     RenderObject* object = renderer();
    222     if (!object)
    223         return;
    224 
    225     const SVGRenderStyle* svgStyle = object->style()->svgStyle();
    226     Document* document = this->document();
    227 
    228     if (document->parsing())
    229         return;
    230 
    231 #if ENABLE(FILTERS)
    232     SVGResourceFilter* filter = getFilterById(document, svgStyle->filter(), object);
    233     if (filter)
    234         filter->invalidate();
    235 #endif
    236 
    237     SVGResourceMasker* masker = getMaskerById(document, svgStyle->maskElement(), object);
    238     if (masker)
    239         masker->invalidate();
    240 
    241     SVGResourceClipper* clipper = getClipperById(document, svgStyle->clipPath(), object);
    242     if (clipper)
    243         clipper->invalidate();
    244 }
    245 
    246 void SVGStyledElement::invalidateResourcesInAncestorChain() const
    247 {
    248     Node* node = parentNode();
    249     while (node) {
    250         if (!node->isSVGElement())
    251             break;
    252 
    253         SVGElement* element = static_cast<SVGElement*>(node);
    254         if (SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(element->isStyled() ? element : 0))
    255             styledElement->invalidateCanvasResources();
    256 
    257         node = node->parentNode();
    258     }
    259 }
    260 
    261 void SVGStyledElement::invalidateCanvasResources()
    262 {
    263     if (SVGResource* resource = canvasResource(renderer()))
    264         resource->invalidate();
    265 }
    266 
    267 void SVGStyledElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    268 {
    269     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    270 
    271     // Invalidate all SVGElementInstances associated with us
    272     SVGElementInstance::invalidateAllInstancesOfElement(this);
    273 }
    274 
    275 PassRefPtr<RenderStyle> SVGStyledElement::resolveStyle(RenderStyle* parentStyle)
    276 {
    277     if (renderer())
    278         return renderer()->style();
    279     return document()->styleSelector()->styleForElement(this, parentStyle);
    280 }
    281 
    282 PassRefPtr<CSSValue> SVGStyledElement::getPresentationAttribute(const String& name)
    283 {
    284     if (!mappedAttributes())
    285         return 0;
    286 
    287     QualifiedName attributeName(nullAtom, name, nullAtom);
    288     Attribute* attr = mappedAttributes()->getAttributeItem(attributeName);
    289     if (!attr || !attr->isMappedAttribute() || !attr->style())
    290         return 0;
    291 
    292     MappedAttribute* cssSVGAttr = static_cast<MappedAttribute*>(attr);
    293     // This function returns a pointer to a CSSValue which can be mutated from JavaScript.
    294     // If the associated MappedAttribute uses the same CSSMappedAttributeDeclaration
    295     // as StyledElement's mappedAttributeDecls cache, create a new CSSMappedAttributeDeclaration
    296     // before returning so that any modifications to the CSSValue will not affect other attributes.
    297     MappedAttributeEntry entry;
    298     mapToEntry(attributeName, entry);
    299     if (getMappedAttributeDecl(entry, cssSVGAttr) == cssSVGAttr->decl()) {
    300         cssSVGAttr->setDecl(0);
    301         int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(cssSVGAttr->name());
    302         addCSSProperty(cssSVGAttr, propId, cssSVGAttr->value());
    303     }
    304     return cssSVGAttr->style()->getPropertyCSSValue(name);
    305 }
    306 
    307 void SVGStyledElement::detach()
    308 {
    309     SVGResource::removeClient(this);
    310     SVGElement::detach();
    311 }
    312 
    313 bool SVGStyledElement::instanceUpdatesBlocked() const
    314 {
    315     return hasRareSVGData() && rareSVGData()->instanceUpdatesBlocked();
    316 }
    317 
    318 void SVGStyledElement::setInstanceUpdatesBlocked(bool value)
    319 {
    320     if (hasRareSVGData())
    321         rareSVGData()->setInstanceUpdatesBlocked(value);
    322 }
    323 
    324 }
    325 
    326 #endif // ENABLE(SVG)
    327