Bug 472730, window.sizeToContent() causes hang & full CPU usage, due to extreme recursion, r+sr=dbaron
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Wed, 14 Jan 2009 22:42:25 +0200
changeset 23685 40ba2eac8f4b81573bed4174528c3c25e116cbea
parent 23684 9cee068f81089207db9941e8f99a470472cb9985
child 23686 e943eef4d58a87080af2655aa7580a00bf7facaa
push id4678
push useropettay@mozilla.com
push dateWed, 14 Jan 2009 20:43:14 +0000
treeherdermozilla-central@40ba2eac8f4b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs472730
milestone1.9.2a1pre
Bug 472730, window.sizeToContent() causes hang & full CPU usage, due to extreme recursion, r+sr=dbaron
layout/base/nsPresShell.cpp
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1183,16 +1183,17 @@ private:
   nsresult HandleEventInternal(nsEvent* aEvent, nsIView* aView,
                                nsEventStatus *aStatus);
   nsresult HandlePositionedEvent(nsIView*       aView,
                                  nsIFrame*      aTargetFrame,
                                  nsGUIEvent*    aEvent,
                                  nsEventStatus* aEventStatus);
 
   void FireResizeEvent();
+  nsRevocableEventPtr<nsRunnableMethod<PresShell> > mResizeEvent;
 
   typedef void (*nsPluginEnumCallback)(PresShell*, nsIContent*);
   void EnumeratePlugins(nsIDOMDocument *aDocument,
                         const nsString &aPluginTag,
                         nsPluginEnumCallback aCallback);
 };
 
 class NS_STACK_CLASS nsPresShellEventCB : public nsDispatchingCallback
@@ -1650,16 +1651,17 @@ PresShell::Destroy()
     mDocument->DeleteShell(this);
   }
 
   // Revoke any pending reflow event.  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(!).
   mReflowEvent.Revoke();
+  mResizeEvent.Revoke();
 
   CancelAllPendingReflows();
   CancelPostedReflowCallbacks();
 
   // Destroy the frame manager. This will destroy the frame hierarchy
   mFrameConstructor->WillDestroyFrameTree(PR_TRUE);
   FrameManager()->Destroy();
 
@@ -2520,28 +2522,32 @@ PresShell::ResizeReflow(nscoord aWidth, 
     batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
   }
 
   if (aHeight == NS_UNCONSTRAINEDSIZE) {
     mPresContext->SetVisibleArea(
       nsRect(0, 0, aWidth, rootFrame->GetRect().height));
   }
 
-  if (!mIsDestroying) {
-    nsContentUtils::AddScriptRunner(NS_NEW_RUNNABLE_METHOD(PresShell,
-                                                           this,
-                                                           FireResizeEvent));
+  if (!mIsDestroying && !mResizeEvent.IsPending()) {
+    nsRefPtr<nsRunnableMethod<PresShell> > resizeEvent =
+      NS_NEW_RUNNABLE_METHOD(PresShell, this, FireResizeEvent);
+    if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent))) {
+      mResizeEvent = resizeEvent;
+    }
   }
 
   return NS_OK; //XXX this needs to be real. MMP
 }
 
 void
 PresShell::FireResizeEvent()
 {
+  mResizeEvent.Revoke();
+
   if (mIsDocumentGone)
     return;
 
   //Send resize event from here.
   nsEvent event(PR_TRUE, NS_RESIZE_EVENT);
   nsEventStatus status = nsEventStatus_eIgnore;
 
   nsPIDOMWindow *window = mDocument->GetWindow();
@@ -4423,16 +4429,23 @@ PresShell::DoFlushPendingNotifications(m
   NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager");
   // 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 NS_OK;
+      }
+    }
+
     // 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);
 
     // Force flushing of any pending content notifications that might have
     // queued up while our event was pending.  That will ensure that we don't
     // construct frames for content right now that's still waiting to be