Bug 612840. Part 3: Make Layer::CONTENT_NO_TEXT_OVER_TRANSPARENT applicable to all layer types, and set CONTENT_NO_TEXT_OVER_TRANSPARENT on container layers. r=tnikkel,r=vlad
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 20 Dec 2010 14:26:14 +1300
changeset 59481 bc423fb0aa13fb9c2d261c9993ccf6021fe85ff0
parent 59480 53bc550efbccbf583419f1027de08c9b4e56b9ba
child 59482 8019b50e514c708e3b633da8b4c394edd4a27f0b
push id17638
push userrocallahan@mozilla.com
push dateMon, 20 Dec 2010 01:39:18 +0000
treeherdermozilla-central@302d1d3e2817 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel, vlad
bugs612840
milestone2.0b9pre
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 612840. Part 3: Make Layer::CONTENT_NO_TEXT_OVER_TRANSPARENT applicable to all layer types, and set CONTENT_NO_TEXT_OVER_TRANSPARENT on container layers. r=tnikkel,r=vlad
gfx/layers/Layers.h
layout/base/FrameLayerBuilder.cpp
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -477,17 +477,16 @@ public:
   enum {
     /**
      * If this is set, the caller is promising that by the end of this
      * transaction the entire visible region (as specified by
      * SetVisibleRegion) will be filled with opaque content.
      */
     CONTENT_OPAQUE = 0x01,
     /**
-     * ThebesLayers only!
      * If this is set, the caller is promising that the visible region
      * contains no text over transparent pixels (any text, if present,
      * is over fully opaque pixels).
      */
     CONTENT_NO_TEXT_OVER_TRANSPARENT = 0x02
   };
   /**
    * CONSTRUCTION PHASE ONLY
@@ -733,17 +732,17 @@ public:
 protected:
   Layer(LayerManager* aManager, void* aImplData) :
     mManager(aManager),
     mParent(nsnull),
     mNextSibling(nsnull),
     mPrevSibling(nsnull),
     mImplData(aImplData),
     mOpacity(1.0),
-    mContentFlags(0),
+    mContentFlags(CONTENT_NO_TEXT_OVER_TRANSPARENT),
     mUseClipRect(PR_FALSE)
     {}
 
   void Mutated() { mManager->Mutated(this); }
 
   // 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
@@ -827,17 +826,19 @@ public:
   }
 
 protected:
   ThebesLayer(LayerManager* aManager, void* aImplData)
     : Layer(aManager, aImplData)
     , mValidRegion()
     , mXResolution(1.0)
     , mYResolution(1.0)
-  {}
+  {
+    mContentFlags = 0; // Clear NO_TEXT, NO_TEXT_OVER_TRANSPARENT
+  }
 
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
   nsIntRegion mValidRegion;
   // Resolution values tell this to paint its content scaled by
   // <aXResolution, aYResolution>, into a backing buffer with
   // dimensions scaled the same.  A non-1.0 resolution also tells this
   // to set scaling factors that compensate for the re-paint
@@ -915,17 +916,19 @@ public:
   PRBool HasMultipleChildren();
 
 protected:
   ContainerLayer(LayerManager* aManager, void* aImplData)
     : Layer(aManager, aImplData),
       mFirstChild(nsnull),
       mLastChild(nsnull),
       mUseIntermediateSurface(PR_FALSE)
-  {}
+  {
+    mContentFlags = 0; // Clear NO_TEXT, NO_TEXT_OVER_TRANSPARENT
+  }
 
   /**
    * A default implementation of ComputeEffectiveTransforms for use by OpenGL
    * and D3D.
    */
   void DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface);
 
   /**
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -143,18 +143,21 @@ public:
    */
   void ProcessDisplayItems(const nsDisplayList& aList,
                            const FrameLayerBuilder::Clip& aClip);
   /**
    * This finalizes all the open ThebesLayers by popping every element off
    * mThebesLayerDataStack, then sets the children of the container layer
    * to be all the layers in mNewChildLayers in that order and removes any
    * layers as children of the container that aren't in mNewChildLayers.
+   * @param aTextContentFlags if all child layers have CONTENT_NO_TEXT, adds
+   * CONTENT_NO_TEXT to *aTextContentFlags.
+   * Likewise for CONTENT_NO_TEXT_OVER_TRANSPARENT.
    */
