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