Implement fix for bug #5821 as per dbaron's suggestion

This commit is contained in:
kipp%netscape.com 1999-09-03 03:47:49 +00:00
parent b2b92bb835
commit 86e12ae621
6 changed files with 280 additions and 90 deletions

View File

@ -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);
}

View File

@ -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<nsIContent> content;
mBlockReflowState->frame->GetContent(getter_AddRefs(content));
if (content) {
nsCOMPtr<nsIDocument> doc;
content->GetDocument(*getter_AddRefs(doc));
if (doc) {
nsCOMPtr<nsIHTMLDocument> 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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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<nsIContent> content;
mBlockReflowState->frame->GetContent(getter_AddRefs(content));
if (content) {
nsCOMPtr<nsIDocument> doc;
content->GetDocument(*getter_AddRefs(doc));
if (doc) {
nsCOMPtr<nsIHTMLDocument> 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);
}

View File

@ -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;