Bug 539356 - Part 9 - Implement DLBI. r=roc,bz,jwatt
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 29 Aug 2012 17:38:58 +1200
changeset 111865 ef035122864a4a7391746afbb5a9da685a2bd34e
parent 111864 e4dd1fa6d2225c1440752936c3cba38c3e663314
child 111866 074075d10fd8c650453d927f4770d37c1457ea67
push id2248
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 19:23:44 +0000
treeherdermozilla-aurora@118a3b748323 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, bz, jwatt
bugs539356
milestone18.0a1
Bug 539356 - Part 9 - Implement DLBI. r=roc,bz,jwatt
content/base/src/nsFrameLoader.cpp
content/base/src/nsObjectLoadingContent.cpp
content/events/src/nsDOMNotifyPaintEvent.cpp
content/events/src/nsPaintRequest.cpp
content/html/content/src/nsHTMLCanvasElement.cpp
content/media/VideoFrameContainer.cpp
dom/base/nsDOMWindowUtils.cpp
dom/plugins/base/nsPluginInstanceOwner.cpp
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
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/nsLayoutUtils.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/base/nsRefreshDriver.h
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/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/nsImageMap.cpp
layout/generic/nsObjectFrame.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/style/ImageLoader.cpp
layout/svg/nsSVGEffects.cpp
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/xul/base/src/nsBox.cpp
layout/xul/base/src/nsDeckFrame.cpp
layout/xul/base/src/nsImageBoxFrame.cpp
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
view/src/nsViewManager.cpp
view/src/nsViewManager.h
widget/gtk2/nsNativeThemeGTK.cpp
widget/xpwidgets/nsNativeTheme.cpp
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -115,24 +115,16 @@ 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;
 }
 
@@ -157,23 +149,16 @@ 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),
@@ -1826,21 +1811,16 @@ 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;
@@ -1861,17 +1841,17 @@ nsFrameLoader::GetClipSubdocument(bool* 
 }
 
 NS_IMETHODIMP
 nsFrameLoader::SetClipSubdocument(bool aClip)
 {
   mClipSubdocument = aClip;
   nsIFrame* frame = GetPrimaryFrameOfOwningContent();
   if (frame) {
-    InvalidateFrame(frame, 0);
+    frame->InvalidateFrame();
     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->Invalidate(objFrame->GetContentRectRelativeToSelf());
+    objFrame->InvalidateFrame();
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::DisconnectFrame()
 {
   if (mInstanceOwner) {
--- a/content/events/src/nsDOMNotifyPaintEvent.cpp
+++ b/content/events/src/nsDOMNotifyPaintEvent.cpp
@@ -35,22 +35,20 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEve
 
 NS_IMPL_ADDREF_INHERITED(nsDOMNotifyPaintEvent, nsDOMEvent)
 NS_IMPL_RELEASE_INHERITED(nsDOMNotifyPaintEvent, nsDOMEvent)
 
 nsRegion
 nsDOMNotifyPaintEvent::GetRegion()
 {
   nsRegion r;
-  bool isTrusted = nsContentUtils::IsCallerTrustedForRead();
+  if (!nsContentUtils::IsCallerTrustedForRead()) {
+    return r;
+  }
   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)
@@ -94,27 +92,25 @@ 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;
 
-  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);
+  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);
+    }
   }
 
   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,27 +30,17 @@ nsPaintRequest::GetClientRect(nsIDOMClie
   clientRect->SetLayoutRect(mRequest.mRect);
   clientRect.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPaintRequest::GetReason(nsAString& aResult)
 {
-  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;
-  }
+  aResult.AssignLiteral("repaint");
   return NS_OK;
 }
 
 DOMCI_DATA(PaintRequestList, nsPaintRequestList)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPaintRequestList, mParent)
 
 NS_INTERFACE_TABLE_HEAD(nsPaintRequestList)
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -831,42 +831,33 @@ 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));
 
-  nsRect invalRect;
-  nsRect contentArea = frame->GetContentRect();
+  Layer* layer;
   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
-      invalRect = nsRect(realRect.X(), realRect.Y(),
-                         realRect.Width(), realRect.Height());
+      nsIntRect invalRect(realRect.X(), realRect.Y(),
+                          realRect.Width(), realRect.Height());
 
-      invalRect = invalRect.Intersect(nsRect(nsPoint(0,0), contentArea.Size()));
+      layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS, &invalRect);
     }
   } else {
-    invalRect = nsRect(nsPoint(0, 0), contentArea.Size());
+    layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS);
   }
-  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.
@@ -884,17 +875,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->Invalidate(frame->GetContentRect() - frame->GetPosition());
+  frame->InvalidateFrame();
 }
 
 int32_t
 nsHTMLCanvasElement::CountContexts()
 {
   if (mCurrentContext)
     return 1;
 
--- a/content/media/VideoFrameContainer.cpp
+++ b/content/media/VideoFrameContainer.cpp
@@ -126,20 +126,19 @@ void VideoFrameContainer::Invalidate()
         presShell->FrameNeedsReflow(frame,
                                     nsIPresShell::eStyleChange,
                                     NS_FRAME_IS_DIRTY);
       }
     }
   }
 
   if (frame) {
-    nsRect contentRect = frame->GetContentRect() - frame->GetPosition();
     if (invalidateFrame) {
-      frame->Invalidate(contentRect);
+      frame->InvalidateFrame();
     } else {
-      frame->InvalidateLayer(contentRect, nsDisplayItem::TYPE_VIDEO);
+      frame->InvalidateLayer(nsDisplayItem::TYPE_VIDEO);
     }
   }
 
   nsSVGEffects::InvalidateDirectRenderingObservers(mElement);
 }
 
 }
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -215,22 +215,20 @@ 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->InvalidateWithFlags(r, nsIFrame::INVALIDATE_IMMEDIATE);
+        rootFrame->InvalidateFrame();
 
 #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;
@@ -384,24 +382,17 @@ nsDOMWindowUtils::SetDisplayPortForEleme
       // separate notification just for this change.
       nsPresContext* presContext = GetPresContext();
       MaybeReflowForInflationScreenWidthChange(presContext);
     }
   }
 
   nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame();
   if (rootFrame) {
-    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);
+    rootFrame->InvalidateFrame();
 
     // 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,38 +655,34 @@ 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
-
-  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);
+  nsIntRect rect(invalidRect->left,
+                 invalidRect->top,
+                 invalidRect->right - invalidRect->left,
+                 invalidRect->bottom - invalidRect->top);
+  mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
  
 NS_IMETHODIMP
 nsPluginInstanceOwner::RedrawPlugin()
 {
   if (mObjectFrame) {
-    mObjectFrame->InvalidateLayer(mObjectFrame->GetContentRectRelativeToSelf(), nsDisplayItem::TYPE_PLUGIN);
+    mObjectFrame->InvalidateLayer(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");
@@ -3742,17 +3738,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->Invalidate(mObjectFrame->GetContentRectRelativeToSelf());
+    mObjectFrame->InvalidateFrame();
 
     // 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/gfx/layers/ImageLayers.h
+++ b/gfx/layers/ImageLayers.h
@@ -49,16 +49,18 @@ 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
    */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -0,0 +1,333 @@
+/*-*- 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);
+
+  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->GetInvalidRect(), 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);
+  }
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/LayerTreeInvalidation.h
@@ -0,0 +1,67 @@
+/*-*- 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;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* GFX_LAYER_TREE_INVALIDATON_H */
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -967,16 +967,39 @@ 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 nsIntRect& GetInvalidRect() { return mInvalidRect; }
+
+  /**
+   * Mark the entirety of the layer's visible region as being invalid.
+   */
+  void SetInvalidRectToVisibleRegion() { mInvalidRect = GetVisibleRegion().GetBounds(); }
+
+  /**
+   * Adds to the current invalid rect.
+   */
+  void AddInvalidRect(const nsIntRect& aRect) { mInvalidRect = mInvalidRect.Union(aRect); }
+
+  /**
+   * Clear the invalid rect, marking the layer as being identical to what is currently
+   * composited.
+   */
+  void ClearInvalidRect() { mInvalidRect.SetEmpty(); }
+
+
 #ifdef DEBUG
   void SetDebugColorIndex(uint32_t aIndex) { mDebugColorIndex = aIndex; }
   uint32_t GetDebugColorIndex() { return mDebugColorIndex; }
 #endif
 
 protected:
   Layer(LayerManager* aManager, void* aImplData);
 
@@ -1028,16 +1051,17 @@ protected:
   float mPostXScale;
   float mPostYScale;
   gfx3DMatrix mEffectiveTransform;
   AnimationArray mAnimations;
   InfallibleTArray<AnimData> mAnimationData;
   float mOpacity;
   nsIntRect mClipRect;
   nsIntRect mTileSourceRect;
+  nsIntRect mInvalidRect;
   uint32_t mContentFlags;
   bool mUseClipRect;
   bool mUseTileSourceRect;
   bool mIsFixedPosition;
   gfxPoint mAnchor;
   DebugOnly<uint32_t> mDebugColorIndex;
 };
 
@@ -1373,17 +1397,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; }
+  void Updated() { mDirty = true; SetInvalidRectToVisibleRegion(); }
 
   /**
    * 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,16 +39,17 @@ 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 \
@@ -71,16 +72,17 @@ 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
@@ -33,16 +33,17 @@ public:
                  "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");
     mValidRegion.Sub(mValidRegion, aRegion);
+    AddInvalidRect(aRegion.GetBounds());
   }
 
   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,16 +170,17 @@ 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
@@ -41,16 +41,17 @@ ThebesLayerD3D10::ThebesLayerD3D10(Layer
 ThebesLayerD3D10::~ThebesLayerD3D10()
 {
 }
 
 void
 ThebesLayerD3D10::InvalidateRegion(const nsIntRegion &aRegion)
 {
   mValidRegion.Sub(mValidRegion, aRegion);
+  AddInvalidRect(aRegion.GetBounds());
 }
 
 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
@@ -45,16 +45,17 @@ ThebesLayerD3D9::~ThebesLayerD3D9()
  * figure out the optimal threshold.
  */
 #define RETENTION_THRESHOLD 16384
 
 void
 ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
 {
   mValidRegion.Sub(mValidRegion, aRegion);
+  AddInvalidRect(aRegion.GetBounds());
 }
 
 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
@@ -785,16 +785,17 @@ ThebesLayerOGL::SetVisibleRegion(const n
     return;
   ThebesLayer::SetVisibleRegion(aRegion);
 }
 
 void
 ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
 {
   mValidRegion.Sub(mValidRegion, aRegion);
+  AddInvalidRect(aRegion.GetBounds());
 }
 
 void
 ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                             const nsIntPoint& aOffset)
 {
   if (!mBuffer && !CreateSurface()) {
     return;
--- a/gfx/thebes/gfx3DMatrix.cpp
+++ b/gfx/thebes/gfx3DMatrix.cpp
@@ -110,16 +110,23 @@ 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,16 +51,17 @@ 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/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -13,170 +13,152 @@
 #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(LayerManager *aManager) :
-    mInvalidateAllLayers(false),
-    mLayerManager(aManager)
+  LayerManagerData() :
+    mInvalidateAllLayers(false)
   {
     MOZ_COUNT_CTOR(LayerManagerData);
     mFramesWithLayers.Init();
   }
   ~LayerManagerData() {
     // Remove display item data properties now, since we won't be able
     // to find these frames again without mFramesWithLayers.
     mFramesWithLayers.EnumerateEntries(
-        FrameLayerBuilder::RemoveDisplayItemDataForFrame, nullptr);
+        FrameLayerBuilder::RemoveDisplayItemDataForFrame, this);
     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;
 };
 
-LayerManagerLayerBuilder::~LayerManagerLayerBuilder()
-{
-  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,
                  ContainerLayer* aContainerLayer,
                  const FrameLayerBuilder::ContainerParameters& aParameters) :
     mBuilder(aBuilder), mManager(aManager),
     mLayerBuilder(aLayerBuilder),
     mContainerFrame(aContainerFrame), mContainerLayer(aContainerLayer),
     mParameters(aParameters),
-    mNextFreeRecycledThebesLayer(0), mInvalidateAllThebesContent(false)
+    mNextFreeRecycledThebesLayer(0)
   {
     nsPresContext* presContext = aContainerFrame->PresContext();
     mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
     // 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,
@@ -184,17 +166,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);
+  void Finish(uint32_t *aTextContentFlags, LayerManagerData* aData);
 
   nsRect GetChildrenBounds() { return mBounds; }
 
   nscoord GetAppUnitsPerDevPixel() { return mAppUnitsPerDevPixel; }
 
   nsIntRect ScaleToNearestPixels(const nsRect& aRect)
   {
     return aRect.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
@@ -226,18 +208,16 @@ 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
@@ -402,17 +382,19 @@ 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);
+  void InvalidateForLayerChange(nsDisplayItem* aItem, 
+                                Layer* aNewLayer, 
+                                const nsPoint& aTopLeft);
   /**
    * 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);
   /**
@@ -481,27 +463,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.
    */
@@ -514,16 +496,21 @@ 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;
 
   /**
@@ -533,16 +520,23 @@ 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 result of GetPosition() for the active scrolled root of this layer
+  // 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
@@ -640,31 +634,30 @@ FrameLayerBuilder::Shutdown()
     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, 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)
 {
@@ -681,329 +674,57 @@ 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();
   }
 }
 
-/* static */ nsTArray<FrameLayerBuilder::DisplayItemData>*
+nsTArray<nsRefPtr<FrameLayerBuilder::DisplayItemData> >*
 FrameLayerBuilder::GetDisplayItemDataArrayForFrame(nsIFrame* aFrame)
 {
-  FrameProperties props = aFrame->Properties();
-  LayerManagerData *data =
-    reinterpret_cast<LayerManagerData*>(props.Get(LayerManagerDataProperty()));
-  if (!data)
+  LayerManagerData* data = static_cast<LayerManagerData*>
+    (mRetainingManager->GetUserData(&gLayerManagerUserData));
+  if (!data) {
     return nullptr;
+  }
 
   DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame);
-  NS_ASSERTION(entry, "out of sync?");
   if (!entry)
     return nullptr;
 
   return &entry->mData;
 }
 
-/* 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)
-{
-  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);
-  }
-}
-
-/* static */ PLDHashOperator
-FrameLayerBuilder::UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
-                                                 void* aUserArg)
+nsACString&
+AppendToString(nsACString& s, const nsIntRect& r,
+               const char* pfx="", const char* sfx="")
 {
-  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)
-{
-  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;
+  s += pfx;
+  s += nsPrintfCString(
+    "(x=%d, y=%d, w=%d, h=%d)",
+    r.x, r.y, r.width, r.height);
+  return s += sfx;
 }
 
-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;
-        }
-      }
-    }
-  }
-  return nullptr;
-}
-
-Layer*
-FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem)
+nsACString&
+AppendToString(nsACString& s, const nsIntRegion& r,
+               const char* pfx="", const char* sfx="")
 {
-  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;
-    }
+  s += pfx;
+
+  nsIntRegionRectIterator it(r);
+  s += "< ";
+  while (const nsIntRect* sr = it.Next()) {
+    AppendToString(s, *sr) += "; ";
   }
-
-  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;
+  s += ">";
+
+  return s += sfx;
 }
 
 /**
  * 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
@@ -1011,16 +732,397 @@ 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;
+  }
+}
+
+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));
+  if (data) {
+    // Update all the frames that used to have layers.
+    data->mFramesWithLayers.EnumerateEntries(UpdateDisplayItemDataForFrame, this);
+  } else {
+    data = new LayerManagerData();
+    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;
+}
+
+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();
+  FrameProperties props = f->Properties();
+  DisplayItemDataEntry* newDisplayItems =
+    builder ? builder->mNewDisplayItemData.GetEntry(f) : nullptr;
+
+  LayerManagerData* managerData = static_cast<LayerManagerData*>
+    (builder->GetRetainingLayerManager()->GetUserData(&gLayerManagerUserData));
+  LayerManagerData* data = static_cast<LayerManagerData*>(props.Get(LayerManagerDataProperty()));
+  if (!newDisplayItems || newDisplayItems->mData.IsEmpty()) {
+    // This frame was visible, but isn't anymore.
+    if (newDisplayItems) {
+      builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems);
+    }
+    if (data == managerData) {
+      props.Remove(LayerManagerDataProperty());
+    }
+    return PL_DHASH_REMOVE;
+  }
+
+  if (data) {
+    props.Remove(LayerManagerDataProperty());
+  }
+  props.Set(LayerManagerDataProperty(), 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) {
+    FrameProperties props = f->Properties();
+    bool found;
+    LayerManagerData* data = static_cast<LayerManagerData*>(props.Get(LayerManagerDataProperty()));
+    if (data == managerData) {
+      props.Remove(LayerManagerDataProperty(), &found);
+    }
+  }
+  return PL_DHASH_REMOVE;
+}
+
+LayerManagerLayerBuilder::~LayerManagerLayerBuilder()
+{
+  MOZ_COUNT_DTOR(LayerManagerLayerBuilder);
+  if (mDelete) {
+    delete mLayerBuilder;
+  }
+}
+
+/* static */ PLDHashOperator
+FrameLayerBuilder::StoreNewDisplayItemData(DisplayItemDataEntry* aEntry,
+                                           void* aUserArg)
+{
+  LayerManagerData* data = static_cast<LayerManagerData*>(aUserArg);
+  nsIFrame* f = aEntry->GetKey();
+  FrameProperties props = f->Properties();
+
+  // 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.
+  props.Remove(LayerManagerDataProperty());
+  props.Set(LayerManagerDataProperty(), data);
+  return PL_DHASH_REMOVE;
+}
+
+/* static */ FrameLayerBuilder::DisplayItemData*
+FrameLayerBuilder::GetDisplayItemDataForManager(nsIFrame* aFrame, uint32_t aDisplayItemKey, LayerManager* aManager)
+{
+  LayerManagerData* managerData = static_cast<LayerManagerData*>
+    (aManager->GetUserData(&gLayerManagerUserData));
+  if (!managerData) {
+    return nullptr;
+  }
+
+  DisplayItemDataEntry *entry = managerData->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(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;
+}
+
+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;
+}
+
+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)
+{
+  uint32_t key = aItem->GetPerFrameKey();
+  nsIFrame* frame = aItem->GetUnderlyingFrame();
+
+  if (frame) {
+    DisplayItemData* oldData = GetOldLayerForFrame(frame, key);
+    if (oldData) {
+      if (aOldGeometry) {
+        *aOldGeometry = oldData->mGeometry.get();
+      }
+      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();
+      }
+      return oldData->mLayer;
+    }
+  }
+
+  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<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;
@@ -1080,27 +1182,16 @@ 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.
@@ -1131,16 +1222,19 @@ 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)
 {
@@ -1164,44 +1258,53 @@ 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 (mInvalidateAllThebesContent ||
-        data->mXScale != mParameters.mXScale ||
+    if (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 = aActiveScrolledRoot->GetPosition();
+  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();
@@ -1280,16 +1383,40 @@ RestrictVisibleRegionForLayer(Layer* aLa
 
   nsIntRegion rgn = aLayer->GetVisibleRegion();
   if (!visibleRect.Contains(rgn.GetBounds())) {
     rgn.And(rgn, visibleRect);
     aLayer->SetVisibleRegion(rgn);
   }
 }
 
+static void
+SetVisibleRegionForLayer(Layer* aLayer, const nsIntRect& aItemVisible, const nsIntRect& aChildBounds)
+{
+  gfx3DMatrix transform = aLayer->GetTransform();
+
+  // if 'transform' is not invertible, then nothing will be displayed
+  // for the layer, so it doesn't really matter what we do here
+  gfxRect itemVisible(aItemVisible.x, aItemVisible.y, aItemVisible.width, aItemVisible.height);
+  gfxRect layerVisible = transform.Inverse().ProjectRectBounds(itemVisible);
+  layerVisible.RoundOut();
+
+  nsIntRect visibleRect;
+  if (!gfxUtils::GfxRectToIntRect(layerVisible, &visibleRect))
+    return;
+
+  nsIntRegion rgn = aChildBounds;
+  if (!visibleRect.Contains(aChildBounds)) {
+    rgn.And(rgn, visibleRect);
+    aLayer->SetVisibleRegion(rgn);
+  } else {
+    aLayer->SetVisibleRegion(aChildBounds);
+  }
+}
+
 nscolor
 ContainerState::FindOpaqueBackgroundColorFor(int32_t aThebesLayerIndex)
 {
   ThebesLayerData* target = mThebesLayerDataStack[aThebesLayerIndex];
   for (int32_t i = aThebesLayerIndex - 1; i >= 0; --i) {
     ThebesLayerData* candidate = mThebesLayerDataStack[i];
     nsIntRegion visibleAboveIntersection;
     visibleAboveIntersection.And(candidate->mVisibleAboveRegion, target->mVisibleRegion);
@@ -1733,61 +1860,54 @@ 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,
-                   FrameLayerBuilder *aLayerBuilder)
+                   nsRenderingContext* aCtx)
 {
   // 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
-
-  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);
+  basic->SetTarget(context);
+
   if (aItem->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) {
-    static_cast<nsDisplaySVGEffects*>(aItem)->PaintAsLayer(aBuilder, aCtx, tempManager);
-    if (tempManager->InTransaction()) {
-      tempManager->AbortTransaction();
+    static_cast<nsDisplaySVGEffects*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
+    if (basic->InTransaction()) {
+      basic->AbortTransaction();
     }
   } else {
-    tempManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder);
+    basic->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder);
   }
-  aLayerBuilder->DidEndTransaction(tempManager);
+  FrameLayerBuilder *builder = static_cast<FrameLayerBuilder*>(basic->GetUserData(&gLayerManagerLayerBuilder));
+  if (builder) {
+    builder->DidEndTransaction();
+  }
  
+  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();
@@ -1852,16 +1972,17 @@ ContainerState::ProcessDisplayItems(cons
       // that frame.
       forceInactive = true;
       activeScrolledRoot = mBuilder->FindReferenceFrameFor(mContainerFrame);
       isFixed = mBuilder->IsFixedItem(item, nullptr, activeScrolledRoot);
     } else {
       forceInactive = false;
       isFixed = mBuilder->IsFixedItem(item, &activeScrolledRoot);
     }
+    nsPoint topLeft = activeScrolledRoot->GetPosition();
 
     // Assign the item to a layer
     if (layerState == LAYER_ACTIVE_FORCE ||
         (!forceInactive &&
          (layerState == LAYER_ACTIVE_EMPTY ||
           layerState == LAYER_ACTIVE))) {
 
       // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
@@ -1870,27 +1991,31 @@ 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);
+        InvalidateForLayerChange(item, nullptr, topLeft);
         continue;
       }
 
       // Just use its layer.
       nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
       if (!ownLayer) {
-        InvalidateForLayerChange(item, ownLayer);
+        InvalidateForLayerChange(item, ownLayer, topLeft);
         continue;
       }
 
+      if (item->IsInvalid()) {
+        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);
@@ -1930,148 +2055,300 @@ 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);
+      InvalidateForLayerChange(item, ownLayer, topLeft);
 
       mNewChildLayers.AppendElement(ownLayer);
-      mLayerBuilder->AddLayerDisplayItem(ownLayer, item, layerState);
+      mLayerBuilder->AddLayerDisplayItem(ownLayer, item, 
+                                         layerState, topLeft, 
+                                         nullptr);
     } else {
       ThebesLayerData* data =
         FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, aClip,
                            activeScrolledRoot);
 
       data->mLayer->SetIsFixedPosition(isFixed);
 
-      InvalidateForLayerChange(item, data->mLayer);
+      InvalidateForLayerChange(item, data->mLayer, topLeft);
 
       mLayerBuilder->AddThebesDisplayItem(data->mLayer, item, aClip,
                                           mContainerFrame,
-                                          layerState);
+                                          layerState, topLeft);
 
       // 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)
+ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, 
+                                         Layer* aNewLayer, 
+                                         const nsPoint& aTopLeft)
 {
-  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) {
+  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;
+  nsAutoPtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(mBuilder));
+  Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem, &oldGeometry);
+  if (aNewLayer != oldLayer && oldLayer) {
     // The item has changed layers.
     // 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,
-          bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
+          oldGeometry->ComputeInvalidationRegion().ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
           mLayerBuilder->GetLastPaintOffset(t));
     }
     if (aNewLayer) {
-      ThebesLayer* newLayer = aNewLayer->AsThebesLayer();
-      if (newLayer) {
+      ThebesLayer* newThebesLayer = aNewLayer->AsThebesLayer();
+      if (newThebesLayer) {
         ThebesDisplayItemLayerUserData* data =
-            static_cast<ThebesDisplayItemLayerUserData*>(newLayer->GetUserData(&gThebesDisplayItemLayerUserData));
-        InvalidatePostTransformRegion(newLayer,
-            bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
-            GetTranslationForThebesLayer(newLayer));
+            static_cast<ThebesDisplayItemLayerUserData*>(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData));
+        InvalidatePostTransformRegion(newThebesLayer,
+            geometry->ComputeInvalidationRegion().ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
+            GetTranslationForThebesLayer(newThebesLayer));
       }
     }
