Bug 593604. Part 10: When ContainerLayerD3D9 uses an intermediate surface, try to copy up the background into the intermediate surface so we can composite component alpha into it correctly. r=bas,a=blocking
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 03 Jan 2011 14:48:09 +1300
changeset 59776 58aa602af75c43a9887d5ef949b12876a5fac30d
parent 59775 b4e0f47b628df4c655025dc9bdfe8364857577cd
child 59777 5b0756d80fe89399a80bcff2260bbf3bac45355a
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersbas, blocking
bugs593604
milestone2.0b9pre
Bug 593604. Part 10: When ContainerLayerD3D9 uses an intermediate surface, try to copy up the background into the intermediate surface so we can composite component alpha into it correctly. r=bas,a=blocking
gfx/layers/d3d9/ContainerLayerD3D9.cpp
--- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp
@@ -148,40 +148,80 @@ static inline LayerD3D9*
 GetNextSiblingD3D9(LayerD3D9* aLayer)
 {
    Layer* layer = aLayer->GetLayer()->GetNextSibling();
    return layer ? static_cast<LayerD3D9*>(layer->
                                           ImplData())
                  : nsnull;
 }
 
+static PRBool
+HasOpaqueAncestorLayer(Layer* aLayer)
+{
+  for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
+    if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
+      return PR_TRUE;
+  }
+  return PR_FALSE;
+}
+
 void
 ContainerLayerD3D9::RenderLayer()
 {
   nsRefPtr<IDirect3DSurface9> previousRenderTarget;
   nsRefPtr<IDirect3DTexture9> renderTexture;
   float previousRenderTargetOffset[4];
   RECT oldClipRect;
   float renderTargetOffset[] = { 0, 0, 0, 0 };
   float oldViewMatrix[4][4];
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
   PRBool useIntermediate = UseIntermediateSurface();
 
+  mSupportsComponentAlphaChildren = PR_FALSE;
   gfxMatrix contTransform;
   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;
     renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
     device()->SetRenderTarget(0, renderSurface);
-    device()->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0);
+
+    if (mVisibleRegion.GetNumRects() == 1 && (GetContentFlags() & CONTENT_OPAQUE)) {
+      // don't need a background, we're going to paint all opaque stuff
+      mSupportsComponentAlphaChildren = PR_TRUE;
+    } else {
+      const gfx3DMatrix& transform3D = GetEffectiveTransform();
+      gfxMatrix transform;
+      // If we have an opaque ancestor layer, then we can be sure that
+      // all the pixels we draw into are either opaque already or will be
+      // covered by something opaque. Otherwise copying up the background is
+      // not safe.
+      HRESULT hr = E_FAIL;
+      if (HasOpaqueAncestorLayer(this) &&
+          transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) {
+        // Copy background up from below
+        RECT dest = { 0, 0, visibleRect.width, visibleRect.height };
+        RECT src = dest;
+        ::OffsetRect(&src,
+                     visibleRect.x + PRInt32(transform.x0),
+                     visibleRect.y + PRInt32(transform.y0));
+        hr = device()->
+          StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
+      }
+      if (hr == S_OK) {
+        mSupportsComponentAlphaChildren = PR_TRUE;
+      } else {
+        device()->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0);
+      }
+    }
+
     device()->GetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
     renderTargetOffset[0] = (float)visibleRect.x;
     renderTargetOffset[1] = (float)visibleRect.y;
     device()->SetVertexShaderConstantF(CBvRenderTargetOffset, renderTargetOffset, 1);
 
     gfx3DMatrix viewMatrix;
     /*
      * Matrix to transform to viewport space ( <-1.0, 1.0> topleft,