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, &litude,
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