Bug 564991. Part 34: Make sure that ThebesLayerBuffers are always allocated as similar surfaces to the widget surface, whenever possible. r=cjones

This commit is contained in:
Robert O'Callahan 2010-07-16 09:08:10 +12:00
parent cc0c10fa76
commit e98a518e3c
11 changed files with 111 additions and 53 deletions

View File

@ -209,6 +209,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "nsHTMLMediaElement.h"
using namespace mozilla::dom;
using namespace mozilla::layers;
const char kLoadAsData[] = "loadAsData";
@ -6128,7 +6129,7 @@ nsContentUtils::PlatformToDOMLineBreaks(nsString &aString)
}
}
already_AddRefed<mozilla::layers::LayerManager>
already_AddRefed<LayerManager>
nsContentUtils::LayerManagerForDocument(nsIDocument *aDoc)
{
nsIDocument* doc = aDoc;
@ -6163,14 +6164,13 @@ nsContentUtils::LayerManagerForDocument(nsIDocument *aDoc)
nsIWidget* widget =
nsLayoutUtils::GetDisplayRootFrame(rootFrame)->GetNearestWidget();
if (widget) {
nsRefPtr<mozilla::layers::LayerManager> manager = widget->GetLayerManager();
nsRefPtr<LayerManager> manager = widget->GetLayerManager();
return manager.forget();
}
}
}
nsRefPtr<mozilla::layers::LayerManager> manager =
new mozilla::layers::BasicLayerManager(nsnull);
nsRefPtr<LayerManager> manager = new BasicLayerManager();
return manager.forget();
}

View File