-
-    mContainerFrame->InvalidateWithFlags(
-        bounds - mBuilder->ToReferenceFrame(mContainerFrame),
-        nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
-        nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
+    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 then we want to invalidate both the old and new bounds,
+  // otherwise we only want to invalidate the changed areas.
+  nsRegion combined;
+  if (!oldLayer) {
+    //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()) {
+    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 {
+    nsPoint shift = aTopLeft - data->mLastActiveScrolledRootOrigin;
+    oldGeometry->MoveBy(shift);
+    aItem->ComputeInvalidationRegion(mBuilder, oldGeometry, &combined);
+#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));
   }
 }
 
 bool
 FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder,
                                                     nsDisplayItem* aItem)
 {
-  return !aItem->ShouldFixToViewport(aBuilder) ||
-      !HasRetainedLayerFor(aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey());
+  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;
 }
 
 void
 FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
                                         nsDisplayItem* aItem,
                                         const Clip& aClip,
                                         nsIFrame* aContainerLayerFrame,
-                                        LayerState aLayerState)
+                                        LayerState aLayerState,
+                                        const nsPoint& aTopLeft)
 {
-  AddLayerDisplayItem(aLayer, aItem, 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, aLayerState, aTopLeft, tempManager);
 
   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();
+
+      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 = aLayerState != LAYER_NONE;
+    cdi->mInactiveLayer = tempManager;
   }
 }
 
 void
-FrameLayerBuilder::AddLayerDisplayItemForFrame(Layer* aLayer,
-                                               nsIFrame* aFrame,
-                                               uint32_t aDisplayItemKey,
-                                               LayerState aLayerState)
+FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame, DisplayItemData* aData)
 {
-  DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(aFrame);
+  DisplayItemDataEntry *entry = mNewDisplayItemData.GetEntry(aFrame);
+  if (entry) {
+    return;
+  }
+  entry = mNewDisplayItemData.PutEntry(aFrame);
   if (entry) {
-    entry->mContainerLayerGeneration = mContainerLayerGeneration;
-    entry->mData.AppendElement(DisplayItemData(aLayer, aDisplayItemKey, aLayerState, mContainerLayerGeneration));
+    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);
   }
 }
 
 void
 FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
                                        nsDisplayItem* aItem,
-                                       LayerState aLayerState)
+                                       LayerState aLayerState,
+                                       const nsPoint& aTopLeft,
+                                       LayerManager* aManager)
 {
   if (aLayer->Manager() != mRetainingManager)
     return;
-
-  nsIFrame* f = aItem->GetUnderlyingFrame();
-  uint32_t key = aItem->GetPerFrameKey();
-  AddLayerDisplayItemForFrame(aLayer, f, key, aLayerState);
+    
+  nsRefPtr<DisplayItemData> data = 
+    new DisplayItemData(aLayer, aItem->GetPerFrameKey(), aLayerState, mContainerLayerGeneration);
+    
+  ThebesLayer *t = aLayer->AsThebesLayer();
+  if (t) {
+    data->mGeometry = aItem->AllocateGeometry(mDisplayListBuilder);
+  }
+  data->mInactiveManager = aManager;
+
+  DisplayItemDataEntry* entry = 
+    mNewDisplayItemData.PutEntry(aItem->GetUnderlyingFrame());
+  if (entry) {
+    entry->mContainerLayerGeneration = mContainerLayerGeneration;
+    entry->mData.AppendElement(data);
+    data->AddFrame(aItem->GetUnderlyingFrame());
+  }
 
   nsAutoTArray<nsIFrame*,4> mergedFrames;
   aItem->GetMergedFrames(&mergedFrames);
   for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
-    AddLayerDisplayItemForFrame(aLayer, mergedFrames[i], key, aLayerState);
+    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;
   }
 }
 
 nsIntPoint
 FrameLayerBuilder::GetLastPaintOffset(ThebesLayer* aLayer)
 {
   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
   if (entry) {
@@ -2135,30 +2412,35 @@ 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)
+ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData)
 {
   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.
@@ -2278,79 +2560,27 @@ 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;
 }
 
@@ -2407,32 +2637,39 @@ already_AddRefed<ContainerLayer>
 FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
                                           LayerManager* aManager,
                                           nsIFrame* aContainerFrame,
                                           nsDisplayItem* aContainerItem,
                                           const nsDisplayList& aChildren,
                                           const ContainerParameters& aParameters,
                                           const gfx3DMatrix* aTransform)
 {
+  FrameProperties props = aContainerFrame->Properties();
   uint32_t containerDisplayItemKey =
     aContainerItem ? aContainerItem->GetPerFrameKey() : 0;
   NS_ASSERTION(aContainerFrame, "Container display items here should have a frame");
   NS_ASSERTION(!aContainerItem ||
                aContainerItem->GetUnderlyingFrame() == aContainerFrame,
                "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 = aContainerItem ?
-      GetOldLayerFor(aContainerItem) :
-      GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey);
+    Layer* oldLayer = nullptr;
+    if (aContainerItem) {
+      oldLayer = GetOldLayerFor(aContainerItem);
+    } else {
+      DisplayItemData *data = GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey);
+      if (data) {
+        oldLayer = data->mLayer;
+      }
+    }
 
     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 {
@@ -2472,97 +2709,64 @@ FrameLayerBuilder::BuildContainerLayerFo
   ContainerParameters scaleParameters =
     ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame, aTransform, aParameters,
                                containerLayer, state);
 
   uint32_t oldGeneration = mContainerLayerGeneration;
   mContainerLayerGeneration = ++mMaxContainerLayerGeneration;
 
   nsRefPtr<RefCountedRegion> thebesLayerInvalidRegion = nullptr;
-  if (aManager == mRetainingManager) {
-    FrameProperties props = aContainerFrame->Properties();
+  if (mRetainingManager) {
+    nsRefPtr<DisplayItemData> data =
+      new  DisplayItemData(containerLayer, containerDisplayItemKey,
+                           LAYER_ACTIVE, mContainerLayerGeneration);
+
     DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(aContainerFrame);
     if (entry) {
-      entry->mData.AppendElement(
-          DisplayItemData(containerLayer, containerDisplayItemKey,
-                          LAYER_ACTIVE, mContainerLayerGeneration));
-      thebesLayerInvalidRegion = static_cast<RefCountedRegion*>
-        (props.Get(ThebesLayerInvalidRegionProperty()));
-      if (!thebesLayerInvalidRegion) {
-        thebesLayerInvalidRegion = new RefCountedRegion();
+      entry->mData.AppendElement(data);
+      data->AddFrame(aContainerFrame);
+      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);
       }
-      entry->mInvalidRegion = thebesLayerInvalidRegion;
-      entry->mContainerLayerGeneration = mContainerLayerGeneration;
     }
   }
 
   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;
-  bool flattenedLayers = false;
+  
+  LayerManagerData* data = static_cast<LayerManagerData*>
+    (aManager->GetUserData(&gLayerManagerUserData));
   while (true) {
     ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(),
                          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);
+    state.Finish(&flags, data);
     bounds = state.GetChildrenBounds();
     pixBounds = state.ScaleToOutsidePixels(bounds, false);
     appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel();
 
     if ((flags & Layer::CONTENT_COMPONENT_ALPHA) &&
         mRetainingManager &&
         !mRetainingManager->AreComponentAlphaLayersEnabled() &&
         !stateFlags) {
@@ -2571,17 +2775,16 @@ 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);
@@ -2592,160 +2795,69 @@ 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 = GetOldLayerForFrame(f, aItem->GetPerFrameKey());
+  Layer* layer = GetOldLayerFor(aItem);
   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 */
 Layer*
 FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey)
 {
-  nsTArray<DisplayItemData>* array = GetDisplayItemDataArrayForFrame(aFrame);
-  if (!array)
+  FrameProperties props = aFrame->Properties();
+  LayerManagerData* data = static_cast<LayerManagerData*>(props.Get(LayerManagerDataProperty()));
+  if (!data) {
     return nullptr;
-
-  for (uint32_t i = 0; i < array->Length(); ++i) {
-    if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
-      Layer* layer = array->ElementAt(i).mLayer;
+  }
+  DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame);
+  if (!entry) {
+    return nullptr;
+  }
+
+  for (uint32_t i = 0; i < entry->mData.Length(); ++i) {
+    if (entry->mData.ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
+      Layer* layer = entry->mData.ElementAt(i).mLayer;
       if (!layer->HasUserData(&gColorLayerUserData) &&
           !layer->HasUserData(&gImageLayerUserData) &&
           !layer->HasUserData(&gThebesDisplayItemLayerUserData))
         return layer;
     }
   }
   return nullptr;
 }
@@ -2766,35 +2878,37 @@ PredictScaleForContent(nsIFrame* aFrame,
 }
 
 gfxSize
 FrameLayerBuilder::GetThebesLayerScaleForFrame(nsIFrame* aFrame)
 {
   nsIFrame* last;
   for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
     last = f;
-    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));
-          }
+    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));
         }
       }
     }
   }
 
   return PredictScaleForContent(aFrame, last,
       last->PresContext()->PresShell()->GetResolution());
 }
@@ -2908,24 +3022,16 @@ 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);
@@ -2998,17 +3104,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->mItem, aContext, rc, layerBuilder);
+      PaintInactiveLayer(builder, cdi->mInactiveLayer, cdi->mItem, aContext, rc);
     } else {
       nsIFrame* frame = cdi->mItem->GetUnderlyingFrame();
       if (frame) {
         frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
       }
 #ifdef MOZ_DUMP_PAINTING
 
       if (gfxUtils::sDumpPainting) {
@@ -3031,16 +3137,19 @@ 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;
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -6,31 +6,34 @@
 #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"
 
 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,
@@ -43,18 +46,19 @@ enum LayerState {
 class RefCountedRegion : public RefCounted<RefCountedRegion> {
 public:
   RefCountedRegion() : mIsInfinite(false) {}
   nsRegion mRegion;
   bool mIsInfinite;
 };
 
 /**
- * The FrameLayerBuilder belongs to an nsDisplayListBuilder and is
- * responsible for converting display lists into layer trees.
+ * The FrameLayerBuilder is responsible for converting display lists 
+ * into layer trees. Every LayerManager needs a unique FrameLayerBuilder
+ * to build layers.
  * 
  * 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
  * also updates userdata for the retained layer manager, and
  * DisplayItemDataProperty data for frames, to record the relationship
  * between frames and layers.
  * 
@@ -115,28 +119,24 @@ 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 on aManager. If aManager
-   * is not the retained layer manager then it must be a temporary layer
-   * manager that will not be used again.
+   * Call this just before we end a transaction.
    */
-  void WillEndTransaction(LayerManager* aManager);
+  void WillEndTransaction();
 
   /**
-   * 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.
+   * Call this after we end a transaction.
    */
-  void DidEndTransaction(LayerManager* aManager);
+  void DidEndTransaction();
 
   struct ContainerParameters {
     ContainerParameters() :
       mXScale(1), mYScale(1),
       mInTransformedSubtree(false), mInActiveTransformedSubtree(false),
       mDisableSubpixelAntialiasingInDescendants(false)
     {}
     ContainerParameters(float aXScale, float aYScale) :
@@ -207,44 +207,19 @@ 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);
 
   /**
    * 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,
@@ -274,59 +249,59 @@ 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 aManager If the layer is in the LAYER_INACTIVE state,
+   * then this is the temporary layer manager to draw with.
    */
   void AddLayerDisplayItem(Layer* aLayer,
                            nsDisplayItem* aItem,
-                           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);
+                           LayerState aLayerState,
+                           const nsPoint& aTopLeft,
+                           LayerManager* aManager = nullptr);
 
   /**
    * 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.
    */
   struct Clip;
   void AddThebesDisplayItem(ThebesLayer* aLayer,
                             nsDisplayItem* aItem,
                             const Clip& aClip,
                             nsIFrame* aContainerLayerFrame,
-                            LayerState aLayerState);
-
-  /**
-   * 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.
-   */
-  Layer* GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey);
+                            LayerState aLayerState,
+                            const nsPoint& aTopLeft);
 
   /**
    * 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);
+  Layer* GetOldLayerFor(nsDisplayItem* aItem, nsDisplayItemGeometry** aOldGeometry = nullptr);
 
   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);
 
@@ -351,21 +326,25 @@ 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);
+  static bool HasRetainedLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey, LayerManager* aManager);
 
   /**
-   * Save transform that was in aLayer when we last painted. It must be an integer
+   * Save transform that was in aLayer when we last painted, and the position
+   * of the active scrolled root frame. 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).
    */
@@ -466,87 +445,130 @@ 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<LayerManager> mInactiveManager;
+    nsAutoTArray<nsIFrame*, 2> mFrameList;
+    nsAutoPtr<nsDisplayItemGeometry> mGeometry;
     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, 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)
-      , mIsSharingContainerLayer(false)
-      {}
+    { 
+      MOZ_COUNT_CTOR(DisplayItemDataEntry); 
+    }
     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<DisplayItemData, 1> mData;
-    nsRefPtr<RefCountedRegion> mInvalidRegion;
+    nsAutoTArray<nsRefPtr<DisplayItemData>, 1> mData;
     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.
    */
-  static nsTArray<DisplayItemData>* GetDisplayItemDataArrayForFrame(nsIFrame *aFrame);
+  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(nsDisplayItem* aItem, LayerManager* aManager);
 
   /**
    * A useful hashtable iteration function that removes the
    * 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)
-  {
-    return UpdateDisplayItemDataForFrame(aEntry, nullptr);
-  }
+                                                       void* aClosure);
 
   /**
    * 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
@@ -554,20 +576,29 @@ 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> {
@@ -602,16 +633,18 @@ 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);
@@ -634,16 +667,21 @@ 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.
--- a/layout/base/Makefile.in
+++ b/layout/base/Makefile.in
@@ -33,16 +33,17 @@ 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 \
@@ -68,16 +69,17 @@ 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,21 +7699,16 @@ 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
@@ -7745,46 +7740,39 @@ 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->InvalidateOverflowRect();
+        aFrame->InvalidateFrameSubtree();
       }
     }
     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);
-        // Invalidate the old transformed area. The new transformed area
-        // will be invalidated by nsFrame::FinishAndStoreOverflowArea.
-        childFrame->InvalidateTransformLayer();
-      }
-    }
+      }
+    }
+    aFrame->SchedulePaint();
   }
 }
 
 static void
 ApplyRenderingChangeToTree(nsPresContext* aPresContext,
                            nsIFrame* aFrame,
                            nsChangeHint aChange)
 {
@@ -12428,39 +12416,35 @@ 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.
@@ -12521,29 +12505,23 @@ 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,18 +478,19 @@ 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()))
-    InvalidateRects(mCaretRect, GetHookRect(), frame);
+  if (frame && !frame->GetVisualOverflowRect().Contains(GetCaretRect())) {
+    frame->SchedulePaint();
+  }
 }
 
 void nsCaret::UpdateCaretPosition()
 {
   // We'll recalculate anyway if we're not drawn right now.
   if (!mDrawn)
     return;
 
@@ -608,41 +609,19 @@ 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();
 
@@ -656,18 +635,16 @@ 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
@@ -716,17 +693,17 @@ nsCaret::DrawAtPositionWithHint(nsIDOMNo
     }
 
     // Only update the caret's rect when we're not currently drawn.
     if (!UpdateCaretRects(theFrame, theFrameOffset))
       return false;
   }
 
   if (aInvalidate)
-    InvalidateRects(mCaretRect, mHookRect, theFrame);
+    theFrame->SchedulePaint();
 
   return true;
 }
 
 nsresult 
 nsCaret::GetCaretFrameForNodeOffset(nsIContent*             aContentNode,
                                     int32_t                 aOffset,
                                     nsFrameSelection::HINT aFrameHint,
@@ -1132,26 +1109,16 @@ 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,20 +168,16 @@ 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
@@ -198,18 +194,16 @@ 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,16 +23,17 @@
 #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"
@@ -966,18 +967,20 @@ void nsDisplayList::PaintForFrame(nsDisp
                                   nsIFrame* aForFrame,
                                   uint32_t aFlags) const {
   NS_ASSERTION(mDidComputeVisibility,
                "Must call ComputeVisibility before calling Paint");
 
   nsRefPtr<LayerManager> layerManager;
   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);
       }
@@ -1007,21 +1010,35 @@ 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);
@@ -1057,22 +1074,42 @@ 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(layerManager);
+  layerBuilder->WillEndTransaction();
   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(layerManager);
+  layerBuilder->DidEndTransaction();
+
+  nsIntRect invalid;
+  if (props) {
+    invalid = props->ComputeDifferences(root, computeInvalidFunc);
+  }
+
+  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);
+    }
+  }
 
   if (aFlags & PAINT_FLUSH_LAYERS) {
     FrameLayerBuilder::InvalidateAllLayers(layerManager);
   }
 
   nsCSSRendering::DidPaint();
   layerManager->RemoveUserData(&gLayerManagerLayerBuilder);
 }
@@ -1857,17 +1894,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 = GetBounds(aBuilder, aSnap);
+      result = nsRect(ToReferenceFrame(), mFrame->GetSize());
     }
     return result;
   }
 
   nsStyleContext* bgSC;
   nsPresContext* presContext = mFrame->PresContext();
   if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
     return result;
@@ -1957,16 +1994,46 @@ 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) {
@@ -1979,25 +2046,51 @@ 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()
@@ -2089,17 +2182,39 @@ 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(),
@@ -2513,18 +2628,20 @@ 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)
-    : nsDisplayWrapList(aBuilder, aFrame, aList) {
+                                     nsIFrame* aFrame, nsDisplayList* aList,
+                                     uint32_t aFlags)
+    : nsDisplayWrapList(aBuilder, aFrame, aList)
+    , mFlags(aFlags) {
   MOZ_COUNT_CTOR(nsDisplayOwnLayer);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayOwnLayer::~nsDisplayOwnLayer() {
   MOZ_COUNT_DTOR(nsDisplayOwnLayer);
 }
 #endif
@@ -2532,16 +2649,22 @@ 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)
@@ -2994,19 +3117,20 @@ 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)
-    : nsDisplayOwnLayer(aBuilder, aFrame, aList), mAPD(aAPD),
-      mParentAPD(aParentAPD) {
+                             int32_t aAPD, int32_t aParentAPD,
+                             uint32_t aFlags)
+    : nsDisplayOwnLayer(aBuilder, aFrame, aList, aFlags)
+    , 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,16 +20,17 @@
 #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;
@@ -754,16 +755,78 @@ 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() { return mFrame ? mFrame->IsInvalid() : false; }
+
+  /**
+   * 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.
@@ -1602,16 +1665,22 @@ 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
@@ -1704,16 +1773,32 @@ 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);
@@ -1751,16 +1836,31 @@ 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.
  */
@@ -1776,16 +1876,34 @@ 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.
  */
@@ -1882,16 +2000,28 @@ 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()
+  {
+    if (mFrame->IsInvalid()) {
+      return true;
+    }
+    for (uint32_t i = 0; i < mMergedFrames.Length(); i++) {
+      if (mMergedFrames[i]->IsInvalid()) {
+        return true;
+      }
+    }
+    return false;
+  }
   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
@@ -1994,18 +2124,31 @@ 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);
+                    nsDisplayList* aList, uint32_t aFlags = 0);
 #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,
@@ -2015,16 +2158,18 @@ 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 {
@@ -2248,20 +2393,24 @@ 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);
+                int32_t aAPD, int32_t aParentAPD,
+                uint32_t aFlags = 0);
 #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;
