Bug 564993. Part 5: Change ThebesLayer painting to be callback-based; move layer tree construction to FrameLayerBuilder. r=Bas,mats,sr=vlad
☠☠ backed out by c00ecd45cad8 ☠ ☠
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 21 May 2010 15:20:48 +1200
changeset 42579 b37bdb032fe774d3795cf37f4a445c0f62f06c66
parent 42578 f4f9d45743a8b9a5ccf0d2cfe7d34a6df7af3e47
child 42580 229f7795d5d1fc855535801a5ab56e3225c72feb
child 42591 c00ecd45cad848858798599c416c11ed445a9d3a
push id13409
push userrocallahan@mozilla.com
push dateSun, 23 May 2010 21:42:20 +0000
treeherdermozilla-central@5a490984d550 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas, mats, vlad
bugs564993
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 564993. Part 5: Change ThebesLayer painting to be callback-based; move layer tree construction to FrameLayerBuilder. r=Bas,mats,sr=vlad
embedding/browser/webBrowser/nsWebBrowser.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicLayers.cpp
gfx/layers/basic/BasicLayers.h
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
gfx/layers/opengl/ColorLayerOGL.cpp
gfx/layers/opengl/ColorLayerOGL.h
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/ContainerLayerOGL.h
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.h
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/base/Makefile.in
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsPresShell.cpp
--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -1661,16 +1661,29 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShe
    NS_ENSURE_TRUE(mDocShellTreeOwner, NS_ERROR_OUT_OF_MEMORY);
 
    NS_ADDREF(mDocShellTreeOwner);
    mDocShellTreeOwner->WebBrowser(this);
    
    return NS_OK;
 }
 
+static void DrawThebesLayer(ThebesLayer* aLayer,
+                            gfxContext* aContext,
+                            const nsIntRegion& aRegionToDraw,
+                            void* aCallbackData)
+{
+  nscolor* color = static_cast<nscolor*>(aCallbackData);
+  aContext->NewPath();
+  aContext->SetColor(gfxRGBA(*color));
+  nsIntRect dirtyRect = aRegionToDraw.GetBounds();
+  aContext->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
+  aContext->Fill();  
+}
+
 /* static */
 nsEventStatus nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
 {
   nsWebBrowser  *browser = nsnull;
   void          *data = nsnull;
   nsIWidget     *widget = aEvent->widget;
 
   if (!widget)
@@ -1691,29 +1704,17 @@ nsEventStatus nsWebBrowser::HandleEvent(
       layerManager->BeginTransaction();
       nsRefPtr<ThebesLayer> root = layerManager->CreateThebesLayer();
       nsPaintEvent* paintEvent = static_cast<nsPaintEvent*>(aEvent);
       nsIntRect dirtyRect = paintEvent->region.GetBounds();
       if (root) {
           root->SetVisibleRegion(dirtyRect);
           layerManager->SetRoot(root);
       }
-      layerManager->EndConstruction();
-      if (root) {
-          nsIntRegion toDraw;
-          gfxContext* ctx = root->BeginDrawing(&toDraw);
-          if (ctx) {
-              ctx->NewPath();
-              ctx->SetColor(gfxRGBA(browser->mBackgroundColor));
-              ctx->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
-              ctx->Fill();
-          }
-      }
-      root->EndDrawing();
-      layerManager->EndTransaction();
+      layerManager->EndTransaction(DrawThebesLayer, &browser->mBackgroundColor);
       return nsEventStatus_eConsumeDoDefault;
     }
 
   case NS_ACTIVATE: {
 #if defined(DEBUG_smaug)
     nsCOMPtr<nsIDOMDocument> domDocument = do_GetInterface(browser->mDocShell);
     nsAutoString documentURI;
     if (domDocument) {
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -138,24 +138,39 @@ public:
    * Start a new transaction. Nested transactions are not allowed so
    * there must be no transaction currently in progress. 
    * This transaction will render the contents of the layer tree to
    * the given target context. The rendering will be complete when
    * EndTransaction returns.
    */
   virtual void BeginTransactionWithTarget(gfxContext* aTarget) = 0;
   /**
-   * Finish the construction phase of the transaction and enter the
-   * drawing phase.
+   * Function called to draw the contents of each ThebesLayer.
+   * aRegionToDraw contains the region that needs to be drawn.
+   * This would normally be a subregion of the visible region. Drawing is
+   * not necessarily clipped to aRegionToDraw.
+   * The callee must draw all of aRegionToDraw.
+   * 
+   * aContext must not be used after the call has returned.
+   * We guarantee that buffered contents in the visible
+   * region are valid once drawing is complete.
    */
-  virtual void EndConstruction() = 0;
+  typedef void (* DrawThebesLayerCallback)(ThebesLayer* aLayer,
+                                           gfxContext* aContext,
+                                           const nsIntRegion& aRegionToDraw,
+                                           void* aCallbackData);
   /**
-   * Complete the transaction.
+   * Finish the construction phase of the transaction, perform the
+   * drawing phase, and end the transaction.
+   * During the drawing phase, all ThebesLayers in the tree are
+   * drawn in tree order, exactly once each, except for those layers
+   * where it is known that the visible region is empty.
    */
-  virtual void EndTransaction() = 0;
+  virtual void EndTransaction(DrawThebesLayerCallback aCallback,
+                              void* aCallbackData) = 0;
 
   /**
    * CONSTRUCTION PHASE ONLY
    * Set the root layer.
    */
   virtual void SetRoot(Layer* aLayer) = 0;
 
   /**
@@ -192,16 +207,18 @@ public:
   /**
    * Type of layer manager his is. This is to be used sparsely in order to
    * avoid a lot of Layers backend specific code. It should be used only when
    * Layers backend specific functionality is necessary.
    */
   virtual LayersBackend GetBackendType() = 0;
 };
 
+class ThebesLayer;
+
 /**
  * A Layer represents anything that can be rendered onto a destination
  * surface.
  */
 class THEBES_API Layer {
   NS_INLINE_DECL_REFCOUNTING(Layer)  
 
 public:
@@ -293,16 +310,22 @@ public:
   virtual Layer* GetFirstChild() { return nsnull; }
   const gfx3DMatrix& GetTransform() { return mTransform; }
 
   // This setter and getter can be used anytime.
   void SetUserData(void* aData) { mUserData = aData; }
   void* GetUserData() { return mUserData; }
 
   /**
+   * Dynamic downcast to a Thebes layer. Returns null if this is not
+   * a ThebesLayer.
+   */
+  virtual ThebesLayer* AsThebesLayer() { return nsnull; }
+  
+  /**
    * Only the implementation should call this. This is per-implementation
    * private data. Normally, all layers with a given layer manager
    * use the same type of ImplData.
    */
   void* ImplData() { return mImplData; }
 
   /**
    * Only the implementation should use these methods.
@@ -353,46 +376,17 @@ public:
   /**
    * CONSTRUCTION PHASE ONLY
    * Tell this layer that the content in some region has changed and
    * will need to be repainted. This area is removed from the valid
    * region.
    */
   virtual void InvalidateRegion(const nsIntRegion& aRegion) = 0;
 
-  /**
-   * DRAWING PHASE ONLY
-   * Start drawing into the layer. On return, aRegionToDraw contains the
-   * region that needs to be drawn in by the caller. This would normally
-   * be a subregion of the visible region. Drawing is not necessarily
-   * clipped to aRegionToDraw.
-   * 
-   * No other layer operations are allowed until we call EndDrawing on this
-   * layer. During the drawing phase, all ThebesLayers in the tree must be
-   * drawn in tree order, exactly once each, except for those layers
-   * where it is known that the visible region is empty. (Calling
-   * BeginDrawing on non-visible layers is allowed, but aRegionToDraw
-   * will return empty.)
-   * 
-   * When an empty region is returned in aRegionToDraw, BeginDrawing
-   * may return a null context.
-   * 
-   * The layer system will hold a reference to the returned gfxContext*
-   * until EndDrawing is called. The returned gfxContext must not be used
-   * after EndDrawing is called.
-   */
-  virtual gfxContext* BeginDrawing(nsIntRegion* aRegionToDraw) = 0;
-  /**
-   * DRAWING PHASE ONLY
-   * We've finished drawing into this layer. At this point the caller
-   * must have drawn all of aRegionToDraw that was returned by
-   * BeginDrawing, and we guarantee that buffered contents in the visible
-   * region are now valid.
-   */
-  virtual void EndDrawing() = 0;
+  virtual ThebesLayer* AsThebesLayer() { return this; }
 
 protected:
   ThebesLayer(LayerManager* aManager, void* aImplData)
     : Layer(aManager, aImplData) {}
 };
 
 /**
  * A Layer which other layers render into. It holds references to its
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -89,17 +89,19 @@ public:
   const nsIntRegion& GetVisibleRegion() { return mVisibleRegion; }
 
   /**
    * Layers that paint themselves, such as ImageLayers, should paint
    * in response to this method call. aContext will already have been
    * set up to account for all the properties of the layer (transform,
    * opacity, etc).
    */
-  virtual void Paint(gfxContext* aContext) {}
+  virtual void Paint(gfxContext* aContext,
+                     LayerManager::DrawThebesLayerCallback aCallback,
+                     void* aCallbackData) {}
 
 protected:
   nsIntRegion mVisibleRegion;
 };
 
 static BasicImplData*
 ToData(Layer* aLayer)
 {
@@ -235,50 +237,38 @@ public:
     mVisibleRegion = aRegion;
   }
   virtual void InvalidateRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
   }
 
-  virtual gfxContext* BeginDrawing(nsIntRegion* aRegionToDraw);
-  virtual void EndDrawing();
+  virtual void Paint(gfxContext* aContext,
+                     LayerManager::DrawThebesLayerCallback aCallback,
+                     void* aCallbackData);
 
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
 };
 
-gfxContext*
-BasicThebesLayer::BeginDrawing(nsIntRegion* aRegionToDraw)
+void
+BasicThebesLayer::Paint(gfxContext* aContext,
+                        LayerManager::DrawThebesLayerCallback aCallback,
+                        void* aCallbackData)
 {
-  NS_ASSERTION(BasicManager()->IsBeforeInTree(BasicManager()->GetLastPainted(), this),
-               "Painting layers out of order");
   NS_ASSERTION(BasicManager()->InDrawing(),
                "Can only draw in drawing phase");
   gfxContext* target = BasicManager()->GetTarget();
-  if (!target)
-    return nsnull;
-
-  BasicManager()->AdvancePaintingTo(this);
+  NS_ASSERTION(target, "We shouldn't be called if there's no target");
 
-  *aRegionToDraw = mVisibleRegion;
-  return target;
-}
-
-void
-BasicThebesLayer::EndDrawing()
-{
-  NS_ASSERTION(BasicManager()->InDrawing(),
-               "Can only draw in drawing phase");
-  NS_ASSERTION(BasicManager()->GetLastPainted() == this,
-               "Not currently drawing this layer");
+  aCallback(this, target, mVisibleRegion, aCallbackData);
 }
 
 class BasicImageLayer : public ImageLayer, BasicImplData {
 public:
   BasicImageLayer(BasicLayerManager* aLayerManager) :
     ImageLayer(aLayerManager, static_cast<BasicImplData*>(this))
   {
     MOZ_COUNT_CTOR(BasicImageLayer);
@@ -290,27 +280,31 @@ public:
 
   virtual void SetVisibleRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     mVisibleRegion = aRegion;
   }
 
-  virtual void Paint(gfxContext* aContext);
+  virtual void Paint(gfxContext* aContext,
+                     LayerManager::DrawThebesLayerCallback aCallback,
+                     void* aCallbackData);
 
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
 };
 
 void
-BasicImageLayer::Paint(gfxContext* aContext)
+BasicImageLayer::Paint(gfxContext* aContext,
+                       LayerManager::DrawThebesLayerCallback aCallback,
+                       void* aCallbackData)
 {
   if (!mContainer)
     return;
 
   gfxIntSize size;
   nsRefPtr<gfxASurface> surface = mContainer->GetCurrentAsSurface(&size);
   if (!surface) {
     return;
@@ -360,27 +354,31 @@ public:
 
   virtual void SetVisibleRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     mVisibleRegion = aRegion;
   }
 
-  virtual void Paint(gfxContext* aContext);
+  virtual void Paint(gfxContext* aContext,
+                     LayerManager::DrawThebesLayerCallback aCallback,
+                     void* aCallbackData);
 
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
 };
 
 void
