Revert mozilla-inbound to e4dd1fa6d222 for crashes and test failures on a CLOSED TREE
authorEd Morley <emorley@mozilla.com>
Thu, 27 Sep 2012 16:34:46 +0100
changeset 108293 d3f86e3a324043af516650186f801c7117fd12bb
parent 108292 d3d022bd1443dc4a370f8c7add006b0aff2b00bc
child 108294 71e1ca0f2da33bdfc65e60d8dc5fb16ccabbb8dd
push id15464
push useremorley@mozilla.com
push dateThu, 27 Sep 2012 15:36:15 +0000
treeherdermozilla-inbound@d3f86e3a3240 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Revert mozilla-inbound to e4dd1fa6d222 for crashes and test failures on a CLOSED TREE
browser/base/content/tabbrowser.xml
browser/components/tabview/content.js
content/base/src/nsFrameLoader.cpp
content/base/src/nsObjectLoadingContent.cpp
content/events/src/nsDOMNotifyPaintEvent.cpp
content/events/src/nsPaintRequest.cpp
content/events/test/Makefile.in
content/events/test/bug426082.html
content/events/test/bug656379-1.html
content/events/test/test_bug426082.html
content/events/test/test_bug656379-1.html
content/html/content/src/nsHTMLCanvasElement.cpp
content/media/VideoFrameContainer.cpp
dom/base/nsDOMWindowUtils.cpp
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/test/mochitest/test_painting.html
dom/tests/mochitest/chrome/selectAtPoint.html
editor/libeditor/html/crashtests/crashtests.list
editor/reftests/reftest.list
editor/reftests/spellcheck-textarea-focused-notreadonly.html
editor/reftests/spellcheck-textarea-ref2.html
gfx/layers/ImageLayers.h
gfx/layers/LayerTreeInvalidation.cpp
gfx/layers/LayerTreeInvalidation.h
gfx/layers/Layers.h
gfx/layers/Makefile.in
gfx/layers/basic/BasicThebesLayer.h
gfx/layers/basic/BasicTiledThebesLayer.h
gfx/layers/d3d10/ThebesLayerD3D10.cpp
gfx/layers/d3d9/ThebesLayerD3D9.cpp
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/thebes/gfx3DMatrix.cpp
gfx/thebes/gfx3DMatrix.h
image/src/RasterImage.cpp
image/src/RasterImage.h
image/test/mochitest/test_animSVGImage.html
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/base/Makefile.in
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCaret.cpp
layout/base/nsCaret.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsDisplayListInvalidation.cpp
layout/base/nsDisplayListInvalidation.h
layout/base/nsDocumentViewer.cpp
layout/base/nsFrameManager.cpp
layout/base/nsFrameManager.h
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
layout/base/tests/Makefile.in
layout/base/tests/bug450930.xhtml
layout/base/tests/chrome/Makefile.in
layout/base/tests/chrome/test_leaf_layers_partition_browser_window.xul
layout/base/tests/chrome/test_transformed_scrolling_repaints.html
layout/base/tests/chrome/test_transformed_scrolling_repaints_2.html
layout/base/tests/test_after_paint_pref.html
layout/base/tests/test_bug450930.xhtml
layout/forms/nsButtonFrameRenderer.cpp
layout/forms/nsComboboxControlFrame.cpp
layout/forms/nsFieldSetFrame.cpp
layout/forms/nsListControlFrame.cpp
layout/forms/nsListControlFrame.h
layout/forms/nsMeterFrame.cpp
layout/forms/nsProgressFrame.cpp
layout/forms/nsTextControlFrame.cpp
layout/generic/crashtests/crashtests.list
layout/generic/nsAbsoluteContainingBlock.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsBlockReflowState.cpp
layout/generic/nsBulletFrame.cpp
layout/generic/nsCanvasFrame.cpp
layout/generic/nsCanvasFrame.h
layout/generic/nsColumnSetFrame.cpp
layout/generic/nsContainerFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsFrame.h
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsImageFrame.cpp
layout/generic/nsImageFrame.h
layout/generic/nsImageMap.cpp
layout/generic/nsObjectFrame.cpp
layout/generic/nsPageFrame.cpp
layout/generic/nsPlaceholderFrame.cpp
layout/generic/nsSimplePageSequence.cpp
layout/generic/nsSimplePageSequence.h
layout/generic/nsSubDocumentFrame.cpp
layout/generic/nsTextFrame.h
layout/generic/nsTextFrameThebes.cpp
layout/generic/nsVideoFrame.cpp
layout/generic/nsViewportFrame.cpp
layout/generic/nsViewportFrame.h
layout/inspector/src/inFlasher.cpp
layout/ipc/RenderFrameParent.cpp
layout/mathml/nsMathMLChar.cpp
layout/reftests/bidi/reftest.list
layout/reftests/bugs/482659-1a.html
layout/reftests/bugs/482659-1b.html
layout/reftests/bugs/482659-1c.html
layout/reftests/bugs/482659-1d.html
layout/reftests/bugs/reftest.list
layout/reftests/css-invalid/input/input-customerror.html
layout/reftests/css-invalid/input/input-type-invalid.html
layout/reftests/css-invalid/input/reftest.list
layout/reftests/css-invalid/textarea/reftest.list
layout/reftests/css-invalid/textarea/textarea-customerror.html
layout/reftests/css-invalid/textarea/textarea-dyn-disabled.html
layout/reftests/css-invalid/textarea/textarea-dyn-not-disabled.html
layout/reftests/css-invalid/textarea/textarea-dyn-not-readonly.html
layout/reftests/css-invalid/textarea/textarea-dyn-readonly.html
layout/reftests/css-ui-invalid/input/input-customerror.html
layout/reftests/css-ui-invalid/input/input-type-invalid.html
layout/reftests/css-ui-invalid/input/reftest.list
layout/reftests/css-ui-invalid/textarea/reftest.list
layout/reftests/css-ui-invalid/textarea/textarea-customerror.html
layout/reftests/css-ui-invalid/textarea/textarea-dyn-disabled.html
layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-disabled.html
layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-changed.html
layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-not-changed.html
layout/reftests/css-ui-invalid/textarea/textarea-dyn-readonly.html
layout/reftests/css-ui-invalid/textarea/textarea-required-invalid-changed.html
layout/reftests/css-ui-valid/input/input-customerror.html
layout/reftests/css-ui-valid/input/input-type-invalid.html
layout/reftests/css-ui-valid/input/reftest.list
layout/reftests/css-ui-valid/select/reftest.list
layout/reftests/css-ui-valid/select/select-required-multiple-valid-changed.html
layout/reftests/css-ui-valid/textarea/reftest.list
layout/reftests/css-ui-valid/textarea/textarea-customerror.html
layout/reftests/css-ui-valid/textarea/textarea-dyn-disabled.html
layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled-changed.html
layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled.html
layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly-changed.html
layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly.html
layout/reftests/css-ui-valid/textarea/textarea-dyn-readonly.html
layout/reftests/css-ui-valid/textarea/textarea-maxlength-valid-changed.html
layout/reftests/css-valid/input/input-customerror.html
layout/reftests/css-valid/input/input-type-invalid.html
layout/reftests/css-valid/input/reftest.list
layout/reftests/css-valid/textarea/reftest.list
layout/reftests/css-valid/textarea/textarea-customerror.html
layout/reftests/css-valid/textarea/textarea-dyn-disabled.html
layout/reftests/css-valid/textarea/textarea-dyn-not-disabled.html
layout/reftests/css-valid/textarea/textarea-dyn-not-readonly.html
layout/reftests/css-valid/textarea/textarea-dyn-readonly.html
layout/reftests/font-inflation/reftest.list
layout/reftests/forms/placeholder/reftest.list
layout/reftests/layers/reftest.list
layout/reftests/reftest-sanity/invalidation.html
layout/reftests/scrolling/fixed-text-1.html
layout/reftests/svg/reftest.list
layout/reftests/svg/smil/sort/reftest.list
layout/reftests/svg/smil/transform/reftest.list
layout/reftests/text-overflow/reftest.list
layout/reftests/text/reftest.list
layout/style/ImageLoader.cpp
layout/svg/nsSVGEffects.cpp
layout/svg/nsSVGEffects.h
layout/svg/nsSVGForeignObjectFrame.cpp
layout/svg/nsSVGForeignObjectFrame.h
layout/svg/nsSVGIntegrationUtils.cpp
layout/svg/nsSVGIntegrationUtils.h
layout/svg/nsSVGOuterSVGFrame.cpp
layout/svg/nsSVGOuterSVGFrame.h
layout/svg/nsSVGUtils.cpp
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableCellFrame.h
layout/tables/nsTableColFrame.cpp
layout/tables/nsTableColFrame.h
layout/tables/nsTableColGroupFrame.cpp
layout/tables/nsTableColGroupFrame.h
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/tables/nsTableOuterFrame.cpp
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowFrame.h
layout/tables/nsTableRowGroupFrame.cpp
layout/tables/nsTableRowGroupFrame.h
layout/tools/reftest/reftest-content.js
layout/tools/reftest/reftest.js
layout/xul/base/src/nsBox.cpp
layout/xul/base/src/nsDeckFrame.cpp
layout/xul/base/src/nsImageBoxFrame.cpp
layout/xul/base/src/nsImageBoxFrame.h
layout/xul/base/src/nsListBoxLayout.cpp
layout/xul/base/src/nsMenuPopupFrame.cpp
layout/xul/base/src/nsMenuPopupFrame.h
layout/xul/base/src/nsSliderFrame.cpp
layout/xul/base/src/nsStackLayout.cpp
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
mobile/android/base/gfx/ScreenshotLayer.java
toolkit/content/tests/chrome/window_panel.xul
view/src/nsViewManager.cpp
view/src/nsViewManager.h
widget/android/nsLookAndFeel.cpp
widget/android/nsWindow.cpp
widget/android/nsWindow.h
widget/gtk2/nsNativeThemeGTK.cpp
widget/xpwidgets/nsNativeTheme.cpp
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3953,18 +3953,17 @@
                     class="tab-background-middle"/>
           <xul:hbox xbl:inherits="pinned,selected,titlechanged"
                     class="tab-background-end"/>
         </xul:hbox>
         <xul:hbox xbl:inherits="pinned,selected,titlechanged"
                   class="tab-content" align="center">
           <xul:image xbl:inherits="fadein,pinned,busy,progress,selected"
                      class="tab-throbber"
-                     role="presentation"
-                     layer="true" />
+                     role="presentation"/>
           <xul:image xbl:inherits="validate,src=image,fadein,pinned,selected"
                      class="tab-icon-image"
                      role="presentation"/>
           <xul:label flex="1"
                      xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected"
                      class="tab-text tab-label"
                      role="presentation"/>
           <xul:toolbarbutton anonid="close-button"
--- a/browser/components/tabview/content.js
+++ b/browser/components/tabview/content.js
@@ -36,19 +36,17 @@ let WindowEventHandler = {
     sendSyncMessage("Panorama:DOMWillOpenModalDialog");
   },
 
   // ----------
   // Function: onMozAfterPaint
   // Sends an asynchronous message when the "onMozAfterPaint" event
   // is fired.
   onMozAfterPaint: function WEH_onMozAfterPaint(event) {
-    if (event.clientRects.length > 0) {
-      sendAsyncMessage("Panorama:MozAfterPaint");
-    }
+    sendAsyncMessage("Panorama:MozAfterPaint");
   }
 };
 
 // add event listeners
 addEventListener("DOMWillOpenModalDialog", WindowEventHandler.onDOMWillOpenModalDialog, false);
 addEventListener("MozAfterPaint", WindowEventHandler.onMozAfterPaint, false);
 
 // ----------
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -115,16 +115,24 @@ public:
     if (base_win) {
       base_win->Destroy();
     }
     return NS_OK;
   }
   nsRefPtr<nsIDocShell> mDocShell;
 };
 
+static void InvalidateFrame(nsIFrame* aFrame, uint32_t aFlags)
+{
+  if (!aFrame)
+    return;
+  nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size());
+  aFrame->InvalidateWithFlags(rect, aFlags);
+}
+
 NS_IMPL_ISUPPORTS1(nsContentView, nsIContentView)
 
 bool
 nsContentView::IsRoot() const
 {
   return mScrollId == FrameMetrics::ROOT_SCROLL_ID;
 }
 
