Bug 598482 part 15 - Rename view update batches to refresh disable batches and only use them in the two places that can enter reflow (where synchronous painting is permitted). r=roc
authorMarkus Stange <mstange@themasta.com>
Fri, 23 Dec 2011 22:52:23 -0500
changeset 84529 6d9721de770c41005b74cd6d7623cfd32ce29c60
parent 84528 a353425564823a2cd13d02b96a194c2513fcb23e
child 84530 71d77495b606fc145bdceabcda29181978bd9405
push id21854
push userbmo@edmorley.co.uk
push dateSun, 15 Jan 2012 11:56:28 +0000
treeherdermozilla-central@823072af2430 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs598482
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 598482 part 15 - Rename view update batches to refresh disable batches and only use them in the two places that can enter reflow (where synchronous painting is permitted). r=roc
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsDocumentViewer.cpp
layout/base/nsPresShell.cpp
view/public/nsIViewManager.h
view/src/nsViewManager.cpp
view/src/nsViewManager.h
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -4201,25 +4201,16 @@ nsresult nsEditor::BeginUpdateViewBatch(
     nsCOMPtr<nsISelection> selection;
     GetSelection(getter_AddRefs(selection));
 
     if (selection) 
     {
       nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
       selPrivate->StartBatchChanges();
     }
-
-    // Turn off view updating.
-    nsCOMPtr<nsIPresShell> ps = GetPresShell();
-    if (ps) {
-      nsCOMPtr<nsIViewManager> viewManager = ps->GetViewManager();
-      if (viewManager) {
-        mBatch.BeginUpdateViewBatch(viewManager);
-      }
-    }
   }
 
   mUpdateCount++;
 
   return NS_OK;
 }
 
 
@@ -4245,18 +4236,16 @@ nsresult nsEditor::EndUpdateViewBatch()
     nsRefPtr<nsCaret> caret;
     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
 
     if (presShell)
       caret = presShell->GetCaret();
 
     StCaretHider caretHider(caret);
 
-    mBatch.EndUpdateViewBatch();
-
     // 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
@@ -758,17 +758,16 @@ public:
 
 protected:
 
   PRUint32        mModCount;     // number of modifications (for undo/redo stack)
   PRUint32        mFlags;        // behavior flags. See nsIPlaintextEditor.idl for the flags we use.
 
   nsWeakPtr       mSelConWeak;   // weak reference to the nsISelectionController
   PRInt32         mUpdateCount;
