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/. */
7 #include "SVGFilters.h"
10 #include "DOMSVGAnimatedNumberList.h"
11 #include "DOMSVGAnimatedLength.h"
12 #include "nsGkAtoms.h"
15 #include "nsLayoutUtils.h"
16 #include "SVGAnimatedEnumeration.h"
17 #include "SVGAnimatedNumberPair.h"
18 #include "SVGAnimatedString.h"
19 #include "SVGNumberList.h"
20 #include "mozilla/ArrayUtils.h"
21 #include "mozilla/ComputedStyle.h"
22 #include "mozilla/SVGContentUtils.h"
23 #include "mozilla/SVGFilterInstance.h"
24 #include "mozilla/dom/SVGComponentTransferFunctionElement.h"
25 #include "mozilla/dom/SVGElement.h"
26 #include "mozilla/dom/SVGFEDistantLightElement.h"
27 #include "mozilla/dom/SVGFEFuncAElementBinding.h"
28 #include "mozilla/dom/SVGFEFuncBElementBinding.h"
29 #include "mozilla/dom/SVGFEFuncGElementBinding.h"
30 #include "mozilla/dom/SVGFEFuncRElementBinding.h"
31 #include "mozilla/dom/SVGFEPointLightElement.h"
32 #include "mozilla/dom/SVGFESpotLightElement.h"
33 #include "mozilla/dom/SVGFilterElement.h"
34 #include "mozilla/dom/SVGLengthBinding.h"
37 // Prevent Windows redefining LoadImage
41 using namespace mozilla::gfx
;
43 namespace mozilla::dom
{
45 //--------------------Filter Element Base Class-----------------------
47 SVGElement::LengthInfo
SVGFilterPrimitiveElement::sLengthInfo
[4] = {
48 {nsGkAtoms::x
, 0, SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE
,
50 {nsGkAtoms::y
, 0, SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE
,
52 {nsGkAtoms::width
, 100, SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE
,
54 {nsGkAtoms::height
, 100, SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE
,
57 //----------------------------------------------------------------------
60 void SVGFilterPrimitiveElement::GetSourceImageNames(
61 nsTArray
<SVGStringInfo
>& aSources
) {}
63 bool SVGFilterPrimitiveElement::OutputIsTainted(
64 const nsTArray
<bool>& aInputsAreTainted
,
65 nsIPrincipal
* aReferencePrincipal
) {
66 // This is the default implementation for OutputIsTainted.
67 // Our output is tainted if we have at least one tainted input.
68 for (uint32_t i
= 0; i
< aInputsAreTainted
.Length(); i
++) {
69 if (aInputsAreTainted
[i
]) {
76 bool SVGFilterPrimitiveElement::AttributeAffectsRendering(
77 int32_t aNameSpaceID
, nsAtom
* aAttribute
) const {
78 return aNameSpaceID
== kNameSpaceID_None
&&
79 (aAttribute
== nsGkAtoms::x
|| aAttribute
== nsGkAtoms::y
||
80 aAttribute
== nsGkAtoms::width
|| aAttribute
== nsGkAtoms::height
||
81 aAttribute
== nsGkAtoms::result
);
84 already_AddRefed
<DOMSVGAnimatedLength
> SVGFilterPrimitiveElement::X() {
85 return mLengthAttributes
[ATTR_X
].ToDOMAnimatedLength(this);
88 already_AddRefed
<DOMSVGAnimatedLength
> SVGFilterPrimitiveElement::Y() {
89 return mLengthAttributes
[ATTR_Y
].ToDOMAnimatedLength(this);
92 already_AddRefed
<DOMSVGAnimatedLength
> SVGFilterPrimitiveElement::Width() {
93 return mLengthAttributes
[ATTR_WIDTH
].ToDOMAnimatedLength(this);
96 already_AddRefed
<DOMSVGAnimatedLength
> SVGFilterPrimitiveElement::Height() {
97 return mLengthAttributes
[ATTR_HEIGHT
].ToDOMAnimatedLength(this);
100 already_AddRefed
<DOMSVGAnimatedString
> SVGFilterPrimitiveElement::Result() {
101 return GetResultImageName().ToDOMAnimatedString(this);
104 //----------------------------------------------------------------------
105 // SVGElement methods
107 bool SVGFilterPrimitiveElement::StyleIsSetToSRGB() {
108 nsIFrame
* frame
= GetPrimaryFrame();
109 if (!frame
) return false;
111 ComputedStyle
* style
= frame
->Style();
112 return style
->StyleSVG()->mColorInterpolationFilters
==
113 StyleColorInterpolation::Srgb
;
117 bool SVGFilterPrimitiveElement::HasValidDimensions() const {
118 return (!mLengthAttributes
[ATTR_WIDTH
].IsExplicitlySet() ||
119 mLengthAttributes
[ATTR_WIDTH
].GetAnimValInSpecifiedUnits() > 0) &&
120 (!mLengthAttributes
[ATTR_HEIGHT
].IsExplicitlySet() ||
121 mLengthAttributes
[ATTR_HEIGHT
].GetAnimValInSpecifiedUnits() > 0);
124 Size
SVGFilterPrimitiveElement::GetKernelUnitLength(
125 SVGFilterInstance
* aInstance
, SVGAnimatedNumberPair
* aKernelUnitLength
) {
126 if (!aKernelUnitLength
->IsExplicitlySet()) {
130 float kernelX
= aInstance
->GetPrimitiveNumber(
131 SVGContentUtils::X
, aKernelUnitLength
, SVGAnimatedNumberPair::eFirst
);
132 float kernelY
= aInstance
->GetPrimitiveNumber(
133 SVGContentUtils::Y
, aKernelUnitLength
, SVGAnimatedNumberPair::eSecond
);
134 return Size(kernelX
, kernelY
);
137 SVGElement::LengthAttributesInfo
SVGFilterPrimitiveElement::GetLengthInfo() {
138 return LengthAttributesInfo(mLengthAttributes
, sLengthInfo
,
139 ArrayLength(sLengthInfo
));
142 SVGElement::NumberListInfo
143 SVGComponentTransferFunctionElement::sNumberListInfo
[1] = {
144 {nsGkAtoms::tableValues
}};
146 SVGElement::NumberInfo
SVGComponentTransferFunctionElement::sNumberInfo
[5] = {
147 {nsGkAtoms::slope
, 1},
148 {nsGkAtoms::intercept
, 0},
149 {nsGkAtoms::amplitude
, 1},
150 {nsGkAtoms::exponent
, 1},
151 {nsGkAtoms::offset
, 0}};
153 SVGEnumMapping
SVGComponentTransferFunctionElement::sTypeMap
[] = {
154 {nsGkAtoms::identity
, SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY
},
155 {nsGkAtoms::table
, SVG_FECOMPONENTTRANSFER_TYPE_TABLE
},
156 {nsGkAtoms::discrete
, SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE
},
157 {nsGkAtoms::linear
, SVG_FECOMPONENTTRANSFER_TYPE_LINEAR
},
158 {nsGkAtoms::gamma
, SVG_FECOMPONENTTRANSFER_TYPE_GAMMA
},
161 SVGElement::EnumInfo
SVGComponentTransferFunctionElement::sEnumInfo
[1] = {
162 {nsGkAtoms::type
, sTypeMap
, SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY
}};
164 //----------------------------------------------------------------------
165 // nsSVGFilterPrimitiveChildElement methods
167 bool SVGComponentTransferFunctionElement::AttributeAffectsRendering(
168 int32_t aNameSpaceID
, nsAtom
* aAttribute
) const {
169 return aNameSpaceID
== kNameSpaceID_None
&&
170 (aAttribute
== nsGkAtoms::tableValues
||
171 aAttribute
== nsGkAtoms::slope
||
172 aAttribute
== nsGkAtoms::intercept
||
173 aAttribute
== nsGkAtoms::amplitude
||
174 aAttribute
== nsGkAtoms::exponent
||
175 aAttribute
== nsGkAtoms::offset
|| aAttribute
== nsGkAtoms::type
);
178 //----------------------------------------------------------------------
180 already_AddRefed
<DOMSVGAnimatedEnumeration
>
181 SVGComponentTransferFunctionElement::Type() {
182 return mEnumAttributes
[TYPE
].ToDOMAnimatedEnum(this);
185 already_AddRefed
<DOMSVGAnimatedNumberList
>
186 SVGComponentTransferFunctionElement::TableValues() {
187 return DOMSVGAnimatedNumberList::GetDOMWrapper(
188 &mNumberListAttributes
[TABLEVALUES
], this, TABLEVALUES
);
191 already_AddRefed
<DOMSVGAnimatedNumber
>
192 SVGComponentTransferFunctionElement::Slope() {
193 return mNumberAttributes
[SLOPE
].ToDOMAnimatedNumber(this);
196 already_AddRefed
<DOMSVGAnimatedNumber
>
197 SVGComponentTransferFunctionElement::Intercept() {
198 return mNumberAttributes
[INTERCEPT
].ToDOMAnimatedNumber(this);
201 already_AddRefed
<DOMSVGAnimatedNumber
>
202 SVGComponentTransferFunctionElement::Amplitude() {
203 return mNumberAttributes
[AMPLITUDE
].ToDOMAnimatedNumber(this);
206 already_AddRefed
<DOMSVGAnimatedNumber
>
207 SVGComponentTransferFunctionElement::Exponent() {
208 return mNumberAttributes
[EXPONENT
].ToDOMAnimatedNumber(this);
211 already_AddRefed
<DOMSVGAnimatedNumber
>
212 SVGComponentTransferFunctionElement::Offset() {
213 return mNumberAttributes
[OFFSET
].ToDOMAnimatedNumber(this);
216 void SVGComponentTransferFunctionElement::ComputeAttributes(
217 int32_t aChannel
, ComponentTransferAttributes
& aAttributes
) {
218 uint32_t type
= mEnumAttributes
[TYPE
].GetAnimValue();
220 float slope
, intercept
, amplitude
, exponent
, offset
;
221 GetAnimatedNumberValues(&slope
, &intercept
, &litude
, &exponent
, &offset
,
224 const SVGNumberList
& tableValues
=
225 mNumberListAttributes
[TABLEVALUES
].GetAnimValue();
227 aAttributes
.mTypes
[aChannel
] = (uint8_t)type
;
229 case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR
: {
230 aAttributes
.mValues
[aChannel
].SetLength(2);
231 aAttributes
.mValues
[aChannel
][kComponentTransferSlopeIndex
] = slope
;
232 aAttributes
.mValues
[aChannel
][kComponentTransferInterceptIndex
] =
236 case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA
: {
237 aAttributes
.mValues
[aChannel
].SetLength(3);
238 aAttributes
.mValues
[aChannel
][kComponentTransferAmplitudeIndex
] =
240 aAttributes
.mValues
[aChannel
][kComponentTransferExponentIndex
] = exponent
;
241 aAttributes
.mValues
[aChannel
][kComponentTransferOffsetIndex
] = offset
;
244 case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE
:
245 case SVG_FECOMPONENTTRANSFER_TYPE_TABLE
: {
246 if (!tableValues
.IsEmpty()) {
247 aAttributes
.mValues
[aChannel
].AppendElements(&tableValues
[0],
248 tableValues
.Length());
255 //----------------------------------------------------------------------
256 // SVGElement methods
258 SVGElement::NumberListAttributesInfo
259 SVGComponentTransferFunctionElement::GetNumberListInfo() {
260 return NumberListAttributesInfo(mNumberListAttributes
, sNumberListInfo
,
261 ArrayLength(sNumberListInfo
));
264 SVGElement::EnumAttributesInfo
265 SVGComponentTransferFunctionElement::GetEnumInfo() {
266 return EnumAttributesInfo(mEnumAttributes
, sEnumInfo
, ArrayLength(sEnumInfo
));
269 SVGElement::NumberAttributesInfo
270 SVGComponentTransferFunctionElement::GetNumberInfo() {
271 return NumberAttributesInfo(mNumberAttributes
, sNumberInfo
,
272 ArrayLength(sNumberInfo
));
276 JSObject
* SVGFEFuncRElement::WrapNode(JSContext
* aCx
,
277 JS::Handle
<JSObject
*> aGivenProto
) {
278 return SVGFEFuncRElement_Binding::Wrap(aCx
, this, aGivenProto
);
281 } // namespace mozilla::dom
283 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncR
)
285 namespace mozilla::dom
{
287 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncRElement
)
290 JSObject
* SVGFEFuncGElement::WrapNode(JSContext
* aCx
,
291 JS::Handle
<JSObject
*> aGivenProto
) {
292 return SVGFEFuncGElement_Binding::Wrap(aCx
, this, aGivenProto
);
295 } // namespace mozilla::dom
297 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncG
)
299 namespace mozilla::dom
{
301 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncGElement
)
304 JSObject
* SVGFEFuncBElement::WrapNode(JSContext
* aCx
,
305 JS::Handle
<JSObject
*> aGivenProto
) {
306 return SVGFEFuncBElement_Binding::Wrap(aCx
, this, aGivenProto
);
309 } // namespace mozilla::dom
311 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncB
)
313 namespace mozilla::dom
{
315 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncBElement
)
318 JSObject
* SVGFEFuncAElement::WrapNode(JSContext
* aCx
,
319 JS::Handle
<JSObject
*> aGivenProto
) {
320 return SVGFEFuncAElement_Binding::Wrap(aCx
, this, aGivenProto
);
323 } // namespace mozilla::dom
325 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncA
)
327 namespace mozilla::dom
{
329 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncAElement
)
331 //--------------------------------------------------------------------
333 SVGElement::NumberInfo
SVGFELightingElement::sNumberInfo
[4] = {
334 {nsGkAtoms::surfaceScale
, 1},
335 {nsGkAtoms::diffuseConstant
, 1},
336 {nsGkAtoms::specularConstant
, 1},
337 {nsGkAtoms::specularExponent
, 1}};
339 SVGElement::NumberPairInfo
SVGFELightingElement::sNumberPairInfo
[1] = {
340 {nsGkAtoms::kernelUnitLength
, 0, 0}};
342 SVGElement::StringInfo
SVGFELightingElement::sStringInfo
[2] = {
343 {nsGkAtoms::result
, kNameSpaceID_None
, true},
344 {nsGkAtoms::in
, kNameSpaceID_None
, true}};
346 //----------------------------------------------------------------------
349 void SVGFELightingElement::GetSourceImageNames(
350 nsTArray
<SVGStringInfo
>& aSources
) {
351 aSources
.AppendElement(SVGStringInfo(&mStringAttributes
[IN1
], this));
354 LightType
SVGFELightingElement::ComputeLightAttributes(
355 SVGFilterInstance
* aInstance
, nsTArray
<float>& aFloatAttributes
) {
356 // find specified light
357 for (nsCOMPtr
<nsIContent
> child
= nsINode::GetFirstChild(); child
;
358 child
= child
->GetNextSibling()) {
359 if (child
->IsAnyOfSVGElements(nsGkAtoms::feDistantLight
,
360 nsGkAtoms::fePointLight
,
361 nsGkAtoms::feSpotLight
)) {
362 return static_cast<SVGFELightElement
*>(child
.get())
363 ->ComputeLightAttributes(aInstance
, aFloatAttributes
);
367 return LightType::None
;
370 bool SVGFELightingElement::AddLightingAttributes(
371 mozilla::gfx::DiffuseLightingAttributes
* aAttributes
,
372 SVGFilterInstance
* aInstance
) {
373 nsIFrame
* frame
= GetPrimaryFrame();
378 const nsStyleSVGReset
* styleSVGReset
= frame
->Style()->StyleSVGReset();
380 sRGBColor::FromABGR(styleSVGReset
->mLightingColor
.CalcColor(frame
)));
382 float surfaceScale
= mNumberAttributes
[SURFACE_SCALE
].GetAnimValue();
383 Size kernelUnitLength
= GetKernelUnitLength(
384 aInstance
, &mNumberPairAttributes
[KERNEL_UNIT_LENGTH
]);
386 if (kernelUnitLength
.width
<= 0 || kernelUnitLength
.height
<= 0) {
387 // According to spec, A negative or zero value is an error. See link below
389 // https://www.w3.org/TR/SVG/filters.html#feSpecularLightingKernelUnitLengthAttribute
393 aAttributes
->mLightType
=
394 ComputeLightAttributes(aInstance
, aAttributes
->mLightValues
);
395 aAttributes
->mSurfaceScale
= surfaceScale
;
396 aAttributes
->mKernelUnitLength
= kernelUnitLength
;
397 aAttributes
->mColor
= color
;
402 bool SVGFELightingElement::AttributeAffectsRendering(int32_t aNameSpaceID
,
403 nsAtom
* aAttribute
) const {
404 return SVGFELightingElementBase::AttributeAffectsRendering(aNameSpaceID
,
406 (aNameSpaceID
== kNameSpaceID_None
&&
407 (aAttribute
== nsGkAtoms::in
||
408 aAttribute
== nsGkAtoms::surfaceScale
||
409 aAttribute
== nsGkAtoms::kernelUnitLength
));
412 //----------------------------------------------------------------------
413 // SVGElement methods
415 SVGElement::NumberAttributesInfo
SVGFELightingElement::GetNumberInfo() {
416 return NumberAttributesInfo(mNumberAttributes
, sNumberInfo
,
417 ArrayLength(sNumberInfo
));
420 SVGElement::NumberPairAttributesInfo
SVGFELightingElement::GetNumberPairInfo() {
421 return NumberPairAttributesInfo(mNumberPairAttributes
, sNumberPairInfo
,
422 ArrayLength(sNumberPairInfo
));
425 SVGElement::StringAttributesInfo
SVGFELightingElement::GetStringInfo() {
426 return StringAttributesInfo(mStringAttributes
, sStringInfo
,
427 ArrayLength(sStringInfo
));
430 } // namespace mozilla::dom