-BasicColorLayer::Paint(gfxContext* aContext)
+BasicColorLayer::Paint(gfxContext* aContext,
+                       LayerManager::DrawThebesLayerCallback aCallback,
+                       void* aCallbackData)
 {
   aContext->SetColor(mColor);
   aContext->Paint();
 }
 
 class BasicCanvasLayer : public CanvasLayer,
                          BasicImplData
 {
@@ -392,17 +390,19 @@ public:
   }
   virtual ~BasicCanvasLayer()
   {
     MOZ_COUNT_DTOR(BasicCanvasLayer);
   }
 
   virtual void Initialize(const Data& aData);
   virtual void Updated(const nsIntRect& aRect);
-  virtual void Paint(gfxContext* aContext);
+  virtual void Paint(gfxContext* aContext,
+                     LayerManager::DrawThebesLayerCallback aCallback,
+                     void* aCallbackData);
 
 protected:
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<mozilla::gl::GLContext> mGLContext;
 
   nsIntRect mBounds;
   nsIntRect mUpdatedRect;
 
@@ -479,17 +479,19 @@ BasicCanvasLayer::Updated(const nsIntRec
   }
 
   // sanity
   NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect),
                "CanvasLayer: Updated rect bigger than bounds!");
 }
 
 void
-BasicCanvasLayer::Paint(gfxContext* aContext)
+BasicCanvasLayer::Paint(gfxContext* aContext,
+                        LayerManager::DrawThebesLayerCallback aCallback,
+                        void* aCallbackData)
 {
   nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
 
   pat->SetFilter(mFilter);
   pat->SetExtend(gfxPattern::EXTEND_PAD);
 
   gfxRect r(0, 0, mBounds.width, mBounds.height);
   gfxMatrix m;
@@ -506,17 +508,17 @@ BasicCanvasLayer::Paint(gfxContext* aCon
   if (mNeedsYFlip) {
     aContext->SetMatrix(m);
   }
 
   mUpdatedRect.Empty();
 }
 
 BasicLayerManager::BasicLayerManager(gfxContext* aContext) :
-  mDefaultTarget(aContext), mLastPainted(nsnull)
+  mDefaultTarget(aContext)
 #ifdef DEBUG
   , mPhase(PHASE_NONE)
 #endif
 {
   MOZ_COUNT_CTOR(BasicLayerManager);
 }
 
 BasicLayerManager::~BasicLayerManager()
@@ -549,34 +551,33 @@ BasicLayerManager::BeginTransactionWithT
   NS_ASSERTION(mPhase == PHASE_NONE, "Nested transactions not allowed");
 #ifdef DEBUG
   mPhase = PHASE_CONSTRUCTION;
 #endif
   mTarget = aTarget;
 }
 
 void
-BasicLayerManager::EndConstruction()
+BasicLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
+                                  void* aCallbackData)
 {
   NS_ASSERTION(mRoot, "Root not set");
   NS_ASSERTION(mPhase == PHASE_CONSTRUCTION, "Should be in construction phase");
 #ifdef DEBUG
   mPhase = PHASE_DRAWING;
 #endif
-}
 
-void
-BasicLayerManager::EndTransaction()
-{
-  NS_ASSERTION(mPhase == PHASE_DRAWING, "Should be in drawing phase");
+  if (mTarget) {
+    PaintLayer(mRoot, aCallback, aCallbackData);
+    mTarget = nsnull;
+  }
+
 #ifdef DEBUG
   mPhase = PHASE_NONE;
 #endif
-  AdvancePaintingTo(nsnull);
-  mTarget = nsnull;
   // No retained layers supported for now
   mRoot = nsnull;
 }
 
 void
 BasicLayerManager::SetRoot(Layer* aLayer)
 {
   NS_ASSERTION(aLayer, "Root can't be null");
@@ -620,20 +621,24 @@ UseOpaqueSurface(Layer* aLayer)
   // in the container.
   BasicContainerLayer* parent =
     static_cast<BasicContainerLayer*>(aLayer->GetParent());
   return parent && parent->GetFirstChild() == aLayer &&
          UseOpaqueSurface(parent);
 }
 
 void
-BasicLayerManager::BeginPaintingLayer(Layer* aLayer)
+BasicLayerManager::PaintLayer(Layer* aLayer,
+                              DrawThebesLayerCallback aCallback,
+                              void* aCallbackData)
 {
   PRBool needsGroup = NeedsGroup(aLayer);
-  if ((needsGroup || NeedsState(aLayer)) && mTarget) {
+  PRBool needsSaveRestore = needsGroup || NeedsState(aLayer);
+
+ if (needsSaveRestore) {
     mTarget->Save();
 
     if (aLayer->GetClipRect()) {
       const nsIntRect& r = *aLayer->GetClipRect();
       mTarget->NewPath();
       mTarget->Rectangle(gfxRect(r.x, r.y, r.width, r.height), PR_TRUE);
       mTarget->Clip();
     }
@@ -662,76 +667,32 @@ BasicLayerManager::BeginPaintingLayer(La
       mTarget->SetMatrix(currentMatrix);
 
       gfxASurface::gfxContentType type = UseOpaqueSurface(aLayer)
           ? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA;
       mTarget->PushGroup(type);
     }
   }
 
-  mLastPainted = aLayer;
+  ToData(aLayer)->Paint(mTarget, aCallback, aCallbackData);
+  for (Layer* child = aLayer->GetFirstChild(); child;
+       child = child->GetNextSibling()) {
+    PaintLayer(child, aCallback, aCallbackData);
+  }
 
-  // For layers that paint themselves (e.g., BasicImageLayer), paint
-  // them now.
-  ToData(aLayer)->Paint(mTarget);
-}
-
-void
-BasicLayerManager::EndPaintingLayer()
-{
-  PRBool needsGroup = NeedsGroup(mLastPainted);
-  if ((needsGroup || NeedsState(mLastPainted)) && mTarget) {
+  if (needsSaveRestore) {
     if (needsGroup) {
       mTarget->PopGroupToSource();
-      mTarget->Paint(mLastPainted->GetOpacity());
+      mTarget->Paint(aLayer->GetOpacity());
     }
 
     mTarget->Restore();
   }
 }
 
-void
-BasicLayerManager::AdvancePaintingTo(BasicThebesLayer* aLayer)
-{
-  NS_ASSERTION(!aLayer || IsBeforeInTree(mLastPainted, aLayer),
-               "Painting layers out of order");
-
-  // Traverse the layer tree from mLastPainted to aLayer, calling
-  // BeginPaintingLayer and EndPaintingLayer as we enter or exit layers.
-  do {
-    Layer* firstChild;
-    Layer* nextSibling;
-    // Advance mLastPainted one step through the tree in preorder
-    if (!mLastPainted) {
-      // This is the first AdvancePaintingTo call. Start at the root.
-      BeginPaintingLayer(mRoot);
-    } else if ((firstChild = mLastPainted->GetFirstChild()) != nsnull) {
-      // Descend into our first child, if there is one.
-      BeginPaintingLayer(firstChild);
-    } else if ((nextSibling = mLastPainted->GetNextSibling()) != nsnull) {
-      // There are no children to descend into. Leave this layer and
-      // advance to our next sibling, if there is one.
-      EndPaintingLayer();
-      BeginPaintingLayer(nextSibling);
-    } else {
-      // There are no children to descend into and we have no next sibling.
-      // Exit layers until we find a layer which has a next sibling
-      // (or we exit the root).
-      do {
-        EndPaintingLayer();
-        mLastPainted = mLastPainted->GetParent();
-      } while (mLastPainted && !mLastPainted->GetNextSibling());
-      if (mLastPainted) {
-        EndPaintingLayer();
-        BeginPaintingLayer(mLastPainted->GetNextSibling());
-      }
-    }
-  } while (mLastPainted != aLayer);
-}
-
 already_AddRefed<ThebesLayer>
 BasicLayerManager::CreateThebesLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<ThebesLayer> layer = new BasicThebesLayer(this);
   return layer.forget();
 }
 
@@ -762,59 +723,10 @@ BasicLayerManager::CreateColorLayer()
 already_AddRefed<CanvasLayer>
 BasicLayerManager::CreateCanvasLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<CanvasLayer> layer = new BasicCanvasLayer(this);
   return layer.forget();
 }
 
-#ifdef DEBUG
-static void
-AppendAncestors(Layer* aLayer, nsTArray<Layer*>* aAncestors)
-{
-  while (aLayer) {
-    aAncestors->AppendElement(aLayer);
-    aLayer = aLayer->GetParent();
-  }
-}
-
-PRBool
-BasicLayerManager::IsBeforeInTree(Layer* aBefore, Layer* aLayer)
-{
-  if (!aBefore) {
-    return PR_TRUE;
-  }
-  nsAutoTArray<Layer*,8> beforeAncestors, afterAncestors;
-  AppendAncestors(aBefore, &beforeAncestors);
-  AppendAncestors(aLayer, &afterAncestors);
-  PRInt32 beforeIndex = beforeAncestors.Length() - 1;
-  PRInt32 afterIndex = afterAncestors.Length() - 1;
-  NS_ASSERTION(beforeAncestors[beforeIndex] == mRoot, "aBefore not in tree?");
-  NS_ASSERTION(afterAncestors[afterIndex] == mRoot, "aLayer not in tree?");
-  --beforeIndex;
-  --afterIndex;
-  while (beforeIndex >= 0 && afterIndex >= 0) {
-    if (beforeAncestors[beforeIndex] != afterAncestors[afterIndex]) {
-      BasicContainerLayer* parent =
-        static_cast<BasicContainerLayer*>(beforeAncestors[beforeIndex + 1]);
-      for (Layer* child = parent->GetFirstChild();
-           child != afterAncestors[afterIndex];
-           child = child->GetNextSibling()) {
-        if (child == beforeAncestors[beforeIndex]) {
-          return PR_TRUE;
-        }
-      }
-      return PR_FALSE;
-    }
-    --beforeIndex;
-    --afterIndex;
-  }
-  if (afterIndex > 0) {
-    // aBefore is an ancestor of aLayer, so it's before aLayer in preorder
-    return PR_TRUE;
-  }
-  return PR_FALSE;
-}
-#endif
-
 }
 }
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -73,62 +73,46 @@ public:
   /**
    * Set the default target context that will be used when BeginTransaction
    * is called. This can only be called outside a transaction.
    */
   void SetDefaultTarget(gfxContext* aContext);
 
   virtual void BeginTransaction();
   virtual void BeginTransactionWithTarget(gfxContext* aTarget);
-  virtual void EndConstruction();
-  virtual void EndTransaction();
+  virtual void EndTransaction(DrawThebesLayerCallback aCallback,
+                              void* aCallbackData);
 
   virtual void SetRoot(Layer* aLayer);
 
   virtual already_AddRefed<ThebesLayer> CreateThebesLayer();
   virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
   virtual already_AddRefed<ImageLayer> CreateImageLayer();
   virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
   virtual already_AddRefed<ImageContainer> CreateImageContainer();
   virtual already_AddRefed<ColorLayer> CreateColorLayer();
   virtual LayersBackend GetBackendType() { return LAYERS_BASIC; }
 
 #ifdef DEBUG
   PRBool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
   PRBool InDrawing() { return mPhase == PHASE_DRAWING; }
-  PRBool IsBeforeInTree(Layer* aBefore, Layer* aLayer);
 #endif
-  // Prepares mTarget for painting into aLayer. Layers are painted
-  // in tree order, so this method essentially traverses the layer tree
-  // in preorder from mLastPainted to aLayer, doing whatever's needed
-  // as we exit container layers and enter new container layers, and
-  // drawing any non-ThebesLayers we encounter.
-  void AdvancePaintingTo(BasicThebesLayer* aLayer);
-  Layer* GetLastPainted() { return mLastPainted; }
   gfxContext* GetTarget() { return mTarget; }
 
 private:
-  // This gets called when we start painting aLayer. It can change
-  // the state of mTarget by saving state, setting clipping and/or
-  // pushing a group.
-  void BeginPaintingLayer(Layer* aLayer);
-  // This gets called when we finish painting aLayer. It can change
-  // the state of mTarget by popping a group and/or restoring the state.
-  void EndPaintingLayer();
+  // Paints aLayer to mTarget.
+  void PaintLayer(Layer* aLayer,
+                  DrawThebesLayerCallback aCallback,
+                  void* aCallbackData);
 
   nsRefPtr<Layer> mRoot;
   // The default context for BeginTransaction.
   nsRefPtr<gfxContext> mDefaultTarget;
