From: L. David Baron Change the blur radius for -moz-box-shadow and text-shadow to match what is specified in css3-background, and the blur radius for canvas to follow what is specified in HTML5. (Bug 590039) This removes a meaningless but confusing factor of one (the result of (3/2) as an integer division) in gfxAlphaBoxBlur::CalculateBlurRadius that was added in changeset ce9f05b57b95 for bug 467518. CalculateBlurRadius represents multiplication by 1.880, both without and with this patch, and follows the formula in the feGaussianBlur section of the SVG spec. This changes canvas shadow handling to multiply shadowBlur by 2 before taking its square root, as described in the spec. This means that canvas shadow blurs 8px or smaller behave as they did before, but canvas shadow blurs larger than 8px are multiplied by 1.414 relative to their old sizes. This changes text-shadow and -moz-box-shadow handling to use CalculateBlurRadius on half of the value given instead of passing the value through directly. This means that text-shadow and box-shadow blurs are multiplied by 0.940 relative to their old sizes. diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp --- a/content/canvas/src/nsCanvasRenderingContext2D.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp @@ -1876,17 +1876,18 @@ nsCanvasRenderingContext2D::GetShadowCol static const gfxFloat SIGMA_MAX = 25; gfxContext* nsCanvasRenderingContext2D::ShadowInitialize(const gfxRect& extents, gfxAlphaBoxBlur& blur) { gfxIntSize blurRadius; - gfxFloat sigma = CurrentState().shadowBlur > 8 ? sqrt(CurrentState().shadowBlur) : CurrentState().shadowBlur / 2; + float shadowBlur = CurrentState().shadowBlur; + gfxFloat sigma = shadowBlur >= 8 ? sqrt(shadowBlur * 2) : (shadowBlur / 2); // limit to avoid overly huge temp images if (sigma > SIGMA_MAX) sigma = SIGMA_MAX; blurRadius = gfxAlphaBoxBlur::CalculateBlurRadius(gfxPoint(sigma, sigma)); // calculate extents gfxRect drawExtents = extents; diff --git a/gfx/thebes/gfxBlur.cpp b/gfx/thebes/gfxBlur.cpp --- a/gfx/thebes/gfxBlur.cpp +++ b/gfx/thebes/gfxBlur.cpp @@ -458,17 +458,20 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDest aDestinationCtx->Clip(); aDestinationCtx->Mask(mImageSurface, offset); aDestinationCtx->Restore(); } else { aDestinationCtx->Mask(mImageSurface, offset); } } -// 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); +/** + * Compute the box blur size (which we're calling the blur radius) from + * the standard deviation. + */ +static const gfxFloat GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4); gfxIntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd) { return gfxIntSize( static_cast(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5)), static_cast(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5))); } diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -3839,39 +3839,45 @@ nsContextBoxBlur::Init(const nsRect& aRe const gfxRect* aSkipRect, PRUint32 aFlags) { if (aRect.IsEmpty()) { mContext = nsnull; return nsnull; } - PRInt32 blurRadius = static_cast(aBlurRadius / aAppUnitsPerDevPixel); - blurRadius = PR_MIN(blurRadius, MAX_BLUR_RADIUS); + // http://dev.w3.org/csswg/css3-background/#box-shadow says that the + // standard deviation of the blur should be half the given blur value. + gfxFloat blurStdDev = + NS_MIN(gfxFloat(aBlurRadius) / gfxFloat(aAppUnitsPerDevPixel), + gfxFloat(MAX_BLUR_RADIUS)) + / 2.0; + gfxIntSize blurRadius = + gfxAlphaBoxBlur::CalculateBlurRadius(gfxPoint(blurStdDev, blurStdDev)); PRInt32 spreadRadius = static_cast(aSpreadRadius / aAppUnitsPerDevPixel); spreadRadius = PR_MIN(spreadRadius, MAX_BLUR_RADIUS); mDestinationCtx = aDestinationCtx; // If not blurring, draw directly onto the destination device - if (blurRadius <= 0 && spreadRadius <= 0 && !(aFlags & FORCE_MASK)) { + if (blurRadius.width <= 0 && blurRadius.height <= 0 && spreadRadius <= 0 && + !(aFlags & FORCE_MASK)) { mContext = aDestinationCtx; return mContext; } // Convert from app units to device pixels gfxRect rect = nsLayoutUtils::RectToGfxRect(aRect, aAppUnitsPerDevPixel); gfxRect dirtyRect = nsLayoutUtils::RectToGfxRect(aDirtyRect, aAppUnitsPerDevPixel); dirtyRect.RoundOut(); // Create the temporary surface for blurring mContext = blur.Init(rect, gfxIntSize(spreadRadius, spreadRadius), - gfxIntSize(blurRadius, blurRadius), - &dirtyRect, aSkipRect); + blurRadius, &dirtyRect, aSkipRect); return mContext; } void nsContextBoxBlur::DoPaint() { if (mContext == mDestinationCtx) return;