Bug 940845 - Part 4: Add BlurRectangle to gfxAlphaBoxBlur and use it. r=roc

This commit is contained in:
Matt Woodrow 2013-11-26 12:08:29 +13:00
parent d0f9c81a1e
commit cf7881aa40
5 changed files with 93 additions and 52 deletions

View File

@ -69,6 +69,10 @@ struct BaseSize {
Sub operator/(T aScale) const {
return Sub(width / aScale, height / aScale);
}
void Scale(T aXScale, T aYScale) {
width *= aXScale;
height *= aYScale;
}
Sub operator*(const Sub& aSize) const {
return Sub(width * aSize.width, height * aSize.height);

View File

@ -112,3 +112,35 @@ gfxIntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd)
IntSize size = AlphaBoxBlur::CalculateBlurRadius(std);
return gfxIntSize(size.width, size.height);
}
/* static */ void
gfxAlphaBoxBlur::BlurRectangle(gfxContext *aDestinationCtx,
const gfxRect& aRect,
gfxCornerSizes* aCornerRadii,
const gfxIntSize& aBlurRadius,
const gfxRGBA& aShadowColor,
const gfxRect& aDirtyRect,
const gfxRect& aSkipRect)
{
// Create the temporary surface for blurring
gfxAlphaBoxBlur blur;
gfxContext *dest = blur.Init(aRect, gfxIntSize(), aBlurRadius, &aDirtyRect, &aSkipRect);
if (!dest) {
return;
}
gfxRect shadowGfxRect = aRect;
shadowGfxRect.Round();
dest->NewPath();
if (aCornerRadii) {
dest->RoundedRectangle(shadowGfxRect, *aCornerRadii);
} else {
dest->Rectangle(shadowGfxRect);
}
dest->Fill();
aDestinationCtx->SetColor(aShadowColor);
blur.Paint(aDestinationCtx);
}

View File

@ -14,6 +14,9 @@
class gfxContext;
class gfxImageSurface;
struct gfxRect;
struct gfxRGBA;
class gfxCornerSizes;
class gfxMatrix;
namespace mozilla {
namespace gfx {
@ -99,6 +102,16 @@ public:
*/
static gfxIntSize CalculateBlurRadius(const gfxPoint& aStandardDeviation);
static void BlurRectangle(gfxContext *aDestinationCtx,
const gfxRect& aRect,
gfxCornerSizes* aCornerRadii,
const gfxIntSize& aBlurRadius,
const gfxRGBA& aShadowColor,
const gfxRect& aDirtyRect,
const gfxRect& aSkipRect);
protected:
/**
* The context of the temporary alpha surface.

View File

@ -171,6 +171,12 @@ struct gfxCornerSizes {
return sizes[index];
}
void Scale(gfxFloat aXScale, gfxFloat aYScale)
{
for (int i = 0; i < NS_NUM_CORNERS; i++)
sizes[i].Scale(aXScale, aYScale);
}
const gfxSize TopLeft() const { return sizes[NS_CORNER_TOP_LEFT]; }
gfxSize& TopLeft() { return sizes[NS_CORNER_TOP_LEFT]; }

View File

@ -4822,6 +4822,22 @@ nsContextBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
return;
}
gfxRect shadowGfxRect =
nsLayoutUtils::RectToGfxRect(aRect, aAppUnitsPerDevPixel);
if (aBlurRadius <= 0) {
aDestinationCtx->SetColor(aShadowColor);
aDestinationCtx->NewPath();
if (aCornerRadii) {
aDestinationCtx->RoundedRectangle(shadowGfxRect, *aCornerRadii);
} else {
aDestinationCtx->Rectangle(shadowGfxRect);
}
aDestinationCtx->Fill();
return;
}
gfxFloat scaleX = 1;
gfxFloat scaleY = 1;
@ -4830,61 +4846,31 @@ nsContextBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
// and will sometimes get incorrect results (e.g. rotated blurs)
gfxMatrix transform = aDestinationCtx->CurrentMatrix();
// XXX: we could probably handle negative scales but for now it's easier just to fallback
if (transform.HasNonAxisAlignedTransform() || transform.xx <= 0.0 || transform.yy <= 0.0) {
transform = gfxMatrix();
} else {
if (!transform.HasNonAxisAlignedTransform() && transform.xx > 0.0 && transform.yy > 0.0) {
scaleX = transform.xx;
scaleY = transform.yy;
}
gfxRect shadowGfxRect =
nsLayoutUtils::RectToGfxRect(aRect, aAppUnitsPerDevPixel);
gfxIntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel, scaleX, scaleY);
gfxAlphaBoxBlur blur;
gfxContext *dest;
bool preTransformed = false;
if (blurRadius.width <= 0 && blurRadius.height <= 0) {
dest = aDestinationCtx;
} else {
gfxRect dirtyRect =
nsLayoutUtils::RectToGfxRect(aDirtyRect, aAppUnitsPerDevPixel);
dirtyRect.RoundOut();
gfxRect rect = transform.TransformBounds(shadowGfxRect);
preTransformed = !transform.IsIdentity();
// Create the temporary surface for blurring
dirtyRect = transform.TransformBounds(dirtyRect);
gfxRect skipRect = transform.TransformBounds(aSkipRect);
dest = blur.Init(rect, gfxIntSize(), blurRadius, &dirtyRect, &skipRect);
if (!dest) {
return;
}
dest->SetMatrix(transform);
}
shadowGfxRect.Round();
aDestinationCtx->SetColor(aShadowColor);
dest->NewPath();
if (aCornerRadii) {
dest->RoundedRectangle(shadowGfxRect, *aCornerRadii);
} else {
dest->Rectangle(shadowGfxRect);
}
dest->Fill();
if (dest == aDestinationCtx)
return;
if (preTransformed) {
aDestinationCtx->IdentityMatrix();
}
blur.Paint(aDestinationCtx);
gfxIntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel, scaleX, scaleY);
gfxRect dirtyRect =
nsLayoutUtils::RectToGfxRect(aDirtyRect, aAppUnitsPerDevPixel);
dirtyRect.RoundOut();
shadowGfxRect = transform.TransformBounds(shadowGfxRect);
dirtyRect = transform.TransformBounds(dirtyRect);
gfxRect skipRect = transform.TransformBounds(aSkipRect);
if (aCornerRadii) {
aCornerRadii->Scale(scaleX, scaleY);
}
gfxAlphaBoxBlur::BlurRectangle(aDestinationCtx,
shadowGfxRect,
aCornerRadii,
blurRadius,
aShadowColor,
dirtyRect,
skipRect);
}