Bug 534425. Part 6: Let nsIWidgets expose a LayerManager to be used to render into the widget, instead of nsPaintEvent::renderingContext which is removed since it's no longer needed. Currently all widgets fall back to a default BasicLayerManager implementation. Also change nsPaintEvent::region to be an nsIntRegion, and get rid of nsPaintEvent::rect since it's redundant.
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 01 Mar 2010 21:03:49 +1300
changeset 38805 c85d57ea1d37fdfea1ba14d487df44bf66acad3a
parent 38804 97ad975ec651f8c0ffa8cc507765e14ba6c97d76
child 38806 d680b1505f9a8296c93b5787821a5ccf151aeb98
push idunknown
push userunknown
push dateunknown
bugs534425
milestone1.9.3a3pre
Bug 534425. Part 6: Let nsIWidgets expose a LayerManager to be used to render into the widget, instead of nsPaintEvent::renderingContext which is removed since it's no longer needed. Currently all widgets fall back to a default BasicLayerManager implementation. Also change nsPaintEvent::region to be an nsIntRegion, and get rid of nsPaintEvent::rect since it's redundant.
content/canvas/src/nsCanvasRenderingContext2D.cpp
dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl
embedding/browser/build/Makefile.in
embedding/browser/webBrowser/nsWebBrowser.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresShell.cpp
layout/svg/base/src/nsSVGIntegrationUtils.cpp
layout/tools/reftest/reftest.js
view/public/nsIViewObserver.h
view/src/nsViewManager.cpp
view/src/nsViewManager.h
widget/public/nsGUIEvent.h
widget/public/nsIWidget.h
widget/src/build/Makefile.in
widget/src/cocoa/Makefile.in
widget/src/cocoa/nsChildView.mm
widget/src/cocoa/nsCocoaWindow.h
widget/src/cocoa/nsCocoaWindow.mm
widget/src/gtk2/nsWindow.cpp
widget/src/qt/nsWindow.cpp
widget/src/windows/nsWindow.h
widget/src/windows/nsWindowGfx.cpp
widget/src/windows/nsWindowGfx.h
widget/src/xpwidgets/nsBaseWidget.cpp
widget/src/xpwidgets/nsBaseWidget.h
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -3308,16 +3308,19 @@ nsCanvasRenderingContext2D::DrawWindow(n
              nsPresContext::CSSPixelsToAppUnits(aH));
     PRUint32 renderDocFlags = nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
     if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_CARET) {
         renderDocFlags |= nsIPresShell::RENDER_CARET;
     }
     if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_VIEW) {
         renderDocFlags &= ~nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
     }
+    if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_USE_WIDGET_LAYERS) {
+        renderDocFlags |= nsIPresShell::RENDER_USE_WIDGET_LAYERS;
+    }
 
     PRBool oldDisableValue = nsLayoutUtils::sDisableGetUsedXAssertions;
     nsLayoutUtils::sDisableGetUsedXAssertions = oldDisableValue || skipFlush;
     presShell->RenderDocument(r, renderDocFlags, bgColor, mThebes);
     nsLayoutUtils::sDisableGetUsedXAssertions = oldDisableValue;
 
     // get rid of the pattern surface ref, just in case
     mThebes->SetColor(gfxRGBA(1,1,1,1));
--- a/dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl
+++ b/dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl
@@ -175,19 +175,23 @@ interface nsIDOMCanvasRenderingContext2D
   // if scaled.
   attribute boolean mozImageSmoothingEnabled;
 
   // Show the caret if appropriate when drawing
   const unsigned long DRAWWINDOW_DRAW_CARET   = 0x01;
   // Don't flush pending layout notifications that could otherwise
   // be batched up
   const unsigned long DRAWWINDOW_DO_NOT_FLUSH = 0x02;
-
   // Draw scrollbars and scroll the viewport if they are present
   const unsigned long DRAWWINDOW_DRAW_VIEW    = 0x04;
