Bug 957366 - Skip the temporary surface during filter drawing for DrawTarget-backed gfxContexts. r=roc

This commit is contained in:
Markus Stange 2014-01-08 10:30:57 +01:00
parent 77136b7ef2
commit 0f89a17b16
3 changed files with 25 additions and 59 deletions

View File

@ -459,13 +459,15 @@ nsSVGFilterInstance::Render(gfxContext* aContext)
}
nsIntRect filterRect = mPostFilterDirtyRect.Intersect(mFilterSpaceBounds);
gfxMatrix ctm = GetFilterSpaceToDeviceSpaceTransform();
if (filterRect.IsEmpty()) {
if (filterRect.IsEmpty() || ctm.IsSingular()) {
return NS_OK;
}
Matrix oldDTMatrix;
nsRefPtr<gfxASurface> resultImage;
RefPtr<DrawTarget> resultImageDT;
RefPtr<DrawTarget> dt;
if (aContext->IsCairo()) {
resultImage =
gfxPlatform::GetPlatform()->CreateOffscreenSurface(filterRect.Size(),
@ -474,20 +476,24 @@ nsSVGFilterInstance::Render(gfxContext* aContext)
return NS_ERROR_OUT_OF_MEMORY;
// Create a Cairo DrawTarget around resultImage.
resultImageDT =
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(
resultImage, ToIntSize(filterRect.Size()));
dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(
resultImage, ToIntSize(filterRect.Size()));
} else {
resultImageDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
ToIntSize(filterRect.Size()), FORMAT_B8G8R8A8);
// When we have a DrawTarget-backed context, we can call DrawFilter
// directly on the target DrawTarget and don't need a temporary DT.
dt = aContext->GetDrawTarget();
oldDTMatrix = dt->GetTransform();
Matrix matrix = ToMatrix(ctm);
matrix.Translate(filterRect.x, filterRect.y);
dt->SetTransform(matrix * oldDTMatrix);
}
ComputeNeededBoxes();
rv = BuildSourceImage(resultImage, resultImageDT);
rv = BuildSourceImage(resultImage, dt);
if (NS_FAILED(rv))
return rv;
rv = BuildSourcePaints(resultImage, resultImageDT);
rv = BuildSourcePaints(resultImage, dt);
if (NS_FAILED(rv))
return rv;
@ -495,21 +501,23 @@ nsSVGFilterInstance::Render(gfxContext* aContext)
FilterDescription filter(mPrimitiveDescriptions, filterSpaceBounds);
FilterSupport::RenderFilterDescription(
resultImageDT, filter, ToRect(filterRect),
dt, filter, ToRect(filterRect),
mSourceGraphic.mSourceSurface, mSourceGraphic.mSurfaceRect,
mFillPaint.mSourceSurface, mFillPaint.mSurfaceRect,
mStrokePaint.mSourceSurface, mStrokePaint.mSurfaceRect,
mInputImages);
RefPtr<SourceSurface> resultImageSource;
if (!resultImage) {
resultImageSource = resultImageDT->Snapshot();
if (resultImage) {
aContext->Save();
aContext->Multiply(ctm);
aContext->Translate(filterRect.TopLeft());
aContext->SetSource(resultImage);
aContext->Paint();
aContext->Restore();
} else {
dt->SetTransform(oldDTMatrix);
}
gfxMatrix ctm = GetFilterSpaceToDeviceSpaceTransform();
nsSVGUtils::CompositeSurfaceMatrix(aContext, resultImage, resultImageSource,
filterRect.TopLeft(), ctm);
return NS_OK;
}

View File

@ -841,37 +841,6 @@ nsSVGUtils::GetClipRectForFrame(nsIFrame *aFrame,
return gfxRect(aX, aY, aWidth, aHeight);
}
void
nsSVGUtils::CompositeSurfaceMatrix(gfxContext *aContext,
gfxASurface *aSurface,
SourceSurface *aSourceSurface,
const gfxPoint &aSurfaceOffset,
const gfxMatrix &aCTM)
{
if (aCTM.IsSingular())
return;
if (aSurface) {
aContext->Save();
aContext->Multiply(aCTM);
aContext->Translate(aSurfaceOffset);
aContext->SetSource(aSurface);
aContext->Paint();
aContext->Restore();
} else {
DrawTarget *destDT = aContext->GetDrawTarget();
Matrix oldMat = destDT->GetTransform();
destDT->SetTransform(ToMatrix(aCTM) * oldMat);
IntSize size = aSourceSurface->GetSize();
Rect sourceRect(Point(0, 0), Size(size.width, size.height));
Rect drawRect = sourceRect + ToPoint(aSurfaceOffset);
destDT->DrawSurface(aSourceSurface, drawRect, sourceRect);
destDT->SetTransform(oldMat);
}
}
void
nsSVGUtils::SetClipRect(gfxContext *aContext,
const gfxMatrix &aCTM,

View File

@ -413,17 +413,6 @@ public:
GetClipRectForFrame(nsIFrame *aFrame,
float aX, float aY, float aWidth, float aHeight);
/**
* Composites a surface into a context with a given surface offset and an
* additional transform. Supports both Thebes and DrawTarget drawing.
* If aSurface is null, aSourceSurface will be used instead.
*/
static void CompositeSurfaceMatrix(gfxContext *aContext,
gfxASurface *aSurface,
mozilla::gfx::SourceSurface *aSourceSurface,
const gfxPoint &aSurfaceOffset,
const gfxMatrix &aCTM);
static void SetClipRect(gfxContext *aContext,
const gfxMatrix &aCTM,
const gfxRect &aRect);