Remove the SVG elements' attributes macros
[WebKit-https.git] / Source / WebCore / svg / SVGFEConvolveMatrixElement.cpp
1 /*
2  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
3  * Copyright (C) 2018 Apple Inc. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22 #include "SVGFEConvolveMatrixElement.h"
23
24 #include "FilterEffect.h"
25 #include "FloatPoint.h"
26 #include "IntPoint.h"
27 #include "IntSize.h"
28 #include "SVGFilterBuilder.h"
29 #include "SVGNames.h"
30 #include "SVGNumberListValues.h"
31 #include "SVGParserUtilities.h"
32 #include <wtf/IsoMallocInlines.h>
33
34 namespace WebCore {
35
36 WTF_MAKE_ISO_ALLOCATED_IMPL(SVGFEConvolveMatrixElement);
37
38 inline SVGFEConvolveMatrixElement::SVGFEConvolveMatrixElement(const QualifiedName& tagName, Document& document)
39     : SVGFilterPrimitiveStandardAttributes(tagName, document)
40 {
41     ASSERT(hasTagName(SVGNames::feConvolveMatrixTag));
42     registerAttributes();
43 }
44
45 Ref<SVGFEConvolveMatrixElement> SVGFEConvolveMatrixElement::create(const QualifiedName& tagName, Document& document)
46 {
47     return adoptRef(*new SVGFEConvolveMatrixElement(tagName, document));
48 }
49
50 const AtomicString& SVGFEConvolveMatrixElement::kernelUnitLengthXIdentifier()
51 {
52     static NeverDestroyed<AtomicString> s_identifier("SVGKernelUnitLengthX", AtomicString::ConstructFromLiteral);
53     return s_identifier;
54 }
55
56 const AtomicString& SVGFEConvolveMatrixElement::kernelUnitLengthYIdentifier()
57 {
58     static NeverDestroyed<AtomicString> s_identifier("SVGKernelUnitLengthY", AtomicString::ConstructFromLiteral);
59     return s_identifier;
60 }
61
62 const AtomicString& SVGFEConvolveMatrixElement::orderXIdentifier()
63 {
64     static NeverDestroyed<AtomicString> s_identifier("SVGOrderX", AtomicString::ConstructFromLiteral);
65     return s_identifier;
66 }
67
68 const AtomicString& SVGFEConvolveMatrixElement::orderYIdentifier()
69 {
70     static NeverDestroyed<AtomicString> s_identifier("SVGOrderY", AtomicString::ConstructFromLiteral);
71     return s_identifier;
72 }
73
74 void SVGFEConvolveMatrixElement::registerAttributes()
75 {
76     auto& registry = attributeRegistry();
77     if (!registry.isEmpty())
78         return;
79     registry.registerAttribute<SVGNames::inAttr, &SVGFEConvolveMatrixElement::m_in1>();
80     registry.registerAttribute<SVGNames::orderAttr,
81         &SVGFEConvolveMatrixElement::orderXIdentifier, &SVGFEConvolveMatrixElement::m_orderX,
82         &SVGFEConvolveMatrixElement::orderYIdentifier, &SVGFEConvolveMatrixElement::m_orderY>();
83     registry.registerAttribute<SVGNames::kernelMatrixAttr, &SVGFEConvolveMatrixElement::m_kernelMatrix>();
84     registry.registerAttribute<SVGNames::divisorAttr, &SVGFEConvolveMatrixElement::m_divisor>();
85     registry.registerAttribute<SVGNames::biasAttr, &SVGFEConvolveMatrixElement::m_bias>();
86     registry.registerAttribute<SVGNames::targetXAttr, &SVGFEConvolveMatrixElement::m_targetX>();
87     registry.registerAttribute<SVGNames::targetYAttr, &SVGFEConvolveMatrixElement::m_targetY>();
88     registry.registerAttribute<SVGNames::edgeModeAttr, EdgeModeType, &SVGFEConvolveMatrixElement::m_edgeMode>();
89     registry.registerAttribute<SVGNames::kernelUnitLengthAttr,
90         &SVGFEConvolveMatrixElement::kernelUnitLengthXIdentifier, &SVGFEConvolveMatrixElement::m_kernelUnitLengthX,
91         &SVGFEConvolveMatrixElement::kernelUnitLengthYIdentifier, &SVGFEConvolveMatrixElement::m_kernelUnitLengthY>();
92     registry.registerAttribute<SVGNames::preserveAlphaAttr, &SVGFEConvolveMatrixElement::m_preserveAlpha>();
93 }
94
95 void SVGFEConvolveMatrixElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
96 {
97     if (name == SVGNames::inAttr) {
98         m_in1.setValue(value);
99         return;
100     }
101
102     if (name == SVGNames::orderAttr) {
103         float x, y;
104         if (parseNumberOptionalNumber(value, x, y) && x >= 1 && y >= 1) {
105             m_orderX.setValue(x);
106             m_orderY.setValue(y);
107         } else
108             document().accessSVGExtensions().reportWarning("feConvolveMatrix: problem parsing order=\"" + value + "\". Filtered element will not be displayed.");
109         return;
110     }
111
112     if (name == SVGNames::edgeModeAttr) {
113         EdgeModeType propertyValue = SVGPropertyTraits<EdgeModeType>::fromString(value);
114         if (propertyValue > 0)
115             m_edgeMode.setValue(propertyValue);
116         else
117             document().accessSVGExtensions().reportWarning("feConvolveMatrix: problem parsing edgeMode=\"" + value + "\". Filtered element will not be displayed.");
118         return;
119     }
120
121     if (name == SVGNames::kernelMatrixAttr) {
122         SVGNumberListValues newList;
123         newList.parse(value);
124         m_kernelMatrix.detachAnimatedListWrappers(attributeOwnerProxy(), newList.size());
125         m_kernelMatrix.setValue(WTFMove(newList));
126         return;
127     }
128
129     if (name == SVGNames::divisorAttr) {
130         float divisor = value.toFloat();
131         if (divisor)
132             m_divisor.setValue(divisor);
133         else
134             document().accessSVGExtensions().reportWarning("feConvolveMatrix: problem parsing divisor=\"" + value + "\". Filtered element will not be displayed.");
135         return;
136     }
137     
138     if (name == SVGNames::biasAttr) {
139         m_bias.setValue(value.toFloat());
140         return;
141     }
142
143     if (name == SVGNames::targetXAttr) {
144         m_targetX.setValue(value.string().toUIntStrict());
145         return;
146     }
147
148     if (name == SVGNames::targetYAttr) {
149         m_targetY.setValue(value.string().toUIntStrict());
150         return;
151     }
152
153     if (name == SVGNames::kernelUnitLengthAttr) {
154         float x, y;
155         if (parseNumberOptionalNumber(value, x, y) && x > 0 && y > 0) {
156             m_kernelUnitLengthX.setValue(x);
157             m_kernelUnitLengthY.setValue(y);
158         } else
159             document().accessSVGExtensions().reportWarning("feConvolveMatrix: problem parsing kernelUnitLength=\"" + value + "\". Filtered element will not be displayed.");
160         return;
161     }
162
163     if (name == SVGNames::preserveAlphaAttr) {
164         if (value == "true")
165             m_preserveAlpha.setValue(true);
166         else if (value == "false")
167             m_preserveAlpha.setValue(false);
168         else
169             document().accessSVGExtensions().reportWarning("feConvolveMatrix: problem parsing preserveAlphaAttr=\"" + value  + "\". Filtered element will not be displayed.");
170         return;
171     }
172
173     SVGFilterPrimitiveStandardAttributes::parseAttribute(name, value);
174 }
175
176 bool SVGFEConvolveMatrixElement::setFilterEffectAttribute(FilterEffect* effect, const QualifiedName& attrName)
177 {
178     FEConvolveMatrix* convolveMatrix = static_cast<FEConvolveMatrix*>(effect);
179     if (attrName == SVGNames::edgeModeAttr)
180         return convolveMatrix->setEdgeMode(edgeMode());
181     if (attrName == SVGNames::divisorAttr)
182         return convolveMatrix->setDivisor(divisor());
183     if (attrName == SVGNames::biasAttr)
184         return convolveMatrix->setBias(bias());
185     if (attrName == SVGNames::targetXAttr)
186         return convolveMatrix->setTargetOffset(IntPoint(targetX(), targetY()));
187     if (attrName == SVGNames::targetYAttr)
188         return convolveMatrix->setTargetOffset(IntPoint(targetX(), targetY()));
189     if (attrName == SVGNames::kernelUnitLengthAttr)
190         return convolveMatrix->setKernelUnitLength(FloatPoint(kernelUnitLengthX(), kernelUnitLengthY()));
191     if (attrName == SVGNames::preserveAlphaAttr)
192         return convolveMatrix->setPreserveAlpha(preserveAlpha());
193
194     ASSERT_NOT_REACHED();
195     return false;
196 }
197
198 void SVGFEConvolveMatrixElement::setOrder(float x, float y)
199 {
200     m_orderX.setValue(x);
201     m_orderY.setValue(y);
202     invalidate();
203 }
204
205 void SVGFEConvolveMatrixElement::setKernelUnitLength(float x, float y)
206 {
207     m_kernelUnitLengthX.setValue(x);
208     m_kernelUnitLengthY.setValue(y);
209     invalidate();
210 }
211
212 void SVGFEConvolveMatrixElement::svgAttributeChanged(const QualifiedName& attrName)
213 {
214     if (attrName == SVGNames::edgeModeAttr || attrName == SVGNames::divisorAttr || attrName == SVGNames::biasAttr || attrName == SVGNames::targetXAttr || attrName == SVGNames::targetYAttr || attrName == SVGNames::kernelUnitLengthAttr || attrName == SVGNames::preserveAlphaAttr) {
215         InstanceInvalidationGuard guard(*this);
216         primitiveAttributeChanged(attrName);
217         return;
218     }
219
220     if (attrName == SVGNames::inAttr || attrName == SVGNames::orderAttr || attrName == SVGNames::kernelMatrixAttr) {
221         InstanceInvalidationGuard guard(*this);
222         invalidate();
223         return;
224     }
225
226     SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(attrName);
227 }
228
229 RefPtr<FilterEffect> SVGFEConvolveMatrixElement::build(SVGFilterBuilder* filterBuilder, Filter& filter)
230 {
231     auto input1 = filterBuilder->getEffectById(in1());
232
233     if (!input1)
234         return nullptr;
235
236     int orderXValue = orderX();
237     int orderYValue = orderY();
238     if (!hasAttribute(SVGNames::orderAttr)) {
239         orderXValue = 3;
240         orderYValue = 3;
241     }
242     // Spec says order must be > 0. Bail if it is not.
243     if (orderXValue < 1 || orderYValue < 1)
244         return nullptr;
245     auto& kernelMatrix = this->kernelMatrix();
246     int kernelMatrixSize = kernelMatrix.size();
247     // The spec says this is a requirement, and should bail out if fails
248     if (orderXValue * orderYValue != kernelMatrixSize)
249         return nullptr;
250
251     int targetXValue = targetX();
252     int targetYValue = targetY();
253     if (hasAttribute(SVGNames::targetXAttr) && (targetXValue < 0 || targetXValue >= orderXValue))
254         return nullptr;
255     // The spec says the default value is: targetX = floor ( orderX / 2 ))
256     if (!hasAttribute(SVGNames::targetXAttr))
257         targetXValue = static_cast<int>(floorf(orderXValue / 2));
258     if (hasAttribute(SVGNames::targetYAttr) && (targetYValue < 0 || targetYValue >= orderYValue))
259         return nullptr;
260     // The spec says the default value is: targetY = floor ( orderY / 2 ))
261     if (!hasAttribute(SVGNames::targetYAttr))
262         targetYValue = static_cast<int>(floorf(orderYValue / 2));
263
264     // Spec says default kernelUnitLength is 1.0, and a specified length cannot be 0.
265     int kernelUnitLengthXValue = kernelUnitLengthX();
266     int kernelUnitLengthYValue = kernelUnitLengthY();
267     if (!hasAttribute(SVGNames::kernelUnitLengthAttr)) {
268         kernelUnitLengthXValue = 1;
269         kernelUnitLengthYValue = 1;
270     }
271     if (kernelUnitLengthXValue <= 0 || kernelUnitLengthYValue <= 0)
272         return nullptr;
273
274     float divisorValue = divisor();
275     if (hasAttribute(SVGNames::divisorAttr) && !divisorValue)
276         return nullptr;
277     if (!hasAttribute(SVGNames::divisorAttr)) {
278         for (int i = 0; i < kernelMatrixSize; ++i)
279             divisorValue += kernelMatrix.at(i);
280         if (!divisorValue)
281             divisorValue = 1;
282     }
283
284     auto effect = FEConvolveMatrix::create(filter, IntSize(orderXValue, orderYValue), divisorValue, bias(), IntPoint(targetXValue, targetYValue), edgeMode(), FloatPoint(kernelUnitLengthXValue, kernelUnitLengthYValue), preserveAlpha(), kernelMatrix);
285     effect->inputEffects().append(input1);
286     return WTFMove(effect);
287 }
288
289 } // namespace WebCore