Back out 1ac4cb2e7c32 to c631f9c3e9a9 (bug 598482) for Android reftest failures
authorPhil Ringnalda <philringnalda@gmail.com>
Fri, 23 Dec 2011 22:21:58 -0800
changeset 84564 25224a78f895a98acca5cc9db2d47239fb266d84
parent 84563 00f4c8c5bcc7d1663303111fb8e82e4c11c37391
child 84565 94b5440efa60f2b3782898b3947c8afde2ca9ae9
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)
bugs598482
milestone12.0a1
backs out1ac4cb2e7c320d624b863e295b5085a1acbaf2ef
Back out 1ac4cb2e7c32 to c631f9c3e9a9 (bug 598482) for Android reftest failures
content/events/src/nsEventStateManager.cpp
content/events/test/Makefile.in
content/events/test/test_bug635465.html
content/html/content/src/nsTextEditorState.cpp
docshell/base/nsDocShell.cpp
dom/base/nsDOMWindowUtils.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/plugins/base/nsPluginInstanceOwner.cpp
editor/idl/nsIPlaintextEditor.idl
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsDocumentViewer.cpp
layout/base/nsIPresShell.h
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
layout/forms/nsComboboxControlFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsFrameSetFrame.cpp
layout/tools/layout-debug/src/nsLayoutDebuggingTools.cpp
layout/xul/base/src/nsListBoxBodyFrame.cpp
testing/mochitest/tests/SimpleTest/EventUtils.js
view/public/nsIViewManager.h
view/src/nsView.cpp
view/src/nsView.h
view/src/nsViewManager.cpp
view/src/nsViewManager.h
widget/public/nsGUIEvent.h
widget/public/nsIWidget.h
widget/src/android/nsWindow.cpp
widget/src/android/nsWindow.h
widget/src/cocoa/nsChildView.h
widget/src/cocoa/nsChildView.mm
widget/src/cocoa/nsCocoaWindow.h
widget/src/cocoa/nsCocoaWindow.mm
widget/src/gtk2/nsNativeThemeGTK.cpp
widget/src/gtk2/nsWindow.cpp
widget/src/gtk2/nsWindow.h
widget/src/os2/nsWindow.cpp
widget/src/os2/nsWindow.h
widget/src/qt/nsWindow.cpp
widget/src/qt/nsWindow.h
widget/src/windows/nsWindow.cpp
widget/src/windows/nsWindow.h
widget/src/windows/nsWindowGfx.cpp
widget/src/xpwidgets/PuppetWidget.cpp
widget/src/xpwidgets/PuppetWidget.h
widget/src/xpwidgets/nsBaseWidget.cpp
widget/src/xpwidgets/nsBaseWidget.h
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -1141,19 +1141,16 @@ nsEventStateManager::PreHandleEvent(nsPr
     // has completed and so |aTargetFrame| may have been deleted (moving
     // a bookmark, for example).  If this is the case, however, we know
     // that ClearFrameRefs() has been called and it cleared out
     // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
     // into UpdateCursor().
     GenerateDragGesture(aPresContext, (nsMouseEvent*)aEvent);
     UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus);
     GenerateMouseEnterExit((nsGUIEvent*)aEvent);
-    // Flush pending layout changes, so that later mouse move events
-    // will go to the right nodes.
-    FlushPendingEvents(aPresContext);
     break;
   case NS_DRAGDROP_GESTURE:
     if (mClickHoldContextMenu) {
       // an external drag gesture event came in, not generated internally
       // by Gecko. Make sure we get rid of the click-hold timer.
       KillClickHoldTimer();
     }
     break;
--- a/content/events/test/Makefile.in
+++ b/content/events/test/Makefile.in
@@ -108,17 +108,16 @@ include $(topsrcdir)/config/rules.mk
 		test_bug662678.html \
 		test_bug667919-1.html \
 		test_bug667919-2.html \
 		test_bug667612.html \
 		empty.js \
 		test_bug689564.html \
 		test_bug698929.html \
 		test_eventctors.html \
-		test_bug635465.html \
 		$(NULL)
 
 #bug 585630
 ifneq (mobile,$(MOZ_BUILD_APP))
 _TEST_FILES += \
 		test_dragstart.html \
 		$(NULL)
 endif
deleted file mode 100644
--- a/content/events/test/test_bug635465.html
+++ /dev/null
@@ -1,90 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=635465
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 635465</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <style type="text/css">
-      #item {
-        position: relative;
-      }
-      .s-menu-section-submenu {
-        position: absolute;
-        display: none;
-      }
-      .open .s-menu-section-submenu {
-        display: block;
-      }
-</style>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=635465">Mozilla Bug 635465</a>
-<div id="display">
-  <div class="item" id="item"
-       onmouseover="showSubmenu(event)" onmouseout="hideSubmenu(event)">
-    <a href="#" id="firsthover">Hover me</a>
-    <div class="s-menu-section-submenu" id="menu">
-      <a href="#" id="secondhover">Now hover me</a>
-    </div>
-  </div>
-</div>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script type="application/javascript;version=1.8">
-
-/** Test for Bug 635465 **/
-function showSubmenu(event) {
-  var item = document.getElementById('item');
-
-  var width = item.offsetWidth;   // IT WORKS IF YOU REMOVE THIS LINE
-  
-  item.className='open';
-}
-
-function hideSubmenu(event) {
-  document.getElementById('item').className='';
-}
-
-SimpleTest.waitForExplicitFinish();
-
-function executeTests() {
-  // First flush out layout of firsthover
-  ok($("firsthover").getBoundingClientRect().height > 0, true,
-     "Should have a nonzero height before hover");
-
-  // Now trigger a mouseover on firsthover
-  synthesizeMouseAtCenter($("firsthover"), { type: "mousemove" });
-
-  ok($("secondhover").getBoundingClientRect().height > 0, true,
-     "Should have a nonzero height for submenu after hover");
-
-  // Now determine where secondhover is hanging out
-  var rect = $("secondhover").getBoundingClientRect();
-  synthesizeMouseAtCenter($("secondhover"), { type: "mousemove" });
-
-  // And another mouseover one pixel to the right of where the center used to be
-  synthesizeMouseAtPoint(rect.left + rect.width/2 + 1,
-                         rect.top + rect.height/2,
-                         { type: "mousemove" });
-
-  ok($("secondhover").getBoundingClientRect().height > 0, true,
-     "Should have a nonzero height for submenu after second hover");
-
-  // And check computed display of the menu
-  is(getComputedStyle($("menu"), "").display, "block", "Should have block display");
-
-  SimpleTest.finish();
-}
-
-SimpleTest.waitForFocus(executeTests);
-</script>
-</pre>
-</body>
-</html>
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -1155,16 +1155,20 @@ 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;
   if (!mEditor) {
@@ -1305,17 +1309,22 @@ 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()) {
-    rv = newEditor->SetFlags(editorFlags);
+    // 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);
     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);
@@ -1823,16 +1832,17 @@ 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/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4727,17 +4727,18 @@ 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);
 
