diff --git a/gfx/layers/ThebesLayerBuffer.h b/gfx/layers/ThebesLayerBuffer.h index 0e65892e8f6a..936e1c3c2067 100644 --- a/gfx/layers/ThebesLayerBuffer.h +++ b/gfx/layers/ThebesLayerBuffer.h @@ -156,6 +156,17 @@ protected: const nsIntRect& BufferRect() const { return mBufferRect; } const nsIntPoint& BufferRotation() const { return mBufferRotation; } + already_AddRefed + SetBuffer(gfxASurface* aBuffer, + const nsIntRect& aBufferRect, const nsIntPoint& aBufferRotation) + { + gfxASurface* tmp = mBuffer; + mBuffer = aBuffer; + mBufferRect = aBufferRect; + mBufferRotation = aBufferRotation; + return tmp; + } + private: PRBool BufferSizeOkFor(const nsIntSize& aSize) { diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index 3acf7a69fbf2..eb9e519f2df8 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -227,8 +227,41 @@ BasicContainerLayer::RemoveChildInternal(Layer* aChild) NS_RELEASE(aChild); } +class BasicThebesLayer; +class BasicThebesLayerBuffer : public ThebesLayerBuffer { + typedef ThebesLayerBuffer Base; + +public: + BasicThebesLayerBuffer(BasicThebesLayer* aLayer) + : Base(ContainsVisibleBounds) + , mLayer(aLayer) + {} + + virtual ~BasicThebesLayerBuffer() + {} + + using Base::BufferRect; + using Base::BufferRotation; + + /** + * Complete the drawing operation. The region to draw must have been + * drawn before this is called. The contents of the buffer are drawn + * to aTarget. + */ + void DrawTo(ThebesLayer* aLayer, PRBool aIsOpaqueContent, + gfxContext* aTarget, float aOpacity); + + virtual already_AddRefed + CreateBuffer(ContentType aType, const nsIntSize& aSize); + +private: + BasicThebesLayer* mLayer; +}; + class BasicThebesLayer : public ThebesLayer, BasicImplData { public: + typedef BasicThebesLayerBuffer Buffer; + BasicThebesLayer(BasicLayerManager* aLayerManager) : ThebesLayer(aLayerManager, static_cast(this)), mBuffer(this) @@ -257,36 +290,6 @@ public: LayerManager::DrawThebesLayerCallback aCallback, void* aCallbackData, float aOpacity); - -protected: - BasicLayerManager* BasicManager() - { - return static_cast(mManager); - } - - class Buffer : public ThebesLayerBuffer { - public: - Buffer(BasicThebesLayer* aLayer) - : ThebesLayerBuffer(ContainsVisibleBounds) - , mLayer(aLayer) - {} - - /** - * Complete the drawing operation. The region to draw must have been - * drawn before this is called. The contents of the buffer are drawn - * to aTarget. - */ - void DrawTo(PRBool aIsOpaqueContent, gfxContext* aTarget, float aOpacity); - - virtual already_AddRefed - CreateBuffer(ContentType aType, const nsIntSize& aSize) - { - return mLayer->CreateBuffer(aType, aSize); - } - - private: - BasicThebesLayer* mLayer; - }; virtual already_AddRefed CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize) @@ -309,6 +312,24 @@ protected: aType, gfxIntSize(aSize.width, aSize.height)); } +protected: + BasicLayerManager* BasicManager() + { + return static_cast(mManager); + } + + virtual void + PaintBuffer(gfxContext* aContext, + const nsIntRegion& aRegionToDraw, + const nsIntRegion& aRegionToInvalidate, + LayerManager::DrawThebesLayerCallback aCallback, + void* aCallbackData) + { + aCallback(this, aContext, aRegionToDraw, aRegionToInvalidate, + aCallbackData); + mValidRegion.Or(mValidRegion, aRegionToDraw); + } + Buffer mBuffer; }; @@ -373,9 +394,9 @@ BasicThebesLayer::Paint(gfxContext* aContext, // from RGB to RGBA, because we might need to repaint with // subpixel AA) state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion); - aCallback(this, state.mContext, state.mRegionToDraw, - state.mRegionToInvalidate, aCallbackData); - mValidRegion.Or(mValidRegion, state.mRegionToDraw); + PaintBuffer(state.mContext, + state.mRegionToDraw, state.mRegionToInvalidate, + aCallback, aCallbackData); } else { // It's possible that state.mRegionToInvalidate is nonempty here, // if we are shrinking the valid region to nothing. @@ -384,16 +405,17 @@ BasicThebesLayer::Paint(gfxContext* aContext, } } - mBuffer.DrawTo(isOpaqueContent, target, aOpacity); + mBuffer.DrawTo(this, isOpaqueContent, target, aOpacity); } void -BasicThebesLayer::Buffer::DrawTo(PRBool aIsOpaqueContent, - gfxContext* aTarget, - float aOpacity) +BasicThebesLayerBuffer::DrawTo(ThebesLayer* aLayer, + PRBool aIsOpaqueContent, + gfxContext* aTarget, + float aOpacity) { aTarget->Save(); - ClipToRegion(aTarget, mLayer->GetVisibleRegion()); + ClipToRegion(aTarget, aLayer->GetVisibleRegion()); if (aIsOpaqueContent) { aTarget->SetOperator(gfxContext::OPERATOR_SOURCE); } @@ -401,6 +423,13 @@ BasicThebesLayer::Buffer::DrawTo(PRBool aIsOpaqueContent, aTarget->Restore(); } +already_AddRefed +BasicThebesLayerBuffer::CreateBuffer(ContentType aType, + const nsIntSize& aSize) +{ + return mLayer->CreateBuffer(aType, aSize); +} + class BasicImageLayer : public ImageLayer, BasicImplData { public: BasicImageLayer(BasicLayerManager* aLayerManager) : @@ -1178,6 +1207,8 @@ BasicShadowableContainerLayer::RemoveChild(Layer* aChild) class BasicShadowableThebesLayer : public BasicThebesLayer, public BasicShadowableLayer { + typedef BasicThebesLayer Base; + public: BasicShadowableThebesLayer(BasicShadowLayerManager* aManager) : BasicThebesLayer(aManager) @@ -1186,6 +1217,8 @@ public: } virtual ~BasicShadowableThebesLayer() { + if (mBackBuffer) + BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackBuffer); MOZ_COUNT_DTOR(BasicShadowableThebesLayer); } @@ -1196,7 +1229,77 @@ public: virtual Layer* AsLayer() { return this; } virtual ShadowableLayer* AsShadowableLayer() { return this; } + + virtual void SetBackBuffer(gfxSharedImageSurface* aBuffer) + { + mBackBuffer = aBuffer; + } + +private: + BasicShadowLayerManager* BasicManager() + { + return static_cast(mManager); + } + + NS_OVERRIDE virtual void + PaintBuffer(gfxContext* aContext, + const nsIntRegion& aRegionToDraw, + const nsIntRegion& aRegionToInvalidate, + LayerManager::DrawThebesLayerCallback aCallback, + void* aCallbackData); + + NS_OVERRIDE virtual already_AddRefed + CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize); + + nsRefPtr mBackBuffer; + nsIntSize mBufferSize; }; + +void +BasicShadowableThebesLayer::PaintBuffer(gfxContext* aContext, + const nsIntRegion& aRegionToDraw, + const nsIntRegion& aRegionToInvalidate, + LayerManager::DrawThebesLayerCallback aCallback, + void* aCallbackData) +{ + NS_ABORT_IF_FALSE(!!mBackBuffer, "should have a back buffer by now"); + + Base::PaintBuffer(aContext, aRegionToDraw, aRegionToInvalidate, + aCallback, aCallbackData); + + nsRefPtr tmpCtx = new gfxContext(mBackBuffer); + tmpCtx->DrawSurface(aContext->OriginalSurface(), + gfxIntSize(mBufferSize.width, mBufferSize.height)); + + BasicManager()->PaintedThebesBuffer(BasicManager()->Hold(this), + mBuffer.BufferRect(), + mBuffer.BufferRotation(), + mBackBuffer); +} + +already_AddRefed +BasicShadowableThebesLayer::CreateBuffer(Buffer::ContentType aType, + const nsIntSize& aSize) +{ + nsRefPtr tmpFront; + // XXX error handling + if (!BasicManager()->AllocDoubleBuffer(gfxIntSize(aSize.width, aSize.height), + gfxASurface::ImageFormatARGB32, + getter_AddRefs(tmpFront), + getter_AddRefs(mBackBuffer))) + NS_RUNTIMEABORT("creating ThebesLayer 'back buffer' failed!"); + mBufferSize = aSize; + + BasicManager()->CreatedThebesBuffer(BasicManager()->Hold(this), + // only |aSize| really matters + // here, since Painted() soon + // follows + nsIntRect(nsIntPoint(0, 0), aSize), + tmpFront); + + return Base::CreateBuffer(aType, aSize); +} + class BasicShadowableImageLayer : public BasicImageLayer, public BasicShadowableLayer @@ -1383,6 +1486,40 @@ BasicShadowableCanvasLayer::Paint(gfxContext* aContext, mBackBuffer); } +class ShadowThebesLayerBuffer : public BasicThebesLayerBuffer +{ + typedef BasicThebesLayerBuffer Base; + +public: + ShadowThebesLayerBuffer() + : Base(NULL) + { + MOZ_COUNT_CTOR(ShadowThebesLayerBuffer); + } + + ~ShadowThebesLayerBuffer() + { + MOZ_COUNT_DTOR(ShadowThebesLayerBuffer); + } + + already_AddRefed + Swap(gfxSharedImageSurface* aNewFrontBuffer, + const nsIntRect& aBufferRect, + const nsIntPoint& aRotation=nsIntPoint(0, 0)) + { + nsRefPtr newBackBuffer = SetBuffer(aNewFrontBuffer, + aBufferRect, aRotation); + return static_cast(newBackBuffer.forget().get()); + } + +protected: + virtual already_AddRefed + CreateBuffer(ContentType aType, const nsIntSize& aSize) + { + NS_RUNTIMEABORT("ShadowThebesLayer can't paint content"); + return nsnull; + } +}; class BasicShadowThebesLayer : public ShadowThebesLayer, BasicImplData { public: @@ -1391,26 +1528,67 @@ public: { MOZ_COUNT_CTOR(BasicShadowThebesLayer); } - virtual ~BasicShadowThebesLayer() - { - MOZ_COUNT_DTOR(BasicShadowThebesLayer); - } + virtual ~BasicShadowThebesLayer(); virtual already_AddRefed Swap(gfxSharedImageSurface* aNewFront, const nsIntRect& aBufferRect, const nsIntPoint& aRotation) - { return nsnull; } + { + return mFrontBuffer.Swap(aNewFront, aBufferRect, aRotation); + } virtual void Paint(gfxContext* aContext, LayerManager::DrawThebesLayerCallback aCallback, void* aCallbackData, - float aOpacity) - {} + float aOpacity); MOZ_LAYER_DECL_NAME("BasicShadowThebesLayer", TYPE_SHADOW) + +private: + BasicShadowLayerManager* BasicManager() + { + return static_cast(mManager); + } + + ShadowThebesLayerBuffer mFrontBuffer; }; +BasicShadowThebesLayer::~BasicShadowThebesLayer() +{ + nsRefPtr frontBuffer = + mFrontBuffer.Swap(0, nsIntRect()); + if (frontBuffer) { + BasicManager()->ShadowLayerManager::DestroySharedSurface(frontBuffer); + } + + MOZ_COUNT_DTOR(BasicShadowThebesLayer); +} + +void +BasicShadowThebesLayer::Paint(gfxContext* aContext, + LayerManager::DrawThebesLayerCallback aCallback, + void* aCallbackData, + float aOpacity) +{ + NS_ASSERTION(BasicManager()->InDrawing(), + "Can only draw in drawing phase"); + NS_ASSERTION(BasicManager()->IsRetained(), + "ShadowThebesLayer makes no sense without retained mode"); + + gfxContext* target = BasicManager()->GetTarget(); + NS_ASSERTION(target, "We shouldn't be called if there's no target"); + + nsRefPtr targetSurface = aContext->CurrentSurface(); + PRBool isOpaqueContent = + (targetSurface->AreSimilarSurfacesSensitiveToContentType() && + aOpacity == 1.0 && + CanUseOpaqueSurface()); + + mFrontBuffer.DrawTo(this, isOpaqueContent, target, aOpacity); +} + + class BasicShadowImageLayer : public ShadowImageLayer, BasicImplData { public: BasicShadowImageLayer(BasicShadowLayerManager* aLayerManager) :