Bug 395628 - ""ASSERTION: post-reflow queues not empty" with feed in <frame>" [p=mats.palmgren@bredband.net (Mats Palmgren) r=smaug r+sr=dbaron a=blocking1.9+]
authorreed@reedloden.com
Fri, 30 Nov 2007 23:22:44 -0800
changeset 8509 892d596ba80c7440782e87a2438d5fe2b809c4de
parent 8508 8bbbb89664c566f02faf6532dc0348d800ee882b
child 8510 ff4ea918326b02d963a8833ed965c527887f9451
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherderautoland@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, blocking1.9
bugs395628
milestone1.9b2pre
Bug 395628 - ""ASSERTION: post-reflow queues not empty" with feed in <frame>" [p=mats.palmgren@bredband.net (Mats Palmgren) r=smaug r+sr=dbaron a=blocking1.9+]
layout/base/nsIReflowCallback.h
layout/base/nsPresShell.cpp
layout/generic/nsFrameFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/xul/base/src/nsListBoxBodyFrame.cpp
layout/xul/base/src/nsListBoxBodyFrame.h
layout/xul/base/src/nsMenuFrame.cpp
layout/xul/base/src/nsProgressMeterFrame.cpp
layout/xul/base/src/nsTextBoxFrame.cpp
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
layout/xul/base/src/tree/src/nsTreeBodyFrame.h
--- a/layout/base/nsIReflowCallback.h
+++ b/layout/base/nsIReflowCallback.h
@@ -33,25 +33,34 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #ifndef nsIReflowCallback_h___
 #define nsIReflowCallback_h___
 
-class nsIPresShell;
-
 /**
  * Reflow callback interface.
  * These are not refcounted. Objects must be removed from the presshell
  * callback list before they die.
+ * Protocol: objects will either get a ReflowFinished() call when a reflow
+ * has finished or a ReflowCallbackCanceled() call if the shell is destroyed,
+ * whichever happens first. If the object is explicitly removed from the shell
+ * (using nsIPresShell::CancelReflowCallback()) before that occurs then neither
+ * of the callback methods are called.
  */
 class nsIReflowCallback {
 public:
   /**
    * The presshell calls this when reflow has finished. Return PR_TRUE if
    * you need a Flush_Layout to happen after this.
    */
   virtual PRBool ReflowFinished() = 0;
+  /**
+   * The presshell calls this on outstanding callback requests in its
+   * Destroy() method. The shell removes the request after calling
+   * ReflowCallbackCanceled().
+   */
+  virtual void ReflowCallbackCanceled() = 0;
 };
 
-#endif /* nsIFrameUtil_h___ */
+#endif /* nsIReflowCallback_h___ */
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -997,16 +997,17 @@ public:
 #ifdef PR_LOGGING
   static PRLogModuleInfo* gLog;
 #endif
 
 protected:
   virtual ~PresShell();
 
   void HandlePostedReflowCallbacks();
+  void CancelPostedReflowCallbacks();
 
   void UnsuppressAndInvalidate();
 
   void     WillCauseReflow() { ++mChangeNestCount; }
   nsresult DidCauseReflow();
   void     WillDoReflow();
   void     DidDoReflow();
   nsresult ProcessReflowCommands(PRBool aInterruptible);
@@ -1658,16 +1659,17 @@ PresShell::Destroy()
 
   // 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();
 
   CancelAllPendingReflows();
+  CancelPostedReflowCallbacks();
 
   // Destroy the frame manager. This will destroy the frame hierarchy
   mFrameConstructor->WillDestroyFrameTree();
   FrameManager()->Destroy();
 
   NS_WARN_IF_FALSE(!mWeakFrames, "Weak frames alive after destroying FrameManager");
   while (mWeakFrames) {
     mWeakFrames->Clear(this);
@@ -4368,16 +4370,33 @@ PresShell::CancelReflowCallback(nsIReflo
         node = node->next;
       }
    }
 
    return NS_OK;
 }
 
 void