-    NS_ENSURE_SUCCESS(viewManager->InvalidateAllViews(), NS_ERROR_FAILURE);
+    // what about aForce ?
+    NS_ENSURE_SUCCESS(viewManager->UpdateAllViews(0), NS_ERROR_FAILURE);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetParentWidget(nsIWidget ** parentWidget)
 {
     NS_ENSURE_ARG_POINTER(parentWidget);
 
@@ -7318,17 +7319,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->InvalidateView(newRootView);
+                newVM->UpdateView(newRootView, NS_VMREFRESH_NO_SYNC);
             }
         }
     }
 
     return privWin->FireDelayedDOMEvents();
 }
 
 NS_IMETHODIMP
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -757,16 +757,37 @@ 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(b9c1f815-c2f2-4607-a060-6a8566581927)]
+[scriptable, uuid(3af3c5ce-6f2a-47e7-acd0-555ed576fa82)]
 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,16 +373,22 @@ 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
@@ -618,17 +618,18 @@ 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));
+                                  invalidRect->bottom - invalidRect->top),
+                        false);
     return NS_OK;
   }
 #endif
 
   nsPresContext* presContext = mObjectFrame->PresContext();
   nsRect rect(presContext->DevPixelsToAppUnits(invalidRect->left),
               presContext->DevPixelsToAppUnits(invalidRect->top),
               presContext->DevPixelsToAppUnits(invalidRect->right - invalidRect->left),
@@ -650,16 +651,22 @@ 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(07b6d070-ccea-4a00-84b4-f4b94dd9eb52)]
+[scriptable, uuid(05d312ef-8914-494e-91c9-2be8ed7f8e29)]
 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,37 +51,39 @@ 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  = 0x0080;
+  const long eEditorEnableWrapHackMask  = 0x0100;
   // bit for widgets (form elements)
-  const long eEditorWidgetMask          = 0x0100;
+  const long eEditorWidgetMask          = 0x0200;
   // this HTML editor should not create css styles
-  const long eEditorNoCSSMask           = 0x0200;
+  const long eEditorNoCSSMask           = 0x0400;
   // 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    = 0x0400;
+  const long eEditorAllowInteraction    = 0x0800;
   // when this is set, the characters in password editor are always masked.
   // see bug 530367 for the detail.
-  const long eEditorDontEchoPassword    = 0x0800;
+  const long eEditorDontEchoPassword    = 0x1000;
   // 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         = 0x1000;
+  const long eEditorRightToLeft         = 0x2000;
   // when this flag is set, the internal direction of the editor is LTR.
-  const long eEditorLeftToRight         = 0x2000;
+  const long eEditorLeftToRight         = 0x4000;
   // when this flag is set, the editor's text content is not spell checked.
