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 return aInputsAreTainted
.Contains(true);
71 bool SVGFilterPrimitiveElement::AttributeAffectsRendering(
72 int32_t aNameSpaceID
, nsAtom
* aAttribute
) const {
73 return aNameSpaceID
== kNameSpaceID_None
&&
74 (aAttribute
== nsGkAtoms::x
|| aAttribute
== nsGkAtoms::y
||
75 aAttribute
== nsGkAtoms::width
|| aAttribute
== nsGkAtoms::height
||
76 aAttribute
== nsGkAtoms::result
);
79 already_AddRefed
<DOMSVGAnimatedLength
> SVGFilterPrimitiveElement::X() {
80 return mLengthAttributes
[ATTR_X
].ToDOMAnimatedLength(this);
83 already_AddRefed
<DOMSVGAnimatedLength
> SVGFilterPrimitiveElement::Y() {
84 return mLengthAttributes
[ATTR_Y
].ToDOMAnimatedLength(this);
87 already_AddRefed
<DOMSVGAnimatedLength
> SVGFilterPrimitiveElement::Width() {
88 return mLengthAttributes
[ATTR_WIDTH
].ToDOMAnimatedLength(this);
91 already_AddRefed
<DOMSVGAnimatedLength
> SVGFilterPrimitiveElement::Height() {
92 return mLengthAttributes
[ATTR_HEIGHT
].ToDOMAnimatedLength(this);
95 already_AddRefed
<DOMSVGAnimatedString
> SVGFilterPrimitiveElement::Result() {
96 return GetResultImageName().ToDOMAnimatedString(this);
99 //----------------------------------------------------------------------
100 // SVGElement methods
102 bool SVGFilterPrimitiveElement::StyleIsSetToSRGB() {
103 nsIFrame
* frame
= GetPrimaryFrame();
104 if (!frame
) return false;
106 ComputedStyle
* style
= frame
->Style();
107 return style
->StyleSVG()->mColorInterpolationFilters
==
108 StyleColorInterpolation::Srgb
;
112 bool SVGFilterPrimitiveElement::HasValidDimensions() const {
113 return (!mLengthAttributes
[ATTR_WIDTH
].IsExplicitlySet() ||
114 mLengthAttributes
[ATTR_WIDTH
].GetAnimValInSpecifiedUnits() > 0) &&
115 (!mLengthAttributes
[ATTR_HEIGHT
].IsExplicitlySet() ||
116 mLengthAttributes
[ATTR_HEIGHT
].GetAnimValInSpecifiedUnits() > 0);
119 Size
SVGFilterPrimitiveElement::GetKernelUnitLength(
120 SVGFilterInstance
* aInstance
, SVGAnimatedNumberPair
* aKernelUnitLength
) {
121 if (!aKernelUnitLength
->IsExplicitlySet()) {
125 float kernelX
= aInstance
->GetPrimitiveNumber(
126 SVGContentUtils::X
, aKernelUnitLength
, SVGAnimatedNumberPair::eFirst
);
127 float kernelY
= aInstance
->GetPrimitiveNumber(
128 SVGContentUtils::Y
, aKernelUnitLength
, SVGAnimatedNumberPair::eSecond
);
129 return Size(kernelX
, kernelY
);
132 SVGElement::LengthAttributesInfo
SVGFilterPrimitiveElement::GetLengthInfo() {
133 return LengthAttributesInfo(mLengthAttributes
, sLengthInfo
,
134 std::size(sLengthInfo
));
137 SVGElement::NumberListInfo
138 SVGComponentTransferFunctionElement::sNumberListInfo
[1] = {
139 {nsGkAtoms::tableValues
}};
141 SVGElement::NumberInfo
SVGComponentTransferFunctionElement::sNumberInfo
[5] = {
142 {nsGkAtoms::slope
, 1},
143 {nsGkAtoms::intercept
, 0},
144 {nsGkAtoms::amplitude
, 1},
145 {nsGkAtoms::exponent
, 1},
146 {nsGkAtoms::offset
, 0}};
148 SVGEnumMapping
SVGComponentTransferFunctionElement::sTypeMap
[] = {
149 {nsGkAtoms::identity
, SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY
},
150 {nsGkAtoms::table
, SVG_FECOMPONENTTRANSFER_TYPE_TABLE
},
151 {nsGkAtoms::discrete
, SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE
},
152 {nsGkAtoms::linear
, SVG_FECOMPONENTTRANSFER_TYPE_LINEAR
},
153 {nsGkAtoms::gamma
, SVG_FECOMPONENTTRANSFER_TYPE_GAMMA
},
156 SVGElement::EnumInfo
SVGComponentTransferFunctionElement::sEnumInfo
[1] = {
157 {nsGkAtoms::type
, sTypeMap
, SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY
}};
159 //----------------------------------------------------------------------
160 // nsSVGFilterPrimitiveChildElement methods
162 bool SVGComponentTransferFunctionElement::AttributeAffectsRendering(
163 int32_t aNameSpaceID
, nsAtom
* aAttribute
) const {
164 return aNameSpaceID
== kNameSpaceID_None
&&
165 (aAttribute
== nsGkAtoms::tableValues
||
166 aAttribute
== nsGkAtoms::slope
||
167 aAttribute
== nsGkAtoms::intercept
||
168 aAttribute
== nsGkAtoms::amplitude
||
169 aAttribute
== nsGkAtoms::exponent
||
170 aAttribute
== nsGkAtoms::offset
|| aAttribute
== nsGkAtoms::type
);
173 //----------------------------------------------------------------------
175 already_AddRefed
<DOMSVGAnimatedEnumeration
>
176 SVGComponentTransferFunctionElement::Type() {
177 return mEnumAttributes
[TYPE
].ToDOMAnimatedEnum(this);
180 already_AddRefed
<DOMSVGAnimatedNumberList
>
181 SVGComponentTransferFunctionElement::TableValues() {
182 return DOMSVGAnimatedNumberList::GetDOMWrapper(
183 &mNumberListAttributes
[TABLEVALUES
], this, TABLEVALUES
);
186 already_AddRefed
<DOMSVGAnimatedNumber
>
187 SVGComponentTransferFunctionElement::Slope() {
188 return mNumberAttributes
[SLOPE
].ToDOMAnimatedNumber(this);
191 already_AddRefed
<DOMSVGAnimatedNumber
>
192 SVGComponentTransferFunctionElement::Intercept() {
193 return mNumberAttributes
[INTERCEPT
].ToDOMAnimatedNumber(this);
196 already_AddRefed
<DOMSVGAnimatedNumber
>
197 SVGComponentTransferFunctionElement::Amplitude() {
198 return mNumberAttributes
[AMPLITUDE
].ToDOMAnimatedNumber(this);
201 already_AddRefed
<DOMSVGAnimatedNumber
>
202 SVGComponentTransferFunctionElement::Exponent() {
203 return mNumberAttributes
[EXPONENT
].ToDOMAnimatedNumber(this);
206 already_AddRefed
<DOMSVGAnimatedNumber
>
207 SVGComponentTransferFunctionElement::Offset() {
208 return mNumberAttributes
[OFFSET
].ToDOMAnimatedNumber(this);
211 void SVGComponentTransferFunctionElement::ComputeAttributes(
212 int32_t aChannel
, ComponentTransferAttributes
& aAttributes
) {
213 uint32_t type
= mEnumAttributes
[TYPE
].GetAnimValue();
215 float slope
, intercept
, amplitude
, exponent
, offset
;
216 GetAnimatedNumberValues(&slope
, &intercept
, &litude
, &exponent
, &offset
,
219 const SVGNumberList
& tableValues
=
220 mNumberListAttributes
[TABLEVALUES
].GetAnimValue();
222 aAttributes
.mTypes
[aChannel
] = (uint8_t)type
;
224 case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR
: {
225 aAttributes
.mValues
[aChannel
].SetLength(2);
226 aAttributes
.mValues
[aChannel
][kComponentTransferSlopeIndex
] = slope
;
227 aAttributes
.mValues
[aChannel
][kComponentTransferInterceptIndex
] =
231 case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA
: {
232 aAttributes
.mValues
[aChannel
].SetLength(3);
233 aAttributes
.mValues
[aChannel
][kComponentTransferAmplitudeIndex
] =
235 aAttributes
.mValues
[aChannel
][kComponentTransferExponentIndex
] = exponent
;
236 aAttributes
.mValues
[aChannel
][kComponentTransferOffsetIndex
] = offset
;
239 case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE
:
240 case SVG_FECOMPONENTTRANSFER_TYPE_TABLE
: {
241 if (!tableValues
.IsEmpty()) {
242 aAttributes
.mValues
[aChannel
].AppendElements(&tableValues
[0],
243 tableValues
.Length());
250 //----------------------------------------------------------------------
251 // SVGElement methods
253 SVGElement::NumberListAttributesInfo
254 SVGComponentTransferFunctionElement::GetNumberListInfo() {
255 return NumberListAttributesInfo(mNumberListAttributes
, sNumberListInfo
,
256 std::size(sNumberListInfo
));
259 SVGElement::EnumAttributesInfo
260 SVGComponentTransferFunctionElement::GetEnumInfo() {
261 return EnumAttributesInfo(mEnumAttributes
, sEnumInfo
, std::size(sEnumInfo
));
264 SVGElement::NumberAttributesInfo
265 SVGComponentTransferFunctionElement::GetNumberInfo() {
266 return NumberAttributesInfo(mNumberAttributes
, sNumberInfo
,
267 std::size(sNumberInfo
));
271 JSObject
* SVGFEFuncRElement::WrapNode(JSContext
* aCx
,
272 JS::Handle
<JSObject
*> aGivenProto
) {
273 return SVGFEFuncRElement_Binding::Wrap(aCx
, this, aGivenProto
);
276 } // namespace mozilla::dom
278 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncR
)
280 namespace mozilla::dom
{
282 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncRElement
)
285 JSObject
* SVGFEFuncGElement::WrapNode(JSContext
* aCx
,
286 JS::Handle
<JSObject
*> aGivenProto
) {
287 return SVGFEFuncGElement_Binding::Wrap(aCx
, this, aGivenProto
);
290 } // namespace mozilla::dom
292 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncG
)
294 namespace mozilla::dom
{
296 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncGElement
)
299 JSObject
* SVGFEFuncBElement::WrapNode(JSContext
* aCx
,
300 JS::Handle
<JSObject
*> aGivenProto
) {
301 return SVGFEFuncBElement_Binding::Wrap(aCx
, this, aGivenProto
);
304 } // namespace mozilla::dom
306 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncB
)
308 namespace mozilla::dom
{
310 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncBElement
)
313 JSObject
* SVGFEFuncAElement::WrapNode(JSContext
* aCx
,
314 JS::Handle
<JSObject
*> aGivenProto
) {
315 return SVGFEFuncAElement_Binding::Wrap(aCx
, this, aGivenProto
);
318 } // namespace mozilla::dom
320 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncA
)
322 namespace mozilla::dom
{
324 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncAElement
)
326 //--------------------------------------------------------------------
328 SVGElement::NumberInfo
SVGFELightingElement::sNumberInfo
[4] = {
329 {nsGkAtoms::surfaceScale
, 1},
330 {nsGkAtoms::diffuseConstant
, 1},
331 {nsGkAtoms::specularConstant
, 1},
332 {nsGkAtoms::specularExponent
, 1}};
334 SVGElement::NumberPairInfo
SVGFELightingElement::sNumberPairInfo
[1] = {
335 {nsGkAtoms::kernelUnitLength
, 0, 0}};
337 SVGElement::StringInfo
SVGFELightingElement::sStringInfo
[2] = {
338 {nsGkAtoms::result
, kNameSpaceID_None
, true},
339 {nsGkAtoms::in
, kNameSpaceID_None
, true}};
341 //----------------------------------------------------------------------
344 void SVGFELightingElement::GetSourceImageNames(
345 nsTArray
<SVGStringInfo
>& aSources
) {
346 aSources
.AppendElement(SVGStringInfo(&mStringAttributes
[IN1
], this));
349 LightType
SVGFELightingElement::ComputeLightAttributes(
350 SVGFilterInstance
* aInstance
, nsTArray
<float>& aFloatAttributes
) {
351 // find specified light
352 for (nsCOMPtr
<nsIContent
> child
= nsINode::GetFirstChild(); child
;
353 child
= child
->GetNextSibling()) {
354 if (child
->IsAnyOfSVGElements(nsGkAtoms::feDistantLight
,
355 nsGkAtoms::fePointLight
,
356 nsGkAtoms::feSpotLight
)) {
357 return static_cast<SVGFELightElement
*>(child
.get())
358 ->ComputeLightAttributes(aInstance
, aFloatAttributes
);
362 return LightType::None
;
365 bool SVGFELightingElement::AddLightingAttributes(
366 mozilla::gfx::DiffuseLightingAttributes
* aAttributes
,
367 SVGFilterInstance
* aInstance
) {
368 const auto* frame
= GetPrimaryFrame();
373 const nsStyleSVGReset
* styleSVGReset
= frame
->Style()->StyleSVGReset();
375 sRGBColor::FromABGR(styleSVGReset
->mLightingColor
.CalcColor(frame
)));
377 float surfaceScale
= mNumberAttributes
[SURFACE_SCALE
].GetAnimValue();
378 Size kernelUnitLength
= GetKernelUnitLength(
379 aInstance
, &mNumberPairAttributes
[KERNEL_UNIT_LENGTH
]);
381 if (kernelUnitLength
.width
<= 0 || kernelUnitLength
.height
<= 0) {
382 // According to spec, A negative or zero value is an error. See link below
384 // https://www.w3.org/TR/SVG/filters.html#feSpecularLightingKernelUnitLengthAttribute
388 aAttributes
->mLightType
=
389 ComputeLightAttributes(aInstance
, aAttributes
->mLightValues
);
390 aAttributes
->mSurfaceScale
= surfaceScale
;
391 aAttributes
->mKernelUnitLength
= kernelUnitLength
;
392 aAttributes
->mColor
= color
;
397 bool SVGFELightingElement::OutputIsTainted(
398 const nsTArray
<bool>& aInputsAreTainted
,
399 nsIPrincipal
* aReferencePrincipal
) {
400 if (const auto* frame
= GetPrimaryFrame()) {
401 if (frame
->Style()->StyleSVGReset()->mLightingColor
.IsCurrentColor()) {
406 return SVGFELightingElementBase::OutputIsTainted(aInputsAreTainted
,
407 aReferencePrincipal
);
410 bool SVGFELightingElement::AttributeAffectsRendering(int32_t aNameSpaceID
,
411 nsAtom
* aAttribute
) const {
412 return SVGFELightingElementBase::AttributeAffectsRendering(aNameSpaceID
,
414 (aNameSpaceID
== kNameSpaceID_None
&&
415 (aAttribute
== nsGkAtoms::in
||
416 aAttribute
== nsGkAtoms::surfaceScale
||
417 aAttribute
== nsGkAtoms::kernelUnitLength
));
420 //----------------------------------------------------------------------
421 // SVGElement methods
423 SVGElement::NumberAttributesInfo
SVGFELightingElement::GetNumberInfo() {
424 return NumberAttributesInfo(mNumberAttributes
, sNumberInfo
,
425 std::size(sNumberInfo
));
428 SVGElement::NumberPairAttributesInfo
SVGFELightingElement::GetNumberPairInfo() {
429 return NumberPairAttributesInfo(mNumberPairAttributes
, sNumberPairInfo
,
430 std::size(sNumberPairInfo
));
433 SVGElement::StringAttributesInfo
SVGFELightingElement::GetStringInfo() {
434 return StringAttributesInfo(mStringAttributes
, sStringInfo
,
435 std::size(sStringInfo
));
438 } // namespace mozilla::dom