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