Bug 467518. Interpret gfxBlur's border radius properly, as the actual boundary of the shadow, not the box-blur size. r=vlad

This commit is contained in:
Robert O'Callahan 2008-12-08 13:59:21 +13:00
parent 10f2d6de05
commit d980ae8005

View File

@ -186,6 +186,48 @@ BoxBlurVertical(unsigned char* aInput,
} }
} }
static void ComputeLobes(PRInt32 aRadius, PRInt32 aLobes[3][2])
{
PRInt32 major, minor, final;
/* See http://www.w3.org/TR/SVG/filters.html#feGaussianBlur for
* some notes about approximating the Gaussian blur with box-blurs.
* The comments below are in the terminology of that page.
*/
PRInt32 z = aRadius/3;
switch (aRadius % 3) {
case 0:
// aRadius = z*3; choose d = 2*z + 1
major = minor = final = z;
break;
case 1:
// aRadius = z*3 + 1
// This is a tricky case since there is no value of d which will
// yield a radius of exactly aRadius. If d is odd, i.e. d=2*k + 1
// for some integer k, then the radius will be 3*k. If d is even,
// i.e. d=2*k, then the radius will be 3*k - 1.
// So we have to choose values that don't match the standard
// algorithm.
major = z + 1;
minor = final = z;
break;
case 2:
// aRadius = z*3 + 2; choose d = 2*z + 2
major = final = z + 1;
minor = z;
break;
}
NS_ASSERTION(major + minor + final == aRadius,
"Lobes don't sum to the right length");
aLobes[0][0] = major;
aLobes[0][1] = minor;
aLobes[1][0] = minor;
aLobes[1][1] = major;
aLobes[2][0] = final;
aLobes[2][1] = final;
}
void void
gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset) gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
{ {
@ -196,12 +238,6 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
// no need to do all this if not blurring // no need to do all this if not blurring
if (mBlurRadius.width != 0 || mBlurRadius.height != 0) { if (mBlurRadius.width != 0 || mBlurRadius.height != 0) {
// A blur radius of 1 achieves nothing (1/2 = 0 in int terms),
// but we still want a blur!
// XXX this may not be appropriate... perhaps just use actuall Gaussian here?
mBlurRadius.width = PR_MAX(mBlurRadius.width, 2);
mBlurRadius.height = PR_MAX(mBlurRadius.height, 2);
nsTArray<unsigned char> tempAlphaDataBuf; nsTArray<unsigned char> tempAlphaDataBuf;
if (!tempAlphaDataBuf.SetLength(mImageSurface->GetDataSize())) if (!tempAlphaDataBuf.SetLength(mImageSurface->GetDataSize()))
return; // OOM return; // OOM
@ -211,19 +247,19 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
PRInt32 rows = mImageSurface->Height(); PRInt32 rows = mImageSurface->Height();
if (mBlurRadius.width > 0) { if (mBlurRadius.width > 0) {
PRInt32 longLobe = mBlurRadius.width / 2; PRInt32 lobes[3][2];
PRInt32 shortLobe = (mBlurRadius.width & 1) ? longLobe : longLobe - 1; ComputeLobes(mBlurRadius.width, lobes);
BoxBlurHorizontal(boxData, tmpData, longLobe, shortLobe, stride, rows); BoxBlurHorizontal(boxData, tmpData, lobes[0][0], lobes[0][1], stride, rows);
BoxBlurHorizontal(tmpData, boxData, shortLobe, longLobe, stride, rows); BoxBlurHorizontal(tmpData, boxData, lobes[1][0], lobes[1][1], stride, rows);
BoxBlurHorizontal(boxData, tmpData, longLobe, longLobe, stride, rows); BoxBlurHorizontal(boxData, tmpData, lobes[2][0], lobes[2][1], stride, rows);
} }
if (mBlurRadius.height > 0) { if (mBlurRadius.height > 0) {
PRInt32 longLobe = mBlurRadius.height / 2; PRInt32 lobes[3][2];
PRInt32 shortLobe = (mBlurRadius.height & 1) ? longLobe : longLobe - 1; ComputeLobes(mBlurRadius.height, lobes);
BoxBlurVertical(tmpData, boxData, longLobe, shortLobe, stride, rows); BoxBlurVertical(tmpData, boxData, lobes[0][0], lobes[0][1], stride, rows);
BoxBlurVertical(boxData, tmpData, shortLobe, longLobe, stride, rows); BoxBlurVertical(boxData, tmpData, lobes[1][0], lobes[1][1], stride, rows);
BoxBlurVertical(tmpData, boxData, longLobe, longLobe, stride, rows); BoxBlurVertical(tmpData, boxData, lobes[2][0], lobes[2][1], stride, rows);
} }
} }
@ -241,7 +277,8 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
} }
} }
static const gfxFloat GAUSSIAN_SCALE_FACTOR = 3 * sqrt(2 * M_PI) / 4; // Blur radius is approximately 3/2 times the box-blur size
static const gfxFloat GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * (3/2);
gfxIntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd) gfxIntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd)
{ {