Issue #2364 - use DrawTarget::DrawSurfaceWithShadow to render box shadows on platforms that accelerate it.

This commit is contained in:
Moonchild 2023-10-30 13:03:32 +01:00 • committed by roytam1
commit 4beb3b947c
13 changed files with 228 additions and 150 deletions

View file

@ -776,5 +776,11 @@ AlphaBoxBlur::CalculateBlurRadius(const Point& aStd)
return size; return size;
} }
Float
AlphaBoxBlur::CalculateBlurSigma(int32_t aBlurRadius)
{
return aBlurRadius / GAUSSIAN_SCALE_FACTOR;
}
} // namespace gfx } // namespace gfx
} // namespace mozilla } // namespace mozilla

View file

@ -99,6 +99,16 @@ public:
*/ */
Rect* GetDirtyRect(); Rect* GetDirtyRect();
/**
* Return the spread radius, in pixels.
*/
IntSize GetSpreadRadius() const { return mSpreadRadius; }
/**
* Return the blur radius, in pixels.
*/
IntSize GetBlurRadius() const { return mBlurRadius; }
/** /**
* Return the minimum buffer size that should be given to Blur() method. If * Return the minimum buffer size that should be given to Blur() method. If
* zero, the class is not properly setup for blurring. Note that this * zero, the class is not properly setup for blurring. Note that this
@ -122,6 +132,7 @@ public:
* constructor, above. * constructor, above.
*/ */
static IntSize CalculateBlurRadius(const Point& aStandardDeviation); static IntSize CalculateBlurRadius(const Point& aStandardDeviation);
static Float CalculateBlurSigma(int32_t aBlurRadius);
private: private:

View file

