Bug 684759 - Part 3a - Sort preserve-3d layers using their z depth at points where they intersect in 2d space. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Fri, 07 Oct 2011 10:23:18 +1300
changeset 78279 39d6e79b44ad645d6050d79877aca414b40dbeb8
parent 78278 3ef0db7dc18dd42295595630c7536a8c979fbc85
child 78280 c17d89a1c4aa80f55c27eab247bc81eec129fb54
push id21283
push userbmo@edmorley.co.uk
push dateFri, 07 Oct 2011 10:41:20 +0000
treeherdermozilla-central@bd1411e362fb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs684759
milestone10.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 684759 - Part 3a - Sort preserve-3d layers using their z depth at points where they intersect in 2d space. r=roc
gfx/layers/LayerSorter.cpp
gfx/layers/LayerSorter.h
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/Makefile.in
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/LayerSorter.cpp
@@ -0,0 +1,258 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Matt Woodrow <mwoodrow@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "LayerSorter.h"
+#include "DirectedGraph.h"
+#include "limits.h"
+
+namespace mozilla {
+namespace layers {
+
+enum LayerSortOrder {
+  Undefined,
+  ABeforeB,
+  BBeforeA,
+};
+
+/**
+ * Recover the z component from a 2d transformed point by finding the intersection
+ * of a line through the point in the z direction and the transformed plane.
+ *
+ * We want to solve:
+ *
+ * point = normal . (p0 - l0) / normal . l
+ */
+static gfxFloat RecoverZDepth(const gfx3DMatrix& aTransform, const gfxPoint& aPoint)
+{
+    const gfxPoint3D l(0, 0, 1);
+    gfxPoint3D l0 = gfxPoint3D(aPoint.x, aPoint.y, 0);
+    gfxPoint3D p0 = aTransform.Transform3D(gfxPoint3D(0, 0, 0));
+    gfxPoint3D normal = aTransform.GetNormalVector();
+
+    gfxFloat n = normal.DotProduct(p0 - l0); 
+    gfxFloat d = normal.DotProduct(l);
+
+    if (!d) {
+        return 0;
+    }
+
+    return n/d;
+}
+
+/**
+ * Determine if this transform layer should be drawn before another when they 
+ * are both preserve-3d children.
+ *
+ * We want to find the relative z depths of the 2 layers at points where they
+ * intersect when projected onto the 2d screen plane.
+ *
+ * If the ordering is consistent at all intersection points, then we have
+ * a definitive order, otherwise the 2 layers must actually intersect in 3d
+ * space, and we just order these arbitrarily.
+ */
+static LayerSortOrder CompareDepth(Layer* aOne, Layer* aTwo) {
+  gfxRect ourRect = aOne->GetEffectiveVisibleRegion().GetBounds();
+  gfxRect otherRect = aTwo->GetEffectiveVisibleRegion().GetBounds();
+
+  gfx3DMatrix ourTransform = aOne->GetTransform();
+  gfx3DMatrix otherTransform = aTwo->GetTransform();
+
+  // Transform both rectangles and project into 2d space.
+  gfxQuad ourTransformedRect = ourTransform.TransformRect(ourRect);
+  gfxQuad otherTransformedRect = otherTransform.TransformRect(otherRect);
+
+  // Make a list of all points that are within the other rect.
+  nsTArray<gfxPoint> points;
+  for (PRUint32 i=0; i<4; i++) {
+    if (ourTransformedRect.Contains(otherTransformedRect.mPoints[i])) {
+      points.AppendElement(otherTransformedRect.mPoints[i]);
+    }
+    if (otherTransformedRect.Contains(ourTransformedRect.mPoints[i])) {
+      points.AppendElement(ourTransformedRect.mPoints[i]);
+    }
+  }
+
+  // No intersections, no defined order between these layers.
+  if (points.IsEmpty()) {
+    return Undefined;
+  }
+
+  // Find the relative Z depths of each intersection point and check that the layers are in the same order.
+  bool drawBefore = false;
+  for (PRUint32 i = 0; i < points.Length(); i++) {
+    bool temp = RecoverZDepth(ourTransform, points.ElementAt(i)) <= RecoverZDepth(otherTransform, points.ElementAt(i));
+    if (i == 0) {
+      drawBefore = temp; 
+    } else if (drawBefore != temp) {
+      // Mixed ordering means an intersection in 3d space that we can't resolve without plane splitting
+      // or depth buffering. Store this as having no defined order for now.
+      return Undefined;
+    }
+  }
+  if (drawBefore) {
+    return ABeforeB;
+  }
+  return BBeforeA;
+}
+
+#ifdef DEBUG
+static bool gDumpLayerSortList = getenv("MOZ_DUMP_LAYER_SORT_LIST") != 0;
+
+static void DumpLayerList(nsTArray<Layer*>& aLayers)
+{
+  for (PRUint32 i = 0; i < aLayers.Length(); i++) {
+    fprintf(stderr, "%p, ", aLayers.ElementAt(i));
+  }
+  fprintf(stderr, "\n");
+}
+
+static void DumpEdgeList(DirectedGraph<Layer*>& aGraph)
+{
+  nsTArray<DirectedGraph<Layer*>::Edge> edges = aGraph.GetEdgeList();
+  
+  for (PRUint32 i = 0; i < edges.Length(); i++) {
+    fprintf(stderr, "From: %p, To: %p\n", edges.ElementAt(i).mFrom, edges.ElementAt(i).mTo);
+  }
+}
+#endif
+
+// The maximum number of layers that we will attempt to sort. Anything
+// greater than this will be left unsorted. We should consider enabling
+// depth buffering for the scene in this case.
+#define MAX_SORTABLE_LAYERS 100
+
+void SortLayersBy3DZOrder(nsTArray<Layer*>& aLayers)
+{
+  PRUint32 nodeCount = aLayers.Length();
+  if (nodeCount > MAX_SORTABLE_LAYERS) {
+    return;
+  }
+  DirectedGraph<Layer*> graph;
+
+#ifdef DEBUG
+  if (gDumpLayerSortList) {
+    fprintf(stderr, " --- Layers before sorting: --- \n");
+    DumpLayerList(aLayers);
+  }
+#endif
+
+  // Iterate layers and determine edges.
+  for (PRUint32 i = 0; i < nodeCount; i++) {
+    for (PRUint32 j = i + 1; j < nodeCount; j++) {
+      Layer* a = aLayers.ElementAt(i);
+      Layer* b = aLayers.ElementAt(j);
+      LayerSortOrder order = CompareDepth(a, b);
+      if (order == ABeforeB) {
+        graph.AddEdge(a, b);
+      } else if (order == BBeforeA) {
+        graph.AddEdge(b, a);
+      }
+    }
+  }
+
+#ifdef DEBUG
+  if (gDumpLayerSortList) {
+    fprintf(stderr, " --- Edge List: --- \n");
+    DumpEdgeList(graph);
+  }
+#endif
+
+  // Build a new array using the graph.
+  nsTArray<Layer*> noIncoming;
+  nsTArray<Layer*> sortedList;
+
+  // Make a list of all layers with no incoming edges.
+  noIncoming.AppendElements(aLayers);
+  const nsTArray<DirectedGraph<Layer*>::Edge>& edges = graph.GetEdgeList();
+  for (PRUint32 i = 0; i < edges.Length(); i++) {
+    noIncoming.RemoveElement(edges.ElementAt(i).mTo);
+  }
+
+  // Move each item without incoming edges into the sorted list,
+  // and remove edges from it.
+  while (!noIncoming.IsEmpty()) {
+    PRUint32 last = noIncoming.Length() - 1;
+
+    Layer* layer = noIncoming.ElementAt(last);
+
+    noIncoming.RemoveElementAt(last);
+    sortedList.AppendElement(layer);
+
+    nsTArray<DirectedGraph<Layer*>::Edge> outgoing;
+    graph.GetEdgesFrom(layer, outgoing);
+    for (PRUint32 i = 0; i < outgoing.Length(); i++) {
+      DirectedGraph<Layer*>::Edge edge = outgoing.ElementAt(i);
+      graph.RemoveEdge(edge);
+      if (!graph.NumEdgesTo(edge.mTo)) {
+        // If this node also has no edges now, add it to the list
+        noIncoming.AppendElement(edge.mTo);
+      }
+    }
+
+    // If there are no nodes without incoming edges, but there
+    // are still edges, then we have a cycle.
+    if (noIncoming.IsEmpty() && graph.GetEdgeCount()) {
+      // Find the node with the least incoming edges.
+      PRUint32 minEdges = UINT_MAX;
+      Layer* minNode = nsnull;
+      for (PRUint32 i = 0; i < aLayers.Length(); i++) {
+        PRUint32 edgeCount = graph.NumEdgesTo(aLayers.ElementAt(i));
+        if (edgeCount && edgeCount < minEdges) {
+          minEdges = edgeCount;
+          minNode = aLayers.ElementAt(i);
+        }
+      }
+
+      // Remove all of them!
+      graph.RemoveEdgesTo(minNode);
+      noIncoming.AppendElement(minNode);
+    }
+  }
+  NS_ASSERTION(!graph.GetEdgeCount(), "Cycles detected!");
+#ifdef DEBUG
+  if (gDumpLayerSortList) {
+    fprintf(stderr, " --- Layers after sorting: --- \n");
+    DumpLayerList(sortedList);
+  }
+#endif
+
+  aLayers.Clear();
+  aLayers.AppendElements(sortedList);
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/layers/LayerSorter.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Matt Woodrow <mwoodrow@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef GFX_LAYERSORTER_H
+#define GFX_LAYERSORTER_H
+
+#include "Layers.h"
+
+namespace mozilla {
+namespace layers {
+
+void SortLayersBy3DZOrder(nsTArray<Layer*>& aLayers);
+
+}
+}
+#endif /* GFX_LAYERSORTER_H */
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -43,16 +43,17 @@
 
 #include "ImageLayers.h"
 #include "Layers.h"
 #include "gfxPlatform.h"
 #include "ReadbackLayer.h"
 #include "gfxUtils.h"
 #include "nsPrintfCString.h"
 #include "mozilla/Util.h"
+#include "LayerSorter.h"
 
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 typedef FrameMetrics::ViewID ViewID;
 const ViewID FrameMetrics::NULL_SCROLL_ID = 0;
 const ViewID FrameMetrics::ROOT_SCROLL_ID = 1;
 const ViewID FrameMetrics::START_SCROLL_ID = 2;
@@ -411,16 +412,39 @@ ContainerLayer::HasMultipleChildren()
     if (count > 1)
       return PR_TRUE;
   }
 
   return PR_FALSE;
 }
 
 void
+ContainerLayer::SortChildrenBy3DZOrder(nsTArray<Layer*>& aArray)
+{
+  nsAutoTArray<Layer*, 10> toSort;
+
+  for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
+    ContainerLayer* container = l->AsContainerLayer();
+    if (container && container->GetContentFlags() & CONTENT_PRESERVE_3D) {
+      toSort.AppendElement(l);
+    } else {
+      if (toSort.Length() > 0) {
+        SortLayersBy3DZOrder(toSort);
+        aArray.MoveElementsFrom(toSort);
+      }
+      aArray.AppendElement(l);
+    }
+  }
+  if (toSort.Length() > 0) {
+    SortLayersBy3DZOrder(toSort);
+    aArray.MoveElementsFrom(toSort);
+  }
+}
+
+void
 ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
 {
   gfxMatrix residual;
   gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
   mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), &residual);
 
   bool useIntermediateSurface;
   float opacity = GetEffectiveOpacity();
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -43,16 +43,17 @@
 #include "nsRegion.h"
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsISupportsImpl.h"
 #include "nsAutoPtr.h"
 #include "gfx3DMatrix.h"
 #include "gfxColor.h"
 #include "gfxPattern.h"