-  nsIViewManager::UpdateViewBatch mBatch;
 
   // Spellchecking
   enum Tristate {
     eTriUnset,
     eTriFalse,
     eTriTrue
   }                 mSpellcheckCheckboxState;
   nsCOMPtr<nsIInlineSpellChecker> mInlineSpellChecker;
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7769,28 +7769,24 @@ ApplyRenderingChangeToTree(nsPresContext
 
   nsIViewManager* viewManager = shell->GetViewManager();
 
   // Trigger rendering updates by damaging this frame and any
   // continuations of this frame.
 
   // XXX this needs to detect the need for a view due to an opacity change and deal with it...
 
-  nsIViewManager::UpdateViewBatch batch(viewManager);
-
 #ifdef DEBUG
   gInApplyRenderingChangeToTree = true;
 #endif
   DoApplyRenderingChangeToTree(aFrame, viewManager, shell->FrameManager(),
                                aChange);
 #ifdef DEBUG
   gInApplyRenderingChangeToTree = false;
 #endif
-  
-  batch.EndUpdateViewBatch();
 }
 
 /**
  * This method invalidates the canvas when frames are removed or added for a
  * node that might have its background propagated to the canvas, i.e., a
  * document root node or an HTML BODY which is a child of the root node.
  *
  * @param aFrame a frame for a content node about to be removed or a frame that
@@ -7821,23 +7817,18 @@ InvalidateCanvasIfNeeded(nsIPresShell* p
     }
   }
 
   // At this point the node has no parent or it's an HTML <body> child of the
   // root.  We might not need to invalidate in this case (eg we might be in
   // XHTML or something), but chances are we want to.  Play it safe.
   // Invalidate the viewport.
 
-  // Wrap this in a DEFERRED view update batch so we don't try to
-  // flush out layout here
-
-  nsIViewManager::UpdateViewBatch batch(presShell->GetViewManager());
   nsIFrame* rootFrame = presShell->GetRootFrame();
   rootFrame->InvalidateFrameSubtree();
-  batch.EndUpdateViewBatch();
 }
 
 nsresult
 nsCSSFrameConstructor::StyleChangeReflow(nsIFrame* aFrame,
                                          nsChangeHint aHint)
 {
   // If the frame hasn't even received an initial reflow, then don't
   // send it a style-change reflow!
@@ -11594,33 +11585,32 @@ nsCSSFrameConstructor::RebuildAllStyleDa
   mRebuildAllStyleData = false;
   NS_UpdateHint(aExtraHint, mRebuildAllExtraHint);
   mRebuildAllExtraHint = nsChangeHint(0);
 
   if (!mPresShell || !mPresShell->GetRootFrame())
     return;
 
   // Make sure that the viewmanager will outlive the presshell
-  nsIViewManager::UpdateViewBatch batch(mPresShell->GetViewManager());
+  nsCOMPtr<nsIViewManager> vm = mPresShell->GetViewManager();
 
   // Processing the style changes could cause a flush that propagates to
   // the parent frame and thus destroys the pres shell.
   nsCOMPtr<nsIPresShell> kungFuDeathGrip(mPresShell);
 
   // We may reconstruct frames below and hence process anything that is in the
   // tree. We don't want to get notified to process those items again after.
   mPresShell->GetDocument()->FlushPendingNotifications(Flush_ContentAndNotify);
 
   nsAutoScriptBlocker scriptBlocker;
 
   // Tell the style set to get the old rule tree out of the way
   // so we can recalculate while maintaining rule tree immutability
   nsresult rv = mPresShell->StyleSet()->BeginReconstruct();
   if (NS_FAILED(rv)) {
-    batch.EndUpdateViewBatch();
     return;
   }
 
   nsPresContext *presContext = mPresShell->GetPresContext();
   presContext->SetProcessingRestyles(true);
   // Recalculate all of the style contexts for the document
   // Note that we can ignore the return value of ComputeStyleChangeFor
   // because we never need to reframe the root frame
@@ -11645,17 +11635,16 @@ nsCSSFrameConstructor::RebuildAllStyleDa
   ProcessPendingRestyles();
 
   // Tell the style set it's safe to destroy the old rule tree.  We
   // must do this after the ProcessRestyledFrames call in case the
   // change list has frame reconstructs in it (since frames to be
   // reconstructed will still have their old style context pointers
   // until they are destroyed).
   mPresShell->StyleSet()->EndReconstruct();
-  batch.EndUpdateViewBatch();
 }
 
 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
@@ -2821,36 +2821,32 @@ NS_IMETHODIMP
 DocumentViewerImpl::SetTextZoom(float aTextZoom)
 {
   if (GetIsPrintPreview()) {
     return NS_OK;
   }
 
   mTextZoom = aTextZoom;
 
-  nsIViewManager::UpdateViewBatch batch(GetViewManager());
-      
   // Set the text zoom on all children of mContainer (even if our zoom didn't
   // change, our children's zoom may be different, though it would be unusual).
   // Do this first, in case kids are auto-sizing and post reflow commands on
   // our presshell (which should be subsumed into our own style change reflow).
   struct ZoomInfo ZoomInfo = { aTextZoom };
   CallChildren(SetChildTextZoom, &ZoomInfo);
 
   // Now change our own zoom
   nsPresContext* pc = GetPresContext();
   if (pc && aTextZoom != mPresContext->TextZoom()) {
       pc->SetTextZoom(aTextZoom);
   }
 
   // And do the external resources
   mDocument->EnumerateExternalResources(SetExtResourceTextZoom, &ZoomInfo);
 
-  batch.EndUpdateViewBatch();
-  
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DocumentViewerImpl::GetTextZoom(float* aTextZoom)
 {
   NS_ENSURE_ARG_POINTER(aTextZoom);
   nsPresContext* pc = GetPresContext();
@@ -2862,36 +2858,32 @@ NS_IMETHODIMP
 DocumentViewerImpl::SetMinFontSize(PRInt32 aMinFontSize)
 {
   if (GetIsPrintPreview()) {
     return NS_OK;
   }
 
   mMinFontSize = aMinFontSize;
 
-  nsIViewManager::UpdateViewBatch batch(GetViewManager());
-      
   // Set the min font on all children of mContainer (even if our min font didn't
   // change, our children's min font may be different, though it would be unusual).
   // Do this first, in case kids are auto-sizing and post reflow commands on
   // our presshell (which should be subsumed into our own style change reflow).
   CallChildren(SetChildMinFontSize, NS_INT32_TO_PTR(aMinFontSize));
 
   // Now change our own min font
   nsPresContext* pc = GetPresContext();
   if (pc && aMinFontSize != mPresContext->MinFontSize()) {
     pc->SetMinFontSize(aMinFontSize);
   }
 
   // And do the external resources
   mDocument->EnumerateExternalResources(SetExtResourceMinFontSize,
                                         NS_INT32_TO_PTR(aMinFontSize));
 
-  batch.EndUpdateViewBatch();
-  
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DocumentViewerImpl::GetMinFontSize(PRInt32* aMinFontSize)
 {
   NS_ENSURE_ARG_POINTER(aMinFontSize);
   nsPresContext* pc = GetPresContext();
@@ -2904,17 +2896,16 @@ DocumentViewerImpl::SetFullZoom(float aF
 {
 #ifdef NS_PRINT_PREVIEW
   if (GetIsPrintPreview()) {
     nsPresContext* pc = GetPresContext();
     NS_ENSURE_TRUE(pc, NS_OK);
     nsCOMPtr<nsIPresShell> shell = pc->GetPresShell();
     NS_ENSURE_TRUE(shell, NS_OK);
 
-    nsIViewManager::UpdateViewBatch batch(shell->GetViewManager());
     if (!mPrintPreviewZoomed) {
       mOriginalPrintPreviewScale = pc->GetPrintPreviewScale();
       mPrintPreviewZoomed = true;
     }
 
     mPrintPreviewZoom = aFullZoom;
     pc->SetPrintPreviewScale(aFullZoom * mOriginalPrintPreviewScale);
     nsIPageSequenceFrame* pf = shell->GetPageSequenceFrame();
@@ -2923,38 +2914,33 @@ DocumentViewerImpl::SetFullZoom(float aF
       shell->FrameNeedsReflow(f, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
     }
 
     nsIFrame* rootFrame = shell->GetRootFrame();
     if (rootFrame) {
       nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
       rootFrame->Invalidate(rect);
     }
-    batch.EndUpdateViewBatch();
     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();
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DocumentViewerImpl::GetFullZoom(float* aFullZoom)
 {
   NS_ENSURE_ARG_POINTER(aFullZoom);
 #ifdef NS_PRINT_PREVIEW
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -2110,18 +2110,16 @@ PresShell::ResizeReflowIgnoreOverride(ns
 
   // There isn't anything useful we can do if the initial reflow hasn't happened
   rootFrame = FrameManager()->GetRootFrame();
   if (!rootFrame)
     return NS_OK;
 
   if (!GetPresContext()->SupressingResizeReflow())
   {
-    nsIViewManager::UpdateViewBatch batch(mViewManager);
-
     // Have to make sure that the content notifications are flushed before we
     // start messing with the frame model; otherwise we can get content doubling.
     mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
 
     // Make sure style is up to date
     {
       nsAutoScriptBlocker scriptBlocker;
       mFrameConstructor->CreateNeededFrames();
@@ -2134,25 +2132,24 @@ PresShell::ResizeReflowIgnoreOverride(ns
       // the way don't have region accumulation issues?
 
       {
         nsAutoCauseReflowNotifier crNotifier(this);
         WillDoReflow();
 
         // Kick off a top-down reflow
         AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
+        nsIViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
 
         mDirtyRoots.RemoveElement(rootFrame);
         DoReflow(rootFrame, true);
       }
 
       DidDoReflow(true);
     }
-
-    batch.EndUpdateViewBatch();
   }
 
   rootFrame = FrameManager()->GetRootFrame();
   if (aHeight == NS_UNCONSTRAINEDSIZE && rootFrame) {
     mPresContext->SetVisibleArea(
       nsRect(0, 0, aWidth, rootFrame->GetRect().height));
   }
 
@@ -2955,33 +2952,31 @@ PresShell::RecreateFramesFor(nsIContent*
     // root we will crash.
     return NS_OK;
   }
 
   // Don't call RecreateFramesForContent since that is not exported and we want
   // to keep the number of entrypoints down.
 
   NS_ASSERTION(mViewManager, "Should have view manager");
-  nsIViewManager::UpdateViewBatch batch(mViewManager);
 
   // Have to make sure that the content notifications are flushed before we
   // start messing with the frame model; otherwise we can get content doubling.
   mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
 
   nsAutoScriptBlocker scriptBlocker;
 
   nsStyleChangeList changeList;
   changeList.AppendChange(nsnull, aContent, nsChangeHint_ReconstructFrame);
 
   // Mark ourselves as not safe to flush while we're doing frame construction.
   ++mChangeNestCount;
   nsresult rv = mFrameConstructor->ProcessRestyledFrames(changeList);
   --mChangeNestCount;
   
-  batch.EndUpdateViewBatch();
   return rv;
 }
 
 void
 nsIPresShell::PostRecreateFramesFor(Element* aElement)
 {
   FrameConstructor()->PostRestyleEvent(aElement, nsRestyleHint(0),
                                        nsChangeHint_ReconstructFrame);
@@ -3988,35 +3983,30 @@ PresShell::FlushPendingNotifications(moz
   // it's safe to run script.
   bool hasHadScriptObject;
   if (mDocument->GetScriptHandlingObject(hasHadScriptObject) ||
       hasHadScriptObject) {
     isSafeToFlush = isSafeToFlush && nsContentUtils::IsSafeToRunScript();
   }
 
   NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager");
-  // Make sure the view manager stays alive while batching view updates.
+  // Make sure the view manager stays alive.
   nsCOMPtr<nsIViewManager> viewManagerDeathGrip = mViewManager;
   if (isSafeToFlush && mViewManager) {
     // Processing pending notifications can kill us, and some callers only
     // hold weak refs when calling FlushPendingNotifications().  :(
     nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
 
     if (mResizeEvent.IsPending()) {
       FireResizeEvent();
       if (mIsDestroying) {
         return;
       }
     }
 
-    // Style reresolves not in conjunction with reflows can't cause
-    // painting or geometry changes, so don't bother with view update
-    // batching if we only have style reresolve
-    nsIViewManager::UpdateViewBatch batch(mViewManager);
-
     // We need to make sure external resource documents are flushed too (for
     // example, svg filters that reference a filter in an external document
     // need the frames in the external document to be constructed for the
     // filter to work). We only need external resources to be flushed when the
     // main document is flushing >= Flush_Frames, so we flush external
     // resources here instead of nsDocument::FlushPendingNotifications.
     mDocument->FlushExternalResources(aType);
 
@@ -4100,18 +4090,16 @@ PresShell::FlushPendingNotifications(moz
       // 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();
       }
     }
-
-    batch.EndUpdateViewBatch();
   }
 }
 
 void
 PresShell::CharacterDataChanged(nsIDocument *aDocument,
                                 nsIContent*  aContent,
                                 CharacterDataChangeInfo* aInfo)
 {
@@ -7424,16 +7412,17 @@ PresShell::ProcessReflowCommands(bool aI
         ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime)
         : (PRIntervalTime)0;
 
     // Scope for the reflow entry point
     {
       nsAutoScriptBlocker scriptBlocker;
       WillDoReflow();
       AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
+      nsIViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
 
       do {
         // Send an incremental reflow notification to the target frame.
         PRInt32 idx = mDirtyRoots.Length() - 1;
         nsIFrame *target = mDirtyRoots[idx];
         mDirtyRoots.RemoveElementAt(idx);
 
         if (!NS_SUBTREE_DIRTY(target)) {
@@ -7572,17 +7561,16 @@ PresShell::Observe(nsISupports* aSubject
 {
 #ifdef MOZ_XUL
   if (!nsCRT::strcmp(aTopic, "chrome-flush-skin-caches")) {
     nsIFrame *rootFrame = FrameManager()->GetRootFrame();
     // Need to null-check because "chrome-flush-skin-caches" can happen
     // at interesting times during startup.
     if (rootFrame) {
       NS_ASSERTION(mViewManager, "View manager must exist");
-      nsIViewManager::UpdateViewBatch batch(mViewManager);
 
       nsWeakFrame weakRoot(rootFrame);
       // Have to make sure that the content notifications are flushed before we
       // start messing with the frame model; otherwise we can get content doubling.
       mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
 
       if (weakRoot.IsAlive()) {
         WalkFramesThroughPlaceholders(mPresContext, rootFrame,
@@ -7597,17 +7585,16 @@ PresShell::Observe(nsISupports* aSubject
         // construction.
         {
           nsAutoScriptBlocker scriptBlocker;
           ++mChangeNestCount;
           mFrameConstructor->ProcessRestyledFrames(changeList);
           --mChangeNestCount;
         }
       }
-      batch.EndUpdateViewBatch();
     }
     return NS_OK;
   }
 #endif
 
   if (!nsCRT::strcmp(aTopic, "agent-sheet-added") && mStyleSet) {
     AddAgentSheet(aSubject);
     return NS_OK;
--- a/view/public/nsIViewManager.h
+++ b/view/public/nsIViewManager.h
@@ -254,75 +254,52 @@ public:
   virtual nsIPresShell* GetPresShell() = 0;
 
   /**
    * Get the device context associated with this manager
    * @result device context
    */
   NS_IMETHOD  GetDeviceContext(nsDeviceContext *&aContext) = 0;
 