@@ -149,16 +157,23 @@ nsContentView::Update(const ViewConfig& 
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
   if (RenderFrameParent* rfp = mFrameLoader->GetCurrentRemoteFrame()) {
     rfp->ContentViewScaleChanged(this);
   }
 
+  // XXX could be clever here and compute a smaller invalidation
+  // rect
+  // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
+  // semantics the same for both in-process and out-of-process
+  // <browser>.  This is just a transform of the layer subtree in
+  // both.
+  InvalidateFrame(mFrameLoader->GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentView::ScrollTo(float aXpx, float aYpx)
 {
   ViewConfig config(mConfig);
   config.mScrollOffset = nsPoint(nsPresContext::CSSPixelsToAppUnits(aXpx),
@@ -1811,16 +1826,21 @@ nsFrameLoader::GetRenderMode(uint32_t* a
 NS_IMETHODIMP
 nsFrameLoader::SetRenderMode(uint32_t aRenderMode)
 {
   if (aRenderMode == mRenderMode) {
     return NS_OK;
   }
 
   mRenderMode = aRenderMode;
+  // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
+  // semantics the same for both in-process and out-of-process
+  // <browser>.  This is just a transform of the layer subtree in
+  // both.
+  InvalidateFrame(GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFrameLoader::GetEventMode(uint32_t* aEventMode)
 {
   *aEventMode = mEventMode;
   return NS_OK;
@@ -1841,17 +1861,17 @@ nsFrameLoader::GetClipSubdocument(bool* 
 }
 
 NS_IMETHODIMP
 nsFrameLoader::SetClipSubdocument(bool aClip)
 {
   mClipSubdocument = aClip;
   nsIFrame* frame = GetPrimaryFrameOfOwningContent();
   if (frame) {
-    frame->InvalidateFrame();
+    InvalidateFrame(frame, 0);
     frame->PresContext()->PresShell()->
       FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
     nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
     if (subdocFrame) {
       nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
       if (subdocRootFrame) {
         nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
           GetRootScrollFrame();
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -946,17 +946,17 @@ nsObjectLoadingContent::HasNewFrame(nsIO
     DisconnectFrame();
 
     // Set up relationship between instance owner and frame.
     nsObjectFrame *objFrame = static_cast<nsObjectFrame*>(aFrame);
     mInstanceOwner->SetFrame(objFrame);
 
     // Set up new frame to draw.
     objFrame->FixupWindow(objFrame->GetContentRectRelativeToSelf().Size());
-    objFrame->InvalidateFrame();
+    objFrame->Invalidate(objFrame->GetContentRectRelativeToSelf());
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::DisconnectFrame()
 {
   if (mInstanceOwner) {
--- a/content/events/src/nsDOMNotifyPaintEvent.cpp
+++ b/content/events/src/nsDOMNotifyPaintEvent.cpp
@@ -35,20 +35,22 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEve
 
 NS_IMPL_ADDREF_INHERITED(nsDOMNotifyPaintEvent, nsDOMEvent)
 NS_IMPL_RELEASE_INHERITED(nsDOMNotifyPaintEvent, nsDOMEvent)
 
 nsRegion
 nsDOMNotifyPaintEvent::GetRegion()
 {
   nsRegion r;
-  if (!nsContentUtils::IsCallerTrustedForRead()) {
-    return r;
-  }
+  bool isTrusted = nsContentUtils::IsCallerTrustedForRead();
   for (uint32_t i = 0; i < mInvalidateRequests.Length(); ++i) {
+    if (!isTrusted &&
+        (mInvalidateRequests[i].mFlags & nsIFrame::INVALIDATE_CROSS_DOC))
+      continue;
+
     r.Or(r, mInvalidateRequests[i].mRect);
     r.SimplifyOutward(10);
   }
   return r;
 }
 
 NS_IMETHODIMP
 nsDOMNotifyPaintEvent::GetBoundingClientRect(nsIDOMClientRect** aResult)
@@ -92,25 +94,27 @@ nsDOMNotifyPaintEvent::GetClientRects(ns
 NS_IMETHODIMP
 nsDOMNotifyPaintEvent::GetPaintRequests(nsIDOMPaintRequestList** aResult)
 {
   nsRefPtr<nsPaintRequestList> requests =
     new nsPaintRequestList(static_cast<nsDOMEvent*>(this));
   if (!requests)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  if (nsContentUtils::IsCallerTrustedForRead()) {
-    for (uint32_t i = 0; i < mInvalidateRequests.Length(); ++i) {
-      nsRefPtr<nsPaintRequest> r = new nsPaintRequest();
-      if (!r)
-        return NS_ERROR_OUT_OF_MEMORY;
- 
-      r->SetRequest(mInvalidateRequests[i]);
-      requests->Append(r);
-    }
+  bool isTrusted = nsContentUtils::IsCallerTrustedForRead();
+  for (uint32_t i = 0; i < mInvalidateRequests.Length(); ++i) {
+    if (!isTrusted &&
+        (mInvalidateRequests[i].mFlags & nsIFrame::INVALIDATE_CROSS_DOC))
+      continue;
+
+    nsRefPtr<nsPaintRequest> r = new nsPaintRequest();
+    if (!r)
+      return NS_ERROR_OUT_OF_MEMORY;
+    r->SetRequest(mInvalidateRequests[i]);
+    requests->Append(r);
   }
 
   requests.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP_(void)
 nsDOMNotifyPaintEvent::Serialize(IPC::Message* aMsg,
--- a/content/events/src/nsPaintRequest.cpp
+++ b/content/events/src/nsPaintRequest.cpp
@@ -30,17 +30,27 @@ nsPaintRequest::GetClientRect(nsIDOMClie
   clientRect->SetLayoutRect(mRequest.mRect);
   clientRect.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPaintRequest::GetReason(nsAString& aResult)
 {
-  aResult.AssignLiteral("repaint");
+  switch (mRequest.mFlags & nsIFrame::INVALIDATE_REASON_MASK) {
+  case nsIFrame::INVALIDATE_REASON_SCROLL_BLIT:
+    aResult.AssignLiteral("scroll copy");
+    break;
+  case nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT:
+    aResult.AssignLiteral("scroll repaint");
+    break;
+  default:
+    aResult.Truncate();
+    break;
+  }
   return NS_OK;
 }
 
 DOMCI_DATA(PaintRequestList, nsPaintRequestList)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPaintRequestList, mParent)
 
 NS_INTERFACE_TABLE_HEAD(nsPaintRequestList)
--- a/content/events/test/Makefile.in
+++ b/content/events/test/Makefile.in
@@ -31,17 +31,16 @@ MOCHITEST_FILES = \
 		test_bug379120.html \
 		test_bug391568.xhtml \
 		test_bug402089.html \
 		test_bug405632.html \
 		test_bug409604.html \
 		test_bug412567.html \
 		test_bug422132.html \
 		test_bug426082.html \
-		bug426082.html \
 		test_bug427537.html \
 		test_bug432698.html \
 		test_bug443985.html \
 		test_bug447736.html \
 		test_bug448602.html \
 		test_bug450876.html \
 		test_bug456273.html \
 		test_bug457672.html \
@@ -67,17 +66,16 @@ MOCHITEST_FILES = \
 		test_bug613634.html \
 		test_bug607464.html \
 		test_bug624127.html \
 		test_bug650493.html \
 		test_bug641477.html \
 		test_bug648573.html \
 		test_bug615597.html \
 		test_bug656379-1.html \
-		bug656379-1.html \
 		test_bug656379-2.html \
 		test_bug656954.html \
 		test_bug659071.html \
 		window_bug659071.html \
 		test_bug659350.html \
 		test_bug662678.html \
 		test_bug667919-1.html \
 		test_bug667919-2.html \
deleted file mode 100644
--- a/content/events/test/bug426082.html
+++ /dev/null
@@ -1,161 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=426082
--->
-<head>
-  <title>Test for Bug 426082</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <style>
-    canvas {
-      display: none;
-    }
-  </style>
-</head>
-<body onload="runTests()">
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=426082">Mozilla Bug 426082</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<p><input type="button" value="Button" id="button"></p>
-<p><label for="button" id="label">Label</label></p>
-<p id="outside">Something under the label</p>
-<pre id="test">
-<script type="application/javascript;version=1.8">
-
-/** Test for Bug 426082 **/
-
-var normalButtonCanvas, pressedButtonCanvas, normalFocusedButtonCanvas,
-    pressedFocusedButtonCanvas, currentSnapshot, button, label, outside;
-
-function runTests() {
-  button = $("button");
-  label = $("label");
-  outside = $("outside");
-  SimpleTest.executeSoon(executeTests);
-}
-
-function isRectContainedInRectFromRegion(rect, region) {
-  return Array.some(region, function (r) {
-    return rect.left >= r.left &&
-           rect.top >= r.top &&
-           rect.right <= r.right &&
-           rect.bottom <= r.bottom;
-  });
-}
-
-function paintListener(e) {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  if (isRectContainedInRectFromRegion(buttonRect(), e.clientRects)) {
-    gNeedsPaint = false;
-    currentSnapshot = takeSnapshot();
-  }
-}
-
-var gNeedsPaint = false;
-function executeTests() {
-  var testYielder = tests();
-  function execNext() {
-    try {
-      if (!gNeedsPaint) {
-        testYielder.next();
-        button.getBoundingClientRect(); // Flush.
-        gNeedsPaint = true;
-      }
-      SimpleTest.executeSoon(execNext);
-    } catch (e) {}
-  }
-  execNext();
-}
-
-function tests() {
-  window.addEventListener("MozAfterPaint", paintListener, false);
-  normalButtonCanvas = takeSnapshot();
-  // Press the button.
-  sendMouseEvent("mousemove", button);
-  sendMouseEvent("mousedown", button);
-  yield;
-  pressedFocusedButtonCanvas = takeSnapshot();
-  compareSnapshots_(normalButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal buttons.");
-  // Release.
-  sendMouseEvent("mouseup", button);
-  yield;
-  // make sure the button is focused as this doesn't happen on click on Mac
-  button.focus();
-  normalFocusedButtonCanvas = takeSnapshot();
-  compareSnapshots_(normalFocusedButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal focused buttons.");
-  // Unfocus the button.
-  sendMouseEvent("mousedown", outside);
-  sendMouseEvent("mouseup", outside);
-  yield;
-
-  // Press the label.
-  sendMouseEvent("mousemove", label);
-  sendMouseEvent("mousedown", label);
-  yield;
-  compareSnapshots_(normalButtonCanvas, currentSnapshot, false, "Pressing the label should have pressed the button.");
-  pressedButtonCanvas = takeSnapshot();
-  // Move the mouse down from the label.
-  sendMouseEvent("mousemove", outside);
-  yield;
-  compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Moving the mouse down from the label should have unpressed the button.");
-  // ... and up again.
-  sendMouseEvent("mousemove", label);
-  yield;
-  compareSnapshots_(pressedButtonCanvas, currentSnapshot, true, "Moving the mouse back on top of the label should have pressed the button.");
-  // Release.
-  sendMouseEvent("mouseup", label);
-  yield;
-  compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
-  // Press the label and remove it.
-  sendMouseEvent("mousemove", label);
-  sendMouseEvent("mousedown", label);
-  yield;
-  label.parentNode.removeChild(label);
-  yield;
-  compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Removing the label should have unpressed the button.");
-  sendMouseEvent("mouseup", label);
-  window.removeEventListener("MozAfterPaint", paintListener, false);
-  window.opener.finishTests();
- }
-
-function sendMouseEvent(t, elem) {
-  var r = elem.getBoundingClientRect();
-  synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
-}
-
-function compareSnapshots_(c1, c2, shouldBeIdentical, msg) {
-  var [correct, c1url, c2url] = compareSnapshots(c1, c2, shouldBeIdentical);
-  if (correct) {
-    if (shouldBeIdentical) {
-      window.opener.ok(true, msg + " - expected " + c1url);
-    } else {
-      window.opener.ok(true, msg + " - got " + c1url + " and " + c2url);
-    }
-  } else {
-    if (shouldBeIdentical) {
-      window.opener.ok(false, msg + " - expected " + c1url + " but got " + c2url);
-    } else {
-      window.opener.ok(false, msg + " - expected something other than " + c1url);
-    }
-  }
-}
-
-function takeSnapshot() {
-  var r = buttonRect();
-  adjustedRect = { left: r.left - 2, top: r.top - 2,
-                   width: r.width + 4, height: r.height + 4 };
-  return SpecialPowers.snapshotRect(window, adjustedRect);
-}
-
-function buttonRect() {
-  return button.getBoundingClientRect();
-}
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/events/test/bug656379-1.html
+++ /dev/null
@@ -1,181 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=656379
--->
-<head>
-  <title>Test for Bug 656379</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <style>
-    canvas {
-      display: none;
-    }
-    input[type=button] {
-      -moz-appearance: none;
-      padding: 0;
-      border: none;
-      color: black;
-      background: white;
-    }
-    input[type=button]::-moz-focus-inner { border: none; }
-
-    /* Make sure that normal, focused, hover+active, focused+hover+active
-       buttons all have different styles so that the test keeps moving along. */
-    input[type=button]:hover:active {
-      background: red;
-    }
-    input[type=button]:focus {
-      background: green;
-    }
-    input[type=button]:focus:hover:active {
-      background: purple;
-    }
-  </style>
-</head>
-<body onload="runTests()">
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=656379">Mozilla Bug 656379</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script type="application/javascript;version=1.8">
-
-
-var normalButtonCanvas, pressedButtonCanvas, normalFocusedButtonCanvas,
-    pressedFocusedButtonCanvas, currentSnapshot, button, label, outside;
-
-function runTests() {
-  button = $("button");
-  label = $("label");
-  outside = $("outside");
-  SimpleTest.executeSoon(executeTests);
-}
-
-function isRectContainedInRectFromRegion(rect, region) {
-  return Array.some(region, function (r) {
-    return rect.left >= r.left &&
-           rect.top >= r.top &&
-           rect.right <= r.right &&
-           rect.bottom <= r.bottom;
-  });
-}
-
-function paintListener(e) {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  if (isRectContainedInRectFromRegion(buttonRect(), e.clientRects)) {
-    gNeedsPaint = false;
-    currentSnapshot = takeSnapshot();
-  }
-}
-
-var gNeedsPaint = false;
-function executeTests() {
-  var testYielder = tests();
-  function execNext() {
-    try {
-      if (!gNeedsPaint) {
-        testYielder.next();
-        button.getBoundingClientRect(); // Flush.
-        gNeedsPaint = true;
-      }
-      SimpleTest.executeSoon(execNext);
-    } catch (e) {}
-  }
-  execNext();
-}
-
-function tests() {
-  window.addEventListener("MozAfterPaint", paintListener, false);
-  normalButtonCanvas = takeSnapshot();
-  // Press the button.
-  sendMouseEvent("mousemove", button);
-  sendMouseEvent("mousedown", button);
-  yield;
-  pressedFocusedButtonCanvas = takeSnapshot();
-  compareSnapshots_(normalButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal buttons.");
-  // Release.
-  sendMouseEvent("mouseup", button);
-  yield;
-  // make sure the button is focused as this doesn't happen on click on Mac
-  button.focus();
-  normalFocusedButtonCanvas = takeSnapshot();
-  compareSnapshots_(normalFocusedButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal focused buttons.");
-  // Unfocus the button.
-  sendMouseEvent("mousedown", outside);
-  sendMouseEvent("mouseup", outside);
-  yield;
-
-  // Press the label.
-  sendMouseEvent("mousemove", label);
-  sendMouseEvent("mousedown", label);
-  yield;
-  compareSnapshots_(normalButtonCanvas, currentSnapshot, false, "Pressing the label should have pressed the button.");
-  pressedButtonCanvas = takeSnapshot();
-  // Move the mouse down from the label.
-  sendMouseEvent("mousemove", outside);
-  yield;
-  compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Moving the mouse down from the label should have unpressed the button.");
-  // ... and up again.
-  sendMouseEvent("mousemove", label);
-  yield;
-  compareSnapshots_(pressedButtonCanvas, currentSnapshot, true, "Moving the mouse back on top of the label should have pressed the button.");
-  // Release.
-  sendMouseEvent("mouseup", label);
-  yield;
-  compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
-  // Press the label and remove it.
-  sendMouseEvent("mousemove", label);
-  sendMouseEvent("mousedown", label);
-  yield;
-  label.parentNode.removeChild(label);
-  yield;
-  compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Removing the label should have unpressed the button.");
-  sendMouseEvent("mouseup", label);
-  window.removeEventListener("MozAfterPaint", paintListener, false);
-  window.opener.finishTests();
- }
-
-function sendMouseEvent(t, elem) {
-  var r = elem.getBoundingClientRect();
-  synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
-}
-
-function compareSnapshots_(c1, c2, shouldBeIdentical, msg) {
-  var [correct, c1url, c2url] = compareSnapshots(c1, c2, shouldBeIdentical);
-  if (correct) {
-    if (shouldBeIdentical) {
-      window.opener.ok(true, msg + " - expected " + c1url);
-    } else {
-      window.opener.ok(true, msg + " - got " + c1url + " and " + c2url);
-    }
-  } else {
-    if (shouldBeIdentical) {
-      window.opener.ok(false, msg + " - expected " + c1url + " but got " + c2url);
-    } else {
-      window.opener.ok(false, msg + " - expected something other than " + c1url);
-    }
-  }
-}
-
-function takeSnapshot(canvas) {
-  var r = buttonRect();
-  adjustedRect = { left: r.left - 2, top: r.top - 2,
-                   width: r.width + 4, height: r.height + 4 };
-  return SpecialPowers.snapshotRect(window, adjustedRect);
-}
-
-function buttonRect() {
-  return button.getBoundingClientRect();
-}
-</script>
-</pre>
-<p><input type="button" value="Button" id="button"></p>
-<p><label for="button" id="label">Label</label></p>
-<p id="outside">Something under the label</p>
-
-</body>
-</html>
--- a/content/events/test/test_bug426082.html
+++ b/content/events/test/test_bug426082.html
@@ -4,27 +4,161 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=426082
 -->
 <head>
   <title>Test for Bug 426082</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style>
+    canvas {
+      display: none;
+    }
+  </style>
 </head>
-<body>
-
+<body onload="runTests()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=426082">Mozilla Bug 426082</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
 <pre id="test">
 <script type="application/javascript;version=1.8">
 
 /** Test for Bug 426082 **/
 SimpleTest.waitForExplicitFinish();
-var subwindow = window.open("./bug426082.html", "bug426082", "width=800,height=1000");
+
+var normalButtonCanvas, pressedButtonCanvas, normalFocusedButtonCanvas,
+    pressedFocusedButtonCanvas, currentSnapshot, button, label, outside;
+
+function runTests() {
+  button = $("button");
+  label = $("label");
+  outside = $("outside");
+  SimpleTest.executeSoon(executeTests);
+}
+
+function isRectContainedInRectFromRegion(rect, region) {
+  return Array.some(region, function (r) {
+    return rect.left >= r.left &&
+           rect.top >= r.top &&
+           rect.right <= r.right &&
+           rect.bottom <= r.bottom;
+  });
+}
+
+function paintListener(e) {
+  if (isRectContainedInRectFromRegion(buttonRect(), e.clientRects)) {
+    gNeedsPaint = false;
+    currentSnapshot = takeSnapshot();
+  }
+}
+
+var gNeedsPaint = false;
+function executeTests() {
+  var testYielder = tests();
+  function execNext() {
+    try {
+      if (!gNeedsPaint) {
+        testYielder.next();
+        button.getBoundingClientRect(); // Flush.
+        gNeedsPaint = true;
+      }
+      SimpleTest.executeSoon(execNext);
+    } catch (e) {}
+  }
+  execNext();
+}
 
-function finishTests() {
-  subwindow.close();
+function tests() {
+  window.addEventListener("MozAfterPaint", paintListener, false);
+  normalButtonCanvas = takeSnapshot();
+  // Press the button.
+  sendMouseEvent("mousemove", button);
+  sendMouseEvent("mousedown", button);
+  yield;
+  pressedFocusedButtonCanvas = takeSnapshot();
+  compareSnapshots_(normalButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal buttons.");
+  // Release.
+  sendMouseEvent("mouseup", button);
+  yield;
+  // make sure the button is focused as this doesn't happen on click on Mac
+  button.focus();
+  normalFocusedButtonCanvas = takeSnapshot();
+  compareSnapshots_(normalFocusedButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal focused buttons.");
+  // Unfocus the button.
+  sendMouseEvent("mousedown", outside);
+  sendMouseEvent("mouseup", outside);
+  yield;
+
+  // Press the label.
+  sendMouseEvent("mousemove", label);
+  sendMouseEvent("mousedown", label);
+  yield;
+  compareSnapshots_(normalButtonCanvas, currentSnapshot, false, "Pressing the label should have pressed the button.");
+  pressedButtonCanvas = takeSnapshot();
+  // Move the mouse down from the label.
+  sendMouseEvent("mousemove", outside);
+  yield;
+  compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Moving the mouse down from the label should have unpressed the button.");
+  // ... and up again.
+  sendMouseEvent("mousemove", label);
+  yield;
+  compareSnapshots_(pressedButtonCanvas, currentSnapshot, true, "Moving the mouse back on top of the label should have pressed the button.");
+  // Release.
+  sendMouseEvent("mouseup", label);
+  yield;
+  compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
+  // Press the label and remove it.
+  sendMouseEvent("mousemove", label);
+  sendMouseEvent("mousedown", label);
+  yield;
+  label.parentNode.removeChild(label);
+  yield;
+  compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Removing the label should have unpressed the button.");
+  sendMouseEvent("mouseup", label);
+  window.removeEventListener("MozAfterPaint", paintListener, false);
   SimpleTest.finish();
 }
+
+function sendMouseEvent(t, elem) {
+  var r = elem.getBoundingClientRect();
+  synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
+}
+
+function compareSnapshots_(c1, c2, shouldBeIdentical, msg) {
+  var [correct, c1url, c2url] = compareSnapshots(c1, c2, shouldBeIdentical);
+  if (correct) {
+    if (shouldBeIdentical) {
+      ok(true, msg + " - expected " + c1url);
+    } else {
+      ok(true, msg + " - got " + c1url + " and " + c2url);
+    }
+  } else {
+    if (shouldBeIdentical) {
+      ok(false, msg + " - expected " + c1url + " but got " + c2url);
+    } else {
+      ok(false, msg + " - expected something other than " + c1url);
+    }
+  }
+}
+
+function takeSnapshot() {
+  var r = buttonRect();
+  adjustedRect = { left: r.left - 2, top: r.top - 2,
+                   width: r.width + 4, height: r.height + 4 };
+  return SpecialPowers.snapshotRect(window, adjustedRect);
+}
+
+function buttonRect() {
+  return button.getBoundingClientRect();
+}
+
+
 </script>
 </pre>
+<p><input type="button" value="Button" id="button"></p>
+<p><label for="button" id="label">Label</label></p>
+<p id="outside">Something under the label</p>
 
 </body>
 </html>
--- a/content/events/test/test_bug656379-1.html
+++ b/content/events/test/test_bug656379-1.html
@@ -4,27 +4,181 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=656379
 -->
 <head>
   <title>Test for Bug 656379</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style>
+    canvas {
+      display: none;
+    }
+    input[type=button] {
+      -moz-appearance: none;
+      padding: 0;
+      border: none;
+      color: black;
+      background: white;
+    }
+    input[type=button]::-moz-focus-inner { border: none; }
+
+    /* Make sure that normal, focused, hover+active, focused+hover+active
+       buttons all have different styles so that the test keeps moving along. */
+    input[type=button]:hover:active {
+      background: red;
+    }
+    input[type=button]:focus {
+      background: green;
+    }
+    input[type=button]:focus:hover:active {
+      background: purple;
+    }
+  </style>
 </head>
-<body>
-
+<body onload="runTests()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=426082">Mozilla Bug 426082</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
 <pre id="test">
 <script type="application/javascript;version=1.8">
 
-/** Test for Bug 656379 **/
+/** Test for Bug 426082 **/
 SimpleTest.waitForExplicitFinish();
-var subwindow = window.open("./bug656379-1.html", "bug656379", "width=800,height=1000");
+
+var normalButtonCanvas, pressedButtonCanvas, normalFocusedButtonCanvas,
+    pressedFocusedButtonCanvas, currentSnapshot, button, label, outside;
+
+function runTests() {
+  button = $("button");
+  label = $("label");
+  outside = $("outside");
+  SimpleTest.executeSoon(executeTests);
+}
+
+function isRectContainedInRectFromRegion(rect, region) {
+  return Array.some(region, function (r) {
+    return rect.left >= r.left &&
+           rect.top >= r.top &&
+           rect.right <= r.right &&
+           rect.bottom <= r.bottom;
+  });
+}
+
+function paintListener(e) {
+  if (isRectContainedInRectFromRegion(buttonRect(), e.clientRects)) {
+    gNeedsPaint = false;
+    currentSnapshot = takeSnapshot();
+  }
+}
+
+var gNeedsPaint = false;
+function executeTests() {
+  var testYielder = tests();
+  function execNext() {
+    try {
+      if (!gNeedsPaint) {
+        testYielder.next();
+        button.getBoundingClientRect(); // Flush.
+        gNeedsPaint = true;
+      }
+      SimpleTest.executeSoon(execNext);
+    } catch (e) {}
+  }
+  execNext();
+}
 
-function finishTests() {
-  subwindow.close();
+function tests() {
+  window.addEventListener("MozAfterPaint", paintListener, false);
+  normalButtonCanvas = takeSnapshot();
+  // Press the button.
+  sendMouseEvent("mousemove", button);
+  sendMouseEvent("mousedown", button);
+  yield;
+  pressedFocusedButtonCanvas = takeSnapshot();
+  compareSnapshots_(normalButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal buttons.");
+  // Release.
+  sendMouseEvent("mouseup", button);
+  yield;
+  // make sure the button is focused as this doesn't happen on click on Mac
+  button.focus();
+  normalFocusedButtonCanvas = takeSnapshot();
+  compareSnapshots_(normalFocusedButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal focused buttons.");
+  // Unfocus the button.
+  sendMouseEvent("mousedown", outside);
+  sendMouseEvent("mouseup", outside);
+  yield;
+
+  // Press the label.
+  sendMouseEvent("mousemove", label);
+  sendMouseEvent("mousedown", label);
+  yield;
+  compareSnapshots_(normalButtonCanvas, currentSnapshot, false, "Pressing the label should have pressed the button.");
+  pressedButtonCanvas = takeSnapshot();
+  // Move the mouse down from the label.
+  sendMouseEvent("mousemove", outside);
+  yield;
+  compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Moving the mouse down from the label should have unpressed the button.");
+  // ... and up again.
+  sendMouseEvent("mousemove", label);
+  yield;
+  compareSnapshots_(pressedButtonCanvas, currentSnapshot, true, "Moving the mouse back on top of the label should have pressed the button.");
+  // Release.
+  sendMouseEvent("mouseup", label);
+  yield;
+  compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
+  // Press the label and remove it.
+  sendMouseEvent("mousemove", label);
+  sendMouseEvent("mousedown", label);
+  yield;
+  label.parentNode.removeChild(label);
+  yield;
+  compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Removing the label should have unpressed the button.");
+  sendMouseEvent("mouseup", label);
+  window.removeEventListener("MozAfterPaint", paintListener, false);
   SimpleTest.finish();
 }
+
+function sendMouseEvent(t, elem) {
+  var r = elem.getBoundingClientRect();
+  synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
+}
+
+function compareSnapshots_(c1, c2, shouldBeIdentical, msg) {
+  var [correct, c1url, c2url] = compareSnapshots(c1, c2, shouldBeIdentical);
+  if (correct) {
+    if (shouldBeIdentical) {
+      ok(true, msg + " - expected " + c1url);
+    } else {
+      ok(true, msg + " - got " + c1url + " and " + c2url);
+    }
+  } else {
+    if (shouldBeIdentical) {
+      ok(false, msg + " - expected " + c1url + " but got " + c2url);
+    } else {
+      ok(false, msg + " - expected something other than " + c1url);
+    }
+  }
+}
+
+function takeSnapshot(canvas) {
+  var r = buttonRect();
+  adjustedRect = { left: r.left - 2, top: r.top - 2,
+                   width: r.width + 4, height: r.height + 4 };
+  return SpecialPowers.snapshotRect(window, adjustedRect);
+}
+
+function buttonRect() {
+  return button.getBoundingClientRect();
+}
+
+
 </script>
 </pre>
+<p><input type="button" value="Button" id="button"></p>
+<p><label for="button" id="label">Label</label></p>
+<p id="outside">Something under the label</p>
 
 </body>
 </html>
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -831,33 +831,42 @@ nsHTMLCanvasElement::InvalidateCanvasCon
   // We don't need to flush anything here; if there's no frame or if
   // we plan to reframe we don't need to invalidate it anyway.
   nsIFrame *frame = GetPrimaryFrame();
   if (!frame)
     return;
 
   frame->MarkLayersActive(nsChangeHint(0));
 
-  Layer* layer;
+  nsRect invalRect;
+  nsRect contentArea = frame->GetContentRect();
   if (damageRect) {
     nsIntSize size = GetWidthHeight();
     if (size.width != 0 && size.height != 0) {
 
+      // damageRect and size are in CSS pixels; contentArea is in appunits
+      // We want a rect in appunits; so avoid doing pixels-to-appunits and
+      // vice versa conversion here.
       gfxRect realRect(*damageRect);
+      realRect.Scale(contentArea.width / gfxFloat(size.width),
+                     contentArea.height / gfxFloat(size.height));
       realRect.RoundOut();
 
       // then make it a nsRect
-      nsIntRect invalRect(realRect.X(), realRect.Y(),
-                          realRect.Width(), realRect.Height());
+      invalRect = nsRect(realRect.X(), realRect.Y(),
+                         realRect.Width(), realRect.Height());
 
-      layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS, &invalRect);
+      invalRect = invalRect.Intersect(nsRect(nsPoint(0,0), contentArea.Size()));
     }
   } else {
-    layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS);
+    invalRect = nsRect(nsPoint(0, 0), contentArea.Size());
   }
+  invalRect.MoveBy(contentArea.TopLeft() - frame->GetPosition());
+
+  Layer* layer = frame->InvalidateLayer(invalRect, nsDisplayItem::TYPE_CANVAS);
   if (layer) {
     static_cast<CanvasLayer*>(layer)->Updated();
   }
 
   /*
    * Treat canvas invalidations as animation activity for JS. Frequently
    * invalidating a canvas will feed into heuristics and cause JIT code to be
    * kept around longer, for smoother animations.
@@ -875,17 +884,17 @@ void
 nsHTMLCanvasElement::InvalidateCanvas()
 {
   // We don't need to flush anything here; if there's no frame or if
   // we plan to reframe we don't need to invalidate it anyway.
   nsIFrame *frame = GetPrimaryFrame();
   if (!frame)
     return;
 
-  frame->InvalidateFrame();
+  frame->Invalidate(frame->GetContentRect() - frame->GetPosition());
 }
 
 int32_t
 nsHTMLCanvasElement::CountContexts()
 {
   if (mCurrentContext)
     return 1;
 
--- a/content/media/VideoFrameContainer.cpp
+++ b/content/media/VideoFrameContainer.cpp
@@ -126,19 +126,20 @@ void VideoFrameContainer::Invalidate()
         presShell->FrameNeedsReflow(frame,
                                     nsIPresShell::eStyleChange,
                                     NS_FRAME_IS_DIRTY);
       }
     }
   }
 
   if (frame) {
+    nsRect contentRect = frame->GetContentRect() - frame->GetPosition();
     if (invalidateFrame) {
-      frame->InvalidateFrame();
+      frame->Invalidate(contentRect);
     } else {
-      frame->InvalidateLayer(nsDisplayItem::TYPE_VIDEO);
+      frame->InvalidateLayer(contentRect, nsDisplayItem::TYPE_VIDEO);
     }
   }
 
   nsSVGEffects::InvalidateDirectRenderingObservers(mElement);
 }
 
 }
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -215,20 +215,22 @@ nsDOMWindowUtils::Redraw(uint32_t aCount
 
   if (aCount == 0)
     aCount = 1;
 
   if (nsIPresShell* presShell = GetPresShell()) {
     nsIFrame *rootFrame = presShell->GetRootFrame();
 
     if (rootFrame) {
+      nsRect r(nsPoint(0, 0), rootFrame->GetSize());
+
       PRIntervalTime iStart = PR_IntervalNow();
 
       for (uint32_t i = 0; i < aCount; i++)
-        rootFrame->InvalidateFrame();
+        rootFrame->InvalidateWithFlags(r, nsIFrame::INVALIDATE_IMMEDIATE);
 
 #if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK)
       XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), False);
 #endif
 
       *aDurationOut = PR_IntervalToMilliseconds(PR_IntervalNow() - iStart);
 
       return NS_OK;
@@ -382,17 +384,24 @@ nsDOMWindowUtils::SetDisplayPortForEleme
       // separate notification just for this change.
       nsPresContext* presContext = GetPresContext();
       MaybeReflowForInflationScreenWidthChange(presContext);
     }
   }
 
   nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame();
   if (rootFrame) {
-    rootFrame->InvalidateFrame();
+    nsIContent* rootContent =
+      rootScrollFrame ? rootScrollFrame->GetContent() : nullptr;
+    nsRect rootDisplayport;
+    bool usingDisplayport = rootContent &&
+      nsLayoutUtils::GetDisplayPort(rootContent, &rootDisplayport);
+    rootFrame->InvalidateWithFlags(
+      usingDisplayport ? rootDisplayport : rootFrame->GetVisualOverflowRect(),
+      nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
 
     // If we are hiding something that is a display root then send empty paint
     // transaction in order to release retained layers because it won't get
     // any more paint requests when it is hidden.
     if (displayport.IsEmpty() &&
         rootFrame == nsLayoutUtils::GetDisplayRootFrame(rootFrame)) {
       nsCOMPtr<nsIWidget> widget = GetWidget();
       if (widget) {
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -655,34 +655,38 @@ NS_IMETHODIMP nsPluginInstanceOwner::Inv
   // Silverlight does and expects it to "work"
   if (mWidget) {
     mWidget->Invalidate(nsIntRect(invalidRect->left, invalidRect->top,
                                   invalidRect->right - invalidRect->left,
                                   invalidRect->bottom - invalidRect->top));
     return NS_OK;
   }
 #endif
-  nsIntRect rect(invalidRect->left,
-                 invalidRect->top,
-                 invalidRect->right - invalidRect->left,
-                 invalidRect->bottom - invalidRect->top);
-  mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect);
+
+  nsPresContext* presContext = mObjectFrame->PresContext();
+  nsRect rect(presContext->DevPixelsToAppUnits(invalidRect->left),
+              presContext->DevPixelsToAppUnits(invalidRect->top),
+              presContext->DevPixelsToAppUnits(invalidRect->right - invalidRect->left),
+              presContext->DevPixelsToAppUnits(invalidRect->bottom - invalidRect->top));
+
+  rect.MoveBy(mObjectFrame->GetContentRectRelativeToSelf().TopLeft());
+  mObjectFrame->InvalidateLayer(rect, nsDisplayItem::TYPE_PLUGIN);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
  
 NS_IMETHODIMP
 nsPluginInstanceOwner::RedrawPlugin()
 {
   if (mObjectFrame) {
-    mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN);
+    mObjectFrame->InvalidateLayer(mObjectFrame->GetContentRectRelativeToSelf(), nsDisplayItem::TYPE_PLUGIN);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
 {
   if (!mObjectFrame) {
     NS_WARNING("plugin owner has no owner in getting doc's window handle");
@@ -3738,17 +3742,17 @@ void nsPluginInstanceOwner::SetFrame(nsO
   if (mObjectFrame) {
     mObjectFrame->SetInstanceOwner(this);
     // Can only call PrepForDrawing on an object frame once. Don't do it here unless
     // widget creation is complete. Doesn't matter if we actually have a widget.
     if (mWidgetCreationComplete) {
       mObjectFrame->PrepForDrawing(mWidget);
     }
     mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size());
-    mObjectFrame->InvalidateFrame();
+    mObjectFrame->Invalidate(mObjectFrame->GetContentRectRelativeToSelf());
 
     // Scroll position listening is only required for Carbon event model plugins on Mac OS X.
 #if defined(XP_MACOSX) && !defined(NP_NO_CARBON)
     AddScrollPositionListener();
 #endif
     
     nsFocusManager* fm = nsFocusManager::GetFocusManager();
     const nsIContent* content = aFrame->GetContent();
--- a/dom/plugins/test/mochitest/test_painting.html
+++ b/dom/plugins/test/mochitest/test_painting.html
@@ -89,19 +89,18 @@ function invalidate() {
 function done() {
   paintCountIs(clipped, 2, "painted after invalidate");
 
   SimpleTest.finish();  
 }
 
 function waitForPaint(func) {
   paint_waiter.last_paint_count = paint_waiter.getPaintCount();
-  // Ensure the waiter has had a style change, so that this will
+  // Ensure the waiter has been reflowed with zero height, so that this will
   // change its size and cause a paint.
-  paint_waiter.style.backgroundColor = paint_waiter.style.backgroundColor == "blue" ? "yellow" : "blue";
   var flush = paint_waiter.offsetHeight;
   paint_waiter.style.height = "1px";
   waitForPaintHelper(func);
 }
 
 function waitForPaintHelper(func) {
   if (paint_waiter.getPaintCount() != paint_waiter.last_paint_count) {
     // hide the paint waiter
--- a/dom/tests/mochitest/chrome/selectAtPoint.html
+++ b/dom/tests/mochitest/chrome/selectAtPoint.html
@@ -192,33 +192,23 @@
   let pageLoad = false;
   let painted = false;
   function testReady() {
     if (frameLoad && pageLoad && painted) 
       doTest();
   }
 
   function onFrameLoad() {
-    // Exit the onload handler before trying the test, because we need
-    // to ensure that paint unsupression has happened.
-    setTimeout(function() {
-      frameLoad = true;
-      testReady();
-    }, 0);
+    frameLoad = true;
+    testReady();
   }
 
   function onPageLoad() {
-    // Exit the onload handler before trying the test, because we need
-    // to ensure that paint unsupression has happened
-    // XXXroc why do we need to separately test for the loading of the frame
-    // and a paint? That should not be necessary for this test.
-    setTimeout(function() {
-      pageLoad = true;
-      testReady();
-    }, 0);
+    pageLoad = true;
+    testReady();
   }
 
   function onPaint() {
     window.removeEventListener("MozAfterPaint", onPaint, false);
     painted = true;
     testReady();
   }
 
--- a/editor/libeditor/html/crashtests/crashtests.list
+++ b/editor/libeditor/html/crashtests/crashtests.list
@@ -20,17 +20,17 @@ load 535632-1.xhtml
 load 574558-1.xhtml
 load 582138-1.xhtml
 load 612565-1.html
 asserts(0-6) load 615015-1.html # Bug 439258
 load 615450-1.html
 load 639736-1.xhtml
 load 643786-1.html
 load 682650-1.html
-asserts(0-1) load 716456-1.html
+load 716456-1.html
 load 759748.html
 load 761861.html
 load 769008-1.html
 load 766305.html
 load 766387.html
 load 766795.html
 load 767169.html
 load 769967.xhtml
--- a/editor/reftests/reftest.list
+++ b/editor/reftests/reftest.list
@@ -40,17 +40,17 @@ fails-if(Android) != spellcheck-input-at
 fails-if(Android) != spellcheck-input-property-dynamic-override.html spellcheck-input-ref.html
 == spellcheck-input-property-dynamic-override-inherit.html spellcheck-input-nofocus-ref.html
 fails-if(Android) != spellcheck-input-property-dynamic-override-inherit.html spellcheck-input-ref.html
 == spellcheck-textarea-attr.html spellcheck-textarea-nofocus-ref.html
 #the random-if(Android) tests pass on android native, but fail on android-xul, see bug 728942
 random-if(Android) != spellcheck-textarea-attr.html spellcheck-textarea-ref.html
 needs-focus == spellcheck-textarea-focused.html spellcheck-textarea-ref.html
 needs-focus == spellcheck-textarea-focused-reframe.html spellcheck-textarea-ref.html
-needs-focus == spellcheck-textarea-focused-notreadonly.html spellcheck-textarea-ref2.html
+needs-focus == spellcheck-textarea-focused-notreadonly.html spellcheck-textarea-ref.html
 random-if(Android) != spellcheck-textarea-nofocus.html spellcheck-textarea-ref.html
 random-if(Android) != spellcheck-textarea-disabled.html spellcheck-textarea-ref.html
 random-if(Android) != spellcheck-textarea-attr-inherit.html spellcheck-textarea-ref.html
 random-if(Android) != spellcheck-textarea-attr-dynamic.html spellcheck-textarea-ref.html
 random-if(Android) != spellcheck-textarea-attr-dynamic-inherit.html spellcheck-textarea-ref.html
 random-if(Android) != spellcheck-textarea-property-dynamic.html spellcheck-textarea-ref.html
 random-if(Android) != spellcheck-textarea-property-dynamic-inherit.html spellcheck-textarea-ref.html
 random-if(Android) != spellcheck-textarea-attr-dynamic-override.html spellcheck-textarea-ref.html
--- a/editor/reftests/spellcheck-textarea-focused-notreadonly.html
+++ b/editor/reftests/spellcheck-textarea-focused-notreadonly.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
 <body>
 
-  <textarea id="testBox" style="padding:2px;" readonly></textarea>
+  <textarea id="testBox" readonly></textarea>
   <script type="text/javascript">
     //Adding focus to the textbox should trigger a spellcheck
     var textbox = document.getElementById("testBox");
     addEventListener("load", function() {
       textbox.readOnly = false;
       textbox.focus();
       textbox.value = "blahblahblah";
       textbox.selectionStart = textbox.selectionEnd = 0;
deleted file mode 100644
--- a/editor/reftests/spellcheck-textarea-ref2.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-  <textarea spellcheck="true" style="padding:2px;">blahblahblah</textarea>
-  <script type="text/javascript">
-    var box = document.getElementsByTagName("textarea")[0];
-    box.focus(); //Bring the textbox into focus, triggering a spellcheck
-    box.blur(); //Blur in order to make things similar to other tests otherwise
-  </script>
-</body>
-</html>
--- a/gfx/layers/ImageLayers.h
+++ b/gfx/layers/ImageLayers.h
@@ -49,18 +49,16 @@ public:
   {
     mScaleToSize = aSize;
     mScaleMode = aMode;
   }
 
 
   ImageContainer* GetContainer() { return mContainer; }
   gfxPattern::GraphicsFilter GetFilter() { return mFilter; }
-  const gfxIntSize& GetScaleToSize() { return mScaleToSize; }
-  ScaleMode GetScaleMode() { return mScaleMode; }
 
   MOZ_LAYER_DECL_NAME("ImageLayer", TYPE_IMAGE)
 
   virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface);
 
   /**
    * if true, the image will only be backed by a single tile texture
    */
deleted file mode 100644
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ /dev/null
@@ -1,341 +0,0 @@
-/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "LayerTreeInvalidation.h"
-#include "Layers.h"
-#include "ImageLayers.h"
-#include "gfxUtils.h"
-
-namespace mozilla {
-namespace layers {
-
-struct LayerPropertiesBase;
-LayerPropertiesBase* CloneLayerTreePropertiesInternal(Layer* aRoot);
-
-static nsIntRect 
-TransformRect(const nsIntRect& aRect, const gfx3DMatrix& aTransform)
-{
-  if (aRect.IsEmpty()) {
-    return nsIntRect();
-  }
-
-  gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height);
-  rect = aTransform.TransformBounds(rect);
-  rect.RoundOut();
-
-  nsIntRect intRect;
-  if (!gfxUtils::GfxRectToIntRect(rect, &intRect)) {
-    return nsIntRect();
-  }
-
-  return intRect;
-}
-
-/**
- * Walks over this layer, and all descendant layers.
- * If any of these are a ContainerLayer that reports invalidations to a PresShell,
- * then report that the entire bounds have changed.
- */
-static void
-NotifySubdocumentInvalidationRecursive(Layer* aLayer, NotifySubDocInvalidationFunc aCallback)
-{
-  aLayer->ClearInvalidRect();
-  ContainerLayer* container = aLayer->AsContainerLayer();
-
-  if (aLayer->GetMaskLayer()) {
-    NotifySubdocumentInvalidationRecursive(aLayer->GetMaskLayer(), aCallback);
-  }
-
-  if (!container) {
-    return;
-  }
-
-  for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
-    NotifySubdocumentInvalidationRecursive(child, aCallback);
-  }
-
-  aCallback(container, container->GetVisibleRegion());
-}
-
-struct LayerPropertiesBase : public LayerProperties
-{
-  LayerPropertiesBase(Layer* aLayer)
-    : mLayer(aLayer)
-    , mMaskLayer(nullptr)
-    , mVisibleBounds(aLayer->GetVisibleRegion().GetBounds())
-    , mTransform(aLayer->GetTransform())
-    , mOpacity(aLayer->GetOpacity())
-    , mUseClipRect(!!aLayer->GetClipRect())
-  {
-    MOZ_COUNT_CTOR(LayerPropertiesBase);
-    if (aLayer->GetMaskLayer()) {
-      mMaskLayer = CloneLayerTreePropertiesInternal(aLayer->GetMaskLayer());
-    }
-    if (mUseClipRect) {
-      mClipRect = *aLayer->GetClipRect();
-    }
-  }
-  LayerPropertiesBase()
-    : mLayer(nullptr)
-    , mMaskLayer(nullptr)
-  {
-    MOZ_COUNT_CTOR(LayerPropertiesBase);
-  }
-  ~LayerPropertiesBase()
-  {
-    MOZ_COUNT_DTOR(LayerPropertiesBase);
-  }
-  
-  virtual nsIntRect ComputeDifferences(Layer* aRoot, 
-                                       NotifySubDocInvalidationFunc aCallback);
-
-  virtual void MoveBy(const nsIntPoint& aOffset);
-
-  nsIntRect ComputeChange(NotifySubDocInvalidationFunc aCallback)
-  {
-    bool transformChanged = mTransform != mLayer->GetTransform();
-    Layer* otherMask = mLayer->GetMaskLayer();
-    const nsIntRect* otherClip = mLayer->GetClipRect();
-    nsIntRect result;
-    if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask ||
-        (mUseClipRect != !!otherClip) ||
-        mLayer->GetOpacity() != mOpacity ||
-        transformChanged) 
-    {
-      result = OldTransformedBounds();
-      if (transformChanged) {
-        result = result.Union(NewTransformedBounds());
-      }
-
-      // If we don't have to generate invalidations separately for child
-      // layers then we can just stop here since we've already invalidated the entire
-      // old and new bounds.
-      if (!aCallback) {
-        ClearInvalidations(mLayer);
-        return result;
-      }
-    }
-
-    result = result.Union(ComputeChangeInternal(aCallback));
-    result = result.Union(TransformRect(mLayer->GetInvalidRegion().GetBounds(), mTransform));
-
-    if (mMaskLayer && otherMask) {
-      nsIntRect maskDiff = mMaskLayer->ComputeChange(aCallback);
-      result = result.Union(TransformRect(maskDiff, mTransform));
-    }
-
-    if (mUseClipRect && otherClip) {
-      if (!mClipRect.IsEqualInterior(*otherClip)) {
-        nsIntRegion tmp; 
-        tmp.Xor(mClipRect, *otherClip); 
-        result = result.Union(tmp.GetBounds());
-      }
-    }
-
-    mLayer->ClearInvalidRect();
-    return result;
-  }
-
-  nsIntRect NewTransformedBounds()
-  {
-    return TransformRect(mLayer->GetVisibleRegion().GetBounds(), mLayer->GetTransform());
-  }
-
-  nsIntRect OldTransformedBounds()
-  {
-    return TransformRect(mVisibleBounds, mTransform);
-  }
-
-  virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback) { return nsIntRect(); }
-
-  nsRefPtr<Layer> mLayer;
-  nsAutoPtr<LayerPropertiesBase> mMaskLayer;
-  nsIntRect mVisibleBounds;
-  gfx3DMatrix mTransform;
-  float mOpacity;
-  nsIntRect mClipRect;
-  bool mUseClipRect;
-};
-
-struct ContainerLayerProperties : public LayerPropertiesBase
-{
-  ContainerLayerProperties(ContainerLayer* aLayer)
-    : LayerPropertiesBase(aLayer)
-  {
-    for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) {
-      mChildren.AppendElement(CloneLayerTreePropertiesInternal(child));
-    }
-  }
-
-  virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback)
-  {
-    ContainerLayer* container = mLayer->AsContainerLayer();
-    nsIntRegion result;
-
-    uint32_t i = 0;
-    for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
-      if (i >= mChildren.Length() || child != mChildren[i]->mLayer) {
-        // Child change. Invalidate the full areas.
-        // TODO: We could be smarter here if non-overlapping children
-        // swap order.
-        result.Or(result, TransformRect(child->GetVisibleRegion().GetBounds(), child->GetTransform()));
-        if (i < mChildren.Length()) {
-          result.Or(result, mChildren[i]->OldTransformedBounds());
-        }
-        if (aCallback) {
-          NotifySubdocumentInvalidationRecursive(child, aCallback);
-        } else {
-          ClearInvalidations(child);
-        }
-      } else {
-        // Same child, check for differences within the child
-        result.Or(result, mChildren[i]->ComputeChange(aCallback));
-      }
-
-      i++;
-    }
-
-    // Process remaining removed children.
-    while (i < mChildren.Length()) {
-      result.Or(result, mChildren[i]->OldTransformedBounds());
-      i++;
-    }
-
-    if (aCallback) {
-      aCallback(container, result);
-    }
-
-    return TransformRect(result.GetBounds(), mLayer->GetTransform());
-  }
-
-  nsAutoTArray<nsAutoPtr<LayerPropertiesBase>,1> mChildren;
-};
-
-struct ColorLayerProperties : public LayerPropertiesBase
-{
-  ColorLayerProperties(ColorLayer *aLayer)
-    : LayerPropertiesBase(aLayer)
-    , mColor(aLayer->GetColor())
-  { }
-
-  virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback)
-  {
-    ColorLayer* color = static_cast<ColorLayer*>(mLayer.get());
-
-    if (mColor != color->GetColor()) {
-      return NewTransformedBounds();
-    }
-
-    return nsIntRect();
-  }
-
-  gfxRGBA mColor;
-};
-
-struct ImageLayerProperties : public LayerPropertiesBase
-{
-  ImageLayerProperties(ImageLayer* aImage)
-    : LayerPropertiesBase(aImage)
-    , mVisibleRegion(aImage->GetVisibleRegion())
-    , mContainer(aImage->GetContainer())
-    , mFilter(aImage->GetFilter())
-    , mScaleToSize(aImage->GetScaleToSize())
-    , mScaleMode(aImage->GetScaleMode())
-  { }
-
-  virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback)
-  {
-    ImageLayer* image = static_cast<ImageLayer*>(mLayer.get());
-    
-    if (!image->GetVisibleRegion().IsEqual(mVisibleRegion)) {
-      nsIntRect result = NewTransformedBounds();
-      result = result.Union(OldTransformedBounds());
-      return result;
-    }
-
-    if (mContainer != image->GetContainer() ||
-        mFilter != image->GetFilter() ||
-        mScaleToSize != image->GetScaleToSize() ||
-        mScaleMode != image->GetScaleMode()) {
-      return NewTransformedBounds();
-    }
-
-    return nsIntRect();
-  }
-
-  nsIntRegion mVisibleRegion;
-  nsRefPtr<ImageContainer> mContainer;
-  gfxPattern::GraphicsFilter mFilter;
-  gfxIntSize mScaleToSize;
-  ImageLayer::ScaleMode mScaleMode;
-};
-
-LayerPropertiesBase*
-CloneLayerTreePropertiesInternal(Layer* aRoot)
-{
-  if (!aRoot) {
-    return new LayerPropertiesBase();
-  }
-
-  switch (aRoot->GetType()) {
-    case Layer::TYPE_CONTAINER:  return new ContainerLayerProperties(aRoot->AsContainerLayer());
-    case Layer::TYPE_COLOR:  return new ColorLayerProperties(static_cast<ColorLayer*>(aRoot));
-    case Layer::TYPE_IMAGE:  return new ImageLayerProperties(static_cast<ImageLayer*>(aRoot));
-    default: return new LayerPropertiesBase(aRoot);
-  }
-
-  return nullptr;
-}
-
-/* static */ LayerProperties*
-LayerProperties::CloneFrom(Layer* aRoot)
-{
-  return CloneLayerTreePropertiesInternal(aRoot);
-}
-
-/* static */ void 
-LayerProperties::ClearInvalidations(Layer *aLayer)
-{
-  aLayer->ClearInvalidRect();
-  if (aLayer->GetMaskLayer()) {
-    ClearInvalidations(aLayer->GetMaskLayer());
-  }
-
-  ContainerLayer* container = aLayer->AsContainerLayer();
-  if (!container) {
-    return;
-  }
-
-  for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
-    ClearInvalidations(child);
-  }
-}
-
-nsIntRect
-LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFunc aCallback)
-{
-  NS_ASSERTION(aRoot, "Must have a layer tree to compare against!");
-  if (mLayer != aRoot) {
-    if (aCallback) {
-      NotifySubdocumentInvalidationRecursive(aRoot, aCallback);
-    } else {
-      ClearInvalidations(aRoot);
-    }
-    nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(), aRoot->GetTransform());
-    result = result.Union(OldTransformedBounds());
-    return result;
-  } else {
-    return ComputeChange(aCallback);
-  }
-}
-  
-void 
-LayerPropertiesBase::MoveBy(const nsIntPoint& aOffset)
-{
-  mTransform.TranslatePost(gfxPoint3D(aOffset.x, aOffset.y, 0)); 
-}
-
-} // namespace layers
-} // namespace mozilla
deleted file mode 100644
--- a/gfx/layers/LayerTreeInvalidation.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef GFX_LAYER_TREE_INVALIDATION_H
-#define GFX_LAYER_TREE_INVALIDATION_H
-
-#include "nsRegion.h"
-
-class nsPresContext;
-
-namespace mozilla {
-namespace layers {
-
-class Layer;
-class ContainerLayer;
-
-/**
- * Callback for ContainerLayer invalidations.
- *
- * @param aContainer ContainerLayer being invalidated.
- * @param aRegion Invalidated region in the ContainerLayer's coordinate
- * space.
- */
-typedef void (*NotifySubDocInvalidationFunc)(ContainerLayer* aLayer,
-                                             const nsIntRegion& aRegion);
-
-/**
- * A set of cached layer properties (including those of child layers),
- * used for comparing differences in layer trees.
- */
-struct LayerProperties
-{
-  virtual ~LayerProperties() {}
-
-  /**
-   * Copies the current layer tree properties into
-   * a new LayerProperties object.
-   *
-   * @param Layer tree to copy, or nullptr if we have no 
-   * initial layer tree.
-   */
-  static LayerProperties* CloneFrom(Layer* aRoot);
-
-  /**
-   * Clear all invalidation status from this layer tree.
-   */
-  static void ClearInvalidations(Layer* aRoot);
-
-  /**
-   * Compares a set of existing layer tree properties to the current layer
-   * tree and generates the changed rectangle.
-   *
-   * @param aRoot Root layer of the layer tree to compare against.
-   * @param aCallback If specified, callback to call when ContainerLayers
-   * are invalidated.
-   * @return Painted area changed by the layer tree changes.
-   */
-  virtual nsIntRect ComputeDifferences(Layer* aRoot, 
-                                       NotifySubDocInvalidationFunc aCallback) = 0;
-  
-  
-  virtual void MoveBy(const nsIntPoint& aOffset) = 0;
-};
-
-} // namespace layers
-} // namespace mozilla
-
-#endif /* GFX_LAYER_TREE_INVALIDATON_H */
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -82,16 +82,30 @@ class SpecificLayerAttributes;
 /**
  * Base class for userdata objects attached to layers and layer managers.
  */
 class THEBES_API LayerUserData {
 public:
   virtual ~LayerUserData() {}
 };
 
+class LayerManagerLayerBuilder : public LayerUserData {
+public:
+  LayerManagerLayerBuilder(FrameLayerBuilder* aBuilder, bool aDelete = true)
+    : mLayerBuilder(aBuilder)
+    , mDelete(aDelete)
+  {
+    MOZ_COUNT_CTOR(LayerManagerLayerBuilder);
+  }
+  ~LayerManagerLayerBuilder();
+
+  FrameLayerBuilder* mLayerBuilder;
+  bool mDelete;
+};
+
 /*
  * Motivation: For truly smooth animation and video playback, we need to
  * be able to compose frames and render them on a dedicated thread (i.e.
  * off the main thread where DOM manipulation, script execution and layout
  * induce difficult-to-bound latency). This requires Gecko to construct
  * some kind of persistent scene structure (graph or tree) that can be
  * safely transmitted across threads. We have other scenarios (e.g. mobile 
  * browsing) where retaining some rendered data between paints is desired
@@ -194,17 +208,18 @@ public:
 
   enum EndTransactionFlags {
     END_DEFAULT = 0,
     END_NO_IMMEDIATE_REDRAW = 1 << 0,  // Do not perform the drawing phase
     END_NO_COMPOSITE = 1 << 1 // Do not composite after drawing thebes layer contents.
   };
 
   FrameLayerBuilder* GetLayerBuilder() {
-    return reinterpret_cast<FrameLayerBuilder*>(GetUserData(&gLayerManagerLayerBuilder));
+    LayerManagerLayerBuilder *data = static_cast<LayerManagerLayerBuilder*>(GetUserData(&gLayerManagerLayerBuilder));
+    return data ? data->mLayerBuilder : nullptr;
   }
 
   /**
    * Attempts to end an "empty transaction". There must have been no
    * changes to the layer tree since the BeginTransaction().
    * It's possible for this to fail; ThebesLayers may need to be updated
    * due to VRAM data being lost, for example. In such cases this method
    * returns false, and the caller must proceed with a normal layer tree
@@ -952,39 +967,16 @@ public:
   /**
    * Log information about just this layer manager itself to the NSPR
    * log (if enabled for "Layers").
    */
   void LogSelf(const char* aPrefix="");
 
   static bool IsLogEnabled() { return LayerManager::IsLogEnabled(); }
 
-  /**
-   * Returns the current area of the layer (in layer-space coordinates)
-   * marked as needed to be recomposited.
-   */
-  const nsIntRegion& GetInvalidRegion() { return mInvalidRegion; }
-
-  /**
-   * Mark the entirety of the layer's visible region as being invalid.
-   */
-  void SetInvalidRectToVisibleRegion() { mInvalidRegion = GetVisibleRegion(); }
-
-  /**
-   * Adds to the current invalid rect.
-   */
-  void AddInvalidRect(const nsIntRect& aRect) { mInvalidRegion.Or(mInvalidRegion, aRect); }
-
-  /**
-   * Clear the invalid rect, marking the layer as being identical to what is currently
-   * composited.
-   */
-  void ClearInvalidRect() { mInvalidRegion.SetEmpty(); }
-
-
 #ifdef DEBUG
   void SetDebugColorIndex(uint32_t aIndex) { mDebugColorIndex = aIndex; }
   uint32_t GetDebugColorIndex() { return mDebugColorIndex; }
 #endif
 
 protected:
   Layer(LayerManager* aManager, void* aImplData);
 
@@ -1036,17 +1028,16 @@ protected:
   float mPostXScale;
   float mPostYScale;
   gfx3DMatrix mEffectiveTransform;
   AnimationArray mAnimations;
   InfallibleTArray<AnimData> mAnimationData;
   float mOpacity;
   nsIntRect mClipRect;
   nsIntRect mTileSourceRect;
-  nsIntRegion mInvalidRegion;
   uint32_t mContentFlags;
   bool mUseClipRect;
   bool mUseTileSourceRect;
   bool mIsFixedPosition;
   gfxPoint mAnchor;
   DebugOnly<uint32_t> mDebugColorIndex;
 };
 
@@ -1382,17 +1373,17 @@ public:
    * This must only be called once.
    */
   virtual void Initialize(const Data& aData) = 0;
 
   /**
    * Notify this CanvasLayer that the canvas surface contents have
    * changed (or will change) before the next transaction.
    */
-  void Updated() { mDirty = true; SetInvalidRectToVisibleRegion(); }
+  void Updated() { mDirty = true; }
 
   /**
    * Register a callback to be called at the end of each transaction.
    */
   typedef void (* DidTransactionCallback)(void* aClosureData);
   void SetDidTransactionCallback(DidTransactionCallback aCallback, void* aClosureData)
   {
     mCallback = aCallback;
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -39,17 +39,16 @@ EXPORTS = \
         ImageLayers.h \
         ImageTypes.h \
         Layers.h \
         LayersTypes.h \
         LayerManagerOGLShaders.h \
         LayerManagerOGL.h \
         LayerManagerOGLProgram.h \
         LayerSorter.h \
-        LayerTreeInvalidation.h \
         ReadbackLayer.h \
         ShadowLayersManager.h \
         SharedTextureImage.h \
         TexturePoolOGL.h \
         $(NULL)
 
 CPPSRCS = \
         BasicImages.cpp \
@@ -72,17 +71,16 @@ CPPSRCS = \
         ContainerLayerOGL.cpp \
         ImageLayerOGL.cpp \
         LayerManagerOGL.cpp \
         ThebesLayerOGL.cpp \
         TiledThebesLayerOGL.cpp \
         ReusableTileStoreOGL.cpp \
         LayerManagerOGLProgram.cpp \
         LayerSorter.cpp \
-        LayerTreeInvalidation.cpp \
         ImageLayers.cpp \
         TexturePoolOGL.cpp \
         $(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 ifdef MOZ_ENABLE_D3D9_LAYER
 EXPORTS += \
         LayerManagerD3D9.h \
--- a/gfx/layers/basic/BasicThebesLayer.h
+++ b/gfx/layers/basic/BasicThebesLayer.h
@@ -32,19 +32,17 @@ public:
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     ThebesLayer::SetVisibleRegion(aRegion);
   }
   virtual void InvalidateRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
-    mInvalidRegion.Or(mInvalidRegion, aRegion);
-    mInvalidRegion.SimplifyOutward(10);
-    mValidRegion.Sub(mValidRegion, mInvalidRegion);
+    mValidRegion.Sub(mValidRegion, aRegion);
   }
 
   virtual void PaintThebes(gfxContext* aContext,
                            Layer* aMaskLayer,
                            LayerManager::DrawThebesLayerCallback aCallback,
                            void* aCallbackData,
                            ReadbackProcessor* aReadback);
 
--- a/gfx/layers/basic/BasicTiledThebesLayer.h
+++ b/gfx/layers/basic/BasicTiledThebesLayer.h
@@ -170,17 +170,16 @@ public:
   {
     MOZ_COUNT_DTOR(BasicTiledThebesLayer);
   }
 
 
   // Thebes Layer
   virtual Layer* AsLayer() { return this; }
   virtual void InvalidateRegion(const nsIntRegion& aRegion) {
-    mInvalidRegion.Or(mInvalidRegion, aRegion);
     mValidRegion.Sub(mValidRegion, aRegion);
   }
 
   // Shadow methods
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs);
   virtual ShadowableLayer* AsShadowableLayer() { return this; }
 
   virtual void Disconnect()
--- a/gfx/layers/d3d10/ThebesLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ThebesLayerD3D10.cpp
@@ -40,19 +40,17 @@ ThebesLayerD3D10::ThebesLayerD3D10(Layer
 
 ThebesLayerD3D10::~ThebesLayerD3D10()
 {
 }
 
 void
 ThebesLayerD3D10::InvalidateRegion(const nsIntRegion &aRegion)
 {
-  mInvalidRegion.Or(mInvalidRegion, aRegion);
-  mInvalidRegion.SimplifyOutward(10);
-  mValidRegion.Sub(mValidRegion, mInvalidRegion);
+  mValidRegion.Sub(mValidRegion, aRegion);
 }
 
 void ThebesLayerD3D10::CopyRegion(ID3D10Texture2D* aSrc, const nsIntPoint &aSrcOffset,
                                   ID3D10Texture2D* aDest, const nsIntPoint &aDestOffset,
                                   const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion)
 {
   nsIntRegion retainedRegion;
   nsIntRegionRectIterator iter(aCopyRegion);
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -44,19 +44,17 @@ ThebesLayerD3D9::~ThebesLayerD3D9()
  * layer content retention. This is a guesstimate. Profiling could be done to
  * figure out the optimal threshold.
  */
 #define RETENTION_THRESHOLD 16384
 
 void
 ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
 {
-  mInvalidRegion.Or(mInvalidRegion, aRegion);
-  mInvalidRegion.SimplifyOutward(10);
-  mValidRegion.Sub(mValidRegion, mInvalidRegion);
+  mValidRegion.Sub(mValidRegion, aRegion);
 }
 
 void
 ThebesLayerD3D9::CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffset,
                             IDirect3DTexture9* aDest, const nsIntPoint &aDestOffset,
                             const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion)
 {
   nsRefPtr<IDirect3DSurface9> srcSurface, dstSurface;
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -784,19 +784,17 @@ ThebesLayerOGL::SetVisibleRegion(const n
   if (aRegion.IsEqual(mVisibleRegion))
     return;
   ThebesLayer::SetVisibleRegion(aRegion);
 }
 
 void
 ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
 {
-  mInvalidRegion.Or(mInvalidRegion, aRegion);
-  mInvalidRegion.SimplifyOutward(10);
-  mValidRegion.Sub(mValidRegion, mInvalidRegion);
+  mValidRegion.Sub(mValidRegion, aRegion);
 }
 
 void
 ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                             const nsIntPoint& aOffset)
 {
   if (!mBuffer && !CreateSurface()) {
     return;
--- a/gfx/thebes/gfx3DMatrix.cpp
+++ b/gfx/thebes/gfx3DMatrix.cpp
@@ -110,23 +110,16 @@ gfx3DMatrix::operator==(const gfx3DMatri
 {
   // XXX would be nice to memcmp here, but that breaks IEEE 754 semantics
   return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 &&
          _21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 &&
          _31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 &&
          _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44;
 }
 
-bool
-gfx3DMatrix::operator!=(const gfx3DMatrix& o) const
-{
-  return !((*this) == o);
-}
-
-
 gfx3DMatrix&
 gfx3DMatrix::operator/=(const gfxFloat scalar)
 {
   _11 /= scalar;
   _12 /= scalar;
   _13 /= scalar;
   _14 /= scalar;
   _21 /= scalar;
--- a/gfx/thebes/gfx3DMatrix.h
+++ b/gfx/thebes/gfx3DMatrix.h
@@ -51,17 +51,16 @@ public:
       NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
       return *reinterpret_cast<const gfxPointH3D*>((&_11)+4*aIndex);
   }
 
   /**
    * Return true if this matrix and |aMatrix| are the same matrix.
    */
   bool operator==(const gfx3DMatrix& aMatrix) const;
-  bool operator!=(const gfx3DMatrix& aMatrix) const;
   
   /**
    * Divide all values in the matrix by a scalar value
    */
   gfx3DMatrix& operator/=(gfxFloat scalar);
 
   /**
    * Create a 3D matrix from a gfxMatrix 2D affine transformation.
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -166,18 +166,17 @@ RasterImage::RasterImage(imgStatusTracke
   mDecodeOnDraw(false),
   mMultipart(false),
   mDiscardable(false),
   mHasSourceData(false),
   mDecoded(false),
   mHasBeenDecoded(false),
   mInDecoder(false),
   mAnimationFinished(false),
-  mFinishing(false),
-  mInUpdateImageContainer(false)
+  mFinishing(false)
 {
   // Set up the discard tracker node.
   mDiscardTrackerNode.img = this;
   Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
 
   // Statistics
   num_containers++;
 
@@ -288,16 +287,17 @@ RasterImage::AdvanceFrame(TimeStamp aTim
 {
   NS_ASSERTION(aTime <= TimeStamp::Now(),
                "Given time appears to be in the future");
 
   imgFrame* nextFrame = nullptr;
   uint32_t currentFrameIndex = mAnim->currentAnimationFrameIndex;
   uint32_t nextFrameIndex = mAnim->currentAnimationFrameIndex + 1;
   uint32_t timeout = 0;
+  mImageContainer = nullptr;
 
   // Figure out if we have the next full frame. This is more complicated than
   // just checking for mFrames.Length() because decoders append their frames
   // before they're filled in.
   NS_ABORT_IF_FALSE(mDecoder || nextFrameIndex <= mFrames.Length(),
                     "How did we get 2 indices too far by incrementing?");
 
   // If we don't have a decoder, we know we've got everything we're going to
@@ -434,17 +434,16 @@ RasterImage::RequestRefresh(const mozill
 
     // Notify listeners that our frame has actually changed, but do this only
     // once for all frames that we've now passed (if AdvanceFrame() was called
     // more than once).
     #ifdef DEBUG
       mFramesNotified++;
     #endif
 
-    UpdateImageContainer();
     observer->FrameChanged(nullptr, this, &dirtyRect);
   }
 }
 
 //******************************************************************************
 /* [noscript] imgIContainer extractFrame(uint32_t aWhichFrame,
  *                                       [const] in nsIntRect aRegion,
  *                                       in uint32_t aFlags); */
@@ -858,78 +857,51 @@ RasterImage::GetFrame(uint32_t aWhichFra
     framesurf = imgsurf;
   }
 
   *_retval = framesurf.forget().get();
 
   return rv;
 }
 
-already_AddRefed<layers::Image>
-RasterImage::GetCurrentImage()
-{
-  nsRefPtr<gfxASurface> imageSurface;
-  nsresult rv = GetFrame(FRAME_CURRENT, FLAG_SYNC_DECODE, getter_AddRefs(imageSurface));
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  CairoImage::Data cairoData;
-  cairoData.mSurface = imageSurface;
-  GetWidth(&cairoData.mSize.width);
-  GetHeight(&cairoData.mSize.height);
-
-  ImageFormat cairoFormat = CAIRO_SURFACE;
-  nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&cairoFormat, 1);
-  NS_ASSERTION(image, "Failed to create Image");
-  
-  NS_ASSERTION(image->GetFormat() == cairoFormat, "Wrong format");
-  static_cast<CairoImage*>(image.get())->SetData(cairoData);
-
-  return image.forget();
-}
-
 
 NS_IMETHODIMP
 RasterImage::GetImageContainer(ImageContainer **_retval)
 {
   if (mImageContainer) {
     *_retval = mImageContainer;
     NS_ADDREF(*_retval);
     return NS_OK;
   }
   
+  CairoImage::Data cairoData;
+  nsRefPtr<gfxASurface> imageSurface;
+  nsresult rv = GetFrame(FRAME_CURRENT, FLAG_SYNC_DECODE, getter_AddRefs(imageSurface));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  cairoData.mSurface = imageSurface;
+  GetWidth(&cairoData.mSize.width);
+  GetHeight(&cairoData.mSize.height);
+
   mImageContainer = LayerManager::CreateImageContainer();
   
-  nsRefPtr<layers::Image> image = GetCurrentImage();
-  if (!image) {
-    return NS_ERROR_FAILURE;
-  }
+  // Now create a CairoImage to display the surface.
+  ImageFormat cairoFormat = CAIRO_SURFACE;
+  nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&cairoFormat, 1);
+  NS_ASSERTION(image, "Failed to create Image");
+
+  NS_ASSERTION(image->GetFormat() == cairoFormat, "Wrong format");
+  static_cast<CairoImage*>(image.get())->SetData(cairoData);
   mImageContainer->SetCurrentImageInTransaction(image);
 
   *_retval = mImageContainer;
   NS_ADDREF(*_retval);
   return NS_OK;
 }
 
-void
-RasterImage::UpdateImageContainer()
-{
-  if (!mImageContainer || IsInUpdateImageContainer()) {
-    return;
-  }
-
-  SetInUpdateImageContainer(true);
-
-  nsRefPtr<layers::Image> image = GetCurrentImage();
-  if (!image) {
-    return;
-  }
-  mImageContainer->SetCurrentImage(image);
-  SetInUpdateImageContainer(false);
-}
-
 size_t
 RasterImage::HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const
 {
   // n == 0 is possible for two reasons. 
   // - This is a zero-length image.
   // - We're on a platform where moz_malloc_size_of always returns 0.
   // In either case the fallback works appropriately.
   size_t n = mSourceData.SizeOfExcludingThis(aMallocSizeOf);
@@ -1208,21 +1180,18 @@ void
 RasterImage::FrameUpdated(uint32_t aFrameNum, nsIntRect &aUpdatedRect)
 {
   NS_ABORT_IF_FALSE(aFrameNum < mFrames.Length(), "Invalid frame index!");
 
   imgFrame *frame = GetImgFrameNoDecode(aFrameNum);
   NS_ABORT_IF_FALSE(frame, "Calling FrameUpdated on frame that doesn't exist!");
 
   frame->ImageUpdated(aUpdatedRect);
-    
-  if (aFrameNum == GetCurrentImgFrameIndex()) {
-    // The image has changed, so we need to invalidate our cached ImageContainer.
-    UpdateImageContainer();
-  }
+  // The image has changed, so we need to invalidate our cached ImageContainer.
+  mImageContainer = NULL;
 }
 
 nsresult
 RasterImage::SetFrameDisposalMethod(uint32_t aFrameNum,
                                     int32_t aDisposalMethod)
 {
   if (mError)
     return NS_ERROR_FAILURE;
@@ -1406,17 +1375,17 @@ RasterImage::ResetAnimation()
 
   mAnimationFinished = false;
 
   if (mAnimating)
     StopAnimation();
 
   mAnim->lastCompositedFrameIndex = -1;
   mAnim->currentAnimationFrameIndex = 0;
-  UpdateImageContainer();
+  mImageContainer = nullptr;
 
   // Note - We probably want to kick off a redecode somewhere around here when
   // we fix bug 500402.
 
   // Update display if we were animating before
   nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
   if (mAnimating && observer)
     observer->FrameChanged(nullptr, this, &(mAnim->firstFrameRefreshArea));
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -122,17 +122,16 @@ class nsIInputStream;
  * because the first two have public setters and the observer we only get
  * in Init().
  */
 
 namespace mozilla {
 namespace layers {
 class LayerManager;
 class ImageContainer;
-class Image;
 }
 namespace image {
 
 class Decoder;
 
 class RasterImage : public Image
                   , public nsIProperties
                   , public nsSupportsWeakReference
@@ -570,22 +569,16 @@ private:
                                   uint32_t **paletteData, uint32_t *paletteLength);
   nsresult InternalAddFrame(uint32_t framenum, int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight,
                             gfxASurface::gfxImageFormat aFormat, uint8_t aPaletteDepth,
                             uint8_t **imageData, uint32_t *imageLength,
                             uint32_t **paletteData, uint32_t *paletteLength);
 
   bool ApplyDecodeFlags(uint32_t aNewFlags);
 
-  already_AddRefed<layers::Image> GetCurrentImage();
-  void UpdateImageContainer();
-
-  void SetInUpdateImageContainer(bool aInUpdate) { mInUpdateImageContainer = aInUpdate; }
-  bool IsInUpdateImageContainer() { return mInUpdateImageContainer; }
-
 private: // data
 
   nsIntSize                  mSize;
 
   // Whether mFrames below were decoded using any special flags.
   // Some flags (e.g. unpremultiplied data) may not be compatible
   // with the browser's needs for displaying the image to the user.
   // As such, we may need to redecode if we're being asked for
@@ -656,18 +649,16 @@ private: // data
 
   // Whether the animation can stop, due to running out
   // of frames, or no more owning request
   bool                       mAnimationFinished:1;
 
   // Whether we're calling Decoder::Finish() from ShutdownDecoder.
   bool                       mFinishing:1;
 
-  bool                       mInUpdateImageContainer:1;
-
   // Decoding
   nsresult WantDecodedFrames();
   nsresult SyncDecode();
   nsresult InitDecoder(bool aDoSizeDecode);
   nsresult WriteToDecoder(const char *aBuffer, uint32_t aCount);
   nsresult DecodeSomeData(uint32_t aMaxBytes);
   bool     IsDecodeFinished();
   TimeStamp mDrawStartTime;
--- a/image/test/mochitest/test_animSVGImage.html
+++ b/image/test/mochitest/test_animSVGImage.html
@@ -50,25 +50,23 @@ function takeReferenceSnapshot() {
   referenceDiv.style.display = "none";
   let blankSnapshot2 = snapshotWindow(window, false);
   ok(compareSnapshots(blankSnapshot, blankSnapshot2, true)[0],
      "reference div should disappear when it becomes display:none");
 }
 
 function myOnStopFrame(aRequest, aFrame) {
   gOnStopFrameCounter++;
-  ok(true, "myOnStopFrame called");
   let currentSnapshot = snapshotWindow(window, false);
   if (compareSnapshots(currentSnapshot, gReferenceSnapshot, true)[0]) {
     // SUCCESS!
     ok(true, "Animated image looks correct, " +
              "at call #" + gOnStopFrameCounter + " to onStopFrame");
     cleanUpAndFinish();
   }
-  setTimeout(function() { myOnStopFrame(0, 0); }, 1000);
 }
 
 function failTest() {
   ok(false, "timing out after " + FAILURE_TIMEOUT + "ms.  " +
             "Animated image still doesn't look correct, " +
             "after call #" + gOnStopFrameCounter + " to onStopFrame");
   cleanUpAndFinish();
 }
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -9,167 +9,174 @@
 #include "nsPresContext.h"
 #include "nsLayoutUtils.h"
 #include "Layers.h"
 #include "BasicLayers.h"
 #include "nsSubDocumentFrame.h"
 #include "nsCSSRendering.h"
 #include "nsCSSFrameConstructor.h"
 #include "gfxUtils.h"
+#include "nsImageFrame.h"
 #include "nsRenderingContext.h"
 #include "MaskLayerImageCache.h"
 #include "nsIScrollableFrame.h"
-#include "nsPrintfCString.h"
-#include "LayerTreeInvalidation.h"
-#include "nsSVGIntegrationUtils.h"
 
 #include "mozilla/Preferences.h"
 #include "sampler.h"
 
 #include "nsAnimationManager.h"
 #include "nsTransitionManager.h"
 
 #ifdef DEBUG
 #include <stdio.h>
-//#define DEBUG_INVALIDATIONS
 #endif
 
 using namespace mozilla::layers;
 
 namespace mozilla {
 
 FrameLayerBuilder::DisplayItemData::DisplayItemData(Layer* aLayer, uint32_t aKey, LayerState aLayerState, uint32_t aGeneration)
   : mLayer(aLayer)
   , mDisplayItemKey(aKey)
   , mContainerLayerGeneration(aGeneration)
   , mLayerState(aLayerState)
-  , mUsed(false)
 {}
 
-FrameLayerBuilder::DisplayItemData::DisplayItemData(DisplayItemData &toCopy)
-{
-  // This isn't actually a copy-constructor; notice that it steals toCopy's
-  // mGeometry pointer.  Be careful.
-  mLayer = toCopy.mLayer;
-  mInactiveManager = toCopy.mInactiveManager;
-  mFrameList = toCopy.mFrameList;
-  mGeometry = toCopy.mGeometry;
-  mDisplayItemKey = toCopy.mDisplayItemKey;
-  mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
-  mLayerState = toCopy.mLayerState;
-  mUsed = toCopy.mUsed;
-}
-
 FrameLayerBuilder::DisplayItemData::~DisplayItemData()
 {}
 
-bool
-FrameLayerBuilder::DisplayItemData::FrameListMatches(nsDisplayItem* aOther)
-{
-  nsAutoTArray<nsIFrame*, 4> copy = mFrameList;
-  if (!copy.RemoveElement(aOther->GetUnderlyingFrame())) {
-    return false;
-  }
-  
-  nsAutoTArray<nsIFrame*,4> mergedFrames;
-  aOther->GetMergedFrames(&mergedFrames);
-  for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
-    if (!copy.RemoveElement(mergedFrames[i])) {
-      return false;
-    }
-  }
-
-  return copy.IsEmpty();
-}
-
 /**
  * This is the userdata we associate with a layer manager.
  */
 class LayerManagerData : public LayerUserData {
 public:
-  LayerManagerData() :
-    mInvalidateAllLayers(false)
+  LayerManagerData(LayerManager *aManager) :
+    mInvalidateAllLayers(false),
+    mLayerManager(aManager)
   {
     MOZ_COUNT_CTOR(LayerManagerData);
     mFramesWithLayers.Init();
   }
   ~LayerManagerData() {
-    MOZ_COUNT_DTOR(LayerManagerData);
     // Remove display item data properties now, since we won't be able
     // to find these frames again without mFramesWithLayers.
     mFramesWithLayers.EnumerateEntries(
-        FrameLayerBuilder::RemoveDisplayItemDataForFrame, this);
+        FrameLayerBuilder::RemoveDisplayItemDataForFrame, nullptr);
+    MOZ_COUNT_DTOR(LayerManagerData);
   }
 
   /**
    * Tracks which frames have layers associated with them.
    */
   nsTHashtable<FrameLayerBuilder::DisplayItemDataEntry> mFramesWithLayers;
   bool mInvalidateAllLayers;
+  /** Layer manager we belong to, we hold a reference to this object. */
+  nsRefPtr<LayerManager> mLayerManager;
 };
 
-/* static */ void
-FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame)
+LayerManagerLayerBuilder::~LayerManagerLayerBuilder()
 {
-  FrameProperties props = aFrame->Properties();
-  props.Delete(LayerManagerDataProperty());
-  props.Delete(LayerManagerSecondaryDataProperty());
+  MOZ_COUNT_DTOR(LayerManagerLayerBuilder);
+  if (mDelete) {
+    delete mLayerBuilder;
+  }
 }
 
 namespace {
 
 // a global cache of image containers used for mask layers
 static MaskLayerImageCache* gMaskLayerImageCache = nullptr;
 
 static inline MaskLayerImageCache* GetMaskLayerImageCache()
 {
   if (!gMaskLayerImageCache) {
     gMaskLayerImageCache = new MaskLayerImageCache();
   }
 
   return gMaskLayerImageCache;
 }
 
+static void DestroyRefCountedRegion(void* aPropertyValue)
+{
+  static_cast<RefCountedRegion*>(aPropertyValue)->Release();
+}
+
+/**
+ * This property represents a region that should be invalidated in every
+ * ThebesLayer child whose parent ContainerLayer is associated with the
+ * frame. This is an nsRegion*; the coordinates of the region are
+ * relative to the top-left of the border-box of the frame the property
+ * is attached to (which is the frame for the ContainerLayer).
+ * 
+ * We add to this region in InvalidateThebesLayerContents. The region
+ * is propagated to ContainerState in BuildContainerLayerFor, and then
+ * the region(s) are actually invalidated in CreateOrRecycleThebesLayer.
+ *
+ * When the property value is null, the region is infinite --- i.e. all
+ * areas of the ThebesLayers should be invalidated.
+ */
+NS_DECLARE_FRAME_PROPERTY(ThebesLayerInvalidRegionProperty, DestroyRefCountedRegion)
+
+static void DestroyPoint(void* aPropertyValue)
+{
+  delete static_cast<nsPoint*>(aPropertyValue);
+}
+
+/**
+ * The valid content in our child ThebesLayers is defined relative to
+ * the offset from this frame to its active scroll root, mapped back
+ * by the ThebesLayer's inverse transform.  Since we accumulate the
+ * region invalidated between last-paint and next-paint, and because
+ * the offset of this frame to its active root may change during that
+ * period, we save the offset at last-paint in this property and use
+ * it to invalidate at next-paint.
+ */
+NS_DECLARE_FRAME_PROPERTY(ThebesLayerLastPaintOffsetProperty, DestroyPoint)
+
 /**
  * This is a helper object used to build up the layer children for
  * a ContainerLayer.
  */
 class ContainerState {
 public:
   ContainerState(nsDisplayListBuilder* aBuilder,
                  LayerManager* aManager,
                  FrameLayerBuilder* aLayerBuilder,
                  nsIFrame* aContainerFrame,
-                 nsDisplayItem* aContainerItem,
                  ContainerLayer* aContainerLayer,
                  const FrameLayerBuilder::ContainerParameters& aParameters) :
     mBuilder(aBuilder), mManager(aManager),
     mLayerBuilder(aLayerBuilder),
-    mContainerFrame(aContainerFrame),
-    mContainerLayer(aContainerLayer),
+    mContainerFrame(aContainerFrame), mContainerLayer(aContainerLayer),
     mParameters(aParameters),
-    mNextFreeRecycledThebesLayer(0)
+    mNextFreeRecycledThebesLayer(0), mInvalidateAllThebesContent(false)
   {
     nsPresContext* presContext = aContainerFrame->PresContext();
     mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
-    mContainerReferenceFrame = aContainerItem ? aContainerItem->ReferenceFrame() :
-      mBuilder->FindReferenceFrameFor(mContainerFrame);
     // When AllowResidualTranslation is false, display items will be drawn
     // scaled with a translation by integer pixels, so we know how the snapping
     // will work.
     mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() &&
       !mParameters.AllowResidualTranslation();
     mRecycledMaskImageLayers.Init();
     CollectOldLayers();
   }
 
   enum ProcessDisplayItemsFlags {
     NO_COMPONENT_ALPHA = 0x01,
   };
 
+  void AddInvalidThebesContent(const nsIntRegion& aRegion)
+  {
+    mInvalidThebesContent.Or(mInvalidThebesContent, aRegion);
+  }
+  void SetInvalidateAllThebesContent()
+  {
+    mInvalidateAllThebesContent = true;
+  }
   /**
    * This is the method that actually walks a display list and builds
    * the child layers. We invoke it recursively to process clipped sublists.
    * @param aClipRect the clip rect to apply to the list items, or null
    * if no clipping is required
    */
   void ProcessDisplayItems(const nsDisplayList& aList,
                            FrameLayerBuilder::Clip& aClip,
@@ -177,17 +184,17 @@ public:
   /**
    * This finalizes all the open ThebesLayers by popping every element off
    * mThebesLayerDataStack, then sets the children of the container layer
    * to be all the layers in mNewChildLayers in that order and removes any
    * layers as children of the container that aren't in mNewChildLayers.
    * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA,
    * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA
    */
-  void Finish(uint32_t *aTextContentFlags, LayerManagerData* aData);
+  void Finish(uint32_t *aTextContentFlags);
 
   nsRect GetChildrenBounds() { return mBounds; }
 
   nscoord GetAppUnitsPerDevPixel() { return mAppUnitsPerDevPixel; }
 
   nsIntRect ScaleToNearestPixels(const nsRect& aRect)
   {
     return aRect.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
@@ -219,16 +226,18 @@ public:
   {
     if (aSnap && mSnappingEnabled) {
       return ScaleRegionToNearestPixels(aRegion);
     }
     return aRegion.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale,
                                         mAppUnitsPerDevPixel);
   }
 
+  const FrameLayerBuilder::ContainerParameters& ScaleParameters() { return mParameters; };
+
 protected:
   /**
    * We keep a stack of these to represent the ThebesLayers that are
    * currently available to have display items added to.
    * We use a stack here because as much as possible we want to
    * assign display items to existing ThebesLayers, and to the lowest
    * ThebesLayer in z-order. This reduces the number of layers and
    * makes it more likely a display item will be rendered to an opaque
@@ -305,17 +314,17 @@ protected:
      * Same coordinate system as mVisibleRegion.
      */
     nsIntRegion  mOpaqueRegion;
     /**
      * The "active scrolled root" for all content in the layer. Must
      * be non-null; all content in a ThebesLayer must have the same
      * active scrolled root.
      */
-    const nsIFrame* mActiveScrolledRoot;
+    const nsIFrame*    mActiveScrolledRoot;
     ThebesLayer* mLayer;
     /**
      * If mIsSolidColorInVisibleRegion is true, this is the color of the visible
      * region.
      */
     nscolor      mSolidColor;
     /**
      * True if every pixel in mVisibleRegion will have color mSolidColor.
@@ -333,17 +342,17 @@ protected:
      * part of its surface.
      */
     bool mForceTransparentSurface;
 
     /**
      * Stores the pointer to the nsDisplayImage if we want to
      * convert this to an ImageLayer.
      */
-    nsDisplayImageContainer* mImage;
+    nsDisplayImage* mImage;
     /**
      * Stores the clip that we need to apply to the image or, if there is no
      * image, a clip for SOME item in the layer. There is no guarantee which
      * item's clip will be stored here and mItemClip should not be used to clip
      * the whole layer - only some part of the clip should be used, as determined
      * by ThebesDisplayItemLayerUserData::GetCommonClipCount() - which may even be
      * no part at all.
      */
@@ -366,19 +375,17 @@ protected:
   friend class ThebesLayerData;
 
   /**
    * Grab the next recyclable ThebesLayer, or create one if there are no
    * more recyclable ThebesLayers. Does any necessary invalidation of
    * a recycled ThebesLayer, and sets up the transform on the ThebesLayer
    * to account for scrolling.
    */
-  already_AddRefed<ThebesLayer> CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot, 
-                                                           const nsIFrame *aReferenceFrame, 
-                                                           const nsPoint& aTopLeft);
+  already_AddRefed<ThebesLayer> CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot, const nsIFrame *aReferenceFrame);
   /**
    * Grab the next recyclable ColorLayer, or create one if there are no
    * more recyclable ColorLayers.
    */
   already_AddRefed<ColorLayer> CreateOrRecycleColorLayer(ThebesLayer* aThebes);
   /**
    * Grab the next recyclable ImageLayer, or create one if there are no
    * more recyclable ImageLayers.
@@ -395,20 +402,17 @@ protected:
    * available for recycling.
    */
   void CollectOldLayers();
   /**
    * If aItem used to belong to a ThebesLayer, invalidates the area of
    * aItem in that layer. If aNewLayer is a ThebesLayer, invalidates the area of
    * aItem in that layer.
    */
-  void InvalidateForLayerChange(nsDisplayItem* aItem, 
-                                Layer* aNewLayer,
-                                const FrameLayerBuilder::Clip& aClip,
-                                const nsPoint& aTopLeft);
+  void InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer);
   /**
    * Try to determine whether the ThebesLayer at aThebesLayerIndex
    * has a single opaque color behind it, over the entire bounds of its visible
    * region.
    * If successful, return that color, otherwise return NS_RGBA(0,0,0,0).
    */
   nscolor FindOpaqueBackgroundColorFor(int32_t aThebesLayerIndex);
   /**
@@ -433,18 +437,17 @@ protected:
    * @param aOpaqueRect if non-null, a region of the display item that is opaque
    * @param aSolidColor if non-null, indicates that every pixel in aVisibleRect
    * will be painted with aSolidColor by the item
    */
   ThebesLayerData* FindThebesLayerFor(nsDisplayItem* aItem,
                                                    const nsIntRect& aVisibleRect,
                                                    const nsIntRect& aDrawRect,
                                                    const FrameLayerBuilder::Clip& aClip,
-                                                   const nsIFrame* aActiveScrolledRoot,
-                                                   const nsPoint& aTopLeft);
+                                                   const nsIFrame* aActiveScrolledRoot);
   ThebesLayerData* GetTopThebesLayerData()
   {
     return mThebesLayerDataStack.IsEmpty() ? nullptr
         : mThebesLayerDataStack[mThebesLayerDataStack.Length() - 1].get();
   }
 
   /* Build a mask layer to represent the clipping region. Will return null if
    * there is no clipping specified or a mask layer cannot be built.
@@ -457,17 +460,16 @@ protected:
    */
   void SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aClip,
                       uint32_t aRoundedRectClipCount = PR_UINT32_MAX);
 
   nsDisplayListBuilder*            mBuilder;
   LayerManager*                    mManager;
   FrameLayerBuilder*               mLayerBuilder;
   nsIFrame*                        mContainerFrame;
-  const nsIFrame*                  mContainerReferenceFrame;
   ContainerLayer*                  mContainerLayer;
   FrameLayerBuilder::ContainerParameters mParameters;
   /**
    * The region of ThebesLayers that should be invalidated every time
    * we recycle one.
    */
   nsIntRegion                      mInvalidThebesContent;
   nsRect                           mBounds;
@@ -479,27 +481,27 @@ protected:
    */
   typedef nsAutoTArray<nsRefPtr<Layer>,1> AutoLayersArray;
   AutoLayersArray                  mNewChildLayers;
   nsTArray<nsRefPtr<ThebesLayer> > mRecycledThebesLayers;
   nsDataHashtable<nsPtrHashKey<Layer>, nsRefPtr<ImageLayer> >
     mRecycledMaskImageLayers;
   uint32_t                         mNextFreeRecycledThebesLayer;
   nscoord                          mAppUnitsPerDevPixel;
+  bool                             mInvalidateAllThebesContent;
   bool                             mSnappingEnabled;
 };
 
 class ThebesDisplayItemLayerUserData : public LayerUserData
 {
 public:
   ThebesDisplayItemLayerUserData() :
     mMaskClipCount(0),
     mForcedBackgroundColor(NS_RGBA(0,0,0,0)),
     mXScale(1.f), mYScale(1.f),
-    mAppUnitsPerDevPixel(0),
     mTranslation(0, 0),
     mActiveScrolledRootPosition(0, 0) {}
 
   /**
    * Record the number of clips in the Thebes layer's mask layer.
    * Should not be reset when the layer is recycled since it is used to track
    * changes in the use of mask layers.
    */
@@ -512,21 +514,16 @@ public:
   nscolor mForcedBackgroundColor;
 
   /**
    * The resolution scale used.
    */
   float mXScale, mYScale;
 
   /**
-   * The appunits per dev pixel for the items in this layer.
-   */
-  nscoord mAppUnitsPerDevPixel;
-
-  /**
    * The offset from the ThebesLayer's 0,0 to the
    * reference frame. This isn't necessarily the same as the transform
    * set on the ThebesLayer since we might also be applying an extra
    * offset specified by the parent ContainerLayer/
    */
   nsIntPoint mTranslation;
 
   /**
@@ -536,24 +533,16 @@ public:
    * we force the ThebesLayer transform to be an integer translation, and we may
    * have a resolution scale, so we have to snap the ThebesLayer transform, so
    * 0,0 may not be exactly the top-left of the active scrolled root. Here we
    * store the coordinates in ThebesLayer space of the top-left of the
    * active scrolled root.
    */
   gfxPoint mActiveScrolledRootPosition;
 
-  nsIntRegion mRegionToInvalidate;
-
-  // The offset between the active scrolled root of this layer
-  // and the root of the container for the previous and current 
-  // paints respectively.
-  nsPoint mLastActiveScrolledRootOrigin;
-  nsPoint mActiveScrolledRootOrigin;
-
   nsRefPtr<ColorLayer> mColorLayer;
   nsRefPtr<ImageLayer> mImageLayer;
 };
 
 /*
  * User data for layers which will be used as masks.
  */
 struct MaskLayerUserData : public LayerUserData
@@ -639,97 +628,43 @@ MaskLayerUserData* GetMaskLayerUserData(
 ThebesDisplayItemLayerUserData* GetThebesDisplayItemLayerUserData(Layer* aLayer)
 {
   return static_cast<ThebesDisplayItemLayerUserData*>(
     aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
 }
 
 } // anonymous namespace
 
-uint8_t gLayerManagerSecondary;
-
-bool FrameLayerBuilder::sWidgetManagerSecondary = nullptr;
-
-/* static */ const FramePropertyDescriptor* 
-FrameLayerBuilder::GetDescriptorForManager(LayerManager* aManager)
-{
-  bool secondary = sWidgetManagerSecondary;
-  if (aManager) {
-    secondary = !!static_cast<LayerManagerSecondary*>(aManager->GetUserData(&gLayerManagerSecondary));
-  }
-
-  return secondary ? LayerManagerSecondaryDataProperty() : LayerManagerDataProperty();
-}
-
-LayerManagerData*
-FrameLayerBuilder::GetManagerData(nsIFrame* aFrame, LayerManager* aManager)
-{
-  FrameProperties props = aFrame->Properties();
-  return static_cast<LayerManagerData*>(props.Get(GetDescriptorForManager(aManager)));
-}
-
-void
-FrameLayerBuilder::SetManagerData(nsIFrame* aFrame, LayerManagerData* aData)
-{
-  FrameProperties props = aFrame->Properties();
-  const FramePropertyDescriptor* desc = GetDescriptorForManager(nullptr);
-
-  props.Remove(desc);
-  if (aData) {
-    props.Set(desc, aData);
-  }
-}
-
-void
-FrameLayerBuilder::ClearManagerData(nsIFrame* aFrame)
-{
-  SetManagerData(aFrame, nullptr);
-}
-
-void
-FrameLayerBuilder::ClearManagerData(nsIFrame* aFrame, LayerManagerData* aData)
-{
-  NS_ABORT_IF_FALSE(aData, "Must have a widget manager to check for manager data!");
-
-  FrameProperties props = aFrame->Properties();
-  if (aData == static_cast<LayerManagerData*>(props.Get(LayerManagerDataProperty()))) {
-    props.Remove(LayerManagerDataProperty());
-    return;
-  }
-  if (aData == static_cast<LayerManagerData*>(props.Get(LayerManagerSecondaryDataProperty()))) {
-    props.Remove(LayerManagerSecondaryDataProperty());
-    return;
-  }
-}
 /* static */ void
 FrameLayerBuilder::Shutdown()
 {
   if (gMaskLayerImageCache) {
     delete gMaskLayerImageCache;
     gMaskLayerImageCache = nullptr;
   }
 }
 
 void
 FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager)
 {
-  mDisplayListBuilder = aBuilder;
   mRootPresContext = aBuilder->RootReferenceFrame()->PresContext()->GetRootPresContext();
   if (mRootPresContext) {
     mInitialDOMGeneration = mRootPresContext->GetDOMGeneration();
   }
-  aManager->SetUserData(&gLayerManagerLayerBuilder, this);
+  aManager->SetUserData(&gLayerManagerLayerBuilder, new LayerManagerLayerBuilder(this));
 }
 
 bool
 FrameLayerBuilder::DisplayItemDataEntry::HasNonEmptyContainerLayer()
 {
+  if (mIsSharingContainerLayer)
+    return true;
   for (uint32_t i = 0; i < mData.Length(); ++i) {
-    if (mData[i]->mLayer->GetType() == Layer::TYPE_CONTAINER &&
-        mData[i]->mLayerState != LAYER_ACTIVE_EMPTY)
+    if (mData[i].mLayer->GetType() == Layer::TYPE_CONTAINER &&
+        mData[i].mLayerState != LAYER_ACTIVE_EMPTY)
       return true;
   }
   return false;
 }
 
 void
 FrameLayerBuilder::FlashPaint(gfxContext *aContext)
 {
@@ -746,57 +681,329 @@ FrameLayerBuilder::FlashPaint(gfxContext
     float r = float(rand()) / RAND_MAX;
     float g = float(rand()) / RAND_MAX;
     float b = float(rand()) / RAND_MAX;
     aContext->SetColor(gfxRGBA(r, g, b, 0.2));
     aContext->Paint();
   }
 }
 
-nsTArray<nsRefPtr<FrameLayerBuilder::DisplayItemData> >*
+/* static */ nsTArray<FrameLayerBuilder::DisplayItemData>*
 FrameLayerBuilder::GetDisplayItemDataArrayForFrame(nsIFrame* aFrame)
 {
-  LayerManagerData* data = static_cast<LayerManagerData*>
-    (mRetainingManager->GetUserData(&gLayerManagerUserData));
-  if (!data) {
+  FrameProperties props = aFrame->Properties();
+  LayerManagerData *data =
+    reinterpret_cast<LayerManagerData*>(props.Get(LayerManagerDataProperty()));
+  if (!data)
     return nullptr;
-  }
 
   DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame);
+  NS_ASSERTION(entry, "out of sync?");
   if (!entry)
     return nullptr;
 
   return &entry->mData;
 }
 
-nsACString&
-AppendToString(nsACString& s, const nsIntRect& r,
-               const char* pfx="", const char* sfx="")
+/* static */ void
+FrameLayerBuilder::RemoveFrameFromLayerManager(nsIFrame* aFrame,
+                                               void* aPropertyValue)
+{
+  LayerManagerData *data = reinterpret_cast<LayerManagerData*>(aPropertyValue);
+  data->mFramesWithLayers.RemoveEntry(aFrame);
+  if (data->mFramesWithLayers.Count() == 0) {
+    data->mLayerManager->RemoveUserData(&gLayerManagerUserData);
+  }
+}
+
+void
+FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager)
+{
+  mRetainingManager = aManager;
+  LayerManagerData* data = static_cast<LayerManagerData*>
+    (aManager->GetUserData(&gLayerManagerUserData));
+  if (data) {
+    mInvalidateAllLayers = data->mInvalidateAllLayers;
+  }
+}
+
+/**
+ * A helper function to remove the mThebesLayerItems entries and
+ * layer ownership user-data for every layer in aLayer's subtree.
+ */
+void
+FrameLayerBuilder::RemoveThebesItemsAndOwnerDataForLayerSubtree(Layer* aLayer,
+                                                                bool aRemoveThebesItems,
+                                                                bool aRemoveOwnerData)
+{
+  if (aRemoveOwnerData) {
+    // Remove the layer owner flag so that this layer can be recovered by other
+    // frames in future layer tree constructions.
+    aLayer->RemoveUserData(&gLayerOwnerUserData);
+  }
+
+  ThebesLayer* thebes = aLayer->AsThebesLayer();
+  if (thebes) {
+    if (aRemoveThebesItems) {
+      mThebesLayerItems.RemoveEntry(thebes);
+    }
+    return;
+  }
+
+  for (Layer* child = aLayer->GetFirstChild(); child;
+       child = child->GetNextSibling()) {
+    RemoveThebesItemsAndOwnerDataForLayerSubtree(child, aRemoveThebesItems,
+                                                 aRemoveOwnerData);
+  }
+}
+
+void
+FrameLayerBuilder::DidEndTransaction(LayerManager* aManager)
+{
+  Layer* root = aManager->GetRoot();
+  if (root) {
+    RemoveThebesItemsAndOwnerDataForLayerSubtree(root, aManager != mRetainingManager, true);
+  }
+
+  GetMaskLayerImageCache()->Sweep();
+}
+
+void
+FrameLayerBuilder::WillEndTransaction(LayerManager* aManager)
 {
-  s += pfx;
-  s += nsPrintfCString(
-    "(x=%d, y=%d, w=%d, h=%d)",
-    r.x, r.y, r.width, r.height);
-  return s += sfx;
+  if (aManager != mRetainingManager)
+    return;
+
+  // We need to save the data we'll need to support retaining. We do this
+  // before we paint so that invalidation triggered by painting will
+  // be able to update the ThebesLayerInvalidRegionProperty values
+  // correctly and the NS_FRAME_HAS_CONTAINER_LAYER bits will be set
+  // correctly.
+  LayerManagerData* data = static_cast<LayerManagerData*>
+    (mRetainingManager->GetUserData(&gLayerManagerUserData));
+  if (data) {
+    // Update all the frames that used to have layers.
+    data->mFramesWithLayers.EnumerateEntries(UpdateDisplayItemDataForFrame, this);
+  } else {
+    data = new LayerManagerData(mRetainingManager);
+    mRetainingManager->SetUserData(&gLayerManagerUserData, data);
+  }
+  // Now go through all the frames that didn't have any retained
+  // display items before, and record those retained display items.
+  // This also empties mNewDisplayItemData.
+  mNewDisplayItemData.EnumerateEntries(StoreNewDisplayItemData, data);
+  data->mInvalidateAllLayers = false;
+
+  NS_ASSERTION(data->mFramesWithLayers.Count() > 0,
+               "Some frame must have a layer!");
+}
+
+/**
+ * If *aThebesLayerInvalidRegion is non-null, use it as this frame's
+ * region property. Otherwise set it to the frame's region property.
+ */
+static void
+SetHasContainerLayer(nsIFrame* aFrame, nsPoint aOffsetToRoot)
+{
+  aFrame->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER);
+  for (nsIFrame* f = aFrame;
+       f && !(f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
+       f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
+    f->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
+  }
+
+  FrameProperties props = aFrame->Properties();
+  nsPoint* lastPaintOffset = static_cast<nsPoint*>
+    (props.Get(ThebesLayerLastPaintOffsetProperty()));
+  if (lastPaintOffset) {
+    *lastPaintOffset = aOffsetToRoot;
+  } else {
+    props.Set(ThebesLayerLastPaintOffsetProperty(), new nsPoint(aOffsetToRoot));
+  }
+}
+
+static void
+SetNoContainerLayer(nsIFrame* aFrame)
+{
+  FrameProperties props = aFrame->Properties();
+  props.Delete(ThebesLayerInvalidRegionProperty());
+  props.Delete(ThebesLayerLastPaintOffsetProperty());
+  aFrame->RemoveStateBits(NS_FRAME_HAS_CONTAINER_LAYER);
+}
+
+/* static */ void
+FrameLayerBuilder::SetAndClearInvalidRegion(DisplayItemDataEntry* aEntry)
+{
+  if (aEntry->mInvalidRegion) {
+    nsIFrame* f = aEntry->GetKey();
+    FrameProperties props = f->Properties();
+
+    RefCountedRegion* invalidRegion;
+    aEntry->mInvalidRegion.forget(&invalidRegion);
+
+    invalidRegion->mRegion.SetEmpty();
+    invalidRegion->mIsInfinite = false;
+    props.Set(ThebesLayerInvalidRegionProperty(), invalidRegion);
+  }
 }
 
-nsACString&
-AppendToString(nsACString& s, const nsIntRegion& r,
-               const char* pfx="", const char* sfx="")
+/* static */ PLDHashOperator
+FrameLayerBuilder::UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
+                                                 void* aUserArg)
+{
+  FrameLayerBuilder* builder = static_cast<FrameLayerBuilder*>(aUserArg);
+  nsIFrame* f = aEntry->GetKey();
+  FrameProperties props = f->Properties();
+  DisplayItemDataEntry* newDisplayItems =
+    builder ? builder->mNewDisplayItemData.GetEntry(f) : nullptr;
+  if (!newDisplayItems || (newDisplayItems->mData.IsEmpty() &&
+                           !newDisplayItems->mIsSharingContainerLayer)) {
+    // This frame was visible, but isn't anymore.
+    if (newDisplayItems) {
+      builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems);
+    }
+    bool found;
+    props.Remove(LayerManagerDataProperty(), &found);
+    NS_ASSERTION(found, "How can the frame property be missing?");
+    SetNoContainerLayer(f);
+    return PL_DHASH_REMOVE;
+  }
+
+  if (!newDisplayItems->HasNonEmptyContainerLayer()) {
+    SetNoContainerLayer(f);
+  }
+
+  // Steal the list of display item layers and invalid region
+  aEntry->mData.SwapElements(newDisplayItems->mData);
+  aEntry->mInvalidRegion.swap(newDisplayItems->mInvalidRegion);
+  // Clear and reset the invalid region now so we can start collecting new
+  // dirty areas.
+  SetAndClearInvalidRegion(aEntry);
+  // Don't need to process this frame again
+  builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems);
+  return PL_DHASH_NEXT;
+}
+
+/* static */ PLDHashOperator
+FrameLayerBuilder::StoreNewDisplayItemData(DisplayItemDataEntry* aEntry,
+                                           void* aUserArg)
+{
+  LayerManagerData* data = static_cast<LayerManagerData*>(aUserArg);
+  nsIFrame* f = aEntry->GetKey();
+  FrameProperties props = f->Properties();
+
+  // Clear and reset the invalid region now so we can start collecting new
+  // dirty areas.
+  SetAndClearInvalidRegion(aEntry);
+
+  // Remember that this frame has display items in retained layers
+  NS_ASSERTION(!data->mFramesWithLayers.GetEntry(f),
+               "We shouldn't get here if we're already in mFramesWithLayers");
+  DisplayItemDataEntry *newEntry = data->mFramesWithLayers.PutEntry(f);
+  NS_ASSERTION(!props.Get(LayerManagerDataProperty()),
+               "mFramesWithLayers out of sync");
+
+  newEntry->mData.SwapElements(aEntry->mData);
+  props.Set(LayerManagerDataProperty(), data);
+  return PL_DHASH_REMOVE;
+}
+
+bool
+FrameLayerBuilder::HasRetainedLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
 {
-  s += pfx;
-
-  nsIntRegionRectIterator it(r);
-  s += "< ";
-  while (const nsIntRect* sr = it.Next()) {
-    AppendToString(s, *sr) += "; ";
+  nsTArray<DisplayItemData> *array = GetDisplayItemDataArrayForFrame(aFrame);
+  if (!array)
+    return false;
+
+  for (uint32_t i = 0; i < array->Length(); ++i) {
+    if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
+      Layer* layer = array->ElementAt(i).mLayer;
+      if (layer->Manager()->GetUserData(&gLayerManagerUserData)) {
+        // All layer managers with our user data are retained layer managers
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+Layer*
+FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey)
+{
+  // If we need to build a new layer tree, then just refuse to recycle
+  // anything.
+  if (!mRetainingManager || mInvalidateAllLayers)
+    return nullptr;
+
+  nsTArray<DisplayItemData> *array = GetDisplayItemDataArrayForFrame(aFrame);
+  if (!array)
+    return nullptr;
+
+  for (uint32_t i = 0; i < array->Length(); ++i) {
+    if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
+      Layer* layer = array->ElementAt(i).mLayer;
+      if (layer->Manager() == mRetainingManager) {
+        LayerOwnerUserData* layerOwner = static_cast<LayerOwnerUserData*>
+          (layer->GetUserData(&gLayerOwnerUserData));
+        if (!layerOwner || layerOwner->mOwnerFrame == aFrame) {
+          return layer;
+        }
+      }
+    }
   }
-  s += ">";
-
-  return s += sfx;
+  return nullptr;
+}
+
+Layer*
+FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem)
+{
+  uint32_t key = aItem->GetPerFrameKey();
+  nsIFrame* frame = aItem->GetUnderlyingFrame();
+
+  if (frame) {
+    Layer* oldLayer = GetOldLayerForFrame(frame, key);
+    if (oldLayer) {
+      return oldLayer;
+    }
+  }
+
+  nsAutoTArray<nsIFrame*,4> mergedFrames;
+  aItem->GetMergedFrames(&mergedFrames);
+  for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
+    Layer* oldLayer = GetOldLayerForFrame(mergedFrames[i], key);
+    if (oldLayer) {
+      return oldLayer;
+    }
+  }
+
+  return nullptr;
+}
+
+/* static */ Layer*
+FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
+{
+  FrameProperties props = aFrame->Properties();
+  LayerManagerData* data = static_cast<LayerManagerData*>(props.Get(LayerManagerDataProperty()));
+  if (!data) {
+    return nullptr;
+  }
+  DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame);
+  if (!entry)
+    return nullptr;
+
+  nsTArray<DisplayItemData> *array = &entry->mData;
+  if (!array)
+    return nullptr;
+
+  for (uint32_t i = 0; i < array->Length(); ++i) {
+    if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
+      return array->ElementAt(i).mLayer;
+    }
+  }
+  return nullptr;
 }
 
 /**
  * Invalidate aRegion in aLayer. aLayer is in the coordinate system
  * *after* aTranslation has been applied, so we need to
  * apply the inverse of that transform before calling InvalidateRegion.
  */
 static void
@@ -804,460 +1011,16 @@ InvalidatePostTransformRegion(ThebesLaye
                               const nsIntPoint& aTranslation)
 {
   // Convert the region from the coordinates of the container layer
   // (relative to the snapped top-left of the display list reference frame)
   // to the ThebesLayer's own coordinates
   nsIntRegion rgn = aRegion;
   rgn.MoveBy(-aTranslation);
   aLayer->InvalidateRegion(rgn);
-#ifdef DEBUG_INVALIDATIONS
-  nsAutoCString str;
-  AppendToString(str, rgn);
-  printf("Invalidating layer %p: %s\n", aLayer, str.get());
-#endif
-}
-
-static nsIntPoint
-GetTranslationForThebesLayer(ThebesLayer* aLayer)
-{
-  ThebesDisplayItemLayerUserData* data = 
-    static_cast<ThebesDisplayItemLayerUserData*>
-      (aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
-  NS_ASSERTION(data, "Must be a tracked thebes layer!");
-
-  return data->mTranslation;
-}
-
-/**
- * Some frames can have multiple, nested, retaining layer managers
- * associated with them (normal manager, inactive managers, SVG effects).
- * In these cases we store the 'outermost' LayerManager data property
- * on the frame since we can walk down the chain from there.
- *
- * If one of these frames has just been destroyed, we will free the inner
- * layer manager when removing the entry from mFramesWithLayers. Destroying
- * the layer manager destroys the LayerManagerData and calls into 
- * RemoveDisplayItemDataForFrame. If the inner layer manager had any
- * items with the same frame, then we attempt to retrieve properties
- * from the deleted frame.
- *
- * Cache the destroyed frame pointer here so we can avoid crashing in this case.
- */
-static nsIFrame* sDestroyedFrame = NULL;
-
-/* static */ void
-FrameLayerBuilder::RemoveFrameFromLayerManager(nsIFrame* aFrame,
-                                               void* aPropertyValue)
-{
-  LayerManagerData *data = reinterpret_cast<LayerManagerData*>(aPropertyValue);
-
-  DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame);
-  for (uint32_t i = 0; i < entry->mData.Length(); ++i) {
-    ThebesLayer* t = entry->mData[i]->mLayer->AsThebesLayer();
-    if (t) {
-      ThebesDisplayItemLayerUserData* data =
-          static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData));
-      if (data) {
-        nsRegion old = entry->mData[i]->mGeometry->ComputeInvalidationRegion();
-        nsIntRegion rgn = old.ScaleToOutsidePixels(data->mXScale, data->mYScale, data->mAppUnitsPerDevPixel);
-        rgn.MoveBy(-GetTranslationForThebesLayer(t));
-        data->mRegionToInvalidate.Or(data->mRegionToInvalidate, rgn);
-      }
-    }
-  }
-
-  sDestroyedFrame = aFrame;
-  data->mFramesWithLayers.RemoveEntry(aFrame);
-  sDestroyedFrame = NULL;
-}
-
-void
-FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager)
-{
-  mRetainingManager = aManager;
-  LayerManagerData* data = static_cast<LayerManagerData*>
-    (aManager->GetUserData(&gLayerManagerUserData));
-  if (data) {
-    mInvalidateAllLayers = data->mInvalidateAllLayers;
-  } else {
-    data = new LayerManagerData();
-    aManager->SetUserData(&gLayerManagerUserData, data);
-  }
-}
-
-void
-FrameLayerBuilder::StoreOptimizedLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey, Layer* aImage)
-{
-  DisplayItemDataEntry *entry = mNewDisplayItemData.GetEntry(aFrame);
-  if (!entry)
-    return;
-
-  nsTArray<nsRefPtr<DisplayItemData> > *array = &entry->mData;
-  if (!array)
-    return;
-
-  for (uint32_t i = 0; i < array->Length(); ++i) {
-    if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) {
-      array->ElementAt(i)->mOptLayer = aImage;
-      return;
-    }
-  }
-}
-
-void
-FrameLayerBuilder::DidEndTransaction()
-{
-  GetMaskLayerImageCache()->Sweep();
-}
-
-void
-FrameLayerBuilder::WillEndTransaction()
-{
-  if (!mRetainingManager) {
-    return;
-  }
-
-  // We need to save the data we'll need to support retaining.
-  LayerManagerData* data = static_cast<LayerManagerData*>
-    (mRetainingManager->GetUserData(&gLayerManagerUserData));
-  NS_ASSERTION(data, "Must have data!");
-  // Update all the frames that used to have layers.
-  data->mFramesWithLayers.EnumerateEntries(UpdateDisplayItemDataForFrame, this);
-  
-  // Now go through all the frames that didn't have any retained
-  // display items before, and record those retained display items.
-  // This also empties mNewDisplayItemData.
-  mNewDisplayItemData.EnumerateEntries(StoreNewDisplayItemData, data);
-  data->mInvalidateAllLayers = false;
-}
-
-struct ProcessRemovedDisplayItemsData
-{
-  ProcessRemovedDisplayItemsData(Layer* aLayer, FrameLayerBuilder* aLayerBuilder)
-    : mLayer(aLayer)
-    , mLayerBuilder(aLayerBuilder)
-  {}
-
-  Layer *mLayer;
-  FrameLayerBuilder *mLayerBuilder;
-};
-
-/* static */ PLDHashOperator
-FrameLayerBuilder::ProcessRemovedDisplayItems(DisplayItemDataEntry* aEntry,
-                                              void* aUserArg)
-{
-  ProcessRemovedDisplayItemsData *userData =
-    static_cast<ProcessRemovedDisplayItemsData*>(aUserArg);
-  Layer* layer = userData->mLayer;
-  FrameLayerBuilder* layerBuilder = userData->mLayerBuilder;
-  for (uint32_t i = 0; i < aEntry->mData.Length(); ++i) {
-    DisplayItemData* item = aEntry->mData[i];
-    ThebesLayer* t = item->mLayer->AsThebesLayer();
-    if (!item->mUsed && t && item->mLayer == layer) {
-#ifdef DEBUG_INVALIDATIONS
-      printf("Invalidating unused display item (%i) belonging to frame %p from layer %p\n", item->mDisplayItemKey, aEntry->GetKey(), t);
-#endif
-      ThebesDisplayItemLayerUserData* data =
-          static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData));
-      InvalidatePostTransformRegion(t,
-          item->mGeometry->ComputeInvalidationRegion().
-            ScaleToOutsidePixels(data->mXScale, data->mYScale, data->mAppUnitsPerDevPixel),
-          layerBuilder->GetLastPaintOffset(t));
-    }
-  }
-  return PL_DHASH_NEXT;
-}
-
-/* static */ PLDHashOperator
-FrameLayerBuilder::UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
-                                                 void* aUserArg)
-{
-  FrameLayerBuilder* builder = static_cast<FrameLayerBuilder*>(aUserArg);
-  nsIFrame* f = aEntry->GetKey();
-  DisplayItemDataEntry* newDisplayItems =
-    builder ? builder->mNewDisplayItemData.GetEntry(f) : nullptr;
-
-  LayerManagerData* managerData = static_cast<LayerManagerData*>
-    (builder->GetRetainingLayerManager()->GetUserData(&gLayerManagerUserData));
-  LayerManagerData* data = GetManagerData(f);
-  if (!newDisplayItems || newDisplayItems->mData.IsEmpty()) {
-    // This frame was visible, but isn't anymore.
-    if (newDisplayItems) {
-      builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems);
-    }
-    if (data == managerData) {
-      ClearManagerData(f);
-    }
-    return PL_DHASH_REMOVE;
-  }
-
-  SetManagerData(f, managerData);
-
-  // Steal the list of display item layers and invalid region
-  aEntry->mData.SwapElements(newDisplayItems->mData);
-  // Don't need to process this frame again
-  builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems);
-  return PL_DHASH_NEXT;
-}
-  
-/* static */ PLDHashOperator 
-FrameLayerBuilder::RemoveDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
-                                                 void* aClosure)
-{
-  LayerManagerData* managerData = static_cast<LayerManagerData*>(aClosure);
-  nsIFrame* f = aEntry->GetKey();
-  // If this was called from a frame destructor then the prop is definitely already gone,
-  // and we could crash trying to check. See the definition of sDestroyedFrame.
-  if (f != sDestroyedFrame) {
-    ClearManagerData(f, managerData);
-  }
-  return PL_DHASH_REMOVE;
-}
-
-/* static */ PLDHashOperator
-FrameLayerBuilder::StoreNewDisplayItemData(DisplayItemDataEntry* aEntry,
-                                           void* aUserArg)
-{
-  LayerManagerData* data = static_cast<LayerManagerData*>(aUserArg);
-  nsIFrame* f = aEntry->GetKey();
-
-  // Remember that this frame has display items in retained layers
-  NS_ASSERTION(!data->mFramesWithLayers.GetEntry(f),
-               "We shouldn't get here if we're already in mFramesWithLayers");
-  DisplayItemDataEntry *newEntry = data->mFramesWithLayers.PutEntry(f);
-
-  newEntry->mData.SwapElements(aEntry->mData);
-  // Remove any old layer manager data for this frame. We don't destroy it
-  // because we don't want it to call the frame destroyed function.
-  // When a frame has multiple layer managers (main, inactive, svg), we
-  // only need to store the outermost one since that will be enough to
-  // invalidate the entire region covered by all the children.
-  SetManagerData(f, data);
-  return PL_DHASH_REMOVE;
-}
-
-/**
- * Attempts to find the LayerManagerData for the widget manager
- * for the given frame, nullptr otherwise.
- */
-static LayerManagerData*
-GetDefaultLayerManagerDataForFrame(nsIFrame* aFrame)
-{
-  FrameProperties props = aFrame->Properties();
-  return static_cast<LayerManagerData*>(props.Get(FrameLayerBuilder::LayerManagerDataProperty()));
-}
-
-static LayerManagerData*
-GetSecondaryLayerManagerDataForFrame(nsIFrame* aFrame)
-{
-  FrameProperties props = aFrame->Properties();
-  return static_cast<LayerManagerData*>(props.Get(FrameLayerBuilder::LayerManagerSecondaryDataProperty()));
-}
-
-/* static */ FrameLayerBuilder::DisplayItemData*
-FrameLayerBuilder::GetDisplayItemDataForManager(nsIFrame* aFrame,
-                                                uint32_t aDisplayItemKey,
-                                                LayerManagerData* aData)
-{
-  DisplayItemDataEntry *entry = aData->mFramesWithLayers.GetEntry(aFrame);
-  if (!entry) {
-    return nullptr;
-  }
-
-  for (uint32_t i = 0; i < entry->mData.Length(); ++i) {
-    if (entry->mData[i]->mDisplayItemKey == aDisplayItemKey) {
-      return entry->mData[i];
-    }
-  }
-  
-  return nullptr;
-}
-
-/* static */ FrameLayerBuilder::DisplayItemData*
-FrameLayerBuilder::GetDisplayItemDataForManager(nsIFrame* aFrame, 
-                                                uint32_t aDisplayItemKey, 
-                                                LayerManager* aManager)
-{
-  LayerManagerData *data = 
-    static_cast<LayerManagerData*>(aManager->GetUserData(&gLayerManagerUserData));
-  
-  if (!data) {
-    return nullptr;
-  }
-
-  return GetDisplayItemDataForManager(aFrame, aDisplayItemKey, data);
-}
-
-/* static */ FrameLayerBuilder::DisplayItemData*
-FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem, 
-                                                LayerManager* aManager)
-{
-  DisplayItemData* data = 
-    GetDisplayItemDataForManager(aItem->GetUnderlyingFrame(), 
-                                 aItem->GetPerFrameKey(), 
-                                 aManager);
-  if (data) {
-    return data->FrameListMatches(aItem) ? data : nullptr;
-  }
-
-  nsAutoTArray<nsIFrame*,4> mergedFrames;
-  aItem->GetMergedFrames(&mergedFrames);
-  for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
-    data = 
-      GetDisplayItemDataForManager(mergedFrames[i], 
-                                   aItem->GetPerFrameKey(), 
-                                   aManager);
-    if (data) {
-      return data->FrameListMatches(aItem) ? data : nullptr;
-    }
-  }
-  return nullptr;
-}
-
-/* static */ FrameLayerBuilder::DisplayItemData*
-FrameLayerBuilder::GetDisplayItemDataForManager(nsIFrame* aFrame, 
-                                                uint32_t aDisplayItemKey)
-{
-  LayerManagerData *data = GetDefaultLayerManagerDataForFrame(aFrame);
-  
-  if (!data) {
-    return nullptr;
-  }
-  
-  return GetDisplayItemDataForManager(aFrame, aDisplayItemKey, data);
-}
-
-bool
-FrameLayerBuilder::HasRetainedLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey, LayerManager* aManager)
-{
-  DisplayItemData* data = GetDisplayItemDataForManager(aFrame, aDisplayItemKey, aManager);
-  if (data) {
-    Layer* layer = data->mLayer;
-    if (layer->Manager()->GetUserData(&gLayerManagerUserData)) {
-      // All layer managers with our user data are retained layer managers
-      return true;
-    }
-  }
-  return false;
-}
-
-bool
-FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
-{
-  LayerManagerData* data = GetDefaultLayerManagerDataForFrame(aFrame);
-  if (data && GetDisplayItemDataForManager(aFrame, aDisplayItemKey, data)) {
-    return true;
-  }
-  data = GetSecondaryLayerManagerDataForFrame(aFrame);
-  if (data && GetDisplayItemDataForManager(aFrame, aDisplayItemKey, data)) {
-    return true;
-  }
-  return false;
-}
-
-FrameLayerBuilder::DisplayItemData*
-FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey)
-{
-  // If we need to build a new layer tree, then just refuse to recycle
-  // anything.
-  if (!mRetainingManager || mInvalidateAllLayers)
-    return nullptr;
-
-  nsTArray<nsRefPtr<DisplayItemData> > *array = GetDisplayItemDataArrayForFrame(aFrame);
-  if (!array)
-    return nullptr;
-
-  for (uint32_t i = 0; i < array->Length(); ++i) {
-    if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) {
-      Layer* layer = array->ElementAt(i)->mLayer;
-      if (layer->Manager() == mRetainingManager) {
-        return array->ElementAt(i);
-      }
-    }
-  }
-  return nullptr;
-}
-
-Layer*
-FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem, nsDisplayItemGeometry** aOldGeometry, Clip** aOldClip)
-{
-  uint32_t key = aItem->GetPerFrameKey();
-  nsIFrame* frame = aItem->GetUnderlyingFrame();
-
-  if (frame) {
-    DisplayItemData* oldData = GetOldLayerForFrame(frame, key);
-    if (oldData) {
-      if (aOldGeometry) {
-        *aOldGeometry = oldData->mGeometry.get();
-      }
-      if (aOldClip) {
-        *aOldClip = &oldData->mClip;
-      }
-      return oldData->mLayer;
-    }
-  }
-
-  nsAutoTArray<nsIFrame*,4> mergedFrames;
-  aItem->GetMergedFrames(&mergedFrames);
-  for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
-    DisplayItemData* oldData = GetOldLayerForFrame(mergedFrames[i], key);
-    if (oldData) {
-      if (aOldGeometry) {
-        *aOldGeometry = oldData->mGeometry.get();
-      }
-      if (aOldClip) {
-        *aOldClip = &oldData->mClip;
-      }
-      return oldData->mLayer;
-    }
-  }
-
-  return nullptr;
-} 
-
-/* static */ Layer*
-FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
-{
-  LayerManagerData* data = GetManagerData(aFrame);
-  if (!data) {
-    return nullptr;
-  }
-  DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame);
-  if (!entry)
-    return nullptr;
-
-  nsTArray<nsRefPtr<DisplayItemData> > *array = &entry->mData;
-  if (!array)
-    return nullptr;
-
-  for (uint32_t i = 0; i < array->Length(); ++i) {
-    if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) {
-      return array->ElementAt(i)->mLayer;
-    }
-  }
-  return nullptr;
-}
-
-LayerManager*
-FrameLayerBuilder::GetInactiveLayerManagerFor(nsDisplayItem* aItem)
-{
-  nsTArray<nsRefPtr<FrameLayerBuilder::DisplayItemData> > *array = GetDisplayItemDataArrayForFrame(aItem->GetUnderlyingFrame());
-  NS_ASSERTION(array, "We need an array here!. Really, we do.");
-
-  nsRefPtr<LayerManager> tempManager;
-  for (uint32_t i = 0; i < array->Length(); ++i) {
-    if (array->ElementAt(i)->mDisplayItemKey == aItem->GetPerFrameKey()) {
-      NS_ASSERTION(array->ElementAt(i)->mInactiveManager, "Must already have one of these");
-      return array->ElementAt(i)->mInactiveManager;
-      
-    }
-  }
-  NS_ERROR("Failed to find data for display item");
-  return NULL;
 }
 
 already_AddRefed<ColorLayer>
 ContainerState::CreateOrRecycleColorLayer(ThebesLayer *aThebes)
 {
   ThebesDisplayItemLayerUserData* data = 
       static_cast<ThebesDisplayItemLayerUserData*>(aThebes->GetUserData(&gThebesDisplayItemLayerUserData));
   nsRefPtr<ColorLayer> layer = data->mColorLayer;
@@ -1317,16 +1080,27 @@ ContainerState::CreateOrRecycleMaskImage
       return nullptr;
     result->SetUserData(&gMaskLayerUserData, new MaskLayerUserData());
     result->SetForceSingleTile(true);
   }
   
   return result.forget();
 }
 