+  // Use the widget layer manager if available. This means hardware
+  // acceleration may be used, but it might actually be slower or
+  // lower quality than normal. It will however more accurately reflect
+  // the pixels rendered to the screen.
+  const unsigned long DRAWWINDOW_USE_WIDGET_LAYERS = 0x08;
 
   /**
    * Renders a region of a window into the canvas.  The contents of
    * the window's viewport are rendered, ignoring viewport clipping
    * and scrolling.
    *
    * @param x
    * @param y
--- a/embedding/browser/build/Makefile.in
+++ b/embedding/browser/build/Makefile.in
@@ -47,19 +47,17 @@ MODULE		= webbrwsr
 LIBRARY_NAME	= webbrwsr
 IS_COMPONENT	= 1
 MODULE_NAME	= Browser_Embedding_Module
 EXPORT_LIBRARY	= 1
 GRE_MODULE	= 1
 LIBXUL_LIBRARY	= 1
 
 
-ifeq (,$(filter-out WINCE WINNT,$(OS_ARCH)))
-EXTRA_DSO_LIBS	= gkgfx
-endif
+EXTRA_DSO_LIBS	= gkgfx thebes
 
 CPPSRCS		= \
 		nsWebBrowserModule.cpp		\
 		$(NULL)
 
 SHARED_LIBRARY_LIBS= \
 		../webBrowser/$(LIB_PREFIX)nsWebBrowser_s.$(LIB_SUFFIX) \
 		$(NULL)
--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -69,32 +69,36 @@
 #include "nsGUIEvent.h"
 #include "nsISHistoryListener.h"
 #include "nsIURI.h"
 #include "nsIWebBrowserPersist.h"
 #include "nsCWebBrowserPersist.h"
 #include "nsIServiceManager.h"
 #include "nsAutoPtr.h"
 #include "nsFocusManager.h"
+#include "Layers.h"
+#include "gfxContext.h"
 
 // for painting the background window
 #include "nsIRenderingContext.h"
 #include "nsIDeviceContext.h"
 #include "nsIRegion.h"
 #include "nsILookAndFeel.h"
 
 // Printing Includes
 #ifdef NS_PRINTING
 #include "nsIWebBrowserPrint.h"
 #include "nsIContentViewer.h"
 #endif
 
 // PSM2 includes
 #include "nsISecureBrowserUI.h"
 
+using namespace mozilla::layers;
+
 static NS_DEFINE_IID(kWindowCID, NS_WINDOW_CID);
 static NS_DEFINE_CID(kChildCID, NS_CHILD_CID);
 static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 
 
 //*****************************************************************************
 //***    nsWebBrowser: Object Management
 //*****************************************************************************
@@ -1662,62 +1666,54 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShe
    return NS_OK;
 }
 
 /* static */
 nsEventStatus nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
 {
   nsWebBrowser  *browser = nsnull;
   void          *data = nsnull;
+  nsIWidget     *widget = aEvent->widget;
 
-  if (!aEvent->widget)
+  if (!widget)
     return nsEventStatus_eIgnore;
 
-  aEvent->widget->GetClientData(data);
+  widget->GetClientData(data);
   if (!data)
     return nsEventStatus_eIgnore;
 
   browser = static_cast<nsWebBrowser *>(data);
 
   switch(aEvent->message) {
 
   case NS_PAINT: {
-      nsPaintEvent *paintEvent = static_cast<nsPaintEvent *>(aEvent);
-      nsIRenderingContext *rc = paintEvent->renderingContext;
-      nscolor oldColor;
-      rc->GetColor(oldColor);
-      rc->SetColor(browser->mBackgroundColor);
-      
-      nsCOMPtr<nsIDeviceContext> dx;
-      rc->GetDeviceContext(*getter_AddRefs(dx));
-      PRInt32 appUnitsPerDevPixel = dx->AppUnitsPerDevPixel();
+      LayerManager* layerManager = widget->GetLayerManager();
+      NS_ASSERTION(layerManager, "Must be in paint event");
 
-      nsIRegion *region = paintEvent->region;
-      if (region) {
-          nsRegionRectSet *rects = nsnull;
-          region->GetRects(&rects);
-          if (rects) {
-              for (PRUint32 i = 0; i < rects->mNumRects; ++i) {
-                  nsRect r(rects->mRects[i].x*appUnitsPerDevPixel,
-                           rects->mRects[i].y*appUnitsPerDevPixel,
-                           rects->mRects[i].width*appUnitsPerDevPixel,
-                           rects->mRects[i].height*appUnitsPerDevPixel);
-                  rc->FillRect(r);
-              }
-
-              region->FreeRects(rects);
+      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();
           }
-      } else if (paintEvent->rect) {
-          nsRect r(paintEvent->rect->x*appUnitsPerDevPixel,
-                   paintEvent->rect->y*appUnitsPerDevPixel,
-                   paintEvent->rect->width*appUnitsPerDevPixel,
-                   paintEvent->rect->height*appUnitsPerDevPixel);
-          rc->FillRect(r);
       }
-      rc->SetColor(oldColor);
+      root->EndDrawing();
+      layerManager->EndTransaction();
       return nsEventStatus_eConsumeDoDefault;
     }
 
   case NS_ACTIVATE: {
 #if defined(DEBUG_smaug)
     nsCOMPtr<nsIDOMDocument> domDocument = do_GetInterface(browser->mDocShell);
     nsAutoString documentURI;
     if (domDocument) {
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -725,26 +725,46 @@ nsDisplayList::BuildLayer(nsDisplayListB
 }
 
 /**
  * We paint by executing a layer manager transaction, constructing a
  * single layer representing the display list, and then making it the
  * root of the layer manager, drawing into the ThebesLayers.
  */
 void nsDisplayList::Paint(nsDisplayListBuilder* aBuilder,
-                          nsIRenderingContext* aCtx) const {
+                          nsIRenderingContext* aCtx,
+                          PRUint32 aFlags) const {
   NS_ASSERTION(mDidComputeVisibility,
                "Must call ComputeVisibility before calling Paint");
 
-  // To paint a display list, we construct a BasicLayerManager and
-  // a layer tree for it, and ask the BasicLayerManager to render.
-  nsRefPtr<LayerManager> layerManager = new BasicLayerManager();
-  if (!layerManager)
-    return;
-  layerManager->BeginTransactionWithTarget(aCtx->ThebesContext());
+  nsRefPtr<LayerManager> layerManager;
+  if (aFlags & PAINT_USE_WIDGET_LAYERS) {
+    nsIFrame* referenceFrame = aBuilder->ReferenceFrame();
+    NS_ASSERTION(referenceFrame == nsLayoutUtils::GetDisplayRootFrame(referenceFrame),
+                 "Reference frame must be a display root for us to use the layer manager");
+    nsIWidget* window = referenceFrame->GetWindow();
+    if (window) {
+      layerManager = window->GetLayerManager();
+    }
+  }
+  if (!layerManager) {
+    if (!aCtx) {
+      NS_WARNING("Nowhere to paint into");
+      return;
+    }
+    layerManager = new BasicLayerManager(aCtx->ThebesContext());
+    if (!layerManager)
+      return;
+  }
+
+  if (aCtx) {
+    layerManager->BeginTransactionWithTarget(aCtx->ThebesContext());
+  } else {
+    layerManager->BeginTransaction();
+  }
 
   nsAutoTArray<LayerItems,10> layers;
   nsRefPtr<Layer> root = BuildLayer(aBuilder, layerManager, &layers);
   if (!root)
     return;
 
   layerManager->SetRoot(root);
   layerManager->EndConstruction();
@@ -1824,17 +1844,17 @@ void nsDisplayTransform::Paint(nsDisplay
 
   /* Set the matrix for the transform based on the old matrix and the new
    * transform data.
    */
   gfx->SetMatrix(newTransformMatrix);
 
   /* Now, send the paint call down.
    */    
-  mStoredList.GetList()->Paint(aBuilder, aCtx);
+  mStoredList.GetList()->Paint(aBuilder, aCtx, nsDisplayList::PAINT_DEFAULT);
 
   /* The AutoSaveRestore object will clean things up. */
 }
 
 PRBool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,
                                              nsRegion *aVisibleRegion,
                                              nsRegion *aVisibleRegionBeforeMove)
 {
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -545,16 +545,17 @@ public:
    * This can only be called when aBuilder->IsMovingFrame(mFrame) is true.
    * It return PR_TRUE for all wrapped lists.
    */
   virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder)
   { return PR_FALSE; }
   /**
    * Actually paint this item to some rendering context.
    * Content outside mVisibleRect need not be painted.
+   * aCtx must be set up as for nsDisplayList::Paint.
    */
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx) {}
   /**
    * Get the layer drawn by this display item, if any. If this display
    * item doesn't have its own layer, then Paint will be called on it
    * later. If it returns a layer here then Paint will not be called.
    * This is called while aManager is in the construction phase.
    * This is where content can decide to be rendered by the layer
@@ -843,19 +844,30 @@ public:
   }
   /**
    * Paint the list to the rendering context. We assume that (0,0) in aCtx
    * corresponds to the origin of the reference frame. For best results,
    * aCtx's current transform should make (0,0) pixel-aligned. The
    * rectangle in aDirtyRect is painted, which *must* be contained in the
    * dirty rect used to construct the display list.
    * 
+   * If aFlags contains PAINT_USE_WIDGET_LAYERS and
+   * ShouldUseWidgetLayerManager() is set, then we will paint using
+   * the reference frame's widget's layer manager (and ctx may be null),
+   * otherwise we will use a temporary BasicLayerManager and ctx must
+   * not be null.
+   * 
    * ComputeVisibility must be called before Paint.
    */
-  void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx) const;
+  enum {
+    PAINT_DEFAULT = 0,
+    PAINT_USE_WIDGET_LAYERS = 0x01
+  };
+  void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
+             PRUint32 aFlags) const;
   /**
    * Get the bounds. Takes the union of the bounds of all children.
    */
   nsRect GetBounds(nsDisplayListBuilder* aBuilder) const;
   /**
    * Find the topmost display item that returns a non-null frame, and return
    * the frame.
    */
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -819,25 +819,33 @@ public:
    *   set RENDER_IS_UNTRUSTED if the contents may be passed to malicious
    * agents. E.g. we might choose not to paint the contents of sensitive widgets
    * such as the file name in a file upload widget, and we might choose not
    * to paint themes.
    *   set RENDER_IGNORE_VIEWPORT_SCROLLING to ignore
    * clipping/scrolling/scrollbar painting due to scrolling in the viewport
    *   set RENDER_CARET to draw the caret if one would be visible
    * (by default the caret is never drawn)
+   *   set RENDER_USE_LAYER_MANAGER to force rendering to go through
+   * the layer manager for the window. This may be unexpectedly slow
+   * (if the layer manager must read back data from the GPU) or low-quality
+   * (if the layer manager reads back pixel data and scales it
+   * instead of rendering using the appropriate scaling). It may also
+   * slow everything down if the area rendered does not correspond to the
+   * normal visible area of the window.
    * @param aBackgroundColor a background color to render onto
    * @param aRenderedContext the gfxContext to render to. We render so that
    * one CSS pixel in the source document is rendered to one unit in the current
    * transform.
    */
   enum {
     RENDER_IS_UNTRUSTED = 0x01,
     RENDER_IGNORE_VIEWPORT_SCROLLING = 0x02,
-    RENDER_CARET = 0x04
+    RENDER_CARET = 0x04,
+    RENDER_USE_WIDGET_LAYERS = 0x08
   };
   NS_IMETHOD RenderDocument(const nsRect& aRect, PRUint32 aFlags,
                             nscolor aBackgroundColor,
                             gfxContext* aRenderedContext) = 0;
 
   /**
    * Renders a node aNode to a surface and returns it. The aRegion may be used
    * to clip the rendering. This region is measured in device pixels from the
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1187,17 +1187,21 @@ nsLayoutUtils::PaintFrame(nsIRenderingCo
 
 #ifdef DEBUG
   if (gDumpPaintList) {
     fprintf(stderr, "Painting --- after optimization:\n");
     nsFrame::PrintDisplayList(&builder, list);
   }
 #endif
 
-  list.Paint(&builder, aRenderingContext);
+  PRUint32 flags = nsDisplayList::PAINT_DEFAULT;
+  if (aFlags & PAINT_WIDGET_LAYERS) {
+    flags |= nsDisplayList::PAINT_USE_WIDGET_LAYERS;
+  }
+  list.Paint(&builder, aRenderingContext, flags);
   // Flush the list so we don't trigger the IsEmpty-on-destruction assertion
   list.DeleteAll();
   return NS_OK;
 }
 
 #ifdef DEBUG
 static void
 PrintAddedRegion(const char* aFormat, nsIFrame* aFrame,
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -472,32 +472,54 @@ public:
    * @param aFactor The number of app units per graphics unit.
    * @return The smallest rectangle in app space that contains aRect.
    */
   static nsRect RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor);
 
 
   enum {
     PAINT_IN_TRANSFORM = 0x01,
-    PAINT_SYNC_DECODE_IMAGES = 0x02
+    PAINT_SYNC_DECODE_IMAGES = 0x02,
+    PAINT_WIDGET_LAYERS = 0x04
   };
 
   /**
    * Given aFrame, the root frame of a stacking context, paint it and its
    * descendants to aRenderingContext. 
    * @param aRenderingContext a rendering context translated so that (0,0)
    * is the origin of aFrame; for best results, (0,0) should transform
-   * to pixel-aligned coordinates
+   * to pixel-aligned coordinates. This can be null, in which case
+   * aFrame must be a "display root" (root frame for a root document,
+   * or the root of a popup) with an associated widget and we draw using
+   * the layer manager for the frame's widget.
    * @param aDirtyRegion the region that must be painted, in the coordinates
    * of aFrame
    * @param aBackstop paint the dirty area with this color before drawing
    * the actual content; pass NS_RGBA(0,0,0,0) to draw no background
    * @param aFlags if PAINT_IN_TRANSFORM is set, then we assume
    * this is inside a transform or SVG foreignObject. If
-   * PAINT_SYNC_DECODE_IMAGES is set, we force synchronous decode on all images.
+   * PAINT_SYNC_DECODE_IMAGES is set, we force synchronous decode on all
+   * images. If PAINT_WIDGET_LAYERS is set, aFrame must be a display root,
+   * and we will use the frame's widget's layer manager to paint
+   * even if aRenderingContext is non-null. This is useful if you want
+   * to force rendering to use the widget's layer manager for testing
+   * or speed. PAINT_WIDGET_LAYERS must be set if aRenderingContext is null.
+   * 
+   * So there are three possible behaviours:
+   * 1) PAINT_WIDGET_LAYERS is set and aRenderingContext is null; we paint
+   * by calling BeginTransaction on the widget's layer manager
+   * 2) PAINT_WIDGET_LAYERS is set and aRenderingContext is non-null; we
+   * paint by calling BeginTransactionWithTarget on the widget's layer
+   * maanger
+   * 3) PAINT_WIDGET_LAYERS is not set and aRenderingContext is non-null;
+   * we paint by construct a BasicLayerManager and calling
+   * BeginTransactionWithTarget on it. This is desirable if we're doing
+   * something like drawWindow in a mode where what gets rendered doesn't
+   * necessarily correspond to what's visible in the window; we don't
+   * want to mess up the widget's layer tree.
    */
   static nsresult PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFrame,
                              const nsRegion& aDirtyRegion, nscolor aBackstop,
                              PRUint32 aFlags = 0);
 
   /**
    * @param aRootFrame the root frame of the tree to be displayed
    * @param aMovingFrame a frame that has moved
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -201,16 +201,18 @@
 // Content viewer interfaces
 #include "nsIContentViewer.h"
 #include "imgIEncoder.h"
 #include "gfxPlatform.h"
 
 #include "nsContentCID.h"
 static NS_DEFINE_IID(kRangeCID,     NS_RANGE_CID);
 
+using namespace mozilla::layers;
+
 PRBool nsIPresShell::gIsAccessibilityActive = PR_FALSE;
 CapturingContentInfo nsIPresShell::gCaptureInfo;
 
 // convert a color value to a string, in the CSS format #RRGGBB
 // *  - initially created for bugs 31816, 20760, 22963
 static void ColorToString(nscolor aColor, nsAutoString &aString);
 
 // Class ID's
@@ -779,22 +781,21 @@ public:
                                                    nsIntRect* aScreenRect);
 
   virtual already_AddRefed<gfxASurface> RenderSelection(nsISelection* aSelection,
                                                         nsIntPoint& aPoint,
                                                         nsIntRect* aScreenRect);
 
   //nsIViewObserver interface
 
-  NS_IMETHOD Paint(nsIView *aView,
-                   nsIRenderingContext* aRenderingContext,
-                   const nsRegion& aDirtyRegion);
-  NS_IMETHOD PaintDefaultBackground(nsIView *aView,
-                                    nsIRenderingContext* aRenderingContext,
-                                    const nsRect& aDirtyRect);
+  NS_IMETHOD Paint(nsIView* aDisplayRoot,
+                   nsIView* aViewToPaint,
+                   nsIWidget* aWidget,
+                   const nsRegion& aDirtyRegion,
+                   PRBool aPaintDefaultBackground);
   NS_IMETHOD ComputeRepaintRegionForCopy(nsIView*      aRootView,
                                          nsIView*      aMovingView,
                                          nsPoint       aDelta,
                                          const nsRect& aUpdateRect,
                                          nsRegion*     aBlitRegion,
                                          nsRegion*     aRepaintRegion);
   NS_IMETHOD HandleEvent(nsIView*        aView,
                          nsGUIEvent*     aEvent,
@@ -1282,17 +1283,17 @@ private:
   PRPackedBool mInResize;
 
 private:
   /*
    * Computes the backstop color for the view: transparent if in a transparent
    * widget, otherwise the PresContext default background color. This color is
    * only visible if the contents of the view as a whole are translucent.
    */
-  nscolor ComputeBackstopColor(nsIView* aView);
+  nscolor ComputeBackstopColor(nsIView* aDisplayRoot);
 
 #ifdef DEBUG
   // Ensure that every allocation from the PresArena is eventually freed.
   PRUint32 mPresArenaAllocCount;
 #endif
 };
 
 class nsAutoCauseReflowNotifier
@@ -5274,17 +5275,21 @@ PresShell::RenderDocument(const nsRect& 
       nsIDeviceContext* devCtx = mPresContext->DeviceContext();
       gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
       aThebesContext->Scale(scale, scale);
       
       nsCOMPtr<nsIRenderingContext> rc;
       devCtx->CreateRenderingContextInstance(*getter_AddRefs(rc));
       rc->Init(devCtx, aThebesContext);
 
-      list.Paint(&builder, rc);
+      PRUint32 flags = nsDisplayList::PAINT_DEFAULT;
+      if (aFlags & RENDER_USE_WIDGET_LAYERS) {
+        flags |= nsDisplayList::PAINT_USE_WIDGET_LAYERS;
+      }
+      list.Paint(&builder, rc, flags);
       // Flush the list so we don't trigger the IsEmpty-on-destruction assertion
       list.DeleteAll();
 
       aThebesContext->Restore();
     }
   }
 
   if (!didPrepareContext)
@@ -5567,17 +5572,17 @@ PresShell::PaintRangePaintInfo(nsTArray<
     // the display lists paint relative to the offset from the reference
     // frame, so translate the rendering context
     nsIRenderingContext::AutoPushTranslation
       translate(rc, rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y);
 
     aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y);
     nsRegion visible(aArea);
     rangeInfo->mList.ComputeVisibility(&rangeInfo->mBuilder, &visible, nsnull);
-    rangeInfo->mList.Paint(&rangeInfo->mBuilder, rc);
+    rangeInfo->mList.Paint(&rangeInfo->mBuilder, rc, nsDisplayList::PAINT_DEFAULT);
     aArea.MoveBy(rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y);
   }
 
   // restore the old selection display state
   frameSelection->SetDisplaySelection(oldDisplaySelection);
 
   NS_ADDREF(surface);
   return surface;
@@ -5711,71 +5716,105 @@ void PresShell::UpdateCanvasBackground()
   // If the root element of the document (ie html) has style 'display: none'
   // then the document's background color does not get drawn; cache the
   // color we actually draw.
   if (!FrameConstructor()->GetRootElementFrame()) {
     mCanvasBackgroundColor = mPresContext->DefaultBackgroundColor();
   }
 }
 