new file mode 100644
--- /dev/null
+++ b/layout/base/nsDisplayListInvalidation.cpp
@@ -0,0 +1,70 @@
+/*-*- 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);
+}
+
new file mode 100644
--- /dev/null
+++ b/layout/base/nsDisplayListInvalidation.h
@@ -0,0 +1,96 @@
+/*-*- 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.
+   */
+  nsRegion 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,18 +2901,17 @@ 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) {
-      nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
-      rootFrame->Invalidate(rect);
+      rootFrame->InvalidateFrame();
     }
     return NS_OK;
   }
 #endif
 
   mPageZoom = aFullZoom;
 
   struct ZoomInfo ZoomInfo = { aFullZoom };
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -462,32 +462,21 @@ nsFrameManager::InsertFrames(nsIFrame*  
            InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
   } else {
     return aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
   }
 }
 
 nsresult
 nsFrameManager::RemoveFrame(ChildListID     aListID,
-                            nsIFrame*       aOldFrame,
-                            bool            aInvalidate /* = true */)
+                            nsIFrame*       aOldFrame)
 {
   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
-  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.");
   nsresult rv = NS_OK;
--- a/layout/base/nsFrameManager.h
+++ b/layout/base/nsFrameManager.h
@@ -90,18 +90,17 @@ public:
                                     nsFrameList&    aFrameList);
 
   NS_HIDDEN_(nsresult) InsertFrames(nsIFrame*       aParentFrame,
                                     ChildListID     aListID,
                                     nsIFrame*       aPrevFrame,
                                     nsFrameList&    aFrameList);
 
   NS_HIDDEN_(nsresult) RemoveFrame(ChildListID     aListID,
-                                   nsIFrame*       aOldFrame,
-                                   bool            aInvalidate = true);
+                                   nsIFrame*       aOldFrame);
 
   /*
    * 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/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3996,16 +3996,18 @@ 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 (IsPopup(f))
       return f;
     nsIFrame* parent = GetCrossDocParentFrame(f);
     if (!parent)
       return f;
     f = parent;
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -83,16 +83,18 @@
 //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),
@@ -124,16 +126,32 @@ 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);
@@ -771,17 +789,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.
-    FrameLayerBuilder::InvalidateThebesLayersInSubtreeWithUntrustedFrameGeometry(rootFrame);
+    rootFrame->InvalidateFrameSubtree();
   }
 }
 
 void
 nsPresContext::AppUnitsPerDevPixelChanged()
 {
   InvalidateThebesLayers();
 
@@ -1963,39 +1981,24 @@ void
 nsPresContext::FireDOMPaintEvent()
 {
   nsPIDOMWindow* ourWindow = mDocument->GetWindow();
   if (!ourWindow)
     return;
 
   nsCOMPtr<nsIDOMEventTarget> dispatchTarget = do_QueryInterface(ourWindow);
   nsCOMPtr<nsIDOMEventTarget> eventTarget = dispatchTarget;
-  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;
-      }
+  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;
     }
   }
   // 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).
@@ -2010,16 +2013,34 @@ nsPresContext::FireDOMPaintEvent()
   // 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();
@@ -2060,26 +2081,46 @@ 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(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 (aRect.IsEmpty() || !MayHavePaintEventListener())
-    return;
 
   nsPresContext* pc;
   for (pc = this; pc; pc = pc->GetParentPresContext()) {
     if (pc->mFireAfterPaintEvents)
       break;
     pc->mFireAfterPaintEvents = true;
   }
   if (!pc) {
@@ -2093,45 +2134,68 @@ 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();
   }
 
-  if (!mInvalidateRequests.mRequests.IsEmpty()) {
-    nsCOMPtr<nsIRunnable> ev =
-      NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
-    nsContentUtils::AddScriptRunner(ev);
-  }
+  mFireAfterPaintEvents = false;
+
+  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,16 +27,17 @@
 #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;
@@ -107,16 +108,27 @@ 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;
 
@@ -789,22 +801,26 @@ public:
 
   // 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(const nsRect& aRect, uint32_t aFlags);
+  // aRect is in device pixels
+  void NotifyInvalidation(const nsIntRect& aRect, uint32_t aFlags);
   void NotifyDidPaintForSubtree();
   void FireDOMPaintEvent();
 
-  bool IsDOMPaintEventPending() {
-    return !mInvalidateRequests.mRequests.IsEmpty();
-  }
+  // Callback for catching invalidations in ContainerLayers
+  // Passed to LayerProperties::ComputeDifference
+  static void NotifySubDocInvalidation(mozilla::layers::ContainerLayer* aContainer,
+                                       const nsIntRegion& aRegion);
+  bool IsDOMPaintEventPending();
   void ClearMozAfterPaintEvents() {
     mInvalidateRequests.mRequests.Clear();
   }
 
   bool IsProcessingRestyles() const {
     return mProcessingRestyles;
   }
 
@@ -998,22 +1014,32 @@ 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.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -3540,18 +3540,17 @@ 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
-    nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
-    rootFrame->Invalidate(rect);
+    rootFrame->InvalidateFrame();
 
     if (mCaretEnabled && mCaret) {
       mCaret->CheckCaretDrawingState();
     }
 
     nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
     if (rootPC) {
       rootPC->RequestUpdatePluginGeometry();
@@ -3949,16 +3948,17 @@ PresShell::DocumentStatesChanged(nsIDocu
     nsIFrame* root = mFrameConstructor->GetRootFrame();
     if (root) {
       root->InvalidateFrameSubtree();
       if (root->HasView()) {
         root->GetView()->SetForcedRepaint(true);
       }
     }
   }
+  ScheduleViewManagerFlush();
 }
 
 void
 PresShell::AttributeWillChange(nsIDocument* aDocument,
                                Element*     aElement,
                                int32_t      aNameSpaceID,
                                nsIAtom*     aAttribute,
                                int32_t      aModType)
@@ -6096,23 +6096,21 @@ PresShell::GetTouchEventTargetDocument()
 
 #ifdef DEBUG
 void
 PresShell::ShowEventTargetDebug()
 {
   if (nsFrame::GetShowEventTargetFrameBorder() &&
       GetCurrentEventFrame()) {
     if (mDrawEventTargetFrame) {
-      mDrawEventTargetFrame->Invalidate(
-          nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize()));
+      mDrawEventTargetFrame->InvalidateFrame();
     }
 
     mDrawEventTargetFrame = mCurrentEventFrame;
-    mDrawEventTargetFrame->Invalidate(
-        nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize()));
+    mDrawEventTargetFrame->InvalidateFrame();
   }
 }
 #endif
 
 nsresult
 PresShell::HandlePositionedEvent(nsIFrame*      aTargetFrame,
                                  nsGUIEvent*    aEvent,
                                  nsEventStatus* aEventStatus)
@@ -7280,16 +7278,18 @@ PresShell::ScheduleReflowOffTimer()
     }
   }
   return true;
 }
 
 bool
 PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
 {
+  target->SchedulePaint();
+
   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();
@@ -7311,21 +7311,16 @@ 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/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -147,16 +147,19 @@ public:
 
   /**
    * 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
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -112,21 +112,28 @@ public:
 #endif  
   
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
     aOutFrames->AppendElement(mFrame);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
 private:
   nsButtonFrameRenderer* mBFR;
 };
 
+nsRect
+nsDisplayButtonBorderBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+  *aSnap = false;
+  return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
+}
+
 class nsDisplayButtonForeground : public nsDisplayItem {
 public:
   nsDisplayButtonForeground(nsDisplayListBuilder* aBuilder,
                             nsButtonFrameRenderer* aRenderer)
     : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
     MOZ_COUNT_CTOR(nsDisplayButtonForeground);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -351,17 +351,17 @@ nsComboboxControlFrame::SetFocus(bool aO
 
   if (!weakFrame.IsAlive()) {
     return;
   }
 
   // This is needed on a temporary basis. It causes the focus
   // rect to be drawn. This is much faster than ReResolvingStyle
   // Bug 32920
-  Invalidate(nsRect(0,0,mRect.width,mRect.height));
+  InvalidateFrame();
 }
 
 void
 nsComboboxControlFrame::ShowPopup(bool aShowPopup)
 {
   nsIView* view = mDropdownFrame->GetView();
   nsIViewManager* viewManager = view->GetViewManager();
 
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -579,17 +579,17 @@ nsFieldSetFrame::Reflow(nsPresContext*  
   aDesiredSize.width = contentRect.width + borderPadding.LeftRight();
   aDesiredSize.SetOverflowAreasToDesiredBounds();
   if (mLegendFrame)
     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mLegendFrame);
   if (mContentFrame)
     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mContentFrame);
   FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
 
-  Invalidate(aDesiredSize.VisualOverflow());
+  InvalidateFrame();
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return NS_OK;
 }
 
 int
 nsFieldSetFrame::GetSkipSides() const
 {
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -251,25 +251,17 @@ void nsListControlFrame::PaintFocus(nsRe
 void
 nsListControlFrame::InvalidateFocus()
 {
   if (mFocused != this)
     return;
 
   nsIFrame* containerFrame = GetOptionsContainer();
   if (containerFrame) {
-    // Invalidating from the containerFrame because that's where our focus
-    // is drawn.
-    // The origin of the scrollport is the origin of containerFrame.
-    float inflation = nsLayoutUtils::FontSizeInflationFor(this);
-    nsRect invalidateArea = containerFrame->GetVisualOverflowRect();
-    nsRect emptyFallbackArea(0, 0, GetScrollPortRect().width,
-                             CalcFallbackRowHeight(inflation));
-    invalidateArea.UnionRect(invalidateArea, emptyFallbackArea);
-    containerFrame->Invalidate(invalidateArea);
+    containerFrame->InvalidateFrame();
   }
 }
 
 NS_QUERYFRAME_HEAD(nsListControlFrame)
   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
   NS_QUERYFRAME_ENTRY(nsIListControlFrame)
   NS_QUERYFRAME_ENTRY(nsISelectControlFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsHTMLScrollFrame)
@@ -995,16 +987,18 @@ nsListControlFrame::Init(nsIContent*    
   mContent->AddEventListener(NS_LITERAL_STRING("mousemove"), mEventListener,
                              false, false);
 
   mStartSelectionIndex = kNothingSelected;
   mEndSelectionIndex = kNothingSelected;
 
   mLastDropdownBackstopColor = PresContext()->DefaultBackgroundColor();
 
+  AddStateBits(NS_FRAME_IN_POPUP);
+
   return result;
 }
 
 already_AddRefed<nsIContent> 
 nsListControlFrame::GetOptionAsContent(nsIDOMHTMLOptionsCollection* aCollection, int32_t aIndex) 
 {
   nsIContent * content = nullptr;
   nsCOMPtr<nsIDOMHTMLOptionElement> optionElement = GetOption(aCollection,
@@ -1674,28 +1668,16 @@ nsListControlFrame::DidReflow(nsPresCont
 }
 
 nsIAtom*
 nsListControlFrame::GetType() const
 {
   return nsGkAtoms::listControlFrame; 
 }
 
-void
-nsListControlFrame::InvalidateInternal(const nsRect& aDamageRect,
-                                       nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                       uint32_t aFlags)
-{
-  if (!IsInDropDownMode()) {
-    nsHTMLScrollFrame::InvalidateInternal(aDamageRect, aX, aY, this, aFlags);
-    return;
-  }
-  InvalidateRoot(aDamageRect + nsPoint(aX, aY), aFlags);
-}
-
 #ifdef DEBUG
 NS_IMETHODIMP
 nsListControlFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("ListControl"), aResult);
 }
 #endif
 
--- a/layout/forms/nsListControlFrame.h
+++ b/layout/forms/nsListControlFrame.h
@@ -87,20 +87,16 @@ public:
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const
   {
     return nsHTMLScrollFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
-  virtual void InvalidateInternal(const nsRect& aDamageRect,
-                                  nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                  uint32_t aFlags) MOZ_OVERRIDE;
-
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
     // nsIFormControlFrame
   virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) MOZ_OVERRIDE;
   virtual nsresult GetFormProperty(nsIAtom* aName, nsAString& aValue) const MOZ_OVERRIDE; 
   virtual void SetFocus(bool aOn = true, bool aRepaint = false);
--- a/layout/forms/nsMeterFrame.cpp
+++ b/layout/forms/nsMeterFrame.cpp
@@ -204,17 +204,17 @@ nsMeterFrame::AttributeChanged(int32_t  
       (aAttribute == nsGkAtoms::value ||
        aAttribute == nsGkAtoms::max   ||
        aAttribute == nsGkAtoms::min )) {
     nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
     NS_ASSERTION(barFrame, "The meter frame should have a child with a frame!");
     PresContext()->PresShell()->FrameNeedsReflow(barFrame,
                                                  nsIPresShell::eResize,
                                                  NS_FRAME_IS_DIRTY);
-    Invalidate(GetVisualOverflowRectRelativeToSelf());
+    InvalidateFrame();
   }
 
   return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
                                             aModType);
 }
 
 nsSize
 nsMeterFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
--- a/layout/forms/nsProgressFrame.cpp
+++ b/layout/forms/nsProgressFrame.cpp
@@ -219,17 +219,17 @@ nsProgressFrame::AttributeChanged(int32_
   NS_ASSERTION(mBarDiv, "Progress bar div must exist!");
 
   if (aNameSpaceID == kNameSpaceID_None &&
       (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::max)) {
     nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
     NS_ASSERTION(barFrame, "The progress frame should have a child with a frame!");
     PresContext()->PresShell()->FrameNeedsReflow(barFrame, nsIPresShell::eResize,
                                                  NS_FRAME_IS_DIRTY);
-    Invalidate(GetVisualOverflowRectRelativeToSelf());
+    InvalidateFrame();
   }
 
   return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 nsSize
 nsProgressFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
                                  nsSize aCBSize, nscoord aAvailableWidth,
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -536,19 +536,16 @@ nsTextControlFrame::Reflow(nsPresContext
   aDesiredSize.SetOverflowAreasToDesiredBounds();
   // perform reflow on all kids
   nsIFrame* kid = mFrames.FirstChild();
   while (kid) {
     ReflowTextControlChild(kid, aPresContext, aReflowState, aStatus, aDesiredSize);
     kid = kid->GetNextSibling();
   }
 
-  // If we're resizing, we might need to invalidate our border areas and such
-  CheckInvalidateSizeChange(aDesiredSize);
-
   // take into account css properties that affect overflow handling
   FinishAndStoreOverflow(&aDesiredSize);
 
   aStatus = NS_FRAME_COMPLETE;
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return NS_OK;
 }
 
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -451,33 +451,16 @@ nsAbsoluteContainingBlock::ReflowAbsolut
     // Size and position the view and set its opacity, visibility, content
     // transparency, and clip
     nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
                                                kidDesiredSize.VisualOverflow());
   } else {
     nsContainerFrame::PositionChildViews(aKidFrame);
   }
 
-  if (oldRect.TopLeft() != rect.TopLeft() || 
-      (aDelegatingFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
-    // The frame moved
-    aKidFrame->GetParent()->Invalidate(oldOverflowRect);
-    aKidFrame->InvalidateFrameSubtree();
-  } else if (oldRect.Size() != rect.Size()) {
-    // Invalidate the area where the frame changed size.
-    nscoord innerWidth = NS_MIN(oldRect.width, rect.width);
-    nscoord innerHeight = NS_MIN(oldRect.height, rect.height);
-    nscoord outerWidth = NS_MAX(oldRect.width, rect.width);
-    nscoord outerHeight = NS_MAX(oldRect.height, rect.height);
-    aKidFrame->GetParent()->Invalidate(
-        nsRect(rect.x + innerWidth, rect.y, outerWidth - innerWidth, outerHeight));
-    // Invalidate the horizontal strip
-    aKidFrame->GetParent()->Invalidate(
-        nsRect(rect.x, rect.y + innerHeight, outerWidth, outerHeight - innerHeight));
-  }
   aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED);
 
 #ifdef DEBUG
   if (nsBlockFrame::gNoisyReflow) {
     nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1);
     printf("abs pos ");
     if (aKidFrame) {
       nsAutoString name;
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -482,42 +482,16 @@ nsBlockFrame::GetFrameName(nsAString& aR
 #endif
 
 nsIAtom*
 nsBlockFrame::GetType() const
 {
   return nsGkAtoms::blockFrame;
 }
 
-void
-nsBlockFrame::InvalidateInternal(const nsRect& aDamageRect,
-                                 nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                 uint32_t aFlags)
-{
-  // Optimize by suppressing invalidation of areas that are clipped out
-  // with CSS 'clip'. Don't suppress invalidation of *this* frame directly,
-  // because when 'clip' shrinks we need to invalidate this frame and
-  // be able to invalidate areas outside the 'clip'.
-  if (aForChild) {
-    const nsStyleDisplay* disp = GetStyleDisplay();
-    nsRect clipRect;
-    if (GetClipPropClipRect(disp, &clipRect, GetSize())) {
-      // Restrict the invalidated area to abs-pos clip rect
-      // abs-pos clipping clips everything in the frame
-      nsRect r;
-      if (r.IntersectRect(aDamageRect, clipRect - nsPoint(aX, aY))) {
-        nsBlockFrameSuper::InvalidateInternal(r, aX, aY, this, aFlags);
-      }
-      return;
-    }
-  }
-
-  nsBlockFrameSuper::InvalidateInternal(aDamageRect, aX, aY, this, aFlags);
-}
-
 nscoord
 nsBlockFrame::GetBaseline() const
 {
   nscoord result;
   if (nsLayoutUtils::GetLastLineBaseline(this, &result))
     return result;
   return nsFrame::GetBaseline();
 }
@@ -1209,19 +1183,16 @@ nsBlockFrame::Reflow(nsPresContext*     
                                 containingBlockSize.height, true,
                                 cbWidthChanged, cbHeightChanged,
                                 &aMetrics.mOverflowAreas);
 
       //XXXfr Why isn't this rv (and others in this file) checked/returned?
     }
   }
 
-  // Determine if we need to repaint our border, background or outline
-  CheckInvalidateSizeChange(aMetrics);
-
   FinishAndStoreOverflow(&aMetrics);
 
   // Clear the float manager pointer in the block reflow state so we
   // don't waste time translating the coordinate system back on a dead
   // float manager.
   if (needFloatManager)
     state.mFloatManager = nullptr;
 
@@ -2471,28 +2442,16 @@ nsBlockFrame::DeleteLine(nsBlockReflowSt
     FreeLineBox(line);
     // Mark the previous margin of the next line dirty since we need to
     // recompute its top position.
     if (aLine != aLineEnd)
       aLine->MarkPreviousMarginDirty();
   }
 }
 
-static void
-InvalidateThebesLayersInLineBox(nsIFrame* aBlock, nsLineBox* aLine)
-{
-  if (aBlock->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT) {
-    int32_t childCount = aLine->GetChildCount();
-    for (nsIFrame* f = aLine->mFirstChild; childCount;
-         --childCount, f = f->GetNextSibling()) {
-      FrameLayerBuilder::InvalidateThebesLayersInSubtree(f);
-    }
-  }
-}
-
 /**
  * Reflow a line. The line will either contain a single block frame
  * or contain 1 or more inline frames. aKeepReflowGoing indicates
  * whether or not the caller should continue to reflow more lines.
  */
 nsresult
 nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
                          line_iterator aLine,
