diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index bdae2c8e90e1..68d1572ad09e 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -92,7 +92,7 @@ class ShadowableLayer; */ class BasicImplData { public: - BasicImplData() + BasicImplData() : mHidden(PR_FALSE) { MOZ_COUNT_CTOR(BasicImplData); } @@ -136,16 +136,13 @@ public: virtual void ClearCachedResources() {} /** - * This variable is used by layer manager in order to - * MarkLeafLayersCoveredByOpaque() before painting. - * We keep it here for now. Once we need to cull completely covered - * non-Basic layers, mCoveredByOpaque should be moved to Layer. + * This variable is set by MarkLeafLayersHidden() before painting. */ - void SetCoveredByOpaque(PRBool aCovered) { mCoveredByOpaque = aCovered; } - PRBool IsCoveredByOpaque() const { return mCoveredByOpaque; } + void SetHidden(PRBool aCovered) { mHidden = aCovered; } + PRBool IsHidden() const { return PR_FALSE; } protected: - PRPackedBool mCoveredByOpaque; + PRPackedBool mHidden; }; static BasicImplData* @@ -554,7 +551,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, mBuffer.Clear(); nsIntRegion toDraw = IntersectWithClip(mVisibleRegion, aContext); - if (!toDraw.IsEmpty()) { + if (!toDraw.IsEmpty() && !IsHidden()) { if (!aCallback) { BasicManager()->SetTransactionIncomplete(); return; @@ -620,7 +617,9 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, } } - mBuffer.DrawTo(this, aContext, opacity); + if (!IsHidden()) { + mBuffer.DrawTo(this, aContext, opacity); + } for (PRUint32 i = 0; i < readbackUpdates.Length(); ++i) { ReadbackProcessor::Update& update = readbackUpdates[i]; @@ -739,6 +738,8 @@ protected: void BasicImageLayer::Paint(gfxContext* aContext) { + if (IsHidden()) + return; nsRefPtr dontcare = GetAndPaintCurrentImage(aContext, GetEffectiveOpacity()); } @@ -850,6 +851,8 @@ public: virtual void Paint(gfxContext* aContext) { + if (IsHidden()) + return; PaintColorTo(mColor, GetEffectiveOpacity(), aContext); } @@ -994,6 +997,8 @@ BasicCanvasLayer::UpdateSurface() void BasicCanvasLayer::Paint(gfxContext* aContext) { + if (IsHidden()) + return; UpdateSurface(); FireDidTransactionCallback(); PaintWithOpacity(aContext, GetEffectiveOpacity()); @@ -1084,6 +1089,11 @@ MayHaveOverlappingOrTransparentLayers(Layer* aLayer, const nsIntRect& aBounds, nsIntRegion* aDirtyVisibleRegionInContainer) { + if (static_cast(aLayer->ImplData())->IsHidden()) { + // This layer won't be painted, so just ignore it. + return PR_FALSE; + } + if (!(aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE)) { return PR_TRUE; } @@ -1244,17 +1254,27 @@ TransformIntRect(nsIntRect& aRect, const gfxMatrix& aMatrix, aRect = (*aRoundMethod)(gr); } -// This implementation assumes that GetEffectiveTransform transforms -// all layers to the same coordinate system. It can't be used as is -// by accelerated layers because of intermediate surfaces. -// aClipRect and aRegion are in that global coordinate system. +/** + * This function assumes that GetEffectiveTransform transforms + * all layers to the same coordinate system (the "root coordinate system"). + * It can't be used as is by accelerated layers because of intermediate surfaces. + * This must set the hidden flag to true or false on *all* layers in the subtree. + * @param aClipRect the cliprect, in the root coordinate system. We assume + * that any layer drawing is clipped to this rect. It is therefore not + * allowed to add to the opaque region outside that rect. + * @param aDirtyRect the dirty rect that will be painted, in the root + * coordinate system. Layers outside this rect should be hidden. + * @param aOpaqueRegion the opaque region covering aLayer, in the + * root coordinate system. + */ static void -MarkLeafLayersCoveredByOpaque(Layer* aLayer, const nsIntRect& aClipRect, - nsIntRegion& aRegion) +MarkLeafLayersHidden(Layer* aLayer, const nsIntRect& aClipRect, + const nsIntRect& aDirtyRect, + nsIntRegion& aOpaqueRegion) { Layer* child = aLayer->GetLastChild(); BasicImplData* data = ToData(aLayer); - data->SetCoveredByOpaque(PR_FALSE); + data->SetHidden(PR_FALSE); nsIntRect newClipRect(aClipRect); @@ -1274,6 +1294,8 @@ MarkLeafLayersCoveredByOpaque(Layer* aLayer, const nsIntRect& aClipRect, if (aLayer->GetParent()) { gfxMatrix tr; if (aLayer->GetParent()->GetEffectiveTransform().Is2D(&tr)) { + // Clip rect is applied after aLayer's transform, i.e., in the coordinate + // system of aLayer's parent. TransformIntRect(cr, tr, ToInsideIntRect); } else { cr.SetRect(0, 0, 0, 0); @@ -1292,7 +1314,8 @@ MarkLeafLayersCoveredByOpaque(Layer* aLayer, const nsIntRect& aClipRect, nsIntRegion region = aLayer->GetEffectiveVisibleRegion(); nsIntRect r = region.GetBounds(); TransformIntRect(r, transform, ToOutsideIntRect); - data->SetCoveredByOpaque(aRegion.Contains(r)); + r.IntersectRect(r, aDirtyRect); + data->SetHidden(aOpaqueRegion.Contains(r)); // Allow aLayer to cover underlying layers only if aLayer's // content is opaque @@ -1307,12 +1330,12 @@ MarkLeafLayersCoveredByOpaque(Layer* aLayer, const nsIntRect& aClipRect, r.IntersectRect(r, newClipRect); if (!r.IsEmpty()) { - aRegion.Or(aRegion, r); + aOpaqueRegion.Or(aOpaqueRegion, r); } } } else { for (; child; child = child->GetPrevSibling()) { - MarkLeafLayersCoveredByOpaque(child, newClipRect, aRegion); + MarkLeafLayersHidden(child, newClipRect, aDirtyRect, aOpaqueRegion); } } } @@ -1341,29 +1364,48 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback, mTransactionIncomplete = false; if (mTarget && mRoot) { - nsRefPtr finalTarget = mTarget; - gfxPoint cachedSurfaceOffset; - - nsIntRegion rootRegion; - PRBool useDoubleBuffering = mUsingDefaultTarget && - mDoubleBuffering != BUFFER_NONE && - MayHaveOverlappingOrTransparentLayers(mRoot, - ToOutsideIntRect(mTarget->GetClipExtents()), - &rootRegion); - if (useDoubleBuffering) { - nsRefPtr targetSurface = mTarget->CurrentSurface(); - mTarget = PushGroupWithCachedSurface(mTarget, targetSurface->GetContentType(), - &cachedSurfaceOffset); + nsIntRect clipRect; + if (HasShadowManager()) { + // If this has a shadow manager, the clip extents of mTarget are meaningless. + // So instead just use the root layer's visible region bounds. + const nsIntRect& bounds = mRoot->GetVisibleRegion().GetBounds(); + gfxRect deviceRect = + mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)); + clipRect = ToOutsideIntRect(deviceRect); + } else { + gfxContextMatrixAutoSaveRestore save(mTarget); + mTarget->SetMatrix(gfxMatrix()); + clipRect = ToOutsideIntRect(mTarget->GetClipExtents()); } + // Need to do this before we call MarkLeafLayersHidden, + // which depends on correct effective transforms mSnapEffectiveTransforms = !(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING); mRoot->ComputeEffectiveTransforms(gfx3DMatrix::From2D(mTarget->CurrentMatrix())); - nsIntRegion region; - MarkLeafLayersCoveredByOpaque(mRoot, - mRoot->GetEffectiveVisibleRegion().GetBounds(), - region); + // Need to do this before we call MayHaveOverlappingOrTransparentLayers, + // which uses information about which layers are going to be drawn. + if (IsRetained()) { + nsIntRegion region; + MarkLeafLayersHidden(mRoot, clipRect, clipRect, region); + } + + nsRefPtr finalTarget = mTarget; + gfxPoint cachedSurfaceOffset; + nsIntRegion rootRegion; + PRBool useDoubleBuffering = mUsingDefaultTarget && + mDoubleBuffering != BUFFER_NONE && + MayHaveOverlappingOrTransparentLayers(mRoot, clipRect, &rootRegion); + + if (useDoubleBuffering) { + nsRefPtr targetSurface = mTarget->CurrentSurface(); + mTarget = PushGroupWithCachedSurface(mTarget, targetSurface->GetContentType(), + &cachedSurfaceOffset); + // Recompute effective transforms since the gfxContext matrix has changed + mRoot->ComputeEffectiveTransforms(gfx3DMatrix::From2D(mTarget->CurrentMatrix())); + } + PaintLayer(mRoot, aCallback, aCallbackData, nsnull); // If we're doing manual double-buffering, we need to avoid drawing @@ -1495,14 +1537,12 @@ BasicLayerManager::PaintLayer(Layer* aLayer, BasicImplData* data = ToData(aLayer); #ifdef MOZ_LAYERS_HAVE_LOG MOZ_LAYERS_LOG(("%s (0x%p) is covered: %i\n", __FUNCTION__, - (void*)aLayer, data->IsCoveredByOpaque())); + (void*)aLayer, data->IsHidden())); #endif - if (!data->IsCoveredByOpaque()) { - if (aLayer->AsThebesLayer()) { - data->PaintThebes(mTarget, aCallback, aCallbackData, aReadback); - } else { - data->Paint(mTarget); - } + if (aLayer->AsThebesLayer()) { + data->PaintThebes(mTarget, aCallback, aCallbackData, aReadback); + } else { + data->Paint(mTarget); } } else { ReadbackProcessor readback; diff --git a/gfx/layers/basic/BasicLayers.h b/gfx/layers/basic/BasicLayers.h index 392479d38e80..41c684ffa88a 100644 --- a/gfx/layers/basic/BasicLayers.h +++ b/gfx/layers/basic/BasicLayers.h @@ -181,6 +181,8 @@ public: void SetTransactionIncomplete() { mTransactionIncomplete = true; } virtual PRBool IsCompositingCheap() { return PR_FALSE; } + virtual bool HasShadowManagerInternal() const { return false; } + bool HasShadowManager() const { return HasShadowManagerInternal(); } protected: #ifdef DEBUG @@ -260,6 +262,7 @@ public: ShadowableLayer* Hold(Layer* aLayer); + bool HasShadowManager() const { return ShadowLayerForwarder::HasShadowManager(); } PLayersChild* GetShadowManager() const { return mShadowManager; } void SetShadowManager(PLayersChild* aShadowManager) @@ -268,6 +271,7 @@ public: } virtual PRBool IsCompositingCheap(); + virtual bool HasShadowManagerInternal() const { return HasShadowManager(); } private: /**