Bug 492627 - Remove Placeholder Continuations [Part VI: Handle <br clear>] r=roc
authorfantasai <fantasai.cvs@inkedblade.net>
Mon, 31 Aug 2009 11:25:36 -0700
changeset 32109 ccbef5922a0f8027fbc088c159a9e6af15045b76
parent 32108 28008648ca049b3cfc661700e2b4bf2d586e864a
child 32110 ac59a41e7815b553ce69f0548439b3b627f4d07c
push id8851
push userfantasai.cvs@inkedblade.net
push dateMon, 31 Aug 2009 19:40:38 +0000
treeherderautoland@1b724a06a345 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs492627
milestone1.9.3a1pre
Bug 492627 - Remove Placeholder Continuations [Part VI: Handle <br clear>] r=roc
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsFloatManager.cpp
layout/generic/nsFloatManager.h
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -986,16 +986,24 @@ nsBlockFrame::Reflow(nsPresContext*     
 
   NS_MergeReflowStatusInto(&state.mReflowStatus, ocStatus);
   NS_MergeReflowStatusInto(&state.mReflowStatus, fcStatus);
 
   // Put continued floats at the end of mFloats
   if (state.mFloatContinuations.NotEmpty())
     mFloats.AppendFrames(nsnull, state.mFloatContinuations);
 
+  // If we end in a BR with clear and affected floats continue,
+  // we need to continue, too.
+  if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight &&
+      NS_FRAME_IS_COMPLETE(state.mReflowStatus) &&
+      state.mFloatManager->ClearContinues(FindTrailingClear())) {
+    NS_FRAME_SET_INCOMPLETE(state.mReflowStatus);
+  }
+
   if (!NS_FRAME_IS_FULLY_COMPLETE(state.mReflowStatus)) {
     if (GetOverflowLines()) {
       state.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
     }
 
 #ifdef DEBUG_kipp
     ListTag(stdout); printf(": block is not fully complete\n");
 #endif
@@ -1685,17 +1693,17 @@ static void DumpLine(const nsBlockReflow
  * Reflow the dirty lines
  */
 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 foundAnyClears = aState.mFloatBreakType != NS_STYLE_CLEAR_NONE;
   PRBool willReflowAgain = PR_FALSE;
 
 #ifdef DEBUG
   if (gNoisyReflow) {
     IndentBy(stdout, gNoiseIndent);
     ListTag(stdout);
     printf(": reflowing dirty lines");
     printf(" computedWidth=%d\n", aState.mReflowState.ComputedWidth());
@@ -1720,20 +1728,21 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
     // the amount by which we will slide the current line if it is not
     // dirty
   nscoord deltaY = 0;
 
     // whether we did NOT reflow the previous line and thus we need to
     // recompute the carried out margin before the line if we want to
     // reflow it or if its previous margin is dirty
   PRBool needToRecoverState = PR_FALSE;
-  PRBool reflowedFloat = PR_FALSE;
+    // Float continuations were reflowed in ReflowFloatContinuations
+  PRBool reflowedFloat = mFloats.NotEmpty() && mFloats.FirstChild()->GetPrevInFlow();
   PRBool lastLineMovedUp = PR_FALSE;
   // We save up information about BR-clearance here
-  PRUint8 inlineFloatBreakType = NS_STYLE_CLEAR_NONE;
+  PRUint8 inlineFloatBreakType = aState.mFloatBreakType;
 
   line_iterator line = begin_lines(), line_end = end_lines();
 
   // Reflow the lines that are already ours
   for ( ; line != line_end; ++line, aState.AdvanceToNextLine()) {
     DumpLine(aState, line, deltaY, 0);
 #ifdef DEBUG
     AutoNoisyIndenter indent2(gNoisyReflow);
@@ -2849,19 +2858,16 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
     return NS_ERROR_NULL_POINTER; 
   }
 
   // Prepare the block reflow engine
   const nsStyleDisplay* display = frame->GetStyleDisplay();
   nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState);
 
   PRUint8 breakType = display->mBreakType;
-  // If a float split and its prev-in-flow was followed by a <BR>, then combine 
-  // the <BR>'s break type with the block's break type (the block will be the very 
-  // next frame after the split float).
   if (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType) {
     breakType = nsLayoutUtils::CombineBreakType(breakType,
                                                 aState.mFloatBreakType);
     aState.mFloatBreakType = NS_STYLE_CLEAR_NONE;
   }
 
   // Clear past floats before the block if the clear style is not none
   aLine->SetBreakTypeBefore(breakType);
@@ -5652,16 +5658,30 @@ nsBlockFrame::ReflowFloat(nsBlockReflowS
 #ifdef NOISY_FLOAT
   printf("end ReflowFloat %p, sized to %d,%d\n",
          aFloat, metrics.width, metrics.height);
 #endif
 
   return NS_OK;
 }
 
+PRUint8
+nsBlockFrame::FindTrailingClear()
+{
+  // find the break type of the last line
+  for (nsIFrame* b = this; b; b = b->GetPrevInFlow()) {
+    nsBlockFrame* block = static_cast<nsBlockFrame*>(b);
+    line_iterator endLine = block->end_lines();
+    if (endLine != block->begin_lines()) {
+      --endLine;
+      return endLine->GetBreakTypeAfter();
+    }
+  }
+}
+
 nsresult
 nsBlockFrame::ReflowFloatContinuations(nsBlockReflowState& aState,
                                        nsRect&             aBounds,
                                        nsReflowStatus&     aStatus)
 {
   nsresult rv = NS_OK;
   for (nsIFrame* f = mFloats.FirstChild(); f && f->GetPrevInFlow();
        f = f->GetNextSibling()) {
@@ -5698,16 +5718,22 @@ nsBlockFrame::ReflowFloatContinuations(n
       aState.mFloatManager->AddFloat(f, region);
       if (f->GetNextInFlow())
         NS_MergeReflowStatusInto(&aStatus, NS_FRAME_OVERFLOW_INCOMPLETE);
     }
 
     ConsiderChildOverflow(aBounds, f);
   }
 
+  // If there are continued floats, then we may need to continue BR clearance
+  if (0 != aState.ClearFloats(0, NS_STYLE_CLEAR_LEFT_AND_RIGHT)) {
+    aState.mFloatBreakType = static_cast<nsBlockFrame*>(GetPrevInFlow())
+                               ->FindTrailingClear();
+  }
+
   return rv;
 }
 
 void
 nsBlockFrame::RecoverFloats(nsFloatManager& aFloatManager)
 {
   // Recover our own floats
   nsIFrame* stop = nsnull; // Stop before we reach float continuations that
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -460,16 +460,20 @@ protected:
   void RecoverFloats(nsFloatManager& aFloatManager);
 
   /** Reflow float continuations
    */
   nsresult ReflowFloatContinuations(nsBlockReflowState& aState,
                                     nsRect&             aBounds,
                                     nsReflowStatus&     aStatus);
 
+  /** Find any trailing BR clear from the last line of the block (or its PIFs)
+   */
+  PRUint8 FindTrailingClear();
+
   /**
     * Remove a float from our float list and also the float cache
     * for the line its placeholder is on.
     */
   line_iterator RemoveFloat(nsIFrame* aFloat);
 
   void CollectFloats(nsIFrame* aFrame, nsFrameList& aList, nsIFrame** aTail,
                      PRBool aFromOverflow, PRBool aCollectFromSiblings);
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -500,16 +500,37 @@ nsFloatManager::ClearFloats(nscoord aY, 
       break;
   }
 
   bottom -= mY;
 
   return bottom;
 }
 
+PRBool
+nsFloatManager::ClearContinues(PRUint8 aBreakType) const
+{
+  if (!HasAnyFloats() || aBreakType == NS_STYLE_CLEAR_NONE)
+    return PR_FALSE;
+  for (PRUint32 i = mFloats.Length(); i > 0; i--) {
+    nsIFrame* f = mFloats[i-1].mFrame;
+    if (f->GetNextInFlow()) {
+      if (aBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT)
+        return PR_TRUE;
+      PRUint8 floatSide = f->GetStyleDisplay()->mFloats;
+      if ((aBreakType == NS_STYLE_CLEAR_LEFT &&
+           floatSide == NS_STYLE_FLOAT_LEFT) ||
+          (aBreakType == NS_STYLE_CLEAR_RIGHT &&
+           floatSide == NS_STYLE_FLOAT_RIGHT))
+        return PR_TRUE;
+    }
+  }
+  return PR_FALSE;
+}
+
 /////////////////////////////////////////////////////////////////////////////
 // FloatInfo
 
 nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame, const nsRect& aRect)
   : mFrame(aFrame), mRect(aRect)
 {
   MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
 }
--- a/layout/generic/nsFloatManager.h
+++ b/layout/generic/nsFloatManager.h
@@ -245,16 +245,22 @@ public:
   /**
    * Return the coordinate of the lowest float matching aBreakType in this
    * float manager. Returns aY if there are no matching floats.
    *
    * Both aY and the result are relative to the current translation.
    */
   nscoord ClearFloats(nscoord aY, PRUint8 aBreakType) const;
 
+  /**
+   * Checks if clear would pass into the floats' BFC's next-in-flow,
+   * i.e. whether floats affecting this clear have continuations.
+   */
+  PRBool ClearContinues(PRUint8 aBreakType) const;
+
   void AssertStateMatches(SavedState *aState) const
   {
     NS_ASSERTION(aState->mX == mX && aState->mY == mY &&
                  aState->mFloatInfoCount == mFloats.Length(),
                  "float manager state should match saved state");
   }
 
 #ifdef DEBUG