mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-26 13:58:49 +00:00
Issue #2364 - use DrawTarget::DrawSurfaceWithShadow to render box shadows on platforms that accelerate it.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -99,6 +99,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
|
||||
@@ -122,6 +132,7 @@ public:
|
||||
* constructor, above.
|
||||
*/
|
||||
static IntSize CalculateBlurRadius(const Point& aStandardDeviation);
|
||||
static Float CalculateBlurSigma(int32_t aBlurRadius);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
+17
-16
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
+3
-3
@@ -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);
|
||||
|
||||
+132
-111
@@ -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;
|
||||
}
|
||||
BackendType backend = aReferenceDT->GetBackendType();
|
||||
|
||||
RefPtr<DrawTarget> dt =
|
||||
gfxPlatform::CreateDrawTargetForData(mData,
|
||||
// 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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
mDrawTarget->SetTransform(Matrix::Translation(-mBlur.GetRect().TopLeft()));
|
||||
return do_AddRef(mDrawTarget);
|
||||
}
|
||||
|
||||
already_AddRefed<SourceSurface>
|
||||
gfxAlphaBoxBlur::DoBlur(DrawTarget* aDT, IntPoint* aTopLeft)
|
||||
gfxAlphaBoxBlur::DoBlur(const Color* aShadowColor, IntPoint* aOutTopLeft)
|
||||
{
|
||||
if (mData) {
|
||||
mBlur.Blur(mData);
|
||||
}
|
||||
|
||||
*aTopLeft = mBlur.GetRect().TopLeft();
|
||||
if (aOutTopLeft) {
|
||||
*aOutTopLeft = mBlur.GetRect().TopLeft();
|
||||
}
|
||||
|
||||
return aDT->CreateSourceSurfaceFromData(mData,
|
||||
mBlur.GetSize(),
|
||||
mBlur.GetStride(),
|
||||
SurfaceFormat::A8);
|
||||
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();
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
@@ -482,22 +531,6 @@ CreateBlurMask(DrawTarget* aDestDrawTarget,
|
||||
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>
|
||||
GetBlur(gfxContext* aDestinationCtx,
|
||||
const IntSize& aRectSize,
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+23
-3
@@ -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 */
|
||||
|
||||
@@ -1309,7 +1309,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();
|
||||
@@ -1322,7 +1327,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,
|
||||
|
||||
@@ -6029,10 +6029,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user