diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp
index 8968b8bbe9a..a48726b334b 100644
--- a/mozilla/layout/generic/nsBlockFrame.cpp
+++ b/mozilla/layout/generic/nsBlockFrame.cpp
@@ -953,29 +953,43 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
aStatus = state.mReflowStatus;
- // If there are incomplete floaters then they will go in the 1st line of the overflow lines.
+ // Put continued floaters at the beginning of the first overflow line. If the first line
+ // is a block then create a new line as the first line and put the floaters there. If there
+ // are no overflow lines, then create one and put the floaters in it.
if (state.mOverflowFloaters.NotEmpty()) {
- aStatus = NS_FRAME_NOT_COMPLETE;
nsLineList* overflowLines = GetOverflowLines(aPresContext, PR_FALSE);
if (overflowLines) {
- // put the floaters at the beginning of the line
line_iterator firstLine = overflowLines->begin();
- nsIFrame* firstFrame = firstLine->mFirstChild;
- firstLine->mFirstChild = state.mOverflowFloaters.FirstChild();
- PRInt32 numOverflowFloaters = state.mOverflowFloaters.GetLength();
- state.mOverflowFloaters.LastChild()->SetNextSibling(firstFrame);
- firstLine->SetChildCount(firstLine->GetChildCount() + numOverflowFloaters);
+ if (firstLine->IsBlock()) { // floaters go on a new line before 1st overflow line
+ nsLineBox* newLine = state.NewLineBox(state.mOverflowFloaters.FirstChild(),
+ state.mOverflowFloaters.GetLength(), PR_FALSE);
+ firstLine = mLines.before_insert(firstLine, newLine);
+ }
+ else { // floaters go on 1st overflow line
+ nsIFrame* firstFrame = firstLine->mFirstChild;
+ firstLine->mFirstChild = state.mOverflowFloaters.FirstChild();
+ PRInt32 numOverflowFloaters = state.mOverflowFloaters.GetLength();
+ // hook up the last placeholder with the original frames
+ nsPlaceholderFrame* lastPlaceholder =
+ (nsPlaceholderFrame*)state.mOverflowFloaters.LastChild();
+ lastPlaceholder->SetNextSibling(firstFrame);
+ NS_ASSERTION(firstFrame != lastPlaceholder, "trying to set next sibling to self");
+ firstLine->SetChildCount(firstLine->GetChildCount() + numOverflowFloaters);
+ }
}
- else {
- // there aren't any overflow lines, so create a line, put the floaters in it, and then push.
+ else {
+ // Create a line, put the floaters in it, and then push.
nsLineBox* newLine = state.NewLineBox(state.mOverflowFloaters.FirstChild(),
state.mOverflowFloaters.GetLength(), PR_FALSE);
if (!newLine)
return NS_ERROR_OUT_OF_MEMORY;
+ state.mOverflowFloaters.SetFrames(nsnull);
mLines.push_back(newLine);
nsLineList::iterator nextToLastLine = ----end_lines();
PushLines(state, nextToLastLine);
}
+ aStatus = NS_FRAME_NOT_COMPLETE;
+ state.mOverflowFloaters.SetFrames(nsnull);
}
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
@@ -3112,6 +3126,63 @@ nsBlockFrame::GetTopBlockChild()
return nsnull;
}
+// If placeholders/floaters split during reflowing a line, but that line will
+// be put on the next page, then put the placeholders/floaters back the way
+// they were before the line was reflowed.
+static void
+UndoPlaceholders(nsBlockReflowState& aState,
+ nsIFrame* aLastPlaceholder)
+{
+ nsIFrame* undoPlaceholder = nsnull;
+ if (aLastPlaceholder) {
+ aLastPlaceholder->GetNextSibling(&undoPlaceholder);
+ aLastPlaceholder->SetNextSibling(nsnull);
+ }
+ else {
+ undoPlaceholder = aState.mOverflowFloaters.FirstChild();
+ aState.mOverflowFloaters.SetFrames(nsnull);
+ }
+ // remove the next in flows of the placeholders that need to be removed
+ for (nsIFrame* placeholder = undoPlaceholder; placeholder; ) {
+ nsSplittableFrame::RemoveFromFlow(placeholder);
+ nsIFrame* savePlaceholder = placeholder;
+ placeholder->GetNextSibling(&placeholder);
+ savePlaceholder->Destroy(aState.mPresContext);
+ }
+}
+
+// Combine aNewBreakType with aOrigBreakType, but limit the break types
+// to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT. When there is a
right
+// after a floater and the floater splits, then the
's break type is combined
+// with the break type of the frame right after the floaters next-in-flow.
+static PRUint8
+CombineBreakType(PRUint8 aOrigBreakType,
+ PRUint8 aNewBreakType)
+{
+ PRUint8 breakType = aOrigBreakType;
+ switch(breakType) {
+ case NS_STYLE_CLEAR_LEFT:
+ if ((NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
+ (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
+ breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
+ }
+ break;
+ case NS_STYLE_CLEAR_RIGHT:
+ if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
+ (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
+ breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
+ }
+ break;
+ case NS_STYLE_CLEAR_NONE:
+ if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
+ (NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
+ (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
+ breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
+ }
+ }
+ return breakType;
+}
+
nsresult
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
line_iterator aLine,
@@ -3146,8 +3217,15 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
applyTopMargin = ShouldApplyTopMargin(aState, aLine);
}
- // Clear past floaters before the block if the clear style is not none
PRUint8 breakType = display->mBreakType;
+ // If a floater split and its prev-in-flow was followed by a
, then combine
+ // the
's break type with the block's break type (the block will be the very
+ // next frame after the split floater).
+ if (NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType) {
+ breakType = ::CombineBreakType(breakType, aState.mFloaterBreakType);
+ aState.mFloaterBreakType = NS_STYLE_CLEAR_NONE;
+ }
+ // Clear past floaters before the block if the clear style is not none
aLine->SetBreakType(breakType);
if (NS_STYLE_CLEAR_NONE != breakType) {
PRBool alsoApplyTopMargin = aState.ClearPastFloaters(breakType);
@@ -3219,6 +3297,9 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
}
}
+ // keep track of the last overflow floater in case we need to undo any new additions
+ nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild();
+
// Reflow the block into the available space
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
nsMargin computedOffsets;
@@ -3226,6 +3307,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
applyTopMargin, aState.mPrevBottomMargin,
aState.IsAdjacentWithTop(),
computedOffsets, frameReflowStatus);
+
if (brc.BlockShouldInvalidateItself() && !mRect.IsEmpty()) {
Invalidate(aState.mPresContext, mRect);
}
@@ -3245,6 +3327,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
// None of the child block fits.
+ ::UndoPlaceholders(aState, lastPlaceholder);
PushLines(aState, aLine.prev());
*aKeepReflowGoing = PR_FALSE;
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
@@ -3420,6 +3503,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
else {
// Push the line that didn't fit and any lines that follow it
// to our next-in-flow.
+ ::UndoPlaceholders(aState, lastPlaceholder);
PushLines(aState, aLine.prev());
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
}
@@ -3533,22 +3617,8 @@ nsBlockFrame::PushTruncatedPlaceholderLine(nsBlockReflowState& aState,
nsIFrame* aLastPlaceholder,
PRBool& aKeepReflowGoing)
{
- nsIFrame* undoPlaceholder = nsnull;
- if (aLastPlaceholder) {
- aLastPlaceholder->GetNextSibling(&undoPlaceholder);
- aLastPlaceholder->SetNextSibling(nsnull);
- }
- else {
- undoPlaceholder = aState.mOverflowFloaters.FirstChild();
- aState.mOverflowFloaters.SetFrames(nsnull);
- }
- // remove the next in flows of the placeholders that need to be removed
- for (nsIFrame* placeholder = undoPlaceholder; placeholder; ) {
- nsSplittableFrame::RemoveFromFlow(placeholder);
- nsIFrame* savePlaceholder = placeholder;
- placeholder->GetNextSibling(&placeholder);
- savePlaceholder->Destroy(aState.mPresContext);
- }
+ ::UndoPlaceholders(aState, aLastPlaceholder);
+
line_iterator prevLine = aLine;
--prevLine;
PushLines(aState, prevLine);
@@ -3616,7 +3686,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
}
- // keep track of the last overflow floater in case we need to undo and push the line
+ // keep track of the last overflow floater in case we need to undo any new additions
nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild();
// Reflow the frames that are already on the line first
@@ -3707,7 +3777,9 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// If we are propagating out a break-before status then there is
// no point in placing the line.
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
- rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth);
+ if (PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth)) {
+ ::UndoPlaceholders(aState, lastPlaceholder); // undo since we pushed the current line
+ }
}
}
*aLineReflowStatus = lineReflowStatus;
@@ -3792,14 +3864,16 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
// block or we are an inline. This makes a total of 10 cases
// (fortunately, there is some overlap).
aLine->SetBreakType(NS_STYLE_CLEAR_NONE);
- if (NS_INLINE_IS_BREAK(frameReflowStatus)) {
+ if (NS_INLINE_IS_BREAK(frameReflowStatus) ||
+ (NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType)) {
// Always abort the line reflow (because a line break is the
// minimal amount of break we do).
*aLineReflowStatus = LINE_REFLOW_STOP;
// XXX what should aLine's break-type be set to in all these cases?
PRUint8 breakType = NS_INLINE_GET_BREAK_TYPE(frameReflowStatus);
- NS_ASSERTION(breakType != NS_STYLE_CLEAR_NONE, "bad break type");
+ NS_ASSERTION((NS_STYLE_CLEAR_NONE != breakType) ||
+ (NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType), "bad break type");
NS_ASSERTION(NS_STYLE_CLEAR_PAGE != breakType, "no page breaks yet");
if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
@@ -3828,6 +3902,13 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
}
}
else {
+ // If a floater split and its prev-in-flow was followed by a
, then combine
+ // the
's break type with the inline's break type (the inline will be the very
+ // next frame after the split floater).
+ if (NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType) {
+ breakType = ::CombineBreakType(breakType, aState.mFloaterBreakType);
+ aState.mFloaterBreakType = NS_STYLE_CLEAR_NONE;
+ }
// Break-after cases
if (breakType == NS_STYLE_CLEAR_LINE) {
if (!aLineLayout.GetLineEndsInBR()) {
@@ -4061,15 +4142,13 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState,
return PR_FALSE;
}
-nsresult
+PRBool
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
- nsLineLayout& aLineLayout,
- line_iterator aLine,
- PRBool* aKeepReflowGoing,
- PRBool aUpdateMaximumWidth)
+ nsLineLayout& aLineLayout,
+ line_iterator aLine,
+ PRBool* aKeepReflowGoing,
+ PRBool aUpdateMaximumWidth)
{
- nsresult rv = NS_OK;
-
// Trim extra white-space from the line before placing the frames
aLineLayout.TrimTrailingWhiteSpace();
@@ -4242,7 +4321,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
*aKeepReflowGoing = PR_FALSE;
}
- return rv;
+ return PR_TRUE;
}
aState.mY = newY;
@@ -4376,7 +4455,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
break;
}
- return rv;
+ return PR_FALSE;
}
// Compute the line's max-element-size by adding into the raw value
@@ -4484,7 +4563,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
}
void
-nsBlockFrame::PushLines(nsBlockReflowState& aState,
+nsBlockFrame::PushLines(nsBlockReflowState& aState,
nsLineList::iterator aLineBefore)
{
nsLineList::iterator overBegin(aLineBefore.next());
@@ -5405,6 +5484,39 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
#ifdef NOISY_FLOATER
printf("end ReflowFloater %p, sized to %d,%d\n", floater, metrics.width, metrics.height);
#endif
+
+ // If the placeholder was continued and its first-in-flow was followed by a
+ //
, then cache the
's break type in aState.mFloaterBreakType so that
+ // the next frame after the placeholder can combine that break type with its own
+ nsIFrame* prevPlaceholder = nsnull;
+ aPlaceholder->GetPrevInFlow(&prevPlaceholder);
+ if (prevPlaceholder) {
+ // the break occurs only after the last continued placeholder
+ PRBool lastPlaceholder = PR_TRUE;
+ nsIFrame* next;
+ aPlaceholder->GetNextSibling(&next);
+ if (next) {
+ nsCOMPtr nextType;
+ next->GetFrameType(getter_AddRefs(nextType));
+ if (nsLayoutAtoms::placeholderFrame == nextType) {
+ lastPlaceholder = PR_FALSE;
+ }
+ }
+ if (lastPlaceholder) {
+ // get the containing block of prevPlaceholder which is our prev-in-flow
+ if (mPrevInFlow) {
+ // get the break type of the last line in mPrevInFlow
+ line_iterator endLine = --((nsBlockFrame*)mPrevInFlow)->end_lines();
+ PRUint8 breakType = endLine->GetBreakType();
+ if ((NS_STYLE_CLEAR_LEFT == breakType) ||
+ (NS_STYLE_CLEAR_RIGHT == breakType) ||
+ (NS_STYLE_CLEAR_LEFT_AND_RIGHT == breakType)) {
+ aState.mFloaterBreakType = breakType;
+ }
+ }
+ else NS_ASSERTION(PR_FALSE, "no prev in flow");
+ }
+ }
return NS_OK;
}
diff --git a/mozilla/layout/generic/nsBlockFrame.h b/mozilla/layout/generic/nsBlockFrame.h
index 318b095d81c..1ecf8b23b4e 100644
--- a/mozilla/layout/generic/nsBlockFrame.h
+++ b/mozilla/layout/generic/nsBlockFrame.h
@@ -333,11 +333,12 @@ protected:
PRBool* aKeepReflowGoing,
PRBool aDamageDirtyArea = PR_FALSE);
- nsresult PlaceLine(nsBlockReflowState& aState,
- nsLineLayout& aLineLayout,
- line_iterator aLine,
- PRBool* aKeepReflowGoing,
- PRBool aUpdateMaximumWidth);
+ // Return PR_TRUE if aLine gets pushed.
+ PRBool PlaceLine(nsBlockReflowState& aState,
+ nsLineLayout& aLineLayout,
+ line_iterator aLine,
+ PRBool* aKeepReflowGoing,
+ PRBool aUpdateMaximumWidth);
/**
* Mark |aLine| dirty, and, if necessary because of possible
diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp
index 0f10fcf420b..847a6eefe12 100644
--- a/mozilla/layout/generic/nsBlockReflowState.cpp
+++ b/mozilla/layout/generic/nsBlockReflowState.cpp
@@ -66,7 +66,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mLastFloaterY(0),
mPrevBottomMargin(),
mLineNumber(0),
- mFlags(0)
+ mFlags(0),
+ mFloaterBreakType(NS_STYLE_CLEAR_NONE)
{
const nsMargin& borderPadding = BorderPadding();
@@ -974,6 +975,13 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
}
}
+ // If the floater is continued, it will get the same x value as its prev-in-flow
+ nsRect prevInFlowRect(0,0,0,0);
+ nsIFrame* prevInFlow;
+ floater->GetPrevInFlow(&prevInFlow);
+ if (prevInFlow) {
+ prevInFlow->GetRect(prevInFlowRect);
+ }
// Assign an x and y coordinate to the floater. Note that the x,y
// coordinates are computed relative to the translation in the
// spacemanager which means that the impacted region will be
@@ -982,7 +990,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
PRBool isLeftFloater;
if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) {
isLeftFloater = PR_TRUE;
- region.x = mAvailSpaceRect.x;
+ region.x = (prevInFlow) ? prevInFlowRect.x : mAvailSpaceRect.x;
}
else {
isLeftFloater = PR_FALSE;
@@ -990,9 +998,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
nsIFrame* prevInFlow;
floater->GetPrevInFlow(&prevInFlow);
if (prevInFlow) {
- nsRect rect;
- prevInFlow->GetRect(rect);
- region.x = rect.x;
+ region.x = prevInFlowRect.x;
}
else if (!keepFloaterOnSameLine) {
region.x = mAvailSpaceRect.XMost() - region.width;
@@ -1022,6 +1028,11 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
// Place the floater in the space manager
if (okToAddRectRegion) {
+ // if the floater split, then take up all of the vertical height
+ if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) &&
+ (NS_UNCONSTRAINEDSIZE != mContentArea.height)) {
+ region.height += PR_MAX(region.height, mContentArea.height);
+ }
#ifdef DEBUG
nsresult rv =
#endif
diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h
index c82f058c2e5..694b4230f9d 100644
--- a/mozilla/layout/generic/nsBlockReflowState.h
+++ b/mozilla/layout/generic/nsBlockReflowState.h
@@ -256,6 +256,8 @@ public:
#define BRS_LASTFLAG BRS_DAMAGECONSTRAINED
PRInt16 mFlags;
+
+ PRUint8 mFloaterBreakType;
void SetFlag(PRUint32 aFlag, PRBool aValue)
{
diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp
index 8968b8bbe9a..a48726b334b 100644
--- a/mozilla/layout/html/base/src/nsBlockFrame.cpp
+++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp
@@ -953,29 +953,43 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
aStatus = state.mReflowStatus;
- // If there are incomplete floaters then they will go in the 1st line of the overflow lines.
+ // Put continued floaters at the beginning of the first overflow line. If the first line
+ // is a block then create a new line as the first line and put the floaters there. If there
+ // are no overflow lines, then create one and put the floaters in it.
if (state.mOverflowFloaters.NotEmpty()) {
- aStatus = NS_FRAME_NOT_COMPLETE;
nsLineList* overflowLines = GetOverflowLines(aPresContext, PR_FALSE);
if (overflowLines) {
- // put the floaters at the beginning of the line
line_iterator firstLine = overflowLines->begin();
- nsIFrame* firstFrame = firstLine->mFirstChild;
- firstLine->mFirstChild = state.mOverflowFloaters.FirstChild();
- PRInt32 numOverflowFloaters = state.mOverflowFloaters.GetLength();
- state.mOverflowFloaters.LastChild()->SetNextSibling(firstFrame);
- firstLine->SetChildCount(firstLine->GetChildCount() + numOverflowFloaters);
+ if (firstLine->IsBlock()) { // floaters go on a new line before 1st overflow line
+ nsLineBox* newLine = state.NewLineBox(state.mOverflowFloaters.FirstChild(),
+ state.mOverflowFloaters.GetLength(), PR_FALSE);
+ firstLine = mLines.before_insert(firstLine, newLine);
+ }
+ else { // floaters go on 1st overflow line
+ nsIFrame* firstFrame = firstLine->mFirstChild;
+ firstLine->mFirstChild = state.mOverflowFloaters.FirstChild();
+ PRInt32 numOverflowFloaters = state.mOverflowFloaters.GetLength();
+ // hook up the last placeholder with the original frames
+ nsPlaceholderFrame* lastPlaceholder =
+ (nsPlaceholderFrame*)state.mOverflowFloaters.LastChild();
+ lastPlaceholder->SetNextSibling(firstFrame);
+ NS_ASSERTION(firstFrame != lastPlaceholder, "trying to set next sibling to self");
+ firstLine->SetChildCount(firstLine->GetChildCount() + numOverflowFloaters);
+ }
}
- else {
- // there aren't any overflow lines, so create a line, put the floaters in it, and then push.
+ else {
+ // Create a line, put the floaters in it, and then push.
nsLineBox* newLine = state.NewLineBox(state.mOverflowFloaters.FirstChild(),
state.mOverflowFloaters.GetLength(), PR_FALSE);
if (!newLine)
return NS_ERROR_OUT_OF_MEMORY;
+ state.mOverflowFloaters.SetFrames(nsnull);
mLines.push_back(newLine);
nsLineList::iterator nextToLastLine = ----end_lines();
PushLines(state, nextToLastLine);
}
+ aStatus = NS_FRAME_NOT_COMPLETE;
+ state.mOverflowFloaters.SetFrames(nsnull);
}
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
@@ -3112,6 +3126,63 @@ nsBlockFrame::GetTopBlockChild()
return nsnull;
}
+// If placeholders/floaters split during reflowing a line, but that line will
+// be put on the next page, then put the placeholders/floaters back the way
+// they were before the line was reflowed.
+static void
+UndoPlaceholders(nsBlockReflowState& aState,
+ nsIFrame* aLastPlaceholder)
+{
+ nsIFrame* undoPlaceholder = nsnull;
+ if (aLastPlaceholder) {
+ aLastPlaceholder->GetNextSibling(&undoPlaceholder);
+ aLastPlaceholder->SetNextSibling(nsnull);
+ }
+ else {
+ undoPlaceholder = aState.mOverflowFloaters.FirstChild();
+ aState.mOverflowFloaters.SetFrames(nsnull);
+ }
+ // remove the next in flows of the placeholders that need to be removed
+ for (nsIFrame* placeholder = undoPlaceholder; placeholder; ) {
+ nsSplittableFrame::RemoveFromFlow(placeholder);
+ nsIFrame* savePlaceholder = placeholder;
+ placeholder->GetNextSibling(&placeholder);
+ savePlaceholder->Destroy(aState.mPresContext);
+ }
+}
+
+// Combine aNewBreakType with aOrigBreakType, but limit the break types
+// to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT. When there is a
right
+// after a floater and the floater splits, then the
's break type is combined
+// with the break type of the frame right after the floaters next-in-flow.
+static PRUint8
+CombineBreakType(PRUint8 aOrigBreakType,
+ PRUint8 aNewBreakType)
+{
+ PRUint8 breakType = aOrigBreakType;
+ switch(breakType) {
+ case NS_STYLE_CLEAR_LEFT:
+ if ((NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
+ (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
+ breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
+ }
+ break;
+ case NS_STYLE_CLEAR_RIGHT:
+ if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
+ (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
+ breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
+ }
+ break;
+ case NS_STYLE_CLEAR_NONE:
+ if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
+ (NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
+ (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
+ breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
+ }
+ }
+ return breakType;
+}
+
nsresult
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
line_iterator aLine,
@@ -3146,8 +3217,15 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
applyTopMargin = ShouldApplyTopMargin(aState, aLine);
}
- // Clear past floaters before the block if the clear style is not none
PRUint8 breakType = display->mBreakType;
+ // If a floater split and its prev-in-flow was followed by a
, then combine
+ // the
's break type with the block's break type (the block will be the very
+ // next frame after the split floater).
+ if (NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType) {
+ breakType = ::CombineBreakType(breakType, aState.mFloaterBreakType);
+ aState.mFloaterBreakType = NS_STYLE_CLEAR_NONE;
+ }
+ // Clear past floaters before the block if the clear style is not none
aLine->SetBreakType(breakType);
if (NS_STYLE_CLEAR_NONE != breakType) {
PRBool alsoApplyTopMargin = aState.ClearPastFloaters(breakType);
@@ -3219,6 +3297,9 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
}
}
+ // keep track of the last overflow floater in case we need to undo any new additions
+ nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild();
+
// Reflow the block into the available space
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
nsMargin computedOffsets;
@@ -3226,6 +3307,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
applyTopMargin, aState.mPrevBottomMargin,
aState.IsAdjacentWithTop(),
computedOffsets, frameReflowStatus);
+
if (brc.BlockShouldInvalidateItself() && !mRect.IsEmpty()) {
Invalidate(aState.mPresContext, mRect);
}
@@ -3245,6 +3327,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
// None of the child block fits.
+ ::UndoPlaceholders(aState, lastPlaceholder);
PushLines(aState, aLine.prev());
*aKeepReflowGoing = PR_FALSE;
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
@@ -3420,6 +3503,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
else {
// Push the line that didn't fit and any lines that follow it
// to our next-in-flow.
+ ::UndoPlaceholders(aState, lastPlaceholder);
PushLines(aState, aLine.prev());
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
}
@@ -3533,22 +3617,8 @@ nsBlockFrame::PushTruncatedPlaceholderLine(nsBlockReflowState& aState,
nsIFrame* aLastPlaceholder,
PRBool& aKeepReflowGoing)
{
- nsIFrame* undoPlaceholder = nsnull;
- if (aLastPlaceholder) {
- aLastPlaceholder->GetNextSibling(&undoPlaceholder);
- aLastPlaceholder->SetNextSibling(nsnull);
- }
- else {
- undoPlaceholder = aState.mOverflowFloaters.FirstChild();
- aState.mOverflowFloaters.SetFrames(nsnull);
- }
- // remove the next in flows of the placeholders that need to be removed
- for (nsIFrame* placeholder = undoPlaceholder; placeholder; ) {
- nsSplittableFrame::RemoveFromFlow(placeholder);
- nsIFrame* savePlaceholder = placeholder;
- placeholder->GetNextSibling(&placeholder);
- savePlaceholder->Destroy(aState.mPresContext);
- }
+ ::UndoPlaceholders(aState, aLastPlaceholder);
+
line_iterator prevLine = aLine;
--prevLine;
PushLines(aState, prevLine);
@@ -3616,7 +3686,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
}
- // keep track of the last overflow floater in case we need to undo and push the line
+ // keep track of the last overflow floater in case we need to undo any new additions
nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild();
// Reflow the frames that are already on the line first
@@ -3707,7 +3777,9 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// If we are propagating out a break-before status then there is
// no point in placing the line.
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
- rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth);
+ if (PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth)) {
+ ::UndoPlaceholders(aState, lastPlaceholder); // undo since we pushed the current line
+ }
}
}
*aLineReflowStatus = lineReflowStatus;
@@ -3792,14 +3864,16 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
// block or we are an inline. This makes a total of 10 cases
// (fortunately, there is some overlap).
aLine->SetBreakType(NS_STYLE_CLEAR_NONE);
- if (NS_INLINE_IS_BREAK(frameReflowStatus)) {
+ if (NS_INLINE_IS_BREAK(frameReflowStatus) ||
+ (NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType)) {
// Always abort the line reflow (because a line break is the
// minimal amount of break we do).
*aLineReflowStatus = LINE_REFLOW_STOP;
// XXX what should aLine's break-type be set to in all these cases?
PRUint8 breakType = NS_INLINE_GET_BREAK_TYPE(frameReflowStatus);
- NS_ASSERTION(breakType != NS_STYLE_CLEAR_NONE, "bad break type");
+ NS_ASSERTION((NS_STYLE_CLEAR_NONE != breakType) ||
+ (NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType), "bad break type");
NS_ASSERTION(NS_STYLE_CLEAR_PAGE != breakType, "no page breaks yet");
if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
@@ -3828,6 +3902,13 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
}
}
else {
+ // If a floater split and its prev-in-flow was followed by a
, then combine
+ // the
's break type with the inline's break type (the inline will be the very
+ // next frame after the split floater).
+ if (NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType) {
+ breakType = ::CombineBreakType(breakType, aState.mFloaterBreakType);
+ aState.mFloaterBreakType = NS_STYLE_CLEAR_NONE;
+ }
// Break-after cases
if (breakType == NS_STYLE_CLEAR_LINE) {
if (!aLineLayout.GetLineEndsInBR()) {
@@ -4061,15 +4142,13 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState,
return PR_FALSE;
}
-nsresult
+PRBool
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
- nsLineLayout& aLineLayout,
- line_iterator aLine,
- PRBool* aKeepReflowGoing,
- PRBool aUpdateMaximumWidth)
+ nsLineLayout& aLineLayout,
+ line_iterator aLine,
+ PRBool* aKeepReflowGoing,
+ PRBool aUpdateMaximumWidth)
{
- nsresult rv = NS_OK;
-
// Trim extra white-space from the line before placing the frames
aLineLayout.TrimTrailingWhiteSpace();
@@ -4242,7 +4321,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
*aKeepReflowGoing = PR_FALSE;
}
- return rv;
+ return PR_TRUE;
}
aState.mY = newY;
@@ -4376,7 +4455,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
break;
}
- return rv;
+ return PR_FALSE;
}
// Compute the line's max-element-size by adding into the raw value
@@ -4484,7 +4563,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
}
void
-nsBlockFrame::PushLines(nsBlockReflowState& aState,
+nsBlockFrame::PushLines(nsBlockReflowState& aState,
nsLineList::iterator aLineBefore)
{
nsLineList::iterator overBegin(aLineBefore.next());
@@ -5405,6 +5484,39 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
#ifdef NOISY_FLOATER
printf("end ReflowFloater %p, sized to %d,%d\n", floater, metrics.width, metrics.height);
#endif
+
+ // If the placeholder was continued and its first-in-flow was followed by a
+ //
, then cache the
's break type in aState.mFloaterBreakType so that
+ // the next frame after the placeholder can combine that break type with its own
+ nsIFrame* prevPlaceholder = nsnull;
+ aPlaceholder->GetPrevInFlow(&prevPlaceholder);
+ if (prevPlaceholder) {
+ // the break occurs only after the last continued placeholder
+ PRBool lastPlaceholder = PR_TRUE;
+ nsIFrame* next;
+ aPlaceholder->GetNextSibling(&next);
+ if (next) {
+ nsCOMPtr nextType;
+ next->GetFrameType(getter_AddRefs(nextType));
+ if (nsLayoutAtoms::placeholderFrame == nextType) {
+ lastPlaceholder = PR_FALSE;
+ }
+ }
+ if (lastPlaceholder) {
+ // get the containing block of prevPlaceholder which is our prev-in-flow
+ if (mPrevInFlow) {
+ // get the break type of the last line in mPrevInFlow
+ line_iterator endLine = --((nsBlockFrame*)mPrevInFlow)->end_lines();
+ PRUint8 breakType = endLine->GetBreakType();
+ if ((NS_STYLE_CLEAR_LEFT == breakType) ||
+ (NS_STYLE_CLEAR_RIGHT == breakType) ||
+ (NS_STYLE_CLEAR_LEFT_AND_RIGHT == breakType)) {
+ aState.mFloaterBreakType = breakType;
+ }
+ }
+ else NS_ASSERTION(PR_FALSE, "no prev in flow");
+ }
+ }
return NS_OK;
}
diff --git a/mozilla/layout/html/base/src/nsBlockFrame.h b/mozilla/layout/html/base/src/nsBlockFrame.h
index 318b095d81c..1ecf8b23b4e 100644
--- a/mozilla/layout/html/base/src/nsBlockFrame.h
+++ b/mozilla/layout/html/base/src/nsBlockFrame.h
@@ -333,11 +333,12 @@ protected:
PRBool* aKeepReflowGoing,
PRBool aDamageDirtyArea = PR_FALSE);
- nsresult PlaceLine(nsBlockReflowState& aState,
- nsLineLayout& aLineLayout,
- line_iterator aLine,
- PRBool* aKeepReflowGoing,
- PRBool aUpdateMaximumWidth);
+ // Return PR_TRUE if aLine gets pushed.
+ PRBool PlaceLine(nsBlockReflowState& aState,
+ nsLineLayout& aLineLayout,
+ line_iterator aLine,
+ PRBool* aKeepReflowGoing,
+ PRBool aUpdateMaximumWidth);
/**
* Mark |aLine| dirty, and, if necessary because of possible
diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp
index 0f10fcf420b..847a6eefe12 100644
--- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp
+++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp
@@ -66,7 +66,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mLastFloaterY(0),
mPrevBottomMargin(),
mLineNumber(0),
- mFlags(0)
+ mFlags(0),
+ mFloaterBreakType(NS_STYLE_CLEAR_NONE)
{
const nsMargin& borderPadding = BorderPadding();
@@ -974,6 +975,13 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
}
}
+ // If the floater is continued, it will get the same x value as its prev-in-flow
+ nsRect prevInFlowRect(0,0,0,0);
+ nsIFrame* prevInFlow;
+ floater->GetPrevInFlow(&prevInFlow);
+ if (prevInFlow) {
+ prevInFlow->GetRect(prevInFlowRect);
+ }
// Assign an x and y coordinate to the floater. Note that the x,y
// coordinates are computed relative to the translation in the
// spacemanager which means that the impacted region will be
@@ -982,7 +990,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
PRBool isLeftFloater;
if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) {
isLeftFloater = PR_TRUE;
- region.x = mAvailSpaceRect.x;
+ region.x = (prevInFlow) ? prevInFlowRect.x : mAvailSpaceRect.x;
}
else {
isLeftFloater = PR_FALSE;
@@ -990,9 +998,7 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
nsIFrame* prevInFlow;
floater->GetPrevInFlow(&prevInFlow);
if (prevInFlow) {
- nsRect rect;
- prevInFlow->GetRect(rect);
- region.x = rect.x;
+ region.x = prevInFlowRect.x;
}
else if (!keepFloaterOnSameLine) {
region.x = mAvailSpaceRect.XMost() - region.width;
@@ -1022,6 +1028,11 @@ nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
// Place the floater in the space manager
if (okToAddRectRegion) {
+ // if the floater split, then take up all of the vertical height
+ if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) &&
+ (NS_UNCONSTRAINEDSIZE != mContentArea.height)) {
+ region.height += PR_MAX(region.height, mContentArea.height);
+ }
#ifdef DEBUG
nsresult rv =
#endif
diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h
index c82f058c2e5..694b4230f9d 100644
--- a/mozilla/layout/html/base/src/nsBlockReflowState.h
+++ b/mozilla/layout/html/base/src/nsBlockReflowState.h
@@ -256,6 +256,8 @@ public:
#define BRS_LASTFLAG BRS_DAMAGECONSTRAINED
PRInt16 mFlags;
+
+ PRUint8 mFloaterBreakType;
void SetFlag(PRUint32 aFlag, PRBool aValue)
{