@@ -2505,88 +2464,20 @@ nsBlockFrame::ReflowLine(nsBlockReflowSt
   // Setup the line-layout for the new line
   aState.mCurrentLine = aLine;
   aLine->ClearDirty();
   aLine->InvalidateCachedIsEmpty();
   aLine->ClearHadFloatPushed();
 
   // Now that we know what kind of line we have, reflow it
   if (aLine->IsBlock()) {
-    nsRect oldBounds = aLine->mFirstChild->GetRect();
-    nsRect oldVisOverflow(aLine->GetVisualOverflowArea());
     rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing);
-    nsRect newBounds = aLine->mFirstChild->GetRect();
-
-    // We expect blocks to damage any area inside their bounds that is
-    // dirty; however, if the frame changes size or position then we
-    // need to do some repainting.
-    // XXX roc --- the above statement is ambiguous about whether 'bounds'
-    // means the frame's bounds or overflowArea, and in fact this is a source
-    // of much confusion and bugs. Thus the following hack considers *both*
-    // overflowArea and bounds. This should be considered a temporary hack
-    // until we decide how it's really supposed to work.
-    // Note that we have a similar hack in nsTableFrame::InvalidateFrame.
-    nsRect visOverflow(aLine->GetVisualOverflowArea());
-    if (oldVisOverflow.TopLeft() != visOverflow.TopLeft() ||
-        oldBounds.TopLeft() != newBounds.TopLeft()) {
-      // The block has moved, and so to be safe we need to repaint
-      // XXX We need to improve on this...
-      nsRect  dirtyRect;
-      dirtyRect.UnionRect(oldVisOverflow, visOverflow);
-#ifdef NOISY_BLOCK_INVALIDATE
-      printf("%p invalidate 6 (%d, %d, %d, %d)\n",
-             this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
-#endif
-      Invalidate(dirtyRect);
-      FrameLayerBuilder::InvalidateThebesLayersInSubtree(aLine->mFirstChild);
-    } else {
-      nsRect combinedAreaHStrip, combinedAreaVStrip;
-      nsRect boundsHStrip, boundsVStrip;
-      nsLayoutUtils::GetRectDifferenceStrips(oldBounds, newBounds,
-                                             &boundsHStrip, &boundsVStrip);
-      nsLayoutUtils::GetRectDifferenceStrips(oldVisOverflow, visOverflow,
-                                             &combinedAreaHStrip,
-                                             &combinedAreaVStrip);
-
-#ifdef NOISY_BLOCK_INVALIDATE
-      printf("%p invalidate boundsVStrip (%d, %d, %d, %d)\n",
-             this, boundsVStrip.x, boundsVStrip.y, boundsVStrip.width, boundsVStrip.height);
-      printf("%p invalidate boundsHStrip (%d, %d, %d, %d)\n",
-             this, boundsHStrip.x, boundsHStrip.y, boundsHStrip.width, boundsHStrip.height);
-      printf("%p invalidate combinedAreaVStrip (%d, %d, %d, %d)\n",
-             this, combinedAreaVStrip.x, combinedAreaVStrip.y, combinedAreaVStrip.width, combinedAreaVStrip.height);
-      printf("%p invalidate combinedAreaHStrip (%d, %d, %d, %d)\n",
-             this, combinedAreaHStrip.x, combinedAreaHStrip.y, combinedAreaHStrip.width, combinedAreaHStrip.height);
-#endif
-      // The first thing Invalidate does is check if the rect is empty, so
-      // don't bother doing that here.
-      Invalidate(boundsVStrip);
-      Invalidate(boundsHStrip);
-      Invalidate(combinedAreaVStrip);
-      Invalidate(combinedAreaHStrip);
-    }
-  }
-  else {
-    nsRect oldVisOverflow(aLine->GetVisualOverflowArea());
+  } else {
     aLine->SetLineWrapped(false);
-
     rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
-
-    // We don't really know what changed in the line, so use the union
-    // of the old and new combined areas
-    nsRect dirtyRect;
-    dirtyRect.UnionRect(oldVisOverflow, aLine->GetVisualOverflowArea());
-#ifdef NOISY_BLOCK_INVALIDATE
-    printf("%p invalidate (%d, %d, %d, %d)\n",
-           this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
-    if (aLine->IsForceInvalidate())
-      printf("  dirty line is %p\n", static_cast<void*>(aLine.get()));
-#endif
-    Invalidate(dirtyRect);
-    InvalidateThebesLayersInLineBox(this, aLine);
   }
 
   return rv;
 }
 
 nsIFrame*
 nsBlockFrame::PullFrame(nsBlockReflowState& aState,
                         line_iterator       aLine)
@@ -2680,27 +2571,23 @@ nsBlockFrame::PullFrameFrom(nsBlockReflo
   if (fromLine->GetChildCount() > 1) {
     // Mark line dirty now that we pulled a child
     fromLine->NoteFrameRemoved(frame);
     fromLine->MarkDirty();
     fromLine->mFirstChild = newFirstChild;
   } else {
     // Free up the fromLine now that it's empty
     // Its bounds might need to be redrawn, though.
-    // XXX WHY do we invalidate the bounds AND the combined area? doesn't
-    // the combined area always enclose the bounds?
-    Invalidate(fromLine->mBounds);
     FrameLines* overflowLines =
       aFromOverflowLine ? aFromContainer->RemoveOverflowLines() : nullptr;
     nsLineList* fromLineList =
       aFromOverflowLine ? &overflowLines->mLines : &aFromContainer->mLines;
     if (aFromLine.next() != fromLineList->end())
       aFromLine.next()->MarkPreviousMarginDirty();
 
-    Invalidate(fromLine->GetVisualOverflowArea());
     fromLineList->erase(aFromLine);
     // aFromLine is now invalid
     aFromContainer->FreeLineBox(fromLine);
 
     // Put any remaining overflow lines back.
     if (aFromOverflowLine) {
       if (!fromLineList->empty()) {
         aFromContainer->SetOverflowLines(overflowLines);
@@ -2730,21 +2617,18 @@ PlaceFrameView(nsIFrame* aFrame)
 }
 
 void
 nsBlockFrame::SlideLine(nsBlockReflowState& aState,
                         nsLineBox* aLine, nscoord aDY)
 {
   NS_PRECONDITION(aDY != 0, "why slide a line nowhere?");
 
-  Invalidate(aLine->GetVisualOverflowArea());
   // Adjust line state
   aLine->SlideBy(aDY);
-  Invalidate(aLine->GetVisualOverflowArea());
-  InvalidateThebesLayersInLineBox(this, aLine);
 
   // Adjust the frames in the line
   nsIFrame* kid = aLine->mFirstChild;
   if (!kid) {
     return;
   }
 
   if (aLine->IsBlock()) {
@@ -3033,19 +2917,16 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
   nsIFrame* clearanceFrame = nullptr;
   nscoord startingY = aState.mY;
   nsCollapsingMargin incomingMargin = aState.mPrevBottomMargin;
   nscoord clearance;
   // Save the original position of the frame so that we can reposition
   // its view as needed.
   nsPoint originalPosition = frame->GetPosition();
   while (true) {
-    // Save the frame's current position. We might need it later.
-    nscoord passOriginalY = frame->GetRect().y;
-    
     clearance = 0;
     nscoord topMargin = 0;
     bool mayNeedRetry = false;
     bool clearedFloats = false;
     if (applyTopMargin) {
       // Precompute the blocks top margin value so that we can get the
       // correct available space (there might be a float that's
       // already been placed below the aState.mPrevBottomMargin
@@ -3202,24 +3083,16 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
       blockHtmlRS.mDiscoveredClearance = aState.mReflowState.mDiscoveredClearance;
     }
     
     nsReflowStatus frameReflowStatus = NS_FRAME_COMPLETE;
     rv = brc.ReflowBlock(availSpace, applyTopMargin, aState.mPrevBottomMargin,
                          clearance, aState.IsAdjacentWithTop(),
                          aLine.get(), blockHtmlRS, frameReflowStatus, aState);
 
-    // If this was a second-pass reflow and the block's vertical position
-    // changed, invalidates from the first pass might have happened in the
-    // wrong places.  Invalidate the entire overflow rect at the new position.
-    if (!mayNeedRetry && clearanceFrame &&
-        frame->GetRect().y != passOriginalY) {
-      Invalidate(frame->GetVisualOverflowRect() + frame->GetPosition());
-    }
-    
     NS_ENSURE_SUCCESS(rv, rv);
     
     if (mayNeedRetry && clearanceFrame) {
       aState.mFloatManager->PopState(&floatManagerState);
       aState.mY = startingY;
       aState.mPrevBottomMargin = incomingMargin;
       continue;
     }
@@ -5535,17 +5408,16 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
         // a call to RemoveFrame(), but we may not need to do this in all
         // cases...
         nsRect visOverflow(cur->GetVisualOverflowArea());
 #ifdef NOISY_BLOCK_INVALIDATE
         printf("%p invalidate 10 (%d, %d, %d, %d)\n",
                this, visOverflow.x, visOverflow.y,
                visOverflow.width, visOverflow.height);
 #endif
-        Invalidate(visOverflow);
       } else {
         // XXX update searchingOverflowList directly, remove only when empty
         FrameLines* overflowLines = RemoveOverflowLines();
         line = overflowLines->mLines.erase(line);
         if (!overflowLines->mLines.empty()) {
           SetOverflowLines(overflowLines);
         } else {
           delete overflowLines;
@@ -5994,34 +5866,18 @@ nsBlockFrame::ReflowPushedFloats(nsBlock
     nsIFrame *prevContinuation = f->GetPrevContinuation();
     if (prevContinuation && prevContinuation->GetParent() == f->GetParent()) {
       mFloats.RemoveFrame(f);
       aState.AppendPushedFloat(f);
       continue;
     }
 
     if (NS_SUBTREE_DIRTY(f) || aState.mReflowState.ShouldReflowAllKids()) {
-      // Cache old bounds
-      nsRect oldRect = f->GetRect();
-      nsRect oldOverflow = f->GetVisualOverflowRect();
-
       // Reflow
       aState.FlowAndPlaceFloat(f);
-
-      // Invalidate if there was a position or size change
-      nsRect rect = f->GetRect();
-      if (!rect.IsEqualInterior(oldRect)) {
-        nsRect dirtyRect = oldOverflow;
-        dirtyRect.MoveBy(oldRect.x, oldRect.y);
-        Invalidate(dirtyRect);
-
-        dirtyRect = f->GetVisualOverflowRect();
-        dirtyRect.MoveBy(rect.x, rect.y);
-        Invalidate(dirtyRect);
-      }
     }
     else {
       // Just reload the float region into the space manager
       nsRect region = nsFloatManager::GetRegionFor(f);
       aState.mFloatManager->AddFloat(f, region);
       if (f->GetNextInFlow())
         NS_MergeReflowStatusInto(&aStatus, NS_FRAME_OVERFLOW_INCOMPLETE);
     }
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -153,19 +153,16 @@ public:
   virtual nscoord GetBaseline() const;
   virtual nscoord GetCaretBaseline() const;
   virtual void DestroyFrom(nsIFrame* aDestructRoot);
   virtual nsSplittableType GetSplittableType() const;
   virtual bool IsFloatContainingBlock() const;
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists);
-  virtual void InvalidateInternal(const nsRect& aDamageRect,
-                                  nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                  uint32_t aFlags);
   virtual nsIAtom* GetType() const;
   virtual bool IsFrameOfType(uint32_t aFlags) const
   {
     return nsContainerFrame::IsFrameOfType(aFlags &
              ~(nsIFrame::eCanContainOverflowContainers |
                nsIFrame::eBlockFrame));
   }
 
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -785,17 +785,16 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
   // Position the float and make sure and views are properly
   // positioned. We need to explicitly position its child views as
   // well, since we're moving the float after flowing it.
   bool moved = aFloat->GetPosition() != origin;
   if (moved) {
     aFloat->SetPosition(origin);
     nsContainerFrame::PositionFrameView(aFloat);
     nsContainerFrame::PositionChildViews(aFloat);
-    FrameLayerBuilder::InvalidateThebesLayersInSubtree(aFloat);
   }
 
   // Update the float combined area state
   // XXX Floats should really just get invalidated here if necessary
   mFloatOverflowAreas.UnionWith(aFloat->GetOverflowAreas() + origin);
 
   // Place the float in the float manager
   // calculate region
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -1476,17 +1476,17 @@ NS_IMETHODIMP nsBulletFrame::OnStartCont
 
 NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest,
                                              bool aCurrentFrame,
                                              const nsIntRect *aRect)
 {
   // The image has changed.
   // Invalidate the entire content area. Maybe it's not optimal but it's simple and
   // always correct, and I'll be a stunned mullet if it ever matters for performance
-  Invalidate(nsRect(0, 0, mRect.width, mRect.height));
+  InvalidateFrame();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsBulletFrame::OnStopDecode(imgIRequest *aRequest,
                                           nsresult aStatus,
                                           const PRUnichar *aStatusArg)
 {
@@ -1518,17 +1518,17 @@ NS_IMETHODIMP nsBulletFrame::OnImageIsAn
 }
 
 NS_IMETHODIMP nsBulletFrame::FrameChanged(imgIRequest *aRequest,
                                           imgIContainer *aContainer,
                                           const nsIntRect *aDirtyRect)
 {
   // Invalidate the entire content area. Maybe it's not optimal but it's simple and
   // always correct.
-  Invalidate(nsRect(0, 0, mRect.width, mRect.height));
+  InvalidateFrame();
 
   return NS_OK;
 }
 
 void
 nsBulletFrame::GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup)
 {
   if (!aPresContext)
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -151,22 +151,16 @@ nsCanvasFrame::RemoveFrame(ChildListID  
   if (aListID != kPrincipalList || aListID != kAbsoluteList) {
     // We only support the Principal and Absolute child lists.
     return NS_ERROR_INVALID_ARG;
   }
 
   if (aOldFrame != mFrames.FirstChild())
     return NS_ERROR_FAILURE;
 
-  // It's our one and only child frame
-  // Damage the area occupied by the deleted frame
-  // The child of the canvas probably can't have an outline, but why bother
-  // thinking about that?
-  Invalidate(aOldFrame->GetVisualOverflowRect() + aOldFrame->GetPosition());
-
   // Remove the frame and destroy it
   mFrames.DestroyFrame(aOldFrame);
 
   PresContext()->PresShell()->
     FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                      NS_FRAME_HAS_DIRTY_CHILDREN);
   return NS_OK;
 }
@@ -502,25 +496,17 @@ nsCanvasFrame::Reflow(nsPresContext*    
       // invalidate our whole rect.
       // Note: Even though we request to be sized to our child's size, our
       // scroll frame ensures that we are always the size of the viewport.
       // Also note: GetPosition() on a CanvasFrame is always going to return
       // (0, 0). We only want to invalidate GetRect() since Get*OverflowRect()
       // could also include overflow to our top and left (out of the viewport)
       // which doesn't need to be painted.
       nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame();
-      viewport->Invalidate(nsRect(nsPoint(0, 0), viewport->GetSize()));
-    } else {
-      nsRect newKidRect = kidFrame->GetRect();
-      if (newKidRect.TopLeft() == oldKidRect.TopLeft()) {
-        InvalidateRectDifference(oldKidRect, kidFrame->GetRect());
-      } else {
-        Invalidate(oldKidRect);
-        Invalidate(newKidRect);
-      }
+      viewport->InvalidateFrame();
     }
     
     // Return our desired size. Normally it's what we're told, but
     // sometimes we can be given an unconstrained height (when a window
     // is sizing-to-content), and we should compute our desired height.
     aDesiredSize.width = aReflowState.ComputedWidth();
     if (aReflowState.ComputedHeight() == NS_UNCONSTRAINEDSIZE) {
       aDesiredSize.height = kidFrame->GetRect().height +
@@ -554,17 +540,17 @@ nsCanvasFrame::Reflow(nsPresContext*    
       nsStyleContext* bgSC =
         nsCSSRendering::FindCanvasBackground(this, rootElementFrame);
       const nsStyleBackground* bg = bgSC->GetStyleBackground();
       if (!bg->IsTransparent()) {
         NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
           const nsStyleBackground::Layer& layer = bg->mLayers[i];
           if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
               layer.RenderingMightDependOnFrameSize()) {
-            Invalidate(nsRect(nsPoint(0, 0), GetSize()));
+            InvalidateFrame();
             break;
           }
         }
       }
     }
   }
 
   if (prevCanvasFrame) {
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -111,16 +111,38 @@ public:
 protected:
   virtual int GetSkipSides() const;
 
   // Data members
   bool                      mDoPaintFocus;
   bool                      mAddedScrollPositionListener;
 };
 
+class nsDisplayCanvasBackgroundGeometry : public nsDisplayItemGeometry
+{
+public:
+  nsDisplayCanvasBackgroundGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder, const nsRect& aChildBorder)
+    : nsDisplayItemGeometry(aItem, aBuilder)
+    , mChildBorder(aChildBorder)
+    , mPaddingRect(aItem->GetPaddingRect())
+    , mContentRect(aItem->GetContentRect())
+  {}
+
+  virtual void MoveBy(const nsPoint& aOffset)
+  {
+    mBounds.MoveBy(aOffset);
+    mPaddingRect.MoveBy(aOffset);
+    mContentRect.MoveBy(aOffset);
+  }
+
+  nsRect mChildBorder;
+  nsRect mPaddingRect;
+  nsRect mContentRect;
+};
+
 /**
  * Override nsDisplayBackground methods so that we pass aBGClipRect to
  * PaintBackground, covering the whole overflow area.
  * We can also paint an "extra background color" behind the normal
  * background.
  */
 class nsDisplayCanvasBackground : public nsDisplayBackground {
 public:
@@ -164,17 +186,49 @@ public:
     return frame->CanvasArea() + ToReferenceFrame();
   }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE
   {
     // We need to override so we don't consider border-radius.
     aOutFrames->AppendElement(mFrame);
   }
+  
+  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
+  {
+    nsIFrame *child = mFrame->GetFirstPrincipalChild();
+    return new nsDisplayCanvasBackgroundGeometry(this, aBuilder, 
+                                                 child ? child->GetRect() : nsRect());;
+  }
 
+  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+                                         const nsDisplayItemGeometry* aGeometry,
+                                         nsRegion* aInvalidRegion)
+  {
+    const nsDisplayCanvasBackgroundGeometry* geometry = static_cast<const nsDisplayCanvasBackgroundGeometry*>(aGeometry);
+    if (ShouldFixToViewport(aBuilder)) {
+      // This is incorrect, We definitely need to check more things here. 
+      return;
+    }
+
+    nsIFrame *child = mFrame->GetFirstPrincipalChild();
+
+    bool snap;
+    if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
+        (child && !geometry->mChildBorder.IsEqualInterior(child->GetRect())) ||
+        !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);
+      }
+    }
+  }
+  
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
 
   void SetExtraBackgroundColor(nscolor aColor)
   {
     mExtraBackgroundColor = aColor;
   }
 
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -436,23 +436,17 @@ PlaceFrameView(nsIFrame* aFrame)
     nsContainerFrame::PositionChildViews(aFrame);
 }
 
 static void MoveChildTo(nsIFrame* aParent, nsIFrame* aChild, nsPoint aOrigin) {
   if (aChild->GetPosition() == aOrigin) {
     return;
   }
   
-  nsRect r = aChild->GetVisualOverflowRect();
-  r += aChild->GetPosition();
-  aParent->Invalidate(r);
-  r -= aChild->GetPosition();
   aChild->SetPosition(aOrigin);
-  r += aOrigin;
-  aParent->Invalidate(r);
   PlaceFrameView(aChild);
 }
 
 nscoord
 nsColumnSetFrame::GetMinWidth(nsRenderingContext *aRenderingContext) {
   nscoord width = 0;
   DISPLAY_MIN_WIDTH(this, width);
   if (mFrames.FirstChild()) {
@@ -1080,18 +1074,16 @@ nsColumnSetFrame::Reflow(nsPresContext* 
 
     if (aPresContext->HasPendingInterrupt() &&
         aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE) {
       // In this situation, we might be lying about our reflow status, because
       // our last kid (the one that got interrupted) was incomplete.  Fix that.
       aStatus = NS_FRAME_COMPLETE;
     }
 
-    CheckInvalidateSizeChange(aDesiredSize);
-
     // XXXjwir3: This call should be replaced with FinishWithAbsoluteFrames
     //           when bug 724978 is fixed and nsColumnSetFrame is a full absolute
     //           container.
     FinishAndStoreOverflow(&aDesiredSize);
 
     aDesiredSize.mCarriedOutBottomMargin = carriedOutBottomMargin;
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -925,21 +925,16 @@ nsContainerFrame::ReflowChild(nsIFrame* 
 
   nsresult  result;
 
   // Send the WillReflow() notification, and position the child frame
   // and its view if requested
   aKidFrame->WillReflow(aPresContext);
 
   if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
-    if ((aFlags & NS_FRAME_INVALIDATE_ON_MOVE) &&
-        !(aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
-        aKidFrame->GetPosition() != nsPoint(aX, aY)) {
-      aKidFrame->InvalidateFrameSubtree();
-    }
     aKidFrame->SetPosition(nsPoint(aX, aY));
   }
 
   if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
     PositionFrameView(aKidFrame);
   }
 
   // Reflow the child frame
@@ -1038,23 +1033,16 @@ nsContainerFrame::FinishReflowChild(nsIF
 
   if (!(aFlags & NS_FRAME_NO_MOVE_VIEW) &&
       (curOrigin.x != aX || curOrigin.y != aY)) {
     if (!aKidFrame->HasView()) {
       // If the frame has moved, then we need to make sure any child views are
       // correctly positioned
       PositionChildViews(aKidFrame);
     }
-
-    // We also need to redraw everything associated with the frame
-    // because if the frame's Reflow issued any invalidates, then they
-    // will be at the wrong offset ... note that this includes
-    // invalidates issued against the frame's children, so we need to
-    // invalidate the overflow area too.
-    aKidFrame->Invalidate(aDesiredSize.VisualOverflow());
   }
 
   return aKidFrame->DidReflow(aPresContext, aReflowState, NS_FRAME_REFLOW_FINISHED);
 }
 
 nsresult
 nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext*           aPresContext,
                                                   const nsHTMLReflowState& aReflowState,
@@ -1124,42 +1112,26 @@ nsContainerFrame::ReflowOverflowContaine
 
       // Initialize reflow params
       nsSize availSpace(prevRect.width, aReflowState.availableHeight);
       nsHTMLReflowMetrics desiredSize;
       nsHTMLReflowState frameState(aPresContext, aReflowState,
                                    frame, availSpace);
       nsReflowStatus frameStatus = NS_FRAME_COMPLETE;
 
-      // Cache old bounds
-      nsRect oldRect = frame->GetRect();
-      nsRect oldOverflow = frame->GetVisualOverflowRect();
-
       // Reflow
       rv = ReflowChild(frame, aPresContext, desiredSize, frameState,
                        prevRect.x, 0, aFlags, frameStatus, &tracker);
       NS_ENSURE_SUCCESS(rv, rv);
       //XXXfr Do we need to override any shrinkwrap effects here?
       // e.g. desiredSize.width = prevRect.width;
       rv = FinishReflowChild(frame, aPresContext, &frameState, desiredSize,
                              prevRect.x, 0, aFlags);
       NS_ENSURE_SUCCESS(rv, rv);
 
-      // Invalidate if there was a position or size change
-      nsRect rect = frame->GetRect();
-      if (!rect.IsEqualInterior(oldRect)) {
-        nsRect dirtyRect = oldOverflow;
-        dirtyRect.MoveBy(oldRect.x, oldRect.y);
-        Invalidate(dirtyRect);
-
-        dirtyRect = frame->GetVisualOverflowRect();
-        dirtyRect.MoveBy(rect.x, rect.y);
-        Invalidate(dirtyRect);
-      }
-
       // Handle continuations
       if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus)) {
         if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
           // Abspos frames can't cause their parent to be incomplete,
           // only overflow incomplete.
           NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus);
         }
         else {
@@ -1364,18 +1336,16 @@ nsContainerFrame::DeleteNextInFlowChild(
     }
     for (int32_t i = frames.Length() - 1; i >= 0; --i) {
       nsIFrame* delFrame = frames.ElementAt(i);
       static_cast<nsContainerFrame*>(delFrame->GetParent())
         ->DeleteNextInFlowChild(aPresContext, delFrame, aDeletingEmptyFrames);
     }
   }
 
-  aNextInFlow->InvalidateFrameSubtree();
-
   // Take the next-in-flow out of the parent's child list
 #ifdef DEBUG
   nsresult rv =
 #endif
     StealFrame(aPresContext, aNextInFlow);
   NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
 
 #ifdef DEBUG
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -80,16 +80,17 @@
 #include "nsDisplayList.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsExpirationTracker.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGEffects.h"
 #include "nsChangeHint.h"
 #include "nsDeckFrame.h"
 #include "nsTableFrame.h"
+#include "nsSubDocumentFrame.h"
 
 #include "gfxContext.h"
 #include "nsRenderingContext.h"
 #include "CSSCalc.h"
 #include "nsAbsoluteContainingBlock.h"
 #include "nsFontInflationData.h"
 #include "nsAnimationManager.h"
 #include "nsTransitionManager.h"
@@ -499,17 +500,18 @@ nsFrame::Init(nsIContent*      aContent,
                        NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
   }
   if (mParent) {
     nsFrameState state = mParent->GetStateBits();
 
     // Make bits that are currently off (see constructor) the same:
     mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
                        NS_FRAME_GENERATED_CONTENT |
-                       NS_FRAME_IS_SVG_TEXT);
+                       NS_FRAME_IS_SVG_TEXT |
+                       NS_FRAME_IN_POPUP);
   }
   const nsStyleDisplay *disp = GetStyleDisplay();
   if (disp->HasTransform()) {
     // The frame gets reconstructed if we toggle the -moz-transform
     // property, so we can set this bit here and then ignore it.
     mState |= NS_FRAME_MAY_BE_TRANSFORMED;
   }
 
@@ -1263,16 +1265,33 @@ void
 nsFrame::GetChildLists(nsTArray<ChildList>* aLists) const
 {
   if (IsAbsoluteContainer()) {
     nsFrameList absoluteList = GetAbsoluteContainingBlock()->GetChildList();
     absoluteList.AppendIfNonempty(aLists, GetAbsoluteListID());
   }
 }
 
+void
+nsIFrame::GetCrossDocChildLists(nsTArray<ChildList>* aLists)
+{
+  nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(this);
+  if (subdocumentFrame) {
+    // Descend into the subdocument
+    nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
+    if (root) {
+      aLists->AppendElement(nsIFrame::ChildList(
+        nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
+        nsIFrame::kPrincipalList));
+    }
+  }
+
+  GetChildLists(aLists);
+}
+
 static nsIFrame*
 GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
 {
   nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
   if (capturingContent) {
     nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
     return activeFrame ? activeFrame : aFrame;
   }
@@ -4563,56 +4582,16 @@ nsFrame::GetType() const
 }
 
 bool
 nsIFrame::IsLeaf() const
 {
   return true;
 }
 
