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