Bug 847120: Move SVGFETurbulenceElement to its own file r=Ms2ger

--HG--
rename : content/svg/content/src/nsSVGFilters.cpp => content/svg/content/src/SVGFETurbulenceElement.cpp
rename : content/svg/content/src/nsSVGFilters.cpp => content/svg/content/src/SVGFETurbulenceElement.h
This commit is contained in:
David Zbarsky 2013-03-26 19:43:33 -04:00
parent 2077c75f8c
commit 84fe1989bf
4 changed files with 575 additions and 546 deletions

View File

@ -95,6 +95,7 @@ CPPSRCS = \
SVGFESpecularLightingElement.cpp \
SVGFESpotLightElement.cpp \
SVGFETileElement.cpp \
SVGFETurbulenceElement.cpp \
SVGFilterElement.cpp \
SVGForeignObjectElement.cpp \
SVGFragmentIdentifier.cpp \
@ -208,6 +209,7 @@ EXPORTS_mozilla/dom = \
SVGFESpecularLightingElement.h \
SVGFESpotLightElement.h \
SVGFETileElement.h \
SVGFETurbulenceElement.h \
SVGFilterElement.h \
SVGForeignObjectElement.h \
SVGGElement.h \

View File

@ -0,0 +1,422 @@
/* a*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/SVGFETurbulenceElement.h"
namespace mozilla {
namespace dom {
nsSVGElement::NumberInfo nsSVGFETurbulenceElement::sNumberInfo[1] =
{
{ &nsGkAtoms::seed, 0, false }
};
nsSVGElement::NumberPairInfo nsSVGFETurbulenceElement::sNumberPairInfo[1] =
{
{ &nsGkAtoms::baseFrequency, 0, 0 }
};
nsSVGElement::IntegerInfo nsSVGFETurbulenceElement::sIntegerInfo[1] =
{
{ &nsGkAtoms::numOctaves, 1 }
};
nsSVGEnumMapping nsSVGFETurbulenceElement::sTypeMap[] = {
{&nsGkAtoms::fractalNoise,
nsIDOMSVGFETurbulenceElement::SVG_TURBULENCE_TYPE_FRACTALNOISE},
{&nsGkAtoms::turbulence,
nsIDOMSVGFETurbulenceElement::SVG_TURBULENCE_TYPE_TURBULENCE},
{nullptr, 0}
};
nsSVGEnumMapping nsSVGFETurbulenceElement::sStitchTilesMap[] = {
{&nsGkAtoms::stitch,
nsIDOMSVGFETurbulenceElement::SVG_STITCHTYPE_STITCH},
{&nsGkAtoms::noStitch,
nsIDOMSVGFETurbulenceElement::SVG_STITCHTYPE_NOSTITCH},
{nullptr, 0}
};
nsSVGElement::EnumInfo nsSVGFETurbulenceElement::sEnumInfo[2] =
{
{ &nsGkAtoms::type,
sTypeMap,
nsIDOMSVGFETurbulenceElement::SVG_TURBULENCE_TYPE_TURBULENCE
},
{ &nsGkAtoms::stitchTiles,
sStitchTilesMap,
nsIDOMSVGFETurbulenceElement::SVG_STITCHTYPE_NOSTITCH
}
};
nsSVGElement::StringInfo nsSVGFETurbulenceElement::sStringInfo[1] =
{
{ &nsGkAtoms::result, kNameSpaceID_None, true }
};
NS_IMPL_NS_NEW_SVG_ELEMENT(FETurbulence)
//----------------------------------------------------------------------
// nsISupports methods
NS_IMPL_ADDREF_INHERITED(nsSVGFETurbulenceElement,nsSVGFETurbulenceElementBase)
NS_IMPL_RELEASE_INHERITED(nsSVGFETurbulenceElement,nsSVGFETurbulenceElementBase)
DOMCI_NODE_DATA(SVGFETurbulenceElement, nsSVGFETurbulenceElement)
NS_INTERFACE_TABLE_HEAD(nsSVGFETurbulenceElement)
NS_NODE_INTERFACE_TABLE5(nsSVGFETurbulenceElement, nsIDOMNode, nsIDOMElement,
nsIDOMSVGElement,
nsIDOMSVGFilterPrimitiveStandardAttributes,
nsIDOMSVGFETurbulenceElement)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGFETurbulenceElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGFETurbulenceElementBase)
//----------------------------------------------------------------------
// nsIDOMNode methods
NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGFETurbulenceElement)
//----------------------------------------------------------------------
// nsIDOMSVGFETurbulenceElement methods
/* readonly attribute nsIDOMSVGAnimatedNumber baseFrequencyX; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetBaseFrequencyX(nsIDOMSVGAnimatedNumber * *aX)
{
return mNumberPairAttributes[BASE_FREQ].ToDOMAnimatedNumber(aX, nsSVGNumberPair::eFirst, this);
}
/* readonly attribute nsIDOMSVGAnimatedNumber baseFrequencyY; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetBaseFrequencyY(nsIDOMSVGAnimatedNumber * *aY)
{
return mNumberPairAttributes[BASE_FREQ].ToDOMAnimatedNumber(aY, nsSVGNumberPair::eSecond, this);
}
/* readonly attribute nsIDOMSVGAnimatedInteger numOctaves; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetNumOctaves(nsIDOMSVGAnimatedInteger * *aNum)
{
return mIntegerAttributes[OCTAVES].ToDOMAnimatedInteger(aNum, this);
}
/* readonly attribute nsIDOMSVGAnimatedNumber seed; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetSeed(nsIDOMSVGAnimatedNumber * *aSeed)
{
return mNumberAttributes[SEED].ToDOMAnimatedNumber(aSeed, this);
}
/* readonly attribute nsIDOMSVGAnimatedEnumeration stitchTiles; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetStitchTiles(nsIDOMSVGAnimatedEnumeration * *aStitch)
{
return mEnumAttributes[STITCHTILES].ToDOMAnimatedEnum(aStitch, this);
}
/* readonly attribute nsIDOMSVGAnimatedEnumeration type; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetType(nsIDOMSVGAnimatedEnumeration * *aType)
{
return mEnumAttributes[TYPE].ToDOMAnimatedEnum(aType, this);
}
nsresult
nsSVGFETurbulenceElement::Filter(nsSVGFilterInstance *instance,
const nsTArray<const Image*>& aSources,
const Image* aTarget,
const nsIntRect& rect)
{
uint8_t* targetData = aTarget->mImage->Data();
uint32_t stride = aTarget->mImage->Stride();
nsIntRect filterSubregion(int32_t(aTarget->mFilterPrimitiveSubregion.X()),
int32_t(aTarget->mFilterPrimitiveSubregion.Y()),
int32_t(aTarget->mFilterPrimitiveSubregion.Width()),
int32_t(aTarget->mFilterPrimitiveSubregion.Height()));
float fX = mNumberPairAttributes[BASE_FREQ].GetAnimValue(nsSVGNumberPair::eFirst);
float fY = mNumberPairAttributes[BASE_FREQ].GetAnimValue(nsSVGNumberPair::eSecond);
float seed = mNumberAttributes[OCTAVES].GetAnimValue();
int32_t octaves = mIntegerAttributes[OCTAVES].GetAnimValue();
uint16_t type = mEnumAttributes[TYPE].GetAnimValue();
uint16_t stitch = mEnumAttributes[STITCHTILES].GetAnimValue();
InitSeed((int32_t)seed);
// XXXroc this makes absolutely no sense to me.
float filterX = instance->GetFilterRegion().X();
float filterY = instance->GetFilterRegion().Y();
float filterWidth = instance->GetFilterRegion().Width();
float filterHeight = instance->GetFilterRegion().Height();
bool doStitch = false;
if (stitch == nsIDOMSVGFETurbulenceElement::SVG_STITCHTYPE_STITCH) {
doStitch = true;
float lowFreq, hiFreq;
lowFreq = floor(filterWidth * fX) / filterWidth;
hiFreq = ceil(filterWidth * fX) / filterWidth;
if (fX / lowFreq < hiFreq / fX)
fX = lowFreq;
else
fX = hiFreq;
lowFreq = floor(filterHeight * fY) / filterHeight;
hiFreq = ceil(filterHeight * fY) / filterHeight;
if (fY / lowFreq < hiFreq / fY)
fY = lowFreq;
else
fY = hiFreq;
}
for (int32_t y = rect.y; y < rect.YMost(); y++) {
for (int32_t x = rect.x; x < rect.XMost(); x++) {
int32_t targIndex = y * stride + x * 4;
double point[2];
point[0] = filterX + (filterWidth * (x + instance->GetSurfaceRect().x)) / (filterSubregion.width - 1);
point[1] = filterY + (filterHeight * (y + instance->GetSurfaceRect().y)) / (filterSubregion.height - 1);
float col[4];
if (type == nsIDOMSVGFETurbulenceElement::SVG_TURBULENCE_TYPE_TURBULENCE) {
for (int i = 0; i < 4; i++)
col[i] = Turbulence(i, point, fX, fY, octaves, false,
doStitch, filterX, filterY, filterWidth, filterHeight) * 255;
} else {
for (int i = 0; i < 4; i++)
col[i] = (Turbulence(i, point, fX, fY, octaves, true,
doStitch, filterX, filterY, filterWidth, filterHeight) * 255 + 255) / 2;
}
for (int i = 0; i < 4; i++) {
col[i] = std::min(col[i], 255.f);
col[i] = std::max(col[i], 0.f);
}
uint8_t r, g, b, a;
a = uint8_t(col[3]);
FAST_DIVIDE_BY_255(r, unsigned(col[0]) * a);
FAST_DIVIDE_BY_255(g, unsigned(col[1]) * a);
FAST_DIVIDE_BY_255(b, unsigned(col[2]) * a);
targetData[targIndex + GFX_ARGB32_OFFSET_B] = b;
targetData[targIndex + GFX_ARGB32_OFFSET_G] = g;
targetData[targIndex + GFX_ARGB32_OFFSET_R] = r;
targetData[targIndex + GFX_ARGB32_OFFSET_A] = a;
}
}
return NS_OK;
}
bool
nsSVGFETurbulenceElement::AttributeAffectsRendering(int32_t aNameSpaceID,
nsIAtom* aAttribute) const
{
return nsSVGFETurbulenceElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
(aNameSpaceID == kNameSpaceID_None &&
(aAttribute == nsGkAtoms::seed ||
aAttribute == nsGkAtoms::baseFrequency ||
aAttribute == nsGkAtoms::numOctaves ||
aAttribute == nsGkAtoms::type ||
aAttribute == nsGkAtoms::stitchTiles));
}
void
nsSVGFETurbulenceElement::InitSeed(int32_t aSeed)
{
double s;
int i, j, k;
aSeed = SetupSeed(aSeed);
for (k = 0; k < 4; k++) {
for (i = 0; i < sBSize; i++) {
mLatticeSelector[i] = i;
for (j = 0; j < 2; j++) {
mGradient[k][i][j] =
(double) (((aSeed =
Random(aSeed)) % (sBSize + sBSize)) - sBSize) / sBSize;
}
s = double (sqrt
(mGradient[k][i][0] * mGradient[k][i][0] +
mGradient[k][i][1] * mGradient[k][i][1]));
mGradient[k][i][0] /= s;
mGradient[k][i][1] /= s;
}
}
while (--i) {
k = mLatticeSelector[i];
mLatticeSelector[i] = mLatticeSelector[j =
(aSeed =
Random(aSeed)) % sBSize];
mLatticeSelector[j] = k;
}
for (i = 0; i < sBSize + 2; i++) {
mLatticeSelector[sBSize + i] = mLatticeSelector[i];
for (k = 0; k < 4; k++)
for (j = 0; j < 2; j++)
mGradient[k][sBSize + i][j] = mGradient[k][i][j];
}
}
#define S_CURVE(t) ( t * t * (3. - 2. * t) )
#define LERP(t, a, b) ( a + t * (b - a) )
double
nsSVGFETurbulenceElement::Noise2(int aColorChannel, double aVec[2],
StitchInfo *aStitchInfo)
{
int bx0, bx1, by0, by1, b00, b10, b01, b11;
double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
register long i, j;
t = aVec[0] + sPerlinN;
bx0 = (int) t;
bx1 = bx0 + 1;
rx0 = t - (int) t;
rx1 = rx0 - 1.0f;
t = aVec[1] + sPerlinN;
by0 = (int) t;
by1 = by0 + 1;
ry0 = t - (int) t;
ry1 = ry0 - 1.0f;
// If stitching, adjust lattice points accordingly.
if (aStitchInfo != NULL) {
if (bx0 >= aStitchInfo->mWrapX)
bx0 -= aStitchInfo->mWidth;
if (bx1 >= aStitchInfo->mWrapX)
bx1 -= aStitchInfo->mWidth;
if (by0 >= aStitchInfo->mWrapY)
by0 -= aStitchInfo->mHeight;
if (by1 >= aStitchInfo->mWrapY)
by1 -= aStitchInfo->mHeight;
}
bx0 &= sBM;
bx1 &= sBM;
by0 &= sBM;
by1 &= sBM;
i = mLatticeSelector[bx0];
j = mLatticeSelector[bx1];
b00 = mLatticeSelector[i + by0];
b10 = mLatticeSelector[j + by0];
b01 = mLatticeSelector[i + by1];
b11 = mLatticeSelector[j + by1];
sx = double (S_CURVE(rx0));
sy = double (S_CURVE(ry0));
q = mGradient[aColorChannel][b00];
u = rx0 * q[0] + ry0 * q[1];
q = mGradient[aColorChannel][b10];
v = rx1 * q[0] + ry0 * q[1];
a = LERP(sx, u, v);
q = mGradient[aColorChannel][b01];
u = rx0 * q[0] + ry1 * q[1];
q = mGradient[aColorChannel][b11];
v = rx1 * q[0] + ry1 * q[1];
b = LERP(sx, u, v);
return LERP(sy, a, b);
}
#undef S_CURVE
#undef LERP
double
nsSVGFETurbulenceElement::Turbulence(int aColorChannel, double *aPoint,
double aBaseFreqX, double aBaseFreqY,
int aNumOctaves, bool aFractalSum,
bool aDoStitching,
double aTileX, double aTileY,
double aTileWidth, double aTileHeight)
{
StitchInfo stitch;
StitchInfo *stitchInfo = NULL; // Not stitching when NULL.
// Adjust the base frequencies if necessary for stitching.
if (aDoStitching) {
// When stitching tiled turbulence, the frequencies must be adjusted
// so that the tile borders will be continuous.
if (aBaseFreqX != 0.0) {
double loFreq = double (floor(aTileWidth * aBaseFreqX)) / aTileWidth;
double hiFreq = double (ceil(aTileWidth * aBaseFreqX)) / aTileWidth;
if (aBaseFreqX / loFreq < hiFreq / aBaseFreqX)
aBaseFreqX = loFreq;
else
aBaseFreqX = hiFreq;
}
if (aBaseFreqY != 0.0) {
double loFreq = double (floor(aTileHeight * aBaseFreqY)) / aTileHeight;
double hiFreq = double (ceil(aTileHeight * aBaseFreqY)) / aTileHeight;
if (aBaseFreqY / loFreq < hiFreq / aBaseFreqY)
aBaseFreqY = loFreq;
else
aBaseFreqY = hiFreq;
}
// Set up initial stitch values.
stitchInfo = &stitch;
stitch.mWidth = int (aTileWidth * aBaseFreqX + 0.5f);
stitch.mWrapX = int (aTileX * aBaseFreqX + sPerlinN + stitch.mWidth);
stitch.mHeight = int (aTileHeight * aBaseFreqY + 0.5f);
stitch.mWrapY = int (aTileY * aBaseFreqY + sPerlinN + stitch.mHeight);
}
double sum = 0.0f;
double vec[2];
vec[0] = aPoint[0] * aBaseFreqX;
vec[1] = aPoint[1] * aBaseFreqY;
double ratio = 1;
for (int octave = 0; octave < aNumOctaves; octave++) {
if (aFractalSum)
sum += double (Noise2(aColorChannel, vec, stitchInfo) / ratio);
else
sum += double (fabs(Noise2(aColorChannel, vec, stitchInfo)) / ratio);
vec[0] *= 2;
vec[1] *= 2;
ratio *= 2;
if (stitchInfo != NULL) {
// Update stitch values. Subtracting sPerlinN before the multiplication
// and adding it afterward simplifies to subtracting it once.
stitch.mWidth *= 2;
stitch.mWrapX = 2 * stitch.mWrapX - sPerlinN;
stitch.mHeight *= 2;
stitch.mWrapY = 2 * stitch.mWrapY - sPerlinN;
}
}
return sum;
}
nsIntRect
nsSVGFETurbulenceElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance)
{
return GetMaxRect();
}
//----------------------------------------------------------------------
// nsSVGElement methods
nsSVGElement::NumberAttributesInfo
nsSVGFETurbulenceElement::GetNumberInfo()
{
return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
ArrayLength(sNumberInfo));
}
nsSVGElement::NumberPairAttributesInfo
nsSVGFETurbulenceElement::GetNumberPairInfo()
{
return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo,
ArrayLength(sNumberPairInfo));
}
nsSVGElement::IntegerAttributesInfo
nsSVGFETurbulenceElement::GetIntegerInfo()
{
return IntegerAttributesInfo(mIntegerAttributes, sIntegerInfo,
ArrayLength(sIntegerInfo));
}
nsSVGElement::EnumAttributesInfo
nsSVGFETurbulenceElement::GetEnumInfo()
{
return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
ArrayLength(sEnumInfo));
}
nsSVGElement::StringAttributesInfo
nsSVGFETurbulenceElement::GetStringInfo()
{
return StringAttributesInfo(mStringAttributes, sStringInfo,
ArrayLength(sStringInfo));
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,151 @@
/* a*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_SVGFETurbulenceElement_h
#define mozilla_dom_SVGFETurbulenceElement_h
#include "nsSVGFilters.h"
namespace mozilla {
namespace dom {
typedef nsSVGFE nsSVGFETurbulenceElementBase;
class nsSVGFETurbulenceElement : public nsSVGFETurbulenceElementBase,
public nsIDOMSVGFETurbulenceElement
{
friend nsresult NS_NewSVGFETurbulenceElement(nsIContent **aResult,
already_AddRefed<nsINodeInfo> aNodeInfo);
protected:
nsSVGFETurbulenceElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsSVGFETurbulenceElementBase(aNodeInfo) {}
public:
virtual bool SubregionIsUnionOfRegions() { return false; }
// interfaces:
NS_DECL_ISUPPORTS_INHERITED
// FE Base
NS_FORWARD_NSIDOMSVGFILTERPRIMITIVESTANDARDATTRIBUTES(nsSVGFETurbulenceElementBase::)
virtual nsresult Filter(nsSVGFilterInstance* aInstance,
const nsTArray<const Image*>& aSources,
const Image* aTarget,
const nsIntRect& aDataRect);
virtual bool AttributeAffectsRendering(
int32_t aNameSpaceID, nsIAtom* aAttribute) const;
virtual nsSVGString& GetResultImageName() { return mStringAttributes[RESULT]; }
virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance);
// Turbulence
NS_DECL_NSIDOMSVGFETURBULENCEELEMENT
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFETurbulenceElementBase::)
NS_FORWARD_NSIDOMNODE_TO_NSINODE
NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
virtual nsXPCClassInfo* GetClassInfo();
virtual nsIDOMNode* AsDOMNode() { return this; }
protected:
virtual NumberAttributesInfo GetNumberInfo();
virtual NumberPairAttributesInfo GetNumberPairInfo();
virtual IntegerAttributesInfo GetIntegerInfo();
virtual EnumAttributesInfo GetEnumInfo();
virtual StringAttributesInfo GetStringInfo();
enum { SEED }; // floating point seed?!
nsSVGNumber2 mNumberAttributes[1];
static NumberInfo sNumberInfo[1];
enum { BASE_FREQ };
nsSVGNumberPair mNumberPairAttributes[1];
static NumberPairInfo sNumberPairInfo[1];
enum { OCTAVES };
nsSVGInteger mIntegerAttributes[1];
static IntegerInfo sIntegerInfo[1];
enum { TYPE, STITCHTILES };
nsSVGEnum mEnumAttributes[2];
static nsSVGEnumMapping sTypeMap[];
static nsSVGEnumMapping sStitchTilesMap[];
static EnumInfo sEnumInfo[2];
enum { RESULT };
nsSVGString mStringAttributes[1];
static StringInfo sStringInfo[1];
private:
/* The turbulence calculation code is an adapted version of what
appears in the SVG 1.1 specification:
http://www.w3.org/TR/SVG11/filters.html#feTurbulence
*/
/* Produces results in the range [1, 2**31 - 2].
Algorithm is: r = (a * r) mod m
where a = 16807 and m = 2**31 - 1 = 2147483647
See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
To test: the algorithm should produce the result 1043618065
as the 10,000th generated number if the original seed is 1.
*/
#define RAND_M 2147483647 /* 2**31 - 1 */
#define RAND_A 16807 /* 7**5; primitive root of m */
#define RAND_Q 127773 /* m / a */
#define RAND_R 2836 /* m % a */
int32_t SetupSeed(int32_t aSeed) {
if (aSeed <= 0)
aSeed = -(aSeed % (RAND_M - 1)) + 1;
if (aSeed > RAND_M - 1)
aSeed = RAND_M - 1;
return aSeed;
}
uint32_t Random(uint32_t aSeed) {
int32_t result = RAND_A * (aSeed % RAND_Q) - RAND_R * (aSeed / RAND_Q);
if (result <= 0)
result += RAND_M;
return result;
}
#undef RAND_M
#undef RAND_A
#undef RAND_Q
#undef RAND_R
const static int sBSize = 0x100;
const static int sBM = 0xff;
const static int sPerlinN = 0x1000;
const static int sNP = 12; /* 2^PerlinN */
const static int sNM = 0xfff;
int32_t mLatticeSelector[sBSize + sBSize + 2];
double mGradient[4][sBSize + sBSize + 2][2];
struct StitchInfo {
int mWidth; // How much to subtract to wrap for stitching.
int mHeight;
int mWrapX; // Minimum value to wrap.
int mWrapY;
};
void InitSeed(int32_t aSeed);
double Noise2(int aColorChannel, double aVec[2], StitchInfo *aStitchInfo);
double
Turbulence(int aColorChannel, double *aPoint, double aBaseFreqX,
double aBaseFreqY, int aNumOctaves, bool aFractalSum,
bool aDoStitching, double aTileX, double aTileY,
double aTileWidth, double aTileHeight);
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_SVGFETurbulenceElement_h