-  const long eEditorSkipSpellCheck      = 0x4000;
+  const long eEditorSkipSpellCheck      = 0x8000;
 
   /*
    * 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
@@ -4193,16 +4193,25 @@ 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;
 }
 
 
@@ -4228,16 +4237,30 @@ 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,16 +684,21 @@ 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;
@@ -758,16 +763,17 @@ 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/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7629,25 +7629,26 @@ 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,
+UpdateViewsForTree(nsIFrame* aFrame, nsIViewManager* aViewManager,
                    nsFrameManager* aFrameManager,
                    nsChangeHint aChange)
 {
   NS_PRECONDITION(gInApplyRenderingChangeToTree,
                   "should only be called within ApplyRenderingChangeToTree");
 
   nsIView* view = aFrame->GetView();
   if (view) {
@@ -7664,49 +7665,50 @@ UpdateViewsForTree(nsIFrame* aFrame,
       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, aFrameManager,
-                                         aChange);
+            DoApplyRenderingChangeToTree(outOfFlowFrame, aViewManager,
+                                         aFrameManager, aChange);
           } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
         } else if (lists.CurrentID() == nsIFrame::kPopupList) {
-          DoApplyRenderingChangeToTree(child, aFrameManager,
-                                       aChange);
+          DoApplyRenderingChangeToTree(child, aViewManager,
+                                       aFrameManager, aChange);
         } else {  // regular frame
           if ((child->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) &&
               (aChange & nsChangeHint_RepaintFrame)) {
             FrameLayerBuilder::InvalidateThebesLayerContents(child,
               child->GetVisualOverflowRectRelativeToSelf());
           }
-          UpdateViewsForTree(child, aFrameManager, aChange);
+          UpdateViewsForTree(child, aViewManager, 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, aFrameManager, aChange);
+    UpdateViewsForTree(aFrame, aViewManager, 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'
@@ -7759,28 +7761,35 @@ 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, shell->FrameManager(), aChange);
+  DoApplyRenderingChangeToTree(aFrame, viewManager, 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
@@ -7811,18 +7820,23 @@ 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!
@@ -11579,32 +11593,33 @@ 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
-  nsCOMPtr<nsIViewManager> vm = mPresShell->GetViewManager();
+  nsIViewManager::UpdateViewBatch batch(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
@@ -11629,16 +11644,17 @@ 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
@@ -1549,18 +1549,19 @@ 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->InvalidateViewNoSuppression(rootView,
-            rootView->GetBounds() - rootView->GetPosition());
+          vm->UpdateViewNoSuppression(rootView,
+            rootView->GetBounds() - rootView->GetPosition(),
+            NS_VMREFRESH_NO_SYNC);
 
           nsIView *rootViewParent = rootView->GetParent();
           if (rootViewParent) {
             nsIViewManager *parentVM = rootViewParent->GetViewManager();
             if (parentVM) {
               parentVM->RemoveChild(rootView);
             }
           }
@@ -2803,32 +2804,36 @@ 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();
@@ -2840,32 +2845,36 @@ 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();
@@ -2878,16 +2887,17 @@ 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();
@@ -2896,33 +2906,38 @@ 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    \
-{ 0x3ab5b116, 0x2d73, 0x431c, \
- { 0x9a, 0x4b, 0x6c, 0x91, 0x9e, 0x42, 0x45, 0xc3 } }
+{ 0x4e23d557, 0x741a, 0x4fd0,\
+  { 0x91, 0x52, 0x34, 0xe2, 0xb4, 0xef, 0xe8, 0x2e } }
 
 // 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,17 +1143,16 @@ 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
@@ -1051,22 +1051,16 @@ 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
@@ -2323,17 +2317,16 @@ 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);
 }
 
@@ -2564,19 +2557,16 @@ 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();
@@ -2588,46 +2578,61 @@ nsRootPresContext::UpdatePluginGeometry(
     return;
   SortConfigurations(&configurations);
   nsIWidget* widget = FrameManager()->GetRootFrame()->GetNearestWidget();
   NS_ASSERTION(widget, "Plugins must have a parent window");
   widget->ConfigureChildren(configurations);
   DidApplyPluginGeometryUpdates();
 }
 
-static void
-UpdatePluginGeometryCallback(nsITimer *aTimer, void *aClosure)
+void
+nsRootPresContext::SynchronousPluginGeometryUpdate()
 {
-  static_cast<nsRootPresContext*>(aClosure)->UpdatePluginGeometry();
+  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();
 }
 
 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
@@ -1261,16 +1261,24 @@ 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
@@ -1332,27 +1340,17 @@ 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
@@ -1263,18 +1263,16 @@ PresShell::Destroy()
       mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
     }
   }
 
   // Revoke any pending events.  We need to do this and cancel pending reflows
   // before we destroy the frame manager, since apparently frame destruction
   // sometimes spins the event queue when plug-ins are involved(!).
   rd->RemoveLayoutFlushObserver(this);
-  rd->RevokeViewManagerFlush();
-
   mResizeEvent.Revoke();
   if (mAsyncResizeTimerIsActive) {
     mAsyncResizeEventTimer->Cancel();
     mAsyncResizeTimerIsActive = false;
   }
 
   CancelAllPendingReflows();
   CancelPostedReflowCallbacks();
@@ -2125,16 +2123,18 @@ 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();
@@ -2147,24 +2147,25 @@ 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));
   }
 
@@ -2472,29 +2473,50 @@ 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::ScrollHorizontal(bool aLeft)
 {
   nsIScrollableFrame* scrollFrame =
     GetFrameToScrollAsScrollable(nsIPresShell::eHorizontal);
   if (scrollFrame) {
     scrollFrame->ScrollBy(nsIntPoint(aLeft ? -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 =
@@ -2962,31 +2984,33 @@ 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);
@@ -3618,28 +3642,16 @@ 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 &&
@@ -3999,30 +4011,35 @@ 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.
+  // Make sure the view manager stays alive while batching view updates.
   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);
 
@@ -4105,21 +4122,25 @@ 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();
       }
-
-      if (!mIsDestroying) {
-        mViewManager->UpdateWidgetGeometry();
-      }
-    }
+    }
+
+    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);
   }
 }
 
 void
 PresShell::CharacterDataChanged(nsIDocument *aDocument,
                                 nsIContent*  aContent,
                                 CharacterDataChangeInfo* aInfo)
 {
@@ -7366,17 +7387,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->InvalidateView(rootView);
+    mViewManager->UpdateView(rootView, NS_VMREFRESH_IMMEDIATE);
 
     FlushPendingNotifications(Flush_Layout);
     mInVerifyReflow = true;
     bool ok = VerifyIncrementalReflow();
     mInVerifyReflow = false;
     if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
       printf("ProcessReflowCommands: finished (%s)\n",
              ok ? "ok" : "failed");
@@ -7413,17 +7434,16 @@ 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)) {
@@ -7561,16 +7581,17 @@ 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,
@@ -7585,16 +7606,17 @@ 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,17 +325,16 @@ 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,17 +50,16 @@
 #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
@@ -69,23 +68,16 @@ 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);
@@ -115,17 +107,16 @@ 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,
@@ -274,17 +265,16 @@ 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();
 }
@@ -436,21 +426,16 @@ 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,27 +172,16 @@ 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);
@@ -233,21 +222,16 @@ 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;
@@ -276,17 +260,16 @@ 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,16 +382,25 @@ 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
@@ -4637,34 +4637,41 @@ 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 && (aFlags & INVALIDATE_EXCLUDE_CURRENT_PAINT)) {
-    nsRegion r;
-    r.Sub(rect, *excludeRegion);
-    if (r.IsEmpty())
-      return;
-    rect = r.GetBounds();
+  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 (!(aFlags & INVALIDATE_NO_UPDATE_LAYER_TREE)) {
     AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
   }
 
   nsIView* view = GetView();
   NS_ASSERTION(view, "This can only be called on frames with views");
-  view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
+  view->GetViewManager()->UpdateViewNoSuppression(view, rect, flags);
 }
 
 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,16 +1528,29 @@ 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/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->InvalidateView(root);
+        vm->UpdateView(root, NS_VMREFRESH_IMMEDIATE);
     }
 }
 
 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,16 +554,25 @@ 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/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -141,41 +141,28 @@ function _parseModifiers(aEvent)
  *
  * If the type is specified, an mouse event of that type is fired. Otherwise,
  * a mousedown followed by a mouse up is performed.
  *
  * aWindow is optional, and defaults to the current window object.
  */
 function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
 {
-  var rect = aTarget.getBoundingClientRect();
-  synthesizeMouseAtPoint(rect.left + aOffsetX, rect.top + aOffsetY,
-			 aEvent, aWindow);
-}
-
-/*
- * Synthesize a mouse event at a particular point in aWindow.
- *
- * aEvent is an object which may contain the properties:
- *   shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type
- *
- * If the type is specified, an mouse event of that type is fired. Otherwise,
- * a mousedown followed by a mouse up is performed.
- *
- * aWindow is optional, and defaults to the current window object.
- */
-function synthesizeMouseAtPoint(left, top, aEvent, aWindow)
-{
   var utils = _getDOMWindowUtils(aWindow);
 
   if (utils) {
     var button = aEvent.button || 0;
     var clickCount = aEvent.clickCount || 1;
     var modifiers = _parseModifiers(aEvent);
 
+    var rect = aTarget.getBoundingClientRect();
+
+    var left = rect.left + aOffsetX;
+    var top = rect.top + aOffsetY;
+
     if (aEvent.type) {
       utils.sendMouseEvent(aEvent.type, left, top, button, clickCount, modifiers);
     }
     else {
       utils.sendMouseEvent("mousedown", left, top, button, clickCount, modifiers);
       utils.sendMouseEvent("mouseup", left, top, button, clickCount, modifiers);
     }
   }
--- 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 \
-{ 0x540610a6, 0x4fdd, 0x4ae3, \
-  { 0x9b, 0xdb, 0xa6, 0x4d, 0x8b, 0xca, 0x02, 0x0f } }
+{ 0x1262a33f, 0xc19f, 0x4e5b, \
+  { 0x85, 0x00, 0xab, 0xf3, 0x7d, 0xcf, 0x30, 0x1d } }
 
 class nsIViewManager : public nsISupports
 {
 public:
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IVIEWMANAGER_IID)
   /**
    * Initialize the ViewManager
@@ -112,35 +112,50 @@ 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  InvalidateView(nsIView *aView) = 0;
+  NS_IMETHOD  UpdateView(nsIView *aView, PRUint32 aUpdateFlags) = 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  InvalidateViewNoSuppression(nsIView *aView, const nsRect &aRect) = 0;
+  NS_IMETHOD  UpdateViewNoSuppression(nsIView *aView, const nsRect &aRect,
+                                      PRUint32 aUpdateFlags) = 0;
 
   /**
-   * Called to inform the view manager that it should invalidate all views.
+   * 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
    */
-  NS_IMETHOD  InvalidateAllViews() = 0;
+  NS_IMETHOD  UpdateAllViews(PRUint32 aUpdateFlags) = 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
@@ -253,61 +268,105 @@ public:
   virtual nsIPresShell* GetPresShell() = 0;
 
   /**
    * Get the device context associated with this manager
    * @result device context
    */
   NS_IMETHOD  GetDeviceContext(nsDeviceContext *&aContext) = 0;
 
+  class UpdateViewBatch {
+  public:
+    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.
+   * 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
    */
-  class NS_STACK_CLASS AutoDisableRefresh {
-  public:
-    AutoDisableRefresh(nsIViewManager* aVM) {
+    UpdateViewBatch(nsIViewManager* aVM) {
       if (aVM) {
-        mRootVM = aVM->IncrementDisableRefreshCount();
+        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();
       }
     }
-    ~AutoDisableRefresh() {
-      if (mRootVM) {
-        mRootVM->DecrementDisableRefreshCount();
-      }
+
+  /**
+   * 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;
     }
+
   private:
-    AutoDisableRefresh(const AutoDisableRefresh& aOther);
-    const AutoDisableRefresh& operator=(const AutoDisableRefresh& aOther);
+    UpdateViewBatch(const UpdateViewBatch& aOther);
+    const UpdateViewBatch& operator=(const UpdateViewBatch& aOther);
 
     nsCOMPtr<nsIViewManager> mRootVM;
   };
-
+  
 private:
-  friend class AutoDisableRefresh;
+  friend class UpdateViewBatch;
 
-  virtual nsIViewManager* IncrementDisableRefreshCount() = 0;
-  virtual void DecrementDisableRefreshCount() = 0;
+  virtual nsIViewManager* BeginUpdateViewBatch(void) = 0;
+  NS_IMETHOD EndUpdateViewBatch(PRUint32 aUpdateFlags) = 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;
 
   /**
@@ -319,24 +378,30 @@ 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,41 +346,40 @@ 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, false);
+  ResetWidgetBounds(true, true, false);
 }
 
 void nsIView::SetInvalidationDimensions(const nsRect* aRect)
 {
   return Impl()->SetInvalidationDimensions(aRect);
 }
 
-void nsView::ResetWidgetBounds(bool aRecurse, bool aForceSync)
-{
+void nsView::ResetWidgetBounds(bool aRecurse, bool aMoveOnly,
+                               bool aInvalidateChangedSize) {
   if (mWindow) {
-    if (!aForceSync) {
-      // Don't change widget geometry synchronously, since that can
-      // cause synchronous painting.
+    // 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()) {
       mViewManager->PostPendingUpdate();
-    } else {
-      DoResetWidgetBounds(false, true);
+      return;
     }
-    return;
-  }
 
-  if (aRecurse) {
+    DoResetWidgetBounds(aMoveOnly, aInvalidateChangedSize);
+  } else if (aRecurse) {
     // reposition any widgets under this view
     for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) {
-      v->ResetWidgetBounds(true, aForceSync);
+      v->ResetWidgetBounds(true, aMoveOnly, aInvalidateChangedSize);
     }
   }
 }
 
 bool nsIView::IsEffectivelyVisible()
 {
   for (nsIView* v = this; v; v = v->mParent) {
     if (v->GetVisibility() == nsViewVisibility_kHide)
@@ -488,17 +487,17 @@ void nsView::SetDimensions(const nsRect&
   if (mDimBounds.TopLeft() == dims.TopLeft() &&
       mDimBounds.Size() == dims.Size()) {
     return;
   }
 
   mDimBounds = dims;
 
   if (aResizeWidget) {
-    ResetWidgetBounds(false, false);
+    ResetWidgetBounds(false, false, aPaint);
   }
 }
 
 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 aForceSync);
+  void ResetWidgetBounds(bool aRecurse, bool aMoveOnly, bool aInvalidateChangedSize);
   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,16 +75,31 @@
    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;
 
@@ -100,28 +115,32 @@ 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;
 
@@ -337,16 +356,19 @@ 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();
@@ -369,18 +391,20 @@ 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;
-    InvalidateAllViews();
+    UpdateAllViews(0);
   }
 }
 
 // aRC and aRegion are in view coordinates
 void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget,
                                 const nsRegion& aRegion,
                                 const nsIntRegion& aIntRegion,
                                 bool aPaintDefaultBackground,
@@ -391,136 +415,149 @@ void nsViewManager::RenderViews(nsView *
 
   if (mPresShell) {
     mPresShell->Paint(aView, aWidget, aRegion, aIntRegion,
                       aPaintDefaultBackground, aWillSendDidPaint);
     mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
   }
 }
 
-void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
-                                                 bool aFlushDirtyRegion)
+void nsViewManager::ProcessPendingUpdates(nsView* aView, bool aDoInvalidate)
 {
   NS_ASSERTION(IsRootVM(), "Updates will be missed");
 
   // Protect against a null-view.
   if (!aView) {
     return;
   }
 
   if (aView->HasWidget()) {
-    aView->ResetWidgetBounds(false, true);
+    aView->ResetWidgetBounds(false, false, true);
   }
 
   // process pending updates in child view.
   for (nsView* childView = aView->GetFirstChild(); childView;
        childView = childView->GetNextSibling()) {
-    ProcessPendingUpdatesForView(childView, aFlushDirtyRegion);
+    ProcessPendingUpdates(childView, aDoInvalidate);
   }
 
-  // Push out updates after we've processed the children; ensures that
-  // damage is applied based on the final widget geometry
-  if (aFlushDirtyRegion) {
-    FlushDirtyRegionToWidget(aView);
+  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();
+    }
   }
 }
 
-void nsViewManager::FlushDirtyRegionToWidget(nsView* aView)
+NS_IMETHODIMP nsViewManager::Composite()
 {
-  if (!aView->HasNonEmptyDirtyRegion())
-    return;
+  if (!IsRootVM()) {
+    return RootViewManager()->Composite();
+  }
+  ForceUpdate();
+  ClearUpdateCount();
 
-  nsRegion* dirtyRegion = aView->GetDirtyRegion();
-  nsView* nearestViewWithWidget = aView;
-  while (!nearestViewWithWidget->HasWidget() &&
-         nearestViewWithWidget->GetParent()) {
-    nearestViewWithWidget = nearestViewWithWidget->GetParent();
-  }
-  nsRegion r =
-    ConvertRegionBetweenViews(*dirtyRegion, aView, nearestViewWithWidget);
-  nsViewManager* widgetVM = nearestViewWithWidget->GetViewManager();
-  widgetVM->InvalidateWidgetArea(nearestViewWithWidget, r);
-  dirtyRegion->SetEmpty();
+  return NS_OK;
 }
 
-NS_IMETHODIMP nsViewManager::InvalidateView(nsIView *aView)
+NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags)
 {
   // Mark the entire view as damaged
-  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();
-  }
+  return UpdateView(aView, aView->GetDimensions(), aUpdateFlags);
 }
 
 /**
+ * @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::InvalidateWidgetArea(nsView *aWidgetView,
-                                    const nsRegion &aDamagedRegion)
+nsViewManager::UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
+                                const nsRegion &aDamagedRegion,
+                                nsView* aIgnoreWidgetView)
 {
   NS_ASSERTION(aWidgetView->GetViewManager() == this,
-               "InvalidateWidgetArea called on view we don't own");
-  nsIWidget* widget = aWidgetView->GetWidget();
+               "UpdateWidgetArea called on view we don't own");
 
 #if 0
   nsRect dbgBounds = aDamagedRegion.GetBounds();
-  printf("InvalidateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
+  printf("UpdateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
     aWidgetView, aWidgetView->IsAttachedToTopLevel(),
-    widget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height);
+    aWidget, 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 (widget) {
+  if (aWidget) {
     bool visible;
-    widget->IsVisible(visible);
+    aWidget->IsVisible(visible);
     if (!visible)
       return;
   }
 
-  if (!widget) {
+  if (aWidgetView == aIgnoreWidgetView) {
+    // the widget for aIgnoreWidgetView (and its children) should be treated as already updated.
+    return;
+  }
+
+  if (!aWidget) {
     // 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 (widget->GetTransparencyMode() != eTransparencyTransparent) {
-    for (nsIWidget* childWidget = widget->GetFirstChild();
+  if (aWidget->GetTransparencyMode() != eTransparencyTransparent) {
+    for (nsIWidget* childWidget = aWidget->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);
@@ -549,20 +586,22 @@ nsViewManager::InvalidateWidgetArea(nsVi
       }
     }
   }
 
   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);
-      widget->Invalidate(bounds);
+      aWidget->Invalidate(bounds, false);
     }
   }
 }
 
 static bool
 ShouldIgnoreInvalidation(nsViewManager* aVM)
 {
   while (aVM) {
@@ -571,81 +610,89 @@ ShouldIgnoreInvalidation(nsViewManager* 
       return true;
     }
     nsView* view = aVM->GetRootViewImpl()->GetParent();
     aVM = view ? view->GetViewManager() : nsnull;
   }
   return false;
 }
 
-nsresult nsViewManager::InvalidateView(nsIView *aView, const nsRect &aRect)
+nsresult nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect,
+                                   PRUint32 aUpdateFlags)
 {
   // 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 InvalidateViewNoSuppression(aView, aRect);
+  return UpdateViewNoSuppression(aView, aRect, aUpdateFlags);
 }
 
-NS_IMETHODIMP nsViewManager::InvalidateViewNoSuppression(nsIView *aView,
-                                                         const nsRect &aRect)
+NS_IMETHODIMP nsViewManager::UpdateViewNoSuppression(nsIView *aView,
+                                                     const nsRect &aRect,
+                                                     PRUint32 aUpdateFlags)
 {
   NS_PRECONDITION(nsnull != aView, "null view");
 
   nsView* view = static_cast<nsView*>(aView);
 
   NS_ASSERTION(view->GetViewManager() == this,
-               "InvalidateViewNoSuppression called on view we don't own");
+               "UpdateView 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);
 
-  // accumulate this rectangle in the view's dirty region, so we can
-  // process it later.
-  AddDirtyRegion(displayRoot, nsRegion(damagedRect));
+  RootViewManager()->IncrementUpdateCount();
 
-  // Schedule an invalidation flush with the refresh driver.
-  PostPendingUpdate();
+  if (!IsRefreshEnabled()) {
+    return NS_OK;
+  }
+
+  // See if we should do an immediate refresh or wait
+  if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) {
+    Composite();
+  } 
 
   return NS_OK;
 }
 
-NS_IMETHODIMP nsViewManager::InvalidateAllViews()
+NS_IMETHODIMP nsViewManager::UpdateAllViews(PRUint32 aUpdateFlags)
 {
   if (RootViewManager() != this) {
-    return RootViewManager()->InvalidateAllViews();
+    return RootViewManager()->UpdateAllViews(aUpdateFlags);
   }
   
-  InvalidateViews(mRootView);
+  UpdateViews(mRootView, aUpdateFlags);
   return NS_OK;
 }
 
-void nsViewManager::InvalidateViews(nsView *aView)
+void nsViewManager::UpdateViews(nsView *aView, PRUint32 aUpdateFlags)
 {
-  // Invalidate this view.
-  InvalidateView(aView);
+  // update this view.
+  UpdateView(aView, aUpdateFlags);
 
-  // Invalidate all children as well.
+  // update all children as well.
   nsView* childView = aView->GetFirstChild();
   while (nsnull != childView)  {
-    childView->GetViewManager()->InvalidateViews(childView);
+    childView->GetViewManager()->UpdateViews(childView, aUpdateFlags);
     childView = childView->GetNextSibling();
   }
 }
 
 static bool
 IsViewForPopup(nsIView* aView)
 {
   nsIWidget* widget = aView->GetWidget();
@@ -748,84 +795,142 @@ 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;
 
-        nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
+        if (aEvent->message == NS_PAINT && event->region.IsEmpty())
+          break;
 
         NS_ASSERTION(static_cast<nsView*>(aView) ==
                        nsView::GetViewFor(event->widget),
                      "view/widget mismatch");
 
-        // 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);
+        // 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);
+
+              // 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");
 
-        // 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;
+            // 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;
 
-    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!");
+            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);
 
-        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);
+                // 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.)
 
-          // Get the view pointer again since NS_WILL_PAINT might have
-          // destroyed it during CallWillPaintOnObservers (bug 378273).
-          view = nsView::GetViewFor(event->widget);
+          UpdateView(aView, rgn.GetBounds(), NS_VMREFRESH_NO_SYNC);
         }
 
-        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;
     }
@@ -1066,17 +1171,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()->InvalidateView(child);
+        child->GetViewManager()->UpdateView(child, NS_VMREFRESH_NO_SYNC);
     }
   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
@@ -1089,17 +1194,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()->InvalidateView(child);
+    child->GetViewManager()->UpdateView(child, NS_VMREFRESH_NO_SYNC);
     parent->RemoveChild(child);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY)
 {
@@ -1111,52 +1216,54 @@ 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->InvalidateView(parentView, oldBounds);
-        parentVM->InvalidateView(parentView, view->GetBoundsInParentUnits());
+        parentVM->UpdateView(parentView, oldBounds, NS_VMREFRESH_NO_SYNC);
+        parentVM->UpdateView(parentView, view->GetBoundsInParentUnits(),
+                             NS_VMREFRESH_NO_SYNC);
       }
     }
   }
   return NS_OK;
 }
 
 void nsViewManager::InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
-  nscoord aY1, nscoord aY2, bool aInCutOut) {
+  PRUint32 aUpdateFlags, 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);
-    InvalidateView(aView, r);
+    UpdateView(aView, r, aUpdateFlags);
   }
   if (!aInCutOut && aCutOut.x < aCutOut.XMost()) {
     nsRect r(aCutOut.x, aY1, aCutOut.width, height);
-    InvalidateView(aView, r);
+    UpdateView(aView, r, aUpdateFlags);
   }
   if (aCutOut.XMost() < aRect.XMost()) {
     nsRect r(aCutOut.XMost(), aY1, aRect.XMost() - aCutOut.XMost(), height);
-    InvalidateView(aView, r);
+    UpdateView(aView, r, aUpdateFlags);
   }
 }
 
-void nsViewManager::InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut) {
+void nsViewManager::InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
+  PRUint32 aUpdateFlags) {
   NS_ASSERTION(aView->GetViewManager() == this,
                "InvalidateRectDifference called on view we don't own");
   if (aRect.y < aCutOut.y) {
-    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aRect.y, aCutOut.y, false);
+    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aRect.y, aCutOut.y, false);
   }
   if (aCutOut.y < aCutOut.YMost()) {
-    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aCutOut.y, aCutOut.YMost(), true);
+    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aCutOut.y, aCutOut.YMost(), true);
   }
   if (aCutOut.YMost() < aRect.YMost()) {
-    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aCutOut.YMost(), aRect.YMost(), false);
+    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, 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");
 
@@ -1170,23 +1277,24 @@ 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
-        InvalidateView(view, aRect);
-        parentVM->InvalidateView(parentView, oldBounds);
+        //Invalidate the union of the old and new size
+        UpdateView(view, aRect, NS_VMREFRESH_NO_SYNC);
+        parentVM->UpdateView(parentView, oldBounds, NS_VMREFRESH_NO_SYNC);
       } else {
-        InvalidateRectDifference(view, aRect, oldDimensions);
+        InvalidateRectDifference(view, aRect, oldDimensions, NS_VMREFRESH_NO_SYNC);
         nsRect newBounds = view->GetBoundsInParentUnits();
-        parentVM->InvalidateRectDifference(parentView, oldBounds, newBounds);
+        parentVM->InvalidateRectDifference(parentView, oldBounds, newBounds,
+                                           NS_VMREFRESH_NO_SYNC);
       } 
     }
   }
 
   // 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
@@ -1215,28 +1323,60 @@ 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()->
-              InvalidateView(parentView, view->GetBoundsInParentUnits());
+              UpdateView(parentView, view->GetBoundsInParentUnits(),
+                         NS_VMREFRESH_NO_SYNC);
           }
         }
         else {
-          InvalidateView(view);
+          UpdateView(view, NS_VMREFRESH_NO_SYNC);
         }
       }
     }
   }
   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();
@@ -1270,47 +1410,91 @@ NS_IMETHODIMP nsViewManager::SetViewZInd
     aZIndex = 0;
   }
 
   PRInt32 oldidx = view->GetZIndex();
   view->SetZIndex(aAutoZIndex, aZIndex, aTopMost);
 
   if (oldidx != aZIndex || oldTopMost != aTopMost ||
       oldIsAuto != aAutoZIndex) {
-    InvalidateView(view);
+    UpdateView(view, NS_VMREFRESH_NO_SYNC);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP nsViewManager::GetDeviceContext(nsDeviceContext *&aContext)
 {
   aContext = mContext;
   NS_IF_ADDREF(aContext);
   return NS_OK;
 }
 
-nsIViewManager*
-nsViewManager::IncrementDisableRefreshCount()
+void nsViewManager::TriggerRefresh(PRUint32 aUpdateFlags)
 {
   if (!IsRootVM()) {
-    return RootViewManager()->IncrementDisableRefreshCount();
+    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;
   }
 
-  ++mRefreshDisableCount;
+  ++mUpdateBatchCnt;
 
   return this;
 }
 
-void
-nsViewManager::DecrementDisableRefreshCount()
+NS_IMETHODIMP nsViewManager::EndUpdateViewBatch(PRUint32 aUpdateFlags)
 {
   NS_ASSERTION(IsRootVM(), "Should only be called on root");
-  --mRefreshDisableCount;
-  NS_ASSERTION(mRefreshDisableCount >= 0, "Invalid refresh disable count!");
+  
+  --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;
 }
 
 NS_IMETHODIMP nsViewManager::GetRootWidget(nsIWidget **aWidget)
 {
   if (!mRootView) {
     *aWidget = nsnull;
     return NS_OK;
   }
@@ -1320,16 +1504,30 @@ 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);
@@ -1344,57 +1542,47 @@ nsIntRect nsViewManager::ViewToWidget(ns
 NS_IMETHODIMP
 nsViewManager::IsPainting(bool& aIsPainting)
 {
   aIsPainting = IsPainting();
   return NS_OK;
 }
 
 void
-nsViewManager::ProcessPendingUpdates()
+nsViewManager::FlushPendingInvalidates()
 {
-  if (!IsRootVM()) {
-    RootViewManager()->ProcessPendingUpdates();
-    return;
-  }
+  NS_ASSERTION(IsRootVM(), "Must be root VM for this to be called!");
+  NS_ASSERTION(mUpdateBatchCnt == 0, "Must not be in an update batch!");
 
   if (mHasPendingUpdates) {
-    ProcessPendingUpdatesForView(mRootView, true);
+    ProcessPendingUpdates(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()
@@ -1411,16 +1599,34 @@ 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,37 +48,46 @@
 #include "nsView.h"
 #include "nsIPresShell.h"
 #include "nsDeviceContext.h"
 
 
 /**
    Invalidation model:
 
-   1) Callers call into the view manager and ask it to invalidate a view.
+   1) Callers call into the view manager and ask it to update 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 stores the rect to invalidate on the widget's
-      view (batching).
+      one that needs invalidation either
 
-   4) The dirty region is flushed to the right widget when
-      ProcessPendingUpdates is called from the RefreshDriver.
+      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.
 
    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, invalidation processing and should only happen on the
-   root viewmanager.
+   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.
 */
 
+class nsInvalidateEvent;
+
 class nsViewManager : public nsIViewManager {
 public:
   nsViewManager();
 
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
   NS_DECL_ISUPPORTS
 
@@ -90,19 +99,22 @@ 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  InvalidateView(nsIView *aView);
-  NS_IMETHOD  InvalidateViewNoSuppression(nsIView *aView, const nsRect &aRect);
-  NS_IMETHOD  InvalidateAllViews();
+  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  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,
@@ -120,99 +132,128 @@ 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* IncrementDisableRefreshCount();
-  virtual void DecrementDisableRefreshCount();
+  virtual nsIViewManager* BeginUpdateViewBatch(void);
+  NS_IMETHOD  EndUpdateViewBatch(PRUint32 aUpdateFlags);
 
   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 ProcessPendingUpdatesForView(nsView *aView,
-                                    bool aFlushDirtyRegion = true);
-  void FlushDirtyRegionToWidget(nsView* aView);
+  void ProcessPendingUpdates(nsView *aView, bool aDoInvalidate);
   /**
    * 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 InvalidateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedRegion);
+  void UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
+                        const nsRegion &aDamagedRegion,
+                        nsView* aIgnoreWidgetView);
 
-  void InvalidateViews(nsView *aView);
+  void UpdateViews(nsView *aView, PRUint32 aUpdateFlags);
+
+  void TriggerRefresh(PRUint32 aUpdateFlags);
 
   // 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);
+  void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut, PRUint32 aUpdateFlags);
   void InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
-                                          nscoord aY1, nscoord aY2, bool aInCutOut);
+                                          PRUint32 aUpdateFlags, 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 InvalidateView(nsIView *aView, const nsRect &aRect);
+  nsresult UpdateView(nsIView *aView, const nsRect &aRect, PRUint32 aUpdateFlags);
 
 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(); }
 
-  // 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; }
+  bool IsRefreshEnabled() { return RootViewManager()->mUpdateBatchCnt == 0; }
 
   // Call this when you need to let the viewmanager know that it now has
   // pending updates.
-  void PostPendingUpdate();
+  void PostPendingUpdate() { RootViewManager()->mHasPendingUpdates = true; }
 
   PRUint32 AppUnitsPerDevPixel() const
   {
     return mContext->AppUnitsPerDevPixel();
   }
 
 private:
   nsRefPtr<nsDeviceContext> mContext;
@@ -222,28 +263,51 @@ 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.
   
-  PRInt32           mRefreshDisableCount;
+  // Use IncrementUpdateCount(), DecrementUpdateCount(), UpdateCount(),
+  // ClearUpdateCount() on the root viewmanager to access mUpdateCnt.
+  PRInt32           mUpdateCnt;
+  PRInt32           mUpdateBatchCnt;
+  PRUint32          mUpdateBatchFlags;
   // 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/public/nsGUIEvent.h
+++ b/widget/public/nsGUIEvent.h
@@ -732,25 +732,23 @@ 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),
-      didSendWillPaint(false)
+      willSendDidPaint(false)
   {
   }
 
   // area that needs repainting
   nsIntRegion region;
   bool willSendDidPaint;
-  bool didSendWillPaint;
 };
 
 /**
  * Scrollbar event
  */
 
 class nsScrollbarEvent : public nsGUIEvent
 {
--- a/widget/public/nsIWidget.h
+++ b/widget/public/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 \
-  { 0xba20ac65, 0xb2a6, 0x4052, \
-    { 0xa4, 0xcb, 0x65, 0x40, 0xf8, 0x87, 0x9c, 0x55 } }
+  { 0x6ca77c11, 0xade7, 0x4715, \
+    { 0x82, 0xe0, 0xfe, 0xae, 0x42, 0xca, 0x5b, 0x1f } }
 /*
  * 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,20 +1016,31 @@ 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 so that it will be repainted
-     * later.
+     * Invalidate a specified rect for a widget and repaints it.
+     *
+     * @param aIsSynchronouse true then repaint synchronously. If false repaint later.
+     * @see #Update()
      */
-    NS_IMETHOD Invalidate(const nsIntRect & aRect) = 0;
+
+    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;
 
     enum LayerManagerPersistence
     {
       LAYER_MANAGER_CURRENT = 0,
       LAYER_MANAGER_PERSISTENT
     };
 
     /**
--- a/widget/src/android/nsWindow.cpp
+++ b/widget/src/android/nsWindow.cpp
@@ -584,23 +584,30 @@ nsWindow::Enable(bool aState)
 NS_IMETHODIMP
 nsWindow::IsEnabled(bool *aState)
 {
     *aState = true;
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsWindow::Invalidate(const nsIntRect &aRect)
+nsWindow::Invalidate(const nsIntRect &aRect,
+                     bool aIsSynchronous)
 {
     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/src/android/nsWindow.h
+++ b/widget/src/android/nsWindow.h
@@ -115,17 +115,19 @@ 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);
+    NS_IMETHOD Invalidate(const nsIntRect &aRect,
+                          bool aIsSynchronous);
+    NS_IMETHOD Update();
     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/src/cocoa/nsChildView.h
+++ b/widget/src/cocoa/nsChildView.h
@@ -413,27 +413,28 @@ 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);
+  NS_IMETHOD              Invalidate(const nsIntRect &aRect, bool aIsSynchronous);
 
   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/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -1393,27 +1393,30 @@ static void blinkRgn(RgnHandle rgn)
 
   if (oldClip != NULL)
     ::SetClip(oldClip);
 }
 
 #endif
 
 // Invalidate this component's visible area
-NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect)
+NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect, bool aIsSynchronous)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   if (!mView || !mVisible)
     return NS_OK;
 
   NSRect r;
   nsCocoaUtils::GeckoRectToNSRect(aRect, r);
   
-  if ([NSView focusView]) {
+  if (aIsSynchronous) {
+    [mView displayRect:r];
+  }
+  else 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];
   }
 
@@ -1434,16 +1437,25 @@ 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
@@ -2503,17 +2515,16 @@ 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/src/cocoa/nsCocoaWindow.h
+++ b/widget/src/cocoa/nsCocoaWindow.h
@@ -247,17 +247,18 @@ 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);
+    NS_IMETHOD Invalidate(const nsIntRect &aRect, bool aIsSynchronous);
+    NS_IMETHOD Update();
     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/src/cocoa/nsCocoaWindow.mm
+++ b/widget/src/cocoa/nsCocoaWindow.mm
@@ -1274,20 +1274,28 @@ 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)
+NS_IMETHODIMP nsCocoaWindow::Invalidate(const nsIntRect & aRect, bool aIsSynchronous)
 {
   if (mPopupContentView)
-    return mPopupContentView->Invalidate(aRect);
+    return mPopupContentView->Invalidate(aRect, aIsSynchronous);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsCocoaWindow::Update()
+{
+  if (mPopupContentView)
+    return mPopupContentView->Update();
 
   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/src/gtk2/nsNativeThemeGTK.cpp
+++ b/widget/src/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->InvalidateAllViews();
+  vm->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
 }
 
 static bool IsFrameContentNodeInNamespace(nsIFrame *aFrame, PRUint32 aNamespace)
 {
   nsIContent *content = aFrame ? aFrame->GetContent() : nsnull;
   if (!content)
     return false;
   return content->IsInNamespace(aNamespace);
--- a/widget/src/gtk2/nsWindow.cpp
+++ b/widget/src/gtk2/nsWindow.cpp
@@ -1731,32 +1731,49 @@ nsWindow::SetCursor(imgIContainer* aCurs
         }
         gdk_cursor_unref(cursor);
     }
 
     return rv;
 }
 
 NS_IMETHODIMP
-nsWindow::Invalidate(const nsIntRect &aRect)
+nsWindow::Invalidate(const nsIntRect &aRect,
+                     bool             aIsSynchronous)
 {
     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\n", (void *)this,
-             rect.x, rect.y, rect.width, rect.height));
+    LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d (sync: %d)\n", (void *)this,
+             rect.x, rect.y, rect.width, rect.height, aIsSynchronous));
 
     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/src/gtk2/nsWindow.h
+++ b/widget/src/gtk2/nsWindow.h
@@ -172,17 +172,19 @@ 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);
+    NS_IMETHOD         Invalidate(const nsIntRect &aRect,
+                                  bool             aIsSynchronous);
+    NS_IMETHOD         Update();
     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/src/os2/nsWindow.cpp
+++ b/widget/src/os2/nsWindow.cpp
@@ -612,22 +612,38 @@ NS_METHOD nsWindow::SetFocus(bool aRaise
       mInSetFocus = false;
     }
   }
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 
-NS_METHOD nsWindow::Invalidate(const nsIntRect& aRect)
+NS_METHOD nsWindow::Invalidate(const nsIntRect& aRect, bool aIsSynchronous)
 {
   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/src/os2/nsWindow.h
+++ b/widget/src/os2/nsWindow.h
@@ -170,17 +170,19 @@ 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);
+  NS_IMETHOD            Invalidate(const nsIntRect& aRect,
+                                   bool aIsSynchronous);
+  NS_IMETHOD            Update();
   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/src/qt/nsWindow.cpp
+++ b/widget/src/qt/nsWindow.cpp
@@ -746,28 +746,42 @@ 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)
+nsWindow::Invalidate(const nsIntRect &aRect,
+                     bool          aIsSynchronous)
 {
-    LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d\n", (void *)this,
-             (void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height));
+    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));
 
     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/src/qt/nsWindow.h
+++ b/widget/src/qt/nsWindow.h
@@ -168,17 +168,19 @@ 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);
+    NS_IMETHOD         Invalidate(const nsIntRect &aRect,
+                                  bool          aIsSynchronous);
+    NS_IMETHOD         Update();
 
     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/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -1275,22 +1275,18 @@ 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();
-    if (syncInvalidate) {
-      ::UpdateWindow(mWnd);
-    }
-  }
+  if (!wasVisible && bState)
+    Invalidate(syncInvalidate);
 #endif
 
   return NS_OK;
 }
 
 /**************************************************************
  *
  * SECTION: nsIWidget::IsVisible
@@ -1486,17 +1482,17 @@ NS_METHOD nsWindow::Resize(PRInt32 aWidt
     }
 
     ClearThemeRegion();
     VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, GetHeight(aHeight), flags));
     SetThemeRegion();
   }
 
   if (aRepaint)
-    Invalidate();
+    Invalidate(false);
 
   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");
@@ -1525,17 +1521,17 @@ NS_METHOD nsWindow::Resize(PRInt32 aX, P
     }
 
     ClearThemeRegion();
     VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, GetHeight(aHeight), flags));
     SetThemeRegion();
   }
 
   if (aRepaint)
-    Invalidate();
+    Invalidate(false);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
 {
   NS_ENSURE_ARG_POINTER(aEvent);
@@ -2016,17 +2012,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();
+  Invalidate(false);
 }
 
 // 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;
@@ -2652,68 +2648,78 @@ 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 aEraseBackground, 
+NS_METHOD nsWindow::Invalidate(bool aIsSynchronous, 
+                               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)
+NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, bool aIsSynchronous)
 {
   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.
@@ -2743,17 +2749,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();
+    Invalidate(false);
   }
 
   // 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
@@ -2762,16 +2768,36 @@ 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.
  *
  **************************************************************/
@@ -4650,17 +4676,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);
+      Invalidate(true, true, true, true);
     }
     break;
 
     case WM_FONTCHANGE:
     {
       nsresult rv;
       bool didChange = false;
 
@@ -5329,17 +5355,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);
+    Invalidate(true, 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
@@ -7205,17 +7231,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());
+        w->Invalidate(r.GetBounds(), false);
       }
     }
     rv = w->SetWindowClipRegion(configuration.mClipRegion, false);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
@@ -7425,17 +7451,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();
+    Invalidate(false);
   }
 #endif
 
   // call the event callback
   if (mEventCallback) {
     nsSizeEvent event(true, NS_SIZE, this);
     InitEvent(event);
     event.windowSize = &aWindowRect;
--- a/widget/src/windows/nsWindow.h
+++ b/widget/src/windows/nsWindow.h
@@ -137,20 +137,22 @@ 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 aEraseBackground = false,
+  NS_IMETHOD              Invalidate(bool aIsSynchronous, 
+                                     bool aEraseBackground = false,
                                      bool aUpdateNCArea = false,
                                      bool aIncludeChildren = false);
-  NS_IMETHOD              Invalidate(const nsIntRect & aRect);
+  NS_IMETHOD              Invalidate(const nsIntRect & aRect, bool aIsSynchronous);
+  NS_IMETHOD              Update();
   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/src/windows/nsWindowGfx.cpp
+++ b/widget/src/windows/nsWindowGfx.cpp
@@ -305,17 +305,16 @@ 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,
@@ -570,28 +569,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();
+            Invalidate(false);
           }
         }
         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();
+            Invalidate(false);
           } else {
             result = DispatchWindowEvent(&event, eventStatus);
           }
         }
         break;
 #endif
       default:
         NS_ERROR("Unknown layers backend used!");
