Bug 1108104 part 4 - Don't use the current next-sibling as a reference point where to continue the loop, since that frame may be pushed if it's also the next-in-flow. Instead, use the frame from the last iteration (the prev-sibling) and query its (potentially new) next-sibling. r=roc
authorMats Palmgren <mats@mozilla.com>
Sun, 14 Dec 2014 17:22:06 +0000
changeset 219676 fe60976ce023c4dfeed64b0decf14959a1157075
parent 219675 9a373a63d7de93b0720c4740a84b5c6bead0dc0d
child 219677 8c9c81ceec62dacb6c7b466c2ed7bf8f15c6fba1
push id10400
push userryanvm@gmail.com
push dateMon, 15 Dec 2014 18:54:54 +0000
treeherderfx-team@5d6e0d038f95 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1108104
milestone37.0a1
Bug 1108104 part 4 - Don't use the current next-sibling as a reference point where to continue the loop, since that frame may be pushed if it's also the next-in-flow. Instead, use the frame from the last iteration (the prev-sibling) and query its (potentially new) next-sibling. r=roc
layout/generic/nsBlockFrame.cpp
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -6013,23 +6013,20 @@ nsBlockFrame::FindTrailingClear()
 
 void
 nsBlockFrame::ReflowPushedFloats(nsBlockReflowState& aState,
                                  nsOverflowAreas&    aOverflowAreas,
                                  nsReflowStatus&     aStatus)
 {
   // Pushed floats live at the start of our float list; see comment
   // above nsBlockFrame::DrainPushedFloats.
-  for (nsIFrame* f = mFloats.FirstChild(), *next;
-       f && (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT);
-       f = next) {
-    // save next sibling now, since reflowing could push the entire
-    // float, changing its siblings
-    next = f->GetNextSibling();
-
+  nsIFrame* f = mFloats.FirstChild();
+  nsIFrame* prev = nullptr;
+  while (f && (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT)) {
+    MOZ_ASSERT(prev == f->GetPrevSibling());
     // When we push a first-continuation float in a non-initial reflow,
     // it's possible that we end up with two continuations with the same
     // parent.  This happens if, on the previous reflow of the block or
     // a previous reflow of the line containing the block, the float was
     // split between continuations A and B of the parent, but on the
     // current reflow, none of the float can fit in A.
     //
     // When this happens, we might even have the two continuations
@@ -6056,24 +6053,32 @@ nsBlockFrame::ReflowPushedFloats(nsBlock
     // continuation of a float gets moved across more than one
     // continuation of the containing block.  In this case we'd manage
     // to push the second continuation without this check, but not the
     // third and later.
     nsIFrame *prevContinuation = f->GetPrevContinuation();
     if (prevContinuation && prevContinuation->GetParent() == f->GetParent()) {
       mFloats.RemoveFrame(f);
       aState.AppendPushedFloat(f);
+      f = !prev ? mFloats.FirstChild() : prev->GetNextSibling();
       continue;
     }
 
     // Always call FlowAndPlaceFloat; we might need to place this float
     // if didn't belong to this block the last time it was reflowed.
     aState.FlowAndPlaceFloat(f);
-
     ConsiderChildOverflow(aOverflowAreas, f);
+
+    nsIFrame* next = !prev ? mFloats.FirstChild() : prev->GetNextSibling();
+    if (next == f) {
+      // We didn't push |f| so its next-sibling is next.
+      next = f->GetNextSibling();
+      prev = f;
+    } // else: we did push |f| so |prev|'s new next-sibling is next.
+    f = next;
   }
 
   // If there are continued floats, then we may need to continue BR clearance
   if (0 != aState.ClearFloats(0, NS_STYLE_CLEAR_BOTH)) {
     aState.mFloatBreakType = static_cast<nsBlockFrame*>(GetPrevInFlow())
                                ->FindTrailingClear();
   }
 }