diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index c50305ea44f..91c1ec4c672 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -3822,7 +3822,12 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, if (gNoisyReflow) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("split line: from line=%p pushCount=%d aFrame=", aLine, pushCount); - nsFrame::ListTag(stdout, aFrame); + if (aFrame) { + nsFrame::ListTag(stdout, aFrame); + } + else { + printf("(null)"); + } printf("\n"); if (gReallyNoisyReflow) { aLine->List(aState.mPresContext, stdout, gNoiseIndent+1); diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index c50305ea44f..91c1ec4c672 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -3822,7 +3822,12 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, if (gNoisyReflow) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("split line: from line=%p pushCount=%d aFrame=", aLine, pushCount); - nsFrame::ListTag(stdout, aFrame); + if (aFrame) { + nsFrame::ListTag(stdout, aFrame); + } + else { + printf("(null)"); + } printf("\n"); if (gReallyNoisyReflow) { aLine->List(aState.mPresContext, stdout, gNoiseIndent+1); diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index c50305ea44f..91c1ec4c672 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -3822,7 +3822,12 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, if (gNoisyReflow) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("split line: from line=%p pushCount=%d aFrame=", aLine, pushCount); - nsFrame::ListTag(stdout, aFrame); + if (aFrame) { + nsFrame::ListTag(stdout, aFrame); + } + else { + printf("(null)"); + } printf("\n"); if (gReallyNoisyReflow) { aLine->List(aState.mPresContext, stdout, gNoiseIndent+1); diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp index d42550ec4e8..e5a75118813 100644 --- a/mozilla/layout/generic/nsLineLayout.cpp +++ b/mozilla/layout/generic/nsLineLayout.cpp @@ -113,6 +113,7 @@ nsLineLayout::nsLineLayout(nsIPresContext& aPresContext, mColumn = 0; mEndsInWhiteSpace = PR_TRUE; mUnderstandsWhiteSpace = PR_FALSE; + mTextStartsWithNBSP = PR_FALSE; mFirstLetterStyleOK = PR_FALSE; mIsTopOfPage = PR_FALSE; mUpdatedBand = PR_FALSE; @@ -270,6 +271,7 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY, mColumn = 0; mEndsInWhiteSpace = PR_TRUE; mUnderstandsWhiteSpace = PR_FALSE; + mTextStartsWithNBSP = PR_FALSE; mFirstLetterStyleOK = PR_FALSE; mIsTopOfPage = aIsTopOfPage; mUpdatedBand = PR_FALSE; @@ -411,6 +413,7 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY, mLastFloaterWasLetterFrame = nsLayoutAtoms::letterFrame == frameType.get(); // Now update all of the open spans... + mRootSpan->mContainsFloater = PR_TRUE; // make sure mRootSpan gets updated too psd = mCurrentSpan; while (psd != mRootSpan) { NS_ASSERTION(nsnull != psd, "null ptr"); @@ -424,6 +427,7 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY, else { psd->mRightEdge += deltaWidth; } + psd->mContainsFloater = PR_TRUE; #ifdef NOISY_REFLOW printf(" span %p: oldRightEdge=%d newRightEdge=%d\n", psd, psd->mRightEdge - deltaWidth, psd->mRightEdge); @@ -479,6 +483,8 @@ nsLineLayout::NewPerSpanData(PerSpanData** aResult) psd->mFrame = nsnull; psd->mFirstFrame = nsnull; psd->mLastFrame = nsnull; + psd->mContainsFloater = PR_FALSE; + psd->mZeroEffectiveSpanBox = PR_FALSE; #ifdef DEBUG mSpansAllocated++; @@ -514,7 +520,6 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame, psd->mLeftEdge = aLeftEdge; psd->mX = aLeftEdge; psd->mRightEdge = aRightEdge; - psd->mZeroEffectiveSpanBox = PR_FALSE; const nsStyleText* styleText; aSpanReflowState->frame->GetStyleData(eStyleStruct_Text, @@ -879,6 +884,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, reflowState.mLineLayout = this; reflowState.isTopOfPage = mIsTopOfPage; mUnderstandsWhiteSpace = PR_FALSE; + mTextStartsWithNBSP = PR_FALSE; // Stash copies of some of the computed state away for later // (vertical alignment, for example) @@ -1095,8 +1101,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, // See if we can place the frame. If we can't fit it, then we // return now. - if (CanPlaceFrame(pfd, reflowState, notSafeToBreak, metrics, - aReflowStatus)) { + if (CanPlaceFrame(pfd, reflowState, notSafeToBreak, metrics, aReflowStatus)) { // Place the frame, updating aBounds with the final size and // location. Then apply the bottom+right margins (as // appropriate) to the frame. @@ -1116,6 +1121,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, else { PushFrame(aFrame); } + mTextStartsWithNBSP = PR_FALSE; // reset for next time #ifdef REALLY_NOISY_REFLOW nsFrame::IndentBy(stdout, mSpanDepth); @@ -1234,7 +1240,7 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd, PerSpanData* psd = mCurrentSpan; if (psd->mNoWrap) { - // When wrapping is off, everything fits + // When wrapping is off, everything fits. return PR_TRUE; } @@ -1345,6 +1351,43 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd, } } + // Special check for span frames + if (pfd->mSpan && pfd->mSpan->mContainsFloater) { + // If the span either directly or indirectly contains a floater then + // it fits. Why? It's kind of complicated, but here goes: + // + // 1. CanPlaceFrame is used for all frame placements on a line, + // and in a span. This includes recursively placement of frames + // inside of spans, and the span itself. Because the logic always + // checks for room before proceeding (the code above here), the + // only things on a line will be those things that "fit". + // + // 2. Before a floater is placed on a line, the line has to be empty + // (otherwise its a "below current line" flaoter and will be placed + // after the line). + // + // Therefore, if the span directly or indirectly has a floater + // then it means that at the time of the placement of the floater + // the line was empty. Because of #1, only the frames that fit can + // be added after that point, therefore we can assume that the + // current span being placed has fit. + // + // So how do we get here and have a span that should already fit + // and yet doesn't: Simple: span's that have the no-wrap attribute + // set on them and contain a floater and are placed where they + // don't naturally fit. + return PR_TRUE; + } + + // Yet another special check. If the text happens to have started + // with a non-breaking space, then we make it sticky on its left + // edge...Which means that whatever piece of text we just formatted + // will be the piece that fits (the text frame logic knows to stop + // when it runs out of room). + if (pfd->mIsNonEmptyTextFrame && mTextStartsWithNBSP) { + return PR_TRUE; + } + #ifdef NOISY_CAN_PLACE_FRAME printf(" ==> didn't fit\n"); #endif diff --git a/mozilla/layout/generic/nsLineLayout.h b/mozilla/layout/generic/nsLineLayout.h index 7426f332de6..e12a094363b 100644 --- a/mozilla/layout/generic/nsLineLayout.h +++ b/mozilla/layout/generic/nsLineLayout.h @@ -128,6 +128,10 @@ public: mUnderstandsWhiteSpace = aSetting; } + void SetTextStartsWithNBSP(PRBool aYes) { + mTextStartsWithNBSP = aYes; + } + void RecordWordFrame(nsIFrame* aWordFrame) { mWordFrames.AppendElement(aWordFrame); } @@ -222,6 +226,7 @@ protected: PRInt32 mColumn; PRBool mEndsInWhiteSpace; PRBool mUnderstandsWhiteSpace; + PRBool mTextStartsWithNBSP; PRBool mFirstLetterStyleOK; PRBool mIsTopOfPage; PRBool mUpdatedBand; @@ -317,6 +322,7 @@ public: PRUint8 mDirection; PRBool mChangedFrameDirection; PRBool mZeroEffectiveSpanBox; + PRBool mContainsFloater; nscoord mLeftEdge; nscoord mX; diff --git a/mozilla/layout/generic/nsTextFrame.cpp b/mozilla/layout/generic/nsTextFrame.cpp index f354552c77e..771daf6404d 100644 --- a/mozilla/layout/generic/nsTextFrame.cpp +++ b/mozilla/layout/generic/nsTextFrame.cpp @@ -2818,6 +2818,8 @@ nsTextFrame::Reflow(nsIPresContext& aPresContext, } } + PRBool firstThing = PR_TRUE; + PRBool textStartsWithNBSP = PR_FALSE; for (;;) { // Get next word/whitespace from the text PRBool isWhitespace; @@ -2886,8 +2888,16 @@ nsTextFrame::Reflow(nsIPresContext& aPresContext, } lastWordWidth = width; } + + // See if the first thing in the section of text is a + // non-breaking space (html nbsp entity). If it is then make + // note of that fact for the line layout logic. + if (wrapping && firstThing && (bp[0] == ' ')) { + textStartsWithNBSP = PR_TRUE; + } skipWhitespace = PR_FALSE; } + firstThing = PR_FALSE; // See if there is room for the text if (measureText) { @@ -3050,6 +3060,7 @@ nsTextFrame::Reflow(nsIPresContext& aPresContext, // text object collapsed into nothingness which means it shouldn't // effect the current setting of the ends-in-whitespace flag. lineLayout.SetUnderstandsWhiteSpace(PR_TRUE); + lineLayout.SetTextStartsWithNBSP(textStartsWithNBSP); if (0 != x) { lineLayout.SetEndsInWhiteSpace(endsInWhitespace); } diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index c50305ea44f..91c1ec4c672 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -3822,7 +3822,12 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, if (gNoisyReflow) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("split line: from line=%p pushCount=%d aFrame=", aLine, pushCount); - nsFrame::ListTag(stdout, aFrame); + if (aFrame) { + nsFrame::ListTag(stdout, aFrame); + } + else { + printf("(null)"); + } printf("\n"); if (gReallyNoisyReflow) { aLine->List(aState.mPresContext, stdout, gNoiseIndent+1); diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index c50305ea44f..91c1ec4c672 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -3822,7 +3822,12 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, if (gNoisyReflow) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("split line: from line=%p pushCount=%d aFrame=", aLine, pushCount); - nsFrame::ListTag(stdout, aFrame); + if (aFrame) { + nsFrame::ListTag(stdout, aFrame); + } + else { + printf("(null)"); + } printf("\n"); if (gReallyNoisyReflow) { aLine->List(aState.mPresContext, stdout, gNoiseIndent+1); diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h index c50305ea44f..91c1ec4c672 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -3822,7 +3822,12 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, if (gNoisyReflow) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("split line: from line=%p pushCount=%d aFrame=", aLine, pushCount); - nsFrame::ListTag(stdout, aFrame); + if (aFrame) { + nsFrame::ListTag(stdout, aFrame); + } + else { + printf("(null)"); + } printf("\n"); if (gReallyNoisyReflow) { aLine->List(aState.mPresContext, stdout, gNoiseIndent+1); diff --git a/mozilla/layout/html/base/src/nsLineLayout.cpp b/mozilla/layout/html/base/src/nsLineLayout.cpp index d42550ec4e8..e5a75118813 100644 --- a/mozilla/layout/html/base/src/nsLineLayout.cpp +++ b/mozilla/layout/html/base/src/nsLineLayout.cpp @@ -113,6 +113,7 @@ nsLineLayout::nsLineLayout(nsIPresContext& aPresContext, mColumn = 0; mEndsInWhiteSpace = PR_TRUE; mUnderstandsWhiteSpace = PR_FALSE; + mTextStartsWithNBSP = PR_FALSE; mFirstLetterStyleOK = PR_FALSE; mIsTopOfPage = PR_FALSE; mUpdatedBand = PR_FALSE; @@ -270,6 +271,7 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY, mColumn = 0; mEndsInWhiteSpace = PR_TRUE; mUnderstandsWhiteSpace = PR_FALSE; + mTextStartsWithNBSP = PR_FALSE; mFirstLetterStyleOK = PR_FALSE; mIsTopOfPage = aIsTopOfPage; mUpdatedBand = PR_FALSE; @@ -411,6 +413,7 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY, mLastFloaterWasLetterFrame = nsLayoutAtoms::letterFrame == frameType.get(); // Now update all of the open spans... + mRootSpan->mContainsFloater = PR_TRUE; // make sure mRootSpan gets updated too psd = mCurrentSpan; while (psd != mRootSpan) { NS_ASSERTION(nsnull != psd, "null ptr"); @@ -424,6 +427,7 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY, else { psd->mRightEdge += deltaWidth; } + psd->mContainsFloater = PR_TRUE; #ifdef NOISY_REFLOW printf(" span %p: oldRightEdge=%d newRightEdge=%d\n", psd, psd->mRightEdge - deltaWidth, psd->mRightEdge); @@ -479,6 +483,8 @@ nsLineLayout::NewPerSpanData(PerSpanData** aResult) psd->mFrame = nsnull; psd->mFirstFrame = nsnull; psd->mLastFrame = nsnull; + psd->mContainsFloater = PR_FALSE; + psd->mZeroEffectiveSpanBox = PR_FALSE; #ifdef DEBUG mSpansAllocated++; @@ -514,7 +520,6 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame, psd->mLeftEdge = aLeftEdge; psd->mX = aLeftEdge; psd->mRightEdge = aRightEdge; - psd->mZeroEffectiveSpanBox = PR_FALSE; const nsStyleText* styleText; aSpanReflowState->frame->GetStyleData(eStyleStruct_Text, @@ -879,6 +884,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, reflowState.mLineLayout = this; reflowState.isTopOfPage = mIsTopOfPage; mUnderstandsWhiteSpace = PR_FALSE; + mTextStartsWithNBSP = PR_FALSE; // Stash copies of some of the computed state away for later // (vertical alignment, for example) @@ -1095,8 +1101,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, // See if we can place the frame. If we can't fit it, then we // return now. - if (CanPlaceFrame(pfd, reflowState, notSafeToBreak, metrics, - aReflowStatus)) { + if (CanPlaceFrame(pfd, reflowState, notSafeToBreak, metrics, aReflowStatus)) { // Place the frame, updating aBounds with the final size and // location. Then apply the bottom+right margins (as // appropriate) to the frame. @@ -1116,6 +1121,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, else { PushFrame(aFrame); } + mTextStartsWithNBSP = PR_FALSE; // reset for next time #ifdef REALLY_NOISY_REFLOW nsFrame::IndentBy(stdout, mSpanDepth); @@ -1234,7 +1240,7 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd, PerSpanData* psd = mCurrentSpan; if (psd->mNoWrap) { - // When wrapping is off, everything fits + // When wrapping is off, everything fits. return PR_TRUE; } @@ -1345,6 +1351,43 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd, } } + // Special check for span frames + if (pfd->mSpan && pfd->mSpan->mContainsFloater) { + // If the span either directly or indirectly contains a floater then + // it fits. Why? It's kind of complicated, but here goes: + // + // 1. CanPlaceFrame is used for all frame placements on a line, + // and in a span. This includes recursively placement of frames + // inside of spans, and the span itself. Because the logic always + // checks for room before proceeding (the code above here), the + // only things on a line will be those things that "fit". + // + // 2. Before a floater is placed on a line, the line has to be empty + // (otherwise its a "below current line" flaoter and will be placed + // after the line). + // + // Therefore, if the span directly or indirectly has a floater + // then it means that at the time of the placement of the floater + // the line was empty. Because of #1, only the frames that fit can + // be added after that point, therefore we can assume that the + // current span being placed has fit. + // + // So how do we get here and have a span that should already fit + // and yet doesn't: Simple: span's that have the no-wrap attribute + // set on them and contain a floater and are placed where they + // don't naturally fit. + return PR_TRUE; + } + + // Yet another special check. If the text happens to have started + // with a non-breaking space, then we make it sticky on its left + // edge...Which means that whatever piece of text we just formatted + // will be the piece that fits (the text frame logic knows to stop + // when it runs out of room). + if (pfd->mIsNonEmptyTextFrame && mTextStartsWithNBSP) { + return PR_TRUE; + } + #ifdef NOISY_CAN_PLACE_FRAME printf(" ==> didn't fit\n"); #endif diff --git a/mozilla/layout/html/base/src/nsLineLayout.h b/mozilla/layout/html/base/src/nsLineLayout.h index 7426f332de6..e12a094363b 100644 --- a/mozilla/layout/html/base/src/nsLineLayout.h +++ b/mozilla/layout/html/base/src/nsLineLayout.h @@ -128,6 +128,10 @@ public: mUnderstandsWhiteSpace = aSetting; } + void SetTextStartsWithNBSP(PRBool aYes) { + mTextStartsWithNBSP = aYes; + } + void RecordWordFrame(nsIFrame* aWordFrame) { mWordFrames.AppendElement(aWordFrame); } @@ -222,6 +226,7 @@ protected: PRInt32 mColumn; PRBool mEndsInWhiteSpace; PRBool mUnderstandsWhiteSpace; + PRBool mTextStartsWithNBSP; PRBool mFirstLetterStyleOK; PRBool mIsTopOfPage; PRBool mUpdatedBand; @@ -317,6 +322,7 @@ public: PRUint8 mDirection; PRBool mChangedFrameDirection; PRBool mZeroEffectiveSpanBox; + PRBool mContainsFloater; nscoord mLeftEdge; nscoord mX; diff --git a/mozilla/layout/html/base/src/nsTextFrame.cpp b/mozilla/layout/html/base/src/nsTextFrame.cpp index f354552c77e..771daf6404d 100644 --- a/mozilla/layout/html/base/src/nsTextFrame.cpp +++ b/mozilla/layout/html/base/src/nsTextFrame.cpp @@ -2818,6 +2818,8 @@ nsTextFrame::Reflow(nsIPresContext& aPresContext, } } + PRBool firstThing = PR_TRUE; + PRBool textStartsWithNBSP = PR_FALSE; for (;;) { // Get next word/whitespace from the text PRBool isWhitespace; @@ -2886,8 +2888,16 @@ nsTextFrame::Reflow(nsIPresContext& aPresContext, } lastWordWidth = width; } + + // See if the first thing in the section of text is a + // non-breaking space (html nbsp entity). If it is then make + // note of that fact for the line layout logic. + if (wrapping && firstThing && (bp[0] == ' ')) { + textStartsWithNBSP = PR_TRUE; + } skipWhitespace = PR_FALSE; } + firstThing = PR_FALSE; // See if there is room for the text if (measureText) { @@ -3050,6 +3060,7 @@ nsTextFrame::Reflow(nsIPresContext& aPresContext, // text object collapsed into nothingness which means it shouldn't // effect the current setting of the ends-in-whitespace flag. lineLayout.SetUnderstandsWhiteSpace(PR_TRUE); + lineLayout.SetTextStartsWithNBSP(textStartsWithNBSP); if (0 != x) { lineLayout.SetEndsInWhiteSpace(endsInWhitespace); }