зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
3f5a4c7fa0
Коммит
c6570f9692
|
@ -96,6 +96,7 @@ CPPSRCS = \
|
|||
SVGFESpecularLightingElement.cpp \
|
||||
SVGFESpotLightElement.cpp \
|
||||
SVGFETileElement.cpp \
|
||||
SVGFETurbulenceElement.cpp \
|
||||
SVGFilterElement.cpp \
|
||||
SVGForeignObjectElement.cpp \
|
||||
SVGFragmentIdentifier.cpp \
|
||||
|
@ -209,6 +210,7 @@ EXPORTS_mozilla/dom = \
|
|||
SVGFESpecularLightingElement.h \
|
||||
SVGFESpotLightElement.h \
|
||||
SVGFETileElement.h \
|
||||
SVGFETurbulenceElement.h \
|
||||
SVGFilterElement.h \
|
||||
SVGForeignObjectElement.h \
|
||||
SVGGElement.h \
|
||||
|
|
|
@ -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
|
|
@ -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 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] =
|
||||
|
|
Загрузка…
Ссылка в новой задаче