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