Backed out changeset: b3d6a8724029 of

Bug 544099 - Allow shadow blurring to skip areas where blurring is unnecessary; Patch 3.1.
which breaks comm-central.
This commit is contained in:
Serge Gautherie 2010-02-04 20:55:10 +01:00
parent 55ebf80987
commit 271756558e
14 changed files with 60 additions and 265 deletions

View File

@ -1452,7 +1452,7 @@ nsCanvasRenderingContext2D::ShadowInitialize(const gfxRect& extents, gfxAlphaBox
blurRadius.height, blurRadius.width);
drawExtents = drawExtents.Intersect(clipExtents - CurrentState().shadowOffset);
gfxContext* ctx = blur.Init(drawExtents, blurRadius, nsnull, nsnull);
gfxContext* ctx = blur.Init(drawExtents, blurRadius, nsnull);
if (!ctx)
return nsnull;

View File

@ -235,20 +235,6 @@ struct NS_GFX nsIntRect {
height += aMargin.top + aMargin.bottom;
}
// Deflate the rect by the specified width/height or margin
void Deflate(PRInt32 aDx, PRInt32 aDy) {
x += aDx;
y += aDy;
width -= aDx*2;
height -= aDy*2;
}
void Deflate(const nsIntMargin &aMargin) {
x += aMargin.left;
y += aMargin.top;
width -= (aMargin.left + aMargin.right);
height -= (aMargin.top + aMargin.bottom);
}
// Overloaded operators. Note that '=' isn't defined so we'll get the
// compiler generated default assignment operator.
PRBool operator==(const nsIntRect& aRect) const {

View File

@ -42,7 +42,6 @@
#include "gfxImageSurface.h"
#include "gfxRect.h"
#include "gfxTypes.h"
#include "nsRect.h"
/**
* Implementation of a box blur approximation of a Gaussian blur.
@ -70,15 +69,10 @@ public:
*
* @param aDirtyRect A pointer to a dirty rect, measured in device units, if available.
* This will be used for optimizing the blur operation. It is safe to pass NULL here.
*
* @param aSkipRect A pointer to a rect, measured in device units, that represents an area
* where blurring is unnecessary and shouldn't be done for speed reasons. It is safe to
* pass NULL here.
*/
gfxContext* Init(const gfxRect& aRect,
const gfxIntSize& aBlurRadius,
const gfxRect* aDirtyRect,
gfxRect* aSkipRect);
const gfxRect* aDirtyRect);
/**
* Returns the context that should be drawn to supply the alpha mask to be
@ -132,15 +126,7 @@ protected:
* mHasDirtyRect is TRUE.
*/
gfxRect mDirtyRect;
/**
* A rect indicating the area where blurring is unnecessary, and the blur
* algorithm should skip over it. This will only be valid if mHasSkipRect
* is TRUE.
*/
nsIntRect mSkipRect;
PRPackedBool mHasDirtyRect;
PRPackedBool mHasSkipRect;
PRBool mHasDirtyRect;
};
#endif /* GFX_BLUR_H */

View File