+static nsIntPoint
+GetTranslationForThebesLayer(ThebesLayer* aLayer)
+{
+  ThebesDisplayItemLayerUserData* data = 
+    static_cast<ThebesDisplayItemLayerUserData*>
+      (aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
+  NS_ASSERTION(data, "Must be a tracked thebes layer!");
+
+  return data->mTranslation;
+}
+
 static const double SUBPIXEL_OFFSET_EPSILON = 0.02;
 
 /**
  * This normally computes NSToIntRoundUp(aValue). However, if that would
  * give a residual near 0.5 while aOldResidual is near -0.5, or
  * it would give a residual near -0.5 while aOldResidual is near 0.5, then
  * instead we return the integer in the other direction so that the residual
  * is close to aOldResidual.
@@ -1357,28 +1131,23 @@ ResetScrollPositionForLayerPixelAlignmen
   if (sf) {
     sf->ResetScrollPositionForLayerPixelAlignment();
   }
 }
 
 static void
 InvalidateEntireThebesLayer(ThebesLayer* aLayer, const nsIFrame* aActiveScrolledRoot)
 {
-#ifdef DEBUG_INVALIDATIONS
-  printf("Invalidating entire layer %p\n", aLayer);
-#endif
   nsIntRect invalidate = aLayer->GetValidRegion().GetBounds();
   aLayer->InvalidateRegion(invalidate);
   ResetScrollPositionForLayerPixelAlignment(aActiveScrolledRoot);
 }
 
 already_AddRefed<ThebesLayer>
-ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot,
-                                           const nsIFrame* aReferenceFrame,
-                                           const nsPoint& aTopLeft)
+ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot, const nsIFrame* aReferenceFrame)
 {
   // We need a new thebes layer
   nsRefPtr<ThebesLayer> layer;
   ThebesDisplayItemLayerUserData* data;
   bool didResetScrollPositionForLayerPixelAlignment = false;
   if (mNextFreeRecycledThebesLayer < mRecycledThebesLayers.Length()) {
     // Recycle a layer
     layer = mRecycledThebesLayers[mNextFreeRecycledThebesLayer];
@@ -1395,53 +1164,44 @@ ContainerState::CreateOrRecycleThebesLay
     // This gets called on recycled ThebesLayers that are going to be in the
     // final layer tree, so it's a convenient time to invalidate the
     // content that changed where we don't know what ThebesLayer it belonged
     // to, or if we need to invalidate the entire layer, we can do that.
     // This needs to be done before we update the ThebesLayer to its new
     // transform. See nsGfxScrollFrame::InvalidateInternal, where
     // we ensure that mInvalidThebesContent is updated according to the
     // scroll position as of the most recent paint.
-    if (data->mXScale != mParameters.mXScale ||
+    if (mInvalidateAllThebesContent ||
+        data->mXScale != mParameters.mXScale ||
         data->mYScale != mParameters.mYScale) {
       InvalidateEntireThebesLayer(layer, aActiveScrolledRoot);
       didResetScrollPositionForLayerPixelAlignment = true;
+    } else {
+      nsIntRect bounds = mInvalidThebesContent.GetBounds();
+      if (!bounds.IsEmpty()) {
+        InvalidatePostTransformRegion(layer, mInvalidThebesContent,
+                                      GetTranslationForThebesLayer(layer));
+      }
     }
-    if (!data->mRegionToInvalidate.IsEmpty()) {
-#ifdef DEBUG_INVALIDATIONS
-      printf("Invalidating deleted frame content from layer %p\n", layer.get());
-#endif
-      layer->InvalidateRegion(data->mRegionToInvalidate);
-#ifdef DEBUG_INVALIDATIONS
-      nsAutoCString str;
-      AppendToString(str, data->mRegionToInvalidate);
-      printf("Invalidating layer %p: %s\n", layer.get(), str.get());
-#endif
-      data->mRegionToInvalidate.SetEmpty();
-    }
-
     // We do not need to Invalidate these areas in the widget because we
     // assume the caller of InvalidateThebesLayerContents has ensured
     // the area is invalidated in the widget.
   } else {
     // Create a new thebes layer
     layer = mManager->CreateThebesLayer();
     if (!layer)
       return nullptr;
     // Mark this layer as being used for Thebes-painting display items
     data = new ThebesDisplayItemLayerUserData();
     layer->SetUserData(&gThebesDisplayItemLayerUserData, data);
     ResetScrollPositionForLayerPixelAlignment(aActiveScrolledRoot);
     didResetScrollPositionForLayerPixelAlignment = true;
   }
   data->mXScale = mParameters.mXScale;
   data->mYScale = mParameters.mYScale;
-  data->mLastActiveScrolledRootOrigin = data->mActiveScrolledRootOrigin;
-  data->mActiveScrolledRootOrigin = aTopLeft;
-  data->mAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
   layer->SetAllowResidualTranslation(mParameters.AllowResidualTranslation());
 
   mLayerBuilder->SaveLastPaintOffset(layer);
 
   // Set up transform so that 0,0 in the Thebes layer corresponds to the
   // (pixel-snapped) top-left of the aActiveScrolledRoot.
   nsPoint offset = aActiveScrolledRoot->GetOffsetToCrossDoc(aReferenceFrame);
   nscoord appUnitsPerDevPixel = aActiveScrolledRoot->PresContext()->AppUnitsPerDevPixel();
@@ -1612,19 +1372,16 @@ ContainerState::PopThebesLayerData()
       imageLayer->SetPostScale(mParameters.mXScale,
                                mParameters.mYScale);
       if (data->mItemClip.mHaveClipRect) {
         nsIntRect clip = ScaleToNearestPixels(data->mItemClip.mClipRect);
         clip.MoveBy(mParameters.mOffset);
         imageLayer->IntersectClipRect(clip);
       }
       layer = imageLayer;
-      mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage->GetUnderlyingFrame(), 
-                                                 data->mImage->GetPerFrameKey(),
-                                                 imageLayer);
     } else {
       nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(data->mLayer);
       colorLayer->SetIsFixedPosition(data->mLayer->GetIsFixedPosition());
       colorLayer->SetColor(data->mSolidColor);
 
       // Copy transform
       colorLayer->SetBaseTransform(data->mLayer->GetBaseTransform());
       colorLayer->SetPostScale(data->mLayer->GetPostXScale(), data->mLayer->GetPostYScale());
@@ -1786,20 +1543,18 @@ ContainerState::ThebesLayerData::Accumul
     // Note that the transform (if any) on the ThebesLayer is always an integer translation so
     // we don't have to factor that in here.
     aItem->DisableComponentAlpha();
   }
 
   /* Mark as available for conversion to image layer if this is a nsDisplayImage and
    * we are the first visible item in the ThebesLayerData object.
    */
-  if (mVisibleRegion.IsEmpty() &&
-      (aItem->GetType() == nsDisplayItem::TYPE_IMAGE ||
-       aItem->GetType() == nsDisplayItem::TYPE_XUL_IMAGE)) {
-    mImage = static_cast<nsDisplayImageContainer*>(aItem);
+  if (mVisibleRegion.IsEmpty() && aItem->GetType() == nsDisplayItem::TYPE_IMAGE) {
+    mImage = static_cast<nsDisplayImage*>(aItem);
   } else {
     mImage = nullptr;
   }
   mItemClip = aClip;
 
   if (!mIsSolidColorInVisibleRegion && mOpaqueRegion.Contains(aDrawRect) &&
       mVisibleRegion.Contains(aVisibleRect)) {
     // A very common case! Most pages have a ThebesLayer with the page
@@ -1900,18 +1655,17 @@ ContainerState::ThebesLayerData::Accumul
   }
 }
 
 ContainerState::ThebesLayerData*
 ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
                                    const nsIntRect& aVisibleRect,
                                    const nsIntRect& aDrawRect,
                                    const FrameLayerBuilder::Clip& aClip,
-                                   const nsIFrame* aActiveScrolledRoot,
-                                   const nsPoint& aTopLeft)
+                                   const nsIFrame* aActiveScrolledRoot)
 {
   int32_t i;
   int32_t lowestUsableLayerWithScrolledRoot = -1;
   int32_t topmostLayerWithScrolledRoot = -1;
   for (i = mThebesLayerDataStack.Length() - 1; i >= 0; --i) {
     ThebesLayerData* data = mThebesLayerDataStack[i];
     if (data->mDrawAboveRegion.Intersects(aVisibleRect)) {
       ++i;
@@ -1941,17 +1695,17 @@ ContainerState::FindThebesLayerFor(nsDis
     while (uint32_t(topmostLayerWithScrolledRoot + 1) < mThebesLayerDataStack.Length()) {
       PopThebesLayerData();
     }
   }
 
   nsRefPtr<ThebesLayer> layer;
   ThebesLayerData* thebesLayerData = nullptr;
   if (lowestUsableLayerWithScrolledRoot < 0) {
-    layer = CreateOrRecycleThebesLayer(aActiveScrolledRoot, aItem->ReferenceFrame(), aTopLeft);
+    layer = CreateOrRecycleThebesLayer(aActiveScrolledRoot, aItem->ReferenceFrame());
 
     NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???");
     mNewChildLayers.AppendElement(layer);
 
     thebesLayerData = new ThebesLayerData();
     mThebesLayerDataStack.AppendElement(thebesLayerData);
     thebesLayerData->mLayer = layer;
     thebesLayerData->mActiveScrolledRoot = aActiveScrolledRoot;
@@ -1979,54 +1733,61 @@ DumpPaintedImage(nsDisplayItem* aItem, g
   fprintf(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
   aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
   fprintf(gfxUtils::sDumpPaintFile, "\";");
 }
 #endif
 
 static void
 PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
-                   LayerManager* aManager,
                    nsDisplayItem* aItem,
                    gfxContext* aContext,
-                   nsRenderingContext* aCtx)
+                   nsRenderingContext* aCtx,
+                   FrameLayerBuilder *aLayerBuilder)
 {
   // This item has an inactive layer. Render it to a ThebesLayer
   // using a temporary BasicLayerManager.
-  BasicLayerManager* basic = static_cast<BasicLayerManager*>(aManager);
-  nsRefPtr<gfxContext> context = aContext;
-#ifdef MOZ_DUMP_PAINTING
   int32_t appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
   nsIntRect itemVisibleRect =
     aItem->GetVisibleRect().ToOutsidePixels(appUnitsPerDevPixel);
 
+  nsRefPtr<gfxContext> context = aContext;
+#ifdef MOZ_DUMP_PAINTING
   nsRefPtr<gfxASurface> surf;
   if (gfxUtils::sDumpPainting) {
     surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(itemVisibleRect.Size(),
                                                               gfxASurface::CONTENT_COLOR_ALPHA);
     surf->SetDeviceOffset(-itemVisibleRect.TopLeft());
     context = new gfxContext(surf);
   }
 #endif
-  basic->SetTarget(context);
-
+
+  nsRefPtr<BasicLayerManager> tempManager = new BasicLayerManager();
+  tempManager->SetUserData(&gLayerManagerLayerBuilder, new LayerManagerLayerBuilder(aLayerBuilder, false));
+  tempManager->BeginTransactionWithTarget(context);
+  nsRefPtr<Layer> layer =
+    aItem->BuildLayer(aBuilder, tempManager, FrameLayerBuilder::ContainerParameters());
+  if (!layer) {
+    tempManager->EndTransaction(nullptr, nullptr);
+    return;
+  }
+  RestrictVisibleRegionForLayer(layer, itemVisibleRect);
+  
+  tempManager->SetRoot(layer);
+  aLayerBuilder->WillEndTransaction(tempManager);
   if (aItem->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) {
-    static_cast<nsDisplaySVGEffects*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
-    if (basic->InTransaction()) {
-      basic->AbortTransaction();
+    static_cast<nsDisplaySVGEffects*>(aItem)->PaintAsLayer(aBuilder, aCtx, tempManager);
+    if (tempManager->InTransaction()) {
+      tempManager->AbortTransaction();
     }
   } else {
-    basic->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder);
+    tempManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder);
   }
-  FrameLayerBuilder *builder = static_cast<FrameLayerBuilder*>(basic->GetUserData(&gLayerManagerLayerBuilder));
-  if (builder) {
-    builder->DidEndTransaction();
-  }
+  aLayerBuilder->DidEndTransaction(tempManager);
  
-  basic->SetUserData(&gLayerManagerLayerBuilder, NULL);
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
     DumpPaintedImage(aItem, surf);
 
     surf->SetDeviceOffset(gfxPoint(0, 0));
     aContext->SetSource(surf, itemVisibleRect.TopLeft());
     aContext->Rectangle(itemVisibleRect);
     aContext->Fill();
@@ -2080,29 +1841,26 @@ ContainerState::ProcessDisplayItems(cons
     mBounds.UnionRect(mBounds, itemContent);
     itemVisibleRect.IntersectRect(itemVisibleRect, itemDrawRect);
 
     LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
 
     bool isFixed;
     bool forceInactive;
     const nsIFrame* activeScrolledRoot;
-    nsPoint topLeft;
     if (aFlags & NO_COMPONENT_ALPHA) {
       // When NO_COMPONENT_ALPHA is set, items will be flattened onto the
       // reference frame. In this case, force the active scrolled root to
       // that frame.
       forceInactive = true;
-      activeScrolledRoot = mContainerReferenceFrame;
-      topLeft = nsPoint(0, 0);
+      activeScrolledRoot = mBuilder->FindReferenceFrameFor(mContainerFrame);
       isFixed = mBuilder->IsFixedItem(item, nullptr, activeScrolledRoot);
     } else {
       forceInactive = false;
       isFixed = mBuilder->IsFixedItem(item, &activeScrolledRoot);
-      topLeft = activeScrolledRoot->GetOffsetToCrossDoc(mContainerReferenceFrame);
     }
 
     // Assign the item to a layer
     if (layerState == LAYER_ACTIVE_FORCE ||
         (!forceInactive &&
          (layerState == LAYER_ACTIVE_EMPTY ||
           layerState == LAYER_ACTIVE))) {
 
@@ -2112,32 +1870,27 @@ ContainerState::ProcessDisplayItems(cons
                    itemVisibleRect.IsEmpty(),
                    "State is LAYER_ACTIVE_EMPTY but visible rect is not.");
 
       // If the item would have its own layer but is invisible, just hide it.
       // Note that items without their own layers can't be skipped this
       // way, since their ThebesLayer may decide it wants to draw them
       // into its buffer even if they're currently covered.
       if (itemVisibleRect.IsEmpty() && layerState != LAYER_ACTIVE_EMPTY) {
-        InvalidateForLayerChange(item, nullptr, aClip, topLeft);
+        InvalidateForLayerChange(item, nullptr);
         continue;
       }
 
       // Just use its layer.
       nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
       if (!ownLayer) {
-        InvalidateForLayerChange(item, ownLayer, aClip, topLeft);
+        InvalidateForLayerChange(item, ownLayer);
         continue;
       }
 
-      nsRect invalid;
-      if (item->IsInvalid(invalid)) {
-        ownLayer->SetInvalidRectToVisibleRegion();
-      }
-
       // If it's not a ContainerLayer, we need to apply the scale transform
       // ourselves.
       if (!ownLayer->AsContainerLayer()) {
         ownLayer->SetPostScale(mParameters.mXScale,
                                mParameters.mYScale);
       }
 
       ownLayer->SetIsFixedPosition(isFixed);
@@ -2177,317 +1930,148 @@ ContainerState::ProcessDisplayItems(cons
 
       ContainerLayer* oldContainer = ownLayer->GetParent();
       if (oldContainer && oldContainer != mContainerLayer) {
         oldContainer->RemoveChild(ownLayer);
       }
       NS_ASSERTION(!mNewChildLayers.Contains(ownLayer),
                    "Layer already in list???");
 
-      InvalidateForLayerChange(item, ownLayer, aClip, topLeft);
+      InvalidateForLayerChange(item, ownLayer);
 
       mNewChildLayers.AppendElement(ownLayer);
-      mLayerBuilder->AddLayerDisplayItem(ownLayer, item, 
-                                         aClip, layerState, 
-                                         topLeft, nullptr);
+      mLayerBuilder->AddLayerDisplayItem(ownLayer, item, layerState);
     } else {
       ThebesLayerData* data =
         FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, aClip,
-                           activeScrolledRoot, topLeft);
+                           activeScrolledRoot);
 
       data->mLayer->SetIsFixedPosition(isFixed);
 
-      InvalidateForLayerChange(item, data->mLayer, aClip, topLeft);
+      InvalidateForLayerChange(item, data->mLayer);
 
       mLayerBuilder->AddThebesDisplayItem(data->mLayer, item, aClip,
                                           mContainerFrame,
-                                          layerState, topLeft);
+                                          layerState);
 
       // check to see if the new item has rounded rect clips in common with
       // other items in the layer
       data->UpdateCommonClipCount(aClip);
     }
   }
 }
 
 void
-ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, 
-                                         Layer* aNewLayer,
-                                         const FrameLayerBuilder::Clip& aClip,
-                                         const nsPoint& aTopLeft)
+ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer)
 {
-  nsIFrame* f = aItem->GetUnderlyingFrame();
-  NS_ASSERTION(f, "Display items that render using Thebes must have a frame");
-  uint32_t key = aItem->GetPerFrameKey();
-  NS_ASSERTION(key, "Display items that render using Thebes must have a key");
-  nsDisplayItemGeometry *oldGeometry = NULL;
-  FrameLayerBuilder::Clip* oldClip = NULL;
-  nsAutoPtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(mBuilder));
-  Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem, &oldGeometry, &oldClip);
-  if (aNewLayer != oldLayer && oldLayer) {
+  NS_ASSERTION(aItem->GetUnderlyingFrame(), "Display items that render using Thebes must have a frame");
+  NS_ASSERTION(aItem->GetPerFrameKey(), "Display items that render using Thebes must have a key");
+  Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem);
+  if (!oldLayer) {
+    // Nothing to do here, this item didn't have a layer before
+    return;
+  }
+  if (aNewLayer != oldLayer) {
     // The item has changed layers.
-    // Invalidate the old bounds in the old layer and new bounds in the new layer.
+    // Invalidate the bounds in the old layer and new layer.
+    // The bounds might have changed, but we assume that any difference
+    // in the bounds will have been invalidated for all Thebes layers
+    // in the container via regular frame invalidation.
+    bool snap;
+    nsRect bounds = aItem->GetBounds(mBuilder, &snap);
+
     ThebesLayer* t = oldLayer->AsThebesLayer();
     if (t) {
+      ThebesDisplayItemLayerUserData* data =
+          static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData));
       // Note that whenever the layer's scale changes, we invalidate the whole thing,
       // so it doesn't matter whether we are using the old scale at last paint
       // or a new scale here
