SVGFETurbulenceElement.cpp (7684B)
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 "mozilla/dom/SVGFETurbulenceElement.h" 8 9 #include "mozilla/SVGFilterInstance.h" 10 #include "mozilla/dom/BindContext.h" 11 #include "mozilla/dom/Document.h" 12 #include "mozilla/dom/SVGFETurbulenceElementBinding.h" 13 14 NS_IMPL_NS_NEW_SVG_ELEMENT(FETurbulence) 15 16 using namespace mozilla::gfx; 17 18 namespace mozilla::dom { 19 20 // Stitch Options 21 static const unsigned short SVG_STITCHTYPE_STITCH = 1; 22 static const unsigned short SVG_STITCHTYPE_NOSTITCH = 2; 23 24 static const int32_t MAX_OCTAVES = 10; 25 26 JSObject* SVGFETurbulenceElement::WrapNode(JSContext* aCx, 27 JS::Handle<JSObject*> aGivenProto) { 28 return SVGFETurbulenceElement_Binding::Wrap(aCx, this, aGivenProto); 29 } 30 31 SVGElement::NumberInfo SVGFETurbulenceElement::sNumberInfo[1] = { 32 {nsGkAtoms::seed, 0}}; 33 34 SVGElement::NumberPairInfo SVGFETurbulenceElement::sNumberPairInfo[1] = { 35 {nsGkAtoms::baseFrequency, 0, 0}}; 36 37 SVGElement::IntegerInfo SVGFETurbulenceElement::sIntegerInfo[1] = { 38 {nsGkAtoms::numOctaves, 1}}; 39 40 SVGEnumMapping SVGFETurbulenceElement::sTypeMap[] = { 41 {nsGkAtoms::fractalNoise, SVG_TURBULENCE_TYPE_FRACTALNOISE}, 42 {nsGkAtoms::turbulence, SVG_TURBULENCE_TYPE_TURBULENCE}, 43 {nullptr, 0}}; 44 45 SVGEnumMapping SVGFETurbulenceElement::sStitchTilesMap[] = { 46 {nsGkAtoms::stitch, SVG_STITCHTYPE_STITCH}, 47 {nsGkAtoms::noStitch, SVG_STITCHTYPE_NOSTITCH}, 48 {nullptr, 0}}; 49 50 SVGElement::EnumInfo SVGFETurbulenceElement::sEnumInfo[2] = { 51 {nsGkAtoms::type, sTypeMap, SVG_TURBULENCE_TYPE_TURBULENCE}, 52 {nsGkAtoms::stitchTiles, sStitchTilesMap, SVG_STITCHTYPE_NOSTITCH}}; 53 54 SVGElement::StringInfo SVGFETurbulenceElement::sStringInfo[1] = { 55 {nsGkAtoms::result, kNameSpaceID_None, true}}; 56 57 //---------------------------------------------------------------------- 58 // nsINode methods 59 60 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFETurbulenceElement) 61 62 //---------------------------------------------------------------------- 63 64 already_AddRefed<DOMSVGAnimatedNumber> 65 SVGFETurbulenceElement::BaseFrequencyX() { 66 return mNumberPairAttributes[BASE_FREQ].ToDOMAnimatedNumber( 67 SVGAnimatedNumberPair::eFirst, this); 68 } 69 70 already_AddRefed<DOMSVGAnimatedNumber> 71 SVGFETurbulenceElement::BaseFrequencyY() { 72 return mNumberPairAttributes[BASE_FREQ].ToDOMAnimatedNumber( 73 SVGAnimatedNumberPair::eSecond, this); 74 } 75 76 already_AddRefed<DOMSVGAnimatedInteger> SVGFETurbulenceElement::NumOctaves() { 77 return mIntegerAttributes[OCTAVES].ToDOMAnimatedInteger(this); 78 } 79 80 already_AddRefed<DOMSVGAnimatedNumber> SVGFETurbulenceElement::Seed() { 81 return mNumberAttributes[SEED].ToDOMAnimatedNumber(this); 82 } 83 84 already_AddRefed<DOMSVGAnimatedEnumeration> 85 SVGFETurbulenceElement::StitchTiles() { 86 return mEnumAttributes[STITCHTILES].ToDOMAnimatedEnum(this); 87 } 88 89 already_AddRefed<DOMSVGAnimatedEnumeration> SVGFETurbulenceElement::Type() { 90 return mEnumAttributes[TYPE].ToDOMAnimatedEnum(this); 91 } 92 93 FilterPrimitiveDescription SVGFETurbulenceElement::GetPrimitiveDescription( 94 SVGFilterInstance* aInstance, const IntRect& aFilterSubregion, 95 const nsTArray<bool>& aInputsAreTainted, 96 nsTArray<RefPtr<SourceSurface>>& aInputImages) { 97 float fX = mNumberPairAttributes[BASE_FREQ].GetAnimValue( 98 SVGAnimatedNumberPair::eFirst); 99 float fY = mNumberPairAttributes[BASE_FREQ].GetAnimValue( 100 SVGAnimatedNumberPair::eSecond); 101 float seed = mNumberAttributes[OCTAVES].GetAnimValue(); 102 uint32_t octaves = 103 std::clamp(mIntegerAttributes[OCTAVES].GetAnimValue(), 0, MAX_OCTAVES); 104 uint32_t type = mEnumAttributes[TYPE].GetAnimValue(); 105 uint16_t stitch = mEnumAttributes[STITCHTILES].GetAnimValue(); 106 107 if (fX == 0 && fY == 0) { 108 // A base frequency of zero results in transparent black for 109 // type="turbulence" and in 50% alpha 50% gray for type="fractalNoise". 110 if (type == SVG_TURBULENCE_TYPE_TURBULENCE) { 111 return FilterPrimitiveDescription(); 112 } 113 FloodAttributes atts; 114 atts.mColor = sRGBColor(0.5, 0.5, 0.5, 0.5); 115 return FilterPrimitiveDescription(AsVariant(std::move(atts))); 116 } 117 118 // We interpret the base frequency as relative to user space units. In other 119 // words, we consider one turbulence base period to be 1 / fX user space 120 // units wide and 1 / fY user space units high. We do not scale the frequency 121 // depending on the filter primitive region. 122 // We now convert the frequency from user space to filter space. 123 // If a frequency in user space units is zero, then it will also be zero in 124 // filter space. During the conversion we use a dummy period length of 1 125 // for those frequencies but then ignore the converted length and use 0 126 // for the converted frequency. This avoids division by zero. 127 gfxRect firstPeriodInUserSpace(0, 0, fX == 0 ? 1 : (1 / fX), 128 fY == 0 ? 1 : (1 / fY)); 129 gfxRect firstPeriodInFilterSpace = 130 aInstance->UserSpaceToFilterSpace(firstPeriodInUserSpace); 131 Size frequencyInFilterSpace( 132 fX == 0 ? 0 : (1 / firstPeriodInFilterSpace.width), 133 fY == 0 ? 0 : (1 / firstPeriodInFilterSpace.height)); 134 gfxPoint offset = firstPeriodInFilterSpace.TopLeft(); 135 136 TurbulenceAttributes atts; 137 atts.mOffset = IntPoint::Truncate(offset.x, offset.y); 138 atts.mBaseFrequency = frequencyInFilterSpace; 139 atts.mSeed = seed; 140 atts.mOctaves = octaves; 141 atts.mStitchable = stitch == SVG_STITCHTYPE_STITCH; 142 atts.mType = type; 143 return FilterPrimitiveDescription(AsVariant(std::move(atts))); 144 } 145 146 bool SVGFETurbulenceElement::AttributeAffectsRendering( 147 int32_t aNameSpaceID, nsAtom* aAttribute) const { 148 return SVGFETurbulenceElementBase::AttributeAffectsRendering(aNameSpaceID, 149 aAttribute) || 150 (aNameSpaceID == kNameSpaceID_None && 151 (aAttribute == nsGkAtoms::seed || 152 aAttribute == nsGkAtoms::baseFrequency || 153 aAttribute == nsGkAtoms::numOctaves || 154 aAttribute == nsGkAtoms::type || 155 aAttribute == nsGkAtoms::stitchTiles)); 156 } 157 158 nsresult SVGFETurbulenceElement::BindToTree(BindContext& aCtx, 159 nsINode& aParent) { 160 if (aCtx.InComposedDoc()) { 161 aCtx.OwnerDoc().SetUseCounter(eUseCounter_custom_feTurbulence); 162 } 163 164 return SVGFETurbulenceElementBase::BindToTree(aCtx, aParent); 165 } 166 167 //---------------------------------------------------------------------- 168 // SVGElement methods 169 170 SVGElement::NumberAttributesInfo SVGFETurbulenceElement::GetNumberInfo() { 171 return NumberAttributesInfo(mNumberAttributes, sNumberInfo, 172 std::size(sNumberInfo)); 173 } 174 175 SVGElement::NumberPairAttributesInfo 176 SVGFETurbulenceElement::GetNumberPairInfo() { 177 return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo, 178 std::size(sNumberPairInfo)); 179 } 180 181 SVGElement::IntegerAttributesInfo SVGFETurbulenceElement::GetIntegerInfo() { 182 return IntegerAttributesInfo(mIntegerAttributes, sIntegerInfo, 183 std::size(sIntegerInfo)); 184 } 185 186 SVGElement::EnumAttributesInfo SVGFETurbulenceElement::GetEnumInfo() { 187 return EnumAttributesInfo(mEnumAttributes, sEnumInfo, std::size(sEnumInfo)); 188 } 189 190 SVGElement::StringAttributesInfo SVGFETurbulenceElement::GetStringInfo() { 191 return StringAttributesInfo(mStringAttributes, sStringInfo, 192 std::size(sStringInfo)); 193 } 194 195 } // namespace mozilla::dom