зеркало из https://github.com/mozilla/pjs.git
Bug 370556 - switch filter subregion logic to agree with WG opinion.
r=longsronr, s=roc
This commit is contained in:
Родитель
ca0febb764
Коммит
7a6c67d2e7
|
@ -251,14 +251,6 @@ public:
|
||||||
return mRect;
|
return mRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Releasing a source image will prevent FixupTarget() from copying pixels
|
|
||||||
* outside of the filter sub-region to the target surface.
|
|
||||||
*/
|
|
||||||
void ReleaseSource() {
|
|
||||||
mSourceData = nsnull;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns total length of data buffer in bytes
|
* Returns total length of data buffer in bytes
|
||||||
*/
|
*/
|
||||||
|
@ -273,15 +265,19 @@ public:
|
||||||
return mStride;
|
return mStride;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
/*
|
||||||
void ReleaseTarget();
|
* Copy current sourceImage to targetImage
|
||||||
|
*/
|
||||||
|
void CopySourceImage() { CopyImageSubregion(mTargetData, mSourceData); }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FixupTarget copies the parts of the source image that lie outside of the
|
* Copy subregion from aSrc to aDest.
|
||||||
* filter subregion into the target image. If no source image exists, then
|
current sourceImage to targetImage
|
||||||
* the area outside the filter region is filled with transparent black.
|
|
||||||
*/
|
*/
|
||||||
void FixupTarget();
|
void CopyImageSubregion(PRUint8 *aDest, const PRUint8 *aSrc);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ReleaseTarget();
|
||||||
|
|
||||||
nsAutoString mInput, mResult;
|
nsAutoString mInput, mResult;
|
||||||
nsRect mRect;
|
nsRect mRect;
|
||||||
|
@ -366,7 +362,6 @@ nsSVGFilterResource::ReleaseTarget()
|
||||||
if (!mTargetImage) {
|
if (!mTargetImage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FixupTarget();
|
|
||||||
mInstance->DefineImage(mResult, mTargetImage, mRect, mColorModel);
|
mInstance->DefineImage(mResult, mTargetImage, mRect, mColorModel);
|
||||||
|
|
||||||
// filter instance now owns the image
|
// filter instance now owns the image
|
||||||
|
@ -375,52 +370,15 @@ nsSVGFilterResource::ReleaseTarget()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsSVGFilterResource::FixupTarget()
|
nsSVGFilterResource::CopyImageSubregion(PRUint8 *aDest, const PRUint8 *aSrc)
|
||||||
{
|
{
|
||||||
// top
|
if (!aDest || !aSrc)
|
||||||
if (mRect.y > 0) {
|
return;
|
||||||
for (PRInt32 y = 0; y < mRect.y; y++)
|
|
||||||
if (mSourceData) {
|
|
||||||
memcpy(mTargetData + y * mStride, mSourceData + y * mStride, mStride);
|
|
||||||
} else {
|
|
||||||
memset(mTargetData + y * mStride, 0, mStride);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bottom
|
for (PRInt32 y = mRect.y; y < mRect.YMost(); y++) {
|
||||||
if (mRect.YMost() < mHeight) {
|
memcpy(aDest + y * mStride + 4 * mRect.x,
|
||||||
for (PRInt32 y = mRect.YMost(); y < mHeight; y++)
|
aSrc + y * mStride + 4 * mRect.x,
|
||||||
if (mSourceData) {
|
4 * mRect.width);
|
||||||
memcpy(mTargetData + y * mStride, mSourceData + y * mStride, mStride);
|
|
||||||
} else {
|
|
||||||
memset(mTargetData + y * mStride, 0, mStride);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// left
|
|
||||||
if (mRect.x > 0) {
|
|
||||||
for (PRInt32 y = mRect.y; y < mRect.YMost(); y++)
|
|
||||||
if (mSourceData) {
|
|
||||||
memcpy(mTargetData + y * mStride,
|
|
||||||
mSourceData + y * mStride,
|
|
||||||
4 * mRect.x);
|
|
||||||
} else {
|
|
||||||
memset(mTargetData + y * mStride, 0, 4 * mRect.x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// right
|
|
||||||
if (mRect.XMost() < mWidth) {
|
|
||||||
for (PRInt32 y = mRect.y; y < mRect.YMost(); y++)
|
|
||||||
if (mSourceData) {
|
|
||||||
memcpy(mTargetData + y * mStride + 4 * mRect.XMost(),
|
|
||||||
mSourceData + y * mStride + 4 * mRect.XMost(),
|
|
||||||
4 * (mWidth - mRect.XMost()));
|
|
||||||
} else {
|
|
||||||
memset(mTargetData + y * mStride + 4 * mRect.XMost(),
|
|
||||||
0,
|
|
||||||
4 * (mWidth - mRect.XMost()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,6 +428,21 @@ protected:
|
||||||
static NumberInfo sNumberInfo[2];
|
static NumberInfo sNumberInfo[2];
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMSVGAnimatedString> mIn1;
|
nsCOMPtr<nsIDOMSVGAnimatedString> mIn1;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void BoxBlurH(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
|
PRInt32 aStride, nsRect aRegion,
|
||||||
|
PRUint32 leftLobe, PRUint32 rightLobe);
|
||||||
|
|
||||||
|
void BoxBlurV(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
|
PRInt32 aStride, nsRect aRegion,
|
||||||
|
unsigned topLobe, unsigned bottomLobe);
|
||||||
|
|
||||||
|
nsresult GaussianBlur(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
|
nsSVGFilterResource *aFilterResource,
|
||||||
|
float aStdX, float aStdY);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
nsSVGElement::NumberInfo nsSVGFEGaussianBlurElement::sNumberInfo[2] =
|
nsSVGElement::NumberInfo nsSVGFEGaussianBlurElement::sNumberInfo[2] =
|
||||||
|
@ -576,10 +549,10 @@ nsSVGFEGaussianBlurElement::ParseAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||||
aValue, aResult);
|
aValue, aResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
boxBlurH(PRUint8 *aInput, PRUint8 *aOutput,
|
nsSVGFEGaussianBlurElement::BoxBlurH(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
PRInt32 aStride, nsRect aRegion,
|
PRInt32 aStride, nsRect aRegion,
|
||||||
PRUint32 leftLobe, PRUint32 rightLobe)
|
PRUint32 leftLobe, PRUint32 rightLobe)
|
||||||
{
|
{
|
||||||
PRInt32 boxSize = leftLobe + rightLobe + 1;
|
PRInt32 boxSize = leftLobe + rightLobe + 1;
|
||||||
|
|
||||||
|
@ -616,10 +589,10 @@ boxBlurH(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
boxBlurV(PRUint8 *aInput, PRUint8 *aOutput,
|
nsSVGFEGaussianBlurElement::BoxBlurV(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
PRInt32 aStride, nsRect aRegion,
|
PRInt32 aStride, nsRect aRegion,
|
||||||
unsigned topLobe, unsigned bottomLobe)
|
unsigned topLobe, unsigned bottomLobe)
|
||||||
{
|
{
|
||||||
PRInt32 boxSize = topLobe + bottomLobe + 1;
|
PRInt32 boxSize = topLobe + bottomLobe + 1;
|
||||||
|
|
||||||
|
@ -656,17 +629,16 @@ boxBlurV(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static nsresult
|
nsresult
|
||||||
gaussianBlur(PRUint8 *aInput, PRUint8 *aOutput,
|
nsSVGFEGaussianBlurElement::GaussianBlur(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
PRUint32 aLength, PRInt32 aStride, nsRect aRegion,
|
nsSVGFilterResource *aFilterResource,
|
||||||
float aStdX, float aStdY)
|
float aStdX, float aStdY)
|
||||||
{
|
{
|
||||||
if (aStdX < 0 || aStdY < 0) {
|
if (aStdX < 0 || aStdY < 0) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aStdX == 0 || aStdY == 0) {
|
if (aStdX == 0 || aStdY == 0) {
|
||||||
memset(aOutput, 0, aLength);
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,41 +646,44 @@ gaussianBlur(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
dX = (PRUint32) floor(aStdX * 3*sqrt(2*M_PI)/4 + 0.5);
|
dX = (PRUint32) floor(aStdX * 3*sqrt(2*M_PI)/4 + 0.5);
|
||||||
dY = (PRUint32) floor(aStdY * 3*sqrt(2*M_PI)/4 + 0.5);
|
dY = (PRUint32) floor(aStdY * 3*sqrt(2*M_PI)/4 + 0.5);
|
||||||
|
|
||||||
PRUint8 *tmp = new PRUint8[aLength];
|
PRUint8 *tmp = NS_STATIC_CAST(PRUint8*,
|
||||||
|
calloc(aFilterResource->GetDataLength(), 1));
|
||||||
|
nsRect rect = aFilterResource->GetRect();
|
||||||
|
PRUint32 stride = aFilterResource->GetDataStride();
|
||||||
|
|
||||||
if (dX & 1) {
|
if (dX & 1) {
|
||||||
// odd
|
// odd
|
||||||
boxBlurH(aInput, tmp, aStride, aRegion, dX/2, dX/2);
|
BoxBlurH(aInput, tmp, stride, rect, dX/2, dX/2);
|
||||||
boxBlurH(tmp, aOutput, aStride, aRegion, dX/2, dX/2);
|
BoxBlurH(tmp, aOutput, stride, rect, dX/2, dX/2);
|
||||||
boxBlurH(aOutput, tmp, aStride, aRegion, dX/2, dX/2);
|
BoxBlurH(aOutput, tmp, stride, rect, dX/2, dX/2);
|
||||||
} else {
|
} else {
|
||||||
// even
|
// even
|
||||||
if (dX == 0) {
|
if (dX == 0) {
|
||||||
memcpy(tmp, aInput, aLength);
|
aFilterResource->CopyImageSubregion(tmp, aInput);
|
||||||
} else {
|
} else {
|
||||||
boxBlurH(aInput, tmp, aStride, aRegion, dX/2, dX/2 - 1);
|
BoxBlurH(aInput, tmp, stride, rect, dX/2, dX/2 - 1);
|
||||||
boxBlurH(tmp, aOutput, aStride, aRegion, dX/2 - 1, dX/2);
|
BoxBlurH(tmp, aOutput, stride, rect, dX/2 - 1, dX/2);
|
||||||
boxBlurH(aOutput, tmp, aStride, aRegion, dX/2, dX/2);
|
BoxBlurH(aOutput, tmp, stride, rect, dX/2, dX/2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dY & 1) {
|
if (dY & 1) {
|
||||||
// odd
|
// odd
|
||||||
boxBlurV(tmp, aOutput, aStride, aRegion, dY/2, dY/2);
|
BoxBlurV(tmp, aOutput, stride, rect, dY/2, dY/2);
|
||||||
boxBlurV(aOutput, tmp, aStride, aRegion, dY/2, dY/2);
|
BoxBlurV(aOutput, tmp, stride, rect, dY/2, dY/2);
|
||||||
boxBlurV(tmp, aOutput, aStride, aRegion, dY/2, dY/2);
|
BoxBlurV(tmp, aOutput, stride, rect, dY/2, dY/2);
|
||||||
} else {
|
} else {
|
||||||
// even
|
// even
|
||||||
if (dY == 0) {
|
if (dY == 0) {
|
||||||
memcpy(aOutput, tmp, aLength);
|
aFilterResource->CopyImageSubregion(aOutput, tmp);
|
||||||
} else {
|
} else {
|
||||||
boxBlurV(tmp, aOutput, aStride, aRegion, dY/2, dY/2 - 1);
|
BoxBlurV(tmp, aOutput, stride, rect, dY/2, dY/2 - 1);
|
||||||
boxBlurV(aOutput, tmp, aStride, aRegion, dY/2 - 1, dY/2);
|
BoxBlurV(aOutput, tmp, stride, rect, dY/2 - 1, dY/2);
|
||||||
boxBlurV(tmp, aOutput, aStride, aRegion, dY/2, dY/2);
|
BoxBlurV(tmp, aOutput, stride, rect, dY/2, dY/2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] tmp;
|
free(tmp);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,9 +699,9 @@ nsSVGFEGaussianBlurElement::Filter(nsSVGFilterInstance *instance)
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
rv = fr.AcquireTargetImage(mResult, &targetData);
|
rv = fr.AcquireTargetImage(mResult, &targetData);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
nsRect rect = fr.GetRect();
|
|
||||||
|
|
||||||
#ifdef DEBUG_tor
|
#ifdef DEBUG_tor
|
||||||
|
nsRect rect = fr.GetRect();
|
||||||
fprintf(stderr, "FILTER GAUSS rect: %d,%d %dx%d\n",
|
fprintf(stderr, "FILTER GAUSS rect: %d,%d %dx%d\n",
|
||||||
rect.x, rect.y, rect.width, rect.height);
|
rect.x, rect.y, rect.width, rect.height);
|
||||||
#endif
|
#endif
|
||||||
|
@ -741,11 +716,7 @@ nsSVGFEGaussianBlurElement::Filter(nsSVGFilterInstance *instance)
|
||||||
val.Init(nsSVGUtils::Y, 0xff, stdY, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER);
|
val.Init(nsSVGUtils::Y, 0xff, stdY, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER);
|
||||||
stdY = instance->GetPrimitiveLength(&val);
|
stdY = instance->GetPrimitiveLength(&val);
|
||||||
|
|
||||||
rv = gaussianBlur(sourceData, targetData, fr.GetDataLength(),
|
return GaussianBlur(sourceData, targetData, &fr, stdX, stdY);
|
||||||
fr.GetDataStride(), rect, stdX, stdY);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PRUint32
|
static PRUint32
|
||||||
|
@ -955,7 +926,7 @@ nsSVGFEBlendElement::Filter(nsSVGFilterInstance *instance)
|
||||||
rect.x, rect.y, rect.width, rect.height);
|
rect.x, rect.y, rect.width, rect.height);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
memcpy(targetData, sourceData, rect.height * stride);
|
fr.CopySourceImage();
|
||||||
|
|
||||||
rv = fr.AcquireSourceImage(mIn2, this, &sourceData);
|
rv = fr.AcquireSourceImage(mIn2, this, &sourceData);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -1249,7 +1220,7 @@ nsSVGFECompositeElement::Filter(nsSVGFilterInstance *instance)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Copy the first source image
|
// Copy the first source image
|
||||||
memcpy(targetData, sourceData, rect.height * stride);
|
fr.CopySourceImage();
|
||||||
|
|
||||||
// Blend in the second source image
|
// Blend in the second source image
|
||||||
rv = fr.AcquireSourceImage(mIn1, this, &sourceData);
|
rv = fr.AcquireSourceImage(mIn1, this, &sourceData);
|
||||||
|
@ -1995,7 +1966,6 @@ nsSVGFEMergeElement::Filter(nsSVGFilterInstance *instance)
|
||||||
cairo_set_source_surface(cr, sourceSurface, 0, 0);
|
cairo_set_source_surface(cr, sourceSurface, 0, 0);
|
||||||
cairo_paint(cr);
|
cairo_paint(cr);
|
||||||
}
|
}
|
||||||
fr.ReleaseSource();
|
|
||||||
cairo_destroy(cr);
|
cairo_destroy(cr);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -3236,7 +3206,7 @@ nsSVGFEMorphologyElement::Filter(nsSVGFilterInstance *instance)
|
||||||
mOperator->GetAnimVal(&op);
|
mOperator->GetAnimVal(&op);
|
||||||
|
|
||||||
if (rx == 0 && ry == 0) {
|
if (rx == 0 && ry == 0) {
|
||||||
memcpy(targetData, sourceData, rect.height * stride);
|
fr.CopySourceImage();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
/* Scan the kernel for each pixel to determine max/min RGBA values. Note that
|
/* Scan the kernel for each pixel to determine max/min RGBA values. Note that
|
||||||
|
|
Загрузка…
Ссылка в новой задаче