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 #include "mozilla/dom/SVGFETurbulenceElementBinding.h"
9 #include "mozilla/SVGFilterInstance.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/dom/BindContext.h"
12 
13 NS_IMPL_NS_NEW_SVG_ELEMENT(FETurbulence)
14 
15 using namespace mozilla::gfx;
16 
17 namespace mozilla {
18 namespace 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 
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)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, false}};
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 
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFETurbulenceElement)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>
BaseFrequencyY()71 SVGFETurbulenceElement::BaseFrequencyY() {
72   return mNumberPairAttributes[BASE_FREQ].ToDOMAnimatedNumber(
73       SVGAnimatedNumberPair::eSecond, this);
74 }
75 
NumOctaves()76 already_AddRefed<DOMSVGAnimatedInteger> SVGFETurbulenceElement::NumOctaves() {
77   return mIntegerAttributes[OCTAVES].ToDOMAnimatedInteger(this);
78 }
79 
Seed()80 already_AddRefed<DOMSVGAnimatedNumber> SVGFETurbulenceElement::Seed() {
81   return mNumberAttributes[SEED].ToDOMAnimatedNumber(this);
82 }
83 
84 already_AddRefed<DOMSVGAnimatedEnumeration>
StitchTiles()85 SVGFETurbulenceElement::StitchTiles() {
86   return mEnumAttributes[STITCHTILES].ToDOMAnimatedEnum(this);
87 }
88 
Type()89 already_AddRefed<DOMSVGAnimatedEnumeration> SVGFETurbulenceElement::Type() {
90   return mEnumAttributes[TYPE].ToDOMAnimatedEnum(this);
91 }
92 
GetPrimitiveDescription(SVGFilterInstance * aInstance,const IntRect & aFilterSubregion,const nsTArray<bool> & aInputsAreTainted,nsTArray<RefPtr<SourceSurface>> & aInputImages)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       clamped(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 
AttributeAffectsRendering(int32_t aNameSpaceID,nsAtom * aAttribute) const146 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 
BindToTree(BindContext & aCtx,nsINode & aParent)158 nsresult SVGFETurbulenceElement::BindToTree(BindContext& aCtx,
159                                             nsINode& aParent) {
160   if (aCtx.InComposedDoc()) {
161     aCtx.OwnerDoc().SetUseCounter(eUseCounter_custom_feTurbulence);
162   }
163 
164   return SVGFE::BindToTree(aCtx, aParent);
165 }
166 
167 //----------------------------------------------------------------------
168 // SVGElement methods
169 
GetNumberInfo()170 SVGElement::NumberAttributesInfo SVGFETurbulenceElement::GetNumberInfo() {
171   return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
172                               ArrayLength(sNumberInfo));
173 }
174 
175 SVGElement::NumberPairAttributesInfo
GetNumberPairInfo()176 SVGFETurbulenceElement::GetNumberPairInfo() {
177   return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo,
178                                   ArrayLength(sNumberPairInfo));
179 }
180 
GetIntegerInfo()181 SVGElement::IntegerAttributesInfo SVGFETurbulenceElement::GetIntegerInfo() {
182   return IntegerAttributesInfo(mIntegerAttributes, sIntegerInfo,
183                                ArrayLength(sIntegerInfo));
184 }
185 
GetEnumInfo()186 SVGElement::EnumAttributesInfo SVGFETurbulenceElement::GetEnumInfo() {
187   return EnumAttributesInfo(mEnumAttributes, sEnumInfo, ArrayLength(sEnumInfo));
188 }
189 
GetStringInfo()190 SVGElement::StringAttributesInfo SVGFETurbulenceElement::GetStringInfo() {
191   return StringAttributesInfo(mStringAttributes, sStringInfo,
192                               ArrayLength(sStringInfo));
193 }
194 
195 }  // namespace dom
196 }  // namespace mozilla
197