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