@ -47,6 +47,7 @@
#include "gfxPlatform.h"
#include "gfxUtils.h"
#include "ThebesLayerBuffer.h"
#include "nsIWidget.h"
#include "GLContext.h"
@ -323,8 +324,22 @@ BasicThebesLayer::Paint(gfxContext* aContext,
}
{
nsRefPtr<gfxASurface> referenceSurface = mBuffer.GetBuffer();
if (!referenceSurface) {
gfxContext* defaultTarget = BasicManager()->GetDefaultTarget();
if (defaultTarget) {
referenceSurface = defaultTarget->CurrentSurface();
} else {
nsIWidget* widget = BasicManager()->GetRetainerWidget();
if (widget) {
referenceSurface = widget->GetThebesSurface();
} else {
referenceSurface = aContext->CurrentSurface();
}
}
}
ThebesLayerBuffer::PaintState state =
mBuffer.BeginPaint(this, aContext, flags);
mBuffer.BeginPaint(this, referenceSurface, flags);
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
if (state.mContext) {
@ -697,13 +712,23 @@ MayHaveOverlappingOrTransparentLayers(Layer* aLayer,
return PR_FALSE;
}
BasicLayerManager::BasicLayerManager(gfxContext* aContext) :
mDefaultTarget(aContext)
BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) :
mWidget(aWidget)
#ifdef DEBUG
, mPhase(PHASE_NONE)
#endif
, mDoubleBuffering(BUFFER_NONE), mUsingDefaultTarget(PR_FALSE),
mRetain(PR_FALSE)
, mDoubleBuffering(BUFFER_NONE), mUsingDefaultTarget(PR_FALSE)
{
MOZ_COUNT_CTOR(BasicLayerManager);
NS_ASSERTION(aWidget, "Must provide a widget");
}
BasicLayerManager::BasicLayerManager() :
mWidget(nsnull)
#ifdef DEBUG
, mPhase(PHASE_NONE)
#endif
, mDoubleBuffering(BUFFER_NONE), mUsingDefaultTarget(PR_FALSE)
{
MOZ_COUNT_CTOR(BasicLayerManager);
}
@ -724,14 +749,6 @@ BasicLayerManager::SetDefaultTarget(gfxContext* aContext,
mDoubleBuffering = aDoubleBuffering;
}
void
BasicLayerManager::SetRetain(PRBool aRetain)
{
NS_ASSERTION(!InTransaction(),
"Must set retained mode outside transaction");
mRetain = aRetain;
}
void
BasicLayerManager::BeginTransaction()
{

View File

@ -45,11 +45,11 @@
#include "nsAutoRef.h"
#include "nsThreadUtils.h"
class nsIWidget;
namespace mozilla {
namespace layers {
class BasicThebesLayer;
/**
* This is a cairo/Thebes-only, main-thread-only implementation of layers.
*
@ -61,19 +61,29 @@ class BasicThebesLayer;
class THEBES_API BasicLayerManager : public LayerManager {
public:
/**
* Construct a BasicLayerManager which will render to aContext when
* BeginTransaction is called. This can be null, in which case
* transactions started with BeginTransaction will not do any painting.
* Construct a BasicLayerManager which will have no default
* target context. SetDefaultTarget or BeginTransactionWithTarget
* must be called for any rendering to happen. ThebesLayers will not
* be retained.
*/
BasicLayerManager(gfxContext* aContext);
virtual ~BasicLayerManager();
BasicLayerManager();
/**
* When aRetain is true, we will try to retain the visible contents of
* ThebesLayers as cairo surfaces. This can only be called outside a
* transaction. By default, layer contents are not retained.
* Construct a BasicLayerManager which will have no default
* target context. SetDefaultTarget or BeginTransactionWithTarget
* must be called for any rendering to happen. ThebesLayers will be
* retained; that is, we will try to retain the visible contents of
* ThebesLayers as cairo surfaces. We create ThebesLayer buffers by
* creating similar surfaces to the default target context, or to
* aWidget's GetThebesSurface if there is no default target context, or
* to the passed-in context if there is no widget and no default
* target context.
*
* This does not keep a strong reference to the widget, so the caller
* must ensure that the widget outlives the layer manager or call
* ClearWidget before the widget dies.
*/
void SetRetain(PRBool aRetain);
BasicLayerManager(nsIWidget* aWidget);
virtual ~BasicLayerManager();
/**
* Set the default target context that will be used when BeginTransaction
@ -91,6 +101,10 @@ public:
BUFFER_BUFFERED
};
void SetDefaultTarget(gfxContext* aContext, BufferMode aDoubleBuffering);
gfxContext* GetDefaultTarget() { return mDefaultTarget; }
nsIWidget* GetRetainerWidget() { return mWidget; }
void ClearRetainerWidget() { mWidget = nsnull; }
virtual void BeginTransaction();
virtual void BeginTransactionWithTarget(gfxContext* aTarget);
@ -113,7 +127,7 @@ public:
PRBool InTransaction() { return mPhase != PHASE_NONE; }
#endif
gfxContext* GetTarget() { return mTarget; }
PRBool IsRetained() { return mRetain; }
PRBool IsRetained() { return mWidget != nsnull; }
private:
// Paints aLayer to mTarget.
@ -128,6 +142,9 @@ private:
void PopGroupWithCachedSurface(gfxContext *aTarget,
const gfxPoint& aSavedOffset);
// Widget whose surface should be used as the basis for ThebesLayer
// buffers.
nsIWidget* mWidget;
// The default context for BeginTransaction.
nsRefPtr<gfxContext> mDefaultTarget;
// The context to draw into.
@ -143,7 +160,6 @@ private:
BufferMode mDoubleBuffering;
PRPackedBool mUsingDefaultTarget;
PRPackedBool mRetain;
};
}

View File

@ -132,14 +132,14 @@ CreateBuffer(gfxASurface* aTargetSurface, gfxASurface::gfxContentType aType,
}
ThebesLayerBuffer::PaintState
ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, gfxContext* aTarget,
ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer,
gfxASurface* aReferenceSurface,
PRUint32 aFlags)
{
PaintState result;
gfxASurface::gfxContentType desiredContentType = gfxASurface::CONTENT_COLOR_ALPHA;
nsRefPtr<gfxASurface> targetSurface = aTarget->CurrentSurface();
if (targetSurface->AreSimilarSurfacesSensitiveToContentType()) {
if (aReferenceSurface->AreSimilarSurfacesSensitiveToContentType()) {
if (aFlags & OPAQUE_CONTENT) {
desiredContentType = gfxASurface::CONTENT_COLOR;
}
@ -192,7 +192,8 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, gfxContext* aTarget,
// We can't do a real self-copy because the buffer is rotated.
// So allocate a new buffer for the destination.
destBufferRect = visibleBounds;
destBuffer = CreateBuffer(targetSurface, desiredContentType, destBufferRect.Size());
destBuffer = CreateBuffer(aReferenceSurface, desiredContentType,
destBufferRect.Size());
if (!destBuffer)
return result;
}
@ -210,7 +211,8 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, gfxContext* aTarget,
} else {
// The buffer's not big enough, so allocate a new one
destBufferRect = visibleBounds;
destBuffer = CreateBuffer(targetSurface, desiredContentType, destBufferRect.Size());
destBuffer = CreateBuffer(aReferenceSurface, desiredContentType,
destBufferRect.Size());
if (!destBuffer)
return result;
}

View File

@ -107,14 +107,16 @@ public:
OPAQUE_CONTENT = 0x01
};
/**
* Start a drawing operation. Ths returns a PaintState describing what
* Start a drawing operation. This returns a PaintState describing what
* needs to be drawn to bring the buffer up to date in the visible region.
* This queries aLayer to get the currently valid and visible regions.
* The returned mContext may be null if mRegionToDraw is empty.
* Otherwise it must not be null.
* mRegionToInvalidate will contain mRegionToDraw.
* @param aReferenceSurface if we need to create a buffer, we'll create
* a surface that's similar to aReferenceSurface
*/
PaintState BeginPaint(ThebesLayer* aLayer, gfxContext* aTarget,
PaintState BeginPaint(ThebesLayer* aLayer, gfxASurface* aReferenceSurface,
PRUint32 aFlags);
/**
* Complete the drawing operation. The region to draw must have been drawn
@ -122,6 +124,13 @@ public:
*/
void DrawTo(ThebesLayer* aLayer, PRUint32 aFlags, gfxContext* aTarget, float aOpacity);
/**
* Get the underlying buffer, if any. This is useful because we can pass
* in the buffer as the default "reference surface" if there is one.
* Don't use it for anything else!
*/
gfxASurface* GetBuffer() { return mBuffer; }
protected:
enum XSide {
LEFT, RIGHT

View File

@ -44,11 +44,11 @@
#include "nsString.h"
gfxWindowsSurface::gfxWindowsSurface(HWND wnd) :
gfxWindowsSurface::gfxWindowsSurface(HWND wnd, PRUint32 flags) :
mOwnsDC(PR_TRUE), mForPrinting(PR_FALSE), mWnd(wnd)
{
mDC = ::GetDC(mWnd);
Init(cairo_win32_surface_create(mDC));
InitWithDC(flags);
}
gfxWindowsSurface::gfxWindowsSurface(HDC dc, PRUint32 flags) :
@ -63,11 +63,7 @@ gfxWindowsSurface::gfxWindowsSurface(HDC dc, PRUint32 flags) :
mForPrinting = PR_TRUE;
} else
#endif
if (flags & FLAG_IS_TRANSPARENT) {
Init(cairo_win32_surface_create_with_alpha(mDC));
} else {
Init(cairo_win32_surface_create(mDC));
}
InitWithDC(flags);
}
gfxWindowsSurface::gfxWindowsSurface(const gfxIntSize& size, gfxImageFormat imageFormat) :
@ -110,7 +106,6 @@ gfxWindowsSurface::gfxWindowsSurface(HDC dc, const gfxIntSize& size, gfxImageFor
mDC = nsnull;
}
gfxWindowsSurface::gfxWindowsSurface(cairo_surface_t *csurf) :
mOwnsDC(PR_FALSE), mForPrinting(PR_FALSE), mWnd(nsnull)
{
@ -125,6 +120,16 @@ gfxWindowsSurface::gfxWindowsSurface(cairo_surface_t *csurf) :
Init(csurf, PR_TRUE);
}
void
gfxWindowsSurface::InitWithDC(PRUint32 flags)
{
if (flags & FLAG_IS_TRANSPARENT) {
Init(cairo_win32_surface_create_with_alpha(mDC));
} else {
Init(cairo_win32_surface_create(mDC));
}
}
gfxWindowsSurface::~gfxWindowsSurface()
{
if (mOwnsDC) {

View File

@ -53,7 +53,7 @@ public:
FLAG_IS_TRANSPARENT = (1 << 2),
};
gfxWindowsSurface(HWND wnd);
gfxWindowsSurface(HWND wnd, PRUint32 flags = 0);
gfxWindowsSurface(HDC dc, PRUint32 flags = 0);
// Create a DIB surface
@ -67,6 +67,8 @@ public:
gfxWindowsSurface(cairo_surface_t *csurf);
void InitWithDC(PRUint32 flags);
virtual ~gfxWindowsSurface();
HDC GetDC() { return mDC; }

View File

@ -968,7 +968,7 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
// manager now so that if we need to modify the retained layer
// tree during this process, those modifications will happen
// during the construction phase for the retained layer tree.
tempManager = new BasicLayerManager(nsnull);
tempManager = new BasicLayerManager();
tempManager->BeginTransaction();
nsRefPtr<Layer> layer = aItem->BuildLayer(aBuilder, tempManager);
if (!layer) {

View File

@ -371,7 +371,7 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
NS_WARNING("Nowhere to paint into");
return;
}
layerManager = new BasicLayerManager(nsnull);
layerManager = new BasicLayerManager();
if (!layerManager)
return;
}

View File

@ -3260,7 +3260,11 @@ gfxASurface *nsWindow::GetThebesSurface()
return (new gfxD2DSurface(mWnd, content));
} else {
#endif
return (new gfxWindowsSurface(mWnd));
PRUint32 flags = gfxWindowsSurface::FLAG_TAKE_DC;
if (mTransparencyMode != eTransparencyOpaque) {
flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT;
}
return (new gfxWindowsSurface(mWnd, flags));
#ifdef CAIRO_HAS_D2D_SURFACE
}
#endif

View File

@ -129,6 +129,11 @@ nsBaseWidget::nsBaseWidget()
//-------------------------------------------------------------------------
nsBaseWidget::~nsBaseWidget()
{
if (mLayerManager &&
mLayerManager->GetBackendType() == LayerManager::LAYERS_BASIC) {
static_cast<BasicLayerManager*>(mLayerManager.get())->ClearRetainerWidget();
}
#ifdef NOISY_WIDGET_LEAKS
gNumWidgets--;
printf("WIDGETS- = %d\n", gNumWidgets);
@ -727,9 +732,7 @@ LayerManager* nsBaseWidget::GetLayerManager()
}
}
if (!mLayerManager) {
nsRefPtr<BasicLayerManager> basicManager = new BasicLayerManager(nsnull);
basicManager->SetRetain(PR_TRUE);
mLayerManager = basicManager.forget();
mLayerManager = new BasicLayerManager(this);
}
}
return mLayerManager;