-nscolor PresShell::ComputeBackstopColor(nsIView* aView)
-{
-  nsIWidget* widget = aView->GetNearestWidget(nsnull);
+nscolor PresShell::ComputeBackstopColor(nsIView* aDisplayRoot)
+{
+  nsIWidget* widget = aDisplayRoot->GetWidget();
   if (widget && widget->GetTransparencyMode() != eTransparencyOpaque) {
     // Within a transparent widget, so the backstop color must be
     // totally transparent.
     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();
 }
 
 NS_IMETHODIMP
-PresShell::Paint(nsIView*             aView,
-                 nsIRenderingContext* aRenderingContext,
-                 const nsRegion&      aDirtyRegion)
-{
-  AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint);
+PresShell::Paint(nsIView*        aDisplayRoot,
+                 nsIView*        aViewToPaint,
+                 nsIWidget*      aWidgetToPaint,
+                 const nsRegion& aDirtyRegion,
+                 PRBool          aPaintDefaultBackground)
+{
+  nsPresContext* presContext = GetPresContext();
+  AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
 
   NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
-  NS_ASSERTION(aView, "null view");
-
-  nscolor bgcolor = ComputeBackstopColor(aView);
-
-  nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
-  if (frame) {
-    nsLayoutUtils::PaintFrame(aRenderingContext, frame, aDirtyRegion, bgcolor);
-  } else {
-    bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
-    aRenderingContext->SetColor(bgcolor);
-    aRenderingContext->FillRect(aDirtyRegion.GetBounds());
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-PresShell::PaintDefaultBackground(nsIView*             aView,
-                                  nsIRenderingContext* aRenderingContext,
-                                  const nsRect&        aDirtyRect)
-{
-  AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint);
-
-  NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
-  NS_ASSERTION(aView, "null view");
-
-  // We must not look at the frame tree, so all we have to use is the canvas
-  // default color as set above.
-
-  nscolor bgcolor = NS_ComposeColors(ComputeBackstopColor(aView),
-                                     mCanvasBackgroundColor);
-
-  aRenderingContext->SetColor(bgcolor);
-  aRenderingContext->FillRect(aDirtyRect);
+  NS_ASSERTION(aDisplayRoot, "null view");
+  NS_ASSERTION(aViewToPaint, "null view");
+  NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
+
+  nscolor bgcolor = ComputeBackstopColor(aDisplayRoot);
+
+  nsIFrame* frame = aPaintDefaultBackground
+      ? nsnull : static_cast<nsIFrame*>(aDisplayRoot->GetClientData());
+
+  if (frame && aViewToPaint == aDisplayRoot) {
+    // We can paint directly into the widget using its layer manager.
+    // When we get rid of child widgets, this will be the only path we
+    // need. (aPaintDefaultBackground will never be needed since the
+    // chrome can always paint a default background.)
+    nsLayoutUtils::PaintFrame(nsnull, frame, aDirtyRegion, bgcolor,
+                              nsLayoutUtils::PAINT_WIDGET_LAYERS);
+    return NS_OK;
+  }
+
+  LayerManager* layerManager = aWidgetToPaint->GetLayerManager();
+  NS_ASSERTION(layerManager, "Must be in paint event");
+
+  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);
+          nsIRenderingContext::AutoPushTranslation
+            push(rc, -offsetToRoot.x, -offsetToRoot.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();
+
   return NS_OK;
 }
 
 // static
 void
 nsIPresShell::SetCapturingContent(nsIContent* aContent, PRUint8 aFlags)
 {
   NS_IF_RELEASE(gCaptureInfo.mContent);
--- a/layout/svg/base/src/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/base/src/nsSVGIntegrationUtils.cpp
@@ -204,17 +204,17 @@ public:
                             const nsPoint& aOffset)
     : mBuilder(aBuilder), mInnerList(aInnerList), mOffset(aOffset) {}
 
   virtual void Paint(nsSVGRenderState *aContext, nsIFrame *aTarget,
                      const nsIntRect* aDirtyRect)
   {
     nsIRenderingContext* ctx = aContext->GetRenderingContext(aTarget);
     nsIRenderingContext::AutoPushTranslation push(ctx, -mOffset.x, -mOffset.y);
-    mInnerList->Paint(mBuilder, ctx);
+    mInnerList->Paint(mBuilder, ctx, nsDisplayList::PAINT_DEFAULT);
   }
 
 private:
   nsDisplayListBuilder* mBuilder;
   nsDisplayList* mInnerList;
   nsPoint mOffset;
 };
 
@@ -297,17 +297,17 @@ nsSVGIntegrationUtils::PaintFramesWithEf
 
   /* Paint the child */
   if (filterFrame) {
     RegularFramePaintCallback paint(aBuilder, aInnerList, userSpaceRect.TopLeft());
     nsIntRect r = (aDirtyRect - userSpaceRect.TopLeft()).ToOutsidePixels(appUnitsPerDevPixel);
     filterFrame->FilterPaint(&svgContext, aEffectsFrame, &paint, &r);
   } else {
     gfx->SetMatrix(savedCTM);
-    aInnerList->Paint(aBuilder, aCtx);
+    aInnerList->Paint(aBuilder, aCtx, nsDisplayList::PAINT_DEFAULT);
     aCtx->Translate(userSpaceRect.x, userSpaceRect.y);
   }
 
   if (clipPathFrame && isTrivialClip) {
     gfx->Restore();
   }
 
   /* No more effects, we're done. */
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -872,17 +872,18 @@ function InitCurrentCanvasWithSnapshot()
     // drawWindow always draws one canvas pixel for each CSS pixel in the source
     // window, so scale the drawing to show the zoom (making each canvas pixel be one
     // device pixel instead)
     ctx.scale(scale, scale);
     ctx.drawWindow(win, win.scrollX, win.scrollY,
                    Math.ceil(gCurrentCanvas.width / scale),
                    Math.ceil(gCurrentCanvas.height / scale),
                    "rgb(255,255,255)",
-                   ctx.DRAWWINDOW_DRAW_CARET);
+                   ctx.DRAWWINDOW_DRAW_CARET |
+                   ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
     ctx.restore();
 }
 
 function roundTo(x, fraction)
 {
     return Math.round(x/fraction)*fraction;
 }
 
--- a/view/public/nsIViewObserver.h
+++ b/view/public/nsIViewObserver.h
@@ -42,58 +42,45 @@
 #include "nsEvent.h"
 #include "nsColor.h"
 #include "nsRect.h"
 
 class nsIRenderingContext;
 class nsGUIEvent;
 
 #define NS_IVIEWOBSERVER_IID  \
-  { 0xba1357b6, 0xe3c7, 0x426a, \
-    { 0xb3, 0x68, 0xfe, 0xe8, 0x24, 0x8c, 0x08, 0x38 } }
+  { 0xac43a985, 0xcae6, 0x499d, \
+    { 0xae, 0x8f, 0x9c, 0x92, 0xec, 0x6f, 0x2c, 0x47 } }
 
 class nsIViewObserver : public nsISupports
 {
 public:
   
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IVIEWOBSERVER_IID)
 
   /* called when the observer needs to paint. This paints the entire
    * frame subtree rooted at the view, including frame subtrees from
    * subdocuments.
-   * @param aRenderingContext rendering context to paint to; the origin
-   * of the view is painted at (0,0) in the rendering context's current
-   * transform. For best results this should transform to pixel-aligned
-   * coordinates.
+   * @param aViewToPaint the view for the widget that is being painted
    * @param aDirtyRegion the region to be painted, in the coordinates of
-   * aRootView
+   * aViewToPaint
+   * @param aPaintDefaultBackground just paint the default background,
+   * don't try to paint any content. This is set when the observer
+   * needs to paint something, but the view tree is unstable, so it
+   * must *not* paint, or even examine, the frame subtree rooted at the
+   * view.  (It is, however, safe to inspect the state of the view itself,
+   * and any associated widget.) The name illustrates the expected behavior,
+   * which is to paint some default background color over the dirty region.
    * @return error status
    */
-  NS_IMETHOD Paint(nsIView*             aRootView,
-                   nsIRenderingContext* aRenderingContext,
-                   const nsRegion&      aDirtyRegion) = 0;
-
-  /* called when the observer needs to paint something, but the view
-   * tree is unstable, so it must *not* paint, or even examine, the
-   * frame subtree rooted at the view.  (It is, however, safe to inspect
-   * the state of the view itself, and any associated widget.)  The name
-   * illustrates the expected behavior, which is to paint some default
-   * background color over the dirty rect.
-   *
-   * @param aRenderingContext rendering context to paint to; the origin
-   * of the view is painted at (0,0) in the rendering context's current
-   * transform. For best results this should transform to pixel-aligned
-   * coordinates.
-   * @param aDirtyRect the rectangle to be painted, in the coordinates
-   * of aRootView
-   * @return error status
-   */
-  NS_IMETHOD PaintDefaultBackground(nsIView*             aRootView,
-                                    nsIRenderingContext* aRenderingContext,
-                                    const nsRect&        aDirtyRect) = 0;
+  NS_IMETHOD Paint(nsIView*        aDisplayRoot,
+                   nsIView*        aViewToPaint,
+                   nsIWidget*      aWidgetToPaint,
+                   const nsRegion& aDirtyRegion,
+                   PRBool          aPaintDefaultBackground) = 0;
 
   /* called when the observer needs to handle an event
    * @param aView  - where to start processing the event; the root view,
    * or the view that's currently capturing this sort of event; must be a view
    * for this presshell
    * @param aEvent - event notification
    * @param aEventStatus - out parameter for event handling
    *                       status
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -347,38 +347,30 @@ NS_IMETHODIMP nsViewManager::FlushDelaye
 {
   if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
     DoSetWindowDimensions(mDelayedResize.width, mDelayedResize.height);
     mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
   }
   return NS_OK;
 }
 
-static void ConvertNativeRegionToAppRegion(nsIRegion* aIn, nsRegion* aOut,
-                                           nsIDeviceContext* context)
+static nsRegion ConvertDeviceRegionToAppRegion(const nsIntRegion& aIn,
+                                               nsIDeviceContext* aContext)
 {
-  nsRegionRectSet* rects = nsnull;
-  aIn->GetRects(&rects);
-  if (!rects)
-    return;
-
-  PRInt32 p2a = context->AppUnitsPerDevPixel();
+  PRInt32 p2a = aContext->AppUnitsPerDevPixel();
 
-  PRUint32 i;
-  for (i = 0; i < rects->mNumRects; i++) {
-    const nsRegionRect& inR = rects->mRects[i];
-    nsRect outR;
-    outR.x = NSIntPixelsToAppUnits(inR.x, p2a);
-    outR.y = NSIntPixelsToAppUnits(inR.y, p2a);
-    outR.width = NSIntPixelsToAppUnits(inR.width, p2a);
-    outR.height = NSIntPixelsToAppUnits(inR.height, p2a);
-    aOut->Or(*aOut, outR);
+  nsRegion out;
+  nsIntRegionRectIterator iter(aIn);
+  for (;;) {
+    const nsIntRect* r = iter.Next();
+    if (!r)
+      break;
+    out.Or(out, r->ToAppUnits(p2a));
   }
-
-  aIn->FreeRects(rects);
+  return out;
 }
 
 static nsView* GetDisplayRootFor(nsView* aView)
 {
   nsView *displayRoot = aView;
   for (;;) {
     nsView *displayParent = displayRoot->GetParent();
     if (!displayParent)
@@ -387,34 +379,33 @@ static nsView* GetDisplayRootFor(nsView*
     if (displayRoot->GetFloating() && !displayParent->GetFloating())
       return displayRoot;
     displayRoot = displayParent;
   }
 }
 
 /**
    aRegion is given in device coordinates!!
+   aContext may be null, in which case layers should be used for
+   rendering.
 */
-void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
-                            nsIRegion *aRegion, PRUint32 aUpdateFlags)
+void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
+                            const nsIntRegion& aRegion,
+                            PRUint32 aUpdateFlags)
 {
-  NS_ASSERTION(aRegion != nsnull, "Null aRegion");
-
   if (! IsRefreshEnabled())
     return;
 
   nsRect viewRect;
   aView->GetDimensions(viewRect);
   nsPoint vtowoffset = aView->ViewToWidgetOffset();
 
   // damageRegion is the damaged area, in twips, relative to the view origin
-  nsRegion damageRegion;
-  // convert pixels-relative-to-widget-origin to twips-relative-to-widget-origin
-  ConvertNativeRegionToAppRegion(aRegion, &damageRegion, mContext);
-  // move it from widget coordinates into view coordinates
+  nsRegion damageRegion = ConvertDeviceRegionToAppRegion(aRegion, mContext);
+  // move region from widget coordinates into view coordinates
   damageRegion.MoveBy(viewRect.TopLeft() - vtowoffset);
 
   if (damageRegion.IsEmpty()) {
 #ifdef DEBUG_roc
     nsRect damageRect = damageRegion.GetBounds();
     printf("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
            damageRect.x, damageRect.y, damageRect.width, damageRect.height,
            viewRect.x, viewRect.y, viewRect.width, viewRect.height);
@@ -427,78 +418,44 @@ void nsViewManager::Refresh(nsView *aVie
     RootViewManager()->mRecursiveRefreshPending = PR_TRUE;
     return;
   }  
 
   {
     nsAutoScriptBlocker scriptBlocker;
     SetPainting(PR_TRUE);
 
-    nsCOMPtr<nsIRenderingContext> localcx;
-    if (nsnull == aContext)
-      {
-        localcx = CreateRenderingContext(*aView);
-
-        //couldn't get rendering context. this is ok at init time atleast
-        if (nsnull == localcx) {
-          SetPainting(PR_FALSE);
-          return;
-        }
-      } else {
-        // plain assignment grabs another reference.
-        localcx = aContext;
-      }
-
-    PRInt32 p2a = mContext->AppUnitsPerDevPixel();
-
-    nsRefPtr<gfxContext> ctx = localcx->ThebesContext();
-
-    ctx->Save();
-
-    ctx->Translate(gfxPoint(gfxFloat(vtowoffset.x) / p2a,
-                            gfxFloat(vtowoffset.y) / p2a));
-
-    ctx->Translate(gfxPoint(-gfxFloat(viewRect.x) / p2a,
-                            -gfxFloat(viewRect.y) / p2a));
-
-    RenderViews(aView, *localcx, damageRegion);
-
-    ctx->Restore();
+    RenderViews(aView, aWidget, damageRegion);
 
     SetPainting(PR_FALSE);
   }
 
   if (RootViewManager()->mRecursiveRefreshPending) {
     // Unset this flag first, since if aUpdateFlags includes NS_VMREFRESH_IMMEDIATE
     // we'll reenter this code from the UpdateAllViews call.
     RootViewManager()->mRecursiveRefreshPending = PR_FALSE;
     UpdateAllViews(aUpdateFlags);
   }
 }
 
 // aRC and aRegion are in view coordinates
-void nsViewManager::RenderViews(nsView *aView, nsIRenderingContext& aRC,
+void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget,
                                 const nsRegion& aRegion)
 {
   nsView* displayRoot = GetDisplayRootFor(aView);
   // Make sure we call Paint from the view manager that owns displayRoot.
   // (Bug 485275)
   nsViewManager* displayRootVM = displayRoot->GetViewManager();
-  if (displayRootVM && displayRootVM != this)
-    return displayRootVM->RenderViews(aView, aRC, aRegion);
+  if (displayRootVM && displayRootVM != this) {
+    displayRootVM->RenderViews(aView, aWidget, aRegion);
+    return;
+  }
 
   if (mObserver) {
-    nsPoint offsetToRoot = aView->GetOffsetTo(displayRoot);
-    nsRegion damageRegion(aRegion);
-    damageRegion.MoveBy(offsetToRoot);
-
-    aRC.PushState();
-    aRC.Translate(-offsetToRoot.x, -offsetToRoot.y);
-    mObserver->Paint(displayRoot, &aRC, damageRegion);
-    aRC.PopState();
+    mObserver->Paint(displayRoot, aView, aWidget, aRegion, PR_FALSE);
   }
 }
 
 void nsViewManager::ProcessPendingUpdates(nsView* aView, PRBool aDoInvalidate)
 {
   NS_ASSERTION(IsRootVM(), "Updates will be missed");
 
   // Protect against a null-view.
@@ -834,31 +791,21 @@ NS_IMETHODIMP nsViewManager::DispatchEve
       {
         nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
 
         if (!aView || !mContext)
           break;
 
         *aStatus = nsEventStatus_eConsumeNoDefault;
 
+        if (aEvent->message == NS_PAINT && event->region.IsEmpty())
+          break;
+
         // The rect is in device units, and it's in the coordinate space of its
         // associated window.
-        nsCOMPtr<nsIRegion> region = event->region;
-        if (aEvent->message == NS_PAINT) {
-          if (!region) {
-            if (NS_FAILED(CreateRegion(getter_AddRefs(region))))
-              break;
-
-            const nsIntRect& damrect = *event->rect;
-            region->SetTo(damrect.x, damrect.y, damrect.width, damrect.height);
-          }
-
-          if (region->IsEmpty())
-            break;
-        }
 
         // Refresh the view
         if (IsRefreshEnabled()) {
           nsRefPtr<nsViewManager> rootVM = RootViewManager();
 
           // If an ancestor widget was hidden and then shown, we could
           // have a delayed resize to handle.
           PRBool didResize = PR_FALSE;
@@ -921,38 +868,26 @@ NS_IMETHODIMP nsViewManager::DispatchEve
             }
             // Make sure to sync up any widget geometry changes we
             // have pending before we paint.
             if (rootVM->mHasPendingUpdates) {
               rootVM->ProcessPendingUpdates(mRootView, PR_FALSE);
             }
             
             if (view && aEvent->message == NS_PAINT) {
-              Refresh(view, event->renderingContext, region,
-                      NS_VMREFRESH_DOUBLE_BUFFER);
+              Refresh(view, event->widget,
+                      event->region, NS_VMREFRESH_DOUBLE_BUFFER);
             }
           }
         } else if (aEvent->message == NS_PAINT) {
           // since we got an NS_PAINT event, we need to
           // draw something so we don't get blank areas,
           // unless there's no widget or it's transparent.
-          nsIntRect damIntRect;
-          region->GetBoundingBox(&damIntRect.x, &damIntRect.y,
-                                 &damIntRect.width, &damIntRect.height);
-          nsRect damRect =
-            damIntRect.ToAppUnits(mContext->AppUnitsPerDevPixel());
-
-          nsCOMPtr<nsIRenderingContext> context = event->renderingContext;
-          if (!context)
-            context = CreateRenderingContext(*static_cast<nsView*>(aView));
-
-          if (context)
-            mObserver->PaintDefaultBackground(aView, context, damRect);
-          else
-            NS_WARNING("nsViewManager: no rc for default refresh");        
+          nsRegion rgn = ConvertDeviceRegionToAppRegion(event->region, mContext);
+          mObserver->Paint(aView, aView, event->widget, rgn, PR_TRUE);
 
           // Clients like the editor can trigger multiple
           // reflows during what the user perceives as a single
           // edit operation, so it disables view manager
           // refreshing until the edit operation is complete
           // so that users don't see the intermediate steps.
           // 
           // Unfortunately some of these reflows can trigger
@@ -968,17 +903,17 @@ NS_IMETHODIMP nsViewManager::DispatchEve
           //
           // Note that calling UpdateView() here was deemed
           // to have the least impact on performance, since the
           // other alternative was to make Scroll() post an
           // async paint event for the *entire* ScrollPort or
           // ScrollingView's viewable area. (See bug 97674 for this
           // alternate patch.)
 
-          UpdateView(aView, damRect, NS_VMREFRESH_NO_SYNC);
+          UpdateView(aView, rgn.GetBounds(), NS_VMREFRESH_NO_SYNC);
         }
 
         break;
       }
 
     case NS_CREATE:
     case NS_DESTROY:
     case NS_SETZLEVEL:
@@ -1545,63 +1480,16 @@ NS_IMETHODIMP nsViewManager::GetViewObse
 
 NS_IMETHODIMP nsViewManager::GetDeviceContext(nsIDeviceContext *&aContext)
 {
   NS_IF_ADDREF(mContext);
   aContext = mContext;
   return NS_OK;
 }
 
-already_AddRefed<nsIRenderingContext>
-nsViewManager::CreateRenderingContext(nsView &aView)
-{
-  nsView              *par = &aView;
-  nsIWidget*          win;
-  nsIRenderingContext *cx = nsnull;
-  nscoord             ax = 0, ay = 0;
-
-  do
-    {
-      win = par->GetWidget();
-      if (win)
-        break;
-
-      //get absolute coordinates of view, but don't
-      //add in view pos since the first thing you ever
-      //need to do when painting a view is to translate
-      //the rendering context by the views pos and other parts
-      //of the code do this for us...
-
-      if (par != &aView)
-        {
-          par->ConvertToParentCoords(&ax, &ay);
-        }
-
-      par = par->GetParent();
-    }
-  while (nsnull != par);
-
-  if (nsnull != win)
-    {
-      // XXXkt this has an origin at top-left of win ...
-      mContext->CreateRenderingContext(par, cx);
-
-      // XXXkt ... but the translation is between the origins of views
-      NS_ASSERTION(aView.ViewToWidgetOffset()
-                   - aView.GetDimensions().TopLeft() ==
-                   par->ViewToWidgetOffset()
-                   - par->GetDimensions().TopLeft(),
-                   "ViewToWidgetOffset not handled!");
-      if (nsnull != cx)
-        cx->Translate(ax, ay);
-    }
-
-  return cx;
-}
-
 void nsViewManager::TriggerRefresh(PRUint32 aUpdateFlags)
 {
   if (!IsRootVM()) {
     RootViewManager()->TriggerRefresh(aUpdateFlags);
     return;
   }
   
   if (mUpdateBatchCnt > 0)
--- a/view/src/nsViewManager.h
+++ b/view/src/nsViewManager.h
@@ -174,28 +174,27 @@ private:
   void FlushPendingInvalidates();
   void ProcessPendingUpdates(nsView *aView, PRBool aDoInvalidate);
   /**
    * Call WillPaint() on all view observers under this vm root.
    */
   void CallWillPaintOnObservers();
   void ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget);
   void ReparentWidgets(nsIView* aView, nsIView *aParent);
-  already_AddRefed<nsIRenderingContext> CreateRenderingContext(nsView &aView);
   void UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
                         const nsRegion &aDamagedRegion,
                         nsView* aIgnoreWidgetView);
 
   void UpdateViews(nsView *aView, PRUint32 aUpdateFlags);
 
   void TriggerRefresh(PRUint32 aUpdateFlags);
 
-  void Refresh(nsView *aView, nsIRenderingContext *aContext,
-               nsIRegion *region, PRUint32 aUpdateFlags);
-  void RenderViews(nsView *aRootView, nsIRenderingContext& aRC,
+  void Refresh(nsView *aView, nsIWidget *aWidget,
+               const nsIntRegion& aRegion, PRUint32 aUpdateFlags);
+  void RenderViews(nsView *aRootView, nsIWidget *aWidget,
                    const nsRegion& aRegion);
 
   void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut, PRUint32 aUpdateFlags);
   void InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
                                           PRUint32 aUpdateFlags, nscoord aY1, nscoord aY2, PRBool aInCutOut);
 
   // Utilities
 
--- a/widget/public/nsGUIEvent.h
+++ b/widget/public/nsGUIEvent.h
@@ -54,17 +54,16 @@
 #include "nsWeakPtr.h"
 #include "nsIWidget.h"
 #include "nsTArray.h"
 #include "nsTraceRefcnt.h"
 #include "nsITransferable.h"
 #include "nsIVariant.h"
 
 class nsIRenderingContext;
