Bug 602200. Share code to compute effective transforms and opacity, and snap effective transforms. r=bas,sr=vlad,a=blocker

This commit is contained in:
Robert O'Callahan
2010-11-08 22:06:15 +13:00
parent ff8dbcc9b6
commit d1cc7cc31e
54 changed files with 659 additions and 484 deletions

View File

@@ -108,8 +108,7 @@ public:
*/
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity) {}
void* aCallbackData) {}
virtual ShadowableLayer* AsShadowableLayer() { return nsnull; }
@@ -174,6 +173,25 @@ public:
ContainerRemoveChild(aChild, this);
}
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
{
// We push groups for container layers if we need to, which always
// are aligned in device space, so it doesn't really matter how we snap
// containers.
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), nsnull);
// We always pass the ideal matrix down to our children, so there is no
// need to apply any compensation using the residual from SnapTransform.
ComputeEffectiveTransformsForChildren(idealTransform);
/* If we have a single child, it can just inherit our opacity,
* otherwise we need a PushGroup and we need to mark ourselves as using
* an intermediate surface so our children don't inherit our opacity
* via GetEffectiveOpacity.
*/
mUseIntermediateSurface = GetEffectiveOpacity() != 1.0 && HasMultipleChildren();
}
protected:
BasicLayerManager* BasicManager()
{
@@ -344,8 +362,7 @@ public:
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity);
void* aCallbackData);
virtual void ClearCachedResources() { mBuffer.Clear(); mValidRegion.SetEmpty(); }
@@ -446,8 +463,7 @@ IntersectWithClip(const nsIntRegion& aRegion, gfxContext* aContext)
void
BasicThebesLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
NS_ASSERTION(BasicManager()->InDrawing(),
"Can only draw in drawing phase");
@@ -461,9 +477,10 @@ BasicThebesLayer::Paint(gfxContext* aContext,
Buffer::ContentType contentType =
opaqueBuffer ? gfxASurface::CONTENT_COLOR :
gfxASurface::CONTENT_COLOR_ALPHA;
float opacity = GetEffectiveOpacity();
if (!BasicManager()->IsRetained() ||
(aOpacity == 1.0 && !canUseOpaqueSurface &&
(opacity == 1.0 && !canUseOpaqueSurface &&
!ShouldRetainTransparentSurface(mContentFlags, targetSurface) &&
!MustRetainContent())) {
mValidRegion.SetEmpty();
@@ -473,13 +490,13 @@ BasicThebesLayer::Paint(gfxContext* aContext,
if (!toDraw.IsEmpty()) {
target->Save();
gfxUtils::ClipToRegionSnapped(target, toDraw);
if (aOpacity != 1.0) {
if (opacity != 1.0) {
target->PushGroup(contentType);
}
aCallback(this, target, toDraw, nsIntRegion(), aCallbackData);
if (aOpacity != 1.0) {
if (opacity != 1.0) {
target->PopGroupToSource();
target->Paint(aOpacity);
target->Paint(opacity);
}
target->Restore();
}
@@ -513,7 +530,7 @@ BasicThebesLayer::Paint(gfxContext* aContext,
}
}
mBuffer.DrawTo(this, canUseOpaqueSurface, target, aOpacity);
mBuffer.DrawTo(this, canUseOpaqueSurface, target, opacity);
}
static PRBool
@@ -600,8 +617,7 @@ public:
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity);
void* aCallbackData);
static void PaintContext(gfxPattern* aPattern,
const gfxIntSize& aSize,
@@ -624,10 +640,10 @@ protected:
void
BasicImageLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
nsRefPtr<gfxPattern> dontcare = GetAndPaintCurrentImage(aContext, aOpacity);
nsRefPtr<gfxPattern> dontcare =
GetAndPaintCurrentImage(aContext, GetEffectiveOpacity());
}
already_AddRefed<gfxPattern>
@@ -677,8 +693,9 @@ BasicImageLayer::PaintContext(gfxPattern* aPattern,
/* Draw RGB surface onto frame */
aContext->NewPath();
aContext->PixelSnappedRectangleAndSetPattern(
gfxRect(0, 0, aSize.width, aSize.height), aPattern);
// No need to snap here; our transform has already taken care of it.
aContext->Rectangle(gfxRect(0, 0, aSize.width, aSize.height));
aContext->SetPattern(aPattern);
if (aOpacity != 1.0) {
aContext->Save();
aContext->Clip();
@@ -710,10 +727,9 @@ public:
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
PaintColorTo(mColor, mOpacity, aContext);
PaintColorTo(mColor, GetEffectiveOpacity(), aContext);
}
static void PaintColorTo(gfxRGBA aColor, float aOpacity,
@@ -759,8 +775,7 @@ public:
virtual void Updated(const nsIntRect& aRect);
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity);
void* aCallbackData);
protected:
BasicLayerManager* BasicManager()
@@ -772,7 +787,6 @@ protected:
nsRefPtr<mozilla::gl::GLContext> mGLContext;
PRUint32 mCanvasFramebuffer;
nsIntRect mBounds;
nsIntRect mUpdatedRect;
PRPackedBool mGLBufferIsPremultiplied;
@@ -870,8 +884,7 @@ BasicCanvasLayer::Updated(const nsIntRect& aRect)
void
BasicCanvasLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
NS_ASSERTION(BasicManager()->InDrawing(),
"Can only draw in drawing phase");
@@ -881,7 +894,6 @@ BasicCanvasLayer::Paint(gfxContext* aContext,
pat->SetFilter(mFilter);
pat->SetExtend(gfxPattern::EXTEND_PAD);
gfxRect r(0, 0, mBounds.width, mBounds.height);
gfxMatrix m;
if (mNeedsYFlip) {
m = aContext->CurrentMatrix();
@@ -889,12 +901,16 @@ BasicCanvasLayer::Paint(gfxContext* aContext,
aContext->Scale(1.0, -1.0);
}
float opacity = GetEffectiveOpacity();
aContext->NewPath();
aContext->PixelSnappedRectangleAndSetPattern(r, pat);
if (aOpacity != 1.0) {
// No need to snap here; our transform is already set up to snap our rect
aContext->Rectangle(gfxRect(0, 0, mBounds.width, mBounds.height));
aContext->SetPattern(pat);
if (opacity != 1.0) {
aContext->Save();
aContext->Clip();
aContext->Paint(aOpacity);
aContext->Paint(opacity);
aContext->Restore();
} else {
aContext->Fill();
@@ -1108,8 +1124,11 @@ BasicLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
&cachedSurfaceOffset);
}
PaintLayer(mRoot, aCallback, aCallbackData, mRoot->GetOpacity());
mSnapEffectiveTransforms =
!(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING);
mRoot->ComputeEffectiveTransforms(gfx3DMatrix::From2D(mTarget->CurrentMatrix()));
PaintLayer(mRoot, aCallback, aCallbackData);
if (useDoubleBuffering) {
finalTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
PopGroupWithCachedSurface(finalTarget, cachedSurfaceOffset);
@@ -1138,87 +1157,69 @@ BasicLayerManager::SetRoot(Layer* aLayer)
mRoot = aLayer;
}
// Returns true if we need to save the state of the gfxContext when
// we start painting aLayer (and restore the state when we've finished
// painting aLayer)
static PRBool
NeedsState(Layer* aLayer)
{
return aLayer->GetEffectiveClipRect() != nsnull ||
!aLayer->GetEffectiveTransform().IsIdentity();
}
static inline int
GetChildCount(Layer *aLayer)
{
int count = 0;
for (Layer* child = aLayer->GetFirstChild(); child;
child = child->GetNextSibling()) {
count++;
}
return count;
}
void
BasicLayerManager::PaintLayer(Layer* aLayer,
DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
PRBool needsGroup = aOpacity != 1.0;
PRBool needsSaveRestore = needsGroup || NeedsState(aLayer);
int children = GetChildCount(aLayer);
const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
const gfx3DMatrix& effectiveTransform = aLayer->GetEffectiveTransform();
PRBool needsGroup = aLayer->GetFirstChild() &&
static_cast<BasicContainerLayer*>(aLayer)->UseIntermediateSurface();
// If needsSaveRestore is false, we should still save and restore
// the CTM
PRBool needsSaveRestore = needsGroup || clipRect;
if (needsSaveRestore) {
gfxMatrix savedMatrix;
if (needsSaveRestore) {
mTarget->Save();
if (const nsIntRect* r = aLayer->GetEffectiveClipRect()) {
if (clipRect) {
mTarget->NewPath();
mTarget->Rectangle(gfxRect(r->x, r->y, r->width, r->height), PR_TRUE);
mTarget->Rectangle(gfxRect(clipRect->x, clipRect->y, clipRect->width, clipRect->height), PR_TRUE);
mTarget->Clip();
}
} else {
savedMatrix = mTarget->CurrentMatrix();
}
gfxMatrix transform;
// XXX we need to add some kind of 3D transform support, possibly
// using pixman?
NS_ASSERTION(aLayer->GetEffectiveTransform().Is2D(),
"Only 2D transforms supported currently");
aLayer->GetEffectiveTransform().Is2D(&transform);
mTarget->Multiply(transform);
gfxMatrix transform;
// XXX we need to add some kind of 3D transform support, possibly
// using pixman?
NS_ASSERTION(effectiveTransform.Is2D(),
"Only 2D transforms supported currently");
effectiveTransform.Is2D(&transform);
mTarget->SetMatrix(transform);
if (needsGroup && children > 1) {
// If we need to call PushGroup, we should clip to the smallest possible
// area first to minimize the size of the temporary surface.
ClipToContain(mTarget, aLayer->GetEffectiveVisibleRegion().GetBounds());
if (needsGroup) {
// If we need to call PushGroup, we should clip to the smallest possible
// area first to minimize the size of the temporary surface.
ClipToContain(mTarget, aLayer->GetEffectiveVisibleRegion().GetBounds());
gfxASurface::gfxContentType type = aLayer->CanUseOpaqueSurface()
? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA;
mTarget->PushGroup(type);
}
gfxASurface::gfxContentType type = aLayer->CanUseOpaqueSurface()
? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA;
mTarget->PushGroup(type);
}
/* Only paint ourself, or our children - This optimization relies on this! */
if (!children) {
ToData(aLayer)->Paint(mTarget, aCallback, aCallbackData, aOpacity);
Layer* child = aLayer->GetFirstChild();
if (!child) {
ToData(aLayer)->Paint(mTarget, aCallback, aCallbackData);
} else {
for (Layer* child = aLayer->GetFirstChild(); child;
child = child->GetNextSibling()) {
/* If we have a single child, we can pass the aOpacity down, otherwise we will have double buffered */
if (needsGroup && children == 1) {
PaintLayer(child, aCallback, aCallbackData, child->GetOpacity() * aOpacity);
} else {
PaintLayer(child, aCallback, aCallbackData, child->GetOpacity());
}
for (; child; child = child->GetNextSibling()) {
PaintLayer(child, aCallback, aCallbackData);
}
}
if (needsSaveRestore) {
if (needsGroup && children > 1) {
mTarget->PopGroupToSource();
mTarget->Paint(aOpacity);
}
if (needsGroup) {
mTarget->PopGroupToSource();
mTarget->Paint(aLayer->GetEffectiveOpacity());
}
if (needsSaveRestore) {
mTarget->Restore();
} else {
mTarget->SetMatrix(savedMatrix);
}
}
@@ -1591,8 +1592,7 @@ public:
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity);
void* aCallbackData);
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
{
@@ -1625,11 +1625,10 @@ private:
void
BasicShadowableImageLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
gfxIntSize oldSize = mSize;
nsRefPtr<gfxPattern> pat = GetAndPaintCurrentImage(aContext, aOpacity);
nsRefPtr<gfxPattern> pat = GetAndPaintCurrentImage(aContext, GetEffectiveOpacity());
if (!pat || !HasShadow())
return;
@@ -1713,8 +1712,7 @@ public:
virtual void Initialize(const Data& aData);
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity);
void* aCallbackData);
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
{
@@ -1777,10 +1775,9 @@ BasicShadowableCanvasLayer::Initialize(const Data& aData)
void
BasicShadowableCanvasLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
BasicCanvasLayer::Paint(aContext, aCallback, aCallbackData, aOpacity);
BasicCanvasLayer::Paint(aContext, aCallback, aCallbackData);
if (!HasShadow())
return;
@@ -1897,8 +1894,7 @@ public:
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity);
void* aCallbackData);
private:
BasicShadowLayerManager* BasicManager()
@@ -1987,8 +1983,7 @@ BasicShadowThebesLayer::Swap(const ThebesBuffer& aNewFront,
void
BasicShadowThebesLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
NS_ASSERTION(BasicManager()->InDrawing(),
"Can only draw in drawing phase");
@@ -2002,13 +1997,7 @@ BasicShadowThebesLayer::Paint(gfxContext* aContext,
gfxContext* target = BasicManager()->GetTarget();
NS_ASSERTION(target, "We shouldn't be called if there's no target");
nsRefPtr<gfxASurface> targetSurface = aContext->CurrentSurface();
PRBool isOpaqueContent =
(targetSurface->AreSimilarSurfacesSensitiveToContentType() &&
aOpacity == 1.0 &&
CanUseOpaqueSurface());
mFrontBuffer.DrawTo(this, isOpaqueContent, target, aOpacity);
mFrontBuffer.DrawTo(this, CanUseOpaqueSurface(), target, GetEffectiveOpacity());
}
class BasicShadowContainerLayer : public ShadowContainerLayer, BasicImplData {
@@ -2036,6 +2025,25 @@ public:
{ ContainerInsertAfter(aChild, aAfter, this); }
virtual void RemoveChild(Layer* aChild)
{ ContainerRemoveChild(aChild, this); }
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
{
// We push groups for container layers if we need to, which always
// are aligned in device space, so it doesn't really matter how we snap
// containers.
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), nsnull);
// We always pass the ideal matrix down to our children, so there is no
// need to apply any compensation using the residual from SnapTransform.
ComputeEffectiveTransformsForChildren(idealTransform);
/* If we have a single child, it can just inherit our opacity,
* otherwise we need a PushGroup and we need to mark ourselves as using
* an intermediate surface so our children don't inherit our opacity
* via GetEffectiveOpacity.
*/
mUseIntermediateSurface = GetEffectiveOpacity() != 1.0 && HasMultipleChildren();
}
};
class BasicShadowImageLayer : public ShadowImageLayer, BasicImplData {
@@ -2071,8 +2079,7 @@ public:
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity);
void* aCallbackData);
protected:
BasicShadowLayerManager* BasicManager()
@@ -2105,8 +2112,7 @@ BasicShadowImageLayer::Swap(gfxSharedImageSurface* newFront)
void
BasicShadowImageLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
if (!mFrontSurface) {
return;
@@ -2114,7 +2120,7 @@ BasicShadowImageLayer::Paint(gfxContext* aContext,
nsRefPtr<gfxPattern> pat = new gfxPattern(mFrontSurface);
pat->SetFilter(mFilter);
BasicImageLayer::PaintContext(pat, mSize, aOpacity, aContext);
BasicImageLayer::PaintContext(pat, mSize, GetEffectiveOpacity(), aContext);
}
class BasicShadowColorLayer : public ShadowColorLayer,
@@ -2133,10 +2139,9 @@ public:
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
BasicColorLayer::PaintColorTo(mColor, aOpacity, aContext);
BasicColorLayer::PaintColorTo(mColor, GetEffectiveOpacity(), aContext);
}
};
@@ -2178,8 +2183,7 @@ public:
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity);
void* aCallbackData);
private:
BasicShadowLayerManager* BasicManager()
@@ -2188,7 +2192,6 @@ private:
}
nsRefPtr<gfxSharedImageSurface> mFrontSurface;
nsIntRect mBounds;
};
@@ -2214,8 +2217,7 @@ BasicShadowCanvasLayer::Swap(gfxSharedImageSurface* newFront)
void
BasicShadowCanvasLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
float aOpacity)
void* aCallbackData)
{
NS_ASSERTION(BasicManager()->InDrawing(),
"Can only draw in drawing phase");
@@ -2231,7 +2233,9 @@ BasicShadowCanvasLayer::Paint(gfxContext* aContext,
gfxRect r(0, 0, mBounds.width, mBounds.height);
aContext->NewPath();
aContext->PixelSnappedRectangleAndSetPattern(r, pat);
// No need to snap here; our transform has already taken care of it
aContext->Rectangle(r);
aContext->SetPattern(pat);
aContext->Fill();
}