From 9d5423718d4076a3623da95ea8da652725a04a26 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Fri, 13 Jan 2012 09:48:29 -0500 Subject: [PATCH] Bug 717921. Only have one thebes surface. r=bas --- gfx/thebes/gfxPlatform.cpp | 29 +++++++++++++++++++--- gfx/thebes/gfxPlatform.h | 3 +++ gfx/thebes/gfxPlatformMac.cpp | 24 ++++++++++++------ gfx/thebes/gfxWindowsPlatform.cpp | 41 ++++++++++++++++++++----------- 4 files changed, 73 insertions(+), 24 deletions(-) diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index d01f26e4c1c6..63a33e6a1387 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -532,9 +532,26 @@ DataSourceSurfaceDestroy(void *dataSourceSurface) static_cast(dataSourceSurface)->Release(); } +void DestroyThebesSurface(void *data) +{ + gfxASurface *surface = static_cast(data); + surface->Release(); +} + +UserDataKey ThebesSurfaceKey; + +// The semantics of this function are sort of weird. We snapshot the first +// time and then return the snapshotted surface for the lifetime of the +// draw target already_AddRefed gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) { + void *surface = aTarget->GetUserData(&ThebesSurfaceKey); + if (surface) { + nsRefPtr surf = static_cast(surface); + return surf.forget(); + } + RefPtr source = aTarget->Snapshot(); RefPtr data = source->GetDataSurface(); @@ -545,12 +562,18 @@ gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) IntSize size = data->GetSize(); gfxASurface::gfxImageFormat format = gfxASurface::FormatFromContent(ContentForFormat(data->GetFormat())); - nsRefPtr image = + nsRefPtr surf = new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height), data->Stride(), format); - image->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy); - return image.forget(); + surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy); + + // add a reference to be held by the drawTarget + // careful, the reference graph is getting complicated here + surf->AddRef(); + aTarget->AddUserData(&ThebesSurfaceKey, surf.get(), DestroyThebesSurface); + + return surf.forget(); } RefPtr diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index adf3346c4277..d4cbfc879b6f 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -71,6 +71,9 @@ class gfxTextRun; class nsIURI; class nsIAtom; +extern mozilla::gfx::UserDataKey ThebesSurfaceKey; +void DestroyThebesSurface(void *data); + extern cairo_user_data_key_t kDrawTarget; // pref lang id's for font prefs diff --git a/gfx/thebes/gfxPlatformMac.cpp b/gfx/thebes/gfxPlatformMac.cpp index f2d1d98ecc9f..c897882967e8 100644 --- a/gfx/thebes/gfxPlatformMac.cpp +++ b/gfx/thebes/gfxPlatformMac.cpp @@ -303,16 +303,26 @@ already_AddRefed gfxPlatformMac::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) { if (aTarget->GetType() == BACKEND_COREGRAPHICS) { - CGContextRef cg = static_cast(aTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT)); + void *surface = aTarget->GetUserData(&ThebesSurfaceKey); + if (surface) { + nsRefPtr surf = static_cast(surface); + return surf.forget(); + } else { + CGContextRef cg = static_cast(aTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT)); - //XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize - IntSize intSize = aTarget->GetSize(); - gfxIntSize size(intSize.width, intSize.height); + //XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize + IntSize intSize = aTarget->GetSize(); + gfxIntSize size(intSize.width, intSize.height); - nsRefPtr surf = - new gfxQuartzSurface(cg, size); + nsRefPtr surf = + new gfxQuartzSurface(cg, size); - return surf.forget(); + // add a reference to be held by the drawTarget + surf->AddRef(); + aTarget->AddUserData(&ThebesSurfaceKey, surf.get(), DestroyThebesSurface); + + return surf.forget(); + } } return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 2b7ca62b7981..9ed6ae286c84 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -507,22 +507,35 @@ gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) { #ifdef XP_WIN if (aTarget->GetType() == BACKEND_DIRECT2D) { - RefPtr texture = - static_cast(aTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE)); + void *surface = aTarget->GetUserData(&ThebesSurfaceKey); + if (surface) { + nsRefPtr surf = static_cast(surface); + return surf.forget(); + } else { + RefPtr texture = + static_cast(aTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE)); - if (!texture) { - return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); + if (!texture) { + return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); + } + + aTarget->Flush(); + + nsRefPtr surf = + new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat())); + + // add a reference to be held by the drawTarget + surf->AddRef(); + aTarget->AddUserData(&ThebesSurfaceKey, surf.get(), DestroyThebesSurface); + /* "It might be worth it to clear cairo surfaces associated with a drawtarget. + The strong reference means for example for D2D that cairo's scratch surface + will be kept alive (well after a user being done) and consume extra VRAM. + We can deal with this in a follow-up though." */ + + // shouldn't this hold a reference? + surf->SetData(&kDrawTarget, aTarget, NULL); + return surf.forget(); } - - aTarget->Flush(); - - nsRefPtr surf = - new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat())); - - // shouldn't this hold a reference? - surf->SetData(&kDrawTarget, aTarget, NULL); - - return surf.forget(); } #endif