1 /* 2 * Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org> 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20 #include "config.h" 21 22 #include "core/svg/SVGFEConvolveMatrixElement.h" 23 24 #include "SVGNames.h" 25 #include "core/platform/graphics/FloatPoint.h" 26 #include "core/platform/graphics/IntPoint.h" 27 #include "core/platform/graphics/IntSize.h" 28 #include "core/platform/graphics/filters/FilterEffect.h" 29 #include "core/svg/SVGElementInstance.h" 30 #include "core/svg/SVGParserUtilities.h" 31 #include "core/svg/graphics/filters/SVGFilterBuilder.h" 32 33 namespace WebCore { 34 35 // Animated property definitions 36 DEFINE_ANIMATED_STRING(SVGFEConvolveMatrixElement, SVGNames::inAttr, In1, in1) 37 DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFEConvolveMatrixElement, SVGNames::orderAttr, orderXIdentifier(), OrderX, orderX) 38 DEFINE_ANIMATED_INTEGER_MULTIPLE_WRAPPERS(SVGFEConvolveMatrixElement, SVGNames::orderAttr, orderYIdentifier(), OrderY, orderY) 39 DEFINE_ANIMATED_NUMBER_LIST(SVGFEConvolveMatrixElement, SVGNames::kernelMatrixAttr, KernelMatrix, kernelMatrix) 40 DEFINE_ANIMATED_NUMBER(SVGFEConvolveMatrixElement, SVGNames::divisorAttr, Divisor, divisor) 41 DEFINE_ANIMATED_NUMBER(SVGFEConvolveMatrixElement, SVGNames::biasAttr, Bias, bias) 42 DEFINE_ANIMATED_INTEGER(SVGFEConvolveMatrixElement, SVGNames::targetXAttr, TargetX, targetX) 43 DEFINE_ANIMATED_INTEGER(SVGFEConvolveMatrixElement, SVGNames::targetYAttr, TargetY, targetY) 44 DEFINE_ANIMATED_ENUMERATION(SVGFEConvolveMatrixElement, SVGNames::edgeModeAttr, EdgeMode, edgeMode, EdgeModeType) 45 DEFINE_ANIMATED_NUMBER_MULTIPLE_WRAPPERS(SVGFEConvolveMatrixElement, SVGNames::kernelUnitLengthAttr, kernelUnitLengthXIdentifier(), KernelUnitLengthX, kernelUnitLengthX) 46 DEFINE_ANIMATED_NUMBER_MULTIPLE_WRAPPERS(SVGFEConvolveMatrixElement, SVGNames::kernelUnitLengthAttr, kernelUnitLengthYIdentifier(), KernelUnitLengthY, kernelUnitLengthY) 47 DEFINE_ANIMATED_BOOLEAN(SVGFEConvolveMatrixElement, SVGNames::preserveAlphaAttr, PreserveAlpha, preserveAlpha) 48 49 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFEConvolveMatrixElement) 50 REGISTER_LOCAL_ANIMATED_PROPERTY(in1) 51 REGISTER_LOCAL_ANIMATED_PROPERTY(orderX) 52 REGISTER_LOCAL_ANIMATED_PROPERTY(orderY) 53 REGISTER_LOCAL_ANIMATED_PROPERTY(kernelMatrix) 54 REGISTER_LOCAL_ANIMATED_PROPERTY(divisor) 55 REGISTER_LOCAL_ANIMATED_PROPERTY(bias) 56 REGISTER_LOCAL_ANIMATED_PROPERTY(targetX) 57 REGISTER_LOCAL_ANIMATED_PROPERTY(targetY) 58 REGISTER_LOCAL_ANIMATED_PROPERTY(edgeMode) 59 REGISTER_LOCAL_ANIMATED_PROPERTY(kernelUnitLengthX) 60 REGISTER_LOCAL_ANIMATED_PROPERTY(kernelUnitLengthY) 61 REGISTER_LOCAL_ANIMATED_PROPERTY(preserveAlpha) 62 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGFilterPrimitiveStandardAttributes) 63 END_REGISTER_ANIMATED_PROPERTIES 64 65 inline SVGFEConvolveMatrixElement::SVGFEConvolveMatrixElement(const QualifiedName& tagName, Document* document) 66 : SVGFilterPrimitiveStandardAttributes(tagName, document) 67 , m_edgeMode(EDGEMODE_DUPLICATE) 68 { 69 ASSERT(hasTagName(SVGNames::feConvolveMatrixTag)); 70 ScriptWrappable::init(this); 71 registerAnimatedPropertiesForSVGFEConvolveMatrixElement(); 72 } 73 74 PassRefPtr<SVGFEConvolveMatrixElement> SVGFEConvolveMatrixElement::create(const QualifiedName& tagName, Document* document) 75 { 76 return adoptRef(new SVGFEConvolveMatrixElement(tagName, document)); 77 } 78 79 const AtomicString& SVGFEConvolveMatrixElement::kernelUnitLengthXIdentifier() 80 { 81 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGKernelUnitLengthX", AtomicString::ConstructFromLiteral)); 82 return s_identifier; 83 } 84 85 const AtomicString& SVGFEConvolveMatrixElement::kernelUnitLengthYIdentifier() 86 { 87 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGKernelUnitLengthY", AtomicString::ConstructFromLiteral)); 88 return s_identifier; 89 } 90 91 const AtomicString& SVGFEConvolveMatrixElement::orderXIdentifier() 92 { 93 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGOrderX", AtomicString::ConstructFromLiteral)); 94 return s_identifier; 95 } 96 97 const AtomicString& SVGFEConvolveMatrixElement::orderYIdentifier() 98 { 99 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGOrderY", AtomicString::ConstructFromLiteral)); 100 return s_identifier; 101 } 102 103 bool SVGFEConvolveMatrixElement::isSupportedAttribute(const QualifiedName& attrName) 104 { 105 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 106 if (supportedAttributes.isEmpty()) { 107 supportedAttributes.add(SVGNames::inAttr); 108 supportedAttributes.add(SVGNames::orderAttr); 109 supportedAttributes.add(SVGNames::kernelMatrixAttr); 110 supportedAttributes.add(SVGNames::edgeModeAttr); 111 supportedAttributes.add(SVGNames::divisorAttr); 112 supportedAttributes.add(SVGNames::biasAttr); 113 supportedAttributes.add(SVGNames::targetXAttr); 114 supportedAttributes.add(SVGNames::targetYAttr); 115 supportedAttributes.add(SVGNames::kernelUnitLengthAttr); 116 supportedAttributes.add(SVGNames::preserveAlphaAttr); 117 } 118 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 119 } 120 121 void SVGFEConvolveMatrixElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 122 { 123 if (!isSupportedAttribute(name)) { 124 SVGFilterPrimitiveStandardAttributes::parseAttribute(name, value); 125 return; 126 } 127 128 if (name == SVGNames::inAttr) { 129 setIn1BaseValue(value); 130 return; 131 } 132 133 if (name == SVGNames::orderAttr) { 134 float x, y; 135 if (parseNumberOptionalNumber(value, x, y) && x >= 1 && y >= 1) { 136 setOrderXBaseValue(x); 137 setOrderYBaseValue(y); 138 } else 139 document()->accessSVGExtensions()->reportWarning( 140 "feConvolveMatrix: problem parsing order=\"" + value 141 + "\". Filtered element will not be displayed."); 142 return; 143 } 144 145 if (name == SVGNames::edgeModeAttr) { 146 EdgeModeType propertyValue = SVGPropertyTraits<EdgeModeType>::fromString(value); 147 if (propertyValue > 0) 148 setEdgeModeBaseValue(propertyValue); 149 else 150 document()->accessSVGExtensions()->reportWarning( 151 "feConvolveMatrix: problem parsing edgeMode=\"" + value 152 + "\". Filtered element will not be displayed."); 153 return; 154 } 155 156 if (name == SVGNames::kernelMatrixAttr) { 157 SVGNumberList newList; 158 newList.parse(value); 159 detachAnimatedKernelMatrixListWrappers(newList.size()); 160 setKernelMatrixBaseValue(newList); 161 return; 162 } 163 164 if (name == SVGNames::divisorAttr) { 165 float divisor = value.toFloat(); 166 if (divisor) 167 setDivisorBaseValue(divisor); 168 else 169 document()->accessSVGExtensions()->reportWarning( 170 "feConvolveMatrix: problem parsing divisor=\"" + value 171 + "\". Filtered element will not be displayed."); 172 return; 173 } 174 175 if (name == SVGNames::biasAttr) { 176 setBiasBaseValue(value.toFloat()); 177 return; 178 } 179 180 if (name == SVGNames::targetXAttr) { 181 setTargetXBaseValue(value.string().toUIntStrict()); 182 return; 183 } 184 185 if (name == SVGNames::targetYAttr) { 186 setTargetYBaseValue(value.string().toUIntStrict()); 187 return; 188 } 189 190 if (name == SVGNames::kernelUnitLengthAttr) { 191 float x, y; 192 if (parseNumberOptionalNumber(value, x, y) && x > 0 && y > 0) { 193 setKernelUnitLengthXBaseValue(x); 194 setKernelUnitLengthYBaseValue(y); 195 } else 196 document()->accessSVGExtensions()->reportWarning( 197 "feConvolveMatrix: problem parsing kernelUnitLength=\"" + value 198 + "\". Filtered element will not be displayed."); 199 return; 200 } 201 202 if (name == SVGNames::preserveAlphaAttr) { 203 if (value == "true") 204 setPreserveAlphaBaseValue(true); 205 else if (value == "false") 206 setPreserveAlphaBaseValue(false); 207 else 208 document()->accessSVGExtensions()->reportWarning( 209 "feConvolveMatrix: problem parsing preserveAlphaAttr=\"" + value 210 + "\". Filtered element will not be displayed."); 211 return; 212 } 213 214 ASSERT_NOT_REACHED(); 215 } 216 217 bool SVGFEConvolveMatrixElement::setFilterEffectAttribute(FilterEffect* effect, const QualifiedName& attrName) 218 { 219 FEConvolveMatrix* convolveMatrix = static_cast<FEConvolveMatrix*>(effect); 220 if (attrName == SVGNames::edgeModeAttr) 221 return convolveMatrix->setEdgeMode(edgeModeCurrentValue()); 222 if (attrName == SVGNames::divisorAttr) 223 return convolveMatrix->setDivisor(divisorCurrentValue()); 224 if (attrName == SVGNames::biasAttr) 225 return convolveMatrix->setBias(biasCurrentValue()); 226 if (attrName == SVGNames::targetXAttr) 227 return convolveMatrix->setTargetOffset(IntPoint(targetXCurrentValue(), targetYCurrentValue())); 228 if (attrName == SVGNames::targetYAttr) 229 return convolveMatrix->setTargetOffset(IntPoint(targetXCurrentValue(), targetYCurrentValue())); 230 if (attrName == SVGNames::kernelUnitLengthAttr) 231 return convolveMatrix->setKernelUnitLength(FloatPoint(kernelUnitLengthXCurrentValue(), kernelUnitLengthYCurrentValue())); 232 if (attrName == SVGNames::preserveAlphaAttr) 233 return convolveMatrix->setPreserveAlpha(preserveAlphaCurrentValue()); 234 235 ASSERT_NOT_REACHED(); 236 return false; 237 } 238 239 void SVGFEConvolveMatrixElement::setOrder(float x, float y) 240 { 241 setOrderXBaseValue(x); 242 setOrderYBaseValue(y); 243 invalidate(); 244 } 245 246 void SVGFEConvolveMatrixElement::setKernelUnitLength(float x, float y) 247 { 248 setKernelUnitLengthXBaseValue(x); 249 setKernelUnitLengthYBaseValue(y); 250 invalidate(); 251 } 252 253 void SVGFEConvolveMatrixElement::svgAttributeChanged(const QualifiedName& attrName) 254 { 255 if (!isSupportedAttribute(attrName)) { 256 SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(attrName); 257 return; 258 } 259 260 SVGElementInstance::InvalidationGuard invalidationGuard(this); 261 262 if (attrName == SVGNames::edgeModeAttr 263 || attrName == SVGNames::divisorAttr 264 || attrName == SVGNames::biasAttr 265 || attrName == SVGNames::targetXAttr 266 || attrName == SVGNames::targetYAttr 267 || attrName == SVGNames::kernelUnitLengthAttr 268 || attrName == SVGNames::preserveAlphaAttr) { 269 primitiveAttributeChanged(attrName); 270 return; 271 } 272 273 if (attrName == SVGNames::inAttr 274 || attrName == SVGNames::orderAttr 275 || attrName == SVGNames::kernelMatrixAttr) { 276 invalidate(); 277 return; 278 } 279 280 ASSERT_NOT_REACHED(); 281 } 282 283 PassRefPtr<FilterEffect> SVGFEConvolveMatrixElement::build(SVGFilterBuilder* filterBuilder, Filter* filter) 284 { 285 FilterEffect* input1 = filterBuilder->getEffectById(in1CurrentValue()); 286 287 if (!input1) 288 return 0; 289 290 int orderXValue = orderXCurrentValue(); 291 int orderYValue = orderYCurrentValue(); 292 if (!hasAttribute(SVGNames::orderAttr)) { 293 orderXValue = 3; 294 orderYValue = 3; 295 } 296 // Spec says order must be > 0. Bail if it is not. 297 if (orderXValue < 1 || orderYValue < 1) 298 return 0; 299 SVGNumberList& kernelMatrix = this->kernelMatrixCurrentValue(); 300 int kernelMatrixSize = kernelMatrix.size(); 301 // The spec says this is a requirement, and should bail out if fails 302 if (orderXValue * orderYValue != kernelMatrixSize) 303 return 0; 304 305 int targetXValue = targetXCurrentValue(); 306 int targetYValue = targetYCurrentValue(); 307 if (hasAttribute(SVGNames::targetXAttr) && (targetXValue < 0 || targetXValue >= orderXValue)) 308 return 0; 309 // The spec says the default value is: targetX = floor ( orderX / 2 )) 310 if (!hasAttribute(SVGNames::targetXAttr)) 311 targetXValue = static_cast<int>(floorf(orderXValue / 2)); 312 if (hasAttribute(SVGNames::targetYAttr) && (targetYValue < 0 || targetYValue >= orderYValue)) 313 return 0; 314 // The spec says the default value is: targetY = floor ( orderY / 2 )) 315 if (!hasAttribute(SVGNames::targetYAttr)) 316 targetYValue = static_cast<int>(floorf(orderYValue / 2)); 317 318 // Spec says default kernelUnitLength is 1.0, and a specified length cannot be 0. 319 int kernelUnitLengthXValue = kernelUnitLengthXCurrentValue(); 320 int kernelUnitLengthYValue = kernelUnitLengthYCurrentValue(); 321 if (!hasAttribute(SVGNames::kernelUnitLengthAttr)) { 322 kernelUnitLengthXValue = 1; 323 kernelUnitLengthYValue = 1; 324 } 325 if (kernelUnitLengthXValue <= 0 || kernelUnitLengthYValue <= 0) 326 return 0; 327 328 float divisorValue = divisorCurrentValue(); 329 if (hasAttribute(SVGNames::divisorAttr) && !divisorValue) 330 return 0; 331 if (!hasAttribute(SVGNames::divisorAttr)) { 332 for (int i = 0; i < kernelMatrixSize; ++i) 333 divisorValue += kernelMatrix.at(i).value(); 334 if (!divisorValue) 335 divisorValue = 1; 336 } 337 338 RefPtr<FilterEffect> effect = FEConvolveMatrix::create(filter, 339 IntSize(orderXValue, orderYValue), divisorValue, 340 biasCurrentValue(), IntPoint(targetXValue, targetYValue), edgeModeCurrentValue(), 341 FloatPoint(kernelUnitLengthXValue, kernelUnitLengthYValue), preserveAlphaCurrentValue(), kernelMatrix.toFloatVector()); 342 effect->inputEffects().append(input1); 343 return effect.release(); 344 } 345 346 } // namespace WebCore 347