Bug 940845 - Part 2: Add a static BlurRectangle method to nsContextBoxBlur and use it when we're blurring a rectangle. r=roc

This commit is contained in:
Matt Woodrow 2013-11-26 12:06:17 +13:00
parent 701b35213b
commit 20050256f7
2 changed files with 87 additions and 50 deletions

View File

@ -1085,12 +1085,8 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
nsRect shadowRect = frameRect;
shadowRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
nscoord pixelSpreadRadius;
if (nativeTheme) {
pixelSpreadRadius = shadowItem->mSpread;
} else {
if (!nativeTheme) {
shadowRect.Inflate(shadowItem->mSpread, shadowItem->mSpread);
pixelSpreadRadius = 0;
}
// shadowRect won't include the blur, so make an extra rect here that includes the blur
@ -1100,32 +1096,10 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
shadowRectPlusBlur.Inflate(
nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel));
gfxRect shadowGfxRect =
nsLayoutUtils::RectToGfxRect(shadowRect, twipsPerPixel);
gfxRect shadowGfxRectPlusBlur =
nsLayoutUtils::RectToGfxRect(shadowRectPlusBlur, twipsPerPixel);
shadowGfxRect.Round();
shadowGfxRectPlusBlur.RoundOut();
gfxContext* renderContext = aRenderingContext.ThebesContext();
nsContextBoxBlur blurringArea;
// When getting the widget shape from the native theme, we're going
// to draw the widget into the shadow surface to create a mask.
// We need to ensure that there actually *is* a shadow surface
// and that we're not going to draw directly into renderContext.
gfxContext* shadowContext =
blurringArea.Init(shadowRect, pixelSpreadRadius,
blurRadius, twipsPerPixel, renderContext, aDirtyRect,
useSkipGfxRect ? &skipGfxRect : nullptr,
nativeTheme ? nsContextBoxBlur::FORCE_MASK : 0);
if (!shadowContext)
continue;
// shadowContext is owned by either blurringArea or aRenderingContext.
MOZ_ASSERT(shadowContext == renderContext ||
shadowContext == blurringArea.GetContext());
// Set the shadow color; if not specified, use the foreground color
nscolor shadowColor;
if (shadowItem->mHasColor)
@ -1136,15 +1110,34 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
gfxRGBA gfxShadowColor(shadowColor);
gfxShadowColor.a *= aOpacity;
renderContext->Save();
renderContext->SetColor(gfxShadowColor);
// Draw the shape of the frame so it can be blurred. Recall how nsContextBoxBlur
// doesn't make any temporary surfaces if blur is 0 and it just returns the original
// surface? If we have no blur, we're painting this fill on the actual content surface
// (renderContext == shadowContext) which is why we set up the color and clip
// before doing this.
gfxContext* renderContext = aRenderingContext.ThebesContext();
if (nativeTheme) {
nsContextBoxBlur blurringArea;
// When getting the widget shape from the native theme, we're going
// to draw the widget into the shadow surface to create a mask.
// We need to ensure that there actually *is* a shadow surface
// and that we're not going to draw directly into renderContext.
gfxContext* shadowContext =
blurringArea.Init(shadowRect, shadowItem->mSpread,
blurRadius, twipsPerPixel, renderContext, aDirtyRect,
useSkipGfxRect ? &skipGfxRect : nullptr,
nsContextBoxBlur::FORCE_MASK);
if (!shadowContext)
continue;
// shadowContext is owned by either blurringArea or aRenderingContext.
MOZ_ASSERT(shadowContext == blurringArea.GetContext());
renderContext->Save();
renderContext->SetColor(gfxShadowColor);
// Draw the shape of the frame so it can be blurred. Recall how nsContextBoxBlur
// doesn't make any temporary surfaces if blur is 0 and it just returns the original
// surface? If we have no blur, we're painting this fill on the actual content surface
// (renderContext == shadowContext) which is why we set up the color and clip
// before doing this.
// We don't clip the border-box from the shadow, nor any other box.
// We assume that the native theme is going to paint over the shadow.
@ -1159,7 +1152,11 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
nativeRect.IntersectRect(frameRect, aDirtyRect);
aPresContext->GetTheme()->DrawWidgetBackground(wrapperCtx, aForFrame,
styleDisplay->mAppearance, aFrameArea, nativeRect);
blurringArea.DoPaint();
renderContext->Restore();
} else {
renderContext->Save();
// Clip out the area of the actual frame so the shadow is not shown within
// the frame
renderContext->NewPath();
@ -1173,9 +1170,8 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
renderContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
renderContext->Clip();
shadowContext->NewPath();
gfxCornerSizes clipRectRadii;
if (hasBorderRadius) {
gfxCornerSizes clipRectRadii;
gfxFloat spreadDistance = shadowItem->mSpread / twipsPerPixel;
gfxFloat borderSizes[4];
@ -1187,15 +1183,19 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
nsCSSBorderRenderer::ComputeOuterRadii(borderRadii, borderSizes,
&clipRectRadii);
shadowContext->RoundedRectangle(shadowGfxRect, clipRectRadii);
} else {
shadowContext->Rectangle(shadowGfxRect);
}
shadowContext->Fill();
nsContextBoxBlur::BlurRectangle(renderContext,
shadowRect,
twipsPerPixel,
hasBorderRadius ? &clipRectRadii : nullptr,
blurRadius,
gfxShadowColor,
aDirtyRect,
skipGfxRect);
renderContext->Restore();
}
blurringArea.DoPaint();
renderContext->Restore();
}
}
@ -4807,3 +4807,38 @@ nsContextBoxBlur::GetBlurRadiusMargin(nscoord aBlurRadius,
result.left = blurRadius.width * aAppUnitsPerDevPixel;
return result;
}
/* static */ void
nsContextBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
const nsRect& aRect,
int32_t aAppUnitsPerDevPixel,
gfxCornerSizes* aCornerRadii,
nscoord aBlurRadius,
const gfxRGBA& aShadowColor,
const nsRect& aDirtyRect,
const gfxRect& aSkipRect)
{
nsContextBoxBlur blur;
gfxContext *dest = blur.Init(aRect, 0, aBlurRadius, aAppUnitsPerDevPixel,
aDestinationCtx, aDirtyRect, &aSkipRect);
if (!dest) {
return;
}
gfxRect shadowGfxRect =
nsLayoutUtils::RectToGfxRect(aRect, aAppUnitsPerDevPixel);
shadowGfxRect.Round();
aDestinationCtx->SetColor(aShadowColor);
dest->NewPath();
if (aCornerRadii) {
dest->RoundedRectangle(shadowGfxRect, *aCornerRadii);
} else {
dest->Rectangle(shadowGfxRect);
}
dest->Fill();
blur.DoPaint();
}

View File

@ -784,13 +784,6 @@ public:
const nsRect& aDirtyRect, const gfxRect* aSkipRect,
uint32_t aFlags = 0);
/**
* Does the actual blurring/spreading. Users of this object *must*
* have called Init() first, then have drawn whatever they want to be
* blurred onto the internal gfxContext before calling this.
*/
void DoEffects();
/**
* Does the actual blurring and mask applying. Users of this object *must*
* have called Init() first, then have drawn whatever they want to be
@ -814,6 +807,15 @@ public:
static nsMargin GetBlurRadiusMargin(nscoord aBlurRadius,
int32_t aAppUnitsPerDevPixel);
static void BlurRectangle(gfxContext* aDestinationCtx,
const nsRect& aRect,
int32_t aAppUnitsPerDevPixel,
gfxCornerSizes* aCornerRadii,
nscoord aBlurRadius,
const gfxRGBA& aShadowColor,
const nsRect& aDirtyRect,
const gfxRect& aSkipRect);
protected:
gfxAlphaBoxBlur blur;
nsRefPtr<gfxContext> mContext;