-class nsIRegion;
 class nsIMenuItem;
 class nsIAccessible;
 class nsIContent;
 class nsIURI;
 class nsHashKey;
 
 /**
  * Event Struct Types
@@ -631,27 +630,22 @@ public:
 /**
  * Window repaint event
  */
 
 class nsPaintEvent : public nsGUIEvent
 {
 public:
   nsPaintEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
-    : nsGUIEvent(isTrusted, msg, w, NS_PAINT_EVENT),
-      renderingContext(nsnull), region(nsnull), rect(nsnull)
+    : nsGUIEvent(isTrusted, msg, w, NS_PAINT_EVENT)
   {
   }
 
-  /// Context to paint in.
-  nsIRenderingContext *renderingContext;
-  /// area to paint  (should be used instead of rect)
-  nsIRegion           *region;
-  /// x,y, width, height in pixels of area to paint
-  nsIntRect           *rect;
+  // area that needs repainting
+  nsIntRegion region;
 };
 
 /**
  * Scrollbar event
  */
 
 class nsScrollbarEvent : public nsGUIEvent
 {
--- a/widget/public/nsIWidget.h
+++ b/widget/public/nsIWidget.h
@@ -61,16 +61,22 @@ class   nsIDeviceContext;
 struct  nsFont;
 class   nsIRollupListener;
 class   nsIMenuRollup;
 class   nsGUIEvent;
 class   imgIContainer;
 class   gfxASurface;
 class   nsIContent;
 
+namespace mozilla {
+namespace layers {
+class LayerManager;
+}
+}
+
 /**
  * Callback function that processes events.
  *
  * The argument is actually a subtype (subclass) of nsEvent which carries
  * platform specific information about the event. Platform specific code
  * knows how to deal with it.
  *
  * The return value determines whether or not the default action should take
@@ -98,17 +104,17 @@ typedef nsEventStatus (* EVENT_CALLBACK)
 #endif
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #endif
 
 #define NS_IWIDGET_IID \
-{ 0x6bdb96ba, 0x1727, 0x40ae, \
+{ 0x9383831, 0x1039, 0x010f9, \
   { 0x85, 0x55, 0x9c, 0x53, 0x4b, 0x95, 0x23, 0x98 } }
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
@@ -175,16 +181,17 @@ enum nsTopLevelWidgetZPlacement { // for
 
 /**
  * The base class for all the widgets. It provides the interface for
  * all basic and necessary functionality.
  */
 class nsIWidget : public nsISupports {
 
   public:
+    typedef mozilla::layers::LayerManager LayerManager;
 
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWIDGET_IID)
 
     nsIWidget()
       : mLastChild(nsnull)
       , mPrevSibling(nsnull)
     {}
 
@@ -663,16 +670,24 @@ class nsIWidget : public nsISupports {
      * An AddRef has NOT been done for the caller.
      *
      * @return the toolkit this widget was created in. See nsToolkit.
      */
 
     virtual nsIToolkit* GetToolkit() = 0;    
 
     /**
+     * Return the widget's LayerManager. The layer tree for that
+     * LayerManager is what gets rendered to the widget.
+     * The layer manager is guaranteed to be the same for the lifetime
+     * of the widget.
+     */
+    virtual LayerManager* GetLayerManager() = 0;
+
+    /**
      * Scroll a set of rectangles in this widget and (as simultaneously as
      * possible) modify the specified child widgets.
      * 
      * This will invalidate areas of the children that have changed, unless
      * they have just moved by the scroll amount, but does not need to
      * invalidate any part of this widget, except where the scroll
      * operation fails to blit because part of the window is unavailable
      * (e.g. partially offscreen).
--- a/widget/src/build/Makefile.in
+++ b/widget/src/build/Makefile.in
@@ -50,16 +50,17 @@ RESFILE		= widget.res
 MODULE_NAME	= nsWidgetModule
 LIBXUL_LIBRARY = 1
 
 
 CPPSRCS		= nsWinWidgetFactory.cpp
 
 EXTRA_DSO_LIBS	= gkgfx \
 		  thebes \
+		  layers \
 		  $(NULL)
 
 LOCAL_INCLUDES	= \
 		-I$(srcdir) \
 		-I$(srcdir)/../xpwidgets \
 		-I$(srcdir)/../windows \
 		$(NULL)
 
--- a/widget/src/cocoa/Makefile.in
+++ b/widget/src/cocoa/Makefile.in
@@ -101,16 +101,17 @@ XPIDLSRCS	+= \
 SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a
 
 EXTRA_DSO_LDOPTS += \
 		$(MOZ_UNICHARUTIL_LIBS) \
 		$(TK_LIBS) \
 		$(call EXPAND_LIBNAME_PATH,gkgfx,$(DEPTH)/gfx/src) \
 		$(MOZ_COMPONENT_LIBS) \
 		-lthebes \
+		-llayers \
 		$(QCMS_LIBS) \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 NIB_FILES = \
 	classes.nib \
 	info.nib \
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -174,17 +174,17 @@ PRUint32 nsChildView::sLastInputEventCou
 - (void)processPendingRedraws;
 
 - (PRBool)processKeyDownEvent:(NSEvent*)theEvent keyEquiv:(BOOL)isKeyEquiv;
 
 - (void)maybeInitContextMenuTracking;
 
 + (NSEvent*)makeNewCocoaEventWithType:(NSEventType)type fromEvent:(NSEvent*)theEvent;
 
-- (BOOL)beginMaybeResetUnifiedToolbar:(nsIRegion*)aRegion context:(CGContextRef)aContext;
+- (BOOL)beginMaybeResetUnifiedToolbar:(nsIntRegion*)aRegion context:(CGContextRef)aContext;
 - (void)endMaybeResetUnifiedToolbar:(BOOL)aReset;
 
 #if USE_CLICK_HOLD_CONTEXTMENU
  // called on a timer two seconds after a mouse down to see if we should display
  // a context menu (click-hold)
 - (void)clickHoldCallback:(id)inEvent;
 #endif
 
@@ -1664,17 +1664,16 @@ void nsChildView::Scroll(const nsIntPoin
 
       // Areas that could be affected by the
       // translateRectsNeedingDisplayInRect but aren't in any destination
       // may have had their invalidation moved incorrectly. So just
       // invalidate them now. Unfortunately Apple hasn't given us an API
       // to do exactly what we need here.
       nsIntRegion needsInvalidation;
       needsInvalidation.Sub(allRects, destRegion);
-      nsIntRegionRectIterator iter(needsInvalidation);
       const nsIntRect* invalidate;
       for (nsIntRegionRectIterator iter(needsInvalidation);
            (invalidate = iter.Next()) != nsnull;) {
         NSRect rect;
         GeckoRectToNSRect(*invalidate, rect);
         [mView setNeedsDisplayInRect:rect];
       }
     }
@@ -2448,21 +2447,21 @@ static BOOL DrawingAtWindowTop(CGContext
   CGAffineTransform ctm = CGContextGetCTM(aContext);
   if (ctm.a != 1.0f || ctm.b != 0.0f || ctm.c != 0.0f || ctm.d != -1.0f)
     return NO;
 
   // ctm.ty contains the vertical offset from the window's bottom edge.
   return ctm.ty >= [[[[NSView focusView] window] contentView] bounds].size.height;
 }
 
-- (BOOL)beginMaybeResetUnifiedToolbar:(nsIRegion*)aRegion context:(CGContextRef)aContext
+- (BOOL)beginMaybeResetUnifiedToolbar:(nsIntRegion*)aRegion context:(CGContextRef)aContext
 {
   if (![[self window] isKindOfClass:[ToolbarWindow class]] ||
       !DrawingAtWindowTop(aContext) ||
-      !aRegion->ContainsRect(0, 0, (int)[self bounds].size.width, 1))
+      !aRegion->Contains(nsIntRect(0, 0, (int)[self bounds].size.width, 1)))
     return NO;
 
   [(ToolbarWindow*)[self window] beginMaybeResetUnifiedToolbar];
   return YES;
 }
 
 - (void)endMaybeResetUnifiedToolbar:(BOOL)aReset
 {
@@ -2507,101 +2506,81 @@ static BOOL DrawingAtWindowTop(CGContext
 
   // Create Cairo objects.
   NSSize bufferSize = [self bounds].size;
   nsRefPtr<gfxQuartzSurface> targetSurface =
     new gfxQuartzSurface(aContext, gfxSize(bufferSize.width, bufferSize.height));
 
   nsRefPtr<gfxContext> targetContext = new gfxContext(targetSurface);
 
-  nsCOMPtr<nsIRenderingContext> rc;
-  mGeckoChild->GetDeviceContext()->CreateRenderingContextInstance(*getter_AddRefs(rc));
-  rc->Init(mGeckoChild->GetDeviceContext(), targetContext);
-
-  // Build a region.
-  nsCOMPtr<nsIRegion> rgn(do_CreateInstance(kRegionCID));
-  if (!rgn)
-    return;
-  rgn->Init();
+  // Create the event so we can fill in its region
+  nsPaintEvent paintEvent(PR_TRUE, NS_PAINT, mGeckoChild);
 
   const NSRect *rects;
   NSInteger count, i;
   [[NSView focusView] getRectsBeingDrawn:&rects count:&count];
   if (count < MAX_RECTS_IN_REGION) {
     for (i = 0; i < count; ++i) {
       // Add the rect to the region.
       const NSRect& r = [self convertRect:rects[i] fromView:[NSView focusView]];
-      rgn->Union((PRInt32)r.origin.x, (PRInt32)r.origin.y, (PRInt32)r.size.width, (PRInt32)r.size.height);
+      paintEvent.region.Or(paintEvent.region,
+        nsIntRect(r.origin.x, r.origin.y, r.size.width, r.size.height));
     }
   } else {
-    rgn->Union(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
+    paintEvent.region =
+      nsIntRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
   }
 
   // Subtract child view rectangles from the region
   NSArray* subviews = [self subviews];
   for (int i = 0; i < int([subviews count]); ++i) {
     NSView* view = [subviews objectAtIndex:i];
     if (![view isKindOfClass:[ChildView class]] || [view isHidden])
       continue;
     NSRect frame = [view frame];
-    rgn->Subtract(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+    paintEvent.region.Sub(paintEvent.region,
+      nsIntRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height));
   }
 
   // Set up the clip region.
-  nsRegionRectSet* rgnRects = nsnull;
-  rgn->GetRects(&rgnRects);
-  if (!rgnRects)
-    return;
-
-  for (PRUint32 i = 0; i < rgnRects->mNumRects; ++i) {
-    const nsRegionRect& rect = rgnRects->mRects[i];
-    targetContext->Rectangle(gfxRect(rect.x, rect.y, rect.width, rect.height));
+  nsIntRegionRectIterator iter(paintEvent.region);
+  targetContext->NewPath();
+  for (;;) {
+    const nsIntRect* r = iter.Next();
+    if (!r)
+      break;
+    targetContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
   }
-  rgn->FreeRects(rgnRects);
   targetContext->Clip();
 
-  // bounding box of the dirty area
-  nsIntRect fullRect;
-  NSRectToGeckoRect(aRect, fullRect);
-
-  // Create the event and dispatch it.
-  nsPaintEvent paintEvent(PR_TRUE, NS_PAINT, mGeckoChild);
-  paintEvent.renderingContext = rc;
-  paintEvent.rect = &fullRect;
-  paintEvent.region = rgn;
-
-  BOOL resetUnifiedToolbar = [self beginMaybeResetUnifiedToolbar:rgn context:aContext];
+  BOOL resetUnifiedToolbar =
+    [self beginMaybeResetUnifiedToolbar:&paintEvent.region context:aContext];
 
   nsAutoRetainCocoaObject kungFuDeathGrip(self);
-  PRBool painted = mGeckoChild->DispatchWindowEvent(paintEvent);
+  PRBool painted;
+  {
+    nsBaseWidget::AutoLayerManagerSetup setupLayerManager(mGeckoChild, targetContext);
+    painted = mGeckoChild->DispatchWindowEvent(paintEvent);
+  }
+
   if (!painted && [self isOpaque]) {
     // Gecko refused to draw, but we've claimed to be opaque, so we have to
     // draw something--fill with white.
     CGContextSetRGBFillColor(aContext, 1, 1, 1, 1);
     CGContextFillRect(aContext, CGRectMake(aRect.origin.x, aRect.origin.y,
                                            aRect.size.width, aRect.size.height));
   }
 
   [self endMaybeResetUnifiedToolbar:resetUnifiedToolbar];
 
-  if (!mGeckoChild)
-    return;
-
-  paintEvent.renderingContext = nsnull;
-  paintEvent.region = nsnull;
-
-  targetContext = nsnull;
-  targetSurface = nsnull;
-
   // note that the cairo surface *MUST* be destroyed at this point,
   // or bad things will happen (since we can't keep the cgContext around
   // beyond this drawRect message handler)
 
 #ifdef DEBUG_UPDATE
-  fprintf (stderr, "  window coords: [%d %d %d %d]\n", fullRect.x, fullRect.y, fullRect.width, fullRect.height);
   fprintf (stderr, "---- update done ----\n");
 
 #if 0
   CGContextSetRGBStrokeColor (aContext,
                             ((((unsigned long)self) & 0xff)) / 255.0,
                             ((((unsigned long)self) & 0xff00) >> 8) / 255.0,
                             ((((unsigned long)self) & 0xff0000) >> 16) / 255.0,
                             0.5);
--- a/widget/src/cocoa/nsCocoaWindow.h
+++ b/widget/src/cocoa/nsCocoaWindow.h
@@ -242,16 +242,17 @@ public:
     NS_IMETHOD              SetTitle(const nsAString& aTitle);
 
     NS_IMETHOD Invalidate(const nsIntRect &aRect, PRBool aIsSynchronous);
     NS_IMETHOD Update();
     virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
     virtual void Scroll(const nsIntPoint& aDelta,
                         const nsTArray<nsIntRect>& aDestRects,
                         const nsTArray<Configuration>& aConfigurations);
+    virtual LayerManager* GetLayerManager();
     NS_IMETHOD DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus) ;
     NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, nsIMenuRollup * aMenuRollup,
                                    PRBool aDoCapture, PRBool aConsumeRollupEvent);
     NS_IMETHOD GetAttention(PRInt32 aCycleCount);
     virtual PRBool HasPendingInputEvent();
     virtual nsTransparencyMode GetTransparencyMode();
     virtual void SetTransparencyMode(nsTransparencyMode aMode);
     NS_IMETHOD SetWindowShadowStyle(PRInt32 aStyle);
--- a/widget/src/cocoa/nsCocoaWindow.mm
+++ b/widget/src/cocoa/nsCocoaWindow.mm
@@ -66,16 +66,23 @@
 #include "nsStyleConsts.h"
 #include "nsNativeThemeColors.h"
 #include "nsChildView.h"
 #include "nsIMenuRollup.h"
 
 #include "gfxPlatform.h"
 #include "qcms.h"
 
+namespace mozilla {
+namespace layers {
+class LayerManager;
+}
+}
+using namespace mozilla::layers;
+
 // defined in nsAppShell.mm
 extern nsCocoaAppModalWindowList *gCocoaAppModalWindowList;
 
 PRInt32 gXULModalLevel = 0;
 
 // In principle there should be only one app-modal window at any given time.
 // But sometimes, despite our best efforts, another window appears above the
 // current app-modal window.  So we need to keep a linked list of app-modal
@@ -903,16 +910,25 @@ nsCocoaWindow::Scroll(const nsIntPoint& 
                       const nsTArray<nsIntRect>& aDestRects,
                       const nsTArray<Configuration>& aConfigurations)
 {
   if (mPopupContentView) {
     mPopupContentView->Scroll(aDelta, aDestRects, aConfigurations);
   }
 }
 
+LayerManager*
+nsCocoaWindow::GetLayerManager()
+{
+  if (mPopupContentView) {
+    return mPopupContentView->GetLayerManager();
+  }
+  return nsnull;
+}
+
 nsTransparencyMode nsCocoaWindow::GetTransparencyMode()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   return [mWindow isOpaque] ? eTransparencyOpaque : eTransparencyTransparent;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(eTransparencyOpaque);
 }
--- a/widget/src/gtk2/nsWindow.cpp
+++ b/widget/src/gtk2/nsWindow.cpp
@@ -43,17 +43,16 @@
 #endif
 
 #include "prlink.h"
 
 #include "nsWindow.h"
 #include "nsGTKToolkit.h"
 #include "nsIDeviceContext.h"
 #include "nsIRenderingContext.h"
-#include "nsIRegion.h"
 #include "nsIRollupListener.h"
 #include "nsIMenuRollup.h"
 #include "nsIDOMNode.h"
 
 #include "nsWidgetsCID.h"
 #include "nsDragService.h"
 #include "nsIDragSessionGTK.h"
 
@@ -2328,23 +2327,19 @@ nsWindow::OnExposeEvent(GtkWidget *aWidg
              (void *)this, (void *)aEvent->window));
         return FALSE;
     }
 
     // Windows that are not visible will be painted after they become visible.
     if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
         return FALSE;
 
-    static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
-
-    nsCOMPtr<nsIRegion> updateRegion = do_CreateInstance(kRegionCID);
-    if (!updateRegion)
-        return FALSE;
-
-    updateRegion->Init();
+    nsPaintEvent event(PR_TRUE, NS_PAINT, this);
+    event.refPoint.x = aEvent->area.x;
+    event.refPoint.y = aEvent->area.y;
 
     GdkRectangle *rects;
     gint nrects;
     gdk_region_get_rectangles(aEvent->region, &rects, &nrects);
     if (NS_UNLIKELY(!rects)) // OOM
         return FALSE;
 
     if (nrects > MAX_RECTS_IN_REGION) {
@@ -2355,17 +2350,17 @@ nsWindow::OnExposeEvent(GtkWidget *aWidg
 
     LOGDRAW(("sending expose event [%p] %p 0x%lx (rects follow):\n",
              (void *)this, (void *)aEvent->window,
              GDK_WINDOW_XWINDOW(aEvent->window)));
 
     GdkRectangle *r;
     GdkRectangle *r_end = rects + nrects;
     for (r = rects; r < r_end; ++r) {
-        updateRegion->Union(r->x, r->y, r->width, r->height);
+        event.region.Or(event.region, nsIntRect(r->x, r->y, r->width, r->height));
         LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
     }
 
     PRBool translucent = eTransparencyTransparent == GetTransparencyMode();
     if (!translucent) {
         GList *children =
             gdk_window_peek_children(mGdkWindow);
         while (children) {
@@ -2373,70 +2368,58 @@ nsWindow::OnExposeEvent(GtkWidget *aWidg
             nsWindow *kid = get_window_for_gdk_window(gdkWin);
             if (kid && gdk_window_is_visible(gdkWin)) {
                 nsAutoTArray<nsIntRect,1> clipRects;
                 kid->GetWindowClipRegion(&clipRects);
                 nsIntRect bounds;
                 kid->GetBounds(bounds);
                 for (PRUint32 i = 0; i < clipRects.Length(); ++i) {
                     nsIntRect r = clipRects[i] + bounds.TopLeft();
-                    updateRegion->Subtract(r.x, r.y, r.width, r.height);
+                    event.region.Sub(event.region, r);
                 }
             }
             children = children->next;
         }
     }
 
-    if (updateRegion->IsEmpty()) {
+    if (event.region.IsEmpty()) {
         g_free(rects);
         return TRUE;
     }
 
+    nsRefPtr<gfxContext> ctx = new gfxContext(GetThebesSurface());
+    if (NS_UNLIKELY(!ctx)) {
+        g_free(rects);
+        return FALSE;
+    }
+
+    // The context that we'll actually paint into. When we're double-
+    // buffering, this can be different from ctx.
+    nsRefPtr<gfxContext> paintCtx = ctx;
+
 #ifdef MOZ_DFB
-    nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
-    if (NS_UNLIKELY(!rc)) {
-        g_free(rects);
-        return FALSE;
-    }
-
-    // do double-buffering and clipping here
-    nsRefPtr<gfxContext> ctx = rc->ThebesContext();
-
     gfxPlatformGtk::GetPlatform()->SetGdkDrawable(ctx->OriginalSurface(),
                                                   GDK_DRAWABLE(mGdkWindow));
 
     // clip to the update region
-    ctx->Save();
     ctx->NewPath();
     for (r = rects; r < r_end; ++r) {
         ctx->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
     }
     ctx->Clip();
 #endif
 
 #ifdef MOZ_X11
-    nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
-    if (NS_UNLIKELY(!rc)) {
-        g_free(rects);
-        return FALSE;
-    }
-
-    nsIntRect boundsRect;
+    nsIntRect boundsRect = event.region.GetBounds();
 
     GdkPixmap* bufferPixmap = nsnull;
     gfxIntSize bufferPixmapSize;
 
     nsRefPtr<gfxASurface> bufferPixmapSurface;
 
-    updateRegion->GetBoundingBox(&boundsRect.x, &boundsRect.y,
-                                 &boundsRect.width, &boundsRect.height);
-
-    // do double-buffering and clipping here
-    nsRefPtr<gfxContext> ctx = rc->ThebesContext();
-    ctx->Save();
     ctx->NewPath();
     if (translucent) {
         // Collapse update area to the bounding box. This is so we only have to
         // call UpdateTranslucentWindowAlpha once. After we have dropped
         // support for non-Thebes graphics, UpdateTranslucentWindowAlpha will be
         // our private interface so we can rework things to avoid this.
         ctx->Rectangle(gfxRect(boundsRect.x, boundsRect.y,
                                boundsRect.width, boundsRect.height));
@@ -2510,28 +2493,21 @@ nsWindow::OnExposeEvent(GtkWidget *aWidg
                 bufferPixmapSurface = nsnull;
             }
             if (bufferPixmapSurface) {
                 gfxPlatformGtk::GetPlatform()->SetGdkDrawable(
                         static_cast<gfxASurface *>(bufferPixmapSurface),
                         GDK_DRAWABLE(bufferPixmap));
 
                 bufferPixmapSurface->SetDeviceOffset(gfxPoint(-boundsRect.x, -boundsRect.y));
-                nsCOMPtr<nsIRenderingContext> newRC;
-                nsresult rv = GetDeviceContext()->
-                    CreateRenderingContextInstance(*getter_AddRefs(newRC));
-                if (NS_FAILED(rv)) {
-                    bufferPixmapSurface = nsnull;
+                nsRefPtr<gfxContext> newCtx = new gfxContext(bufferPixmapSurface);
+                if (newCtx) {
+                    paintCtx = newCtx.forget();
                 } else {
-                    rv = newRC->Init(GetDeviceContext(), bufferPixmapSurface);
-                    if (NS_FAILED(rv)) {
-                        bufferPixmapSurface = nsnull;
-                    } else {
-                        rc = newRC;
-                    }
+                    bufferPixmapSurface = nsnull;
                 }
             }
         }
     }
 
 #if 0
     // NOTE: Paint flashing region would be wrong for cairo, since
     // cairo inflates the update region, etc.  So don't paint flash
@@ -2539,25 +2515,21 @@ nsWindow::OnExposeEvent(GtkWidget *aWidg
 #ifdef DEBUG
     if (WANT_PAINT_FLASHING && aEvent->window)
         gdk_window_flash(aEvent->window, 1, 100, aEvent->region);
 #endif
 #endif
 
 #endif // MOZ_X11
 
-    nsPaintEvent event(PR_TRUE, NS_PAINT, this);
-    event.refPoint.x = aEvent->area.x;
-    event.refPoint.y = aEvent->area.y;
-    event.rect = nsnull;
-    event.region = updateRegion;
-    event.renderingContext = rc;
-
     nsEventStatus status;
-    DispatchEvent(&event, status);
+    {
+      AutoLayerManagerSetup setupLayerManager(this, paintCtx);
+      DispatchEvent(&event, status);
+    }
 
 #ifdef MOZ_X11
     // DispatchEvent can Destroy us (bug 378273), avoid doing any paint
     // operations below if that happened - it will lead to XError and exit().
     if (NS_LIKELY(!mIsDestroyed)) {
         if (status != nsEventStatus_eIgnore) {
             if (translucent) {
                 nsRefPtr<gfxPattern> pattern = ctx->PopGroup();
@@ -2593,25 +2565,19 @@ nsWindow::OnExposeEvent(GtkWidget *aWidg
             // ignore
             if (translucent)
                 ctx->PopGroup();
         }
 
         // if we had to allocate a local pixmap, free it here
         if (bufferPixmap && bufferPixmap != gBufferPixmap)
             g_object_unref(G_OBJECT(bufferPixmap));
-
-        ctx->Restore();
     }
 #endif // MOZ_X11
 
-#ifdef MOZ_DFB
-    ctx->Restore();
-#endif
-
     g_free(rects);
 
     // check the return value!
     return TRUE;
 }
 
 gboolean
 nsWindow::OnConfigureEvent(GtkWidget *aWidget, GdkEventConfigure *aEvent)
--- a/widget/src/qt/nsWindow.cpp
+++ b/widget/src/qt/nsWindow.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+./* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim:expandtab:shiftwidth=4:tabstop=4:
  */
 /* ***** 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
@@ -1007,33 +1007,28 @@ nsWindow::DoPaint(QPainter* aPainter, co
         targetSurface = new gfxQPainterSurface(aPainter);
     }
 
     if (NS_UNLIKELY(!targetSurface))
         return nsEventStatus_eIgnore;
 
     nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
 
-    nsCOMPtr<nsIRenderingContext> rc;
-    GetDeviceContext()->CreateRenderingContextInstance(*getter_AddRefs(rc));
-    if (NS_UNLIKELY(!rc))
-        return nsEventStatus_eIgnore;
-
-    rc->Init(GetDeviceContext(), ctx);
-
     nsPaintEvent event(PR_TRUE, NS_PAINT, this);
 
     nsIntRect rect(r.x(), r.y(), r.width(), r.height());
     event.refPoint.x = r.x();
     event.refPoint.y = r.y();
-    event.rect = &rect;
-    event.region = nsnull;
-    event.renderingContext = rc;
+    event.region = nsIntRegion(rect);
 
-    nsEventStatus status = DispatchEvent(&event);
+    nsEventStatus status;
+    {
+      AutoLayerManagerSetup setupLayerManager(this, ctx);
+      status = DispatchEvent(&event);
+    }
 
     // DispatchEvent can Destroy us (bug 378273), avoid doing any paint
     // operations below if that happened - it will lead to XError and exit().
     if (NS_UNLIKELY(mIsDestroyed))
         return status;
 
     if (status == nsEventStatus_eIgnore)
         return status;
--- a/widget/src/windows/nsWindow.h
+++ b/widget/src/windows/nsWindow.h
@@ -397,17 +397,17 @@ protected:
    * Misc.
    */
   UINT                    MapFromNativeToDOM(UINT aNativeKeyCode);
   void                    StopFlashing();
   static PRBool           IsTopLevelMouseExit(HWND aWnd);
   static void             SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers);
   nsresult                SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
                                               PRBool aIntersectWithExisting);