View File

@ -660,552 +660,6 @@ NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncAElement)
} // namespace dom
} // namespace mozilla
//---------------------Turbulence------------------------
typedef nsSVGFE nsSVGFETurbulenceElementBase;
class nsSVGFETurbulenceElement : public nsSVGFETurbulenceElementBase,
public nsIDOMSVGFETurbulenceElement
{
friend nsresult NS_NewSVGFETurbulenceElement(nsIContent **aResult,
already_AddRefed<nsINodeInfo> aNodeInfo);
protected:
nsSVGFETurbulenceElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsSVGFETurbulenceElementBase(aNodeInfo) {}
public:
virtual bool SubregionIsUnionOfRegions() { return false; }
// interfaces:
NS_DECL_ISUPPORTS_INHERITED
// FE Base
NS_FORWARD_NSIDOMSVGFILTERPRIMITIVESTANDARDATTRIBUTES(nsSVGFETurbulenceElementBase::)
virtual nsresult Filter(nsSVGFilterInstance* aInstance,
const nsTArray<const Image*>& aSources,
const Image* aTarget,
const nsIntRect& aDataRect);
virtual bool AttributeAffectsRendering(
int32_t aNameSpaceID, nsIAtom* aAttribute) const;
virtual nsSVGString& GetResultImageName() { return mStringAttributes[RESULT]; }
virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance);
// Turbulence
NS_DECL_NSIDOMSVGFETURBULENCEELEMENT
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFETurbulenceElementBase::)
NS_FORWARD_NSIDOMNODE_TO_NSINODE
NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
virtual nsXPCClassInfo* GetClassInfo();
virtual nsIDOMNode* AsDOMNode() { return this; }
protected:
virtual NumberAttributesInfo GetNumberInfo();
virtual NumberPairAttributesInfo GetNumberPairInfo();
virtual IntegerAttributesInfo GetIntegerInfo();
virtual EnumAttributesInfo GetEnumInfo();
virtual StringAttributesInfo GetStringInfo();
enum { SEED }; // floating point seed?!
nsSVGNumber2 mNumberAttributes[1];
static NumberInfo sNumberInfo[1];
enum { BASE_FREQ };
nsSVGNumberPair mNumberPairAttributes[1];
static NumberPairInfo sNumberPairInfo[1];
enum { OCTAVES };
nsSVGInteger mIntegerAttributes[1];
static IntegerInfo sIntegerInfo[1];
enum { TYPE, STITCHTILES };
nsSVGEnum mEnumAttributes[2];
static nsSVGEnumMapping sTypeMap[];
static nsSVGEnumMapping sStitchTilesMap[];
static EnumInfo sEnumInfo[2];
enum { RESULT };
nsSVGString mStringAttributes[1];
static StringInfo sStringInfo[1];
private:
/* The turbulence calculation code is an adapted version of what
appears in the SVG 1.1 specification:
http://www.w3.org/TR/SVG11/filters.html#feTurbulence
*/
/* Produces results in the range [1, 2**31 - 2].
Algorithm is: r = (a * r) mod m
where a = 16807 and m = 2**31 - 1 = 2147483647
See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
To test: the algorithm should produce the result 1043618065
as the 10,000th generated number if the original seed is 1.
*/
#define RAND_M 2147483647 /* 2**31 - 1 */
#define RAND_A 16807 /* 7**5; primitive root of m */
#define RAND_Q 127773 /* m / a */
#define RAND_R 2836 /* m % a */
int32_t SetupSeed(int32_t aSeed) {
if (aSeed <= 0)
aSeed = -(aSeed % (RAND_M - 1)) + 1;
if (aSeed > RAND_M - 1)
aSeed = RAND_M - 1;
return aSeed;
}
uint32_t Random(uint32_t aSeed) {
int32_t result = RAND_A * (aSeed % RAND_Q) - RAND_R * (aSeed / RAND_Q);
if (result <= 0)
result += RAND_M;
return result;
}
#undef RAND_M
#undef RAND_A
#undef RAND_Q
#undef RAND_R
const static int sBSize = 0x100;
const static int sBM = 0xff;
const static int sPerlinN = 0x1000;
const static int sNP = 12; /* 2^PerlinN */
const static int sNM = 0xfff;
int32_t mLatticeSelector[sBSize + sBSize + 2];
double mGradient[4][sBSize + sBSize + 2][2];
struct StitchInfo {
int mWidth; // How much to subtract to wrap for stitching.
int mHeight;
int mWrapX; // Minimum value to wrap.
int mWrapY;
};
void InitSeed(int32_t aSeed);
double Noise2(int aColorChannel, double aVec[2], StitchInfo *aStitchInfo);
double
Turbulence(int aColorChannel, double *aPoint, double aBaseFreqX,
double aBaseFreqY, int aNumOctaves, bool aFractalSum,
bool aDoStitching, double aTileX, double aTileY,
double aTileWidth, double aTileHeight);
};
nsSVGElement::NumberInfo nsSVGFETurbulenceElement::sNumberInfo[1] =
{
{ &nsGkAtoms::seed, 0, false }
};
nsSVGElement::NumberPairInfo nsSVGFETurbulenceElement::sNumberPairInfo[1] =
{
{ &nsGkAtoms::baseFrequency, 0, 0 }
};
nsSVGElement::IntegerInfo nsSVGFETurbulenceElement::sIntegerInfo[1] =
{
{ &nsGkAtoms::numOctaves, 1 }
};
nsSVGEnumMapping nsSVGFETurbulenceElement::sTypeMap[] = {
{&nsGkAtoms::fractalNoise,
nsIDOMSVGFETurbulenceElement::SVG_TURBULENCE_TYPE_FRACTALNOISE},
{&nsGkAtoms::turbulence,
nsIDOMSVGFETurbulenceElement::SVG_TURBULENCE_TYPE_TURBULENCE},
{nullptr, 0}
};
nsSVGEnumMapping nsSVGFETurbulenceElement::sStitchTilesMap[] = {
{&nsGkAtoms::stitch,
nsIDOMSVGFETurbulenceElement::SVG_STITCHTYPE_STITCH},
{&nsGkAtoms::noStitch,
nsIDOMSVGFETurbulenceElement::SVG_STITCHTYPE_NOSTITCH},
{nullptr, 0}
};
nsSVGElement::EnumInfo nsSVGFETurbulenceElement::sEnumInfo[2] =
{
{ &nsGkAtoms::type,
sTypeMap,
nsIDOMSVGFETurbulenceElement::SVG_TURBULENCE_TYPE_TURBULENCE
},
{ &nsGkAtoms::stitchTiles,
sStitchTilesMap,
nsIDOMSVGFETurbulenceElement::SVG_STITCHTYPE_NOSTITCH
}
};
nsSVGElement::StringInfo nsSVGFETurbulenceElement::sStringInfo[1] =
{
{ &nsGkAtoms::result, kNameSpaceID_None, true }
};
NS_IMPL_NS_NEW_SVG_ELEMENT(FETurbulence)
//----------------------------------------------------------------------
// nsISupports methods
NS_IMPL_ADDREF_INHERITED(nsSVGFETurbulenceElement,nsSVGFETurbulenceElementBase)
NS_IMPL_RELEASE_INHERITED(nsSVGFETurbulenceElement,nsSVGFETurbulenceElementBase)
DOMCI_NODE_DATA(SVGFETurbulenceElement, nsSVGFETurbulenceElement)
NS_INTERFACE_TABLE_HEAD(nsSVGFETurbulenceElement)
NS_NODE_INTERFACE_TABLE5(nsSVGFETurbulenceElement, nsIDOMNode, nsIDOMElement,
nsIDOMSVGElement,
nsIDOMSVGFilterPrimitiveStandardAttributes,
nsIDOMSVGFETurbulenceElement)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGFETurbulenceElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGFETurbulenceElementBase)
//----------------------------------------------------------------------
// nsIDOMNode methods
NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGFETurbulenceElement)
//----------------------------------------------------------------------
// nsIDOMSVGFETurbulenceElement methods
/* readonly attribute nsIDOMSVGAnimatedNumber baseFrequencyX; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetBaseFrequencyX(nsIDOMSVGAnimatedNumber * *aX)
{
return mNumberPairAttributes[BASE_FREQ].ToDOMAnimatedNumber(aX, nsSVGNumberPair::eFirst, this);
}
/* readonly attribute nsIDOMSVGAnimatedNumber baseFrequencyY; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetBaseFrequencyY(nsIDOMSVGAnimatedNumber * *aY)
{
return mNumberPairAttributes[BASE_FREQ].ToDOMAnimatedNumber(aY, nsSVGNumberPair::eSecond, this);
}
/* readonly attribute nsIDOMSVGAnimatedInteger numOctaves; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetNumOctaves(nsIDOMSVGAnimatedInteger * *aNum)
{
return mIntegerAttributes[OCTAVES].ToDOMAnimatedInteger(aNum, this);
}
/* readonly attribute nsIDOMSVGAnimatedNumber seed; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetSeed(nsIDOMSVGAnimatedNumber * *aSeed)
{
return mNumberAttributes[SEED].ToDOMAnimatedNumber(aSeed, this);
}
/* readonly attribute nsIDOMSVGAnimatedEnumeration stitchTiles; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetStitchTiles(nsIDOMSVGAnimatedEnumeration * *aStitch)
{
return mEnumAttributes[STITCHTILES].ToDOMAnimatedEnum(aStitch, this);
}
/* readonly attribute nsIDOMSVGAnimatedEnumeration type; */
NS_IMETHODIMP nsSVGFETurbulenceElement::GetType(nsIDOMSVGAnimatedEnumeration * *aType)
{
return mEnumAttributes[TYPE].ToDOMAnimatedEnum(aType, this);
}
nsresult
nsSVGFETurbulenceElement::Filter(nsSVGFilterInstance *instance,
const nsTArray<const Image*>& aSources,
const Image* aTarget,
const nsIntRect& rect)
{
uint8_t* targetData = aTarget->mImage->Data();
uint32_t stride = aTarget->mImage->Stride();
nsIntRect filterSubregion(int32_t(aTarget->mFilterPrimitiveSubregion.X()),
int32_t(aTarget->mFilterPrimitiveSubregion.Y()),
int32_t(aTarget->mFilterPrimitiveSubregion.Width()),
int32_t(aTarget->mFilterPrimitiveSubregion.Height()));
float fX = mNumberPairAttributes[BASE_FREQ].GetAnimValue(nsSVGNumberPair::eFirst);
float fY = mNumberPairAttributes[BASE_FREQ].GetAnimValue(nsSVGNumberPair::eSecond);
float seed = mNumberAttributes[OCTAVES].GetAnimValue();
int32_t octaves = mIntegerAttributes[OCTAVES].GetAnimValue();
uint16_t type = mEnumAttributes[TYPE].GetAnimValue();
uint16_t stitch = mEnumAttributes[STITCHTILES].GetAnimValue();
InitSeed((int32_t)seed);
// XXXroc this makes absolutely no sense to me.
float filterX = instance->GetFilterRegion().X();
float filterY = instance->GetFilterRegion().Y();
float filterWidth = instance->GetFilterRegion().Width();
float filterHeight = instance->GetFilterRegion().Height();
bool doStitch = false;
if (stitch == nsIDOMSVGFETurbulenceElement::SVG_STITCHTYPE_STITCH) {
doStitch = true;
float lowFreq, hiFreq;
lowFreq = floor(filterWidth * fX) / filterWidth;
hiFreq = ceil(filterWidth * fX) / filterWidth;
if (fX / lowFreq < hiFreq / fX)
fX = lowFreq;
else
fX = hiFreq;
lowFreq = floor(filterHeight * fY) / filterHeight;
hiFreq = ceil(filterHeight * fY) / filterHeight;
if (fY / lowFreq < hiFreq / fY)
fY = lowFreq;
else
fY = hiFreq;
}
for (int32_t y = rect.y; y < rect.YMost(); y++) {
for (int32_t x = rect.x; x < rect.XMost(); x++) {
int32_t targIndex = y * stride + x * 4;
double point[2];
point[0] = filterX + (filterWidth * (x + instance->GetSurfaceRect().x)) / (filterSubregion.width - 1);
point[1] = filterY + (filterHeight * (y + instance->GetSurfaceRect().y)) / (filterSubregion.height - 1);
float col[4];
if (type == nsIDOMSVGFETurbulenceElement::SVG_TURBULENCE_TYPE_TURBULENCE) {
for (int i = 0; i < 4; i++)
col[i] = Turbulence(i, point, fX, fY, octaves, false,
doStitch, filterX, filterY, filterWidth, filterHeight) * 255;
} else {
for (int i = 0; i < 4; i++)
col[i] = (Turbulence(i, point, fX, fY, octaves, true,
doStitch, filterX, filterY, filterWidth, filterHeight) * 255 + 255) / 2;
}
for (int i = 0; i < 4; i++) {
col[i] = std::min(col[i], 255.f);
col[i] = std::max(col[i], 0.f);
}
uint8_t r, g, b, a;
a = uint8_t(col[3]);
FAST_DIVIDE_BY_255(r, unsigned(col[0]) * a);
FAST_DIVIDE_BY_255(g, unsigned(col[1]) * a);
FAST_DIVIDE_BY_255(b, unsigned(col[2]) * a);
targetData[targIndex + GFX_ARGB32_OFFSET_B] = b;
targetData[targIndex + GFX_ARGB32_OFFSET_G] = g;
targetData[targIndex + GFX_ARGB32_OFFSET_R] = r;
targetData[targIndex + GFX_ARGB32_OFFSET_A] = a;
}
}
return NS_OK;
}
bool
nsSVGFETurbulenceElement::AttributeAffectsRendering(int32_t aNameSpaceID,
nsIAtom* aAttribute) const
{
return nsSVGFETurbulenceElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
(aNameSpaceID == kNameSpaceID_None &&
(aAttribute == nsGkAtoms::seed ||
aAttribute == nsGkAtoms::baseFrequency ||
aAttribute == nsGkAtoms::numOctaves ||
aAttribute == nsGkAtoms::type ||
aAttribute == nsGkAtoms::stitchTiles));
}
void
nsSVGFETurbulenceElement::InitSeed(int32_t aSeed)
{
double s;
int i, j, k;
aSeed = SetupSeed(aSeed);
for (k = 0; k < 4; k++) {
for (i = 0; i < sBSize; i++) {
mLatticeSelector[i] = i;
for (j = 0; j < 2; j++) {
mGradient[k][i][j] =
(double) (((aSeed =
Random(aSeed)) % (sBSize + sBSize)) - sBSize) / sBSize;
}
s = double (sqrt
(mGradient[k][i][0] * mGradient[k][i][0] +
mGradient[k][i][1] * mGradient[k][i][1]));
mGradient[k][i][0] /= s;
mGradient[k][i][1] /= s;
}
}
while (--i) {
k = mLatticeSelector[i];
mLatticeSelector[i] = mLatticeSelector[j =
(aSeed =
Random(aSeed)) % sBSize];
mLatticeSelector[j] = k;
}
for (i = 0; i < sBSize + 2; i++) {
mLatticeSelector[sBSize + i] = mLatticeSelector[i];
for (k = 0; k < 4; k++)
for (j = 0; j < 2; j++)
mGradient[k][sBSize + i][j] = mGradient[k][i][j];
}
}
#define S_CURVE(t) ( t * t * (3. - 2. * t) )
#define LERP(t, a, b) ( a + t * (b - a) )
double
nsSVGFETurbulenceElement::Noise2(int aColorChannel, double aVec[2],
StitchInfo *aStitchInfo)
{
int bx0, bx1, by0, by1, b00, b10, b01, b11;
double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
register long i, j;
t = aVec[0] + sPerlinN;
bx0 = (int) t;
bx1 = bx0 + 1;
rx0 = t - (int) t;
rx1 = rx0 - 1.0f;
t = aVec[1] + sPerlinN;
by0 = (int) t;
by1 = by0 + 1;
ry0 = t - (int) t;
ry1 = ry0 - 1.0f;
// If stitching, adjust lattice points accordingly.
if (aStitchInfo != NULL) {
if (bx0 >= aStitchInfo->mWrapX)
bx0 -= aStitchInfo->mWidth;
if (bx1 >= aStitchInfo->mWrapX)
bx1 -= aStitchInfo->mWidth;
if (by0 >= aStitchInfo->mWrapY)
by0 -= aStitchInfo->mHeight;
if (by1 >= aStitchInfo->mWrapY)
by1 -= aStitchInfo->mHeight;
}
bx0 &= sBM;
bx1 &= sBM;
by0 &= sBM;
by1 &= sBM;
i = mLatticeSelector[bx0];
j = mLatticeSelector[bx1];
b00 = mLatticeSelector[i + by0];
b10 = mLatticeSelector[j + by0];
b01 = mLatticeSelector[i + by1];
b11 = mLatticeSelector[j + by1];
sx = double (S_CURVE(rx0));
sy = double (S_CURVE(ry0));
q = mGradient[aColorChannel][b00];
u = rx0 * q[0] + ry0 * q[1];
q = mGradient[aColorChannel][b10];
v = rx1 * q[0] + ry0 * q[1];
a = LERP(sx, u, v);
q = mGradient[aColorChannel][b01];
u = rx0 * q[0] + ry1 * q[1];
q = mGradient[aColorChannel][b11];
v = rx1 * q[0] + ry1 * q[1];
b = LERP(sx, u, v);
return LERP(sy, a, b);
}
#undef S_CURVE
#undef LERP
double
nsSVGFETurbulenceElement::Turbulence(int aColorChannel, double *aPoint,
double aBaseFreqX, double aBaseFreqY,
int aNumOctaves, bool aFractalSum,
bool aDoStitching,
double aTileX, double aTileY,
double aTileWidth, double aTileHeight)
{
StitchInfo stitch;
StitchInfo *stitchInfo = NULL; // Not stitching when NULL.
// Adjust the base frequencies if necessary for stitching.
if (aDoStitching) {
// When stitching tiled turbulence, the frequencies must be adjusted
// so that the tile borders will be continuous.
if (aBaseFreqX != 0.0) {
double loFreq = double (floor(aTileWidth * aBaseFreqX)) / aTileWidth;
double hiFreq = double (ceil(aTileWidth * aBaseFreqX)) / aTileWidth;
if (aBaseFreqX / loFreq < hiFreq / aBaseFreqX)
aBaseFreqX = loFreq;
else
aBaseFreqX = hiFreq;
}
if (aBaseFreqY != 0.0) {
double loFreq = double (floor(aTileHeight * aBaseFreqY)) / aTileHeight;
double hiFreq = double (ceil(aTileHeight * aBaseFreqY)) / aTileHeight;
if (aBaseFreqY / loFreq < hiFreq / aBaseFreqY)
aBaseFreqY = loFreq;
else
aBaseFreqY = hiFreq;
}
// Set up initial stitch values.
stitchInfo = &stitch;
stitch.mWidth = int (aTileWidth * aBaseFreqX + 0.5f);
stitch.mWrapX = int (aTileX * aBaseFreqX + sPerlinN + stitch.mWidth);
stitch.mHeight = int (aTileHeight * aBaseFreqY + 0.5f);
stitch.mWrapY = int (aTileY * aBaseFreqY + sPerlinN + stitch.mHeight);
}
double sum = 0.0f;
double vec[2];
vec[0] = aPoint[0] * aBaseFreqX;
vec[1] = aPoint[1] * aBaseFreqY;
double ratio = 1;
for (int octave = 0; octave < aNumOctaves; octave++) {
if (aFractalSum)
sum += double (Noise2(aColorChannel, vec, stitchInfo) / ratio);
else
sum += double (fabs(Noise2(aColorChannel, vec, stitchInfo)) / ratio);
vec[0] *= 2;
vec[1] *= 2;
ratio *= 2;
if (stitchInfo != NULL) {
// Update stitch values. Subtracting sPerlinN before the multiplication
// and adding it afterward simplifies to subtracting it once.
stitch.mWidth *= 2;
stitch.mWrapX = 2 * stitch.mWrapX - sPerlinN;
stitch.mHeight *= 2;
stitch.mWrapY = 2 * stitch.mWrapY - sPerlinN;
}
}
return sum;
}
nsIntRect
nsSVGFETurbulenceElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance)
{
return GetMaxRect();
}
//----------------------------------------------------------------------
// nsSVGElement methods
nsSVGElement::NumberAttributesInfo
nsSVGFETurbulenceElement::GetNumberInfo()
{
return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
ArrayLength(sNumberInfo));
}
nsSVGElement::NumberPairAttributesInfo
nsSVGFETurbulenceElement::GetNumberPairInfo()
{
return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo,
ArrayLength(sNumberPairInfo));
}
nsSVGElement::IntegerAttributesInfo
nsSVGFETurbulenceElement::GetIntegerInfo()
{
return IntegerAttributesInfo(mIntegerAttributes, sIntegerInfo,
ArrayLength(sIntegerInfo));
}
nsSVGElement::EnumAttributesInfo
nsSVGFETurbulenceElement::GetEnumInfo()
{
return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
ArrayLength(sEnumInfo));
}
nsSVGElement::StringAttributesInfo
nsSVGFETurbulenceElement::GetStringInfo()
{
return StringAttributesInfo(mStringAttributes, sStringInfo,
ArrayLength(sStringInfo));
}
//--------------------------------------------------------------------
//
nsSVGElement::NumberInfo nsSVGFELightingElement::sNumberInfo[4] =