Bug 602200. Share code to compute effective transforms and opacity, and snap effective transforms. r=bas,sr=vlad,a=blocker
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 08 Nov 2010 22:06:15 +1300
changeset 57097 f35c89eac3923034bc4a373d05b9772c6a05afc0
parent 57096 362567eee98261c00a8544f714eeaa0b436c12a7
child 57098 c6b6c4d8b9bb4264d9974877b1685ac1330ee160
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas, vlad, blocker
bugs602200
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 602200. Share code to compute effective transforms and opacity, and snap effective transforms. r=bas,sr=vlad,a=blocker
gfx/layers/ImageLayers.h
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicLayers.cpp
gfx/layers/basic/BasicLayers.h
gfx/layers/d3d10/CanvasLayerD3D10.cpp
gfx/layers/d3d10/CanvasLayerD3D10.h
gfx/layers/d3d10/ColorLayerD3D10.cpp
gfx/layers/d3d10/ColorLayerD3D10.h
gfx/layers/d3d10/ContainerLayerD3D10.cpp
gfx/layers/d3d10/ContainerLayerD3D10.h
gfx/layers/d3d10/ImageLayerD3D10.cpp
gfx/layers/d3d10/ImageLayerD3D10.h
gfx/layers/d3d10/LayerManagerD3D10.cpp
gfx/layers/d3d10/LayerManagerD3D10.h
gfx/layers/d3d10/ThebesLayerD3D10.cpp
gfx/layers/d3d10/ThebesLayerD3D10.h
gfx/layers/d3d9/CanvasLayerD3D9.cpp
gfx/layers/d3d9/CanvasLayerD3D9.h
gfx/layers/d3d9/ColorLayerD3D9.cpp
gfx/layers/d3d9/ColorLayerD3D9.h
gfx/layers/d3d9/ContainerLayerD3D9.cpp
gfx/layers/d3d9/ContainerLayerD3D9.h
gfx/layers/d3d9/ImageLayerD3D9.cpp
gfx/layers/d3d9/ImageLayerD3D9.h
gfx/layers/d3d9/LayerManagerD3D9.cpp
gfx/layers/d3d9/LayerManagerD3D9.h
gfx/layers/d3d9/ThebesLayerD3D9.cpp
gfx/layers/d3d9/ThebesLayerD3D9.h
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
gfx/layers/opengl/ColorLayerOGL.cpp
gfx/layers/opengl/ColorLayerOGL.h
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/ContainerLayerOGL.h
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.h
layout/reftests/bugs/581317-1-ref.html
layout/reftests/bugs/581317-1.html
layout/reftests/bugs/602200-1-ref.html
layout/reftests/bugs/602200-1.html
layout/reftests/bugs/602200-2-ref.html
layout/reftests/bugs/602200-2.html
layout/reftests/bugs/602200-3-ref.html
layout/reftests/bugs/602200-3.html
layout/reftests/bugs/602200-4-ref.html
layout/reftests/bugs/602200-4.html
layout/reftests/bugs/reftest.list
modules/plugin/test/reftest/div-alpha-opacity.html
modules/plugin/test/reftest/plugin-alpha-opacity.html
--- a/gfx/layers/ImageLayers.h
+++ b/gfx/layers/ImageLayers.h
@@ -202,16 +202,33 @@ public:
    */
   void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; }
 
   ImageContainer* GetContainer() { return mContainer; }
   gfxPattern::GraphicsFilter GetFilter() { return mFilter; }
 
   MOZ_LAYER_DECL_NAME("ImageLayer", TYPE_IMAGE)
 
+  virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
+  {
+    // Snap image edges to pixel boundaries
+    gfxRect snap(0, 0, 0, 0);
+    if (mContainer) {
+      gfxIntSize size = mContainer->GetCurrentSize();
+      snap.size = gfxSize(size.width, size.height);
+    }
+    // Snap our local transform first, and snap the inherited transform as well.
+    // This makes our snapping equivalent to what would happen if our content
+    // was drawn into a ThebesLayer (gfxContext would snap using the local
+    // transform, then we'd snap again when compositing the ThebesLayer).
+    mEffectiveTransform =
+        SnapTransform(GetLocalTransform(), snap, nsnull)*
+        SnapTransform(aTransformToSurface, gfxRect(0, 0, 0, 0), nsnull);
+  }
+
 protected:
   ImageLayer(LayerManager* aManager, void* aImplData)
     : Layer(aManager, aImplData), mFilter(gfxPattern::FILTER_GOOD) {}
 
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
   nsRefPtr<ImageContainer> mContainer;
   gfxPattern::GraphicsFilter mFilter;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -221,33 +221,153 @@ const nsIntRegion&
 Layer::GetEffectiveVisibleRegion()
 {
   if (ShadowLayer* shadow = AsShadowLayer()) {
     return shadow->GetShadowVisibleRegion();
   }
   return GetVisibleRegion();
 }
 
-const gfx3DMatrix&
-Layer::GetEffectiveTransform()
-{
-  if (ShadowLayer* shadow = AsShadowLayer()) {
-    return shadow->GetShadowTransform();
-  }
-  return GetTransform();
-}
-
 #else
 
 const nsIntRect* Layer::GetEffectiveClipRect() { return GetClipRect(); }
 const nsIntRegion& Layer::GetEffectiveVisibleRegion() { return GetVisibleRegion(); }
-const gfx3DMatrix& Layer::GetEffectiveTransform() { return GetTransform(); }
 
 #endif  // MOZ_IPC
 
+gfx3DMatrix
+Layer::SnapTransform(const gfx3DMatrix& aTransform,
+                     const gfxRect& aSnapRect,
+                     gfxMatrix* aResidualTransform)
+{
+  if (aResidualTransform) {
+    *aResidualTransform = gfxMatrix();
+  }
+
+  gfxMatrix matrix2D;
+  gfx3DMatrix result;
+  if (mManager->IsSnappingEffectiveTransforms() &&
+      aTransform.Is2D(&matrix2D) &&
+      matrix2D.HasNonIntegerTranslation() &&
+      !matrix2D.IsSingular() &&
+      !matrix2D.HasNonAxisAlignedTransform()) {
+    gfxMatrix snappedMatrix;
+    gfxPoint topLeft = matrix2D.Transform(aSnapRect.TopLeft());
+    topLeft.Round();
+    // first compute scale factors that scale aSnapRect to the snapped rect
+    if (aSnapRect.IsEmpty()) {
+      snappedMatrix.xx = matrix2D.xx;
+      snappedMatrix.yy = matrix2D.yy;
+    } else {
+      gfxPoint bottomRight = matrix2D.Transform(aSnapRect.BottomRight());
+      bottomRight.Round();
+      snappedMatrix.xx = (bottomRight.x - topLeft.x)/aSnapRect.Width();
+      snappedMatrix.yy = (bottomRight.y - topLeft.y)/aSnapRect.Height();
+    }
+    // compute translation factors that will move aSnapRect to the snapped rect
+    // given those scale factors
+    snappedMatrix.x0 = topLeft.x - aSnapRect.pos.x*snappedMatrix.xx;
+    snappedMatrix.y0 = topLeft.y - aSnapRect.pos.y*snappedMatrix.yy;
+    result = gfx3DMatrix::From2D(snappedMatrix);
+    if (aResidualTransform && !snappedMatrix.IsSingular()) {
+      // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
+      // (i.e., appying snappedMatrix after aResidualTransform gives the
+      // ideal transform.
+      gfxMatrix snappedMatrixInverse = snappedMatrix;
+      snappedMatrixInverse.Invert();
+      *aResidualTransform = matrix2D * snappedMatrixInverse;
+    }
+  } else {
+    result = aTransform;
+  }
+  return result;
+}
+
+const gfx3DMatrix&
+Layer::GetLocalTransform()
+{
+#ifdef MOZ_IPC
+  if (ShadowLayer* shadow = AsShadowLayer())
+    return shadow->GetShadowTransform();
+#endif
+  return mTransform;
+}
+
+float
+Layer::GetEffectiveOpacity()
+{
+  float opacity = GetOpacity();
+  for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
+       c = c->GetParent()) {
+    opacity *= c->GetOpacity();
+  }
+  return opacity;
+}
+
+PRBool
+ContainerLayer::HasMultipleChildren()
+{
+  PRUint32 count = 0;
+  for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
+    const nsIntRect *clipRect = child->GetEffectiveClipRect();
+    if (clipRect && clipRect->IsEmpty())
+      continue;
+    if (child->GetVisibleRegion().IsEmpty())
+      continue;
+    ++count;
+    if (count > 1)
+      return PR_TRUE;
+  }
+
+  return PR_FALSE;
+}
+
+void
+ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
+{
+  gfxMatrix residual;
+  gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
+  mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), &residual);
+
+  PRBool useIntermediateSurface;
+  float opacity = GetEffectiveOpacity();
+  if (opacity != 1.0f && HasMultipleChildren()) {
+    useIntermediateSurface = PR_TRUE;
+  } else {
+    useIntermediateSurface = PR_FALSE;
+    if (!mEffectiveTransform.IsIdentity()) {
+      for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
+        const nsIntRect *clipRect = child->GetEffectiveClipRect();
+        /* We can't (easily) forward our transform to children with a non-empty clip
+         * rect since it would need to be adjusted for the transform.
+         * TODO: This is easily solvable for translation/scaling transforms.
+         */
+        if (clipRect && !clipRect->IsEmpty() && !child->GetVisibleRegion().IsEmpty()) {
+          useIntermediateSurface = PR_TRUE;
+          break;
+        }
+      }
+    }
+  }
+
+  mUseIntermediateSurface = useIntermediateSurface;
+  if (useIntermediateSurface) {
+    ComputeEffectiveTransformsForChildren(gfx3DMatrix::From2D(residual));
+  } else {
+    ComputeEffectiveTransformsForChildren(idealTransform);
+  }
+}
+
+void
+ContainerLayer::ComputeEffectiveTransformsForChildren(const gfx3DMatrix& aTransformToSurface)
+{
+  for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
+    l->ComputeEffectiveTransforms(aTransformToSurface);
+  }
+}
 
 #ifdef MOZ_LAYERS_HAVE_LOG
 
 static nsACString& PrintInfo(nsACString& aTo, ShadowLayer* aShadowLayer);
 
 void
 Layer::Dump(FILE* aFile, const char* aPrefix)
 {
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -224,17 +224,17 @@ class THEBES_API LayerManager {
 public:
   enum LayersBackend {
     LAYERS_BASIC = 0,
     LAYERS_OPENGL,
     LAYERS_D3D9,
     LAYERS_D3D10
   };
 
-  LayerManager() : mDestroyed(PR_FALSE)
+  LayerManager() : mDestroyed(PR_FALSE), mSnapEffectiveTransforms(PR_TRUE)
   {
     InitLog();
   }
   virtual ~LayerManager() {}
 
   /**
    * Release layers and resources held by this layer manager, and mark
    * it as destroyed.  Should do any cleanup necessary in preparation
@@ -295,16 +295,18 @@ public:
    * drawing phase, and end the transaction.
    * During the drawing phase, all ThebesLayers in the tree are
    * drawn in tree order, exactly once each, except for those layers
    * where it is known that the visible region is empty.
    */
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData) = 0;
 
+  PRBool IsSnappingEffectiveTransforms() { return mSnapEffectiveTransforms; } 
+
   /**
    * CONSTRUCTION PHASE ONLY
    * Set the root layer.
    */
   virtual void SetRoot(Layer* aLayer) = 0;
   /**
    * Can be called anytime
    */
@@ -420,16 +422,17 @@ public:
 
   static bool IsLogEnabled();
   static PRLogModuleInfo* GetLog() { return sLog; }
 
 protected:
   nsRefPtr<Layer> mRoot;
   LayerUserDataSet mUserData;
   PRPackedBool mDestroyed;
+  PRPackedBool mSnapEffectiveTransforms;
 
   // Print interesting information about this into aTo.  Internally
   // used to implement Dump*() and Log*().
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
   static void InitLog();
   static PRLogModuleInfo* sLog;
 };
@@ -650,17 +653,43 @@ public:
    */
   virtual ShadowLayer* AsShadowLayer() { return nsnull; }
 
   // These getters can be used anytime.  They return the effective
   // values that should be used when drawing this layer to screen,
   // accounting for this layer possibly being a shadow.
   const nsIntRect* GetEffectiveClipRect();
   const nsIntRegion& GetEffectiveVisibleRegion();