-#ifdef DEBUG_INVALIDATIONS
-      printf("Display item type %s(%p) changed layers %p to %p!\n", aItem->Name(), f, t, aNewLayer);
-#endif
-      ThebesDisplayItemLayerUserData* data =
-          static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData));
       InvalidatePostTransformRegion(t,
-          oldGeometry->ComputeInvalidationRegion().
-            ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
+          bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
           mLayerBuilder->GetLastPaintOffset(t));
     }
     if (aNewLayer) {
-      ThebesLayer* newThebesLayer = aNewLayer->AsThebesLayer();
-      if (newThebesLayer) {
+      ThebesLayer* newLayer = aNewLayer->AsThebesLayer();
+      if (newLayer) {
         ThebesDisplayItemLayerUserData* data =
-            static_cast<ThebesDisplayItemLayerUserData*>(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData));
-        InvalidatePostTransformRegion(newThebesLayer,
-            geometry->ComputeInvalidationRegion().
-              ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
-            GetTranslationForThebesLayer(newThebesLayer));
+            static_cast<ThebesDisplayItemLayerUserData*>(newLayer->GetUserData(&gThebesDisplayItemLayerUserData));
+        InvalidatePostTransformRegion(newLayer,
+            bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
+            GetTranslationForThebesLayer(newLayer));
       }
     }
-    return;
-  } 
-  if (!aNewLayer) {
-    return;
-  }
-
-  ThebesLayer* newThebesLayer = aNewLayer->AsThebesLayer();
-  if (!newThebesLayer) {
-    return;
-  }
-
-  ThebesDisplayItemLayerUserData* data =
-    static_cast<ThebesDisplayItemLayerUserData*>(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData));
-  // If the frame is marked as invalidated, and didn't specify a rect to invalidate  then we want to 
-  // invalidate both the old and new bounds, otherwise we only want to invalidate the changed areas.
-  // If we do get an invalid rect, then we want to add this on top of the change areas.
-  nsRect invalid;
-  nsRegion combined;
-  if (!oldLayer) {
-    // This item is being added for the first time, invalidate its entire area.
-    //TODO: We call GetGeometry again in AddThebesDisplayItem, we should reuse this.
-    combined = geometry->ComputeInvalidationRegion();
-#ifdef DEBUG_INVALIDATIONS
-    printf("Display item type %s(%p) added to layer %p!\n", aItem->Name(), f, aNewLayer);
-#endif
-  } else if (aItem->IsInvalid(invalid) && invalid.IsEmpty()) {
-    // Either layout marked item as needing repainting, invalidate the entire old and new areas.
-    combined.Or(geometry->ComputeInvalidationRegion(), oldGeometry->ComputeInvalidationRegion());
-#ifdef DEBUG_INVALIDATIONS
-    printf("Display item type %s(%p) (in layer %p) belongs to an invalidated frame!\n", aItem->Name(), f, aNewLayer);
-#endif
-  } else {
-    // Let the display item check for geometry changes and decide what needs to be
-    // repainted.
-    nsPoint shift = aTopLeft - data->mLastActiveScrolledRootOrigin;
-    oldGeometry->MoveBy(shift);
-    aItem->ComputeInvalidationRegion(mBuilder, oldGeometry, &combined);
-    oldClip->AddOffsetAndComputeDifference(shift, oldGeometry->ComputeInvalidationRegion(),
-                                           aClip, geometry->ComputeInvalidationRegion(),
-                                           &combined);
-
-    // Add in any rect that the frame specified
-    combined = combined.Or(combined, invalid);
-#ifdef DEBUG_INVALIDATIONS
-    if (!combined.IsEmpty()) {
-      printf("Display item type %s(%p) (in layer %p) changed geometry!\n", aItem->Name(), f, aNewLayer);
-    }
-#endif
-  }
-  if (!combined.IsEmpty()) {
-    InvalidatePostTransformRegion(newThebesLayer,
-        combined.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
-        GetTranslationForThebesLayer(newThebesLayer));
+
+    mContainerFrame->InvalidateWithFlags(
+        bounds - mBuilder->ToReferenceFrame(mContainerFrame),
+        nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
+        nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
   }
 }
 
 bool
 FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder,
                                                     nsDisplayItem* aItem)
 {
-  if (!aItem->ShouldFixToViewport(aBuilder)) {
-    return true;
-  }
-
-  nsRefPtr<LayerManager> layerManager;
-  nsIFrame* referenceFrame = aBuilder->RootReferenceFrame();
-  NS_ASSERTION(referenceFrame == nsLayoutUtils::GetDisplayRootFrame(referenceFrame),
-               "Reference frame must be a display root for us to use the layer manager");
-  nsIWidget* window = referenceFrame->GetNearestWidget();
-  if (window) {
-    layerManager = window->GetLayerManager();
-  }
-
-  if (layerManager) {
-    return !HasRetainedLayerFor(aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey(), layerManager);
-  }
-
-  return true;
+  return !aItem->ShouldFixToViewport(aBuilder) ||
+      !HasRetainedLayerFor(aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey());
 }
 
 void
 FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
                                         nsDisplayItem* aItem,
                                         const Clip& aClip,
                                         nsIFrame* aContainerLayerFrame,
-                                        LayerState aLayerState,
-                                        const nsPoint& aTopLeft)
+                                        LayerState aLayerState)
 {
-  nsRefPtr<LayerManager> tempManager;
-  if (aLayerState != LAYER_NONE) {
-    DisplayItemData *data = GetDisplayItemDataForManager(aItem, aLayer->Manager());
-    if (data) {
-      tempManager = data->mInactiveManager;
-    }
-    if (!tempManager) {
-      tempManager = new BasicLayerManager();
-    }
-  }
-
-  AddLayerDisplayItem(aLayer, aItem, aClip, aLayerState, aTopLeft, tempManager);
+  AddLayerDisplayItem(aLayer, aItem, aLayerState);
 
   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
   if (entry) {
     entry->mContainerLayerFrame = aContainerLayerFrame;
     if (entry->mContainerLayerGeneration == 0) {
       entry->mContainerLayerGeneration = mContainerLayerGeneration;
     }
     NS_ASSERTION(aItem->GetUnderlyingFrame(), "Must have frame");
-    if (tempManager) {
-      FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
-      layerBuilder->Init(mDisplayListBuilder, tempManager);
-
-      tempManager->BeginTransaction();
-      if (mRetainingManager) {
-        layerBuilder->DidBeginRetainedLayerTransaction(tempManager);
-      }
-  
-      nsAutoPtr<LayerProperties> props(LayerProperties::CloneFrom(tempManager->GetRoot()));
-      nsRefPtr<Layer> layer =
-        aItem->BuildLayer(mDisplayListBuilder, tempManager, FrameLayerBuilder::ContainerParameters());
-      // We have no easy way of detecting if this transaction will ever actually get finished.
-      // For now, I've just silenced the warning with nested transactions in BasicLayers.cpp
-      if (!layer) {
-        tempManager->EndTransaction(nullptr, nullptr);
-        tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
-        return;
-      }
-
-      // If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been
-      // stored in layerBuilder. Manually add it now.
-      nsRefPtr<DisplayItemData> data = 
-        new DisplayItemData(layer, aItem->GetPerFrameKey(), 
-                            LAYER_ACTIVE, mContainerLayerGeneration);
-      layerBuilder->StoreDataForFrame(aItem->GetUnderlyingFrame(), data);
-
-      tempManager->SetRoot(layer);
-      layerBuilder->WillEndTransaction();
-
-      nsIntPoint offset = GetLastPaintOffset(aLayer) - GetTranslationForThebesLayer(aLayer);
-      props->MoveBy(-offset);
-      nsIntRect invalid = props->ComputeDifferences(layer, nullptr);
-      if (aLayerState == LAYER_SVG_EFFECTS) {
-        invalid = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(aItem->GetUnderlyingFrame(), invalid);
-      }
-      if (!invalid.IsEmpty()) {
-#ifdef DEBUG_INVALIDATIONS
-        printf("Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p\n", tempManager.get(), aItem->Name(), aItem->GetUnderlyingFrame(), aLayer);
-#endif
-        ThebesDisplayItemLayerUserData* data =
-          static_cast<ThebesDisplayItemLayerUserData*>(aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
-        invalid.ScaleRoundOut(data->mXScale, data->mYScale);
-        InvalidatePostTransformRegion(aLayer, invalid,
-                                      GetTranslationForThebesLayer(aLayer));
-      }
-    }
     ClippedDisplayItem* cdi =
       entry->mItems.AppendElement(ClippedDisplayItem(aItem, aClip,
                                                      mContainerLayerGeneration));
-    cdi->mInactiveLayer = tempManager;
+    cdi->mInactiveLayer = aLayerState != LAYER_NONE;
   }
 }
 
 void
-FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame, DisplayItemData* aData)
+FrameLayerBuilder::AddLayerDisplayItemForFrame(Layer* aLayer,
+                                               nsIFrame* aFrame,
+                                               uint32_t aDisplayItemKey,
+                                               LayerState aLayerState)
 {
-  DisplayItemDataEntry *entry = mNewDisplayItemData.GetEntry(aFrame);
-  if (entry) {
-    return;
-  }
-  entry = mNewDisplayItemData.PutEntry(aFrame);
+  DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(aFrame);
   if (entry) {
-    entry->mData.AppendElement(aData);
-  }
-}
-
-FrameLayerBuilder::ClippedDisplayItem::~ClippedDisplayItem()
-{
-  if (mInactiveLayer) {
-    // We always start a transaction during layer construction for all inactive
-    // layers, but we don't necessarily call EndTransaction during painting.
-    // If the transaaction is still open, end it to avoid assertions.
-    BasicLayerManager* basic = static_cast<BasicLayerManager*>(mInactiveLayer.get());
-    if (basic->InTransaction()) {
-      basic->EndTransaction(nullptr, nullptr);
-    }
-    basic->SetUserData(&gLayerManagerLayerBuilder, nullptr);
+    entry->mContainerLayerGeneration = mContainerLayerGeneration;
+    entry->mData.AppendElement(DisplayItemData(aLayer, aDisplayItemKey, aLayerState, mContainerLayerGeneration));
   }
 }
 
 void
 FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
                                        nsDisplayItem* aItem,
-                                       const Clip& aClip,
-                                       LayerState aLayerState,
-                                       const nsPoint& aTopLeft,
-                                       LayerManager* aManager)
+                                       LayerState aLayerState)
 {
   if (aLayer->Manager() != mRetainingManager)
     return;
-    
-  nsRefPtr<DisplayItemData> data = 
-    new DisplayItemData(aLayer, aItem->GetPerFrameKey(), aLayerState, mContainerLayerGeneration);
-    
-  ThebesLayer *t = aLayer->AsThebesLayer();
-  if (t) {
-    data->mGeometry = aItem->AllocateGeometry(mDisplayListBuilder);
-    data->mClip = aClip;
-  }
-  data->mInactiveManager = aManager;
-
-  DisplayItemDataEntry* entry = 
-    mNewDisplayItemData.PutEntry(aItem->GetUnderlyingFrame());
-  if (entry) {
-    entry->mContainerLayerGeneration = mContainerLayerGeneration;
-    entry->mData.AppendElement(data);
-    data->AddFrame(aItem->GetUnderlyingFrame());
-  }
+
+  nsIFrame* f = aItem->GetUnderlyingFrame();
+  uint32_t key = aItem->GetPerFrameKey();
+  AddLayerDisplayItemForFrame(aLayer, f, key, aLayerState);
 
   nsAutoTArray<nsIFrame*,4> mergedFrames;
   aItem->GetMergedFrames(&mergedFrames);
   for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
-    entry = mNewDisplayItemData.PutEntry(mergedFrames[i]);
-    if (entry) {
-      entry->mContainerLayerGeneration = mContainerLayerGeneration;
-      entry->mData.AppendElement(data);
-      data->AddFrame(mergedFrames[i]);
-    }
-  }
-  
-  DisplayItemData* oldData = GetDisplayItemDataForManager(aItem, mRetainingManager);
-  if (oldData && oldData->FrameListMatches(aItem)) {
-    oldData->mUsed = true;
+    AddLayerDisplayItemForFrame(aLayer, mergedFrames[i], key, aLayerState);
   }
 }
 
 nsIntPoint
 FrameLayerBuilder::GetLastPaintOffset(ThebesLayer* aLayer)
 {
   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
   if (entry) {
@@ -2551,35 +2135,30 @@ ContainerState::CollectOldLayers()
       NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE,
                    "Could not recycle mask layer, unsupported layer type.");
       mRecycledMaskImageLayers.Put(layer, static_cast<ImageLayer*>(maskLayer));
     }
   }
 }
 
 void
-ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData)
+ContainerState::Finish(uint32_t* aTextContentFlags)
 {
   while (!mThebesLayerDataStack.IsEmpty()) {
     PopThebesLayerData();
   }
 
   uint32_t textContentFlags = 0;
 
   // Make sure that current/existing layers are added to the parent and are
   // in the correct order.
   Layer* layer = nullptr;
   for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i) {
     Layer* prevChild = i == 0 ? nullptr : mNewChildLayers[i - 1].get();
     layer = mNewChildLayers[i];
-      
-    if (aData) {
-      ProcessRemovedDisplayItemsData data(layer, mLayerBuilder);
-      aData->mFramesWithLayers.EnumerateEntries(FrameLayerBuilder::ProcessRemovedDisplayItems, &data);
-    }
 
     if (!layer->GetVisibleRegion().IsEmpty()) {
       textContentFlags |= layer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA;
     }
 
     if (!layer->GetParent()) {
       // This is not currently a child of the container, so just add it
       // now.
@@ -2699,27 +2278,79 @@ ChooseScaleAndSetTransform(FrameLayerBui
     }
   }
   if (isRetained && (!canDraw2D || transform2d.HasNonIntegerTranslation())) {
     result.mDisableSubpixelAntialiasingInDescendants = true;
   }
   return result;
 }
 
+static void
+ApplyThebesLayerInvalidation(nsDisplayListBuilder* aBuilder,
+                             nsIFrame* aContainerFrame,
+                             nsDisplayItem* aContainerItem,
+                             ContainerState& aState,
+                             nsPoint* aCurrentOffset,
+                             nsDisplayTransform* aTransform)
+{
+  *aCurrentOffset = aContainerItem ? aContainerItem->ToReferenceFrame()
+    : aBuilder->ToReferenceFrame(aContainerFrame);
+
+  FrameProperties props = aContainerFrame->Properties();
+  RefCountedRegion* invalidThebesContent = static_cast<RefCountedRegion*>
+    (props.Get(ThebesLayerInvalidRegionProperty()));
+  const FrameLayerBuilder::ContainerParameters& scaleParameters = aState.ScaleParameters();
+
+  nsRegion invalidRegion;
+  if (invalidThebesContent) {
+    if (invalidThebesContent->mIsInfinite) {
+      // The region was marked as infinite to indicate that everything should be
+      // invalidated.
+      aState.SetInvalidateAllThebesContent();
+      return;
+    }
+
+    invalidRegion = invalidThebesContent->mRegion;
+  } else {
+    // The region doesn't exist, so this is a newly visible frame. Invalidate
+    // the frame area.
+    invalidRegion =
+      aContainerFrame->GetVisualOverflowRectRelativeToSelf() + *aCurrentOffset;
+  }
+
+  if (aTransform) {
+    // XXX We're simplifying the transform by only using the bounds of the
+    //     region. This may have performance implications.
+    invalidRegion = aTransform->
+      TransformRectOut(invalidRegion.GetBounds(),
+                       aTransform->GetUnderlyingFrame(), -(*aCurrentOffset));
+  }
+
+  aState.AddInvalidThebesContent(invalidRegion.
+    ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
+                         aState.GetAppUnitsPerDevPixel()));
+
+  // We have to preserve the current contents of invalidThebesContent
+  // because there might be multiple container layers for the same
+  // frame and we need to invalidate the ThebesLayer children of all
+  // of them. Also, multiple calls to ApplyThebesLayerInvalidation for the
+  // same layer can share the same region.
+}
+
 /* static */ PLDHashOperator
 FrameLayerBuilder::RestoreDisplayItemData(DisplayItemDataEntry* aEntry, void* aUserArg)
 {
   uint32_t *generation = static_cast<uint32_t*>(aUserArg);
 
   if (aEntry->mContainerLayerGeneration >= *generation) {
     return PL_DHASH_REMOVE;
   }
 
   for (uint32_t i = 0; i < aEntry->mData.Length(); i++) {
-    if (aEntry->mData[i]->mContainerLayerGeneration >= *generation) {
+    if (aEntry->mData[i].mContainerLayerGeneration >= *generation) {
       aEntry->mData.TruncateLength(i);
       return PL_DHASH_NEXT;
     }
   }
 
   return PL_DHASH_NEXT;
 }
 
@@ -2737,16 +2368,46 @@ FrameLayerBuilder::RestoreThebesLayerIte
       aEntry->mItems.TruncateLength(i);
       return PL_DHASH_NEXT;
     }
   }
 
   return PL_DHASH_NEXT;
 }
 
+static nsDisplayTransform* FindTransformForContainerFrame(nsIFrame* aContainerFrame,
+                                                          nsDisplayItem* aContainerItem)
+{
+  if (!aContainerFrame->IsTransformed() ||
+      aContainerItem->GetType() == nsDisplayItem::TYPE_TRANSFORM)
+    return nullptr;
+
+  nsTArray<nsDisplayItem*> queue;
+  queue.AppendElement(aContainerItem);
+  while (queue.Length()) {
+    nsDisplayItem* item = queue[queue.Length() - 1];
+    queue.RemoveElementAt(queue.Length() - 1);
+
+    if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
+      return static_cast<nsDisplayTransform*>(item);
+    }
+
+    if (item->GetList()) {
+      for (nsDisplayItem* child = item->GetList()->GetBottom(); child;
+           child = child->GetAbove()) {
+        if (child->GetUnderlyingFrame() == aContainerFrame) {
+          queue.AppendElement(child);
+        }
+      }
+    }
+  }
+
+  return nullptr;
+}
+
 already_AddRefed<ContainerLayer>
 FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
                                           LayerManager* aManager,
                                           nsIFrame* aContainerFrame,
                                           nsDisplayItem* aContainerItem,
                                           const nsDisplayList& aChildren,
                                           const ContainerParameters& aParameters,
                                           const gfx3DMatrix* aTransform)
@@ -2759,25 +2420,19 @@ FrameLayerBuilder::BuildContainerLayerFo
                "Container display item must match given frame");
 
   nsRefPtr<ContainerLayer> containerLayer;
   if (aManager == mRetainingManager) {
     // Using GetOldLayerFor will search merged frames, as well as the underlying
     // frame. The underlying frame can change when a page scrolls, so this
     // avoids layer recreation in the situation that a new underlying frame is
     // picked for a layer.
-    Layer* oldLayer = nullptr;
-    if (aContainerItem) {
-      oldLayer = GetOldLayerFor(aContainerItem);
-    } else {
-      DisplayItemData *data = GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey);
-      if (data) {
-        oldLayer = data->mLayer;
-      }
-    }
+    Layer* oldLayer = aContainerItem ?
+      GetOldLayerFor(aContainerItem) :
+      GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey);
 
     if (oldLayer) {
       NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager");
       if (oldLayer->HasUserData(&gThebesDisplayItemLayerUserData)) {
         // The old layer for this item is actually our ThebesLayer
         // because we rendered its layer into that ThebesLayer. So we
         // don't actually have a retained container layer.
       } else {
@@ -2817,65 +2472,97 @@ FrameLayerBuilder::BuildContainerLayerFo
   ContainerParameters scaleParameters =
     ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame, aTransform, aParameters,
                                containerLayer, state);
 
   uint32_t oldGeneration = mContainerLayerGeneration;
   mContainerLayerGeneration = ++mMaxContainerLayerGeneration;
 
   nsRefPtr<RefCountedRegion> thebesLayerInvalidRegion = nullptr;
-  if (mRetainingManager) {
-    nsRefPtr<DisplayItemData> data =
-      new  DisplayItemData(containerLayer, containerDisplayItemKey,
-                           LAYER_ACTIVE, mContainerLayerGeneration);
-
+  if (aManager == mRetainingManager) {
+    FrameProperties props = aContainerFrame->Properties();
     DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(aContainerFrame);
     if (entry) {
-      entry->mData.AppendElement(data);
-      data->AddFrame(aContainerFrame);
+      entry->mData.AppendElement(
+          DisplayItemData(containerLayer, containerDisplayItemKey,
+                          LAYER_ACTIVE, mContainerLayerGeneration));
+      thebesLayerInvalidRegion = static_cast<RefCountedRegion*>
+        (props.Get(ThebesLayerInvalidRegionProperty()));
+      if (!thebesLayerInvalidRegion) {
+        thebesLayerInvalidRegion = new RefCountedRegion();
+      }
+      entry->mInvalidRegion = thebesLayerInvalidRegion;
       entry->mContainerLayerGeneration = mContainerLayerGeneration;
     }
-
-    nsAutoTArray<nsIFrame*,4> mergedFrames;
-    if (aContainerItem) {
-      aContainerItem->GetMergedFrames(&mergedFrames);
-    }
-    for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
-      nsIFrame* mergedFrame = mergedFrames[i];
-      entry = mNewDisplayItemData.PutEntry(mergedFrame);
-      if (entry) {
-        entry->mContainerLayerGeneration = mContainerLayerGeneration;
-        entry->mData.AppendElement(data);
-        data->AddFrame(mergedFrame);
-      }
-    }
   }
 
   nsRect bounds;
   nsIntRect pixBounds;
   int32_t appUnitsPerDevPixel;
   uint32_t stateFlags =
     (aContainerFrame->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) ?
       ContainerState::NO_COMPONENT_ALPHA : 0;
   uint32_t flags;
-  
-  LayerManagerData* data = static_cast<LayerManagerData*>
-    (aManager->GetUserData(&gLayerManagerUserData));
+  bool flattenedLayers = false;
   while (true) {
     ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(),
-                         aContainerFrame, aContainerItem,
-                         containerLayer, scaleParameters);
-    
+                         aContainerFrame, containerLayer, scaleParameters);
+    if (flattenedLayers) {
+      state.SetInvalidateAllThebesContent();
+    }
+
+    if (aManager == mRetainingManager) {
+      // If the container frame has a transform and it's contained in the
+      // container item's sub-tree, we need to transform the invalid region
+      // before applying it.
+      nsDisplayTransform* transformItem =
+        FindTransformForContainerFrame(aContainerFrame, aContainerItem);
+
+      nsPoint currentOffset;
+      ApplyThebesLayerInvalidation(aBuilder, aContainerFrame, aContainerItem, state,
+                                   &currentOffset, transformItem);
+      SetHasContainerLayer(aContainerFrame, currentOffset);
+
+      nsAutoTArray<nsIFrame*,4> mergedFrames;
+      if (aContainerItem) {
+        aContainerItem->GetMergedFrames(&mergedFrames);
+      }
+      for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
+        nsIFrame* mergedFrame = mergedFrames[i];
+        DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(mergedFrame);
+        if (entry) {
+          // Append the container layer so we don't regenerate layers when
+          // the underlying frame of an item changes to one of the existing
+          // merged frames.
+          entry->mData.AppendElement(
+              DisplayItemData(containerLayer, containerDisplayItemKey,
+                              LAYER_ACTIVE, mContainerLayerGeneration));
+
+          // Ensure that UpdateDisplayItemDataForFrame recognizes that we
+          // still have a container layer associated with this frame.
+          entry->mIsSharingContainerLayer = true;
+
+          // Store the invalid region property in case this frame is represented
+          // by multiple container layers. This is cleared and set when iterating
+          // over the DisplayItemDataEntry's in WillEndTransaction.
+          entry->mInvalidRegion = thebesLayerInvalidRegion;
+        }
+        ApplyThebesLayerInvalidation(aBuilder, mergedFrame, nullptr, state,
+                                     &currentOffset, transformItem);
+        SetHasContainerLayer(mergedFrame, currentOffset);
+      }
+    }
+
     Clip clip;
     state.ProcessDisplayItems(aChildren, clip, stateFlags);
 
     // Set CONTENT_COMPONENT_ALPHA if any of our children have it.
     // This is suboptimal ... a child could have text that's over transparent
     // pixels in its own layer, but over opaque parts of previous siblings.
-    state.Finish(&flags, data);
+    state.Finish(&flags);
     bounds = state.GetChildrenBounds();
     pixBounds = state.ScaleToOutsidePixels(bounds, false);
     appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel();
 
     if ((flags & Layer::CONTENT_COMPONENT_ALPHA) &&
         mRetainingManager &&
         !mRetainingManager->AreComponentAlphaLayersEnabled() &&
         !stateFlags) {
@@ -2884,16 +2571,17 @@ FrameLayerBuilder::BuildContainerLayerFo
       // We restore the previous FrameLayerBuilder state since the first set
       // of layer building will have changed it.
       stateFlags = ContainerState::NO_COMPONENT_ALPHA;
       mNewDisplayItemData.EnumerateEntries(RestoreDisplayItemData,
                                            &mContainerLayerGeneration);
       mThebesLayerItems.EnumerateEntries(RestoreThebesLayerItemEntries,
                                          &mContainerLayerGeneration);
       aContainerFrame->AddStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
+      flattenedLayers = true;
       continue;
     }
     break;
   }
 
   NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds");
   pixBounds.MoveBy(nsIntPoint(scaleParameters.mOffset.x, scaleParameters.mOffset.y));
   containerLayer->SetVisibleRegion(pixBounds);
@@ -2904,87 +2592,165 @@ FrameLayerBuilder::BuildContainerLayerFo
     if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) {
       // Clear CONTENT_COMPONENT_ALPHA
       flags = Layer::CONTENT_OPAQUE;
     }
   }
   containerLayer->SetContentFlags(flags);
 
   mContainerLayerGeneration = oldGeneration;
-  containerLayer->SetUserData(&gNotifySubDocInvalidationData, nullptr);
-
   return containerLayer.forget();
 }
 
 Layer*
 FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
+                                   LayerManager* aManager,
                                    nsDisplayItem* aItem)
 {
+  if (aManager != mRetainingManager)
+    return nullptr;
+
   nsIFrame* f = aItem->GetUnderlyingFrame();
   NS_ASSERTION(f, "Can only call GetLeafLayerFor on items that have a frame");
-  Layer* layer = GetOldLayerFor(aItem);
+  Layer* layer = GetOldLayerForFrame(f, aItem->GetPerFrameKey());
   if (!layer)
     return nullptr;
   if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
     // This layer was created to render Thebes-rendered content for this
     // display item. The display item should not use it for its own
     // layer rendering.
     return nullptr;
   }
   // Clear clip rect; the caller is responsible for setting it.
   layer->SetClipRect(nullptr);
   layer->SetMaskLayer(nullptr);
   return layer;
 }
 
 /* static */ void
+FrameLayerBuilder::InvalidateThebesLayerContents(nsIFrame* aFrame,
+                                                 const nsRect& aRect)
+{
+  FrameProperties props = aFrame->Properties();
+  RefCountedRegion* invalidThebesContent = static_cast<RefCountedRegion*>
+    (props.Get(ThebesLayerInvalidRegionProperty()));
+  if (!invalidThebesContent)
+    return;
+
+  nsPoint* offsetAtLastPaint = static_cast<nsPoint*>
+    (props.Get(ThebesLayerLastPaintOffsetProperty()));
+  NS_ASSERTION(offsetAtLastPaint,
+               "This must have been set up along with ThebesLayerInvalidRegionProperty");
+  invalidThebesContent->mRegion.Or(invalidThebesContent->mRegion,
+          aRect + *offsetAtLastPaint);
+  invalidThebesContent->mRegion.SimplifyOutward(20);
+}
+
+/**
+ * Returns true if we find a descendant with a container layer
+ */
+static bool
+InternalInvalidateThebesLayersInSubtree(nsIFrame* aFrame, bool aTrustFrameGeometry)
+{
+  if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT))
+    return false;
+
+  bool foundContainerLayer = false;
+  if (aFrame->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) {
+    if (aTrustFrameGeometry) {
+      // Just invalidate the area covered by the frame. This helps if a single
+      // region is being shared by multiple container layers.
+      FrameLayerBuilder::InvalidateThebesLayerContents(aFrame,
+        aFrame->GetVisualOverflowRectRelativeToSelf());
+    } else {
+      // Mark the invalid region as infinite to indicate that all Thebes
+      // contents need to be invalidated
+      FrameProperties props = aFrame->Properties();
+      RefCountedRegion* invalidRegion = static_cast<RefCountedRegion*>
+        (props.Get(ThebesLayerInvalidRegionProperty()));
+      if (!invalidRegion) {
+        invalidRegion = new RefCountedRegion();
+        invalidRegion->AddRef();
+        props.Set(ThebesLayerInvalidRegionProperty(), invalidRegion);
+      }
+      invalidRegion->mIsInfinite = true;
+    }
+    foundContainerLayer = true;
+  }
+
+  nsAutoTArray<nsIFrame::ChildList,4> childListArray;
+  if (!aFrame->GetFirstPrincipalChild()) {
+    nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(aFrame);
+    if (subdocumentFrame) {
+      // Descend into the subdocument
+      nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
+      if (root) {
+        childListArray.AppendElement(nsIFrame::ChildList(
+          nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
+          nsIFrame::kPrincipalList));
+      }
+    }
+  }
+
+  aFrame->GetChildLists(&childListArray);
+  nsIFrame::ChildListArrayIterator lists(childListArray);
+  for (; !lists.IsDone(); lists.Next()) {
+    nsFrameList::Enumerator childFrames(lists.CurrentList());
+    for (; !childFrames.AtEnd(); childFrames.Next()) {
+      if (InternalInvalidateThebesLayersInSubtree(childFrames.get(),
+                                                  aTrustFrameGeometry)) {
+        foundContainerLayer = true;
+      }
+    }
+  }
+
+  if (!foundContainerLayer) {
+    aFrame->RemoveStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
+  }
+  return foundContainerLayer;
+}
+
+/* static */ void
+FrameLayerBuilder::InvalidateThebesLayersInSubtree(nsIFrame* aFrame)
+{
+  InternalInvalidateThebesLayersInSubtree(aFrame, true);
+}
+
+/* static */ void
+FrameLayerBuilder::InvalidateThebesLayersInSubtreeWithUntrustedFrameGeometry(nsIFrame* aFrame)
+{
+  InternalInvalidateThebesLayersInSubtree(aFrame, false);
+}
+
+/* static */ void
 FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager)
 {
   LayerManagerData* data = static_cast<LayerManagerData*>
     (aManager->GetUserData(&gLayerManagerUserData));
   if (data) {
     data->mInvalidateAllLayers = true;
   }
 }
 
-/* static */ void
-FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame)
-{
-  LayerManagerData* data = GetDefaultLayerManagerDataForFrame(aFrame);
-  if (data) {
-    data->mInvalidateAllLayers = true;
-  }
-  data = GetSecondaryLayerManagerDataForFrame(aFrame);
-  if (data) {
-    data->mInvalidateAllLayers = true;
-  }
-}
-
 /* static */
 Layer*
 FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey)
 {
-  //TODO: This isn't completely correct, since a frame could exist as a layer
-  // in the normal widget manager, and as a different layer (or no layer)
-  // in the secondary manager
-
-  DisplayItemData *data = GetDisplayItemDataForManager(aFrame, aDisplayItemKey);
-  if (!data) {
+  nsTArray<DisplayItemData>* array = GetDisplayItemDataArrayForFrame(aFrame);
+  if (!array)
     return nullptr;
-  }
-
-  if (data->mOptLayer) {
-    return data->mOptLayer;
-  }
-
-  Layer* layer = data->mLayer;
-  if (!layer->HasUserData(&gColorLayerUserData) &&
-      !layer->HasUserData(&gImageLayerUserData) &&
-      !layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
-    return layer;
+
+  for (uint32_t i = 0; i < array->Length(); ++i) {
+    if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
+      Layer* layer = array->ElementAt(i).mLayer;
+      if (!layer->HasUserData(&gColorLayerUserData) &&
+          !layer->HasUserData(&gImageLayerUserData) &&
+          !layer->HasUserData(&gThebesDisplayItemLayerUserData))
+        return layer;
+    }
   }
   return nullptr;
 }
 
 static gfxSize
 PredictScaleForContent(nsIFrame* aFrame, nsIFrame* aAncestorWithScale,
                        const gfxSize& aScale)
 {
@@ -3000,37 +2766,35 @@ PredictScaleForContent(nsIFrame* aFrame,
 }
 
 gfxSize
 FrameLayerBuilder::GetThebesLayerScaleForFrame(nsIFrame* aFrame)
 {
   nsIFrame* last;
   for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
     last = f;
-    LayerManagerData *data = GetDefaultLayerManagerDataForFrame(f);
-    if (!data)
-      continue;
-    DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(f);
-    // Some frames with NS_FRAME_HAS_CONTAINER_LAYER may not have display items.
-    // In particular the root frame probably doesn't!
-    if (!entry)
-      continue;
-    nsTArray<nsRefPtr<DisplayItemData> >* array = &entry->mData;
-    for (uint32_t i = 0; i < array->Length(); ++i) {
-      Layer* layer = array->ElementAt(i)->mLayer;
-      ContainerLayer* container = layer->AsContainerLayer();
-      if (!container) {
-        continue;
-      }
-      for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
-        ThebesDisplayItemLayerUserData* data =
-            static_cast<ThebesDisplayItemLayerUserData*>
-              (l->GetUserData(&gThebesDisplayItemLayerUserData));
-        if (data) {
-          return PredictScaleForContent(aFrame, f, gfxSize(data->mXScale, data->mYScale));
+    if (f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) {
+      nsTArray<DisplayItemData>* array = GetDisplayItemDataArrayForFrame(f);
+	  // Some frames with NS_FRAME_HAS_CONTAINER_LAYER may not have display items.
+	  // In particular the root frame probably doesn't!
+      if (!array)
+	    continue;
+      for (uint32_t i = 0; i < array->Length(); ++i) {
+        Layer* layer = array->ElementAt(i).mLayer;
+        ContainerLayer* container = layer->AsContainerLayer();
+        if (!container) {
+          continue;
+        }
+        for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
+          ThebesDisplayItemLayerUserData* data =
+              static_cast<ThebesDisplayItemLayerUserData*>
+                (l->GetUserData(&gThebesDisplayItemLayerUserData));
+          if (data) {
+            return PredictScaleForContent(aFrame, f, gfxSize(data->mXScale, data->mYScale));
+          }
         }
       }
     }
   }
 
   return PredictScaleForContent(aFrame, last,
       last->PresContext()->PresShell()->GetResolution());
 }
@@ -3144,16 +2908,24 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
   // Apply the residual transform if it has been enabled, to ensure that
   // snapping when we draw into aContext exactly matches the ideal transform.
   // See above for why this is OK.
   aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y));
   aContext->Scale(userData->mXScale, userData->mYScale);
 
   nsPresContext* presContext = containerLayerFrame->PresContext();
   int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