-Layer*
-nsIFrame::InvalidateLayer(const nsRect& aDamageRect, uint32_t aDisplayItemKey)
-{
-  NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
-
-  Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
-  if (!layer) {
-    Invalidate(aDamageRect);
-    return nullptr;
-  }
-
-  uint32_t flags = INVALIDATE_NO_THEBES_LAYERS;
-  if (aDisplayItemKey == nsDisplayItem::TYPE_VIDEO ||
-      aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
-      aDisplayItemKey == nsDisplayItem::TYPE_CANVAS) {
-    flags |= INVALIDATE_NO_UPDATE_LAYER_TREE;
-  }
-
-  InvalidateWithFlags(aDamageRect, flags);
-  return layer;
-}
-
-void
-nsIFrame::InvalidateTransformLayer()
-{
-  NS_ASSERTION(mParent, "How can a viewport frame have a transform?");
-
-  bool hasLayer =
-      FrameLayerBuilder::GetDedicatedLayer(this, nsDisplayItem::TYPE_TRANSFORM) != nullptr;
-  // Invalidate post-transform area in the parent. We have to invalidate
-  // in the parent because our transform style may have changed from what was
-  // used to paint this frame.
-  // It's OK to bypass the SVG effects processing and other processing
-  // performed if we called this->InvalidateWithFlags, because those effects
-  // are performed before applying transforms.
-  mParent->InvalidateInternal(GetVisualOverflowRect() + GetPosition(),
-                              0, 0, this,
-                              hasLayer ? INVALIDATE_NO_THEBES_LAYERS : 0);
-}
-
 class LayerActivity {
 public:
   LayerActivity(nsIFrame* aFrame) : mFrame(aFrame), mChangeHint(nsChangeHint(0)) {}
   ~LayerActivity();
   nsExpirationState* GetExpirationState() { return &mState; }
 
   nsIFrame* mFrame;
   nsExpirationState mState;
@@ -4699,141 +4678,16 @@ nsIFrame::AreLayersMarkedActive(nsChange
 
 /* static */ void
 nsFrame::ShutdownLayerActivityTimer()
 {
   delete gLayerActivityTracker;
   gLayerActivityTracker = nullptr;
 }
 
-void
-nsIFrame::InvalidateWithFlags(const nsRect& aDamageRect, uint32_t aFlags)
-{
-  if (aDamageRect.IsEmpty()) {
-    return;
-  }
-
-  // Don't allow invalidates to do anything when
-  // painting is suppressed.
-  nsIPresShell *shell = PresContext()->GetPresShell();
-  if (shell) {
-    if (shell->IsPaintingSuppressed())
-      return;
-  }
-
-  InvalidateInternal(aDamageRect, 0, 0, nullptr, aFlags);
-}
-
-/**
- * Helper function that funnels an InvalidateInternal request up to the
- * parent.  This function is used so that if MOZ_SVG is not defined, we still
- * have unified control paths in the InvalidateInternal chain.
- *
- * @param aDamageRect The rect to invalidate.
- * @param aX The x offset from the origin of this frame to the rectangle.
- * @param aY The y offset from the origin of this frame to the rectangle.
- * @param aImmediate Whether to redraw immediately.
- * @return None, though this funnels the request up to the parent frame.
- */
-void
-nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
-                                        nscoord aY, uint32_t aFlags)
-{
-  if (aDamageRect.IsEmpty()) {
-    return;
-  }
-
-  /* If we're a transformed frame, then we need to apply our transform to the
-   * damage rectangle so that the redraw correctly redraws the transformed
-   * region.  We're moved over aX and aY from our origin, but since this aX
-   * and aY is contained within our border, we need to scoot back by -aX and
-   * -aY to get back to the origin of the transform.
-   *
-   * There's one more problem, though, and that's that we don't know what
-   * coordinate space this rectangle is in.  Sometimes it's in the local
-   * coordinate space for the frame, and sometimes its in the transformed
-   * coordinate space.  If we get it wrong, we'll display incorrectly.  Until I
-   * find a better fix for this problem, we'll invalidate the union of the two
-   * rectangles (original rectangle and transformed rectangle).  At least one of
-   * these will be correct.
-   *
-   * When we are preserving-3d, we can have arbitrary hierarchies of preserved 3d
-   * children. The computed transform on these children is relative to the root
-   * transform object in the hierarchy, not necessarily their direct ancestor.
-   * In this case we transform by the child's transform, and mark the rectangle
-   * as being transformed until it is passed up to the root of the hierarchy.
-   *
-   * See bug #452496 for more details.
-   */
-
-  // Check the transformed flags and remove it
-  bool rectIsTransformed = (aFlags & INVALIDATE_ALREADY_TRANSFORMED);
-  if (!Preserves3D()) {
-    // We only want to remove the flag if we aren't preserving 3d. Otherwise
-    // the rect will already have been transformed into the root preserve-3d
-    // frame coordinate space, and we should continue passing it up without
-    // further transforms.
-    aFlags &= ~INVALIDATE_ALREADY_TRANSFORMED;
-  }
-
-  if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
-      !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
-    // XXX need to set INVALIDATE_NO_THEBES_LAYERS for certain kinds of
-    // invalidation, e.g. video update, 'opacity' change
-    FrameLayerBuilder::InvalidateThebesLayerContents(this,
-        aDamageRect + nsPoint(aX, aY));
-    // Don't need to invalidate any more Thebes layers
-    aFlags |= INVALIDATE_NO_THEBES_LAYERS;
-    if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
-      return;
-    }
-  }
-  if (IsTransformed() && !rectIsTransformed) {
-    nsRect newDamageRect = nsDisplayTransform::TransformRectOut
-                             (aDamageRect, this, nsPoint(-aX, -aY));
-    if (!(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
-      newDamageRect.UnionRect(newDamageRect, aDamageRect);
-    }
-
-    // If we are preserving 3d, then our computed transform includes that of any
-    // ancestor frames that also preserve 3d. Mark the rectangle as already being
-    // transformed into the parent's coordinate space.
-    if (Preserves3D()) {
-      aFlags |= INVALIDATE_ALREADY_TRANSFORMED;
-    }
-
-    GetParent()->
-      InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this,
-                         aFlags);
-  }
-  else 
-    GetParent()->
-      InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aFlags);
-}
-
-void
-nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
-                             nsIFrame* aForChild, uint32_t aFlags)
-{
-  ClearDisplayItemCache();
-  nsSVGEffects::InvalidateDirectRenderingObservers(this);
-  if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) {
-    nsRect r = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(this,
-            aDamageRect + nsPoint(aX, aY));
-    /* Rectangle is now in our own local space, so aX and aY are effectively
-     * zero.  Thus we'll pretend that the entire time this was in our own
-     * local coordinate space and do any remaining processing.
-     */
-    InvalidateInternalAfterResize(r, 0, 0, aFlags);
-    return;
-  }
-  
-  InvalidateInternalAfterResize(aDamageRect, aX, aY, aFlags);
-}
-
 gfx3DMatrix
 nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
                              nsIFrame** aOutAncestor)
 {
   NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
 
   /* If we're transformed, we want to hand back the combination
    * transform/translate matrix that will apply our current transform, then
@@ -4892,74 +4746,115 @@ nsIFrame::GetTransformMatrix(const nsIFr
   int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel();
   return gfx3DMatrix().Translation
     (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
      NSAppUnitsToFloatPixels(delta.y, scaleFactor),
      0.0f);
 }
 
 void
-nsIFrame::InvalidateRectDifference(const nsRect& aR1, const nsRect& aR2)
-{
-  nsRect sizeHStrip, sizeVStrip;
-  nsLayoutUtils::GetRectDifferenceStrips(aR1, aR2, &sizeHStrip, &sizeVStrip);
-  Invalidate(sizeVStrip);
-  Invalidate(sizeHStrip);
+nsIFrame::InvalidateFrameSubtree(uint32_t aFlags)
+{
+  InvalidateFrame(aFlags);
+  
+  nsAutoTArray<nsIFrame::ChildList,4> childListArray;
+  GetCrossDocChildLists(&childListArray);
+
+  nsIFrame::ChildListArrayIterator lists(childListArray);
+  for (; !lists.IsDone(); lists.Next()) {
+    nsFrameList::Enumerator childFrames(lists.CurrentList());
+    for (; !childFrames.AtEnd(); childFrames.Next()) {
+      childFrames.get()->
+        InvalidateFrameSubtree(aFlags | INVALIDATE_DONT_SCHEDULE_PAINT);
+    }
+  }
+}
+
+void
+nsIFrame::ClearInvalidationStateBits()
+{
+  if (HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
+    nsAutoTArray<nsIFrame::ChildList,4> childListArray;
+    GetCrossDocChildLists(&childListArray);
+
+    nsIFrame::ChildListArrayIterator lists(childListArray);
+    for (; !lists.IsDone(); lists.Next()) {
+      nsFrameList::Enumerator childFrames(lists.CurrentList());
+      for (; !childFrames.AtEnd(); childFrames.Next()) {
+        childFrames.get()->ClearInvalidationStateBits();
+      }
+    }
+  }
+
+  RemoveStateBits(NS_FRAME_NEEDS_PAINT | NS_FRAME_DESCENDANT_NEEDS_PAINT);
 }
 
 void
-nsIFrame::InvalidateFrameSubtree()
-{
-  Invalidate(GetVisualOverflowRectRelativeToSelf());
-  FrameLayerBuilder::InvalidateThebesLayersInSubtree(this);
+nsIFrame::InvalidateFrame(uint32_t aFlags)
+{
+  AddStateBits(NS_FRAME_NEEDS_PAINT);
+  nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(this);
+  while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
+    parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
+    parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
+  }
+  if (!(aFlags & INVALIDATE_DONT_SCHEDULE_PAINT)) {
+    SchedulePaint();
+  }
+}
+  
+bool 
+nsIFrame::IsInvalid() 
+{
+  return HasAnyStateBits(NS_FRAME_NEEDS_PAINT);
 }
 
 void
-nsIFrame::InvalidateOverflowRect()
-{
-  Invalidate(GetVisualOverflowRectRelativeToSelf());
+nsIFrame::SchedulePaint()
+{
+  nsPresContext *pres = PresContext()->GetRootPresContext();
+  if (HasAnyStateBits(NS_FRAME_IN_POPUP) || !pres) {
+    nsIFrame *displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
+    NS_ASSERTION(displayRoot, "Need a display root to schedule a paint!");
+    if (!displayRoot) {
+      return;
+    }
+    pres = displayRoot->PresContext();
+  }
+  pres->PresShell()->ScheduleViewManagerFlush();
+}
+
+Layer*
+nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey, const nsIntRect* aDamageRect)
+{
+  NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
+
+  Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
+  if (aDamageRect && aDamageRect->IsEmpty()) {
+    return layer;
+  }
+
+  if (!layer) {
+    InvalidateFrame();
+    return nullptr;
+  }
+
+  if (aDamageRect) {
+    layer->AddInvalidRect(*aDamageRect);
+  } else {
+    layer->SetInvalidRectToVisibleRegion();
+  }
+
+  SchedulePaint();
+  return layer;
 }
 
 NS_DECLARE_FRAME_PROPERTY(DeferInvalidatesProperty, nsIFrame::DestroyRegion)
 
 void
-nsIFrame::InvalidateRoot(const nsRect& aDamageRect, uint32_t aFlags)
-{
-  NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
-               "Can only call this on display roots");
-
-  if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
-      !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
-    FrameLayerBuilder::InvalidateThebesLayerContents(this, aDamageRect);
-    if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
-      return;
-    }
-  }
-
-  nsRect rect = aDamageRect;
-  nsRegion* excludeRegion = static_cast<nsRegion*>
-    (Properties().Get(DeferInvalidatesProperty()));
-  if (excludeRegion && (aFlags & INVALIDATE_EXCLUDE_CURRENT_PAINT)) {
-    nsRegion r;
-    r.Sub(rect, *excludeRegion);
-    if (r.IsEmpty())
-      return;
-    rect = r.GetBounds();
-  }
-
-  if (!(aFlags & INVALIDATE_NO_UPDATE_LAYER_TREE)) {
-    AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
-  }
-
-  nsIView* view = GetView();
-  NS_ASSERTION(view, "This can only be called on frames with views");
-  view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
-}
-
-void
 nsIFrame::BeginDeferringInvalidatesForDisplayRoot(const nsRegion& aExcludeRegion)
 {
   NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
                "Can only call this on display roots");
   Properties().Set(DeferInvalidatesProperty(), new nsRegion(aExcludeRegion));
 }
 
 void
@@ -5200,117 +5095,16 @@ nsFrame::UpdateOverflow()
     }
 
     return true;
   }
 
   return false;
 }
 
-void
-nsFrame::CheckInvalidateSizeChange(nsHTMLReflowMetrics& aNewDesiredSize)
-{
-  nsIFrame::CheckInvalidateSizeChange(mRect, GetVisualOverflowRect(),
-      nsSize(aNewDesiredSize.width, aNewDesiredSize.height));
-}
-
-static void
-InvalidateRectForFrameSizeChange(nsIFrame* aFrame, const nsRect& aRect)
-{
-  nsStyleContext *bgSC;
-  if (!nsCSSRendering::FindBackground(aFrame->PresContext(), aFrame, &bgSC)) {
-    nsIFrame* rootFrame =
-      aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame();
-    rootFrame->Invalidate(nsRect(nsPoint(0, 0), rootFrame->GetSize()));
-  }
-
-  aFrame->Invalidate(aRect);
-}
-
-void
-nsIFrame::CheckInvalidateSizeChange(const nsRect& aOldRect,
-                                    const nsRect& aOldVisualOverflowRect,
-                                    const nsSize& aNewDesiredSize)
-{
-  if (aNewDesiredSize == aOldRect.Size())
-    return;
-
-  // Below, we invalidate the old frame area (or, in the case of
-  // outline, combined area) if the outline, border or background
-  // settings indicate that something other than the difference
-  // between the old and new areas needs to be painted. We are
-  // assuming that the difference between the old and new areas will
-  // be invalidated by some other means. That also means invalidating
-  // the old frame area is the same as invalidating the new frame area
-  // (since in either case the UNION of old and new areas will be
-  // invalidated)
-
-  // We use InvalidateRectForFrameSizeChange throughout this method, even
-  // though root-invalidation is technically only needed in the case where
-  // layer.RenderingMightDependOnFrameSize().  This allows us to simplify the
-  // code somewhat and return immediately after invalidation in the earlier
-  // cases.
-
-  // Invalidate the entire old frame+outline if the frame has an outline
-  bool anyOutlineOrEffects;
-  nsRect r = ComputeOutlineAndEffectsRect(this, &anyOutlineOrEffects,
-                                          aOldVisualOverflowRect,
-                                          aNewDesiredSize,
-                                          false);
-  if (anyOutlineOrEffects) {
-    r.UnionRect(aOldVisualOverflowRect, r);
-    InvalidateRectForFrameSizeChange(this, r);
-    return;
-  }
-
-  // Invalidate the old frame border box if the frame has borders. Those
-  // borders may be moving.
-  const nsStyleBorder* border = GetStyleBorder();
-  NS_FOR_CSS_SIDES(side) {
-    if (border->GetComputedBorderWidth(side) != 0) {
-      if ((side == NS_SIDE_LEFT || side == NS_SIDE_TOP) &&
-          !nsLayoutUtils::HasNonZeroCornerOnSide(border->mBorderRadius, side) &&
-          !border->GetBorderImage() &&
-          border->GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_SOLID) {
-        // We also need to be sure that the bottom-left or top-right
-        // corner is simple. For example, if the bottom or right border
-        // has a different color, we would need to invalidate the corner
-        // area. But that's OK because if there is a right or bottom border,
-        // we'll invalidate the entire border-box here anyway.
-        continue;
-      }
-      InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
-      return;
-    }
-  }
-
-  const nsStyleBackground *bg = GetStyleBackground();
-  if (!bg->IsTransparent()) {
-    // Invalidate the old frame background if the frame has a background
-    // whose position depends on the size of the frame
-    NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
-      const nsStyleBackground::Layer &layer = bg->mLayers[i];
-      if (layer.RenderingMightDependOnFrameSize()) {
-        InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
-        return;
-      }
-    }
-
-    // Invalidate the old frame background if the frame has a background
-    // that is being clipped by border-radius, since the old or new area
-    // clipped off by the radius is not necessarily in the area that has
-    // already been invalidated (even if only the top-left corner has a
-    // border radius).
-    if (nsLayoutUtils::HasNonZeroCorner(border->mBorderRadius)) {
-      InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
-      return;
-    }
-  }
-}
-
 // Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
 // 4 for the frames above the document's frames: 
 //  the Viewport, GFXScroll, ScrollPort, and Canvas
 #define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4)
 
 bool
 nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
                             nsHTMLReflowMetrics& aMetrics,
@@ -7036,48 +6830,26 @@ nsIFrame::FinishAndStoreOverflow(nsOverf
       // nsCSSFrameConstructor::DoApplyRenderingChangeToTree in response
       // to nsChangeHint_RepaintFrame. Since the new overflow area is not
       // known at that time, we have to handle it here.
       // If the overflow area hasn't changed, then we don't have to do
       // anything here since repainting the old overflow area was enough.
       // If there is no outline or other effects now, then we don't have
       // to do anything here since removing those styles can't require
       // repainting of areas that weren't in the old overflow area.
-      Invalidate(aOverflowAreas.VisualOverflow());
+      InvalidateFrame();
     } else if (hasClipPropClip || didHaveClipPropClip) {
       // If we are (or were) clipped by the 'clip' property, and our
       // overflow area changes, it might be because the clipping changed.
       // The nsChangeHint_RepaintFrame for the style change will only
       // repaint the old overflow area, so if the overflow area has
       // changed (in particular, if it grows), we have to repaint the
       // new area here.
-      Invalidate(aOverflowAreas.VisualOverflow());
-    }
-  }
-  // XXXSDL For SVG the invalidation happens in ReflowSVG for now, so we
-  // don't currently invalidate SVG here:
-  if (anyOverflowChanged && hasTransform &&
-      !(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
-    // When there's a transform, changes to that style might require
-    // repainting of the old and new overflow areas in the widget.
-    // Repainting of the frame itself will not be required if there's
-    // a retained layer, so we can call InvalidateLayer here
-    // which will avoid repainting ThebesLayers if possible.
-    // nsCSSFrameConstructor::DoApplyRenderingChangeToTree repaints
-    // the old overflow area in the widget in response to
-    // nsChangeHint_UpdateTransformLayer. But since the new overflow
-    // area is not known at that time, we have to handle it here.
-    // If the overflow area hasn't changed, then it doesn't matter that
-    // we didn't reach here since repainting the old overflow area was enough.
-    // If there is no transform now, then the container layer for
-    // the transform will go away and the frame contents will change
-    // ThebesLayers, forcing it to be invalidated, so it doesn't matter
-    // that we didn't reach here.
-    InvalidateLayer(aOverflowAreas.VisualOverflow(),
-                    nsDisplayItem::TYPE_TRANSFORM);
+      InvalidateFrame();
+    }
   }
 
   return anyOverflowChanged;
 }
 
 void
 nsIFrame::RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds)
 {
@@ -7591,21 +7363,18 @@ nsFrame::RefreshSizeCache(nsBoxLayoutSta
     nsPresContext* presContext = aState.PresContext();
 
     // If we don't have any HTML constraints and it's a resize, then nothing in the block
     // could have changed, so no refresh is necessary.
     nsBoxLayoutMetrics* metrics = BoxMetrics();
     if (!DoesNeedRecalc(metrics->mBlockPrefSize))
       return NS_OK;
 
-    // get the old rect.
-    nsRect oldRect = GetRect();
-
     // the rect we plan to size to.
-    nsRect rect(oldRect);
+    nsRect rect = GetRect();
 
     nsMargin bp(0,0,0,0);
     GetBorderAndPadding(bp);
 
     {
       // If we're a container for font size inflation, then shrink
       // wrapping inside of us should not apply font size inflation.
       AutoMaybeDisableFontInflation an(this);
@@ -7617,25 +7386,16 @@ nsFrame::RefreshSizeCache(nsBoxLayoutSta
     }
 
     // do the nasty.
     nsHTMLReflowMetrics desiredSize;
     rv = BoxReflow(aState, presContext, desiredSize, rendContext,
                    rect.x, rect.y,
                    metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE);
 
-    nsRect newRect = GetRect();
-
-    // make sure we draw any size change
-    if (oldRect.width != newRect.width || oldRect.height != newRect.height) {
-      newRect.x = 0;
-      newRect.y = 0;
-      Redraw(aState, &newRect);
-    }
-
     metrics->mBlockMinSize.height = 0;
     // ok we need the max ascent of the items on the line. So to do this
     // ask the block for its line iterator. Get the max ascent.
     nsAutoLineIterator lines = GetLineIterator();
     if (lines) 
     {
       metrics->mBlockMinSize.height = 0;
       int count = 0;
@@ -8142,16 +7902,65 @@ nsBoxLayoutMetrics*
 nsFrame::BoxMetrics() const
 {
   nsBoxLayoutMetrics* metrics =
     static_cast<nsBoxLayoutMetrics*>(Properties().Get(BoxMetricsProperty()));
   NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
   return metrics;
 }
 
+/**
+ * Adds the NS_FRAME_IN_POPUP state bit to the current frame,
+ * and all descendant frames (including cross-doc ones).
+ */
+static void
+AddInPopupStateBitToDescendants(nsIFrame* aFrame)
+{
+  aFrame->AddStateBits(NS_FRAME_IN_POPUP);
+
+  nsAutoTArray<nsIFrame::ChildList,4> childListArray;
+  aFrame->GetCrossDocChildLists(&childListArray);
+
+  nsIFrame::ChildListArrayIterator lists(childListArray);
+  for (; !lists.IsDone(); lists.Next()) {
+    nsFrameList::Enumerator childFrames(lists.CurrentList());
+    for (; !childFrames.AtEnd(); childFrames.Next()) {
+      AddInPopupStateBitToDescendants(childFrames.get());
+    }
+  }
+}
+
+/**
+ * Removes the NS_FRAME_IN_POPUP state bit from the current
+ * frames and all descendant frames (including cross-doc ones),
+ * unless the frame is a popup itself.
+ */
+static void
+RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame)
+{
+  if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) ||
+      aFrame->GetType() == nsGkAtoms::listControlFrame ||
+      aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
+    return;
+  }
+
+  aFrame->RemoveStateBits(NS_FRAME_IN_POPUP);
+
+  nsAutoTArray<nsIFrame::ChildList,4> childListArray;
+  aFrame->GetCrossDocChildLists(&childListArray);
+
+  nsIFrame::ChildListArrayIterator lists(childListArray);
+  for (; !lists.IsDone(); lists.Next()) {
+    nsFrameList::Enumerator childFrames(lists.CurrentList());
+    for (; !childFrames.AtEnd(); childFrames.Next()) {
+      RemoveInPopupStateBitFromDescendants(childFrames.get());
+    }
+  }
+}
+
 void
 nsFrame::SetParent(nsIFrame* aParent)
 {
   bool wasBoxWrapped = IsBoxWrapped();
   mParent = aParent;
   if (!wasBoxWrapped && IsBoxWrapped()) {
     InitBoxMetrics(true);
   } else if (wasBoxWrapped && !IsBoxWrapped()) {
@@ -8160,23 +7969,29 @@ nsFrame::SetParent(nsIFrame* aParent)
 
   if (GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
     for (nsIFrame* f = aParent;
          f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
          f = f->GetParent()) {
       f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
     }
   }
-
-  if (GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT) {
+  
+  if (HasInvalidFrameInSubtree()) {
     for (nsIFrame* f = aParent;
-         f && !(f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
+         f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
          f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
-      f->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
-    }
+      f->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
+    }
+  }
+
+  if (aParent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
+    AddInPopupStateBitToDescendants(this);
+  } else {
+    RemoveInPopupStateBitFromDescendants(this);
   }
 }
 
 void
 nsFrame::InitBoxMetrics(bool aClear)
 {
   FrameProperties props = Properties();
   if (aClear) {
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -386,26 +386,16 @@ public:
 
   // We compute and store the HTML content's overflow area. So don't
   // try to compute it in the box code.
   virtual bool ComputesOwnOverflowArea() MOZ_OVERRIDE { return true; }
 
   //--------------------------------------------------
   // Additional methods
 
-  /**
-   * Helper method to invalidate portions of a standard container frame if the
-   * desired size indicates that the size has changed (specifically border,
-   * background and outline).
-   * We assume that the difference between the old frame area and the new
-   * frame area is invalidated by some other means.
-   * @param aDesiredSize the new size of the frame
-   */
-  void CheckInvalidateSizeChange(nsHTMLReflowMetrics&     aNewDesiredSize);
-
   // Helper function that tests if the frame tree is too deep; if it is
   // it marks the frame as "unflowable", zeroes out the metrics, sets
   // the reflow status, and returns true. Otherwise, the frame is
   // unmarked "unflowable" and the metrics and reflow status are not
   // touched and false is returned.
   bool IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
                             nsHTMLReflowMetrics& aMetrics,
                             nsReflowStatus& aStatus);
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -155,104 +155,16 @@ nsHTMLScrollFrame::GetSkipSides() const
 }
 
 nsIAtom*
 nsHTMLScrollFrame::GetType() const
 {
   return nsGkAtoms::scrollFrame; 
 }
 
-void
-nsHTMLScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
-                                      nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                      uint32_t aFlags)
-{
-  if (aForChild) {
-    if (aForChild == mInner.mScrolledFrame) {
-      nsRect damage = aDamageRect + nsPoint(aX, aY);
-      // This is the damage rect that we're going to pass up to our parent.
-      nsRect parentDamage;
-      if (mInner.IsIgnoringViewportClipping()) {
-        parentDamage = damage;
-      } else {
-        // If we're using a displayport, we might be displaying an area
-        // different than our scroll port and the damage needs to be
-        // clipped to that instead.
-        nsRect displayport;
-        bool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(),
-                                                                &displayport);
-        if (usingDisplayport) {
-          parentDamage.IntersectRect(damage, displayport);
-        } else {
-          parentDamage.IntersectRect(damage, mInner.mScrollPort);
-        }
-      }
-
-      if (IsScrollingActive()) {
-        // This is the damage rect that we're going to pass up and
-        // only request invalidation of ThebesLayers for.
-        // damage is now in our coordinate system, which means it was
-        // translated using the current scroll position. Adjust it to
-        // reflect the scroll position at last paint, since that's what
-        // the ThebesLayers are currently set up for.
-        // This should not be clipped to the scrollport since ThebesLayers
-        // can contain content outside the scrollport that may need to be
-        // invalidated.
-        nsRect thebesLayerDamage = damage + GetScrollPosition() - mInner.mScrollPosAtLastPaint;
-        if (parentDamage.IsEqualInterior(thebesLayerDamage)) {
-          // This single call will take care of both rects
-          nsContainerFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags);
-        } else {
-          // Invalidate rects separately
-          if (!(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
-            nsContainerFrame::InvalidateInternal(thebesLayerDamage, 0, 0, aForChild,
-                                                 aFlags | INVALIDATE_ONLY_THEBES_LAYERS);
-          }
-          if (!(aFlags & INVALIDATE_ONLY_THEBES_LAYERS) && !parentDamage.IsEmpty()) {
-            nsContainerFrame::InvalidateInternal(parentDamage, 0, 0, aForChild,
-                                                 aFlags | INVALIDATE_NO_THEBES_LAYERS);
-          }
-        }
-      } else {
-        if (!parentDamage.IsEmpty()) {
-          nsContainerFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags);
-        }
-      }
-
-      if (mInner.mIsRoot && !parentDamage.IsEqualInterior(damage)) {
-        // Make sure we notify our prescontext about invalidations outside
-        // viewport clipping.
-        // This is important for things that are snapshotting the viewport,
-        // possibly outside the scrolled bounds.
-        // We don't need to propagate this any further up, though. Anyone who
-        // cares about scrolled-out-of-view invalidates had better be listening
-        // to our window directly.
-        PresContext()->NotifyInvalidation(damage, aFlags);
-      }
-      return;
-    } else if (aForChild == mInner.mHScrollbarBox) {
-      if (!mInner.mHasHorizontalScrollbar) {
-        // Our scrollbars may send up invalidations even when they're collapsed,
-        // because we just size a collapsed scrollbar to empty and some
-        // descendants may be non-empty. Suppress that invalidation here.
-        return;
-      }
-    } else if (aForChild == mInner.mVScrollbarBox) {
-      if (!mInner.mHasVerticalScrollbar) {
-        // Our scrollbars may send up invalidations even when they're collapsed,
-        // because we just size a collapsed scrollbar to empty and some
-        // descendants may be non-empty. Suppress that invalidation here.
-        return;
-      }
-    }
-  }
- 
-  nsContainerFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aFlags);
-}
-
 /**
  HTML scrolling implementation
 
  All other things being equal, we prefer layouts with fewer scrollbars showing.
 */
 
 struct ScrollReflowState {
   const nsHTMLReflowState& mReflowState;
@@ -911,18 +823,16 @@ nsHTMLScrollFrame::Reflow(nsPresContext*
     state.mComputedBorder.TopBottom();
 
   aDesiredSize.SetOverflowAreasToDesiredBounds();
   if (mInner.IsIgnoringViewportClipping()) {
     aDesiredSize.mOverflowAreas.UnionWith(
       state.mContentsOverflowAreas + mInner.mScrolledFrame->GetPosition());
   }
 
-  CheckInvalidateSizeChange(aDesiredSize);
-
   FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
 
   if (!InInitialReflow() && !mInner.mHadNonInitialReflow) {
     mInner.mHadNonInitialReflow = true;
   }
 
   if (mInner.mIsRoot && !oldScrolledAreaBounds.IsEqualEdges(newScrolledAreaBounds)) {
     mInner.PostScrolledAreaEvent();
@@ -1095,73 +1005,16 @@ nsXULScrollFrame::GetSkipSides() const
 }
 
 nsIAtom*
 nsXULScrollFrame::GetType() const
 {
   return nsGkAtoms::scrollFrame; 
 }
 
-void
-nsXULScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
-                                     nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                     uint32_t aFlags)
-{
-  if (aForChild == mInner.mScrolledFrame) {
-    nsRect damage = aDamageRect + nsPoint(aX, aY);
-    // This is the damage rect that we're going to pass up to our parent.
-    nsRect parentDamage;
-    // If we're using a displayport, we might be displaying an area
-    // different than our scroll port and the damage needs to be
-    // clipped to that instead.
-    nsRect displayport;
-    bool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(),
-                                                            &displayport);
-    if (usingDisplayport) {
-      parentDamage.IntersectRect(damage, displayport);
-    } else {
-      parentDamage.IntersectRect(damage, mInner.mScrollPort);
-    }
-
-    if (IsScrollingActive()) {
-      // This is the damage rect that we're going to pass up and
-      // only request invalidation of ThebesLayers for.
-      // damage is now in our coordinate system, which means it was
-      // translated using the current scroll position. Adjust it to
-      // reflect the scroll position at last paint, since that's what
-      // the ThebesLayers are currently set up for.
-      // This should not be clipped to the scrollport since ThebesLayers
-      // can contain content outside the scrollport that may need to be
-      // invalidated.
-      nsRect thebesLayerDamage = damage + GetScrollPosition() - mInner.mScrollPosAtLastPaint;
-      if (parentDamage.IsEqualInterior(thebesLayerDamage)) {
-        // This single call will take care of both rects
-        nsBoxFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags);
-      } else {
-        // Invalidate rects separately
-        if (!(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
-          nsBoxFrame::InvalidateInternal(thebesLayerDamage, 0, 0, aForChild,
-                                         aFlags | INVALIDATE_ONLY_THEBES_LAYERS);
-        }
-        if (!(aFlags & INVALIDATE_ONLY_THEBES_LAYERS) && !parentDamage.IsEmpty()) {
-          nsBoxFrame::InvalidateInternal(parentDamage, 0, 0, aForChild,
-                                         aFlags | INVALIDATE_NO_THEBES_LAYERS);
-        }
-      }
-    } else {
-      if (!parentDamage.IsEmpty()) {
-        nsBoxFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags);
-      }
-    }
-    return;
-  }
-  
-  nsBoxFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aFlags);
-}
-
 nscoord
 nsXULScrollFrame::GetBoxAscent(nsBoxLayoutState& aState)
 {
   if (!mInner.mScrolledFrame)
     return 0;
 
   nscoord ascent = mInner.mScrolledFrame->GetBoxAscent(aState);
   nsMargin m(0,0,0,0);
@@ -1837,17 +1690,17 @@ InvalidateFixedBackgroundFramesFromList(
       InvalidateFixedBackgroundFramesFromList(aBuilder, aMovingFrame, *sublist);
       continue;
     }
     nsIFrame* f = item->GetUnderlyingFrame();
     if (f &&
         item->IsVaryingRelativeToMovingFrame(aBuilder, aMovingFrame)) {
       if (FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(aBuilder, item)) {
         // FrameLayerBuilder does not take care of scrolling this one
-        f->Invalidate(item->GetVisibleRect() - item->ToReferenceFrame());
+        f->InvalidateFrame();
       }
     }
   }
 }
 
 static void
 InvalidateFixedBackgroundFrames(nsIFrame* aRootFrame,
                                 nsIFrame* aMovingFrame,
@@ -1935,70 +1788,40 @@ void nsGfxScrollFrameInner::ScrollVisual
     return;
   }
 
   rootPresContext->RequestUpdatePluginGeometry();
 
   AdjustViews(mScrolledFrame);
   // We need to call this after fixing up the view positions
   // to be consistent with the frame hierarchy.