-  const gfx3DMatrix& GetEffectiveTransform();
+  /**
+   * Returns the product of the opacities of this layer and all ancestors up
+   * to and excluding the nearest ancestor that has UseIntermediateSurface() set.
+   */
+  float GetEffectiveOpacity();
+  /**
+   * This returns the effective transform computed by
+   * ComputeEffectiveTransforms. Typically this is a transform that transforms
+   * this layer all the way to some intermediate surface or destination
+   * surface. For non-BasicLayers this will be a transform to the nearest
+   * ancestor with UseIntermediateSurface() (or to the root, if there is no
+   * such ancestor), but for BasicLayers it's different.
+   */
+  const gfx3DMatrix& GetEffectiveTransform() const { return mEffectiveTransform; }
+
+  /**
+   * @param aTransformToSurface the composition of the transforms
+   * from the parent layer (if any) to the destination pixel grid.
+   *
+   * Computes mEffectiveTransform for this layer and all its descendants.
+   * mEffectiveTransform transforms this layer up to the destination
+   * pixel grid (whatever aTransformToSurface is relative to).
+   * 
+   * We promise that when this is called on a layer, all ancestor layers
+   * have already had ComputeEffectiveTransforms called.
+   */
+  virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) = 0;
 
   virtual const char* Name() const =0;
   virtual LayerType GetType() const =0;
 
   /**
    * Only the implementation should call this. This is per-implementation
    * private data. Normally, all layers with a given layer manager
    * use the same type of ImplData.
@@ -714,24 +743,46 @@ protected:
 
   // Print interesting information about this into aTo.  Internally
   // used to implement Dump*() and Log*().  If subclasses have
   // additional interesting properties, they should override this with
   // an implementation that first calls the base implementation then
   // appends additional info to aTo.
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
+  /**
+   * Returns the local transform for this layer: either mTransform or,
+   * for shadow layers, GetShadowTransform()
+   */
+  const gfx3DMatrix& GetLocalTransform();
+
+  /**
+   * Computes a tweaked version of aTransform that snaps a point or a rectangle
+   * to pixel boundaries. Snapping is only performed if this layer's
+   * layer manager has enabled snapping (which is the default).
+   * @param aSnapRect a rectangle whose edges should be snapped to pixel
+   * boundaries in the destination surface. If the rectangle is empty,
+   * then the snapping process should preserve the scale factors of the
+   * transform matrix
+   * @param aResidualTransform a transform to apply before mEffectiveTransform
+   * in order to get the results to completely match aTransform
+   */
+  gfx3DMatrix SnapTransform(const gfx3DMatrix& aTransform,
+                            const gfxRect& aSnapRect,
+                            gfxMatrix* aResidualTransform);
+
   LayerManager* mManager;
   ContainerLayer* mParent;
   Layer* mNextSibling;
   Layer* mPrevSibling;
   void* mImplData;
   LayerUserDataSet mUserData;
   nsIntRegion mVisibleRegion;
   gfx3DMatrix mTransform;
+  gfx3DMatrix mEffectiveTransform;
   float mOpacity;
   nsIntRect mClipRect;
   PRUint32 mContentFlags;
   PRPackedBool mUseClipRect;
 };
 
 /**
  * A Layer which we can draw into using Thebes. It is a conceptually
@@ -760,16 +811,23 @@ public:
   const nsIntRegion& GetValidRegion() const { return mValidRegion; }
   float GetXResolution() const { return mXResolution; }
   float GetYResolution() const { return mYResolution; }
 
   virtual ThebesLayer* AsThebesLayer() { return this; }
 
   MOZ_LAYER_DECL_NAME("ThebesLayer", TYPE_THEBES)
 
+  virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
+  {
+    // The default implementation just snaps 0,0 to pixels.
+    gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
+    mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), nsnull);
+  }
+
 protected:
   ThebesLayer(LayerManager* aManager, void* aImplData)
     : Layer(aManager, aImplData)
     , mValidRegion()
     , mXResolution(1.0)
     , mYResolution(1.0)
   {}
 
@@ -826,26 +884,60 @@ public:
 
   // These getters can be used anytime.
 
   virtual Layer* GetFirstChild() { return mFirstChild; }
   const FrameMetrics& GetFrameMetrics() { return mFrameMetrics; }
 
   MOZ_LAYER_DECL_NAME("ContainerLayer", TYPE_CONTAINER)
 
+  /**
+   * ContainerLayer backends need to override ComputeEffectiveTransforms
+   * since the decision about whether to use a temporary surface for the
+   * container is backend-specific. ComputeEffectiveTransforms must also set
+   * mUseIntermediateSurface.
+   */
+  virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) = 0;
+
+  /**
+   * Call this only after ComputeEffectiveTransforms has been invoked
+   * on this layer.
+   * Returns true if this will use an intermediate surface. This is largely
+   * backend-dependent, but it affects the operation of GetEffectiveOpacity().
+   */
+  PRBool UseIntermediateSurface() { return mUseIntermediateSurface; }
+
+  /**
+   * Returns true if this container has more than one non-empty child
+   */
+  PRBool HasMultipleChildren();
+
 protected:
   ContainerLayer(LayerManager* aManager, void* aImplData)
     : Layer(aManager, aImplData),
-      mFirstChild(nsnull)
+      mFirstChild(nsnull),
+      mUseIntermediateSurface(PR_FALSE)
   {}
 
+  /**
+   * A default implementation of ComputeEffectiveTransforms for use by OpenGL
+   * and D3D.
+   */
+  void DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface);
+
+  /**
+   * Loops over the children calling ComputeEffectiveTransforms on them.
+   */
+  void ComputeEffectiveTransformsForChildren(const gfx3DMatrix& aTransformToSurface);
+
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
   Layer* mFirstChild;
   FrameMetrics mFrameMetrics;
+  PRPackedBool mUseIntermediateSurface;
 };
 
 /**
  * A Layer which just renders a solid color in its visible region. It actually
  * can fill any area that contains the visible region, so if you need to
  * restrict the area filled, set a clip region on this layer.
  */
 class THEBES_API ColorLayer : public Layer {
@@ -859,16 +951,23 @@ public:
     mColor = aColor;
   }
 
   // This getter can be used anytime.
   virtual const gfxRGBA& GetColor() { return mColor; }
 
   MOZ_LAYER_DECL_NAME("ColorLayer", TYPE_COLOR)
 
+  virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
+  {
+    // Snap 0,0 to pixel boundaries, no extra internal transform.
+    gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
+    mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), nsnull);
+  }
+
 protected:
   ColorLayer(LayerManager* aManager, void* aImplData)
     : Layer(aManager, aImplData),
       mColor(0.0, 0.0, 0.0, 0.0)
   {}
 
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
@@ -929,21 +1028,37 @@ public:
    * CONSTRUCTION PHASE ONLY
    * Set the filter used to resample this image (if necessary).
    */
   void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; }
   gfxPattern::GraphicsFilter GetFilter() const { return mFilter; }
 
   MOZ_LAYER_DECL_NAME("CanvasLayer", TYPE_CANVAS)
 
+  virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
+  {
+    // Snap our local transform first, and snap the inherited transform as well.
+    // This makes our snapping equivalent to what would happen if our content
+    // was drawn into a ThebesLayer (gfxContext would snap using the local
+    // transform, then we'd snap again when compositing the ThebesLayer).
+    mEffectiveTransform =
+        SnapTransform(GetLocalTransform(), gfxRect(0, 0, mBounds.width, mBounds.height),
+                      nsnull)*
+        SnapTransform(aTransformToSurface, gfxRect(0, 0, 0, 0), nsnull);
+  }
+
 protected:
   CanvasLayer(LayerManager* aManager, void* aImplData)
     : Layer(aManager, aImplData), mFilter(gfxPattern::FILTER_GOOD) {}
 
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
+  /**
+   * 0, 0, canvaswidth, canvasheight
+   */
+  nsIntRect mBounds;
   gfxPattern::GraphicsFilter mFilter;
 };
 
 }
 }
 
 #endif /* GFX_LAYERS_H */
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -103,18 +103,17 @@ public:
   /**
    * Layers that paint themselves, such as ImageLayers, should paint
    * in response to this method call. aContext will already have been
    * set up to account for all the properties of the layer (transform,
    * opacity, etc).
    */
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
-                     void* aCallbackData,
-                     float aOpacity) {}
+                     void* aCallbackData) {}
 
   virtual ShadowableLayer* AsShadowableLayer() { return nsnull; }
 
   /**
    * Implementations return true here if they *must* retain their
    * layer contents.  This is true of shadowable layers with shadows,
    * because there's no target on which to composite directly in the
    * layer-publishing child process.
@@ -169,16 +168,35 @@ public:
 
   virtual void RemoveChild(Layer* aChild)
   { 
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     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()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
 };
 
 BasicContainerLayer::~BasicContainerLayer()
@@ -339,18 +357,17 @@ public:
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     mValidRegion.Sub(mValidRegion, aRegion);
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
-                     void* aCallbackData,
-                     float aOpacity);
+                     void* aCallbackData);
 
   virtual void ClearCachedResources() { mBuffer.Clear(); mValidRegion.SetEmpty(); }
   
   virtual already_AddRefed<gfxASurface>
   CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize)
   {
     nsRefPtr<gfxASurface> referenceSurface = mBuffer.GetBuffer();
     if (!referenceSurface) {
@@ -441,50 +458,50 @@ IntersectWithClip(const nsIntRegion& aRe
   nsIntRegion result;
   result.And(aRegion, r);
   return result;
 }
 
 void
 BasicThebesLayer::Paint(gfxContext* aContext,
                         LayerManager::DrawThebesLayerCallback aCallback,
-                        void* aCallbackData,
-                        float aOpacity)
+                        void* aCallbackData)
 {
   NS_ASSERTION(BasicManager()->InDrawing(),
                "Can only draw in drawing phase");
   gfxContext* target = BasicManager()->GetTarget();
   NS_ASSERTION(target, "We shouldn't be called if there's no target");
   nsRefPtr<gfxASurface> targetSurface = aContext->CurrentSurface();
 
   PRBool canUseOpaqueSurface = CanUseOpaqueSurface();
   PRBool opaqueBuffer = canUseOpaqueSurface &&
     targetSurface->AreSimilarSurfacesSensitiveToContentType();
   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();
     mBuffer.Clear();
 
     nsIntRegion toDraw = IntersectWithClip(mVisibleRegion, target);
     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();
     }
     return;
   }
 
   {
     float paintXRes = BasicManager()->XResolution();
@@ -508,17 +525,17 @@ BasicThebesLayer::Paint(gfxContext* aCon
     } else {
       // It's possible that state.mRegionToInvalidate is nonempty here,
       // if we are shrinking the valid region to nothing.
       NS_ASSERTION(state.mRegionToDraw.IsEmpty(),
                    "If we need to draw, we should have a context");
     }
   }
 
-  mBuffer.DrawTo(this, canUseOpaqueSurface, target, aOpacity);
+  mBuffer.DrawTo(this, canUseOpaqueSurface, target, opacity);
 }
 
 static PRBool
 IsClippingCheap(gfxContext* aTarget, const nsIntRegion& aRegion)
 {
   // Assume clipping is cheap if the context just has an integer
   // translation, and the visible region is simple.
   return !aTarget->CurrentMatrix().HasNonIntegerTranslation() &&
@@ -595,18 +612,17 @@ public:
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     ImageLayer::SetVisibleRegion(aRegion);
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
-                     void* aCallbackData,
-                     float aOpacity);
+                     void* aCallbackData);
 
   static void PaintContext(gfxPattern* aPattern,
                            const gfxIntSize& aSize,
                            float aOpacity,
                            gfxContext* aContext);
 
 protected:
   BasicLayerManager* BasicManager()
@@ -619,20 +635,20 @@ protected:
                           float aOpacity);
 
   gfxIntSize mSize;
 };
 
 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>
 BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext,
                                          float aOpacity)
 {
   if (!mContainer)
     return nsnull;
@@ -672,18 +688,19 @@ BasicImageLayer::PaintContext(gfxPattern
       type == gfxASurface::SurfaceTypeQuartz) {
     extend = gfxPattern::EXTEND_NONE;
   }
 
   aPattern->SetExtend(extend);
 
   /* 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();
     aContext->Paint(aOpacity);
     aContext->Restore();
   } else {
     aContext->Fill();
   }
@@ -705,20 +722,19 @@ public:
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     ColorLayer::SetVisibleRegion(aRegion);
   }
 
   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,
                            gfxContext* aContext);
 
 protected:
   BasicLayerManager* BasicManager()
   {
@@ -754,30 +770,28 @@ public:
                  "Can only set properties in construction phase");
     CanvasLayer::SetVisibleRegion(aRegion);
   }
 
   virtual void Initialize(const Data& aData);
   virtual void Updated(const nsIntRect& aRect);
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
-                     void* aCallbackData,
-                     float aOpacity);
+                     void* aCallbackData);
 
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
 
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<mozilla::gl::GLContext> mGLContext;
   PRUint32 mCanvasFramebuffer;
 
-  nsIntRect mBounds;
   nsIntRect mUpdatedRect;
 
   PRPackedBool mGLBufferIsPremultiplied;
   PRPackedBool mNeedsYFlip;
 };
 
 void
 BasicCanvasLayer::Initialize(const Data& aData)
@@ -865,41 +879,43 @@ BasicCanvasLayer::Updated(const nsIntRec
   // sanity
   NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect),
                "CanvasLayer: Updated rect bigger than bounds!");
 }
 
 void
 BasicCanvasLayer::Paint(gfxContext* aContext,
                         LayerManager::DrawThebesLayerCallback aCallback,
-                        void* aCallbackData,
-                        float aOpacity)
+                        void* aCallbackData)
 {
   NS_ASSERTION(BasicManager()->InDrawing(),
                "Can only draw in drawing phase");
 
   nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
 
   pat->SetFilter(mFilter);
   pat->SetExtend(gfxPattern::EXTEND_PAD);
 
-  gfxRect r(0, 0, mBounds.width, mBounds.height);
   gfxMatrix m;
   if (mNeedsYFlip) {
     m = aContext->CurrentMatrix();
     aContext->Translate(gfxPoint(0.0, mBounds.height));
     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();
   }
 
   if (mNeedsYFlip) {
     aContext->SetMatrix(m);
   }
@@ -1103,18 +1119,21 @@ BasicLayerManager::EndTransaction(DrawTh
                                             ToOutsideIntRect(mTarget->GetClipExtents()),
                                             &rootRegion);
     if (useDoubleBuffering) {
       nsRefPtr<gfxASurface> targetSurface = mTarget->CurrentSurface();
       mTarget = PushGroupWithCachedSurface(mTarget, targetSurface->GetContentType(),
                                            &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);
     }
 
     mTarget = nsnull;
   }
 
@@ -1133,97 +1152,79 @@ void
 BasicLayerManager::SetRoot(Layer* aLayer)
 {
   NS_ASSERTION(aLayer, "Root can't be null");
   NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   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! */
