Bug 320378. Skip reflowing lines in ReflowDirtyLines if we know that we're going to come back here because clearance was detected. r+sr=dbaron
authorroc+@cs.cmu.edu
Thu, 29 Nov 2007 17:49:01 -0800
changeset 8457 d351d96a8a37b3e20cc0c5cc98ac5b2a48c92835
parent 8456 e724bbe58c3e6b49201bcc3626720b192d9fd5ed
child 8458 db9a33675d79d50cf09ffcf1fe07c36680c37cb2
push idunknown
push userunknown
push dateunknown
bugs320378
milestone1.9b2pre
Bug 320378. Skip reflowing lines in ReflowDirtyLines if we know that we're going to come back here because clearance was detected. r+sr=dbaron
layout/generic/nsBlockFrame.cpp
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1714,16 +1714,17 @@ static void DumpLine(const nsBlockReflow
  */
 nsresult
 nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
 {
   nsresult rv = NS_OK;
   PRBool keepGoing = PR_TRUE;
   PRBool repositionViews = PR_FALSE; // should we really need this?
   PRBool foundAnyClears = PR_FALSE;
+  PRBool willReflowAgain = PR_FALSE;
 
 #ifdef DEBUG
   if (gNoisyReflow) {
     IndentBy(stdout, gNoiseIndent);
     ListTag(stdout);
     printf(": reflowing dirty lines");
     printf(" computedWidth=%d\n", aState.mReflowState.ComputedWidth());
   }
@@ -1839,34 +1840,40 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
       // this line.  This is expensive in some cases, since it requires
       // walking |GetNextSibling|.
       if (line->IsDirty())
         aState.mPrevChild = line.prev()->LastChild();
     }
 
     // Now repair the line and update |aState.mY| by calling
     // |ReflowLine| or |SlideLine|.
-    if (line->IsDirty()) {
+    if (line->IsDirty() && !willReflowAgain) {
       lastLineMovedUp = PR_TRUE;
 
       PRBool maybeReflowingForFirstTime =
         line->mBounds.x == 0 && line->mBounds.y == 0 &&
         line->mBounds.width == 0 && line->mBounds.height == 0;
 
       // Compute the dirty lines "before" YMost, after factoring in
       // the running deltaY value - the running value is implicit in
       // aState.mY.
       nscoord oldY = line->mBounds.y;
       nscoord oldYMost = line->mBounds.YMost();
 
       // Reflow the dirty line. If it's an incremental reflow, then force
       // it to invalidate the dirty area if necessary
       rv = ReflowLine(aState, line, &keepGoing);
       NS_ENSURE_SUCCESS(rv, rv);
-      
+
+      if (aState.mReflowState.mDiscoveredClearance &&
+          *aState.mReflowState.mDiscoveredClearance) {
+        line->MarkDirty();
+        willReflowAgain = PR_TRUE;
+      }
+
       if (line->HasFloats()) {
         reflowedFloat = PR_TRUE;
       }
 
       if (!keepGoing) {
         DumpLine(aState, line, deltaY, -1);
         if (0 == line->GetChildCount()) {
           DeleteLine(aState, line, line_end);
@@ -1984,17 +1991,17 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
   // -- the next in flow is not changing
   // -- and we cannot have added more space for its first line to be
   // pulled up into,
   // -- it's an incremental reflow of a descendant
   // -- and we didn't reflow any floats (so the available space
   // didn't change)
   // -- my chain of next-in-flows either has no first line, or its first
   // line isn't dirty.
-  PRBool skipPull = PR_FALSE;
+  PRBool skipPull = willReflowAgain;
   if (aState.mNextInFlow &&
       (aState.mReflowState.mFlags.mNextInFlowUntouched &&
        !lastLineMovedUp && 
        !(GetStateBits() & NS_FRAME_IS_DIRTY) &&
        !reflowedFloat)) {
     // We'll place lineIter at the last line of this block, so that 
     // nsBlockInFlowLineIterator::Next() will take us to the first
     // line of my next-in-flow-chain.  (But first, check that I 
@@ -2823,16 +2830,17 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
       // the next reflow.
       treatWithClearance = PR_TRUE;
       // Only record the first frame that requires clearance
       if (!*aState.mReflowState.mDiscoveredClearance) {
         *aState.mReflowState.mDiscoveredClearance = frame;
       }
       // Exactly what we do now is flexible since we'll definitely be
       // reflowed.
+      return NS_OK;
     }
   }
   if (treatWithClearance) {
     applyTopMargin = PR_TRUE;
   }
 
   nsIFrame* clearanceFrame = nsnull;
   nscoord startingY = aState.mY;
@@ -6617,42 +6625,50 @@ void nsBlockFrame::CollectFloats(nsIFram
     aFrame = aFrame->GetNextSibling();
   }
 }
 
 void
 nsBlockFrame::CheckFloats(nsBlockReflowState& aState)
 {
 #ifdef DEBUG
+  // If any line is still dirty, that must mean we're going to reflow this
+  // block again soon (e.g. because we bailed out after noticing that
+  // clearance was imposed), so don't worry if the floats are out of sync.
+  PRBool anyLineDirty = PR_FALSE;
+
   // Check that the float list is what we would have built
   nsAutoVoidArray lineFloats;
   for (line_iterator line = begin_lines(), line_end = end_lines();
        line != line_end; ++line) {
     if (line->HasFloats()) {
       nsFloatCache* fc = line->GetFirstFloat();
       while (fc) {
         nsIFrame* floatFrame = fc->mPlaceholder->GetOutOfFlowFrame();
         lineFloats.AppendElement(floatFrame);
         fc = fc->Next();
       }
     }
+    if (line->IsDirty()) {
+      anyLineDirty = PR_TRUE;
+    }
   }
   
   nsAutoVoidArray storedFloats;
   PRBool equal = PR_TRUE;
   PRInt32 i = 0;
   for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
     storedFloats.AppendElement(f);
     if (i < lineFloats.Count() && lineFloats.ElementAt(i) != f) {
       equal = PR_FALSE;
     }
     ++i;
   }
 
-  if (!equal || lineFloats.Count() != storedFloats.Count()) {
+  if ((!equal || lineFloats.Count() != storedFloats.Count()) && !anyLineDirty) {
     NS_WARNING("nsBlockFrame::CheckFloats: Explicit float list is out of sync with float cache");
 #if defined(DEBUG_roc)
     nsIFrameDebug::RootFrameList(PresContext(), stdout, 0);
     for (i = 0; i < lineFloats.Count(); ++i) {
       printf("Line float: %p\n", lineFloats.ElementAt(i));
     }
     for (i = 0; i < storedFloats.Count(); ++i) {
       printf("Stored float: %p\n", storedFloats.ElementAt(i));