diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp index d6727505d81..157f5888c83 100644 --- a/mozilla/layout/generic/nsInlineFrame.cpp +++ b/mozilla/layout/generic/nsInlineFrame.cpp @@ -1445,7 +1445,9 @@ nsInlineFrame::ReflowInlineFrames(nsIPresContext* aPresContext, // that are empty we force to empty so that things like collapsed // whitespace in an inline element don't affect the line-height. nsSize size; - lineLayout->EndSpan(this, size, aMetrics.maxElementSize); + PRBool haveAtLeastOneNonEmptyTextFrame; + lineLayout->EndSpan(this, size, aMetrics.maxElementSize, + &haveAtLeastOneNonEmptyTextFrame); if ((0 == size.height) && (0 == size.width) && ((nsnull != mPrevInFlow) || (nsnull != mNextInFlow))) { // This is a continuation of a previous inline. Therefore make @@ -1475,53 +1477,91 @@ nsInlineFrame::ReflowInlineFrames(nsIPresContext* aPresContext, nsIFontMetrics* fm; aReflowState.rendContext->GetFontMetrics(fm); - // Compute final height. The height of our box is the sum of our - // font size plus the top and bottom border and padding. The height - // of children do not affect our height. - fm->GetMaxAscent(aMetrics.ascent); - fm->GetMaxDescent(aMetrics.descent); - fm->GetHeight(aMetrics.height); - aMetrics.ascent += aReflowState.mComputedBorderPadding.top; - aMetrics.descent += aReflowState.mComputedBorderPadding.bottom; - aMetrics.height += aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.bottom; +#ifdef DEBUG_kipp + static PRBool forceStrictMode = PR_FALSE; +#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS) + { + static PRBool firstTime = PR_TRUE; + if (firstTime) { + if (getenv("GECKO_FORCE_STRICT_MODE")) { + forceStrictMode = PR_TRUE; + } + } + } +#endif +#endif + + // Compute final height. + if (lineLayout->InStrictMode() || haveAtLeastOneNonEmptyTextFrame || +#ifdef DEBUG_kipp + forceStrictMode || +#endif + aReflowState.mComputedBorderPadding.top || + aReflowState.mComputedBorderPadding.right || + aReflowState.mComputedBorderPadding.bottom || + aReflowState.mComputedBorderPadding.left || + aReflowState.mComputedMargin.top || + aReflowState.mComputedMargin.right || + aReflowState.mComputedMargin.bottom || + aReflowState.mComputedMargin.left) { + // Do things the standard css2 way. The height of our box is the + // sum of our font size plus the top and bottom border and + // padding. The height of children do not affect our height. + fm->GetMaxAscent(aMetrics.ascent); + fm->GetMaxDescent(aMetrics.descent); + fm->GetHeight(aMetrics.height); + aMetrics.ascent += aReflowState.mComputedBorderPadding.top; + aMetrics.descent += aReflowState.mComputedBorderPadding.bottom; + aMetrics.height += aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom; #ifdef DEBUG_kipp - // Note: we use the actual font height for sizing our selves - // instead of the computed font height. On systems where they - // disagree the actual font height is more appropriate. This - // little hack lets us override that behavior to allow for more - // precise layout in the face of imprecise fonts. - static PRBool useComputedHeight = PR_FALSE; + // Note: we use the actual font height for sizing our selves + // instead of the computed font height. On systems where they + // disagree the actual font height is more appropriate. This + // little hack lets us override that behavior to allow for more + // precise layout in the face of imprecise fonts. + static PRBool useComputedHeight = PR_FALSE; #if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS) - static PRBool firstTime = 1; - if (firstTime) { - if (getenv("GECKO_USE_COMPUTED_HEIGHT")) { - useComputedHeight = PR_TRUE; - } - firstTime = 0; - } -#endif - if (useComputedHeight) { - // Special debug code that violates the above CSS2 spec - // clarification. Why? So that we can predictably compute the - // values for testing layout. - nscoord computedHeight = aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.bottom + - font->mFont.size; - if (computedHeight != aMetrics.height) { -#ifdef DEBUG - if (0 == (mState & 0x80000000)) { - nsFrame::ListTag(stdout, this); - printf(": using computedHeight %d instead of actual height %d\n", - computedHeight, aMetrics.height); - mState |= 0x80000000; + static PRBool firstTime = 1; + if (firstTime) { + if (getenv("GECKO_USE_COMPUTED_HEIGHT")) { + useComputedHeight = PR_TRUE; + } + firstTime = 0; + } +#endif + if (useComputedHeight) { + // Special debug code that violates the above CSS2 spec + // clarification. Why? So that we can predictably compute the + // values for testing layout. + nscoord computedHeight = aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom + + font->mFont.size; + if (computedHeight != aMetrics.height) { +#ifdef DEBUG + if (0 == (mState & 0x80000000)) { + nsFrame::ListTag(stdout, this); + printf(": using computedHeight %d instead of actual height %d\n", + computedHeight, aMetrics.height); + mState |= 0x80000000; + } +#endif + aMetrics.height = computedHeight; } -#endif - aMetrics.height = computedHeight; } - } #endif /* DEBUG_kipp */ + } + else { + // When in compatability mode, and we have no css2 style applied + // to us, make this frame disappear if it has no text in + // it. That way it will not affect the line box's height and + // thus be more compatible. + aMetrics.ascent = 0; + aMetrics.descent = 0; + aMetrics.height = 0; + } + NS_RELEASE(fm); } diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp index 93e67024cfd..6cc43c1d79b 100644 --- a/mozilla/layout/generic/nsLineLayout.cpp +++ b/mozilla/layout/generic/nsLineLayout.cpp @@ -29,6 +29,10 @@ #include "nsLayoutAtoms.h" #include "nsPlaceholderFrame.h" +#include "nsIDocument.h" +#include "nsIHTMLDocument.h" +#include "nsIContent.h" + #ifdef DEBUG #undef NOISY_HORIZONTAL_ALIGN #undef REALLY_NOISY_HORIZONTAL_ALIGN @@ -38,7 +42,7 @@ #undef REALLY_NOISY_REFLOW #undef NOISY_PUSHING #undef REALLY_NOISY_PUSHING -#define DEBUG_ADD_TEXT +#undef DEBUG_ADD_TEXT #undef NOISY_MAX_ELEMENT_SIZE #undef REALLY_NOISY_MAX_ELEMENT_SIZE #undef NOISY_CAN_PLACE_FRAME @@ -131,6 +135,7 @@ nsLineLayout::nsLineLayout(nsIPresContext& aPresContext, mTextRuns = nsnull; mTextRunP = &mTextRuns; mNewTextRun = nsnull; + mKnowStrictMode = PR_FALSE; } nsLineLayout::nsLineLayout(nsIPresContext& aPresContext) @@ -172,6 +177,37 @@ nsLineLayout::~nsLineLayout() } } +PRBool +nsLineLayout::InStrictMode() +{ + if (!mKnowStrictMode) { + mKnowStrictMode = PR_TRUE; + mInStrictMode = PR_TRUE; + + // Dig up the compatabilty mode out of the underlying document, if + // we can find it. + if (mBlockReflowState->frame) { + nsCOMPtr content; + mBlockReflowState->frame->GetContent(getter_AddRefs(content)); + if (content) { + nsCOMPtr doc; + content->GetDocument(*getter_AddRefs(doc)); + if (doc) { + nsCOMPtr hdoc(do_QueryInterface(doc)); + if (hdoc) { + nsDTDMode mode; + hdoc->GetDTDMode(mode); + if (eDTDMode_NoQuirks != mode) { + mInStrictMode = PR_FALSE; + } + } + } + } + } + } + return mInStrictMode; +} + void nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, @@ -472,7 +508,8 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame, void nsLineLayout::EndSpan(nsIFrame* aFrame, nsSize& aSizeResult, - nsSize* aMaxElementSize) + nsSize* aMaxElementSize, + PRBool* aHaveAtLeastOneNonEmptyTextFrame) { NS_ASSERTION(mSpanDepth > 0, "end-span without begin-span"); #ifdef NOISY_REFLOW @@ -485,11 +522,13 @@ nsLineLayout::EndSpan(nsIFrame* aFrame, nscoord maxHeight = 0; nscoord maxElementWidth = 0; nscoord maxElementHeight = 0; + PRBool haveAtLeastOneNonEmptyTextFrame = PR_FALSE; if (nsnull != psd->mLastFrame) { width = psd->mX - psd->mLeftEdge; PerFrameData* pfd = psd->mFirstFrame; while (nsnull != pfd) { if (pfd->mBounds.height > maxHeight) maxHeight = pfd->mBounds.height; + if (pfd->mIsNonEmptyTextFrame) haveAtLeastOneNonEmptyTextFrame = PR_TRUE; // Compute max-element-size if necessary if (aMaxElementSize) { @@ -521,6 +560,9 @@ nsLineLayout::EndSpan(nsIFrame* aFrame, aMaxElementSize->height = maxElementHeight; } } + if (aHaveAtLeastOneNonEmptyTextFrame) { + *aHaveAtLeastOneNonEmptyTextFrame = haveAtLeastOneNonEmptyTextFrame; + } mSpanDepth--; mCurrentSpan->mReflowState = nsnull; // no longer valid so null it out! @@ -849,6 +891,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, // the floater. nsIAtom* frameType; aFrame->GetFrameType(&frameType); + pfd->mIsNonEmptyTextFrame = 0; if (frameType) { if (frameType == nsLayoutAtoms::placeholderFrame) { nsIFrame* outOfFlowFrame = ((nsPlaceholderFrame*)aFrame)->GetOutOfFlowFrame(); @@ -875,6 +918,12 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, } } } + else if (frameType == nsLayoutAtoms::textFrame) { + // Note non-empty text-frames for inline frame compatability hackery + if (metrics.width) { + pfd->mIsNonEmptyTextFrame = PR_TRUE; + } + } NS_RELEASE(frameType); } diff --git a/mozilla/layout/generic/nsLineLayout.h b/mozilla/layout/generic/nsLineLayout.h index b5f1291df31..19eded3304c 100644 --- a/mozilla/layout/generic/nsLineLayout.h +++ b/mozilla/layout/generic/nsLineLayout.h @@ -75,7 +75,10 @@ public: nscoord aRightEdge); void EndSpan(nsIFrame* aFrame, nsSize& aSizeResult, - nsSize* aMaxElementSize); + nsSize* aMaxElementSize, + PRBool* aHaveAtLeastOneNonEmptyTextFrame); + + PRBool InStrictMode(); PRInt32 GetCurrentSpanCount() const; @@ -219,6 +222,8 @@ protected: PRBool mUpdatedBand; PRBool mImpactedByFloaters; PRBool mCanPlaceFloater; + PRBool mKnowStrictMode; + PRBool mInStrictMode; PRUint8 mPlacedFloaters; PRInt32 mTotalPlacedFrames; nsVoidArray mWordFrames; @@ -267,6 +272,7 @@ protected: // Other state we use PRUint8 mVerticalAlign; + PRBool mIsNonEmptyTextFrame; }; PerFrameData mFrameDataBuf[NS_LINELAYOUT_NUM_FRAMES]; PerFrameData* mFrameFreeList; diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp index d6727505d81..157f5888c83 100644 --- a/mozilla/layout/html/base/src/nsInlineFrame.cpp +++ b/mozilla/layout/html/base/src/nsInlineFrame.cpp @@ -1445,7 +1445,9 @@ nsInlineFrame::ReflowInlineFrames(nsIPresContext* aPresContext, // that are empty we force to empty so that things like collapsed // whitespace in an inline element don't affect the line-height. nsSize size; - lineLayout->EndSpan(this, size, aMetrics.maxElementSize); + PRBool haveAtLeastOneNonEmptyTextFrame; + lineLayout->EndSpan(this, size, aMetrics.maxElementSize, + &haveAtLeastOneNonEmptyTextFrame); if ((0 == size.height) && (0 == size.width) && ((nsnull != mPrevInFlow) || (nsnull != mNextInFlow))) { // This is a continuation of a previous inline. Therefore make @@ -1475,53 +1477,91 @@ nsInlineFrame::ReflowInlineFrames(nsIPresContext* aPresContext, nsIFontMetrics* fm; aReflowState.rendContext->GetFontMetrics(fm); - // Compute final height. The height of our box is the sum of our - // font size plus the top and bottom border and padding. The height - // of children do not affect our height. - fm->GetMaxAscent(aMetrics.ascent); - fm->GetMaxDescent(aMetrics.descent); - fm->GetHeight(aMetrics.height); - aMetrics.ascent += aReflowState.mComputedBorderPadding.top; - aMetrics.descent += aReflowState.mComputedBorderPadding.bottom; - aMetrics.height += aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.bottom; +#ifdef DEBUG_kipp + static PRBool forceStrictMode = PR_FALSE; +#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS) + { + static PRBool firstTime = PR_TRUE; + if (firstTime) { + if (getenv("GECKO_FORCE_STRICT_MODE")) { + forceStrictMode = PR_TRUE; + } + } + } +#endif +#endif + + // Compute final height. + if (lineLayout->InStrictMode() || haveAtLeastOneNonEmptyTextFrame || +#ifdef DEBUG_kipp + forceStrictMode || +#endif + aReflowState.mComputedBorderPadding.top || + aReflowState.mComputedBorderPadding.right || + aReflowState.mComputedBorderPadding.bottom || + aReflowState.mComputedBorderPadding.left || + aReflowState.mComputedMargin.top || + aReflowState.mComputedMargin.right || + aReflowState.mComputedMargin.bottom || + aReflowState.mComputedMargin.left) { + // Do things the standard css2 way. The height of our box is the + // sum of our font size plus the top and bottom border and + // padding. The height of children do not affect our height. + fm->GetMaxAscent(aMetrics.ascent); + fm->GetMaxDescent(aMetrics.descent); + fm->GetHeight(aMetrics.height); + aMetrics.ascent += aReflowState.mComputedBorderPadding.top; + aMetrics.descent += aReflowState.mComputedBorderPadding.bottom; + aMetrics.height += aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom; #ifdef DEBUG_kipp - // Note: we use the actual font height for sizing our selves - // instead of the computed font height. On systems where they - // disagree the actual font height is more appropriate. This - // little hack lets us override that behavior to allow for more - // precise layout in the face of imprecise fonts. - static PRBool useComputedHeight = PR_FALSE; + // Note: we use the actual font height for sizing our selves + // instead of the computed font height. On systems where they + // disagree the actual font height is more appropriate. This + // little hack lets us override that behavior to allow for more + // precise layout in the face of imprecise fonts. + static PRBool useComputedHeight = PR_FALSE; #if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS) - static PRBool firstTime = 1; - if (firstTime) { - if (getenv("GECKO_USE_COMPUTED_HEIGHT")) { - useComputedHeight = PR_TRUE; - } - firstTime = 0; - } -#endif - if (useComputedHeight) { - // Special debug code that violates the above CSS2 spec - // clarification. Why? So that we can predictably compute the - // values for testing layout. - nscoord computedHeight = aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.bottom + - font->mFont.size; - if (computedHeight != aMetrics.height) { -#ifdef DEBUG - if (0 == (mState & 0x80000000)) { - nsFrame::ListTag(stdout, this); - printf(": using computedHeight %d instead of actual height %d\n", - computedHeight, aMetrics.height); - mState |= 0x80000000; + static PRBool firstTime = 1; + if (firstTime) { + if (getenv("GECKO_USE_COMPUTED_HEIGHT")) { + useComputedHeight = PR_TRUE; + } + firstTime = 0; + } +#endif + if (useComputedHeight) { + // Special debug code that violates the above CSS2 spec + // clarification. Why? So that we can predictably compute the + // values for testing layout. + nscoord computedHeight = aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom + + font->mFont.size; + if (computedHeight != aMetrics.height) { +#ifdef DEBUG + if (0 == (mState & 0x80000000)) { + nsFrame::ListTag(stdout, this); + printf(": using computedHeight %d instead of actual height %d\n", + computedHeight, aMetrics.height); + mState |= 0x80000000; + } +#endif + aMetrics.height = computedHeight; } -#endif - aMetrics.height = computedHeight; } - } #endif /* DEBUG_kipp */ + } + else { + // When in compatability mode, and we have no css2 style applied + // to us, make this frame disappear if it has no text in + // it. That way it will not affect the line box's height and + // thus be more compatible. + aMetrics.ascent = 0; + aMetrics.descent = 0; + aMetrics.height = 0; + } + NS_RELEASE(fm); } diff --git a/mozilla/layout/html/base/src/nsLineLayout.cpp b/mozilla/layout/html/base/src/nsLineLayout.cpp index 93e67024cfd..6cc43c1d79b 100644 --- a/mozilla/layout/html/base/src/nsLineLayout.cpp +++ b/mozilla/layout/html/base/src/nsLineLayout.cpp @@ -29,6 +29,10 @@ #include "nsLayoutAtoms.h" #include "nsPlaceholderFrame.h" +#include "nsIDocument.h" +#include "nsIHTMLDocument.h" +#include "nsIContent.h" + #ifdef DEBUG #undef NOISY_HORIZONTAL_ALIGN #undef REALLY_NOISY_HORIZONTAL_ALIGN @@ -38,7 +42,7 @@ #undef REALLY_NOISY_REFLOW #undef NOISY_PUSHING #undef REALLY_NOISY_PUSHING -#define DEBUG_ADD_TEXT +#undef DEBUG_ADD_TEXT #undef NOISY_MAX_ELEMENT_SIZE #undef REALLY_NOISY_MAX_ELEMENT_SIZE #undef NOISY_CAN_PLACE_FRAME @@ -131,6 +135,7 @@ nsLineLayout::nsLineLayout(nsIPresContext& aPresContext, mTextRuns = nsnull; mTextRunP = &mTextRuns; mNewTextRun = nsnull; + mKnowStrictMode = PR_FALSE; } nsLineLayout::nsLineLayout(nsIPresContext& aPresContext) @@ -172,6 +177,37 @@ nsLineLayout::~nsLineLayout() } } +PRBool +nsLineLayout::InStrictMode() +{ + if (!mKnowStrictMode) { + mKnowStrictMode = PR_TRUE; + mInStrictMode = PR_TRUE; + + // Dig up the compatabilty mode out of the underlying document, if + // we can find it. + if (mBlockReflowState->frame) { + nsCOMPtr content; + mBlockReflowState->frame->GetContent(getter_AddRefs(content)); + if (content) { + nsCOMPtr doc; + content->GetDocument(*getter_AddRefs(doc)); + if (doc) { + nsCOMPtr hdoc(do_QueryInterface(doc)); + if (hdoc) { + nsDTDMode mode; + hdoc->GetDTDMode(mode); + if (eDTDMode_NoQuirks != mode) { + mInStrictMode = PR_FALSE; + } + } + } + } + } + } + return mInStrictMode; +} + void nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, @@ -472,7 +508,8 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame, void nsLineLayout::EndSpan(nsIFrame* aFrame, nsSize& aSizeResult, - nsSize* aMaxElementSize) + nsSize* aMaxElementSize, + PRBool* aHaveAtLeastOneNonEmptyTextFrame) { NS_ASSERTION(mSpanDepth > 0, "end-span without begin-span"); #ifdef NOISY_REFLOW @@ -485,11 +522,13 @@ nsLineLayout::EndSpan(nsIFrame* aFrame, nscoord maxHeight = 0; nscoord maxElementWidth = 0; nscoord maxElementHeight = 0; + PRBool haveAtLeastOneNonEmptyTextFrame = PR_FALSE; if (nsnull != psd->mLastFrame) { width = psd->mX - psd->mLeftEdge; PerFrameData* pfd = psd->mFirstFrame; while (nsnull != pfd) { if (pfd->mBounds.height > maxHeight) maxHeight = pfd->mBounds.height; + if (pfd->mIsNonEmptyTextFrame) haveAtLeastOneNonEmptyTextFrame = PR_TRUE; // Compute max-element-size if necessary if (aMaxElementSize) { @@ -521,6 +560,9 @@ nsLineLayout::EndSpan(nsIFrame* aFrame, aMaxElementSize->height = maxElementHeight; } } + if (aHaveAtLeastOneNonEmptyTextFrame) { + *aHaveAtLeastOneNonEmptyTextFrame = haveAtLeastOneNonEmptyTextFrame; + } mSpanDepth--; mCurrentSpan->mReflowState = nsnull; // no longer valid so null it out! @@ -849,6 +891,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, // the floater. nsIAtom* frameType; aFrame->GetFrameType(&frameType); + pfd->mIsNonEmptyTextFrame = 0; if (frameType) { if (frameType == nsLayoutAtoms::placeholderFrame) { nsIFrame* outOfFlowFrame = ((nsPlaceholderFrame*)aFrame)->GetOutOfFlowFrame(); @@ -875,6 +918,12 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, } } } + else if (frameType == nsLayoutAtoms::textFrame) { + // Note non-empty text-frames for inline frame compatability hackery + if (metrics.width) { + pfd->mIsNonEmptyTextFrame = PR_TRUE; + } + } NS_RELEASE(frameType); } diff --git a/mozilla/layout/html/base/src/nsLineLayout.h b/mozilla/layout/html/base/src/nsLineLayout.h index b5f1291df31..19eded3304c 100644 --- a/mozilla/layout/html/base/src/nsLineLayout.h +++ b/mozilla/layout/html/base/src/nsLineLayout.h @@ -75,7 +75,10 @@ public: nscoord aRightEdge); void EndSpan(nsIFrame* aFrame, nsSize& aSizeResult, - nsSize* aMaxElementSize); + nsSize* aMaxElementSize, + PRBool* aHaveAtLeastOneNonEmptyTextFrame); + + PRBool InStrictMode(); PRInt32 GetCurrentSpanCount() const; @@ -219,6 +222,8 @@ protected: PRBool mUpdatedBand; PRBool mImpactedByFloaters; PRBool mCanPlaceFloater; + PRBool mKnowStrictMode; + PRBool mInStrictMode; PRUint8 mPlacedFloaters; PRInt32 mTotalPlacedFrames; nsVoidArray mWordFrames; @@ -267,6 +272,7 @@ protected: // Other state we use PRUint8 mVerticalAlign; + PRBool mIsNonEmptyTextFrame; }; PerFrameData mFrameDataBuf[NS_LINELAYOUT_NUM_FRAMES]; PerFrameData* mFrameFreeList;