+  Layer* child = aLayer->GetFirstChild();
+  if (!child) {
+    ToData(aLayer)->Paint(mTarget, aCallback, aCallbackData);
+  } else {
+    for (; child; child = child->GetNextSibling()) {
+      PaintLayer(child, aCallback, aCallbackData);
     }
   }
 
-  /* Only paint ourself, or our children - This optimization relies on this! */
-  if (!children) {
-    ToData(aLayer)->Paint(mTarget, aCallback, aCallbackData, aOpacity);
-  } 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());
-      }
-    }
+  if (needsGroup) {
+    mTarget->PopGroupToSource();
+    mTarget->Paint(aLayer->GetEffectiveOpacity());
   }
 
   if (needsSaveRestore) {
-    if (needsGroup && children > 1) {
-      mTarget->PopGroupToSource();
-      mTarget->Paint(aOpacity);
-    }
-
     mTarget->Restore();
+  } else {
+    mTarget->SetMatrix(savedMatrix);
   }
 }
 
 void
 BasicLayerManager::ClearCachedResources()
 {
   if (mRoot) {
     ClearLayer(mRoot);
@@ -1586,18 +1587,17 @@ public:
     if (mBackSurface) {
       BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackSurface);
     }
     MOZ_COUNT_DTOR(BasicShadowableImageLayer);
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
-                     void* aCallbackData,
-                     float aOpacity);
+                     void* aCallbackData);
 
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
   {
     aAttrs = ImageLayerAttributes(mFilter);
   }
 
   virtual Layer* AsLayer() { return this; }
   virtual ShadowableLayer* AsShadowableLayer() { return this; }
@@ -1620,21 +1620,20 @@ private:
   }
 
   nsRefPtr<gfxSharedImageSurface> mBackSurface;
 };
  
 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;
 
   if (oldSize != mSize) {
     NS_ASSERTION(oldSize == gfxIntSize(-1, -1), "video changed size?");
 
     if (mBackSurface) {
       BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackSurface);
@@ -1708,18 +1707,17 @@ public:
       BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackBuffer);
     }
     MOZ_COUNT_DTOR(BasicShadowableCanvasLayer);
   }
 
   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)
   {
     aAttrs = CanvasLayerAttributes(mFilter);
   }
 
   virtual Layer* AsLayer() { return this; }
   virtual ShadowableLayer* AsShadowableLayer() { return this; }
@@ -1772,20 +1770,19 @@ BasicShadowableCanvasLayer::Initialize(c
   BasicManager()->CreatedCanvasBuffer(BasicManager()->Hold(this),
                                       aData.mSize,
                                       tmpFrontBuffer);
 }
 
 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;
 
   // XXX this is yucky and slow.  It'd be nice to draw directly into
   // the shmem back buffer
   nsRefPtr<gfxContext> tmpCtx = new gfxContext(mBackBuffer);
   tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
   tmpCtx->DrawSurface(mSurface, gfxSize(mBounds.width, mBounds.height));
@@ -1892,18 +1889,17 @@ public:
 
     if (IsSurfaceDescriptorValid(mFrontBufferDescriptor)) {
       BasicManager()->ShadowLayerManager::DestroySharedSurface(&mFrontBufferDescriptor, mAllocator);
     }
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
-                     void* aCallbackData,
-                     float aOpacity);
+                     void* aCallbackData);
 
 private:
   BasicShadowLayerManager* BasicManager()
   {
     return static_cast<BasicShadowLayerManager*>(mManager);
   }
 
   ShadowThebesLayerBuffer mFrontBuffer;
@@ -1982,38 +1978,31 @@ BasicShadowThebesLayer::Swap(const Thebe
 
   *aReadOnlyFront = aNewFront;
   *aFrontUpdatedRegion = aUpdatedRegion;
 }
 
 void
 BasicShadowThebesLayer::Paint(gfxContext* aContext,
                               LayerManager::DrawThebesLayerCallback aCallback,
-                              void* aCallbackData,
-                              float aOpacity)
+                              void* aCallbackData)
 {
   NS_ASSERTION(BasicManager()->InDrawing(),
                "Can only draw in drawing phase");
   NS_ASSERTION(BasicManager()->IsRetained(),
                "ShadowThebesLayer makes no sense without retained mode");
 
   if (!mFrontBuffer.GetBuffer()) {
     return;
   }
 
   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 {
   template<class Container>
   friend void ContainerInsertAfter(Layer* aChild, Layer* aAfter, Container* aContainer);
   template<class Container>
   friend void ContainerRemoveChild(Layer* aChild, Container* aContainer);
 
@@ -2031,16 +2020,35 @@ public:
 
     MOZ_COUNT_DTOR(BasicShadowContainerLayer);
   }
 
   virtual void InsertAfter(Layer* aChild, Layer* aAfter)
   { 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 {
 public:
   BasicShadowImageLayer(BasicShadowLayerManager* aLayerManager) :
     ShadowImageLayer(aLayerManager, static_cast<BasicImplData*>(this))
   {
     MOZ_COUNT_CTOR(BasicShadowImageLayer);
@@ -2066,18 +2074,17 @@ public:
     if (mFrontSurface) {
       BasicManager()->ShadowLayerManager::DestroySharedSurface(mFrontSurface, mAllocator);
     }
     mFrontSurface = nsnull;
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
-                     void* aCallbackData,
-                     float aOpacity);
+                     void* aCallbackData);
 
 protected:
   BasicShadowLayerManager* BasicManager()
   {
     return static_cast<BasicShadowLayerManager*>(mManager);
   }
 
   // XXX ShmemImage?
@@ -2100,26 +2107,25 @@ BasicShadowImageLayer::Swap(gfxSharedIma
   already_AddRefed<gfxSharedImageSurface> tmp = mFrontSurface.forget();
   mFrontSurface = newFront;
   return tmp;
 }
 
 void
 BasicShadowImageLayer::Paint(gfxContext* aContext,
                              LayerManager::DrawThebesLayerCallback aCallback,
-                             void* aCallbackData,
-                             float aOpacity)
+                             void* aCallbackData)
 {
   if (!mFrontSurface) {
     return;
   }
 
   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,
                               BasicImplData
 {
 public:
   BasicShadowColorLayer(BasicShadowLayerManager* aLayerManager) :
     ShadowColorLayer(aLayerManager, static_cast<BasicImplData*>(this))
@@ -2128,20 +2134,19 @@ public:
   }
   virtual ~BasicShadowColorLayer()
   {
     MOZ_COUNT_DTOR(BasicShadowColorLayer);
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
-                     void* aCallbackData,
-                     float aOpacity)
+                     void* aCallbackData)
   {
-    BasicColorLayer::PaintColorTo(mColor, aOpacity, aContext);
+    BasicColorLayer::PaintColorTo(mColor, GetEffectiveOpacity(), aContext);
   }
 };
 
 class BasicShadowCanvasLayer : public ShadowCanvasLayer,
                                BasicImplData
 {
 public:
   BasicShadowCanvasLayer(BasicShadowLayerManager* aLayerManager) :
@@ -2173,27 +2178,25 @@ public:
     if (mFrontSurface) {
       BasicManager()->ShadowLayerManager::DestroySharedSurface(mFrontSurface, mAllocator);
     }
     mFrontSurface = nsnull;
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
-                     void* aCallbackData,
-                     float aOpacity);
+                     void* aCallbackData);
 
 private:
   BasicShadowLayerManager* BasicManager()
   {
     return static_cast<BasicShadowLayerManager*>(mManager);
   }
 
   nsRefPtr<gfxSharedImageSurface> mFrontSurface;
-  nsIntRect mBounds;
 };
 
 
 void
 BasicShadowCanvasLayer::Initialize(const Data& aData)
 {
   NS_ASSERTION(mFrontSurface == nsnull,
                "BasicCanvasLayer::Initialize called twice!");
@@ -2209,34 +2212,35 @@ BasicShadowCanvasLayer::Swap(gfxSharedIm
   already_AddRefed<gfxSharedImageSurface> tmp = mFrontSurface.forget();
   mFrontSurface = newFront;
   return tmp;
 }
 
 void
 BasicShadowCanvasLayer::Paint(gfxContext* aContext,
                               LayerManager::DrawThebesLayerCallback aCallback,
-                              void* aCallbackData,
-                              float aOpacity)
+                              void* aCallbackData)
 {
   NS_ASSERTION(BasicManager()->InDrawing(),
                "Can only draw in drawing phase");
 
   if (!mFrontSurface) {
     return;
   }
 
   nsRefPtr<gfxPattern> pat = new gfxPattern(mFrontSurface);
 
   pat->SetFilter(mFilter);
   pat->SetExtend(gfxPattern::EXTEND_PAD);
 
   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();
 }
 
 // Create a shadow layer (PLayerChild) for aLayer, if we're forwarding
 // our layer tree to a parent process.  Record the new layer creation
 // in the current open transaction as a side effect.
 template<typename CreatedMethod>
 static void
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -188,18 +188,17 @@ protected:
   };
   TransactionPhase mPhase;
 #endif
 
 private:
   // Paints aLayer to mTarget.
   void PaintLayer(Layer* aLayer,
                   DrawThebesLayerCallback aCallback,
-                  void* aCallbackData,
-                  float aOpacity);
+                  void* aCallbackData);
 
   // 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,
--- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp
@@ -197,27 +197,25 @@ CanvasLayerD3D10::Updated(const nsIntRec
 
 Layer*
 CanvasLayerD3D10::GetLayer()
 {
   return this;
 }
 
 void
-CanvasLayerD3D10::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
+CanvasLayerD3D10::RenderLayer()
 {
   if (!mTexture) {
     return;
   }
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
 
-  gfx3DMatrix transform = mTransform * aTransform;
-  effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform._11, 0, 64);
-  effect()->GetVariableByName("fLayerOpacity")->AsScalar()->SetFloat(GetOpacity() * aOpacity);
+  SetEffectTransformAndOpacity();
 
   ID3D10EffectTechnique *technique;
 
   if (mDataIsPremultiplied) {
     if (mSurface && mSurface->GetContentType() == gfxASurface::CONTENT_COLOR) {
       if (mFilter == gfxPattern::FILTER_NEAREST) {
         technique = effect()->GetTechniqueByName("RenderRGBLayerPremulPoint");
       } else {
--- a/gfx/layers/d3d10/CanvasLayerD3D10.h
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.h
@@ -48,45 +48,41 @@ namespace layers {
 
 class THEBES_API CanvasLayerD3D10 : public CanvasLayer,
                                     public LayerD3D10
 {
 public:
   CanvasLayerD3D10(LayerManagerD3D10 *aManager)
     : CanvasLayer(aManager, NULL),
       LayerD3D10(aManager),
-      mTexture(0),
       mDataIsPremultiplied(PR_FALSE),
       mNeedsYFlip(PR_FALSE)
   {
       mImplData = static_cast<LayerD3D10*>(this);
   }
 
   ~CanvasLayerD3D10();
 
   // CanvasLayer implementation
   virtual void Initialize(const Data& aData);
   virtual void Updated(const nsIntRect& aRect);
 
   // LayerD3D10 implementation
   virtual Layer* GetLayer();
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
+  virtual void RenderLayer();
 
 private:
   typedef mozilla::gl::GLContext GLContext;
 
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<GLContext> mGLContext;
-
-  PRUint32 mCanvasFramebuffer;
-
   nsRefPtr<ID3D10Texture2D> mTexture;
   nsRefPtr<ID3D10ShaderResourceView> mSRView;
 
-  nsIntRect mBounds;
+  PRUint32 mCanvasFramebuffer;
 
   PRPackedBool mDataIsPremultiplied;
   PRPackedBool mNeedsYFlip;
   PRPackedBool mIsD2DTexture;
 };
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/d3d10/ColorLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ColorLayerD3D10.cpp
@@ -50,28 +50,29 @@ ColorLayerD3D10::ColorLayerD3D10(LayerMa
 
 Layer*
 ColorLayerD3D10::GetLayer()
 {
   return this;
 }
 
 void
-ColorLayerD3D10::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
+ColorLayerD3D10::RenderLayer()
 {
   float color[4];
   // color is premultiplied, so we need to adjust all channels
-  color[0] = (float)(mColor.r * GetOpacity() * aOpacity);
-  color[1] = (float)(mColor.g * GetOpacity() * aOpacity);
-  color[2] = (float)(mColor.b * GetOpacity() * aOpacity);
-  color[3] = (float)(mColor.a * GetOpacity() * aOpacity);
+  float opacity = GetEffectiveOpacity();
+  color[0] = (float)(mColor.r * opacity);
+  color[1] = (float)(mColor.g * opacity);
+  color[2] = (float)(mColor.b * opacity);
+  color[3] = (float)(mColor.a * opacity);
 
-  gfx3DMatrix transform = mTransform * aTransform;
-
-  effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform._11, 0, 64);
+  const gfx3DMatrix& transform = GetEffectiveTransform();
+  void* raw = &const_cast<gfx3DMatrix&>(transform)._11;
+  effect()->GetVariableByName("mLayerTransform")->SetRawValue(raw, 0, 64);
   effect()->GetVariableByName("fLayerColor")->AsVector()->SetFloatVector(color);
 
   ID3D10EffectTechnique *technique;
   technique = effect()->GetTechniqueByName("RenderSolidColorLayer");
 
   nsIntRegionRectIterator iter(mVisibleRegion);
 
   const nsIntRect *iterRect;
--- a/gfx/layers/d3d10/ColorLayerD3D10.h
+++ b/gfx/layers/d3d10/ColorLayerD3D10.h
@@ -47,14 +47,14 @@ namespace layers {
 class ColorLayerD3D10 : public ColorLayer,
                         public LayerD3D10
 {
 public:
   ColorLayerD3D10(LayerManagerD3D10 *aManager);
 
   /* LayerD3D10 implementation */
   virtual Layer* GetLayer();
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
+  virtual void RenderLayer();
 };
 
 } /* layers */
 } /* mozilla */
 #endif /* GFX_THEBESLAYERD3D10_H */
--- a/gfx/layers/d3d10/ContainerLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.cpp
@@ -131,24 +131,23 @@ ContainerLayerD3D10::GetFirstChildD3D10(
 {
   if (!mFirstChild) {
     return nsnull;
   }
   return static_cast<LayerD3D10*>(mFirstChild->ImplData());
 }
 
 void
-ContainerLayerD3D10::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
+ContainerLayerD3D10::RenderLayer()
 {
   float renderTargetOffset[] = { 0, 0 };
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
-  float opacity = GetOpacity() * aOpacity;
-  gfx3DMatrix transform = mTransform * aTransform;
-  PRBool useIntermediate = ShouldUseIntermediate(aOpacity, transform);
+  float opacity = GetEffectiveOpacity();
+  PRBool useIntermediate = UseIntermediateSurface();
 
   nsRefPtr<ID3D10RenderTargetView> previousRTView;
   nsRefPtr<ID3D10Texture2D> renderTexture;
   nsRefPtr<ID3D10RenderTargetView> rtView;
   float previousRenderTargetOffset[2];
   nsIntSize previousViewportSize;
 
   gfx3DMatrix oldViewMatrix;
@@ -235,21 +234,17 @@ ContainerLayerD3D10::RenderLayer(float a
       d3drect.top = NS_MAX<PRInt32>(r.top, 0);
       d3drect.bottom = r.bottom;
       d3drect.right = r.right;
 
       device()->RSSetScissorRects(1, &d3drect);
     }
 
     // SetScissorRect
-    if (!useIntermediate) {
-      layerToRender->RenderLayer(opacity, transform);
-    } else {
-      layerToRender->RenderLayer(1.0f, gfx3DMatrix());
-    }
+    layerToRender->RenderLayer();
 
     if (clipRect || useIntermediate) {
       device()->RSSetScissorRects(1, &oldScissor);
     }
 
     Layer *nextSibling = layerToRender->GetLayer()->GetNextSibling();
     layerToRender = nextSibling ? static_cast<LayerD3D10*>(nextSibling->
                                                           ImplData())
@@ -258,18 +253,17 @@ ContainerLayerD3D10::RenderLayer(float a
 
   if (useIntermediate) {
     mD3DManager->SetViewport(previousViewportSize);
     ID3D10RenderTargetView *rtView = previousRTView;
     device()->OMSetRenderTargets(1, &rtView, NULL);
     effect()->GetVariableByName("vRenderTargetOffset")->
       SetRawValue(previousRenderTargetOffset, 0, 8);
 
-    effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform._11, 0, 64);
-    effect()->GetVariableByName("fLayerOpacity")->AsScalar()->SetFloat(opacity);
+    SetEffectTransformAndOpacity();
 
     ID3D10EffectTechnique *technique;
     technique = effect()->GetTechniqueByName("RenderRGBALayerPremul");
 
     effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
       ShaderConstantRectD3D10(
         (float)visibleRect.x,
         (float)visibleRect.y,
@@ -301,37 +295,10 @@ ContainerLayerD3D10::Validate()
 {
   Layer *layer = GetFirstChild();
   while (layer) {
     static_cast<LayerD3D10*>(layer->ImplData())->Validate();
     layer = layer->GetNextSibling();
   }
 }
 
-bool
-ContainerLayerD3D10::ShouldUseIntermediate(float aOpacity,
-                                           const gfx3DMatrix &aMatrix)
-{
-  if (aOpacity == 1.0f && aMatrix.IsIdentity()) {
-    return false;
-  }
-
-  Layer *firstChild = GetFirstChild();
-
-  if (!firstChild || (!firstChild->GetNextSibling() &&
-      !firstChild->GetClipRect())) {
-    // If we forward our transform to a child without using an intermediate, we
-    // need to be sure that child does not have a clip rect since the clip rect
-    // needs to be applied after its transform.
-    return false;
-  }
-
-  if (aMatrix.IsIdentity() && (!firstChild || !firstChild->GetNextSibling())) {
-    // If there's no transforms applied and a single child, opacity can always
-    // be forwarded to our only child.
-    return false;
-  }
-
-  return true;
-}
-
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/d3d10/ContainerLayerD3D10.h
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.h
@@ -58,21 +58,23 @@ public:
 
   virtual void RemoveChild(Layer* aChild);
 
   /* LayerD3D10 implementation */
   virtual Layer* GetLayer();
 
   virtual LayerD3D10* GetFirstChildD3D10();
 
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
+  virtual void RenderLayer();
   virtual void Validate();
 
   virtual void LayerManagerDestroyed();
 
-private:
-  bool ShouldUseIntermediate(float aOpacity, const gfx3DMatrix &aTransform);
+  virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
+  {
+    DefaultComputeEffectiveTransforms(aTransformToSurface);
+  }
 };
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_CONTAINERLAYERD3D10_H */
--- a/gfx/layers/d3d10/ImageLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ImageLayerD3D10.cpp
@@ -140,28 +140,25 @@ ImageContainerD3D10::SetLayerManager(Lay
 
 Layer*
 ImageLayerD3D10::GetLayer()
 {
   return this;
 }
 
 void
-ImageLayerD3D10::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
+ImageLayerD3D10::RenderLayer()
 {
   if (!GetContainer()) {
     return;
   }
 
   nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
 
-
-  gfx3DMatrix transform = mTransform * aTransform;
-  effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform._11, 0, 64);
-  effect()->GetVariableByName("fLayerOpacity")->AsScalar()->SetFloat(GetOpacity() * aOpacity);
+  SetEffectTransformAndOpacity();
 
   ID3D10EffectTechnique *technique;
 
   if (image->GetFormat() == Image::PLANAR_YCBCR) {
     PlanarYCbCrImageD3D10 *yuvImage =
       static_cast<PlanarYCbCrImageD3D10*>(image.get());
 
     if (!yuvImage->HasData()) {
--- a/gfx/layers/d3d10/ImageLayerD3D10.h
+++ b/gfx/layers/d3d10/ImageLayerD3D10.h
@@ -83,17 +83,17 @@ public:
     , LayerD3D10(aManager)
   {
     mImplData = static_cast<LayerD3D10*>(this);
   }
 
   // LayerD3D10 Implementation
   virtual Layer* GetLayer();
 
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
+  virtual void RenderLayer();
 };
 
 class THEBES_API ImageD3D10
 {
 public:
   virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
 };
 
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -231,16 +231,21 @@ LayerManagerD3D10::BeginTransactionWithT
 }
 
 void
 LayerManagerD3D10::EndTransaction(DrawThebesLayerCallback aCallback,
                                   void* aCallbackData)
 {
   mCurrentCallbackInfo.Callback = aCallback;
   mCurrentCallbackInfo.CallbackData = aCallbackData;
+
+  // The results of our drawing always go directly into a pixel buffer,
+  // so we don't need to pass any global transform here.
+  mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
+
   Render();
   mCurrentCallbackInfo.Callback = nsnull;
   mCurrentCallbackInfo.CallbackData = nsnull;
   mTarget = nsnull;
 }
 
 already_AddRefed<ThebesLayer>
 LayerManagerD3D10::CreateThebesLayer()
@@ -457,17 +462,17 @@ LayerManagerD3D10::Render()
       r.bottom = (LONG)(clipRect->y + clipRect->height);
     } else {
       r.left = r.top = 0;
       r.right = rect.width;
       r.bottom = rect.height;
     }
     device()->RSSetScissorRects(1, &r);
 
-    static_cast<LayerD3D10*>(mRoot->ImplData())->RenderLayer(1, gfx3DMatrix());
+    static_cast<LayerD3D10*>(mRoot->ImplData())->RenderLayer();
   }
 
   if (mTarget) {
     PaintToTarget();
   } else {
     mSwapChain->Present(0, 0);
   }
 }
--- a/gfx/layers/d3d10/LayerManagerD3D10.h
+++ b/gfx/layers/d3d10/LayerManagerD3D10.h
@@ -186,28 +186,36 @@ public:
   virtual LayerD3D10 *GetFirstChildD3D10() { return nsnull; }
 
   void SetFirstChild(LayerD3D10 *aParent);
 
   virtual Layer* GetLayer() = 0;
 
   /**
    * This will render a child layer to whatever render target is currently
-   * active. aOpacity and aTransform will pass any 'carried' transformations
-   * and/or opacity from the parent. This allows the parent to avoid
-   * rendering to intermediate surfaces when possible.
+   * active.
    */
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform) = 0;
+  virtual void RenderLayer() = 0;
   virtual void Validate() {}
 
   ID3D10Device1 *device() const { return mD3DManager->device(); }
   ID3D10Effect *effect() const { return mD3DManager->effect(); }
 
   /* Called by the layer manager when it's destroyed */
   virtual void LayerManagerDestroyed() {}
+
+  void SetEffectTransformAndOpacity()
+  {
+    Layer* layer = GetLayer();
+    const gfx3DMatrix& transform = layer->GetEffectiveTransform();
+    void* raw = &const_cast<gfx3DMatrix&>(transform)._11;
+    effect()->GetVariableByName("mLayerTransform")->SetRawValue(raw, 0, 64);
+    effect()->GetVariableByName("fLayerOpacity")->AsScalar()->SetFloat(layer->GetEffectiveOpacity());
+  }
+
 protected:
   LayerManagerD3D10 *mD3DManager;
 };
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_LAYERMANAGERD3D9_H */
--- a/gfx/layers/d3d10/ThebesLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ThebesLayerD3D10.cpp
@@ -147,27 +147,25 @@ ThebesLayerD3D10::SetVisibleRegion(const
 
 void
 ThebesLayerD3D10::InvalidateRegion(const nsIntRegion &aRegion)
 {
   mValidRegion.Sub(mValidRegion, aRegion);
 }
 
 void
-ThebesLayerD3D10::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
+ThebesLayerD3D10::RenderLayer()
 {
   if (!mTexture) {
     return;
   }
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
 
-  gfx3DMatrix transform = mTransform * aTransform;
-  effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform._11, 0, 64);
-  effect()->GetVariableByName("fLayerOpacity")->AsScalar()->SetFloat(GetOpacity() * aOpacity);
+  SetEffectTransformAndOpacity();
 
   ID3D10EffectTechnique *technique;
   if (CanUseOpaqueSurface()) {
     technique = effect()->GetTechniqueByName("RenderRGBLayerPremul");
   } else {
     technique = effect()->GetTechniqueByName("RenderRGBALayerPremul");
   }
 
--- a/gfx/layers/d3d10/ThebesLayerD3D10.h
+++ b/gfx/layers/d3d10/ThebesLayerD3D10.h
@@ -54,17 +54,17 @@ public:
   /* Layer implementation */
   void SetVisibleRegion(const nsIntRegion& aRegion);
 
   /* ThebesLayer implementation */
   void InvalidateRegion(const nsIntRegion& aRegion);
 
   /* LayerD3D10 implementation */
   virtual Layer* GetLayer();
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
+  virtual void RenderLayer();
   virtual void Validate();
   virtual void LayerManagerDestroyed();
 
 private:
   /* Texture with our surface data */
   nsRefPtr<ID3D10Texture2D> mTexture;
 
   /* Shader resource view for our texture */
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -222,17 +222,17 @@ CanvasLayerD3D9::Updated(const nsIntRect
 
 Layer*
 CanvasLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
-CanvasLayerD3D9::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
+CanvasLayerD3D9::RenderLayer()
 {
   if (!mTexture) {
     Updated(mBounds);
   }
 
   /*
    * We flip the Y axis here, note we can only do this because we are in 
    * CULL_NONE mode!
@@ -241,26 +241,17 @@ CanvasLayerD3D9::RenderLayer(float aOpac
   ShaderConstantRect quad(0, 0, mBounds.width, mBounds.height);
   if (mNeedsYFlip) {
     quad.mHeight = (float)-mBounds.height;
     quad.mY = (float)mBounds.height;
   }
 
   device()->SetVertexShaderConstantF(CBvLayerQuad, quad, 1);
 
-  gfx3DMatrix transform = mTransform * aTransform;
-  device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
-
-  float opacity[4];
-  /*
-   * We always upload a 4 component float, but the shader will use only the
-   * first component since it's declared as a 'float'.
-   */
-  opacity[0] = GetOpacity();
-  device()->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1);
+  SetShaderTransformAndOpacity();
 
   mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);
 
   if (!mDataIsPremultiplied) {
     device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
     device()->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
   }
   device()->SetTexture(0, mTexture);
--- a/gfx/layers/d3d9/CanvasLayerD3D9.h
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.h
@@ -49,52 +49,48 @@ namespace layers {
 class THEBES_API CanvasLayerD3D9 :
   public CanvasLayer,
   public LayerD3D9
 {
 public:
   CanvasLayerD3D9(LayerManagerD3D9 *aManager)
     : CanvasLayer(aManager, NULL),
       LayerD3D9(aManager),
-      mTexture(0),
       mDataIsPremultiplied(PR_FALSE),
       mNeedsYFlip(PR_FALSE)
   {
       mImplData = static_cast<LayerD3D9*>(this);
       aManager->deviceManager()->mLayersWithResources.AppendElement(this);
   }
 
   ~CanvasLayerD3D9();
 
   // CanvasLayer implementation
   virtual void Initialize(const Data& aData);
   virtual void Updated(const nsIntRect& aRect);
 
   // LayerD3D9 implementation
   virtual Layer* GetLayer();
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
+  virtual void RenderLayer();
   virtual void CleanResources();
   virtual void LayerManagerDestroyed();
 
   void CreateTexture();
 
 protected:
   typedef mozilla::gl::GLContext GLContext;
 
-  // Indicates whether our texture was obtained through D2D interop.
-  bool mIsInteropTexture;
-
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<GLContext> mGLContext;
+  nsRefPtr<IDirect3DTexture9> mTexture;
 
   PRUint32 mCanvasFramebuffer;
 
-  nsRefPtr<IDirect3DTexture9> mTexture;
-
-  nsIntRect mBounds;
+  // Indicates whether our texture was obtained through D2D interop.
+  bool mIsInteropTexture;
 
   PRPackedBool mDataIsPremultiplied;
   PRPackedBool mNeedsYFlip;
 };
 
 } /* layers */
 } /* mozilla */
 #endif /* GFX_CANVASLAYERD3D9_H */
--- a/gfx/layers/d3d9/ColorLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ColorLayerD3D9.cpp
@@ -43,40 +43,41 @@ namespace layers {
 
 Layer*
 ColorLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
-ColorLayerD3D9::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
+ColorLayerD3D9::RenderLayer()
 {
   // XXX we might be able to improve performance by using
   // IDirect3DDevice9::Clear
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
 
   device()->SetVertexShaderConstantF(
     CBvLayerQuad,
     ShaderConstantRect(visibleRect.x,
                        visibleRect.y,
                        visibleRect.width,
                        visibleRect.height),
     1);
 
-  gfx3DMatrix transform = mTransform * aTransform;
+  const gfx3DMatrix& transform = GetEffectiveTransform();
   device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
 
   float color[4];
+  float opacity = GetEffectiveOpacity();
   // color is premultiplied, so we need to adjust all channels
-  color[0] = (float)(mColor.r * GetOpacity() * aOpacity);
-  color[1] = (float)(mColor.g * GetOpacity() * aOpacity);
-  color[2] = (float)(mColor.b * GetOpacity() * aOpacity);
-  color[3] = (float)(mColor.a * GetOpacity() * aOpacity);
+  color[0] = (float)(mColor.r * opacity);
+  color[1] = (float)(mColor.g * opacity);
+  color[2] = (float)(mColor.b * opacity);
+  color[3] = (float)(mColor.a * opacity);
 
   device()->SetPixelShaderConstantF(0, color, 1);
 
   mD3DManager->SetShaderMode(DeviceManagerD3D9::SOLIDCOLORLAYER);
 
   device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
 }
 
--- a/gfx/layers/d3d9/ColorLayerD3D9.h
+++ b/gfx/layers/d3d9/ColorLayerD3D9.h
@@ -53,15 +53,15 @@ public:
     , LayerD3D9(aManager)
   {
     mImplData = static_cast<LayerD3D9*>(this);
   }
 
   // LayerD3D9 Implementation
   virtual Layer* GetLayer();
 
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
+  virtual void RenderLayer();
 };
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_COLORLAYERD3D9_H */
--- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp
@@ -130,30 +130,27 @@ ContainerLayerD3D9::GetFirstChildD3D9()
 {
   if (!mFirstChild) {
     return nsnull;
   }
   return static_cast<LayerD3D9*>(mFirstChild->ImplData());
 }
 
 void
-ContainerLayerD3D9::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
+ContainerLayerD3D9::RenderLayer()
 {
-  float opacity = GetOpacity() * aOpacity;
   nsRefPtr<IDirect3DSurface9> previousRenderTarget;
   nsRefPtr<IDirect3DTexture9> renderTexture;
   float previousRenderTargetOffset[4];
   RECT oldClipRect;
   float renderTargetOffset[] = { 0, 0, 0, 0 };
   float oldViewMatrix[4][4];
 
-  gfx3DMatrix transform = mTransform * aTransform;
-
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
-  PRBool useIntermediate = ShouldUseIntermediate(opacity, transform);
+  PRBool useIntermediate = UseIntermediateSurface();
 
   if (useIntermediate) {
     device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
     device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
                             D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
                             D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
                             NULL);
     nsRefPtr<IDirect3DSurface9> renderSurface;
@@ -218,21 +215,17 @@ ContainerLayerD3D9::RenderLayer(float aO
         r.top = NS_MAX<LONG>(0, r.top);
       }
       r.bottom = NS_MIN<LONG>(r.bottom, desc.Height);
       r.right = NS_MIN<LONG>(r.right, desc.Width);
 
       device()->SetScissorRect(&r);
     }
 
-    if (!useIntermediate) {
-      layerToRender->RenderLayer(opacity, transform);
-    } else {
-      layerToRender->RenderLayer(1.0, gfx3DMatrix());
-    }
+    layerToRender->RenderLayer();
 
     if (clipRect || useIntermediate) {
       device()->SetScissorRect(&oldClipRect);
     }
 
     Layer *nextSibling = layerToRender->GetLayer()->GetNextSibling();
     layerToRender = nextSibling ? static_cast<LayerD3D9*>(nextSibling->
                                                           ImplData())
@@ -246,25 +239,17 @@ ContainerLayerD3D9::RenderLayer(float aO
 
     device()->SetVertexShaderConstantF(CBvLayerQuad,
                                        ShaderConstantRect(visibleRect.x,
                                                           visibleRect.y,
                                                           visibleRect.width,
                                                           visibleRect.height),
                                        1);
 
-    device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
-
-    float opacityVector[4];
-    /*
-     * We always upload a 4 component float, but the shader will use only the
-     * first component since it's declared as a 'float'.
-     */
-    opacityVector[0] = opacity;
-    device()->SetPixelShaderConstantF(CBfLayerOpacity, opacityVector, 1);
+    SetShaderTransformAndOpacity();
 
     mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);
 
     device()->SetTexture(0, renderTexture);
     device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
   }
 }
 
@@ -272,37 +257,10 @@ void
 ContainerLayerD3D9::LayerManagerDestroyed()
 {
   while (mFirstChild) {
     GetFirstChildD3D9()->LayerManagerDestroyed();
     RemoveChild(mFirstChild);
   }
 }
 
-bool
-ContainerLayerD3D9::ShouldUseIntermediate(float aOpacity,
-                                          const gfx3DMatrix &aMatrix)
-{
-  if (aOpacity == 1.0f && aMatrix.IsIdentity()) {
-    return false;
-  }
-
-  Layer *firstChild = GetFirstChild();
-
-  if (!firstChild || (!firstChild->GetNextSibling() &&
-      !firstChild->GetClipRect())) {
-    // If we forward our transform to a child without using an intermediate,
-    // we need to be sure that child does not have a clip rect, since its clip
-    // rect would be applied after our transform.
-    return false;
-  }
-
-  if (aMatrix.IsIdentity() && (!firstChild || !firstChild->GetNextSibling())) {
-    // If there's no transforms applied and a single child, opacity can always
-    // be forwarded to our only child.
-    return false;
-  }
-
-  return true;
-}
-
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/d3d9/ContainerLayerD3D9.h
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.h
@@ -60,21 +60,22 @@ public:
 
   /* LayerD3D9 implementation */
   Layer* GetLayer();
 
   LayerD3D9* GetFirstChildD3D9();
 
   PRBool IsEmpty();
 
-  void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
+  void RenderLayer();
 
   virtual void LayerManagerDestroyed();
 
-private:
-  bool ShouldUseIntermediate(float aOpacity,
-                             const gfx3DMatrix &aMatrix);
+  virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
+  {
+    DefaultComputeEffectiveTransforms(aTransformToSurface);
+  }
 };
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_CONTAINERLAYERD3D9_H */
--- a/gfx/layers/d3d9/ImageLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp
@@ -143,17 +143,17 @@ ImageContainerD3D9::SetLayerManager(Laye
 
 Layer*
 ImageLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
-ImageLayerD3D9::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
+ImageLayerD3D9::RenderLayer()
 {
   if (!GetContainer()) {
     return;
   }
 
   nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
 
   if (image->GetFormat() == Image::PLANAR_YCBCR) {
@@ -167,26 +167,17 @@ ImageLayerD3D9::RenderLayer(float aOpaci
 
     device()->SetVertexShaderConstantF(CBvLayerQuad,
                                        ShaderConstantRect(0,
                                                           0,
                                                           yuvImage->mSize.width,
                                                           yuvImage->mSize.height),
                                        1);
 
-    gfx3DMatrix transform = mTransform * aTransform;
-    device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
-
-    float opacity[4];
-    /*
-     * We always upload a 4 component float, but the shader will
-     * only use the the first component since it's declared as a 'float'.
-     */
-    opacity[0] = GetOpacity() * aOpacity;
-    device()->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1);
+    SetShaderTransformAndOpacity();
 
     mD3DManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER);
 
     /* 
      * Send 3d control data and metadata 
      */ 
     if (mD3DManager->Is3DEnabled() && mD3DManager->GetNv3DVUtils()) { 
       mD3DManager->GetNv3DVUtils()->SendNv3DVControl(STEREO_MODE_RIGHT_LEFT, true, FIREFOX_3DV_APP_HANDLE); 
@@ -216,26 +207,17 @@ ImageLayerD3D9::RenderLayer(float aOpaci
 
     device()->SetVertexShaderConstantF(CBvLayerQuad,
                                        ShaderConstantRect(0,
                                                           0,
                                                           cairoImage->mSize.width,
                                                           cairoImage->mSize.height),
                                        1);
 
-    gfx3DMatrix transform = mTransform * aTransform;
-    device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
-
-    float opacity[4];
-    /*
-     * We always upload a 4 component float, but the shader will
-     * only use the the first component since it's declared as a 'float'.
-     */
-    opacity[0] = GetOpacity() * aOpacity;
-    device()->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1);
+    SetShaderTransformAndOpacity();
 
     mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);
 
     device()->SetTexture(0, cairoImage->mTexture);
     device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
   }
 }
 
--- a/gfx/layers/d3d9/ImageLayerD3D9.h
+++ b/gfx/layers/d3d9/ImageLayerD3D9.h
@@ -82,17 +82,17 @@ public:
     , LayerD3D9(aManager)
   {
     mImplData = static_cast<LayerD3D9*>(this);
   }
 
   // LayerD3D9 Implementation
   virtual Layer* GetLayer();
 
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
+  virtual void RenderLayer();
 };
 
 class THEBES_API ImageD3D9
 {
 public:
   virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
 };
 
