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 "SVGFilters.h"
8
9 #include <algorithm>
10 #include "DOMSVGAnimatedNumberList.h"
11 #include "DOMSVGAnimatedLength.h"
12 #include "nsGkAtoms.h"
13 #include "nsCOMPtr.h"
14 #include "nsIFrame.h"
15 #include "nsLayoutUtils.h"
16 #include "SVGAnimatedEnumeration.h"
17 #include "SVGAnimatedNumberPair.h"
18 #include "SVGAnimatedString.h"
19 #include "nsSVGFilterInstance.h"
20 #include "SVGNumberList.h"
21 #include "mozilla/ArrayUtils.h"
22 #include "mozilla/ComputedStyle.h"
23 #include "mozilla/SVGContentUtils.h"
24 #include "nsSVGUtils.h"
25 #include "mozilla/dom/SVGComponentTransferFunctionElement.h"
26 #include "mozilla/dom/SVGElement.h"
27 #include "mozilla/dom/SVGFEDistantLightElement.h"
28 #include "mozilla/dom/SVGFEFuncAElementBinding.h"
29 #include "mozilla/dom/SVGFEFuncBElementBinding.h"
30 #include "mozilla/dom/SVGFEFuncGElementBinding.h"
31 #include "mozilla/dom/SVGFEFuncRElementBinding.h"
32 #include "mozilla/dom/SVGFEPointLightElement.h"
33 #include "mozilla/dom/SVGFESpotLightElement.h"
34 #include "mozilla/dom/SVGFilterElement.h"
35 #include "mozilla/dom/SVGLengthBinding.h"
36
37 #if defined(XP_WIN)
38 // Prevent Windows redefining LoadImage
39 # undef LoadImage
40 #endif
41
42 using namespace mozilla::gfx;
43
44 namespace mozilla {
45 namespace dom {
46
47 //--------------------Filter Element Base Class-----------------------
48
49 SVGElement::LengthInfo SVGFE::sLengthInfo[4] = {
50 {nsGkAtoms::x, 0, SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE,
51 SVGContentUtils::X},
52 {nsGkAtoms::y, 0, SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE,
53 SVGContentUtils::Y},
54 {nsGkAtoms::width, 100, SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE,
55 SVGContentUtils::X},
56 {nsGkAtoms::height, 100, SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE,
57 SVGContentUtils::Y}};
58
59 //----------------------------------------------------------------------
60 // nsISupports methods
61
NS_IMPL_ADDREF_INHERITED(SVGFE,SVGFEBase)62 NS_IMPL_ADDREF_INHERITED(SVGFE, SVGFEBase)
63 NS_IMPL_RELEASE_INHERITED(SVGFE, SVGFEBase)
64
65 NS_INTERFACE_MAP_BEGIN(SVGFE)
66 NS_INTERFACE_MAP_ENTRY_CONCRETE(SVGFE)
67 NS_INTERFACE_MAP_END_INHERITING(SVGFEBase)
68
69 //----------------------------------------------------------------------
70 // Implementation
71
72 void SVGFE::GetSourceImageNames(nsTArray<SVGStringInfo>& aSources) {}
73
OutputIsTainted(const nsTArray<bool> & aInputsAreTainted,nsIPrincipal * aReferencePrincipal)74 bool SVGFE::OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
75 nsIPrincipal* aReferencePrincipal) {
76 // This is the default implementation for OutputIsTainted.
77 // Our output is tainted if we have at least one tainted input.
78 for (uint32_t i = 0; i < aInputsAreTainted.Length(); i++) {
79 if (aInputsAreTainted[i]) {
80 return true;
81 }
82 }
83 return false;
84 }
85
AttributeAffectsRendering(int32_t aNameSpaceID,nsAtom * aAttribute) const86 bool SVGFE::AttributeAffectsRendering(int32_t aNameSpaceID,
87 nsAtom* aAttribute) const {
88 return aNameSpaceID == kNameSpaceID_None &&
89 (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y ||
90 aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height ||
91 aAttribute == nsGkAtoms::result);
92 }
93
X()94 already_AddRefed<DOMSVGAnimatedLength> SVGFE::X() {
95 return mLengthAttributes[ATTR_X].ToDOMAnimatedLength(this);
96 }
97
Y()98 already_AddRefed<DOMSVGAnimatedLength> SVGFE::Y() {
99 return mLengthAttributes[ATTR_Y].ToDOMAnimatedLength(this);
100 }
101
Width()102 already_AddRefed<DOMSVGAnimatedLength> SVGFE::Width() {
103 return mLengthAttributes[ATTR_WIDTH].ToDOMAnimatedLength(this);
104 }
105
Height()106 already_AddRefed<DOMSVGAnimatedLength> SVGFE::Height() {
107 return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
108 }
109
Result()110 already_AddRefed<DOMSVGAnimatedString> SVGFE::Result() {
111 return GetResultImageName().ToDOMAnimatedString(this);
112 }
113
114 //----------------------------------------------------------------------
115 // nsIContent methods
116
NS_IMETHODIMP_(bool)117 NS_IMETHODIMP_(bool)
118 SVGFE::IsAttributeMapped(const nsAtom* name) const {
119 static const MappedAttributeEntry* const map[] = {sFiltersMap};
120
121 return FindAttributeDependence(name, map) ||
122 SVGFEBase::IsAttributeMapped(name);
123 }
124
125 //----------------------------------------------------------------------
126 // SVGElement methods
127
StyleIsSetToSRGB()128 bool SVGFE::StyleIsSetToSRGB() {
129 nsIFrame* frame = GetPrimaryFrame();
130 if (!frame) return false;
131
132 ComputedStyle* style = frame->Style();
133 return style->StyleSVG()->mColorInterpolationFilters ==
134 StyleColorInterpolation::Srgb;
135 }
136
137 /* virtual */
HasValidDimensions() const138 bool SVGFE::HasValidDimensions() const {
139 return (!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
140 mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
141 (!mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() ||
142 mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0);
143 }
144
GetKernelUnitLength(nsSVGFilterInstance * aInstance,SVGAnimatedNumberPair * aKernelUnitLength)145 Size SVGFE::GetKernelUnitLength(nsSVGFilterInstance* aInstance,
146 SVGAnimatedNumberPair* aKernelUnitLength) {
147 if (!aKernelUnitLength->IsExplicitlySet()) {
148 return Size(1, 1);
149 }
150
151 float kernelX = aInstance->GetPrimitiveNumber(
152 SVGContentUtils::X, aKernelUnitLength, SVGAnimatedNumberPair::eFirst);
153 float kernelY = aInstance->GetPrimitiveNumber(
154 SVGContentUtils::Y, aKernelUnitLength, SVGAnimatedNumberPair::eSecond);
155 return Size(kernelX, kernelY);
156 }
157
GetLengthInfo()158 SVGElement::LengthAttributesInfo SVGFE::GetLengthInfo() {
159 return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
160 ArrayLength(sLengthInfo));
161 }
162
163 SVGElement::NumberListInfo
164 SVGComponentTransferFunctionElement::sNumberListInfo[1] = {
165 {nsGkAtoms::tableValues}};
166
167 SVGElement::NumberInfo SVGComponentTransferFunctionElement::sNumberInfo[5] = {
168 {nsGkAtoms::slope, 1, false},
169 {nsGkAtoms::intercept, 0, false},
170 {nsGkAtoms::amplitude, 1, false},
171 {nsGkAtoms::exponent, 1, false},
172 {nsGkAtoms::offset, 0, false}};
173
174 SVGEnumMapping SVGComponentTransferFunctionElement::sTypeMap[] = {
175 {nsGkAtoms::identity, SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY},
176 {nsGkAtoms::table, SVG_FECOMPONENTTRANSFER_TYPE_TABLE},
177 {nsGkAtoms::discrete, SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE},
178 {nsGkAtoms::linear, SVG_FECOMPONENTTRANSFER_TYPE_LINEAR},
179 {nsGkAtoms::gamma, SVG_FECOMPONENTTRANSFER_TYPE_GAMMA},
180 {nullptr, 0}};
181
182 SVGElement::EnumInfo SVGComponentTransferFunctionElement::sEnumInfo[1] = {
183 {nsGkAtoms::type, sTypeMap, SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY}};
184
185 //----------------------------------------------------------------------
186 // nsISupports methods
187
NS_IMPL_ADDREF_INHERITED(SVGComponentTransferFunctionElement,SVGComponentTransferFunctionElementBase)188 NS_IMPL_ADDREF_INHERITED(SVGComponentTransferFunctionElement,
189 SVGComponentTransferFunctionElementBase)
190 NS_IMPL_RELEASE_INHERITED(SVGComponentTransferFunctionElement,
191 SVGComponentTransferFunctionElementBase)
192
193 NS_INTERFACE_MAP_BEGIN(SVGComponentTransferFunctionElement)
194 NS_INTERFACE_MAP_ENTRY_CONCRETE(SVGComponentTransferFunctionElement)
195 NS_INTERFACE_MAP_END_INHERITING(SVGComponentTransferFunctionElementBase)
196
197 //----------------------------------------------------------------------
198 // nsFEUnstyledElement methods
199
200 bool SVGComponentTransferFunctionElement::AttributeAffectsRendering(
201 int32_t aNameSpaceID, nsAtom* aAttribute) const {
202 return aNameSpaceID == kNameSpaceID_None &&
203 (aAttribute == nsGkAtoms::tableValues ||
204 aAttribute == nsGkAtoms::slope ||
205 aAttribute == nsGkAtoms::intercept ||
206 aAttribute == nsGkAtoms::amplitude ||
207 aAttribute == nsGkAtoms::exponent ||
208 aAttribute == nsGkAtoms::offset || aAttribute == nsGkAtoms::type);
209 }
210
211 //----------------------------------------------------------------------
212
213 already_AddRefed<DOMSVGAnimatedEnumeration>
Type()214 SVGComponentTransferFunctionElement::Type() {
215 return mEnumAttributes[TYPE].ToDOMAnimatedEnum(this);
216 }
217
218 already_AddRefed<DOMSVGAnimatedNumberList>
TableValues()219 SVGComponentTransferFunctionElement::TableValues() {
220 return DOMSVGAnimatedNumberList::GetDOMWrapper(
221 &mNumberListAttributes[TABLEVALUES], this, TABLEVALUES);
222 }
223
224 already_AddRefed<DOMSVGAnimatedNumber>
Slope()225 SVGComponentTransferFunctionElement::Slope() {
226 return mNumberAttributes[SLOPE].ToDOMAnimatedNumber(this);
227 }
228
229 already_AddRefed<DOMSVGAnimatedNumber>
Intercept()230 SVGComponentTransferFunctionElement::Intercept() {
231 return mNumberAttributes[INTERCEPT].ToDOMAnimatedNumber(this);
232 }
233
234 already_AddRefed<DOMSVGAnimatedNumber>
Amplitude()235 SVGComponentTransferFunctionElement::Amplitude() {
236 return mNumberAttributes[AMPLITUDE].ToDOMAnimatedNumber(this);
237 }
238
239 already_AddRefed<DOMSVGAnimatedNumber>
Exponent()240 SVGComponentTransferFunctionElement::Exponent() {
241 return mNumberAttributes[EXPONENT].ToDOMAnimatedNumber(this);
242 }
243
244 already_AddRefed<DOMSVGAnimatedNumber>
Offset()245 SVGComponentTransferFunctionElement::Offset() {
246 return mNumberAttributes[OFFSET].ToDOMAnimatedNumber(this);
247 }
248
ComputeAttributes(int32_t aChannel,ComponentTransferAttributes & aAttributes)249 void SVGComponentTransferFunctionElement::ComputeAttributes(
250 int32_t aChannel, ComponentTransferAttributes& aAttributes) {
251 uint32_t type = mEnumAttributes[TYPE].GetAnimValue();
252
253 float slope, intercept, amplitude, exponent, offset;
254 GetAnimatedNumberValues(&slope, &intercept, &litude, &exponent, &offset,
255 nullptr);
256
257 const SVGNumberList& tableValues =
258 mNumberListAttributes[TABLEVALUES].GetAnimValue();
259
260 aAttributes.mTypes[aChannel] = (uint8_t)type;
261 switch (type) {
262 case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR: {
263 aAttributes.mValues[aChannel].SetLength(2);
264 aAttributes.mValues[aChannel][kComponentTransferSlopeIndex] = slope;
265 aAttributes.mValues[aChannel][kComponentTransferInterceptIndex] =
266 intercept;
267 break;
268 }
269 case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA: {
270 aAttributes.mValues[aChannel].SetLength(3);
271 aAttributes.mValues[aChannel][kComponentTransferAmplitudeIndex] =
272 amplitude;
273 aAttributes.mValues[aChannel][kComponentTransferExponentIndex] = exponent;
274 aAttributes.mValues[aChannel][kComponentTransferOffsetIndex] = offset;
275 break;
276 }
277 case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
278 case SVG_FECOMPONENTTRANSFER_TYPE_TABLE: {
279 if (!tableValues.IsEmpty()) {
280 aAttributes.mValues[aChannel].AppendElements(&tableValues[0],
281 tableValues.Length());
282 }
283 break;
284 }
285 }
286 }
287
288 //----------------------------------------------------------------------
289 // SVGElement methods
290
291 SVGElement::NumberListAttributesInfo
GetNumberListInfo()292 SVGComponentTransferFunctionElement::GetNumberListInfo() {
293 return NumberListAttributesInfo(mNumberListAttributes, sNumberListInfo,
294 ArrayLength(sNumberListInfo));
295 }
296
297 SVGElement::EnumAttributesInfo
GetEnumInfo()298 SVGComponentTransferFunctionElement::GetEnumInfo() {
299 return EnumAttributesInfo(mEnumAttributes, sEnumInfo, ArrayLength(sEnumInfo));
300 }
301
302 SVGElement::NumberAttributesInfo
GetNumberInfo()303 SVGComponentTransferFunctionElement::GetNumberInfo() {
304 return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
305 ArrayLength(sNumberInfo));
306 }
307
308 /* virtual */
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)309 JSObject* SVGFEFuncRElement::WrapNode(JSContext* aCx,
310 JS::Handle<JSObject*> aGivenProto) {
311 return SVGFEFuncRElement_Binding::Wrap(aCx, this, aGivenProto);
312 }
313
314 } // namespace dom
315 } // namespace mozilla
316
317 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncR)
318
319 namespace mozilla {
320 namespace dom {
321
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncRElement)322 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncRElement)
323
324 /* virtual */
325 JSObject* SVGFEFuncGElement::WrapNode(JSContext* aCx,
326 JS::Handle<JSObject*> aGivenProto) {
327 return SVGFEFuncGElement_Binding::Wrap(aCx, this, aGivenProto);
328 }
329
330 } // namespace dom
331 } // namespace mozilla
332
333 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncG)
334
335 namespace mozilla {
336 namespace dom {
337
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncGElement)338 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncGElement)
339
340 /* virtual */
341 JSObject* SVGFEFuncBElement::WrapNode(JSContext* aCx,
342 JS::Handle<JSObject*> aGivenProto) {
343 return SVGFEFuncBElement_Binding::Wrap(aCx, this, aGivenProto);
344 }
345
346 } // namespace dom
347 } // namespace mozilla
348
349 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncB)
350
351 namespace mozilla {
352 namespace dom {
353
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncBElement)354 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncBElement)
355
356 /* virtual */
357 JSObject* SVGFEFuncAElement::WrapNode(JSContext* aCx,
358 JS::Handle<JSObject*> aGivenProto) {
359 return SVGFEFuncAElement_Binding::Wrap(aCx, this, aGivenProto);
360 }
361
362 } // namespace dom
363 } // namespace mozilla
364
365 NS_IMPL_NS_NEW_SVG_ELEMENT(FEFuncA)
366
367 namespace mozilla {
368 namespace dom {
369
370 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncAElement)
371
372 //--------------------------------------------------------------------
373 //
374 SVGElement::NumberInfo SVGFELightingElement::sNumberInfo[4] = {
375 {nsGkAtoms::surfaceScale, 1, false},
376 {nsGkAtoms::diffuseConstant, 1, false},
377 {nsGkAtoms::specularConstant, 1, false},
378 {nsGkAtoms::specularExponent, 1, false}};
379
380 SVGElement::NumberPairInfo SVGFELightingElement::sNumberPairInfo[1] = {
381 {nsGkAtoms::kernelUnitLength, 0, 0}};
382
383 SVGElement::StringInfo SVGFELightingElement::sStringInfo[2] = {
384 {nsGkAtoms::result, kNameSpaceID_None, true},
385 {nsGkAtoms::in, kNameSpaceID_None, true}};
386
387 //----------------------------------------------------------------------
388 // Implementation
389
NS_IMETHODIMP_(bool)390 NS_IMETHODIMP_(bool)
391 SVGFELightingElement::IsAttributeMapped(const nsAtom* name) const {
392 static const MappedAttributeEntry* const map[] = {sColorMap,
393 sLightingEffectsMap};
394
395 return FindAttributeDependence(name, map) ||
396 SVGFELightingElementBase::IsAttributeMapped(name);
397 }
398
GetSourceImageNames(nsTArray<SVGStringInfo> & aSources)399 void SVGFELightingElement::GetSourceImageNames(
400 nsTArray<SVGStringInfo>& aSources) {
401 aSources.AppendElement(SVGStringInfo(&mStringAttributes[IN1], this));
402 }
403
ComputeLightAttributes(nsSVGFilterInstance * aInstance,nsTArray<float> & aFloatAttributes)404 LightType SVGFELightingElement::ComputeLightAttributes(
405 nsSVGFilterInstance* aInstance, nsTArray<float>& aFloatAttributes) {
406 // find specified light
407 for (nsCOMPtr<nsIContent> child = nsINode::GetFirstChild(); child;
408 child = child->GetNextSibling()) {
409 if (child->IsAnyOfSVGElements(nsGkAtoms::feDistantLight,
410 nsGkAtoms::fePointLight,
411 nsGkAtoms::feSpotLight)) {
412 return static_cast<SVGFELightElement*>(child.get())
413 ->ComputeLightAttributes(aInstance, aFloatAttributes);
414 }
415 }
416
417 return LightType::None;
418 }
419
AddLightingAttributes(mozilla::gfx::DiffuseLightingAttributes * aAttributes,nsSVGFilterInstance * aInstance)420 bool SVGFELightingElement::AddLightingAttributes(
421 mozilla::gfx::DiffuseLightingAttributes* aAttributes,
422 nsSVGFilterInstance* aInstance) {
423 nsIFrame* frame = GetPrimaryFrame();
424 if (!frame) {
425 return false;
426 }
427
428 const nsStyleSVGReset* styleSVGReset = frame->Style()->StyleSVGReset();
429 sRGBColor color(
430 sRGBColor::FromABGR(styleSVGReset->mLightingColor.CalcColor(frame)));
431 color.a = 1.f;
432 float surfaceScale = mNumberAttributes[SURFACE_SCALE].GetAnimValue();
433 Size kernelUnitLength = GetKernelUnitLength(
434 aInstance, &mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
435
436 if (kernelUnitLength.width <= 0 || kernelUnitLength.height <= 0) {
437 // According to spec, A negative or zero value is an error. See link below
438 // for details.
439 // https://www.w3.org/TR/SVG/filters.html#feSpecularLightingKernelUnitLengthAttribute
440 return false;
441 }
442
443 aAttributes->mLightType =
444 ComputeLightAttributes(aInstance, aAttributes->mLightValues);
445 aAttributes->mSurfaceScale = surfaceScale;
446 aAttributes->mKernelUnitLength = kernelUnitLength;
447 aAttributes->mColor = color;
448
449 return true;
450 }
451
AttributeAffectsRendering(int32_t aNameSpaceID,nsAtom * aAttribute) const452 bool SVGFELightingElement::AttributeAffectsRendering(int32_t aNameSpaceID,
453 nsAtom* aAttribute) const {
454 return SVGFELightingElementBase::AttributeAffectsRendering(aNameSpaceID,
455 aAttribute) ||
456 (aNameSpaceID == kNameSpaceID_None &&
457 (aAttribute == nsGkAtoms::in ||
458 aAttribute == nsGkAtoms::surfaceScale ||
459 aAttribute == nsGkAtoms::kernelUnitLength));
460 }
461
462 //----------------------------------------------------------------------
463 // SVGElement methods
464
GetNumberInfo()465 SVGElement::NumberAttributesInfo SVGFELightingElement::GetNumberInfo() {
466 return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
467 ArrayLength(sNumberInfo));
468 }
469
GetNumberPairInfo()470 SVGElement::NumberPairAttributesInfo SVGFELightingElement::GetNumberPairInfo() {
471 return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo,
472 ArrayLength(sNumberPairInfo));
473 }
474
GetStringInfo()475 SVGElement::StringAttributesInfo SVGFELightingElement::GetStringInfo() {
476 return StringAttributesInfo(mStringAttributes, sStringInfo,
477 ArrayLength(sStringInfo));
478 }
479
480 } // namespace dom
481 } // namespace mozilla
482