-  // The context to draw into. This is always the context that
-  // our ThebesLayers will return.
+  // The context to draw into.
   nsRefPtr<gfxContext> mTarget;
-  // The most recently painted layer during the drawing phase of
-  // a transaction, or null if no layer has been painted in this
-  // transaction.
-  Layer* mLastPainted;
 
 #ifdef DEBUG
   enum TransactionPhase { PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING };
   TransactionPhase mPhase;
 #endif
 };
 
 }
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -193,17 +193,19 @@ CanvasLayerOGL::Updated(const nsIntRect&
     }
   }
 
   // sanity
   NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect), "CanvasLayer: Updated rect bigger than bounds!");
 }
 
 void
-CanvasLayerOGL::RenderLayer(int aPreviousDestination)
+CanvasLayerOGL::RenderLayer(int aPreviousDestination,
+                            DrawThebesLayerCallback aCallback,
+                            void* aCallbackData)
 {
   LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
   GLContext *gl = glManager->gl();
   glManager->MakeCurrent();
 
   float quadTransform[4][4];
   // Transform the quad to the size of the canvas.
   memset(&quadTransform, 0, sizeof(quadTransform));
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -61,17 +61,19 @@ public:
 
   // CanvasLayer implementation
   virtual void Initialize(const Data& aData);
   virtual void Updated(const nsIntRect& aRect);
 
   // LayerOGL implementation
   virtual LayerType GetType() { return TYPE_CANVAS; }
   virtual Layer* GetLayer() { return this; }
-  virtual void RenderLayer(int aPreviousDestination);
+  virtual void RenderLayer(int aPreviousDestination,
+                           DrawThebesLayerCallback aCallback,
+                           void* aCallbackData);
 
 protected:
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<GLContext> mGLContext;
 
   unsigned int mTexture;
 
   nsIntRect mBounds;
--- a/gfx/layers/opengl/ColorLayerOGL.cpp
+++ b/gfx/layers/opengl/ColorLayerOGL.cpp
@@ -48,17 +48,17 @@ ColorLayerOGL::GetType()
 
 Layer*
 ColorLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
-ColorLayerOGL::RenderLayer(int)
+ColorLayerOGL::RenderLayer(int, DrawThebesLayerCallback, void*)
 {
   static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
 
   // XXX we might be able to improve performance by using glClear
 
   float quadTransform[4][4];
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
   // Transform the quad to the size of the visible area.
--- a/gfx/layers/opengl/ColorLayerOGL.h
+++ b/gfx/layers/opengl/ColorLayerOGL.h
@@ -56,17 +56,19 @@ public:
 
   virtual void SetVisibleRegion(const nsIntRegion& aRegion) { mVisibleRegion = aRegion; }
 
   // LayerOGL Implementation
   virtual LayerType GetType();
 
   virtual Layer* GetLayer();
 
-  virtual void RenderLayer(int aPreviousDestination);
+  virtual void RenderLayer(int aPreviousDestination,
+                           DrawThebesLayerCallback aCallback,
+                           void* aCallbackData);
 
 protected:
   nsIntRegion mVisibleRegion;
 };
 
 } /* layers */
 } /* mozilla */
 #endif /* GFX_COLORLAYEROGL_H */
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -120,17 +120,19 @@ ContainerLayerOGL::GetFirstChildOGL()
 {
   if (!mFirstChild) {
     return nsnull;
   }
   return static_cast<LayerOGL*>(mFirstChild->ImplData());
 }
 
 void
-ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer)
+ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
+                               DrawThebesLayerCallback aCallback,
+                               void* aCallbackData)
 {
   /**
    * Setup our temporary texture for rendering the contents of this container.
    */
   GLuint containerSurface;
   GLuint frameBuffer;
   RGBLayerProgram *rgbProgram =
     static_cast<LayerManagerOGL*>(mManager)->GetRGBLayerProgram();
@@ -197,17 +199,17 @@ ContainerLayerOGL::RenderLayer(int aPrev
       gl()->fScissor(clipRect->x - GetVisibleRect().x,
                    clipRect->y - GetVisibleRect().y,
                    clipRect->width,
                    clipRect->height);
     } else {
       gl()->fScissor(0, 0, GetVisibleRect().width, GetVisibleRect().height);
     }
 
-    layerToRender->RenderLayer(frameBuffer);
+    layerToRender->RenderLayer(frameBuffer, aCallback, aCallbackData);
     layerToRender = layerToRender->GetNextSibling();
   }
 
   if (GetOpacity() != 1.0) {
     // Unbind the current framebuffer and rebind the previous one.
     gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
     gl()->fDeleteFramebuffers(1, &frameBuffer);
 
--- a/gfx/layers/opengl/ContainerLayerOGL.h
+++ b/gfx/layers/opengl/ContainerLayerOGL.h
@@ -63,17 +63,19 @@ public:
   LayerType GetType();
 
   Layer* GetLayer();
 
   LayerOGL* GetFirstChildOGL();
 
   PRBool IsEmpty();
 
-  void RenderLayer(int aPreviousFrameBuffer);
+  void RenderLayer(int aPreviousFrameBuffer,
+                   DrawThebesLayerCallback aCallback,
+                   void* aCallbackData);
 private:
   nsIntRect mVisibleRect;
 
   GLuint mTexture;
 };
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -264,17 +264,18 @@ ImageLayerOGL::GetType()
 
 Layer*
 ImageLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
-ImageLayerOGL::RenderLayer(int)
+ImageLayerOGL::RenderLayer(int, DrawThebesLayerCallback aCallback,
+                           void* aCallbackData)
 {
   if (!GetContainer()) {
     return;
   }
 
   LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(mManager);
   manager->MakeCurrent();
 
--- a/gfx/layers/opengl/ImageLayerOGL.h
+++ b/gfx/layers/opengl/ImageLayerOGL.h
@@ -170,17 +170,19 @@ public:
     mImplData = static_cast<LayerOGL*>(this);
   }
 
   // LayerOGL Implementation
   virtual LayerType GetType();
 
   virtual Layer* GetLayer();
 
-  virtual void RenderLayer(int aPreviousDestination);
+  virtual void RenderLayer(int aPreviousDestination,
+                           DrawThebesLayerCallback aCallback,
+                           void* aCallbackData);
 };
 
 class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage
 {
   typedef mozilla::gl::GLContext GLContext;
 
 public:
   PlanarYCbCrImageOGL(RecycleBin *aRecycleBin);
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -277,24 +277,20 @@ LayerManagerOGL::BeginTransaction()
 
 void
 LayerManagerOGL::BeginTransactionWithTarget(gfxContext *aTarget)
 {
   mTarget = aTarget;
 }
 
 void
-LayerManagerOGL::EndConstruction()
+LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
+                                void* aCallbackData)
 {
-}
-
-void
-LayerManagerOGL::EndTransaction()
-{
-  Render();
+  Render(aCallback, aCallbackData);
   mTarget = NULL;
 }
 
 void
 LayerManagerOGL::SetRoot(Layer *aLayer)
 {
   mRootLayer =  static_cast<LayerOGL*>(aLayer->ImplData());;
 }
@@ -353,17 +349,18 @@ LayerManagerOGL::SetClippingEnabled(PRBo
 
 void
 LayerManagerOGL::MakeCurrent()
 {
     mGLContext->MakeCurrent();
 }
 
 void
-LayerManagerOGL::Render()
+LayerManagerOGL::Render(DrawThebesLayerCallback aCallback,
+                        void* aCallbackData)
 {
   nsIntRect rect;
   mWidget->GetBounds(rect);
   GLint width = rect.width;
   GLint height = rect.height;
 
   MakeCurrent();
   SetupBackBuffer();
@@ -379,17 +376,17 @@ LayerManagerOGL::Render()
   if (mRootLayer) {
     const nsIntRect *clipRect = mRootLayer->GetLayer()->GetClipRect();
     if (clipRect) {
       mGLContext->fScissor(clipRect->x, clipRect->y, clipRect->width, clipRect->height);
     } else {
       mGLContext->fScissor(0, 0, width, height);
     }
 
-    mRootLayer->RenderLayer(mFrameBuffer);
+    mRootLayer->RenderLayer(mFrameBuffer, aCallback, aCallbackData);
   }
 
   if (mTarget) {
     CopyToTarget();
   } else {
     /**
      * Draw our backbuffer to the screen without using vertex or fragment
      * shaders. We're fine with just calculating the viewport coordinates
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -211,17 +211,18 @@ public:
    * LayerManager implementation.
    */
   void BeginTransaction();
 
   void BeginTransactionWithTarget(gfxContext* aTarget);
 
   void EndConstruction();
 
-  void EndTransaction();
+  virtual void EndTransaction(DrawThebesLayerCallback aCallback,
+                              void* aCallbackData);
 
   void SetRoot(Layer* aLayer);
   
   virtual already_AddRefed<ThebesLayer> CreateThebesLayer();
 
   virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
 
   virtual already_AddRefed<ImageLayer> CreateImageLayer();
@@ -288,17 +289,18 @@ private:
 
   /**
    * Region we're clipping our current drawing to.
    */
   nsIntRegion mClippingRegion;
   /**
    * Render the current layer tree to the active target.
    */
-  void Render();
+  void Render(DrawThebesLayerCallback aCallback,
+              void* aCallbackData);
   /**
    * Setup the pipeline.
    */
   void SetupPipeline();
   /**
    * Setup the backbuffer.
    *
    * \return PR_TRUE if setup was succesful
@@ -311,16 +313,18 @@ private:
 };
 
 /**
  * General information and tree management for OGL layers.
  */
 class LayerOGL
 {
 public:
+  typedef LayerManager::DrawThebesLayerCallback DrawThebesLayerCallback;
+
   LayerOGL(LayerManagerOGL *aManager);
 
   enum LayerType {
     TYPE_THEBES,
     TYPE_CONTAINER,
     TYPE_IMAGE,
     TYPE_COLOR,
     TYPE_CANVAS
@@ -331,17 +335,18 @@ public:
   LayerOGL *GetNextSibling();
   virtual LayerOGL *GetFirstChildOGL() { return nsnull; }
 
   void SetNextSibling(LayerOGL *aParent);
   void SetFirstChild(LayerOGL *aParent);
 
   virtual Layer* GetLayer() = 0;
 
-  virtual void RenderLayer(int aPreviousFrameBuffer) = 0;
+  virtual void RenderLayer(int aPreviousFrameBuffer, DrawThebesLayerCallback aCallback,
+                           void* aCallbackData) = 0;
 
   typedef mozilla::gl::GLContext GLContext;
 
   GLContext *gl() const { return mOGLManager->gl(); }
 protected:
   LayerManagerOGL *mOGLManager;
   LayerOGL *mNextSibling;
 };
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -123,125 +123,100 @@ void
 ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
 {
   nsIntRegion invalidatedRegion;
   invalidatedRegion.Or(aRegion, mInvalidatedRect);
   invalidatedRegion.And(invalidatedRegion, mVisibleRect);
   mInvalidatedRect = invalidatedRegion.GetBounds();
 }
 
-gfxContext *
-ThebesLayerOGL::BeginDrawing(nsIntRegion *aRegion)
-{
-  if (mInvalidatedRect.IsEmpty()) {
-    aRegion->SetEmpty();
-    return NULL;
-  }
-  if (!mTexture) {
-    aRegion->SetEmpty();
-    return NULL;
-  }
-  *aRegion = mInvalidatedRect;
-
-  gfxASurface::gfxImageFormat imageFormat;
-
-  if (UseOpaqueSurface(this)) {
-    imageFormat = gfxASurface::ImageFormatRGB24;
-  } else {
-    imageFormat = gfxASurface::ImageFormatARGB32;
-  }
-
-  mDestinationSurface =
-    gfxPlatform::GetPlatform()->
-      CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width,
-                                        mInvalidatedRect.height),
-                             imageFormat);
-
-  mContext = new gfxContext(mDestinationSurface);
-  mContext->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
-  return mContext.get();
-}
-
-void
-ThebesLayerOGL::EndDrawing()
-{
-  static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
-
-  nsRefPtr<gfxImageSurface> imageSurface;
-
-  gfxASurface::gfxImageFormat imageFormat;
-
-  if (UseOpaqueSurface(this)) {
-    imageFormat = gfxASurface::ImageFormatRGB24;
-  } else {
-    imageFormat = gfxASurface::ImageFormatARGB32;
-  }
-
-  switch (mDestinationSurface->GetType()) {
-    case gfxASurface::SurfaceTypeImage:
-      imageSurface = static_cast<gfxImageSurface*>(mDestinationSurface.get());
-      break;
-#ifdef XP_WIN
-    case gfxASurface::SurfaceTypeWin32:
-      imageSurface =
-        static_cast<gfxWindowsSurface*>(mDestinationSurface.get())->
-          GetImageSurface();
-      break;
-#endif
-    default:
-      /** 
-       * XXX - This is very undesirable. Implement this for other platforms in
-       * a more efficient way as well!
-       */
-      {
-        imageSurface = new gfxImageSurface(gfxIntSize(mInvalidatedRect.width,
-                                                      mInvalidatedRect.height),
-                                           imageFormat);
-        nsRefPtr<gfxContext> tmpContext = new gfxContext(imageSurface);
-        tmpContext->SetSource(mDestinationSurface);
-        tmpContext->SetOperator(gfxContext::OPERATOR_SOURCE);
-        tmpContext->Paint();
-      }
-      break;
-  }
-
-  gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-  gl()->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
-                       0,
-                       mInvalidatedRect.x - mVisibleRect.x,
-                       mInvalidatedRect.y - mVisibleRect.y,
-                       mInvalidatedRect.width,
-                       mInvalidatedRect.height,
-                       LOCAL_GL_BGRA,
-                       LOCAL_GL_UNSIGNED_BYTE,
-                       imageSurface->Data());
-
-  mDestinationSurface = NULL;
-  mContext = NULL;
-}
-
 LayerOGL::LayerType
 ThebesLayerOGL::GetType()
 {
   return TYPE_THEBES;
 }
 
 const nsIntRect&
 ThebesLayerOGL::GetVisibleRect()
 {
   return mVisibleRect;
 }
 
 void
-ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer)
+ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
+                            DrawThebesLayerCallback aCallback,
+                            void* aCallbackData)
 {
   if (!mTexture) {
     return;
   }
 
+  if (!mInvalidatedRect.IsEmpty()) {
+    gfxASurface::gfxImageFormat imageFormat;
+
+    if (UseOpaqueSurface(this)) {
+      imageFormat = gfxASurface::ImageFormatRGB24;
+    } else {
+      imageFormat = gfxASurface::ImageFormatARGB32;
+    }
+
+    nsRefPtr<gfxASurface> surface =
+      gfxPlatform::GetPlatform()->
+        CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width,
+                                          mInvalidatedRect.height),
+                               imageFormat);
+
+    nsRefPtr<gfxContext> ctx = new gfxContext(surface);
+    ctx->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
+    aCallback(this, ctx, mInvalidatedRect, aCallbackData);
+
+    static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
+
+    nsRefPtr<gfxImageSurface> imageSurface;
+
+    switch (surface->GetType()) {
+      case gfxASurface::SurfaceTypeImage:
+        imageSurface = static_cast<gfxImageSurface*>(surface.get());
+        break;
+#ifdef XP_WIN
+      case gfxASurface::SurfaceTypeWin32:
+        imageSurface =
+          static_cast<gfxWindowsSurface*>(surface.get())->
+            GetImageSurface();
+        break;
+#endif
+      default:
+        /** 
+         * XXX - This is very undesirable. Implement this for other platforms in
+         * a more efficient way as well!
+         */
+        {
+          imageSurface = new gfxImageSurface(gfxIntSize(mInvalidatedRect.width,
+                                                        mInvalidatedRect.height),
+                                             imageFormat);
+          nsRefPtr<gfxContext> tmpContext = new gfxContext(imageSurface);
+          tmpContext->SetSource(surface);
+          tmpContext->SetOperator(gfxContext::OPERATOR_SOURCE);
+          tmpContext->Paint();
+        }
+        break;
+    }
+
+    gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+    gl()->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
+                         0,
+                         mInvalidatedRect.x - mVisibleRect.x,
+                         mInvalidatedRect.y - mVisibleRect.y,
+                         mInvalidatedRect.width,
+                         mInvalidatedRect.height,
+                         LOCAL_GL_BGRA,
+                         LOCAL_GL_UNSIGNED_BYTE,
+                         imageSurface->Data());
+  }
+
   float quadTransform[4][4];
   /*
    * Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position
    * and size.
    */
   memset(&quadTransform, 0, sizeof(quadTransform));
   quadTransform[0][0] = (float)GetVisibleRect().width;
   quadTransform[1][1] = (float)GetVisibleRect().height;
