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 #include "core/svg/SVGFilterElement.h"
     27 
     28 #include "XLinkNames.h"
     29 #include "core/rendering/svg/RenderSVGResourceFilter.h"
     30 #include "core/svg/SVGElementInstance.h"
     31 #include "core/svg/SVGParserUtilities.h"
     32 
     33 namespace WebCore {
     34 
     35 // Animated property definitions
     36 DEFINE_ANIMATED_ENUMERATION(SVGFilterElement, SVGNames::filterUnitsAttr, FilterUnits, filterUnits, SVGUnitTypes::SVGUnitType)
     37 DEFINE_ANIMATED_ENUMERATION(SVGFilterElement, SVGNames::primitiveUnitsAttr, PrimitiveUnits, primitiveUnits, SVGUnitTypes::SVGUnitType)
     38 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::xAttr, X, x)
     39 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::yAttr, Y, y)
     40 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::widthAttr, Width, width)
     41 DEFINE_ANIMATED_LENGTH(SVGFilterElement, SVGNames::heightAttr, Height, height)
     42 DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFilterElement, SVGNames::filterResAttr, filterResXIdentifier(), FilterResX, filterResX)
     43 DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFilterElement, SVGNames::filterResAttr, filterResYIdentifier(), FilterResY, filterResY)
     44 DEFINE_ANIMATED_STRING(SVGFilterElement, XLinkNames::hrefAttr, Href, href)
     45 DEFINE_ANIMATED_BOOLEAN(SVGFilterElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
     46 
     47 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFilterElement)
     48     REGISTER_LOCAL_ANIMATED_PROPERTY(filterUnits)
     49     REGISTER_LOCAL_ANIMATED_PROPERTY(primitiveUnits)
     50     REGISTER_LOCAL_ANIMATED_PROPERTY(x)
     51     REGISTER_LOCAL_ANIMATED_PROPERTY(y)
     52     REGISTER_LOCAL_ANIMATED_PROPERTY(width)
     53     REGISTER_LOCAL_ANIMATED_PROPERTY(height)
     54     REGISTER_LOCAL_ANIMATED_PROPERTY(filterResX)
     55     REGISTER_LOCAL_ANIMATED_PROPERTY(filterResY)
     56     REGISTER_LOCAL_ANIMATED_PROPERTY(href)
     57     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
     58 END_REGISTER_ANIMATED_PROPERTIES
     59 
     60 inline SVGFilterElement::SVGFilterElement(Document& document)
     61     : SVGElement(SVGNames::filterTag, document)
     62     , m_filterUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
     63     , m_primitiveUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
     64     , m_x(LengthModeWidth, "-10%")
     65     , m_y(LengthModeHeight, "-10%")
     66     , m_width(LengthModeWidth, "120%")
     67     , m_height(LengthModeHeight, "120%")
     68 {
     69     // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
     70     // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
     71     ScriptWrappable::init(this);
     72     registerAnimatedPropertiesForSVGFilterElement();
     73 }
     74 
     75 PassRefPtr<SVGFilterElement> SVGFilterElement::create(Document& document)
     76 {
     77     return adoptRef(new SVGFilterElement(document));
     78 }
     79 
     80 const AtomicString& SVGFilterElement::filterResXIdentifier()
     81 {
     82     DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGFilterResX", AtomicString::ConstructFromLiteral));
     83     return s_identifier;
     84 }
     85 
     86 const AtomicString& SVGFilterElement::filterResYIdentifier()
     87 {
     88     DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGFilterResY", AtomicString::ConstructFromLiteral));
     89     return s_identifier;
     90 }
     91 
     92 void SVGFilterElement::setFilterRes(unsigned filterResX, unsigned filterResY)
     93 {
     94     setFilterResXBaseValue(filterResX);
     95     setFilterResYBaseValue(filterResY);
     96 
     97     RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
     98     if (renderer)
     99         renderer->invalidateCacheAndMarkForLayout();
    100 }
    101 
    102 bool SVGFilterElement::isSupportedAttribute(const QualifiedName& attrName)
    103 {
    104     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
    105     if (supportedAttributes.isEmpty()) {
    106         SVGURIReference::addSupportedAttributes(supportedAttributes);
    107         SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
    108         supportedAttributes.add(SVGNames::filterUnitsAttr);
    109         supportedAttributes.add(SVGNames::primitiveUnitsAttr);
    110         supportedAttributes.add(SVGNames::xAttr);
    111         supportedAttributes.add(SVGNames::yAttr);
    112         supportedAttributes.add(SVGNames::widthAttr);
    113         supportedAttributes.add(SVGNames::heightAttr);
    114         supportedAttributes.add(SVGNames::filterResAttr);
    115     }
    116     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
    117 }
    118 
    119 void SVGFilterElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    120 {
    121     SVGParsingError parseError = NoError;
    122 
    123     if (!isSupportedAttribute(name))
    124         SVGElement::parseAttribute(name, value);
    125     else if (name == SVGNames::filterUnitsAttr) {
    126         SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
    127         if (propertyValue > 0)
    128             setFilterUnitsBaseValue(propertyValue);
    129     } else if (name == SVGNames::primitiveUnitsAttr) {
    130         SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
    131         if (propertyValue > 0)
    132             setPrimitiveUnitsBaseValue(propertyValue);
    133     } else if (name == SVGNames::xAttr)
    134         setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
    135     else if (name == SVGNames::yAttr)
    136         setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
    137     else if (name == SVGNames::widthAttr)
    138         setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
    139     else if (name == SVGNames::heightAttr)
    140         setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
    141     else if (name == SVGNames::filterResAttr) {
    142         float x, y;
    143         if (parseNumberOptionalNumber(value, x, y)) {
    144             setFilterResXBaseValue(x);
    145             setFilterResYBaseValue(y);
    146         }
    147     } else if (SVGURIReference::parseAttribute(name, value)
    148              || SVGExternalResourcesRequired::parseAttribute(name, value)) {
    149     } else
    150         ASSERT_NOT_REACHED();
    151 
    152     reportAttributeParsingError(parseError, name, value);
    153 }
    154 
    155 void SVGFilterElement::svgAttributeChanged(const QualifiedName& attrName)
    156 {
    157     if (!isSupportedAttribute(attrName)) {
    158         SVGElement::svgAttributeChanged(attrName);
    159         return;
    160     }
    161 
    162     SVGElementInstance::InvalidationGuard invalidationGuard(this);
    163 
    164     if (attrName == SVGNames::xAttr
    165         || attrName == SVGNames::yAttr
    166         || attrName == SVGNames::widthAttr
    167         || attrName == SVGNames::heightAttr)
    168         updateRelativeLengthsInformation();
    169 
    170     RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
    171     if (renderer)
    172         renderer->invalidateCacheAndMarkForLayout();
    173 }
    174 
    175 void SVGFilterElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    176 {
    177     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    178 
    179     if (changedByParser)
    180         return;
    181 
    182     if (RenderObject* object = renderer())
    183         object->setNeedsLayout();
    184 }
    185 
    186 RenderObject* SVGFilterElement::createRenderer(RenderStyle*)
    187 {
    188     RenderSVGResourceFilter* renderer = new RenderSVGResourceFilter(this);
    189 
    190     HashSet<RefPtr<Node> >::iterator layerEnd = m_clientsToAdd.end();
    191     for (HashSet<RefPtr<Node> >::iterator it = m_clientsToAdd.begin(); it != layerEnd; ++it)
    192         renderer->addClientRenderLayer((*it).get());
    193     m_clientsToAdd.clear();
    194 
    195     return renderer;
    196 }
    197 
    198 bool SVGFilterElement::childShouldCreateRenderer(const Node& child) const
    199 {
    200     if (!child.isSVGElement())
    201         return false;
    202 
    203     const SVGElement* svgElement = toSVGElement(&child);
    204 
    205     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, allowedChildElementTags, ());
    206     if (allowedChildElementTags.isEmpty()) {
    207         allowedChildElementTags.add(SVGNames::feBlendTag);
    208         allowedChildElementTags.add(SVGNames::feColorMatrixTag);
    209         allowedChildElementTags.add(SVGNames::feComponentTransferTag);
    210         allowedChildElementTags.add(SVGNames::feCompositeTag);
    211         allowedChildElementTags.add(SVGNames::feConvolveMatrixTag);
    212         allowedChildElementTags.add(SVGNames::feDiffuseLightingTag);
    213         allowedChildElementTags.add(SVGNames::feDisplacementMapTag);
    214         allowedChildElementTags.add(SVGNames::feDistantLightTag);
    215         allowedChildElementTags.add(SVGNames::feDropShadowTag);
    216         allowedChildElementTags.add(SVGNames::feFloodTag);
    217         allowedChildElementTags.add(SVGNames::feFuncATag);
    218         allowedChildElementTags.add(SVGNames::feFuncBTag);
    219         allowedChildElementTags.add(SVGNames::feFuncGTag);
    220         allowedChildElementTags.add(SVGNames::feFuncRTag);
    221         allowedChildElementTags.add(SVGNames::feGaussianBlurTag);
    222         allowedChildElementTags.add(SVGNames::feImageTag);
    223         allowedChildElementTags.add(SVGNames::feMergeTag);
    224         allowedChildElementTags.add(SVGNames::feMergeNodeTag);
    225         allowedChildElementTags.add(SVGNames::feMorphologyTag);
    226         allowedChildElementTags.add(SVGNames::feOffsetTag);
    227         allowedChildElementTags.add(SVGNames::fePointLightTag);
    228         allowedChildElementTags.add(SVGNames::feSpecularLightingTag);
    229         allowedChildElementTags.add(SVGNames::feSpotLightTag);
    230         allowedChildElementTags.add(SVGNames::feTileTag);
    231         allowedChildElementTags.add(SVGNames::feTurbulenceTag);
    232     }
    233 
    234     return allowedChildElementTags.contains<SVGAttributeHashTranslator>(svgElement->tagQName());
    235 }
    236 
    237 bool SVGFilterElement::selfHasRelativeLengths() const
    238 {
    239     return xCurrentValue().isRelative()
    240         || yCurrentValue().isRelative()
    241         || widthCurrentValue().isRelative()
    242         || heightCurrentValue().isRelative();
    243 }
    244 
    245 void SVGFilterElement::addClient(Node* client)
    246 {
    247     ASSERT(client);
    248     m_clientsToAdd.add(client);
    249 }
    250 
    251 void SVGFilterElement::removeClient(Node* client)
    252 {
    253     ASSERT(client);
    254     m_clientsToAdd.remove(client);
    255 }
    256 
    257 }
    258