-  void Finish();
+  void Finish(PRUint32 *aTextContentFlags);
 
 protected:
   /**
    * We keep a stack of these to represent the ThebesLayers that are
    * currently available to have display items added to.
    * We use a stack here because as much as possible we want to
    * assign display items to existing ThebesLayers, and to the lowest
    * ThebesLayer in z-order. This reduces the number of layers and
@@ -1262,28 +1265,33 @@ ContainerState::CollectOldLayers()
     } else if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
       NS_ASSERTION(layer->AsThebesLayer(), "Wrong layer type");
       mRecycledThebesLayers.AppendElement(static_cast<ThebesLayer*>(layer));
     }
   }
 }
 
 void
-ContainerState::Finish()
+ContainerState::Finish(PRUint32* aTextContentFlags)
 {
   while (!mThebesLayerDataStack.IsEmpty()) {
     PopThebesLayerData();
   }
 
+  PRUint32 textContentFlags = Layer::CONTENT_NO_TEXT_OVER_TRANSPARENT;
+
   for (PRUint32 i = 0; i <= mNewChildLayers.Length(); ++i) {
     // An invariant of this loop is that the layers in mNewChildLayers
     // with index < i are the first i child layers of mContainerLayer.
     Layer* layer;
     if (i < mNewChildLayers.Length()) {
       layer = mNewChildLayers[i];
+      if (!layer->GetVisibleRegion().IsEmpty()) {
+        textContentFlags &= layer->GetContentFlags();
+      }
       if (!layer->GetParent()) {
         // This is not currently a child of the container, so just add it
         // now.
         Layer* prevChild = i == 0 ? nsnull : mNewChildLayers[i - 1].get();
         mContainerLayer->InsertAfter(layer, prevChild);
         continue;
       }
       NS_ASSERTION(layer->GetParent() == mContainerLayer,
@@ -1302,16 +1310,18 @@ ContainerState::Finish()
     while (nextOldChild != layer) {
       Layer* tmp = nextOldChild;
       nextOldChild = nextOldChild->GetNextSibling();
       mContainerLayer->RemoveChild(tmp);
     }
     // If non-null, 'layer' is now in the right place in the list, so we
     // can just move on to the next one.
   }
+
+  *aTextContentFlags = textContentFlags;
 }
 
 static void
 SetHasContainerLayer(nsIFrame* aFrame)
 {
   aFrame->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER);
   for (nsIFrame* f = aFrame;
        f && !(f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
@@ -1390,21 +1400,28 @@ FrameLayerBuilder::BuildContainerLayerFo
       // invalidated.
       state.SetInvalidateAllThebesContent();
     }
     SetHasContainerLayer(aContainerFrame);
   }
 
   Clip clip;
   state.ProcessDisplayItems(aChildren, clip);
-  state.Finish();
 
-  PRUint32 flags = aChildren.IsOpaque() && 
-                   !aChildren.NeedsTransparentSurface() ? Layer::CONTENT_OPAQUE : 0;
+  // Set CONTENT_NO_TEXT_OVER_TRANSPARENT if any of our children have it.
+  // This is suboptimal ... a child could have text that's over transparent
+  // pixels in its own layer, but over opaque parts of previous siblings.
+  PRUint32 flags;
+  state.Finish(&flags);
+
+  if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) {
+    flags |= Layer::CONTENT_OPAQUE;
+  }
   containerLayer->SetContentFlags(flags);
+
   return containerLayer.forget();
 }
 
 Layer*
 FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    nsDisplayItem* aItem)
 {