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/ArrayUtils.h"
8 
9 #include "nsSVGElement.h"
10 #include "nsGkAtoms.h"
11 #include "nsSVGNumber2.h"
12 #include "nsSVGNumberPair.h"
13 #include "nsSVGInteger.h"
14 #include "nsSVGIntegerPair.h"
15 #include "nsSVGBoolean.h"
16 #include "nsCOMPtr.h"
17 #include "nsSVGFilterInstance.h"
18 #include "nsSVGEnum.h"
19 #include "SVGNumberList.h"
20 #include "SVGAnimatedNumberList.h"
21 #include "DOMSVGAnimatedNumberList.h"
22 #include "nsSVGFilters.h"
23 #include "nsLayoutUtils.h"
24 #include "nsSVGUtils.h"
25 #include "nsStyleContext.h"
26 #include "nsIFrame.h"
27 #include "imgIContainer.h"
28 #include "mozilla/dom/SVGFilterElement.h"
29 #include "nsSVGString.h"
30 #include "SVGContentUtils.h"
31 #include <algorithm>
32 #include "mozilla/dom/SVGAnimatedLength.h"
33 #include "mozilla/dom/SVGComponentTransferFunctionElement.h"
34 #include "mozilla/dom/SVGFEDistantLightElement.h"
35 #include "mozilla/dom/SVGFEFuncAElementBinding.h"
36 #include "mozilla/dom/SVGFEFuncBElementBinding.h"
37 #include "mozilla/dom/SVGFEFuncGElementBinding.h"
38 #include "mozilla/dom/SVGFEFuncRElementBinding.h"
39 #include "mozilla/dom/SVGFEPointLightElement.h"
40 #include "mozilla/dom/SVGFESpotLightElement.h"
41 
42 #if defined(XP_WIN)
43 // Prevent Windows redefining LoadImage
44 #undef LoadImage
45 #endif
46 
47 using namespace mozilla;
48 using namespace mozilla::dom;
49 using namespace mozilla::gfx;
50 
51 //--------------------Filter Element Base Class-----------------------
52 
53 nsSVGElement::LengthInfo nsSVGFE::sLengthInfo[4] =
54 {
55   { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X },
56   { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y },
57   { &nsGkAtoms::width, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X },
58   { &nsGkAtoms::height, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y }
59 };
60 
61 //----------------------------------------------------------------------
62 // nsISupports methods
63 
64 NS_IMPL_ADDREF_INHERITED(nsSVGFE,nsSVGFEBase)
65 NS_IMPL_RELEASE_INHERITED(nsSVGFE,nsSVGFEBase)
66 
67 NS_INTERFACE_MAP_BEGIN(nsSVGFE)
68    // nsISupports is an ambiguous base of nsSVGFE so we have to work
69    // around that
70    if ( aIID.Equals(NS_GET_IID(nsSVGFE)) )
71      foundInterface = static_cast<nsISupports*>(static_cast<void*>(this));
72    else
NS_INTERFACE_MAP_END_INHERITING(nsSVGFEBase)73 NS_INTERFACE_MAP_END_INHERITING(nsSVGFEBase)
74 
75 //----------------------------------------------------------------------
76 // Implementation
77 
78 void
79 nsSVGFE::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
80 {
81 }
82 
83 bool
OutputIsTainted(const nsTArray<bool> & aInputsAreTainted,nsIPrincipal * aReferencePrincipal)84 nsSVGFE::OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
85                          nsIPrincipal* aReferencePrincipal)
86 {
87   // This is the default implementation for OutputIsTainted.
88   // Our output is tainted if we have at least one tainted input.
89   for (uint32_t i = 0; i < aInputsAreTainted.Length(); i++) {
90     if (aInputsAreTainted[i]) {
91       return true;
92     }
93   }
94   return false;
95 }
96 
97 bool
AttributeAffectsRendering(int32_t aNameSpaceID,nsIAtom * aAttribute) const98 nsSVGFE::AttributeAffectsRendering(int32_t aNameSpaceID,
99                                    nsIAtom* aAttribute) const
100 {
101   return aNameSpaceID == kNameSpaceID_None &&
102          (aAttribute == nsGkAtoms::x ||
103           aAttribute == nsGkAtoms::y ||
104           aAttribute == nsGkAtoms::width ||
105           aAttribute == nsGkAtoms::height ||
106           aAttribute == nsGkAtoms::result);
107 }
108 
109 already_AddRefed<SVGAnimatedLength>
X()110 nsSVGFE::X()
111 {
112   return mLengthAttributes[ATTR_X].ToDOMAnimatedLength(this);
113 }
114 
115 already_AddRefed<SVGAnimatedLength>
Y()116 nsSVGFE::Y()
117 {
118   return mLengthAttributes[ATTR_Y].ToDOMAnimatedLength(this);
119 }
120 
121 already_AddRefed<SVGAnimatedLength>
Width()122 nsSVGFE::Width()
123 {
124   return mLengthAttributes[ATTR_WIDTH].ToDOMAnimatedLength(this);
125 }
126 
127 already_AddRefed<SVGAnimatedLength>
Height()128 nsSVGFE::Height()
129 {
130   return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
131 }
132 
133 already_AddRefed<SVGAnimatedString>
Result()134 nsSVGFE::Result()
135 {
136   return GetResultImageName().ToDOMAnimatedString(this);
137 }
138 
139 //----------------------------------------------------------------------
140 // nsIContent methods
141 
NS_IMETHODIMP_(bool)142 NS_IMETHODIMP_(bool)
143 nsSVGFE::IsAttributeMapped(const nsIAtom* name) const
144 {
145   static const MappedAttributeEntry* const map[] = {
146     sFiltersMap
147   };
148 
149   return FindAttributeDependence(name, map) ||
150     nsSVGFEBase::IsAttributeMapped(name);
151 }
152 
153 //----------------------------------------------------------------------
154 // nsSVGElement methods
155 
156 
157 bool
StyleIsSetToSRGB()158 nsSVGFE::StyleIsSetToSRGB()
159 {
160   nsIFrame* frame = GetPrimaryFrame();
161   if (!frame) return false;
162 
163   nsStyleContext* style = frame->StyleContext();
164   return style->StyleSVG()->mColorInterpolationFilters ==
165            NS_STYLE_COLOR_INTERPOLATION_SRGB;
166 }
167 
168 /* virtual */ bool
HasValidDimensions() const169 nsSVGFE::HasValidDimensions() const
170 {
171   return (!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
172            mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
173          (!mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() ||
174            mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0);
175 }
176 
177 Size
GetKernelUnitLength(nsSVGFilterInstance * aInstance,nsSVGNumberPair * aKernelUnitLength)178 nsSVGFE::GetKernelUnitLength(nsSVGFilterInstance* aInstance,
179                              nsSVGNumberPair *aKernelUnitLength)
180 {
181   if (!aKernelUnitLength->IsExplicitlySet()) {
182     return Size(1, 1);
183   }
184 
185   float kernelX = aInstance->GetPrimitiveNumber(SVGContentUtils::X,
186                                                 aKernelUnitLength,
187                                                 nsSVGNumberPair::eFirst);
188   float kernelY = aInstance->GetPrimitiveNumber(SVGContentUtils::Y,
189                                                 aKernelUnitLength,
190                                                 nsSVGNumberPair::eSecond);
191   return Size(kernelX, kernelY);
192 }
193 
194 nsSVGElement::LengthAttributesInfo
GetLengthInfo()195 nsSVGFE::GetLengthInfo()
196 {
197   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
198                               ArrayLength(sLengthInfo));
199 }
200 
201 namespace mozilla {
202 namespace dom {
203 
204 nsSVGElement::NumberListInfo SVGComponentTransferFunctionElement::sNumberListInfo[1] =
205 {
206   { &nsGkAtoms::tableValues }
207 };
208 
209 nsSVGElement::NumberInfo SVGComponentTransferFunctionElement::sNumberInfo[5] =
210 {
211   { &nsGkAtoms::slope,     1, false },
212   { &nsGkAtoms::intercept, 0, false },
213   { &nsGkAtoms::amplitude, 1, false },
214   { &nsGkAtoms::exponent,  1, false },
215   { &nsGkAtoms::offset,    0, false }
216 };
217 
218 nsSVGEnumMapping SVGComponentTransferFunctionElement::sTypeMap[] = {
219   {&nsGkAtoms::identity,
220    SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY},
221   {&nsGkAtoms::table,
222    SVG_FECOMPONENTTRANSFER_TYPE_TABLE},
223   {&nsGkAtoms::discrete,
224    SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE},
225   {&nsGkAtoms::linear,
226    SVG_FECOMPONENTTRANSFER_TYPE_LINEAR},
227   {&nsGkAtoms::gamma,
228    SVG_FECOMPONENTTRANSFER_TYPE_GAMMA},
229   {nullptr, 0}
230 };
231 
232 nsSVGElement::EnumInfo SVGComponentTransferFunctionElement::sEnumInfo[1] =
233 {
234   { &nsGkAtoms::type,
235     sTypeMap,
236     SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY
237   }
238 };
239 
240 //----------------------------------------------------------------------
241 // nsISupports methods
242 
243 NS_IMPL_ADDREF_INHERITED(SVGComponentTransferFunctionElement,SVGComponentTransferFunctionElementBase)
244 NS_IMPL_RELEASE_INHERITED(SVGComponentTransferFunctionElement,SVGComponentTransferFunctionElementBase)
245 
246 NS_INTERFACE_MAP_BEGIN(SVGComponentTransferFunctionElement)
247    // nsISupports is an ambiguous base of nsSVGFE so we have to work
248    // around that
249    if ( aIID.Equals(NS_GET_IID(SVGComponentTransferFunctionElement)) )
250      foundInterface = static_cast<nsISupports*>(static_cast<void*>(this));
251    else
NS_INTERFACE_MAP_END_INHERITING(SVGComponentTransferFunctionElementBase)252 NS_INTERFACE_MAP_END_INHERITING(SVGComponentTransferFunctionElementBase)
253 
254 
255 //----------------------------------------------------------------------
256 // nsFEUnstyledElement methods
257 
258 bool
259 SVGComponentTransferFunctionElement::AttributeAffectsRendering(int32_t aNameSpaceID,
260                                                                nsIAtom* aAttribute) const
261 {
262   return aNameSpaceID == kNameSpaceID_None &&
263          (aAttribute == nsGkAtoms::tableValues ||
264           aAttribute == nsGkAtoms::slope ||
265           aAttribute == nsGkAtoms::intercept ||
266           aAttribute == nsGkAtoms::amplitude ||
267           aAttribute == nsGkAtoms::exponent ||
268           aAttribute == nsGkAtoms::offset ||
269           aAttribute == nsGkAtoms::type);
270 }
271 
272 //----------------------------------------------------------------------
273 
274 already_AddRefed<SVGAnimatedEnumeration>
Type()275 SVGComponentTransferFunctionElement::Type()
276 {
277   return mEnumAttributes[TYPE].ToDOMAnimatedEnum(this);
278 }
279 
280 already_AddRefed<DOMSVGAnimatedNumberList>
TableValues()281 SVGComponentTransferFunctionElement::TableValues()
282 {
283   return DOMSVGAnimatedNumberList::GetDOMWrapper(
284     &mNumberListAttributes[TABLEVALUES], this, TABLEVALUES);
285 }
286 
287 already_AddRefed<SVGAnimatedNumber>
Slope()288 SVGComponentTransferFunctionElement::Slope()
289 {
290   return mNumberAttributes[SLOPE].ToDOMAnimatedNumber(this);
291 }
292 
293 already_AddRefed<SVGAnimatedNumber>
Intercept()294 SVGComponentTransferFunctionElement::Intercept()
295 {
296   return mNumberAttributes[INTERCEPT].ToDOMAnimatedNumber(this);
297 }
298 
299 already_AddRefed<SVGAnimatedNumber>
Amplitude()300 SVGComponentTransferFunctionElement::Amplitude()
301 {
302   return mNumberAttributes[AMPLITUDE].ToDOMAnimatedNumber(this);
303 }
304 
305 already_AddRefed<SVGAnimatedNumber>
Exponent()306 SVGComponentTransferFunctionElement::Exponent()
307 {
308   return mNumberAttributes[EXPONENT].ToDOMAnimatedNumber(this);
309 }
310 
311 already_AddRefed<SVGAnimatedNumber>
Offset()312 SVGComponentTransferFunctionElement::Offset()
313 {
314   return mNumberAttributes[OFFSET].ToDOMAnimatedNumber(this);
315 }
316 
317 AttributeMap
ComputeAttributes()318 SVGComponentTransferFunctionElement::ComputeAttributes()
319 {
320   uint32_t type = mEnumAttributes[TYPE].GetAnimValue();
321 
322   float slope, intercept, amplitude, exponent, offset;
323   GetAnimatedNumberValues(&slope, &intercept, &amplitude,
324                           &exponent, &offset, nullptr);
325 
326   const SVGNumberList &tableValues =
327     mNumberListAttributes[TABLEVALUES].GetAnimValue();
328 
329   AttributeMap map;
330   map.Set(eComponentTransferFunctionType, type);
331   map.Set(eComponentTransferFunctionSlope, slope);
332   map.Set(eComponentTransferFunctionIntercept, intercept);
333   map.Set(eComponentTransferFunctionAmplitude, amplitude);
334   map.Set(eComponentTransferFunctionExponent, exponent);
335   map.Set(eComponentTransferFunctionOffset, offset);
336   if (tableValues.Length()) {
337     map.Set(eComponentTransferFunctionTableValues, &tableValues[0], tableValues.Length());
338   } else {
339     map.Set(eComponentTransferFunctionTableValues, nullptr, 0);
340   }
341   return map;
342 }
343 
344 //----------------------------------------------------------------------
345 // nsSVGElement methods
346 
347 nsSVGElement::NumberListAttributesInfo
GetNumberListInfo()348 SVGComponentTransferFunctionElement::GetNumberListInfo()
349 {
350   return NumberListAttributesInfo(mNumberListAttributes, sNumberListInfo,
351                                   ArrayLength(sNumberListInfo));
352 }
353 
354 nsSVGElement::EnumAttributesInfo
GetEnumInfo()355 SVGComponentTransferFunctionElement::GetEnumInfo()
356 {
357   return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
358                             ArrayLength(sEnumInfo));
359 }
360 
361 nsSVGElement::NumberAttributesInfo
GetNumberInfo()362 SVGComponentTransferFunctionElement::GetNumberInfo()
363 {
364   return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
365                               ArrayLength(sNumberInfo));
366 }
367 
368 /* virtual */ JSObject*
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)369 SVGFEFuncRElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
370 {
371   return SVGFEFuncRElementBinding::Wrap(aCx, this, aGivenProto);
372 }
373 
374 } // namespace dom
375 } // namespace mozilla
376 
377 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEFuncR)
378 
379 namespace mozilla {
380 namespace dom {
381 
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncRElement)382 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncRElement)
383 
384 /* virtual */ JSObject*
385 SVGFEFuncGElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
386 {
387   return SVGFEFuncGElementBinding::Wrap(aCx, this, aGivenProto);
388 }
389 
390 } // namespace dom
391 } // namespace mozilla
392 
393 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEFuncG)
394 
395 namespace mozilla {
396 namespace dom {
397 
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncGElement)398 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncGElement)
399 
400 /* virtual */ JSObject*
401 SVGFEFuncBElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
402 {
403   return SVGFEFuncBElementBinding::Wrap(aCx, this, aGivenProto);
404 }
405 
406 } // namespace dom
407 } // namespace mozilla
408 
409 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEFuncB)
410 
411 namespace mozilla {
412 namespace dom {
413 
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncBElement)414 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncBElement)
415 
416 /* virtual */ JSObject*
417 SVGFEFuncAElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
418 {
419   return SVGFEFuncAElementBinding::Wrap(aCx, this, aGivenProto);
420 }
421 
422 } // namespace dom
423 } // namespace mozilla
424 
425 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEFuncA)
426 
427 namespace mozilla {
428 namespace dom {
429 
430 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncAElement)
431 
432 } // namespace dom
433 } // namespace mozilla
434 
435 //--------------------------------------------------------------------
436 //
437 nsSVGElement::NumberInfo nsSVGFELightingElement::sNumberInfo[4] =
438 {
439   { &nsGkAtoms::surfaceScale, 1, false },
440   { &nsGkAtoms::diffuseConstant, 1, false },
441   { &nsGkAtoms::specularConstant, 1, false },
442   { &nsGkAtoms::specularExponent, 1, false }
443 };
444 
445 nsSVGElement::NumberPairInfo nsSVGFELightingElement::sNumberPairInfo[1] =
446 {
447   { &nsGkAtoms::kernelUnitLength, 0, 0 }
448 };
449 
450 nsSVGElement::StringInfo nsSVGFELightingElement::sStringInfo[2] =
451 {
452   { &nsGkAtoms::result, kNameSpaceID_None, true },
453   { &nsGkAtoms::in, kNameSpaceID_None, true }
454 };
455 
456 //----------------------------------------------------------------------
457 // nsISupports methods
458 
NS_IMPL_ADDREF_INHERITED(nsSVGFELightingElement,nsSVGFELightingElementBase)459 NS_IMPL_ADDREF_INHERITED(nsSVGFELightingElement,nsSVGFELightingElementBase)
460 NS_IMPL_RELEASE_INHERITED(nsSVGFELightingElement,nsSVGFELightingElementBase)
461 
462 NS_INTERFACE_MAP_BEGIN(nsSVGFELightingElement)
463 NS_INTERFACE_MAP_END_INHERITING(nsSVGFELightingElementBase)
464 
465 //----------------------------------------------------------------------
466 // Implementation
467 
468 NS_IMETHODIMP_(bool)
469 nsSVGFELightingElement::IsAttributeMapped(const nsIAtom* name) const
470 {
471   static const MappedAttributeEntry* const map[] = {
472     sLightingEffectsMap
473   };
474 
475   return FindAttributeDependence(name, map) ||
476     nsSVGFELightingElementBase::IsAttributeMapped(name);
477 }
478 
479 void
GetSourceImageNames(nsTArray<nsSVGStringInfo> & aSources)480 nsSVGFELightingElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
481 {
482   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
483 }
484 
485 AttributeMap
ComputeLightAttributes(nsSVGFilterInstance * aInstance)486 nsSVGFELightingElement::ComputeLightAttributes(nsSVGFilterInstance* aInstance)
487 {
488   // find specified light
489   for (nsCOMPtr<nsIContent> child = nsINode::GetFirstChild();
490        child;
491        child = child->GetNextSibling()) {
492     if (child->IsAnyOfSVGElements(nsGkAtoms::feDistantLight,
493                                   nsGkAtoms::fePointLight,
494                                   nsGkAtoms::feSpotLight)) {
495       return static_cast<SVGFELightElement*>(child.get())->ComputeLightAttributes(aInstance);
496     }
497   }
498 
499   AttributeMap map;
500   map.Set(eLightType, (uint32_t)eLightTypeNone);
501   return map;
502 }
503 
504 FilterPrimitiveDescription
AddLightingAttributes(FilterPrimitiveDescription aDescription,nsSVGFilterInstance * aInstance)505 nsSVGFELightingElement::AddLightingAttributes(FilterPrimitiveDescription aDescription,
506                                               nsSVGFilterInstance* aInstance)
507 {
508   nsIFrame* frame = GetPrimaryFrame();
509   if (!frame) {
510     return FilterPrimitiveDescription(PrimitiveType::Empty);
511   }
512 
513   nsStyleContext* style = frame->StyleContext();
514   Color color(Color::FromABGR(style->StyleSVGReset()->mLightingColor));
515   color.a = 1.f;
516   float surfaceScale = mNumberAttributes[SURFACE_SCALE].GetAnimValue();
517   Size kernelUnitLength =
518     GetKernelUnitLength(aInstance, &mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
519 
520   if (kernelUnitLength.width <= 0 || kernelUnitLength.height <= 0) {
521     // According to spec, A negative or zero value is an error. See link below for details.
522     // https://www.w3.org/TR/SVG/filters.html#feSpecularLightingKernelUnitLengthAttribute
523     return FilterPrimitiveDescription(PrimitiveType::Empty);
524   }
525 
526   FilterPrimitiveDescription& descr = aDescription;
527   descr.Attributes().Set(eLightingLight, ComputeLightAttributes(aInstance));
528   descr.Attributes().Set(eLightingSurfaceScale, surfaceScale);
529   descr.Attributes().Set(eLightingKernelUnitLength, kernelUnitLength);
530   descr.Attributes().Set(eLightingColor, color);
531   return descr;
532 }
533 
534 bool
AttributeAffectsRendering(int32_t aNameSpaceID,nsIAtom * aAttribute) const535 nsSVGFELightingElement::AttributeAffectsRendering(int32_t aNameSpaceID,
536                                                   nsIAtom* aAttribute) const
537 {
538   return nsSVGFELightingElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
539          (aNameSpaceID == kNameSpaceID_None &&
540           (aAttribute == nsGkAtoms::in ||
541            aAttribute == nsGkAtoms::surfaceScale ||
542            aAttribute == nsGkAtoms::kernelUnitLength));
543 }
544 
545 //----------------------------------------------------------------------
546 // nsSVGElement methods
547 
548 nsSVGElement::NumberAttributesInfo
GetNumberInfo()549 nsSVGFELightingElement::GetNumberInfo()
550 {
551   return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
552                               ArrayLength(sNumberInfo));
553 }
554 
555 nsSVGElement::NumberPairAttributesInfo
GetNumberPairInfo()556 nsSVGFELightingElement::GetNumberPairInfo()
557 {
558   return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo,
559                                   ArrayLength(sNumberPairInfo));
560 }
561 
562 nsSVGElement::StringAttributesInfo
GetStringInfo()563 nsSVGFELightingElement::GetStringInfo()
564 {
565   return StringAttributesInfo(mStringAttributes, sStringInfo,
566                               ArrayLength(sStringInfo));
567 }
568