+PresShell::CancelPostedReflowCallbacks()
+{
+  while (mFirstCallbackEventRequest) {
+    nsCallbackEventRequest* node = mFirstCallbackEventRequest;
+    mFirstCallbackEventRequest = node->next;
+    if (!mFirstCallbackEventRequest) {
+      mLastCallbackEventRequest = nsnull;
+    }
+    nsIReflowCallback* callback = node->callback;
+    FreeFrame(sizeof(nsCallbackEventRequest), node);
+    if (callback) {
+      callback->ReflowCallbackCanceled();
+    }
+  }
+}
+
+void
 PresShell::HandlePostedReflowCallbacks()
 {
    PRBool shouldFlush = PR_FALSE;
 
    while (mFirstCallbackEventRequest) {
      nsCallbackEventRequest* node = mFirstCallbackEventRequest;
      mFirstCallbackEventRequest = node->next;
      if (!mFirstCallbackEventRequest) {
@@ -5487,17 +5506,17 @@ PresShell::HandleEvent(nsIView         *
     // list.
     if (framePresContext == rootPresContext &&
         frame == FrameManager()->GetRootFrame()) {
 
 #ifdef MOZ_XUL
       nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
       if (pm) {
         nsTArray<nsIFrame*> popups = pm->GetOpenPopups();
-        PRInt32 i;
+        PRUint32 i;
         // Search from top to bottom
         for (i = 0; i < popups.Length(); i++) {
           nsIFrame* popup = popups[i];
           if (popup->GetOverflowRect().Contains(
               nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, popup))) {
             // The event should target the popup
             frame = popup;
             break;
--- a/layout/generic/nsFrameFrame.cpp
+++ b/layout/generic/nsFrameFrame.cpp
@@ -171,16 +171,17 @@ public:
 
   // nsIFrameFrame
   NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
 
   NS_IMETHOD  VerifyTree() const;
 
   // nsIReflowCallback
   virtual PRBool ReflowFinished();
+  virtual void ReflowCallbackCanceled();
 
 protected:
   nsSize GetMargin();
   PRBool IsInline() { return mIsInline; }
   nsresult ShowDocShell();
   nsresult CreateViewAndWidget(nsContentType aContentType);
 
   virtual nscoord GetIntrinsicWidth();
@@ -579,16 +580,21 @@ nsSubDocumentFrame::ReflowFinished()
   } else {
     // Make sure that we can post a reflow callback in the future.
     mPostedReflowCallback = PR_FALSE;
   }
 
   return PR_FALSE;
 }
 
+void
+nsSubDocumentFrame::ReflowCallbackCanceled()
+{
+  mPostedReflowCallback = PR_FALSE;
+}
 
 NS_IMETHODIMP
 nsSubDocumentFrame::VerifyTree() const
 {
   // XXX Completely disabled for now; once pseud-frames are reworked
   // then we can turn it back on.
   return NS_OK;
 }
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2384,16 +2384,22 @@ nsGfxScrollFrameInner::ReflowFinished()
   // maximization.)
   if (!mHScrollbarBox && !mVScrollbarBox)
     return PR_FALSE;
   CurPosAttributeChanged(mVScrollbarBox ? mVScrollbarBox->GetContent()
                                         : mHScrollbarBox->GetContent());
   return PR_TRUE;
 }
 
+void
+nsGfxScrollFrameInner::ReflowCallbackCanceled()
+{
+  mPostedReflowCallback = PR_FALSE;
+}
+
 static void LayoutAndInvalidate(nsBoxLayoutState& aState,
                                 nsIFrame* aBox, const nsRect& aRect)
 {
   // When a child box changes shape of position, the parent
   // is responsible for invalidation; the overflow rect must be invalidated
   // to make sure to catch any overflow
   PRBool rectChanged = aBox->GetRect() != aRect;
   if (rectChanged)
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -91,16 +91,17 @@ public:
                             const nsRect&           aDirtyRect,
                             const nsDisplayListSet& aLists);
 
   virtual void InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
                                   nsIFrame* aForChild, PRBool aImmediate);
 
   // nsIReflowCallback
   virtual PRBool ReflowFinished();
+  virtual void ReflowCallbackCanceled();
 
   // nsIScrollPositionListener
 
   NS_IMETHOD ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
   NS_IMETHOD ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
 
   // This gets called when the 'curpos' attribute on one of the scrollbars changes
   void CurPosAttributeChanged(nsIContent* aChild);
--- a/layout/xul/base/src/nsListBoxBodyFrame.cpp
+++ b/layout/xul/base/src/nsListBoxBodyFrame.cpp
@@ -502,16 +502,22 @@ nsListBoxBodyFrame::ReflowFinished()
        mAdjustScroll = PR_TRUE;
     mRowHeightWasSet = PR_FALSE;
   }
 
   mReflowCallbackPosted = PR_FALSE;
   return PR_TRUE;
 }
 
+void
+nsListBoxBodyFrame::ReflowCallbackCanceled()
+{
+  mReflowCallbackPosted = PR_FALSE;
+}
+
 ///////// nsIListBoxObject ///////////////
 
 NS_IMETHODIMP
 nsListBoxBodyFrame::GetListboxBody(nsIListBoxObject * *aListboxBody)
 {
   *aListboxBody = this;
   NS_IF_ADDREF(*aListboxBody);
   return NS_OK;
--- a/layout/xul/base/src/nsListBoxBodyFrame.h
+++ b/layout/xul/base/src/nsListBoxBodyFrame.h
@@ -83,16 +83,17 @@ public:
 
   // nsIScrollbarMediator
   NS_IMETHOD PositionChanged(nsISupports* aScrollbar, PRInt32 aOldIndex, PRInt32& aNewIndex);
   NS_IMETHOD ScrollbarButtonPressed(nsISupports* aScrollbar, PRInt32 aOldIndex, PRInt32 aNewIndex);
   NS_IMETHOD VisibilityChanged(nsISupports* aScrollbar, PRBool aVisible);
 
   // nsIReflowCallback
   virtual PRBool ReflowFinished();
+  virtual void ReflowCallbackCanceled();
 
   // nsIBox
   NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState);
   virtual void MarkIntrinsicWidthsDirty();
 
   virtual nsSize GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState);
   virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState);
 