@ -931,16 +931,18 @@ DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface,
if (cairo_surface_get_type(sourcesurf) == CAIRO_SURFACE_TYPE_TEE) { if (cairo_surface_get_type(sourcesurf) == CAIRO_SURFACE_TYPE_TEE) {
blursurf = cairo_tee_surface_index(sourcesurf, 0); blursurf = cairo_tee_surface_index(sourcesurf, 0);
surf = cairo_tee_surface_index(sourcesurf, 1); surf = cairo_tee_surface_index(sourcesurf, 1);
} else {
blursurf = sourcesurf;
surf = sourcesurf;
}
if (aSigma != 0.0f) {
MOZ_ASSERT(cairo_surface_get_type(blursurf) == CAIRO_SURFACE_TYPE_IMAGE); MOZ_ASSERT(cairo_surface_get_type(blursurf) == CAIRO_SURFACE_TYPE_IMAGE);
Rect extents(0, 0, width, height); Rect extents(0, 0, width, height);
AlphaBoxBlur blur(extents, AlphaBoxBlur blur(extents,
cairo_image_surface_get_stride(blursurf), cairo_image_surface_get_stride(blursurf),
aSigma, aSigma); aSigma, aSigma);
blur.Blur(cairo_image_surface_get_data(blursurf)); blur.Blur(cairo_image_surface_get_data(blursurf));
} else {
blursurf = sourcesurf;
surf = sourcesurf;
} }
WillChange(); WillChange();
@ -951,25 +953,24 @@ DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface,
cairo_identity_matrix(mContext); cairo_identity_matrix(mContext);
cairo_translate(mContext, aDest.x, aDest.y); cairo_translate(mContext, aDest.x, aDest.y);
if (IsOperatorBoundByMask(aOperator)){ bool needsGroup = !IsOperatorBoundByMask(aOperator);
cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a); if (needsGroup) {
cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y); cairo_push_group(mContext);
}
cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a);
cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y);
if (blursurf != surf ||
aSurface->GetFormat() != SurfaceFormat::A8) {
// Now that the shadow has been drawn, we can draw the surface on top. // Now that the shadow has been drawn, we can draw the surface on top.
cairo_set_source_surface(mContext, surf, 0, 0); cairo_set_source_surface(mContext, surf, 0, 0);
cairo_new_path(mContext); cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, width, height); cairo_rectangle(mContext, 0, 0, width, height);
cairo_fill(mContext); cairo_fill(mContext);
} else { }
cairo_push_group(mContext);
cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a);
cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y);
// Now that the shadow has been drawn, we can draw the surface on top. if (needsGroup) {
cairo_set_source_surface(mContext, surf, 0, 0);
cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, width, height);
cairo_fill(mContext);
cairo_pop_group_to_source(mContext); cairo_pop_group_to_source(mContext);
cairo_paint(mContext); cairo_paint(mContext);
} }
@ -1924,7 +1925,7 @@ DrawTargetCairo::CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFor
// If we don't have a blur then we can use the RGBA mask and keep all the // If we don't have a blur then we can use the RGBA mask and keep all the
// operations in graphics memory. // operations in graphics memory.
if (aSigma == 0.0F) { if (aSigma == 0.0f || aFormat == SurfaceFormat::A8) {
RefPtr<DrawTargetCairo> target = new DrawTargetCairo(); RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
if (target->InitAlreadyReferenced(similar, aSize)) { if (target->InitAlreadyReferenced(similar, aSize)) {
return target.forget(); return target.forget();

View file

@ -244,21 +244,29 @@ DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface *aSurface,
// Step 1, create the shadow effect. // Step 1, create the shadow effect.
RefPtr<ID2D1Effect> shadowEffect; RefPtr<ID2D1Effect> shadowEffect;
HRESULT hr = mDC->CreateEffect(CLSID_D2D1Shadow, getter_AddRefs(shadowEffect)); HRESULT hr = mDC->CreateEffect(mFormat == SurfaceFormat::A8 ? CLSID_D2D1GaussianBlur : CLSID_D2D1Shadow,
getter_AddRefs(shadowEffect));
if (FAILED(hr) || !shadowEffect) { if (FAILED(hr) || !shadowEffect) {
gfxWarning() << "Failed to create shadow effect. Code: " << hexa(hr); gfxWarning() << "Failed to create shadow effect. Code: " << hexa(hr);
return; return;
} }
shadowEffect->SetInput(0, image); shadowEffect->SetInput(0, image);
shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, aSigma); if (mFormat == SurfaceFormat::A8) {
D2D1_VECTOR_4F color = { aColor.r, aColor.g, aColor.b, aColor.a }; shadowEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, aSigma);
shadowEffect->SetValue(D2D1_SHADOW_PROP_COLOR, color); shadowEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_BORDER_MODE, D2D1_BORDER_MODE_HARD);
} else {
shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, aSigma);
D2D1_VECTOR_4F color = { aColor.r, aColor.g, aColor.b, aColor.a };
shadowEffect->SetValue(D2D1_SHADOW_PROP_COLOR, color);
}
D2D1_POINT_2F shadowPoint = D2DPoint(aDest + aOffset); D2D1_POINT_2F shadowPoint = D2DPoint(aDest + aOffset);
mDC->DrawImage(shadowEffect, &shadowPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator)); mDC->DrawImage(shadowEffect, &shadowPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator));
D2D1_POINT_2F imgPoint = D2DPoint(aDest); if (aSurface->GetFormat() != SurfaceFormat::A8) {
mDC->DrawImage(image, &imgPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator)); D2D1_POINT_2F imgPoint = D2DPoint(aDest);
mDC->DrawImage(image, &imgPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator));
}
} }
void void

View file

@ -713,9 +713,11 @@ DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface,
mCanvas->drawImage(image, shadowDest.x, shadowDest.y, &shadowPaint); mCanvas->drawImage(image, shadowDest.x, shadowDest.y, &shadowPaint);
} }
// Composite the original image after the shadow if (aSurface->GetFormat() != SurfaceFormat::A8) {
auto dest = IntPoint::Round(aDest); // Composite the original image after the shadow
mCanvas->drawImage(image, dest.x, dest.y, &paint); auto dest = IntPoint::Round(aDest);
mCanvas->drawImage(image, dest.x, dest.y, &paint);
}
mCanvas->restore(); mCanvas->restore();
} }

View file