+  if (!aRegionToInvalidate.IsEmpty()) {
+    nsRect r = (aRegionToInvalidate.GetBounds() + offset).
+      ToAppUnits(appUnitsPerDevPixel);
+    r.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
+    containerLayerFrame->InvalidateWithFlags(r,
+        nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
+        nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
+  }
 
   uint32_t i;
   // Update visible regions. We need perform visibility analysis again
   // because we may be asked to draw into part of a ThebesLayer that
   // isn't actually visible in the window (e.g., because a ThebesLayer
   // expanded its visible region to a rectangle internally), in which
   // case the mVisibleRect stored in the display item may be wrong.
   nsRegion visible = aRegionToDraw.ToAppUnits(appUnitsPerDevPixel);
@@ -3226,17 +2998,17 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
         aContext->Save();
         NS_ASSERTION(commonClipCount < 100,
           "Maybe you really do have more than a hundred clipping rounded rects, or maybe something has gone wrong.");
         currentClip.ApplyTo(aContext, presContext, commonClipCount);
       }
     }
 
     if (cdi->mInactiveLayer) {
-      PaintInactiveLayer(builder, cdi->mInactiveLayer, cdi->mItem, aContext, rc);
+      PaintInactiveLayer(builder, cdi->mItem, aContext, rc, layerBuilder);
     } else {
       nsIFrame* frame = cdi->mItem->GetUnderlyingFrame();
       if (frame) {
         frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
       }
 #ifdef MOZ_DUMP_PAINTING
 
       if (gfxUtils::sDumpPainting) {
@@ -3259,19 +3031,16 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
     items.SwapElements(entry->mItems);
   }
 
   if (setClipRect) {
     aContext->Restore();
   }
 
   FlashPaint(aContext);
-  if (!aRegionToInvalidate.IsEmpty()) {
-    aLayer->AddInvalidRect(aRegionToInvalidate.GetBounds());
-  }
 }
 
 bool
 FrameLayerBuilder::CheckDOMModified()
 {
   if (!mRootPresContext ||
       mInitialDOMGeneration == mRootPresContext->GetDOMGeneration())
     return false;
@@ -3493,53 +3262,16 @@ FrameLayerBuilder::Clip::RemoveRoundedCo
 {
   if (mRoundedClipRects.IsEmpty())
     return;
 
   mClipRect = NonRoundedIntersection();
   mRoundedClipRects.Clear();
 }
 
-static void
-AccumulateRectDifference(const nsRect& aR1, const nsRect& aR2, nsRegion* aOut)
-{
-  if (aR1.IsEqualInterior(aR2))
-    return;
-  nsRegion r;
-  r.Xor(aR1, aR2);
-  aOut->Or(*aOut, r);
-}
-
-void
-FrameLayerBuilder::Clip::AddOffsetAndComputeDifference(const nsPoint& aOffset,
-                                                       const nsRect& aBounds,
-                                                       const Clip& aOther,
-                                                       const nsRect& aOtherBounds,
-                                                       nsRegion* aDifference)
-{
-  if (mHaveClipRect != aOther.mHaveClipRect ||
-      mRoundedClipRects.Length() != aOther.mRoundedClipRects.Length()) {
-    aDifference->Or(*aDifference, aBounds);
-    aDifference->Or(*aDifference, aOtherBounds);
-    return;
-  }
-  if (mHaveClipRect) {
-    AccumulateRectDifference((mClipRect + aOffset).Intersect(aBounds),
-                             aOther.mClipRect.Intersect(aOtherBounds),
-                             aDifference);
-  }
-  for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
-    if (mRoundedClipRects[i] + aOffset != aOther.mRoundedClipRects[i]) {
-      // The corners make it tricky so we'll just add both rects here.
-      aDifference->Or(*aDifference, mRoundedClipRects[i].mRect.Intersect(aBounds));
-      aDifference->Or(*aDifference, aOther.mRoundedClipRects[i].mRect.Intersect(aOtherBounds));
-    }
-  }
-}
-
 gfxRect
 CalculateBounds(const nsTArray<FrameLayerBuilder::Clip::RoundedRect>& aRects, int32_t A2D)
 {
   nsRect bounds = aRects[0].mRect;
   for (uint32_t i = 1; i < aRects.Length(); ++i) {
     bounds.UnionRect(bounds, aRects[i].mRect);
    }
  
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -6,70 +6,62 @@
 #ifndef FRAMELAYERBUILDER_H_
 #define FRAMELAYERBUILDER_H_
 
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 #include "nsRegion.h"
 #include "nsIFrame.h"
-#include "nsDisplayListInvalidation.h"
-#include "LayerTreeInvalidation.h"
-#include "ImageLayers.h"
 
 class nsDisplayListBuilder;
 class nsDisplayList;
 class nsDisplayItem;
 class gfxContext;
 class nsRootPresContext;
 
 namespace mozilla {
 namespace layers {
 class ContainerLayer;
 class LayerManager;
 class ThebesLayer;
 }
 
 class FrameLayerBuilder;
-class LayerManagerData;
 
 enum LayerState {
   LAYER_NONE,
   LAYER_INACTIVE,
   LAYER_ACTIVE,
   // Force an active layer even if it causes incorrect rendering, e.g.
   // when the layer has rounded rect clips.
   LAYER_ACTIVE_FORCE,
   // Special layer that is metadata only.
   LAYER_ACTIVE_EMPTY,
   // Inactive style layer for rendering SVG effects.
   LAYER_SVG_EFFECTS
 };
 
-extern uint8_t gLayerManagerSecondary;
-
-class LayerManagerSecondary : public layers::LayerUserData {
-};
-
 class RefCountedRegion : public RefCounted<RefCountedRegion> {
 public:
   RefCountedRegion() : mIsInfinite(false) {}
   nsRegion mRegion;
   bool mIsInfinite;
 };
 
 /**
- * The FrameLayerBuilder is responsible for converting display lists 
- * into layer trees. Every LayerManager needs a unique FrameLayerBuilder
- * to build layers.
+ * The FrameLayerBuilder belongs to an nsDisplayListBuilder and is
+ * responsible for converting display lists into layer trees.
  * 
  * The most important API in this class is BuildContainerLayerFor. This
  * method takes a display list as input and constructs a ContainerLayer
  * with child layers that render the contents of the display list. It
- * records the relationship between frames and layers.
+ * also updates userdata for the retained layer manager, and
+ * DisplayItemDataProperty data for frames, to record the relationship
+ * between frames and layers.
  * 
  * That data enables us to retain layer trees. When constructing a
  * ContainerLayer, we first check to see if there's an existing
  * ContainerLayer for the same frame that can be recycled. If we recycle
  * it, we also try to reuse its existing ThebesLayer children to render
  * the display items without layers of their own. The idea is that by
  * recycling layers deterministically, we can ensure that when nothing
  * changes in a display list, we will reuse the existing layers without
@@ -78,33 +70,32 @@ public:
  * We expose a GetLeafLayerFor method that can be called by display items
  * that make their own layers (e.g. canvas and video); this method
  * locates the last layer used to render the display item, if any, and
  * return it as a candidate for recycling.
  * 
  * FrameLayerBuilder sets up ThebesLayers so that 0,0 in the Thebes layer
  * corresponds to the (pixel-snapped) top-left of the aActiveScrolledRoot.
  * It sets up ContainerLayers so that 0,0 in the container layer
- * corresponds to the snapped top-left of the display item reference frame.
+ * corresponds to the snapped top-left of the display list reference frame.
  *
  * When we construct a container layer, we know the transform that will be
  * applied to the layer. If the transform scales the content, we can get
  * better results when intermediate buffers are used by pushing some scale
  * from the container's transform down to the children. For ThebesLayer
  * children, the scaling can be achieved by changing the size of the layer
  * and drawing into it with increased or decreased resolution. By convention,
  * integer types (nsIntPoint/nsIntSize/nsIntRect/nsIntRegion) are all in layer
  * coordinates, post-scaling, whereas appunit types are all pre-scaling.
  */
-class FrameLayerBuilder : public layers::LayerUserData {
+class FrameLayerBuilder {
 public:
   typedef layers::ContainerLayer ContainerLayer;
   typedef layers::Layer Layer;
   typedef layers::ThebesLayer ThebesLayer;
-  typedef layers::ImageLayer ImageLayer;
   typedef layers::LayerManager LayerManager;
 
   FrameLayerBuilder() :
     mRetainingManager(nullptr),
     mDetectedDOMModification(false),
     mInvalidateAllLayers(false),
     mContainerLayerGeneration(0),
     mMaxContainerLayerGeneration(0)
@@ -124,24 +115,28 @@ public:
 
   /**
    * Call this to notify that we have just started a transaction on the
    * retained layer manager aManager.
    */
   void DidBeginRetainedLayerTransaction(LayerManager* aManager);
 
   /**
-   * Call this just before we end a transaction.
+   * Call this just before we end a transaction on aManager. If aManager
+   * is not the retained layer manager then it must be a temporary layer
+   * manager that will not be used again.
    */
-  void WillEndTransaction();
+  void WillEndTransaction(LayerManager* aManager);
 
   /**
-   * Call this after we end a transaction.
+   * Call this after we end a transaction on aManager. If aManager
+   * is not the retained layer manager then it must be a temporary layer
+   * manager that will not be used again.
    */
-  void DidEndTransaction();
+  void DidEndTransaction(LayerManager* aManager);
 
   struct ContainerParameters {
     ContainerParameters() :
       mXScale(1), mYScale(1),
       mInTransformedSubtree(false), mInActiveTransformedSubtree(false),
       mDisableSubpixelAntialiasingInDescendants(false)
     {}
     ContainerParameters(float aXScale, float aYScale) :
@@ -212,24 +207,48 @@ public:
    * null if no retained layer is available, which usually means that this
    * display item didn't have a layer before so the caller will
    * need to create one.
    * Returns a layer with clip rect cleared; it is the
    * caller's responsibility to add any clip rect and set the visible
    * region.
    */
   Layer* GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
+                         LayerManager* aManager,
                          nsDisplayItem* aItem);
 
   /**
+   * Call this during invalidation if aFrame has
+   * the NS_FRAME_HAS_CONTAINER_LAYER state bit. Only the nearest
+   * ancestor frame of the damaged frame that has
+   * NS_FRAME_HAS_CONTAINER_LAYER needs to be invalidated this way.
+   * It is assumed that aRect does NOT have the frame's transforms applied.
+   */
+  static void InvalidateThebesLayerContents(nsIFrame* aFrame,
+                                            const nsRect& aRect);
+
+  /**
+   * For any descendant frame of aFrame (including across documents) that
+   * has an associated container layer, invalidate all the contents of
+   * all ThebesLayer children of the container. Useful when aFrame is
+   * being moved and we need to invalidate everything in aFrame's subtree.
+   */
+  static void InvalidateThebesLayersInSubtree(nsIFrame* aFrame);
+
+  /**
+   * As InvalidateThebesLayersInSubtree, but don't trust frame geometry
+   * (e.g. because appunits-per-dev-pixel changed).
+   */
+  static void InvalidateThebesLayersInSubtreeWithUntrustedFrameGeometry(nsIFrame* aFrame);
+
+  /**
    * Call this to force all retained layers to be discarded and recreated at
    * the next paint.
    */
   static void InvalidateAllLayers(LayerManager* aManager);
-  static void InvalidateAllLayersForFrame(nsIFrame *aFrame);
 
   /**
    * Call this to determine if a frame has a dedicated (non-Thebes) layer
    * for the given display item key. If there isn't one, we return null,
    * otherwise we return the layer.
    */
   static Layer* GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey);
 
@@ -255,116 +274,75 @@ public:
 
   /******* PRIVATE METHODS to FrameLayerBuilder.cpp ********/
   /* These are only in the public section because they need
    * to be called by file-scope helper functions in FrameLayerBuilder.cpp.
    */
 
   /**
    * Record aItem as a display item that is rendered by aLayer.
-   *
-   * @param aLayer Layer that the display item will be rendered into
-   * @param aItem Display item to be drawn.
-   * @param aLayerState What LayerState the item is using.
-   * @param aTopLeft offset from active scrolled root to reference frame
-   * @param aManager If the layer is in the LAYER_INACTIVE state,
-   * then this is the temporary layer manager to draw with.
    */
-  struct Clip;
   void AddLayerDisplayItem(Layer* aLayer,
                            nsDisplayItem* aItem,
-                           const Clip& aClip,
-                           LayerState aLayerState,
-                           const nsPoint& aTopLeft,
-                           LayerManager* aManager = nullptr);
+                           LayerState aLayerState);
+
+  /**
+   * Record aFrame as a frame that is rendered by an item on aLayer.
+   */
+  void AddLayerDisplayItemForFrame(Layer* aLayer,
+                                   nsIFrame* aFrame,
+                                   uint32_t aDisplayItemKey,
+                                   LayerState aLayerState);
 
   /**
    * Record aItem as a display item that is rendered by the ThebesLayer
    * aLayer, with aClipRect, where aContainerLayerFrame is the frame
    * for the container layer this ThebesItem belongs to.
    * aItem must have an underlying frame.
-   * @param aTopLeft offset from active scrolled root to reference frame
    */
+  struct Clip;
   void AddThebesDisplayItem(ThebesLayer* aLayer,
                             nsDisplayItem* aItem,
                             const Clip& aClip,
                             nsIFrame* aContainerLayerFrame,
-                            LayerState aLayerState,
-                            const nsPoint& aTopLeft);
-
-  /**
-   * Set the current top-level LayerManager for the widget being
-   * painted.
-   */
-  static void SetWidgetLayerManager(LayerManager* aManager)
-  {
-    LayerManagerSecondary* secondary = 
-      static_cast<LayerManagerSecondary*>(aManager->GetUserData(&gLayerManagerSecondary));
-    sWidgetManagerSecondary = !!secondary;
-  }
-
-  /**
-   * Gets the frame property descriptor for the given manager, or for the current
-   * widget layer manager if nullptr is passed.
-   */
-  static const FramePropertyDescriptor* GetDescriptorForManager(LayerManager* aManager);
+                            LayerState aLayerState);
 
   /**
-   * Get the LayerManagerData for a given frame and layer manager. If no layer manager
-   * is passed, then the current widget layer manager is used.
-   */
-  static LayerManagerData* GetManagerData(nsIFrame* aFrame, LayerManager* aManager = nullptr);
-
-  /**
-   * Set the LayerManagerData for a given frame and current widget layer manager.
-   * This replaces any existing data for the same frame/layer manager pair.
+   * Given a frame and a display item key that uniquely identifies a
+   * display item for the frame, find the layer that was last used to
+   * render that display item. Returns null if there is no such layer.
+   * This could be a dedicated layer for the display item, or a ThebesLayer
+   * that renders many display items.
    */
-  static void SetManagerData(nsIFrame* aFrame, LayerManagerData* aData);
-
-  /**
-   * Clears the current LayerManagerData for the given frame and current widget
-   * layer manager.
-   */
-  static void ClearManagerData(nsIFrame* aFrame);
-
-  /**
-   * Clears any references to the given LayerManagerData for the given frame
-   * and belonging to any layer manager.
-   */
-  static void ClearManagerData(nsIFrame* aFrame, LayerManagerData* aData);
+  Layer* GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey);
 
   /**
    * Calls GetOldLayerForFrame on the underlying frame of the display item,
    * and each subsequent merged frame if no layer is found for the underlying
    * frame.
    */
-  Layer* GetOldLayerFor(nsDisplayItem* aItem, nsDisplayItemGeometry** aOldGeometry = nullptr, Clip** aOldClip = nullptr);
+  Layer* GetOldLayerFor(nsDisplayItem* aItem);
 
   static Layer* GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
-
-  /**
-   * If the display item was previously drawn as an inactive layer,
-   * then return the layer manager used for the inactive transaction.
-   * Returns nullptr if no manager could be found.
-   */
-  LayerManager* GetInactiveLayerManagerFor(nsDisplayItem* aItem);
-
   /**
    * Try to determine whether the ThebesLayer aLayer paints an opaque
    * single color everywhere it's visible in aRect.
    * If successful, return that color, otherwise return NS_RGBA(0,0,0,0).
    */
   nscolor FindOpaqueColorCovering(nsDisplayListBuilder* aBuilder,
                                   ThebesLayer* aLayer, const nsRect& aRect);
 
   /**
    * Destroy any stored LayerManagerDataProperty and the associated data for
    * aFrame.
    */
-  static void DestroyDisplayItemDataFor(nsIFrame* aFrame);
+  static void DestroyDisplayItemDataFor(nsIFrame* aFrame)
+  {
+    aFrame->Properties().Delete(LayerManagerDataProperty());
+  }
 
   LayerManager* GetRetainingLayerManager() { return mRetainingManager; }
 
   /**
    * Returns true if the given item (which we assume here is
    * background-attachment:fixed) needs to be repainted as we scroll in its
    * document.
    * Returns false if it doesn't need to be repainted because the layer system
@@ -373,31 +351,21 @@ public:
   static bool NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder,
                                                  nsDisplayItem* aItem);
 
   /**
    * Returns true if the given display item was rendered directly
    * into a retained layer.
    * Returns false if it was rendered into a temporary layer manager and then
    * into a retained layer.
-   *
-   * Since display items can belong to multiple retained LayerManagers, we need to
-   * specify which LayerManager to check.
    */
-  static bool HasRetainedLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey, LayerManager* aManager);
+  static bool HasRetainedLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
 
   /**
-   * Returns true if the given display item was rendered during the previous
-   * paint. Returns false otherwise.
-   */
-  static bool HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
-
-  /**
-   * Save transform that was in aLayer when we last painted, and the position
-   * of the active scrolled root frame. It must be an integer
+   * Save transform that was in aLayer when we last painted. It must be an integer
    * translation.
    */
   void SaveLastPaintOffset(ThebesLayer* aLayer);
   /**
    * Get the translation transform that was in aLayer when we last painted. It's either
    * the transform saved by SaveLastPaintTransform, or else the transform
    * that's currently in the layer (which must be an integer translation).
    */
@@ -408,38 +376,25 @@ public:
    * assuming they are being painted to retained layers. This takes into account
    * the resolution the contents of the ContainerLayer containing aFrame are
    * being rendered at, as well as any currently-inactive transforms between
    * aFrame and that container layer.
    */
   static gfxSize GetThebesLayerScaleForFrame(nsIFrame* aFrame);
 
   /**
-   * Stores a Layer as the dedicated layer in the DisplayItemData for a given frame/key pair.
-   *
-   * Used when we optimize a ThebesLayer into an ImageLayer and want to retroactively update the 
-   * DisplayItemData so we can retrieve the layer from within layout.
-   */
-  void StoreOptimizedLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey, Layer* aImage);
-
-  /**
    * Clip represents the intersection of an optional rectangle with a
    * list of rounded rectangles.
    */
   struct Clip {
     struct RoundedRect {
       nsRect mRect;
       // Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
       nscoord mRadii[8];
 
-      RoundedRect operator+(const nsPoint& aOffset) const {
-        RoundedRect r = *this;
-        r.mRect += aOffset;
-        return r;
-      }
       bool operator==(const RoundedRect& aOther) const {
         if (!mRect.IsEqualInterior(aOther.mRect)) {
           return false;
         }
 
         NS_FOR_CSS_HALF_CORNERS(corner) {
           if (mRadii[corner] != aOther.mRadii[corner]) {
             return false;
@@ -492,165 +447,106 @@ public:
     bool IsRectClippedByRoundedCorner(const nsRect& aRect) const;
 
     // Intersection of all rects in this clip ignoring any rounded corners.
     nsRect NonRoundedIntersection() const;
 
     // Gets rid of any rounded corners in this clip.
     void RemoveRoundedCorners();
 
-    // Adds the difference between Intersect(*this + aPoint, aBounds) and
-    // Intersect(aOther, aOtherBounds) to aDifference.
-    void AddOffsetAndComputeDifference(const nsPoint& aPoint, const nsRect& aBounds,
-                                       const Clip& aOther, const nsRect& aOtherBounds,
-                                       nsRegion* aDifference);
-
     bool operator==(const Clip& aOther) const {
       return mHaveClipRect == aOther.mHaveClipRect &&
              (!mHaveClipRect || mClipRect.IsEqualInterior(aOther.mClipRect)) &&
              mRoundedClipRects == aOther.mRoundedClipRects;
     }
     bool operator!=(const Clip& aOther) const {
       return !(*this == aOther);
     }
   };
-  
-  NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty,
-                                               RemoveFrameFromLayerManager)
-
-  NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerSecondaryDataProperty,
-                                               RemoveFrameFromLayerManager)
 
 protected:
   /**
    * We store an array of these for each frame that is associated with
    * one or more retained layers. Each DisplayItemData records the layer
    * used to render one of the frame's display items.
    */
   class DisplayItemData {
   public:
     DisplayItemData(Layer* aLayer, uint32_t aKey, LayerState aLayerState, uint32_t aGeneration);
-    DisplayItemData()
-      : mUsed(false)
-    {}
-    DisplayItemData(DisplayItemData &toCopy);
     ~DisplayItemData();
 
-    NS_INLINE_DECL_REFCOUNTING(DisplayItemData)
-
-    void AddFrame(nsIFrame* aFrame)
-    {
-      mFrameList.AppendElement(aFrame);
-    }
-
-    bool FrameListMatches(nsDisplayItem* aOther);
-
     nsRefPtr<Layer> mLayer;
-    nsRefPtr<Layer> mOptLayer;
-    nsRefPtr<LayerManager> mInactiveManager;
-    nsAutoTArray<nsIFrame*, 2> mFrameList;
-    nsAutoPtr<nsDisplayItemGeometry> mGeometry;
-    Clip            mClip;
     uint32_t        mDisplayItemKey;
     uint32_t        mContainerLayerGeneration;
     LayerState      mLayerState;
-
-    /**
-     * Used to track if data currently stored in mFramesWithLayers (from an existing
-     * paint) is also used in the current paint and has an equivalent data object
-     * in mNewDisplayItemData.
-     */
-    bool            mUsed;
   };
 
   static void RemoveFrameFromLayerManager(nsIFrame* aFrame, void* aPropertyValue);
 
-  /**
-   * Given a frame and a display item key that uniquely identifies a
-   * display item for the frame, find the layer that was last used to
-   * render that display item. Returns null if there is no such layer.
-   * This could be a dedicated layer for the display item, or a ThebesLayer
-   * that renders many display items.
-   */
-  DisplayItemData* GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey);
+  NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty,
+                                               RemoveFrameFromLayerManager)
 
   /**
    * We accumulate DisplayItemData elements in a hashtable during
-   * the paint process, one per visible display item.
-   * There is one hashtable per layer manager, and one entry
-   * per frame. This is the hashentry for that hashtable.
+   * the paint process, and store them in the frame property only when
+   * paint is complete. This is the hashentry for that hashtable.
    */
   class DisplayItemDataEntry : public nsPtrHashKey<nsIFrame> {
   public:
     DisplayItemDataEntry(const nsIFrame *key)
       : nsPtrHashKey<nsIFrame>(key)
-    { 
-      MOZ_COUNT_CTOR(DisplayItemDataEntry); 
-    }
+      , mIsSharingContainerLayer(false)
+      {}
     DisplayItemDataEntry(DisplayItemDataEntry &toCopy)
       : nsPtrHashKey<nsIFrame>(toCopy.mKey)
+      , mIsSharingContainerLayer(toCopy.mIsSharingContainerLayer)
     {
-      MOZ_COUNT_CTOR(DisplayItemDataEntry);
       // This isn't actually a copy-constructor; notice that it steals toCopy's
       // array and invalid region.  Be careful.
       mData.SwapElements(toCopy.mData);
+      mInvalidRegion.swap(toCopy.mInvalidRegion);
       mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
     }
-    ~DisplayItemDataEntry() { MOZ_COUNT_DTOR(DisplayItemDataEntry); }
 
     bool HasNonEmptyContainerLayer();
 
-    nsAutoTArray<nsRefPtr<DisplayItemData>, 1> mData;
+    nsAutoTArray<DisplayItemData, 1> mData;
+    nsRefPtr<RefCountedRegion> mInvalidRegion;
     uint32_t mContainerLayerGeneration;
+    bool mIsSharingContainerLayer;
 
     enum { ALLOW_MEMMOVE = false };
   };
 
   // LayerManagerData needs to see DisplayItemDataEntry.
   friend class LayerManagerData;
 
-  /**
-   * Stores DisplayItemData associated with aFrame, stores the data in
-   * mNewDisplayItemData.
-   */
-  void StoreDataForFrame(nsIFrame* aFrame, DisplayItemData* data);
-
   // Flash the area within the context clip if paint flashing is enabled.
   static void FlashPaint(gfxContext *aContext);
 
   /*
    * Get the DisplayItemData array associated with this frame, or null if one
    * doesn't exist.
    *
    * Note that the pointer returned here is only valid so long as you don't
    * poke the LayerManagerData's mFramesWithLayers hashtable.
    */
-  nsTArray<nsRefPtr<DisplayItemData> >* GetDisplayItemDataArrayForFrame(nsIFrame *aFrame);
-
-  /*
-   * Get the DisplayItemData associated with this frame / display item pair,
-   * using the LayerManager instead of FrameLayerBuilder.
-   */
-  static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame, 
-                                                       uint32_t aDisplayItemKey, 
-                                                       LayerManager* aManager);
-  static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame, 
-                                                       uint32_t aDisplayItemKey);
-  static DisplayItemData* GetDisplayItemDataForManager(nsDisplayItem* aItem, LayerManager* aManager);
-  static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame, 
-                                                       uint32_t aDisplayItemKey, 
-                                                       LayerManagerData* aData);
+  static nsTArray<DisplayItemData>* GetDisplayItemDataArrayForFrame(nsIFrame *aFrame);
 
   /**
    * A useful hashtable iteration function that removes the
-   * DisplayItemData property for the frame and returns PL_DHASH_REMOVE.
+   * DisplayItemData property for the frame, clears its
+   * NS_FRAME_HAS_CONTAINER_LAYER bit and returns PL_DHASH_REMOVE.
    * aClosure is ignored.
    */
   static PLDHashOperator RemoveDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
-                                                       void* aClosure);
+                                                       void* aClosure)
+  {
+    return UpdateDisplayItemDataForFrame(aEntry, nullptr);
+  }
 
   /**
    * We store one of these for each display item associated with a
    * ThebesLayer, in a hashtable that maps each ThebesLayer to an array
    * of ClippedDisplayItems. (ThebesLayerItemsEntry is the hash entry
    * for that hashtable.)
    * These are only stored during the paint process, so that the
    * DrawThebesLayer callback can figure out which items to draw for the
@@ -658,29 +554,20 @@ protected:
    * mItem always has an underlying frame.
    */
   struct ClippedDisplayItem {
     ClippedDisplayItem(nsDisplayItem* aItem, const Clip& aClip, uint32_t aGeneration)
       : mItem(aItem), mClip(aClip), mContainerLayerGeneration(aGeneration)
     {
     }
 
-    ~ClippedDisplayItem();
-
     nsDisplayItem* mItem;
-
-    /**
-     * If the display item is being rendered as an inactive
-     * layer, then this stores the layer manager being
-     * used for the inactive transaction.
-     */
-    nsRefPtr<LayerManager> mInactiveLayer;
-
     Clip mClip;
     uint32_t mContainerLayerGeneration;
+    bool mInactiveLayer;
   };
 
   /**
    * We accumulate ClippedDisplayItem elements in a hashtable during
    * the paint process. This is the hashentry for that hashtable.
    */
 public:
   class ThebesLayerItemsEntry : public nsPtrHashKey<ThebesLayer> {
@@ -715,18 +602,16 @@ public:
    * Get the ThebesLayerItemsEntry object associated with aLayer in this
    * FrameLayerBuilder
    */
   ThebesLayerItemsEntry* GetThebesLayerItemsEntry(ThebesLayer* aLayer)
   {
     return mThebesLayerItems.GetEntry(aLayer);
   }
 
-  static PLDHashOperator ProcessRemovedDisplayItems(DisplayItemDataEntry* aEntry,
-                                                    void* aUserArg);
 protected:
   void RemoveThebesItemsAndOwnerDataForLayerSubtree(Layer* aLayer,
                                                     bool aRemoveThebesItems,
                                                     bool aRemoveOwnerData);
 
   static void SetAndClearInvalidRegion(DisplayItemDataEntry* aEntry);
   static PLDHashOperator UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
                                                        void* aUserArg);
@@ -749,21 +634,16 @@ protected:
    * The layer manager belonging to the widget that is being retained
    * across paints.
    */
   LayerManager*                       mRetainingManager;
   /**
    * The root prescontext for the display list builder reference frame
    */
   nsRootPresContext*                  mRootPresContext;
-
-  /**
-   * The display list builder being used.
-   */
-  nsDisplayListBuilder*               mDisplayListBuilder;
   /**
    * A map from frames to a list of (display item key, layer) pairs that
    * describes what layers various parts of the frame are assigned to.
    */
   nsTHashtable<DisplayItemDataEntry>  mNewDisplayItemData;
   /**
    * A map from ThebesLayers to the list of display items (plus
    * clipping data) to be rendered in the layer.
@@ -781,19 +661,13 @@ protected:
   /**
    * Indicates that the entire layer tree should be rerendered
    * during this paint.
    */
   bool                                mInvalidateAllLayers;
 
   uint32_t                            mContainerLayerGeneration;
   uint32_t                            mMaxContainerLayerGeneration;
-
-  /**
-   * True if the current top-level LayerManager for the widget being
-   * painted is marked as being a 'secondary' LayerManager.
-   */
-  static bool                         sWidgetManagerSecondary;
 };
 
 }
 
 #endif /* FRAMELAYERBUILDER_H_ */
--- a/layout/base/Makefile.in
+++ b/layout/base/Makefile.in
@@ -33,17 +33,16 @@ EXPORTS		= \
 		nsBidi.h \
 		nsBidiPresUtils.h \
 		nsCaret.h \
 		nsCSSFrameConstructor.h \
 		nsChangeHint.h \
 		nsCompatibility.h \
 		nsDisplayItemTypes.h \
 		nsDisplayList.h \
-		nsDisplayListInvalidation.h \
 		nsFrameManager.h \
 		nsFrameManagerBase.h \
 		nsFrameIterator.h \
 		nsILayoutDebugger.h \
 		nsILayoutHistoryState.h \
 		nsIPercentHeightObserver.h  \
 		nsIPresShell.h \
 		nsIReflowCallback.h \
@@ -69,17 +68,16 @@ CPPSRCS		= \
 		nsCSSColorUtils.cpp \
 		nsCSSFrameConstructor.cpp \
 		nsCSSRendering.cpp \
 		nsCSSRenderingBorders.cpp \
 		nsCaret.cpp \
 		nsChildIterator.cpp \
 		nsCounterManager.cpp \
 		nsDisplayList.cpp \
-		nsDisplayListInvalidation.cpp \
 		nsDocumentViewer.cpp \
 		nsFrameManager.cpp \
 		nsFrameIterator.cpp \
 		nsGenConList.cpp \
 		nsLayoutDebugger.cpp \
 		nsLayoutHistoryState.cpp \
 		nsLayoutUtils.cpp \
 		nsPresArena.cpp \
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7699,16 +7699,21 @@ UpdateViewsForTree(nsIFrame* aFrame,
           do {
             DoApplyRenderingChangeToTree(outOfFlowFrame, aFrameManager,
                                          aChange);
           } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
         } else if (lists.CurrentID() == nsIFrame::kPopupList) {
           DoApplyRenderingChangeToTree(child, aFrameManager,
                                        aChange);
         } else {  // regular frame
+          if ((child->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) &&
+              (aChange & nsChangeHint_RepaintFrame)) {
+            FrameLayerBuilder::InvalidateThebesLayerContents(child,
+              child->GetVisualOverflowRectRelativeToSelf());
+          }
           UpdateViewsForTree(child, aFrameManager, aChange);
         }
       }
     }
   }
 }
 
 static void
@@ -7740,39 +7745,46 @@ DoApplyRenderingChangeToTree(nsIFrame* a
         if (aChange & nsChangeHint_UpdateEffects) {
           // Invalidate and update our area:
           nsSVGUtils::InvalidateAndScheduleReflowSVG(aFrame);
         } else {
           // Just invalidate our area:
           nsSVGUtils::InvalidateBounds(aFrame);
         }
       } else {
-        aFrame->InvalidateFrameSubtree();
+        aFrame->InvalidateOverflowRect();
       }
     }
     if (aChange & nsChangeHint_UpdateOpacityLayer) {
       aFrame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
+      aFrame->InvalidateLayer(aFrame->GetVisualOverflowRectRelativeToSelf(),
+                              nsDisplayItem::TYPE_OPACITY);
     }
     
     if (aChange & nsChangeHint_UpdateTransformLayer) {
       aFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
+      // Invalidate the old transformed area. The new transformed area
+      // will be invalidated by nsFrame::FinishAndStoreOverflowArea.
+      aFrame->InvalidateTransformLayer();
     }
     if (aChange & nsChangeHint_ChildrenOnlyTransform) {
       // The long comment in ProcessRestyledFrames that precedes the
       // |frame->GetContent()->GetPrimaryFrame()| and abort applies here too.
       nsIFrame *f = aFrame->GetContent()->GetPrimaryFrame();
       NS_ABORT_IF_FALSE(f->IsFrameOfType(nsIFrame::eSVG |
                                          nsIFrame::eSVGContainer),
                         "Children-only transforms only expected on SVG frames");
       nsIFrame* childFrame = f->GetFirstPrincipalChild();
       for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
         childFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
-      }
-    }
-    aFrame->SchedulePaint();
+        // Invalidate the old transformed area. The new transformed area
+        // will be invalidated by nsFrame::FinishAndStoreOverflowArea.
+        childFrame->InvalidateTransformLayer();
+      }
+    }
   }
 }
 
 static void
 ApplyRenderingChangeToTree(nsPresContext* aPresContext,
                            nsIFrame* aFrame,
                            nsChangeHint aChange)
 {
@@ -12416,35 +12428,39 @@ nsCSSFrameConstructor::RecomputePosition
   }
 
   const nsStyleDisplay* display = aFrame->GetStyleDisplay();
   // Changes to the offsets of a non-positioned element can safely be ignored.
   if (display->mPosition == NS_STYLE_POSITION_STATIC) {
     return true;
   }
 
-  aFrame->SchedulePaint();
-
   // For relative positioning, we can simply update the frame rect
   if (display->mPosition == NS_STYLE_POSITION_RELATIVE) {
     nsIFrame* cb = aFrame->GetContainingBlock();
     const nsSize size = cb->GetSize();
     const nsPoint oldOffsets = aFrame->GetRelativeOffset();
     nsMargin newOffsets;
 
+    // Invalidate the old rect
+    aFrame->InvalidateOverflowRect();
+
     // Move the frame
     nsHTMLReflowState::ComputeRelativeOffsets(
         cb->GetStyleVisibility()->mDirection,
         aFrame, size.width, size.height, newOffsets);
     NS_ASSERTION(newOffsets.left == -newOffsets.right &&
                  newOffsets.top == -newOffsets.bottom,
                  "ComputeRelativeOffsets should return valid results");
     aFrame->SetPosition(aFrame->GetPosition() - oldOffsets +
                         nsPoint(newOffsets.left, newOffsets.top));
 
+    // Invalidate the new rect
+    aFrame->InvalidateFrameSubtree();
+
     return true;
   }
 
   // For absolute positioning, the width can potentially change if width is
   // auto and either of left or right are not.  The height can also potentially
   // change if height is auto and either of top or bottom are not.  In these
   // cases we fall back to a reflow, and in all other cases, we attempt to
   // move the frame here.
@@ -12505,23 +12521,29 @@ nsCSSFrameConstructor::RecomputePosition
 
     if (NS_AUTOOFFSET == reflowState.mComputedOffsets.top) {
       reflowState.mComputedOffsets.top = cbSize.height -
                                          reflowState.mComputedOffsets.bottom -
                                          reflowState.mComputedMargin.bottom -
                                          size.height -
                                          reflowState.mComputedMargin.top;
     }
-    
+
+    // Invalidate the old rect
+    aFrame->InvalidateFrameSubtree();
+
     // Move the frame
     nsPoint pos(parentBorder.left + reflowState.mComputedOffsets.left +
                 reflowState.mComputedMargin.left,
                 parentBorder.top + reflowState.mComputedOffsets.top +
                 reflowState.mComputedMargin.top);
     aFrame->SetPosition(pos);
 
+    // Invalidate the new rect
+    aFrame->InvalidateFrameSubtree();
+
     return true;
   }
 
   // Fall back to a reflow
   StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
   return false;
 }
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -478,19 +478,18 @@ nsIFrame * nsCaret::GetCaretFrame(int32_
   return frame;
 }
 
 void nsCaret::InvalidateOutsideCaret()
 {
   nsIFrame *frame = GetCaretFrame();
 
   // Only invalidate if we are not fully contained by our frame's rect.
-  if (frame && !frame->GetVisualOverflowRect().Contains(GetCaretRect())) {
-    frame->SchedulePaint();
-  }
+  if (frame && !frame->GetVisualOverflowRect().Contains(GetCaretRect()))
+    InvalidateRects(mCaretRect, GetHookRect(), frame);
 }
 
 void nsCaret::UpdateCaretPosition()
 {
   // We'll recalculate anyway if we're not drawn right now.
   if (!mDrawn)
     return;
 
@@ -609,19 +608,41 @@ nsresult nsCaret::PrimeTimer()
 
     mBlinkTimer->InitWithFuncCallback(CaretBlinkCallback, this, mBlinkRate,
                                       nsITimer::TYPE_REPEATING_SLACK);
   }
 
   return NS_OK;
 }
 
+void nsCaret::InvalidateTextOverflowBlock()
+{
+  // If the nearest block has a potential 'text-overflow' marker then
+  // invalidate it.
+  if (mLastContent) {
+    nsIFrame* caretFrame = mLastContent->GetPrimaryFrame();
+    if (caretFrame) {
+      nsIFrame* block = nsLayoutUtils::GetAsBlock(caretFrame) ? caretFrame :
+        nsLayoutUtils::FindNearestBlockAncestor(caretFrame);
+      if (block) {
+        const nsStyleTextReset* style = block->GetStyleTextReset();
+        if (style->mTextOverflow.mLeft.mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
+            style->mTextOverflow.mRight.mType != NS_STYLE_TEXT_OVERFLOW_CLIP) {
+          block->InvalidateOverflowRect();
+        }
+      }
+    }
+  }
+}
+
 //-----------------------------------------------------------------------------
 void nsCaret::StartBlinking()
 {
+  InvalidateTextOverflowBlock();
+
   if (mReadOnly) {
     // Make sure the one draw command we use for a readonly caret isn't
     // done until the selection is set
     DrawCaretAfterBriefDelay();
     return;
   }
   PrimeTimer();
 
@@ -635,16 +656,18 @@ void nsCaret::StartBlinking()
 
   DrawCaret(true);    // draw it right away
 }
 
 
 //-----------------------------------------------------------------------------
 void nsCaret::StopBlinking()
 {
+  InvalidateTextOverflowBlock();
+
   if (mDrawn)     // erase the caret if necessary
     DrawCaret(true);
 
   NS_ASSERTION(!mDrawn, "Caret still drawn after StopBlinking().");
   KillTimer();
 }
 
 bool
@@ -693,17 +716,17 @@ nsCaret::DrawAtPositionWithHint(nsIDOMNo
     }
 
     // Only update the caret's rect when we're not currently drawn.
     if (!UpdateCaretRects(theFrame, theFrameOffset))
       return false;
   }
 
   if (aInvalidate)
-    theFrame->SchedulePaint();
+    InvalidateRects(mCaretRect, mHookRect, theFrame);
 
   return true;
 }
 
 nsresult 
 nsCaret::GetCaretFrameForNodeOffset(nsIContent*             aContentNode,
                                     int32_t                 aOffset,
                                     nsFrameSelection::HINT aFrameHint,
@@ -1109,16 +1132,26 @@ nsCaret::UpdateCaretRects(nsIFrame* aFra
                       mCaretRect.y + bidiIndicatorSize,
                       bidiIndicatorSize,
                       mCaretRect.width);
   }
 #endif //IBMBIDI
   return true;
 }
 
