mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-28 05:10:49 +00:00
Bug 468018 - Optimize box-shadow rendering even further by doing more intersections; r=vladimir
This commit is contained in:
parent
8abd186fde
commit
f770f5b88f
@ -1468,7 +1468,7 @@ nsCanvasRenderingContext2D::ShadowInitialize(const gfxRect& extents, gfxAlphaBox
|
||||
blurRadius.height, blurRadius.width);
|
||||
drawExtents = drawExtents.Intersect(clipExtents - CurrentState().shadowOffset);
|
||||
|
||||
gfxContext* ctx = blur.Init(drawExtents, blurRadius);
|
||||
gfxContext* ctx = blur.Init(drawExtents, blurRadius, nsnull);
|
||||
|
||||
if (!ctx)
|
||||
return nsnull;
|
||||
|
@ -66,9 +66,13 @@ public:
|
||||
* @param aRect The coordinates of the surface to create in device units.
|
||||
*
|
||||
* @param aBlurRadius The blur radius in pixels
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
gfxContext* Init(const gfxRect& aRect,
|
||||
const gfxIntSize& aBlurRadius);
|
||||
const gfxIntSize& aBlurRadius,
|
||||
const gfxRect* aDirtyRect);
|
||||
|
||||
/**
|
||||
* Returns the context that should be drawn to supply the alpha mask to be
|
||||
@ -116,6 +120,13 @@ protected:
|
||||
* The temporary alpha surface.
|
||||
*/
|
||||
nsRefPtr<gfxImageSurface> mImageSurface;
|
||||
|
||||
/**
|
||||
* A copy of the dirty rect passed to Init(). This will only be valid if
|
||||
* mHasDirtyRect is TRUE.
|
||||
*/
|
||||
gfxRect mDirtyRect;
|
||||
PRBool mHasDirtyRect;
|
||||
};
|
||||
|
||||
#endif /* GFX_BLUR_H */
|
||||
|
@ -54,12 +54,12 @@ gfxAlphaBoxBlur::~gfxAlphaBoxBlur()
|
||||
|
||||
gfxContext*
|
||||
gfxAlphaBoxBlur::Init(const gfxRect& aRect,
|
||||
const gfxIntSize& aBlurRadius)
|
||||
const gfxIntSize& aBlurRadius,
|
||||
const gfxRect* aDirtyRect)
|
||||
{
|
||||
mBlurRadius = aBlurRadius;
|
||||
|
||||
gfxRect rect(aRect);
|
||||
|
||||
rect.Outset(aBlurRadius.height, aBlurRadius.width,
|
||||
aBlurRadius.height, aBlurRadius.width);
|
||||
rect.RoundOut();
|
||||
@ -67,6 +67,19 @@ gfxAlphaBoxBlur::Init(const gfxRect& aRect,
|
||||
if (rect.IsEmpty())
|
||||
return nsnull;
|
||||
|
||||
if (aDirtyRect) {
|
||||
// If we get passed a dirty rect from layout, we can minimize the
|
||||
// shadow size and make painting faster.
|
||||
mHasDirtyRect = PR_TRUE;
|
||||
mDirtyRect = *aDirtyRect;
|
||||
gfxRect requiredBlurArea = mDirtyRect.Intersect(rect);
|
||||
requiredBlurArea.Outset(aBlurRadius.height, aBlurRadius.width,
|
||||
aBlurRadius.height, aBlurRadius.width);
|
||||
rect = requiredBlurArea.Intersect(rect);
|
||||
} else {
|
||||
mHasDirtyRect = 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())),
|
||||
@ -214,7 +227,18 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
|
||||
}
|
||||
}
|
||||
|
||||
aDestinationCtx->Mask(mImageSurface, offset);
|
||||
// Avoid a semi-expensive clip operation if we can, otherwise
|
||||
// clip to the dirty rect
|
||||
if (mHasDirtyRect) {
|
||||
aDestinationCtx->Save();
|
||||
aDestinationCtx->NewPath();
|
||||
aDestinationCtx->Rectangle(mDirtyRect);
|
||||
aDestinationCtx->Clip();
|
||||
aDestinationCtx->Mask(mImageSurface, offset);
|
||||
aDestinationCtx->Restore();
|
||||
} else {
|
||||
aDestinationCtx->Mask(mImageSurface, offset);
|
||||
}
|
||||
}
|
||||
|
||||
static const gfxFloat GAUSSIAN_SCALE_FACTOR = 3 * sqrt(2 * M_PI) / 4;
|
||||
|
@ -2567,22 +2567,11 @@ nsContextBoxBlur::Init(const gfxRect& aRect, nscoord aBlurRadius,
|
||||
|
||||
gfxRect dirtyRect = aDirtyRect;
|
||||
dirtyRect.ScaleInverse(aAppUnitsPerDevPixel);
|
||||
gfxRect rectWithBlur = rect;
|
||||
rectWithBlur.Outset(blurRadius);
|
||||
|
||||
// Determine the area of the shadow we need.
|
||||
mRequiredShadowArea = dirtyRect.Intersect(rectWithBlur);
|
||||
|
||||
mDestinationCtx = aDestinationCtx;
|
||||
|
||||
// XXX the temporary surface will be the mRequiredShadowArea inflated by
|
||||
// blurRadius in each direction so that the required shadow pixels are computed
|
||||
// correctly. We could actually use a smaller temporary surface by observing
|
||||
// that where the temporary surface is outside the rectWithBlur, the pixel
|
||||
// values are guaranteed to be fully transparent, so we could intersect the
|
||||
// inflated mRequiredShadowArea with rectWithBlur to compute the temporary
|
||||
// surface area. But we're not doing that right now because it's more complex to do.
|
||||
mContext = blur.Init(mRequiredShadowArea, gfxIntSize(blurRadius, blurRadius));
|
||||
// Create the temporary surface for blurring
|
||||
mContext = blur.Init(rect, gfxIntSize(blurRadius, blurRadius), &dirtyRect);
|
||||
return mContext;
|
||||
}
|
||||
|
||||
@ -2592,12 +2581,7 @@ nsContextBoxBlur::DoPaint()
|
||||
if (mContext == mDestinationCtx)
|
||||
return;
|
||||
|
||||
mDestinationCtx->Save();
|
||||
mDestinationCtx->NewPath();
|
||||
mDestinationCtx->Rectangle(mRequiredShadowArea);
|
||||
mDestinationCtx->Clip();
|
||||
blur.Paint(mDestinationCtx);
|
||||
mDestinationCtx->Restore();
|
||||
}
|
||||
|
||||
gfxContext*
|
||||
|
@ -327,8 +327,6 @@ protected:
|
||||
gfxAlphaBoxBlur blur;
|
||||
nsRefPtr<gfxContext> mContext;
|
||||
gfxContext* mDestinationCtx;
|
||||
|
||||
gfxRect mRequiredShadowArea;
|
||||
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user