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 
      7     This library is free software; you can redistribute it and/or
      8     modify it under the terms of the GNU Library General Public
      9     License as published by the Free Software Foundation; either
     10     version 2 of the License, or (at your option) any later version.
     11 
     12     This library is distributed in the hope that it will be useful,
     13     but WITHOUT ANY WARRANTY; without even the implied warranty of
     14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15     Library General Public License for more details.
     16 
     17     You should have received a copy of the GNU Library General Public License
     18     along with this library; see the file COPYING.LIB.  If not, write to
     19     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20     Boston, MA 02110-1301, USA.
     21 */
     22 
     23 #include "config.h"
     24 
     25 #if ENABLE(SVG) && ENABLE(FILTERS)
     26 #include "SVGFilterElement.h"
     27 
     28 #include "Attr.h"
     29 #include "FloatSize.h"
     30 #include "MappedAttribute.h"
     31 #include "PlatformString.h"
     32 #include "SVGFilterBuilder.h"
     33 #include "SVGFilterPrimitiveStandardAttributes.h"
     34 #include "SVGLength.h"
     35 #include "SVGNames.h"
     36 #include "SVGParserUtilities.h"
     37 #include "SVGResourceFilter.h"
     38 #include "SVGUnitTypes.h"
     39 
     40 namespace WebCore {
     41 
     42 char SVGFilterResXIdentifier[] = "SVGFilterResX";
     43 char SVGFilterResYIdentifier[] = "SVGFilterResY";
     44 
     45 SVGFilterElement::SVGFilterElement(const QualifiedName& tagName, Document* doc)
     46     : SVGStyledElement(tagName, doc)
     47     , SVGURIReference()
     48     , SVGLangSpace()
     49     , SVGExternalResourcesRequired()
     50     , m_filterUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
     51     , m_primitiveUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
     52     , m_x(LengthModeWidth, "-10%")
     53     , m_y(LengthModeHeight, "-10%")
     54     , m_width(LengthModeWidth, "120%")
     55     , m_height(LengthModeHeight, "120%")
     56 {
     57     // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
     58     // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
     59 }
     60 
     61 SVGFilterElement::~SVGFilterElement()
     62 {
     63 }
     64 
     65 void SVGFilterElement::setFilterRes(unsigned long, unsigned long) const
     66 {
     67 }
     68 
     69 void SVGFilterElement::parseMappedAttribute(MappedAttribute* attr)
     70 {
     71     const String& value = attr->value();
     72     if (attr->name() == SVGNames::filterUnitsAttr) {
     73         if (value == "userSpaceOnUse")
     74             setFilterUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
     75         else if (value == "objectBoundingBox")
     76             setFilterUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
     77     } else if (attr->name() == SVGNames::primitiveUnitsAttr) {
     78         if (value == "userSpaceOnUse")
     79             setPrimitiveUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
     80         else if (value == "objectBoundingBox")
     81             setPrimitiveUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
     82     } else if (attr->name() == SVGNames::xAttr)
     83         setXBaseValue(SVGLength(LengthModeWidth, value));
     84     else if (attr->name() == SVGNames::yAttr)
     85         setYBaseValue(SVGLength(LengthModeHeight, value));
     86     else if (attr->name() == SVGNames::widthAttr)
     87         setWidthBaseValue(SVGLength(LengthModeWidth, value));
     88     else if (attr->name() == SVGNames::heightAttr)
     89         setHeightBaseValue(SVGLength(LengthModeHeight, value));
     90     else if (attr->name() == SVGNames::filterResAttr) {
     91         float x, y;
     92         if (parseNumberOptionalNumber(value, x, y)) {
     93             setFilterResXBaseValue(x);
     94             setFilterResYBaseValue(y);
     95         }
     96     } else {
     97         if (SVGURIReference::parseMappedAttribute(attr))
     98             return;
     99         if (SVGLangSpace::parseMappedAttribute(attr))
    100             return;
    101         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
    102             return;
    103 
    104         SVGStyledElement::parseMappedAttribute(attr);
    105     }
    106 }
    107 
    108 void SVGFilterElement::synchronizeProperty(const QualifiedName& attrName)
    109 {
    110     SVGStyledElement::synchronizeProperty(attrName);
    111 
    112     if (attrName == anyQName()) {
    113         synchronizeX();
    114         synchronizeY();
    115         synchronizeWidth();
    116         synchronizeHeight();
    117         synchronizeFilterUnits();
    118         synchronizePrimitiveUnits();
    119         synchronizeFilterResX();
    120         synchronizeFilterResY();
    121         synchronizeExternalResourcesRequired();
    122         synchronizeHref();
    123         return;
    124     }
    125 
    126     if (attrName == SVGNames::xAttr)
    127         synchronizeX();
    128     else if (attrName == SVGNames::yAttr)
    129         synchronizeY();
    130     else if (attrName == SVGNames::widthAttr)
    131         synchronizeWidth();
    132     else if (attrName == SVGNames::heightAttr)
    133         synchronizeHeight();
    134     else if (attrName == SVGNames::filterUnitsAttr)
    135         synchronizeFilterUnits();
    136     else if (attrName == SVGNames::primitiveUnitsAttr)
    137         synchronizePrimitiveUnits();
    138     else if (attrName == SVGNames::filterResAttr) {
    139         synchronizeFilterResX();
    140         synchronizeFilterResY();
    141     } else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
    142         synchronizeExternalResourcesRequired();
    143     else if (SVGURIReference::isKnownAttribute(attrName))
    144         synchronizeHref();
    145 }
    146 
    147 FloatRect SVGFilterElement::filterBoundingBox(const FloatRect& objectBoundingBox) const
    148 {
    149     FloatRect filterBBox;
    150     if (filterUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
    151         filterBBox = FloatRect(x().valueAsPercentage() * objectBoundingBox.width() + objectBoundingBox.x(),
    152                                y().valueAsPercentage() * objectBoundingBox.height() + objectBoundingBox.y(),
    153                                width().valueAsPercentage() * objectBoundingBox.width(),
    154                                height().valueAsPercentage() * objectBoundingBox.height());
    155     else
    156         filterBBox = FloatRect(x().value(this),
    157                                y().value(this),
    158                                width().value(this),
    159                                height().value(this));
    160 
    161     return filterBBox;
    162 }
    163 
    164 void SVGFilterElement::buildFilter(const FloatRect& targetRect) const
    165 {
    166     bool filterBBoxMode = filterUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
    167     bool primitiveBBoxMode = primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
    168 
    169     FloatRect filterBBox;
    170     if (filterBBoxMode)
    171         filterBBox = FloatRect(x().valueAsPercentage(),
    172                                y().valueAsPercentage(),
    173                                width().valueAsPercentage(),
    174                                height().valueAsPercentage());
    175     else
    176         filterBBox = FloatRect(x().value(this),
    177                                y().value(this),
    178                                width().value(this),
    179                                height().value(this));
    180 
    181     FloatRect filterRect = filterBBox;
    182     if (filterBBoxMode)
    183         filterRect = FloatRect(targetRect.x() + filterRect.x() * targetRect.width(),
    184                                targetRect.y() + filterRect.y() * targetRect.height(),
    185                                filterRect.width() * targetRect.width(),
    186                                filterRect.height() * targetRect.height());
    187 
    188     m_filter->setFilterBoundingBox(filterRect);
    189     m_filter->setFilterRect(filterBBox);
    190     m_filter->setEffectBoundingBoxMode(primitiveBBoxMode);
    191     m_filter->setFilterBoundingBoxMode(filterBBoxMode);
    192 
    193     if (hasAttribute(SVGNames::filterResAttr)) {
    194         m_filter->setHasFilterResolution(true);
    195         m_filter->setFilterResolution(FloatSize(filterResX(), filterResY()));
    196     }
    197 
    198     // Add effects to the filter
    199     m_filter->builder()->clearEffects();
    200     for (Node* n = firstChild(); n != 0; n = n->nextSibling()) {
    201         SVGElement* element = 0;
    202         if (n->isSVGElement()) {
    203             element = static_cast<SVGElement*>(n);
    204             if (element->isFilterEffect()) {
    205                 SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element);
    206                 if (!effectElement->build(m_filter.get())) {
    207                     m_filter->builder()->clearEffects();
    208                     break;
    209                 }
    210             }
    211         }
    212     }
    213 }
    214 
    215 SVGResource* SVGFilterElement::canvasResource(const RenderObject*)
    216 {
    217     if (!attached())
    218         return 0;
    219 
    220     if (!m_filter)
    221         m_filter = SVGResourceFilter::create(this);
    222     return m_filter.get();
    223 }
    224 
    225 }
    226 
    227 #endif // ENABLE(SVG) && ENABLE(FILTERS)
    228