mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 13:55:43 +00:00
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:
parent
2077c75f8c
commit
84fe1989bf
@ -95,6 +95,7 @@ CPPSRCS = \
|
|||||||
SVGFESpecularLightingElement.cpp \
|
SVGFESpecularLightingElement.cpp \
|
||||||
SVGFESpotLightElement.cpp \
|
SVGFESpotLightElement.cpp \
|
||||||
SVGFETileElement.cpp \
|
SVGFETileElement.cpp \
|
||||||
|
SVGFETurbulenceElement.cpp \
|
||||||
SVGFilterElement.cpp \
|
SVGFilterElement.cpp \
|
||||||
SVGForeignObjectElement.cpp \
|
SVGForeignObjectElement.cpp \
|
||||||
SVGFragmentIdentifier.cpp \
|
SVGFragmentIdentifier.cpp \
|
||||||
@ -208,6 +209,7 @@ EXPORTS_mozilla/dom = \
|
|||||||
SVGFESpecularLightingElement.h \
|
SVGFESpecularLightingElement.h \
|
||||||
SVGFESpotLightElement.h \
|
SVGFESpotLightElement.h \
|
||||||
SVGFETileElement.h \
|
SVGFETileElement.h \
|
||||||
|
SVGFETurbulenceElement.h \
|
||||||
SVGFilterElement.h \
|
SVGFilterElement.h \
|
||||||
SVGForeignObjectElement.h \
|
SVGForeignObjectElement.h \
|
||||||
SVGGElement.h \
|
SVGGElement.h \
|
||||||
|
422
content/svg/content/src/SVGFETurbulenceElement.cpp
Normal file
422
content/svg/content/src/SVGFETurbulenceElement.cpp
Normal 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
|
151
content/svg/content/src/SVGFETurbulenceElement.h
Normal file
151
content/svg/content/src/SVGFETurbulenceElement.h
Normal 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
|
@ -660,552 +660,6 @@ NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFuncAElement)
|
|||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // 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] =
|
nsSVGElement::NumberInfo nsSVGFELightingElement::sNumberInfo[4] =
|
||||||
|
Loading…
Reference in New Issue
Block a user