--- a/gfx/layers/opengl/ThebesLayerOGL.h
+++ b/gfx/layers/opengl/ThebesLayerOGL.h
@@ -54,50 +54,38 @@ public:
   virtual ~ThebesLayerOGL();
 
   /** Layer implementation */
   void SetVisibleRegion(const nsIntRegion& aRegion);
 
   /** ThebesLayer implementation */
   void InvalidateRegion(const nsIntRegion& aRegion);
 
-  gfxContext *BeginDrawing(nsIntRegion* aRegionToDraw);
-
-  void EndDrawing();
-
   /** LayerOGL implementation */
   LayerType GetType();
   Layer* GetLayer();
   virtual PRBool IsEmpty();
-  virtual void RenderLayer(int aPreviousFrameBuffer);
+  virtual void RenderLayer(int aPreviousFrameBuffer,
+                           DrawThebesLayerCallback aCallback,
+                           void* aCallbackData);
 
   /** ThebesLayerOGL */
   const nsIntRect &GetVisibleRect();
   const nsIntRect &GetInvalidatedRect();
 
 private:
   /** 
    * Visible rectangle, this is used to know the size and position of the quad
    * when doing the rendering of this layer.
    */
   nsIntRect mVisibleRect;
   /**
    * Currently invalidated rectangular area.
    */
   nsIntRect mInvalidatedRect;
-  /**
-   * Destination surface used for this layer's drawing operation. This is 
-   * created on BeginDrawing() and should be removed on EndDrawing().
-   */
-  nsRefPtr<gfxASurface> mDestinationSurface;
-
-  /**
-   * We hold the reference to the context.
-   */
-  nsRefPtr<gfxContext> mContext;
 
   /**
    * OpenGL Texture
    */
   GLuint mTexture;
 
 };
 