--- a/gfx/layers/d3d9/LayerManagerD3D9.cpp
+++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp
@@ -150,16 +150,21 @@ LayerManagerD3D9::EndConstruction()
 }
 
 void
 LayerManagerD3D9::EndTransaction(DrawThebesLayerCallback aCallback,
                                  void* aCallbackData)
 {
   mCurrentCallbackInfo.Callback = aCallback;
   mCurrentCallbackInfo.CallbackData = aCallbackData;
+
+  // The results of our drawing always go directly into a pixel buffer,
+  // so we don't need to pass any global transform here.
+  mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
+
   Render();
   /* Clean this out for sanity */
   mCurrentCallbackInfo.Callback = NULL;
   mCurrentCallbackInfo.CallbackData = NULL;
   // Clear mTarget, next transaction could have no target
   mTarget = NULL;
 }
 
@@ -293,17 +298,17 @@ LayerManagerD3D9::Render()
       r.bottom = (LONG)(clipRect->y + clipRect->height);
     } else {
       r.left = r.top = 0;
       r.right = rect.width;
       r.bottom = rect.height;
     }
     device()->SetScissorRect(&r);
 
-    static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer(1.0, gfx3DMatrix());
+    static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer();
   }
 
   device()->EndScene();
 
   if (!mTarget) {
     const nsIntRect *r;
     for (nsIntRegionRectIterator iter(mClippingRegion);
          (r = iter.Next()) != nsnull;) {
--- a/gfx/layers/d3d9/LayerManagerD3D9.h
+++ b/gfx/layers/d3d9/LayerManagerD3D9.h
@@ -246,31 +246,48 @@ public:
   LayerD3D9(LayerManagerD3D9 *aManager);
 
   virtual LayerD3D9 *GetFirstChildD3D9() { return nsnull; }
 
   void SetFirstChild(LayerD3D9 *aParent);
 
   virtual Layer* GetLayer() = 0;
 
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform) = 0;
+  virtual void RenderLayer() = 0;
 
+  /**
   /* This function may be used on device resets to clear all VRAM resources
    * that a layer might be using.
    */
   virtual void CleanResources() {}
 
   IDirect3DDevice9 *device() const { return mD3DManager->device(); }
 
   /* Called by the layer manager when it's destroyed */
   virtual void LayerManagerDestroyed() {}
 
   void ReportFailure(const nsACString &aMsg, HRESULT aCode) {
     return mD3DManager->ReportFailure(aMsg, aCode);
   }
+
+  void SetShaderTransformAndOpacity()
+  {
+    Layer* layer = GetLayer();
+    const gfx3DMatrix& transform = layer->GetEffectiveTransform();
+    device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
+
+    float opacity[4];
+    /*
+     * We always upload a 4 component float, but the shader will use only the
+     * first component since it's declared as a 'float'.
+     */
+    opacity[0] = layer->GetEffectiveOpacity();
+    device()->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1);
+  }
+
 protected:
   LayerManagerD3D9 *mD3DManager;
 };
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_LAYERMANAGERD3D9_H */
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -167,17 +167,17 @@ ThebesLayerD3D9::SetVisibleRegion(const 
 
 void
 ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
 {
   mValidRegion.Sub(mValidRegion, aRegion);
 }
 
 void
-ThebesLayerD3D9::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
+ThebesLayerD3D9::RenderLayer()
 {
   if (mVisibleRegion.IsEmpty()) {
     return;
   }
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
 
   // We differentiate between these formats since D3D9 will only allow us to
@@ -220,26 +220,17 @@ ThebesLayerD3D9::RenderLayer(float aOpac
     nsIntRegion region;
     region.Sub(mVisibleRegion, mValidRegion);
 
     DrawRegion(region);
 
     mValidRegion = mVisibleRegion;
   }
 
-  gfx3DMatrix transform = mTransform * aTransform;
-  device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
-
-  float opacity[4];
-  /*
-   * We always upload a 4 component float, but the shader will use only the
-   * first component since it's declared as a 'float'.
-   */
-  opacity[0] = GetOpacity() * aOpacity;
-  device()->SetPixelShaderConstantF(0, opacity, 1);
+  SetShaderTransformAndOpacity();
 
 #ifdef CAIRO_HAS_D2D_SURFACE
   if (mD2DSurface && CanUseOpaqueSurface()) {
     mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER);
   } else
 #endif
   mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);
 