--- a/widget/src/xpwidgets/PuppetWidget.cpp
+++ b/widget/src/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);
+    aWidget->Invalidate(*r, false/*async*/);
   }
 }
 
 /*static*/ already_AddRefed<nsIWidget>
 nsIWidget::CreatePuppetWidget(PBrowserChild *aTabChild)
 {
   NS_ABORT_IF_FALSE(nsIWidget::UsePuppetWidgets(),
                     "PuppetWidgets not allowed in this configuration");
@@ -223,37 +223,55 @@ 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)
+PuppetWidget::Invalidate(const nsIntRect& aRect, bool aIsSynchronous)
 {
 #ifdef DEBUG
-  debug_DumpInvalidate(stderr, this, &aRect,
+  debug_DumpInvalidate(stderr, this, &aRect, aIsSynchronous,
                        nsCAutoString("PuppetWidget"), nsnull);
 #endif
 
   if (mChild) {
-    return mChild->Invalidate(aRect);
+    return mChild->Invalidate(aRect, aIsSynchronous);
   }
 
   mDirtyRegion.Or(mDirtyRegion, aRect);
 
-  if (!mDirtyRegion.IsEmpty() && !mPaintTask.IsPending()) {
+  if (mDirtyRegion.IsEmpty()) {
+    return NS_OK;
+  } else if (aIsSynchronous) {
+    DispatchPaintEvent();
+    return NS_OK;
+  } else if (!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/src/xpwidgets/PuppetWidget.h
+++ b/widget/src/xpwidgets/PuppetWidget.h
@@ -118,17 +118,19 @@ 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);
+  NS_IMETHOD Invalidate(const nsIntRect& aRect, bool aIsSynchronous);
+
+  NS_IMETHOD Update();
 
   // 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/src/xpwidgets/nsBaseWidget.cpp
+++ b/widget/src/xpwidgets/nsBaseWidget.cpp
@@ -1464,16 +1464,17 @@ 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");
@@ -1495,15 +1496,19 @@ 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/src/xpwidgets/nsBaseWidget.h
+++ b/widget/src/xpwidgets/nsBaseWidget.h
@@ -292,16 +292,17 @@ 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);