-  nsCOMPtr<nsIRegion>     GetRegionToPaint(PRBool aForceFullRepaint, 
+  nsIntRegion             GetRegionToPaint(PRBool aForceFullRepaint, 
                                            PAINTSTRUCT ps, HDC aDC);
 #if !defined(WINCE)
   static void             ActivateOtherWindowHelper(HWND aWnd);
 #endif
 #ifdef ACCESSIBILITY
   static STDMETHODIMP_(LRESULT) LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc);
 #endif // ACCESSIBILITY
 
--- a/widget/src/windows/nsWindowGfx.cpp
+++ b/widget/src/windows/nsWindowGfx.cpp
@@ -128,54 +128,44 @@ static NS_DEFINE_IID(kRenderingContextCI
  **************************************************************/
 
 static PRBool
 IsRenderMode(gfxWindowsPlatform::RenderMode rmode)
 {
   return gfxWindowsPlatform::GetPlatform()->GetRenderMode() == rmode;
 }
 
-void
-nsWindowGfx::AddRECTToRegion(const RECT& aRect, nsIRegion* aRegion)
-{
-  aRegion->Union(aRect.left, aRect.top, aRect.right - aRect.left, aRect.bottom - aRect.top);
-}
-
-already_AddRefed<nsIRegion>
+nsIntRegion
 nsWindowGfx::ConvertHRGNToRegion(HRGN aRgn)
 {
   NS_ASSERTION(aRgn, "Don't pass NULL region here");
 
-  nsCOMPtr<nsIRegion> region = do_CreateInstance(kRegionCID);
-  if (!region)
-    return nsnull;
-
-  region->Init();
+  nsIntRegion rgn;
 
   DWORD size = ::GetRegionData(aRgn, 0, NULL);
   nsAutoTArray<PRUint8,100> buffer;
   if (!buffer.SetLength(size))
-    return region.forget();
+    return rgn;
 
   RGNDATA* data = reinterpret_cast<RGNDATA*>(buffer.Elements());
   if (!::GetRegionData(aRgn, size, data))
-    return region.forget();
+    return rgn;
 
   if (data->rdh.nCount > MAX_RECTS_IN_REGION) {
-    AddRECTToRegion(data->rdh.rcBound, region);
-    return region.forget();
+    rgn = ToIntRect(data->rdh.rcBound);
+    return rgn;
   }
 
   RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
   for (PRUint32 i = 0; i < data->rdh.nCount; ++i) {
     RECT* r = rects + i;
-    AddRECTToRegion(*r, region);
+    rgn.Or(rgn, ToIntRect(*r));
   }
 
-  return region.forget();
+  return rgn;
 }
 
 #ifdef CAIRO_HAS_DDRAW_SURFACE
 PRBool
 nsWindowGfx::InitDDraw()
 {
   HRESULT hr;
 
@@ -248,66 +238,55 @@ void nsWindow::SetUpForPaint(HDC aHDC)
   ::SetTextColor(aHDC, NSRGB_2_COLOREF(mForeground));
   ::SetBkMode (aHDC, TRANSPARENT);
 }
 
 // GetRegionToPaint returns the invalidated region that needs to be painted
 // it's abstracted out because Windows XP/Vista/7 handles this for us, but
 // we need to keep track of it our selves for Windows CE and Windows Mobile
 
-nsCOMPtr<nsIRegion> nsWindow::GetRegionToPaint(PRBool aForceFullRepaint,
-                                               PAINTSTRUCT ps, HDC aDC)
+nsIntRegion nsWindow::GetRegionToPaint(PRBool aForceFullRepaint,
+                                       PAINTSTRUCT ps, HDC aDC)
 { 
-  HRGN paintRgn = NULL;
-  nsCOMPtr<nsIRegion> paintRgnWin;
   if (aForceFullRepaint) {
     RECT paintRect;
     ::GetClientRect(mWnd, &paintRect);
-    paintRgn = ::CreateRectRgn(paintRect.left, paintRect.top, 
-                               paintRect.right, paintRect.bottom);
-    if (paintRgn) {
-      paintRgnWin = nsWindowGfx::ConvertHRGNToRegion(paintRgn);
-      ::DeleteObject(paintRgn);
-      return paintRgnWin;
-    }
+    return nsIntRegion(nsWindowGfx::ToIntRect(paintRect));
   }
+
 #ifndef WINCE
-  paintRgn = ::CreateRectRgn(0, 0, 0, 0);
+  HRGN paintRgn = ::CreateRectRgn(0, 0, 0, 0);
   if (paintRgn != NULL) {
     int result = GetRandomRgn(aDC, paintRgn, SYSRGN);
     if (result == 1) {
       POINT pt = {0,0};
       ::MapWindowPoints(NULL, mWnd, &pt, 1);
       ::OffsetRgn(paintRgn, pt.x, pt.y);
     }
-    paintRgnWin = nsWindowGfx::ConvertHRGNToRegion(paintRgn);
+    nsIntRegion rgn(nsWindowGfx::ConvertHRGNToRegion(paintRgn));
     ::DeleteObject(paintRgn);
+    return rgn;
   }
 #else
 # ifdef WINCE_WINDOWS_MOBILE
-  paintRgn = ::CreateRectRgn(0, 0, 0, 0);
+  HRGN paintRgn = ::CreateRectRgn(0, 0, 0, 0);
   if (paintRgn != NULL) {
     int result = GetUpdateRgn(mWnd, paintRgn, FALSE);
     if (result == 1) {
       POINT pt = {0,0};
       ::MapWindowPoints(NULL, mWnd, &pt, 1);
       ::OffsetRgn(paintRgn, pt.x, pt.y);
     }
-    paintRgnWin = nsWindowGfx::ConvertHRGNToRegion(paintRgn);
+    nsIntRegion rgn(nsWindowGfx::ConvertHRGNToRegion(paintRgn));
     ::DeleteObject(paintRgn);
+    return rgn;
   }
 # endif
-  paintRgn = ::CreateRectRgn(ps.rcPaint.left, ps.rcPaint.top,
-                             ps.rcPaint.right, ps.rcPaint.bottom);
-  if (paintRgn) {
-    paintRgnWin = nsWindowGfx::ConvertHRGNToRegion(paintRgn);
-    ::DeleteObject(paintRgn);
-  }
 #endif
-  return paintRgnWin;
+  return nsIntRegion(nsWindowGfx::ToIntRect(ps.rcPaint));
 }
 
 #define WORDSSIZE(x) ((x).width * (x).height)
 static PRBool
 EnsureSharedSurfaceSize(gfxIntSize size)
 {
   gfxIntSize screenSize;
   screenSize.height = GetSystemMetrics(SM_CYSCREEN);
@@ -411,35 +390,29 @@ PRBool nsWindow::OnPaint(HDC aDC)
   }
 #endif // WIDGET_DEBUG_OUTPUT
 
   HDC hDC = aDC ? aDC : (::BeginPaint(mWnd, &ps));
   if (!IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)) {
     mPaintDC = hDC;
   }
 