@ -595,6 +595,8 @@ CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestin
// //
// //
int Bpp = BytesPerPixel(aSurface->GetFormat());
if (uploadRect.Contains(rect)) { if (uploadRect.Contains(rect)) {
// Extend mode is irrelevant, the displayed rect is completely contained // Extend mode is irrelevant, the displayed rect is completely contained
// by the source bitmap. // by the source bitmap.
@ -631,7 +633,7 @@ CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestin
// A partial upload will suffice. // A partial upload will suffice.
aRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)), aRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)),
mapping.GetData() + int(uploadRect.x) * 4 + int(uploadRect.y) * mapping.GetStride(), mapping.GetData() + int(uploadRect.x) * Bpp + int(uploadRect.y) * mapping.GetStride(),
mapping.GetStride(), mapping.GetStride(),
D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())), D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())),
getter_AddRefs(bitmap)); getter_AddRefs(bitmap));
@ -641,8 +643,6 @@ CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestin
return bitmap.forget(); return bitmap.forget();
} else { } else {
int Bpp = BytesPerPixel(aSurface->GetFormat());
if (Bpp != 4) { if (Bpp != 4) {
// This shouldn't actually happen in practice! // This shouldn't actually happen in practice!
MOZ_ASSERT(false); MOZ_ASSERT(false);

View file

@ -20,7 +20,8 @@ using namespace mozilla;
using namespace mozilla::gfx; using namespace mozilla::gfx;
gfxAlphaBoxBlur::gfxAlphaBoxBlur() gfxAlphaBoxBlur::gfxAlphaBoxBlur()
: mData(nullptr) : mData(nullptr),
mAccelerated(false)
{ {
} }
@ -32,16 +33,18 @@ gfxAlphaBoxBlur::~gfxAlphaBoxBlur()
} }
already_AddRefed<gfxContext> already_AddRefed<gfxContext>
gfxAlphaBoxBlur::Init(const gfxRect& aRect, gfxAlphaBoxBlur::Init(gfxContext* aDestinationCtx,
const gfxRect& aRect,
const IntSize& aSpreadRadius, const IntSize& aSpreadRadius,
const IntSize& aBlurRadius, const IntSize& aBlurRadius,
const gfxRect* aDirtyRect, const gfxRect* aDirtyRect,
const gfxRect* aSkipRect) const gfxRect* aSkipRect)
{ {
DrawTarget* refDT = aDestinationCtx->GetDrawTarget();
Maybe<Rect> dirtyRect = aDirtyRect ? Some(ToRect(*aDirtyRect)) : Nothing(); Maybe<Rect> dirtyRect = aDirtyRect ? Some(ToRect(*aDirtyRect)) : Nothing();
Maybe<Rect> skipRect = aSkipRect ? Some(ToRect(*aSkipRect)) : Nothing(); Maybe<Rect> skipRect = aSkipRect ? Some(ToRect(*aSkipRect)) : Nothing();
RefPtr<DrawTarget> dt = RefPtr<DrawTarget> dt =
InitDrawTarget(ToRect(aRect), aSpreadRadius, aBlurRadius, InitDrawTarget(refDT, ToRect(aRect), aSpreadRadius, aBlurRadius,
dirtyRect.ptrOr(nullptr), skipRect.ptrOr(nullptr)); dirtyRect.ptrOr(nullptr), skipRect.ptrOr(nullptr));
if (!dt) { if (!dt) {
return nullptr; return nullptr;
@ -54,7 +57,8 @@ gfxAlphaBoxBlur::Init(const gfxRect& aRect,
} }
already_AddRefed<DrawTarget> already_AddRefed<DrawTarget>
gfxAlphaBoxBlur::InitDrawTarget(const Rect& aRect, gfxAlphaBoxBlur::InitDrawTarget(const DrawTarget* aReferenceDT,
const Rect& aRect,
const IntSize& aSpreadRadius, const IntSize& aSpreadRadius,
const IntSize& aBlurRadius, const IntSize& aBlurRadius,
const Rect* aDirtyRect, const Rect* aDirtyRect,
@ -66,90 +70,134 @@ gfxAlphaBoxBlur::InitDrawTarget(const Rect& aRect,
return nullptr; return nullptr;
} }
// Make an alpha-only surface to draw on. We will play with the data after BackendType backend = aReferenceDT->GetBackendType();
// everything is drawn to create a blur effect.
mData = static_cast<uint8_t*>(calloc(1, blurDataSize));
if (!mData) {
return nullptr;
}
RefPtr<DrawTarget> dt = // Check if the backend has an accelerated DrawSurfaceWithShadow.
gfxPlatform::CreateDrawTargetForData(mData, // Currently, only D2D1.1 supports this.
// Otherwise, DrawSurfaceWithShadow only supports square blurs without spread.
if (aBlurRadius.IsSquare() && aSpreadRadius.IsEmpty() &&
backend == BackendType::DIRECT2D1_1) {
mAccelerated = true;
mDrawTarget =
aReferenceDT->CreateShadowDrawTarget(mBlur.GetSize(),
SurfaceFormat::A8,
AlphaBoxBlur::CalculateBlurSigma(aBlurRadius.width));
} else {
// Make an alpha-only surface to draw on. We will play with the data after
// everything is drawn to create a blur effect.
mData = static_cast<uint8_t*>(calloc(1, blurDataSize));
if (!mData) {
return nullptr;
}
mDrawTarget =
Factory::DoesBackendSupportDataDrawtarget(backend) ?
Factory::CreateDrawTargetForData(backend,
mData,
mBlur.GetSize(), mBlur.GetSize(),
mBlur.GetStride(), mBlur.GetStride(),
SurfaceFormat::A8); SurfaceFormat::A8) :
if (!dt || !dt->IsValid()) { gfxPlatform::CreateDrawTargetForData(mData,
mBlur.GetSize(),
mBlur.GetStride(),
SurfaceFormat::A8);
}
if (!mDrawTarget || !mDrawTarget->IsValid()) {
return nullptr; return nullptr;
} }
dt->SetTransform(Matrix::Translation(-mBlur.GetRect().TopLeft())); mDrawTarget->SetTransform(Matrix::Translation(-mBlur.GetRect().TopLeft()));
return dt.forget(); return do_AddRef(mDrawTarget);
}
void
DrawBlur(gfxContext* aDestinationCtx,
SourceSurface* aBlur,
const IntPoint& aTopLeft,
const Rect* aDirtyRect)
{
DrawTarget *dest = aDestinationCtx->GetDrawTarget();
RefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern();
Pattern* pat = thebesPat->GetPattern(dest, nullptr);
Matrix oldTransform = dest->GetTransform();
Matrix newTransform = oldTransform;
newTransform.PreTranslate(aTopLeft.x, aTopLeft.y);
// Avoid a semi-expensive clip operation if we can, otherwise
// clip to the dirty rect
if (aDirtyRect) {
dest->PushClipRect(*aDirtyRect);
}
dest->SetTransform(newTransform);
dest->MaskSurface(*pat, aBlur, Point(0, 0));
dest->SetTransform(oldTransform);
if (aDirtyRect) {
dest->PopClip();
}
} }
already_AddRefed<SourceSurface> already_AddRefed<SourceSurface>
gfxAlphaBoxBlur::DoBlur(DrawTarget* aDT, IntPoint* aTopLeft) gfxAlphaBoxBlur::DoBlur(const Color* aShadowColor, IntPoint* aOutTopLeft)
{ {
if (mData) {
mBlur.Blur(mData); mBlur.Blur(mData);
}
*aTopLeft = mBlur.GetRect().TopLeft(); if (aOutTopLeft) {
*aOutTopLeft = mBlur.GetRect().TopLeft();
}
return aDT->CreateSourceSurfaceFromData(mData, RefPtr<SourceSurface> blurMask = mDrawTarget->Snapshot();
mBlur.GetSize(), if (mAccelerated) {
mBlur.GetStride(), RefPtr<DrawTarget> blurDT =
SurfaceFormat::A8); Factory::CreateDrawTarget(mDrawTarget->GetBackendType(),
blurMask->GetSize(),
SurfaceFormat::A8);
if (!blurDT) {
return nullptr;
}
blurDT->DrawSurfaceWithShadow(blurMask, Point(0, 0), Color(1, 1, 1), Point(0, 0),
AlphaBoxBlur::CalculateBlurSigma(mBlur.GetBlurRadius().width),
CompositionOp::OP_OVER);
blurMask = blurDT->Snapshot();
}
if (!aShadowColor) {
return blurMask.forget();
}
RefPtr<DrawTarget> shadowDT =
Factory::CreateDrawTarget(mDrawTarget->GetBackendType(),
blurMask->GetSize(),
SurfaceFormat::B8G8R8A8);
if (!shadowDT) {
return nullptr;
}
ColorPattern shadowColor(ToDeviceColor(*aShadowColor));
shadowDT->MaskSurface(shadowColor, blurMask, Point(0, 0));
return shadowDT->Snapshot();
} }
void void
gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx) gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx)
{ {
if (!mData) if (!mAccelerated && !mData) {
return; return;
}
DrawTarget *dest = aDestinationCtx->GetDrawTarget(); DrawTarget *dest = aDestinationCtx->GetDrawTarget();
if (!dest) { if (!dest) {
NS_WARNING("Blurring not supported for Thebes contexts!"); NS_WARNING("Blurring not supported for Thebes contexts!");
return; return;
} }
Rect* dirtyRect = mBlur.GetDirtyRect(); RefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern();
Pattern* pat = thebesPat->GetPattern(dest, nullptr);
if (!pat) {
NS_WARNING("Failed to get pattern for blur!");
return;
}
IntPoint topLeft; IntPoint topLeft;
RefPtr<SourceSurface> mask = DoBlur(dest, &topLeft); RefPtr<SourceSurface> mask = DoBlur(nullptr, &topLeft);
if (!mask) { if (!mask) {
NS_ERROR("Failed to create mask!"); NS_ERROR("Failed to create mask!");
return; return;
} }
DrawBlur(aDestinationCtx, mask, topLeft, dirtyRect); // Avoid a semi-expensive clip operation if we can, otherwise
// clip to the dirty rect
Rect* dirtyRect = mBlur.GetDirtyRect();
if (dirtyRect) {
dest->PushClipRect(*dirtyRect);
}
Matrix oldTransform = dest->GetTransform();
Matrix newTransform = oldTransform;
newTransform.PreTranslate(topLeft);
dest->SetTransform(newTransform);
dest->MaskSurface(*pat, mask, Point(0, 0));
dest->SetTransform(oldTransform);
if (dirtyRect) {
dest->PopClip();
}
} }
IntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd) IntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd)
@ -433,14 +481,15 @@ CacheBlur(DrawTarget* aDT,
} }
} }
// Blurs a small surface and creates the mask. // Blurs a small surface and creates the colored box shadow.
static already_AddRefed<SourceSurface> static already_AddRefed<SourceSurface>
CreateBlurMask(DrawTarget* aDestDrawTarget, CreateBoxShadow(DrawTarget* aDestDrawTarget,
const IntSize& aMinSize, const IntSize& aMinSize,
const RectCornerRadii* aCornerRadii, const RectCornerRadii* aCornerRadii,
const IntSize& aBlurRadius, const IntSize& aBlurRadius,
bool aMirrorCorners, const Color& aShadowColor,
IntMargin& aOutBlurMargin) bool aMirrorCorners,
IntMargin& aOutBlurMargin)
{ {
gfxAlphaBoxBlur blur; gfxAlphaBoxBlur blur;
Rect minRect(Point(0, 0), Size(aMinSize)); Rect minRect(Point(0, 0), Size(aMinSize));
@ -453,7 +502,7 @@ CreateBlurMask(DrawTarget* aDestDrawTarget,
} }
IntSize zeroSpread(0, 0); IntSize zeroSpread(0, 0);
RefPtr<DrawTarget> blurDT = RefPtr<DrawTarget> blurDT =
blur.InitDrawTarget(blurRect, zeroSpread, aBlurRadius); blur.InitDrawTarget(aDestDrawTarget, blurRect, zeroSpread, aBlurRadius);
if (!blurDT) { if (!blurDT) {
return nullptr; return nullptr;
} }
@ -469,7 +518,7 @@ CreateBlurMask(DrawTarget* aDestDrawTarget,
} }
IntPoint topLeft; IntPoint topLeft;
RefPtr<SourceSurface> result = blur.DoBlur(aDestDrawTarget, &topLeft); RefPtr<SourceSurface> result = blur.DoBlur(&aShadowColor, &topLeft);
if (!result) { if (!result) {
return nullptr; return nullptr;
} }
@ -482,22 +531,6 @@ CreateBlurMask(DrawTarget* aDestDrawTarget,
return result.forget(); return result.forget();
} }
static already_AddRefed<SourceSurface>
CreateBoxShadow(DrawTarget* aDestDT, SourceSurface* aBlurMask, const Color& aShadowColor)
{
IntSize blurredSize = aBlurMask->GetSize();
RefPtr<DrawTarget> boxShadowDT =
Factory::CreateDrawTarget(aDestDT->GetBackendType(), blurredSize, SurfaceFormat::B8G8R8A8);
if (!boxShadowDT) {
return nullptr;
}
ColorPattern shadowColor(ToDeviceColor(aShadowColor));
boxShadowDT->MaskSurface(shadowColor, aBlurMask, Point(0, 0));
return boxShadowDT->Snapshot();
}
static already_AddRefed<SourceSurface> static already_AddRefed<SourceSurface>
GetBlur(gfxContext* aDestinationCtx, GetBlur(gfxContext* aDestinationCtx,
const IntSize& aRectSize, const IntSize& aRectSize,
@ -533,21 +566,16 @@ GetBlur(gfxContext* aDestinationCtx,
aCornerRadii, aShadowColor, aCornerRadii, aShadowColor,
destDT->GetBackendType()); destDT->GetBackendType());
if (cached) { if (cached) {
// See CreateBlurMask() for these values // See CreateBoxShadow() for these values
aOutBlurMargin = cached->mBlurMargin; aOutBlurMargin = cached->mBlurMargin;
RefPtr<SourceSurface> blur = cached->mBlur; RefPtr<SourceSurface> blur = cached->mBlur;
return blur.forget(); return blur.forget();
} }
} }
RefPtr<SourceSurface> blurMask = RefPtr<SourceSurface> boxShadow =
CreateBlurMask(destDT, minSize, aCornerRadii, aBlurRadius, CreateBoxShadow(destDT, minSize, aCornerRadii, aBlurRadius,
aMirrorCorners, aOutBlurMargin); aShadowColor, aMirrorCorners, aOutBlurMargin);
if (!blurMask) {
return nullptr;
}
RefPtr<SourceSurface> boxShadow = CreateBoxShadow(destDT, blurMask, aShadowColor);
if (!boxShadow) { if (!boxShadow) {
return nullptr; return nullptr;
} }
@ -1065,7 +1093,7 @@ gfxAlphaBoxBlur::GetInsetBlur(const Rect& aOuterRect,
} }
IntSize zeroSpread(0, 0); IntSize zeroSpread(0, 0);
RefPtr<DrawTarget> minDrawTarget = RefPtr<DrawTarget> minDrawTarget =
InitDrawTarget(blurRect, zeroSpread, aBlurRadius); InitDrawTarget(aDestDrawTarget, blurRect, zeroSpread, aBlurRadius);
if (!minDrawTarget) { if (!minDrawTarget) {
return nullptr; return nullptr;
} }
@ -1089,15 +1117,8 @@ gfxAlphaBoxBlur::GetInsetBlur(const Rect& aOuterRect,
ColorPattern black(Color(0.f, 0.f, 0.f, 1.f)); ColorPattern black(Color(0.f, 0.f, 0.f, 1.f));
minDrawTarget->Fill(maskPath, black); minDrawTarget->Fill(maskPath, black);
// Create the A8 mask // Blur and fill in with the color we actually wanted
IntPoint topLeft; RefPtr<SourceSurface> minInsetBlur = DoBlur(&aShadowColor);
RefPtr<SourceSurface> minMask = DoBlur(minDrawTarget, &topLeft);
if (!minMask) {
return nullptr;
}
// Fill in with the color we actually wanted
RefPtr<SourceSurface> minInsetBlur = CreateBoxShadow(aDestDrawTarget, minMask, aShadowColor);
if (!minInsetBlur) { if (!minInsetBlur) {
return nullptr; return nullptr;
} }

View file

@ -56,6 +56,9 @@ public:
/** /**
* Constructs a box blur and initializes the temporary surface. * Constructs a box blur and initializes the temporary surface.
*
* @param aDestinationCtx The destination to blur to.
*
* @param aRect The coordinates of the surface to create in device units. * @param aRect The coordinates of the surface to create in device units.
* *
* @param aBlurRadius The blur radius in pixels. This is the radius of * @param aBlurRadius The blur radius in pixels. This is the radius of
@ -73,21 +76,27 @@ public:
* for speed reasons. It is safe to pass nullptr here. * for speed reasons. It is safe to pass nullptr here.
*/ */
already_AddRefed<gfxContext> already_AddRefed<gfxContext>
Init(const gfxRect& aRect, Init(gfxContext* aDestinationCtx,
const gfxRect& aRect,
const mozilla::gfx::IntSize& aSpreadRadius, const mozilla::gfx::IntSize& aSpreadRadius,
const mozilla::gfx::IntSize& aBlurRadius, const mozilla::gfx::IntSize& aBlurRadius,
const gfxRect* aDirtyRect, const gfxRect* aDirtyRect,
const gfxRect* aSkipRect); const gfxRect* aSkipRect);
already_AddRefed<DrawTarget> already_AddRefed<DrawTarget>
InitDrawTarget(const mozilla::gfx::Rect& aRect, InitDrawTarget(const mozilla::gfx::DrawTarget* aReferenceDT,
const mozilla::gfx::Rect& aRect,
const mozilla::gfx::IntSize& aSpreadRadius, const mozilla::gfx::IntSize& aSpreadRadius,
const mozilla::gfx::IntSize& aBlurRadius, const mozilla::gfx::IntSize& aBlurRadius,
const mozilla::gfx::Rect* aDirtyRect = nullptr, const mozilla::gfx::Rect* aDirtyRect = nullptr,
const mozilla::gfx::Rect* aSkipRect = nullptr); const mozilla::gfx::Rect* aSkipRect = nullptr);
/**
* Performs the blur and optionally colors the result if aShadowColor is not null.
*/
already_AddRefed<mozilla::gfx::SourceSurface> already_AddRefed<mozilla::gfx::SourceSurface>
DoBlur(DrawTarget* aDT, mozilla::gfx::IntPoint* aTopLeft); DoBlur(const mozilla::gfx::Color* aShadowColor = nullptr,
mozilla::gfx::IntPoint* aOutTopLeft = nullptr);
/** /**
* Does the actual blurring/spreading and mask applying. Users of this * Does the actual blurring/spreading and mask applying. Users of this
@ -170,6 +179,12 @@ protected:
DrawTarget* aDestDrawTarget, DrawTarget* aDestDrawTarget,
bool aMirrorCorners); bool aMirrorCorners);
/**
* The DrawTarget of the temporary alpha surface.
*/
RefPtr<DrawTarget> mDrawTarget;
/** /**
* The temporary alpha surface. * The temporary alpha surface.
*/ */
@ -179,6 +194,11 @@ protected:
* The object that actually does the blurring for us. * The object that actually does the blurring for us.
*/ */
mozilla::gfx::AlphaBoxBlur mBlur; mozilla::gfx::AlphaBoxBlur mBlur;
/**
* Indicates using DrawTarget-accelerated blurs.
*/
bool mAccelerated;
}; };
#endif /* GFX_BLUR_H */ #endif /* GFX_BLUR_H */

