Merge m-c tip to m-i
authorJustin Wood <Callek@gmail.com>
Sun, 15 Jan 2012 05:29:24 -0500
changeset 85766 bc30dee3a6f22a57e17d8382f9d416fbde1413ed
parent 85712 d7984d345c24a28ec1c158d09a914ea12b008f29 (current diff)
parent 85765 006ab840347570b92f26c28f2efe05973357ced6 (diff)
child 85767 823072af2430cf86939ff891f8bfb11243be7415
child 85789 f65331c8b0e71969936fb6d2b3327b49f553d03d
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
Merge m-c tip to m-i
editor/libeditor/base/nsEditor.cpp
js/src/jsapi.h
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/nsXPConnect.cpp
layout/base/nsPresShell.cpp
xpcom/threads/nsThreadUtilsInternal.h
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -151,17 +151,20 @@ class RemoteAutomation(Automation):
     class RProcess(object):
         # device manager process
         dm = None
         def __init__(self, dm, cmd, stdout = None, stderr = None, env = None, cwd = '.'):
             self.dm = dm
             self.stdoutlen = 0
             self.proc = dm.launchProcess(cmd, stdout, cwd, env, True)
             if (self.proc is None):
-              raise Exception("unable to launch process")
+              if cmd[0] == 'am':
+                self.proc = stdout
+              else:
+                raise Exception("unable to launch process")
             exepath = cmd[0]
             name = exepath.split('/')[-1]
             self.procName = name
 
             # Setting timeout at 1 hour since on a remote device this takes much longer
             self.timeout = 3600
             time.sleep(15)
 
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -498,17 +498,18 @@ nsGenericHTMLElement::GetOffsetRect(nsRe
   nsIFrame* frame = GetStyledFrame();
   if (!frame) {
     return;
   }
 
   nsIFrame* parent = frame->GetParent();
   nsPoint origin(0, 0);
 
-  if (parent && parent->GetType() == nsGkAtoms::tableOuterFrame) {
+  if (parent && parent->GetType() == nsGkAtoms::tableOuterFrame &&
+      frame->GetType() == nsGkAtoms::tableFrame) {
     origin = parent->GetPositionIgnoringScrolling();
     parent = parent->GetParent();
   }
 
   Element* docElement = GetCurrentDoc()->GetRootElement();
   nsIContent* content = frame->GetContent();
 
   if (content && (content->IsHTML(nsGkAtoms::body) || content == docElement)) {
--- a/content/html/content/src/nsHTMLDNSPrefetch.cpp
+++ b/content/html/content/src/nsHTMLDNSPrefetch.cpp
@@ -135,27 +135,16 @@ nsHTMLDNSPrefetch::IsAllowed (nsIDocumen
 {
   // There is no need to do prefetch on non UI scenarios such as XMLHttpRequest.
   return aDocument->IsDNSPrefetchAllowed() && aDocument->GetWindow();
 }
 
 nsresult
 nsHTMLDNSPrefetch::Prefetch(Link *aElement, PRUint16 flags)
 {
-  if (IsNeckoChild()) {
-    // Instead of transporting the Link object to the other process
-    // we are using the hostname based function here, too. Compared to the 
-    // IPC the performance hit should be negligible.
-    nsAutoString hostname;
-    nsresult rv = aElement->GetHostname(hostname);
-    NS_ENSURE_SUCCESS(rv,rv);
-
-    return Prefetch(hostname, flags);
-  }
-
   if (!(sInitialized && sPrefetches && sDNSService && sDNSListener))
     return NS_ERROR_NOT_AVAILABLE;
 
   return sPrefetches->Add(flags, aElement);
 }
 
 nsresult
 nsHTMLDNSPrefetch::PrefetchLow(Link *aElement)
@@ -294,21 +283,26 @@ nsHTMLDNSPrefetch::nsDeferrals::SubmitQu
     nsCOMPtr<nsIContent> content = do_QueryReferent(mEntries[mTail].mElement);
     if (content) {
       nsCOMPtr<Link> link = do_QueryInterface(content);
       nsCOMPtr<nsIURI> hrefURI(link ? link->GetURI() : nsnull);
       if (hrefURI)
         hrefURI->GetAsciiHost(hostName);
 
       if (!hostName.IsEmpty()) {
-        nsCOMPtr<nsICancelable> tmpOutstanding;
+        if (IsNeckoChild()) {
+          gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName),
+                                           mEntries[mTail].mFlags);
+        } else {
+          nsCOMPtr<nsICancelable> tmpOutstanding;
 
-        sDNSService->AsyncResolve(hostName, 
+          sDNSService->AsyncResolve(hostName, 
                                   mEntries[mTail].mFlags | nsIDNSService::RESOLVE_SPECULATE,
                                   sDNSListener, nsnull, getter_AddRefs(tmpOutstanding));
+        }
       }
     }
     
     mEntries[mTail].mElement = nsnull;
     mTail = (mTail + 1) & sMaxDeferredMask;
   }
   
   if (mTimerArmed) {
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -1155,20 +1155,16 @@ nsTextEditorState::PrepareEditor(const n
   if (IsSingleLineTextControl())
     editorFlags |= nsIPlaintextEditor::eEditorSingleLineMask;
   if (IsPasswordTextControl())
     editorFlags |= nsIPlaintextEditor::eEditorPasswordMask;
 
   // All nsTextControlFrames are widgets
   editorFlags |= nsIPlaintextEditor::eEditorWidgetMask;
 
-  // Use async reflow and painting for text widgets to improve
-  // performance.
-  editorFlags |= nsIPlaintextEditor::eEditorUseAsyncUpdatesMask;
-  
   // Spell check is diabled at creation time. It is enabled once
   // the editor comes into focus.
   editorFlags |= nsIPlaintextEditor::eEditorSkipSpellCheck;
 
   bool shouldInitializeEditor = false;
   nsCOMPtr<nsIEditor> newEditor; // the editor that we might create
   nsresult rv = NS_OK;
   if (!mEditor) {
@@ -1309,22 +1305,17 @@ nsTextEditorState::PrepareEditor(const n
   }
 
   // If we have a default value, insert it under the div we created
   // above, but be sure to use the editor so that '*' characters get
   // displayed for password fields, etc. SetValue() will call the
   // editor for us.
 
   if (!defaultValue.IsEmpty()) {
-    // Avoid causing reentrant painting and reflowing by telling the editor
-    // that we don't want it to force immediate view refreshes or force
-    // immediate reflows during any editor calls.
-
-    rv = newEditor->SetFlags(editorFlags |
-                             nsIPlaintextEditor::eEditorUseAsyncUpdatesMask);
+    rv = newEditor->SetFlags(editorFlags);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Now call SetValue() which will make the necessary editor calls to set
     // the default value.  Make sure to turn off undo before setting the default
     // value, and turn it back on afterwards. This will make sure we can't undo
     // past the default value.
 
     rv = newEditor->EnableUndo(false);
@@ -1832,17 +1823,16 @@ nsTextEditorState::SetValue(const nsAStr
 
         // get the flags, remove readonly and disabled, set the value,
         // restore flags
         PRUint32 flags, savedFlags;
         mEditor->GetFlags(&savedFlags);
         flags = savedFlags;
         flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
         flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
-        flags |= nsIPlaintextEditor::eEditorUseAsyncUpdatesMask;
         flags |= nsIPlaintextEditor::eEditorDontEchoPassword;
         mEditor->SetFlags(flags);
 
         mTextListener->SettingValue(true);
 
         // Also don't enforce max-length here
         PRInt32 savedMaxLength;
         plaintextEditor->GetMaxTextLength(&savedMaxLength);
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -277,16 +277,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug617528.html \
 		test_bug660959-1.html \
 		test_bug660959-2.html \
 		test_bug660959-3.html \
 		test_checked.html \
 		test_bug677658.html \
 		test_bug677463.html \
 		test_bug682886.html \
+		test_bug717819.html \
 		file_fullscreen-api.html \
 		file_fullscreen-api-keys.html \
 		test_fullscreen-api.html \
 		file_fullscreen-plugins.html \
 		file_fullscreen-denied.html \
 		file_fullscreen-denied-inner.html \
 		file_fullscreen-hidden.html \
 		file_fullscreen-navigation.html \
--- a/content/html/content/test/test_bug375003-1.html
+++ b/content/html/content/test/test_bug375003-1.html
@@ -71,18 +71,17 @@ function run_test() {
    t3('tr7'  ,[0,0,39,24],[9,9,39,24],[0,0,39,22],'table7');
    t3('span8' ,[0,0,20,20],[26,37,20,20],[0,0,20,20],'table7');
    t3('table7',[7,7,43,54],[10,319,57,68],[0,0,57,50],'body');
    t3('div7',[10,10,-1,68],[0,309,-1,88],[0,0,-1,70],'body');
 
    t3('span9' ,[0,0,20,20],[1,1,20,20],[0,0,20,20],'td9');
    t3('td9'   ,[1,1,22,22],[15,15,24,24],[0,0,24,24],'table9');
    t3('tr9'  ,[0,0,24,24],[15,15,24,24],[0,0,24,22],'table9');
-   // t3('span10' ,[0,0,20,20],[3,30,20,20],[0,0,20,20],'table9');
-   t3('span10' ,[0,0,20,20],[27,450,20,20],[0,0,20,20],'body');  // bug: 'body' should be 'table9'
+   t3('span10' ,[0,0,20,20],[17,43,20,20],[0,0,20,20],'table9');
    t3('table9',[13,13,28,34],[10,407,54,60],[0,0,54,50],'body');
    t3('div9',[10,10,-1,0],[0,397,-1,20],[0,0,-1,70],'body');
 
    t3('span11' ,[0,0,20,20],[1,1,20,20],[0,0,20,20],'td11');
    t3('td11'   ,[0,0,22,22],[2,2,22,22],[0,0,22,22],'table11');
    t3('tr11'  ,[0,0,22,22],[2,2,22,22],[0,0,22,22],'table11');
    t3('span12' ,[0,0,20,20],[28,454,20,20],[0,0,20,20],'body');
    t3('table11',[0,0,26,30],[10,427,26,30],[0,0,26,50],'body');
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug717819.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=717819
+-->
+<head>
+  <title>Test for Bug 717819</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717819">Mozilla Bug 717819</a>
+<p id="display"></p>
+<div id="content">
+  <table style="position: relative; top: 100px;">
+    <tr>
+      <td>
+        <div id="test" style="position: absolute; top: 50px;"></div>
+      </td>
+    </tr>
+  </table>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 717819 **/
+var div = document.getElementById("test");
+is(div.offsetTop, 50, "The offsetTop must be calculated correctly");
+is(div.offsetParent, document.querySelector("table"),
+   "The offset should be calculated off of the correct parent");
+
+</script>
+</pre>
+</body>
+</html>
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4727,18 +4727,17 @@ nsDocShell::Repaint(bool aForce)
 {
     nsCOMPtr<nsIPresShell> presShell;
     GetPresShell(getter_AddRefs(presShell));
     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
 
     nsIViewManager* viewManager = presShell->GetViewManager();
     NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
 
-    // what about aForce ?
-    NS_ENSURE_SUCCESS(viewManager->UpdateAllViews(0), NS_ERROR_FAILURE);
+    NS_ENSURE_SUCCESS(viewManager->InvalidateAllViews(), NS_ERROR_FAILURE);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetParentWidget(nsIWidget ** parentWidget)
 {
     NS_ENSURE_ARG_POINTER(parentWidget);
 
@@ -7319,17 +7318,17 @@ nsDocShell::RestoreFromHistory()
 
         newVM = shell->GetViewManager();
         if (newVM) {
             // When we insert the root view above the resulting invalidate is
             // dropped because painting is suppressed in the presshell until we
             // call Thaw. So we issue the invalidate here.
             newRootView = newVM->GetRootView();
             if (newRootView) {
-                newVM->UpdateView(newRootView, NS_VMREFRESH_NO_SYNC);
+                newVM->InvalidateView(newRootView);
             }
         }
     }
 
     return privWin->FireDelayedDOMEvents();
 }
 
 NS_IMETHODIMP
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -757,37 +757,16 @@ nsDOMWindowUtils::CycleCollect(nsICycleC
   }
 #endif
 
   nsJSContext::CycleCollectNow(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::ProcessUpdates()
-{
-  nsPresContext* presContext = GetPresContext();
-  if (!presContext)
-    return NS_ERROR_UNEXPECTED;
-
-  nsIPresShell* shell = presContext->GetPresShell();
-  if (!shell)
-    return NS_ERROR_UNEXPECTED;
-
-  nsIViewManager *viewManager = shell->GetViewManager();
-  if (!viewManager)
-    return NS_ERROR_UNEXPECTED;
-  
-  nsIViewManager::UpdateViewBatch batch;
-  batch.BeginUpdateViewBatch(viewManager);
-  batch.EndUpdateViewBatch(NS_VMREFRESH_IMMEDIATE);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType,
                                          float aX,
                                          float aY,
                                          PRUint32 aDirection,
                                          PRFloat64 aDelta,
                                          PRInt32 aModifiers)
 {
   if (!IsUniversalXPConnectCapable()) {
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -64,17 +64,17 @@ interface nsIDOMHTMLCanvasElement;
 interface nsIDOMEvent;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIDOMBlob;
 interface nsIDOMFile;
 interface nsIFile;
 
-[scriptable, uuid(15fcceb0-37ea-11e1-b86c-0800200c9a66)]
+[scriptable, uuid(b9c1f815-c2f2-4607-a060-6a8566581927)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -373,22 +373,16 @@ interface nsIDOMWindowUtils : nsISupport
    * privileges in non-debug builds. Available to all callers in debug builds.
    *
    * @param aListener listener that receives information about the CC graph
    *                  (see @mozilla.org/cycle-collector-logger;1 for a logger
    *                   component)
    */
   void cycleCollect([optional] in nsICycleCollectorListener aListener);
 
-  /**
-   * Force processing of any queued paints
-   */
-
-  void processUpdates();
-
   /** Synthesize a simple gesture event for a window. The event types
    *  supported are: MozSwipeGesture, MozMagnifyGestureStart,
    *  MozMagnifyGestureUpdate, MozMagnifyGesture, MozRotateGestureStart,
    *  MozRotateGestureUpdate, MozRotateGesture, MozPressTapGesture, and
    *  MozTapGesture.
    *
    * Cannot be accessed from unprivileged context (not
    * content-accessible) Will throw a DOM security error if called
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -616,18 +616,17 @@ NS_IMETHODIMP nsPluginInstanceOwner::Inv
   }
 
 #ifndef XP_MACOSX
   // Windowed plugins should not be calling NPN_InvalidateRect, but
   // Silverlight does and expects it to "work"
   if (mWidget) {
     mWidget->Invalidate(nsIntRect(invalidRect->left, invalidRect->top,
                                   invalidRect->right - invalidRect->left,
-                                  invalidRect->bottom - invalidRect->top),
-                        false);
+                                  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),
@@ -649,22 +648,16 @@ NS_IMETHODIMP nsPluginInstanceOwner::Inv
 
 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::ForceRedraw()
 {
-  NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_NULL_POINTER);
-  nsIView* view = mObjectFrame->GetView();
-  if (view) {
-    return view->GetViewManager()->Composite();
-  }
-
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
 {
   if (!mObjectFrame) {
     NS_WARNING("plugin owner has no owner in getting doc's window handle");
     return NS_ERROR_FAILURE;
--- a/editor/idl/nsIPlaintextEditor.idl
+++ b/editor/idl/nsIPlaintextEditor.idl
@@ -32,17 +32,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
  
 #include "nsISupports.idl"
 
-[scriptable, uuid(05d312ef-8914-494e-91c9-2be8ed7f8e29)]
+[scriptable, uuid(07b6d070-ccea-4a00-84b4-f4b94dd9eb52)]
 interface nsIPlaintextEditor : nsISupports
 {
 
   // XXX Why aren't these in nsIEditor?
   // only plain text entry is allowed via events
   const long eEditorPlaintextMask       = 0x0001;
   // enter key and CR-LF handled specially
   const long eEditorSingleLineMask      = 0x0002;
@@ -51,39 +51,37 @@ interface nsIPlaintextEditor : nsISuppor
   // editing events are disabled.  Editor may still accept focus.
   const long eEditorReadonlyMask        = 0x0008;
   // all events are disabled (like scrolling).  Editor will not accept focus.
   const long eEditorDisabledMask        = 0x0010;
   // text input is limited to certain character types, use mFilter
   const long eEditorFilterInputMask     = 0x0020;
   // use mail-compose editing rules
   const long eEditorMailMask            = 0x0040;
-  // prevent immediate reflows and view refreshes
-  const long eEditorUseAsyncUpdatesMask = 0x0080;
   // allow the editor to set font: monospace on the root node
-  const long eEditorEnableWrapHackMask  = 0x0100;
+  const long eEditorEnableWrapHackMask  = 0x0080;
   // bit for widgets (form elements)
-  const long eEditorWidgetMask          = 0x0200;
+  const long eEditorWidgetMask          = 0x0100;
   // this HTML editor should not create css styles
-  const long eEditorNoCSSMask           = 0x0400;
+  const long eEditorNoCSSMask           = 0x0200;
   // whether HTML document specific actions are executed or not.
   // e.g., if this flag is set, the editor doesn't handle Tab key.
   // besides, anchors of HTML are not clickable.
-  const long eEditorAllowInteraction    = 0x0800;
+  const long eEditorAllowInteraction    = 0x0400;
   // when this is set, the characters in password editor are always masked.
   // see bug 530367 for the detail.
-  const long eEditorDontEchoPassword    = 0x1000;
+  const long eEditorDontEchoPassword    = 0x0800;
   // when this flag is set, the internal direction of the editor is RTL.
   // if neither of the direction flags are set, the direction is determined
   // from the text control's content node.
-  const long eEditorRightToLeft         = 0x2000;
+  const long eEditorRightToLeft         = 0x1000;
   // when this flag is set, the internal direction of the editor is LTR.
-  const long eEditorLeftToRight         = 0x4000;
+  const long eEditorLeftToRight         = 0x2000;
   // when this flag is set, the editor's text content is not spell checked.
-  const long eEditorSkipSpellCheck      = 0x8000;
+  const long eEditorSkipSpellCheck      = 0x4000;
 
   /*
    * The valid values for newlines handling.
    * Can't change the values unless we remove
    * use of the pref.
    */
   const long eNewlinesPasteIntact                = 0;
   const long eNewlinesPasteToFirst               = 1;
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -4201,25 +4201,16 @@ nsresult nsEditor::BeginUpdateViewBatch(
     nsCOMPtr<nsISelection> selection;
     GetSelection(getter_AddRefs(selection));
 
     if (selection) 
     {
       nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
       selPrivate->StartBatchChanges();
     }
-
-    // Turn off view updating.
-    nsCOMPtr<nsIPresShell> ps = GetPresShell();
-    if (ps) {
-      nsCOMPtr<nsIViewManager> viewManager = ps->GetViewManager();
-      if (viewManager) {
-        mBatch.BeginUpdateViewBatch(viewManager);
-      }
-    }
   }
 
   mUpdateCount++;
 
   return NS_OK;
 }
 
 
@@ -4245,30 +4236,16 @@ nsresult nsEditor::EndUpdateViewBatch()
     nsRefPtr<nsCaret> caret;
     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
 
     if (presShell)
       caret = presShell->GetCaret();
 
     StCaretHider caretHider(caret);
 
-    PRUint32 flags = 0;
-
-    GetFlags(&flags);
-
-    // Turn view updating back on.
-    PRUint32 updateFlag = NS_VMREFRESH_IMMEDIATE;
-
-    // If we're doing async updates, use NS_VMREFRESH_DEFERRED here, so that
-    // the reflows we caused will get processed before the invalidates.
-    if (flags & nsIPlaintextEditor::eEditorUseAsyncUpdatesMask) {
-      updateFlag = NS_VMREFRESH_DEFERRED;
-    }
-    mBatch.EndUpdateViewBatch(updateFlag);
-
     // Turn selection updating and notifications back on.
 
     nsCOMPtr<nsISelection>selection;
     GetSelection(getter_AddRefs(selection));
 
     if (selection) {
       nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
       selPrivate->EndBatchChanges();
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -684,21 +684,16 @@ public:
     return (mFlags & nsIPlaintextEditor::eEditorFilterInputMask) != 0;
   }
 
   bool IsMailEditor() const
   {
     return (mFlags & nsIPlaintextEditor::eEditorMailMask) != 0;
   }
 
-  bool UseAsyncUpdate() const
-  {
-    return (mFlags & nsIPlaintextEditor::eEditorUseAsyncUpdatesMask) != 0;
-  }
-
   bool IsWrapHackEnabled() const
   {
     return (mFlags & nsIPlaintextEditor::eEditorEnableWrapHackMask) != 0;
   }
 
   bool IsFormWidget() const
   {
     return (mFlags & nsIPlaintextEditor::eEditorWidgetMask) != 0;
@@ -763,17 +758,16 @@ public:
 
 protected:
 
   PRUint32        mModCount;     // number of modifications (for undo/redo stack)
   PRUint32        mFlags;        // behavior flags. See nsIPlaintextEditor.idl for the flags we use.
 
   nsWeakPtr       mSelConWeak;   // weak reference to the nsISelectionController
   PRInt32         mUpdateCount;
-  nsIViewManager::UpdateViewBatch mBatch;
 
   // Spellchecking
   enum Tristate {
     eTriUnset,
     eTriFalse,
     eTriTrue
   }                 mSpellcheckCheckboxState;
   nsCOMPtr<nsIInlineSpellChecker> mInlineSpellChecker;
--- a/editor/libeditor/base/tests/test_selection_move_commands.xul
+++ b/editor/libeditor/base/tests/test_selection_move_commands.xul
@@ -27,22 +27,26 @@ function execTests() {
   var root = doc.documentElement;
   var body = doc.body;
 
   body.style.fontSize='16px';
   body.style.lineHeight='16px';
   body.style.height='400px';
   body.style.padding='0px';
   body.style.margin='0px';
-  body.style.borderSize='0px';
+  body.style.borderWidth='0px';
 
   var sel = win.getSelection();
   doc.designMode='on';
   body.innerHTML = "1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>10<br>11<br>12<br>";
   win.focus();
+  // Flush out layout to make sure that the subdocument will be the size we
+  // expect by the time we try to scroll it.
+  is(body.getBoundingClientRect().height, 400,
+     "Body height should be what we set it to");
   yield;
 
   function doCommand(cmd) {
     var controller = document.commandDispatcher.getControllerForCommand(cmd);
     if (controller) {
       controller.doCommand(cmd);
     }
   }
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-private.hh
@@ -371,19 +371,19 @@ struct Ligature
     if (first_was_mark && found_non_mark)
       c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
 
     /* Allocate new ligature id */
     unsigned int lig_id = allocate_lig_id (c->buffer);
     c->buffer->info[c->buffer->i].lig_comp() = 0;
     c->buffer->info[c->buffer->i].lig_id() = lig_id;
 
-    if (j == c->buffer->i + i) /* No input glyphs skipped */
+    if (j < c->buffer->i + count) /* No input glyphs skipped */
     {
-      c->replace_glyphs_be16 (i, 1, (const uint16_t *) &ligGlyph);
+      c->replace_glyphs_be16 (count, 1, (const uint16_t *) &ligGlyph);
     }
     else
     {
       c->replace_glyph (ligGlyph);
 
       /* Now we must do a second loop to copy the skipped glyphs to
 	 `out' and assign component values to it.  We start with the
 	 glyph after the first component.  Glyphs between component
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -2980,24 +2980,24 @@ protected:
 };
 
 void
 BasicShadowImageLayer::Swap(const SharedImage& aNewFront,
                             SharedImage* aNewBack)
 {
   nsRefPtr<gfxASurface> surface =
     BasicManager()->OpenDescriptor(aNewFront);
-  // Destroy mFrontBuffer if size different
-  bool needDrop = false;
+  // Destroy mFrontBuffer if size different or image type is different
+  bool surfaceConfigChanged = surface->GetSize() != mSize;
   if (IsSurfaceDescriptorValid(mFrontBuffer)) {
     nsRefPtr<gfxASurface> front = BasicManager()->OpenDescriptor(mFrontBuffer);
-    needDrop = surface->GetSize() != mSize ||
-               surface->GetContentType() != front->GetContentType();
+    surfaceConfigChanged = surfaceConfigChanged ||
+                           surface->GetContentType() != front->GetContentType();
   }
-  if (needDrop) {
+  if (surfaceConfigChanged) {
     DestroyFrontBuffer();
     mSize = surface->GetSize();
   }
 
   // If mFrontBuffer
   if (IsSurfaceDescriptorValid(mFrontBuffer)) {
     *aNewBack = mFrontBuffer;
   } else {
@@ -3102,23 +3102,23 @@ BasicShadowCanvasLayer::Initialize(const
 void
 BasicShadowCanvasLayer::Swap(const CanvasSurface& aNewFront, bool needYFlip,
                              CanvasSurface* aNewBack)
 {
   nsRefPtr<gfxASurface> surface =
     BasicManager()->OpenDescriptor(aNewFront);
   // Destroy mFrontBuffer if size different
   gfxIntSize sz = surface->GetSize();
-  bool needDrop = false;
+  bool surfaceConfigChanged = sz != gfxIntSize(mBounds.width, mBounds.height);
   if (IsSurfaceDescriptorValid(mFrontSurface)) {
     nsRefPtr<gfxASurface> front = BasicManager()->OpenDescriptor(mFrontSurface);
-    needDrop = sz != gfxIntSize(mBounds.width, mBounds.height) ||
-               surface->GetContentType() != front->GetContentType();
+    surfaceConfigChanged = surfaceConfigChanged ||
+                           surface->GetContentType() != front->GetContentType();
   }
-  if (needDrop) {
+  if (surfaceConfigChanged) {
     DestroyFrontBuffer();
     mBounds.SetRect(0, 0, sz.width, sz.height);
   }
 
   mNeedsYFlip = needYFlip;
   // If mFrontBuffer
   if (IsSurfaceDescriptorValid(mFrontSurface)) {
     *aNewBack = mFrontSurface;
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -3372,19 +3372,23 @@ void gfxFontGroup::ComputeRanges(nsTArra
 {
     aRanges.Clear();
 
     if (aLength == 0) {
         return;
     }
 
     PRUint32 prevCh = 0;
-    gfxFont *prevFont = nsnull;
     PRUint8 matchType = 0;
 
+    // initialize prevFont to the group's primary font, so that this will be
+    // used for string-initial control chars, etc rather than risk hitting font
+    // fallback for these (bug 716229)
+    gfxFont *prevFont = GetFontAt(0);
+
     for (PRUint32 i = 0; i < aLength; i++) {
 
         const PRUint32 origI = i; // save off in case we increase for surrogate
 
         // set up current ch
         PRUint32 ch = aString[i];
 
         // in 16-bit case only, check for surrogate pair
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -648,17 +648,17 @@ class Value
         JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
         JS_STATIC_ASSERT(sizeof(JSBool) == 4);
         JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
         JS_STATIC_ASSERT(sizeof(Value) == 8);
     }
 
     friend jsval_layout (::JSVAL_TO_IMPL)(Value);
     friend Value (::IMPL_TO_JSVAL)(jsval_layout l);
-} JSVAL_ALIGNMENT;
+};
 
 inline bool
 IsPoisonedValue(const Value &v)
 {
     if (v.isString())
         return IsPoisonedPtr(v.toString());
     if (v.isObject())
         return IsPoisonedPtr(&v.toObject());
@@ -1153,16 +1153,21 @@ JSVAL_TO_IMPL(jsval v)
 static JS_ALWAYS_INLINE jsval
 IMPL_TO_JSVAL(jsval_layout l)
 {
     JS::Value v;
     v.data = l;
     return v;
 }
 
+#ifdef DEBUG
+struct JSValueAlignmentTester { char c; JS::Value v; };
+JS_STATIC_ASSERT(sizeof(JSValueAlignmentTester) == 16);
+#endif /* DEBUG */
+
 #else  /* defined(__cplusplus) */
 
 /*
  * For SpiderMonkey C clients, there is no JS::Value class, only the
  * traditional jsval with the traditional JSVAL_* operations. Since
  * SpiderMonkey itself is always compiled as C++, this relies on the binary
  * compatibility of jsval_layout and JS::Value (statically asserted below).
  */
@@ -1177,16 +1182,21 @@ JSVAL_TO_IMPL(jsval v)
 static JS_ALWAYS_INLINE jsval
 IMPL_TO_JSVAL(jsval_layout l)
 {
     return l;
 }
 
 #endif  /* defined(__cplusplus) */
 
+#ifdef DEBUG
+typedef struct { char c; jsval_layout l; } JSLayoutAlignmentTester;
+JS_STATIC_ASSERT(sizeof(JSLayoutAlignmentTester) == 16);
+#endif /* DEBUG */
+
 JS_STATIC_ASSERT(sizeof(jsval_layout) == sizeof(jsval));
 
 /************************************************************************/
 
 /* JSClass operation signatures. */
 
 /*
  * Add, delete, or get a property named by id in obj.  Note the jsid id
--- a/js/src/jsval.h
+++ b/js/src/jsval.h
@@ -305,17 +305,17 @@ typedef union jsval_layout
             void           *ptr;
             JSWhyMagic     why;
             size_t         word;
         } payload;
         JSValueTag tag;
     } s;
     double asDouble;
     void *asPtr;
-} jsval_layout;
+} JSVAL_ALIGNMENT jsval_layout;
 # elif JS_BITS_PER_WORD == 64
 typedef union jsval_layout
 {
     uint64_t asBits;
 #if (!defined(_WIN64) && defined(__cplusplus))
     /* MSVC does not pack these correctly :-( */
     struct {
         uint64_t           payload47 : 47;
@@ -327,17 +327,17 @@ typedef union jsval_layout
             int32_t        i32;
             uint32_t       u32;
             JSWhyMagic     why;
         } payload;
     } s;
     double asDouble;
     void *asPtr;
     size_t asWord;
-} jsval_layout;
+} JSVAL_ALIGNMENT jsval_layout;
 # endif  /* JS_BITS_PER_WORD */
 #else   /* defined(IS_LITTLE_ENDIAN) */
 # if JS_BITS_PER_WORD == 32
 typedef union jsval_layout
 {
     uint64_t asBits;
     struct {
         JSValueTag tag;
@@ -349,17 +349,17 @@ typedef union jsval_layout
             JSObject       *obj;
             void           *ptr;
             JSWhyMagic     why;
             size_t         word;
         } payload;
     } s;
     double asDouble;
     void *asPtr;
-} jsval_layout;
+} JSVAL_ALIGNMENT jsval_layout;
 # elif JS_BITS_PER_WORD == 64
 typedef union jsval_layout
 {
     uint64_t asBits;
     struct {
         JSValueTag         tag : 17;
         uint64_t           payload47 : 47;
     } debugView;
@@ -369,17 +369,17 @@ typedef union jsval_layout
             int32_t        i32;
             uint32_t       u32;
             JSWhyMagic     why;
         } payload;
     } s;
     double asDouble;
     void *asPtr;
     size_t asWord;
-} jsval_layout;
+} JSVAL_ALIGNMENT jsval_layout;
 # endif /* JS_BITS_PER_WORD */
 #endif  /* defined(IS_LITTLE_ENDIAN) */
 
 JS_STATIC_ASSERT(sizeof(jsval_layout) == 8);
 
 #if JS_BITS_PER_WORD == 32
 
 /*
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -44,33 +44,34 @@
 
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 #include "nsBaseHashtable.h"
 #include "nsHashKeys.h"
 #include "jsatom.h"
 #include "jsfriendapi.h"
 #include "jsgc.h"
-#include "nsThreadUtilsInternal.h"
 #include "dom_quickstubs.h"
 #include "nsNullPrincipal.h"
 #include "nsIURI.h"
 #include "nsJSEnvironment.h"
+#include "nsThreadUtils.h"
 
 #include "XrayWrapper.h"
 #include "WrapperFactory.h"
 #include "AccessCheck.h"
 
 #include "jsdIDebuggerService.h"
 
 #include "XPCQuickStubs.h"
 #include "dombindings.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Base64.h"
+#include "mozilla/Util.h"
 
 #include "nsWrapperCacheInlines.h"
 
 NS_IMPL_THREADSAFE_ISUPPORTS7(nsXPConnect,
                               nsIXPConnect,
                               nsISupportsWeakReference,
                               nsIThreadObserver,
                               nsIJSRuntimeService,
@@ -100,16 +101,17 @@ const char XPC_XPCONNECT_CONTRACTID[]   
 
 nsXPConnect::nsXPConnect()
     :   mRuntime(nsnull),
         mInterfaceInfoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)),
         mDefaultSecurityManager(nsnull),
         mDefaultSecurityManagerFlags(0),
         mShuttingDown(false),
         mNeedGCBeforeCC(true),
+        mEventDepth(0),
         mCycleCollectionContext(nsnull)
 {
     mRuntime = XPCJSRuntime::newXPCJSRuntime(this);
 
     nsCycleCollector_registerRuntime(nsIProgrammingLanguage::JAVASCRIPT, this);
 #ifdef DEBUG_CC
     mJSRoots.ops = nsnull;
 #endif
@@ -159,16 +161,22 @@ nsXPConnect::~nsXPConnect()
     gSelf = nsnull;
     gOnceAliveNowDead = true;
 }
 
 // static
 nsXPConnect*
 nsXPConnect::GetXPConnect()
 {
+    // Do a release-mode assert that we're not doing anything significant in
+    // XPConnect off the main thread. If you're an extension developer hitting
+    // this, you need to change your code. See bug 716167.
+    if (!NS_LIKELY(NS_IsMainThread() || NS_IsCycleCollectorThread()))
+        JS_Assert("NS_IsMainThread()", __FILE__, __LINE__);
+
     if (!gSelf) {
         if (gOnceAliveNowDead)
             return nsnull;
         gSelf = new nsXPConnect();
         if (!gSelf)
             return nsnull;
 
         if (!gSelf->mRuntime) {
@@ -176,17 +184,24 @@ nsXPConnect::GetXPConnect()
         }
         if (!gSelf->mInterfaceInfoManager) {
             NS_RUNTIMEABORT("Couldn't get global interface info manager.");
         }
 
         // Initial extra ref to keep the singleton alive
         // balanced by explicit call to ReleaseXPConnectSingleton()
         NS_ADDREF(gSelf);
-        if (NS_FAILED(NS_SetGlobalThreadObserver(gSelf))) {
+
+        // Add XPConnect as an thread observer.
+        //
+        // The cycle collector sometimes calls GetXPConnect, but it should never
+        // be the one that initializes gSelf.
+        MOZ_ASSERT(NS_IsMainThread());
+        nsCOMPtr<nsIThreadInternal> thread = do_QueryInterface(NS_GetCurrentThread());
+        if (NS_FAILED(thread->AddObserver(gSelf))) {
             NS_RELEASE(gSelf);
             // Fall through to returning null
         }
     }
     return gSelf;
 }
 
 // static
@@ -199,17 +214,24 @@ nsXPConnect::GetSingleton()
 }
 
 // static
 void
 nsXPConnect::ReleaseXPConnectSingleton()
 {
     nsXPConnect* xpc = gSelf;
     if (xpc) {
-        NS_SetGlobalThreadObserver(nsnull);
+
+        // The thread subsystem may have been shut down already, so make sure
+        // to check for null here.
+        nsCOMPtr<nsIThreadInternal> thread = do_QueryInterface(NS_GetCurrentThread());
+        if (thread) {
+            MOZ_ASSERT(NS_IsMainThread());
+            thread->RemoveObserver(xpc);
+        }
 
 #ifdef DEBUG
         // force a dump of the JavaScript gc heap if JS is still alive
         // if requested through XPC_SHUTDOWN_HEAP_DUMP environment variable
         {
             // autoscope
             XPCCallContext ccx(NATIVE_CALLER);
             if (ccx.IsValid()) {
@@ -2340,29 +2362,37 @@ nsXPConnect::JSToVariant(JSContext* ctx,
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPConnect::OnProcessNextEvent(nsIThreadInternal *aThread, bool aMayWait,
                                 PRUint32 aRecursionDepth)
 {
+    // Record this event.
+    mEventDepth++;
+
     // Push a null JSContext so that we don't see any script during
     // event processing.
+    MOZ_ASSERT(NS_IsMainThread());
     return Push(nsnull);
 }
 
 NS_IMETHODIMP
 nsXPConnect::AfterProcessNextEvent(nsIThreadInternal *aThread,
                                    PRUint32 aRecursionDepth)
 {
+    // Watch out for unpaired events during observer registration.
+    if (NS_UNLIKELY(mEventDepth == 0))
+        return NS_OK;
+    mEventDepth--;
+
     // Call cycle collector occasionally.
-    if (NS_IsMainThread()) {
-        nsJSContext::MaybePokeCC();
-    }
+    MOZ_ASSERT(NS_IsMainThread());
+    nsJSContext::MaybePokeCC();
 
     return Pop(nsnull);
 }
 
 NS_IMETHODIMP
 nsXPConnect::OnDispatchedEvent(nsIThreadInternal* aThread)
 {
     NS_NOTREACHED("Why tell us?");
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -592,16 +592,23 @@ private:
     static JSBool            gOnceAliveNowDead;
 
     XPCJSRuntime*            mRuntime;
     nsCOMPtr<nsIInterfaceInfoSuperManager> mInterfaceInfoManager;
     nsIXPCSecurityManager*   mDefaultSecurityManager;
     PRUint16                 mDefaultSecurityManagerFlags;
     JSBool                   mShuttingDown;
     JSBool                   mNeedGCBeforeCC;
+
+    // nsIThreadInternal doesn't remember which observers it called
+    // OnProcessNextEvent on when it gets around to calling AfterProcessNextEvent.
+    // So if XPConnect gets initialized mid-event (which can happen), we'll get
+    // an 'after' notification without getting an 'on' notification. If we don't
+    // watch out for this, we'll do an unmatched |pop| on the context stack.
+    PRUint16                   mEventDepth;
 #ifdef DEBUG_CC
     PLDHashTable             mJSRoots;
 #endif
     nsAutoPtr<XPCCallContext> mCycleCollectionContext;
 
     typedef nsBaseHashtable<nsVoidPtrHashKey, nsISupports*, nsISupports*> ScopeSet;
     ScopeSet mScopes;
     nsCOMPtr<nsIXPCScriptable> mBackstagePass;
@@ -3639,16 +3646,22 @@ private:
 class XPCPerThreadData
 {
     typedef mozilla::Mutex Mutex;
 
 public:
     // Get the instance of this object for the current thread
     static inline XPCPerThreadData* GetData(JSContext *cx)
     {
+        // Do a release-mode assert that we're not doing anything significant in
+        // XPConnect off the main thread. If you're an extension developer hitting
+        // this, you need to change your code. See bug 716167.
+        if (!NS_LIKELY(NS_IsMainThread() || NS_IsCycleCollectorThread()))
+            JS_Assert("NS_IsMainThread()", __FILE__, __LINE__);
+
         if (cx) {
             NS_ASSERTION(js::GetContextThread(cx), "Uh, JS context w/o a thread?");
 
             if (js::GetContextThread(cx) == sMainJSThread)
                 return sMainThreadData;
         } else if (sMainThreadData && sMainThreadData->mThread == PR_GetCurrentThread()) {
             return sMainThreadData;
         }
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7630,26 +7630,25 @@ nsCSSFrameConstructor::ContentRemoved(ns
 #ifdef DEBUG
   // To ensure that the functions below are only called within
   // |ApplyRenderingChangeToTree|.
 static bool gInApplyRenderingChangeToTree = false;
 #endif
 
 static void
 DoApplyRenderingChangeToTree(nsIFrame* aFrame,
-                             nsIViewManager* aViewManager,
                              nsFrameManager* aFrameManager,
                              nsChangeHint aChange);
 
 /**
  * @param aBoundsRect returns the bounds enclosing the areas covered by aFrame and its childre
  * This rect is relative to aFrame's parent
  */
 static void
-UpdateViewsForTree(nsIFrame* aFrame, nsIViewManager* aViewManager,
+UpdateViewsForTree(nsIFrame* aFrame,
                    nsFrameManager* aFrameManager,
                    nsChangeHint aChange)
 {
   NS_PRECONDITION(gInApplyRenderingChangeToTree,
                   "should only be called within ApplyRenderingChangeToTree");
 
   nsIView* view = aFrame->GetView();
   if (view) {
@@ -7666,50 +7665,49 @@ UpdateViewsForTree(nsIFrame* aFrame, nsI
       nsIFrame* child = childFrames.get();
       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
         // only do frames that don't have placeholders
         if (nsGkAtoms::placeholderFrame == child->GetType()) {
           // do the out-of-flow frame and its continuations
           nsIFrame* outOfFlowFrame =
             nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
           do {
-            DoApplyRenderingChangeToTree(outOfFlowFrame, aViewManager,
-                                         aFrameManager, aChange);
+            DoApplyRenderingChangeToTree(outOfFlowFrame, aFrameManager,
+                                         aChange);
           } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
         } else if (lists.CurrentID() == nsIFrame::kPopupList) {
-          DoApplyRenderingChangeToTree(child, aViewManager,
-                                       aFrameManager, aChange);
+          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, aViewManager, aFrameManager, aChange);
+          UpdateViewsForTree(child, aFrameManager, aChange);
         }
       }
     }
   }
 }
 
 static void
 DoApplyRenderingChangeToTree(nsIFrame* aFrame,
-                             nsIViewManager* aViewManager,
                              nsFrameManager* aFrameManager,
                              nsChangeHint aChange)
 {
   NS_PRECONDITION(gInApplyRenderingChangeToTree,
                   "should only be called within ApplyRenderingChangeToTree");
 
   for ( ; aFrame; aFrame = nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame)) {
     // Get view if this frame has one and trigger an update. If the
     // frame doesn't have a view, find the nearest containing view
     // (adjusting r's coordinate system to reflect the nesting) and
     // update there.
-    UpdateViewsForTree(aFrame, aViewManager, aFrameManager, aChange);
+    UpdateViewsForTree(aFrame, aFrameManager, aChange);
 
     // if frame has view, will already be invalidated
     if (aChange & nsChangeHint_RepaintFrame) {
       if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
         if (!(aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
           nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(aFrame);
           if (outerSVGFrame) {
             // We need this to invalidate frames when their 'filter' or 'marker'
@@ -7762,35 +7760,28 @@ ApplyRenderingChangeToTree(nsPresContext
   // If the frame's background is propagated to an ancestor, walk up to
   // that ancestor.
   nsStyleContext *bgSC;
   while (!nsCSSRendering::FindBackground(aPresContext, aFrame, &bgSC)) {
     aFrame = aFrame->GetParent();
     NS_ASSERTION(aFrame, "root frame must paint");
   }
 
-  nsIViewManager* viewManager = shell->GetViewManager();
-
   // Trigger rendering updates by damaging this frame and any
   // continuations of this frame.
 
   // XXX this needs to detect the need for a view due to an opacity change and deal with it...
 
-  nsIViewManager::UpdateViewBatch batch(viewManager);
-
 #ifdef DEBUG
   gInApplyRenderingChangeToTree = true;
 #endif
-  DoApplyRenderingChangeToTree(aFrame, viewManager, shell->FrameManager(),
-                               aChange);
+  DoApplyRenderingChangeToTree(aFrame, shell->FrameManager(), aChange);
 #ifdef DEBUG
   gInApplyRenderingChangeToTree = false;
 #endif
-  
-  batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
 }
 
 /**
  * This method invalidates the canvas when frames are removed or added for a
  * node that might have its background propagated to the canvas, i.e., a
  * document root node or an HTML BODY which is a child of the root node.
  *
  * @param aFrame a frame for a content node about to be removed or a frame that
@@ -7821,23 +7812,18 @@ InvalidateCanvasIfNeeded(nsIPresShell* p
     }
   }
 
   // At this point the node has no parent or it's an HTML <body> child of the
   // root.  We might not need to invalidate in this case (eg we might be in
   // XHTML or something), but chances are we want to.  Play it safe.
   // Invalidate the viewport.
 
-  // Wrap this in a DEFERRED view update batch so we don't try to
-  // flush out layout here
-
-  nsIViewManager::UpdateViewBatch batch(presShell->GetViewManager());
   nsIFrame* rootFrame = presShell->GetRootFrame();
   rootFrame->InvalidateFrameSubtree();
-  batch.EndUpdateViewBatch(NS_VMREFRESH_DEFERRED);
 }
 
 nsresult
 nsCSSFrameConstructor::StyleChangeReflow(nsIFrame* aFrame,
                                          nsChangeHint aHint)
 {
   // If the frame hasn't even received an initial reflow, then don't
   // send it a style-change reflow!
@@ -11594,33 +11580,32 @@ nsCSSFrameConstructor::RebuildAllStyleDa
   mRebuildAllStyleData = false;
   NS_UpdateHint(aExtraHint, mRebuildAllExtraHint);
   mRebuildAllExtraHint = nsChangeHint(0);
 
   if (!mPresShell || !mPresShell->GetRootFrame())
     return;
 
   // Make sure that the viewmanager will outlive the presshell
-  nsIViewManager::UpdateViewBatch batch(mPresShell->GetViewManager());
+  nsCOMPtr<nsIViewManager> vm = mPresShell->GetViewManager();
 
   // Processing the style changes could cause a flush that propagates to
   // the parent frame and thus destroys the pres shell.
   nsCOMPtr<nsIPresShell> kungFuDeathGrip(mPresShell);
 
   // We may reconstruct frames below and hence process anything that is in the
   // tree. We don't want to get notified to process those items again after.
   mPresShell->GetDocument()->FlushPendingNotifications(Flush_ContentAndNotify);
 
   nsAutoScriptBlocker scriptBlocker;
 
   // Tell the style set to get the old rule tree out of the way
   // so we can recalculate while maintaining rule tree immutability
   nsresult rv = mPresShell->StyleSet()->BeginReconstruct();
   if (NS_FAILED(rv)) {
-    batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
     return;
   }
 
   nsPresContext *presContext = mPresShell->GetPresContext();
   presContext->SetProcessingRestyles(true);
   // Recalculate all of the style contexts for the document
   // Note that we can ignore the return value of ComputeStyleChangeFor
   // because we never need to reframe the root frame
@@ -11645,17 +11630,16 @@ nsCSSFrameConstructor::RebuildAllStyleDa
   ProcessPendingRestyles();
 
   // Tell the style set it's safe to destroy the old rule tree.  We
   // must do this after the ProcessRestyledFrames call in case the
   // change list has frame reconstructs in it (since frames to be
   // reconstructed will still have their old style context pointers
   // until they are destroyed).
   mPresShell->StyleSet()->EndReconstruct();
-  batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
 }
 
 void
 nsCSSFrameConstructor::ProcessPendingRestyles()
 {
   NS_PRECONDITION(mDocument, "No document?  Pshaw!");
   NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
                   "Missing a script blocker!");
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -1563,19 +1563,18 @@ DocumentViewerImpl::Destroy()
       nsIViewManager *vm = mPresShell->GetViewManager();
       if (vm) {
         nsIView *rootView = vm->GetRootView();
 
         if (rootView) {
           // The invalidate that removing this view causes is dropped because
           // the Freeze call above sets painting to be suppressed for our
           // document. So we do it ourselves and make it happen.
-          vm->UpdateViewNoSuppression(rootView,
-            rootView->GetBounds() - rootView->GetPosition(),
-            NS_VMREFRESH_NO_SYNC);
+          vm->InvalidateViewNoSuppression(rootView,
+            rootView->GetBounds() - rootView->GetPosition());
 
           nsIView *rootViewParent = rootView->GetParent();
           if (rootViewParent) {
             nsIViewManager *parentVM = rootViewParent->GetViewManager();
             if (parentVM) {
               parentVM->RemoveChild(rootView);
             }
           }
@@ -2822,36 +2821,32 @@ NS_IMETHODIMP
 DocumentViewerImpl::SetTextZoom(float aTextZoom)
 {
   if (GetIsPrintPreview()) {
     return NS_OK;
   }
 
   mTextZoom = aTextZoom;
 
-  nsIViewManager::UpdateViewBatch batch(GetViewManager());
-      
   // Set the text zoom on all children of mContainer (even if our zoom didn't
   // change, our children's zoom may be different, though it would be unusual).
   // Do this first, in case kids are auto-sizing and post reflow commands on
   // our presshell (which should be subsumed into our own style change reflow).
   struct ZoomInfo ZoomInfo = { aTextZoom };
   CallChildren(SetChildTextZoom, &ZoomInfo);
 
   // Now change our own zoom
   nsPresContext* pc = GetPresContext();
   if (pc && aTextZoom != mPresContext->TextZoom()) {
       pc->SetTextZoom(aTextZoom);
   }
 
   // And do the external resources
   mDocument->EnumerateExternalResources(SetExtResourceTextZoom, &ZoomInfo);
 
-  batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
-  
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DocumentViewerImpl::GetTextZoom(float* aTextZoom)
 {
   NS_ENSURE_ARG_POINTER(aTextZoom);
   nsPresContext* pc = GetPresContext();
@@ -2863,36 +2858,32 @@ NS_IMETHODIMP
 DocumentViewerImpl::SetMinFontSize(PRInt32 aMinFontSize)
 {
   if (GetIsPrintPreview()) {
     return NS_OK;
   }
 
   mMinFontSize = aMinFontSize;
 
-  nsIViewManager::UpdateViewBatch batch(GetViewManager());
-      
   // Set the min font on all children of mContainer (even if our min font didn't
   // change, our children's min font may be different, though it would be unusual).
   // Do this first, in case kids are auto-sizing and post reflow commands on
   // our presshell (which should be subsumed into our own style change reflow).
   CallChildren(SetChildMinFontSize, NS_INT32_TO_PTR(aMinFontSize));
 
   // Now change our own min font
   nsPresContext* pc = GetPresContext();
   if (pc && aMinFontSize != mPresContext->MinFontSize()) {
     pc->SetMinFontSize(aMinFontSize);
   }
 
   // And do the external resources
   mDocument->EnumerateExternalResources(SetExtResourceMinFontSize,
                                         NS_INT32_TO_PTR(aMinFontSize));
 
-  batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
-  
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DocumentViewerImpl::GetMinFontSize(PRInt32* aMinFontSize)
 {
   NS_ENSURE_ARG_POINTER(aMinFontSize);
   nsPresContext* pc = GetPresContext();
@@ -2905,17 +2896,16 @@ DocumentViewerImpl::SetFullZoom(float aF
 {
 #ifdef NS_PRINT_PREVIEW
   if (GetIsPrintPreview()) {
     nsPresContext* pc = GetPresContext();
     NS_ENSURE_TRUE(pc, NS_OK);
     nsCOMPtr<nsIPresShell> shell = pc->GetPresShell();
     NS_ENSURE_TRUE(shell, NS_OK);
 
-    nsIViewManager::UpdateViewBatch batch(shell->GetViewManager());
     if (!mPrintPreviewZoomed) {
       mOriginalPrintPreviewScale = pc->GetPrintPreviewScale();
       mPrintPreviewZoomed = true;
     }
 
     mPrintPreviewZoom = aFullZoom;
     pc->SetPrintPreviewScale(aFullZoom * mOriginalPrintPreviewScale);
     nsIPageSequenceFrame* pf = shell->GetPageSequenceFrame();
@@ -2924,38 +2914,33 @@ DocumentViewerImpl::SetFullZoom(float aF
       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);
     }
-    batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
     return NS_OK;
   }
 #endif
 
   mPageZoom = aFullZoom;
 
-  nsIViewManager::UpdateViewBatch batch(GetViewManager());
-
   struct ZoomInfo ZoomInfo = { aFullZoom };
   CallChildren(SetChildFullZoom, &ZoomInfo);
 
   nsPresContext* pc = GetPresContext();
   if (pc) {
     pc->SetFullZoom(aFullZoom);
   }
 
   // And do the external resources
   mDocument->EnumerateExternalResources(SetExtResourceFullZoom, &ZoomInfo);
 
-  batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DocumentViewerImpl::GetFullZoom(float* aFullZoom)
 {
   NS_ENSURE_ARG_POINTER(aFullZoom);
 #ifdef NS_PRINT_PREVIEW
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -136,18 +136,18 @@ typedef struct CapturingContentInfo {
   // capture should only be allowed during a mousedown event
   bool mAllowed;
   bool mRetargetToElement;
   bool mPreventDrag;
   nsIContent* mContent;
 } CapturingContentInfo;
 
 #define NS_IPRESSHELL_IID    \
-{ 0x4e23d557, 0x741a, 0x4fd0,\
-  { 0x91, 0x52, 0x34, 0xe2, 0xb4, 0xef, 0xe8, 0x2e } }
+{ 0x3ab5b116, 0x2d73, 0x431c, \
+ { 0x9a, 0x4b, 0x6c, 0x91, 0x9e, 0x42, 0x45, 0xc3 } }
 
 // Constants for ScrollContentIntoView() function
 #define NS_PRESSHELL_SCROLL_TOP      0
 #define NS_PRESSHELL_SCROLL_BOTTOM   100
 #define NS_PRESSHELL_SCROLL_LEFT     0
 #define NS_PRESSHELL_SCROLL_RIGHT    100
 #define NS_PRESSHELL_SCROLL_CENTER   50
 #define NS_PRESSHELL_SCROLL_ANYWHERE -1
@@ -1143,16 +1143,17 @@ public:
                      bool aPaintDefaultBackground, bool aWillSendDidPaint) = 0;
   virtual nsresult HandleEvent(nsIFrame*       aFrame,
                                nsGUIEvent*     aEvent,
                                bool            aDontRetargetEvents,
                                nsEventStatus*  aEventStatus) = 0;
   virtual bool ShouldIgnoreInvalidation() = 0;
   virtual void WillPaint(bool aWillSendDidPaint) = 0;
   virtual void DidPaint() = 0;
+  virtual void ScheduleViewManagerFlush() = 0;
   virtual void ClearMouseCaptureOnView(nsIView* aView) = 0;
   virtual bool IsVisible() = 0;
   virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange) = 0;
 
   /**
    * Refresh observer management.
    */
 protected:
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1076,16 +1076,22 @@ nsPresContext::SetShell(nsIPresShell* aS
     if (mTransitionManager) {
       mTransitionManager->Disconnect();
       mTransitionManager = nsnull;
     }
     if (mAnimationManager) {
       mAnimationManager->Disconnect();
       mAnimationManager = nsnull;
     }
+
+    if (IsRoot()) {
+      // Have to cancel our plugin geometry timer, because the
+      // callback for that depends on a non-null presshell.
+      static_cast<nsRootPresContext*>(this)->CancelUpdatePluginGeometryTimer();
+    }
   }
 }
 
 void
 nsPresContext::DestroyImageLoaders()
 {
   // Destroy image loaders. This is important to do when frames are being
   // destroyed because imageloaders can have pointers to frames and we don't
@@ -2349,16 +2355,17 @@ nsRootPresContext::nsRootPresContext(nsI
   mRegisteredPlugins.Init();
 }
 
 nsRootPresContext::~nsRootPresContext()
 {
   NS_ASSERTION(mRegisteredPlugins.Count() == 0,
                "All plugins should have been unregistered");
   CancelDidPaintTimer();
+  CancelUpdatePluginGeometryTimer();
 }
 
 void
 nsRootPresContext::RegisterPluginForGeometryUpdates(nsObjectFrame* aPlugin)
 {
   mRegisteredPlugins.PutEntry(aPlugin);
 }
 
@@ -2589,16 +2596,19 @@ SortConfigurations(nsTArray<nsIWidget::C
 }
 
 void
 nsRootPresContext::UpdatePluginGeometry()
 {
   if (!mNeedsToUpdatePluginGeometry)
     return;
   mNeedsToUpdatePluginGeometry = false;
+  // Cancel out mUpdatePluginGeometryTimer so it doesn't do a random
+  // update when we don't actually want one.
+  CancelUpdatePluginGeometryTimer();
 
   nsIFrame* f = mUpdatePluginGeometryForFrame;
   if (f) {
     mUpdatePluginGeometryForFrame->PresContext()->
       SetContainsUpdatePluginGeometryFrame(false);
     mUpdatePluginGeometryForFrame = nsnull;
   } else {
     f = FrameManager()->GetRootFrame();
@@ -2610,61 +2620,46 @@ nsRootPresContext::UpdatePluginGeometry(
     return;
   SortConfigurations(&configurations);
   nsIWidget* widget = FrameManager()->GetRootFrame()->GetNearestWidget();
   NS_ASSERTION(widget, "Plugins must have a parent window");
   widget->ConfigureChildren(configurations);
   DidApplyPluginGeometryUpdates();
 }
 
-void
-nsRootPresContext::SynchronousPluginGeometryUpdate()
+static void
+UpdatePluginGeometryCallback(nsITimer *aTimer, void *aClosure)
 {
-  if (!mNeedsToUpdatePluginGeometry) {
-    // Nothing to do
-    return;
-  }
-
-  // Force synchronous paint
-  nsIPresShell* shell = GetPresShell();
-  if (!shell)
-    return;
-  nsIFrame* rootFrame = shell->GetRootFrame();
-  if (!rootFrame)
-    return;
-  nsCOMPtr<nsIWidget> widget = rootFrame->GetNearestWidget();
-  if (!widget)
-    return;
-  // Force synchronous paint of a single pixel, just to force plugin
-  // updates to be flushed. Doing plugin updates during paint is the best
-  // way to ensure that plugin updates are in sync with our content.
-  widget->Invalidate(nsIntRect(0,0,1,1), true);
-
-  // Update plugin geometry just in case that invalidate didn't work
-  // (e.g. if none of the widget is visible, it might not have processed
-  // a paint event). Normally this won't need to do anything.
-  UpdatePluginGeometry();
+  static_cast<nsRootPresContext*>(aClosure)->UpdatePluginGeometry();
 }
 
 void
 nsRootPresContext::RequestUpdatePluginGeometry(nsIFrame* aFrame)
 {
   if (mRegisteredPlugins.Count() == 0)
     return;
 
   if (!mNeedsToUpdatePluginGeometry) {
+    // We'll update the plugin geometry during the next paint in this
+    // presContext (either from nsPresShell::WillPaint or from
+    // nsPresShell::DidPaint, depending on the platform) or on the next
+    // layout flush, whichever comes first.  But we may not have anyone
+    // flush layout, and paints might get optimized away if the old
+    // plugin geometry covers the whole canvas, so set a backup timer to
+    // do this too.  We want to make sure this won't fire before our
+    // normal paint notifications, if those would update the geometry,
+    // so set it for double the refresh driver interval.
+    mUpdatePluginGeometryTimer = do_CreateInstance("@mozilla.org/timer;1");
+    if (mUpdatePluginGeometryTimer) {
+      mUpdatePluginGeometryTimer->
+        InitWithFuncCallback(UpdatePluginGeometryCallback, this,
+                             nsRefreshDriver::DefaultInterval() * 2,
+                             nsITimer::TYPE_ONE_SHOT);
+    }
     mNeedsToUpdatePluginGeometry = true;
-
-    // Dispatch a Gecko event to ensure plugin geometry gets updated
-    // XXX this really should be done through the refresh driver, once
-    // all painting happens in the refresh driver
-    nsCOMPtr<nsIRunnable> event =
-      NS_NewRunnableMethod(this, &nsRootPresContext::SynchronousPluginGeometryUpdate);
-    NS_DispatchToMainThread(event);
-
     mUpdatePluginGeometryForFrame = aFrame;
     mUpdatePluginGeometryForFrame->PresContext()->
       SetContainsUpdatePluginGeometryFrame(true);
   } else {
     if (!mUpdatePluginGeometryForFrame ||
         aFrame == mUpdatePluginGeometryForFrame)
       return;
     mUpdatePluginGeometryForFrame->PresContext()->
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -1265,24 +1265,16 @@ public:
    * in case the nsObjectFrames have work to do after the widgets
    * have been updated.
    */
   void DidApplyPluginGeometryUpdates();
 
   virtual bool IsRoot() { return true; }
 
   /**
-   * This method is called off an event to force the plugin geometry to
-   * be updated. First we try to paint, since updating plugin geometry
-   * during paint is best for keeping plugins in sync with content.
-   * But we also force geometry updates in case painting doesn't work.
-   */
-  void SynchronousPluginGeometryUpdate();
-
-  /**
    * Call this after reflow and scrolling to ensure that the geometry
    * of any windowed plugins is updated. aFrame is the root of the
    * frame subtree whose geometry has changed.
    */
   void RequestUpdatePluginGeometry(nsIFrame* aFrame);
 
   /**
    * Call this when a frame is being destroyed and
@@ -1344,17 +1336,27 @@ protected:
       if (mPresContext) {
         mPresContext->FlushWillPaintObservers();
       }
       return NS_OK;
     }
     nsRootPresContext* mPresContext;
   };
 
+  friend class nsPresContext;
+  void CancelUpdatePluginGeometryTimer()
+  {
+    if (mUpdatePluginGeometryTimer) {
+      mUpdatePluginGeometryTimer->Cancel();
+      mUpdatePluginGeometryTimer = nsnull;
+    }
+  }
+
   nsCOMPtr<nsITimer> mNotifyDidPaintTimer;
+  nsCOMPtr<nsITimer> mUpdatePluginGeometryTimer;
   nsTHashtable<nsPtrHashKey<nsObjectFrame> > mRegisteredPlugins;
   // if mNeedsToUpdatePluginGeometry is set, then this is the frame to
   // use as the root of the subtree to search for plugin updates, or
   // null to use the root frame of this prescontext
   nsTArray<nsCOMPtr<nsIRunnable> > mWillPaintObservers;
   nsRevocableEventPtr<RunWillPaintObservers> mWillPaintFallbackEvent;
   nsIFrame* mUpdatePluginGeometryForFrame;
   PRUint32 mDOMGeneration;
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1248,16 +1248,18 @@ PresShell::Destroy()
       mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
     }
   }
 
   // Revoke any pending events.  We need to do this and cancel pending reflows
   // before we destroy the frame manager, since apparently frame destruction
   // sometimes spins the event queue when plug-ins are involved(!).
   rd->RemoveLayoutFlushObserver(this);
+  rd->RevokeViewManagerFlush();
+
   mResizeEvent.Revoke();
   if (mAsyncResizeTimerIsActive) {
     mAsyncResizeEventTimer->Cancel();
     mAsyncResizeTimerIsActive = false;
   }
 
   CancelAllPendingReflows();
   CancelPostedReflowCallbacks();
@@ -2108,18 +2110,16 @@ PresShell::ResizeReflowIgnoreOverride(ns
 
   // There isn't anything useful we can do if the initial reflow hasn't happened
   rootFrame = FrameManager()->GetRootFrame();
   if (!rootFrame)
     return NS_OK;
 
   if (!GetPresContext()->SupressingResizeReflow())
   {
-    nsIViewManager::UpdateViewBatch batch(mViewManager);
-
     // Have to make sure that the content notifications are flushed before we
     // start messing with the frame model; otherwise we can get content doubling.
     mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
 
     // Make sure style is up to date
     {
       nsAutoScriptBlocker scriptBlocker;
       mFrameConstructor->CreateNeededFrames();
@@ -2132,25 +2132,24 @@ PresShell::ResizeReflowIgnoreOverride(ns
       // the way don't have region accumulation issues?
 
       {
         nsAutoCauseReflowNotifier crNotifier(this);
         WillDoReflow();
 
         // Kick off a top-down reflow
         AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
+        nsIViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
 
         mDirtyRoots.RemoveElement(rootFrame);
         DoReflow(rootFrame, true);
       }
 
       DidDoReflow(true);
     }
-
-    batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
   }
 
   rootFrame = FrameManager()->GetRootFrame();
   if (aHeight == NS_UNCONSTRAINEDSIZE && rootFrame) {
     mPresContext->SetVisibleArea(
       nsRect(0, 0, aWidth, rootFrame->GetRect().height));
   }
 
@@ -2463,50 +2462,29 @@ PresShell::ScrollLine(bool aForward)
   nsIScrollableFrame* scrollFrame =
     GetFrameToScrollAsScrollable(nsIPresShell::eVertical);
   if (scrollFrame) {
     // Scroll 2 lines at a time to improve scrolling speed.
     PRInt32 lineCount = 2;
     scrollFrame->ScrollBy(nsIntPoint(0, aForward ? lineCount : -lineCount),
                           nsIScrollableFrame::LINES,
                           nsIScrollableFrame::SMOOTH);
-      
-//NEW FOR LINES    
-    // force the update to happen now, otherwise multiple scrolls can
-    // occur before the update is processed. (bug #7354)
-
-  // I'd use Composite here, but it doesn't always work.
-    // vm->Composite();
-    nsIViewManager* viewManager = GetViewManager();
-    if (viewManager) {
-      viewManager->ForceUpdate();
-    }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresShell::ScrollCharacter(bool aRight)
 {
   nsIScrollableFrame* scrollFrame =
     GetFrameToScrollAsScrollable(nsIPresShell::eHorizontal);
   if (scrollFrame) {
     scrollFrame->ScrollBy(nsIntPoint(aRight ? 1 : -1, 0),
                           nsIScrollableFrame::LINES,
                           nsIScrollableFrame::SMOOTH);
-//NEW FOR LINES    
-    // force the update to happen now, otherwise multiple scrolls can
-    // occur before the update is processed. (bug #7354)
-
-  // I'd use Composite here, but it doesn't always work.
-    // vm->Composite();
-    nsIViewManager* viewManager = GetViewManager();
-    if (viewManager) {
-      viewManager->ForceUpdate();
-    }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresShell::CompleteScroll(bool aForward)
 {
   nsIScrollableFrame* scrollFrame =
@@ -2974,33 +2952,31 @@ PresShell::RecreateFramesFor(nsIContent*
     // root we will crash.
     return NS_OK;
   }
 
   // Don't call RecreateFramesForContent since that is not exported and we want
   // to keep the number of entrypoints down.
 
   NS_ASSERTION(mViewManager, "Should have view manager");
-  nsIViewManager::UpdateViewBatch batch(mViewManager);
 
   // Have to make sure that the content notifications are flushed before we
   // start messing with the frame model; otherwise we can get content doubling.
   mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
 
   nsAutoScriptBlocker scriptBlocker;
 
   nsStyleChangeList changeList;
   changeList.AppendChange(nsnull, aContent, nsChangeHint_ReconstructFrame);
 
   // Mark ourselves as not safe to flush while we're doing frame construction.
   ++mChangeNestCount;
   nsresult rv = mFrameConstructor->ProcessRestyledFrames(changeList);
   --mChangeNestCount;
   
-  batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
   return rv;
 }
 
 void
 nsIPresShell::PostRecreateFramesFor(Element* aElement)
 {
   FrameConstructor()->PostRestyleEvent(aElement, nsRestyleHint(0),
                                        nsChangeHint_ReconstructFrame);
@@ -3629,16 +3605,28 @@ nsresult PresShell::GetLinkLocation(nsID
     }
   }
 
   // if no link, fail.
   return NS_ERROR_FAILURE;
 }
 
 void
+PresShell::ScheduleViewManagerFlush()
+{
+  nsPresContext* presContext = GetPresContext();
+  if (presContext) {
+    presContext->RefreshDriver()->ScheduleViewManagerFlush();
+  }
+  if (mDocument) {
+    mDocument->SetNeedLayoutFlush();
+  }
+}
+
+void
 PresShell::DispatchSynthMouseMove(nsGUIEvent *aEvent,
                                   bool aFlushOnHoverChange)
 {
   PRUint32 hoverGenerationBefore = mFrameConstructor->GetHoverGeneration();
   nsEventStatus status;
   nsIView* targetView = nsIView::GetViewFor(aEvent->widget);
   targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
   if (aFlushOnHoverChange &&
@@ -3998,35 +3986,30 @@ PresShell::FlushPendingNotifications(moz
   // it's safe to run script.
   bool hasHadScriptObject;
   if (mDocument->GetScriptHandlingObject(hasHadScriptObject) ||
       hasHadScriptObject) {
     isSafeToFlush = isSafeToFlush && nsContentUtils::IsSafeToRunScript();
   }
 
   NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager");
-  // Make sure the view manager stays alive while batching view updates.
+  // Make sure the view manager stays alive.
   nsCOMPtr<nsIViewManager> viewManagerDeathGrip = mViewManager;
   if (isSafeToFlush && mViewManager) {
     // Processing pending notifications can kill us, and some callers only
     // hold weak refs when calling FlushPendingNotifications().  :(
     nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
 
     if (mResizeEvent.IsPending()) {
       FireResizeEvent();
       if (mIsDestroying) {
         return;
       }
     }
 
-    // Style reresolves not in conjunction with reflows can't cause
-    // painting or geometry changes, so don't bother with view update
-    // batching if we only have style reresolve
-    nsIViewManager::UpdateViewBatch batch(mViewManager);
-
     // We need to make sure external resource documents are flushed too (for
     // example, svg filters that reference a filter in an external document
     // need the frames in the external document to be constructed for the
     // filter to work). We only need external resources to be flushed when the
     // main document is flushing >= Flush_Frames, so we flush external
     // resources here instead of nsDocument::FlushPendingNotifications.
     mDocument->FlushExternalResources(aType);
 
@@ -4109,25 +4092,21 @@ PresShell::FlushPendingNotifications(moz
     if (aType >= Flush_Layout) {
       // Flush plugin geometry. Don't flush plugin geometry for
       // interruptible layouts, since WillPaint does an interruptible
       // layout.
       nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
       if (rootPresContext) {
         rootPresContext->UpdatePluginGeometry();
       }
-    }
-
-    PRUint32 updateFlags = NS_VMREFRESH_NO_SYNC;
-    if (aType >= Flush_Display) {
-      // Flushing paints, so perform the invalidates and drawing
-      // immediately
-      updateFlags = NS_VMREFRESH_IMMEDIATE;
-    }
-    batch.EndUpdateViewBatch(updateFlags);
+
+      if (!mIsDestroying) {
+        mViewManager->UpdateWidgetGeometry();
+      }
+    }
   }
 }
 
 void
 PresShell::CharacterDataChanged(nsIDocument *aDocument,
                                 nsIContent*  aContent,
                                 CharacterDataChangeInfo* aInfo)
 {
@@ -7393,17 +7372,17 @@ PresShell::DoReflow(nsIFrame* target, bo
 #ifdef DEBUG
 void
 PresShell::DoVerifyReflow()
 {
   if (GetVerifyReflowEnable()) {
     // First synchronously render what we have so far so that we can
     // see it.
     nsIView* rootView = mViewManager->GetRootView();
-    mViewManager->UpdateView(rootView, NS_VMREFRESH_IMMEDIATE);
+    mViewManager->InvalidateView(rootView);
 
     FlushPendingNotifications(Flush_Layout);
     mInVerifyReflow = true;
     bool ok = VerifyIncrementalReflow();
     mInVerifyReflow = false;
     if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
       printf("ProcessReflowCommands: finished (%s)\n",
              ok ? "ok" : "failed");
@@ -7440,16 +7419,17 @@ PresShell::ProcessReflowCommands(bool aI
         ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime)
         : (PRIntervalTime)0;
 
     // Scope for the reflow entry point
     {
       nsAutoScriptBlocker scriptBlocker;
       WillDoReflow();
       AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
+      nsIViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
 
       do {
         // Send an incremental reflow notification to the target frame.
         PRInt32 idx = mDirtyRoots.Length() - 1;
         nsIFrame *target = mDirtyRoots[idx];
         mDirtyRoots.RemoveElementAt(idx);
 
         if (!NS_SUBTREE_DIRTY(target)) {
@@ -7588,17 +7568,16 @@ PresShell::Observe(nsISupports* aSubject
 {
 #ifdef MOZ_XUL
   if (!nsCRT::strcmp(aTopic, "chrome-flush-skin-caches")) {
     nsIFrame *rootFrame = FrameManager()->GetRootFrame();
     // Need to null-check because "chrome-flush-skin-caches" can happen
     // at interesting times during startup.
     if (rootFrame) {
       NS_ASSERTION(mViewManager, "View manager must exist");
-      nsIViewManager::UpdateViewBatch batch(mViewManager);
 
       nsWeakFrame weakRoot(rootFrame);
       // Have to make sure that the content notifications are flushed before we
       // start messing with the frame model; otherwise we can get content doubling.
       mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
 
       if (weakRoot.IsAlive()) {
         WalkFramesThroughPlaceholders(mPresContext, rootFrame,
@@ -7613,17 +7592,16 @@ PresShell::Observe(nsISupports* aSubject
         // construction.
         {
           nsAutoScriptBlocker scriptBlocker;
           ++mChangeNestCount;
           mFrameConstructor->ProcessRestyledFrames(changeList);
           --mChangeNestCount;
         }
       }
-      batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
     }
     return NS_OK;
   }
 #endif
 
   if (!nsCRT::strcmp(aTopic, "agent-sheet-added") && mStyleSet) {
     AddAgentSheet(aSubject);
     return NS_OK;
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -325,16 +325,17 @@ public:
                                                         nsEvent* aEvent,
                                                         nsEventStatus* aStatus);
   virtual NS_HIDDEN_(nsresult) HandleDOMEventWithTarget(nsIContent* aTargetContent,
                                                         nsIDOMEvent* aEvent,
                                                         nsEventStatus* aStatus);
   virtual bool ShouldIgnoreInvalidation();
   virtual void WillPaint(bool aWillSendDidPaint);
   virtual void DidPaint();
+  virtual void ScheduleViewManagerFlush();
   virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange);
   virtual void ClearMouseCaptureOnView(nsIView* aView);
   virtual bool IsVisible();
 
   // caret handling
   virtual NS_HIDDEN_(already_AddRefed<nsCaret>) GetCaret() const;
   virtual NS_HIDDEN_(void) MaybeInvalidateCaretPosition();
   NS_IMETHOD SetCaretEnabled(bool aInEnable);
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -50,16 +50,17 @@
 #include "nsAutoPtr.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsIDocument.h"
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "jsapi.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
+#include "nsIViewManager.h"
 
 using mozilla::TimeStamp;
 using mozilla::TimeDuration;
 
 using namespace mozilla;
 
 #define DEFAULT_FRAME_RATE 60
 #define DEFAULT_THROTTLED_FRAME_RATE 1
@@ -68,16 +69,23 @@ static bool sPrecisePref;
 
 /* static */ void
 nsRefreshDriver::InitializeStatics()
 {
   Preferences::AddBoolVarCache(&sPrecisePref,
                                "layout.frame_rate.precise",
                                false);
 }
+
+/* static */ PRInt32
+nsRefreshDriver::DefaultInterval()
+{
+  return NSToIntRound(1000.0 / DEFAULT_FRAME_RATE);
+}
+
 // Compute the interval to use for the refresh driver timer, in
 // milliseconds
 PRInt32
 nsRefreshDriver::GetRefreshTimerInterval() const
 {
   const char* prefName =
     mThrottled ? "layout.throttled_frame_rate" : "layout.frame_rate";
   PRInt32 rate = Preferences::GetInt(prefName, -1);
@@ -107,16 +115,17 @@ nsRefreshDriver::GetRefreshTimerType() c
 }
 
 nsRefreshDriver::nsRefreshDriver(nsPresContext *aPresContext)
   : mPresContext(aPresContext),
     mFrozen(false),
     mThrottled(false),
     mTestControllingRefreshes(false),
     mTimerIsPrecise(false),
+    mViewManagerFlushIsPending(false),
     mLastTimerInterval(0)
 {
   mRequests.Init();
 }
 
 nsRefreshDriver::~nsRefreshDriver()
 {
   NS_ABORT_IF_FALSE(ObserverCount() == 0,
@@ -265,16 +274,17 @@ nsRefreshDriver::ObserverCount() const
 
   // Even while throttled, we need to process layout and style changes.  Style
   // changes can trigger transitions which fire events when they complete, and
   // layout changes can affect media queries on child documents, triggering
   // style changes, etc.
   sum += mStyleFlushObservers.Length();
   sum += mLayoutFlushObservers.Length();
   sum += mFrameRequestCallbackDocs.Length();
+  sum += mViewManagerFlushIsPending;
   return sum;
 }
 
 PRUint32
 nsRefreshDriver::ImageRequestCount() const
 {
   return mRequests.Count();
 }
@@ -426,16 +436,21 @@ nsRefreshDriver::Notify(nsITimer *aTimer
    */
 
   ImageRequestParameters parms = {mMostRecentRefresh};
   if (mRequests.Count()) {
     mRequests.EnumerateEntries(nsRefreshDriver::ImageRequestEnumerator, &parms);
     EnsureTimerStarted(false);
   }
 
+  if (mViewManagerFlushIsPending) {
+    mViewManagerFlushIsPending = false;
+    mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates();
+  }
+
   if (mThrottled ||
       (mTimerIsPrecise !=
        (GetRefreshTimerType() == nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP))) {
     // Stop the timer now and restart it here.  Stopping is in the mThrottled
     // case ok because either it's already one-shot, and it just fired, and all
     // we need to do is null it out, or it's repeating and we need to reset it
     // to be one-shot.  Stopping and restarting in the case when we need to
     // switch from precise to slack timers or vice versa is unfortunately
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -172,16 +172,27 @@ public:
   void RemoveLayoutFlushObserver(nsIPresShell* aShell) {
     mLayoutFlushObservers.RemoveElement(aShell);
   }
   bool IsLayoutFlushObserver(nsIPresShell* aShell) {
     return mLayoutFlushObservers.Contains(aShell);
   }
 
   /**
+   * Remember whether our presshell's view manager needs a flush
+   */
+  void ScheduleViewManagerFlush() {
+    mViewManagerFlushIsPending = true;
+    EnsureTimerStarted(false);
+  }
+  void RevokeViewManagerFlush() {
+    mViewManagerFlushIsPending = false;
+  }
+
+  /**
    * Add a document for which we have nsIFrameRequestCallbacks
    */
   void ScheduleFrameRequestCallbacks(nsIDocument* aDocument);
 
   /**
    * Remove a document for which we have nsIFrameRequestCallbacks
    */
   void RevokeFrameRequestCallbacks(nsIDocument* aDocument);
@@ -222,16 +233,21 @@ public:
 #ifdef DEBUG
   /**
    * Check whether the given observer is an observer for the given flush type
    */
   bool IsRefreshObserver(nsARefreshObserver *aObserver,
 			   mozFlushType aFlushType);
 #endif
 
+  /**
+   * Default interval the refresh driver uses, in ms.
+   */
+  static PRInt32 DefaultInterval();
+
 private:
   typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
   typedef nsTHashtable<nsISupportsHashKey> RequestTable;
 
   void EnsureTimerStarted(bool aAdjustingTimer);
   void StopTimer();
 
   PRUint32 ObserverCount() const;
@@ -260,16 +276,17 @@ private:
 
   bool mFrozen;
   bool mThrottled;
   bool mTestControllingRefreshes;
   /* If mTimer is non-null, this boolean indicates whether the timer is
      a precise timer.  If mTimer is null, this boolean's value can be
      anything.  */
   bool mTimerIsPrecise;
+  bool mViewManagerFlushIsPending;
 
   // separate arrays for each flush type we support
   ObserverArray mObservers[3];
   RequestTable mRequests;
 
   nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
   nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
   // nsTArray on purpose, because we want to be able to swap.
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -382,25 +382,16 @@ 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));
-
-  // Make sure the content area gets updated for where the dropdown was
-  // This is only needed for embedding, the focus may go to 
-  // the chrome that is not part of the Gecko system (Bug 83493)
-  // XXX this is rather inefficient
-  nsIViewManager* vm = PresContext()->GetPresShell()->GetViewManager();
-  if (vm) {
-    vm->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
-  }
 }
 
 void
 nsComboboxControlFrame::ShowPopup(bool aShowPopup)
 {
   nsIView* view = mDropdownFrame->GetView();
   nsIViewManager* viewManager = view->GetViewManager();
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4639,41 +4639,34 @@ nsIFrame::InvalidateRoot(const nsRect& a
   if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
       !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
     FrameLayerBuilder::InvalidateThebesLayerContents(this, aDamageRect);
     if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
       return;
     }
   }
 
-  PRUint32 flags =
-    (aFlags & INVALIDATE_IMMEDIATE) ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_NO_SYNC;
-
   nsRect rect = aDamageRect;
   nsRegion* excludeRegion = static_cast<nsRegion*>
     (Properties().Get(DeferInvalidatesProperty()));
-  if (excludeRegion) {
-    flags = NS_VMREFRESH_DEFERRED;
-
-    if (aFlags & INVALIDATE_EXCLUDE_CURRENT_PAINT) {
-      nsRegion r;
-      r.Sub(rect, *excludeRegion);
-      if (r.IsEmpty())
-        return;
-      rect = r.GetBounds();
-    }
+  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()->UpdateViewNoSuppression(view, rect, flags);
+  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));
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -1528,29 +1528,16 @@ nsHTMLFramesetFrame::MouseDrag(nsPresCon
       // Setting the attr will trigger a reflow
       mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::rows, newRowAttr, true);
     }
   }
 
   ENSURE_TRUE(weakFrame.IsAlive());
   if (change != 0) {
     mDrag.Reset(mDragger->mVertical, mDragger->mPrevNeighbor, change, this);
-    nsIFrame* parentFrame = GetParent();
-    if (!parentFrame) {
-      return;
-    }
-
-    // Update the view immediately (make drag appear snappier)
-    nsIViewManager* vm = aPresContext->GetPresShell()->GetViewManager();
-    if (vm) {
-      nsIView* root = vm->GetRootView();
-      if (root) {
-        vm->UpdateView(root, NS_VMREFRESH_IMMEDIATE);
-      }
-    }
   }
 }  
 
 void
 nsHTMLFramesetFrame::EndMouseDrag(nsPresContext* aPresContext)
 {
   nsIPresShell::SetCapturingContent(nsnull, 0);
   mDragger = nsnull;
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -1378,17 +1378,17 @@ void BuildTextRunsScanner::FlushFrames(b
       mNextRunContextInfo = nsTextFrameUtils::INCOMING_NONE;
       if (textRun->GetFlags() & nsTextFrameUtils::TEXT_TRAILING_WHITESPACE) {
         mNextRunContextInfo |= nsTextFrameUtils::INCOMING_WHITESPACE;
       }
       if (textRun->GetFlags() & gfxTextRunFactory::TEXT_TRAILING_ARABICCHAR) {
         mNextRunContextInfo |= nsTextFrameUtils::INCOMING_ARABICCHAR;
       }
     } else {
-      nsAutoTArray<PRUint8,BIG_TEXT_NODE_SIZE> buffer;
+      AutoFallibleTArray<PRUint8,BIG_TEXT_NODE_SIZE> buffer;
       PRUint32 bufferSize = mMaxTextLength*(mDoubleByteText ? 2 : 1);
       if (bufferSize < mMaxTextLength || bufferSize == PR_UINT32_MAX ||
           !buffer.AppendElements(bufferSize)) {
         return;
       }
       textRun = BuildTextRunForFrames(buffer.Elements());
     }
   }
@@ -1820,22 +1820,22 @@ BuildTextRunsScanner::BuildTextRunForFra
       PRUnichar* bufEnd = nsTextFrameUtils::TransformText(
           frag->Get2b() + contentStart, contentLength, bufStart,
           compression, &mNextRunContextInfo, &builder, &analysisFlags);
       aTextBuffer = bufEnd;
     } else {
       if (mDoubleByteText) {
         // Need to expand the text. First transform it into a temporary buffer,
         // then expand.
-        nsAutoTArray<PRUint8,BIG_TEXT_NODE_SIZE> tempBuf;
-        if (!tempBuf.AppendElements(contentLength)) {
+        AutoFallibleTArray<PRUint8,BIG_TEXT_NODE_SIZE> tempBuf;
+        PRUint8* bufStart = tempBuf.AppendElements(contentLength);
+        if (!bufStart) {
           DestroyUserData(userDataToDestroy);
           return nsnull;
         }
-        PRUint8* bufStart = tempBuf.Elements();
         PRUint8* end = nsTextFrameUtils::TransformText(
             reinterpret_cast<const PRUint8*>(frag->Get1b()) + contentStart, contentLength,
             bufStart, compression, &mNextRunContextInfo, &builder, &analysisFlags);
         aTextBuffer = ExpandBuffer(static_cast<PRUnichar*>(aTextBuffer),
                                    tempBuf.Elements(), end - tempBuf.Elements());
       } else {
         PRUint8* bufStart = static_cast<PRUint8*>(aTextBuffer);
         PRUint8* end = nsTextFrameUtils::TransformText(
@@ -2024,21 +2024,23 @@ BuildTextRunsScanner::BuildTextRunForFra
 // context for the line-breaker, when the textrun has already been created.
 // So it does the same walk over the mMappedFlows, but doesn't actually
 // build a new textrun.
 bool
 BuildTextRunsScanner::SetupLineBreakerContext(gfxTextRun *aTextRun)
 {
   AutoFallibleTArray<PRUint8,BIG_TEXT_NODE_SIZE> buffer;
   PRUint32 bufferSize = mMaxTextLength*(mDoubleByteText ? 2 : 1);
-  if (bufferSize < mMaxTextLength || bufferSize == PR_UINT32_MAX ||
-      !buffer.AppendElements(bufferSize)) {
+  if (bufferSize < mMaxTextLength || bufferSize == PR_UINT32_MAX) {
     return false;
   }
-  void *textPtr = buffer.Elements();
+  void *textPtr = buffer.AppendElements(bufferSize);
+  if (!textPtr) {
+    return false;
+  }
 
   gfxSkipCharsBuilder builder;
 
   nsAutoTArray<PRInt32,50> textBreakPoints;
   TextRunUserData dummyData;
   TextRunMappedFlow dummyMappedFlow;
 
   TextRunUserData* userData;
@@ -2101,21 +2103,21 @@ BuildTextRunsScanner::SetupLineBreakerCo
           frag->Get2b() + contentStart, contentLength, bufStart,
           compression, &mNextRunContextInfo, &builder, &analysisFlags);
       textPtr = bufEnd;
     } else {
       if (mDoubleByteText) {
         // Need to expand the text. First transform it into a temporary buffer,
         // then expand.
         AutoFallibleTArray<PRUint8,BIG_TEXT_NODE_SIZE> tempBuf;
-        if (!tempBuf.AppendElements(contentLength)) {
+        PRUint8* bufStart = tempBuf.AppendElements(contentLength);
+        if (!bufStart) {
           DestroyUserData(userDataToDestroy);
           return false;
         }
-        PRUint8* bufStart = tempBuf.Elements();
         PRUint8* end = nsTextFrameUtils::TransformText(
             reinterpret_cast<const PRUint8*>(frag->Get1b()) + contentStart, contentLength,
             bufStart, compression, &mNextRunContextInfo, &builder, &analysisFlags);
         textPtr = ExpandBuffer(static_cast<PRUnichar*>(textPtr),
                                tempBuf.Elements(), end - tempBuf.Elements());
       } else {
         PRUint8* bufStart = static_cast<PRUint8*>(textPtr);
         PRUint8* end = nsTextFrameUtils::TransformText(
@@ -5093,20 +5095,22 @@ nsTextFrame::PaintTextWithSelectionColor
     const gfxRect& aDirtyRect,
     PropertyProvider& aProvider,
     PRUint32 aContentOffset, PRUint32 aContentLength,
     nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails,
     SelectionType* aAllTypes,
     const nsCharClipDisplayItem::ClipEdges& aClipEdges)
 {
   // Figure out which selections control the colors to use for each character.
-  nsAutoTArray<SelectionDetails*,BIG_TEXT_NODE_SIZE> prevailingSelectionsBuffer;
-  if (!prevailingSelectionsBuffer.AppendElements(aContentLength))
+  AutoFallibleTArray<SelectionDetails*,BIG_TEXT_NODE_SIZE> prevailingSelectionsBuffer;
+  SelectionDetails** prevailingSelections =
+    prevailingSelectionsBuffer.AppendElements(aContentLength);
+  if (!prevailingSelections) {
     return false;
-  SelectionDetails** prevailingSelections = prevailingSelectionsBuffer.Elements();
+  }
 
   SelectionType allTypes = 0;
   for (PRUint32 i = 0; i < aContentLength; ++i) {
     prevailingSelections[i] = nsnull;
   }
 
   SelectionDetails *sdptr = aDetails;
   bool anyBackgrounds = false;
@@ -5216,20 +5220,22 @@ nsTextFrame::PaintTextSelectionDecoratio
     nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails,
     SelectionType aSelectionType)
 {
   // Hide text decorations if we're currently hiding @font-face fallback text
   if (aProvider.GetFontGroup()->ShouldSkipDrawing())
     return;
 
   // Figure out which characters will be decorated for this selection.
-  nsAutoTArray<SelectionDetails*, BIG_TEXT_NODE_SIZE> selectedCharsBuffer;
-  if (!selectedCharsBuffer.AppendElements(aContentLength))
+  AutoFallibleTArray<SelectionDetails*, BIG_TEXT_NODE_SIZE> selectedCharsBuffer;
+  SelectionDetails** selectedChars =
+    selectedCharsBuffer.AppendElements(aContentLength);
+  if (!selectedChars) {
     return;
-  SelectionDetails** selectedChars = selectedCharsBuffer.Elements();
+  }
   for (PRUint32 i = 0; i < aContentLength; ++i) {
     selectedChars[i] = nsnull;
   }
 
   SelectionDetails *sdptr = aDetails;
   while (sdptr) {
     if (sdptr->mType == aSelectionType) {
       PRInt32 start = NS_MAX(0, sdptr->mStart - PRInt32(aContentOffset));
@@ -6595,17 +6601,17 @@ nsTextFrame::AddInlineMinWidthForFlow(ns
 
   bool collapseWhitespace = !textStyle->WhiteSpaceIsSignificant();
   bool preformatNewlines = textStyle->NewlineIsSignificant();
   bool preformatTabs = textStyle->WhiteSpaceIsSignificant();
   gfxFloat tabWidth = -1;
   PRUint32 start =
     FindStartAfterSkippingWhitespace(&provider, aData, textStyle, &iter, flowEndInTextRun);
 
-  nsAutoTArray<bool,BIG_TEXT_NODE_SIZE> hyphBuffer;
+  AutoFallibleTArray<bool,BIG_TEXT_NODE_SIZE> hyphBuffer;
   bool *hyphBreakBefore = nsnull;
   if (hyphenating) {
     hyphBreakBefore = hyphBuffer.AppendElements(flowEndInTextRun - start);
     if (hyphBreakBefore) {
       provider.GetHyphenationBreaks(start, flowEndInTextRun - start,
                                     hyphBreakBefore);
     }
   }
--- a/layout/reftests/bugs/542605-hidden-unscrollable-ref.xul
+++ b/layout/reftests/bugs/542605-hidden-unscrollable-ref.xul
@@ -1,8 +1,12 @@
 <?xml version="1.0"?>
 <somenode xmlns:html="http://www.w3.org/1999/xhtml" 
 	style="overflow: -moz-hidden-unscrollable;"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 	<html:input  value="lime"/>
-        <button  label="Credits" accesskey="C"/>
+        <!--
+        pointer-events: none so that our look doesn't depend on
+        mouse position
+        -->
+        <button  label="Credits" accesskey="C" style="pointer-events: none"/>
 </somenode>
 
--- a/layout/reftests/bugs/542605-hidden-unscrollable.xul
+++ b/layout/reftests/bugs/542605-hidden-unscrollable.xul
@@ -5,10 +5,14 @@
 	<!--
 	a clipping problem in the cairo-win32 show-glyphs
 	implementation was causing the text on the button
 	to be clipped out. The clip was null and we weren't
 	reseting the clip causing us to use the clip of the
 	input element. Not using -moz-hidden-unscrollable
 	causes this problem to show up for reasons unknown.
 	-->
-        <button  label="Credits" accesskey="C"/>
+        <!--
+        pointer-events: none so that our look doesn't depend on
+        mouse position
+        -->
+        <button  label="Credits" accesskey="C" style="pointer-events: none"/>
 </somenode>
--- a/layout/reftests/flexbox/flexbox-attributes-no-input-horizontal-ref.xhtml
+++ b/layout/reftests/flexbox/flexbox-attributes-no-input-horizontal-ref.xhtml
@@ -4,16 +4,17 @@
 <title>Test that XUL attributes are not supported on non-XUL elements</title>
 <style type="text/css">
 <![CDATA[
 
 html, body {
   display: -moz-box;
   margin: 0; padding: 0;
   width: 100%; height: 100%;
+  pointer-events: none;
 }
 
 body > div {
   display: -moz-box;
   background: yellow;
   -moz-box-flex: 1;
   -moz-box-orient: horizontal;
 }
--- a/layout/reftests/flexbox/flexbox-attributes-no-input-horizontal.xhtml
+++ b/layout/reftests/flexbox/flexbox-attributes-no-input-horizontal.xhtml
@@ -4,16 +4,18 @@
 <title>Test that XUL attributes are not supported on non-XUL elements</title>
 <style type="text/css">
 <![CDATA[
 
 html, body {
   display: -moz-box;
   margin: 0; padding: 0;
   width: 100%; height: 100%;
+  /* Disable pointer-events so we don't get weird hover artifacts */
+  pointer-events: none;
 }
 
 body > div {
   display: -moz-box;
   background: yellow;
   -moz-box-flex: 1;
   -moz-box-orient: horizontal;
 }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/dynamic-text-07-ref.svg
@@ -0,0 +1,11 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg">
+  <title>Reference to check whitespace handling</title>
+
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=717870 -->
+
+  <text x="10" y="50" font-size="50">A B</text>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/dynamic-text-07.svg
@@ -0,0 +1,23 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" class="reftest-wait" onload="m();">
+  <title>Testcase to check whitespace handling</title>
+
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=717870 -->
+
+  <text id="t" x="10" y="50" font-size="50">A </text>
+  <script>
+    function m()
+    {
+      // Force frame construction
+      document.documentElement.getBoundingClientRect();
+
+      // A dynamic change
+      document.getElementById("t").appendChild(document.createTextNode("B"));
+      
+      document.documentElement.removeAttribute("class");
+    }
+  </script>
+</svg>
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -94,16 +94,17 @@ include svg-integration/reftest.list
 == dynamic-small-object-scaled-up-02.svg pass.svg
 == dynamic-switch-01.svg pass.svg
 == dynamic-text-01.svg dynamic-text-01-ref.svg
 == dynamic-text-02.svg dynamic-text-02-ref.svg
 == dynamic-text-03.svg dynamic-text-03-ref.svg
 fails-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == dynamic-text-04.svg dynamic-text-04-ref.svg # bug 421587 for WinXP
 == dynamic-text-05.svg pass.svg
 == dynamic-text-06.svg pass.svg
+== dynamic-text-07.svg dynamic-text-07-ref.svg
 == dynamic-textPath-01.svg dynamic-textPath-01-ref.svg
 == dynamic-use-01.svg pass.svg
 == dynamic-use-02.svg pass.svg
 == dynamic-use-03.svg pass.svg
 == dynamic-use-04.svg pass.svg
 == dynamic-use-05.svg pass.svg
 random == dynamic-use-nested-01.svg dynamic-use-nested-01-ref.svg # bug 467498
 == dynamic-use-remove-width.svg dynamic-use-remove-width-ref.svg
--- a/layout/svg/base/src/nsSVGGlyphFrame.h
+++ b/layout/svg/base/src/nsSVGGlyphFrame.h
@@ -116,20 +116,26 @@ public:
   void GetEffectiveRotate(PRInt32 strLength,
                           nsTArray<float> &aRotate);
   PRUint16 GetTextAnchor();
   bool IsAbsolutelyPositioned();
   bool IsTextEmpty() const {
     return mContent->GetText()->GetLength() == 0;
   }
   void SetTrimLeadingWhitespace(bool aTrimLeadingWhitespace) {
-    mTrimLeadingWhitespace = aTrimLeadingWhitespace;
+    if (mTrimLeadingWhitespace != aTrimLeadingWhitespace) {
+      mTrimLeadingWhitespace = aTrimLeadingWhitespace;
+      ClearTextRun();
+    }
   }
   void SetTrimTrailingWhitespace(bool aTrimTrailingWhitespace) {
-    mTrimTrailingWhitespace = aTrimTrailingWhitespace;
+    if (mTrimTrailingWhitespace != aTrimTrailingWhitespace) {
+      mTrimTrailingWhitespace = aTrimTrailingWhitespace;
+      ClearTextRun();
+    }
   }
   bool EndsWithWhitespace() const;
   bool IsAllWhitespace() const;
 
   // nsIFrame interface:
   NS_IMETHOD  CharacterDataChanged(CharacterDataChangeInfo* aInfo);
 
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext);
@@ -188,17 +194,20 @@ public:
   // These do not use the global transform if NS_STATE_NONDISPLAY_CHILD
   virtual PRUint32 GetNumberOfChars();
   virtual float GetComputedTextLength();
   virtual float GetSubStringLength(PRUint32 charnum, PRUint32 fragmentChars);
   virtual PRInt32 GetCharNumAtPosition(nsIDOMSVGPoint *point);
   NS_IMETHOD_(nsSVGGlyphFrame *) GetFirstGlyphFrame();
   NS_IMETHOD_(nsSVGGlyphFrame *) GetNextGlyphFrame();
   NS_IMETHOD_(void) SetWhitespaceCompression(bool aCompressWhitespace) {
-    mCompressWhitespace = aCompressWhitespace;
+    if (mCompressWhitespace != aCompressWhitespace) {
+      mCompressWhitespace = aCompressWhitespace;
+      ClearTextRun();
+    }
   }
 
 protected:
   friend class CharacterIterator;
 
   // Use a power of 2 here. It's not so important to match
   // nsDeviceContext::AppUnitsPerDevPixel, but since we do a lot of
   // multiplying by 1/GetTextRunUnitsFactor, it's good for it to be a
--- a/layout/svg/base/src/nsSVGTextFrame.cpp
+++ b/layout/svg/base/src/nsSVGTextFrame.cpp
@@ -293,30 +293,44 @@ nsSVGTextFrame::NotifyGlyphMetricsChange
   UpdateGlyphPositioning(false);
 }
 
 void
 nsSVGTextFrame::SetWhitespaceHandling(nsSVGGlyphFrame *aFrame)
 {
   SetWhitespaceCompression();
 
+  nsSVGGlyphFrame* firstFrame = aFrame;
   bool trimLeadingWhitespace = true;
   nsSVGGlyphFrame* lastNonWhitespaceFrame = aFrame;
 
+  // If the previous frame ended with whitespace
+  // then display of leading whitespace should be suppressed
+  // when we are compressing whitespace.
   while (aFrame) {
     if (!aFrame->IsAllWhitespace()) {
       lastNonWhitespaceFrame = aFrame;
     }
 
     aFrame->SetTrimLeadingWhitespace(trimLeadingWhitespace);
     trimLeadingWhitespace = aFrame->EndsWithWhitespace();
 
     aFrame = aFrame->GetNextGlyphFrame();
   }
 
+  // When there is only whitespace left we need to trim off
+  // the end of the last frame that isn't entirely whitespace.
+  // Making sure that we reset earlier frames as they may once
+  // have been the last non-whitespace frame.
+  aFrame = firstFrame;
+  while (aFrame != lastNonWhitespaceFrame) {
+    aFrame->SetTrimTrailingWhitespace(false);
+    aFrame = aFrame->GetNextGlyphFrame();
+  }
+
   lastNonWhitespaceFrame->SetTrimTrailingWhitespace(true);
 }
 
 void
 nsSVGTextFrame::UpdateGlyphPositioning(bool aForceGlobalTransform)
 {
   if (mMetricsState == suspended || !mPositioningDirty)
     return;
--- a/layout/tools/layout-debug/src/nsLayoutDebuggingTools.cpp
+++ b/layout/tools/layout-debug/src/nsLayoutDebuggingTools.cpp
@@ -557,17 +557,17 @@ nsLayoutDebuggingTools::DumpReflowStats(
 
 void nsLayoutDebuggingTools::ForceRefresh()
 {
     nsCOMPtr<nsIViewManager> vm(view_manager(mDocShell));
     if (!vm)
         return;
     nsIView* root = vm->GetRootView();
     if (root) {
-        vm->UpdateView(root, NS_VMREFRESH_IMMEDIATE);
+        vm->InvalidateView(root);
     }
 }
 
 nsresult
 nsLayoutDebuggingTools::SetBoolPrefAndRefresh(const char * aPrefName,
                                               bool aNewVal)
 {
     NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
--- a/layout/xul/base/src/nsListBoxBodyFrame.cpp
+++ b/layout/xul/base/src/nsListBoxBodyFrame.cpp
@@ -554,25 +554,16 @@ nsListBoxBodyFrame::ScrollByLines(PRInt3
     PRInt32 numRows = GetRowCount();
     PRInt32 lastPageTopRow = numRows - visibleRows;
     if (scrollIndex > lastPageTopRow)
       scrollIndex = lastPageTopRow;
   }
   
   ScrollToIndex(scrollIndex);
 
-  // we have to do a sync update for mac because if we scroll too quickly
-  // w/out going back to the main event loop we can easily scroll the wrong
-  // bits and it looks like garbage (bug 63465).
-  // XXXbz is this seriously still needed?
-    
-  // I'd use Composite here, but it doesn't always work.
-  // vm->Composite();
-  PresContext()->GetPresShell()->GetViewManager()->ForceUpdate();
-
   return NS_OK;
 }
 
 // walks the DOM to get the zero-based row index of the content
 nsresult
 nsListBoxBodyFrame::GetIndexOfItem(nsIDOMElement* aItem, PRInt32* _retval)
 {
   if (aItem) {
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -588,35 +588,44 @@ abstract public class GeckoApp
 
                 ViewportMetrics viewportMetrics = mSoftwareLayerClient.getGeckoViewportMetrics();
                 if (viewportMetrics != null)
                     mLastViewport = viewportMetrics.toJSON();
 
                 mLastUri = lastHistoryEntry.mUri;
                 mLastTitle = lastHistoryEntry.mTitle;
                 Bitmap bitmap = mSoftwareLayerClient.getBitmap();
+
                 if (bitmap != null) {
                     ByteArrayOutputStream bos = new ByteArrayOutputStream();
                     bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
-                    mLastScreen = bos.toByteArray();
-
-                    // Make a thumbnail for the given tab, if it's still selected
-                    // NOTE: bitmap is recycled in updateThumbnail
-                    if (tab == mThumbnailTab) {
-                        if (mThumbnailTab.getURL().equals("about:home"))
-                            mThumbnailTab.updateThumbnail(null);
-                        else
-                            mThumbnailTab.updateThumbnail(bitmap);
-                    }
+                    processThumbnail(tab, bitmap, bos.toByteArray());
                 } else {
                     mLastScreen = null;
+                    GeckoAppShell.sendEventToGecko(
+                        new GeckoEvent("Tab:Screenshot", 
+                                       "{\"width\": \"" + mSoftwareLayerClient.getWidth() + "\", " +
+                                       "\"height\": \"" + mSoftwareLayerClient.getHeight() + "\", " +
+                                       "\"tabID\": \"" + tab.getId() + "\" }"));
                 }
             }
         }
     }
+    
+    void processThumbnail(Tab thumbnailTab, Bitmap bitmap, byte[] compressed) {
+        if (Tabs.getInstance().isSelectedTab(thumbnailTab))
+            mLastScreen = compressed;
+        if (thumbnailTab.getURL().equals("about:home")) {
+            thumbnailTab.updateThumbnail(null);
+            return;
+        }
+        if (bitmap == null)
+            bitmap = BitmapFactory.decodeByteArray(compressed, 0, compressed.length);
+        thumbnailTab.updateThumbnail(bitmap);
+    }
 
     private void maybeCancelFaviconLoad(Tab tab) {
         long faviconLoadId = tab.getFaviconLoadId();
 
         if (faviconLoadId == Favicons.NOT_LOADING)
             return;
 
         // Cancel pending favicon load task
@@ -893,16 +902,20 @@ abstract public class GeckoApp
                 Tab tab = handleAddTab(message);
                 Boolean selected = message.getBoolean("selected");
                 if (selected)
                     handleSelectTab(tab.getId());
             } else if (event.equals("Tab:Closed")) {
                 Log.i(LOGTAG, "Destroyed a tab");
                 int tabId = message.getInt("tabID");
                 handleCloseTab(tabId);
+            } else if (event.equals("Tab:ScreenshotData")) {
+                int tabId = message.getInt("tabID");
+                Tab tab = Tabs.getInstance().getTab(tabId);
+                processThumbnail(tab, null, Base64.decode(message.getString("data").substring(22), Base64.DEFAULT));
             } else if (event.equals("Tab:Selected")) {
                 int tabId = message.getInt("tabID");
                 Log.i(LOGTAG, "Switched to tab: " + tabId);
                 handleSelectTab(tabId);
             } else if (event.equals("Doorhanger:Add")) {
                 handleDoorHanger(message);
             } else if (event.equals("Doorhanger:Remove")) {
                 handleDoorHangerRemove(message);
@@ -1529,16 +1542,17 @@ abstract public class GeckoApp
         GeckoAppShell.registerGeckoEventListener("Content:LocationChange", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Content:SecurityChange", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Content:StateChange", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Content:LoadError", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("onCameraCapture", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Tab:Added", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Tab:Closed", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Tab:Selected", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Tab:ScreenshotData", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Doorhanger:Add", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Doorhanger:Remove", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Menu:Add", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Menu:Remove", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Gecko:Ready", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Toast:Show", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("ToggleChrome:Hide", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("ToggleChrome:Show", GeckoApp.mAppContext);
@@ -1765,16 +1779,17 @@ abstract public class GeckoApp
         GeckoAppShell.unregisterGeckoEventListener("Content:LocationChange", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Content:SecurityChange", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Content:StateChange", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Content:LoadError", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("onCameraCapture", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Tab:Added", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Tab:Closed", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Tab:Selected", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Tab:ScreenshotData", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Doorhanger:Add", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Menu:Add", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Menu:Remove", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Gecko:Ready", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Toast:Show", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("ToggleChrome:Hide", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("ToggleChrome:Show", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext);
--- a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
+++ b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
@@ -113,16 +113,23 @@ public class GeckoSoftwareLayerClient ex
             public IntSize getSize() { return mBufferSize; }
             @Override
             public int getFormat() { return mFormat; }
         };
 
         mTileLayer = new MultiTileLayer(mCairoImage, TILE_SIZE);
     }
 
+    public int getWidth() {
+        return mBufferSize.width;
+    }
+
+    public int getHeight() {
+        return mBufferSize.height;
+    }
 
     protected void finalize() throws Throwable {
         try {
             if (mBuffer != null)
                 GeckoAppShell.freeDirectBuffer(mBuffer);
             mBuffer = null;
         } finally {
             super.finalize();
@@ -269,23 +276,29 @@ public class GeckoSoftwareLayerClient ex
     public Bitmap getBitmap() {
         // Begin a tile transaction, otherwise the buffer can be destroyed while
         // we're reading from it.
         beginTransaction(mTileLayer);
         try {
             if (mBuffer == null || mBufferSize.width <= 0 || mBufferSize.height <= 0)
                 return null;
             try {
-                Bitmap b = Bitmap.createBitmap(mBufferSize.width, mBufferSize.height,
-                                               CairoUtils.cairoFormatTobitmapConfig(mFormat));
+                Bitmap b = null;
 
-                if (mTileLayer instanceof MultiTileLayer)
+                if (mTileLayer instanceof MultiTileLayer) {
+                    b = Bitmap.createBitmap(mBufferSize.width, mBufferSize.height,
+                                               CairoUtils.cairoFormatTobitmapConfig(mFormat));
                     copyPixelsFromMultiTileLayer(b);
-                else
+                } else if (mTileLayer instanceof SingleTileLayer) {
+                    b = Bitmap.createBitmap(mBufferSize.width, mBufferSize.height,
+                                               CairoUtils.cairoFormatTobitmapConfig(mFormat));
                     b.copyPixelsFromBuffer(mBuffer.asIntBuffer());
+                } else {
+                    Log.w(LOGTAG, "getBitmap() called on a layer (" + mTileLayer + ") we don't know how to get a bitmap from");
+                }
 
                 return b;
             } catch (OutOfMemoryError oom) {
                 Log.w(LOGTAG, "Unable to create bitmap", oom);
                 return null;
             }
         } finally {
             endTransaction(mTileLayer);
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -203,16 +203,17 @@ var BrowserApp = {
     ViewportHandler.init();
 
     getBridge().setDrawMetadataProvider(MetadataProvider);
 
     Services.obs.addObserver(this, "Tab:Add", false);
     Services.obs.addObserver(this, "Tab:Load", false);
     Services.obs.addObserver(this, "Tab:Select", false);
     Services.obs.addObserver(this, "Tab:Close", false);
+    Services.obs.addObserver(this, "Tab:Screenshot", false);
     Services.obs.addObserver(this, "Session:Back", false);
     Services.obs.addObserver(this, "Session:Forward", false);
     Services.obs.addObserver(this, "Session:Reload", false);
     Services.obs.addObserver(this, "Session:Stop", false);
     Services.obs.addObserver(this, "SaveAs:PDF", false);
     Services.obs.addObserver(this, "Browser:Quit", false);
     Services.obs.addObserver(this, "Preferences:Get", false);
     Services.obs.addObserver(this, "Preferences:Set", false);
@@ -465,16 +466,24 @@ var BrowserApp = {
     let evt = document.createEvent("UIEvents");
     evt.initUIEvent("TabClose", true, false, window, null);
     aTab.browser.dispatchEvent(evt);
 
     aTab.destroy();
     this._tabs.splice(this._tabs.indexOf(aTab), 1);
   },
 
+  screenshotTab: function screenshotTab(aData) {
+      let json = JSON.parse(aData);
+      let tab = this.getTabForId(parseInt(json.tabID));
+      let width = parseInt(json.width);
+      let height =  parseInt(json.height);
+      tab.screenshot(width, height);
+  },
+
   selectTab: function selectTab(aTab) {
     if (aTab != null) {
       this.selectedTab = aTab;
       aTab.active = true;
       let message = {
         gecko: {
           type: "Tab:Selected",
           tabID: aTab.id
@@ -818,16 +827,18 @@ var BrowserApp = {
       if (aTopic == "Tab:Add")
         this.addTab(url, params);
       else
         this.loadURI(url, browser, params);
     } else if (aTopic == "Tab:Select") {
       this.selectTab(this.getTabForId(parseInt(aData)));
     } else if (aTopic == "Tab:Close") {
       this.closeTab(this.getTabForId(parseInt(aData)));
+    } else if (aTopic == "Tab:Screenshot") {
+      this.screenshotTab(aData);
     } else if (aTopic == "Browser:Quit") {
       this.quit();
     } else if (aTopic == "SaveAs:PDF") {
       this.saveAsPDF(browser);
     } else if (aTopic == "Preferences:Get") {
       this.getPreferences(aData);
     } else if (aTopic == "Preferences:Set") {
       this.setPreferences(aData);
@@ -1462,16 +1473,36 @@ Tab.prototype = {
       this._viewport.zoom = aViewport.zoom;
       transformChanged = true;
     }
 
     if (transformChanged)
       this.updateTransform();
   },
 
+  screenshot: function(aWidth, aHeight) {
+      if (!this.browser || !this.browser.contentWindow)
+          return;
+      let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+      canvas.setAttribute("width", aWidth);  
+      canvas.setAttribute("height", aHeight);
+      let ctx = canvas.getContext("2d");
+      ctx.drawWindow(this.browser.contentWindow, 0, 0, aWidth, aHeight, "rgb(255, 255, 255)");
+      let message = {
+        gecko: {
+          type: "Tab:ScreenshotData",
+          tabID: this.id,
+          width: aWidth,
+          height: aHeight,
+          data: canvas.toDataURL()
+        }
+      };
+      sendMessageToJava(message);
+  },
+
   updateTransform: function() {
     let hasZoom = (Math.abs(this._viewport.zoom - 1.0) >= 1e-6);
     let x = this._viewport.offsetX + Math.round(-this.viewportExcess.x * this._viewport.zoom);
     let y = this._viewport.offsetY + Math.round(-this.viewportExcess.y * this._viewport.zoom);
 
     let transform =
       "translate(" + x + "px, " +
                      y + "px)";
--- a/netwerk/protocol/http/SpdySession.cpp
+++ b/netwerk/protocol/http/SpdySession.cpp
@@ -772,41 +772,53 @@ SpdySession::CleanupStream(SpdyStream *a
 }
 
 nsresult
 SpdySession::HandleSynStream(SpdySession *self)
 {
   NS_ABORT_IF_FALSE(self->mFrameControlType == CONTROL_TYPE_SYN_STREAM,
                     "wrong control type");
   
-  if (self->mFrameDataSize < 12) {
+  if (self->mFrameDataSize < 18) {
     LOG3(("SpdySession::HandleSynStream %p SYN_STREAM too short data=%d",
           self, self->mFrameDataSize));
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
   PRUint32 streamID =
     PR_ntohl(reinterpret_cast<PRUint32 *>(self->mFrameBuffer.get())[2]);
+  PRUint32 associatedID =
+    PR_ntohl(reinterpret_cast<PRUint32 *>(self->mFrameBuffer.get())[3]);
 
-  LOG3(("SpdySession::HandleSynStream %p recv SYN_STREAM (push) for ID 0x%X.",
-        self, streamID));
+  LOG3(("SpdySession::HandleSynStream %p recv SYN_STREAM (push) "
+        "for ID 0x%X associated with 0x%X.",
+        self, streamID, associatedID));
     
   if (streamID & 0x01) {                   // test for odd stream ID
     LOG3(("SpdySession::HandleSynStream %p recvd SYN_STREAM id must be even.",
           self));
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
   ++(self->mServerPushedResources);
 
   // Anytime we start using the high bit of stream ID (either client or server)
   // begin to migrate to a new session.
   if (streamID >= kMaxStreamID)
     self->mShouldGoAway = true;
 
+  // Need to decompress the headers even though we aren't using them yet in
+  // order to keep the compression context consistent for other syn_reply frames
+  nsresult rv = self->DownstreamUncompress(self->mFrameBuffer + 18,
+                                           self->mFrameDataSize - 10);
+  if (NS_FAILED(rv)) {
+    LOG(("SpdySession::HandleSynStream uncompress failed\n"));
+    return rv;
+  }
+
   // todo populate cache. For now, just reject server push p3
   self->GenerateRstStream(RST_REFUSED_STREAM, streamID);
   self->ChangeDownstreamState(BUFFERING_FRAME_HEADER);
   return NS_OK;
 }
 
 nsresult
 SpdySession::HandleSynReply(SpdySession *self)
@@ -867,18 +879,20 @@ SpdySession::HandleSynReply(SpdySession 
   // compressed name/value header block lives.
   // We unpack that into the mDecompressBuffer - we can't do
   // it streamed because the version and status information
   // is not guaranteed to be first. This is then finally
   // converted to HTTP format in mFlatHTTPResponseHeaders
 
   nsresult rv = self->DownstreamUncompress(self->mFrameBuffer + 14,
                                            self->mFrameDataSize - 6);
-  if (NS_FAILED(rv))
+  if (NS_FAILED(rv)) {
+    LOG(("SpdySession::HandleSynReply uncompress failed\n"));
     return rv;
+  }
   
   Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_SIZE,
                         self->mFrameDataSize - 6);
   PRUint32 ratio =
     (self->mFrameDataSize - 6) * 100 / self->mDecompressBufferUsed;
   Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_RATIO, ratio);
 
   // status and version are required.
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -323,19 +323,16 @@ nsHttpChannel::Connect(bool firstTime)
         // If we have a fallback URI (and we're not already
         // falling back), process the fallback asynchronously.
         if (!mFallbackChannel && !mFallbackKey.IsEmpty()) {
             return AsyncCall(&nsHttpChannel::HandleAsyncFallback);
         }
         return NS_ERROR_DOCUMENT_NOT_CACHED;
     }
 
-    // check to see if authorization headers should be included
-    mAuthProvider->AddAuthorizationHeaders();
-
     if (mLoadFlags & LOAD_NO_NETWORK_IO) {
         return NS_ERROR_DOCUMENT_NOT_CACHED;
     }
 
     // hit the net...
     rv = SetupTransaction();
     if (NS_FAILED(rv)) return rv;
 
@@ -3737,16 +3734,19 @@ nsHttpChannel::AsyncOpen(nsIStreamListen
     
     // Remember the cookie header that was set, if any
     const char *cookieHeader = mRequestHead.PeekHeader(nsHttp::Cookie);
     if (cookieHeader) {
         mUserSetCookieHeader = cookieHeader;
     }
 
     AddCookiesToRequest();
+ 
+    // check to see if authorization headers should be included
+    mAuthProvider->AddAuthorizationHeaders();
 
     // notify "http-on-modify-request" observers
     gHttpHandler->OnModifyRequest(this);
 
     // Adjust mCaps according to our request headers:
     //  - If "Connection: close" is set as a request header, then do not bother
     //    trying to establish a keep-alive connection.
     if (mRequestHead.HasHeaderValue(nsHttp::Connection, "close"))
--- a/toolkit/components/passwordmgr/test/test_privbrowsing.html
+++ b/toolkit/components/passwordmgr/test/test_privbrowsing.html
@@ -225,17 +225,16 @@ function handleLoad(aEvent) {
     SimpleTest.finish();
   }
 }
 
 
 var pb = get_PBSvc();
 if (!pb) { // Private Browsing might not be available
   ok(true, "Private browsing service is not available");
-  SimpleTest.finish();
 } else {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
   ok(Ci != null, "Access Ci");
   ok(Cc != null, "Access Cc");
 
   var prefBranch = Cc["@mozilla.org/preferences-service;1"].
                    getService(Ci.nsIPrefBranch);
--- a/toolkit/components/satchel/test/test_privbrowsing.html
+++ b/toolkit/components/satchel/test/test_privbrowsing.html
@@ -46,17 +46,16 @@ function handleLoad(aEvent) {
     prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
     SimpleTest.finish();
   }
 }
 
 var pb = get_PBSvc();
 if (!pb) { // Private Browsing might not be available
   ok(true, "Private browsing service is not available");
-  SimpleTest.finish();
 } else {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
   var prefBranch = Cc["@mozilla.org/preferences-service;1"].
                    getService(Ci.nsIPrefBranch);
   prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
 
   var formhist = Cc["@mozilla.org/satchel/form-history;1"].
--- a/tools/profiler/sampler.h
+++ b/tools/profiler/sampler.h
@@ -81,17 +81,17 @@
 #define FULLFUNCTION __FUNCSIG__
 #elif (__GNUC__ >= 4)
 #define FULLFUNCTION __PRETTY_FUNCTION__
 #else
 #define FULLFUNCTION __FUNCTION__
 #endif
 
 // Redefine the macros for platforms where SPS is supported.
-#if defined(ANDROID) || defined(XP_UNIX) || defined(XP_MACOSX) || defined(XP_WIN)
+#if defined(ANDROID) || defined(__linux__) || defined(XP_MACOSX) || defined(XP_WIN)
 
 #include "sps_sampler.h"
 
 #else
 
 // Initialize the sampler. Any other calls will be silently discarded
 // before the sampler has been initialized (i.e. early start-up code)
 #define SAMPLER_INIT()
--- a/view/public/nsIViewManager.h
+++ b/view/public/nsIViewManager.h
@@ -43,18 +43,18 @@
 #include "nsEvent.h"
 
 class nsIWidget;
 struct nsRect;
 class nsRegion;
 class nsDeviceContext;
 
 #define NS_IVIEWMANAGER_IID \
-{ 0x1262a33f, 0xc19f, 0x4e5b, \
-  { 0x85, 0x00, 0xab, 0xf3, 0x7d, 0xcf, 0x30, 0x1d } }
+{ 0x540610a6, 0x4fdd, 0x4ae3, \
+  { 0x9b, 0xdb, 0xa6, 0x4d, 0x8b, 0xca, 0x02, 0x0f } }
 
 class nsIViewManager : public nsISupports
 {
 public:
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IVIEWMANAGER_IID)
   /**
    * Initialize the ViewManager
@@ -112,50 +112,35 @@ public:
   NS_IMETHOD  SetWindowDimensions(nscoord aWidth, nscoord aHeight) = 0;
 
   /**
    * Do any resizes that are pending.
    */
   NS_IMETHOD  FlushDelayedResize(bool aDoReflow) = 0;
 
   /**
-   * Called to force a redrawing of any dirty areas.
-   */
-  // XXXbz why is this exposed?  Shouldn't update view batches handle this?
-  // It's not like Composite() does what's expected inside a view update batch
-  // anyway, since dirty areas may not have been invalidated on the widget yet
-  // and widget changes may not have been propagated yet.  Maybe this should
-  // call FlushPendingInvalidates()?
-  NS_IMETHOD  Composite(void) = 0;
-
-  /**
    * Called to inform the view manager that the entire area of a view
    * is dirty and needs to be redrawn.
    * @param aView view to paint. should be root view
-   * @param aUpdateFlags see bottom of nsIViewManager.h for description
    */
-  NS_IMETHOD  UpdateView(nsIView *aView, PRUint32 aUpdateFlags) = 0;
+  NS_IMETHOD  InvalidateView(nsIView *aView) = 0;
 
   /**
    * Called to inform the view manager that some portion of a view is dirty and
    * needs to be redrawn. The rect passed in should be in the view's coordinate
    * space. Does not check for paint suppression.
    * @param aView view to paint. should be root view
    * @param rect rect to mark as damaged
-   * @param aUpdateFlags see bottom of nsIViewManager.h for description
    */
-  NS_IMETHOD  UpdateViewNoSuppression(nsIView *aView, const nsRect &aRect,
-                                      PRUint32 aUpdateFlags) = 0;
+  NS_IMETHOD  InvalidateViewNoSuppression(nsIView *aView, const nsRect &aRect) = 0;
 
   /**
-   * Called to inform the view manager that it should redraw all views.
-   * @param aView view to paint. should be root view
-   * @param aUpdateFlags see bottom of nsIViewManager.h for description
+   * Called to inform the view manager that it should invalidate all views.
    */
-  NS_IMETHOD  UpdateAllViews(PRUint32 aUpdateFlags) = 0;
+  NS_IMETHOD  InvalidateAllViews() = 0;
 
   /**
    * Called to dispatch an event to the appropriate view. Often called
    * as a result of receiving a mouse or keyboard event from the widget
    * event system.
    * @param aEvent event to dispatch
    * @param aViewTarget dispatch the event to this view
    * @param aStatus event handling status
@@ -268,105 +253,61 @@ public:
   virtual nsIPresShell* GetPresShell() = 0;
 
   /**
    * Get the device context associated with this manager
    * @result device context
    */
   NS_IMETHOD  GetDeviceContext(nsDeviceContext *&aContext) = 0;
 
-  class UpdateViewBatch {
+  /**
+   * A stack class for disallowing changes that would enter painting. For
+   * example, popup widgets shouldn't be resized during reflow, since doing so
+   * might cause synchronous painting inside reflow which is forbidden.
+   * While refresh is disabled, widget geometry changes are deferred and will
+   * be handled later, either from the refresh driver or from an NS_WILL_PAINT
+   * event.
+   * We don't want to defer widget geometry changes all the time. Resizing a
+   * popup from script doesn't need to be deferred, for example, especially
+   * since popup widget geometry is observable from script and expected to
+   * update synchronously.
+   */
+  class NS_STACK_CLASS AutoDisableRefresh {
   public:
-    UpdateViewBatch() {}
-  /**
-   * prevents the view manager from refreshing. allows UpdateView()
-   * to notify widgets of damaged regions that should be repainted
-   * when the batch is ended. Call EndUpdateViewBatch on this object
-   * before it is destroyed
-   * @return error status
-   */
-    UpdateViewBatch(nsIViewManager* aVM) {
+    AutoDisableRefresh(nsIViewManager* aVM) {
       if (aVM) {
-        mRootVM = aVM->BeginUpdateViewBatch();
-      }
-    }
-    ~UpdateViewBatch() {
-      NS_ASSERTION(!mRootVM, "Someone forgot to call EndUpdateViewBatch!");
-    }
-    
-    /**
-     * See the constructor, this lets you "fill in" a blank UpdateViewBatch.
-     */
-    void BeginUpdateViewBatch(nsIViewManager* aVM) {
-      NS_ASSERTION(!mRootVM, "already started a batch!");
-      if (aVM) {
-        mRootVM = aVM->BeginUpdateViewBatch();
+        mRootVM = aVM->IncrementDisableRefreshCount();
       }
     }
-
-  /**
-   * allow the view manager to refresh any damaged areas accumulated
-   * after the BeginUpdateViewBatch() call.  this may cause a
-   * synchronous paint to occur inside the call if aUpdateFlags
-   * NS_VMREFRESH_IMMEDIATE is set.
-   *
-   * If this is not the outermost view batch command, then this does
-   * nothing except that the specified flags are remembered. When the
-   * outermost batch finally ends, we merge together all the flags for the
-   * inner batches in the following way:
-   * -- If any batch specified NS_VMREFRESH_IMMEDIATE, then we use that flag
-   * (i.e. there is a synchronous paint under the last EndUpdateViewBatch)
-   * -- Otherwise if any batch specified NS_VMREFERSH_DEFERRED, then we use
-   * that flag (i.e. invalidation is deferred until the processing of an
-   * Invalidate PLEvent)
-   * -- Otherwise all batches specified NS_VMREFRESH_NO_SYNC and we honor
-   * that; all widgets are invalidated normally and will be painted the next
-   * time the toolkit chooses to update them.
-   *
-   * @param aUpdateFlags see bottom of nsIViewManager.h for
-   * description @return error status
-   */
-    void EndUpdateViewBatch(PRUint32 aUpdateFlags) {
-      if (!mRootVM)
-        return;
-      mRootVM->EndUpdateViewBatch(aUpdateFlags);
-      mRootVM = nsnull;
+    ~AutoDisableRefresh() {
+      if (mRootVM) {
+        mRootVM->DecrementDisableRefreshCount();
+      }
     }
-
   private:
-    UpdateViewBatch(const UpdateViewBatch& aOther);
-    const UpdateViewBatch& operator=(const UpdateViewBatch& aOther);
+    AutoDisableRefresh(const AutoDisableRefresh& aOther);
+    const AutoDisableRefresh& operator=(const AutoDisableRefresh& aOther);
 
     nsCOMPtr<nsIViewManager> mRootVM;
   };
-  
+
 private:
-  friend class UpdateViewBatch;
+  friend class AutoDisableRefresh;
 
-  virtual nsIViewManager* BeginUpdateViewBatch(void) = 0;
-  NS_IMETHOD EndUpdateViewBatch(PRUint32 aUpdateFlags) = 0;
+  virtual nsIViewManager* IncrementDisableRefreshCount() = 0;
+  virtual void DecrementDisableRefreshCount() = 0;
 
 public:
   /**
    * Retrieve the widget at the root of the nearest enclosing
    * view manager whose root view has a widget.
    */
   NS_IMETHOD GetRootWidget(nsIWidget **aWidget) = 0;
 
   /**
-   * Force update of view manager widget
-   * Callers should use UpdateView(view, NS_VMREFRESH_IMMEDIATE) in most cases instead
-   * @result error status
-   */
-  // XXXbz Callers seem to be confused about this one... and it doesn't play
-  // right with view update batching at all (will miss updates).  Maybe this
-  // should call FlushPendingInvalidates()?
-  NS_IMETHOD ForceUpdate() = 0;
-
-  /**
    * Indicate whether the viewmanager is currently painting
    *
    * @param aPainting true if the viewmanager is painting
    *                  false otherwise
    */
   NS_IMETHOD IsPainting(bool& aIsPainting)=0;
 
   /**
@@ -378,30 +319,24 @@ public:
    */
   NS_IMETHOD GetLastUserEventTime(PRUint32& aTime)=0;
 
   /**
    * Find the nearest display root view for the view aView. This is the view for
    * the nearest enclosing popup or the root view for the root document.
    */
   static nsIView* GetDisplayRootFor(nsIView* aView);
+
+  /**
+   * Flush the accumulated dirty region to the widget and update widget
+   * geometry.
+   */
+  virtual void ProcessPendingUpdates()=0;
+
+  /**
+   * Just update widget geometry without flushing the dirty region
+   */
+  virtual void UpdateWidgetGeometry() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewManager, NS_IVIEWMANAGER_IID)
 
-// Paint timing mode flags
-
-// intermediate: do no special timing processing; repaint when the
-// toolkit issues an expose event (which will happen *before* PLEvent
-// processing). This is essentially the default.
-#define NS_VMREFRESH_NO_SYNC            0
-
-// least immediate: we suppress invalidation, storing dirty areas in
-// views, and post an Invalidate PLEvent. The Invalidate event gets
-// processed after toolkit events such as window resize events!
-// This is only usable with EndUpdateViewBatch and EnableRefresh.
-#define NS_VMREFRESH_DEFERRED           0x0001
-
-// most immediate: force a call to nsViewManager::Composite, which
-// synchronously updates the window(s) right away before returning
-#define NS_VMREFRESH_IMMEDIATE          0x0002
-
 #endif  // nsIViewManager_h___
--- a/view/src/nsView.cpp
+++ b/view/src/nsView.cpp
@@ -346,40 +346,41 @@ void nsView::SetPosition(nscoord aX, nsc
   mDimBounds.x += aX - mPosX;
   mDimBounds.y += aY - mPosY;
   mPosX = aX;
   mPosY = aY;
 
   NS_ASSERTION(GetParent() || (aX == 0 && aY == 0),
                "Don't try to move the root widget to something non-zero");
 
-  ResetWidgetBounds(true, true, false);
+  ResetWidgetBounds(true, false);
 }
 
 void nsIView::SetInvalidationDimensions(const nsRect* aRect)
 {
   return Impl()->SetInvalidationDimensions(aRect);
 }
 
-void nsView::ResetWidgetBounds(bool aRecurse, bool aMoveOnly,
-                               bool aInvalidateChangedSize) {
+void nsView::ResetWidgetBounds(bool aRecurse, bool aForceSync)
+{
   if (mWindow) {
-    // If our view manager has refresh disabled, then do nothing; the view
-    // manager will set our position when refresh is reenabled.  Just let it
-    // know that it has pending updates.
-    if (!mViewManager->IsRefreshEnabled()) {
+    if (!aForceSync) {
+      // Don't change widget geometry synchronously, since that can
+      // cause synchronous painting.
       mViewManager->PostPendingUpdate();
-      return;
+    } else {
+      DoResetWidgetBounds(false, true);
     }
+    return;
+  }
 
-    DoResetWidgetBounds(aMoveOnly, aInvalidateChangedSize);
-  } else if (aRecurse) {
+  if (aRecurse) {
     // reposition any widgets under this view
     for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) {
-      v->ResetWidgetBounds(true, aMoveOnly, aInvalidateChangedSize);
+      v->ResetWidgetBounds(true, aForceSync);
     }
   }
 }
 
 bool nsIView::IsEffectivelyVisible()
 {
   for (nsIView* v = this; v; v = v->mParent) {
     if (v->GetVisibility() == nsViewVisibility_kHide)
@@ -487,17 +488,17 @@ void nsView::SetDimensions(const nsRect&
   if (mDimBounds.TopLeft() == dims.TopLeft() &&
       mDimBounds.Size() == dims.Size()) {
     return;
   }
 
   mDimBounds = dims;
 
   if (aResizeWidget) {
-    ResetWidgetBounds(false, false, aPaint);
+    ResetWidgetBounds(false, false);
   }
 }
 
 void nsView::SetInvalidationDimensions(const nsRect* aRect)
 {
   if ((mHaveInvalidationDimensions = !!aRect)) {
     mInvalidationDimensions = *aRect;
   }
--- a/view/src/nsView.h
+++ b/view/src/nsView.h
@@ -176,17 +176,17 @@ public:
   void SetNextSibling(nsView *aSibling) { mNextSibling = aSibling; }
 
   PRUint32 GetViewFlags() const { return mVFlags; }
   void SetViewFlags(PRUint32 aFlags) { mVFlags = aFlags; }
 
   void SetTopMost(bool aTopMost) { aTopMost ? mVFlags |= NS_VIEW_FLAG_TOPMOST : mVFlags &= ~NS_VIEW_FLAG_TOPMOST; }
   bool IsTopMost() { return((mVFlags & NS_VIEW_FLAG_TOPMOST) != 0); }
 
-  void ResetWidgetBounds(bool aRecurse, bool aMoveOnly, bool aInvalidateChangedSize);
+  void ResetWidgetBounds(bool aRecurse, bool aForceSync);
   void AssertNoWindow();
 
   void NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible);
 
   // Update the cached RootViewManager for all view manager descendents,
   // If the hierarchy is being removed, aViewManagerParent points to the view
   // manager for the hierarchy's old parent, and will have its mouse grab
   // released if it points to any view in this view hierarchy.
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -75,31 +75,16 @@
    We assume that a widget is z-ordered on top of its parent.
    
    We do NOT assume anything about the relative z-ordering of sibling widgets. Even though
    we ask for a specific z-order, we don't assume that widget z-ordering actually works.
 */
 
 #define NSCOORD_NONE      PR_INT32_MIN
 
-void
-nsViewManager::PostInvalidateEvent()
-{
-  NS_ASSERTION(IsRootVM(), "Caller screwed up");
-
-  if (!mInvalidateEvent.IsPending()) {
-    nsRefPtr<nsInvalidateEvent> ev = new nsInvalidateEvent(this);
-    if (NS_FAILED(NS_DispatchToCurrentThread(ev))) {
-      NS_WARNING("failed to dispatch nsInvalidateEvent");
-    } else {
-      mInvalidateEvent = ev;
-    }
-  }
-}
-
 #undef DEBUG_MOUSE_LOCATION
 
 PRInt32 nsViewManager::mVMCount = 0;
 
 // Weakly held references to all of the view managers
 nsVoidArray* nsViewManager::gViewManagers = nsnull;
 PRUint32 nsViewManager::gLastUserEventTime = 0;
 
@@ -115,32 +100,28 @@ nsViewManager::nsViewManager()
  
   gViewManagers->AppendElement(this);
 
   ++mVMCount;
 
   // NOTE:  we use a zeroing operator new, so all data members are
   // assumed to be cleared here.
   mHasPendingUpdates = false;
+  mHasPendingWidgetGeometryChanges = false;
   mRecursiveRefreshPending = false;
-  mUpdateBatchFlags = 0;
 }
 
 nsViewManager::~nsViewManager()
 {
   if (mRootView) {
     // Destroy any remaining views
     mRootView->Destroy();
     mRootView = nsnull;
   }
 
-  // Make sure to revoke pending events for all viewmanagers, since some events
-  // are posted by a non-root viewmanager.
-  mInvalidateEvent.Revoke();
-  
   if (!IsRootVM()) {
     // We have a strong ref to mRootViewManager
     NS_RELEASE(mRootViewManager);
   }
 
   NS_ASSERTION((mVMCount > 0), "underflow of viewmanagers");
   --mVMCount;
 
@@ -356,19 +337,16 @@ nsIView* nsIViewManager::GetDisplayRootF
    rendering.
 */
 void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
                             const nsIntRegion& aRegion)
 {
   NS_ASSERTION(aView == nsView::GetViewFor(aWidget), "view widget mismatch");
   NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
 
-  if (! IsRefreshEnabled())
-    return;
-
   // damageRegion is the damaged area, in twips, relative to the view origin
   nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
   // move region from widget coordinates into view coordinates
   damageRegion.MoveBy(-aView->ViewToWidgetOffset());
 
   if (damageRegion.IsEmpty()) {
 #ifdef DEBUG_roc
     nsRect viewRect = aView->GetDimensions();
@@ -391,20 +369,18 @@ void nsViewManager::Refresh(nsView *aVie
     SetPainting(true);
 
     RenderViews(aView, aWidget, damageRegion, aRegion, false, false);
 
     SetPainting(false);
   }
 
   if (RootViewManager()->mRecursiveRefreshPending) {
-    // Unset this flag first, since if aUpdateFlags includes NS_VMREFRESH_IMMEDIATE
-    // we'll reenter this code from the UpdateAllViews call.
     RootViewManager()->mRecursiveRefreshPending = false;
-    UpdateAllViews(0);
+    InvalidateAllViews();
   }
 }
 
 // aRC and aRegion are in view coordinates
 void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget,
                                 const nsRegion& aRegion,
                                 const nsIntRegion& aIntRegion,
                                 bool aPaintDefaultBackground,
@@ -415,149 +391,136 @@ void nsViewManager::RenderViews(nsView *
 
   if (mPresShell) {
     mPresShell->Paint(aView, aWidget, aRegion, aIntRegion,
                       aPaintDefaultBackground, aWillSendDidPaint);
     mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
   }
 }
 
-void nsViewManager::ProcessPendingUpdates(nsView* aView, bool aDoInvalidate)
+void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
+                                                 bool aFlushDirtyRegion)
 {
   NS_ASSERTION(IsRootVM(), "Updates will be missed");
 
   // Protect against a null-view.
   if (!aView) {
     return;
   }
 
   if (aView->HasWidget()) {
-    aView->ResetWidgetBounds(false, false, true);
+    aView->ResetWidgetBounds(false, true);
   }
 
   // process pending updates in child view.
   for (nsView* childView = aView->GetFirstChild(); childView;
        childView = childView->GetNextSibling()) {
-    ProcessPendingUpdates(childView, aDoInvalidate);
+    ProcessPendingUpdatesForView(childView, aFlushDirtyRegion);
   }
 
-  if (aDoInvalidate && aView->HasNonEmptyDirtyRegion()) {
-    // Push out updates after we've processed the children; ensures that
-    // damage is applied based on the final widget geometry
-    NS_ASSERTION(IsRefreshEnabled(), "Cannot process pending updates with refresh disabled");
-    nsRegion* dirtyRegion = aView->GetDirtyRegion();
-    if (dirtyRegion) {
-      nsView* nearestViewWithWidget = aView;
-      while (!nearestViewWithWidget->HasWidget() &&
-             nearestViewWithWidget->GetParent()) {
-        nearestViewWithWidget = nearestViewWithWidget->GetParent();
-      }
-      nsRegion r =
-        ConvertRegionBetweenViews(*dirtyRegion, aView, nearestViewWithWidget);
-      nsViewManager* widgetVM = nearestViewWithWidget->GetViewManager();
-      widgetVM->
-        UpdateWidgetArea(nearestViewWithWidget,
-                         nearestViewWithWidget->GetWidget(), r, nsnull);
-      dirtyRegion->SetEmpty();
-    }
+  // Push out updates after we've processed the children; ensures that
+  // damage is applied based on the final widget geometry
+  if (aFlushDirtyRegion) {
+    FlushDirtyRegionToWidget(aView);
   }
 }
 
-NS_IMETHODIMP nsViewManager::Composite()
+void nsViewManager::FlushDirtyRegionToWidget(nsView* aView)
 {
-  if (!IsRootVM()) {
-    return RootViewManager()->Composite();
+  if (!aView->HasNonEmptyDirtyRegion())
+    return;
+
+  nsRegion* dirtyRegion = aView->GetDirtyRegion();
+  nsView* nearestViewWithWidget = aView;
+  while (!nearestViewWithWidget->HasWidget() &&
+         nearestViewWithWidget->GetParent()) {
+    nearestViewWithWidget = nearestViewWithWidget->GetParent();
   }
-  ForceUpdate();
-  ClearUpdateCount();
-
-  return NS_OK;
+  nsRegion r =
+    ConvertRegionBetweenViews(*dirtyRegion, aView, nearestViewWithWidget);
+  nsViewManager* widgetVM = nearestViewWithWidget->GetViewManager();
+  widgetVM->InvalidateWidgetArea(nearestViewWithWidget, r);
+  dirtyRegion->SetEmpty();
 }
 
-NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags)
+NS_IMETHODIMP nsViewManager::InvalidateView(nsIView *aView)
 {
   // Mark the entire view as damaged
-  return UpdateView(aView, aView->GetDimensions(), aUpdateFlags);
+  return InvalidateView(aView, aView->GetDimensions());
+}
+
+static void
+AddDirtyRegion(nsView *aView, const nsRegion &aDamagedRegion)
+{
+  nsRegion* dirtyRegion = aView->GetDirtyRegion();
+  if (!dirtyRegion)
+    return;
+
+  dirtyRegion->Or(*dirtyRegion, aDamagedRegion);
+  dirtyRegion->SimplifyOutward(8);
+}
+
+void
+nsViewManager::PostPendingUpdate()
+{
+  nsViewManager* rootVM = RootViewManager();
+  rootVM->mHasPendingUpdates = true;
+  rootVM->mHasPendingWidgetGeometryChanges = true;
+  if (rootVM->mPresShell) {
+    rootVM->mPresShell->ScheduleViewManagerFlush();
+  }
 }
 
 /**
- * @param aWidget the widget for aWidgetView; in some cases the widget
- * is being managed directly by the frame system, so aWidgetView->GetWidget()
- * will return null but nsView::GetViewFor(aWidget) returns aWidgetview
  * @param aDamagedRegion this region, relative to aWidgetView, is invalidated in
  * every widget child of aWidgetView, plus aWidgetView's own widget
- * @param aIgnoreWidgetView if non-null, the aIgnoreWidgetView's widget and its
- * children are not updated.
  */
 void
-nsViewManager::UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
-                                const nsRegion &aDamagedRegion,
-                                nsView* aIgnoreWidgetView)
+nsViewManager::InvalidateWidgetArea(nsView *aWidgetView,
+                                    const nsRegion &aDamagedRegion)
 {
   NS_ASSERTION(aWidgetView->GetViewManager() == this,
-               "UpdateWidgetArea called on view we don't own");
+               "InvalidateWidgetArea called on view we don't own");
+  nsIWidget* widget = aWidgetView->GetWidget();
 
 #if 0
   nsRect dbgBounds = aDamagedRegion.GetBounds();
-  printf("UpdateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
+  printf("InvalidateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
     aWidgetView, aWidgetView->IsAttachedToTopLevel(),
-    aWidget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height);
+    widget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height);
 #endif
 
-  if (!IsRefreshEnabled()) {
-    // accumulate this rectangle in the view's dirty region, so we can
-    // process it later.
-    nsRegion* dirtyRegion = aWidgetView->GetDirtyRegion();
-    if (!dirtyRegion) return;
-
-    dirtyRegion->Or(*dirtyRegion, aDamagedRegion);
-    // Don't let dirtyRegion grow beyond 8 rects
-    dirtyRegion->SimplifyOutward(8);
-    nsViewManager* rootVM = RootViewManager();
-    rootVM->mHasPendingUpdates = true;
-    rootVM->IncrementUpdateCount();
-    return;
-    // this should only happen at the top level, and this result
-    // should not be consumed by top-level callers, so it doesn't
-    // really matter what we return
-  }
-
   // If the bounds don't overlap at all, there's nothing to do
   nsRegion intersection;
   intersection.And(aWidgetView->GetInvalidationDimensions(), aDamagedRegion);
   if (intersection.IsEmpty()) {
     return;
   }
 
   // If the widget is hidden, it don't cover nothing
-  if (aWidget) {
+  if (widget) {
     bool visible;
-    aWidget->IsVisible(visible);
+    widget->IsVisible(visible);
     if (!visible)
       return;
   }
 
-  if (aWidgetView == aIgnoreWidgetView) {
-    // the widget for aIgnoreWidgetView (and its children) should be treated as already updated.
-    return;
-  }
-
-  if (!aWidget) {
+  if (!widget) {
     // The root view or a scrolling view might not have a widget
     // (for example, during printing). We get here when we scroll
     // during printing to show selected options in a listbox, for example.
     return;
   }
 
   // Update all child widgets with the damage. In the process,
   // accumulate the union of all the child widget areas, or at least
   // some subset of that.
   nsRegion children;
-  if (aWidget->GetTransparencyMode() != eTransparencyTransparent) {
-    for (nsIWidget* childWidget = aWidget->GetFirstChild();
+  if (widget->GetTransparencyMode() != eTransparencyTransparent) {
+    for (nsIWidget* childWidget = widget->GetFirstChild();
          childWidget;
          childWidget = childWidget->GetNextSibling()) {
       nsView* view = nsView::GetViewFor(childWidget);
       NS_ASSERTION(view != aWidgetView, "will recur infinitely");
       bool visible;
       childWidget->IsVisible(visible);
       nsWindowType type;
       childWidget->GetWindowType(type);
@@ -586,22 +549,20 @@ nsViewManager::UpdateWidgetArea(nsView *
       }
     }
   }
 
   nsRegion leftOver;
   leftOver.Sub(intersection, children);
 
   if (!leftOver.IsEmpty()) {
-    NS_ASSERTION(IsRefreshEnabled(), "Can only get here with refresh enabled, I hope");
-
     const nsRect* r;
     for (nsRegionRectIterator iter(leftOver); (r = iter.Next());) {
       nsIntRect bounds = ViewToWidget(aWidgetView, *r);
-      aWidget->Invalidate(bounds, false);
+      widget->Invalidate(bounds);
     }
   }
 }
 
 static bool
 ShouldIgnoreInvalidation(nsViewManager* aVM)
 {
   while (aVM) {
@@ -610,89 +571,81 @@ ShouldIgnoreInvalidation(nsViewManager* 
       return true;
     }
     nsView* view = aVM->GetRootViewImpl()->GetParent();
     aVM = view ? view->GetViewManager() : nsnull;
   }
   return false;
 }
 
-nsresult nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect,
-                                   PRUint32 aUpdateFlags)
+nsresult nsViewManager::InvalidateView(nsIView *aView, const nsRect &aRect)
 {
   // If painting is suppressed in the presshell or an ancestor drop all
   // invalidates, it will invalidate everything when it unsuppresses.
   if (ShouldIgnoreInvalidation(this)) {
     return NS_OK;
   }
 
-  return UpdateViewNoSuppression(aView, aRect, aUpdateFlags);
+  return InvalidateViewNoSuppression(aView, aRect);
 }
 
-NS_IMETHODIMP nsViewManager::UpdateViewNoSuppression(nsIView *aView,
-                                                     const nsRect &aRect,
-                                                     PRUint32 aUpdateFlags)
+NS_IMETHODIMP nsViewManager::InvalidateViewNoSuppression(nsIView *aView,
+                                                         const nsRect &aRect)
 {
   NS_PRECONDITION(nsnull != aView, "null view");
 
   nsView* view = static_cast<nsView*>(aView);
 
   NS_ASSERTION(view->GetViewManager() == this,
-               "UpdateView called on view we don't own");
+               "InvalidateViewNoSuppression called on view we don't own");
 
   nsRect damagedRect(aRect);
   if (damagedRect.IsEmpty()) {
     return NS_OK;
   }
 
   nsView* displayRoot = static_cast<nsView*>(GetDisplayRootFor(view));
   nsViewManager* displayRootVM = displayRoot->GetViewManager();
   // Propagate the update to the displayRoot, since iframes, for example,
   // can overlap each other and be translucent.  So we have to possibly
   // invalidate our rect in each of the widgets we have lying about.
   damagedRect.MoveBy(view->GetOffsetTo(displayRoot));
   PRInt32 rootAPD = displayRootVM->AppUnitsPerDevPixel();
   PRInt32 APD = AppUnitsPerDevPixel();
   damagedRect = damagedRect.ConvertAppUnitsRoundOut(APD, rootAPD);
-  displayRootVM->UpdateWidgetArea(displayRoot, displayRoot->GetWidget(),
-                                  nsRegion(damagedRect), nsnull);
-
-  RootViewManager()->IncrementUpdateCount();
 
-  if (!IsRefreshEnabled()) {
-    return NS_OK;
-  }
+  // accumulate this rectangle in the view's dirty region, so we can
+  // process it later.
+  AddDirtyRegion(displayRoot, nsRegion(damagedRect));
 
-  // See if we should do an immediate refresh or wait
-  if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) {
-    Composite();
-  } 
+  // Schedule an invalidation flush with the refresh driver.
+  PostPendingUpdate();
 
   return NS_OK;
 }
 
-NS_IMETHODIMP nsViewManager::UpdateAllViews(PRUint32 aUpdateFlags)
+NS_IMETHODIMP nsViewManager::InvalidateAllViews()
 {
   if (RootViewManager() != this) {
-    return RootViewManager()->UpdateAllViews(aUpdateFlags);
+    return RootViewManager()->InvalidateAllViews();
   }
   
-  UpdateViews(mRootView, aUpdateFlags);
+  InvalidateViews(mRootView);
   return NS_OK;
 }
 
-void nsViewManager::UpdateViews(nsView *aView, PRUint32 aUpdateFlags)
+void nsViewManager::InvalidateViews(nsView *aView)
 {
-  // update this view.
-  UpdateView(aView, aUpdateFlags);
+  // Invalidate this view.
+  InvalidateView(aView);
 
-  // update all children as well.
+  // Invalidate all children as well.
   nsView* childView = aView->GetFirstChild();
   while (nsnull != childView)  {
-    childView->GetViewManager()->UpdateViews(childView, aUpdateFlags);
+    childView->GetViewManager()->InvalidateViews(childView);
     childView = childView->GetNextSibling();
   }
 }
 
 static bool
 IsViewForPopup(nsIView* aView)
 {
   nsIWidget* widget = aView->GetWidget();
@@ -795,142 +748,84 @@ NS_IMETHODIMP nsViewManager::DispatchEve
               *aStatus = nsEventStatus_eConsumeNoDefault;
             }
           }
         }
       }
       break;
 
     case NS_WILL_PAINT:
-    case NS_PAINT:
       {
-        nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
-
         if (!aView || !mContext)
           break;
 
         *aStatus = nsEventStatus_eConsumeNoDefault;
 
-        if (aEvent->message == NS_PAINT && event->region.IsEmpty())
-          break;
+        nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
 
         NS_ASSERTION(static_cast<nsView*>(aView) ==
                        nsView::GetViewFor(event->widget),
                      "view/widget mismatch");
 
-        // The region is in device units, and it's in the coordinate space of
-        // its associated widget.
-
-        // Refresh the view
-        if (IsRefreshEnabled()) {
-          nsRefPtr<nsViewManager> rootVM = RootViewManager();
-
-          // If an ancestor widget was hidden and then shown, we could
-          // have a delayed resize to handle.
-          bool didResize = false;
-          for (nsViewManager *vm = this; vm;
-               vm = vm->mRootView->GetParent()
-                      ? vm->mRootView->GetParent()->GetViewManager()
-                      : nsnull) {
-            if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
-                vm->mRootView->IsEffectivelyVisible() &&
-                mPresShell && mPresShell->IsVisible()) {
-              vm->FlushDelayedResize(true);
+        // If an ancestor widget was hidden and then shown, we could
+        // have a delayed resize to handle.
+        for (nsViewManager *vm = this; vm;
+             vm = vm->mRootView->GetParent()
+                    ? vm->mRootView->GetParent()->GetViewManager()
+                    : nsnull) {
+          if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
+              vm->mRootView->IsEffectivelyVisible() &&
+              mPresShell && mPresShell->IsVisible()) {
+            vm->FlushDelayedResize(true);
+            vm->InvalidateView(vm->mRootView);
+          }
+        }
 
-              // Paint later.
-              vm->UpdateView(vm->mRootView, NS_VMREFRESH_NO_SYNC);
-              didResize = true;
-
-              // not sure if it's valid for us to claim that we
-              // ignored this, but we're going to do so anyway, since
-              // we didn't actually paint anything
-              *aStatus = nsEventStatus_eIgnore;
-            }
-          }
-
-          if (!didResize) {
-            //NS_ASSERTION(view->IsEffectivelyVisible(), "painting an invisible view");
-
-            // Notify view observers that we're about to paint.
-            // Make sure to not send WillPaint notifications while scrolling.
-
-            nsCOMPtr<nsIWidget> widget;
-            rootVM->GetRootWidget(getter_AddRefs(widget));
-            bool transparentWindow = false;
-            if (widget)
-                transparentWindow = widget->GetTransparencyMode() == eTransparencyTransparent;
+        // Flush things like reflows and plugin widget geometry updates by
+        // calling WillPaint on observer presShells.
+        nsRefPtr<nsViewManager> rootVM = RootViewManager();
+        if (mPresShell) {
+          rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
+        }
+        // Flush view widget geometry updates and invalidations.
+        rootVM->ProcessPendingUpdates();
+      }
+      break;
 
-            nsView* view = static_cast<nsView*>(aView);
-            if (!transparentWindow) {
-              if (mPresShell) {
-                // Do an update view batch.  Make sure not to do it DEFERRED,
-                // since that would effectively delay any invalidates that are
-                // triggered by the WillPaint notification (they'd happen when
-                // the invalid event fires, which is later than the reflow
-                // event would fire and could end up being after some timer
-                // events, leading to frame dropping in DHTML).  Note that the
-                // observer may try to reenter this code from inside
-                // WillPaint() by trying to do a synchronous paint, but since
-                // refresh will be disabled it won't be able to do the paint.
-                // We should really sort out the rules on our synch painting
-                // api....
-                UpdateViewBatch batch(this);
-                rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
-                batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
+    case NS_PAINT:
+      {
+        if (!aView || !mContext)
+          break;
+
+        *aStatus = nsEventStatus_eConsumeNoDefault;
+        nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
+        nsView* view = static_cast<nsView*>(aView);
+        NS_ASSERTION(view == nsView::GetViewFor(event->widget),
+                     "view/widget mismatch");
+        NS_ASSERTION(IsPaintingAllowed(),
+                     "shouldn't be receiving paint events while painting is "
+                     "disallowed!");
 
-                // Get the view pointer again since the code above might have
-                // destroyed it (bug 378273).
-                view = nsView::GetViewFor(aEvent->widget);
-              }
-            }
-            // Make sure to sync up any widget geometry changes we
-            // have pending before we paint.
-            if (rootVM->mHasPendingUpdates) {
-              rootVM->ProcessPendingUpdates(mRootView, false);
-            }
-            
-            if (view && aEvent->message == NS_PAINT) {
-              Refresh(view, event->widget, event->region);
-            }
-          }
-        } else if (aEvent->message == NS_PAINT) {
-          // since we got an NS_PAINT event, we need to
-          // draw something so we don't get blank areas,
-          // unless there's no widget or it's transparent.
-          nsRegion rgn = event->region.ToAppUnits(AppUnitsPerDevPixel());
-          rgn.MoveBy(-aView->ViewToWidgetOffset());
-          RenderViews(static_cast<nsView*>(aView), event->widget, rgn,
-                      event->region, true, event->willSendDidPaint);
-          // Clients like the editor can trigger multiple
-          // reflows during what the user perceives as a single
-          // edit operation, so it disables view manager
-          // refreshing until the edit operation is complete
-          // so that users don't see the intermediate steps.
-          // 
-          // Unfortunately some of these reflows can trigger
-          // nsScrollPortView and nsScrollingView Scroll() calls
-          // which in most cases force an immediate BitBlt and
-          // synchronous paint to happen even if the view manager's
-          // refresh is disabled. (Bug 97674)
-          //
-          // Calling UpdateView() here, is necessary to add
-          // the exposed region specified in the synchronous paint
-          // event to  the view's damaged region so that it gets
-          // painted properly when refresh is enabled.
-          //
-          // Note that calling UpdateView() here was deemed
-          // to have the least impact on performance, since the
-          // other alternative was to make Scroll() post an
-          // async paint event for the *entire* ScrollPort or
-          // ScrollingView's viewable area. (See bug 97674 for this
-          // alternate patch.)
+        if (!event->didSendWillPaint) {
+          // Send NS_WILL_PAINT event ourselves.
+          nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, event->widget);
+          willPaintEvent.willSendDidPaint = event->willSendDidPaint;
+          DispatchEvent(&willPaintEvent, view, aStatus);
 
-          UpdateView(aView, rgn.GetBounds(), NS_VMREFRESH_NO_SYNC);
+          // Get the view pointer again since NS_WILL_PAINT might have
+          // destroyed it during CallWillPaintOnObservers (bug 378273).
+          view = nsView::GetViewFor(event->widget);
         }
 
+        if (!view || event->region.IsEmpty())
+          break;
+
+        // Paint.
+        Refresh(view, event->widget, event->region);
+
         break;
       }
 
     case NS_DID_PAINT: {
       nsRefPtr<nsViewManager> rootVM = RootViewManager();
       rootVM->CallDidPaintOnObservers();
       break;
     }
@@ -1171,17 +1066,17 @@ NS_IMETHODIMP nsViewManager::InsertChild
 
       // if the parent view is marked as "floating", make the newly added view float as well.
       if (parent->GetFloating())
         child->SetFloating(true);
 
       //and mark this area as dirty if the view is visible...
 
       if (nsViewVisibility_kHide != child->GetVisibility())
-        child->GetViewManager()->UpdateView(child, NS_VMREFRESH_NO_SYNC);
+        child->GetViewManager()->InvalidateView(child);
     }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsViewManager::InsertChild(nsIView *aParent, nsIView *aChild, PRInt32 aZIndex)
 {
   // no-one really calls this with anything other than aZIndex == 0 on a fresh view
   // XXX this method should simply be eliminated and its callers redirected to the real method
@@ -1194,17 +1089,17 @@ NS_IMETHODIMP nsViewManager::RemoveChild
   nsView* child = static_cast<nsView*>(aChild);
   NS_ENSURE_ARG_POINTER(child);
 
   nsView* parent = child->GetParent();
 
   if (nsnull != parent) {
     NS_ASSERTION(child->GetViewManager() == this ||
                  parent->GetViewManager() == this, "wrong view manager");
-    child->GetViewManager()->UpdateView(child, NS_VMREFRESH_NO_SYNC);
+    child->GetViewManager()->InvalidateView(child);
     parent->RemoveChild(child);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY)
 {
@@ -1216,54 +1111,52 @@ NS_IMETHODIMP nsViewManager::MoveViewTo(
 
   // only do damage control if the view is visible
 
   if ((aX != oldPt.x) || (aY != oldPt.y)) {
     if (view->GetVisibility() != nsViewVisibility_kHide) {
       nsView* parentView = view->GetParent();
       if (parentView) {
         nsViewManager* parentVM = parentView->GetViewManager();
-        parentVM->UpdateView(parentView, oldBounds, NS_VMREFRESH_NO_SYNC);
-        parentVM->UpdateView(parentView, view->GetBoundsInParentUnits(),
-                             NS_VMREFRESH_NO_SYNC);
+        parentVM->InvalidateView(parentView, oldBounds);
+        parentVM->InvalidateView(parentView, view->GetBoundsInParentUnits());
       }
     }
   }
   return NS_OK;
 }
 
 void nsViewManager::InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
-  PRUint32 aUpdateFlags, nscoord aY1, nscoord aY2, bool aInCutOut) {
+  nscoord aY1, nscoord aY2, bool aInCutOut) {
   nscoord height = aY2 - aY1;
   if (aRect.x < aCutOut.x) {
     nsRect r(aRect.x, aY1, aCutOut.x - aRect.x, height);
-    UpdateView(aView, r, aUpdateFlags);
+    InvalidateView(aView, r);
   }
   if (!aInCutOut && aCutOut.x < aCutOut.XMost()) {
     nsRect r(aCutOut.x, aY1, aCutOut.width, height);
-    UpdateView(aView, r, aUpdateFlags);
+    InvalidateView(aView, r);
   }
   if (aCutOut.XMost() < aRect.XMost()) {
     nsRect r(aCutOut.XMost(), aY1, aRect.XMost() - aCutOut.XMost(), height);
-    UpdateView(aView, r, aUpdateFlags);
+    InvalidateView(aView, r);
   }
 }
 
-void nsViewManager::InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
-  PRUint32 aUpdateFlags) {
+void nsViewManager::InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut) {
   NS_ASSERTION(aView->GetViewManager() == this,
                "InvalidateRectDifference called on view we don't own");
   if (aRect.y < aCutOut.y) {
-    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aRect.y, aCutOut.y, false);
+    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aRect.y, aCutOut.y, false);
   }
   if (aCutOut.y < aCutOut.YMost()) {
-    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aCutOut.y, aCutOut.YMost(), true);
+    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aCutOut.y, aCutOut.YMost(), true);
   }
   if (aCutOut.YMost() < aRect.YMost()) {
-    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aCutOut.YMost(), aRect.YMost(), false);
+    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aCutOut.YMost(), aRect.YMost(), false);
   }
 }
 
 NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, bool aRepaintExposedAreaOnly)
 {
   nsView* view = static_cast<nsView*>(aView);
   NS_ASSERTION(view->GetViewManager() == this, "wrong view manager");
 
@@ -1277,24 +1170,23 @@ NS_IMETHODIMP nsViewManager::ResizeView(
       nsView* parentView = view->GetParent();
       if (!parentView) {
         parentView = view;
       }
       nsRect oldBounds = view->GetBoundsInParentUnits();
       view->SetDimensions(aRect, true);
       nsViewManager* parentVM = parentView->GetViewManager();
       if (!aRepaintExposedAreaOnly) {
-        //Invalidate the union of the old and new size
-        UpdateView(view, aRect, NS_VMREFRESH_NO_SYNC);
-        parentVM->UpdateView(parentView, oldBounds, NS_VMREFRESH_NO_SYNC);
+        // Invalidate the union of the old and new size
+        InvalidateView(view, aRect);
+        parentVM->InvalidateView(parentView, oldBounds);
       } else {
-        InvalidateRectDifference(view, aRect, oldDimensions, NS_VMREFRESH_NO_SYNC);
+        InvalidateRectDifference(view, aRect, oldDimensions);
         nsRect newBounds = view->GetBoundsInParentUnits();
-        parentVM->InvalidateRectDifference(parentView, oldBounds, newBounds,
-                                           NS_VMREFRESH_NO_SYNC);
+        parentVM->InvalidateRectDifference(parentView, oldBounds, newBounds);
       } 
     }
   }
 
   // Note that if layout resizes the view and the view has a custom clip
   // region set, then we expect layout to update the clip region too. Thus
   // in the case where mClipRect has been optimized away to just be a null
   // pointer, and this resize is implicitly changing the clip rect, it's OK
@@ -1323,60 +1215,28 @@ NS_IMETHODIMP nsViewManager::SetViewVisi
     view->SetVisibility(aVisible);
 
     if (IsViewInserted(view)) {
       if (!view->HasWidget()) {
         if (nsViewVisibility_kHide == aVisible) {
           nsView* parentView = view->GetParent();
           if (parentView) {
             parentView->GetViewManager()->
-              UpdateView(parentView, view->GetBoundsInParentUnits(),
-                         NS_VMREFRESH_NO_SYNC);
+              InvalidateView(parentView, view->GetBoundsInParentUnits());
           }
         }
         else {
-          UpdateView(view, NS_VMREFRESH_NO_SYNC);
+          InvalidateView(view);
         }
       }
     }
   }
   return NS_OK;
 }
 
-void nsViewManager::UpdateWidgetsForView(nsView* aView)
-{
-  NS_PRECONDITION(aView, "Must have view!");
-
-  // No point forcing an update if invalidations have been suppressed.
-  if (!IsRefreshEnabled())
-    return;  
-
-  nsWeakView parentWeakView = aView;
-  if (aView->HasWidget()) {
-    aView->GetWidget()->Update();  // Flushes Layout!
-    if (!parentWeakView.IsAlive()) {
-      return;
-    }
-  }
-
-  nsView* childView = aView->GetFirstChild();
-  while (childView) {
-    nsWeakView childWeakView = childView;
-    UpdateWidgetsForView(childView);
-    if (NS_LIKELY(childWeakView.IsAlive())) {
-      childView = childView->GetNextSibling();
-    }
-    else {
-      // The current view was destroyed - restart at the first child if the
-      // parent is still alive.
-      childView = parentWeakView.IsAlive() ? aView->GetFirstChild() : nsnull;
-    }
-  }
-}
-
 bool nsViewManager::IsViewInserted(nsView *aView)
 {
   if (mRootView == aView) {
     return true;
   } else if (aView->GetParent() == nsnull) {
     return false;
   } else {
     nsView* view = aView->GetParent()->GetFirstChild();
@@ -1410,91 +1270,47 @@ NS_IMETHODIMP nsViewManager::SetViewZInd
     aZIndex = 0;
   }
 
   PRInt32 oldidx = view->GetZIndex();
   view->SetZIndex(aAutoZIndex, aZIndex, aTopMost);
 
   if (oldidx != aZIndex || oldTopMost != aTopMost ||
       oldIsAuto != aAutoZIndex) {
-    UpdateView(view, NS_VMREFRESH_NO_SYNC);
+    InvalidateView(view);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP nsViewManager::GetDeviceContext(nsDeviceContext *&aContext)
 {
   aContext = mContext;
   NS_IF_ADDREF(aContext);
   return NS_OK;
 }
 
-void nsViewManager::TriggerRefresh(PRUint32 aUpdateFlags)
+nsIViewManager*
+nsViewManager::IncrementDisableRefreshCount()
 {
   if (!IsRootVM()) {
-    RootViewManager()->TriggerRefresh(aUpdateFlags);
-    return;
-  }
-  
-  if (mUpdateBatchCnt > 0)
-    return;
-
-  // nested batching can combine IMMEDIATE with DEFERRED. Favour
-  // IMMEDIATE over DEFERRED and DEFERRED over NO_SYNC.  We need to
-  // check for IMMEDIATE before checking mHasPendingUpdates, because
-  // the latter might be false as far as gecko is concerned but the OS
-  // might still have queued up expose events that it hasn't sent yet.
-  if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) {
-    FlushPendingInvalidates();
-    Composite();
-  } else if (!mHasPendingUpdates) {
-    // Nothing to do
-  } else if (aUpdateFlags & NS_VMREFRESH_DEFERRED) {
-    PostInvalidateEvent();
-  } else { // NO_SYNC
-    FlushPendingInvalidates();
-  }
-}
-
-nsIViewManager* nsViewManager::BeginUpdateViewBatch(void)
-{
-  if (!IsRootVM()) {
-    return RootViewManager()->BeginUpdateViewBatch();
-  }
-  
-  if (mUpdateBatchCnt == 0) {
-    mUpdateBatchFlags = 0;
+    return RootViewManager()->IncrementDisableRefreshCount();
   }
 
-  ++mUpdateBatchCnt;
+  ++mRefreshDisableCount;
 
   return this;
 }
 
-NS_IMETHODIMP nsViewManager::EndUpdateViewBatch(PRUint32 aUpdateFlags)
+void
+nsViewManager::DecrementDisableRefreshCount()
 {
   NS_ASSERTION(IsRootVM(), "Should only be called on root");
-  
-  --mUpdateBatchCnt;
-
-  NS_ASSERTION(mUpdateBatchCnt >= 0, "Invalid batch count!");
-
-  if (mUpdateBatchCnt < 0)
-    {
-      mUpdateBatchCnt = 0;
-      return NS_ERROR_FAILURE;
-    }
-
-  mUpdateBatchFlags |= aUpdateFlags;
-  if (mUpdateBatchCnt == 0) {
-    TriggerRefresh(mUpdateBatchFlags);
-  }
-
-  return NS_OK;
+  --mRefreshDisableCount;
+  NS_ASSERTION(mRefreshDisableCount >= 0, "Invalid refresh disable count!");
 }
 
 NS_IMETHODIMP nsViewManager::GetRootWidget(nsIWidget **aWidget)
 {
   if (!mRootView) {
     *aWidget = nsnull;
     return NS_OK;
   }
@@ -1504,30 +1320,16 @@ NS_IMETHODIMP nsViewManager::GetRootWidg
     return NS_OK;
   }
   if (mRootView->GetParent())
     return mRootView->GetParent()->GetViewManager()->GetRootWidget(aWidget);
   *aWidget = nsnull;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsViewManager::ForceUpdate()
-{
-  if (!IsRootVM()) {
-    return RootViewManager()->ForceUpdate();
-  }
-
-  // Walk the view tree looking for widgets, and call Update() on each one
-  if (mRootView) {
-    UpdateWidgetsForView(mRootView);
-  }
-  
-  return NS_OK;
-}
-
 nsIntRect nsViewManager::ViewToWidget(nsView *aView, const nsRect &aRect) const
 {
   NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
 
   // intersect aRect with bounds of aView, to prevent generating any illegal rectangles.
   nsRect bounds = aView->GetInvalidationDimensions();
   nsRect rect;
   rect.IntersectRect(aRect, bounds);
@@ -1542,47 +1344,57 @@ nsIntRect nsViewManager::ViewToWidget(ns
 NS_IMETHODIMP
 nsViewManager::IsPainting(bool& aIsPainting)
 {
   aIsPainting = IsPainting();
   return NS_OK;
 }
 
 void
-nsViewManager::FlushPendingInvalidates()
+nsViewManager::ProcessPendingUpdates()
 {
-  NS_ASSERTION(IsRootVM(), "Must be root VM for this to be called!");
-  NS_ASSERTION(mUpdateBatchCnt == 0, "Must not be in an update batch!");
+  if (!IsRootVM()) {
+    RootViewManager()->ProcessPendingUpdates();
+    return;
+  }
 
   if (mHasPendingUpdates) {
-    ProcessPendingUpdates(mRootView, true);
+    ProcessPendingUpdatesForView(mRootView, true);
     mHasPendingUpdates = false;
   }
 }
 
 void
+nsViewManager::UpdateWidgetGeometry()
+{
+  if (!IsRootVM()) {
+    RootViewManager()->UpdateWidgetGeometry();
+    return;
+  }
+
+  if (mHasPendingWidgetGeometryChanges) {
+    ProcessPendingUpdatesForView(mRootView, false);
+    mHasPendingWidgetGeometryChanges = false;
+  }
+}
+
+void
 nsViewManager::CallWillPaintOnObservers(bool aWillSendDidPaint)
 {
   NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
-  NS_PRECONDITION(mUpdateBatchCnt > 0, "Must be in an update batch!");
 
-#ifdef DEBUG
-  PRInt32 savedUpdateBatchCnt = mUpdateBatchCnt;
-#endif
   PRInt32 index;
   for (index = 0; index < mVMCount; index++) {
     nsViewManager* vm = (nsViewManager*)gViewManagers->ElementAt(index);
     if (vm->RootViewManager() == this) {
       // One of our kids.
       if (vm->mRootView && vm->mRootView->IsEffectivelyVisible()) {
         nsCOMPtr<nsIPresShell> shell = vm->GetPresShell();
         if (shell) {
           shell->WillPaint(aWillSendDidPaint);
-          NS_ASSERTION(mUpdateBatchCnt == savedUpdateBatchCnt,
-                       "Observer did not end view batch?");
         }
       }
     }
   }
 }
 
 void
 nsViewManager::CallDidPaintOnObservers()
@@ -1599,34 +1411,16 @@ nsViewManager::CallDidPaintOnObservers()
         if (shell) {
           shell->DidPaint();
         }
       }
     }
   }
 }
 
-void
-nsViewManager::ProcessInvalidateEvent()
-{
-  NS_ASSERTION(IsRootVM(),
-               "Incorrectly targeted invalidate event");
-  // If we're in the middle of an update batch, just repost the event,
-  // to be processed when the batch ends.
-  bool processEvent = (mUpdateBatchCnt == 0);
-  if (processEvent) {
-    FlushPendingInvalidates();
-  }
-  mInvalidateEvent.Forget();
-  if (!processEvent) {
-    // We didn't actually process this event... post a new one
-    PostInvalidateEvent();
-  }
-}
-
 NS_IMETHODIMP
 nsViewManager::GetLastUserEventTime(PRUint32& aTime)
 {
   aTime = gLastUserEventTime;
   return NS_OK;
 }
 
 void
--- a/view/src/nsViewManager.h
+++ b/view/src/nsViewManager.h
@@ -48,46 +48,37 @@
 #include "nsView.h"
 #include "nsIPresShell.h"
 #include "nsDeviceContext.h"
 
 
 /**
    Invalidation model:
 
-   1) Callers call into the view manager and ask it to update a view.
+   1) Callers call into the view manager and ask it to invalidate a view.
    
    2) The view manager finds the "right" widget for the view, henceforth called
       the root widget.
 
    3) The view manager traverses descendants of the root widget and for each
-      one that needs invalidation either
+      one that needs invalidation stores the rect to invalidate on the widget's
+      view (batching).
 
-      a)  Calls Invalidate() on the widget (no batching)
-    or
-      b)  Stores the rect to invalidate on the widget's view (batching)
-
-   // XXXbz we want to change this a bit.  See bug 243726
-
-   4) When batching, the call to end the batch either processes the pending
-      Invalidate() calls on the widgets or posts an event to do so.
+   4) The dirty region is flushed to the right widget when
+      ProcessPendingUpdates is called from the RefreshDriver.
 
    It's important to note that widgets associated to views outside this view
    manager can end up being invalidated during step 3.  Therefore, the end of a
    view update batch really needs to traverse the entire view tree, to ensure
    that those invalidates happen.
 
-   To cope with this, invalidate event processing and view update batch
-   handling should only happen on the root viewmanager.  This means the root
-   view manager is the only thing keeping track of mUpdateCnt.  As a result,
-   Composite() calls should also be forwarded to the root view manager.
+   To cope with this, invalidation processing and should only happen on the
+   root viewmanager.
 */
 
-class nsInvalidateEvent;
-
 class nsViewManager : public nsIViewManager {
 public:
   nsViewManager();
 
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
   NS_DECL_ISUPPORTS
 
@@ -99,22 +90,19 @@ public:
 
   NS_IMETHOD_(nsIView*) GetRootView();
   NS_IMETHOD  SetRootView(nsIView *aView);
 
   NS_IMETHOD  GetWindowDimensions(nscoord *width, nscoord *height);
   NS_IMETHOD  SetWindowDimensions(nscoord width, nscoord height);
   NS_IMETHOD  FlushDelayedResize(bool aDoReflow);
 
-  NS_IMETHOD  Composite(void);
-
-  NS_IMETHOD  UpdateView(nsIView *aView, PRUint32 aUpdateFlags);
-  NS_IMETHOD  UpdateViewNoSuppression(nsIView *aView, const nsRect &aRect,
-                                      PRUint32 aUpdateFlags);
-  NS_IMETHOD  UpdateAllViews(PRUint32 aUpdateFlags);
+  NS_IMETHOD  InvalidateView(nsIView *aView);
+  NS_IMETHOD  InvalidateViewNoSuppression(nsIView *aView, const nsRect &aRect);
+  NS_IMETHOD  InvalidateAllViews();
 
   NS_IMETHOD  DispatchEvent(nsGUIEvent *aEvent,
       nsIView* aTargetView, nsEventStatus* aStatus);
 
   NS_IMETHOD  InsertChild(nsIView *parent, nsIView *child, nsIView *sibling,
                           bool above);
 
   NS_IMETHOD  InsertChild(nsIView *parent, nsIView *child,
@@ -132,128 +120,99 @@ public:
 
   NS_IMETHOD  SetViewZIndex(nsIView *aView, bool aAuto, PRInt32 aZIndex, bool aTopMost=false);
 
   virtual void SetPresShell(nsIPresShell *aPresShell) { mPresShell = aPresShell; }
   virtual nsIPresShell* GetPresShell() { return mPresShell; }
 
   NS_IMETHOD  GetDeviceContext(nsDeviceContext *&aContext);
 
-  virtual nsIViewManager* BeginUpdateViewBatch(void);
-  NS_IMETHOD  EndUpdateViewBatch(PRUint32 aUpdateFlags);
+  virtual nsIViewManager* IncrementDisableRefreshCount();
+  virtual void DecrementDisableRefreshCount();
 
   NS_IMETHOD GetRootWidget(nsIWidget **aWidget);
-  NS_IMETHOD ForceUpdate();
  
   NS_IMETHOD IsPainting(bool& aIsPainting);
   NS_IMETHOD GetLastUserEventTime(PRUint32& aTime);
-  void ProcessInvalidateEvent();
   static PRUint32 gLastUserEventTime;
 
   /* Update the cached RootViewManager pointer on this view manager. */
   void InvalidateHierarchy();
 
+  virtual void ProcessPendingUpdates();
+  virtual void UpdateWidgetGeometry();
+
 protected:
   virtual ~nsViewManager();
 
 private:
 
   void FlushPendingInvalidates();
-  void ProcessPendingUpdates(nsView *aView, bool aDoInvalidate);
+  void ProcessPendingUpdatesForView(nsView *aView,
+                                    bool aFlushDirtyRegion = true);
+  void FlushDirtyRegionToWidget(nsView* aView);
   /**
    * Call WillPaint() on all view observers under this vm root.
    */
   void CallWillPaintOnObservers(bool aWillSendDidPaint);
   void CallDidPaintOnObservers();
   void ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget);
   void ReparentWidgets(nsIView* aView, nsIView *aParent);
-  void UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
-                        const nsRegion &aDamagedRegion,
-                        nsView* aIgnoreWidgetView);
+  void InvalidateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedRegion);
 
-  void UpdateViews(nsView *aView, PRUint32 aUpdateFlags);
-
-  void TriggerRefresh(PRUint32 aUpdateFlags);
+  void InvalidateViews(nsView *aView);
 
   // aView is the view for aWidget and aRegion is relative to aWidget.
   void Refresh(nsView *aView, nsIWidget *aWidget, const nsIntRegion& aRegion);
   // aRootView is the view for aWidget, aRegion is relative to aRootView, and
   // aIntRegion is relative to aWidget.
   void RenderViews(nsView *aRootView, nsIWidget *aWidget,
                    const nsRegion& aRegion, const nsIntRegion& aIntRegion,
                    bool aPaintDefaultBackground, bool aWillSendDidPaint);
 
-  void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut, PRUint32 aUpdateFlags);
+  void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut);
   void InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
-                                          PRUint32 aUpdateFlags, nscoord aY1, nscoord aY2, bool aInCutOut);
+                                          nscoord aY1, nscoord aY2, bool aInCutOut);
 
   // Utilities
 
   bool IsViewInserted(nsView *aView);
 
   /**
-   * Function to recursively call Update() on all widgets belonging to
-   * a view or its kids.
-   */
-  void UpdateWidgetsForView(nsView* aView);
-
-  /**
    * Intersects aRect with aView's bounds and then transforms it from aView's
    * coordinate system to the coordinate system of the widget attached to
    * aView.
    */
   nsIntRect ViewToWidget(nsView *aView, const nsRect &aRect) const;
 
   void DoSetWindowDimensions(nscoord aWidth, nscoord aHeight);
 
-  // Safety helpers
-  void IncrementUpdateCount() {
-    NS_ASSERTION(IsRootVM(),
-                 "IncrementUpdateCount called on non-root viewmanager");
-    ++mUpdateCnt;
-  }
-
-  void DecrementUpdateCount() {
-    NS_ASSERTION(IsRootVM(),
-                 "DecrementUpdateCount called on non-root viewmanager");
-    --mUpdateCnt;
-  }
-
-  PRInt32 UpdateCount() const {
-    NS_ASSERTION(IsRootVM(),
-                 "DecrementUpdateCount called on non-root viewmanager");
-    return mUpdateCnt;
-  }
-
-  void ClearUpdateCount() {
-    NS_ASSERTION(IsRootVM(),
-                 "DecrementUpdateCount called on non-root viewmanager");
-    mUpdateCnt = 0;
-  }
-
   bool IsPainting() const {
     return RootViewManager()->mPainting;
   }
 
   void SetPainting(bool aPainting) {
     RootViewManager()->mPainting = aPainting;
   }
 
-  nsresult UpdateView(nsIView *aView, const nsRect &aRect, PRUint32 aUpdateFlags);
+  nsresult InvalidateView(nsIView *aView, const nsRect &aRect);
 
 public: // NOT in nsIViewManager, so private to the view module
   nsView* GetRootViewImpl() const { return mRootView; }
   nsViewManager* RootViewManager() const { return mRootViewManager; }
   bool IsRootVM() const { return this == RootViewManager(); }
 
-  bool IsRefreshEnabled() { return RootViewManager()->mUpdateBatchCnt == 0; }
+  // Whether synchronous painting is allowed at the moment. For example,
+  // widget geometry changes can cause synchronous painting, so they need to
+  // be deferred while refresh is disabled.
+  bool IsPaintingAllowed() { return RootViewManager()->mRefreshDisableCount == 0; }
 
   // Call this when you need to let the viewmanager know that it now has
   // pending updates.
-  void PostPendingUpdate() { RootViewManager()->mHasPendingUpdates = true; }
+  void PostPendingUpdate();
 
   PRUint32 AppUnitsPerDevPixel() const
   {
     return mContext->AppUnitsPerDevPixel();
   }
 
 private:
   nsRefPtr<nsDeviceContext> mContext;
@@ -263,51 +222,28 @@ private:
   // visible again.
   nsSize            mDelayedResize;
 
   nsView            *mRootView;
   // mRootViewManager is a strong ref unless it equals |this|.  It's
   // never null (if we have no ancestors, it will be |this|).
   nsViewManager     *mRootViewManager;
 
-  nsRevocableEventPtr<nsInvalidateEvent> mInvalidateEvent;
-
   // The following members should not be accessed directly except by
   // the root view manager.  Some have accessor functions to enforce
   // this, as noted.
   
-  // Use IncrementUpdateCount(), DecrementUpdateCount(), UpdateCount(),
-  // ClearUpdateCount() on the root viewmanager to access mUpdateCnt.
-  PRInt32           mUpdateCnt;
-  PRInt32           mUpdateBatchCnt;
-  PRUint32          mUpdateBatchFlags;
+  PRInt32           mRefreshDisableCount;
   // Use IsPainting() and SetPainting() to access mPainting.
   bool              mPainting;
   bool              mRecursiveRefreshPending;
   bool              mHasPendingUpdates;
+  bool              mHasPendingWidgetGeometryChanges;
   bool              mInScroll;
 
   //from here to public should be static and locked... MMP
   static PRInt32           mVMCount;        //number of viewmanagers
 
   //list of view managers
   static nsVoidArray       *gViewManagers;
-
-  void PostInvalidateEvent();
-};
-
-class nsInvalidateEvent : public nsRunnable {
-public:
-  nsInvalidateEvent(class nsViewManager *vm) : mViewManager(vm) {
-    NS_ASSERTION(mViewManager, "null parameter");
-  }
-  void Revoke() { mViewManager = nsnull; }
-
-  NS_IMETHOD Run() {
-    if (mViewManager)
-      mViewManager->ProcessInvalidateEvent();
-    return NS_OK;
-  }
-protected:
-  class nsViewManager *mViewManager;
 };
 
 #endif /* nsViewManager_h___ */
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -585,30 +585,23 @@ nsWindow::Enable(bool aState)
 NS_IMETHODIMP
 nsWindow::IsEnabled(bool *aState)
 {
     *aState = true;
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsWindow::Invalidate(const nsIntRect &aRect,
-                     bool aIsSynchronous)
+nsWindow::Invalidate(const nsIntRect &aRect)
 {
     AndroidGeckoEvent *event = new AndroidGeckoEvent(AndroidGeckoEvent::DRAW, aRect);
     nsAppShell::gAppShell->PostEvent(event);
     return NS_OK;
 }
 
-NS_IMETHODIMP
-nsWindow::Update()
-{
-    return NS_OK;
-}
-
 nsWindow*
 nsWindow::FindTopLevel()
 {
     nsWindow *toplevel = this;
     while (toplevel) {
         if (toplevel->IsTopLevel())
             return toplevel;
 
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -115,19 +115,17 @@ public:
                       bool aRepaint);
     NS_IMETHOD SetZIndex(PRInt32 aZIndex);
     NS_IMETHOD PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
                            nsIWidget *aWidget,
                            bool aActivate);
     NS_IMETHOD SetSizeMode(PRInt32 aMode);
     NS_IMETHOD Enable(bool aState);
     NS_IMETHOD IsEnabled(bool *aState);
-    NS_IMETHOD Invalidate(const nsIntRect &aRect,
-                          bool aIsSynchronous);
-    NS_IMETHOD Update();
+    NS_IMETHOD Invalidate(const nsIntRect &aRect);
     NS_IMETHOD SetFocus(bool aRaise = false);
     NS_IMETHOD GetScreenBounds(nsIntRect &aRect);
     virtual nsIntPoint WidgetToScreenOffset();
     NS_IMETHOD DispatchEvent(nsGUIEvent *aEvent, nsEventStatus &aStatus);
     nsEventStatus DispatchEvent(nsGUIEvent *aEvent);
     NS_IMETHOD MakeFullScreen(bool aFullScreen);
     NS_IMETHOD SetWindowClass(const nsAString& xulWinType);
 
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -413,28 +413,27 @@ public:
   NS_IMETHOD              Resize(PRInt32 aWidth,PRInt32 aHeight, bool aRepaint);
   NS_IMETHOD              Resize(PRInt32 aX, PRInt32 aY,PRInt32 aWidth,PRInt32 aHeight, bool aRepaint);
 
   NS_IMETHOD              Enable(bool aState);
   NS_IMETHOD              IsEnabled(bool *aState);
   NS_IMETHOD              SetFocus(bool aRaise);
   NS_IMETHOD              GetBounds(nsIntRect &aRect);
 
-  NS_IMETHOD              Invalidate(const nsIntRect &aRect, bool aIsSynchronous);
+  NS_IMETHOD              Invalidate(const nsIntRect &aRect);
 
   virtual void*           GetNativeData(PRUint32 aDataType);
   virtual nsresult        ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
   virtual nsIntPoint      WidgetToScreenOffset();
   virtual bool            ShowsResizeIndicator(nsIntRect* aResizerRect);
 
   static  bool            ConvertStatus(nsEventStatus aStatus)
                           { return aStatus == nsEventStatus_eConsumeNoDefault; }
   NS_IMETHOD              DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus);
 
-  NS_IMETHOD              Update();
   virtual bool            GetShouldAccelerate();
 
   NS_IMETHOD        SetCursor(nsCursor aCursor);
   NS_IMETHOD        SetCursor(imgIContainer* aCursor, PRUint32 aHotspotX, PRUint32 aHotspotY);
   
   NS_IMETHOD        CaptureRollupEvents(nsIRollupListener * aListener, bool aDoCapture, bool aConsumeRollupEvent);
   NS_IMETHOD        SetTitle(const nsAString& title);
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -1393,30 +1393,27 @@ static void blinkRgn(RgnHandle rgn)
 
   if (oldClip != NULL)
     ::SetClip(oldClip);
 }
 
 #endif
 
 // Invalidate this component's visible area
-NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect, bool aIsSynchronous)
+NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   if (!mView || !mVisible)
     return NS_OK;
 
   NSRect r;
   nsCocoaUtils::GeckoRectToNSRect(aRect, r);
   
-  if (aIsSynchronous) {
-    [mView displayRect:r];
-  }
-  else if ([NSView focusView]) {
+  if ([NSView focusView]) {
     // if a view is focussed (i.e. being drawn), then postpone the invalidate so that we
     // don't lose it.
     [mView setNeedsPendingDisplayInRect:r];
   }
   else {
     [mView setNeedsDisplayInRect:r];
   }
 
@@ -1437,25 +1434,16 @@ nsChildView::GetShouldAccelerate()
 }
 
 inline PRUint16 COLOR8TOCOLOR16(PRUint8 color8)
 {
   // return (color8 == 0xFF ? 0xFFFF : (color8 << 8));
   return (color8 << 8) | color8;  /* (color8 * 257) == (color8 * 0x0101) */
 }
 
-// The OS manages repaints well enough on its own, so we don't have to
-// flush them out here.  In other words, the OS will automatically call
-// displayIfNeeded at the appropriate times, so we don't need to do it
-// ourselves.  See bmo bug 459319.
-NS_IMETHODIMP nsChildView::Update()
-{
-  return NS_OK;
-}
-
 #pragma mark -
 
 nsresult nsChildView::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
 {
   for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
     const Configuration& config = aConfigurations[i];
     nsChildView* child = static_cast<nsChildView*>(config.mChild);
 #ifdef DEBUG
@@ -2515,16 +2503,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
            aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height, aContext,
            geckoBounds.x, geckoBounds.y, geckoBounds.width, geckoBounds.height);
 
   CGAffineTransform xform = CGContextGetCTM(aContext);
   fprintf (stderr, "  xform in: [%f %f %f %f %f %f]\n", xform.a, xform.b, xform.c, xform.d, xform.tx, xform.ty);
 #endif
   // Create the event so we can fill in its region
   nsPaintEvent paintEvent(true, NS_PAINT, mGeckoChild);
+  paintEvent.didSendWillPaint = true;
 
   nsIntRect boundingRect =
     nsIntRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
   const NSRect *rects;
   NSInteger count, i;
   [[NSView focusView] getRectsBeingDrawn:&rects count:&count];
   if (count < MAX_RECTS_IN_REGION) {
     for (i = 0; i < count; ++i) {
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -247,18 +247,17 @@ public:
     NS_IMETHOD              GetScreenBounds(nsIntRect &aRect);
     void                    ReportMoveEvent();
     void                    ReportSizeEvent();
     NS_IMETHOD              SetCursor(nsCursor aCursor);
     NS_IMETHOD              SetCursor(imgIContainer* aCursor, PRUint32 aHotspotX, PRUint32 aHotspotY);
 
     NS_IMETHOD              SetTitle(const nsAString& aTitle);
 
-    NS_IMETHOD Invalidate(const nsIntRect &aRect, bool aIsSynchronous);
-    NS_IMETHOD Update();
+    NS_IMETHOD Invalidate(const nsIntRect &aRect);
     virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
     virtual LayerManager* GetLayerManager(PLayersChild* aShadowManager = nsnull,
                                           LayersBackend aBackendHint = LayerManager::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                           bool* aAllowRetaining = nsnull);
     NS_IMETHOD DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus) ;
     NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, bool aDoCapture, bool aConsumeRollupEvent);
     NS_IMETHOD GetAttention(PRInt32 aCycleCount);
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -1274,28 +1274,20 @@ NS_IMETHODIMP nsCocoaWindow::SetTitle(co
   NSString* title = [NSString stringWithCharacters:strTitle.get() length:strTitle.Length()];
   [mWindow setTitle:title];
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
-NS_IMETHODIMP nsCocoaWindow::Invalidate(const nsIntRect & aRect, bool aIsSynchronous)
+NS_IMETHODIMP nsCocoaWindow::Invalidate(const nsIntRect & aRect)
 {
   if (mPopupContentView)
-    return mPopupContentView->Invalidate(aRect, aIsSynchronous);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsCocoaWindow::Update()
-{
-  if (mPopupContentView)
-    return mPopupContentView->Update();
+    return mPopupContentView->Invalidate(aRect);
 
   return NS_OK;
 }
 
 // Pass notification of some drag event to Gecko
 //
 // The drag manager has let us know that something related to a drag has
 // occurred in this window. It could be any number of things, ranging from 
--- a/widget/gtk2/nsNativeThemeGTK.cpp
+++ b/widget/gtk2/nsNativeThemeGTK.cpp
@@ -111,17 +111,17 @@ nsNativeThemeGTK::RefreshWidgetWindow(ns
   nsIPresShell *shell = GetPresShell(aFrame);
   if (!shell)
     return;
 
   nsIViewManager* vm = shell->GetViewManager();
   if (!vm)
     return;
  
-  vm->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
+  vm->InvalidateAllViews();
 }
 
 static bool IsFrameContentNodeInNamespace(nsIFrame *aFrame, PRUint32 aNamespace)
 {
   nsIContent *content = aFrame ? aFrame->GetContent() : nsnull;
   if (!content)
     return false;
   return content->IsInNamespace(aNamespace);
--- a/widget/gtk2/nsWindow.cpp
+++ b/widget/gtk2/nsWindow.cpp
@@ -1690,49 +1690,32 @@ nsWindow::SetCursor(imgIContainer* aCurs
         }
         gdk_cursor_unref(cursor);
     }
 
     return rv;
 }
 
 NS_IMETHODIMP
-nsWindow::Invalidate(const nsIntRect &aRect,
-                     bool             aIsSynchronous)
+nsWindow::Invalidate(const nsIntRect &aRect)
 {
     if (!mGdkWindow)
         return NS_OK;
 
     GdkRectangle rect;
     rect.x = aRect.x;
     rect.y = aRect.y;
     rect.width = aRect.width;
     rect.height = aRect.height;
 
-    LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d (sync: %d)\n", (void *)this,
-             rect.x, rect.y, rect.width, rect.height, aIsSynchronous));
+    LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d\n", (void *)this,
+             rect.x, rect.y, rect.width, rect.height));
 
     gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
-    if (aIsSynchronous)
-        gdk_window_process_updates(mGdkWindow, FALSE);
-
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindow::Update()
-{
-    if (!mGdkWindow)
-        return NS_OK;
-
-    LOGDRAW(("Update [%p] %p\n", this, mGdkWindow));
-
-    gdk_window_process_updates(mGdkWindow, FALSE);
-    // Send the updates to the server.
-    gdk_display_flush(gdk_window_get_display(mGdkWindow));
+
     return NS_OK;
 }
 
 void*
 nsWindow::GetNativeData(PRUint32 aDataType)
 {
     switch (aDataType) {
     case NS_NATIVE_WINDOW:
--- a/widget/gtk2/nsWindow.h
+++ b/widget/gtk2/nsWindow.h
@@ -168,19 +168,17 @@ public:
     NS_IMETHOD         GetScreenBounds(nsIntRect &aRect);
     NS_IMETHOD         GetClientBounds(nsIntRect &aRect);
     virtual nsIntPoint GetClientOffset();
     NS_IMETHOD         SetForegroundColor(const nscolor &aColor);
     NS_IMETHOD         SetBackgroundColor(const nscolor &aColor);
     NS_IMETHOD         SetCursor(nsCursor aCursor);
     NS_IMETHOD         SetCursor(imgIContainer* aCursor,
                                  PRUint32 aHotspotX, PRUint32 aHotspotY);
-    NS_IMETHOD         Invalidate(const nsIntRect &aRect,
-                                  bool             aIsSynchronous);
-    NS_IMETHOD         Update();
+    NS_IMETHOD         Invalidate(const nsIntRect &aRect);
     virtual void*      GetNativeData(PRUint32 aDataType);
     NS_IMETHOD         SetTitle(const nsAString& aTitle);
     NS_IMETHOD         SetIcon(const nsAString& aIconSpec);
     NS_IMETHOD         SetWindowClass(const nsAString& xulWinType);
     virtual nsIntPoint WidgetToScreenOffset();
     NS_IMETHOD         EnableDragDrop(bool aEnable);
     NS_IMETHOD         CaptureMouse(bool aCapture);
     NS_IMETHOD         CaptureRollupEvents(nsIRollupListener *aListener,
--- a/widget/nsGUIEvent.h
+++ b/widget/nsGUIEvent.h
@@ -732,23 +732,25 @@ public:
  * Window repaint event
  */
 
 class nsPaintEvent : public nsGUIEvent
 {
 public:
   nsPaintEvent(bool isTrusted, PRUint32 msg, nsIWidget *w)
     : nsGUIEvent(isTrusted, msg, w, NS_PAINT_EVENT),
-      willSendDidPaint(false)
+      willSendDidPaint(false),
+      didSendWillPaint(false)
   {
   }
 
   // area that needs repainting
   nsIntRegion region;
   bool willSendDidPaint;
+  bool didSendWillPaint;
 };
 
 /**
  * Scrollbar event
  */
 
 class nsScrollbarEvent : public nsGUIEvent
 {
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -113,18 +113,18 @@ typedef nsEventStatus (* EVENT_CALLBACK)
 #endif
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #endif
 
 #define NS_IWIDGET_IID \
-  { 0x6ca77c11, 0xade7, 0x4715, \
-    { 0x82, 0xe0, 0xfe, 0xae, 0x42, 0xca, 0x5b, 0x1f } }
+  { 0xba20ac65, 0xb2a6, 0x4052, \
+    { 0xa4, 0xcb, 0x65, 0x40, 0xf8, 0x87, 0x9c, 0x55 } }
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
 #define NS_STYLE_WINDOW_SHADOW_MENU             2
@@ -1016,31 +1016,20 @@ class nsIWidget : public nsISupports {
 
     /**
      * Put the toplevel window into or out of fullscreen mode.
      *
      */
     NS_IMETHOD MakeFullScreen(bool aFullScreen) = 0;
 
     /**
-     * Invalidate a specified rect for a widget and repaints it.
-     *
-     * @param aIsSynchronouse true then repaint synchronously. If false repaint later.
-     * @see #Update()
+     * Invalidate a specified rect for a widget so that it will be repainted
+     * later.
      */
-
-    NS_IMETHOD Invalidate(const nsIntRect & aRect, bool aIsSynchronous) = 0;
-
-    /**
-     * Force a synchronous repaint of the window if there are dirty rects.
-     *
-     * @see Invalidate()
-     */
-
-     NS_IMETHOD Update() = 0;
+    NS_IMETHOD Invalidate(const nsIntRect & aRect) = 0;
 
     enum LayerManagerPersistence
     {
       LAYER_MANAGER_CURRENT = 0,
       LAYER_MANAGER_PERSISTENT
     };
 
     /**
--- a/widget/os2/nsWindow.cpp
+++ b/widget/os2/nsWindow.cpp
@@ -612,38 +612,22 @@ NS_METHOD nsWindow::SetFocus(bool aRaise
       mInSetFocus = false;
     }
   }
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 
-NS_METHOD nsWindow::Invalidate(const nsIntRect& aRect, bool aIsSynchronous)
+NS_METHOD nsWindow::Invalidate(const nsIntRect& aRect)
 {
   if (mWnd) {
     RECTL rcl = {aRect.x, aRect.y, aRect.x + aRect.width, aRect.y + aRect.height};
     NS2PM(rcl);
     WinInvalidateRect(mWnd, &rcl, false);
-#if 0
-    if (aIsSynchronous) {
-      Update();
-    }
-#endif
-  }
-  return NS_OK;
-}
-
-//-----------------------------------------------------------------------------
-// Force a synchronous repaint of the window.
-
-NS_IMETHODIMP nsWindow::Update()
-{
-  if (mWnd) {
-    WinUpdateWindow(mWnd);
   }
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // Create a Thebes surface using the current window handle.
 
 gfxASurface* nsWindow::GetThebesSurface()
--- a/widget/os2/nsWindow.h
+++ b/widget/os2/nsWindow.h
@@ -170,19 +170,17 @@ public:
   NS_IMETHOD            Destroy();
   virtual nsIWidget*    GetParent();
   virtual float         GetDPI();
   NS_IMETHOD            Enable(bool aState);
   NS_IMETHOD            IsEnabled(bool* aState);
   NS_IMETHOD            Show(bool aState);
   NS_IMETHOD            IsVisible(bool& aState);
   NS_IMETHOD            SetFocus(bool aRaise);
-  NS_IMETHOD            Invalidate(const nsIntRect& aRect,
-                                   bool aIsSynchronous);
-  NS_IMETHOD            Update();
+  NS_IMETHOD            Invalidate(const nsIntRect& aRect);
   gfxASurface*          GetThebesSurface();
   virtual void*         GetNativeData(PRUint32 aDataType);
   virtual void          FreeNativeData(void* aDatum, PRUint32 aDataType);
   NS_IMETHOD            CaptureMouse(bool aCapture);
   virtual bool          HasPendingInputEvent();
   NS_IMETHOD            GetBounds(nsIntRect& aRect);
   NS_IMETHOD            GetClientBounds(nsIntRect& aRect);
   virtual nsIntPoint    WidgetToScreenOffset();
--- a/widget/qt/nsWindow.cpp
+++ b/widget/qt/nsWindow.cpp
@@ -746,42 +746,28 @@ nsWindow::SetCursor(nsCursor aCursor)
 NS_IMETHODIMP
 nsWindow::SetCursor(imgIContainer* aCursor,
                     PRUint32 aHotspotX, PRUint32 aHotspotY)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 NS_IMETHODIMP
-nsWindow::Invalidate(const nsIntRect &aRect,
-                     bool          aIsSynchronous)
+nsWindow::Invalidate(const nsIntRect &aRect)
 {
-    LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d (sync: %d)\n", (void *)this,
-             (void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height, aIsSynchronous));
+    LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d\n", (void *)this,
+             (void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height));
 
     if (!mWidget)
         return NS_OK;
 
     mDirtyScrollArea = mDirtyScrollArea.united(QRect(aRect.x, aRect.y, aRect.width, aRect.height));
 
     mWidget->update(aRect.x, aRect.y, aRect.width, aRect.height);
 
-    // QGraphicsItems cannot trigger a repaint themselves, so we start it on the view
-    if (aIsSynchronous) {
-        QWidget *widget = GetViewWidget();
-        if (widget)
-            widget->repaint();
-    }
-
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindow::Update()
-{
     return NS_OK;
 }
 
 // Returns the graphics view widget for this nsWindow by iterating
 // the chain of parents until a toplevel window with a view/scene is found.
 // (This function always returns something or asserts if the precondition
 // is not met)
 QWidget* nsWindow::GetViewWidget()
--- a/widget/qt/nsWindow.h
+++ b/widget/qt/nsWindow.h
@@ -168,19 +168,17 @@ public:
     NS_IMETHOD         SetBackgroundColor(const nscolor &aColor);
     NS_IMETHOD         SetCursor(nsCursor aCursor);
     NS_IMETHOD         SetCursor(imgIContainer* aCursor,
                                  PRUint32 aHotspotX, PRUint32 aHotspotY);
     NS_IMETHOD         SetHasTransparentBackground(bool aTransparent);
     NS_IMETHOD         GetHasTransparentBackground(bool& aTransparent);
     NS_IMETHOD         HideWindowChrome(bool aShouldHide);
     NS_IMETHOD         MakeFullScreen(bool aFullScreen);
-    NS_IMETHOD         Invalidate(const nsIntRect &aRect,
-                                  bool          aIsSynchronous);
-    NS_IMETHOD         Update();
+    NS_IMETHOD         Invalidate(const nsIntRect &aRect);
 
     virtual void*      GetNativeData(PRUint32 aDataType);
     NS_IMETHOD         SetTitle(const nsAString& aTitle);
     NS_IMETHOD         SetIcon(const nsAString& aIconSpec);
     virtual nsIntPoint WidgetToScreenOffset();
     NS_IMETHOD         DispatchEvent(nsGUIEvent *aEvent, nsEventStatus &aStatus);
 
     NS_IMETHOD         EnableDragDrop(bool aEnable);
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -1236,18 +1236,22 @@ NS_METHOD nsWindow::Show(bool bState)
       } else {
         ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
                        SWP_NOZORDER | SWP_NOACTIVATE);
       }
     }
   }
   
 #ifdef MOZ_XUL
-  if (!wasVisible && bState)
-    Invalidate(syncInvalidate);
+  if (!wasVisible && bState) {
+    Invalidate();
+    if (syncInvalidate) {
+      ::UpdateWindow(mWnd);
+    }
+  }
 #endif
 
   return NS_OK;
 }
 
 /**************************************************************
  *
  * SECTION: nsIWidget::IsVisible
@@ -1443,17 +1447,17 @@ NS_METHOD nsWindow::Resize(PRInt32 aWidt
     }
 
     ClearThemeRegion();
     VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
     SetThemeRegion();
   }
 
   if (aRepaint)
-    Invalidate(false);
+    Invalidate();
 
   return NS_OK;
 }
 
 // Resize this component
 NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, bool aRepaint)
 {
   NS_ASSERTION((aWidth >=0 ),  "Negative width passed to nsWindow::Resize");
@@ -1482,17 +1486,17 @@ NS_METHOD nsWindow::Resize(PRInt32 aX, P
     }
 
     ClearThemeRegion();
     VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
     SetThemeRegion();
   }
 
   if (aRepaint)
-    Invalidate(false);
+    Invalidate();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
 {
   NS_ENSURE_ARG_POINTER(aEvent);
@@ -1973,17 +1977,17 @@ nsWindow::ResetLayout()
 
   // Send a gecko size event to trigger reflow.
   RECT clientRc = {0};
   GetClientRect(mWnd, &clientRc);
   nsIntRect evRect(nsWindowGfx::ToIntRect(clientRc));
   OnResize(evRect);
 
   // Invalidate and update
-  Invalidate(false);
+  Invalidate();
 }
 
 // Internally track the caption status via a window property. Required
 // due to our internal handling of WM_NCACTIVATE when custom client
 // margins are set.
 static const PRUnichar kManageWindowInfoProperty[] = L"ManageWindowInfoProperty";
 typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi);
 static GetWindowInfoPtr sGetWindowInfoPtrStub = NULL;
@@ -2651,78 +2655,68 @@ NS_IMETHODIMP nsWindow::HideWindowChrome
  *
  * SECTION: nsWindow::Invalidate
  *
  * Invalidate an area of the client for painting.
  *
  **************************************************************/
 
 // Invalidate this component visible area
-NS_METHOD nsWindow::Invalidate(bool aIsSynchronous, 
-                               bool aEraseBackground, 
+NS_METHOD nsWindow::Invalidate(bool aEraseBackground, 
                                bool aUpdateNCArea,
                                bool aIncludeChildren)
 {
   if (!mWnd) {
     return NS_OK;
   }
 
 #ifdef WIDGET_DEBUG_OUTPUT
   debug_DumpInvalidate(stdout,
                        this,
                        nsnull,
-                       aIsSynchronous,
                        nsCAutoString("noname"),
                        (PRInt32) mWnd);
 #endif // WIDGET_DEBUG_OUTPUT
 
   DWORD flags = RDW_INVALIDATE;
   if (aEraseBackground) {
     flags |= RDW_ERASE;
   }
-  if (aIsSynchronous) {
-    flags |= RDW_UPDATENOW;
-  }
   if (aUpdateNCArea) {
     flags |= RDW_FRAME;
   }
   if (aIncludeChildren) {
     flags |= RDW_ALLCHILDREN;
   }
 
   VERIFY(::RedrawWindow(mWnd, NULL, NULL, flags));
   return NS_OK;
 }
 
 // Invalidate this component visible area
-NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, bool aIsSynchronous)
+NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect)
 {
   if (mWnd)
   {
 #ifdef WIDGET_DEBUG_OUTPUT
     debug_DumpInvalidate(stdout,
                          this,
                          &aRect,
-                         aIsSynchronous,
                          nsCAutoString("noname"),
                          (PRInt32) mWnd);
 #endif // WIDGET_DEBUG_OUTPUT
 
     RECT rect;
 
     rect.left   = aRect.x;
     rect.top    = aRect.y;
     rect.right  = aRect.x + aRect.width;
     rect.bottom = aRect.y + aRect.height;
 
     VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
-
-    if (aIsSynchronous) {
-      VERIFY(::UpdateWindow(mWnd));
-    }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::MakeFullScreen(bool aFullScreen)
 {
   // taskbarInfo will be NULL pre Windows 7 until Bug 680227 is resolved.
@@ -2752,17 +2746,17 @@ nsWindow::MakeFullScreen(bool aFullScree
   
   // Will call hide chrome, reposition window. Note this will
   // also cache dimensions for restoration, so it should only
   // be called once per fullscreen request.
   nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen);
 
   if (visible) {
     Show(true);
-    Invalidate(false);
+    Invalidate();
   }
 
   // Notify the taskbar that we have exited full screen mode.
   if (!aFullScreen && taskbarInfo) {
     taskbarInfo->PrepareFullScreenHWND(mWnd, FALSE);
   }
 
   // Let the dom know via web shell window
@@ -2771,36 +2765,16 @@ nsWindow::MakeFullScreen(bool aFullScree
   InitEvent(event);
   DispatchWindowEvent(&event);
 
   return rv;
 }
 
 /**************************************************************
  *
- * SECTION: nsIWidget::Update
- *
- * Force a synchronous repaint of the window.
- *
- **************************************************************/
-
-NS_IMETHODIMP nsWindow::Update()
-{
-  nsresult rv = NS_OK;
-
-  // updates can come through for windows no longer holding an mWnd during
-  // deletes triggered by JavaScript in buttons with mouse feedback
-  if (mWnd)
-    VERIFY(::UpdateWindow(mWnd));
-
-  return rv;
-}
-
-/**************************************************************
- *
  * SECTION: Native data storage
  *
  * nsIWidget::GetNativeData
  * nsIWidget::FreeNativeData
  *
  * Set or clear native data based on a constant.
  *
  **************************************************************/
@@ -4673,17 +4647,17 @@ bool nsWindow::ProcessMessage(UINT msg, 
       UpdateNonClientMargins();
       nsUXThemeData::InitTitlebarInfo();
       nsUXThemeData::UpdateNativeThemeInfo();
 
       DispatchStandardEvent(NS_THEMECHANGED);
 
       // Invalidate the window so that the repaint will
       // pick up the new theme.
-      Invalidate(true, true, true, true);
+      Invalidate(true, true, true);
     }
     break;
 
     case WM_FONTCHANGE:
     {
       nsresult rv;
       bool didChange = false;
 
@@ -5352,17 +5326,17 @@ bool nsWindow::ProcessMessage(UINT msg, 
     // should use same state as here for consistency painting.
     nsUXThemeData::CheckForCompositor(true);
 
     UpdateNonClientMargins();
     RemovePropW(mWnd, kManageWindowInfoProperty);
     BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
     DispatchStandardEvent(NS_THEMECHANGED);
     UpdateGlass();
-    Invalidate(true, true, true, true);
+    Invalidate(true, true, true);
     break;
 #endif
 
   case WM_UPDATEUISTATE:
   {
     // If the UI state has changed, fire an event so the UI updates the
     // keyboard cues based on the system setting and how the window was
     // opened. For example, a dialog opened via a keyboard press on a button
@@ -7241,17 +7215,17 @@ nsWindow::ConfigureChildren(const nsTArr
           GetLayerManager()->GetBackendType() != LayerManager::LAYERS_BASIC) {
         // XXX - Workaround for Bug 587508. This will invalidate the part of the
         // plugin window that might be touched by moving content somehow. The
         // underlying problem should be found and fixed!
         nsIntRegion r;
         r.Sub(bounds, configuration.mBounds);
         r.MoveBy(-bounds.x,
                  -bounds.y);
-        w->Invalidate(r.GetBounds(), false);
+        w->Invalidate(r.GetBounds());
       }
     }
     rv = w->SetWindowClipRegion(configuration.mClipRegion, false);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
@@ -7461,17 +7435,17 @@ bool nsWindow::OnMove(PRInt32 aX, PRInt3
 }
 
 // Send a resize message to the listener
 bool nsWindow::OnResize(nsIntRect &aWindowRect)
 {
 #ifdef CAIRO_HAS_D2D_SURFACE
   if (mD2DWindowSurface) {
     mD2DWindowSurface = NULL;
-    Invalidate(false);
+    Invalidate();
   }
 #endif
 
   // call the event callback
   if (mEventCallback) {
     nsSizeEvent event(true, NS_SIZE, this);
     InitEvent(event);
     event.windowSize = &aWindowRect;
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -141,22 +141,20 @@ public:
   virtual nsIntPoint      GetClientOffset();
   NS_IMETHOD              SetBackgroundColor(const nscolor &aColor);
   NS_IMETHOD              SetCursor(imgIContainer* aCursor,
                                     PRUint32 aHotspotX, PRUint32 aHotspotY);
   NS_IMETHOD              SetCursor(nsCursor aCursor);
   virtual nsresult        ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
   NS_IMETHOD              MakeFullScreen(bool aFullScreen);
   NS_IMETHOD              HideWindowChrome(bool aShouldHide);
-  NS_IMETHOD              Invalidate(bool aIsSynchronous, 
-                                     bool aEraseBackground = false,
+  NS_IMETHOD              Invalidate(bool aEraseBackground = false,
                                      bool aUpdateNCArea = false,
                                      bool aIncludeChildren = false);
-  NS_IMETHOD              Invalidate(const nsIntRect & aRect, bool aIsSynchronous);
-  NS_IMETHOD              Update();
+  NS_IMETHOD              Invalidate(const nsIntRect & aRect);
   virtual void*           GetNativeData(PRUint32 aDataType);
   virtual void            FreeNativeData(void * data, PRUint32 aDataType);
   NS_IMETHOD              SetTitle(const nsAString& aTitle);
   NS_IMETHOD              SetIcon(const nsAString& aIconSpec);
   virtual nsIntPoint      WidgetToScreenOffset();
   virtual nsIntSize       ClientToWindowSize(const nsIntSize& aClientSize);
   NS_IMETHOD              DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus);
   NS_IMETHOD              EnableDragDrop(bool aEnable);
--- a/widget/windows/nsWindowGfx.cpp
+++ b/widget/windows/nsWindowGfx.cpp
@@ -307,16 +307,17 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
 
 #ifdef MOZ_XUL
   bool forceRepaint = aDC || (eTransparencyTransparent == mTransparencyMode);
 #else
   bool forceRepaint = NULL != aDC;
 #endif
   event.region = GetRegionToPaint(forceRepaint, ps, hDC);
   event.willSendDidPaint = true;
+  event.didSendWillPaint = true;
 
   if (!event.region.IsEmpty() && mEventCallback)
   {
     // Should probably pass in a real region here, using GetRandomRgn
     // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/clipping_4q0e.asp
 
 #ifdef WIDGET_DEBUG_OUTPUT
     debug_DumpPaintEvent(stdout,
@@ -571,28 +572,28 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
           layerManagerD3D9->SetClippingRegion(event.region);
           result = DispatchWindowEvent(&event, eventStatus);
           if (layerManagerD3D9->DeviceWasRemoved()) {
             mLayerManager->Destroy();
             mLayerManager = nsnull;
             // When our device was removed, we should have gfxWindowsPlatform
             // check if its render mode is up to date!
             gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
-            Invalidate(false);
+            Invalidate();
           }
         }
         break;
 #endif
 #ifdef MOZ_ENABLE_D3D10_LAYER
       case LayerManager::LAYERS_D3D10:
         {
           gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
           LayerManagerD3D10 *layerManagerD3D10 = static_cast<mozilla::layers::LayerManagerD3D10*>(GetLayerManager());
           if (layerManagerD3D10->device() != gfxWindowsPlatform::GetPlatform()->GetD3D10Device()) {
-            Invalidate(false);
+            Invalidate();
           } else {
             result = DispatchWindowEvent(&event, eventStatus);
           }
         }
         break;
 #endif
       default:
         NS_ERROR("Unknown layers backend used!");
--- a/widget/xpwidgets/PuppetWidget.cpp
+++ b/widget/xpwidgets/PuppetWidget.cpp
@@ -51,17 +51,17 @@ using namespace mozilla::layers;
 using namespace mozilla::widget;
 using namespace mozilla::dom;
 
 static void
 InvalidateRegion(nsIWidget* aWidget, const nsIntRegion& aRegion)
 {
   nsIntRegionRectIterator it(aRegion);
   while(const nsIntRect* r = it.Next()) {
-    aWidget->Invalidate(*r, false/*async*/);
+    aWidget->Invalidate(*r);
   }
 }
 
 /*static*/ already_AddRefed<nsIWidget>
 nsIWidget::CreatePuppetWidget(PBrowserChild *aTabChild)
 {
   NS_ABORT_IF_FALSE(nsIWidget::UsePuppetWidgets(),
                     "PuppetWidgets not allowed in this configuration");
@@ -223,55 +223,37 @@ NS_IMETHODIMP
 PuppetWidget::SetFocus(bool aRaise)
 {
   // XXX/cjones: someone who knows about event handling needs to
   // decide how this should work.
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PuppetWidget::Invalidate(const nsIntRect& aRect, bool aIsSynchronous)
+PuppetWidget::Invalidate(const nsIntRect& aRect)
 {
 #ifdef DEBUG
-  debug_DumpInvalidate(stderr, this, &aRect, aIsSynchronous,
+  debug_DumpInvalidate(stderr, this, &aRect,
                        nsCAutoString("PuppetWidget"), nsnull);
 #endif
 
   if (mChild) {
-    return mChild->Invalidate(aRect, aIsSynchronous);
+    return mChild->Invalidate(aRect);
   }
 
   mDirtyRegion.Or(mDirtyRegion, aRect);
 
-  if (mDirtyRegion.IsEmpty()) {
-    return NS_OK;
-  } else if (aIsSynchronous) {
-    DispatchPaintEvent();
-    return NS_OK;
-  } else if (!mPaintTask.IsPending()) {
+  if (!mDirtyRegion.IsEmpty() && !mPaintTask.IsPending()) {
     mPaintTask = new PaintTask(this);
     return NS_DispatchToCurrentThread(mPaintTask.get());
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-PuppetWidget::Update()
-{
-  if (mChild) {
-    return mChild->Update();
-  }
-
-  if (mDirtyRegion.IsEmpty()) {
-    return NS_OK;
-  }
-  return DispatchPaintEvent();
-}
-
 void
 PuppetWidget::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
 {
   if (nsnull == aPoint) {
     event.refPoint.x = 0;
     event.refPoint.y = 0;
   }
   else {
--- a/widget/xpwidgets/PuppetWidget.h
+++ b/widget/xpwidgets/PuppetWidget.h
@@ -118,19 +118,17 @@ public:
   { *aState = mEnabled;  return NS_OK; }
 
   NS_IMETHOD SetFocus(bool aRaise = false);
 
   // PuppetWidgets don't care about children.
   virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
   { return NS_OK; }
 
-  NS_IMETHOD Invalidate(const nsIntRect& aRect, bool aIsSynchronous);
-
-  NS_IMETHOD Update();
+  NS_IMETHOD Invalidate(const nsIntRect& aRect);
 
   // This API is going away, steer clear.
   virtual void Scroll(const nsIntPoint& aDelta,
                       const nsTArray<nsIntRect>& aDestRects,
                       const nsTArray<Configuration>& aReconfigureChildren)
   { /* dead man walking */ }
 
   // PuppetWidgets don't have native data, as they're purely nonnative.
--- a/widget/xpwidgets/nsBaseWidget.cpp
+++ b/widget/xpwidgets/nsBaseWidget.cpp
@@ -1464,17 +1464,16 @@ nsBaseWidget::debug_DumpPaintEvent(FILE 
   
   fprintf(aFileOut,"\n");
 }
 //////////////////////////////////////////////////////////////
 /* static */ void
 nsBaseWidget::debug_DumpInvalidate(FILE *                aFileOut,
                                    nsIWidget *           aWidget,
                                    const nsIntRect *     aRect,
-                                   bool                  aIsSynchronous,
                                    const nsCAutoString & aWidgetName,
                                    PRInt32               aWindowID)
 {
   if (!debug_GetCachedBoolPref("nglayout.debug.invalidate_dumping"))
     return;
 
   NS_ASSERTION(nsnull != aFileOut,"cmon, null output FILE");
   NS_ASSERTION(nsnull != aWidget,"cmon, the widget is null");
@@ -1496,19 +1495,15 @@ nsBaseWidget::debug_DumpInvalidate(FILE 
             aRect->height);
   }
   else
   {
     fprintf(aFileOut,
             " rect=%-15s",
             "none");
   }
-
-  fprintf(aFileOut,
-          " sync=%s",
-          (const char *) (aIsSynchronous ? "yes" : "no "));
   
   fprintf(aFileOut,"\n");
 }
 //////////////////////////////////////////////////////////////
 
 #endif // DEBUG
 
--- a/widget/xpwidgets/nsBaseWidget.h
+++ b/widget/xpwidgets/nsBaseWidget.h
@@ -292,17 +292,16 @@ protected:
 #ifdef DEBUG
 protected:
   static nsAutoString debug_GuiEventToString(nsGUIEvent * aGuiEvent);
   static bool debug_WantPaintFlashing();
 
   static void debug_DumpInvalidate(FILE *                aFileOut,
                                    nsIWidget *           aWidget,
                                    const nsIntRect *     aRect,
-                                   bool                  aIsSynchronous,
                                    const nsCAutoString & aWidgetName,
                                    PRInt32               aWindowID);
 
   static void debug_DumpEvent(FILE *                aFileOut,
                               nsIWidget *           aWidget,
                               nsGUIEvent *          aGuiEvent,
                               const nsCAutoString & aWidgetName,
                               PRInt32               aWindowID);
--- a/xpcom/threads/Makefile.in
+++ b/xpcom/threads/Makefile.in
@@ -63,17 +63,16 @@ CPPSRCS		= \
 		HangMonitor.cpp \
 		LazyIdleThread.cpp \
 		$(NULL)
 
 EXPORTS		= \
 		nsThread.h \
 		nsProcess.h \
 		nsEventQueue.h \
-		nsThreadUtilsInternal.h \
 		$(NULL)
 
 EXPORTS_mozilla = \
   HangMonitor.h \
   LazyIdleThread.h \
   $(NULL)
 
 XPIDLSRCS	= \
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -39,17 +39,16 @@
 #include "mozilla/ReentrantMonitor.h"
 #include "nsThread.h"
 #include "nsThreadManager.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "prlog.h"
-#include "nsThreadUtilsInternal.h"
 #include "nsIObserverService.h"
 #include "mozilla/HangMonitor.h"
 #include "mozilla/Services.h"
 
 #define HAVE_UALARM _BSD_SOURCE || (_XOPEN_SOURCE >= 500 ||                 \
                       _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) &&           \
                       !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
 
@@ -76,18 +75,16 @@ using namespace mozilla;
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo *sLog = PR_NewLogModule("nsThread");
 #endif
 #define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args)
 
 NS_DECL_CI_INTERFACE_GETTER(nsThread)
 
-nsIThreadObserver* nsThread::sGlobalObserver;
-
 namespace mozilla {
 
 // Fun fact: Android's GCC won't convert bool* to PRInt32*, so we can't
 // PR_ATOMIC_SET a bool.
 static PRInt32 sMemoryPressurePending = 0;
 
 /*
  * It's important that this function not acquire any locks, nor do anything
@@ -501,16 +498,21 @@ nsThread::Shutdown()
   while (!context.shutdownAck)
     NS_ProcessNextEvent(context.joiningThread);
 
   // Now, it should be safe to join without fear of dead-locking.
 
   PR_JoinThread(mThread);
   mThread = nsnull;
 
+  // We hold strong references to our event observers, and once the thread is
+  // shut down the observers can't easily unregister themselves. Do it here
+  // to avoid leaking.
+  ClearObservers();
+
 #ifdef DEBUG
   {
     MutexAutoLock lock(mLock);
     NS_ASSERTION(!mObserver, "Should have been cleared at shutdown!");
   }
 #endif
 
   return NS_OK;
@@ -607,21 +609,16 @@ nsThread::ProcessNextEvent(bool mayWait,
                             NS_LITERAL_STRING("low-memory").get());
       }
       else {
         NS_WARNING("Can't get observer service!");
       }
     }
   }
 
-  bool notifyGlobalObserver = (sGlobalObserver != nsnull);
-  if (notifyGlobalObserver) 
-    sGlobalObserver->OnProcessNextEvent(this, mayWait && !ShuttingDown(),
-                                        mRunningEvent);
-
   nsCOMPtr<nsIThreadObserver> obs = mObserver;
   if (obs)
     obs->OnProcessNextEvent(this, mayWait && !ShuttingDown(), mRunningEvent);
 
   NOTIFY_EVENT_OBSERVERS(OnProcessNextEvent,
                          (this, mayWait && !ShuttingDown(), mRunningEvent));
 
   ++mRunningEvent;
@@ -667,19 +664,16 @@ nsThread::ProcessNextEvent(bool mayWait,
 
   --mRunningEvent;
 
   NOTIFY_EVENT_OBSERVERS(AfterProcessNextEvent, (this, mRunningEvent));
 
   if (obs)
     obs->AfterProcessNextEvent(this, mRunningEvent);
 
-  if (notifyGlobalObserver && sGlobalObserver)
-    sGlobalObserver->AfterProcessNextEvent(this, mRunningEvent);
-
   return rv;
 }
 
 //-----------------------------------------------------------------------------
 // nsISupportsPriority
 
 NS_IMETHODIMP
 nsThread::GetPriority(PRInt32 *priority)
@@ -834,23 +828,8 @@ nsThreadSyncDispatch::Run()
   if (mSyncTask) {
     mResult = mSyncTask->Run();
     mSyncTask = nsnull;
     // unblock the origin thread
     mOrigin->Dispatch(this, NS_DISPATCH_NORMAL);
   }
   return NS_OK;
 }
-
-nsresult
-NS_SetGlobalThreadObserver(nsIThreadObserver* aObserver)
-{
-  if (aObserver && nsThread::sGlobalObserver) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  if (!NS_IsMainThread()) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  nsThread::sGlobalObserver = aObserver;
-  return NS_OK;
-}
--- a/xpcom/threads/nsThread.h
+++ b/xpcom/threads/nsThread.h
@@ -72,18 +72,18 @@ public:
 
   // The PRThread corresponding to this thread.
   PRThread *GetPRThread() { return mThread; }
 
   // If this flag is true, then the nsThread was created using
   // nsIThreadManager::NewThread.
   bool ShutdownRequired() { return mShutdownRequired; }
 
-  // The global thread observer
-  static nsIThreadObserver* sGlobalObserver;
+  // Clear the observer list.
+  void ClearObservers() { mEventObservers.Clear(); }
 
 private:
   friend class nsThreadShutdownEvent;
 
   ~nsThread();
 
   bool ShuttingDown() { return mShutdownContext != nsnull; }
 
--- a/xpcom/threads/nsThreadManager.cpp
+++ b/xpcom/threads/nsThreadManager.cpp
@@ -171,16 +171,17 @@ nsThreadManager::Shutdown()
     MutexAutoLock lock(*mLock);
     mThreadsByPRThread.Clear();
   }
 
   // Normally thread shutdown clears the observer for the thread, but since the
   // main thread is special we do it manually here after we're sure all events
   // have been processed.
   mMainThread->SetObserver(nsnull);
+  mMainThread->ClearObservers();
 
   // Release main thread object.
   mMainThread = nsnull;
   mLock = nsnull;
 
   // Remove the TLS entry for the main thread.
   PR_SetThreadPrivate(mCurThreadIndex, nsnull);
 }
deleted file mode 100644
--- a/xpcom/threads/nsThreadUtilsInternal.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla code.
- *
- * The Initial Developer of the Original Code is the Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Boris Zbarsky <bzbarsky@mit.edu>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef nsThreadUtilsInternal_h_
-#define nsThreadUtilsInternal_h_
-
-#ifdef MOZILLA_INTERNAL_API
-
-class nsIThreadObserver;
-
-/**
- * Function to set a "global" thread observer that all threads will notify when
- * they process an event.  This observer will not be notified when events are
- * posted to threads.  Only one global observer can be set at a time; an
- * attempt to change the value without setting it to null first will throw.
- * This function does NOT take a reference to the observer; the caller of this
- * function is responsible for setting the observer to null when it goes away.
- * This method may only be called on the main thread; attempts to do it on
- * other threads will return an error.
- */
-extern nsresult
-NS_SetGlobalThreadObserver(nsIThreadObserver* aObserver);
-
-#endif // MOZILLA_INTERNAL_API
-
-#endif  // nsThreadUtilsInternal_h_