@ -149,10 +149,6 @@ struct THEBES_API gfxRect {
// new |RoundAwayFromZero()| method.
void Round();
// Snap the rectangle edges to integer coordinates, such that the
// original rectangle contains the resulting rectangle.
void RoundIn();
// Snap the rectangle edges to integer coordinates, such that the
// resulting rectangle contains the original rectangle.
void RoundOut();

View File

@ -52,23 +52,10 @@ gfxAlphaBoxBlur::~gfxAlphaBoxBlur()
{
}
// Copied from nsSVGUtils
// Converts a gfxRect to an nsIntRect for speed
static nsIntRect
GfxRectToIntRect(const gfxRect& aIn)
{
nsIntRect result(PRInt32(aIn.X()), PRInt32(aIn.Y()),
PRInt32(aIn.Width()), PRInt32(aIn.Height()));
NS_ASSERTION(gfxRect(result.x, result.y, result.width, result.height) == aIn,
"The given gfxRect isn't rounded properly!");
return result;
}
gfxContext*
gfxAlphaBoxBlur::Init(const gfxRect& aRect,
const gfxIntSize& aBlurRadius,
const gfxRect* aDirtyRect,
gfxRect* aSkipRect)
const gfxRect* aDirtyRect)
{
mBlurRadius = aBlurRadius;
@ -93,25 +80,6 @@ gfxAlphaBoxBlur::Init(const gfxRect& aRect,
mHasDirtyRect = PR_FALSE;
}
if (aSkipRect) {
// If we get passed a skip rect, we can lower the amount of
// blurring we need to do. We convert it to nsIntRect to avoid
// expensive int<->float conversions if we were to use gfxRect instead.
aSkipRect->RoundIn();
mSkipRect = GfxRectToIntRect(*aSkipRect);
nsIntRect shadowIntRect = GfxRectToIntRect(rect);
mSkipRect.Deflate(aBlurRadius.width, aBlurRadius.height);
mSkipRect.IntersectRect(mSkipRect, shadowIntRect);
if (mSkipRect == shadowIntRect)
return nsnull;
mSkipRect -= shadowIntRect.TopLeft();
mHasSkipRect = !mSkipRect.IsEmpty();
} else {
mHasSkipRect = PR_FALSE;
}
// Make an alpha-only surface to draw on. We will play with the data after
// everything is drawn to create a blur effect.
mImageSurface = new gfxImageSurface(gfxIntSize(static_cast<PRInt32>(rect.Width()), static_cast<PRInt32>(rect.Height())),
@ -151,7 +119,6 @@ gfxAlphaBoxBlur::PremultiplyAlpha(gfxFloat alpha)
* @param aRightLobe The number of pixels to blend on the right.
* @param aStride The stride of the buffers.
* @param aRows The number of rows in the buffers.
* @param aSkipRect An area to skip blurring in.
*/
static void
BoxBlurHorizontal(unsigned char* aInput,
@ -159,24 +126,11 @@ BoxBlurHorizontal(unsigned char* aInput,
PRInt32 aLeftLobe,
PRInt32 aRightLobe,
PRInt32 aStride,
PRInt32 aRows,
const nsIntRect* aSkipRect)
PRInt32 aRows)
{
PRInt32 boxSize = aLeftLobe + aRightLobe + 1;
PRBool skipRectSpans = aSkipRect && aSkipRect->x <= 0 &&
aSkipRect->XMost() >= aStride - 1;
for (PRInt32 y = 0; y < aRows; y++) {
// Check whether the skip rect intersects this row. If the skip
// rect covers the whole surface in this row, we can avoid
// this row entirely (and any others along the skip rect).
PRBool inSkipRectY = aSkipRect && y >= aSkipRect->y &&
y < aSkipRect->YMost();
if (inSkipRectY && skipRectSpans) {
y = aSkipRect->YMost() - 1;
continue;
}
PRInt32 alphaSum = 0;
for (PRInt32 i = 0; i < boxSize; i++) {
PRInt32 pos = i - aLeftLobe;
@ -185,24 +139,6 @@ BoxBlurHorizontal(unsigned char* aInput,
alphaSum += aInput[aStride * y + pos];
}
for (PRInt32 x = 0; x < aStride; x++) {
// Check whether we are within the skip rect. If so, go
// to the next point outside the skip rect.
if (inSkipRectY && x >= aSkipRect->x &&
x < aSkipRect->XMost()) {
x = aSkipRect->XMost();
if (x >= aStride)
break;
// Recalculate the neighbouring alpha values for
// our new point on the surface.
alphaSum = 0;
for (PRInt32 i = 0; i < boxSize; i++) {
PRInt32 pos = x + i - aLeftLobe;
pos = PR_MAX(pos, 0);
pos = PR_MIN(pos, aStride - 1);
alphaSum += aInput[aStride * y + pos];
}
}
PRInt32 tmp = x - aLeftLobe;
PRInt32 last = PR_MAX(tmp, 0);
PRInt32 next = PR_MIN(tmp + boxSize, aStride - 1);
@ -225,21 +161,11 @@ BoxBlurVertical(unsigned char* aInput,
PRInt32 aTopLobe,
PRInt32 aBottomLobe,
PRInt32 aStride,
PRInt32 aRows,
const nsIntRect* aSkipRect)
PRInt32 aRows)
{
PRInt32 boxSize = aTopLobe + aBottomLobe + 1;
PRBool skipRectSpans = aSkipRect && aSkipRect->y <= 0 &&
aSkipRect->YMost() >= aRows - 1;
for (PRInt32 x = 0; x < aStride; x++) {
PRBool inSkipRectX = aSkipRect && x >= aSkipRect->x &&
x < aSkipRect->XMost();
if (inSkipRectX && skipRectSpans) {
x = aSkipRect->XMost() - 1;
continue;
}
PRInt32 alphaSum = 0;
for (PRInt32 i = 0; i < boxSize; i++) {
PRInt32 pos = i - aTopLobe;
@ -248,20 +174,6 @@ BoxBlurVertical(unsigned char* aInput,
alphaSum += aInput[aStride * pos + x];
}
for (PRInt32 y = 0; y < aRows; y++) {
if (inSkipRectX && y >= aSkipRect->y &&
y < aSkipRect->YMost()) {
y = aSkipRect->YMost();
if (y >= aRows)
break;
alphaSum = 0;
for (PRInt32 i = 0; i < boxSize; i++) {
PRInt32 pos = y + i - aTopLobe;
pos = PR_MAX(pos, 0);
pos = PR_MIN(pos, aRows - 1);
alphaSum += aInput[aStride * pos + x];
}
}
PRInt32 tmp = y - aTopLobe;
PRInt32 last = PR_MAX(tmp, 0);
PRInt32 next = PR_MIN(tmp + boxSize, aRows - 1);
@ -333,22 +245,21 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
unsigned char* tmpData = tempAlphaDataBuf.Elements();
PRInt32 stride = mImageSurface->Stride();
PRInt32 rows = mImageSurface->Height();
const nsIntRect* skipRect = (mHasSkipRect ? &mSkipRect : nsnull);
if (mBlurRadius.width > 0) {
PRInt32 lobes[3][2];
ComputeLobes(mBlurRadius.width, lobes);
BoxBlurHorizontal(boxData, tmpData, lobes[0][0], lobes[0][1], stride, rows, skipRect);
BoxBlurHorizontal(tmpData, boxData, lobes[1][0], lobes[1][1], stride, rows, skipRect);
BoxBlurHorizontal(boxData, tmpData, lobes[2][0], lobes[2][1], stride, rows, skipRect);
BoxBlurHorizontal(boxData, tmpData, lobes[0][0], lobes[0][1], stride, rows);
BoxBlurHorizontal(tmpData, boxData, lobes[1][0], lobes[1][1], stride, rows);
BoxBlurHorizontal(boxData, tmpData, lobes[2][0], lobes[2][1], stride, rows);
}
if (mBlurRadius.height > 0) {
PRInt32 lobes[3][2];
ComputeLobes(mBlurRadius.height, lobes);
BoxBlurVertical(tmpData, boxData, lobes[0][0], lobes[0][1], stride, rows, skipRect);
BoxBlurVertical(boxData, tmpData, lobes[1][0], lobes[1][1], stride, rows, skipRect);
BoxBlurVertical(tmpData, boxData, lobes[2][0], lobes[2][1], stride, rows, skipRect);
BoxBlurVertical(tmpData, boxData, lobes[0][0], lobes[0][1], stride, rows);
BoxBlurVertical(boxData, tmpData, lobes[1][0], lobes[1][1], stride, rows);
BoxBlurVertical(tmpData, boxData, lobes[2][0], lobes[2][1], stride, rows);
}
}

View File

@ -103,21 +103,6 @@ gfxRect::Round()
size.height = y1 - y0;
}
void
gfxRect::RoundIn()
{
gfxFloat x0 = NS_ceil(X());
gfxFloat y0 = NS_ceil(Y());
gfxFloat x1 = NS_floor(XMost());
gfxFloat y1 = NS_floor(YMost());
pos.x = x0;
pos.y = y0;
size.width = x1 - x0;
size.height = y1 - y0;
}
void
gfxRect::RoundOut()
{

View File

@ -1154,14 +1154,6 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
gfxRect frameGfxRect = RectToGfxRect(aFrameArea, twipsPerPixel);
frameGfxRect.Round();
// We don't show anything that intersects with the frame we're blurring on. So tell the
// blurrer not to do unnecessary work there.
gfxRect skipGfxRect = frameGfxRect;
if (hasBorderRadius) {
skipGfxRect.Inset(PR_MAX(borderRadii[C_TL].height, borderRadii[C_TR].height), 0,
PR_MAX(borderRadii[C_BL].height, borderRadii[C_BR].height), 0);
}
for (PRUint32 i = shadows->Length(); i > 0; --i) {
nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
if (shadowItem->mInset)
@ -1186,8 +1178,7 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
nsRefPtr<gfxContext> shadowContext;
nsContextBoxBlur blurringArea;
shadowContext = blurringArea.Init(shadowRect, blurRadius, twipsPerPixel, renderContext,
aDirtyRect, &skipGfxRect);
shadowContext = blurringArea.Init(shadowRect, blurRadius, twipsPerPixel, renderContext, aDirtyRect);
if (!shadowContext)
continue;
@ -1314,9 +1305,46 @@ nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
shadowClipRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
shadowClipRect.Deflate(shadowItem->mSpread, shadowItem->mSpread);
gfxCornerSizes clipRectRadii;
gfxContext* renderContext = aRenderingContext.ThebesContext();
nsRefPtr<gfxContext> shadowContext;
nsContextBoxBlur blurringArea;
shadowContext = blurringArea.Init(shadowPaintRect, blurRadius, twipsPerPixel, renderContext, aDirtyRect);
if (!shadowContext)
continue;
// Set the shadow color; if not specified, use the foreground color
nscolor shadowColor;
if (shadowItem->mHasColor)
shadowColor = shadowItem->mColor;
else
shadowColor = aForFrame->GetStyleColor()->mColor;
renderContext->Save();
renderContext->SetColor(gfxRGBA(shadowColor));
// Clip the context to the area of the frame's padding rect, so no part of the
// shadow is painted outside
gfxRect shadowGfxRect = RectToGfxRect(paddingRect, twipsPerPixel);
shadowGfxRect.Round();
renderContext->NewPath();
if (hasBorderRadius)
renderContext->RoundedRectangle(shadowGfxRect, innerRadii, PR_FALSE);
else
renderContext->Rectangle(shadowGfxRect);
renderContext->Clip();
// Fill the temporary surface minus the area within the frame that we should
// not paint in, and blur and apply it
gfxRect shadowPaintGfxRect = RectToGfxRect(shadowPaintRect, twipsPerPixel);
gfxRect shadowClipGfxRect = RectToGfxRect(shadowClipRect, twipsPerPixel);
shadowPaintGfxRect.RoundOut();
shadowClipGfxRect.Round();
shadowContext->NewPath();
shadowContext->Rectangle(shadowPaintGfxRect);
if (hasBorderRadius) {
// Calculate the radii the inner clipping rect will have
gfxCornerSizes clipRectRadii;
gfxFloat spreadDistance = shadowItem->mSpread / twipsPerPixel;
gfxFloat borderSizes[4] = {0, 0, 0, 0};
@ -1339,63 +1367,10 @@ nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
nsCSSBorderRenderer::ComputeInnerRadii(innerRadii, borderSizes,
&clipRectRadii);
}
// Set the "skip rect" to the area within the frame that we don't paint in,
// including after blurring. We also use this for clipping later on.
nsRect skipRect = shadowClipRect;
skipRect.Deflate(blurRadius, blurRadius);
gfxRect skipGfxRect = RectToGfxRect(skipRect, twipsPerPixel);
if (hasBorderRadius) {
skipGfxRect.Inset(PR_MAX(clipRectRadii[C_TL].height, clipRectRadii[C_TR].height), 0,
PR_MAX(clipRectRadii[C_BL].height, clipRectRadii[C_BR].height), 0);
}
gfxContext* renderContext = aRenderingContext.ThebesContext();
nsRefPtr<gfxContext> shadowContext;
nsContextBoxBlur blurringArea;
shadowContext = blurringArea.Init(shadowPaintRect, blurRadius, twipsPerPixel, renderContext,
aDirtyRect, &skipGfxRect);
if (!shadowContext)
continue;
// Set the shadow color; if not specified, use the foreground color
nscolor shadowColor;
if (shadowItem->mHasColor)
shadowColor = shadowItem->mColor;
else
shadowColor = aForFrame->GetStyleColor()->mColor;
renderContext->Save();
renderContext->SetColor(gfxRGBA(shadowColor));
// Clip the context to the area of the frame's padding rect, so no part of the
// shadow is painted outside. Also cut out anything beyond where the inset shadow
// will be.
gfxRect shadowGfxRect = RectToGfxRect(paddingRect, twipsPerPixel);
shadowGfxRect.Round();
renderContext->NewPath();
if (hasBorderRadius)
renderContext->RoundedRectangle(shadowGfxRect, innerRadii, PR_FALSE);
else
renderContext->Rectangle(shadowGfxRect);
renderContext->Rectangle(skipGfxRect);
renderContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
renderContext->Clip();
// Fill the temporary surface minus the area within the frame that we should
// not paint in, and blur and apply it
gfxRect shadowPaintGfxRect = RectToGfxRect(shadowPaintRect, twipsPerPixel);
shadowPaintGfxRect.RoundOut();
gfxRect shadowClipGfxRect = RectToGfxRect(shadowClipRect, twipsPerPixel);
shadowClipGfxRect.Round();
shadowContext->NewPath();
shadowContext->Rectangle(shadowPaintGfxRect);
if (hasBorderRadius)
shadowContext->RoundedRectangle(shadowClipGfxRect, clipRectRadii, PR_FALSE);
else
} else {
shadowContext->Rectangle(shadowClipGfxRect);
}
shadowContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
shadowContext->Fill();
@ -3692,8 +3667,7 @@ gfxContext*
nsContextBoxBlur::Init(const nsRect& aRect, nscoord aBlurRadius,
PRInt32 aAppUnitsPerDevPixel,
gfxContext* aDestinationCtx,
const nsRect& aDirtyRect,
gfxRect* aSkipRect)
const nsRect& aDirtyRect)
{
if (aRect.IsEmpty()) {
mContext = nsnull;
@ -3717,8 +3691,7 @@ nsContextBoxBlur::Init(const nsRect& aRect, nscoord aBlurRadius,
dirtyRect.RoundOut();
// Create the temporary surface for blurring
mContext = blur.Init(rect, gfxIntSize(blurRadius, blurRadius),
&dirtyRect, aSkipRect);
mContext = blur.Init(rect, gfxIntSize(blurRadius, blurRadius), &dirtyRect);
return mContext;
}

View File

@ -417,9 +417,6 @@ public:
* @param aDirtyRect The absolute dirty rect in app units. Used to
* optimize the temporary surface size and speed up blur.
*
* @param aSkipRect An area in device pixels (NOT app units!) to avoid
* blurring over, to prevent unnecessary work.
*
* @return A blank 8-bit alpha-channel-only graphics context to
* draw on, or null on error. Must not be freed. The
* context has a device offset applied to it given by
@ -435,7 +432,7 @@ public:
*/
gfxContext* Init(const nsRect& aRect, nscoord aBlurRadius,
PRInt32 aAppUnitsPerDevPixel, gfxContext* aDestinationCtx,
const nsRect& aDirtyRect, gfxRect* aSkipRect);
const nsRect& aDirtyRect);
/**
* Does the actual blurring and mask applying. Users of this object *must*

View File

@ -264,7 +264,7 @@ nsDisplayTextShadow::Paint(nsDisplayListBuilder* aBuilder,
nsContextBoxBlur contextBoxBlur;
gfxContext* shadowCtx = contextBoxBlur.Init(shadowRect, mBlurRadius,
presContext->AppUnitsPerDevPixel(),
thebesCtx, mVisibleRect, nsnull);
thebesCtx, mVisibleRect);
if (!shadowCtx)
return;

View File

@ -4478,12 +4478,12 @@ nsTextFrame::PaintOneShadow(PRUint32 aOffset, PRUint32 aLength,
gfxRect shadowGfxRect = shadowMetrics.mBoundingBox +
gfxPoint(aFramePt.x, aTextBaselinePt.y) + shadowOffset;
nsRect shadowRect(shadowGfxRect.X(), shadowGfxRect.Y(),
shadowGfxRect.Width(), shadowGfxRect.Height());
shadowGfxRect.Width(), shadowGfxRect.Height());;
nsContextBoxBlur contextBoxBlur;
gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, blurRadius,
PresContext()->AppUnitsPerDevPixel(),
aCtx, aDirtyRect, nsnull);
aCtx, aDirtyRect);
if (!shadowContext)
return;

View File

@ -1,24 +0,0 @@
<!DOCTYPE HTML>
<style>
#thediv {
width: 400px;
height: 250px;
position: absolute;
top: -500px;
left: -500px;
-moz-box-shadow: 540px 540px 15px black;
}
#blankdiv {
width: 400px;
height: 250px;
background-color: white;
position: absolute;
top: 40px;
left: 40px;
}
</style>
<div id="thediv">&nbsp;</div>
<div id="blankdiv">&nbsp;</div>

View File

@ -1,14 +0,0 @@
<!DOCTYPE HTML>
<style>
#thediv {
width: 400px;
height: 250px;
position: absolute;
top: 40px;
left: 40px;
-moz-box-shadow: 0px 0px 15px black;
}
</style>
<div id="thediv">&nbsp;</div>

View File

@ -13,4 +13,3 @@
== boxshadow-rounded-spread.html boxshadow-rounded-spread-ref.html
HTTP(..) == boxshadow-dynamic.xul boxshadow-dynamic-ref.xul
== boxshadow-onecorner.html boxshadow-onecorner-ref.html
== boxshadow-skiprect.html boxshadow-skiprect-ref.html

View File

@ -579,7 +579,7 @@ void nsTextBoxFrame::PaintOneShadow(gfxContext* aCtx,
nsContextBoxBlur contextBoxBlur;
gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, blurRadius,
PresContext()->AppUnitsPerDevPixel(),
aCtx, aDirtyRect, nsnull);
aCtx, aDirtyRect);
if (!shadowContext)
return;