-  uint32_t flags = nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT;
+  bool invalidate = false;
   bool canScrollWithBlitting = CanScrollWithBlitting(mOuter);
   mOuter->RemoveStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
   if (IsScrollingActive()) {
     if (!canScrollWithBlitting) {
       MarkInactive();
     } else {
-      flags |= nsIFrame::INVALIDATE_NO_THEBES_LAYERS;
+      invalidate = true;
     }
   }
   if (canScrollWithBlitting) {
     MarkActive();
   }
 
-  nsRect invalidateRect, displayPort;
-  bool hasDisplayPort =
-    nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort);
-  if (IsIgnoringViewportClipping()) {
-    nsRect visualOverflow = mScrolledFrame->GetVisualOverflowRect();
-    invalidateRect.UnionRect(visualOverflow + mScrolledFrame->GetPosition(),
-            visualOverflow + aOldScrolledFramePos);
-  } else {
-    invalidateRect = hasDisplayPort ? displayPort : mScrollPort;
-  }
-
-  mOuter->InvalidateWithFlags(invalidateRect, flags);
-
-  if (flags & nsIFrame::INVALIDATE_NO_THEBES_LAYERS) {
+  mOuter->SchedulePaint();
+
+  if (invalidate) {
     nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(mOuter);
     nsRect update =
       GetScrollPortRect() + mOuter->GetOffsetToCrossDoc(displayRoot);
     nsRect displayRootUpdate = update.ConvertAppUnitsRoundOut(
       mOuter->PresContext()->AppUnitsPerDevPixel(),
       displayRoot->PresContext()->AppUnitsPerDevPixel());
     InvalidateFixedBackgroundFrames(displayRoot, mScrolledFrame, displayRootUpdate);
-
-    // Invalidate content that has scrolled into view. Normally, this will
-    // already be invalid, because it shouldn't have been drawn in any layer,
-    // but there can be stray rows/columns of pixels that partially overlapped
-    // the layer's visible region and hence were drawn and added to the layer's
-    // visible region, but these pixels ended up outside the cliprect after
-    // snapping so their contents need to be updated now that new content has
-    // scrolled into the cliprect.
-    nsPoint scrollDelta = mScrolledFrame->GetPosition() - aOldScrolledFramePos;
-    if (!hasDisplayPort) {
-      displayPort = GetScrollPortRect();
-    }
-    nsRect preservedContents = displayPort + scrollDelta;
-    nsRegion invalidate;
-    invalidate.Sub(displayPort, preservedContents);
-    nsRegionRectIterator iter(invalidate);
-    while (const nsRect* r = iter.Next()) {
-      mOuter->InvalidateWithFlags(*r, nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT);
-    }
   }
 }
 
 /**
  * Return an appunit value close to aDesired and between aLower and aUpper
  * such that (aDesired - aCurrent)*aRes/aAppUnitsPerPixel is an integer (or
  * as close as we can get modulo rounding to appunits). If that
  * can't be done, just returns aDesired.
@@ -3255,38 +3078,16 @@ nsXULScrollFrame::LayoutScrollArea(nsBox
     childRect.height = NS_MAX(childRect.height, mInner.mScrollPort.height);
 
     // remove overflow areas when we update the bounds,
     // because we've already accounted for it
     // REVIEW: Have we accounted for both?
     ClampAndSetBounds(aState, childRect, aScrollPosition, true);
   }
 
-  nsRect finalRect = mInner.mScrolledFrame->GetRect();
-  nsRect finalVisOverflow = mInner.mScrolledFrame->GetVisualOverflowRect();
-  // The position of the scrolled frame shouldn't change, but if it does or
-  // the position of the overflow rect changes just invalidate both the old
-  // and new overflow rect.
-  if (originalRect.TopLeft() != finalRect.TopLeft() ||
-      originalVisOverflow.TopLeft() != finalVisOverflow.TopLeft())
-  {
-    // The old overflow rect needs to be adjusted if the frame's position
-    // changed.
-    mInner.mScrolledFrame->Invalidate(
-      originalVisOverflow + originalRect.TopLeft() - finalRect.TopLeft());
-    mInner.mScrolledFrame->Invalidate(finalVisOverflow);
-  } else if (!originalVisOverflow.IsEqualInterior(finalVisOverflow)) {
-    // If the overflow rect changed then invalidate the difference between the
-    // old and new overflow rects.
-    mInner.mScrolledFrame->CheckInvalidateSizeChange(
-      originalRect, originalVisOverflow, finalRect.Size());
-    mInner.mScrolledFrame->InvalidateRectDifference(
-      originalVisOverflow, finalVisOverflow);
-  }
-
   aState.SetLayoutFlags(oldflags);
 
 }
 
 void nsGfxScrollFrameInner::PostOverflowEvent()
 {
   if (mAsyncScrollPortEvent.IsPending())
     return;
@@ -3690,50 +3491,16 @@ nsGfxScrollFrameInner::ReflowFinished()
 }
 
 void
 nsGfxScrollFrameInner::ReflowCallbackCanceled()
 {
   mPostedReflowCallback = false;
 }
 
-static void LayoutAndInvalidate(nsBoxLayoutState& aState,
-                                nsIFrame* aBox, const nsRect& aRect,
-                                bool aScrollbarIsBeingHidden)
-{
-  // When a child box changes shape of position, the parent
-  // is responsible for invalidation; the overflow rect must be invalidated
-  // to make sure to catch any overflow.
-  // We invalidate the parent (i.e. the scrollframe) directly, because
-  // invalidates coming from scrollbars are suppressed by nsHTMLScrollFrame when
-  // mHasVScrollbar/mHasHScrollbar is false, and this is called after those
-  // flags have been set ... if a scrollbar is being hidden, we still need
-  // to invalidate the scrollbar area here.
-  // But we also need to invalidate the scrollbar itself in case it has
-  // its own layer; we need to ensure that layer is updated.
-  bool rectChanged = !aBox->GetRect().IsEqualInterior(aRect);
-  if (rectChanged) {
-    if (aScrollbarIsBeingHidden) {
-      aBox->GetParent()->Invalidate(aBox->GetVisualOverflowRect() +
-                                    aBox->GetPosition());
-    } else {
-      aBox->InvalidateFrameSubtree();
-    }
-  }
-  nsBoxFrame::LayoutChildAt(aState, aBox, aRect);
-  if (rectChanged) {
-    if (aScrollbarIsBeingHidden) {
-      aBox->GetParent()->Invalidate(aBox->GetVisualOverflowRect() +
-                                    aBox->GetPosition());
-    } else {
-      aBox->InvalidateFrameSubtree();
-    }
-  }
-}
-
 bool
 nsGfxScrollFrameInner::UpdateOverflow()
 {
   nsIScrollableFrame* sf = do_QueryFrame(mOuter);
   ScrollbarStyles ss = sf->GetScrollbarStyles();
 
   if (ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN ||
       ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN ||
@@ -3818,17 +3585,17 @@ nsGfxScrollFrameInner::LayoutScrollbars(
     } else {
       // scrollbar (if any) on bottom
       r.height = aContentArea.YMost() - mScrollPort.YMost();
       r.y = aContentArea.YMost() - r.height;
       NS_ASSERTION(r.height >= 0, "Scroll area should be inside client rect");
     }
 
     if (mScrollCornerBox) {
-      LayoutAndInvalidate(aState, mScrollCornerBox, r, false);
+      nsBoxFrame::LayoutChildAt(aState, mScrollCornerBox, r);
     }
 
     if (hasResizer) {
       // if a resizer is present, get its size. Assume a default size of 15 pixels.
       nsSize resizerSize;
       nscoord defaultSize = nsPresContext::CSSPixelsToAppUnits(15);
       resizerSize.width =
         mVScrollbarBox ? mVScrollbarBox->GetMinSize(aState).width : defaultSize;
@@ -3841,51 +3608,51 @@ nsGfxScrollFrameInner::LayoutScrollbars(
       resizerSize.height =
         mHScrollbarBox ? mHScrollbarBox->GetMinSize(aState).height : defaultSize;
       if (resizerSize.height > r.height) {
         r.height = resizerSize.height;
         if (aContentArea.y == mScrollPort.y)
           r.y = aContentArea.YMost() - r.height;
       }
 
-      LayoutAndInvalidate(aState, mResizerBox, r, false);
+      nsBoxFrame::LayoutChildAt(aState, mResizerBox, r);
     }
     else if (mResizerBox) {
       // otherwise lay out the resizer with an empty rectangle
-      LayoutAndInvalidate(aState, mResizerBox, nsRect(), false);
+      nsBoxFrame::LayoutChildAt(aState, mResizerBox, nsRect());
     }
   }
 
   nsPresContext* presContext = mScrolledFrame->PresContext();
   if (mVScrollbarBox) {
     NS_PRECONDITION(mVScrollbarBox->IsBoxFrame(), "Must be a box frame!");
     nsRect vRect(mScrollPort);
     vRect.width = aContentArea.width - mScrollPort.width;
     vRect.x = scrollbarOnLeft ? aContentArea.x : mScrollPort.XMost();
     if (mHasVerticalScrollbar) {
       nsMargin margin;
       mVScrollbarBox->GetMargin(margin);
       vRect.Deflate(margin);
     }
     AdjustScrollbarRectForResizer(mOuter, presContext, vRect, hasResizer, true);
-    LayoutAndInvalidate(aState, mVScrollbarBox, vRect, !mHasVerticalScrollbar);
+    nsBoxFrame::LayoutChildAt(aState, mVScrollbarBox, vRect);
   }
 
   if (mHScrollbarBox) {
     NS_PRECONDITION(mHScrollbarBox->IsBoxFrame(), "Must be a box frame!");
     nsRect hRect(mScrollPort);
     hRect.height = aContentArea.height - mScrollPort.height;
     hRect.y = true ? mScrollPort.YMost() : aContentArea.y;
     if (mHasHorizontalScrollbar) {
       nsMargin margin;
       mHScrollbarBox->GetMargin(margin);
       hRect.Deflate(margin);
     }
     AdjustScrollbarRectForResizer(mOuter, presContext, hRect, hasResizer, false);
-    LayoutAndInvalidate(aState, mHScrollbarBox, hRect, !mHasHorizontalScrollbar);
+    nsBoxFrame::LayoutChildAt(aState, mHScrollbarBox, hRect);
   }
 
   // may need to update fixed position children of the viewport,
   // if the client area changed size because of an incremental
   // reflow of a descendant.  (If the outer frame is dirty, the fixed
   // children will be re-laid out anyway)
   if (aOldScrollArea.Size() != mScrollPort.Size() && 
       !(mOuter->GetStateBits() & NS_FRAME_IS_DIRTY) &&
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -418,20 +418,16 @@ public:
   virtual nsIScrollableFrame* GetScrollTargetFrame() {
     return this;
   }
 
   virtual nsIFrame* GetContentInsertionFrame() {
     return mInner.GetScrolledFrame()->GetContentInsertionFrame();
   }
 
-  virtual void InvalidateInternal(const nsRect& aDamageRect,
-                                  nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                  uint32_t aFlags);
-
   virtual bool DoesClipChildren() { return true; }
   virtual nsSplittableType GetSplittableType() const;
 
   virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
   { nsPoint pt = aChild->GetPosition();
     if (aChild == mInner.GetScrolledFrame()) pt += GetScrollPosition();
     return pt;
   }
@@ -633,20 +629,16 @@ public:
   virtual nsIScrollableFrame* GetScrollTargetFrame() {
     return this;
   }
 
   virtual nsIFrame* GetContentInsertionFrame() MOZ_OVERRIDE {
     return mInner.GetScrolledFrame()->GetContentInsertionFrame();
   }
 
-  virtual void InvalidateInternal(const nsRect& aDamageRect,
-                                  nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                  uint32_t aFlags);
-
   virtual bool DoesClipChildren() { return true; }
   virtual nsSplittableType GetSplittableType() const;
 
   virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
   { nsPoint pt = aChild->GetPosition();
     if (aChild == mInner.GetScrolledFrame())
       pt += mInner.GetLogicalScrollPosition();
     return pt;
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -208,20 +208,16 @@ nsHTMLCanvasFrame::Reflow(nsPresContext*
     nscoord y = GetContinuationOffset(&aMetrics.width);
     aMetrics.height -= y + mBorderPadding.top;
     aMetrics.height = NS_MAX(0, aMetrics.height);
   }
 
   aMetrics.SetOverflowAreasToDesiredBounds();
   FinishAndStoreOverflow(&aMetrics);
 
-  if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) {
-    Invalidate(nsRect(0, 0, mRect.width, mRect.height));
-  }
-
   // Reflow the single anon block child.
   nsReflowStatus childStatus;
   nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE);
   nsIFrame* childFrame = mFrames.FirstChild();
   NS_ASSERTION(!childFrame->GetNextSibling(), "HTML canvas should have 1 kid");
   nsHTMLReflowMetrics childDesiredSize(aMetrics.mFlags);
   nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame,
                                      availSize);
@@ -263,17 +259,17 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayL
 
   nsPresContext* presContext = PresContext();
   element->HandlePrintCallback(presContext->Type());
 
   if (canvasSize.width <= 0 || canvasSize.height <= 0 || area.IsEmpty())
     return nullptr;
 
   CanvasLayer* oldLayer = static_cast<CanvasLayer*>
-    (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem));
+    (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
   nsRefPtr<CanvasLayer> layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager);
   if (!layer)
     return nullptr;
 
   gfxRect r = gfxRect(presContext->AppUnitsToGfxUnits(area.x),
                       presContext->AppUnitsToGfxUnits(area.y),
                       presContext->AppUnitsToGfxUnits(area.width),
                       presContext->AppUnitsToGfxUnits(area.height));
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -133,20 +133,16 @@ typedef uint64_t nsFrameState;
 // cleared.
 #define NS_FRAME_FIRST_REFLOW                       NS_FRAME_STATE_BIT(1)
 
 // For a continuation frame, if this bit is set, then this a "fluid" 
 // continuation, i.e., across a line boundary. Otherwise it's a "hard"
 // continuation, e.g. a bidi continuation.
 #define NS_FRAME_IS_FLUID_CONTINUATION              NS_FRAME_STATE_BIT(2)
 
-// This bit is set whenever the frame has one or more associated
-// container layers.
-#define NS_FRAME_HAS_CONTAINER_LAYER                NS_FRAME_STATE_BIT(3)
-
 // If this bit is set, then a reference to the frame is being held
 // elsewhere.  The frame may want to send a notification when it is
 // destroyed to allow these references to be cleared.
 #define NS_FRAME_EXTERNAL_REFERENCE                 NS_FRAME_STATE_BIT(4)
 
 // If this bit is set, this frame or one of its descendants has a
 // percentage height that depends on an ancestor of this frame.
 // (Or it did at one point in the past, since we don't necessarily clear
@@ -248,20 +244,16 @@ typedef uint64_t nsFrameState;
 // TEXT_FORCE_TRIM_WHITESPACE.  That's OK because we only check the
 // NS_FRAME_IS_PUSHED_FLOAT bit on frames which we already know are
 // out-of-flow.
 #define NS_FRAME_IS_PUSHED_FLOAT                    NS_FRAME_STATE_BIT(32)
 
 // This bit acts as a loop flag for recursive paint server drawing.
 #define NS_FRAME_DRAWING_AS_PAINTSERVER             NS_FRAME_STATE_BIT(33)
 
-// Frame or one of its (cross-doc) descendants may have the
-// NS_FRAME_HAS_CONTAINER_LAYER bit.
-#define NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT     NS_FRAME_STATE_BIT(34)
-
 // Frame's overflow area was clipped by the 'clip' property.
 #define NS_FRAME_HAS_CLIP                           NS_FRAME_STATE_BIT(35)
 
 // Frame is a display root and the retained layer tree needs to be updated
 // at the next paint via display list construction.
 // Only meaningful for display roots, so we don't really need a global state
 // bit; we could free up this bit with a little extra complexity.
 #define NS_FRAME_UPDATE_LAYER_TREE                  NS_FRAME_STATE_BIT(36)
@@ -306,16 +298,26 @@ typedef uint64_t nsFrameState;
 // Frame has a cached rasterization of anV
 // nsDisplayBackground display item
 #define NS_FRAME_HAS_CACHED_BACKGROUND              NS_FRAME_STATE_BIT(46)
 
 // The frame is a descendant of nsSVGTextFrame2 and is thus used for SVG
 // text layout.
 #define NS_FRAME_IS_SVG_TEXT                        NS_FRAME_STATE_BIT(47)
 
+// Frame is marked as needing painting
+#define NS_FRAME_NEEDS_PAINT                        NS_FRAME_STATE_BIT(48)
+
+// Frame has a descendant frame that needs painting - This includes
+// cross-doc children.
+#define NS_FRAME_DESCENDANT_NEEDS_PAINT             NS_FRAME_STATE_BIT(49)
+
+// Frame is a descendant of a popup
+#define NS_FRAME_IN_POPUP                           NS_FRAME_STATE_BIT(50)
+
 // Box layout bits
 #define NS_STATE_IS_HORIZONTAL                      NS_FRAME_STATE_BIT(22)
 #define NS_STATE_IS_DIRECTION_NORMAL                NS_FRAME_STATE_BIT(31)
 
 // Helper macros
 #define NS_SUBTREE_DIRTY(_frame)  \
   (((_frame)->GetStateBits() &      \
     (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0)
@@ -1071,16 +1073,23 @@ public:
    *
    * @param   aListID identifies the requested child list.
    * @return  the child list.  If the requested list is unsupported by this
    *          frame type, an empty list will be returned.
    */
   virtual const nsFrameList& GetChildList(ChildListID aListID) const = 0;
   const nsFrameList& PrincipalChildList() { return GetChildList(kPrincipalList); }
   virtual void GetChildLists(nsTArray<ChildList>* aLists) const = 0;
+
+  /**
+   * Gets the child lists for this frame, including
+   * ones belong to a child document.
+   */
+  void GetCrossDocChildLists(nsTArray<ChildList>* aLists);
+
   // XXXbz this method should go away
   nsIFrame* GetFirstChild(ChildListID aListID) const {
     return GetChildList(aListID).FirstChild();
   }
   // XXXmats this method should also go away then
   nsIFrame* GetLastChild(ChildListID aListID) const {
     return GetChildList(aListID).LastChild();
   }
@@ -1395,16 +1404,26 @@ public:
 
   /**
    * Update the current frame-state value for this frame. 
    */
   void AddStateBits(nsFrameState aBits) { mState |= aBits; }
   void RemoveStateBits(nsFrameState aBits) { mState &= ~aBits; }
 
   /**
+   * Checks if the current frame-state includes all of the listed bits
+   */
+  bool HasAllStateBits(nsFrameState aBits) { return (mState & aBits) == aBits; }
+  
+  /**
+   * Checks if the current frame-state includes any of the listed bits
+   */
+  bool HasAnyStateBits(nsFrameState aBits) { return mState & aBits; }
+
+  /**
    * This call is invoked on the primary frame for a character data content
    * node, when it is changed in the content tree.
    */
   NS_IMETHOD  CharacterDataChanged(CharacterDataChangeInfo* aInfo) = 0;
 
   /**
    * This call is invoked when the value of a content objects's attribute
    * is changed. 
@@ -2142,151 +2161,81 @@ public:
    * @param aChangeHint nsChangeHint_UpdateTransformLayer or
    * nsChangeHint_UpdateOpacityLayer. We return true only if
    * a change in the transform or opacity has been recorded while layers have
    * been marked active for this frame.
    */
   bool AreLayersMarkedActive(nsChangeHint aChangeHint);
 
   /**
-   * @param aFlags see InvalidateInternal below
-   */
-  void InvalidateWithFlags(const nsRect& aDamageRect, uint32_t aFlags);
-
-  /**
-   * Invalidate part of the frame by asking the view manager to repaint.
-   * aDamageRect is allowed to extend outside the frame's bounds. We'll do the right
-   * thing.
-   * We deliberately don't have an Invalidate() method that defaults to the frame's bounds.
-   * We want all callers to *think* about what has changed in the frame and what area might
-   * need to be repainted.
+   * Marks all display items created by this frame as needing a repaint,
+   * and calls SchedulePaint() if requested.
    *
-   * @param aDamageRect is in the frame's local coordinate space
+   * This includes all display items created by this frame, including
+   * container types.
+   * @param aFlags INVALIDATE_DONT_SCHEDULE_PAINT: Don't call SchedulePaint()
+   * when invalidating.
    */
-  void Invalidate(const nsRect& aDamageRect)
-  { return InvalidateWithFlags(aDamageRect, 0); }
-
+  enum {
+    INVALIDATE_DONT_SCHEDULE_PAINT
+  };
+  virtual void InvalidateFrame(uint32_t aFlags = 0);
+  
   /**
-   * As Invalidate above, except that this should be called when the
-   * rendering that has changed is performed using layers so we can avoid
-   * updating the contents of ThebesLayers.
-   * If the frame has a dedicated layer rendering this display item, we
-   * return that layer.
-   * @param aDisplayItemKey must not be zero; indicates the kind of display
-   * item that is being invalidated.
+   * Calls InvalidateFrame() on all frames descendant frames (including
+   * this one).
+   * 
+   * This function doesn't walk through placeholder frames to invalidate
+   * the out-of-flow frames.
    */
-  Layer* InvalidateLayer(const nsRect& aDamageRect, uint32_t aDisplayItemKey);
-
+  void InvalidateFrameSubtree(uint32_t aFlags = 0);
+  
   /**
-   * Invalidate the area of the parent that's covered by the transformed
-   * visual overflow rect of this frame. Don't depend on the transform style
-   * for this frame, in case that's changed since this frame was painted.
+   * Checks if a frame has had InvalidateFrame() called on it since the
+   * last paint.
    */
