1/* 2 * Copyright (C) 2009 Dirk Schulze <krit@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#include "core/svg/SVGFEConvolveMatrixElement.h" 22 23#include "core/SVGNames.h" 24#include "core/dom/Document.h" 25#include "core/svg/SVGDocumentExtensions.h" 26#include "core/svg/SVGParserUtilities.h" 27#include "core/svg/graphics/filters/SVGFilterBuilder.h" 28#include "platform/geometry/FloatPoint.h" 29#include "platform/geometry/IntPoint.h" 30#include "platform/geometry/IntSize.h" 31#include "platform/graphics/filters/FilterEffect.h" 32 33namespace blink { 34 35template<> const SVGEnumerationStringEntries& getStaticStringEntries<EdgeModeType>() 36{ 37 DEFINE_STATIC_LOCAL(SVGEnumerationStringEntries, entries, ()); 38 if (entries.isEmpty()) { 39 entries.append(std::make_pair(EDGEMODE_DUPLICATE, "duplicate")); 40 entries.append(std::make_pair(EDGEMODE_WRAP, "wrap")); 41 entries.append(std::make_pair(EDGEMODE_NONE, "none")); 42 } 43 return entries; 44} 45 46inline SVGFEConvolveMatrixElement::SVGFEConvolveMatrixElement(Document& document) 47 : SVGFilterPrimitiveStandardAttributes(SVGNames::feConvolveMatrixTag, document) 48 , m_bias(SVGAnimatedNumber::create(this, SVGNames::biasAttr, SVGNumber::create())) 49 , m_divisor(SVGAnimatedNumber::create(this, SVGNames::divisorAttr, SVGNumber::create())) 50 , m_in1(SVGAnimatedString::create(this, SVGNames::inAttr, SVGString::create())) 51 , m_edgeMode(SVGAnimatedEnumeration<EdgeModeType>::create(this, SVGNames::edgeModeAttr, EDGEMODE_DUPLICATE)) 52 , m_kernelMatrix(SVGAnimatedNumberList::create(this, SVGNames::kernelMatrixAttr, SVGNumberList::create())) 53 , m_kernelUnitLength(SVGAnimatedNumberOptionalNumber::create(this, SVGNames::kernelUnitLengthAttr)) 54 , m_order(SVGAnimatedIntegerOptionalInteger::create(this, SVGNames::orderAttr)) 55 , m_preserveAlpha(SVGAnimatedBoolean::create(this, SVGNames::preserveAlphaAttr, SVGBoolean::create())) 56 , m_targetX(SVGAnimatedInteger::create(this, SVGNames::targetXAttr, SVGInteger::create())) 57 , m_targetY(SVGAnimatedInteger::create(this, SVGNames::targetYAttr, SVGInteger::create())) 58{ 59 addToPropertyMap(m_preserveAlpha); 60 addToPropertyMap(m_divisor); 61 addToPropertyMap(m_bias); 62 addToPropertyMap(m_kernelUnitLength); 63 addToPropertyMap(m_kernelMatrix); 64 addToPropertyMap(m_in1); 65 addToPropertyMap(m_edgeMode); 66 addToPropertyMap(m_order); 67 addToPropertyMap(m_targetX); 68 addToPropertyMap(m_targetY); 69} 70 71DEFINE_NODE_FACTORY(SVGFEConvolveMatrixElement) 72 73bool SVGFEConvolveMatrixElement::isSupportedAttribute(const QualifiedName& attrName) 74{ 75 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 76 if (supportedAttributes.isEmpty()) { 77 supportedAttributes.add(SVGNames::inAttr); 78 supportedAttributes.add(SVGNames::orderAttr); 79 supportedAttributes.add(SVGNames::kernelMatrixAttr); 80 supportedAttributes.add(SVGNames::edgeModeAttr); 81 supportedAttributes.add(SVGNames::divisorAttr); 82 supportedAttributes.add(SVGNames::biasAttr); 83 supportedAttributes.add(SVGNames::targetXAttr); 84 supportedAttributes.add(SVGNames::targetYAttr); 85 supportedAttributes.add(SVGNames::kernelUnitLengthAttr); 86 supportedAttributes.add(SVGNames::preserveAlphaAttr); 87 } 88 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 89} 90 91void SVGFEConvolveMatrixElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 92{ 93 if (!isSupportedAttribute(name)) { 94 SVGFilterPrimitiveStandardAttributes::parseAttribute(name, value); 95 return; 96 } 97 98 SVGParsingError parseError = NoError; 99 100 if (name == SVGNames::inAttr) 101 m_in1->setBaseValueAsString(value, parseError); 102 else if (name == SVGNames::divisorAttr) 103 m_divisor->setBaseValueAsString(value, parseError); 104 else if (name == SVGNames::biasAttr) 105 m_bias->setBaseValueAsString(value, parseError); 106 else if (name == SVGNames::kernelUnitLengthAttr) 107 m_kernelUnitLength->setBaseValueAsString(value, parseError); 108 else if (name == SVGNames::kernelMatrixAttr) 109 m_kernelMatrix->setBaseValueAsString(value, parseError); 110 else if (name == SVGNames::preserveAlphaAttr) 111 m_preserveAlpha->setBaseValueAsString(value, parseError); 112 else if (name == SVGNames::edgeModeAttr) 113 m_edgeMode->setBaseValueAsString(value, parseError); 114 else if (name == SVGNames::targetXAttr) 115 m_targetX->setBaseValueAsString(value, parseError); 116 else if (name == SVGNames::targetYAttr) 117 m_targetY->setBaseValueAsString(value, parseError); 118 else if (name == SVGNames::orderAttr) { 119 m_order->setBaseValueAsString(value, parseError); 120 if (parseError == NoError && (orderX()->baseValue()->value() < 1 || orderY()->baseValue()->value() < 1)) { 121 document().accessSVGExtensions().reportWarning( 122 "feConvolveMatrix: problem parsing order=\"" + value 123 + "\". Filtered element will not be displayed."); 124 } 125 } else 126 ASSERT_NOT_REACHED(); 127 128 reportAttributeParsingError(parseError, name, value); 129} 130 131bool SVGFEConvolveMatrixElement::setFilterEffectAttribute(FilterEffect* effect, const QualifiedName& attrName) 132{ 133 FEConvolveMatrix* convolveMatrix = static_cast<FEConvolveMatrix*>(effect); 134 if (attrName == SVGNames::edgeModeAttr) 135 return convolveMatrix->setEdgeMode(m_edgeMode->currentValue()->enumValue()); 136 if (attrName == SVGNames::divisorAttr) 137 return convolveMatrix->setDivisor(m_divisor->currentValue()->value()); 138 if (attrName == SVGNames::biasAttr) 139 return convolveMatrix->setBias(m_bias->currentValue()->value()); 140 if (attrName == SVGNames::targetXAttr) 141 return convolveMatrix->setTargetOffset(IntPoint(m_targetX->currentValue()->value(), m_targetY->currentValue()->value())); 142 if (attrName == SVGNames::targetYAttr) 143 return convolveMatrix->setTargetOffset(IntPoint(m_targetX->currentValue()->value(), m_targetY->currentValue()->value())); 144 if (attrName == SVGNames::kernelUnitLengthAttr) 145 return convolveMatrix->setKernelUnitLength(FloatPoint(kernelUnitLengthX()->currentValue()->value(), kernelUnitLengthY()->currentValue()->value())); 146 if (attrName == SVGNames::preserveAlphaAttr) 147 return convolveMatrix->setPreserveAlpha(m_preserveAlpha->currentValue()->value()); 148 149 ASSERT_NOT_REACHED(); 150 return false; 151} 152 153void SVGFEConvolveMatrixElement::svgAttributeChanged(const QualifiedName& attrName) 154{ 155 if (!isSupportedAttribute(attrName)) { 156 SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(attrName); 157 return; 158 } 159 160 SVGElement::InvalidationGuard invalidationGuard(this); 161 162 if (attrName == SVGNames::edgeModeAttr 163 || attrName == SVGNames::divisorAttr 164 || attrName == SVGNames::biasAttr 165 || attrName == SVGNames::targetXAttr 166 || attrName == SVGNames::targetYAttr 167 || attrName == SVGNames::kernelUnitLengthAttr 168 || attrName == SVGNames::preserveAlphaAttr) { 169 primitiveAttributeChanged(attrName); 170 return; 171 } 172 173 if (attrName == SVGNames::inAttr 174 || attrName == SVGNames::orderAttr 175 || attrName == SVGNames::kernelMatrixAttr) { 176 invalidate(); 177 return; 178 } 179 180 ASSERT_NOT_REACHED(); 181} 182 183PassRefPtr<FilterEffect> SVGFEConvolveMatrixElement::build(SVGFilterBuilder* filterBuilder, Filter* filter) 184{ 185 FilterEffect* input1 = filterBuilder->getEffectById(AtomicString(m_in1->currentValue()->value())); 186 187 if (!input1) 188 return nullptr; 189 190 int orderXValue = orderX()->currentValue()->value(); 191 int orderYValue = orderY()->currentValue()->value(); 192 if (!hasAttribute(SVGNames::orderAttr)) { 193 orderXValue = 3; 194 orderYValue = 3; 195 } 196 // Spec says order must be > 0. Bail if it is not. 197 if (orderXValue < 1 || orderYValue < 1) 198 return nullptr; 199 RefPtr<SVGNumberList> kernelMatrix = this->m_kernelMatrix->currentValue(); 200 size_t kernelMatrixSize = kernelMatrix->length(); 201 // The spec says this is a requirement, and should bail out if fails 202 if (orderXValue * orderYValue != static_cast<int>(kernelMatrixSize)) 203 return nullptr; 204 205 int targetXValue = m_targetX->currentValue()->value(); 206 int targetYValue = m_targetY->currentValue()->value(); 207 if (hasAttribute(SVGNames::targetXAttr) && (targetXValue < 0 || targetXValue >= orderXValue)) 208 return nullptr; 209 // The spec says the default value is: targetX = floor ( orderX / 2 )) 210 if (!hasAttribute(SVGNames::targetXAttr)) 211 targetXValue = static_cast<int>(floorf(orderXValue / 2)); 212 if (hasAttribute(SVGNames::targetYAttr) && (targetYValue < 0 || targetYValue >= orderYValue)) 213 return nullptr; 214 // The spec says the default value is: targetY = floor ( orderY / 2 )) 215 if (!hasAttribute(SVGNames::targetYAttr)) 216 targetYValue = static_cast<int>(floorf(orderYValue / 2)); 217 218 // Spec says default kernelUnitLength is 1.0, and a specified length cannot be 0. 219 // FIXME: Why is this cast from float -> int -> float? 220 int kernelUnitLengthXValue = kernelUnitLengthX()->currentValue()->value(); 221 int kernelUnitLengthYValue = kernelUnitLengthY()->currentValue()->value(); 222 if (!hasAttribute(SVGNames::kernelUnitLengthAttr)) { 223 kernelUnitLengthXValue = 1; 224 kernelUnitLengthYValue = 1; 225 } 226 if (kernelUnitLengthXValue <= 0 || kernelUnitLengthYValue <= 0) 227 return nullptr; 228 229 float divisorValue = m_divisor->currentValue()->value(); 230 if (hasAttribute(SVGNames::divisorAttr) && !divisorValue) 231 return nullptr; 232 if (!hasAttribute(SVGNames::divisorAttr)) { 233 for (size_t i = 0; i < kernelMatrixSize; ++i) 234 divisorValue += kernelMatrix->at(i)->value(); 235 if (!divisorValue) 236 divisorValue = 1; 237 } 238 239 RefPtr<FilterEffect> effect = FEConvolveMatrix::create(filter, 240 IntSize(orderXValue, orderYValue), divisorValue, 241 m_bias->currentValue()->value(), IntPoint(targetXValue, targetYValue), m_edgeMode->currentValue()->enumValue(), 242 FloatPoint(kernelUnitLengthXValue, kernelUnitLengthYValue), m_preserveAlpha->currentValue()->value(), m_kernelMatrix->currentValue()->toFloatVector()); 243 effect->inputEffects().append(input1); 244 return effect.release(); 245} 246 247} // namespace blink 248