--- a/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -229,29 +229,35 @@ nsMenuFrame::InitMenuParent(nsIFrame* aP
 class nsASyncMenuInitialization : public nsIReflowCallback
 {
 public:
   nsASyncMenuInitialization(nsIFrame* aFrame)
     : mWeakFrame(aFrame)
   {
   }
 
-  virtual PRBool ReflowFinished() {
+  virtual PRBool ReflowFinished()
+  {
     PRBool shouldFlush = PR_FALSE;
     if (mWeakFrame.IsAlive()) {
       if (mWeakFrame.GetFrame()->GetType() == nsGkAtoms::menuFrame) {
         nsMenuFrame* menu = static_cast<nsMenuFrame*>(mWeakFrame.GetFrame());
         menu->UpdateMenuType(menu->PresContext());
         shouldFlush = PR_TRUE;
       }
     }
     delete this;
     return shouldFlush;
   }
 
+  virtual void ReflowCallbackCanceled()
+  {
+    delete this;
+  }
+
   nsWeakFrame mWeakFrame;
 };
 
 NS_IMETHODIMP
 nsMenuFrame::Init(nsIContent*      aContent,
                   nsIFrame*        aParent,
                   nsIFrame*        aPrevInFlow)
 {
--- a/layout/xul/base/src/nsProgressMeterFrame.cpp
+++ b/layout/xul/base/src/nsProgressMeterFrame.cpp
@@ -83,16 +83,21 @@ public:
     if (frame) {
       frame->AttributeChanged(kNameSpaceID_None, nsGkAtoms::value, 0);
       shouldFlush = PR_TRUE;
     }
     delete this;
     return shouldFlush;
   }
 
+  virtual void ReflowCallbackCanceled()
+  {
+    delete this;
+  }
+
   nsWeakFrame mWeakFrame;
 };
 
 NS_IMETHODIMP
 nsProgressMeterFrame::DoLayout(nsBoxLayoutState& aState)
 {
   if (mNeedsReflowCallback) {
     nsIReflowCallback* cb = new nsAsyncProgressMeterInit(this);
--- a/layout/xul/base/src/nsTextBoxFrame.cpp
+++ b/layout/xul/base/src/nsTextBoxFrame.cpp
@@ -220,16 +220,21 @@ public:
             static_cast<nsTextBoxFrame*>(mWeakFrame.GetFrame());
         if (frame) {
             shouldFlush = frame->UpdateAccesskey(mWeakFrame);
         }
         delete this;
         return shouldFlush;
     }
 
+    virtual void ReflowCallbackCanceled()
+    {
+        delete this;
+    }
+
     nsWeakFrame mWeakFrame;
 };
 
 PRBool
 nsTextBoxFrame::UpdateAccesskey(nsWeakFrame& aWeakThis)
 {
     nsAutoString accesskey;
     nsCOMPtr<nsIDOMXULLabelElement> labelElement = do_QueryInterface(mContent);
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
@@ -476,16 +476,21 @@ nsTreeBodyFrame::ReflowFinished()
       return PR_FALSE;
     }
   }
 
   mReflowCallbackPosted = PR_FALSE;
   return PR_FALSE;
 }
 
+void
+nsTreeBodyFrame::ReflowCallbackCanceled()
+{
+  mReflowCallbackPosted = PR_FALSE;
+}
 
 NS_IMETHODIMP nsTreeBodyFrame::GetView(nsITreeView * *aView)
 {
   EnsureView();
   NS_IF_ADDREF(*aView = mView);
   return NS_OK;
 }
 
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.h
+++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.h
@@ -89,16 +89,17 @@ public:
 
   // nsIBox
   virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState);
   virtual void SetBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect,
                          PRBool aRemoveOverflowArea = PR_FALSE);
 
   // nsIReflowCallback
   virtual PRBool ReflowFinished();
+  virtual void ReflowCallbackCanceled();
 
   // nsICSSPseudoComparator
   NS_IMETHOD PseudoMatches(nsIAtom* aTag, nsCSSSelector* aSelector, PRBool* aResult);
 
   // nsIScrollbarMediator
   NS_IMETHOD PositionChanged(nsISupports* aScrollbar, PRInt32 aOldIndex, PRInt32& aNewIndex);
   NS_IMETHOD ScrollbarButtonPressed(nsISupports* aScrollbar, PRInt32 aOldIndex, PRInt32 aNewIndex);
   NS_IMETHOD VisibilityChanged(nsISupports* aScrollbar, PRBool aVisible) { Invalidate(); return NS_OK; }