diff options
author | Moonchild <moonchild@palemoon.org> | 2023-10-30 13:03:32 +0100 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2023-11-01 10:31:16 +0100 |
commit | 2fae5d3e6ba64821ce3ffeb74ac372d6496f5593 (patch) | |
tree | 64b617e87058a728414f8fbf0ec919984ade0511 /gfx | |
parent | 5fd365cb76597c272356810f36efba33d8b013fe (diff) | |
download | uxp-2fae5d3e6ba64821ce3ffeb74ac372d6496f5593.tar.gz |
Issue #2364 - use DrawTarget::DrawSurfaceWithShadow to render box
shadows on platforms that accelerate it.
Diffstat (limited to 'gfx')
-rw-r--r-- | gfx/2d/Blur.cpp | 6 | ||||
-rw-r--r-- | gfx/2d/Blur.h | 11 | ||||
-rw-r--r-- | gfx/2d/DrawTargetCairo.cpp | 33 | ||||
-rw-r--r-- | gfx/2d/DrawTargetD2D1.cpp | 20 | ||||
-rw-r--r-- | gfx/2d/DrawTargetSkia.cpp | 8 | ||||
-rw-r--r-- | gfx/2d/HelpersD2D.h | 6 | ||||
-rw-r--r-- | gfx/thebes/gfxBlur.cpp | 241 | ||||
-rw-r--r-- | gfx/thebes/gfxBlur.h | 26 | ||||
-rw-r--r-- | gfx/thebes/gfxPlatform.cpp | 11 |
9 files changed, 220 insertions, 142 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, |