1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "mozilla/dom/SVGFEConvolveMatrixElement.h"
8 #include "mozilla/dom/SVGFEConvolveMatrixElementBinding.h"
9 #include "mozilla/UniquePtr.h"
10 #include "mozilla/UniquePtrExtensions.h"
11 #include "DOMSVGAnimatedNumberList.h"
12 #include "nsSVGUtils.h"
13 #include "nsSVGFilterInstance.h"
14
15 NS_IMPL_NS_NEW_SVG_ELEMENT(FEConvolveMatrix)
16
17 using namespace mozilla::gfx;
18
19 namespace mozilla {
20 namespace dom {
21
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)22 JSObject* SVGFEConvolveMatrixElement::WrapNode(
23 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
24 return SVGFEConvolveMatrixElement_Binding::Wrap(aCx, this, aGivenProto);
25 }
26
27 SVGElement::NumberInfo SVGFEConvolveMatrixElement::sNumberInfo[2] = {
28 {nsGkAtoms::divisor, 1, false}, {nsGkAtoms::bias, 0, false}};
29
30 SVGElement::NumberPairInfo SVGFEConvolveMatrixElement::sNumberPairInfo[1] = {
31 {nsGkAtoms::kernelUnitLength, 0, 0}};
32
33 SVGElement::IntegerInfo SVGFEConvolveMatrixElement::sIntegerInfo[2] = {
34 {nsGkAtoms::targetX, 0}, {nsGkAtoms::targetY, 0}};
35
36 SVGElement::IntegerPairInfo SVGFEConvolveMatrixElement::sIntegerPairInfo[1] = {
37 {nsGkAtoms::order, 3, 3}};
38
39 SVGElement::BooleanInfo SVGFEConvolveMatrixElement::sBooleanInfo[1] = {
40 {nsGkAtoms::preserveAlpha, false}};
41
42 SVGEnumMapping SVGFEConvolveMatrixElement::sEdgeModeMap[] = {
43 {nsGkAtoms::duplicate, SVG_EDGEMODE_DUPLICATE},
44 {nsGkAtoms::wrap, SVG_EDGEMODE_WRAP},
45 {nsGkAtoms::none, SVG_EDGEMODE_NONE},
46 {nullptr, 0}};
47
48 SVGElement::EnumInfo SVGFEConvolveMatrixElement::sEnumInfo[1] = {
49 {nsGkAtoms::edgeMode, sEdgeModeMap, SVG_EDGEMODE_DUPLICATE}};
50
51 SVGElement::StringInfo SVGFEConvolveMatrixElement::sStringInfo[2] = {
52 {nsGkAtoms::result, kNameSpaceID_None, true},
53 {nsGkAtoms::in, kNameSpaceID_None, true}};
54
55 SVGElement::NumberListInfo SVGFEConvolveMatrixElement::sNumberListInfo[1] = {
56 {nsGkAtoms::kernelMatrix}};
57
58 //----------------------------------------------------------------------
59 // nsINode methods
60
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEConvolveMatrixElement)61 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEConvolveMatrixElement)
62
63 //----------------------------------------------------------------------
64
65 already_AddRefed<DOMSVGAnimatedString> SVGFEConvolveMatrixElement::In1() {
66 return mStringAttributes[IN1].ToDOMAnimatedString(this);
67 }
68
OrderX()69 already_AddRefed<DOMSVGAnimatedInteger> SVGFEConvolveMatrixElement::OrderX() {
70 return mIntegerPairAttributes[ORDER].ToDOMAnimatedInteger(
71 SVGAnimatedIntegerPair::eFirst, this);
72 }
73
OrderY()74 already_AddRefed<DOMSVGAnimatedInteger> SVGFEConvolveMatrixElement::OrderY() {
75 return mIntegerPairAttributes[ORDER].ToDOMAnimatedInteger(
76 SVGAnimatedIntegerPair::eSecond, this);
77 }
78
79 already_AddRefed<DOMSVGAnimatedNumberList>
KernelMatrix()80 SVGFEConvolveMatrixElement::KernelMatrix() {
81 return DOMSVGAnimatedNumberList::GetDOMWrapper(
82 &mNumberListAttributes[KERNELMATRIX], this, KERNELMATRIX);
83 }
84
TargetX()85 already_AddRefed<DOMSVGAnimatedInteger> SVGFEConvolveMatrixElement::TargetX() {
86 return mIntegerAttributes[TARGET_X].ToDOMAnimatedInteger(this);
87 }
88
TargetY()89 already_AddRefed<DOMSVGAnimatedInteger> SVGFEConvolveMatrixElement::TargetY() {
90 return mIntegerAttributes[TARGET_Y].ToDOMAnimatedInteger(this);
91 }
92
93 already_AddRefed<DOMSVGAnimatedEnumeration>
EdgeMode()94 SVGFEConvolveMatrixElement::EdgeMode() {
95 return mEnumAttributes[EDGEMODE].ToDOMAnimatedEnum(this);
96 }
97
98 already_AddRefed<DOMSVGAnimatedBoolean>
PreserveAlpha()99 SVGFEConvolveMatrixElement::PreserveAlpha() {
100 return mBooleanAttributes[PRESERVEALPHA].ToDOMAnimatedBoolean(this);
101 }
102
Divisor()103 already_AddRefed<DOMSVGAnimatedNumber> SVGFEConvolveMatrixElement::Divisor() {
104 return mNumberAttributes[DIVISOR].ToDOMAnimatedNumber(this);
105 }
106
Bias()107 already_AddRefed<DOMSVGAnimatedNumber> SVGFEConvolveMatrixElement::Bias() {
108 return mNumberAttributes[BIAS].ToDOMAnimatedNumber(this);
109 }
110
111 already_AddRefed<DOMSVGAnimatedNumber>
KernelUnitLengthX()112 SVGFEConvolveMatrixElement::KernelUnitLengthX() {
113 return mNumberPairAttributes[KERNEL_UNIT_LENGTH].ToDOMAnimatedNumber(
114 SVGAnimatedNumberPair::eFirst, this);
115 }
116
117 already_AddRefed<DOMSVGAnimatedNumber>
KernelUnitLengthY()118 SVGFEConvolveMatrixElement::KernelUnitLengthY() {
119 return mNumberPairAttributes[KERNEL_UNIT_LENGTH].ToDOMAnimatedNumber(
120 SVGAnimatedNumberPair::eSecond, this);
121 }
122
GetSourceImageNames(nsTArray<SVGStringInfo> & aSources)123 void SVGFEConvolveMatrixElement::GetSourceImageNames(
124 nsTArray<SVGStringInfo>& aSources) {
125 aSources.AppendElement(SVGStringInfo(&mStringAttributes[IN1], this));
126 }
127
GetPrimitiveDescription(nsSVGFilterInstance * aInstance,const IntRect & aFilterSubregion,const nsTArray<bool> & aInputsAreTainted,nsTArray<RefPtr<SourceSurface>> & aInputImages)128 FilterPrimitiveDescription SVGFEConvolveMatrixElement::GetPrimitiveDescription(
129 nsSVGFilterInstance* aInstance, const IntRect& aFilterSubregion,
130 const nsTArray<bool>& aInputsAreTainted,
131 nsTArray<RefPtr<SourceSurface>>& aInputImages) {
132 FilterPrimitiveDescription failureDescription;
133
134 const SVGNumberList& kernelMatrix =
135 mNumberListAttributes[KERNELMATRIX].GetAnimValue();
136 uint32_t kmLength = kernelMatrix.Length();
137
138 int32_t orderX = mIntegerPairAttributes[ORDER].GetAnimValue(
139 SVGAnimatedIntegerPair::eFirst);
140 int32_t orderY = mIntegerPairAttributes[ORDER].GetAnimValue(
141 SVGAnimatedIntegerPair::eSecond);
142
143 if (orderX <= 0 || orderY <= 0 ||
144 static_cast<uint32_t>(orderX * orderY) != kmLength) {
145 return failureDescription;
146 }
147
148 int32_t targetX, targetY;
149 GetAnimatedIntegerValues(&targetX, &targetY, nullptr);
150
151 if (mIntegerAttributes[TARGET_X].IsExplicitlySet()) {
152 if (targetX < 0 || targetX >= orderX) return failureDescription;
153 } else {
154 targetX = orderX / 2;
155 }
156 if (mIntegerAttributes[TARGET_Y].IsExplicitlySet()) {
157 if (targetY < 0 || targetY >= orderY) return failureDescription;
158 } else {
159 targetY = orderY / 2;
160 }
161
162 if (orderX > NS_SVG_OFFSCREEN_MAX_DIMENSION ||
163 orderY > NS_SVG_OFFSCREEN_MAX_DIMENSION)
164 return failureDescription;
165 UniquePtr<float[]> kernel = MakeUniqueFallible<float[]>(orderX * orderY);
166 if (!kernel) return failureDescription;
167 for (uint32_t i = 0; i < kmLength; i++) {
168 kernel[kmLength - 1 - i] = kernelMatrix[i];
169 }
170
171 float divisor;
172 if (mNumberAttributes[DIVISOR].IsExplicitlySet()) {
173 divisor = mNumberAttributes[DIVISOR].GetAnimValue();
174 if (divisor == 0) return failureDescription;
175 } else {
176 divisor = kernel[0];
177 for (uint32_t i = 1; i < kmLength; i++) divisor += kernel[i];
178 if (divisor == 0) divisor = 1;
179 }
180
181 uint32_t edgeMode = mEnumAttributes[EDGEMODE].GetAnimValue();
182 bool preserveAlpha = mBooleanAttributes[PRESERVEALPHA].GetAnimValue();
183 float bias = mNumberAttributes[BIAS].GetAnimValue();
184
185 Size kernelUnitLength = GetKernelUnitLength(
186 aInstance, &mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
187
188 if (kernelUnitLength.width <= 0 || kernelUnitLength.height <= 0) {
189 // According to spec, A negative or zero value is an error. See link below
190 // for details.
191 // https://www.w3.org/TR/SVG/filters.html#feConvolveMatrixElementKernelUnitLengthAttribute
192 return failureDescription;
193 }
194
195 ConvolveMatrixAttributes atts;
196 atts.mKernelSize = IntSize(orderX, orderY);
197 atts.mKernelMatrix.AppendElements(&kernelMatrix[0], kmLength);
198 atts.mDivisor = divisor;
199 atts.mBias = bias;
200 atts.mTarget = IntPoint(targetX, targetY);
201 atts.mEdgeMode = edgeMode;
202 atts.mKernelUnitLength = kernelUnitLength;
203 atts.mPreserveAlpha = preserveAlpha;
204
205 return FilterPrimitiveDescription(AsVariant(std::move(atts)));
206 }
207
AttributeAffectsRendering(int32_t aNameSpaceID,nsAtom * aAttribute) const208 bool SVGFEConvolveMatrixElement::AttributeAffectsRendering(
209 int32_t aNameSpaceID, nsAtom* aAttribute) const {
210 return SVGFEConvolveMatrixElementBase::AttributeAffectsRendering(
211 aNameSpaceID, aAttribute) ||
212 (aNameSpaceID == kNameSpaceID_None &&
213 (aAttribute == nsGkAtoms::in || aAttribute == nsGkAtoms::divisor ||
214 aAttribute == nsGkAtoms::bias ||
215 aAttribute == nsGkAtoms::kernelUnitLength ||
216 aAttribute == nsGkAtoms::targetX ||
217 aAttribute == nsGkAtoms::targetY || aAttribute == nsGkAtoms::order ||
218 aAttribute == nsGkAtoms::preserveAlpha ||
219 aAttribute == nsGkAtoms::edgeMode ||
220 aAttribute == nsGkAtoms::kernelMatrix));
221 }
222
223 //----------------------------------------------------------------------
224 // SVGElement methods
225
GetNumberInfo()226 SVGElement::NumberAttributesInfo SVGFEConvolveMatrixElement::GetNumberInfo() {
227 return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
228 ArrayLength(sNumberInfo));
229 }
230
231 SVGElement::NumberPairAttributesInfo
GetNumberPairInfo()232 SVGFEConvolveMatrixElement::GetNumberPairInfo() {
233 return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo,
234 ArrayLength(sNumberPairInfo));
235 }
236
GetIntegerInfo()237 SVGElement::IntegerAttributesInfo SVGFEConvolveMatrixElement::GetIntegerInfo() {
238 return IntegerAttributesInfo(mIntegerAttributes, sIntegerInfo,
239 ArrayLength(sIntegerInfo));
240 }
241
242 SVGElement::IntegerPairAttributesInfo
GetIntegerPairInfo()243 SVGFEConvolveMatrixElement::GetIntegerPairInfo() {
244 return IntegerPairAttributesInfo(mIntegerPairAttributes, sIntegerPairInfo,
245 ArrayLength(sIntegerPairInfo));
246 }
247
GetBooleanInfo()248 SVGElement::BooleanAttributesInfo SVGFEConvolveMatrixElement::GetBooleanInfo() {
249 return BooleanAttributesInfo(mBooleanAttributes, sBooleanInfo,
250 ArrayLength(sBooleanInfo));
251 }
252
GetEnumInfo()253 SVGElement::EnumAttributesInfo SVGFEConvolveMatrixElement::GetEnumInfo() {
254 return EnumAttributesInfo(mEnumAttributes, sEnumInfo, ArrayLength(sEnumInfo));
255 }
256
GetStringInfo()257 SVGElement::StringAttributesInfo SVGFEConvolveMatrixElement::GetStringInfo() {
258 return StringAttributesInfo(mStringAttributes, sStringInfo,
259 ArrayLength(sStringInfo));
260 }
261
262 SVGElement::NumberListAttributesInfo
GetNumberListInfo()263 SVGFEConvolveMatrixElement::GetNumberListInfo() {
264 return NumberListAttributesInfo(mNumberListAttributes, sNumberListInfo,
265 ArrayLength(sNumberListInfo));
266 }
267
268 } // namespace dom
269 } // namespace mozilla
270