summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gfx/2d/Blur.cpp6
-rw-r--r--gfx/2d/Blur.h11
-rw-r--r--gfx/2d/DrawTargetCairo.cpp33
-rw-r--r--gfx/2d/DrawTargetD2D1.cpp20
-rw-r--r--gfx/2d/DrawTargetSkia.cpp8
-rw-r--r--gfx/2d/HelpersD2D.h6
-rw-r--r--gfx/thebes/gfxBlur.cpp241
-rw-r--r--gfx/thebes/gfxBlur.h26
-rw-r--r--gfx/thebes/gfxPlatform.cpp11
-rw-r--r--layout/base/nsCSSRendering.cpp4
-rw-r--r--layout/reftests/box-shadow/reftest.list8
-rw-r--r--layout/reftests/bugs/reftest.list2
-rw-r--r--layout/reftests/outline/reftest.list2
13 files changed, 228 insertions, 150 deletions
diff --git a/gfx/2d/Blur.cpp b/gfx/2d/Blur.cpp
index 143a39e9ad..d838e182f0 100644
--- a/gfx/2d/Blur.cpp
+++ b/gfx/2d/Blur.cpp
@@ -776,5 +776,11 @@ AlphaBoxBlur::CalculateBlurRadius(const Point& aStd)
return size;
}
+Float
+AlphaBoxBlur::CalculateBlurSigma(int32_t aBlurRadius)
+{
+ return aBlurRadius / GAUSSIAN_SCALE_FACTOR;
+}
+
} // namespace gfx
} // namespace mozilla
diff --git a/gfx/2d/Blur.h b/gfx/2d/Blur.h
index d4a9af3e36..0777e1ef1c 100644
--- a/gfx/2d/Blur.h
+++ b/gfx/2d/Blur.h
@@ -100,6 +100,16 @@ public:
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
* zero, the class is not properly setup for blurring. Note that this
* includes the extra three bytes on top of the stride*width, where something
@@ -122,6 +132,7 @@ public:
* constructor, above.
*/
static IntSize CalculateBlurRadius(const Point& aStandardDeviation);
+ static Float CalculateBlurSigma(int32_t aBlurRadius);
private:
diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp
index c0e4f0af26..ad22a9a456 100644
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -931,16 +931,18 @@ DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface,
if (cairo_surface_get_type(sourcesurf) == CAIRO_SURFACE_TYPE_TEE) {
blursurf = cairo_tee_surface_index(sourcesurf, 0);
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);
Rect extents(0, 0, width, height);
AlphaBoxBlur blur(extents,
cairo_image_surface_get_stride(blursurf),
aSigma, aSigma);
blur.Blur(cairo_image_surface_get_data(blursurf));
- } else {
- blursurf = sourcesurf;
- surf = sourcesurf;
}
WillChange();
@@ -951,25 +953,24 @@ DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface,
cairo_identity_matrix(mContext);
cairo_translate(mContext, aDest.x, aDest.y);
- if (IsOperatorBoundByMask(aOperator)){
- cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a);
- cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y);
+ bool needsGroup = !IsOperatorBoundByMask(aOperator);
+ if (needsGroup) {
+ 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.
cairo_set_source_surface(mContext, surf, 0, 0);
cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, width, height);
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.
- cairo_set_source_surface(mContext, surf, 0, 0);
- cairo_new_path(mContext);
- cairo_rectangle(mContext, 0, 0, width, height);
- cairo_fill(mContext);
+ if (needsGroup) {
cairo_pop_group_to_source(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
// operations in graphics memory.
- if (aSigma == 0.0F) {
+ if (aSigma == 0.0f || aFormat == SurfaceFormat::A8) {
RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
if (target->InitAlreadyReferenced(similar, aSize)) {
return target.forget();
diff --git a/gfx/2d/DrawTargetD2D1.cpp b/gfx/2d/DrawTargetD2D1.cpp
index a2e8541078..1e1f49ba47 100644
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -244,21 +244,29 @@ DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface *aSurface,
// Step 1, create the shadow effect.
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) {
gfxWarning() << "Failed to create shadow effect. Code: " << hexa(hr);
return;
}
shadowEffect->SetInput(0, image);
- 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);
+ if (mFormat == SurfaceFormat::A8) {
+ shadowEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, aSigma);
+ 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);
mDC->DrawImage(shadowEffect, &shadowPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator));
- D2D1_POINT_2F imgPoint = D2DPoint(aDest);
- mDC->DrawImage(image, &imgPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator));
+ if (aSurface->GetFormat() != SurfaceFormat::A8) {
+ D2D1_POINT_2F imgPoint = D2DPoint(aDest);
+ mDC->DrawImage(image, &imgPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator));
+ }
}
void
diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp
index 7e71e54ccf..130623658e 100644
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -713,9 +713,11 @@ DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface,
mCanvas->drawImage(image, shadowDest.x, shadowDest.y, &shadowPaint);
}
- // Composite the original image after the shadow
- auto dest = IntPoint::Round(aDest);
- mCanvas->drawImage(image, dest.x, dest.y, &paint);
+ if (aSurface->GetFormat() != SurfaceFormat::A8) {
+ // Composite the original image after the shadow
+ auto dest = IntPoint::Round(aDest);
+ mCanvas->drawImage(image, dest.x, dest.y, &paint);
+ }
mCanvas->restore();
}
diff --git a/gfx/2d/HelpersD2D.h b/gfx/2d/HelpersD2D.h
index 48aec2cb5e..455b158671 100644
--- a/gfx/2d/HelpersD2D.h
+++ b/gfx/2d/HelpersD2D.h
@@ -595,6 +595,8 @@ CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestin
//
//
+ int Bpp = BytesPerPixel(aSurface->GetFormat());
+
if (uploadRect.Contains(rect)) {
// Extend mode is irrelevant, the displayed rect is completely contained
// by the source bitmap.
@@ -631,7 +633,7 @@ CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestin
// A partial upload will suffice.
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(),
D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())),
getter_AddRefs(bitmap));
@@ -641,8 +643,6 @@ CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestin
return bitmap.forget();
} else {
- int Bpp = BytesPerPixel(aSurface->GetFormat());
-
if (Bpp != 4) {
// This shouldn't actually happen in practice!
MOZ_ASSERT(false);
diff --git a/gfx/thebes/gfxBlur.cpp b/gfx/thebes/gfxBlur.cpp
index 479a1b36d0..77003d3f9a 100644
--- a/gfx/thebes/gfxBlur.cpp
+++ b/gfx/thebes/gfxBlur.cpp
@@ -20,7 +20,8 @@ using namespace mozilla;
using namespace mozilla::gfx;
gfxAlphaBoxBlur::gfxAlphaBoxBlur()
- : mData(nullptr)
+ : mData(nullptr),
+ mAccelerated(false)
{
}
@@ -32,16 +33,18 @@ gfxAlphaBoxBlur::~gfxAlphaBoxBlur()
}
already_AddRefed<gfxContext>
-gfxAlphaBoxBlur::Init(const gfxRect& aRect,
+gfxAlphaBoxBlur::Init(gfxContext* aDestinationCtx,
+ const gfxRect& aRect,
const IntSize& aSpreadRadius,
const IntSize& aBlurRadius,
const gfxRect* aDirtyRect,
const gfxRect* aSkipRect)
{
+ DrawTarget* refDT = aDestinationCtx->GetDrawTarget();
Maybe<Rect> dirtyRect = aDirtyRect ? Some(ToRect(*aDirtyRect)) : Nothing();
Maybe<Rect> skipRect = aSkipRect ? Some(ToRect(*aSkipRect)) : Nothing();
RefPtr<DrawTarget> dt =
- InitDrawTarget(ToRect(aRect), aSpreadRadius, aBlurRadius,
+ InitDrawTarget(refDT, ToRect(aRect), aSpreadRadius, aBlurRadius,
dirtyRect.ptrOr(nullptr), skipRect.ptrOr(nullptr));
if (!dt) {
return nullptr;
@@ -54,7 +57,8 @@ gfxAlphaBoxBlur::Init(const gfxRect& aRect,
}
already_AddRefed<DrawTarget>
-gfxAlphaBoxBlur::InitDrawTarget(const Rect& aRect,
+gfxAlphaBoxBlur::InitDrawTarget(const DrawTarget* aReferenceDT,
+ const Rect& aRect,
const IntSize& aSpreadRadius,
const IntSize& aBlurRadius,
const Rect* aDirtyRect,
@@ -66,90 +70,134 @@ gfxAlphaBoxBlur::InitDrawTarget(const Rect& aRect,
return nullptr;
}
- // 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;
- }
-
- RefPtr<DrawTarget> dt =
- gfxPlatform::CreateDrawTargetForData(mData,
+ BackendType backend = aReferenceDT->GetBackendType();
+
+ // Check if the backend has an accelerated DrawSurfaceWithShadow.
+ // 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.GetStride(),
- SurfaceFormat::A8);
- if (!dt || !dt->IsValid()) {
+ SurfaceFormat::A8) :
+ gfxPlatform::CreateDrawTargetForData(mData,
+ mBlur.GetSize(),
+ mBlur.GetStride(),
+ SurfaceFormat::A8);
+ }
+
+ if (!mDrawTarget || !mDrawTarget->IsValid()) {
return nullptr;
}
- dt->SetTransform(Matrix::Translation(-mBlur.GetRect().TopLeft()));
- return dt.forget();
+ mDrawTarget->SetTransform(Matrix::Translation(-mBlur.GetRect().TopLeft()));
+ return do_AddRef(mDrawTarget);
}
-void
-DrawBlur(gfxContext* aDestinationCtx,
- SourceSurface* aBlur,
- const IntPoint& aTopLeft,
- const Rect* aDirtyRect)
+already_AddRefed<SourceSurface>
+gfxAlphaBoxBlur::DoBlur(const Color* aShadowColor, IntPoint* aOutTopLeft)
{
- 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);
- }
+ if (mData) {
+ mBlur.Blur(mData);
+ }
- dest->SetTransform(newTransform);
- dest->MaskSurface(*pat, aBlur, Point(0, 0));
- dest->SetTransform(oldTransform);
+ if (aOutTopLeft) {
+ *aOutTopLeft = mBlur.GetRect().TopLeft();
+ }
- if (aDirtyRect) {
- dest->PopClip();
+ RefPtr<SourceSurface> blurMask = mDrawTarget->Snapshot();
+ if (mAccelerated) {
+ RefPtr<DrawTarget> blurDT =
+ 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();
+ }
-already_AddRefed<SourceSurface>
-gfxAlphaBoxBlur::DoBlur(DrawTarget* aDT, IntPoint* aTopLeft)
-{
- mBlur.Blur(mData);
+ if (!aShadowColor) {
+ return blurMask.forget();
+ }
- *aTopLeft = mBlur.GetRect().TopLeft();
+ 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 aDT->CreateSourceSurfaceFromData(mData,
- mBlur.GetSize(),
- mBlur.GetStride(),
- SurfaceFormat::A8);
+ return shadowDT->Snapshot();
}
void
gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx)
{
- if (!mData)
- return;
+ if (!mAccelerated && !mData) {
+ return;
+ }
- DrawTarget *dest = aDestinationCtx->GetDrawTarget();
- if (!dest) {
- NS_WARNING("Blurring not supported for Thebes contexts!");
- return;
- }
+ DrawTarget *dest = aDestinationCtx->GetDrawTarget();
+ if (!dest) {
+ NS_WARNING("Blurring not supported for Thebes contexts!");
+ 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;
- RefPtr<SourceSurface> mask = DoBlur(dest, &topLeft);
- if (!mask) {
- NS_ERROR("Failed to create mask!");
- return;
- }
+ IntPoint topLeft;
+ RefPtr<SourceSurface> mask = DoBlur(nullptr, &topLeft);
+ if (!mask) {
+ NS_ERROR("Failed to create mask!");
+ 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)
@@ -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>
-CreateBlurMask(DrawTarget* aDestDrawTarget,
- const IntSize& aMinSize,
- const RectCornerRadii* aCornerRadii,
- const IntSize& aBlurRadius,
- bool aMirrorCorners,
- IntMargin& aOutBlurMargin)
+CreateBoxShadow(DrawTarget* aDestDrawTarget,
+ const IntSize& aMinSize,
+ const RectCornerRadii* aCornerRadii,
+ const IntSize& aBlurRadius,
+ const Color& aShadowColor,
+ bool aMirrorCorners,
+ IntMargin& aOutBlurMargin)
{
gfxAlphaBoxBlur blur;
Rect minRect(Point(0, 0), Size(aMinSize));
@@ -453,7 +502,7 @@ CreateBlurMask(DrawTarget* aDestDrawTarget,
}
IntSize zeroSpread(0, 0);
RefPtr<DrawTarget> blurDT =
- blur.InitDrawTarget(blurRect, zeroSpread, aBlurRadius);
+ blur.InitDrawTarget(aDestDrawTarget, blurRect, zeroSpread, aBlurRadius);
if (!blurDT) {
return nullptr;
}
@@ -469,7 +518,7 @@ CreateBlurMask(DrawTarget* aDestDrawTarget,
}
IntPoint topLeft;
- RefPtr<SourceSurface> result = blur.DoBlur(aDestDrawTarget, &topLeft);
+ RefPtr<SourceSurface> result = blur.DoBlur(&aShadowColor, &topLeft);
if (!result) {
return nullptr;
}
@@ -483,22 +532,6 @@ CreateBlurMask(DrawTarget* aDestDrawTarget,
}
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>
GetBlur(gfxContext* aDestinationCtx,
const IntSize& aRectSize,
const IntSize& aBlurRadius,
@@ -533,21 +566,16 @@ GetBlur(gfxContext* aDestinationCtx,
aCornerRadii, aShadowColor,
destDT->GetBackendType());
if (cached) {
- // See CreateBlurMask() for these values
+ // See CreateBoxShadow() for these values
aOutBlurMargin = cached->mBlurMargin;
RefPtr<SourceSurface> blur = cached->mBlur;
return blur.forget();
}
}
- RefPtr<SourceSurface> blurMask =
- CreateBlurMask(destDT, minSize, aCornerRadii, aBlurRadius,
- aMirrorCorners, aOutBlurMargin);
- if (!blurMask) {
- return nullptr;
- }
-
- RefPtr<SourceSurface> boxShadow = CreateBoxShadow(destDT, blurMask, aShadowColor);
+ RefPtr<SourceSurface> boxShadow =
+ CreateBoxShadow(destDT, minSize, aCornerRadii, aBlurRadius,
+ aShadowColor, aMirrorCorners, aOutBlurMargin);
if (!boxShadow) {
return nullptr;
}
@@ -1065,7 +1093,7 @@ gfxAlphaBoxBlur::GetInsetBlur(const Rect& aOuterRect,
}
IntSize zeroSpread(0, 0);
RefPtr<DrawTarget> minDrawTarget =
- InitDrawTarget(blurRect, zeroSpread, aBlurRadius);
+ InitDrawTarget(aDestDrawTarget, blurRect, zeroSpread, aBlurRadius);
if (!minDrawTarget) {
return nullptr;
}
@@ -1089,15 +1117,8 @@ gfxAlphaBoxBlur::GetInsetBlur(const Rect& aOuterRect,
ColorPattern black(Color(0.f, 0.f, 0.f, 1.f));
minDrawTarget->Fill(maskPath, black);
- // Create the A8 mask
- IntPoint topLeft;
- 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);
+ // Blur and fill in with the color we actually wanted
+ RefPtr<SourceSurface> minInsetBlur = DoBlur(&aShadowColor);
if (!minInsetBlur) {
return nullptr;
}
diff --git a/gfx/thebes/gfxBlur.h b/gfx/thebes/gfxBlur.h
index ff0a051364..9ff5d14a34 100644
--- a/gfx/thebes/gfxBlur.h
+++ b/gfx/thebes/gfxBlur.h
@@ -56,6 +56,9 @@ public:
/**
* 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 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.
*/
already_AddRefed<gfxContext>
- Init(const gfxRect& aRect,
+ Init(gfxContext* aDestinationCtx,
+ const gfxRect& aRect,
const mozilla::gfx::IntSize& aSpreadRadius,
const mozilla::gfx::IntSize& aBlurRadius,
const gfxRect* aDirtyRect,
const gfxRect* aSkipRect);
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& aBlurRadius,
const mozilla::gfx::Rect* aDirtyRect = 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>
- 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
@@ -170,6 +179,12 @@ protected:
DrawTarget* aDestDrawTarget,
bool aMirrorCorners);
+
+ /**
+ * The DrawTarget of the temporary alpha surface.
+ */
+ RefPtr<DrawTarget> mDrawTarget;
+
/**
* The temporary alpha surface.
*/
@@ -179,6 +194,11 @@ protected:
* The object that actually does the blurring for us.
*/
mozilla::gfx::AlphaBoxBlur mBlur;
+
+ /**
+ * Indicates using DrawTarget-accelerated blurs.
+ */
+ bool mAccelerated;
};
#endif /* GFX_BLUR_H */
diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp
index 848f810094..9a29c2a1e3 100644
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1304,7 +1304,12 @@ gfxPlatform::CreateSimilarSoftwareDrawTarget(DrawTarget* aDT,
if (Factory::DoesBackendSupportDataDrawtarget(aDT->GetBackendType())) {
dt = aDT->CreateSimilarDrawTarget(aSize, aFormat);
} 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();
@@ -1317,7 +1322,11 @@ gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize,
NS_ASSERTION(backendType != BackendType::NONE, "No backend.");
if (!Factory::DoesBackendSupportDataDrawtarget(backendType)) {
+#ifdef USE_SKIA
+ backendType = BackendType::SKIA;
+#else
backendType = BackendType::CAIRO;
+#endif
}
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(backendType,
diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp
index d430230894..3084cf9085 100644
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -6023,10 +6023,10 @@ nsContextBoxBlur::Init(const nsRect& aRect, nscoord aSpreadRadius,
dirtyRect = transform.TransformBounds(dirtyRect);
if (aSkipRect) {
gfxRect skipRect = transform.TransformBounds(*aSkipRect);
- mContext = mAlphaBoxBlur.Init(rect, spreadRadius,
+ mContext = mAlphaBoxBlur.Init(aDestinationCtx, rect, spreadRadius,
blurRadius, &dirtyRect, &skipRect);
} else {
- mContext = mAlphaBoxBlur.Init(rect, spreadRadius,
+ mContext = mAlphaBoxBlur.Init(aDestinationCtx, rect, spreadRadius,
blurRadius, &dirtyRect, nullptr);
}
diff --git a/layout/reftests/box-shadow/reftest.list b/layout/reftests/box-shadow/reftest.list
index 8f62299432..0c3bb1d38a 100644
--- a/layout/reftests/box-shadow/reftest.list
+++ b/layout/reftests/box-shadow/reftest.list
@@ -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-twocorners.html boxshadow-twocorners-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-color-rounding.html boxshadow-color-rounding-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(d2d,2,1080) == boxshadow-border-radius-int.html boxshadow-border-radius-int-ref.html
+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(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-spread2.html boxshadow-inset-neg-spread2-ref.html
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
# 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-ref2.html
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list
index e6cc895d94..3591f38c0c 100644
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1818,7 +1818,7 @@ HTTP(..) == 983985-2.html 983985-2-ref.html
== 985303-1a.html 985303-1-ref.html
== 985303-1b.html 985303-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
== 1003425-1.html 1003425-1-ref.html
== 1003425-2.html 1003425-2-ref.html
diff --git a/layout/reftests/outline/reftest.list b/layout/reftests/outline/reftest.list
index a729d892e9..df7e11564a 100644
--- a/layout/reftests/outline/reftest.list
+++ b/layout/reftests/outline/reftest.list
@@ -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-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