Bug 370556 - switch filter subregion logic to agree with WG opinion.

r=longsronr, s=roc
This commit is contained in:
tor%cs.brown.edu 2007-02-19 20:05:17 +00:00
Родитель 8b3f3d0df5
Коммит c4f5f1c92d
1 изменённых файлов: 68 добавлений и 98 удалений

Просмотреть файл

@ -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