Bug 492627 - Remove Placeholder Continuations [Part VI: Handle <br clear>] r=roc
--- 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