-  class UpdateViewBatch {
+  /**
+   * A stack class for disallowing changes that would enter painting. For
+   * example, popup widgets shouldn't be resized during reflow, since doing so
+   * might cause synchronous painting inside reflow which is forbidden.
+   * While refresh is disabled, widget geometry changes are deferred and will
+   * be handled later, either from the refresh driver or from an NS_WILL_PAINT
+   * event.
+   * We don't want to defer widget geometry changes all the time. Resizing a
+   * popup from script doesn't need to be deferred, for example, especially
+   * since popup widget geometry is observable from script and expected to
+   * update synchronously.
+   */
+  class NS_STACK_CLASS AutoDisableRefresh {
   public:
-    UpdateViewBatch() {}
-  /**
-   * prevents the view manager from refreshing. allows UpdateView()
-   * to notify widgets of damaged regions that should be repainted
-   * when the batch is ended. Call EndUpdateViewBatch on this object
-   * before it is destroyed
-   * @return error status
-   */
-    UpdateViewBatch(nsIViewManager* aVM) {
+    AutoDisableRefresh(nsIViewManager* aVM) {
       if (aVM) {
-        mRootVM = aVM->BeginUpdateViewBatch();
+        mRootVM = aVM->IncrementDisableRefreshCount();
       }
     }
-    ~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.
-   *
-   * If this is not the outermost view batch command, then this does
-   * nothing. When the
-   * outermost batch finally ends, all widgets are invalidated normally
-   * and will be painted the next time the toolkit chooses to update them.
-   *
-   * description @return error status
-   */
-    void EndUpdateViewBatch() {
-      if (!mRootVM)
-        return;
-      mRootVM->EndUpdateViewBatch();
-      mRootVM = nsnull;
-    }
-
   private:
-    UpdateViewBatch(const UpdateViewBatch& aOther);
-    const UpdateViewBatch& operator=(const UpdateViewBatch& aOther);
+    AutoDisableRefresh(const AutoDisableRefresh& aOther);
+    const AutoDisableRefresh& operator=(const AutoDisableRefresh& aOther);
 
     nsCOMPtr<nsIViewManager> mRootVM;
   };
-  
+
 private:
-  friend class UpdateViewBatch;
+  friend class AutoDisableRefresh;
 
-  virtual nsIViewManager* BeginUpdateViewBatch(void) = 0;
-  NS_IMETHOD EndUpdateViewBatch() = 0;
+  virtual nsIViewManager* IncrementDisableRefreshCount() = 0;
+  virtual void DecrementDisableRefreshCount() = 0;
 
 public:
   /**
    * Retrieve the widget at the root of the nearest enclosing
    * view manager whose root view has a widget.
    */
   NS_IMETHOD GetRootWidget(nsIWidget **aWidget) = 0;
 
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -804,21 +804,17 @@ NS_IMETHODIMP nsViewManager::DispatchEve
           rootVM->GetRootWidget(getter_AddRefs(widget));
           bool transparentWindow = false;
           if (widget)
               transparentWindow = widget->GetTransparencyMode() == eTransparencyTransparent;
 
           nsView* view = static_cast<nsView*>(aView);
           if (!transparentWindow) {
             if (mPresShell) {
-              // Do an update view batch.
-              UpdateViewBatch batch(this);
               rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
-              batch.EndUpdateViewBatch();
-
               // 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) {
@@ -1292,42 +1288,34 @@ NS_IMETHODIMP nsViewManager::SetViewZInd
 
 NS_IMETHODIMP nsViewManager::GetDeviceContext(nsDeviceContext *&aContext)
 {
   aContext = mContext;
   NS_IF_ADDREF(aContext);
   return NS_OK;
 }
 
-nsIViewManager* nsViewManager::BeginUpdateViewBatch(void)
+nsIViewManager*
+nsViewManager::IncrementDisableRefreshCount()
 {
   if (!IsRootVM()) {
-    return RootViewManager()->BeginUpdateViewBatch();
+    return RootViewManager()->IncrementDisableRefreshCount();
   }
-  
-  ++mUpdateBatchCnt;
+
+  ++mRefreshDisableCount;
 
   return this;
 }
 
-NS_IMETHODIMP nsViewManager::EndUpdateViewBatch()
+void
+nsViewManager::DecrementDisableRefreshCount()
 {
   NS_ASSERTION(IsRootVM(), "Should only be called on root");
-  
-  --mUpdateBatchCnt;
-
-  NS_ASSERTION(mUpdateBatchCnt >= 0, "Invalid batch count!");
-
-  if (mUpdateBatchCnt < 0)
-    {
-      mUpdateBatchCnt = 0;
-      return NS_ERROR_FAILURE;
-    }
-
-  return NS_OK;
+  --mRefreshDisableCount;
+  NS_ASSERTION(mRefreshDisableCount >= 0, "Invalid refresh disable count!");
 }
 
 NS_IMETHODIMP nsViewManager::GetRootWidget(nsIWidget **aWidget)
 {
   if (!mRootView) {
     *aWidget = nsnull;
     return NS_OK;
   }
@@ -1378,32 +1366,26 @@ nsViewManager::ProcessPendingUpdates()
     mHasPendingUpdates = 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()
--- a/view/src/nsViewManager.h
+++ b/view/src/nsViewManager.h
@@ -127,18 +127,18 @@ public:
 
   NS_IMETHOD  SetViewZIndex(nsIView *aView, bool aAuto, PRInt32 aZIndex, bool aTopMost=false);
 
   virtual void SetPresShell(nsIPresShell *aPresShell) { mPresShell = aPresShell; }
   virtual nsIPresShell* GetPresShell() { return mPresShell; }
 
   NS_IMETHOD  GetDeviceContext(nsDeviceContext *&aContext);
 
-  virtual nsIViewManager* BeginUpdateViewBatch(void);
-  NS_IMETHOD  EndUpdateViewBatch();
+  virtual nsIViewManager* IncrementDisableRefreshCount();
+  virtual void DecrementDisableRefreshCount();
 
   NS_IMETHOD GetRootWidget(nsIWidget **aWidget);
  
   NS_IMETHOD IsPainting(bool& aIsPainting);
   NS_IMETHOD GetLastUserEventTime(PRUint32& aTime);
   static PRUint32 gLastUserEventTime;
 
   /* Update the cached RootViewManager pointer on this view manager. */
@@ -200,17 +200,20 @@ private:
 
   nsresult UpdateView(nsIView *aView, const nsRect &aRect);
 
 public: // NOT in nsIViewManager, so private to the view module
   nsView* GetRootViewImpl() const { return mRootView; }
   nsViewManager* RootViewManager() const { return mRootViewManager; }
   bool IsRootVM() const { return this == RootViewManager(); }
 
-  bool IsPaintingAllowed() { return RootViewManager()->mUpdateBatchCnt == 0; }
+  // Whether synchronous painting is allowed at the moment. For example,
+  // widget geometry changes can cause synchronous painting, so they need to
+  // be deferred while refresh is disabled.
+  bool IsPaintingAllowed() { return RootViewManager()->mRefreshDisableCount == 0; }
 
   // Call this when you need to let the viewmanager know that it now has
   // pending updates.
   void PostPendingUpdate();
 
   PRUint32 AppUnitsPerDevPixel() const
   {
     return mContext->AppUnitsPerDevPixel();
@@ -228,17 +231,17 @@ private:
   // mRootViewManager is a strong ref unless it equals |this|.  It's
   // never null (if we have no ancestors, it will be |this|).
   nsViewManager     *mRootViewManager;
 
   // The following members should not be accessed directly except by
   // the root view manager.  Some have accessor functions to enforce
   // this, as noted.
   
-  PRInt32           mUpdateBatchCnt;
+  PRInt32           mRefreshDisableCount;
   // Use IsPainting() and SetPainting() to access mPainting.
   bool              mPainting;
   bool              mRecursiveRefreshPending;
   bool              mHasPendingUpdates;
   bool              mInScroll;
 
   //from here to public should be static and locked... MMP
   static PRInt32           mVMCount;        //number of viewmanagers