Bug 1023677 - Don't set mSupportComponentAlphaChildren unless we actually have them. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Fri, 18 Jul 2014 18:48:23 +1200
changeset 215672 151b2045009ea7f0642b36923792a8f2c98a4ab8
parent 215671 167bb4ee1c8aec0502a236c460fed26af998a016
child 215673 7b6209437d8f1d373d2d5846902d03182d82fe18
push id3857
push userraliiev@mozilla.com
push dateTue, 02 Sep 2014 16:39:23 +0000
treeherdermozilla-beta@5638b907b505 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1023677
milestone33.0a1
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 1023677 - Don't set mSupportComponentAlphaChildren unless we actually have them. r=roc
gfx/layers/Layers.cpp
gfx/layers/Layers.h
layout/base/FrameLayerBuilder.cpp
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -1018,16 +1018,24 @@ ContainerLayer::DefaultComputeEffectiveT
   } else {
     ComputeEffectiveTransformForMaskLayer(Matrix4x4());
   }
 }
 
 void
 ContainerLayer::DefaultComputeSupportsComponentAlphaChildren(bool* aNeedsSurfaceCopy)
 {
+  if (!(GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT)) {
+    mSupportsComponentAlphaChildren = false;
+    if (aNeedsSurfaceCopy) {
+      *aNeedsSurfaceCopy = false;
+    }
+    return;
+  }
+
   bool supportsComponentAlphaChildren = false;
   bool needsSurfaceCopy = false;
   CompositionOp blendMode = GetEffectiveMixBlendMode();
   if (UseIntermediateSurface()) {
     if (GetEffectiveVisibleRegion().GetNumRects() == 1 &&
         (GetContentFlags() & Layer::CONTENT_OPAQUE))
     {
       supportsComponentAlphaChildren = true;
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -743,32 +743,38 @@ public:
      * require per-component alpha for optimal fidelity. However, there is no
      * guarantee that component alpha will be supported for this layer at
      * paint time.
      * This should never be set at the same time as CONTENT_OPAQUE.
      */
     CONTENT_COMPONENT_ALPHA = 0x02,
 
     /**
+     * If this is set then one of the descendant layers of this one has
+     * CONTENT_COMPONENT_ALPHA set.
+     */
+    CONTENT_COMPONENT_ALPHA_DESCENDANT = 0x04,
+
+    /**
      * If this is set then this layer is part of a preserve-3d group, and should
      * be sorted with sibling layers that are also part of the same group.
      */
-    CONTENT_PRESERVE_3D = 0x04,
+    CONTENT_PRESERVE_3D = 0x08,
     /**
      * This indicates that the transform may be changed on during an empty
      * transaction where there is no possibility of redrawing the content, so the
      * implementation should be ready for that.
      */
-    CONTENT_MAY_CHANGE_TRANSFORM = 0x08,
+    CONTENT_MAY_CHANGE_TRANSFORM = 0x10,
 
     /**
      * Disable subpixel AA for this layer. This is used if the display isn't suited
      * for subpixel AA like hidpi or rotated content.
      */
-    CONTENT_DISABLE_SUBPIXEL_AA = 0x10
+    CONTENT_DISABLE_SUBPIXEL_AA = 0x20
   };
   /**
    * CONSTRUCTION PHASE ONLY
    * This lets layout make some promises about what will be drawn into the
    * visible region of the ThebesLayer. This enables internal quality
    * and performance optimizations.
    */
   void SetContentFlags(uint32_t aFlags)
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -3076,17 +3076,19 @@ ContainerState::Finish(uint32_t* aTextCo
   // Make sure that current/existing layers are added to the parent and are
   // in the correct order.
   Layer* layer = nullptr;
   for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i) {
     Layer* prevChild = i == 0 ? nullptr : mNewChildLayers[i - 1].get();
     layer = mNewChildLayers[i];
 
     if (!layer->GetVisibleRegion().IsEmpty()) {
-      textContentFlags |= layer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA;
+      textContentFlags |=
+        layer->GetContentFlags() & (Layer::CONTENT_COMPONENT_ALPHA |
+                                    Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT);
     }
 
     if (!layer->GetParent()) {
       // This is not currently a child of the container, so just add it
       // now.
       mContainerLayer->InsertAfter(layer, prevChild);
       continue;
     }
@@ -3449,23 +3451,34 @@ FrameLayerBuilder::BuildContainerLayerFo
   NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds");
   pixBounds.MoveBy(nsIntPoint(scaleParameters.mOffset.x, scaleParameters.mOffset.y));
   if (aParameters.mAncestorClipRect && !(aFlags & CONTAINER_NOT_CLIPPED_BY_ANCESTORS)) {
     SetVisibleRegionForLayer(containerLayer, nsIntRegion(pixBounds),
                              *aParameters.mAncestorClipRect);
   } else {
     containerLayer->SetVisibleRegion(pixBounds);
   }
+
+  // CONTENT_COMPONENT_ALPHA is propogated up to the nearest CONTENT_OPAQUE
+  // ancestor so that BasicLayerManager knows when to copy the background into
+  // pushed groups. Accelerated layers managers can't necessarily do this (only
+  // when the visible region is a simple rect), so we propogate
+  // CONTENT_COMPONENT_ALPHA_DESCENDANT all the way to the root.
+  if (flags & Layer::CONTENT_COMPONENT_ALPHA) {
+    flags |= Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT;
+  }
+
   // Make sure that rounding the visible region out didn't add any area
   // we won't paint
   if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) {
     bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
     if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) {
-      // Clear CONTENT_COMPONENT_ALPHA
-      flags = Layer::CONTENT_OPAQUE;
+      // Clear CONTENT_COMPONENT_ALPHA and add CONTENT_OPAQUE instead.
+      flags &= ~Layer::CONTENT_COMPONENT_ALPHA;
+      flags |= Layer::CONTENT_OPAQUE;
     }
   }
   containerLayer->SetContentFlags(flags);
 
   mContainerLayerGeneration = oldGeneration;
   nsPresContext::ClearNotifySubDocInvalidationData(containerLayer);
 
   return containerLayer.forget();