+  // generate the event and call the event callback
+  nsPaintEvent event(PR_TRUE, NS_PAINT, this);
+  InitEvent(event);
+
 #ifdef MOZ_XUL
   PRBool forceRepaint = aDC || (eTransparencyTransparent == mTransparencyMode);
 #else
   PRBool forceRepaint = NULL != aDC;
 #endif
-  nsCOMPtr<nsIRegion> paintRgnWin = GetRegionToPaint(forceRepaint, ps, hDC);
+  event.region = GetRegionToPaint(forceRepaint, ps, hDC);
 
-  if (paintRgnWin &&
-      !paintRgnWin->IsEmpty() &&
-      mEventCallback)
+  if (!event.region.IsEmpty() && mEventCallback)
   {
-    // generate the event and call the event callback
-    nsPaintEvent event(PR_TRUE, NS_PAINT, this);
-
-    InitEvent(event);
-
-    event.region = paintRgnWin;
-    event.rect = nsnull;
- 
     // Should probably pass in a real region here, using GetRandomRgn
     // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/clipping_4q0e.asp
 
 #ifdef WIDGET_DEBUG_OUTPUT
     debug_DumpPaintEvent(stdout,
                          this,
                          &event,
                          nsCAutoString("noname"),
@@ -568,33 +541,21 @@ DDRAW_FAILED:
       } else
 #endif
       {
         // If we're not doing translucency, then double buffer
         thebesContext->PushGroup(gfxASurface::CONTENT_COLOR);
       }
     }
 
-    nsCOMPtr<nsIRenderingContext> rc;
-    nsresult rv = mContext->CreateRenderingContextInstance (*getter_AddRefs(rc));
-    if (NS_FAILED(rv)) {
-      NS_WARNING("CreateRenderingContextInstance failed");
-      return PR_FALSE;
+    {
+      AutoLayerManagerSetup setupLayerManager(this, thebesContext);
+      result = DispatchWindowEvent(&event, eventStatus);
     }
 
-    rv = rc->Init(mContext, thebesContext);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("RC::Init failed");
-      return PR_FALSE;
-    }
-
-    event.renderingContext = rc;
-    result = DispatchWindowEvent(&event, eventStatus);
-    event.renderingContext = nsnull;
-
 #ifdef MOZ_XUL
     if (IsRenderMode(gfxWindowsPlatform::RENDER_GDI) &&
         eTransparencyTransparent == mTransparencyMode) {
       // Data from offscreen drawing surface was copied to memory bitmap of transparent
       // bitmap. Now it can be read from memory bitmap to apply alpha channel and after
       // that displayed on the screen.
       UpdateTranslucentWindow();
     } else