--- a/gfx/layers/d3d9/ThebesLayerD3D9.h
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.h
@@ -56,17 +56,17 @@ public:
   void SetVisibleRegion(const nsIntRegion& aRegion);
 
   /* ThebesLayer implementation */
   void InvalidateRegion(const nsIntRegion& aRegion);
 
   /* LayerD3D9 implementation */
   Layer* GetLayer();
   virtual PRBool IsEmpty();
-  virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
+  virtual void RenderLayer();
   virtual void CleanResources();
   virtual void LayerManagerDestroyed();
 
 private:
   /*
    * D3D9 texture
    */
   nsRefPtr<IDirect3DTexture9> mTexture;
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -226,19 +226,17 @@ CanvasLayerOGL::Updated(const nsIntRect&
 
   // sanity
   NS_ASSERTION(mBounds.Contains(mUpdatedRect),
                "CanvasLayer: Updated rect bigger than bounds!");
 }
 
 void
 CanvasLayerOGL::RenderLayer(int aPreviousDestination,
-                            const nsIntPoint& aOffset,
-                            float aOpacity,
-                            const gfx3DMatrix& aMatrix)
+                            const nsIntPoint& aOffset)
 {
   mOGLManager->MakeCurrent();
 
   // XXX We're going to need a different program depending on if
   // mGLBufferIsPremultiplied is TRUE or not.  The RGBLayerProgram
   // assumes that it's true.
 
   ColorTextureLayerProgram *program = nsnull;
@@ -263,18 +261,18 @@ CanvasLayerOGL::RenderLayer(int aPreviou
   program =
     mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(),
                                       useGLContext != 0);
 
   ApplyFilter(mFilter);
 
   program->Activate();
   program->SetLayerQuadRect(mBounds);
-  program->SetLayerTransform(GetEffectiveTransform() * aMatrix);
-  program->SetLayerOpacity(GetOpacity() * aOpacity);
+  program->SetLayerTransform(GetEffectiveTransform());
+  program->SetLayerOpacity(GetEffectiveOpacity());
   program->SetRenderOffset(aOffset);
   program->SetTextureUnit(0);
 
   mOGLManager->BindAndDrawQuad(program, mNeedsYFlip ? true : false);
 
   DEBUG_GL_ERROR_CHECK(gl());
 
   if (useGLContext) {
@@ -349,34 +347,32 @@ ShadowCanvasLayerOGL::Destroy()
 Layer*
 ShadowCanvasLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
 ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                                  const nsIntPoint& aOffset,
-                                  float aOpacity,
-                                  const gfx3DMatrix& aMatrix)
+                                  const nsIntPoint& aOffset)
 {
   mOGLManager->MakeCurrent();
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
   ColorTextureLayerProgram *program =
     mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(),
                                       mTexImage->IsRGB());
 
   ApplyFilter(mFilter);
 
   program->Activate();
   program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize()));
-  program->SetLayerTransform(mTransform * aMatrix);
-  program->SetLayerOpacity(GetOpacity() * aOpacity);
+  program->SetLayerTransform(GetEffectiveTransform());
+  program->SetLayerOpacity(GetEffectiveOpacity());
   program->SetRenderOffset(aOffset);
   program->SetTextureUnit(0);
 
   mOGLManager->BindAndDrawQuad(program);
 
   DEBUG_GL_ERROR_CHECK(gl());
 }
 
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -66,28 +66,25 @@ public:
   // CanvasLayer implementation
   virtual void Initialize(const Data& aData);
   virtual void Updated(const nsIntRect& aRect);
 
   // LayerOGL implementation
   virtual void Destroy();
   virtual Layer* GetLayer() { return this; }
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix);
+                           const nsIntPoint& aOffset);
 
 protected:
   nsRefPtr<gfxASurface> mCanvasSurface;
   nsRefPtr<GLContext> mCanvasGLContext;
 
   void MakeTexture();
   GLuint mTexture;
 
-  nsIntRect mBounds;
   nsIntRect mUpdatedRect;
 
   PRPackedBool mGLBufferIsPremultiplied;
   PRPackedBool mNeedsYFlip;
 };
 
 #ifdef MOZ_IPC
 // NB: eventually we'll have separate shadow canvas2d and shadow
@@ -112,19 +109,17 @@ public:
   Swap(gfxSharedImageSurface* aNewFront);
 
   virtual void DestroyFrontBuffer();
 
   // LayerOGL impl
   void Destroy();
   Layer* GetLayer();
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix);
+                           const nsIntPoint& aOffset);
 
 private:
   nsRefPtr<TextureImage> mTexImage;
 
 
   // XXX FIXME holding to free
   nsRefPtr<gfxSharedImageSurface> mDeadweight;
 
--- a/gfx/layers/opengl/ColorLayerOGL.cpp
+++ b/gfx/layers/opengl/ColorLayerOGL.cpp
@@ -38,64 +38,59 @@
 
 #include "ColorLayerOGL.h"
 
 namespace mozilla {
 namespace layers {
 
 static void
 RenderColorLayer(ColorLayer* aLayer, LayerManagerOGL *aManager,
-                 const nsIntPoint& aOffset, float aOpacity,
-                 const gfx3DMatrix& aMatrix)
+                 const nsIntPoint& aOffset)
 {
   aManager->MakeCurrent();
 
   // XXX we might be able to improve performance by using glClear
 
   nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
   
   /* Multiply color by the layer opacity, as the shader
    * ignores layer opacity and expects a final color to
    * write to the color buffer.  This saves a needless
    * multiply in the fragment shader.
    */
-  float opacity = aLayer->GetOpacity() * aOpacity;
+  float opacity = aLayer->GetEffectiveOpacity();
   gfxRGBA color(aLayer->GetColor());
   color.r *= opacity;
   color.g *= opacity;
   color.b *= opacity;
   color.a *= opacity;
 
   SolidColorLayerProgram *program = aManager->GetColorLayerProgram();
   program->Activate();
   program->SetLayerQuadRect(visibleRect);
-  program->SetLayerTransform(aLayer->GetEffectiveTransform() * aMatrix);
+  program->SetLayerTransform(aLayer->GetEffectiveTransform());
   program->SetRenderOffset(aOffset);
   program->SetRenderColor(color);
 
   aManager->BindAndDrawQuad(program);
 
   DEBUG_GL_ERROR_CHECK(aManager->gl());
 }
 
 void
 ColorLayerOGL::RenderLayer(int,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix)
+                           const nsIntPoint& aOffset)
 {
-  return RenderColorLayer(this, mOGLManager, aOffset, aOpacity, aMatrix);
+  return RenderColorLayer(this, mOGLManager, aOffset);
 }
 
 #ifdef MOZ_IPC
 void
 ShadowColorLayerOGL::RenderLayer(int,
-                                 const nsIntPoint& aOffset,
-                                 float aOpacity,
-                                 const gfx3DMatrix& aMatrix)
+                                 const nsIntPoint& aOffset)
 {
-  return RenderColorLayer(this, mOGLManager, aOffset, aOpacity, aMatrix);
+  return RenderColorLayer(this, mOGLManager, aOffset);
 }
 #endif  // MOZ_IPC
 
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ColorLayerOGL.h
+++ b/gfx/layers/opengl/ColorLayerOGL.h
@@ -61,19 +61,17 @@ public:
   ~ColorLayerOGL() { Destroy(); }
 
   // LayerOGL Implementation
   virtual Layer* GetLayer() { return this; }
 
   virtual void Destroy() { mDestroyed = PR_TRUE; }
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix);
+                           const nsIntPoint& aOffset);
 };
 
 #ifdef MOZ_IPC
 class ShadowColorLayerOGL : public ShadowColorLayer,
                             public LayerOGL
 {
 public:
   ShadowColorLayerOGL(LayerManagerOGL *aManager)
@@ -85,17 +83,15 @@ public:
   ~ShadowColorLayerOGL() { Destroy(); }
 
   // LayerOGL Implementation
   virtual Layer* GetLayer() { return this; }
 
   virtual void Destroy() { mDestroyed = PR_TRUE; }
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix);
+                           const nsIntPoint& aOffset);
 };
 #endif  // MOZ_IPC
 
 } /* layers */
 } /* mozilla */
 #endif /* GFX_COLORLAYEROGL_H */
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -116,75 +116,37 @@ ContainerDestroy(Container* aContainer)
       aContainer->GetFirstChildOGL()->Destroy();
       aContainer->RemoveChild(aContainer->mFirstChild);
     }
     aContainer->mDestroyed = PR_TRUE;
   }
 }
 
 template<class Container>
