From bac56e54f32b6763f8695dbb47e6c923fa11ef14 Mon Sep 17 00:00:00 2001 From: Mounir Lamouri Date: Tue, 17 May 2011 11:44:17 +0200 Subject: [PATCH] Backout bug 629866 and bug 647560. --- gfx/layers/basic/BasicLayers.cpp | 550 ++++++++++------------------ gfx/layers/basic/BasicLayers.h | 21 +- gfx/thebes/gfxCachedTempSurface.cpp | 11 +- gfx/thebes/gfxCachedTempSurface.h | 4 +- 4 files changed, 215 insertions(+), 371 deletions(-) diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index 65c723a1aa1..bdae2c8e90e 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -92,7 +92,7 @@ class ShadowableLayer; */ class BasicImplData { public: - BasicImplData() : mHidden(PR_FALSE), mOperator(gfxContext::OPERATOR_OVER) + BasicImplData() { MOZ_COUNT_CTOR(BasicImplData); } @@ -136,45 +136,16 @@ public: virtual void ClearCachedResources() {} /** - * This variable is set by MarkLayersHidden() before painting. It indicates - * that the layer should not be composited during this transaction. + * 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. */ - void SetHidden(PRBool aCovered) { mHidden = aCovered; } - PRBool IsHidden() const { return PR_FALSE; } - /** - * This variable is set by MarkLayersHidden() before painting. This is - * the operator to be used when compositing the layer in this transaction. It must - * be OVER or SOURCE. - */ - void SetOperator(gfxContext::GraphicsOperator aOperator) - { - NS_ASSERTION(aOperator == gfxContext::OPERATOR_OVER || - aOperator == gfxContext::OPERATOR_SOURCE, - "Bad composition operator"); - mOperator = aOperator; - } - gfxContext::GraphicsOperator GetOperator() const { return mOperator; } + void SetCoveredByOpaque(PRBool aCovered) { mCoveredByOpaque = aCovered; } + PRBool IsCoveredByOpaque() const { return mCoveredByOpaque; } protected: - PRPackedBool mHidden; - gfxContext::GraphicsOperator mOperator; -}; - -class AutoSetOperator { -public: - AutoSetOperator(gfxContext* aContext, gfxContext::GraphicsOperator aOperator) { - if (aOperator != gfxContext::OPERATOR_OVER) { - aContext->SetOperator(aOperator); - mContext = aContext; - } - } - ~AutoSetOperator() { - if (mContext) { - mContext->SetOperator(gfxContext::OPERATOR_OVER); - } - } -private: - nsRefPtr mContext; + PRPackedBool mCoveredByOpaque; }; static BasicImplData* @@ -188,7 +159,7 @@ static void ContainerInsertAfter(Layer* aChild, Layer* aAfter, Container* aConta template static void ContainerRemoveChild(Layer* aChild, Container* aContainer); -class BasicContainerLayer : public ContainerLayer, public BasicImplData { +class BasicContainerLayer : public ContainerLayer, BasicImplData { template friend void ContainerInsertAfter(Layer* aChild, Layer* aAfter, Container* aContainer); template @@ -242,23 +213,6 @@ public: mUseIntermediateSurface = GetEffectiveOpacity() != 1.0 && HasMultipleChildren(); } - /** - * Returns true when: - * a) no (non-hidden) childrens' visible areas overlap in - * (aInRect intersected with this layer's visible region). - * b) the (non-hidden) childrens' visible areas cover - * (aInRect intersected with this layer's visible region). - * c) this layer and all (non-hidden) children have transforms that are translations - * by integers. - * aInRect is in the root coordinate system. - * Child layers with opacity do not contribute to the covered area in check b). - * This method can be conservative; it's OK to return false under any - * circumstances. - */ - PRBool ChildrenPartitionVisibleRegion(const nsIntRect& aInRect); - - void ForceIntermediateSurface() { mUseIntermediateSurface = PR_TRUE; } - protected: BasicLayerManager* BasicManager() { @@ -275,43 +229,6 @@ BasicContainerLayer::~BasicContainerLayer() MOZ_COUNT_DTOR(BasicContainerLayer); } -PRBool -BasicContainerLayer::ChildrenPartitionVisibleRegion(const nsIntRect& aInRect) -{ - gfxMatrix transform; - if (!GetEffectiveTransform().Is2D(&transform) || - transform.HasNonIntegerTranslation()) - return PR_FALSE; - - nsIntPoint offset(PRInt32(transform.x0), PRInt32(transform.y0)); - nsIntRect rect = aInRect.Intersect(GetEffectiveVisibleRegion().GetBounds() + offset); - nsIntRegion covered; - - for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) { - if (ToData(l)->IsHidden()) - continue; - - gfxMatrix childTransform; - if (!l->GetEffectiveTransform().Is2D(&childTransform) || - childTransform.HasNonIntegerTranslation() || - l->GetEffectiveOpacity() != 1.0) - return PR_FALSE; - nsIntRegion childRegion = l->GetEffectiveVisibleRegion(); - childRegion.MoveBy(PRInt32(childTransform.x0), PRInt32(childTransform.y0)); - childRegion.And(childRegion, rect); - if (l->GetClipRect()) { - childRegion.And(childRegion, *l->GetClipRect() + offset); - } - nsIntRegion intersection; - intersection.And(covered, childRegion); - if (!intersection.IsEmpty()) - return PR_FALSE; - covered.Or(covered, childRegion); - } - - return covered.Contains(rect); -} - template static void ContainerInsertAfter(Layer* aChild, Layer* aAfter, Container* aContainer) @@ -444,7 +361,7 @@ private: BasicThebesLayer* mLayer; }; -class BasicThebesLayer : public ThebesLayer, public BasicImplData { +class BasicThebesLayer : public ThebesLayer, BasicImplData { public: typedef BasicThebesLayerBuffer Buffer; @@ -583,16 +500,15 @@ SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget) aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)))); } -already_AddRefed -BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer, - const nsIntRegion& aRegion, - PRBool* aNeedsClipToVisibleRegion) +static PRBool +PushGroupForLayer(gfxContext* aContext, Layer* aLayer, const nsIntRegion& aRegion) { // If we need to call PushGroup, we should clip to the smallest possible // area first to minimize the size of the temporary surface. PRBool didCompleteClip = ClipToContain(aContext, aRegion.GetBounds()); - nsRefPtr result; + gfxASurface::gfxContentType contentType = gfxASurface::CONTENT_COLOR_ALPHA; + PRBool needsClipToVisibleRegion = PR_FALSE; if (aLayer->CanUseOpaqueSurface() && ((didCompleteClip && aRegion.GetNumRects() == 1) || !aContext->CurrentMatrix().HasNonIntegerTranslation())) { @@ -600,14 +516,11 @@ BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer, // group. We need to make sure that only pixels inside the layer's visible // region are copied back to the destination. Remember if we've already // clipped precisely to the visible region. - *aNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1; - result = PushGroupWithCachedSurface(aContext, gfxASurface::CONTENT_COLOR); - } else { - *aNeedsClipToVisibleRegion = PR_FALSE; - result = aContext; - aContext->PushGroupAndCopyBackground(gfxASurface::CONTENT_COLOR_ALPHA); + needsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1; + contentType = gfxASurface::CONTENT_COLOR; } - return result.forget(); + aContext->PushGroupAndCopyBackground(contentType); + return needsClipToVisibleRegion; } void @@ -640,8 +553,8 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, mValidRegion.SetEmpty(); mBuffer.Clear(); - nsIntRegion toDraw = IntersectWithClip(GetEffectiveVisibleRegion(), aContext); - if (!toDraw.IsEmpty() && !IsHidden()) { + nsIntRegion toDraw = IntersectWithClip(mVisibleRegion, aContext); + if (!toDraw.IsEmpty()) { if (!aCallback) { BasicManager()->SetTransactionIncomplete(); return; @@ -650,27 +563,16 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, aContext->Save(); PRBool needsClipToVisibleRegion = PR_FALSE; - PRBool needsGroup = - opacity != 1.0 || GetOperator() != gfxContext::OPERATOR_OVER; - nsRefPtr groupContext; - if (needsGroup) { - groupContext = - BasicManager()->PushGroupForLayer(aContext, this, toDraw, - &needsClipToVisibleRegion); - if (GetOperator() != gfxContext::OPERATOR_OVER) { - needsClipToVisibleRegion = PR_TRUE; - } - } else { - groupContext = aContext; + if (opacity != 1.0) { + needsClipToVisibleRegion = PushGroupForLayer(aContext, this, toDraw); } - SetAntialiasingFlags(this, groupContext); - aCallback(this, groupContext, toDraw, nsIntRegion(), aCallbackData); - if (needsGroup) { - BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext); + SetAntialiasingFlags(this, aContext); + aCallback(this, aContext, toDraw, nsIntRegion(), aCallbackData); + if (opacity != 1.0) { + aContext->PopGroupToSource(); if (needsClipToVisibleRegion) { gfxUtils::ClipToRegion(aContext, toDraw); } - AutoSetOperator setOperator(aContext, GetOperator()); aContext->Paint(opacity); } @@ -699,8 +601,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, // (this could be the whole visible area if our buffer switched // from RGB to RGBA, because we might need to repaint with // subpixel AA) - state.mRegionToInvalidate.And(state.mRegionToInvalidate, - GetEffectiveVisibleRegion()); + state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion); nsIntRegion extendedDrawRegion = state.mRegionToDraw; extendedDrawRegion.ExtendForScaling(paintXRes, paintYRes); mXResolution = paintXRes; @@ -719,10 +620,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, } } - if (!IsHidden()) { - AutoSetOperator setOperator(aContext, GetOperator()); - mBuffer.DrawTo(this, aContext, opacity); - } + mBuffer.DrawTo(this, aContext, opacity); for (PRUint32 i = 0; i < readbackUpdates.Length(); ++i) { ReadbackProcessor::Update& update = readbackUpdates[i]; @@ -758,13 +656,13 @@ BasicThebesLayerBuffer::DrawTo(ThebesLayer* aLayer, // no need to clip. But we'll still clip if clipping is cheap --- // that might let us copy a smaller region of the buffer. if (!aLayer->GetValidRegion().Contains(BufferRect()) || - IsClippingCheap(aTarget, aLayer->GetEffectiveVisibleRegion())) { + IsClippingCheap(aTarget, aLayer->GetVisibleRegion())) { // We don't want to draw invalid stuff, so we need to clip. Might as // well clip to the smallest area possible --- the visible region. // Bug 599189 if there is a non-integer-translation transform in aTarget, - // we might sample pixels outside GetEffectiveVisibleRegion(), which is wrong + // we might sample pixels outside GetVisibleRegion(), which is wrong // and may cause gray lines. - gfxUtils::ClipToRegionSnapped(aTarget, aLayer->GetEffectiveVisibleRegion()); + gfxUtils::ClipToRegionSnapped(aTarget, aLayer->GetVisibleRegion()); } DrawBufferWithRotation(aTarget, aOpacity, aLayer->GetXResolution(), aLayer->GetYResolution()); @@ -797,7 +695,7 @@ BasicThebesLayerBuffer::SetBackingBufferAndUpdateFrom( srcBuffer.DrawBufferWithRotation(destCtx, 1.0, aXResolution, aYResolution); } -class BasicImageLayer : public ImageLayer, public BasicImplData { +class BasicImageLayer : public ImageLayer, BasicImplData { public: BasicImageLayer(BasicLayerManager* aLayerManager) : ImageLayer(aLayerManager, static_cast(this)), @@ -841,8 +739,6 @@ protected: void BasicImageLayer::Paint(gfxContext* aContext) { - if (IsHidden()) - return; nsRefPtr dontcare = GetAndPaintCurrentImage(aContext, GetEffectiveOpacity()); } @@ -872,7 +768,6 @@ BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext, // tiling, we don't want to draw into that area, so just draw within // the image bounds. const nsIntRect* tileSrcRect = GetTileSourceRect(); - AutoSetOperator setOperator(aContext, GetOperator()); PaintContext(pat, tileSrcRect ? GetVisibleRegion() : nsIntRegion(nsIntRect(0, 0, mSize.width, mSize.height)), tileSrcRect, @@ -934,7 +829,7 @@ BasicImageLayer::PaintContext(gfxPattern* aPattern, aPattern->SetExtend(extend); } -class BasicColorLayer : public ColorLayer, public BasicImplData { +class BasicColorLayer : public ColorLayer, BasicImplData { public: BasicColorLayer(BasicLayerManager* aLayerManager) : ColorLayer(aLayerManager, static_cast(this)) @@ -955,9 +850,6 @@ public: virtual void Paint(gfxContext* aContext) { - if (IsHidden()) - return; - AutoSetOperator setOperator(aContext, GetOperator()); PaintColorTo(mColor, GetEffectiveOpacity(), aContext); } @@ -980,7 +872,7 @@ BasicColorLayer::PaintColorTo(gfxRGBA aColor, float aOpacity, } class BasicCanvasLayer : public CanvasLayer, - public BasicImplData + BasicImplData { public: BasicCanvasLayer(BasicLayerManager* aLayerManager) : @@ -1102,8 +994,6 @@ BasicCanvasLayer::UpdateSurface() void BasicCanvasLayer::Paint(gfxContext* aContext) { - if (IsHidden()) - return; UpdateSurface(); FireDidTransactionCallback(); PaintWithOpacity(aContext, GetEffectiveOpacity()); @@ -1128,7 +1018,6 @@ BasicCanvasLayer::PaintWithOpacity(gfxContext* aContext, aContext->Scale(1.0, -1.0); } - AutoSetOperator setOperator(aContext, GetOperator()); aContext->NewPath(); // No need to snap here; our transform is already set up to snap our rect aContext->Rectangle(gfxRect(0, 0, mBounds.width, mBounds.height)); @@ -1141,7 +1030,7 @@ BasicCanvasLayer::PaintWithOpacity(gfxContext* aContext, } class BasicReadbackLayer : public ReadbackLayer, - public BasicImplData + BasicImplData { public: BasicReadbackLayer(BasicLayerManager* aLayerManager) : @@ -1184,6 +1073,64 @@ ToInsideIntRect(const gfxRect& aRect) return nsIntRect(r.X(), r.Y(), r.Width(), r.Height()); } +/** + * Returns false if there is at most one leaf layer overlapping aBounds + * and that layer is opaque. + * aDirtyVisibleRegionInContainer is filled in only if we return false. + * It contains the union of the visible regions of leaf layers under aLayer. + */ +static PRBool +MayHaveOverlappingOrTransparentLayers(Layer* aLayer, + const nsIntRect& aBounds, + nsIntRegion* aDirtyVisibleRegionInContainer) +{ + if (!(aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE)) { + return PR_TRUE; + } + + gfxMatrix matrix; + if (!aLayer->GetTransform().Is2D(&matrix) || + matrix.HasNonIntegerTranslation()) { + return PR_TRUE; + } + + nsIntPoint translation = nsIntPoint(PRInt32(matrix.x0), PRInt32(matrix.y0)); + nsIntRect bounds = aBounds - translation; + + nsIntRect clippedDirtyRect = bounds; + const nsIntRect* clipRect = aLayer->GetClipRect(); + if (clipRect) { + clippedDirtyRect.IntersectRect(clippedDirtyRect, *clipRect - translation); + } + aDirtyVisibleRegionInContainer->And(aLayer->GetVisibleRegion(), clippedDirtyRect); + aDirtyVisibleRegionInContainer->MoveBy(translation); + + /* Ignore layers outside the clip rect */ + if (aDirtyVisibleRegionInContainer->IsEmpty()) { + return PR_FALSE; + } + + nsIntRegion region; + + for (Layer* child = aLayer->GetFirstChild(); child; + child = child->GetNextSibling()) { + nsIntRegion childRegion; + if (MayHaveOverlappingOrTransparentLayers(child, bounds, &childRegion)) { + return PR_TRUE; + } + + nsIntRegion tmp; + tmp.And(region, childRegion); + if (!tmp.IsEmpty()) { + return PR_TRUE; + } + + region.Or(region, childRegion); + } + + return PR_FALSE; +} + BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) : #ifdef DEBUG mPhase(PHASE_NONE), @@ -1192,7 +1139,6 @@ BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) : , mYResolution(1.0) , mWidget(aWidget) , mDoubleBuffering(BUFFER_NONE), mUsingDefaultTarget(PR_FALSE) - , mCachedSurfaceInUse(PR_FALSE) , mTransactionIncomplete(false) { MOZ_COUNT_CTOR(BasicLayerManager); @@ -1239,15 +1185,9 @@ BasicLayerManager::BeginTransaction() already_AddRefed BasicLayerManager::PushGroupWithCachedSurface(gfxContext *aTarget, - gfxASurface::gfxContentType aContent) + gfxASurface::gfxContentType aContent, + gfxPoint *aSavedOffset) { - if (mCachedSurfaceInUse) { - aTarget->PushGroup(aContent); - nsRefPtr result = aTarget; - return result.forget(); - } - mCachedSurfaceInUse = PR_TRUE; - gfxContextMatrixAutoSaveRestore saveMatrix(aTarget); aTarget->IdentityMatrix(); @@ -1255,26 +1195,29 @@ BasicLayerManager::PushGroupWithCachedSurface(gfxContext *aTarget, gfxRect clip = aTarget->GetClipExtents(); clip.RoundOut(); - nsRefPtr ctx = mCachedSurface.Get(aContent, clip, currentSurf); + nsRefPtr ctx = + mCachedSurface.Get(aContent, + gfxIntSize(clip.Width(), clip.Height()), + currentSurf); /* Align our buffer for the original surface */ - ctx->SetMatrix(saveMatrix.Matrix()); + ctx->Translate(-clip.TopLeft()); + *aSavedOffset = clip.TopLeft(); + ctx->Multiply(saveMatrix.Matrix()); return ctx.forget(); } void -BasicLayerManager::PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed) +BasicLayerManager::PopGroupWithCachedSurface(gfxContext *aTarget, + const gfxPoint& aSavedOffset) { - if (!aTarget) + if (!mTarget) return; - nsRefPtr current = aPushed->CurrentSurface(); - if (mCachedSurface.IsSurface(current)) { - gfxContextMatrixAutoSaveRestore saveMatrix(aTarget); - aTarget->IdentityMatrix(); - aTarget->SetSource(current); - mCachedSurfaceInUse = PR_FALSE; - } else { - aTarget->PopGroupToSource(); - } + + gfxContextMatrixAutoSaveRestore saveMatrix(aTarget); + aTarget->IdentityMatrix(); + + aTarget->SetSource(mTarget->OriginalSurface(), aSavedOffset); + aTarget->Paint(); } void @@ -1301,36 +1244,25 @@ TransformIntRect(nsIntRect& aRect, const gfxMatrix& aMatrix, aRect = (*aRoundMethod)(gr); } -/** - * 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. - * It also sets the operator for all layers to "OVER". - * @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. - */ -enum { - ALLOW_OPAQUE = 0x01, -}; +// 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. static void -MarkLayersHidden(Layer* aLayer, const nsIntRect& aClipRect, - const nsIntRect& aDirtyRect, - nsIntRegion& aOpaqueRegion, - PRUint32 aFlags) +MarkLeafLayersCoveredByOpaque(Layer* aLayer, const nsIntRect& aClipRect, + nsIntRegion& aRegion) { + Layer* child = aLayer->GetLastChild(); + BasicImplData* data = ToData(aLayer); + data->SetCoveredByOpaque(PR_FALSE); + nsIntRect newClipRect(aClipRect); - PRUint32 newFlags = aFlags; // Allow aLayer or aLayer's descendants to cover underlying layers - // only if it's opaque. + // only if it's opaque. GetEffectiveOpacity() could be used instead, + // but it does extra passes from descendant to ancestor. if (aLayer->GetOpacity() != 1.0f) { - newFlags &= ~ALLOW_OPAQUE; + newClipRect.SetRect(0, 0, 0, 0); } { @@ -1342,8 +1274,6 @@ MarkLayersHidden(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); @@ -1353,102 +1283,36 @@ MarkLayersHidden(Layer* aLayer, const nsIntRect& aClipRect, } } - BasicImplData* data = ToData(aLayer); - data->SetOperator(gfxContext::OPERATOR_OVER); - - if (!aLayer->AsContainerLayer()) { + if (!child) { gfxMatrix transform; if (!aLayer->GetEffectiveTransform().Is2D(&transform)) { - data->SetHidden(PR_FALSE); return; } nsIntRegion region = aLayer->GetEffectiveVisibleRegion(); nsIntRect r = region.GetBounds(); TransformIntRect(r, transform, ToOutsideIntRect); - r.IntersectRect(r, aDirtyRect); - data->SetHidden(aOpaqueRegion.Contains(r)); + data->SetCoveredByOpaque(aRegion.Contains(r)); // Allow aLayer to cover underlying layers only if aLayer's // content is opaque - if ((aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) && - (newFlags & ALLOW_OPAQUE)) { - nsIntRegionRectIterator it(region); - while (const nsIntRect* sr = it.Next()) { - r = *sr; - TransformIntRect(r, transform, ToInsideIntRect); + if (!(aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE)) { + return; + } - r.IntersectRect(r, newClipRect); - aOpaqueRegion.Or(aOpaqueRegion, r); + nsIntRegionRectIterator it(region); + while (const nsIntRect* sr = it.Next()) { + r = *sr; + TransformIntRect(r, transform, ToInsideIntRect); + + r.IntersectRect(r, newClipRect); + if (!r.IsEmpty()) { + aRegion.Or(aRegion, r); } } } else { - Layer* child = aLayer->GetLastChild(); - PRBool allHidden = PR_TRUE; for (; child; child = child->GetPrevSibling()) { - MarkLayersHidden(child, newClipRect, aDirtyRect, aOpaqueRegion, newFlags); - if (!ToData(child)->IsHidden()) { - allHidden = PR_FALSE; - } - } - data->SetHidden(allHidden); - } -} - -/** - * This function assumes that GetEffectiveTransform transforms - * all layers to the same coordinate system (the "root coordinate system"). - * MarkLayersHidden must be called before calling this. - * @param aVisibleRect the rectangle of aLayer that is visible (i.e. not - * clipped and in the dirty rect), in the root coordinate system. - */ -static void -ApplyDoubleBuffering(Layer* aLayer, const nsIntRect& aVisibleRect) -{ - BasicImplData* data = ToData(aLayer); - if (data->IsHidden()) - return; - - nsIntRect newVisibleRect(aVisibleRect); - - { - const nsIntRect* clipRect = aLayer->GetEffectiveClipRect(); - if (clipRect) { - nsIntRect cr = *clipRect; - // clipRect is in the container's coordinate system. Get it into the - // global coordinate system. - if (aLayer->GetParent()) { - gfxMatrix tr; - if (aLayer->GetParent()->GetEffectiveTransform().Is2D(&tr)) { - NS_ASSERTION(!tr.HasNonIntegerTranslation(), - "Parent can only have an integer translation"); - cr += nsIntPoint(PRInt32(tr.x0), PRInt32(tr.y0)); - } else { - NS_ERROR("Parent can only have an integer translation"); - } - } - newVisibleRect.IntersectRect(newVisibleRect, cr); - } - } - - BasicContainerLayer* container = - static_cast(aLayer->AsContainerLayer()); - // Layers that act as their own backbuffers should be drawn to the destination - // using OPERATOR_SOURCE to ensure that alpha values in a transparent window - // are cleared. This can also be faster than OPERATOR_OVER. - if (!container) { - data->SetOperator(gfxContext::OPERATOR_SOURCE); - } else { - if (container->UseIntermediateSurface() || - !container->ChildrenPartitionVisibleRegion(newVisibleRect)) { - // We need to double-buffer this container. - data->SetOperator(gfxContext::OPERATOR_SOURCE); - container->ForceIntermediateSurface(); - } else { - for (Layer* child = aLayer->GetFirstChild(); child; - child = child->GetNextSibling()) { - ApplyDoubleBuffering(child, newVisibleRect); - } + MarkLeafLayersCoveredByOpaque(child, newClipRect, aRegion); } } } @@ -1477,39 +1341,50 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback, mTransactionIncomplete = false; if (mTarget && mRoot) { - 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()); + 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); } - // Need to do this before we call ApplyDoubleBuffering, - // which depends on correct effective transforms mSnapEffectiveTransforms = !(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING); mRoot->ComputeEffectiveTransforms(gfx3DMatrix::From2D(mTarget->CurrentMatrix())); - if (IsRetained()) { - nsIntRegion region; - MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE); - if (mUsingDefaultTarget && mDoubleBuffering != BUFFER_NONE) { - ApplyDoubleBuffering(mRoot, clipRect); - } - } + nsIntRegion region; + MarkLeafLayersCoveredByOpaque(mRoot, + mRoot->GetEffectiveVisibleRegion().GetBounds(), + region); + PaintLayer(mRoot, aCallback, aCallbackData, nsnull); - PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nsnull); + // If we're doing manual double-buffering, we need to avoid drawing + // the results of an incomplete transaction to the destination surface. + // If the transaction is incomplete and we're not double-buffering then + // either the system is double-buffering our window (in which case the + // followup EndTransaction will be drawn over the top of our incomplete + // transaction before the system updates the window), or we have no + // overlapping or transparent layers in the update region, in which case + // our partial transaction drawing will look fine. + if (useDoubleBuffering && !mTransactionIncomplete) { + finalTarget->SetOperator(gfxContext::OPERATOR_SOURCE); + PopGroupWithCachedSurface(finalTarget, cachedSurfaceOffset); + } if (!mTransactionIncomplete) { // Clear out target if we have a complete transaction. mTarget = nsnull; + } else { + // If we don't have a complete transaction set back to the old mTarget. + mTarget = finalTarget; } } @@ -1558,36 +1433,30 @@ BasicLayerManager::SetRoot(Layer* aLayer) } void -BasicLayerManager::PaintLayer(gfxContext* aTarget, - Layer* aLayer, +BasicLayerManager::PaintLayer(Layer* aLayer, DrawThebesLayerCallback aCallback, void* aCallbackData, ReadbackProcessor* aReadback) { const nsIntRect* clipRect = aLayer->GetEffectiveClipRect(); const gfx3DMatrix& effectiveTransform = aLayer->GetEffectiveTransform(); - BasicContainerLayer* container = static_cast(aLayer); PRBool needsGroup = aLayer->GetFirstChild() && - container->UseIntermediateSurface(); - NS_ASSERTION(needsGroup || !aLayer->GetFirstChild() || - container->GetOperator() == gfxContext::OPERATOR_OVER, - "non-OVER operator should have forced UseIntermediateSurface"); - + static_cast(aLayer)->UseIntermediateSurface(); // If needsSaveRestore is false, we should still save and restore // the CTM PRBool needsSaveRestore = needsGroup || clipRect; gfxMatrix savedMatrix; if (needsSaveRestore) { - aTarget->Save(); + mTarget->Save(); if (clipRect) { - aTarget->NewPath(); - aTarget->Rectangle(gfxRect(clipRect->x, clipRect->y, clipRect->width, clipRect->height), PR_TRUE); - aTarget->Clip(); + mTarget->NewPath(); + mTarget->Rectangle(gfxRect(clipRect->x, clipRect->y, clipRect->width, clipRect->height), PR_TRUE); + mTarget->Clip(); } } else { - savedMatrix = aTarget->CurrentMatrix(); + savedMatrix = mTarget->CurrentMatrix(); } gfxMatrix transform; @@ -1596,11 +1465,11 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, NS_ASSERTION(effectiveTransform.Is2D(), "Only 2D transforms supported currently"); effectiveTransform.Is2D(&transform); - aTarget->SetMatrix(transform); + mTarget->SetMatrix(transform); PRBool pushedTargetOpaqueRect = PR_FALSE; const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); - nsRefPtr currentSurface = aTarget->CurrentSurface(); + nsRefPtr currentSurface = mTarget->CurrentSurface(); const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect(); // Try to annotate currentSurface with a region of pixels that have been @@ -1610,17 +1479,14 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, !transform.HasNonAxisAlignedTransform()) { const nsIntRect& bounds = visibleRegion.GetBounds(); currentSurface->SetOpaqueRect( - aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height))); + mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height))); pushedTargetOpaqueRect = PR_TRUE; } PRBool needsClipToVisibleRegion = PR_FALSE; - nsRefPtr groupTarget; if (needsGroup) { - groupTarget = PushGroupForLayer(aTarget, aLayer, aLayer->GetEffectiveVisibleRegion(), - &needsClipToVisibleRegion); - } else { - groupTarget = aTarget; + needsClipToVisibleRegion = + PushGroupForLayer(mTarget, aLayer, aLayer->GetEffectiveVisibleRegion()); } /* Only paint ourself, or our children - This optimization relies on this! */ @@ -1629,12 +1495,14 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, BasicImplData* data = ToData(aLayer); #ifdef MOZ_LAYERS_HAVE_LOG MOZ_LAYERS_LOG(("%s (0x%p) is covered: %i\n", __FUNCTION__, - (void*)aLayer, data->IsHidden())); + (void*)aLayer, data->IsCoveredByOpaque())); #endif - if (aLayer->AsThebesLayer()) { - data->PaintThebes(groupTarget, aCallback, aCallbackData, aReadback); - } else { - data->Paint(groupTarget); + if (!data->IsCoveredByOpaque()) { + if (aLayer->AsThebesLayer()) { + data->PaintThebes(mTarget, aCallback, aCallbackData, aReadback); + } else { + data->Paint(mTarget); + } } } else { ReadbackProcessor readback; @@ -1644,30 +1512,18 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, } for (; child; child = child->GetNextSibling()) { - PaintLayer(groupTarget, child, aCallback, aCallbackData, &readback); + PaintLayer(child, aCallback, aCallbackData, &readback); if (mTransactionIncomplete) break; } } if (needsGroup) { - PopGroupToSourceWithCachedSurface(aTarget, groupTarget); - // If we're doing our own double-buffering, we need to avoid drawing - // the results of an incomplete transaction to the destination surface --- - // that could cause flicker. Double-buffering is implemented using a - // temporary surface for one or more container layers, so we need to stop - // those temporary surfaces from being composited to aTarget. - // ApplyDoubleBuffering guarantees that this container layer can't - // intersect any other leaf layers, so if the transaction is not yet marked - // incomplete, the contents of this container layer are the final contents - // for the window. - if (!mTransactionIncomplete) { - if (needsClipToVisibleRegion) { - gfxUtils::ClipToRegion(aTarget, aLayer->GetEffectiveVisibleRegion()); - } - AutoSetOperator setOperator(aTarget, container->GetOperator()); - aTarget->Paint(aLayer->GetEffectiveOpacity()); + mTarget->PopGroupToSource(); + if (needsClipToVisibleRegion) { + gfxUtils::ClipToRegion(mTarget, aLayer->GetEffectiveVisibleRegion()); } + mTarget->Paint(aLayer->GetEffectiveOpacity()); } if (pushedTargetOpaqueRect) { @@ -1675,9 +1531,9 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, } if (needsSaveRestore) { - aTarget->Restore(); + mTarget->Restore(); } else { - aTarget->SetMatrix(savedMatrix); + mTarget->SetMatrix(savedMatrix); } } @@ -2438,7 +2294,7 @@ protected: }; -class BasicShadowThebesLayer : public ShadowThebesLayer, public BasicImplData { +class BasicShadowThebesLayer : public ShadowThebesLayer, BasicImplData { public: BasicShadowThebesLayer(BasicShadowLayerManager* aLayerManager) : ShadowThebesLayer(aLayerManager, static_cast(this)) @@ -2612,7 +2468,7 @@ BasicShadowThebesLayer::PaintThebes(gfxContext* aContext, mFrontBuffer.DrawTo(this, target, GetEffectiveOpacity()); } -class BasicShadowContainerLayer : public ShadowContainerLayer, public BasicImplData { +class BasicShadowContainerLayer : public ShadowContainerLayer, BasicImplData { template friend void ContainerInsertAfter(Layer* aChild, Layer* aAfter, Container* aContainer); template @@ -2658,7 +2514,7 @@ public: } }; -class BasicShadowImageLayer : public ShadowImageLayer, public BasicImplData { +class BasicShadowImageLayer : public ShadowImageLayer, BasicImplData { public: BasicShadowImageLayer(BasicShadowLayerManager* aLayerManager) : ShadowImageLayer(aLayerManager, static_cast(this)) @@ -2731,7 +2587,6 @@ BasicShadowImageLayer::Paint(gfxContext* aContext) // tiling, we don't want to draw into that area, so just draw within // the image bounds. const nsIntRect* tileSrcRect = GetTileSourceRect(); - AutoSetOperator setOperator(aContext, GetOperator()); BasicImageLayer::PaintContext(pat, tileSrcRect ? GetEffectiveVisibleRegion() : nsIntRegion(nsIntRect(0, 0, mSize.width, mSize.height)), tileSrcRect, @@ -2739,7 +2594,7 @@ BasicShadowImageLayer::Paint(gfxContext* aContext) } class BasicShadowColorLayer : public ShadowColorLayer, - public BasicImplData + BasicImplData { public: BasicShadowColorLayer(BasicShadowLayerManager* aLayerManager) : @@ -2754,13 +2609,12 @@ public: virtual void Paint(gfxContext* aContext) { - AutoSetOperator setOperator(aContext, GetOperator()); BasicColorLayer::PaintColorTo(mColor, GetEffectiveOpacity(), aContext); } }; class BasicShadowCanvasLayer : public ShadowCanvasLayer, - public BasicImplData + BasicImplData { public: BasicShadowCanvasLayer(BasicShadowLayerManager* aLayerManager) : diff --git a/gfx/layers/basic/BasicLayers.h b/gfx/layers/basic/BasicLayers.h index 2704b9c30bf..392479d38e8 100644 --- a/gfx/layers/basic/BasicLayers.h +++ b/gfx/layers/basic/BasicLayers.h @@ -180,16 +180,7 @@ public: void SetTransactionIncomplete() { mTransactionIncomplete = true; } - already_AddRefed PushGroupForLayer(gfxContext* aContext, Layer* aLayer, - const nsIntRegion& aRegion, - PRBool* aNeedsClipToVisibleRegion); - already_AddRefed PushGroupWithCachedSurface(gfxContext *aTarget, - gfxASurface::gfxContentType aContent); - void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed); - virtual PRBool IsCompositingCheap() { return PR_FALSE; } - virtual bool HasShadowManagerInternal() const { return false; } - bool HasShadowManager() const { return HasShadowManagerInternal(); } protected: #ifdef DEBUG @@ -200,8 +191,7 @@ protected: #endif // Paints aLayer to mTarget. - void PaintLayer(gfxContext* aTarget, - Layer* aLayer, + void PaintLayer(Layer* aLayer, DrawThebesLayerCallback aCallback, void* aCallbackData, ReadbackProcessor* aReadback); @@ -209,6 +199,12 @@ protected: // Clear the contents of a layer void ClearLayer(Layer* aLayer); + already_AddRefed PushGroupWithCachedSurface(gfxContext *aTarget, + gfxASurface::gfxContentType aContent, + gfxPoint *aSavedOffset); + void PopGroupWithCachedSurface(gfxContext *aTarget, + const gfxPoint& aSavedOffset); + bool EndTransactionInternal(DrawThebesLayerCallback aCallback, void* aCallbackData); @@ -229,7 +225,6 @@ protected: BufferMode mDoubleBuffering; PRPackedBool mUsingDefaultTarget; - PRPackedBool mCachedSurfaceInUse; bool mTransactionIncomplete; }; @@ -265,7 +260,6 @@ public: ShadowableLayer* Hold(Layer* aLayer); - bool HasShadowManager() const { return ShadowLayerForwarder::HasShadowManager(); } PLayersChild* GetShadowManager() const { return mShadowManager; } void SetShadowManager(PLayersChild* aShadowManager) @@ -274,7 +268,6 @@ public: } virtual PRBool IsCompositingCheap(); - virtual bool HasShadowManagerInternal() const { return HasShadowManager(); } private: /** diff --git a/gfx/thebes/gfxCachedTempSurface.cpp b/gfx/thebes/gfxCachedTempSurface.cpp index b480174315a..a165175e478 100644 --- a/gfx/thebes/gfxCachedTempSurface.cpp +++ b/gfx/thebes/gfxCachedTempSurface.cpp @@ -98,12 +98,12 @@ gfxCachedTempSurface::~gfxCachedTempSurface() already_AddRefed gfxCachedTempSurface::Get(gfxASurface::gfxContentType aContentType, - const gfxRect& aRect, + const gfxIntSize& aSize, gfxASurface* aSimilarTo) { if (mSurface) { /* Verify the current buffer is valid for this purpose */ - if (mSize.width < aRect.width || mSize.height < aRect.height + if (mSize.width < aSize.width || mSize.height < aSize.height || mSurface->GetContentType() != aContentType) { mSurface = nsnull; } else { @@ -114,8 +114,8 @@ gfxCachedTempSurface::Get(gfxASurface::gfxContentType aContentType, PRBool cleared = PR_FALSE; if (!mSurface) { - mSize = gfxIntSize(PRInt32(NS_ceil(aRect.width)), PRInt32(NS_ceil(aRect.height))); - mSurface = aSimilarTo->CreateSimilarSurface(aContentType, mSize); + mSize = aSize; + mSurface = aSimilarTo->CreateSimilarSurface(aContentType, aSize); if (!mSurface) return nsnull; @@ -124,10 +124,9 @@ gfxCachedTempSurface::Get(gfxASurface::gfxContentType aContentType, mType = aSimilarTo->GetType(); #endif } - mSurface->SetDeviceOffset(-aRect.TopLeft()); nsRefPtr ctx = new gfxContext(mSurface); - ctx->Rectangle(aRect); + ctx->Rectangle(gfxRect(0, 0, aSize.width, aSize.height)); ctx->Clip(); if (!cleared && aContentType != gfxASurface::CONTENT_COLOR) { ctx->SetOperator(gfxContext::OPERATOR_CLEAR); diff --git a/gfx/thebes/gfxCachedTempSurface.h b/gfx/thebes/gfxCachedTempSurface.h index 3904cbe32ff..b3dbce37f39 100644 --- a/gfx/thebes/gfxCachedTempSurface.h +++ b/gfx/thebes/gfxCachedTempSurface.h @@ -71,15 +71,13 @@ public: * different format. */ already_AddRefed Get(gfxASurface::gfxContentType aContentType, - const gfxRect& aRect, + const gfxIntSize& aSize, gfxASurface* aSimilarTo); void Expire() { mSurface = nsnull; } nsExpirationState* GetExpirationState() { return &mExpirationState; } ~gfxCachedTempSurface(); - PRBool IsSurface(gfxASurface* aSurface) { return mSurface == aSurface; } - private: nsRefPtr mSurface; gfxIntSize mSize;