@@ -952,38 +913,33 @@ HBITMAP nsWindowGfx::DataToBitmap(PRUint
 PRBool nsWindow::OnPaintImageDDraw16()
 {
   PRBool result = PR_FALSE;
   PAINTSTRUCT ps;
   nsPaintEvent event(PR_TRUE, NS_PAINT, this);
   gfxIntSize surfaceSize;
   nsRefPtr<gfxImageSurface> targetSurfaceImage;
   nsRefPtr<gfxContext> thebesContext;
-  nsCOMPtr<nsIRenderingContext> rc;
   nsEventStatus eventStatus = nsEventStatus_eIgnore;
-  PRInt32 brx, bry, brw, brh;
   gfxIntSize newSize;
   newSize.height = GetSystemMetrics(SM_CYSCREEN);
   newSize.width = GetSystemMetrics(SM_CXSCREEN);
   mPainting = PR_TRUE;
 
   HDC hDC = ::BeginPaint(mWnd, &ps);
   mPaintDC = hDC;
-  nsCOMPtr<nsIRegion> paintRgnWin = GetRegionToPaint(PR_FALSE, ps, hDC);
+  nsIntRegion paintRgn = GetRegionToPaint(PR_FALSE, ps, hDC);
 
-  if (!paintRgnWin || paintRgnWin->IsEmpty() || !mEventCallback) {
+  if (paintRgn.IsEmpty() || !mEventCallback) {
     result = PR_TRUE;
     goto cleanup;
   }
 
   InitEvent(event);
   
-  event.region = paintRgnWin;
-  event.rect = nsnull;
-  
   if (!glpDD) {
     if (!nsWindowGfx::InitDDraw()) {
       NS_WARNING("DirectDraw init failed.  Giving up.");
       goto cleanup;
     }
   }
 
   if (!glpDDSecondary) {
@@ -1009,17 +965,20 @@ PRBool nsWindow::OnPaintImageDDraw16()
     if (FAILED(hr)) {
 #ifdef DEBUG
       DDError("CreateSurface renderer", hr);
 #endif
       goto cleanup;
     }
   }
 
-  paintRgnWin->GetBoundingBox(&brx, &bry, &brw, &brh);
+  PRInt32 brx = paintRgn.GetBounds().x;
+  PRInt32 bry = paintRgn.GetBounds().y;
+  PRInt32 brw = paintRgn.GetBounds().width;
+  PRInt32 brh = paintRgn.GetBounds().height;
   surfaceSize = gfxIntSize(brw, brh);
   
   if (!EnsureSharedSurfaceSize(surfaceSize))
     goto cleanup;
 
   targetSurfaceImage = new gfxImageSurface(sSharedSurfaceData.get(),
                                            surfaceSize,
                                            surfaceSize.width * 4,
@@ -1029,35 +988,25 @@ PRBool nsWindow::OnPaintImageDDraw16()
     goto cleanup;
     
   targetSurfaceImage->SetDeviceOffset(gfxPoint(-brx, -bry));
   
   thebesContext = new gfxContext(targetSurfaceImage);
   thebesContext->SetFlag(gfxContext::FLAG_DESTINED_FOR_SCREEN);
   thebesContext->SetFlag(gfxContext::FLAG_SIMPLIFY_OPERATORS);
     
-  nsresult rv = mContext->CreateRenderingContextInstance (*getter_AddRefs(rc));
-  if (NS_FAILED(rv))
-    goto cleanup;
+  {
+    AutoLayerManagerSetup setupLayerManager(this, thebesContext);
+    event.region = paintRgn;
+    result = DispatchWindowEvent(&event, eventStatus);
+  }
   
-  rv = rc->Init(mContext, thebesContext);
-  if (NS_FAILED(rv))
-    goto cleanup;
-    
-  event.renderingContext = rc;
-  PRBool res = DispatchWindowEvent(&event, eventStatus);
-  event.renderingContext = nsnull;
-  
-  if (!res && eventStatus  == nsEventStatus_eConsumeNoDefault)
+  if (!result && eventStatus  == nsEventStatus_eConsumeNoDefault)
     goto cleanup;
 
-  nsRegionRectSet *rects = nsnull;
-  RECT r;
-  paintRgnWin->GetRects(&rects);
-  
   HRESULT hr = glpDDSecondary->Lock(0, &gDDSDSecondary, DDLOCK_WAITNOTBUSY | DDLOCK_DISCARD, 0); 
   if (FAILED(hr))
     goto cleanup;
 
   pixman_image_t *srcPixmanImage = 
     pixman_image_create_bits(PIXMAN_x8r8g8b8, surfaceSize.width,
                              surfaceSize.height, 
                              (uint32_t*) sSharedSurfaceData.get(),
@@ -1065,45 +1014,44 @@ PRBool nsWindow::OnPaintImageDDraw16()
   
   pixman_image_t *dstPixmanImage = 
     pixman_image_create_bits(PIXMAN_r5g6b5, gDDSDSecondary.dwWidth,
                              gDDSDSecondary.dwHeight,
                              (uint32_t*) gDDSDSecondary.lpSurface,
                              gDDSDSecondary.dwWidth * 2);
   
 
-  for (unsigned int i = 0; i < rects->mNumRects; i++) {
+  const nsIntRect* r;
+  for (nsIntRegionRectIterator iter(paintRgn);
+       (r = iter.Next()) != nsnull;) {
     pixman_image_composite(PIXMAN_OP_SRC, srcPixmanImage, NULL, dstPixmanImage,
-                           rects->mRects[i].x - brx, rects->mRects[i].y - bry, 
-                           0, 0, 
-                           rects->mRects[i].x, rects->mRects[i].y, 
-                           rects->mRects[i].width, rects->mRects[i].height);
-    
-  } 
+                           r->x - brx, r->y - bry,
+                           0, 0,
+                           r->x, r->y,
+                           r->width, r->height);
+  }
   
   pixman_image_unref(dstPixmanImage);
   pixman_image_unref(srcPixmanImage);
 
   hr = glpDDSecondary->Unlock(0);
   if (FAILED(hr))
     goto cleanup;
   
   hr = glpDDClipper->SetHWnd(0, mWnd);
   if (FAILED(hr))
     goto cleanup;
   
-  for (unsigned int i = 0; i < rects->mNumRects; i++) {  
-    r.left = rects->mRects[i].x;
-    r.top = rects->mRects[i].y;
-    r.right = rects->mRects[i].width + rects->mRects[i].x;
-    r.bottom = rects->mRects[i].height + rects->mRects[i].y;
-    RECT renderRect = r;
+  for (nsIntRegionRectIterator iter(paintRgn);
+       (r = iter.Next()) != nsnull;) {
+    RECT wr = { r->x, r->y, r->XMost(), r->YMost() };
+    RECT renderRect = wr;
     SetLastError(0); // See http://msdn.microsoft.com/en-us/library/dd145046%28VS.85%29.aspx
     MapWindowPoints(mWnd, 0, (LPPOINT)&renderRect, 2);
-    hr = glpDDPrimary->Blt(&renderRect, glpDDSecondary, &r, 0, NULL);
+    hr = glpDDPrimary->Blt(&renderRect, glpDDSecondary, &wr, 0, NULL);
     if (FAILED(hr)) {
       NS_ERROR("this blt should never fail!");
       printf("#### %s blt failed: %08lx", __FUNCTION__, hr);
     }
   }
   result = PR_TRUE;
 
 cleanup:
--- a/widget/src/windows/nsWindowGfx.h
+++ b/widget/src/windows/nsWindowGfx.h
@@ -51,18 +51,23 @@
 #include "cairo-features.h"
 
 #ifdef CAIRO_HAS_DDRAW_SURFACE
 #include "gfxDDrawSurface.h"
 #endif
 
 class nsWindowGfx {
 public:
-  static void AddRECTToRegion(const RECT& aRect, nsIRegion* aRegion);
-  static already_AddRefed<nsIRegion> ConvertHRGNToRegion(HRGN aRgn);
+  static nsIntRect ToIntRect(const RECT& aRect)
+  {
+    return nsIntRect(aRect.left, aRect.top,
+                     aRect.right - aRect.left, aRect.bottom - aRect.top);
+  }
+
+  static nsIntRegion ConvertHRGNToRegion(HRGN aRgn);
   static void OnSettingsChangeGfx(WPARAM wParam);
 
 #if defined(CAIRO_HAS_DDRAW_SURFACE)
   static PRBool InitDDraw();
 #endif // defined(CAIRO_HAS_DDRAW_SURFACE)
 
   static nsresult CreateIcon(imgIContainer *aContainer, PRBool aIsCursor, PRUint32 aHotspotX, PRUint32 aHotspotY, HICON *aIcon);
 
--- a/widget/src/xpwidgets/nsBaseWidget.cpp
+++ b/widget/src/xpwidgets/nsBaseWidget.cpp
@@ -44,29 +44,32 @@
 #include "nsServiceManagerUtils.h"
 #include "nsIScreenManager.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIContent.h"
 #include "nsIServiceManager.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch2.h"
+#include "BasicLayers.h"
 
 #ifdef DEBUG
 #include "nsIObserver.h"
 
 static void debug_RegisterPrefCallbacks();
 
 static PRBool debug_InSecureKeyboardInputMode = PR_FALSE;
 #endif
 
 #ifdef NOISY_WIDGET_LEAKS
 static PRInt32 gNumWidgets;
 #endif
 
+using namespace mozilla::layers;
+
 nsIContent* nsBaseWidget::mLastRollup = nsnull;
 
 // nsBaseWidget
 NS_IMPL_ISUPPORTS1(nsBaseWidget, nsIWidget)
 
 
 nsAutoRollup::nsAutoRollup()
 {
@@ -624,16 +627,44 @@ NS_IMETHODIMP nsBaseWidget::MakeFullScre
   } else if (mOriginalBounds) {
     Resize(mOriginalBounds->x, mOriginalBounds->y, mOriginalBounds->width,
            mOriginalBounds->height, PR_TRUE);
   }
 
   return NS_OK;
 }
 
+nsBaseWidget::AutoLayerManagerSetup::AutoLayerManagerSetup(
+    nsBaseWidget* aWidget, gfxContext* aTarget)
+  : mWidget(aWidget)
+{
+  BasicLayerManager* manager =
+    static_cast<BasicLayerManager*>(mWidget->GetLayerManager());
+  if (manager) {
+    manager->SetDefaultTarget(aTarget);
+  }
+}
+
+nsBaseWidget::AutoLayerManagerSetup::~AutoLayerManagerSetup()
+{
+  BasicLayerManager* manager =
+    static_cast<BasicLayerManager*>(mWidget->GetLayerManager());
+  if (manager) {
+    manager->SetDefaultTarget(nsnull);
+  }
+}
+
+LayerManager* nsBaseWidget::GetLayerManager()
+{
+  if (!mLayerManager) {
+    mLayerManager = new BasicLayerManager(nsnull);
+  }
+  return mLayerManager;
+}
+
 //-------------------------------------------------------------------------
 //
 // Create a rendering context from this nsBaseWidget
 //
 //-------------------------------------------------------------------------
 nsIRenderingContext* nsBaseWidget::GetRenderingContext()
 {
   nsresult                      rv;
@@ -1326,30 +1357,16 @@ nsBaseWidget::debug_DumpPaintEvent(FILE 
   
   fprintf(aFileOut,
           "%4d PAINT      widget=%p name=%-12s id=%-8p rect=", 
           _GetPrintCount(),
           (void *) aWidget,
           aWidgetName.get(),
           (void *) aWindowID);
   
-  if (aPaintEvent->rect) 
-  {
-    fprintf(aFileOut,
-            "%3d,%-3d %3d,%-3d",
-            aPaintEvent->rect->x, 
-            aPaintEvent->rect->y,
-            aPaintEvent->rect->width, 
-            aPaintEvent->rect->height);
-  }
-  else
-  {
-    fprintf(aFileOut,"none");
-  }
-  
   fprintf(aFileOut,"\n");
 }
 //////////////////////////////////////////////////////////////
 /* static */ void
 nsBaseWidget::debug_DumpInvalidate(FILE *                aFileOut,
                                    nsIWidget *           aWidget,
                                    const nsIntRect *     aRect,
                                    PRBool                aIsSynchronous,
--- a/widget/src/xpwidgets/nsBaseWidget.h
+++ b/widget/src/xpwidgets/nsBaseWidget.h
@@ -44,16 +44,17 @@
 #include "nsILocalFile.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsGUIEvent.h"
 #include "nsAutoPtr.h"
 
 class nsIContent;
 class nsAutoRollup;
+class gfxContext;
 
 /**
  * Common widget implementation used as base class for native
  * or crossplatform implementations of Widgets. 
  * All cross-platform behavior that all widgets need to implement 
  * should be placed in this class. 
  * (Note: widget implementations are not required to use this
  * class, but it gives them a head start.)
@@ -102,17 +103,18 @@ public:
   virtual nsTransparencyMode GetTransparencyMode();
   virtual void            GetWindowClipRegion(nsTArray<nsIntRect>* aRects);
   NS_IMETHOD              SetWindowShadowStyle(PRInt32 aStyle);
   virtual void            SetShowsToolbarButton(PRBool aShow) {}
   NS_IMETHOD              HideWindowChrome(PRBool aShouldHide);
   NS_IMETHOD              MakeFullScreen(PRBool aFullScreen);
   virtual nsIRenderingContext* GetRenderingContext();
   virtual nsIDeviceContext* GetDeviceContext();
-  virtual nsIToolkit*     GetToolkit();  
+  virtual nsIToolkit*     GetToolkit();
+  virtual LayerManager*   GetLayerManager();
   virtual gfxASurface*    GetThebesSurface();
   NS_IMETHOD              SetModal(PRBool aModal); 
   NS_IMETHOD              SetWindowClass(const nsAString& xulWinType);
   NS_IMETHOD              SetBounds(const nsIntRect &aRect);
   NS_IMETHOD              GetBounds(nsIntRect &aRect);
   NS_IMETHOD              GetClientBounds(nsIntRect &aRect);
   NS_IMETHOD              GetScreenBounds(nsIntRect &aRect);
   NS_IMETHOD              EnableDragDrop(PRBool aEnable);
@@ -136,16 +138,30 @@ public:
   NS_IMETHOD              CancelIMEComposition() { return NS_OK; }
   NS_IMETHOD              GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              OnIMEFocusChange(PRBool aFocus) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              OnIMETextChange(PRUint32 aStart, PRUint32 aOldEnd, PRUint32 aNewEnd) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              OnIMESelectionChange(void) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              OnDefaultButtonLoaded(const nsIntRect &aButtonRect) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta, PRBool aIsHorizontal, PRInt32 &aOverriddenDelta);
 
+  /**
+   * Use this when GetLayerManager() returns a BasicLayerManager
+   * (nsBaseWidget::GetLayerManager() does). This sets up the widget's
+   * layer manager to temporarily render into aTarget.
+   */
+  class AutoLayerManagerSetup {
+  public:
+    AutoLayerManagerSetup(nsBaseWidget* aWidget, gfxContext* aTarget);
+    ~AutoLayerManagerSetup();
+  private:
+    nsBaseWidget* mWidget;
+  };
+  friend class AutoLayerManagerSetup;
+
 protected:
 
   virtual void            ResolveIconName(const nsAString &aIconName,
                                           const nsAString &aIconSuffix,
                                           nsILocalFile **aResult);
   virtual void            OnDestroy();
   virtual void            BaseCreate(nsIWidget *aParent,
                                      const nsIntRect &aRect,
@@ -174,18 +190,19 @@ protected:
 
   // Stores the clip rectangles in aRects into mClipRects. Returns true
   // if the new rectangles are different from the old rectangles.
   PRBool StoreWindowClipRegion(const nsTArray<nsIntRect>& aRects);
 
 protected: 
   void*             mClientData;
   EVENT_CALLBACK    mEventCallback;
-  nsIDeviceContext  *mContext;
-  nsIToolkit        *mToolkit;
+  nsIDeviceContext* mContext;
+  nsIToolkit*       mToolkit;
+  nsRefPtr<LayerManager> mLayerManager;
   nscolor           mBackground;
   nscolor           mForeground;
   nsCursor          mCursor;
   nsWindowType      mWindowType;
   nsBorderStyle     mBorderStyle;
   PRPackedBool      mOnDestroyCalled;
   nsIntRect         mBounds;
   nsIntRect*        mOriginalBounds;