Backout 647560 --- changesets 32a13c864e55 c2dbc3747034 3d845440cbc7 13c5fa1bdfb0 8cf18f0d9e7e 863cd05ae581

This commit is contained in:
Robert O'Callahan 2011-05-17 19:05:23 +12:00
parent 26bbeb07e5
commit 78538a4bce
4 changed files with 215 additions and 371 deletions

View File

@ -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<gfxContext> mContext;
PRPackedBool mCoveredByOpaque;
};
static BasicImplData*
@ -188,7 +159,7 @@ static void ContainerInsertAfter(Layer* aChild, Layer* aAfter, Container* aConta
template<class Container>
static void ContainerRemoveChild(Layer* aChild, Container* aContainer);
class BasicContainerLayer : public ContainerLayer, public BasicImplData {
class BasicContainerLayer : public ContainerLayer, BasicImplData {
template<class Container>
friend void ContainerInsertAfter(Layer* aChild, Layer* aAfter, Container* aContainer);
template<class Container>
@ -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<class Container>
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<gfxContext>
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<gfxContext> 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<gfxContext> 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<BasicImplData*>(this)),
@ -841,8 +739,6 @@ protected:
void
BasicImageLayer::Paint(gfxContext* aContext)
{
if (IsHidden())
return;
nsRefPtr<gfxPattern> 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<BasicImplData*>(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<gfxContext>
BasicLayerManager::PushGroupWithCachedSurface(gfxContext *aTarget,
gfxASurface::gfxContentType aContent)
gfxASurface::gfxContentType aContent,
gfxPoint *aSavedOffset)
{
if (mCachedSurfaceInUse) {
aTarget->PushGroup(aContent);
nsRefPtr<gfxContext> 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<gfxContext> ctx = mCachedSurface.Get(aContent, clip, currentSurf);
nsRefPtr<gfxContext> 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<gfxASurface> 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<BasicContainerLayer*>(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<gfxContext> finalTarget = mTarget;
gfxPoint cachedSurfaceOffset;
nsIntRegion rootRegion;
PRBool useDoubleBuffering = mUsingDefaultTarget &&
mDoubleBuffering != BUFFER_NONE &&
MayHaveOverlappingOrTransparentLayers(mRoot,
ToOutsideIntRect(mTarget->GetClipExtents()),
&rootRegion);
if (useDoubleBuffering) {
nsRefPtr<gfxASurface> 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<BasicContainerLayer*>(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<BasicContainerLayer*>(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<gfxASurface> currentSurface = aTarget->CurrentSurface();
nsRefPtr<gfxASurface> 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<gfxContext> 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<BasicImplData*>(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<class Container>
friend void ContainerInsertAfter(Layer* aChild, Layer* aAfter, Container* aContainer);
template<class Container>
@ -2658,7 +2514,7 @@ public:
}
};
class BasicShadowImageLayer : public ShadowImageLayer, public BasicImplData {
class BasicShadowImageLayer : public ShadowImageLayer, BasicImplData {
public:
BasicShadowImageLayer(BasicShadowLayerManager* aLayerManager) :
ShadowImageLayer(aLayerManager, static_cast<BasicImplData*>(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) :

View File

@ -180,16 +180,7 @@ public:
void SetTransactionIncomplete() { mTransactionIncomplete = true; }
already_AddRefed<gfxContext> PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
const nsIntRegion& aRegion,
PRBool* aNeedsClipToVisibleRegion);
already_AddRefed<gfxContext> 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<gfxContext> 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:
/**

View File

@ -98,12 +98,12 @@ gfxCachedTempSurface::~gfxCachedTempSurface()
already_AddRefed<gfxContext>
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<gfxContext> 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);

View File

@ -71,15 +71,13 @@ public:
* different format.
*/
already_AddRefed<gfxContext> 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<gfxASurface> mSurface;
gfxIntSize mSize;