new file mode 100644
--- /dev/null
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -0,0 +1,497 @@
+/* -*- 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) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Robert O'Callahan <robert@ocallahan.org>
+ *
+ * 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 "FrameLayerBuilder.h"
+
+#include "nsDisplayList.h"
+#include "nsPresContext.h"
+#include "nsLayoutUtils.h"
+
+using namespace mozilla::layers;
+
+namespace mozilla {
+
+namespace {
+
+/**
+ * This class iterates through a display list tree, descending only into
+ * nsDisplayClip items, and returns each display item encountered during
+ * such iteration. Along with each item we also return the clip rect
+ * accumulated for the item.
+ */
+class ClippedItemIterator {
+public:
+  ClippedItemIterator(const nsDisplayList* aList)
+  {
+    DescendIntoList(aList, nsnull, nsnull);
+    AdvanceToItem();
+  }
+  PRBool IsDone()
+  {
+    return mStack.IsEmpty();
+  }
+  void Next()
+  {
+    State* top = StackTop();
+    top->mItem = top->mItem->GetAbove();
+    AdvanceToItem();
+  }
+  // Returns null if there is no clipping affecting the item. The
+  // clip rect is in device pixels
+  const gfxRect* GetEffectiveClipRect()
+  {
+    State* top = StackTop();
+    return top->mHasClipRect ? &top->mEffectiveClipRect : nsnull;
+  }
+  nsDisplayItem* Item()
+  {
+    return StackTop()->mItem;
+  }
+
+private:
+  // We maintain a stack of state objects. Each State object represents
+  // where we're up to in the iteration of a list.
+  struct State {
+    // The current item we're at in the list
+    nsDisplayItem* mItem;
+    // The effective clip rect applying to all the items in this list
+    gfxRect mEffectiveClipRect;
+    PRPackedBool mHasClipRect;
+  };
+
+  State* StackTop()
+  {
+    return &mStack[mStack.Length() - 1];
+  }
+  void DescendIntoList(const nsDisplayList* aList,
+                       nsPresContext* aPresContext,
+                       const nsRect* aClipRect)
+  {
+    State* state = mStack.AppendElement();
+    if (!state)
+      return;
+    if (mStack.Length() >= 2) {
+      *state = mStack[mStack.Length() - 2];
+    } else {
+      state->mHasClipRect = PR_FALSE;
+    }
+    state->mItem = aList->GetBottom();
+    if (aClipRect) {
+      gfxRect r(aClipRect->x, aClipRect->y, aClipRect->width, aClipRect->height);
+      r.ScaleInverse(aPresContext->AppUnitsPerDevPixel());
+      if (state->mHasClipRect) {
+        state->mEffectiveClipRect = state->mEffectiveClipRect.Intersect(r);
+      } else {
+        state->mEffectiveClipRect = r;
+        state->mHasClipRect = PR_TRUE;
+      }
+    }
+  }
+  // Advances to an item that the iterator should return.
+  void AdvanceToItem()
+  {
+    while (!mStack.IsEmpty()) {
+      State* top = StackTop();
+      if (!top->mItem) {
+        mStack.SetLength(mStack.Length() - 1);
+        if (!mStack.IsEmpty()) {
+          top = StackTop();
+          top->mItem = top->mItem->GetAbove();
+        }
+        continue;
+      }
+      if (top->mItem->GetType() != nsDisplayItem::TYPE_CLIP)
+        return;
+      nsDisplayClip* clipItem = static_cast<nsDisplayClip*>(top->mItem);
+      nsRect clip = clipItem->GetClipRect();
+      DescendIntoList(clipItem->GetList(),
+                      clipItem->GetClippingFrame()->PresContext(),
+                      &clip);
+    }
+  }
+
+  nsAutoTArray<State,10> mStack;
+};
+
+/**
+ * This class represents a sublist of consecutive items in an nsDisplayList.
+ * The first item in the sublist is mStartItem and the last item
+ * is the item before mEndItem.
+ * 
+ * These sublists are themselves organized into a linked list of all
+ * the ItemGroups associated with a given layer, via mNextItemsForLayer.
+ * This list will have more than one element if the display items in a layer
+ * come from different nsDisplayLists, or if they come from the same
+ * nsDisplayList but they aren't consecutive in that list.
+ * 
+ * These objects are allocated from the nsDisplayListBuilder arena.
+ */
+struct ItemGroup {
+  // If null, then the item group is empty.
+  nsDisplayItem* mStartItem;
+  nsDisplayItem* mEndItem;
+  ItemGroup* mNextItemsForLayer;
+  // The clipping (if any) that needs to be applied to all these items.
+  gfxRect mClipRect;
+  PRPackedBool mHasClipRect;
+
+  ItemGroup() : mStartItem(nsnull), mEndItem(nsnull),
+    mNextItemsForLayer(nsnull), mHasClipRect(PR_FALSE) {}
+
+  void* operator new(size_t aSize,
+                     nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
+    return aBuilder->Allocate(aSize);
+  }
+};
+
+/**
+ * This class represents a layer and the display item(s) it
+ * will render. The items are stored in a linked list of ItemGroups.
+ */
+struct LayerItems {
+  nsRefPtr<Layer> mLayer;
+  // equal to mLayer, or null if mLayer is not a ThebesLayer
+  ThebesLayer* mThebesLayer;
+  ItemGroup* mItems;
+  // The bounds of the visible region for this layer, in device pixels
+  nsIntRect mVisibleRect;
+
+  LayerItems(ItemGroup* aItems) :
+    mThebesLayer(nsnull), mItems(aItems)
+  {
+  }
+
+  void* operator new(size_t aSize,
+                     nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
+    return aBuilder->Allocate(aSize);
+  }
+};
+
+/**
+ * Given a (possibly clipped) display item in aItem, try to append it to
+ * the items in aGroup. If aItem is the next item in the sublist in
+ * aGroup, and the clipping matches, we can just update aGroup in-place,
+ * otherwise we'll allocate a new ItemGroup, add it to the linked list,
+ * and put aItem in the new ItemGroup. We return the ItemGroup into which
+ * aItem was inserted.
+ */
+static ItemGroup*
+AddToItemGroup(nsDisplayListBuilder* aBuilder,
+               ItemGroup* aGroup, nsDisplayItem* aItem,
+               const gfxRect* aClipRect)
+{
+  NS_ASSERTION(!aGroup->mNextItemsForLayer,
+               "aGroup must be the last group in the chain");
+
+  if (!aGroup->mStartItem) {
+    aGroup->mStartItem = aItem;
+    aGroup->mEndItem = aItem->GetAbove();
+    aGroup->mHasClipRect = aClipRect != nsnull;
+    if (aClipRect) {
+      aGroup->mClipRect = *aClipRect;
+    }
+    return aGroup;
+  }
+
+  if (aGroup->mEndItem == aItem &&
+      (aGroup->mHasClipRect
+       ? (aClipRect && aGroup->mClipRect == *aClipRect)
+       : !aClipRect))  {
+    aGroup->mEndItem = aItem->GetAbove();
+    return aGroup;
+  }
+
+  ItemGroup* itemGroup = new (aBuilder) ItemGroup();
+  if (!itemGroup)
+    return aGroup;
+  aGroup->mNextItemsForLayer = itemGroup;
+  return AddToItemGroup(aBuilder, itemGroup, aItem, aClipRect);
+}
+
+/**
+ * Create an empty Thebes layer, with an empty ItemGroup associated with
+ * it, and append it to aLayers.
+ */
+static ItemGroup*
+CreateEmptyThebesLayer(nsDisplayListBuilder* aBuilder,
+                       LayerManager* aManager,
+                       nsTArray<LayerItems*>* aLayers)
+{
+  ItemGroup* itemGroup = new (aBuilder) ItemGroup();
+  if (!itemGroup)
+    return nsnull;
+  nsRefPtr<ThebesLayer> thebesLayer = aManager->CreateThebesLayer();
+  if (!thebesLayer)
+    return nsnull;
+  LayerItems* layerItems = new (aBuilder) LayerItems(itemGroup);
+  aLayers->AppendElement(layerItems);
+  thebesLayer->SetUserData(layerItems);
+  layerItems->mThebesLayer = thebesLayer;
+  layerItems->mLayer = thebesLayer.forget();
+  return itemGroup;
+}
+
+/**
+ * This is the heart of layout's integration with layers. We
+ * use a ClippedItemIterator to iterate through descendant display
+ * items. Each item either has its own layer or is assigned to a
+ * ThebesLayer. We create ThebesLayers as necessary, although we try
+ * to put items in the bottom-most ThebesLayer because that is most
+ * likely to be able to render with an opaque background, which will often
+ * be required for subpixel text antialiasing to work.
+ */
+static void BuildLayers(nsDisplayListBuilder* aBuilder,
+                        const nsDisplayList& aList,
+                        LayerManager* aManager,
+                        nsTArray<LayerItems*>* aLayers)
+{
+  NS_ASSERTION(aLayers->IsEmpty(), "aLayers must be initially empty");
+
+  // Create "bottom" Thebes layer. We'll try to put as much content
+  // as possible in this layer because if the container is filled with
+  // opaque content, this bottommost layer can also be treated as opaque,
+  // which means content in this layer can have subpixel AA.
+  // firstThebesLayerItems always points to the last ItemGroup for the
+  // first Thebes layer.
+  ItemGroup* firstThebesLayerItems =
+    CreateEmptyThebesLayer(aBuilder, aManager, aLayers);
+  if (!firstThebesLayerItems)
+    return;
+  // lastThebesLayerItems always points to the last ItemGroup for the
+  // topmost layer, if it's a ThebesLayer. If the top layer is not a
+  // Thebes layer, this is null.
+  ItemGroup* lastThebesLayerItems = firstThebesLayerItems;
+  // This region contains the bounds of all the content that is above
+  // the first Thebes layer.
+  nsRegion areaAboveFirstThebesLayer;
+
+  for (ClippedItemIterator iter(&aList); !iter.IsDone(); iter.Next()) {
+    nsDisplayItem* item = iter.Item();
+    const gfxRect* clipRect = iter.GetEffectiveClipRect();
+    // Ask the item if it manages its own layer
+    nsRefPtr<Layer> layer = item->BuildLayer(aBuilder, aManager);
+    nsRect bounds = item->GetBounds(aBuilder);
+    // We set layerItems to point to the LayerItems object where the
+    // item ends up.
+    LayerItems* layerItems = nsnull;
+    if (layer) {
+      // item has a dedicated layer. Add it to the list, with an ItemGroup
+      // covering this item only.
+      ItemGroup* itemGroup = new (aBuilder) ItemGroup();
+      if (itemGroup) {
+        AddToItemGroup(aBuilder, itemGroup, item, clipRect);
+        layerItems = new (aBuilder) LayerItems(itemGroup);
+        aLayers->AppendElement(layerItems);
+        if (layerItems) {
+          if (itemGroup->mHasClipRect) {
+            gfxRect r = itemGroup->mClipRect;
+            r.Round();
+            nsIntRect intRect(r.X(), r.Y(), r.Width(), r.Height());
+            layer->IntersectClipRect(intRect);
+          }
+          layerItems->mLayer = layer.forget();
+        }
+      }
+      // This item is above the first Thebes layer.
+      areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
+      lastThebesLayerItems = nsnull;
+    } else {
+      // No dedicated layer. Add it to a Thebes layer. First try to add
+      // it to the first Thebes layer, which we can do if there's no
+      // content between the first Thebes layer and our display item that
+      // overlaps our display item.
+      if (!areaAboveFirstThebesLayer.Intersects(bounds)) {
+        firstThebesLayerItems =
+          AddToItemGroup(aBuilder, firstThebesLayerItems, item, clipRect);
+        layerItems = aLayers->ElementAt(0);
+      } else if (lastThebesLayerItems) {
+        // Try to add to the last Thebes layer
+        lastThebesLayerItems =
+          AddToItemGroup(aBuilder, lastThebesLayerItems, item, clipRect);
+        // This item is above the first Thebes layer.
+        areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
+        layerItems = aLayers->ElementAt(aLayers->Length() - 1);
+      } else {
+        // Create a new Thebes layer
+        ItemGroup* itemGroup =
+          CreateEmptyThebesLayer(aBuilder, aManager, aLayers);
+        if (itemGroup) {
+          lastThebesLayerItems =
+            AddToItemGroup(aBuilder, itemGroup, item, clipRect);
+          NS_ASSERTION(lastThebesLayerItems == itemGroup,
+                       "AddToItemGroup shouldn't create a new group if the "
+                       "initial group is empty");
+          // This item is above the first Thebes layer.
+          areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
+        }
+      }
+    }
+
+    if (layerItems) {
+      // Update the visible region of the layer to account for the new
+      // item
+      nscoord appUnitsPerDevPixel =
+        item->GetUnderlyingFrame()->PresContext()->AppUnitsPerDevPixel();
+      layerItems->mVisibleRect.UnionRect(layerItems->mVisibleRect,
+        item->GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel));
+    }
+  }
+
+  if (!firstThebesLayerItems->mStartItem) {
+    // The first Thebes layer has nothing in it. Delete the layer.
+    aLayers->RemoveElementAt(0);
+  }
+
+  for (PRUint32 i = 0; i < aLayers->Length(); ++i) {
+    LayerItems* layerItems = aLayers->ElementAt(i);
+
+    gfxMatrix transform;
+    nsIntRect visibleRect = layerItems->mVisibleRect;
+    if (layerItems->mLayer->GetTransform().Is2D(&transform)) {
+      // if 'transform' is not invertible, then nothing will be displayed
+      // for the layer, so it doesn't really matter what we do here
+      transform.Invert();
+      gfxRect layerVisible = transform.TransformBounds(
+          gfxRect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height));
+      layerVisible.RoundOut();
+      if (NS_FAILED(nsLayoutUtils::GfxRectToIntRect(layerVisible, &visibleRect))) {
+        NS_ERROR("Visible rect transformed out of bounds");
+      }
+    } else {
+      NS_ERROR("Only 2D transformations currently supported");
+    }
+    layerItems->mLayer->SetVisibleRegion(nsIntRegion(visibleRect));
+  }
+}
+
+} // anonymous namespace
+
+already_AddRefed<Layer>
+FrameLayerBuilder::MakeContainerLayerFor(nsDisplayListBuilder* aBuilder,
+                                         LayerManager* aManager,
+                                         nsDisplayItem* aContainer,
+                                         const nsDisplayList& aChildren)
+{
+  // If there's only one layer, then in principle we can try to flatten
+  // things by returning that layer here. But that adds complexity to
+  // retained layer management so we don't do it. Layer backends can
+  // flatten internally.
+  nsRefPtr<ContainerLayer> container = aManager->CreateContainerLayer();
+  if (!container)
+    return nsnull;
+
+  nsAutoTArray<LayerItems*,10> layerItems;
+  BuildLayers(aBuilder, aChildren, aManager, &layerItems);
+
+  Layer* lastChild = nsnull;
+  for (PRUint32 i = 0; i < layerItems.Length(); ++i) {
+    Layer* child = layerItems[i]->mLayer;
+    container->InsertAfter(child, lastChild);
+    lastChild = child;
+  }
+  container->SetIsOpaqueContent(aChildren.IsOpaque());
+  nsRefPtr<Layer> layer = container.forget();
+  return layer.forget();
+}
+
+/* static */ void
+FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
+                                   gfxContext* aContext,
+                                   const nsIntRegion& aRegionToDraw,
+                                   void* aCallbackData)
+{
+  LayerItems* layerItems = static_cast<LayerItems*>(aLayer->GetUserData());
+  nsDisplayListBuilder* builder =
+    static_cast<nsDisplayListBuilder*>(aCallbackData);
+
+  // For now, we'll ignore toDraw and just draw the entire visible
+  // area, because the "visible area" is already confined to just the
+  // area that needs to be repainted. Later, when we start reusing layers
+  // from paint to paint, we'll need to pay attention to toDraw and
+  // actually try to avoid drawing stuff that's not in it.
+
+  // Our list may contain content with different prescontexts at
+  // different zoom levels. 'rc' contains the nsIRenderingContext
+  // used for the previous display item, and lastPresContext is the
+  // prescontext for that item. We also cache the clip state for that
+  // item.
+  nsRefPtr<nsIRenderingContext> rc;
+  nsPresContext* lastPresContext = nsnull;
+  gfxRect currentClip;
+  PRBool setClipRect = PR_FALSE;
+  NS_ASSERTION(layerItems->mItems, "No empty layers allowed");
+  for (ItemGroup* group = layerItems->mItems; group;
+       group = group->mNextItemsForLayer) {
+    // If the new desired clip state is different from the current state,
+    // update the clip.
+    if (setClipRect != group->mHasClipRect ||
+        (group->mHasClipRect && group->mClipRect != currentClip)) {
+      if (setClipRect) {
+        aContext->Restore();
+      }
+      setClipRect = group->mHasClipRect;
+      if (setClipRect) {
+        aContext->Save();
+        aContext->NewPath();
+        aContext->Rectangle(group->mClipRect, PR_TRUE);
+        aContext->Clip();
+        currentClip = group->mClipRect;
+      }
+    }
+    NS_ASSERTION(group->mStartItem, "No empty groups allowed");
+    for (nsDisplayItem* item = group->mStartItem; item != group->mEndItem;
+         item = item->GetAbove()) {
+      nsPresContext* presContext = item->GetUnderlyingFrame()->PresContext();
+      if (presContext != lastPresContext) {
+        // Create a new rendering context with the right
+        // appunits-per-dev-pixel.
+        nsresult rv =
+          presContext->DeviceContext()->CreateRenderingContextInstance(*getter_AddRefs(rc));
+        if (NS_FAILED(rv))
+          break;
+        rc->Init(presContext->DeviceContext(), aContext);
+        lastPresContext = presContext;
+      }
+      item->Paint(builder, rc);
+    }
+  }
+  if (setClipRect) {
+    aContext->Restore();
+  }
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/base/FrameLayerBuilder.h
@@ -0,0 +1,77 @@
+/* -*- 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) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Robert O'Callahan <robert@ocallahan.org>
+ *
+ * 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 FRAMELAYERBUILDER_H_
+#define FRAMELAYERBUILDER_H_
+
+#include "Layers.h"
+
+class nsDisplayListBuilder;
+class nsDisplayList;
+class nsDisplayItem;
+
+namespace mozilla {
+
+class FrameLayerBuilder {
+public:
+  typedef mozilla::layers::Layer Layer;
+  typedef mozilla::layers::ThebesLayer ThebesLayer;
+  typedef mozilla::layers::LayerManager LayerManager;
+
+  /**
+   * Create a container layer for a display item that contains a child
+   * list, either reusing an existing one or creating a new one.
+   * aContainer may be null, in which case we construct a root layer.
+   */
+  already_AddRefed<Layer> MakeContainerLayerFor(nsDisplayListBuilder* aBuilder,
+                                                LayerManager* aManager,
+                                                nsDisplayItem* aContainer,
+                                                const nsDisplayList& aChildren);
+
+  /**
+   * This callback must be provided to EndTransaction. The callback data
+   * must be the nsDisplayListBuilder containing this FrameLayerBuilder.
+   */
+  static void DrawThebesLayer(ThebesLayer* aLayer,
+                              gfxContext* aContext,
+                              const nsIntRegion& aRegionToDraw,
+                              void* aCallbackData);
+};
+
+}
+
+#endif /* FRAMELAYERBUILDER_H_ */
--- a/layout/base/Makefile.in
+++ b/layout/base/Makefile.in
@@ -54,16 +54,17 @@ LIBXUL_LIBRARY	= 1
 
 
 
 XPIDLSRCS	= \
 		nsIStyleSheetService.idl	\
 		$(NULL)
 
 EXPORTS		= \