-  void InvalidateTransformLayer();
+  bool IsInvalid();
+ 
+  /**
+   * Check if any frame within the frame subtree (including this frame) 
+   * returns true for IsInvalid().
+   */
+  bool HasInvalidFrameInSubtree()
+  {
+    return HasAnyStateBits(NS_FRAME_NEEDS_PAINT | NS_FRAME_DESCENDANT_NEEDS_PAINT);
+  }
 
   /**
-   * Helper function that can be overridden by frame classes. The rectangle
-   * (plus aOffsetX/aOffsetY) is relative to this frame.
-   * 
-   * The offset is given as two coords rather than as an nsPoint because
-   * gcc optimizes it better that way, in particular in the default
-   * implementation that passes the area to the parent frame becomes a tail
-   * call.
-   *
-   * The default implementation will crash if the frame has no parent so
-   * frames without parents MUST* override.
-   * 
-   * @param aForChild if the invalidation is coming from a child frame, this
-   * is the frame; otherwise, this is null.
-   * @param aFlags INVALIDATE_IMMEDIATE: repaint now if true, repaint later if false.
-   *   In case it's true, pending notifications will be flushed which
-   *   could cause frames to be deleted (including |this|).
-   * @param aFlags INVALIDATE_CROSS_DOC: true if the invalidation
-   *   originated in a subdocument
-   * @param aFlags INVALIDATE_REASON_SCROLL_BLIT: set if the invalidation
-   * was really just the scroll machinery copying pixels from one
-   * part of the window to another
-   * @param aFlags INVALIDATE_REASON_SCROLL_REPAINT: set if the invalidation
-   * was triggered by scrolling
-   * @param aFlags INVALIDATE_NO_THEBES_LAYERS: don't invalidate the
-   * ThebesLayers of any container layer owned by an ancestor. Set this
-   * only if ThebesLayers definitely don't need to be updated.
-   * @param aFlags INVALIDATE_ONLY_THEBES_LAYERS: invalidate only in the
-   * ThebesLayers of the nearest container layer.
-   * @param aFlags INVALIDATE_EXCLUDE_CURRENT_PAINT: if the invalidation
-   * occurs while we're painting (to be precise, while
-   * BeginDeferringInvalidatesForDisplayRoot is active on the display root),
-   * then invalidation in the current paint region is simply discarded.
-   * Use this flag if areas that are being painted do not need
-   * to be invalidated. By default, when this flag is not specified,
-   * areas that are invalidated while currently being painted will be repainted
-   * again.
-   * This flag is useful when, during painting, FrameLayerBuilder discovers that
-   * a region of the window needs to be drawn differently, and that region
-   * may or may not be contained in the currently painted region.
-   * @param aFlags INVALIDATE_NO_UPDATE_LAYER_TREE: display lists and the
-   * layer tree do not need to be updated. This can be used when the layer
-   * tree has already been updated outside a transaction, e.g. via
-   * ImageContainer::SetCurrentImage.
+   * Removes the invalid state from the current frame and all
+   * descendant frames.
    */
-  enum {
-    INVALIDATE_IMMEDIATE = 0x01,
-    INVALIDATE_CROSS_DOC = 0x02,
-    INVALIDATE_REASON_SCROLL_BLIT = 0x04,
-    INVALIDATE_REASON_SCROLL_REPAINT = 0x08,
-    INVALIDATE_REASON_MASK = INVALIDATE_REASON_SCROLL_BLIT |
-                             INVALIDATE_REASON_SCROLL_REPAINT,
-    INVALIDATE_NO_THEBES_LAYERS = 0x10,
-    INVALIDATE_ONLY_THEBES_LAYERS = 0x20,
-    INVALIDATE_EXCLUDE_CURRENT_PAINT = 0x40,
-    INVALIDATE_NO_UPDATE_LAYER_TREE = 0x80,
-    INVALIDATE_ALREADY_TRANSFORMED = 0x100
-  };
-  virtual void InvalidateInternal(const nsRect& aDamageRect,
-                                  nscoord aOffsetX, nscoord aOffsetY,
-                                  nsIFrame* aForChild, uint32_t aFlags);
+  void ClearInvalidationStateBits();
 
   /**
-   * Helper function that funnels an InvalidateInternal request up to the
-   * parent.  This function is used so that if MOZ_SVG is not defined, we still
-   * have unified control paths in the InvalidateInternal chain.
+   * Ensures that the refresh driver is running, and schedules a view 
+   * manager flush on the next tick.
    *
-   * @param aDamageRect The rect to invalidate.
-   * @param aX The x offset from the origin of this frame to the rectangle.
-   * @param aY The y offset from the origin of this frame to the rectangle.
-   * @param aImmediate Whether to redraw immediately.
-   * @return None, though this funnels the request up to the parent frame.
+   * The view manager flush will update the layer tree, repaint any 
+   * invalid areas in the layer tree and schedule a layer tree
+   * composite operation to display the layer tree.
    */
-  void InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
-                                     nscoord aY, uint32_t aFlags);
+  void SchedulePaint();
 
   /**
-   * Take two rectangles in the coordinate system of this frame which
-   * have the same origin and invalidate the difference between them.
-   * This is a helper method to be used when a frame is being resized.
+   * Checks if the layer tree includes a dedicated layer for this 
+   * frame/display item key pair, and invalidates at least aDamageRect
+   * area within that layer.
    *
-   * @param aR1 the first rectangle
-   * @param aR2 the second rectangle
+   * If no layer is found, calls InvalidateFrame() instead.
+   *
+   * @param aDamageRect Area of the layer to invalidate.
+   * @param aDisplayItemKey Display item type.
+   * @return Layer, if found, nullptr otherwise.
    */
-  void InvalidateRectDifference(const nsRect& aR1, const nsRect& aR2);
-
-  /**
-   * Invalidate the entire frame subtree for this frame. Invalidates this
-   * frame's overflow rect, and also ensures that all ThebesLayer children
-   * of ContainerLayers associated with frames in this subtree are
-   * completely invalidated.
-   */
-  void InvalidateFrameSubtree();
-
-  /**
-   * Invalidates this frame's visual overflow rect. Does not necessarily
-   * cause ThebesLayers for descendant frames to be repainted; only this
-   * frame can be relied on to be repainted.
-   */
-  void InvalidateOverflowRect();
+  Layer* InvalidateLayer(uint32_t aDisplayItemKey, const nsIntRect* aDamageRect = nullptr);
 
   /**
    * Returns a rect that encompasses everything that might be painted by
    * this frame.  This includes this frame, all its descendent frames, this
    * frame's outline, and descentant frames' outline, but does not include
    * areas clipped out by the CSS "overflow" and "clip" properties.
    *
    * HasOverflowRects() (below) will return true when this overflow
@@ -2738,17 +2687,17 @@ NS_PTR_TO_INT32(frame->Properties().Get(
 
   // For nsSprocketLayout
   virtual Valignment GetVAlign() const = 0;
   virtual Halignment GetHAlign() const = 0;
 
   bool IsHorizontal() const { return (mState & NS_STATE_IS_HORIZONTAL) != 0; }
   bool IsNormalDirection() const { return (mState & NS_STATE_IS_DIRECTION_NORMAL) != 0; }
 
-  NS_HIDDEN_(nsresult) Redraw(nsBoxLayoutState& aState, const nsRect* aRect = nullptr);
+  NS_HIDDEN_(nsresult) Redraw(nsBoxLayoutState& aState);
   NS_IMETHOD RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIFrame* aChild)=0;
   // XXX take this out after we've branched
   virtual bool GetMouseThrough() const { return false; }
 
 #ifdef DEBUG_LAYOUT
   NS_IMETHOD SetDebug(nsBoxLayoutState& aState, bool aDebug)=0;
   NS_IMETHOD GetDebug(bool& aDebug)=0;
 
@@ -2788,27 +2737,16 @@ NS_PTR_TO_INT32(frame->Properties().Get(
    *         false for getting the last possible caret position
    * @return The caret position in a CaretPosition.
    *         the returned value is a 'best effort' in case errors
    *         are encountered rummaging through the frame.
    */
   CaretPosition GetExtremeCaretPosition(bool aStart);
 
   /**
-   * Same thing as nsFrame::CheckInvalidateSizeChange, but more flexible.  The
-   * implementation of this method must not depend on the mRect or
-   * GetVisualOverflowRect() of the frame!  Note that it's safe to
-   * assume in this method that the frame origin didn't change.  If it
-   * did, whoever moved the frame will invalidate as needed anyway.
-   */
-  void CheckInvalidateSizeChange(const nsRect& aOldRect,
-                                 const nsRect& aOldVisualOverflowRect,
-                                 const nsSize& aNewDesiredSize);
-
-  /**
    * Get a line iterator for this frame, if supported.
    *
    * @return nullptr if no line iterator is supported.
    * @note dispose the line iterator using nsILineIterator::DisposeLineIterator
    */
   virtual nsILineIterator* GetLineIterator() = 0;
 
   /**
@@ -2961,22 +2899,16 @@ protected:
   };
   union {
     uint32_t     mType;
     VisualDeltas mVisualDeltas;
   } mOverflow;
 
   // Helpers
   /**
-   * For frames that have top-level windows (top-level viewports,
-   * comboboxes, menupoups) this function will invalidate the window.
-   */
-  void InvalidateRoot(const nsRect& aDamageRect, uint32_t aFlags);
-
-  /**
    * Can we stop inside this frame when we're skipping non-rendered whitespace?
    * @param  aForward [in] Are we moving forward (or backward) in content order.
    * @param  aOffset [in/out] At what offset into the frame to start looking.
    *         on output - what offset was reached (whether or not we found a place to stop).
    * @return true: An appropriate offset was found within this frame,
    *         and is given by aOffset.
    *         false: Not found within this frame, need to try the next frame.
    */
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -583,29 +583,21 @@ nsImageFrame::OnDataAvailable(imgIReques
     return NS_OK;
   }
 
   // Don't invalidate if the current visible frame isn't the one the data is
   // from
   if (!aCurrentFrame)
     return NS_OK;
 
-  // XXX We really need to round this out, now that we're doing better
-  // image scaling!
-  nsRect r = aRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect()) ?
-    GetInnerArea() :
-    SourceRectToDest(*aRect);
-
 #ifdef DEBUG_decode
-  printf("Source rect (%d,%d,%d,%d) -> invalidate dest rect (%d,%d,%d,%d)\n",
-         aRect->x, aRect->y, aRect->width, aRect->height,
-         r.x, r.y, r.width, r.height);
+  printf("Source rect (%d,%d,%d,%d)\n",
+         aRect->x, aRect->y, aRect->width, aRect->height);
 #endif
-
-  Invalidate(r);
+  InvalidateFrame();
   
   return NS_OK;
 }
 
 nsresult
 nsImageFrame::OnStopDecode(imgIRequest *aRequest,
                            nsresult aStatus,
                            const PRUnichar *aStatusArg)
@@ -654,20 +646,18 @@ nsImageFrame::NotifyNewCurrentRequest(im
   if (mState & IMAGE_GOTINITIALREFLOW) { // do nothing if we haven't gotten the initial reflow yet
     if (!(mState & IMAGE_SIZECONSTRAINED) && intrinsicSizeChanged) {
       nsIPresShell *presShell = PresContext()->GetPresShell();
       if (presShell) { 
         presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
                                     NS_FRAME_IS_DIRTY);
       }
     } else {
-      nsSize s = GetSize();
-      nsRect r(0, 0, s.width, s.height);
       // Update border+content to account for image change
-      Invalidate(r);
+      InvalidateFrame();
     }
   }
 }
 
 nsresult
 nsImageFrame::FrameChanged(imgIRequest *aRequest,
                            imgIContainer *aContainer,
                            const nsIntRect *aDirtyRect)
@@ -676,22 +666,18 @@ nsImageFrame::FrameChanged(imgIRequest *
     return NS_OK;
   }
 
   if (IsPendingLoad(aContainer)) {
     // We don't care about it
     return NS_OK;
   }
 
-  nsRect r = aDirtyRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect()) ?
-    GetInnerArea() :
-    SourceRectToDest(*aDirtyRect);
-
   // Update border+content to account for image change
-  Invalidate(r);
+  InvalidateFrame();
   return NS_OK;
 }
 
 void
 nsImageFrame::EnsureIntrinsicSizeAndRatio(nsPresContext* aPresContext)
 {
   // if mIntrinsicSize.width and height are 0, then we should
   // check to see if the size is already known by the image container.
@@ -876,25 +862,16 @@ nsImageFrame::Reflow(nsPresContext*     
     // splitting, use 1 pixel as the min
     aMetrics.height = NS_MAX(nsPresContext::CSSPixelsToAppUnits(1), aReflowState.availableHeight);
     aStatus = NS_FRAME_NOT_COMPLETE;
   }
 
   aMetrics.SetOverflowAreasToDesiredBounds();
   FinishAndStoreOverflow(&aMetrics);
 
-  // Now that that's all done, check whether we're resizing... if we are,
-  // invalidate our rect.
-  // XXXbz we really only want to do this when reflow is completely done, but
-  // we have no way to detect when mRect changes (since SetRect is non-virtual,
-  // so this is the best we can do).
-  if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) {
-    Invalidate(nsRect(0, 0, mRect.width, mRect.height));
-  }
-
   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
                   ("exit nsImageFrame::Reflow: size=%d,%d",
                   aMetrics.width, aMetrics.height));
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
   return NS_OK;
 }
 
 // Computes the width of the specified string. aMaxWidth specifies the maximum
@@ -2006,17 +1983,17 @@ nsImageFrame::IconLoad::OnImageIsAnimate
 NS_IMETHODIMP
 nsImageFrame::IconLoad::OnStopRequest(imgIRequest *aRequest,
                                       bool aIsLastPart)
 {
   nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers);
   nsImageFrame *frame;
   while (iter.HasMore()) {
     frame = iter.GetNext();
-    frame->Invalidate(frame->GetRect());
+    frame->InvalidateFrame();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsImageFrame::IconLoad::OnDiscard(imgIRequest *aRequest)
 {
@@ -2027,17 +2004,17 @@ NS_IMETHODIMP
 nsImageFrame::IconLoad::FrameChanged(imgIRequest *aRequest,
                                      imgIContainer *aContainer,
                                      const nsIntRect *aDirtyRect)
 {
   nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers);
   nsImageFrame *frame;
   while (iter.HasMore()) {
     frame = iter.GetNext();
-    frame->Invalidate(frame->GetRect());
+    frame->InvalidateFrame();
   }
 
   return NS_OK;
 }
 
 
 
 NS_IMPL_ISUPPORTS2(nsImageListener, imgIDecoderObserver, imgIContainerObserver)
--- a/layout/generic/nsImageMap.cpp
+++ b/layout/generic/nsImageMap.cpp
@@ -976,19 +976,17 @@ nsImageMap::HandleEvent(nsIDOMEvent* aEv
       uint32_t i, n = mAreas.Length();
       for (i = 0; i < n; i++) {
         Area* area = mAreas.ElementAt(i);
         if (area->mArea == targetContent) {
           //Set or Remove internal focus
           area->HasFocus(focus);
           //Now invalidate the rect
           if (mImageFrame) {
-            nsRect dmgRect;
-            area->GetRect(mImageFrame, dmgRect);
-            mImageFrame->Invalidate(dmgRect);
+            mImageFrame->InvalidateFrame();
           }
           break;
         }
       }
     }
   }
   return NS_OK;
 }
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -422,17 +422,17 @@ nsObjectFrame::PrepForDrawing(nsIWidget 
     viewMan->GetDeviceContext(*getter_AddRefs(dx));
     mInnerView->AttachWidgetEventHandler(mWidget);
 
 #ifdef XP_MACOSX
     // On Mac, we need to invalidate ourselves since even windowed
     // plugins are painted through Thebes and we need to ensure
     // the Thebes layer containing the plugin is updated.
     if (parentWidget == GetNearestWidget()) {
-      Invalidate(GetContentRectRelativeToSelf());
+      InvalidateFrame();
     }
 #endif
 
     RegisterPluginForGeometryUpdates();
 
     // Here we set the background color for this widget because some plugins will use 
     // the child window background color when painting. If it's not set, it may default to gray
     // Sometimes, a frame doesn't have a background color or is transparent. In this
@@ -1633,17 +1633,17 @@ nsObjectFrame::BuildLayer(nsDisplayListB
 
   gfxIntSize size(window->width, window->height);
 
   nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
   gfxRect r = nsLayoutUtils::RectToGfxRect(area, PresContext()->AppUnitsPerDevPixel());
   // to provide crisper and faster drawing.
   r.Round();
   nsRefPtr<Layer> layer =
-    (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem));
+    (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
 
   if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN) {
     if (!layer) {
       mInstanceOwner->NotifyPaintWaiter(aBuilder);
       // Initialize ImageLayer
       layer = aManager->CreateImageLayer();
       if (!layer)
         return nullptr;
--- a/layout/generic/nsPlaceholderFrame.cpp
+++ b/layout/generic/nsPlaceholderFrame.cpp
@@ -130,28 +130,27 @@ nsPlaceholderFrame::Reflow(nsPresContext
 }
 
 void
 nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   nsIPresShell* shell = PresContext()->GetPresShell();
   nsIFrame* oof = mOutOfFlowFrame;
   if (oof) {
-    oof->InvalidateFrameSubtree();
     // Unregister out-of-flow frame
     shell->FrameManager()->UnregisterPlaceholderFrame(this);
     mOutOfFlowFrame = nullptr;
     // If aDestructRoot is not an ancestor of the out-of-flow frame,
     // then call RemoveFrame on it here.
     // Also destroy it here if it's a popup frame. (Bug 96291)
     if (shell->FrameManager() &&
         ((GetStateBits() & PLACEHOLDER_FOR_POPUP) ||
          !nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, oof))) {
       ChildListID listId = nsLayoutUtils::GetChildListNameFor(oof);
-      shell->FrameManager()->RemoveFrame(listId, oof, false);
+      shell->FrameManager()->RemoveFrame(listId, oof);
     }
     // else oof will be destroyed by its parent
   }
 
   nsFrame::DestroyFrom(aDestructRoot);
 }
 
 nsIAtom*
--- a/layout/generic/nsSimplePageSequence.cpp
+++ b/layout/generic/nsSimplePageSequence.cpp
@@ -669,29 +669,16 @@ nsSimplePageSequenceFrame::PrePrintNextP
     }
   }
   // If all canvas have finished rendering, return true, otherwise false.
   *aDone = doneCounter == mCurrentCanvasList.Length();
 
   return NS_OK;
 }
 
-void
-nsSimplePageSequenceFrame::InvalidateInternal(const nsRect& aDamageRect,
-                                              nscoord aX, nscoord aY,
-                                              nsIFrame* aForChild,
-                                              uint32_t aFlags)
-{
-  // xxx Invalidate the entire frame as otherwise invalidate of printCanvas
-  // don't work properly. This is hopefully no longer necessary once 539356
-  // lands.
-  nsContainerFrame::InvalidateInternal(
-      nsRect(nsPoint(0,0), GetSize()), 0, 0, aForChild, aFlags); 
-}
-
 NS_IMETHODIMP
 nsSimplePageSequenceFrame::ResetPrintCanvasList()
 {
   for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) {
     nsHTMLCanvasElement* canvas = mCurrentCanvasList[i];
     canvas->ResetPrintCallback();
   }
 
--- a/layout/generic/nsSimplePageSequence.h
+++ b/layout/generic/nsSimplePageSequence.h
@@ -93,20 +93,16 @@ public:
 
   /**
    * Get the "type" of the frame
    *
    * @see nsGkAtoms::sequenceFrame
    */
   virtual nsIAtom* GetType() const;
 
-  virtual void InvalidateInternal(const nsRect& aDamageRect,
-                                  nscoord aX, nscoord aY,
-                                  nsIFrame* aForChild,
-                                  uint32_t aFlags);
 #ifdef DEBUG
   NS_IMETHOD  GetFrameName(nsAString& aResult) const;
 #endif
 
 protected:
   nsSimplePageSequenceFrame(nsStyleContext* aContext);
   virtual ~nsSimplePageSequenceFrame();
 
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -48,16 +48,17 @@
 #include "nsUnicharUtils.h"
 #include "nsIScrollableFrame.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsLayoutUtils.h"
 #include "FrameLayerBuilder.h"
 #include "nsObjectFrame.h"
 #include "nsIServiceManager.h"
 #include "nsContentUtils.h"
+#include "LayerTreeInvalidation.h"
 
 // For Accessibility
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 using namespace mozilla;
 using mozilla::layout::RenderFrameParent;
@@ -378,24 +379,26 @@ nsSubDocumentFrame::BuildDisplayList(nsD
   if (subdocRootFrame && parentAPD != subdocAPD) {
     NS_WARN_IF_FALSE(!addedLayer,
                      "Two container layers have been added. "
                       "Performance may suffer.");
     addedLayer = true;
 
     nsDisplayZoom* zoomItem =
       new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems,
-                                   subdocAPD, parentAPD);
+                                   subdocAPD, parentAPD, 
+                                   nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS);
     childItems.AppendToTop(zoomItem);
   }
 
   if (!addedLayer && presContext->IsRootContentDocument()) {
     // We always want top level content documents to be in their own layer.
     nsDisplayOwnLayer* layerItem = new (aBuilder) nsDisplayOwnLayer(
-      aBuilder, subdocRootFrame ? subdocRootFrame : this, &childItems);
+      aBuilder, subdocRootFrame ? subdocRootFrame : this, 
+      &childItems, nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS);
     childItems.AppendToTop(layerItem);
   }
 
   if (subdocRootFrame) {
     aBuilder->LeavePresShell(subdocRootFrame, dirty);
   }
 
   if (ShouldClipSubdocument()) {
@@ -651,19 +654,16 @@ nsSubDocumentFrame::Reflow(nsPresContext
   aDesiredSize.SetOverflowAreasToDesiredBounds();
   if (!ShouldClipSubdocument()) {
     nsIFrame* subdocRootFrame = GetSubdocumentRootFrame();
     if (subdocRootFrame) {
       aDesiredSize.mOverflowAreas.UnionWith(subdocRootFrame->GetOverflowAreas() + offset);
     }
   }
 
-  // Determine if we need to repaint our border, background or outline
-  CheckInvalidateSizeChange(aDesiredSize);
-
   FinishAndStoreOverflow(&aDesiredSize);
 
   if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
     PresContext()->PresShell()->PostReflowCallback(this);
     mPostedReflowCallback = true;
   }
 
   // printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this,
@@ -949,16 +949,19 @@ nsSubDocumentFrame::BeginSwapDocShells(n
   }
 
   nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
   if (!mFrameLoader || !mDidCreateDoc || mCallingShow ||
       !other->mFrameLoader || !other->mDidCreateDoc) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
+  NS_ASSERTION(HasAnyStateBits(NS_FRAME_IN_POPUP) == other->HasAnyStateBits(NS_FRAME_IN_POPUP),
+               "Can't swap doc shells when only one is within a popup!");
+
   if (mInnerView && other->mInnerView) {
     nsIView* ourSubdocViews = mInnerView->GetFirstChild();
     nsIView* ourRemovedViews = ::BeginSwapDocShellsForViews(ourSubdocViews);
     nsIView* otherSubdocViews = other->mInnerView->GetFirstChild();
     nsIView* otherRemovedViews = ::BeginSwapDocShellsForViews(otherSubdocViews);
 
     ::InsertViewsInReverseOrder(ourRemovedViews, other->mInnerView);
     ::InsertViewsInReverseOrder(otherRemovedViews, mInnerView);
@@ -1003,16 +1006,24 @@ EndSwapDocShellsForDocument(nsIDocument*
 static void
 EndSwapDocShellsForViews(nsIView* aSibling)
 {
   for ( ; aSibling; aSibling = aSibling->GetNextSibling()) {
     nsIDocument* doc = ::GetDocumentFromView(aSibling);
     if (doc) {
       ::EndSwapDocShellsForDocument(doc, nullptr);
     }
+    nsIFrame *frame = aSibling->GetFrame();
+    if (frame && frame->HasInvalidFrameInSubtree()) {
+      nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
+      while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
+        parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
+        parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
+      }
+    }
   }
 }
 
 void
 nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther)
 {
   nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
   nsWeakFrame weakThis(this);
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -24,22 +24,27 @@ class PropertyProvider;
 // This state bit is set on frames which are forced to trim their leading and
 // trailing whitespaces
 #define TEXT_FORCE_TRIM_WHITESPACE       NS_FRAME_STATE_BIT(32)
 
 #define TEXT_HAS_FONT_INFLATION          NS_FRAME_STATE_BIT(61)
 
 typedef nsFrame nsTextFrameBase;
 
+class nsDisplayTextGeometry;
+class nsDisplayText;
+
 class nsTextFrame : public nsTextFrameBase {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsTextFrame)
   NS_DECL_FRAMEARENA_HELPERS
 
   friend class nsContinuingTextFrame;
+  friend class nsDisplayTextGeometry;
+  friend class nsDisplayText;
 
   nsTextFrame(nsStyleContext* aContext)
     : nsTextFrameBase(aContext)
   {
     NS_ASSERTION(mContentOffset == 0, "Bogus content offset");
   }
   
   // nsQueryFrame
@@ -577,16 +582,20 @@ protected:
     {}
 
     bool operator==(const LineDecoration& aOther) const {
       return mFrame == aOther.mFrame &&
              mStyle == aOther.mStyle &&
              mColor == aOther.mColor &&
              mBaselineOffset == aOther.mBaselineOffset;
     }
+
+    bool operator!=(const LineDecoration& aOther) const {
+      return !(*this == aOther);
+    }
   };
   struct TextDecorations {
     nsAutoTArray<LineDecoration, 1> mOverlines, mUnderlines, mStrikes;
 
     TextDecorations() { }
 
     bool HasDecorationLines() const {
       return HasUnderline() || HasOverline() || HasStrikeout();
@@ -595,16 +604,26 @@ protected:
       return !mUnderlines.IsEmpty();
     }
     bool HasOverline() const {
       return !mOverlines.IsEmpty();
     }
     bool HasStrikeout() const {
       return !mStrikes.IsEmpty();
     }
+    bool operator==(const TextDecorations& aOther) const {
+      return mOverlines == aOther.mOverlines &&
+             mUnderlines == aOther.mUnderlines &&
+             mStrikes == aOther.mStrikes;
+    }
+    
+    bool operator!=(const TextDecorations& aOther) const {
+      return !(*this == aOther);
+    }
+
   };
   enum TextDecorationColorResolution {
     eResolvedColors,
     eUnresolvedColors
   };
   void GetTextDecorations(nsPresContext* aPresContext,
                           TextDecorationColorResolution aColorResolution,
                           TextDecorations& aDecorations);
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -3378,18 +3378,17 @@ NS_IMETHODIMP nsBlinkTimer::Notify(nsITi
 #endif
 
   uint32_t i, n = mFrames.Length();
   for (i = 0; i < n; i++) {
     FrameData& frameData = mFrames.ElementAt(i);
 
     // Determine damaged area and tell view manager to redraw it
     // blink doesn't blink outline ... I hope
-    nsRect bounds(nsPoint(0, 0), frameData.mFrame->GetSize());
-    frameData.mFrame->Invalidate(bounds);
+    frameData.mFrame->InvalidateFrame();
   }
   return NS_OK;
 }
 
 
 // static
 void nsBlinkTimer::AddBlinkFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
 {
@@ -4426,16 +4425,17 @@ nsTextFrame::CharacterDataChanged(Charac
                               NS_FRAME_IS_DIRTY);
       lastDirtiedFrame = textFrame;
     } else {
       // if the parent is a block, we're cheating here because we should
       // be marking our line dirty, but we're not. nsTextFrame::SetLength
       // will do that when it gets called during reflow.
       textFrame->AddStateBits(NS_FRAME_IS_DIRTY);
     }
+    textFrame->InvalidateFrame();
 
     // Below, frames that start after the deleted text will be adjusted so that
     // their offsets move with the trailing unchanged text. If this change
     // deletes more text than it inserts, those frame offsets will decrease.
     // We need to maintain the invariant that mContentOffset is non-decreasing
     // along the continuation chain. So we need to ensure that frames that
     // started in the deleted text are all still starting before the
     // unchanged text.
@@ -4466,34 +4466,55 @@ nsTextFrame::CharacterDataChanged(Charac
   return NS_OK;
 }
 
 /* virtual */ void
 nsTextFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
   nsFrame::DidSetStyleContext(aOldStyleContext);
   ClearTextRuns();
-} 
+}
+
+class nsDisplayTextGeometry : public nsDisplayItemGenericGeometry
+{
+public:
+  nsDisplayTextGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
+    : nsDisplayItemGenericGeometry(aItem, aBuilder)
+  {
+    nsTextFrame* f = static_cast<nsTextFrame*>(aItem->GetUnderlyingFrame());
+    f->GetTextDecorations(f->PresContext(), nsTextFrame::eResolvedColors, mDecorations);
+  }
+ 
+  /**
+   * We store the computed text decorations here since they are
+   * computed using style data from parent frames. Any changes to these
+   * styles will only invalidate the parent frame and not this frame.
+   */
+  nsTextFrame::TextDecorations mDecorations;
+};
 
 class nsDisplayText : public nsCharClipDisplayItem {
 public:
   nsDisplayText(nsDisplayListBuilder* aBuilder, nsTextFrame* aFrame) :
     nsCharClipDisplayItem(aBuilder, aFrame),
     mDisableSubpixelAA(false) {
     MOZ_COUNT_CTOR(nsDisplayText);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayText() {
     MOZ_COUNT_DTOR(nsDisplayText);
   }
 #endif
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
     *aSnap = false;
-    return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
+    nsRect temp = mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
+    // Bug 748228
+    temp.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel());
+    return temp;
   }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
     if (nsRect(ToReferenceFrame(), mFrame->GetSize()).Intersects(aRect)) {
       aOutFrames->AppendElement(mFrame);
     }
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
@@ -4501,16 +4522,41 @@ public:
   NS_DISPLAY_DECL_NAME("Text", TYPE_TEXT)
 
   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
   {
     bool snap;
     return GetBounds(aBuilder, &snap);
   }
 