+// static
+void nsCaret::InvalidateRects(const nsRect &aRect, const nsRect &aHook,
+                              nsIFrame *aFrame)
+{
+  NS_ASSERTION(aFrame, "Must have a frame to invalidate");
+  nsRect rect;
+  rect.UnionRect(aRect, aHook);
+  aFrame->Invalidate(rect);
+}
+
 //-----------------------------------------------------------------------------
 /* static */
 void nsCaret::CaretBlinkCallback(nsITimer *aTimer, void *aClosure)
 {
   nsCaret   *theCaret = reinterpret_cast<nsCaret*>(aClosure);
   if (!theCaret) return;
   
   theCaret->DrawCaret(true);
--- a/layout/base/nsCaret.h
+++ b/layout/base/nsCaret.h
@@ -168,16 +168,20 @@ class nsCaret : public nsISelectionListe
 protected:
 
     void          KillTimer();
     nsresult      PrimeTimer();
 
     void          StartBlinking();
     void          StopBlinking();
 
+    // If the nearest block has a potential 'text-overflow' marker then
+    // invalidate it.
+    void          InvalidateTextOverflowBlock();
+    
     bool          DrawAtPositionWithHint(nsIDOMNode* aNode,
                                          int32_t aOffset,
                                          nsFrameSelection::HINT aFrameHint,
                                          uint8_t aBidiLevel,
                                          bool aInvalidate);
 
     struct Metrics {
       nscoord mBidiIndicatorSize; // width and height of bidi indicator
@@ -194,16 +198,18 @@ protected:
     // is true, we don't take into account whether the caret is currently
     // drawn or not. This can be used to determine if the caret is drawn when
     // it shouldn't be.
     bool          MustDrawCaret(bool aIgnoreDrawnState);
 
     void          DrawCaret(bool aInvalidate);
     void          DrawCaretAfterBriefDelay();
     bool          UpdateCaretRects(nsIFrame* aFrame, int32_t aFrameOffset);
+    static void   InvalidateRects(const nsRect &aRect, const nsRect &aHook,
+                                  nsIFrame *aFrame);
     nsRect        GetHookRect()
     {
 #ifdef IBMBIDI
       return mHookRect;
 #else
       return nsRect();
 #endif
     }
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -23,17 +23,16 @@
 #include "gfxContext.h"
 #include "nsStyleStructInlines.h"
 #include "nsStyleTransformMatrix.h"
 #include "gfxMatrix.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsIScrollableFrame.h"
 #include "nsThemeConstants.h"
-#include "LayerTreeInvalidation.h"
 
 #include "imgIContainer.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "BasicLayers.h"
 #include "nsBoxFrame.h"
 #include "nsViewportFrame.h"
 #include "nsSVGEffects.h"
 #include "nsSVGElement.h"
@@ -965,32 +964,27 @@ void nsDisplayList::PaintRoot(nsDisplayL
 void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
                                   nsRenderingContext* aCtx,
                                   nsIFrame* aForFrame,
                                   uint32_t aFlags) const {
   NS_ASSERTION(mDidComputeVisibility,
                "Must call ComputeVisibility before calling Paint");
 
   nsRefPtr<LayerManager> layerManager;
-  bool widgetTransaction = false;
   bool allowRetaining = false;
   bool doBeginTransaction = true;
-  nsIView *view = nullptr;
   if (aFlags & PAINT_USE_WIDGET_LAYERS) {
     nsIFrame* rootReferenceFrame = aBuilder->RootReferenceFrame();
-    view = rootReferenceFrame->GetView();
     NS_ASSERTION(rootReferenceFrame == nsLayoutUtils::GetDisplayRootFrame(rootReferenceFrame),
                  "Reference frame must be a display root for us to use the layer manager");
     nsIWidget* window = rootReferenceFrame->GetNearestWidget();
     if (window) {
       layerManager = window->GetLayerManager(&allowRetaining);
       if (layerManager) {
         doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION);
-        FrameLayerBuilder::SetWidgetLayerManager(layerManager);
-        widgetTransaction = true;
       }
     }
   }
   if (!layerManager) {
     if (!aCtx) {
       NS_WARNING("Nowhere to paint into");
       return;
     }
@@ -1013,35 +1007,21 @@ void nsDisplayList::PaintForFrame(nsDisp
   }
   if (allowRetaining) {
     layerBuilder->DidBeginRetainedLayerTransaction(layerManager);
   }
 
   nsPresContext* presContext = aForFrame->PresContext();
   nsIPresShell* presShell = presContext->GetPresShell();
 
-  NotifySubDocInvalidationFunc computeInvalidFunc =
-    presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
-  bool computeInvalidRect = (computeInvalidFunc ||
-                             (layerManager->GetBackendType() == LAYERS_BASIC)) &&
-                            widgetTransaction;
-
-  nsAutoPtr<LayerProperties> props(computeInvalidRect ? 
-                                     LayerProperties::CloneFrom(layerManager->GetRoot()) : 
-                                     nullptr);
-
   nsDisplayItem::ContainerParameters containerParameters
     (presShell->GetXResolution(), presShell->GetYResolution());
   nsRefPtr<ContainerLayer> root = layerBuilder->
     BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, *this,
                            containerParameters, nullptr);
-  
-  if (widgetTransaction) {
-    aForFrame->ClearInvalidationStateBits();
-  }
 
   if (!root) {
     layerManager->RemoveUserData(&gLayerManagerLayerBuilder);
     return;
   }
   // Root is being scaled up by the X/Y resolution. Scale it back down.
   root->SetPostScale(1.0f/containerParameters.mXScale,
                      1.0f/containerParameters.mYScale);
@@ -1077,44 +1057,22 @@ void nsDisplayList::PaintForFrame(nsDisp
   if (usingDisplayport &&
       !(root->GetContentFlags() & Layer::CONTENT_OPAQUE)) {
     // See bug 693938, attachment 567017
     NS_WARNING("We don't support transparent content with displayports, force it to be opqaue");
     root->SetContentFlags(Layer::CONTENT_OPAQUE);
   }
 
   layerManager->SetRoot(root);
-  layerBuilder->WillEndTransaction();
+  layerBuilder->WillEndTransaction(layerManager);
   bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
   layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
                                aBuilder, (aFlags & PAINT_NO_COMPOSITE) ? LayerManager::END_NO_COMPOSITE : LayerManager::END_DEFAULT);
   aBuilder->SetIsCompositingCheap(temp);
-  layerBuilder->DidEndTransaction();
-
-  nsIntRect invalid;
-  if (props) {
-    invalid = props->ComputeDifferences(root, computeInvalidFunc);
-  } else if (widgetTransaction) {
-    LayerProperties::ClearInvalidations(root);
-  }
-
-  if (view) {
-    if (props) {
-      if (!invalid.IsEmpty()) {
-        nsRect rect(presContext->DevPixelsToAppUnits(invalid.x),
-                    presContext->DevPixelsToAppUnits(invalid.y),
-                    presContext->DevPixelsToAppUnits(invalid.width),
-                    presContext->DevPixelsToAppUnits(invalid.height));
-        view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
-        presContext->NotifyInvalidation(invalid, 0);
-      }
-    } else {
-      view->GetViewManager()->InvalidateView(view);
-    }
-  }
+  layerBuilder->DidEndTransaction(layerManager);
 
   if (aFlags & PAINT_FLUSH_LAYERS) {
     FrameLayerBuilder::InvalidateAllLayers(layerManager);
   }
 
   nsCSSRendering::DidPaint();
   layerManager->RemoveUserData(&gLayerManagerLayerBuilder);
 }
@@ -1899,17 +1857,17 @@ nsDisplayBackground::GetInsideClipRegion
 nsRegion
 nsDisplayBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                      bool* aSnap) {
   nsRegion result;
   *aSnap = false;
   // theme background overrides any other background
   if (mIsThemed) {
     if (mThemeTransparency == nsITheme::eOpaque) {
-      result = nsRect(ToReferenceFrame(), mFrame->GetSize());
+      result = GetBounds(aBuilder, aSnap);
     }
     return result;
   }
 
   nsStyleContext* bgSC;
   nsPresContext* presContext = mFrame->PresContext();
   if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
     return result;
@@ -1999,46 +1957,16 @@ nsDisplayBackground::IsVaryingRelativeTo
   // not the viewport frame, then moving aFrame will move mFrame
   // relative to the viewport, so our fixed-pos background will change.
   return aFrame->GetParent() &&
     (aFrame == mFrame ||
      nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame));
 }
 
 bool
-nsDisplayBackground::RenderingMightDependOnFrameSize()
-{
-  // theme background overrides any other background and we don't know what to do here
-  if (mIsThemed)
-    return true;
-  
-  // We could be smarter with rounded corners and only invalidate the new area + the piece that was previously
-  // clipped out.
-  nscoord radii[8];
-  if (mFrame->GetBorderRadii(radii))
-    return true;
-
-  nsPresContext* presContext = mFrame->PresContext();
-  nsStyleContext *bgSC;
-  bool hasBG =
-    nsCSSRendering::FindBackground(presContext, mFrame, &bgSC);
-  if (!hasBG)
-    return false;
-  const nsStyleBackground* bg = bgSC->GetStyleBackground();
-
-  NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
-    const nsStyleBackground::Layer &layer = bg->mLayers[i];
-    if (layer.RenderingMightDependOnFrameSize()) {
-      return true;
-    }
-  }
-  return false;
-}
-
-bool
 nsDisplayBackground::ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
 {
   return mIsFixed;
 }
 
 void
 nsDisplayBackground::Paint(nsDisplayListBuilder* aBuilder,
                            nsRenderingContext* aCtx) {
@@ -2051,51 +1979,25 @@ nsDisplayBackground::Paint(nsDisplayList
     flags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER;
   }
   nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
                                   mVisibleRect,
                                   nsRect(offset, mFrame->GetSize()),
                                   flags, nullptr, mLayer);
 }
 
-void nsDisplayBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
-                                                    const nsDisplayItemGeometry* aGeometry,
-                                                    nsRegion* aInvalidRegion)
-{
-  const nsDisplayBackgroundGeometry* geometry = static_cast<const nsDisplayBackgroundGeometry*>(aGeometry);
-  if (ShouldFixToViewport(aBuilder)) {
-    // This is incorrect, We definitely need to check more things here. 
-    return;
-  }
-
-  bool snap;
-  if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
-      !geometry->mPaddingRect.IsEqualInterior(GetPaddingRect()) ||
-      !geometry->mContentRect.IsEqualInterior(GetContentRect())) {
-    if (!RenderingMightDependOnFrameSize() && geometry->mBounds.TopLeft() == GetBounds(aBuilder, &snap).TopLeft()) {
-      aInvalidRegion->Xor(GetBounds(aBuilder, &snap), geometry->mBounds);
-    } else {
-      aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
-    }
-  }
-}
-
 nsRect
 nsDisplayBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   nsRect r(nsPoint(0,0), mFrame->GetSize());
   nsPresContext* presContext = mFrame->PresContext();
 
   if (mIsThemed) {
     presContext->GetTheme()->
         GetWidgetOverflow(presContext->DeviceContext(), mFrame,
                           mFrame->GetStyleDisplay()->mAppearance, &r);
-#ifdef XP_MACOSX
-    // Bug 748219
-    r.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel());
-#endif
   }
 
   *aSnap = true;
   return r + ToReferenceFrame();
 }
 
 uint32_t
 nsDisplayBackground::GetPerFrameKey()
@@ -2187,39 +2089,17 @@ nsDisplayBorder::ComputeVisibility(nsDis
     // Skip this if there's a border-image (which draws a background
     // too) or if there is a border-radius (which makes the border draw
     // further in).
     return false;
   }
 
   return true;
 }
-  
-nsDisplayItemGeometry* 
-nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
-{
-  return new nsDisplayBorderGeometry(this, aBuilder);
-}
-
-void
-nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
-                                           const nsDisplayItemGeometry* aGeometry,
-                                           nsRegion* aInvalidRegion)
-{
-  const nsDisplayBorderGeometry* geometry = static_cast<const nsDisplayBorderGeometry*>(aGeometry);
-  bool snap;
-  if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
-      !geometry->mContentRect.IsEqualInterior(GetContentRect())) {
-    // We can probably get away with only invalidating the difference
-    // between the border and padding rects, but the XUL ui at least
-    // is apparently painting a background with this?
-    aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
-  }
-}
-  
+
 void
 nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
                        nsRenderingContext* aCtx) {
   nsPoint offset = ToReferenceFrame();
   nsCSSRendering::PaintBorder(mFrame->PresContext(), *aCtx, mFrame,
                               mVisibleRect,
                               nsRect(offset, mFrame->GetSize()),
                               mFrame->GetStyleContext(),
@@ -2633,20 +2513,18 @@ bool nsDisplayOpacity::TryMerge(nsDispla
   // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
   if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
     return false;
   MergeFromTrackingMergedFrames(static_cast<nsDisplayOpacity*>(aItem));
   return true;
 }
 
 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
-                                     nsIFrame* aFrame, nsDisplayList* aList,
-                                     uint32_t aFlags)
-    : nsDisplayWrapList(aBuilder, aFrame, aList)
-    , mFlags(aFlags) {
+                                     nsIFrame* aFrame, nsDisplayList* aList)
+    : nsDisplayWrapList(aBuilder, aFrame, aList) {
   MOZ_COUNT_CTOR(nsDisplayOwnLayer);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayOwnLayer::~nsDisplayOwnLayer() {
   MOZ_COUNT_DTOR(nsDisplayOwnLayer);
 }
 #endif
@@ -2654,22 +2532,16 @@ nsDisplayOwnLayer::~nsDisplayOwnLayer() 
 // nsDisplayOpacity uses layers for rendering
 already_AddRefed<Layer>
 nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
                               LayerManager* aManager,
                               const ContainerParameters& aContainerParameters) {
   nsRefPtr<Layer> layer = aManager->GetLayerBuilder()->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                            aContainerParameters, nullptr);
-
-  if (mFlags & GENERATE_SUBDOC_INVALIDATIONS) {
-    ContainerLayerPresContext* pres = new ContainerLayerPresContext;
-    pres->mPresContext = mFrame->PresContext();
-    layer->SetUserData(&gNotifySubDocInvalidationData, pres);
-  }
   return layer.forget();
 }
 
 nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
                                                nsIFrame* aFrame,
                                                nsIFrame* aFixedPosFrame,
                                                nsDisplayList* aList)
     : nsDisplayOwnLayer(aBuilder, aFrame, aList)
@@ -3122,20 +2994,19 @@ bool nsDisplayClipRoundedRect::TryMerge(
     return false;
   // No need to track merged frames for clipping
   MergeFrom(other);
   return true;
 }
 
 nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder,
                              nsIFrame* aFrame, nsDisplayList* aList,
-                             int32_t aAPD, int32_t aParentAPD,
-                             uint32_t aFlags)
-    : nsDisplayOwnLayer(aBuilder, aFrame, aList, aFlags)
-    , mAPD(aAPD), mParentAPD(aParentAPD) {
+                             int32_t aAPD, int32_t aParentAPD)
+    : nsDisplayOwnLayer(aBuilder, aFrame, aList), mAPD(aAPD),
+      mParentAPD(aParentAPD) {
   MOZ_COUNT_CTOR(nsDisplayZoom);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayZoom::~nsDisplayZoom() {
   MOZ_COUNT_DTOR(nsDisplayZoom);
 }
 #endif
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -20,17 +20,16 @@
 #include "nsRect.h"
 #include "nsISelection.h"
 #include "nsCaret.h"
 #include "plarena.h"
 #include "nsRegion.h"
 #include "FrameLayerBuilder.h"
 #include "nsThemeConstants.h"
 #include "nsLayoutUtils.h"
-#include "nsDisplayListInvalidation.h"
 
 #include "mozilla/StandardInteger.h"
 
 #include <stdlib.h>
 
 class nsIPresShell;
 class nsIContent;
 class nsRenderingContext;
@@ -755,82 +754,16 @@ public:
    * @return a rectangle relative to aBuilder->ReferenceFrame() that
    * contains the area drawn by this display item
    */
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
   {
     *aSnap = false;
     return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize());
   }
-  nsRect GetBorderRect() {
-    return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize());
-  }
-  nsRect GetPaddingRect() {
-    return GetUnderlyingFrame()->GetPaddingRectRelativeToSelf() + ToReferenceFrame();
-  }
-  nsRect GetContentRect() {
-    return GetUnderlyingFrame()->GetContentRectRelativeToSelf() + ToReferenceFrame();
-  }
-
-  /**
-   * Checks if the frame(s) owning this display item have been marked as invalid,
-   * and needing repainting.
-   */
-  virtual bool IsInvalid(nsRect& aRect) { 
-    bool result = mFrame ? mFrame->IsInvalid(aRect) : false;
-    aRect += ToReferenceFrame();
-    return result;
-  }
-
-  /**
-   * Creates and initializes an nsDisplayItemGeometry object that retains the current
-   * areas covered by this display item. These need to retain enough information
-   * such that they can be compared against a future nsDisplayItem of the same type, 
-   * and determine if repainting needs to happen.
-   *
-   * Subclasses wishing to store more information need to override both this
-   * and ComputeInvalidationRegion, as well as implementing an nsDisplayItemGeometry
-   * subclass.
-   *
-   * The default implementation tracks both the display item bounds, and the frame's
-   * border rect.
-   */
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
-  {
-    return new nsDisplayItemGenericGeometry(this, aBuilder);
-  }
-
-  /**
-   * Compares an nsDisplayItemGeometry object from a previous paint against the 
-   * current item. Computes if the geometry of the item has changed, and the 
-   * invalidation area required for correct repainting.
-   *
-   * The existing geometry will have been created from a display item with a 
-   * matching GetPerFrameKey()/mFrame pair to the current item.
-   *
-   * The default implementation compares the display item bounds, and the frame's
-   * border rect, and invalidates the entire bounds if either rect changes.
-   *
-   * @param aGeometry The geometry of the matching display item from the 
-   * previous paint.
-   * @param aInvalidRegion Output param, the region to invalidate, or
-   * unchanged if none.
-   */
-  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
-                                         const nsDisplayItemGeometry* aGeometry,
-                                         nsRegion* aInvalidRegion)
-  {
-    const nsDisplayItemGenericGeometry* geometry = static_cast<const nsDisplayItemGenericGeometry*>(aGeometry);
-    bool snap;
-    if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
-        !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
-      aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
-    }
-  }
-  
   /**
    * @param aSnap set to true if the edges of the rectangles of the opaque
    * region would be snapped to device pixels when drawing
    * @return a region of the item that is opaque --- that is, every pixel
    * that is visible (according to ComputeVisibility) is painted with an opaque
    * color. This is useful for determining when one piece
    * of content completely obscures another so that we can do occlusion
    * culling.
@@ -1669,22 +1602,16 @@ public:
 #endif
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER)
-  
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder);
-
-  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
-                                         const nsDisplayItemGeometry* aGeometry,
-                                         nsRegion* aInvalidRegion);
 };
 
 /**
  * A simple display item that just renders a solid color across the
  * specified bounds. For canvas frames (in the CSS sense) we split off the
  * drawing of the background color into this class (from nsDisplayBackground
  * via nsDisplayCanvasBackground). This is done so that we can always draw a
  * background color to avoid ugly flashes of white when we can't draw a full
@@ -1777,32 +1704,16 @@ public:
   virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual uint32_t GetPerFrameKey() MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("Background", TYPE_BACKGROUND)
   // Returns the value of GetUnderlyingFrame()->IsThemed(), but cached
   bool IsThemed() { return mIsThemed; }
 
-  /**
-   * Returns true if existing rendered pixels of this display item may need
-   * to be redrawn if the frame size changes.
-   * If false, only the changed area needs to be redrawn.
-   */
-  bool RenderingMightDependOnFrameSize();
-  
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
-  {
-    return new nsDisplayBackgroundGeometry(this, aBuilder);
-  }
-
-  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
-                                         const nsDisplayItemGeometry* aGeometry,
-                                         nsRegion* aInvalidRegion);
-
 protected:
   typedef class mozilla::layers::ImageContainer ImageContainer;
   typedef class mozilla::layers::ImageLayer ImageLayer;
 
   nsRegion GetInsideClipRegion(nsPresContext* aPresContext, uint8_t aClip,
                                const nsRect& aRect, bool* aSnap);
 
   bool TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder);
@@ -1840,31 +1751,16 @@ public:
 #endif
 
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER)
-  
-  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
-                                         const nsDisplayItemGeometry* aGeometry,
-                                         nsRegion* aInvalidRegion)
-  {
-    const nsDisplayItemGenericGeometry* geometry = static_cast<const nsDisplayItemGenericGeometry*>(aGeometry);
-    bool snap;
-    if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
-        !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
-      nsRegion oldShadow, newShadow;
-      oldShadow = oldShadow.Sub(geometry->mBounds, geometry->mBorderRect);
-      newShadow = newShadow.Sub(GetBounds(aBuilder, &snap), GetBorderRect());
-      aInvalidRegion->Or(oldShadow, newShadow);
-    }
-  }
 
 private:
   nsRegion mVisibleRegion;
 };
 
 /**
  * The standard display item to paint the inner CSS box-shadows of a frame.
  */
@@ -1880,34 +1776,16 @@ public:
   }
 #endif
 
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("BoxShadowInner", TYPE_BOX_SHADOW_INNER)
-  
-  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
-  {
-    return new nsDisplayBoxShadowInnerGeometry(this, aBuilder);
-  }
-
-  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
-                                         const nsDisplayItemGeometry* aGeometry,
-                                         nsRegion* aInvalidRegion)
-  {
-    const nsDisplayBoxShadowInnerGeometry* geometry = static_cast<const nsDisplayBoxShadowInnerGeometry*>(aGeometry);
-    if (!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect())) {
-      // nsDisplayBoxShadowInner is based around the padding rect, but it can
-      // touch pixels outside of this. We should invalidate the entire bounds.
-      bool snap;
-      aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap));
-    }
-  }
 
 private:
   nsRegion mVisibleRegion;
 };
 
 /**
  * The standard display item to paint the CSS outline of a frame.
  */
@@ -2004,32 +1882,16 @@ public:
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE {
     NS_WARNING("This list should already have been flattened!!!");
     return false;
   }
   virtual void GetMergedFrames(nsTArray<nsIFrame*>* aFrames) MOZ_OVERRIDE
   {
     aFrames->AppendElements(mMergedFrames);
   }
-  virtual bool IsInvalid(nsRect& aRect)
-  {
-    if (mFrame->IsInvalid(aRect) && aRect.IsEmpty()) {
-      return true;
-    }
-    nsRect temp;
-    for (uint32_t i = 0; i < mMergedFrames.Length(); i++) {
-      if (mMergedFrames[i]->IsInvalid(temp) && temp.IsEmpty()) {
-        aRect.SetEmpty();
-        return true;
-      }
-      aRect = aRect.Union(temp);
-    }
-    aRect += ToReferenceFrame();
-    return !aRect.IsEmpty();
-  }
   NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST)
 
   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder);
                                     
   virtual nsDisplayList* GetList() MOZ_OVERRIDE { return &mList; }
   
   /**
    * This creates a copy of this item, but wrapping aItem instead of
@@ -2132,31 +1994,18 @@ public:
 };
 
 /**
  * A display item that has no purpose but to ensure its contents get
  * their own layer.
  */
 class nsDisplayOwnLayer : public nsDisplayWrapList {
 public:
-
-  /**
-   * nsDisplayOwnLayer constructor flags
-   */
-  enum {
-    GENERATE_SUBDOC_INVALIDATIONS = 0x01
-  };
-
-  /**
-   * @param aFlags GENERATE_SUBDOC_INVALIDATIONS :
-   * Add UserData to the created ContainerLayer, so that invalidations
-   * for this layer are send to our nsPresContext.
-   */
   nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-                    nsDisplayList* aList, uint32_t aFlags = 0);
+                    nsDisplayList* aList);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayOwnLayer();
 #endif
   
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerParameters& aContainerParameters) MOZ_OVERRIDE;
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
@@ -2166,18 +2015,16 @@ public:
     return mozilla::LAYER_ACTIVE_FORCE;
   }
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE
   {
     // Don't allow merging, each sublist must have its own layer
     return false;
   }
   NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
-private:
-  uint32_t mFlags;
 };
 
 /**
  * A display item used to represent fixed position elements. This will ensure
  * the contents gets its own layer, and that the built layer will have
  * position-related metadata set on it.
  */
 class nsDisplayFixedPosition : public nsDisplayOwnLayer {
@@ -2401,24 +2248,20 @@ private:
 class nsDisplayZoom : public nsDisplayOwnLayer {
 public:
   /**
    * @param aFrame is the root frame of the subdocument.
    * @param aList contains the display items for the subdocument.
    * @param aAPD is the app units per dev pixel ratio of the subdocument.
    * @param aParentAPD is the app units per dev pixel ratio of the parent
    * document.
-   * @param aFlags GENERATE_SUBDOC_INVALIDATIONS :
-   * Add UserData to the created ContainerLayer, so that invalidations
-   * for this layer are send to our nsPresContext.
    */
   nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 nsDisplayList* aList,
-                int32_t aAPD, int32_t aParentAPD,
-                uint32_t aFlags = 0);
+                int32_t aAPD, int32_t aParentAPD);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayZoom();
 #endif
   
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
@@ -2728,22 +2571,9 @@ public:
             t == nsDisplayItem::TYPE_TEXT_SHADOW)
       ? static_cast<nsCharClipDisplayItem*>(aItem) : nullptr;
   }
 
   nscoord mLeftEdge;  // length from the left side
   nscoord mRightEdge; // length from the right side
 };
 
-class nsDisplayImageContainer : public nsDisplayItem {
-public:
-  typedef mozilla::layers::ImageContainer ImageContainer;
-  typedef mozilla::layers::ImageLayer ImageLayer;
-
-  nsDisplayImageContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
-    : nsDisplayItem(aBuilder, aFrame)
-  {}
-
-  virtual already_AddRefed<ImageContainer> GetContainer() = 0;
-  virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) = 0;
-};
-
 #endif /*NSDISPLAYLIST_H_*/
deleted file mode 100644
--- a/layout/base/nsDisplayListInvalidation.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsDisplayListInvalidation.h"
-#include "nsDisplayList.h"
-
-nsDisplayItemGeometry::nsDisplayItemGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
-{
-  MOZ_COUNT_CTOR(nsDisplayItemGeometry);
-  bool snap;
-  mBounds = aItem->GetBounds(aBuilder, &snap);
-}
-
-nsDisplayItemGeometry::~nsDisplayItemGeometry()
-{
-  MOZ_COUNT_DTOR(nsDisplayItemGeometry);
-}
-
-nsDisplayItemGenericGeometry::nsDisplayItemGenericGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
-  : nsDisplayItemGeometry(aItem, aBuilder)
-  , mBorderRect(aItem->GetBorderRect())
-{}
-
-void
-nsDisplayItemGenericGeometry::MoveBy(const nsPoint& aOffset)
-{
-  mBounds.MoveBy(aOffset);
-  mBorderRect.MoveBy(aOffset);
-}
-
-nsDisplayBorderGeometry::nsDisplayBorderGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
-  : nsDisplayItemGeometry(aItem, aBuilder)
-  , mContentRect(aItem->GetContentRect())
-{}
-
-void
-nsDisplayBorderGeometry::MoveBy(const nsPoint& aOffset)
-{
-  mBounds.MoveBy(aOffset);
-  mContentRect.MoveBy(aOffset);
-}
-
-nsDisplayBackgroundGeometry::nsDisplayBackgroundGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
-  : nsDisplayItemGeometry(aItem, aBuilder)
-  , mPaddingRect(aItem->GetPaddingRect())
-  , mContentRect(aItem->GetContentRect())
-{}
-
-void
-nsDisplayBackgroundGeometry::MoveBy(const nsPoint& aOffset)
-{
-  mBounds.MoveBy(aOffset);
-  mPaddingRect.MoveBy(aOffset);
-  mContentRect.MoveBy(aOffset);
-}
-
-nsDisplayBoxShadowInnerGeometry::nsDisplayBoxShadowInnerGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
-  : nsDisplayItemGeometry(aItem, aBuilder)
-  , mPaddingRect(aItem->GetPaddingRect())
-{}
-
-void
-nsDisplayBoxShadowInnerGeometry::MoveBy(const nsPoint& aOffset)
-{
-  mBounds.MoveBy(aOffset);
-  mPaddingRect.MoveBy(aOffset);
-}
-
deleted file mode 100644
--- a/layout/base/nsDisplayListInvalidation.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef NSDISPLAYLISTINVALIDATION_H_
-#define NSDISPLAYLISTINVALIDATION_H_
-
-#include "nsRect.h"
-
-class nsDisplayItem;
-class nsDisplayListBuilder;
-
-/**
- * This stores the geometry of an nsDisplayItem, and the area
- * that will be affected when painting the item.
- *
- * It is used to retain information about display items so they
- * can be compared against new display items in the next paint.
- */
-class nsDisplayItemGeometry
-{
-public:
-  nsDisplayItemGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder);
-  virtual ~nsDisplayItemGeometry();
-  
-  /**
-   * Compute the area required to be invalidated if this
-   * display item is removed.
-   */
-  const nsRect& ComputeInvalidationRegion() { return mBounds; }
-  
-  /**
-   * Shifts all retained areas of the nsDisplayItemGeometry by the given offset.
-   * 
-   * This is used to compensate for scrolling, since the destination buffer
-   * can scroll without requiring a full repaint.
-   *
-   * @param aOffset Offset to shift by.
-   */
-  virtual void MoveBy(const nsPoint& aOffset) = 0;
-
-  /**
-   * Bounds of the display item
-   */
-  nsRect mBounds;
-};
-
-/**
- * A default geometry implementation, used by nsDisplayItem. Retains
- * and compares the bounds, and border rect.
- *
- * This should be sufficient for the majority of display items.
- */
-class nsDisplayItemGenericGeometry : public nsDisplayItemGeometry
-{
-public:
-  nsDisplayItemGenericGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder);
-
-  virtual void MoveBy(const nsPoint& aOffset);
-
-  nsRect mBorderRect;
-};
-
-class nsDisplayBorderGeometry : public nsDisplayItemGeometry
-{
-public:
-  nsDisplayBorderGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder);
-
-  virtual void MoveBy(const nsPoint& aOffset);
-
-  nsRect mContentRect;
-};
-
-class nsDisplayBackgroundGeometry : public nsDisplayItemGeometry
-{
-public:
-  nsDisplayBackgroundGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder);
-
-  virtual void MoveBy(const nsPoint& aOffset);
-
-  nsRect mPaddingRect;
-  nsRect mContentRect;
-};
-
-class nsDisplayBoxShadowInnerGeometry : public nsDisplayItemGeometry
-{
-public:
-  nsDisplayBoxShadowInnerGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder);
-  
-  virtual void MoveBy(const nsPoint& aOffset);
-
-  nsRect mPaddingRect;
-};
-
-#endif /*NSDISPLAYLISTINVALIDATION_H_*/
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2901,17 +2901,18 @@ DocumentViewerImpl::SetFullZoom(float aF
     nsIPageSequenceFrame* pf = shell->GetPageSequenceFrame();
     if (pf) {
       nsIFrame* f = do_QueryFrame(pf);
       shell->FrameNeedsReflow(f, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
     }
 
     nsIFrame* rootFrame = shell->GetRootFrame();
     if (rootFrame) {
-      rootFrame->InvalidateFrame();
+      nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
+      rootFrame->Invalidate(rect);
     }
     return NS_OK;
   }
 #endif
 
   mPageZoom = aFullZoom;
 
   struct ZoomInfo ZoomInfo = { aFullZoom };
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -462,28 +462,31 @@ nsFrameManager::InsertFrames(nsIFrame*  
            InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
   } else {
     return aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
   }
 }
 
 nsresult
 nsFrameManager::RemoveFrame(ChildListID     aListID,
-                            nsIFrame*       aOldFrame)
+                            nsIFrame*       aOldFrame,
+                            bool            aInvalidate /* = true */)
 {
   bool wasDestroyingFrames = mIsDestroyingFrames;
   mIsDestroyingFrames = true;
 
   // In case the reflow doesn't invalidate anything since it just leaves
   // a gap where the old frame was, we invalidate it here.  (This is
   // reasonably likely to happen when removing a last child in a way
   // that doesn't change the size of the parent.)
   // This has to sure to invalidate the entire overflow rect; this
   // is important in the presence of absolute positioning
-  aOldFrame->InvalidateFrameForRemoval();
+  if (aInvalidate) {
+    aOldFrame->InvalidateFrameSubtree();
+  }
 
   NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
                // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
                aOldFrame->GetType() == nsGkAtoms::textFrame,
                "Must remove first continuation.");
   NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
                  GetPlaceholderFrameFor(aOldFrame)),
                "Must call RemoveFrame on placeholder for out-of-flows.");
--- a/layout/base/nsFrameManager.h
+++ b/layout/base/nsFrameManager.h
@@ -90,17 +90,18 @@ public:
                                     nsFrameList&    aFrameList);
 
   NS_HIDDEN_(nsresult) InsertFrames(nsIFrame*       aParentFrame,
                                     ChildListID     aListID,
                                     nsIFrame*       aPrevFrame,
                                     nsFrameList&    aFrameList);
 
   NS_HIDDEN_(nsresult) RemoveFrame(ChildListID     aListID,
-                                   nsIFrame*       aOldFrame);
+                                   nsIFrame*       aOldFrame,
+                                   bool            aInvalidate = true);
 
   /*
    * Notification that a frame is about to be destroyed. This allows any
    * outstanding references to the frame to be cleaned up.
    */
   NS_HIDDEN_(void)     NotifyDestroyingFrame(nsIFrame* aFrame);
 
   /*
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1234,21 +1234,16 @@ public:
    * visible presshell in the document tree.
    */
   virtual void WillPaint(bool aWillSendDidPaint) = 0;
   /**
    * Notify that the NS_DID_PAINT event was received. Only fires on the
    * root pres shell.
    */
   virtual void DidPaint() = 0;
-
-  /**
-   * Ensures that the refresh driver is running, and schedules a view 
-   * manager flush on the next tick.
-   */
   virtual void ScheduleViewManagerFlush() = 0;
   virtual void ClearMouseCaptureOnView(nsIView* aView) = 0;
   virtual bool IsVisible() = 0;
   virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange) = 0;
 
   virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                    nsArenaMemoryStats *aArenaObjectsSize,
                                    size_t *aPresShellSize,
@@ -1266,20 +1261,16 @@ public:
   uint32_t FontSizeInflationMinTwips() const {
     return mFontSizeInflationMinTwips;
   }
 
   uint32_t FontSizeInflationLineThreshold() const {
     return mFontSizeInflationLineThreshold;
   }
 
-  virtual void AddInvalidateHiddenPresShellObserver(nsRefreshDriver *aDriver) = 0;
-
-  void InvalidatePresShellIfHidden();
-
   /**
    * Refresh observer management.
    */
 protected:
   virtual bool AddRefreshObserverExternal(nsARefreshObserver* aObserver,
                                             mozFlushType aFlushType);
   bool AddRefreshObserverInternal(nsARefreshObserver* aObserver,
                                     mozFlushType aFlushType);
@@ -1350,17 +1341,16 @@ protected:
   nsCSSFrameConstructor*    mFrameConstructor; // [OWNS]
   nsIViewManager*           mViewManager;   // [WEAK] docViewer owns it so I don't have to
   nsPresArena               mFrameArena;
   nsFrameSelection*         mSelection;
   // Pointer into mFrameConstructor - this is purely so that FrameManager() and
   // GetRootFrame() can be inlined:
   nsFrameManagerBase*       mFrameManager;
   nsWeakPtr                 mForwardingContainer;
-  nsRefreshDriver*          mHiddenInvalidationObserverRefreshDriver;
 #ifdef ACCESSIBILITY
   DocAccessible* mAccDocument;
 #endif
 
 #ifdef DEBUG
   nsIFrame*                 mDrawEventTargetFrame;
   // Ensure that every allocation from the PresArena is eventually freed.
   uint32_t                  mPresArenaAllocCount;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3996,25 +3996,20 @@ nsLayoutUtils::IsPopup(nsIFrame* aFrame)
     return false;
   }
   return IsPopupFrame(aFrame);
 }
 
 /* static */ nsIFrame*
 nsLayoutUtils::GetDisplayRootFrame(nsIFrame* aFrame)
 {
-  // We could use GetRootPresContext() here if the
-  // NS_FRAME_IN_POPUP frame bit is set.
   nsIFrame* f = aFrame;
   for (;;) {
-    if (!f->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
-      f = f->PresContext()->FrameManager()->GetRootFrame();
-    } else if (IsPopup(f)) {
+    if (IsPopup(f))
       return f;
-    }
     nsIFrame* parent = GetCrossDocParentFrame(f);
     if (!parent)
       return f;
     f = parent;
   }
 }
 
 /* static */ uint32_t
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -83,18 +83,16 @@
 //needed for resetting of image service color
 #include "nsLayoutCID.h"
 
 #include "nsCSSParser.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-uint8_t gNotifySubDocInvalidationData;