+#include "nsTArray.h"
 
 #include "mozilla/gfx/2D.h"
 
 #if defined(DEBUG) || defined(PR_LOGGING)
 #  include <stdio.h>            // FILE
 #  include "prlog.h"
 #  define MOZ_LAYERS_HAVE_LOG
 #  define MOZ_LAYERS_LOG(_args)                             \
@@ -572,17 +573,23 @@ public:
     CONTENT_OPAQUE = 0x01,
     /**
      * If this is set, the caller is notifying that the contents of this layer
      * 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
+    CONTENT_COMPONENT_ALPHA = 0x02,
+
+    /**
+     * 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
   };
   /**
    * 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(PRUint32 aFlags)
@@ -1090,16 +1097,18 @@ public:
   void SetFrameMetrics(const FrameMetrics& aFrameMetrics)
   {
     mFrameMetrics = aFrameMetrics;
     Mutated();
   }
 
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs);
 
+  void SortChildrenBy3DZOrder(nsTArray<Layer*>& aArray);
+
   // These getters can be used anytime.
 
   virtual ContainerLayer* AsContainerLayer() { return this; }
 
   virtual Layer* GetFirstChild() { return mFirstChild; }
   virtual Layer* GetLastChild() { return mLastChild; }
   const FrameMetrics& GetFrameMetrics() { return mFrameMetrics; }
 
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -61,30 +61,32 @@ endif
 
 EXPORTS = \
         BasicLayers.h \
         ImageLayers.h \
         Layers.h \
         LayerManagerOGL.h \
         LayerManagerOGLProgram.h \
         ReadbackLayer.h \
+        LayerSorter.h \
         $(NULL)
 
 CPPSRCS = \
         BasicImages.cpp \
         BasicLayers.cpp \
         Layers.cpp \
         ReadbackProcessor.cpp \
         ThebesLayerBuffer.cpp \
         CanvasLayerOGL.cpp \
         ColorLayerOGL.cpp \
         ContainerLayerOGL.cpp \
         ImageLayerOGL.cpp \
         LayerManagerOGL.cpp \
         ThebesLayerOGL.cpp \
+        LayerSorter.cpp \
         $(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 CMMSRCS = \
         MacIOSurfaceImageOGL.mm \
         $(NULL)
 endif
 
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -757,43 +757,25 @@ static bool IsContentLEQ(nsDisplayItem* 
   // These GetUnderlyingFrame calls return non-null because we're only used
   // in sorting
   return nsLayoutUtils::CompareTreePosition(
       aItem1->GetUnderlyingFrame()->GetContent(),
       aItem2->GetUnderlyingFrame()->GetContent(),
       static_cast<nsIContent*>(aClosure)) <= 0;
 }
 
-static bool IsZPositionLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
-                             void* aClosure) {
-  if (!aItem1->GetUnderlyingFrame()->Preserves3D() ||
-      !aItem1->GetUnderlyingFrame()->Preserves3D()) {
-    return IsContentLEQ(aItem1, aItem2, aClosure);
-  }
-
-  nsIFrame* ancestor;
-  gfx3DMatrix matrix1 = aItem1->GetUnderlyingFrame()->GetTransformMatrix(&ancestor);
-  gfx3DMatrix matrix2 = aItem2->GetUnderlyingFrame()->GetTransformMatrix(&ancestor);
-
-  if (matrix1._43 == matrix2._43) {
-    return IsContentLEQ(aItem1, aItem2, aClosure);
-  }
-
-  return matrix1._43 < matrix2._43;
-}
-
 static bool IsZOrderLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
                           void* aClosure) {
   // These GetUnderlyingFrame calls return non-null because we're only used
   // in sorting.  Note that we can't just take the difference of the two
   // z-indices here, because that might overflow a 32-bit int.
   PRInt32 index1 = nsLayoutUtils::GetZIndex(aItem1->GetUnderlyingFrame());
   PRInt32 index2 = nsLayoutUtils::GetZIndex(aItem2->GetUnderlyingFrame());
   if (index1 == index2)
-    return IsZPositionLEQ(aItem1, aItem2, aClosure);
+    return IsContentLEQ(aItem1, aItem2, aClosure);
   return index1 < index2;
 }
 
 void nsDisplayList::ExplodeAnonymousChildLists(nsDisplayListBuilder* aBuilder) {
   // See if there's anything to do
   bool anyAnonymousItems = false;
   nsDisplayItem* i;
   for (i = GetBottom(); i != nsnull; i = i->GetAbove()) {
@@ -830,21 +812,16 @@ void nsDisplayList::SortByZOrder(nsDispl
   Sort(aBuilder, IsZOrderLEQ, aCommonAncestor);
 }
 
 void nsDisplayList::SortByContentOrder(nsDisplayListBuilder* aBuilder,
                                        nsIContent* aCommonAncestor) {
   Sort(aBuilder, IsContentLEQ, aCommonAncestor);
 }
 
-void nsDisplayList::SortByZPosition(nsDisplayListBuilder* aBuilder,
-                                    nsIContent* aCommonAncestor) {
-  Sort(aBuilder, IsZPositionLEQ, aCommonAncestor);
-}
-
 void nsDisplayList::Sort(nsDisplayListBuilder* aBuilder,
                          SortLEQ aCmp, void* aClosure) {
   ExplodeAnonymousChildLists(aBuilder);
   ::Sort(this, Count(), aCmp, aClosure);
 }
 
 bool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
                                           nsRegion* aVisibleRegion) {
@@ -2531,27 +2508,34 @@ already_AddRefed<Layer> nsDisplayTransfo
     GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel());
 
   if (newTransformMatrix.IsSingular() ||
       (mFrame->GetStyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN &&
        newTransformMatrix.GetNormalVector().z <= 0.0)) {
     return nsnull;
   }
 
-  return aBuilder->LayerBuilder()->
+  nsRefPtr<ContainerLayer> container = aBuilder->LayerBuilder()->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetList(),
                            aContainerParameters, &newTransformMatrix);
+
+  // Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags,
+  // so we never need to explicitely unset this flag.
+  if (mFrame->Preserves3D()) {
+    container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_PRESERVE_3D);
+  }
+  return container.forget();
 }
 
 nsDisplayItem::LayerState
 nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
                                   LayerManager* aManager) {
   if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer))
     return LAYER_ACTIVE;
-  if (!GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel()).Is2D())
+  if (!GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel()).Is2D() || mFrame->Preserves3D())
     return LAYER_ACTIVE;
   nsIFrame* activeScrolledRoot =
     nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);
   return !mStoredList.ChildrenCanBeInactive(aBuilder, 
                                              aManager, 
                                              *mStoredList.GetList(), 
                                              activeScrolledRoot)
       ? LAYER_ACTIVE : LAYER_INACTIVE;
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1007,18 +1007,16 @@ public:
    * GetUnderlyingFrame() on each item. z-index is ignored.
    * @param aCommonAncestor a common ancestor of all the content elements
    * associated with the display items, for speeding up tree order
    * checks, or nsnull if not known; it's only a hint, if it is not an
    * ancestor of some elements, then we lose performance but not correctness
    */
   void SortByContentOrder(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor);
 
-  void SortByZPosition(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor);
-
   /**
    * Generic stable sort. Take care, because some of the items might be nsDisplayLists
    * themselves.
    * aCmp(item1, item2) should return true if item1 <= item2. We sort the items
    * into increasing order.
    */
   typedef bool (* SortLEQ)(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
                              void* aClosure);