+		FrameLayerBuilder.h \
 		FramePropertyTable.h \
 		nsBidi.h \
 		nsBidiPresUtils.h \
 		nsCaret.h \
 		nsCSSFrameConstructor.h \
 		nsChangeHint.h \
 		nsCompatibility.h \
 		nsDisplayList.h \
@@ -83,16 +84,17 @@ EXPORTS		= \
 		nsPresContext.h \
 		nsPresState.h \
 		nsRefreshDriver.h \
 		nsStyleChangeList.h \
 		nsStyleConsts.h \
 		$(NULL)
 
 CPPSRCS		= \
+		FrameLayerBuilder.cpp \
 		FramePropertyTable.cpp \
 		nsCSSColorUtils.cpp \
 		nsCSSFrameConstructor.cpp \
 		nsCSSRendering.cpp \
 		nsCSSRenderingBorders.cpp \
 		nsCaret.cpp \
 		nsChildIterator.cpp \
 		nsCounterManager.cpp \
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -57,16 +57,17 @@
 #include "nsSVGIntegrationUtils.h"
 #endif
 #include "nsLayoutUtils.h"
 
 #include "imgIContainer.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "BasicLayers.h"
 
+using namespace mozilla;
 using namespace mozilla::layers;
 
 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
     PRBool aIsForEvents, PRBool aBuildCaret)
     : mReferenceFrame(aReferenceFrame),
       mMovingFrame(nsnull),
       mSaveVisibleRegionOfMovingContent(nsnull),
       mIgnoreScrollFrame(nsnull),
@@ -400,380 +401,16 @@ nsDisplayList::ComputeVisibility(nsDispl
     movingContentVisibleRegionAfterMove);
 
   mIsOpaque = aVisibleRegion->IsEmpty();
 #ifdef DEBUG
   mDidComputeVisibility = PR_TRUE;
 #endif
 }
 
