Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2006 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2006 Samuel Weinig <sam.weinig (at) gmail.com>
      5  * Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org>
      6  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Library General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Library General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along with this library; see the file COPYING.LIB.  If not, write to
     20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21  * Boston, MA 02110-1301, USA.
     22  */
     23 
     24 #include "config.h"
     25 
     26 #if ENABLE(SVG) && ENABLE(FILTERS)
     27 #include "SVGFilterElement.h"
     28 
     29 #include "Attr.h"
     30 #include "RenderSVGResourceFilter.h"
     31 #include "SVGFilterBuilder.h"
     32 #include "SVGFilterPrimitiveStandardAttributes.h"
     33 #include "SVGNames.h"
     34 #include "SVGParserUtilities.h"
     35 #include "SVGUnitTypes.h"
     36 
     37 namespace WebCore {
     38 
     39 // Animated property definitions
     40 DEFINE_ANIMATED_ENUMERATION(SVGFilterElement, SVGNames::filterUnitsAttr, FilterUnits, filterUnits)
     41 DEFINE_ANIMATED_ENUMERATION(SVGFilterElement, SVGNames::primitiveUnitsAttr, PrimitiveUnits, primitiveUnits)
     42 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::xAttr, X, x)
     43 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::yAttr, Y, y)
     44 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::widthAttr, Width, width)
     45 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::heightAttr, Height, height)
     46 DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFilterElement, SVGNames::filterResAttr, filterResXIdentifier(), FilterResX, filterResX)
     47 DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFilterElement, SVGNames::filterResAttr, filterResYIdentifier(), FilterResY, filterResY)
     48 DEFINE_ANIMATED_STRING(SVGFilterElement, XLinkNames::hrefAttr, Href, href)
     49 DEFINE_ANIMATED_BOOLEAN(SVGFilterElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
     50 
     51 inline SVGFilterElement::SVGFilterElement(const QualifiedName& tagName, Document* document)
     52     : SVGStyledElement(tagName, document)
     53     , SVGURIReference()
     54     , SVGLangSpace()
     55     , SVGExternalResourcesRequired()
     56     , m_filterUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
     57     , m_primitiveUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
     58     , m_x(LengthModeWidth, "-10%")
     59     , m_y(LengthModeHeight, "-10%")
     60     , m_width(LengthModeWidth, "120%")
     61     , m_height(LengthModeHeight, "120%")
     62 {
     63     // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
     64     // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
     65 }
     66 
     67 PassRefPtr<SVGFilterElement> SVGFilterElement::create(const QualifiedName& tagName, Document* document)
     68 {
     69     return adoptRef(new SVGFilterElement(tagName, document));
     70 }
     71 
     72 const AtomicString& SVGFilterElement::filterResXIdentifier()
     73 {
     74     DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGFilterResX"));
     75     return s_identifier;
     76 }
     77 
     78 const AtomicString& SVGFilterElement::filterResYIdentifier()
     79 {
     80     DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGFilterResY"));
     81     return s_identifier;
     82 }
     83 
     84 void SVGFilterElement::setFilterRes(unsigned long filterResX, unsigned long filterResY)
     85 {
     86     setFilterResXBaseValue(filterResX);
     87     setFilterResYBaseValue(filterResY);
     88 
     89     if (RenderObject* object = renderer())
     90         object->setNeedsLayout(true);
     91 }
     92 
     93 void SVGFilterElement::parseMappedAttribute(Attribute* attr)
     94 {
     95     const String& value = attr->value();
     96     if (attr->name() == SVGNames::filterUnitsAttr) {
     97         if (value == "userSpaceOnUse")
     98             setFilterUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
     99         else if (value == "objectBoundingBox")
    100             setFilterUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
    101     } else if (attr->name() == SVGNames::primitiveUnitsAttr) {
    102         if (value == "userSpaceOnUse")
    103             setPrimitiveUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
    104         else if (value == "objectBoundingBox")
    105             setPrimitiveUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
    106     } else if (attr->name() == SVGNames::xAttr)
    107         setXBaseValue(SVGLength(LengthModeWidth, value));
    108     else if (attr->name() == SVGNames::yAttr)
    109         setYBaseValue(SVGLength(LengthModeHeight, value));
    110     else if (attr->name() == SVGNames::widthAttr)
    111         setWidthBaseValue(SVGLength(LengthModeWidth, value));
    112     else if (attr->name() == SVGNames::heightAttr)
    113         setHeightBaseValue(SVGLength(LengthModeHeight, value));
    114     else if (attr->name() == SVGNames::filterResAttr) {
    115         float x, y;
    116         if (parseNumberOptionalNumber(value, x, y)) {
    117             setFilterResXBaseValue(x);
    118             setFilterResYBaseValue(y);
    119         }
    120     } else {
    121         if (SVGURIReference::parseMappedAttribute(attr))
    122             return;
    123         if (SVGLangSpace::parseMappedAttribute(attr))
    124             return;
    125         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
    126             return;
    127 
    128         SVGStyledElement::parseMappedAttribute(attr);
    129     }
    130 }
    131 
    132 void SVGFilterElement::svgAttributeChanged(const QualifiedName& attrName)
    133 {
    134     SVGStyledElement::svgAttributeChanged(attrName);
    135 
    136     bool invalidateClients = false;
    137     if (attrName == SVGNames::xAttr
    138         || attrName == SVGNames::yAttr
    139         || attrName == SVGNames::widthAttr
    140         || attrName == SVGNames::heightAttr) {
    141         invalidateClients = true;
    142         updateRelativeLengthsInformation();
    143     }
    144 
    145     RenderObject* object = renderer();
    146     if (!object)
    147         return;
    148 
    149     if (invalidateClients
    150         || attrName == SVGNames::filterUnitsAttr
    151         || attrName == SVGNames::primitiveUnitsAttr
    152         || attrName == SVGNames::filterResAttr
    153         || SVGStyledElement::isKnownAttribute(attrName)
    154         || SVGURIReference::isKnownAttribute(attrName)
    155         || SVGLangSpace::isKnownAttribute(attrName)
    156         || SVGExternalResourcesRequired::isKnownAttribute(attrName))
    157         object->setNeedsLayout(true);
    158 }
    159 
    160 void SVGFilterElement::synchronizeProperty(const QualifiedName& attrName)
    161 {
    162     SVGStyledElement::synchronizeProperty(attrName);
    163 
    164     if (attrName == anyQName()) {
    165         synchronizeX();
    166         synchronizeY();
    167         synchronizeWidth();
    168         synchronizeHeight();
    169         synchronizeFilterUnits();
    170         synchronizePrimitiveUnits();
    171         synchronizeFilterResX();
    172         synchronizeFilterResY();
    173         synchronizeExternalResourcesRequired();
    174         synchronizeHref();
    175         return;
    176     }
    177 
    178     if (attrName == SVGNames::xAttr)
    179         synchronizeX();
    180     else if (attrName == SVGNames::yAttr)
    181         synchronizeY();
    182     else if (attrName == SVGNames::widthAttr)
    183         synchronizeWidth();
    184     else if (attrName == SVGNames::heightAttr)
    185         synchronizeHeight();
    186     else if (attrName == SVGNames::filterUnitsAttr)
    187         synchronizeFilterUnits();
    188     else if (attrName == SVGNames::primitiveUnitsAttr)
    189         synchronizePrimitiveUnits();
    190     else if (attrName == SVGNames::filterResAttr) {
    191         synchronizeFilterResX();
    192         synchronizeFilterResY();
    193     } else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
    194         synchronizeExternalResourcesRequired();
    195     else if (SVGURIReference::isKnownAttribute(attrName))
    196         synchronizeHref();
    197 }
    198 
    199 AttributeToPropertyTypeMap& SVGFilterElement::attributeToPropertyTypeMap()
    200 {
    201     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
    202     return s_attributeToPropertyTypeMap;
    203 }
    204 
    205 void SVGFilterElement::fillAttributeToPropertyTypeMap()
    206 {
    207     AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap();
    208 
    209     SVGStyledElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap);
    210     attributeToPropertyTypeMap.set(SVGNames::filterUnitsAttr, AnimatedEnumeration);
    211     attributeToPropertyTypeMap.set(SVGNames::primitiveUnitsAttr, AnimatedEnumeration);
    212     attributeToPropertyTypeMap.set(SVGNames::xAttr, AnimatedLength);
    213     attributeToPropertyTypeMap.set(SVGNames::yAttr, AnimatedLength);
    214     attributeToPropertyTypeMap.set(SVGNames::widthAttr, AnimatedLength);
    215     attributeToPropertyTypeMap.set(SVGNames::heightAttr, AnimatedLength);
    216     attributeToPropertyTypeMap.set(SVGNames::filterResAttr, AnimatedNumberOptionalNumber);
    217     attributeToPropertyTypeMap.set(XLinkNames::hrefAttr, AnimatedString);
    218 }
    219 
    220 void SVGFilterElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    221 {
    222     SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    223 
    224     if (changedByParser)
    225         return;
    226 
    227     if (RenderObject* object = renderer())
    228         object->setNeedsLayout(true);
    229 }
    230 
    231 FloatRect SVGFilterElement::filterBoundingBox(const FloatRect& objectBoundingBox) const
    232 {
    233     FloatRect filterBBox;
    234     if (filterUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
    235         filterBBox = FloatRect(x().valueAsPercentage() * objectBoundingBox.width() + objectBoundingBox.x(),
    236                                y().valueAsPercentage() * objectBoundingBox.height() + objectBoundingBox.y(),
    237                                width().valueAsPercentage() * objectBoundingBox.width(),
    238                                height().valueAsPercentage() * objectBoundingBox.height());
    239     else
    240         filterBBox = FloatRect(x().value(this),
    241                                y().value(this),
    242                                width().value(this),
    243                                height().value(this));
    244 
    245     return filterBBox;
    246 }
    247 
    248 RenderObject* SVGFilterElement::createRenderer(RenderArena* arena, RenderStyle*)
    249 {
    250     return new (arena) RenderSVGResourceFilter(this);
    251 }
    252 
    253 bool SVGFilterElement::selfHasRelativeLengths() const
    254 {
    255     return x().isRelative()
    256         || y().isRelative()
    257         || width().isRelative()
    258         || height().isRelative();
    259 }
    260 
    261 }
    262 
    263 #endif
    264