-static bool
-ShouldUseIntermediate(Container* aContainer,
-                      float aOpacity, 
-                      const gfx3DMatrix& aMatrix)
-{
-  if (aOpacity == 1.0f && aMatrix.IsIdentity()) {
-    return false;
-  }
-
-  Layer *firstChild = aContainer->GetFirstChild();
-  if (!firstChild) {
-    return false;
-  }
-
-  /* We always require an intermediate layer for opacity */
-  if (aOpacity != 1.0f) {
-    return true;
-  }
-
-  do {
-    const nsIntRect *clipRect = firstChild->GetClipRect();
-    /* We can't (easily) forward our transform to children with a non-emtpy clip 
-     * rect since it would need to be adjusted for the transform.
-     * TODO: This is easily solvable for translation/scaling transforms.
-     */
-    if (clipRect && !clipRect->IsEmpty() && !firstChild->GetVisibleRegion().IsEmpty()) {
-      return true;
-    }
-
-  } while ((firstChild = firstChild->GetNextSibling()) != nsnull);
-
-  /* All children have no clip or are invisible */
-  return false;
-}
-
-template<class Container>
 static void
 ContainerRender(Container* aContainer,
                 int aPreviousFrameBuffer,
                 const nsIntPoint& aOffset,
-                float aOpacity,
-                const gfx3DMatrix& aMatrix,
                 LayerManagerOGL* aManager)
 {
   /**
    * Setup our temporary texture for rendering the contents of this container.
    */
   GLuint containerSurface;
   GLuint frameBuffer;
 
   nsIntPoint childOffset(aOffset);
   nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
-  const gfx3DMatrix& transform = aContainer->GetEffectiveTransform() * aMatrix;
 
   nsIntRect cachedScissor = aContainer->gl()->ScissorRect();
   aContainer->gl()->PushScissorRect();
 
-  float opacity = aContainer->GetOpacity() * aOpacity;
-  bool needsFramebuffer = ShouldUseIntermediate(aContainer, opacity, transform);
+  float opacity = aContainer->GetEffectiveOpacity();
+  const gfx3DMatrix& transform = aContainer->GetEffectiveTransform();
+  bool needsFramebuffer = aContainer->UseIntermediateSurface();
   if (needsFramebuffer) {
     aManager->CreateFBOWithTexture(visibleRect.width,
                                    visibleRect.height,
                                    &frameBuffer,
                                    &containerSurface);
     childOffset.x = visibleRect.x;
     childOffset.y = visibleRect.y;
 
@@ -232,21 +194,17 @@ ContainerRender(Container* aContainer,
                                  scissorRect.height);
     } else {
       aContainer->gl()->fScissor(cachedScissor.x, 
                                  cachedScissor.y, 
                                  cachedScissor.width, 
                                  cachedScissor.height);
     }
 
-    if (!needsFramebuffer) {
-      layerToRender->RenderLayer(frameBuffer, childOffset, opacity, transform);
-    } else {
-      layerToRender->RenderLayer(frameBuffer, childOffset, 1.0, gfx3DMatrix());
-     }
+    layerToRender->RenderLayer(frameBuffer, childOffset);
 
     Layer *nextSibling = layerToRender->GetLayer()->GetNextSibling();
     layerToRender = nextSibling ? static_cast<LayerOGL*>(nextSibling->
                                                          ImplData())
                                 : nsnull;
   }
 
   aContainer->gl()->PopScissorRect();
@@ -331,21 +289,19 @@ ContainerLayerOGL::GetFirstChildOGL()
   if (!mFirstChild) {
     return nsnull;
   }
   return static_cast<LayerOGL*>(mFirstChild->ImplData());
 }
 
 void
 ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                               const nsIntPoint& aOffset,
-                               float aOpacity,
-                               const gfx3DMatrix& aMatrix)
+                               const nsIntPoint& aOffset)
 {
-  ContainerRender(this, aPreviousFrameBuffer, aOffset, aOpacity, aMatrix, mOGLManager);
+  ContainerRender(this, aPreviousFrameBuffer, aOffset, mOGLManager);
 }
 
 
 #ifdef MOZ_IPC
 
 ShadowContainerLayerOGL::ShadowContainerLayerOGL(LayerManagerOGL *aManager)
   : ShadowContainerLayer(aManager, NULL)
   , LayerOGL(aManager)
@@ -382,20 +338,18 @@ ShadowContainerLayerOGL::GetFirstChildOG
   if (!mFirstChild) {
     return nsnull;
    }
   return static_cast<LayerOGL*>(mFirstChild->ImplData());
 }
  
 void
 ShadowContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                                     const nsIntPoint& aOffset,
-                                     float aOpacity,
-                                     const gfx3DMatrix& aMatrix)
+                                     const nsIntPoint& aOffset)
 {
-  ContainerRender(this, aPreviousFrameBuffer, aOffset, aOpacity, aMatrix, mOGLManager);
+  ContainerRender(this, aPreviousFrameBuffer, aOffset, mOGLManager);
 }
 
 #endif  // MOZ_IPC
 
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ContainerLayerOGL.h
+++ b/gfx/layers/opengl/ContainerLayerOGL.h
@@ -55,39 +55,31 @@ template<class Container>
 static void ContainerRemoveChild(Container* aContainer, Layer* aChild);
 template<class Container>
 static void ContainerDestroy(Container* aContainer);
 template<class Container>
 static void ContainerRender(Container* aContainer,
                             int aPreviousFrameBuffer,
                             const nsIntPoint& aOffset,
                             LayerManagerOGL* aManager);
-template<class Container>
-static bool ShouldUseIntermediate(Container* aContainer,
-                                  float aOpacity,
-                                  const gfx3DMatrix& aMatrix);
 
-class ContainerLayerOGL : public ContainerLayer, 
+class ContainerLayerOGL : public ContainerLayer,
                           public LayerOGL
 {
   template<class Container>
   friend void ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter);
   template<class Container>
   friend void ContainerRemoveChild(Container* aContainer, Layer* aChild);
   template<class Container>
   friend void ContainerDestroy(Container* aContainer);
   template<class Container>
   friend void ContainerRender(Container* aContainer,
                               int aPreviousFrameBuffer,
                               const nsIntPoint& aOffset,
                               LayerManagerOGL* aManager);
-  template<class Container>
-  friend bool ShouldUseIntermediate(Container* aContainer,
-                                    float aOpacity,
-                                    const gfx3DMatrix& aMatrix);
 
 public:
   ContainerLayerOGL(LayerManagerOGL *aManager);
   ~ContainerLayerOGL();
 
   void InsertAfter(Layer* aChild, Layer* aAfter);
 
   void RemoveChild(Layer* aChild);
@@ -95,19 +87,22 @@ public:
   /** LayerOGL implementation */
   Layer* GetLayer() { return this; }
 
   void Destroy();
 
   LayerOGL* GetFirstChildOGL();
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix);
+                           const nsIntPoint& aOffset);
+
+  virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
+  {
+    DefaultComputeEffectiveTransforms(aTransformToSurface);
+  }
 };
 
 #ifdef MOZ_IPC
 class ShadowContainerLayerOGL : public ShadowContainerLayer,
                                 public LayerOGL
 {
   template<class Container>
   friend void ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter);
@@ -115,20 +110,16 @@ class ShadowContainerLayerOGL : public S
   friend void ContainerRemoveChild(Container* aContainer, Layer* aChild);
   template<class Container>
   friend void ContainerDestroy(Container* aContainer);
   template<class Container>
   friend void ContainerRender(Container* aContainer,
                               int aPreviousFrameBuffer,
                               const nsIntPoint& aOffset,
                               LayerManagerOGL* aManager);
-  template<class Container>
-  friend bool ShouldUseIntermediate(Container* aContainer,
-                                    float aOpacity,
-                                    const gfx3DMatrix& aMatrix);
 
 public:
   ShadowContainerLayerOGL(LayerManagerOGL *aManager);
   ~ShadowContainerLayerOGL();
 
   void InsertAfter(Layer* aChild, Layer* aAfter);
 
   void RemoveChild(Layer* aChild);
@@ -136,18 +127,21 @@ public:
   // LayerOGL Implementation
   virtual Layer* GetLayer() { return this; }
 
   virtual void Destroy();
 
   LayerOGL* GetFirstChildOGL();
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix);
+                           const nsIntPoint& aOffset);
+
+  virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
+  {
+    DefaultComputeEffectiveTransforms(aTransformToSurface);
+  }
 };
 #endif  // MOZ_IPC
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_CONTAINERLAYEROGL_H */
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -366,19 +366,17 @@ ImageContainerOGL::SetLayerManager(Layer
 Layer*
 ImageLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
 ImageLayerOGL::RenderLayer(int,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix)
+                           const nsIntPoint& aOffset)
 {
   if (!GetContainer())
     return;
 
   mOGLManager->MakeCurrent();
 
   nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
 
@@ -407,18 +405,18 @@ ImageLayerOGL::RenderLayer(int,
     ApplyFilter(mFilter);
 
     YCbCrTextureLayerProgram *program = mOGLManager->GetYCbCrLayerProgram();
 
     program->Activate();
     program->SetLayerQuadRect(nsIntRect(0, 0,
                                         yuvImage->mSize.width,
                                         yuvImage->mSize.height));
-    program->SetLayerTransform(GetEffectiveTransform() * aMatrix);
-    program->SetLayerOpacity(GetOpacity() * aOpacity);
+    program->SetLayerTransform(GetEffectiveTransform());
+    program->SetLayerOpacity(GetEffectiveOpacity());
     program->SetRenderOffset(aOffset);
     program->SetYCbCrTextureUnits(0, 1, 2);
 
     DEBUG_GL_ERROR_CHECK(gl());
 
     mOGLManager->BindAndDrawQuad(program);
 
     // We shouldn't need to do this, but do it anyway just in case
@@ -436,18 +434,18 @@ ImageLayerOGL::RenderLayer(int,
                                         cairoImage->mASurfaceAsGLContext != 0);
 
     ApplyFilter(mFilter);
 
     program->Activate();
     program->SetLayerQuadRect(nsIntRect(0, 0,
                                         cairoImage->mSize.width,
                                         cairoImage->mSize.height));
-    program->SetLayerTransform(GetEffectiveTransform() * aMatrix);
-    program->SetLayerOpacity(GetOpacity() * aOpacity);
+    program->SetLayerTransform(GetEffectiveTransform());
+    program->SetLayerOpacity(GetEffectiveOpacity());
     program->SetRenderOffset(aOffset);
     program->SetTextureUnit(0);
 
     mOGLManager->BindAndDrawQuad(program);
   }
 
   DEBUG_GL_ERROR_CHECK(gl());
 }
@@ -784,34 +782,32 @@ ShadowImageLayerOGL::Destroy()
 Layer*
 ShadowImageLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
 ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                                 const nsIntPoint& aOffset,
-                                 float aOpacity,
-                                 const gfx3DMatrix& aMatrix)
+                                 const nsIntPoint& aOffset)
 {
   mOGLManager->MakeCurrent();
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
   ColorTextureLayerProgram *program =
     mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(),
                                       mTexImage->IsRGB());
 
   ApplyFilter(mFilter);
 
   program->Activate();
   program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize()));
-  program->SetLayerTransform(mTransform * aMatrix);
-  program->SetLayerOpacity(GetOpacity() * aOpacity);
+  program->SetLayerTransform(GetEffectiveTransform());
+  program->SetLayerOpacity(GetEffectiveOpacity());
   program->SetRenderOffset(aOffset);
   program->SetTextureUnit(0);
 
   mOGLManager->BindAndDrawQuad(program);
 
   DEBUG_GL_ERROR_CHECK(gl());
 }
 