-namespace {
-/**
- * This class iterates through a display list tree, descending only into
- * nsDisplayClip items, and returns each display item encountered during
- * such iteration. Along with each item we also return the clip rect
- * accumulated for the item.
- */
-class ClippedItemIterator {
-public:
-  ClippedItemIterator(const nsDisplayList* aList)
-  {
-    DescendIntoList(aList, nsnull, nsnull);
-    AdvanceToItem();
-  }
-  PRBool IsDone()
-  {
-    return mStack.IsEmpty();
-  }
-  void Next()
-  {
-    State* top = StackTop();
-    top->mItem = top->mItem->GetAbove();
-    AdvanceToItem();
-  }
-  // Returns null if there is no clipping affecting the item. The
-  // clip rect is in device pixels
-  const gfxRect* GetEffectiveClipRect()
-  {
-    State* top = StackTop();
-    return top->mHasClipRect ? &top->mEffectiveClipRect : nsnull;
-  }
-  nsDisplayItem* Item()
-  {
-    return StackTop()->mItem;
-  }
-
-private:
-  // We maintain a stack of state objects. Each State object represents
-  // where we're up to in the iteration of a list.
-  struct State {
-    // The current item we're at in the list
-    nsDisplayItem* mItem;
-    // The effective clip rect applying to all the items in this list
-    gfxRect mEffectiveClipRect;
-    PRPackedBool mHasClipRect;
-  };
-
-  State* StackTop()
-  {
-    return &mStack[mStack.Length() - 1];
-  }
-  void DescendIntoList(const nsDisplayList* aList,
-                       nsPresContext* aPresContext,
-                       const nsRect* aClipRect)
-  {
-    State* state = mStack.AppendElement();
-    if (!state)
-      return;
-    if (mStack.Length() >= 2) {
-      *state = mStack[mStack.Length() - 2];
-    } else {
-      state->mHasClipRect = PR_FALSE;
-    }
-    state->mItem = aList->GetBottom();
-    if (aClipRect) {
-      gfxRect r(aClipRect->x, aClipRect->y, aClipRect->width, aClipRect->height);
-      r.ScaleInverse(aPresContext->AppUnitsPerDevPixel());
-      if (state->mHasClipRect) {
-        state->mEffectiveClipRect = state->mEffectiveClipRect.Intersect(r);
-      } else {
-        state->mEffectiveClipRect = r;
-        state->mHasClipRect = PR_TRUE;
-      }
-    }
-  }
-  // Advances to an item that the iterator should return.
-  void AdvanceToItem()
-  {
-    while (!mStack.IsEmpty()) {
-      State* top = StackTop();
-      if (!top->mItem) {
-        mStack.SetLength(mStack.Length() - 1);
-        if (!mStack.IsEmpty()) {
-          top = StackTop();
-          top->mItem = top->mItem->GetAbove();
-        }
-        continue;
-      }
-      if (top->mItem->GetType() != nsDisplayItem::TYPE_CLIP)
-        return;
-      nsDisplayClip* clipItem = static_cast<nsDisplayClip*>(top->mItem);
-      nsRect clip = clipItem->GetClipRect();
-      DescendIntoList(clipItem->GetList(),
-                      clipItem->GetClippingFrame()->PresContext(),
-                      &clip);
-    }
-  }
-
-  nsAutoTArray<State,10> mStack;
-};
-}
-
-/**
- * Given a (possibly clipped) display item in aItem, try to append it to
- * the items in aGroup. If aItem is the next item in the sublist in
- * aGroup, and the clipping matches, we can just update aGroup in-place,
- * otherwise we'll allocate a new ItemGroup, add it to the linked list,
- * and put aItem in the new ItemGroup. We return the ItemGroup into which
- * aItem was inserted.
- */
-static nsDisplayList::ItemGroup*
-AddToItemGroup(nsDisplayListBuilder* aBuilder,
-               nsDisplayList::ItemGroup* aGroup, nsDisplayItem* aItem,
-               const gfxRect* aClipRect) {
-  NS_ASSERTION(!aGroup->mNextItemsForLayer,
-               "aGroup must be the last group in the chain");
-
-  if (!aGroup->mStartItem) {
-    aGroup->mStartItem = aItem;
-    aGroup->mEndItem = aItem->GetAbove();
-    aGroup->mHasClipRect = aClipRect != nsnull;
-    if (aClipRect) {
-      aGroup->mClipRect = *aClipRect;
-    }
-    return aGroup;
-  }
-
-  if (aGroup->mEndItem == aItem &&
-      (aGroup->mHasClipRect
-       ? (aClipRect && aGroup->mClipRect == *aClipRect)
-       : !aClipRect))  {
-    aGroup->mEndItem = aItem->GetAbove();
-    return aGroup;
-  }
-
-  nsDisplayList::ItemGroup* itemGroup =
-    new (aBuilder) nsDisplayList::ItemGroup();
-  if (!itemGroup)
-    return aGroup;
-  aGroup->mNextItemsForLayer = itemGroup;
-  return AddToItemGroup(aBuilder, itemGroup, aItem, aClipRect);
-}
-
-/**
- * Create an empty Thebes layer, with an empty ItemGroup associated with
- * it, and append it to aLayers.
- */
-static nsDisplayList::ItemGroup*
-CreateEmptyThebesLayer(nsDisplayListBuilder* aBuilder,
-                       LayerManager* aManager,
-                       nsTArray<nsDisplayList::LayerItems>* aLayers) {
-  nsDisplayList::ItemGroup* itemGroup =
-    new (aBuilder) nsDisplayList::ItemGroup();
-  if (!itemGroup)
-    return nsnull;
-  nsRefPtr<ThebesLayer> thebesLayer =
-    aManager->CreateThebesLayer();
-  if (!thebesLayer)
-    return nsnull;
-  nsDisplayList::LayerItems* layerItems =
-    aLayers->AppendElement(nsDisplayList::LayerItems(itemGroup));
-  layerItems->mThebesLayer = thebesLayer;
-  layerItems->mLayer = thebesLayer.forget();
-  return itemGroup;
-}
-
-static PRBool
-IsAllUniform(nsDisplayListBuilder* aBuilder, nsDisplayList::ItemGroup* aGroup,
-             nscolor* aColor)
-{
-  nsRect visibleRect = aGroup->mStartItem->GetVisibleRect();
-  nscolor finalColor = NS_RGBA(0,0,0,0);
-  for (nsDisplayList::ItemGroup* group = aGroup; group;
-       group = group->mNextItemsForLayer) {
-    for (nsDisplayItem* item = group->mStartItem; item != group->mEndItem;
-         item = item->GetAbove()) {
-      nscolor color;
-      if (visibleRect != item->GetVisibleRect())
-        return PR_FALSE;
-      if (!item->IsUniform(aBuilder, &color))
-        return PR_FALSE;
-      finalColor = NS_ComposeColors(finalColor, color);
-    }
-  }
-  *aColor = finalColor;
-  return PR_TRUE;
-}
-
-/**
- * This is the heart of layout's integration with layers. We
- * use a ClippedItemIterator to iterate through descendant display
- * items. Each item either has its own layer or is assigned to a
- * ThebesLayer. We create ThebesLayers as necessary, although we try
- * to put items in the bottom-most ThebesLayer because that is most
- * likely to be able to render with an opaque background, which will often
- * be required for subpixel text antialiasing to work.
- */
-void nsDisplayList::BuildLayers(nsDisplayListBuilder* aBuilder,
-                                LayerManager* aManager,
-                                nsTArray<LayerItems>* aLayers) const {
-  NS_ASSERTION(aLayers->IsEmpty(), "aLayers must be initially empty");
-
-  // Create "bottom" Thebes layer. We'll try to put as much content
-  // as possible in this layer because if the container is filled with
-  // opaque content, this bottommost layer can also be treated as opaque,
-  // which means content in this layer can have subpixel AA.
-  // firstThebesLayerItems always points to the last ItemGroup for the
-  // first Thebes layer.
-  ItemGroup* firstThebesLayerItems =
-    CreateEmptyThebesLayer(aBuilder, aManager, aLayers);
-  if (!firstThebesLayerItems)
-    return;
-  // lastThebesLayerItems always points to the last ItemGroup for the
-  // topmost layer, if it's a ThebesLayer. If the top layer is not a
-  // Thebes layer, this is null.
-  ItemGroup* lastThebesLayerItems = firstThebesLayerItems;
-  // This region contains the bounds of all the content that is above
-  // the first Thebes layer.
-  nsRegion areaAboveFirstThebesLayer;
-
-  for (ClippedItemIterator iter(this); !iter.IsDone(); iter.Next()) {
-    nsDisplayItem* item = iter.Item();
-    const gfxRect* clipRect = iter.GetEffectiveClipRect();
-    // Ask the item if it manages its own layer
-    nsRefPtr<Layer> layer = item->BuildLayer(aBuilder, aManager);
-    nsRect bounds = item->GetBounds(aBuilder);
-    // We set layerItems to point to the LayerItems object where the
-    // item ends up.
-    LayerItems* layerItems = nsnull;
-    if (layer) {
-      // item has a dedicated layer. Add it to the list, with an ItemGroup
-      // covering this item only.
-      ItemGroup* itemGroup = new (aBuilder) ItemGroup();
-      if (itemGroup) {
-        AddToItemGroup(aBuilder, itemGroup, item, clipRect);
-        layerItems = aLayers->AppendElement(LayerItems(itemGroup));
-        if (layerItems) {
-          if (itemGroup->mHasClipRect) {
-            gfxRect r = itemGroup->mClipRect;
-            r.Round();
-            nsIntRect intRect(r.X(), r.Y(), r.Width(), r.Height());
-            layer->IntersectClipRect(intRect);
-          }
-          layerItems->mLayer = layer.forget();
-        }
-      }
-      // This item is above the first Thebes layer.
-      areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
-      lastThebesLayerItems = nsnull;
-    } else {
-      // No dedicated layer. Add it to a Thebes layer. First try to add
-      // it to the first Thebes layer, which we can do if there's no
-      // content between the first Thebes layer and our display item that
-      // overlaps our display item.
-      if (!areaAboveFirstThebesLayer.Intersects(bounds)) {
-        firstThebesLayerItems =
-          AddToItemGroup(aBuilder, firstThebesLayerItems, item, clipRect);
-        layerItems = &aLayers->ElementAt(0);
-      } else if (lastThebesLayerItems) {
-        // Try to add to the last Thebes layer
-        lastThebesLayerItems =
-          AddToItemGroup(aBuilder, lastThebesLayerItems, item, clipRect);
-        // This item is above the first Thebes layer.
-        areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
-        layerItems = &aLayers->ElementAt(aLayers->Length() - 1);
-      } else {
-        // Create a new Thebes layer
-        ItemGroup* itemGroup =
-          CreateEmptyThebesLayer(aBuilder, aManager, aLayers);
-        if (itemGroup) {
-          lastThebesLayerItems =
-            AddToItemGroup(aBuilder, itemGroup, item, clipRect);
-          NS_ASSERTION(lastThebesLayerItems == itemGroup,
-                       "AddToItemGroup shouldn't create a new group if the "
-                       "initial group is empty");
-          // This item is above the first Thebes layer.
-          areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
-          layerItems = &aLayers->ElementAt(aLayers->Length() - 1);
-        }
-      }
-    }
-
-    if (layerItems) {
-      // Update the visible region of the layer to account for the new
-      // item
-      nscoord appUnitsPerDevPixel =
-        item->GetUnderlyingFrame()->PresContext()->AppUnitsPerDevPixel();
-      layerItems->mVisibleRect.UnionRect(layerItems->mVisibleRect,
-        item->mVisibleRect.ToNearestPixels(appUnitsPerDevPixel));
-    }
-  }
-
-  if (!firstThebesLayerItems->mStartItem) {
-    // The first Thebes layer has nothing in it. Delete the layer.
-    aLayers->RemoveElementAt(0);
-  }
-
-  for (PRUint32 i = 0; i < aLayers->Length(); ++i) {
-    LayerItems* layerItems = &aLayers->ElementAt(i);
-
-    nscolor color;
-    // Only convert layers with identity transform to ColorLayers, for now.
-    // This simplifies the code to set the clip region.
-    if (layerItems->mThebesLayer &&
-        IsAllUniform(aBuilder, layerItems->mItems, &color) &&
-        layerItems->mLayer->GetTransform().IsIdentity()) {
-      nsRefPtr<ColorLayer> layer = aManager->CreateColorLayer();
-      layer->SetClipRect(layerItems->mThebesLayer->GetClipRect());
-      // Clip to mVisibleRect to ensure only the pixels we want are filled.
-      layer->IntersectClipRect(layerItems->mVisibleRect);
-      layer->SetColor(gfxRGBA(color));
-      layerItems->mLayer = layer.forget();
-      layerItems->mThebesLayer = nsnull;
-    }
-
-    gfxMatrix transform;
-    nsIntRect visibleRect = layerItems->mVisibleRect;
-    if (layerItems->mLayer->GetTransform().Is2D(&transform)) {
-      // if 'transform' is not invertible, then nothing will be displayed
-      // for the layer, so it doesn't really matter what we do here
-      transform.Invert();
-      gfxRect layerVisible = transform.TransformBounds(
-          gfxRect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height));
-      layerVisible.RoundOut();
-      if (NS_FAILED(nsLayoutUtils::GfxRectToIntRect(layerVisible, &visibleRect))) {
-        NS_ERROR("Visible rect transformed out of bounds");
-      }
-    } else {
-      NS_ERROR("Only 2D transformations currently supported");
-    }
-    layerItems->mLayer->SetVisibleRegion(nsIntRegion(visibleRect));
-  }
-}
-
-/**
- * We build a single layer by building a list of layers needed for
- * all the display items and building a container layer to hold them.
- */
-already_AddRefed<Layer>
-nsDisplayList::BuildLayer(nsDisplayListBuilder* aBuilder,
-                          LayerManager* aManager,
-                          nsTArray<LayerItems>* aLayers) const {
-  // If there's only one layer, then in principle we can try to flatten
-  // things by returning that layer here. But that adds complexity to
-  // retained layer management so we don't do it. Layer backends can
-  // flatten internally.
-  nsRefPtr<ContainerLayer> container =
-    aManager->CreateContainerLayer();
-  if (!container)
-    return nsnull;
-
-  BuildLayers(aBuilder, aManager, aLayers);
-
-  Layer* lastChild = nsnull;
-  for (PRUint32 i = 0; i < aLayers->Length(); ++i) {
-    Layer* child = aLayers->ElementAt(i).mLayer;
-    container->InsertAfter(child, lastChild);
-    lastChild = child;
-  }
-  container->SetIsOpaqueContent(mIsOpaque);
-  nsRefPtr<Layer> layer = container.forget();
-  return layer.forget();
-}
-
 void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
                               nsIRenderingContext* aCtx,
                               PRUint32 aFlags) const {
   PaintForFrame(aBuilder, aCtx, aBuilder->ReferenceFrame(), aFlags);
 }
 
 /**
  * We paint by executing a layer manager transaction, constructing a
@@ -808,109 +445,32 @@ void nsDisplayList::PaintForFrame(nsDisp
   }
 
   if (aCtx) {
     layerManager->BeginTransactionWithTarget(aCtx->ThebesContext());
   } else {
     layerManager->BeginTransaction();
   }
 
-  nsAutoTArray<LayerItems,10> layers;
-  nsRefPtr<Layer> root = BuildLayer(aBuilder, layerManager, &layers);
+  nsRefPtr<Layer> root = aBuilder->LayerBuilder()->
+    MakeContainerLayerFor(aBuilder, layerManager, nsnull, *this);
   if (!root)
     return;
 
   nsIntRect visible =
     mVisibleRect.ToNearestPixels(aForFrame->PresContext()->AppUnitsPerDevPixel());
   root->SetVisibleRegion(nsIntRegion(visible));
 
   layerManager->SetRoot(root);
-  layerManager->EndConstruction();
-  PaintThebesLayers(aBuilder, layers);
-  layerManager->EndTransaction();
+  layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
+                               aBuilder);
 
   nsCSSRendering::DidPaint();
 }
 
-void
-nsDisplayList::PaintThebesLayers(nsDisplayListBuilder* aBuilder,
-                                 const nsTArray<LayerItems>& aLayers) const
-{
-  for (PRUint32 i = 0; i < aLayers.Length(); ++i) {
-    ThebesLayer* thebesLayer = aLayers[i].mThebesLayer;
-    if (!thebesLayer) {
-      // Just ask the display item to paint any Thebes layers that it
-      // used to construct its layer
-      aLayers[i].mItems->mStartItem->PaintThebesLayers(aBuilder);
-      continue;
-    }
-
-    // OK, we have a real Thebes layer. Start drawing into it.
-    nsIntRegion toDraw;
-    gfxContext* ctx = thebesLayer->BeginDrawing(&toDraw);
-    if (!ctx)
-      continue;
-    // For now, we'll ignore toDraw and just draw the entire visible
-    // area, because the "visible area" is already confined to just the
-    // area that needs to be repainted. Later, when we start reusing layers
-    // from paint to paint, we'll need to pay attention to toDraw and
-    // actually try to avoid drawing stuff that's not in it.
-
-    // Our list may contain content with different prescontexts at
-    // different zoom levels. 'rc' contains the nsIRenderingContext
-    // used for the previous display item, and lastPresContext is the
-    // prescontext for that item. We also cache the clip state for that
-    // item.
-    nsRefPtr<nsIRenderingContext> rc;
-    nsPresContext* lastPresContext = nsnull;
-    gfxRect currentClip;
-    PRBool setClipRect = PR_FALSE;
-    NS_ASSERTION(aLayers[i].mItems, "No empty layers allowed");
-    for (ItemGroup* group = aLayers[i].mItems; group;
-         group = group->mNextItemsForLayer) {
-      // If the new desired clip state is different from the current state,
-      // update the clip.
-      if (setClipRect != group->mHasClipRect ||
-          (group->mHasClipRect && group->mClipRect != currentClip)) {
-        if (setClipRect) {
-          ctx->Restore();
-        }
-        setClipRect = group->mHasClipRect;
-        if (setClipRect) {
-          ctx->Save();
-          ctx->NewPath();
-          ctx->Rectangle(group->mClipRect, PR_TRUE);
-          ctx->Clip();
-          currentClip = group->mClipRect;
-        }
-      }
-      NS_ASSERTION(group->mStartItem, "No empty groups allowed");
-      for (nsDisplayItem* item = group->mStartItem; item != group->mEndItem;
-           item = item->GetAbove()) {
-        nsPresContext* presContext = item->GetUnderlyingFrame()->PresContext();
-        if (presContext != lastPresContext) {
-          // Create a new rendering context with the right
-          // appunits-per-dev-pixel.
-          nsresult rv =
-            presContext->DeviceContext()->CreateRenderingContextInstance(*getter_AddRefs(rc));
-          if (NS_FAILED(rv))
-            break;
-          rc->Init(presContext->DeviceContext(), ctx);
-          lastPresContext = presContext;
-        }
-        item->Paint(aBuilder, rc);
-      }
-    }
-    if (setClipRect) {
-      ctx->Restore();
-    }
-    thebesLayer->EndDrawing();
-  }
-}
-
 PRUint32 nsDisplayList::Count() const {
   PRUint32 count = 0;
   for (nsDisplayItem* i = GetBottom(); i; i = i->GetAbove()) {
     ++count;
   }
   return count;
 }
 
@@ -1579,30 +1139,25 @@ PRBool nsDisplayOpacity::IsOpaque(nsDisp
   // been created.
   return PR_FALSE;
 }
 
 // nsDisplayOpacity uses layers for rendering
 already_AddRefed<Layer>
 nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
                              LayerManager* aManager) {
-  nsRefPtr<Layer> layer =
-    mList.BuildLayer(aBuilder, aManager, &mChildLayers);
+  nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
+    MakeContainerLayerFor(aBuilder, aManager, this, mList);
   if (!layer)
     return nsnull;
 
   layer->SetOpacity(mFrame->GetStyleDisplay()->mOpacity);
   return layer.forget();
 }
 
-void
-nsDisplayOpacity::PaintThebesLayers(nsDisplayListBuilder* aBuilder) {
-  mList.PaintThebesLayers(aBuilder, mChildLayers);
-}
-
 PRBool nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                            nsRegion* aVisibleRegion,
                                            nsRegion* aVisibleRegionBeforeMove) {
   NS_ASSERTION((aVisibleRegionBeforeMove != nsnull) == aBuilder->HasMovingFrames(),
                "Should have aVisibleRegionBeforeMove when there are moving frames");
 
   // Our children are translucent so we should not allow them to subtract
   // area from aVisibleRegion. We do need to find out what is visible under
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -48,22 +48,23 @@
 #include "nsCOMPtr.h"
 #include "nsIFrame.h"
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsISelection.h"
 #include "nsCaret.h"
 #include "plarena.h"
 #include "Layers.h"
+#include "nsRegion.h"
+#include "FrameLayerBuilder.h"
 
 #include <stdlib.h>
 
 class nsIPresShell;
 class nsIContent;
-class nsRegion;
 class nsIRenderingContext;
 class nsIDeviceContext;
 class nsDisplayTableItem;
 class nsDisplayItem;
 
 /*
  * An nsIFrame can have many different visual parts. For example an image frame
  * can have a background, border, and outline, the image itself, and a
@@ -115,16 +116,17 @@ class nsDisplayItem;
  * the display list memory using a PLArena. It also establishes the reference
  * coordinate system for all display list items. Some of the parameters are
  * available from the prescontext/presshell, but we copy them into the builder
  * for faster/more convenient access.
  */
 class NS_STACK_CLASS nsDisplayListBuilder {
 public:
   typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
+  typedef mozilla::FrameLayerBuilder FrameLayerBuilder;
 
   /**
    * @param aReferenceFrame the frame at the root of the subtree; its origin
    * is the origin of the reference coordinate system for this display list
    * @param aIsForEvents PR_TRUE if we're creating this list in order to
    * determine which frame is under the mouse position
    * @param aBuildCaret whether or not we should include the caret in any
    * display lists that we make.
@@ -334,16 +336,21 @@ public:
    * that might not be displayed, we mark the placeholders and their ancestors
    * to ensure that display list construction descends into them
    * anyway. nsDisplayListBuilder will take care of unmarking them when it is
    * destroyed.
    */
   void MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
                                 const nsFrameList& aFrames,
                                 const nsRect& aDirtyRect);
