Bug 863935. r=roc
authorMats Palmgren <matspal@gmail.com>
Mon, 10 Jun 2013 18:31:59 +0000
changeset 146036 48bbd10759f78f6bd8dd76ec1edae4e3a8264d21
parent 146035 f9c790ff5706b90d72c18b6743da4a6d08d9f819
child 146037 18b7504e921f850f494492d5d1d552d6e3c55a7e
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs863935
milestone24.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 863935. r=roc
layout/generic/nsAbsoluteContainingBlock.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockReflowContext.cpp
layout/generic/nsContainerFrame.cpp
layout/generic/nsContainerFrame.h
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -151,17 +151,17 @@ nsAbsoluteContainingBlock::Reflow(nsCont
         // See bug 154892. Not sure how to do it "right" yet; probably want
         // to keep continuations within an nsAbsoluteContainingBlock eventually.
         tracker.Insert(nextFrame, kidStatus);
         NS_MergeReflowStatusInto(&reflowStatus, kidStatus);
       }
       else {
         // Delete any continuations
         if (nextFrame) {
-          tracker.Finish(kidFrame);
+          nsOverflowContinuationTracker::AutoFinish fini(&tracker, kidFrame);
           static_cast<nsContainerFrame*>(nextFrame->GetParent())
             ->DeleteNextInFlowChild(aPresContext, nextFrame, true);
         }
       }
     }
     else {
       tracker.Skip(kidFrame, reflowStatus);
       if (aOverflowAreas) {
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -3162,17 +3162,17 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
           
           nsIFrame* nextFrame = frame->GetNextInFlow();
           NS_ASSERTION(nextFrame, "We're supposed to have a next-in-flow by now");
           
           if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
             // If nextFrame used to be an overflow container, make it a normal block
             if (!madeContinuation &&
                 (NS_FRAME_IS_OVERFLOW_CONTAINER & nextFrame->GetStateBits())) {
-              aState.mOverflowTracker->Finish(frame);
+              nsOverflowContinuationTracker::AutoFinish fini(aState.mOverflowTracker, frame);
               nsContainerFrame* parent =
                 static_cast<nsContainerFrame*>(nextFrame->GetParent());
               rv = parent->StealFrame(aState.mPresContext, nextFrame);
               NS_ENSURE_SUCCESS(rv, rv);
               if (parent != this)
                 ReparentFrame(nextFrame, parent, this);
               mFrames.InsertFrame(nullptr, frame, nextFrame);
               madeContinuation = true; // needs to be added to mLines
--- a/layout/generic/nsBlockReflowContext.cpp
+++ b/layout/generic/nsBlockReflowContext.cpp
@@ -295,18 +295,17 @@ nsBlockReflowContext::ReflowBlock(const 
     if (NS_FRAME_IS_FULLY_COMPLETE(aFrameReflowStatus)) {
       nsIFrame* kidNextInFlow = mFrame->GetNextInFlow();
       if (nullptr != kidNextInFlow) {
         // Remove all of the childs next-in-flows. Make sure that we ask
         // the right parent to do the removal (it's possible that the
         // parent is not this because we are executing pullup code).
         // Floats will eventually be removed via nsBlockFrame::RemoveFloat
         // which detaches the placeholder from the float.
-/* XXX promote DeleteChildsNextInFlow to nsIFrame to elminate this cast */
-        aState.mOverflowTracker->Finish(mFrame);
+        nsOverflowContinuationTracker::AutoFinish fini(aState.mOverflowTracker, mFrame);
         static_cast<nsContainerFrame*>(kidNextInFlow->GetParent())
           ->DeleteNextInFlowChild(mPresContext, kidNextInFlow, true);
       }
     }
   }
 
   return rv;
 }
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -970,21 +970,21 @@ nsContainerFrame::ReflowChild(nsIFrame* 
   result = aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState,
                              aStatus);
 
   // If the reflow was successful and the child frame is complete, delete any
   // next-in-flows, but only if the NO_DELETE_NEXT_IN_FLOW flag isn't set.
   if (NS_SUCCEEDED(result) && NS_FRAME_IS_FULLY_COMPLETE(aStatus) &&
       !(aFlags & NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD)) {
     nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
-    if (nullptr != kidNextInFlow) {
+    if (kidNextInFlow) {
       // Remove all of the childs next-in-flows. Make sure that we ask
       // the right parent to do the removal (it's possible that the
       // parent is not this because we are executing pullup code)
-      if (aTracker) aTracker->Finish(aKidFrame);
+      nsOverflowContinuationTracker::AutoFinish fini(aTracker, aKidFrame);
       static_cast<nsContainerFrame*>(kidNextInFlow->GetParent())
         ->DeleteNextInFlowChild(aPresContext, kidNextInFlow, true);
     }
   }
   return result;
 }
 
 
@@ -1566,28 +1566,37 @@ nsOverflowContinuationTracker::nsOverflo
   : mOverflowContList(nullptr),
     mPrevOverflowCont(nullptr),
     mSentry(nullptr),
     mParent(aFrame),
     mSkipOverflowContainerChildren(aSkipOverflowContainerChildren),
     mWalkOOFFrames(aWalkOOFFrames)
 {
   NS_PRECONDITION(aFrame, "null frame pointer");
-  nsContainerFrame* next = static_cast<nsContainerFrame*>
-                             (aFrame->GetNextInFlow());
-  if (next) {
-    mOverflowContList = next->GetPropTableFrames(aPresContext,
+  SetupOverflowContList();
+}
+
+void
+nsOverflowContinuationTracker::SetupOverflowContList()
+{
+  NS_PRECONDITION(mParent, "null frame pointer");
+  NS_PRECONDITION(!mOverflowContList, "already have list");
+  nsPresContext* pc = mParent->PresContext();
+  nsContainerFrame* nif =
+    static_cast<nsContainerFrame*>(mParent->GetNextInFlow());
+  if (nif) {
+    mOverflowContList = nif->GetPropTableFrames(pc,
       nsContainerFrame::OverflowContainersProperty());
     if (mOverflowContList) {
-      mParent = next;
+      mParent = nif;
       SetUpListWalker();
     }
   }
   if (!mOverflowContList) {
-    mOverflowContList = mParent->GetPropTableFrames(aPresContext,
+    mOverflowContList = mParent->GetPropTableFrames(pc,
       nsContainerFrame::ExcessOverflowContainersProperty());
     if (mOverflowContList) {
       SetUpListWalker();
     }
   }
 }
 
 /**
@@ -1757,47 +1766,69 @@ nsOverflowContinuationTracker::Insert(ns
       }
       Insert(f, aReflowStatus);
     }
   }
   return rv;
 }
 
 void
-nsOverflowContinuationTracker::Finish(nsIFrame* aChild)
+nsOverflowContinuationTracker::BeginFinish(nsIFrame* aChild)
 {
   NS_PRECONDITION(aChild, "null ptr");
   NS_PRECONDITION(aChild->GetNextInFlow(),
                   "supposed to call Finish *before* deleting next-in-flow!");
-
-  for (nsIFrame* f = aChild; f; ) {
-    // Make sure we drop all references if all the frames in the
-    // overflow containers list are about to be destroyed.
-    nsIFrame* nif = f->GetNextInFlow();
-    if (mOverflowContList &&
-        mOverflowContList->FirstChild() == nif &&
-        (!nif->GetNextSibling() ||
-         nif->GetNextSibling() == nif->GetNextInFlow())) {
-      mOverflowContList = nullptr;
+  for (nsIFrame* f = aChild; f; f = f->GetNextInFlow()) {
+    // We'll update these in EndFinish after the next-in-flows are gone.
+    if (f == mPrevOverflowCont) {
+      mSentry = nullptr;
       mPrevOverflowCont = nullptr;
-      mSentry = nullptr;
-      mParent = static_cast<nsContainerFrame*>(f->GetParent());
       break;
     }
     if (f == mSentry) {
-      // Step past aChild
-      nsIFrame* prevOverflowCont = mPrevOverflowCont;
+      mSentry = nullptr;
+      break;
+    }
+  }
+}
+
+void
+nsOverflowContinuationTracker::EndFinish(nsIFrame* aChild)
+{
+  if (!mOverflowContList) {
+    return;
+  }
+  // Forget mOverflowContList if it was deleted.
+  nsPresContext* pc = aChild->PresContext();
+  FramePropertyTable* propTable = pc->PropertyTable();
+  nsFrameList* eoc = static_cast<nsFrameList*>(propTable->Get(mParent,
+                       nsContainerFrame::ExcessOverflowContainersProperty()));
+  if (eoc != mOverflowContList) {
+    nsFrameList* oc = static_cast<nsFrameList*>(propTable->Get(mParent,
+                        nsContainerFrame::OverflowContainersProperty()));
+    if (oc != mOverflowContList) {
+      // mOverflowContList was deleted
+      mPrevOverflowCont = nullptr;
+      mSentry = nullptr;
+      mParent = static_cast<nsContainerFrame*>(aChild->GetParent());
+      mOverflowContList = nullptr;
+      SetupOverflowContList();
+      return;
+    }
+  }
+  // The list survived, update mSentry if needed.
+  if (!mSentry) {
+    if (!mPrevOverflowCont) {
+      SetUpListWalker();
+    } else {
+      mozilla::AutoRestore<nsIFrame*> saved(mPrevOverflowCont);
+      // step backward to make StepForward() use our current mPrevOverflowCont
+      mPrevOverflowCont = mPrevOverflowCont->GetPrevSibling();
       StepForward();
-      if (mPrevOverflowCont == nif) {
-        // Pull mPrevOverflowChild back to aChild's prevSibling:
-        // aChild will be removed from our list by our caller
-        mPrevOverflowCont = prevOverflowCont;
-      }
     }
-    f = nif;
   }
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Debugging
 
 #ifdef DEBUG
 void
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -595,24 +595,43 @@ public:
    *
    * The caller MUST NOT disconnect the frame from its parent's
    * child list if it is already an NS_FRAME_IS_OVERFLOW_CONTAINER.
    * (In this case we will disconnect and reconnect it ourselves.)
    */
   nsresult Insert(nsIFrame*       aOverflowCont,
                   nsReflowStatus& aReflowStatus);
   /**
-   * This function must be called for each child that is reflowed
+   * Begin/EndFinish() must be called for each child that is reflowed
    * but no longer has an overflow continuation. (It may be called for
    * other children, but in that case has no effect.) It increments our
    * walker and makes sure we drop any dangling pointers to its
    * next-in-flow. This function MUST be called before stealing or
    * deleting aChild's next-in-flow.
+   * The AutoFinish helper object does that for you. Use it like so:
+   * if (kidNextInFlow) {
+   *   nsOverflowContinuationTracker::AutoFinish fini(tracker, kid);
+   *   ... DeleteNextInFlowChild/StealFrame(kidNextInFlow) here ...
+   * }
    */
-  void Finish(nsIFrame* aChild);
+  class MOZ_STACK_CLASS AutoFinish {
+  public:
+    AutoFinish(nsOverflowContinuationTracker* aTracker, nsIFrame* aChild)
+      : mTracker(aTracker), mChild(aChild)
+    {
+      if (mTracker) mTracker->BeginFinish(mChild);
+    }
+    ~AutoFinish() 
+    {
+      if (mTracker) mTracker->EndFinish(mChild);
+    }
+  private:
+    nsOverflowContinuationTracker* mTracker;
+    nsIFrame* mChild;
+  };
 
   /**
    * This function should be called for each child that isn't reflowed.
    * It increments our walker and sets the NS_FRAME_OVERFLOW_INCOMPLETE
    * reflow flag if it encounters an overflow continuation so that our
    * next-in-flow doesn't get prematurely deleted. It MUST be called on
    * each unreflowed child that has an overflow container continuation;
    * it MAY be called on other children, but it isn't necessary (doesn't
@@ -624,16 +643,23 @@ public:
     if (aChild == mSentry) {
       StepForward();
       NS_MergeReflowStatusInto(&aReflowStatus, NS_FRAME_OVERFLOW_INCOMPLETE);
     }
   }
 
 private:
 
+  /**
+   * @see class AutoFinish
+   */
+  void BeginFinish(nsIFrame* aChild);
+  void EndFinish(nsIFrame* aChild);
+
+  void SetupOverflowContList();
   void SetUpListWalker();
   void StepForward();
 
   /* We hold a pointer to either the next-in-flow's overflow containers list
      or, if that doesn't exist, our frame's excess overflow containers list.
      We need to make sure that we drop that pointer if the list becomes
      empty and is deleted elsewhere. */
   nsFrameList* mOverflowContList;