Bug 757039. Handle non-uniform scales when doing device space blurs. r=roc
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Tue, 22 May 2012 11:32:08 -0400
changeset 94597 dc8bae2d72e70557445e4e093315c010e98a3478
parent 94596 7a6feee6c13cf8bf33e792d678bfb872195c8e03
child 94598 41969fb22ac1663cfc2bcce38a7101da9be1a4ec
push id22732
push useremorley@mozilla.com
push dateWed, 23 May 2012 09:43:13 +0000
treeherdermozilla-central@aa2b52bd0374 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs757039
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 757039. Handle non-uniform scales when doing device space blurs. r=roc The Java screenshoting code draws pages at non-uniform scales. It's not much work to handle these so let's do it.
layout/base/nsCSSRendering.cpp
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -4102,28 +4102,28 @@ nsImageRenderer::GetContainer()
   NS_ENSURE_SUCCESS(rv, nsnull);
   return container.forget();
 }
 
 #define MAX_BLUR_RADIUS 300
 #define MAX_SPREAD_RADIUS 50
 
 static inline gfxIntSize
-ComputeBlurRadius(nscoord aBlurRadius, PRInt32 aAppUnitsPerDevPixel, gfxFloat scale = 1.0)
+ComputeBlurRadius(nscoord aBlurRadius, PRInt32 aAppUnitsPerDevPixel, gfxFloat aScaleX = 1.0, gfxFloat aScaleY = 1.0)
 {
   // 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 = gfxFloat(aBlurRadius) / gfxFloat(aAppUnitsPerDevPixel);
 
-  blurStdDev *= scale;
-
-  blurStdDev = NS_MIN(blurStdDev,
-                      gfxFloat(MAX_BLUR_RADIUS)) / 2.0;
+  gfxPoint scaledBlurStdDev = gfxPoint(NS_MIN((blurStdDev * aScaleX),
+                                              gfxFloat(MAX_BLUR_RADIUS)) / 2.0,
+                                       NS_MIN((blurStdDev * aScaleY),
+                                              gfxFloat(MAX_BLUR_RADIUS)) / 2.0);
   return
-    gfxAlphaBoxBlur::CalculateBlurRadius(gfxPoint(blurStdDev, blurStdDev));
+    gfxAlphaBoxBlur::CalculateBlurRadius(scaledBlurStdDev);
 }
 
 // -----
 // nsContextBoxBlur
 // -----
 gfxContext*
 nsContextBoxBlur::Init(const nsRect& aRect, nscoord aSpreadRadius,
                        nscoord aBlurRadius,
@@ -4133,37 +4133,42 @@ nsContextBoxBlur::Init(const nsRect& aRe
                        const gfxRect* aSkipRect,
                        PRUint32 aFlags)
 {
   if (aRect.IsEmpty()) {
     mContext = nsnull;
     return nsnull;
   }
 
-  gfxFloat scale = 1;
+  gfxFloat scaleX = 1;
+  gfxFloat scaleY = 1;
 
   // Do blurs in device space when possible
   // If the scale is not uniform we fall back to transforming on paint.
   // Chrome/Skia always does the blurs in device space
   // and will sometimes get incorrect results (e.g. rotated blurs)
   gfxMatrix transform = aDestinationCtx->CurrentMatrix();
-  if (transform.HasNonAxisAlignedTransform() || transform.xx != transform.yy) {
+  if (transform.HasNonAxisAlignedTransform()) {
     transform = gfxMatrix();
   } else {
-    scale = transform.xx;
+    scaleX = transform.xx;
+    scaleY = transform.yy;
   }
 
   // compute a large or smaller blur radius
-  gfxIntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel, scale);
-  PRInt32 spreadRadius = NS_MIN(PRInt32(aSpreadRadius / aAppUnitsPerDevPixel),
-                                PRInt32(MAX_SPREAD_RADIUS));
+  gfxIntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel, scaleX, scaleY);
+  gfxIntSize spreadRadius = gfxIntSize(NS_MIN(PRInt32(aSpreadRadius * scaleX / aAppUnitsPerDevPixel),
+                                              PRInt32(MAX_SPREAD_RADIUS)),
+                                       NS_MIN(PRInt32(aSpreadRadius * scaleY / aAppUnitsPerDevPixel),
+                                              PRInt32(MAX_SPREAD_RADIUS)));
   mDestinationCtx = aDestinationCtx;
 
   // If not blurring, draw directly onto the destination device
-  if (blurRadius.width <= 0 && blurRadius.height <= 0 && spreadRadius <= 0 &&
+  if (blurRadius.width <= 0 && blurRadius.height <= 0 &&
+      spreadRadius.width <= 0 && spreadRadius.height <= 0 &&
       !(aFlags & FORCE_MASK)) {
     mContext = aDestinationCtx;
     return mContext;
   }
 
   // Convert from app units to device pixels
   gfxRect rect = nsLayoutUtils::RectToGfxRect(aRect, aAppUnitsPerDevPixel);
 
@@ -4174,20 +4179,20 @@ nsContextBoxBlur::Init(const nsRect& aRe
   rect = transform.TransformBounds(rect);
 
   mPreTransformed = !transform.IsIdentity();
 
   // Create the temporary surface for blurring
   dirtyRect = transform.TransformBounds(dirtyRect);
   if (aSkipRect) {
     gfxRect skipRect = transform.TransformBounds(*aSkipRect);
-    mContext = blur.Init(rect, gfxIntSize(spreadRadius, spreadRadius),
+    mContext = blur.Init(rect, spreadRadius,
                          blurRadius, &dirtyRect, &skipRect);
   } else {
-    mContext = blur.Init(rect, gfxIntSize(spreadRadius, spreadRadius),
+    mContext = blur.Init(rect, spreadRadius,
                          blurRadius, &dirtyRect, NULL);
   }
 
   if (mContext) {
     // we don't need to blur if skipRect is equal to rect
     // and mContext will be NULL
     mContext->SetMatrix(transform);
   }