+
+  /**
+   * Return the FrameLayerBuilder.
+   */
+  FrameLayerBuilder* LayerBuilder() { return &mLayerBuilder; }
   
   /**
    * Allocate memory in our arena. It will only be freed when this display list
    * builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem
    * destructors are called as soon as the item is no longer used.
    */
   void* Allocate(size_t aSize);
   
@@ -402,17 +409,18 @@ private:
     nsIFrame*     mCaretFrame;
     PRUint32      mFirstFrameMarkedForDisplay;
   };
   PresShellState* CurrentPresShellState() {
     NS_ASSERTION(mPresShellStates.Length() > 0,
                  "Someone forgot to enter a presshell");
     return &mPresShellStates[mPresShellStates.Length() - 1];
   }
-  
+
+  FrameLayerBuilder              mLayerBuilder;
   nsIFrame*                      mReferenceFrame;
   nsIFrame*                      mMovingFrame;
   nsRegion*                      mSaveVisibleRegionOfMovingContent;
   nsIFrame*                      mIgnoreScrollFrame;
   nsPoint                        mMoveDelta; // only valid when mMovingFrame is non-null
   PLArenaPool                    mPool;
   nsCOMPtr<nsISelection>         mBoundingSelection;
   nsAutoTArray<PresShellState,8> mPresShellStates;
@@ -573,23 +581,16 @@ public:
    * rendering) instead of cairo.
    * 
    * The caller (nsDisplayList) is responsible for setting the visible
    * region of the layer.
    */
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager)
   { return nsnull; }
-  /**
-   * If BuildLayer returned non-null, then this method is called to
-   * paint any ThebesLayers which are descendants of the returned layer.
-   */
-  virtual void PaintThebesLayers(nsDisplayListBuilder* aBuilder)
-  {
-  }
 
   /**
    * On entry, aVisibleRegion contains the region (relative to ReferenceFrame())
    * which may be visible. If the display item opaquely covers an area, it
    * can remove that area from aVisibleRegion before returning.
    * If we're doing scroll analysis with moving frames, then
    * aVisibleRegionBeforeMove will be non-null and contains the region that
    * would have been visible before the move. aVisibleRegion contains the
@@ -625,16 +626,20 @@ public:
   }
   
   /**
    * If this is a leaf item we return null, otherwise we return the wrapped
    * list.
    */
   virtual nsDisplayList* GetList() { return nsnull; }
 
+  /**
+   * Returns the visible rect. Should only be called after ComputeVisibility
+   * has happened.
+   */
   const nsRect& GetVisibleRect() { return mVisibleRect; }
   
 #ifdef NS_DEBUG
   /**
    * For debugging and stuff
    */
   virtual const char* Name() = 0;
 #endif
@@ -887,91 +892,16 @@ public:
   /**
    * Find the topmost display item that returns a non-null frame, and return
    * the frame.
    */
   void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                nsDisplayItem::HitTestState* aState,
                nsTArray<nsIFrame*> *aOutFrames) const;
 
-  /**
-   * This class represents a sublist of consecutive items in an nsDisplayList.
-   * The first item in the sublist is mStartItem and the last item
-   * is the item before mEndItem.
-   * 
-   * These sublists are themselves organized into a linked list of all
-   * the ItemGroups associated with a given layer, via mNextItemsForLayer.
-   * This list will have more than one element if the display items in a layer
-   * come from different nsDisplayLists, or if they come from the same
-   * nsDisplayList but they aren't consecutive in that list.
-   * 
-   * These objects are allocated from the nsDisplayListBuilder arena.
-   */
-  struct ItemGroup {
-    // If null, then the item group is empty.
-    nsDisplayItem* mStartItem;
-    nsDisplayItem* mEndItem;
-    ItemGroup* mNextItemsForLayer;
-    // The clipping (if any) that needs to be applied to all these items.
-    gfxRect mClipRect;
-    PRPackedBool mHasClipRect;
-
-    ItemGroup() : mStartItem(nsnull), mEndItem(nsnull),
-      mNextItemsForLayer(nsnull), mHasClipRect(PR_FALSE) {}
-
-    void* operator new(size_t aSize,
-                       nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
-      return aBuilder->Allocate(aSize);
-    }
-  };
-  /**
-   * This class represents a layer and the display item(s) it
-   * will render. The items are stored in a linked list of ItemGroups.
-   */
-  struct LayerItems {
-    nsRefPtr<Layer> mLayer;
-    // equal to mLayer, or null if mLayer is not a ThebesLayer
-    ThebesLayer* mThebesLayer;
-    ItemGroup* mItems;
-    // The bounds of the visible region for this layer, in device pixels
-    nsIntRect mVisibleRect;
-
-    LayerItems(ItemGroup* aItems) :
-      mThebesLayer(nsnull), mItems(aItems)
-    {
-    }
-  };
-  /**
-   * Compute a list of layers needed to render this display list. The layers
-   * are added to aLayers, which must be empty on entry. This
-   * must be called while aManager is in the construction phase, because
-   * we construct layers belonging to aManager. The layers used to
-   * construct the layer tree (along with the display items associated
-   * with each layer) are returned in aLayers.
-   */
-  void BuildLayers(nsDisplayListBuilder* aBuilder,
-                   LayerManager* aManager,
-                   nsTArray<LayerItems>* aLayers) const;
-  /**
-   * Return a single layer which renders this display list. This
-   * must be called while aManager is in the construction phase, because
-   * we construct layers belonging to aManager. The layers used to
-   * construct the layer tree (along with the display items associated
-   * with each layer) are returned in aLayers.
-   * The caller is responsible for setting the visible region on the layer.
-   */
-  already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
-                                     LayerManager* aManager,
-                                     nsTArray<LayerItems>* aLayers) const;
-  /**
-   * Paint the ThebesLayers in the list of layers.
-   */
-  void PaintThebesLayers(nsDisplayListBuilder* aBuilder,
-                         const nsTArray<LayerItems>& aLayers) const;
-
 private:
   // This class is only used on stack, so we don't have to worry about leaking
   // it.  Don't let us be heap-allocated!
   void* operator new(size_t sz) CPP_THROW_NEW;
   
   // Utility function used to massage the list during ComputeVisibility.
   void FlattenTo(nsTArray<nsDisplayItem*>* aElements);
   // Utility function used to massage the list during sorting, to rewrite
@@ -1543,25 +1473,21 @@ public:
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayOpacity();
 #endif
   
   virtual Type GetType() { return TYPE_OPACITY; }
   virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder);
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager);
-  virtual void PaintThebesLayers(nsDisplayListBuilder* aBuilder);
   virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    nsRegion* aVisibleRegionBeforeMove);  
   virtual PRBool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
   NS_DISPLAY_DECL_NAME("Opacity")
-
-private:
-  nsTArray<nsDisplayList::LayerItems> mChildLayers;
 };
 
 /**
  * nsDisplayClip can clip a list of items, but we take a single item
  * initially and then later merge other items into it when we merge
  * adjacent matching nsDisplayClips
  */
 class nsDisplayClip : public nsDisplayWrapList {
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5673,16 +5673,57 @@ nscolor PresShell::ComputeBackstopColor(
     return NS_RGBA(0,0,0,0);
   }
   // Within an opaque widget (or no widget at all), so the backstop
   // color must be totally opaque. The user's default background
   // as reported by the prescontext is guaranteed to be opaque.
   return GetPresContext()->DefaultBackgroundColor();
 }
 
+struct PaintParams {
+  nsIFrame* mFrame;
+  nsPoint mOffsetToRoot;
+  nsPoint mOffsetToWidget;
+  const nsRegion* mDirtyRegion;
+  nscolor mBackgroundColor;
+};
+
+static void DrawThebesLayer(ThebesLayer* aLayer,
+                            gfxContext* aContext,
+                            const nsIntRegion& aRegionToDraw,
+                            void* aCallbackData)
+{
+  PaintParams* params = static_cast<PaintParams*>(aCallbackData);
+  nsIFrame* frame = params->mFrame;
+  if (frame) {
+    // We're drawing into a child window. Don't pass
+    // nsLayoutUtils::PAINT_WIDGET_LAYERS, since that will draw into
+    // the widget for the display root.
+    nsIDeviceContext* devCtx = frame->PresContext()->DeviceContext();
+    nsCOMPtr<nsIRenderingContext> rc;
+    nsresult rv = devCtx->CreateRenderingContextInstance(*getter_AddRefs(rc));
+    if (NS_SUCCEEDED(rv)) {
+      rc->Init(devCtx, aContext);
+      nsRegion dirtyRegion = *params->mDirtyRegion;
+      dirtyRegion.MoveBy(params->mOffsetToRoot);
+      nsIRenderingContext::AutoPushTranslation
+        push(rc, -params->mOffsetToWidget.x, -params->mOffsetToWidget.y);
+      nsLayoutUtils::PaintFrame(rc, frame, dirtyRegion,
+                                params->mBackgroundColor);
+    }
+  } else {
+    aContext->NewPath();
+    aContext->SetColor(gfxRGBA(params->mBackgroundColor));
+    nsIntRect dirtyRect = aRegionToDraw.GetBounds();
+    aContext->Rectangle(
+      gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
+    aContext->Fill();
+  }
+}
+
 NS_IMETHODIMP
 PresShell::Paint(nsIView*        aDisplayRoot,
                  nsIView*        aViewToPaint,
                  nsIWidget*      aWidgetToPaint,
                  const nsRegion& aDirtyRegion,
                  PRBool          aPaintDefaultBackground)
 {
 #ifdef NS_FUNCTION_TIMER
@@ -5725,52 +5766,27 @@ PresShell::Paint(nsIView*        aDispla
   layerManager->BeginTransaction();
   nsRefPtr<ThebesLayer> root = layerManager->CreateThebesLayer();
   nsIntRect dirtyRect = aDirtyRegion.GetBounds().
     ToOutsidePixels(presContext->AppUnitsPerDevPixel());
   if (root) {
     root->SetVisibleRegion(dirtyRect);
     layerManager->SetRoot(root);
   }
-  layerManager->EndConstruction();
-  if (root) {
-    nsIntRegion toDraw;
-    gfxContext* ctx = root->BeginDrawing(&toDraw);
-    if (ctx) {
-      if (frame) {
-        // We're drawing into a child window. Don't pass
-        // nsLayoutUtils::PAINT_WIDGET_LAYERS, since that will draw into
-        // the widget for the display root.
-        nsIDeviceContext* devCtx = GetPresContext()->DeviceContext();
-        nsCOMPtr<nsIRenderingContext> rc;
-        nsresult rv = devCtx->CreateRenderingContextInstance(*getter_AddRefs(rc));
-        if (NS_SUCCEEDED(rv)) {
-          rc->Init(devCtx, ctx);
-          // Offset to add to aView coordinates to get aWidget coordinates
-          nsPoint offsetToRoot = aViewToPaint->GetOffsetTo(aDisplayRoot);
-          nsRegion dirtyRegion = aDirtyRegion;
-          dirtyRegion.MoveBy(offsetToRoot);
-
-          nsPoint translate = -offsetToRoot + aViewToPaint->ViewToWidgetOffset();
-          nsIRenderingContext::AutoPushTranslation
-            push(rc, translate.x, translate.y);
-
-          nsLayoutUtils::PaintFrame(rc, frame, dirtyRegion, bgcolor);
-        }
-      } else {
-        bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
-        ctx->NewPath();
-        ctx->SetColor(gfxRGBA(bgcolor));
-        ctx->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
-        ctx->Fill();
-      }
-    }
-    root->EndDrawing();
-  }
-  layerManager->EndTransaction();
+  if (!frame) {
+    bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
+  }
+  nsPoint offsetToRoot = aViewToPaint->GetOffsetTo(aDisplayRoot);
+  PaintParams params =
+    { frame,
+      offsetToRoot,
+      offsetToRoot - aViewToPaint->ViewToWidgetOffset(),
+      &aDirtyRegion,
+      bgcolor };
+  layerManager->EndTransaction(DrawThebesLayer, &params);
 
   return NS_OK;
 }
 
 // static
 void
 nsIPresShell::SetCapturingContent(nsIContent* aContent, PRUint8 aFlags)
 {