--- a/gfx/layers/opengl/ImageLayerOGL.h
+++ b/gfx/layers/opengl/ImageLayerOGL.h
@@ -179,19 +179,17 @@ public:
   }
   ~ImageLayerOGL() { Destroy(); }
 
   // LayerOGL Implementation
   virtual void Destroy() { mDestroyed = PR_TRUE; }
   virtual Layer* GetLayer();
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix);
+                           const nsIntPoint& aOffset);
 };
 
 class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage
 {
   typedef mozilla::gl::GLContext GLContext;
 
 public:
   PlanarYCbCrImageOGL(LayerManagerOGL *aManager,
@@ -259,19 +257,17 @@ public:
   virtual void DestroyFrontBuffer();
 
   // LayerOGL impl
   virtual void Destroy();
 
   virtual Layer* GetLayer();
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix);
+                           const nsIntPoint& aOffset);
 
 private:
   nsRefPtr<TextureImage> mTexImage;
 
 
   // XXX FIXME holding to free
   nsRefPtr<gfxSharedImageSurface> mDeadweight;
 
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -399,16 +399,20 @@ LayerManagerOGL::EndTransaction(DrawTheb
   Log();
 #endif
 
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
 
+  // The results of our drawing always go directly into a pixel buffer,
+  // so we don't need to pass any global transform here.
+  mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
+
   mThebesLayerCallback = aCallback;
   mThebesLayerCallbackData = aCallbackData;
 
   // NULL callback means "non-painting transaction"
   if (aCallback) {
     Render();
   }
 
@@ -586,17 +590,17 @@ LayerManagerOGL::Render()
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
 
   // Render our layers.
   RootLayer()->RenderLayer(mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO,
-                           nsIntPoint(0, 0), 1.0, gfx3DMatrix());
+                           nsIntPoint(0, 0));
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   if (mTarget) {
     CopyToTarget();
     return;
   }
 
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -457,19 +457,17 @@ public:
   /* Do NOT call this from the generic LayerOGL destructor.  Only from the
    * concrete class destructor
    */
   virtual void Destroy() = 0;
 
   virtual Layer* GetLayer() = 0;
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix) = 0;
+                           const nsIntPoint& aOffset) = 0;
 
   typedef mozilla::gl::GLContext GLContext;
 
   LayerManagerOGL* OGLManager() const { return mOGLManager; }
   GLContext *gl() const { return mOGLManager->gl(); }
 
   void ApplyFilter(gfxPattern::GraphicsFilter aFilter);
 protected:
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -128,18 +128,17 @@ public:
   ThebesLayerBufferOGL(ThebesLayer* aLayer, LayerOGL* aOGLLayer)
     : mLayer(aLayer)
     , mOGLLayer(aOGLLayer)
   {}
   virtual ~ThebesLayerBufferOGL() {}
 
   virtual PaintState BeginPaint(ContentType aContentType) = 0;
 
-  void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager,
-                float aOpacity, const gfx3DMatrix& aMatrix);
+  void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager);
 
   nsIntSize GetSize() {
     if (mTexImage)
       return mTexImage->GetSize();
     return nsIntSize(0, 0);
   }
 
 protected:
@@ -149,19 +148,17 @@ protected:
 
   ThebesLayer* mLayer;
   LayerOGL* mOGLLayer;
   nsRefPtr<TextureImage> mTexImage;
 };
 
 void
 ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
-                               LayerManagerOGL* aManager,
-                               float aOpacity,
-                               const gfx3DMatrix& aMatrix)
+                               LayerManagerOGL* aManager)
 {
   if (!mTexImage)
     return;
 
   // Note BGR: Cairo's image surfaces are always in what
   // OpenGL and our shaders consider BGR format.
   ColorTextureLayerProgram *program =
     aManager->GetBasicLayerProgram(mLayer->CanUseOpaqueSurface(),
@@ -176,18 +173,18 @@ ThebesLayerBufferOGL::RenderTo(const nsI
   float xres = mLayer->GetXResolution();
   float yres = mLayer->GetYResolution();
 
   nsIntRegionRectIterator iter(mLayer->GetEffectiveVisibleRegion());
   while (const nsIntRect *iterRect = iter.Next()) {
     nsIntRect quadRect = *iterRect;
     program->Activate();
     program->SetLayerQuadRect(quadRect);
-    program->SetLayerOpacity(mLayer->GetOpacity() * aOpacity);
-    program->SetLayerTransform(mLayer->GetEffectiveTransform() * aMatrix);
+    program->SetLayerOpacity(mLayer->GetEffectiveOpacity());
+    program->SetLayerTransform(mLayer->GetEffectiveTransform());
     program->SetRenderOffset(aOffset);
     program->SetTextureUnit(0);
     DEBUG_GL_ERROR_CHECK(gl());
 
     quadRect.MoveBy(-GetOriginOffset());
 
     // The buffer rect and rotation are resolution-neutral; with a
     // non-1.0 resolution, only the texture size is scaled by the
@@ -507,19 +504,17 @@ ThebesLayerOGL::SetVisibleRegion(const n
 void
 ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
 {
   mValidRegion.Sub(mValidRegion, aRegion);
 }
 
 void
 ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                            const nsIntPoint& aOffset,
-                            float aOpacity,
-                            const gfx3DMatrix& aMatrix)
+                            const nsIntPoint& aOffset)
 {
   if (!mBuffer && !CreateSurface()) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
   mOGLManager->MakeCurrent();
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
@@ -539,17 +534,17 @@ ThebesLayerOGL::RenderLayer(int aPreviou
     callback(this, state.mContext, state.mRegionToDraw,
              state.mRegionToInvalidate, callbackData);
     mValidRegion.Or(mValidRegion, state.mRegionToDraw);
   }
 
   DEBUG_GL_ERROR_CHECK(gl());
 
   gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
-  mBuffer->RenderTo(aOffset, mOGLManager, aOpacity, aMatrix);
+  mBuffer->RenderTo(aOffset, mOGLManager);
   DEBUG_GL_ERROR_CHECK(gl());
 }
 
 Layer*
 ThebesLayerOGL::GetLayer()
 {
   return this;
 }
@@ -699,31 +694,29 @@ ShadowThebesLayerOGL::GetLayer()
 PRBool
 ShadowThebesLayerOGL::IsEmpty()
 {
   return !mBuffer;
 }
 
 void
 ShadowThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                                  const nsIntPoint& aOffset,
-                                  float aOpacity,
-                                  const gfx3DMatrix& aMatrix)
+                                  const nsIntPoint& aOffset)
 {
   if (!mBuffer) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
   mOGLManager->MakeCurrent();
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   DEBUG_GL_ERROR_CHECK(gl());
 
   gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
-  mBuffer->RenderTo(aOffset, mOGLManager, aOpacity, aMatrix);
+  mBuffer->RenderTo(aOffset, mOGLManager);
   DEBUG_GL_ERROR_CHECK(gl());
 }
 
 #endif  // MOZ_IPC
 
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ThebesLayerOGL.h
+++ b/gfx/layers/opengl/ThebesLayerOGL.h
@@ -71,19 +71,17 @@ public:
   /** ThebesLayer implementation */
   void InvalidateRegion(const nsIntRegion& aRegion);
 
   /** LayerOGL implementation */
   void Destroy();
   Layer* GetLayer();
   virtual PRBool IsEmpty();
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix);
+                           const nsIntPoint& aOffset);
 
 private:
   friend class BasicBufferOGL;
 
   PRBool CreateSurface();
 
   nsRefPtr<Buffer> mBuffer;
 };
@@ -107,19 +105,17 @@ public:
        OptionalThebesBuffer* aReadOnlyFront, nsIntRegion* aFrontUpdatedRegion);
   virtual void DestroyFrontBuffer();
 
   // LayerOGL impl
   void Destroy();
   Layer* GetLayer();
   virtual PRBool IsEmpty();
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset,
-                           float aOpacity,
-                           const gfx3DMatrix& aMatrix);
+                           const nsIntPoint& aOffset);
 
 private:
   nsRefPtr<ShadowBufferOGL> mBuffer;
 
 
   // XXX FIXME TEMP: hold on to this so that we can free it in DestroyFrontBuffer()
   SurfaceDescriptor mDeadweight;
 
--- a/layout/reftests/bugs/581317-1-ref.html
+++ b/layout/reftests/bugs/581317-1-ref.html
@@ -1,14 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <style>
 #d { width:200px; border:10px solid rgba(200,200,200,0.99); }
-#e { width:200px; height:200px; opacity:0.99; background-color:rgb(200,200,200); }
+#e { width:196px; height:196px; opacity:0.99; background-color:rgb(200,200,200); padding:2px; }
 #f { width:200px; height:10px; opacity:0.8; }
 </style>
 </head>
 <body>
 <div id="d">
   <div id="e">
     <div style="width:10px; height:10px; background:yellow;"></div>
     <div id="f">
--- a/layout/reftests/bugs/581317-1.html
+++ b/layout/reftests/bugs/581317-1.html
@@ -1,14 +1,14 @@
 <!DOCTYPE HTML>
 <html class="reftest-wait">
 <head>
 <style>
 #d { width:200px; }
-#e { width:200px; height:200px; opacity:0.99; }
+#e { width:196px; height:196px; opacity:0.99; border:2px solid rgb(200,200,200); }
 #f { width:200px; height:10px; }
 </style>
 </head>
 <body onload="step()">
 <div id="d">
   <div id="e">
     <div style="width:10px; height:10px; background:yellow;"></div>
     <div id="f">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/602200-1-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="position:absolute; top:10px; left:0; height:1px; width:200px; background:black"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/602200-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<canvas id="c" width="200" height="20" style="position:absolute; top:10.4px; left:0"></canvas>
+<script>
+var c = document.getElementById("c");
+var ctx = c.getContext("2d");
+ctx.fillStyle = "black";
+ctx.fillRect(0, 0, 200, 1);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/602200-2-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="position:absolute; top:10px; left:0; width:200px; height:19px;
+            opacity:0.999; border:1px solid black; border-top:2px solid black; background-color:white"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/602200-2.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="opacity:0.999;">
+  <canvas id="c" width="200" height="20" style="position:absolute; top:10.4px; left:0; border:1px solid black"></canvas>
+</div>
+<div style="position:absolute; top:10px; left:0; width:200px; height:19px;
+            opacity:0.999; border:1px solid black; border-top:2px solid black; background-color:white"></div>
+<script>
+var c = document.getElementById("c");
+var ctx = c.getContext("2d");
+ctx.fillStyle = "black";
+ctx.fillRect(0, 0, 200, 1);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/602200-3-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="width:12px; height:12px; background:black; position:absolute; top:0px"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/602200-3.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="-moz-transform:translate(0.4px); position:absolute; top:0px;">
+  <canvas style="margin-left:0.4px; border:1px solid black; display:block" width="10" height="10" id="c"></canvas>
+</div>
+<div style="position:absolute; top:0px; width:12px; height:12px; background:black;"></div>
+<script>
+var c = document.getElementById("c");
+var ctx = c.getContext('2d');
+ctx.fillStyle = "black";
+ctx.fillRect(0, 0, c.width, c.height);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/602200-4-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="opacity:0.999; border-left:1px solid red; width:12px;">
+  <div style="position:relative; left:1px; opacity:0.999; border-left:1px solid rgb(0,255,0);">
+    <div style="width:10px; height:10px; background:black"></div>
+  </div>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/602200-4.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="-moz-transform:translate(0.4px); opacity:0.999; border-left:1px solid red; width:12px;">
+  <div style="-moz-transform:translate(0.4px); opacity:0.999; border-left:1px solid rgb(0,255,0);">
+    <canvas width="10" height="10" id="c" style="display:block"></canvas>
+  </div>
+</div>
+<script>
+var ctx = document.getElementById("c").getContext("2d");
+ctx.fillStyle = "black";
+ctx.fillRect(0, 0, 10, 10);
+</script>
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1520,13 +1520,17 @@ asserts(0-1) == 582146-1.html about:blan
 == 594624-1.html 594624-1-ref.html
 == 594737-1.html 594737-1-ref.html
 == 597721-1.html 597721-1-ref.html
 == 599113-1.html 599113-1-ref.html
 fails-if(!haveTestPlugin) == 599476.html 599476-ref.html
 == 600045-1.html 600045-1-ref.html
 == 600803-1.html 600803-1-ref.html
 == 600974-1.html 600974-1-ref.html
-== 604737.html 604737-ref.html
 == 600974-2.html 600974-1-ref.html
 == 600974-3.html 600974-1-ref.html
+== 602200-1.html 602200-1-ref.html
+== 602200-2.html 602200-2-ref.html
+== 602200-3.html 602200-3-ref.html
+== 602200-4.html 602200-4-ref.html
+== 604737.html 604737-ref.html
 == 605138-1.html 605138-1-ref.html
 == 605157-1.xhtml 605157-1-ref.xhtml
--- a/modules/plugin/test/reftest/div-alpha-opacity.html
+++ b/modules/plugin/test/reftest/div-alpha-opacity.html
@@ -1,16 +1,17 @@
 <!doctype html>
 <html>
 <head>
 <style type="text/css">
 #one {
   position:absolute;
   left:0px; top:0px;
   width:400px; height:400px;
+  border:2px solid blue;
   background-color: rgb(160,160,160);
   opacity:0.5;
   z-index:1;
 }
 #two {
   position:absolute;
   top:100px; left:100px;
   width:200px; height:200px;
--- a/modules/plugin/test/reftest/plugin-alpha-opacity.html
+++ b/modules/plugin/test/reftest/plugin-alpha-opacity.html
@@ -1,16 +1,17 @@
 <!doctype html>
 <html>
 <head>
 <style type="text/css">
 #one {
   position:absolute;
   left:0px; top:0px;
-  width:400px; height:400px;
+  width:404px; height:404px;
+  border:2px solid blue;
   opacity:.5;
   z-index:1;
 }
 #two {
   position:absolute;
   top:100px; left:100px;
   width:200px; height:200px;
   z-index:0;