tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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