-
 namespace {
 
 class CharSetChangingRunnable : public nsRunnable
 {
 public:
   CharSetChangingRunnable(nsPresContext* aPresContext,
                           const nsCString& aCharSet)
     : mPresContext(aPresContext),
@@ -126,32 +124,16 @@ nsPresContext::MakeColorPref(const nsStr
   }
 
   nscolor color;
   return nsRuleNode::ComputeColor(value, this, nullptr, color)
     ? color
     : NS_RGB(0, 0, 0);
 }
 
-bool
-nsPresContext::IsDOMPaintEventPending() 
-{
-  if (!mInvalidateRequests.mRequests.IsEmpty()) {
-    return true;    
-  }
-  if (GetDisplayRootPresContext()->GetRootPresContext()->mRefreshDriver->ViewManagerFlushIsPending()) {
-    // Since we're promising that there will be a MozAfterPaint event
-    // fired, we record an empty invalidation in case display list
-    // invalidation doesn't invalidate anything further.
-    NotifyInvalidation(nsRect(0, 0, 0, 0), 0);
-    return true;
-  }
-  return false;
-}
-
 int
 nsPresContext::PrefChangedCallback(const char* aPrefName, void* instance_data)
 {
   nsPresContext*  presContext = (nsPresContext*)instance_data;
 
   NS_ASSERTION(nullptr != presContext, "bad instance data");
   if (nullptr != presContext) {
     presContext->PreferenceChanged(aPrefName);
@@ -189,18 +171,17 @@ IsVisualCharset(const nsCString& aCharse
   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 
 nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
   : mType(aType), mDocument(aDocument), mMinFontSize(0),
     mTextZoom(1.0), mFullZoom(1.0), mLastFontInflationScreenWidth(-1.0),
     mPageSize(-1, -1), mPPScale(1.0f),
     mViewportStyleOverflow(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO),
-    mImageAnimationModePref(imgIContainer::kNormalAnimMode),
-    mAllInvalidated(false)
+    mImageAnimationModePref(imgIContainer::kNormalAnimMode)
 {
   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 
   mDoScaledTwips = true;
 
   SetBackgroundImageDraw(true);		// always draw the background
   SetBackgroundColorDraw(true);
@@ -790,17 +771,17 @@ nsPresContext::InvalidateThebesLayers()
 {
   if (!mShell)
     return;
   nsIFrame* rootFrame = mShell->FrameManager()->GetRootFrame();
   if (rootFrame) {
     // FrameLayerBuilder caches invalidation-related values that depend on the
     // appunits-per-dev-pixel ratio, so ensure that all ThebesLayer drawing
     // is completely flushed.
-    rootFrame->InvalidateFrameSubtree();
+    FrameLayerBuilder::InvalidateThebesLayersInSubtreeWithUntrustedFrameGeometry(rootFrame);
   }
 }
 
 void
 nsPresContext::AppUnitsPerDevPixelChanged()
 {
   InvalidateThebesLayers();
 
@@ -1982,67 +1963,63 @@ void
 nsPresContext::FireDOMPaintEvent()
 {
   nsPIDOMWindow* ourWindow = mDocument->GetWindow();
   if (!ourWindow)
     return;
 
   nsCOMPtr<nsIDOMEventTarget> dispatchTarget = do_QueryInterface(ourWindow);
   nsCOMPtr<nsIDOMEventTarget> eventTarget = dispatchTarget;
-  if (!IsChrome() && !mSendAfterPaintToContent) {
-    // Don't tell the window about this event, it should not know that
-    // something happened in a subdocument. Tell only the chrome event handler.
-    // (Events sent to the window get propagated to the chrome event handler
-    // automatically.)
-    dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget());
-    if (!dispatchTarget) {
-      return;
+  if (!IsChrome()) {
+    bool notifyContent = mSendAfterPaintToContent;
+
+    if (notifyContent) {
+      // If the pref is set, we still don't post events when they're
+      // entirely cross-doc.
+      notifyContent = false;
+      for (uint32_t i = 0; i < mInvalidateRequests.mRequests.Length(); ++i) {
+        if (!(mInvalidateRequests.mRequests[i].mFlags &
+              nsIFrame::INVALIDATE_CROSS_DOC)) {
+          notifyContent = true;
+        }
+      }
+    }
+    if (!notifyContent) {
+      // Don't tell the window about this event, it should not know that
+      // something happened in a subdocument. Tell only the chrome event handler.
+      // (Events sent to the window get propagated to the chrome event handler
+      // automatically.)
+      dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget());
+      if (!dispatchTarget) {
+        return;
+      }
     }
   }
   // Events sent to the window get propagated to the chrome event handler
   // automatically.
   nsCOMPtr<nsIDOMEvent> event;
   // This will empty our list in case dispatching the event causes more damage
   // (hopefully it won't, or we're likely to get an infinite loop! At least
   // it won't be blocking app execution though).
   NS_NewDOMNotifyPaintEvent(getter_AddRefs(event), this, nullptr,
                             NS_AFTERPAINT,
                             &mInvalidateRequests);
-  mAllInvalidated = false;
   if (!event) {
     return;
   }
 
   // Even if we're not telling the window about the event (so eventTarget is
   // the chrome event handler, not the window), the window is still
   // logically the event target.
   event->SetTarget(eventTarget);
   event->SetTrusted(true);
   nsEventDispatcher::DispatchDOMEvent(dispatchTarget, nullptr, event, this, nullptr);
 }
 
 static bool
-MayHavePaintEventListenerSubdocumentCallback(nsIDocument* aDocument, void* aData)
-{
-  bool *result = static_cast<bool*>(aData);
-  nsIPresShell* shell = aDocument->GetShell();
-  if (shell) {
-    nsPresContext* pc = shell->GetPresContext();
-    if (pc) {
-      *result = pc->MayHavePaintEventListenerInSubDocument();
-
-      // If we found a paint event listener, then we can stop enumerating
-      // sub documents.
-      return !*result;
-    }
-  }
-  return true;
-}
-
-static bool
 MayHavePaintEventListener(nsPIDOMWindow* aInnerWindow)
 {
   if (!aInnerWindow)
     return false;
   if (aInnerWindow->HasPaintEventListeners())
     return true;
 
   nsIDOMEventTarget* parentTarget = aInnerWindow->GetParentTarget();
@@ -2083,58 +2060,26 @@ MayHavePaintEventListener(nsPIDOMWindow*
 }
 
 bool
 nsPresContext::MayHavePaintEventListener()
 {
   return ::MayHavePaintEventListener(mDocument->GetInnerWindow());
 }
 
-bool
-nsPresContext::MayHavePaintEventListenerInSubDocument()
-{
-  if (MayHavePaintEventListener()) {
-    return true;
-  }
-
-  bool result = false;
-  mDocument->EnumerateSubDocuments(MayHavePaintEventListenerSubdocumentCallback, &result);
-  return result;
-}
-
-void
-nsPresContext::NotifyInvalidation(uint32_t aFlags)
-{
-  nsIFrame* rootFrame = PresShell()->FrameManager()->GetRootFrame();
-  NotifyInvalidation(rootFrame->GetVisualOverflowRect(), aFlags);
-  mAllInvalidated = true;
-}
-
-void
-nsPresContext::NotifyInvalidation(const nsIntRect& aRect, uint32_t aFlags)
-{
-  nsRect rect(DevPixelsToAppUnits(aRect.x),
-              DevPixelsToAppUnits(aRect.y),
-              DevPixelsToAppUnits(aRect.width),
-              DevPixelsToAppUnits(aRect.height));
-  NotifyInvalidation(rect, aFlags);
-}
-
 void
 nsPresContext::NotifyInvalidation(const nsRect& aRect, uint32_t aFlags)
 {
   // If there is no paint event listener, then we don't need to fire
   // the asynchronous event. We don't even need to record invalidation.
   // MayHavePaintEventListener is pretty cheap and we could make it
   // even cheaper by providing a more efficient
   // nsPIDOMWindow::GetListenerManager.
-  
-  if (mAllInvalidated) {
+  if (aRect.IsEmpty() || !MayHavePaintEventListener())
     return;
-  }
 
   nsPresContext* pc;
   for (pc = this; pc; pc = pc->GetParentPresContext()) {
     if (pc->mFireAfterPaintEvents)
       break;
     pc->mFireAfterPaintEvents = true;
   }
   if (!pc) {
@@ -2148,68 +2093,45 @@ nsPresContext::NotifyInvalidation(const 
     mInvalidateRequests.mRequests.AppendElement();
   if (!request)
     return;
 
   request->mRect = aRect;
   request->mFlags = aFlags;
 }
 
-/* static */ void 
-nsPresContext::NotifySubDocInvalidation(ContainerLayer* aContainer,
-                                        const nsIntRegion& aRegion)
-{
-  ContainerLayerPresContext *data = 
-    static_cast<ContainerLayerPresContext*>(
-      aContainer->GetUserData(&gNotifySubDocInvalidationData));
-  if (!data) {
-    return;
-  }
-
-  nsIntPoint topLeft = aContainer->GetVisibleRegion().GetBounds().TopLeft();
-
-  nsIntRegionRectIterator iter(aRegion);
-  while (const nsIntRect* r = iter.Next()) {
-    nsIntRect rect = *r;
-    //PresContext coordinate space is relative to the start of our visible
-    // region. Is this really true? This feels like the wrong way to get the right
-    // answer.
-    rect.MoveBy(-topLeft);
-    data->mPresContext->NotifyInvalidation(rect, 0);
-  }
-}
-
 static bool
 NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
 {
   nsIPresShell* shell = aDocument->GetShell();
   if (shell) {
     nsPresContext* pc = shell->GetPresContext();
     if (pc) {
       pc->NotifyDidPaintForSubtree();
     }
   }
   return true;
 }
 
 void
 nsPresContext::NotifyDidPaintForSubtree()
 {
+  if (!mFireAfterPaintEvents)
+    return;
+  mFireAfterPaintEvents = false;
+
   if (IsRoot()) {
-    if (!mFireAfterPaintEvents)
-      return;
-
     static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
   }
 
-  mFireAfterPaintEvents = false;
-
-  nsCOMPtr<nsIRunnable> ev =
-    NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
-  nsContentUtils::AddScriptRunner(ev);
+  if (!mInvalidateRequests.mRequests.IsEmpty()) {
+    nsCOMPtr<nsIRunnable> ev =
+      NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
+    nsContentUtils::AddScriptRunner(ev);
+  }
 
   mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, nullptr);
 }
 
 bool
 nsPresContext::HasCachedStyleData()
 {
   return mShell && mShell->StyleSet()->HasCachedStyleData();
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -27,17 +27,16 @@
 #include "nsChangeHint.h"
 // This also pulls in gfxTypes.h, which we cannot include directly.
 #include "gfxRect.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
 #include "nsIWidget.h"
 #include "mozilla/TimeStamp.h"
 #include "prclist.h"
-#include "Layers.h"
 
 #ifdef IBMBIDI
 class nsBidiPresUtils;
 #endif // IBMBIDI
 
 struct nsRect;
 
 class imgIRequest;
@@ -108,27 +107,16 @@ public:
   struct Request {
     nsRect   mRect;
     uint32_t mFlags;
   };
 
   nsTArray<Request> mRequests;
 };
 
-/**
- * Layer UserData for ContainerLayers that want to be notified
- * of local invalidations of them and their descendant layers.
- * Pass a callback to ComputeDifferences to have these called.
- */
-class ContainerLayerPresContext : public mozilla::layers::LayerUserData {
-public:
-  nsPresContext* mPresContext;
-};
-extern uint8_t gNotifySubDocInvalidationData;
-
 /* Used by nsPresContext::HasAuthorSpecifiedRules */
 #define NS_AUTHOR_SPECIFIED_BACKGROUND      (1 << 0)
 #define NS_AUTHOR_SPECIFIED_BORDER          (1 << 1)
 #define NS_AUTHOR_SPECIFIED_PADDING         (1 << 2)
 #define NS_AUTHOR_SPECIFIED_TEXT_SHADOW     (1 << 3)
 
 class nsRootPresContext;
 
@@ -800,31 +788,25 @@ public:
   void UserFontSetUpdated();
 
   // Ensure that it is safe to hand out CSS rules outside the layout
   // engine by ensuring that all CSS style sheets have unique inners
   // and, if necessary, synchronously rebuilding all style data.
   // Returns true on success and false on failure (not safe).
   bool EnsureSafeToHandOutCSSRules();
 
-  void NotifyInvalidation(uint32_t aFlags);
   void NotifyInvalidation(const nsRect& aRect, uint32_t aFlags);
-  // aRect is in device pixels
-  void NotifyInvalidation(const nsIntRect& aRect, uint32_t aFlags);
   void NotifyDidPaintForSubtree();
   void FireDOMPaintEvent();
 
-  // Callback for catching invalidations in ContainerLayers
-  // Passed to LayerProperties::ComputeDifference
-  static void NotifySubDocInvalidation(mozilla::layers::ContainerLayer* aContainer,
-                                       const nsIntRegion& aRegion);
-  bool IsDOMPaintEventPending();
+  bool IsDOMPaintEventPending() {
+    return !mInvalidateRequests.mRequests.IsEmpty();
+  }
   void ClearMozAfterPaintEvents() {
     mInvalidateRequests.mRequests.Clear();
-    mAllInvalidated = false;
   }
 
   bool IsProcessingRestyles() const {
     return mProcessingRestyles;
   }
 
   void SetProcessingRestyles(bool aProcessing) {
     NS_ASSERTION(aProcessing != bool(mProcessingRestyles),
@@ -1016,32 +998,22 @@ protected:
     mLangGroupFontPrefs.mLangGroup = nullptr;
   }
 
   NS_HIDDEN_(void) UpdateCharSet(const nsCString& aCharSet);
 
 public:
   void DoChangeCharSet(const nsCString& aCharSet);
 
-  /**
-   * Checks for MozAfterPaint listeners on the document
-   */
-  bool MayHavePaintEventListener();
-
-  /**
-   * Checks for MozAfterPaint listeners on the document and 
-   * any subdocuments, except for subdocuments that are non-top-level
-   * content documents.
-   */
-  bool MayHavePaintEventListenerInSubDocument();
-
 protected:
   void InvalidateThebesLayers();
   void AppUnitsPerDevPixelChanged();
 
+  bool MayHavePaintEventListener();
+
   void HandleRebuildUserFontSet() {
     mPostedFlushUserFontSet = false;
     FlushUserFontSet();
   }
 
   bool HavePendingInputEvent();
 
   // Can't be inline because we can't include nsStyleSet.h.
@@ -1163,17 +1135,16 @@ protected:
   unsigned              mIsRootPaginatedDocument : 1;
   unsigned              mPrefBidiDirection : 1;
   unsigned              mPrefScrollbarSide : 2;
   unsigned              mPendingSysColorChanged : 1;
   unsigned              mPendingThemeChanged : 1;
   unsigned              mPendingMediaFeatureValuesChanged : 1;
   unsigned              mPrefChangePendingNeedsReflow : 1;
   unsigned              mMayHaveFixedBackgroundFrames : 1;
-  unsigned              mAllInvalidated : 1;
 
   // Are we currently drawing an SVG glyph?
   unsigned              mIsGlyph : 1;
 
   // Is the current mUserFontSet valid?
   unsigned              mUserFontSetDirty : 1;
   // Has GetUserFontSet() been called?
   unsigned              mGetUserFontSetCalled : 1;
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -114,18 +114,16 @@
 #include "nsStyleSheetService.h"
 #include "gfxImageSurface.h"
 #include "gfxContext.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif
 #include "nsSMILAnimationController.h"
 #include "SVGContentUtils.h"
-#include "nsSVGUtils.h"
-#include "nsSVGEffects.h"
 #include "SVGFragmentIdentifier.h"
 
 #include "nsRefreshDriver.h"
 
 // Drag & Drop, Clipboard
 #include "nsWidgetsCID.h"
 #include "nsIClipboard.h"
 #include "nsIClipboardHelper.h"
@@ -172,17 +170,16 @@
 #include "gfxPlatform.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "sampler.h"
 #include "mozilla/css/ImageLoader.h"
 
 #include "Layers.h"
-#include "LayerTreeInvalidation.h"
 #include "nsAsyncDOMEvent.h"
 
 #define ANCHOR_SCROLL_FLAGS (SCROLL_OVERFLOW_HIDDEN | SCROLL_NO_PARENT_FRAMES)
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 
@@ -604,34 +601,16 @@ nsIPresShell::GetVerifyReflowEnable()
         }
       }
       printf("\n");
     }
   }
 #endif
   return gVerifyReflowEnabled;
 }
-  
-void 
-PresShell::AddInvalidateHiddenPresShellObserver(nsRefreshDriver *aDriver)
-{
-  if (!mHiddenInvalidationObserverRefreshDriver && !mIsDestroying && !mHaveShutDown) {
-    aDriver->AddPresShellToInvalidateIfHidden(this);
-    mHiddenInvalidationObserverRefreshDriver = aDriver;
-  }
-}
-
-void
-nsIPresShell::InvalidatePresShellIfHidden()
-{
-  if (!IsVisible() && mPresContext) {
-    mPresContext->NotifyInvalidation(0);
-  }
-  mHiddenInvalidationObserverRefreshDriver = nullptr;
-}
 
 void
 nsIPresShell::SetVerifyReflowEnable(bool aEnabled)
 {
   gVerifyReflowEnabled = aEnabled;
 }
 
 /* virtual */ void
@@ -1046,20 +1025,16 @@ PresShell::Destroy()
       mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
     }
   }
 
   // Revoke any pending events.  We need to do this and cancel pending reflows
   // before we destroy the frame manager, since apparently frame destruction
   // sometimes spins the event queue when plug-ins are involved(!).
   rd->RemoveLayoutFlushObserver(this);
-  if (mHiddenInvalidationObserverRefreshDriver) {
-    mHiddenInvalidationObserverRefreshDriver->RemovePresShellToInvalidateIfHidden(this);
-  }
-
   rd->RevokeViewManagerFlush();
 
   mResizeEvent.Revoke();
   if (mAsyncResizeTimerIsActive) {
     mAsyncResizeEventTimer->Cancel();
     mAsyncResizeTimerIsActive = false;
   }
 
@@ -3565,17 +3540,18 @@ PresShell::UnsuppressAndInvalidate()
     // go back to the event loop and actually draw the page.
     nsContentUtils::AddScriptRunner(new nsBeforeFirstPaintDispatcher(mDocument));
   }
 
   mPaintingSuppressed = false;
   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   if (rootFrame) {
     // let's assume that outline on a root frame is not supported
-    rootFrame->InvalidateFrame();
+    nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
+    rootFrame->Invalidate(rect);
 
     if (mCaretEnabled && mCaret) {
       mCaret->CheckCaretDrawingState();
     }
 
     nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
     if (rootPC) {
       rootPC->RequestUpdatePluginGeometry();
@@ -3967,17 +3943,17 @@ PresShell::DocumentStatesChanged(nsIDocu
     mFrameConstructor->PostRestyleEvent(mDocument->GetRootElement(),
                                         eRestyle_Subtree, NS_STYLE_HINT_NONE);
     VERIFY_STYLE_TREE;
   }
 
   if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
     nsIFrame* root = mFrameConstructor->GetRootFrame();
     if (root) {
-      FrameLayerBuilder::InvalidateAllLayersForFrame(root);
+      root->InvalidateFrameSubtree();
       if (root->HasView()) {
         root->GetView()->SetForcedRepaint(true);
       }
     }
   }
 }
 
 void
@@ -5254,55 +5230,27 @@ PresShell::Paint(nsIView*           aVie
       if (layerManager->HasShadowManager()) {
         return;
       }
       layerManager->BeginTransaction();
       if (layerManager->EndEmptyTransaction()) {
         return;
       }
       NS_WARNING("Must complete empty transaction when compositing!");
-    } else {
+    } else  if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) {
       layerManager->BeginTransaction();
-    }
-
-    if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) {
-      NotifySubDocInvalidationFunc computeInvalidFunc =
-        presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
-      bool computeInvalidRect = computeInvalidFunc ||
-                                (layerManager->GetBackendType() == LAYERS_BASIC);
-
-      nsAutoPtr<LayerProperties> props(computeInvalidRect ? 
-                                         LayerProperties::CloneFrom(layerManager->GetRoot()) : 
-                                         nullptr);
-
       if (layerManager->EndEmptyTransaction((aType == PaintType_NoComposite) ? LayerManager::END_NO_COMPOSITE : LayerManager::END_DEFAULT)) {
-        nsIntRect invalid;
-        if (props) {
-          invalid = props->ComputeDifferences(layerManager->GetRoot(), computeInvalidFunc);
-        } else {
-          LayerProperties::ClearInvalidations(layerManager->GetRoot());
-        }
-        if (!invalid.IsEmpty()) {
-          if (props) {
-            nsRect rect(presContext->DevPixelsToAppUnits(invalid.x),
-                        presContext->DevPixelsToAppUnits(invalid.y),
-                        presContext->DevPixelsToAppUnits(invalid.width),
-                        presContext->DevPixelsToAppUnits(invalid.height));
-            aViewToPaint->GetViewManager()->InvalidateViewNoSuppression(aViewToPaint, rect);
-            presContext->NotifyInvalidation(invalid, 0);
-          } else {
-            aViewToPaint->GetViewManager()->InvalidateView(aViewToPaint);
-          }
-        }
-
         frame->UpdatePaintCountForPaintedPresShells();
         presContext->NotifyDidPaintForSubtree();
         return;
       }
-    }
+    } else {
+      layerManager->BeginTransaction();
+    }
+
     frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
   } else {
     layerManager->BeginTransaction();
   }
   if (frame) {
     frame->ClearPresShellsFromLastPaint();
   }
 
@@ -6148,21 +6096,23 @@ PresShell::GetTouchEventTargetDocument()
 
 #ifdef DEBUG
 void
 PresShell::ShowEventTargetDebug()
 {
   if (nsFrame::GetShowEventTargetFrameBorder() &&
       GetCurrentEventFrame()) {
     if (mDrawEventTargetFrame) {
-      mDrawEventTargetFrame->InvalidateFrame();
+      mDrawEventTargetFrame->Invalidate(
+          nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize()));
     }
 
     mDrawEventTargetFrame = mCurrentEventFrame;
-    mDrawEventTargetFrame->InvalidateFrame();
+    mDrawEventTargetFrame->Invalidate(
+        nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize()));
   }
 }
 #endif
 
 nsresult
 PresShell::HandlePositionedEvent(nsIFrame*      aTargetFrame,
                                  nsGUIEvent*    aEvent,
                                  nsEventStatus* aEventStatus)
@@ -7330,23 +7280,16 @@ PresShell::ScheduleReflowOffTimer()
     }
   }
   return true;
 }
 
 bool
 PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
 {
-  target->SchedulePaint();
-  nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(target);
-  while (parent) {
-    nsSVGEffects::InvalidateDirectRenderingObservers(parent);
-    parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
-  }
-
   nsAutoCString docURL("N/A");
   nsIURI *uri = mDocument->GetDocumentURI();
   if (uri)
     uri->GetSpec(docURL);
   SAMPLE_LABEL_PRINTF("layout", "DoReflow", "(%s)", docURL.get());
 
   if (mReflowContinueTimer) {
     mReflowContinueTimer->Cancel();
@@ -7368,16 +7311,21 @@ PresShell::DoReflow(nsIFrame* target, bo
   target->WillReflow(mPresContext);
 
   // If the target frame is the root of the frame hierarchy, then
   // use all the available space. If it's simply a `reflow root',
   // then use the target frame's size as the available space.
   nsSize size;
   if (target == rootFrame) {
      size = mPresContext->GetVisibleArea().Size();
+
+     // target->GetRect() has the old size of the frame,
+     // mPresContext->GetVisibleArea() has the new size.
+     target->InvalidateRectDifference(mPresContext->GetVisibleArea(),
+                                      target->GetRect());
   } else {
      size = target->GetSize();
   }
 
   NS_ASSERTION(!target->GetNextInFlow() && !target->GetPrevInFlow(),
                "reflow roots should never split");
 
   // Don't pass size directly to the reflow state, since a
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -316,19 +316,16 @@ public:
   void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                            nsArenaMemoryStats *aArenaObjectsSize,
                            size_t *aPresShellSize,
                            size_t *aStyleSetsSize,
                            size_t *aTextRunsSize,
                            size_t *aPresContextSize);
   size_t SizeOfTextRuns(nsMallocSizeOfFun aMallocSizeOf) const;
 
-  virtual void AddInvalidateHiddenPresShellObserver(nsRefreshDriver *aDriver);
-
-
   // This data is stored as a content property (nsGkAtoms::scrolling) on
   // mContentToScrollTo when we have a pending ScrollIntoView.
   struct ScrollIntoViewData {
     ScrollAxis mContentScrollVAxis;
     ScrollAxis mContentScrollHAxis;
     uint32_t   mContentToScrollToFlags;
   };
 
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -95,21 +95,16 @@ nsRefreshDriver::nsRefreshDriver(nsPresC
   mRequests.Init();
 }
 
 nsRefreshDriver::~nsRefreshDriver()
 {
   NS_ABORT_IF_FALSE(ObserverCount() == 0,
                     "observers should have unregistered");
   NS_ABORT_IF_FALSE(!mTimer, "timer should be gone");
-  
-  for (uint32_t i = 0; i < mPresShellsToInvalidateIfHidden.Length(); i++) {
-    mPresShellsToInvalidateIfHidden[i]->InvalidatePresShellIfHidden();
-  }
-  mPresShellsToInvalidateIfHidden.Clear();
 }
 
 // Method for testing.  See nsIDOMWindowUtils.advanceTimeAndRefresh
 // for description.
 void
 nsRefreshDriver::AdvanceTimeAndRefresh(int64_t aMilliseconds)
 {
   mTestControllingRefreshes = true;
@@ -412,21 +407,16 @@ nsRefreshDriver::Notify(nsITimer *aTimer
    * for refresh events.
    */
 
   ImageRequestParameters parms = {mMostRecentRefresh};
   if (mRequests.Count()) {
     mRequests.EnumerateEntries(nsRefreshDriver::ImageRequestEnumerator, &parms);
     EnsureTimerStarted(false);
   }
-    
-  for (uint32_t i = 0; i < mPresShellsToInvalidateIfHidden.Length(); i++) {
-    mPresShellsToInvalidateIfHidden[i]->InvalidatePresShellIfHidden();
-  }
-  mPresShellsToInvalidateIfHidden.Clear();
 
   if (mViewManagerFlushIsPending) {
 #ifdef DEBUG_INVALIDATIONS
     printf("Starting ProcessPendingUpdates\n");
 #endif
     mViewManagerFlushIsPending = false;
     mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates();
 #ifdef DEBUG_INVALIDATIONS
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -139,37 +139,24 @@ public:
     return appended;
   }
   void RemoveLayoutFlushObserver(nsIPresShell* aShell) {
     mLayoutFlushObservers.RemoveElement(aShell);
   }
   bool IsLayoutFlushObserver(nsIPresShell* aShell) {
     return mLayoutFlushObservers.Contains(aShell);
   }
-  bool AddPresShellToInvalidateIfHidden(nsIPresShell* aShell) {
-    NS_ASSERTION(!mPresShellsToInvalidateIfHidden.Contains(aShell),
-		 "Double-adding style flush observer");
-    bool appended = mPresShellsToInvalidateIfHidden.AppendElement(aShell) != nullptr;
-    EnsureTimerStarted(false);
-    return appended;
-  }
-  void RemovePresShellToInvalidateIfHidden(nsIPresShell* aShell) {
-    mPresShellsToInvalidateIfHidden.RemoveElement(aShell);
-  }
 
   /**
    * Remember whether our presshell's view manager needs a flush
    */
   void ScheduleViewManagerFlush();
   void RevokeViewManagerFlush() {
     mViewManagerFlushIsPending = false;
   }
-  bool ViewManagerFlushIsPending() {
-    return mViewManagerFlushIsPending;
-  }
 
   /**
    * Add a document for which we have nsIFrameRequestCallbacks
    */
   void ScheduleFrameRequestCallbacks(nsIDocument* aDocument);
 
   /**
    * Remove a document for which we have nsIFrameRequestCallbacks
@@ -263,17 +250,16 @@ private:
   bool mViewManagerFlushIsPending;
 
   // separate arrays for each flush type we support
   ObserverArray mObservers[3];
   RequestTable mRequests;
 
   nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
   nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
-  nsAutoTArray<nsIPresShell*, 16> mPresShellsToInvalidateIfHidden;
   // nsTArray on purpose, because we want to be able to swap.
   nsTArray<nsIDocument*> mFrameRequestCallbackDocs;
 
   // This is the last interval we used for our timer.  May be 0 if we
   // haven't computed a timer interval yet.
   mutable int32_t mLastTimerInterval;
 
   // Helper struct for processing image requests
--- a/layout/base/tests/Makefile.in
+++ b/layout/base/tests/Makefile.in
@@ -43,17 +43,16 @@ MOCHITEST_FILES =	\
 		test_bug394057.html \
 		test_bug399284.html \
 		test_bug399951.html \
 		test_bug404209.xhtml \
 		test_bug416896.html \
 		test_bug423523.html \
 		test_bug449781.html \
 		test_bug450930.xhtml \
-		bug450930.xhtml \
 		test_bug458898.html \
 		test_bug465448.xul \
 		test_bug469170.html \
 		test_bug471126.html \
 		test_bug435293-scale.html \
 		test_bug435293-interaction.html \
 		test_bug435293-skew.html \
 		test_reftests_with_caret.html \
@@ -341,17 +340,17 @@ MOCHITEST_FILES += \
 		$(NULL)
 # THESE TESTS (ABOVE) DO NOT RUN ON WINDOWS
 endif
 
 # test_flush_on_paint.html fails frequently on Mac, bug 688128
 ifeq (,$(filter cocoa,$(MOZ_WIDGET_TOOLKIT)))
 # THESE TESTS (BELOW) DO NOT RUN ON MAC
 MOCHITEST_FILES += \
-		$(warning test_flush_on_paint.html disabled due to random orange; see bug 539356) \
+		test_flush_on_paint.html \
 		$(NULL)
 # THESE TESTS (ABOVE) DO NOT RUN ON MAC
 endif
 
 MOCHITEST_BROWSER_FILES = \
 	browser_bug617076.js \
 	$(NULL)
 
deleted file mode 100644
--- a/layout/base/tests/bug450930.xhtml
+++ /dev/null
@@ -1,183 +0,0 @@
-<?xml version="1.0"?>
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=450930
--->
-<head>
-  <title>Test for Bug 450930 (MozAfterPaint)</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body onload="runNext()">
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=450930">Mozilla Bug 450930</a>
-<div id="display">
-  <div id="d" style="width:400px; height:200px;"></div>
-  <iframe id="iframe" style="width:400px; height:200px;"
-   src="data:text/html,&lt;div id='d'&gt;&lt;span style='margin-left:3px;'&gt;Hello&lt;/span&gt;
-        &lt;/div&gt;&lt;div style='margin-top:500px' id='d2'&gt;
-        &lt;span style='margin-left:3px;'&gt;Goodbye&lt;/span&gt;&lt;/div>"></iframe>
-  <svg:svg style="width:410px; height:210px;" id="svg">
-    <svg:foreignObject width="100%" height="100%">
-      <iframe id="iframe2" style="width:400px; height:200px;"
-       src="data:text/html,&lt;div id='d'&gt;&lt;span style='margin-left:3px;'&gt;Hello&lt;/span&gt;
-            &lt;/div&gt;&lt;div style='margin-top:500px' id='d2'&gt;
-            &lt;span style='margin-left:3px;'&gt;Goodbye&lt;/span&gt;&lt;/div>"></iframe>
-    </svg:foreignObject>
-  </svg:svg>
-</div>
-<div id="content" style="display: none">
-</div>
-
-
-<pre id="test">
-<script class="testbody" type="text/javascript"><![CDATA[
-
-function flash(doc, name) {
-  var d = doc.getElementById(name);
-  d.style.backgroundColor = d.style.backgroundColor == "blue" ? "yellow" : "blue";
-  // Now flush out style changes in that document, since our event listeners
-  // seem to assume that things will work that way.
-  d.getBoundingClientRect();
-}
-
-function le(v1, v2, s) {
-  window.opener.ok(v1 <= v2, s + " (" + v1 + "," + v2 + ")");
-}
-
-function checkContains(r1, r2, s) {
-  le(Math.round(r1.left), Math.round(r2.left), "Left edges out" + s);
-  le(Math.round(r2.right), Math.round(r1.right), "Right edges out" + s);
-  le(Math.round(r1.top), Math.round(r2.top), "Top edges out" + s);
-  le(Math.round(r2.bottom), Math.round(r1.bottom), "Bottom edges out" + s);
-}
-
-function isRect(r1, r2) {
-  return (Math.abs(r1.left - r2.left) <= 1 ||
-          Math.abs(r1.right - r2.right) <= 1 ||
-          Math.abs(r1.top - r2.top) <= 1 ||
-          Math.abs(r1.bottom - r2.bottom) <= 1);
-}
-
-function isRectInList(r, list) {
-  for (var i = 0; i < list.length; ++i) {
-    if (isRect(r, list[i]))
-      return true;
-  }
-  return false;
-}
-
-function doesRectContain(r1, r2) {
-  return Math.floor(r1.left) <= r2.left && r2.right <= Math.ceil(r1.right) &&
-         Math.floor(r1.top) <= r2.top && r2.bottom <= Math.ceil(r1.bottom);
-}
-
-function rectToString(r) {
-  return "(" + r.left + "," + r.top + "," + r.right + "," + r.bottom + ")";
-}
-
-function doesRectContainListElement(r, list) {
-  dump("Incoming rect: " + rectToString(r) + "\n");
-  for (var i = 0; i < list.length; ++i) {
-    dump("List rect " + i + ": " + rectToString(list[i]));
-    if (doesRectContain(r, list[i])) {
-      dump(" FOUND\n");
-      return true;
-    }
-    dump("\n");
-  }
-  dump("NOT FOUND\n");
-  return false;
-}
-
-function checkGotSubdoc(list, container) {
-  var r = container.getBoundingClientRect();
-  return doesRectContainListElement(r, list);
-}
-
-function runTest1() {
-  // test basic functionality
-  var iterations = 0;
-  var foundExactRect = false;
-
-  function listener(event) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var r = event.boundingClientRect;
-    var bounds = document.getElementById('d').getBoundingClientRect();
-    checkContains(r, bounds, "");
-    if (isRectInList(bounds, event.clientRects)) {
-      foundExactRect = true;
-    }
-    window.removeEventListener("MozAfterPaint", listener, false);
-    ++iterations;
-    if (iterations < 4) {
-      setTimeout(triggerPaint, 100);
-    } else {
-      window.opener.ok(foundExactRect, "Found exact rect");
-      runNext();
-    }
-  }
-
-  function triggerPaint() {
-    window.addEventListener("MozAfterPaint", listener, false);
-    flash(document, 'd');
-    window.opener.ok(true, "trigger test1 paint");
-  }
-  triggerPaint();
-}
-
-function runTest2(frameID, containerID) {
-  // test reporting of painting in subdocuments
-  var fired = 0;
-  var gotSubdocPrivileged = false;
-  var iframe = document.getElementById(frameID);
-  var container = document.getElementById(containerID);
-
-  function listener(event) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    if (checkGotSubdoc(event.clientRects, container))
-      gotSubdocPrivileged = true;
-    if (event.clientRects.length > 0) {
-      if (++fired == 1)
-        setTimeout(check, 100);
-    }
-  }
-
-  function check() {
-    window.opener.is(fired, 1, "Wrong event count (" + frameID + ")");
-    window.opener.ok(gotSubdocPrivileged, "Didn't get subdoc invalidation while we were privileged (" + frameID + ")");
-    window.removeEventListener("MozAfterPaint", listener, false);
-    runNext();
-  }
-
-  function triggerPaint() {
-    window.addEventListener("MozAfterPaint", listener, false);
-    document.body.offsetTop;
-    flash(iframe.contentDocument, 'd');
-  }
-  triggerPaint();
-}
-
-var test = 0;
-var tests = [runTest1,
-             function() { runTest2("iframe", "iframe") },
-             function() { runTest2("iframe2", "svg") }];
-function runNext() {
-  if (SpecialPowers.DOMWindowUtils.isMozAfterPaintPending) {
-    // Wait until there are no pending paints before trying to run tests
-    setTimeout(runNext, 100);
-    return;
-  }
-  if (test < tests.length) {
-    ++test;
-    tests[test - 1]();
-  } else {
-    window.opener.finishTests();
-  }
-}
-
-
-]]></script>
-</pre>
-
-</body>
-</html>
--- a/layout/base/tests/chrome/Makefile.in
+++ b/layout/base/tests/chrome/Makefile.in
@@ -45,17 +45,14 @@ MOCHITEST_CHROME_FILES = \
 	test_transformed_scrolling_repaints_2.html \
 	test_transformed_scrolling_repaints_3.html \
 	transformed_scrolling_repaints_3_window.html \
 	test_fixed_bg_scrolling_repaints.html \
 	blue-32x32.png \
 	$(NULL)
 
 ifdef MOZ_DEBUG
-# Disabled on Mac because of Bug 748219
-ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 MOCHITEST_CHROME_FILES += \
 	test_leaf_layers_partition_browser_window.xul \
 	$(NULL)
 endif
-endif
 
 include $(topsrcdir)/config/rules.mk
--- a/layout/base/tests/chrome/test_leaf_layers_partition_browser_window.xul
+++ b/layout/base/tests/chrome/test_leaf_layers_partition_browser_window.xul
@@ -38,17 +38,17 @@
                   .getService(Components.interfaces.nsIWindowMediator)
                   .getMostRecentWindow("navigator:browser")
                   .maximize();
       }
 
       var initialCount = win.mozPaintCount;
 
       function nextStep() {
-        if (win.mozPaintCount == initialCount || win.isMozAfterPaintPending) {
+        if (win.mozPaintCount == initialCount) {
           SimpleTest.info("Waiting for mozPaintCount (= " + initialCount + ") to increase" + testInfo());
           // Do not use SimpleTest.executeSoon() here: give a little more time.
           setTimeout(nextStep, 100);
           return;
         }
 
         isnot(win.mozPaintCount, initialCount, "mozPaintCount has increased" + testInfo());
 
--- a/layout/base/tests/chrome/test_transformed_scrolling_repaints.html
+++ b/layout/base/tests/chrome/test_transformed_scrolling_repaints.html
@@ -28,17 +28,17 @@ function startTest() {
   // Do a couple of scrolls to ensure we've triggered activity heuristics.
   waitForAllPaintsFlushed(function () {
     t.scrollTop = 5;
     waitForAllPaintsFlushed(function () {
       t.scrollTop = 10;
       waitForAllPaintsFlushed(function () {
         // Clear paint state now and scroll again.
         utils.checkAndClearPaintedState(e);
-        t.scrollTop = 15;
+        t.scrollTop = 33;
         waitForAllPaintsFlushed(function () {
           var painted = utils.checkAndClearPaintedState(e);
           if (isLinux && !is64) {
             todo(false, "Fully-visible scrolled element should not have been painted (random on Linux-32)");
           } else {
             is(painted, false, "Fully-visible scrolled element should not have been painted");
           }
           SimpleTest.finish();
--- a/layout/base/tests/chrome/test_transformed_scrolling_repaints_2.html
+++ b/layout/base/tests/chrome/test_transformed_scrolling_repaints_2.html
@@ -4,19 +4,19 @@
   <title>Test that scaled elements with scrolled contents don't repaint unnecessarily when we scroll inside them (1.1 scale)</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="paint_listener.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
 </head>
 <!-- Need a timeout here to allow paint unsuppression before we start the test -->
 <body onload="setTimeout(startTest,0)">
 <div id="t" style="-moz-transform: scale(1.1, 1.1); -moz-transform-origin:top left; width:200px; height:100px; background:yellow; overflow:hidden">
-  <div style="height:40px;"></div>
-  <div id="e" style="height:30px; background:lime"></div>
-  <div style="height:300px; background:yellow"></div>
+  <div style="height:40px;">Hello</div>
+  <div id="e" style="height:30px; background:lime">Kitty</div>
+  <div style="height:300px; background:yellow">Kitty</div>
 </div>
 <pre id="test">
 <script type="application/javascript">
 SimpleTest.waitForExplicitFinish();
 
 var t = document.getElementById("t");
 var e = document.getElementById("e");
 var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
@@ -26,17 +26,17 @@ function startTest() {
   // Do a couple of scrolls to ensure we've triggered activity heuristics
   waitForAllPaintsFlushed(function () {
     t.scrollTop = 5;
     waitForAllPaintsFlushed(function () {
       t.scrollTop = 10;
       waitForAllPaintsFlushed(function () {
         // Clear paint state now and scroll again.
         utils.checkAndClearPaintedState(e);
-        t.scrollTop = 20;
+        t.scrollTop = 33;
         waitForAllPaintsFlushed(function () {
           var painted = utils.checkAndClearPaintedState(e);