+  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
+  {
+    return new nsDisplayTextGeometry(this, aBuilder);
+  }
+
+  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+                                         const nsDisplayItemGeometry* aGeometry,
+                                         nsRegion *aInvalidRegion)
+  {
+    const nsDisplayTextGeometry* geometry = static_cast<const nsDisplayTextGeometry*>(aGeometry);
+    nsTextFrame* f = static_cast<nsTextFrame*>(mFrame);
+
+    nsTextFrame::TextDecorations decorations;
+    f->GetTextDecorations(f->PresContext(), nsTextFrame::eResolvedColors, decorations);
+
+    bool snap;
+    nsRect newRect = geometry->mBounds;
+    nsRect oldRect = GetBounds(aBuilder, &snap);
+    if (decorations != geometry->mDecorations ||
+        !oldRect.IsEqualInterior(newRect) ||
+        !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
+      aInvalidRegion->Or(oldRect, newRect);
+    }
+  }
+  
   virtual void DisableComponentAlpha() { mDisableSubpixelAA = true; }
 
   bool mDisableSubpixelAA;
 };
 
 void
 nsDisplayText::Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) {
@@ -6277,17 +6323,17 @@ nsTextFrame::SetSelectedRange(uint32_t a
         aSelected && f->CombineSelectionUnderlineRect(presContext, r);
       if (didHaveOverflowingSelection || willHaveOverflowingSelection) {
         presContext->PresShell()->FrameNeedsReflow(f,
                                                    nsIPresShell::eStyleChange,
                                                    NS_FRAME_IS_DIRTY);
       }
     }
     // Selection might change anything. Invalidate the overflow area.
-    f->InvalidateOverflowRect();
+    f->InvalidateFrame();
 
     f = static_cast<nsTextFrame*>(f->GetNextContinuation());
   }
 }
 
 NS_IMETHODIMP
 nsTextFrame::GetPointFromOffset(int32_t inOffset,
                                 nsPoint* outPoint)
@@ -8050,17 +8096,17 @@ nsTextFrame::ReflowText(nsLineLayout& aL
     NS_ASSERTION(numJustifiableCharacters <= charsFit,
                  "Bad justifiable character count");
     aLineLayout.SetTextJustificationWeights(numJustifiableCharacters,
         charsFit - numJustifiableCharacters);
   }
 
   SetLength(contentLength, &aLineLayout, ALLOW_FRAME_CREATION_AND_DESTRUCTION);
 
-  Invalidate(aMetrics.VisualOverflow());
+  InvalidateFrame();
 
 #ifdef NOISY_REFLOW
   ListTag(stdout);
   printf(": desiredSize=%d,%d(b=%d) status=%x\n",
          aMetrics.width, aMetrics.height, aMetrics.ascent,
          aStatus);
 #endif
 }
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -191,17 +191,17 @@ nsVideoFrame::BuildLayer(nsDisplayListBu
                       presContext->AppUnitsToGfxUnits(area.height));
   r = CorrectForAspectRatio(r, videoSize);
   r.Round();
   gfxIntSize scaleHint(static_cast<int32_t>(r.Width()),
                        static_cast<int32_t>(r.Height()));
   container->SetScaleHint(scaleHint);
 
   nsRefPtr<ImageLayer> layer = static_cast<ImageLayer*>
-    (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem));
+    (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
   if (!layer) {
     layer = aManager->CreateImageLayer();
     if (!layer)
       return nullptr;
   }
 
   layer->SetContainer(container);
   layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
@@ -296,20 +296,16 @@ nsVideoFrame::Reflow(nsPresContext*     
                                        aReflowState.ComputedWidth(),
                                        aReflowState.ComputedHeight()));
     }
   }
   aMetrics.SetOverflowAreasToDesiredBounds();
 
   FinishAndStoreOverflow(&aMetrics);
 
-  if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) {
-    Invalidate(nsRect(0, 0, mRect.width, mRect.height));
-  }
-
   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
                   ("exit nsVideoFrame::Reflow: size=%d,%d",
                   aMetrics.width, aMetrics.height));
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
 
   return NS_OK;
 }
 
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -29,17 +29,26 @@ NS_NewViewportFrame(nsIPresShell* aPresS
 
 NS_IMPL_FRAMEARENA_HELPERS(ViewportFrame)
 
 NS_IMETHODIMP
 ViewportFrame::Init(nsIContent*      aContent,
                     nsIFrame*        aParent,
                     nsIFrame*        aPrevInFlow)
 {
-  return Super::Init(aContent, aParent, aPrevInFlow);
+  nsresult rv = Super::Init(aContent, aParent, aPrevInFlow);
+
+  nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this);
+  if (parent) {
+    nsFrameState state = parent->GetStateBits();
+
+    mState |= state & (NS_FRAME_IN_POPUP);
+  }
+
+  return rv;
 }
 
 void
 ViewportFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   DestroyAbsoluteFrames(aDestructRoot);
   nsContainerFrame::DestroyFrom(aDestructRoot);
 }
@@ -249,18 +258,17 @@ ViewportFrame::Reflow(nsPresContext*    
     rv = GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus,
                                               width, height,
                                               false, true, true, // XXX could be optimized
                                               &aDesiredSize.mOverflowAreas);
   }
 
   // If we were dirty then do a repaint
   if (GetStateBits() & NS_FRAME_IS_DIRTY) {
-    nsRect damageRect(0, 0, aDesiredSize.width, aDesiredSize.height);
-    Invalidate(damageRect);
+    InvalidateFrame();
   }
 
   // Clipping is handled by the document container (e.g., nsSubDocumentFrame),
   // so we don't need to change our overflow areas.
   bool overflowChanged = FinishAndStoreOverflow(&aDesiredSize);
   if (overflowChanged) {
     // We may need to alert our container to get it to pick up the
     // overflow change.
@@ -278,49 +286,15 @@ ViewportFrame::Reflow(nsPresContext*    
 }
 
 nsIAtom*
 ViewportFrame::GetType() const
 {
   return nsGkAtoms::viewportFrame;
 }
 
-void
-ViewportFrame::InvalidateInternal(const nsRect& aDamageRect,
-                                  nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                  uint32_t aFlags)
-{
-  nsRect r = aDamageRect + nsPoint(aX, aY);
-  nsPresContext* presContext = PresContext();
-  presContext->NotifyInvalidation(r, aFlags);
-
-  if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
-      !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
-    FrameLayerBuilder::InvalidateThebesLayerContents(this, r);
-    // Don't need to invalidate any more Thebes layers
-    aFlags |= INVALIDATE_NO_THEBES_LAYERS;
-    if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
-      return;
-    }
-  }
-
-  nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this);
-  if (parent) {
-    if (!presContext->PresShell()->IsActive())
-      return;
-    nsPoint pt = -parent->GetOffsetToCrossDoc(this);
-    int32_t ourAPD = presContext->AppUnitsPerDevPixel();
-    int32_t parentAPD = parent->PresContext()->AppUnitsPerDevPixel();
-    r = r.ConvertAppUnitsRoundOut(ourAPD, parentAPD);
-    parent->InvalidateInternal(r, pt.x, pt.y, this,
-                               aFlags | INVALIDATE_CROSS_DOC);
-    return;
-  }
-  InvalidateRoot(r, aFlags);
-}
-
 #ifdef DEBUG
 NS_IMETHODIMP
 ViewportFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("Viewport"), aResult);
 }
 #endif
--- a/layout/generic/nsViewportFrame.h
+++ b/layout/generic/nsViewportFrame.h
@@ -65,20 +65,16 @@ public:
 
   /**
    * Get the "type" of the frame
    *
    * @see nsGkAtoms::viewportFrame
    */
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
 
-  virtual void InvalidateInternal(const nsRect& aDamageRect,
-                                  nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                  uint32_t aFlags);
-
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
 private:
   virtual mozilla::layout::FrameChildListID GetAbsoluteListID() const { return kFixedList; }
 
 protected:
--- a/layout/inspector/src/inFlasher.cpp
+++ b/layout/inspector/src/inFlasher.cpp
@@ -98,17 +98,17 @@ inFlasher::SetInvert(bool aInvert)
 
 NS_IMETHODIMP
 inFlasher::RepaintElement(nsIDOMElement* aElement)
 {
   NS_ENSURE_ARG_POINTER(aElement);
   nsIFrame* frame = inLayoutUtils::GetFrameFor(aElement);
   if (!frame) return NS_OK;
 
-  frame->Invalidate(frame->GetRect());
+  frame->InvalidateFrame();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 inFlasher::DrawElementOutline(nsIDOMElement* aElement)
 {
   NS_ENSURE_ARG_POINTER(aElement);
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -641,17 +641,17 @@ RenderFrameParent::BuildLayer(nsDisplayL
     return nullptr;
   }
 
   uint64_t id = GetLayerTreeId();
   if (0 != id) {
     MOZ_ASSERT(!GetRootLayer());
 
     nsRefPtr<Layer> layer =
-      (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem));
+      (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
     if (!layer) {
       layer = aManager->CreateRefLayer();
     }
     if (!layer) {
       // Probably a temporary layer manager that doesn't know how to
       // use ref layers.
       return nullptr;
     }
@@ -833,27 +833,17 @@ RenderFrameParent::TriggerRepaint()
     // Bad, but nothing we can do about it (XXX/cjones: or is there?
     // maybe bug 589337?).  When the new frame is created, we'll
     // probably still be the current render frame and will get to draw
     // our content then.  Or, we're shutting down and this update goes
     // to /dev/null.
     return;
   }
 
-  // FIXME/cjones: we should collect the rects/regions updated for
-  // Painted*Layer() calls and pass that region to here, then only
-  // invalidate that rect
-  //
-  // We pass INVALIDATE_NO_THEBES_LAYERS here because we're
-  // invalidating the <browser> on behalf of its counterpart in the
-  // content process.  Not only do we not need to invalidate the
-  // shadow layers, things would just break if we did --- we have no
-  // way to repaint shadow layers from this process.
-  nsRect rect = nsRect(nsPoint(0, 0), docFrame->GetRect().Size());
-  docFrame->InvalidateWithFlags(rect, nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
+  docFrame->SchedulePaint();
 }
 
 ShadowLayersParent*
 RenderFrameParent::GetShadowLayers() const
 {
   const nsTArray<PLayersParent*>& shadowParents = ManagedPLayersParent();
   NS_ABORT_IF_FALSE(shadowParents.Length() <= 1,
                     "can only support at most 1 ShadowLayersParent");
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -1678,20 +1678,23 @@ public:
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
     *aSnap = false;
     nsRect rect;
     mChar->GetRect(rect);
     nsPoint offset = ToReferenceFrame() + rect.TopLeft();
     nsBoundingMetrics bm;
     mChar->GetBoundingMetrics(bm);
-    return nsRect(offset.x + bm.leftBearing, offset.y,
-                  bm.rightBearing - bm.leftBearing, bm.ascent + bm.descent);
+    nsRect temp(offset.x + bm.leftBearing, offset.y,
+                bm.rightBearing - bm.leftBearing, bm.ascent + bm.descent);
+    // Bug 748220
+    temp.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel());
+    return temp;
   }
-
+  
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx)
   {
     mChar->PaintForeground(mFrame->PresContext(), *aCtx,
                            ToReferenceFrame(), mIsSelected);
   }
 
   NS_DISPLAY_DECL_NAME("MathMLCharForeground", TYPE_MATHML_CHAR_FOREGROUND)
--- a/layout/style/ImageLoader.cpp
+++ b/layout/style/ImageLoader.cpp
@@ -319,35 +319,18 @@ ImageLoader::DoRedraw(FrameSet* aFrameSe
 {
   NS_ASSERTION(aFrameSet, "Must have a frame set");
   NS_ASSERTION(mDocument, "Should have returned earlier!");
 
   FrameSet::size_type length = aFrameSet->Length();
   for (FrameSet::size_type i = 0; i < length; i++) {
     nsIFrame* frame = aFrameSet->ElementAt(i);
 
-    // NOTE: It is not sufficient to invalidate only the size of the image:
-    //       the image may be tiled! 
-    //       The best option is to call into the frame, however lacking this
-    //       we have to at least invalidate the frame's bounds, hence
-    //       as long as we have a frame we'll use its size.
-    //
-
-    // Invalidate the entire frame
-    // XXX We really only need to invalidate the client area of the frame...    
-
-    nsRect bounds(nsPoint(0, 0), frame->GetSize());
-
-    if (frame->GetType() == nsGkAtoms::canvasFrame) {
-      // The canvas's background covers the whole viewport.
-      bounds = frame->GetVisualOverflowRect();
-    }
-
     if (frame->GetStyleVisibility()->IsVisible()) {
-      frame->Invalidate(bounds);
+      frame->InvalidateFrame();
     }
   }
 }
 
 NS_IMPL_ADDREF(ImageLoader)
 NS_IMPL_RELEASE(ImageLoader)
 
 NS_INTERFACE_MAP_BEGIN(ImageLoader)
--- a/layout/svg/nsSVGEffects.cpp
+++ b/layout/svg/nsSVGEffects.cpp
@@ -233,17 +233,17 @@ nsSVGFilterProperty::GetFilterFrame()
     (GetReferencedFrame(nsGkAtoms::svgFilterFrame, nullptr));
 }
 
 static void
 InvalidateAllContinuations(nsIFrame* aFrame)
 {
   for (nsIFrame* f = aFrame; f;
        f = nsLayoutUtils::GetNextContinuationOrSpecialSibling(f)) {
-    f->InvalidateOverflowRect();
+    f->InvalidateFrame();
   }
 }
 
 void
 nsSVGFilterProperty::DoUpdate()
 {
   nsSVGIDRenderingObserver::DoUpdate();
   if (!mFrame)
--- a/layout/svg/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/nsSVGForeignObjectFrame.cpp
@@ -173,47 +173,16 @@ nsSVGForeignObjectFrame::BuildDisplayLis
                                           const nsDisplayListSet& aLists)
 {
   if (!static_cast<const nsSVGElement*>(mContent)->HasValidDimensions()) {
     return NS_OK;
   }
   return BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
 }
 
-void
-nsSVGForeignObjectFrame::InvalidateInternal(const nsRect& aDamageRect,
-                                            nscoord aX, nscoord aY,
-                                            nsIFrame* aForChild,
-                                            uint32_t aFlags)
-{
-  // This is called by our descendants when they change.
-
-  if (GetStateBits() & NS_FRAME_IS_DIRTY) {
-    // Our entire area has been (or will be) invalidated, so no point
-    // keeping track of sub-areas that our descendants dirty.
-    return;
-  }
-
-  if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) {
-    nsSVGEffects::InvalidateRenderingObservers(this);
-    return;
-  }
-
-  if (!mInReflow) {
-    // We can't collect dirty areas, since we don't have a place to reliably
-    // call FlushDirtyRegion before we paint, so we have to invalidate now.
-    InvalidateDirtyRect(aDamageRect + nsPoint(aX, aY), aFlags, false);
-    return;
-  }
-
-  nsRegion* region = (aFlags & INVALIDATE_CROSS_DOC)
-    ? &mSubDocDirtyRegion : &mSameDocDirtyRegion;
-  region->Or(*region, aDamageRect + nsPoint(aX, aY));
-}
-
 bool
 nsSVGForeignObjectFrame::IsSVGTransformed(gfxMatrix *aOwnTransform,
                                          gfxMatrix *aFromParentTransform) const
 {
   bool foundTransform = false;
 
   // Check if our parent has children-only transforms:
   nsIFrame *parent = GetParent();
@@ -417,22 +386,16 @@ nsSVGForeignObjectFrame::ReflowSVG()
   // If mRect's width or height are negative, reflow blows up! We must clamp!
   if (w < 0.0f) w = 0.0f;
   if (h < 0.0f) h = 0.0f;
 
   mRect = nsLayoutUtils::RoundGfxRectToAppRect(
                            gfxRect(x, y, w, h),
                            PresContext()->AppUnitsPerCSSPixel());
 
-  // Since we'll invalidate our entire area at the end of this method, we
-  // empty our cached dirty regions to prevent FlushDirtyRegion under DoReflow
-  // from wasting time invalidating:
-  mSameDocDirtyRegion.SetEmpty();
-  mSubDocDirtyRegion.SetEmpty();
-
   // Fully mark our kid dirty so that it gets resized if necessary
   // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case):
   nsIFrame* kid = GetFirstPrincipalChild();
   kid->AddStateBits(NS_FRAME_IS_DIRTY);
 
   // Make sure to not allow interrupts if we're not being reflown as a root:
   nsPresContext::InterruptPreventer noInterrupts(PresContext());
 
@@ -643,56 +606,25 @@ nsSVGForeignObjectFrame::DoReflow()
   ReflowChild(kid, presContext, desiredSize, reflowState, 0, 0,
               NS_FRAME_NO_MOVE_FRAME, status);
   NS_ASSERTION(mRect.width == desiredSize.width &&
                mRect.height == desiredSize.height, "unexpected size");
   FinishReflowChild(kid, presContext, &reflowState, desiredSize, 0, 0,
                     NS_FRAME_NO_MOVE_FRAME);
   
   mInReflow = false;
-
-  if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
-    // Since we're a reflow root and can be reflowed independently of our
-    // outer-<svg>, we can't just blindly pass 'true' here.
-    FlushDirtyRegion(0, nsSVGUtils::OuterSVGIsCallingReflowSVG(this));
-  }
-}
-
-void
-nsSVGForeignObjectFrame::InvalidateDirtyRect(const nsRect& aRect,
-                                             uint32_t aFlags,
-                                             bool aDuringReflowSVG)
-{
-  if (aRect.IsEmpty())
-    return;
-
-  // Don't invalidate areas outside our bounds:
-  nsRect rect = aRect.Intersect(nsRect(nsPoint(0,0), mRect.Size()));
-  if (rect.IsEmpty())
-    return;
-
-  nsSVGUtils::InvalidateBounds(this, aDuringReflowSVG, &rect, aFlags);
 }
 
-void
-nsSVGForeignObjectFrame::FlushDirtyRegion(uint32_t aFlags,
-                                          bool aDuringReflowSVG)
+nsRect
+nsSVGForeignObjectFrame::GetInvalidRegion()
 {
-  NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
-                    "Should not have been called");
-
-  NS_ASSERTION(!mInReflow,
-               "We shouldn't be flushing while we have a pending flush");
+  nsIFrame* kid = GetFirstPrincipalChild();
+  if (kid->HasInvalidFrameInSubtree()) {
+    gfxRect r(mRect.x, mRect.y, mRect.width, mRect.height);
+    r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
+    nsRect rect = ToCanvasBounds(r, GetCanvasTM(FOR_PAINTING), PresContext());
+    rect = nsSVGUtils::GetPostFilterVisualOverflowRect(this, rect);
+    return rect;
+  }
+  return nsRect();
+}
 
-  if (mSameDocDirtyRegion.IsEmpty() && mSubDocDirtyRegion.IsEmpty()) {
-    return;
-  }
 
-  InvalidateDirtyRect(mSameDocDirtyRegion.GetBounds(),
-                      aFlags,
-                      aDuringReflowSVG);
-  InvalidateDirtyRect(mSubDocDirtyRegion.GetBounds(),
-                      aFlags | INVALIDATE_CROSS_DOC,
-                      aDuringReflowSVG);
-
-  mSameDocDirtyRegion.SetEmpty();
-  mSubDocDirtyRegion.SetEmpty();
-}
--- a/layout/svg/nsSVGForeignObjectFrame.h
+++ b/layout/svg/nsSVGForeignObjectFrame.h
@@ -62,20 +62,16 @@ public:
   virtual nsIAtom* GetType() const;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const
   {
     return nsSVGForeignObjectFrameBase::IsFrameOfType(aFlags &
       ~(nsIFrame::eSVG | nsIFrame::eSVGForeignObject));
   }
 
-  virtual void InvalidateInternal(const nsRect& aDamageRect,
-                                  nscoord aX, nscoord aY, nsIFrame* aForChild,
-                                  uint32_t aFlags);
-
   virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform,
                                 gfxMatrix *aFromParentTransform) const;
 
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGForeignObject"), aResult);
   }
@@ -89,32 +85,24 @@ public:
   vir