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