View file

@ -1309,7 +1309,12 @@ gfxPlatform::CreateSimilarSoftwareDrawTarget(DrawTarget* aDT,
if (Factory::DoesBackendSupportDataDrawtarget(aDT->GetBackendType())) { if (Factory::DoesBackendSupportDataDrawtarget(aDT->GetBackendType())) {
dt = aDT->CreateSimilarDrawTarget(aSize, aFormat); dt = aDT->CreateSimilarDrawTarget(aSize, aFormat);
} else { } else {
dt = Factory::CreateDrawTarget(BackendType::SKIA, aSize, aFormat); #ifdef USE_SKIA
BackendType backendType = BackendType::SKIA;
#else
BackendType backendType = BackendType::CAIRO;
#endif
dt = Factory::CreateDrawTarget(backendType, aSize, aFormat);
} }
return dt.forget(); return dt.forget();
@ -1322,7 +1327,11 @@ gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize,
NS_ASSERTION(backendType != BackendType::NONE, "No backend."); NS_ASSERTION(backendType != BackendType::NONE, "No backend.");
if (!Factory::DoesBackendSupportDataDrawtarget(backendType)) { if (!Factory::DoesBackendSupportDataDrawtarget(backendType)) {
#ifdef USE_SKIA
backendType = BackendType::SKIA;
#else
backendType = BackendType::CAIRO; backendType = BackendType::CAIRO;
#endif
} }
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(backendType, RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(backendType,

View file

@ -6029,10 +6029,10 @@ nsContextBoxBlur::Init(const nsRect& aRect, nscoord aSpreadRadius,
dirtyRect = transform.TransformBounds(dirtyRect); dirtyRect = transform.TransformBounds(dirtyRect);
if (aSkipRect) { if (aSkipRect) {
gfxRect skipRect = transform.TransformBounds(*aSkipRect); gfxRect skipRect = transform.TransformBounds(*aSkipRect);
mContext = mAlphaBoxBlur.Init(rect, spreadRadius, mContext = mAlphaBoxBlur.Init(aDestinationCtx, rect, spreadRadius,
blurRadius, &dirtyRect, &skipRect); blurRadius, &dirtyRect, &skipRect);
} else { } else {
mContext = mAlphaBoxBlur.Init(rect, spreadRadius, mContext = mAlphaBoxBlur.Init(aDestinationCtx, rect, spreadRadius,
blurRadius, &dirtyRect, nullptr); blurRadius, &dirtyRect, nullptr);
} }

View file

@ -18,19 +18,19 @@ fuzzy-if(skiaContent,1,50) HTTP(..) == boxshadow-dynamic.xul boxshadow-dynamic-r
random-if(d2d) == boxshadow-onecorner.html boxshadow-onecorner-ref.html random-if(d2d) == boxshadow-onecorner.html boxshadow-onecorner-ref.html
random-if(d2d) == boxshadow-twocorners.html boxshadow-twocorners-ref.html random-if(d2d) == boxshadow-twocorners.html boxshadow-twocorners-ref.html
random-if(d2d) == boxshadow-threecorners.html boxshadow-threecorners-ref.html random-if(d2d) == boxshadow-threecorners.html boxshadow-threecorners-ref.html
== boxshadow-skiprect.html boxshadow-skiprect-ref.html fuzzy(2,440) == boxshadow-skiprect.html boxshadow-skiprect-ref.html
== boxshadow-opacity.html boxshadow-opacity-ref.html == boxshadow-opacity.html boxshadow-opacity-ref.html
== boxshadow-color-rounding.html boxshadow-color-rounding-ref.html == boxshadow-color-rounding.html boxshadow-color-rounding-ref.html
== boxshadow-color-rounding-middle.html boxshadow-color-rounding-middle-ref.html == boxshadow-color-rounding-middle.html boxshadow-color-rounding-middle-ref.html
fuzzy-if(OSX==1010,1,24) fuzzy-if(d2d,16,568) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649 fuzzy-if(OSX==1010,1,24) fuzzy-if(d2d,16,908) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649
fuzzy-if(d2d,2,1080) == boxshadow-border-radius-int.html boxshadow-border-radius-int-ref.html fuzzy(3,500) fuzzy-if(d2d,2,1080) == boxshadow-border-radius-int.html boxshadow-border-radius-int-ref.html
== boxshadow-inset-neg-spread.html about:blank == boxshadow-inset-neg-spread.html about:blank
== boxshadow-inset-neg-spread2.html boxshadow-inset-neg-spread2-ref.html == boxshadow-inset-neg-spread2.html boxshadow-inset-neg-spread2-ref.html
fuzzy(26,3610) == boxshadow-rotated.html boxshadow-rotated-ref.html # Bug 1211264 fuzzy(26,3610) == boxshadow-rotated.html boxshadow-rotated-ref.html # Bug 1211264
== boxshadow-inset-large-border-radius.html boxshadow-inset-large-border-radius-ref.html == boxshadow-inset-large-border-radius.html boxshadow-inset-large-border-radius-ref.html
# fuzzy due to blur going inside, but as long as it's essentially black instead of a light gray its ok. # fuzzy due to blur going inside, but as long as it's essentially black instead of a light gray its ok.
fuzzy(12,9445) == boxshadow-inset-large-offset.html boxshadow-inset-large-offset-ref.html fuzzy(12,9445) fuzzy-if(d2d,13,10926) == boxshadow-inset-large-offset.html boxshadow-inset-large-offset-ref.html
== overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html
== overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html

View file

@ -1818,7 +1818,7 @@ HTTP(..) == 983985-2.html 983985-2-ref.html
== 985303-1a.html 985303-1-ref.html == 985303-1a.html 985303-1-ref.html
== 985303-1b.html 985303-1-ref.html == 985303-1b.html 985303-1-ref.html
== 987680-1.html 987680-1-ref.html == 987680-1.html 987680-1-ref.html
fuzzy-if(d2d,1,36) == 991046-1.html 991046-1-ref.html fuzzy-if(d2d,1,601) == 991046-1.html 991046-1-ref.html
pref(layout.css.overflow-clip-box.enabled,true) fuzzy-if(skiaContent,2,845) == 992447.html 992447-ref.html pref(layout.css.overflow-clip-box.enabled,true) fuzzy-if(skiaContent,2,845) == 992447.html 992447-ref.html
== 1003425-1.html 1003425-1-ref.html == 1003425-1.html 1003425-1-ref.html
== 1003425-2.html 1003425-2-ref.html == 1003425-2.html 1003425-2-ref.html

View file

@ -1,4 +1,4 @@
== outline-and-box-shadow.html outline-and-box-shadow-ref.html fuzzy(2,18) == outline-and-box-shadow.html outline-and-box-shadow-ref.html
== outline-and-3d-transform-1a.html outline-and-3d-transform-1-ref.html == outline-and-3d-transform-1a.html outline-and-3d-transform-1-ref.html
== outline-and-3d-transform-1b.html outline-and-3d-transform-1-ref.html == outline-and-3d-transform-1b.html outline-and-3d-transform-1-ref.html
fuzzy-if(gtkWidget,136,120) fuzzy-if(d2d,16,96) fuzzy-if(cocoaWidget,255,120) fuzzy-if(winWidget,255,216) == outline-and-3d-transform-2.html outline-and-3d-transform-2-ref.html fuzzy-if(gtkWidget,136,120) fuzzy-if(d2d,16,96) fuzzy-if(cocoaWidget,255,120) fuzzy-if(winWidget,255,216) == outline-and-3d-transform-2.html outline-and-3d-transform-2-ref.html