Bug 907048 - Skip colorlayer if other opacity layer just covers the colorlayer region, r=roc
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 10 Sep 2013 15:06:13 +0800
changeset 146401 a2013b29212c12e298c6ca56895056a53b59be39
parent 146400 8ddd8c297814d7e928547ca0e97d3476cf2d584d
child 146402 d660739f74981545b16aeee25fae6a4bcb10bc8a
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersroc
bugs907048
milestone26.0a1
Bug 907048 - Skip colorlayer if other opacity layer just covers the colorlayer region, r=roc
gfx/layers/composite/ContainerLayerComposite.cpp
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -42,16 +42,48 @@ HasOpaqueAncestorLayer(Layer* aLayer)
 {
   for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
     if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
       return true;
   }
   return false;
 }
 
+/**
+ * Returns a rectangle of content painted opaquely by aLayer. Very consertative;
+ * bails by returning an empty rect in any tricky situations.
+ */
+static nsIntRect
+GetOpaqueRect(Layer* aLayer)
+{
+  nsIntRect result;
+  // Just bail if there's anything difficult to handle.
+  if (!aLayer->GetEffectiveTransform().IsIdentity() ||
+      aLayer->GetEffectiveOpacity() != 1.0f ||
+      aLayer->GetMaskLayer()) {
+    return result;
+  }
+  if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) {
+    result = aLayer->GetEffectiveVisibleRegion().GetLargestRectangle();
+  } else {
+    // Drill down into RefLayers because that's what we particularly care about;
+    // layer construction for aLayer will not have known about the opaqueness
+    // of any RefLayer subtrees.
+    RefLayer* refLayer = aLayer->AsRefLayer();
+    if (refLayer) {
+      result = GetOpaqueRect(refLayer->GetFirstChild());
+    }
+  }
+  const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
+  if (clipRect) {
+    result.IntersectRect(result, *clipRect);
+  }
+  return result;
+}
+
 template<class ContainerT> void
 ContainerRender(ContainerT* aContainer,
                 const nsIntPoint& aOffset,
                 LayerManagerComposite* aManager,
                 const nsIntRect& aClipRect)
 {
   /**
    * Setup our temporary surface for rendering the contents of this container.
@@ -138,16 +170,33 @@ ContainerRender(ContainerT* aContainer,
   for (uint32_t i = 0; i < children.Length(); i++) {
     LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData());
 
     if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty() &&
         !layerToRender->GetLayer()->AsContainerLayer()) {
       continue;
     }
 
+    if (i + 1 < children.Length() &&
+        layerToRender->GetLayer()->GetEffectiveTransform().IsIdentity()) {
+      LayerComposite* nextLayer = static_cast<LayerComposite*>(children.ElementAt(i + 1)->ImplData());
+      nsIntRect nextLayerOpaqueRect;
+      if (nextLayer && nextLayer->GetLayer()) {
+        nextLayerOpaqueRect = GetOpaqueRect(nextLayer->GetLayer());
+      }
+      if (!nextLayerOpaqueRect.IsEmpty()) {
+        nsIntRegion visibleRegion;
+        visibleRegion.Sub(layerToRender->GetShadowVisibleRegion(), nextLayerOpaqueRect);
+        layerToRender->SetShadowVisibleRegion(visibleRegion);
+        if (visibleRegion.IsEmpty()) {
+          continue;
+        }
+      }
+    }
+
     nsIntRect clipRect = layerToRender->GetLayer()->
         CalculateScissorRect(aClipRect, &aManager->GetWorldTransform());
     if (clipRect.IsEmpty()) {
       continue;
     }
 
     layerToRender->RenderLayer(childOffset, clipRect);
     // invariant: our GL context should be current here, I don't think we can