bug 175455 - Added mTableDerivedComputedWidth to the reflow state to detect computed widths which exist only because of table cells. Limit percent width of descendants whose percentage base has such a computed width. sr=roc, r=bernd

This commit is contained in:
karnaze%netscape.com 2003-01-19 20:07:39 +00:00
parent 6345aa5b6c
commit a4389a11ce
9 changed files with 218 additions and 18 deletions

View File

@ -246,10 +246,12 @@ struct nsHTMLReflowState {
struct ReflowStateFlags {
PRUint16 mSpecialHeightReflow:1; // used by tables to communicate special reflow (in process) to handle
// percent height frames inside cells which may not have computed heights
PRUint16 mTableDerivedComputedWidth:1; // Computed width is due to a table cell's final width, not style
// on the frame itself. Restrictions apply.
PRUint16 mIsTopOfPage:1; // is the current context at the top of a page?
PRUint16 mBlinks:1; // Keep track of text-decoration: blink
PRUint16 mVisualBidiFormControl:1; // Keep track of descendants of form controls on Visual Bidi pages
PRUint16 mUnused:12; // for future use
PRUint16 mUnused:11; // for future use
} mFlags;
#ifdef IBMBIDI

View File

@ -121,7 +121,6 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
: mReflowDepth(0)
{
NS_PRECONDITION(nsnull != aRenderingContext, "no rendering context");
mFlags.mSpecialHeightReflow = mFlags.mUnused = 0;
parentReflowState = nsnull;
frame = aFrame;
reason = aReason;
@ -131,7 +130,10 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
rendContext = aRenderingContext;
mSpaceManager = nsnull;
mLineLayout = nsnull;
mFlags.mSpecialHeightReflow = PR_FALSE;
mFlags.mTableDerivedComputedWidth = PR_FALSE;
mFlags.mIsTopOfPage = PR_FALSE;
mFlags.mUnused = 0;
mPercentHeightObserver = nsnull;
mPercentHeightReflowInitiator = nsnull;
Init(aPresContext);
@ -152,7 +154,6 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
{
NS_PRECONDITION(nsnull != aRenderingContext, "no rendering context");
mFlags.mSpecialHeightReflow = mFlags.mUnused = 0;
reason = eReflowReason_Incremental;
path = aReflowPath;
parentReflowState = nsnull;
@ -162,7 +163,10 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
rendContext = aRenderingContext;
mSpaceManager = nsnull;
mLineLayout = nsnull;
mFlags.mSpecialHeightReflow = PR_FALSE;
mFlags.mTableDerivedComputedWidth = PR_FALSE;
mFlags.mIsTopOfPage = PR_FALSE;
mFlags.mUnused = 0;
mPercentHeightObserver = nsnull;
mPercentHeightReflowInitiator = nsnull;
Init(aPresContext);
@ -344,6 +348,9 @@ void nsHTMLReflowState::InitCBReflowState()
parentReflowState->frame->GetFrameType(getter_AddRefs(fType));
if (IS_TABLE_CELL(fType.get())) {
mCBReflowState = parentReflowState;
// Set mFlags.mTableDerivedComputedWidth to true for a cell block. Its default
// value was set to what the parent reflow state has.
mFlags.mTableDerivedComputedWidth = PR_TRUE;
return;
}
}
@ -1661,6 +1668,35 @@ static eNormalLineHeightControl GetNormalLineHeightCalcControl(void)
return sNormalLineHeightControl;
}
// Reset mFlags.mTableDerivedComputedWidth if there is a non percent style width
// or if there is a percent style width and the parent has a style width.
// This function assumes that aWidthUnit is never Auto or Inherit and that aState's
// mFlags.mTableDerivedComputedWidth is set.
static void
CheckResetTableDerivedComputedWidth(nsHTMLReflowState& aState,
nsStyleUnit aWidthUnit)
{
if (eStyleUnit_Percent == aWidthUnit) {
// If the parent isn't a table cell and has a style width reset the flag
if (aState.parentReflowState) {
nsCOMPtr<nsIAtom> parentType;
aState.parentReflowState->frame->GetFrameType(getter_AddRefs(parentType));
if (!IS_TABLE_CELL(parentType)) {
nsStyleUnit parentUnit = aState.parentReflowState->mStylePosition->mWidth.GetUnit();
if ((eStyleUnit_Inherit != parentUnit) &&
(eStyleUnit_Auto != parentUnit)) {
aState.mFlags.mTableDerivedComputedWidth = PR_FALSE;
}
}
}
}
else {
// always reset the flag if there is a fixed width
aState.mFlags.mTableDerivedComputedWidth = PR_FALSE;
}
}
// XXX refactor this code to have methods for each set of properties
// we are computing: width,height,line-height; margin; offsets
@ -1835,9 +1871,10 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
// A specified value of 'auto' uses the element's intrinsic width
mComputedWidth = NS_INTRINSICSIZE;
} else {
if (mFlags.mTableDerivedComputedWidth)
CheckResetTableDerivedComputedWidth(*this, widthUnit);
ComputeHorizontalValue(aContainingBlockWidth, widthUnit,
mStylePosition->mWidth,
mComputedWidth);
mStylePosition->mWidth, mComputedWidth);
}
AdjustComputedWidth();
@ -1893,9 +1930,10 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
}
} else {
if (mFlags.mTableDerivedComputedWidth)
CheckResetTableDerivedComputedWidth(*this, widthUnit);
ComputeHorizontalValue(aContainingBlockWidth, widthUnit,
mStylePosition->mWidth,
mComputedWidth);
mStylePosition->mWidth, mComputedWidth);
}
// Take into account minimum and maximum sizes
@ -1938,9 +1976,10 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
}
} else {
if (mFlags.mTableDerivedComputedWidth)
CheckResetTableDerivedComputedWidth(*this, widthUnit);
ComputeHorizontalValue(aContainingBlockWidth, widthUnit,
mStylePosition->mWidth,
mComputedWidth);
mStylePosition->mWidth, mComputedWidth);
}
// Calculate the computed height
@ -2089,6 +2128,8 @@ nsHTMLReflowState::ComputeBlockBoxData(nsIPresContext* aPresContext,
}
}
else {
if (mFlags.mTableDerivedComputedWidth)
CheckResetTableDerivedComputedWidth(*this, aWidthUnit);
ComputeHorizontalValue(aContainingBlockWidth, aWidthUnit,
mStylePosition->mWidth, mComputedWidth);
}
@ -2747,6 +2788,16 @@ void nsHTMLReflowState::AdjustComputedWidth(void)
// NS_ASSERTION(mComputedWidth>=0, "Negative Width Result - very bad");
// if it did go bozo, set to 0
if(mComputedWidth<0) mComputedWidth = 0;
// Tables allow enough width for cells without considering percent based constraints
// of content within the cells. Since such content could exceed the available width,
// we don't allow that to happen.
if (mFlags.mTableDerivedComputedWidth) {
nscoord borderPadding = mComputedBorderPadding.left + mComputedBorderPadding.right;
if (borderPadding + mComputedWidth > availableWidth) {
mComputedWidth = PR_MAX(0, availableWidth - borderPadding);
}
}
}
}
#ifdef IBMBIDI

View File

@ -246,10 +246,12 @@ struct nsHTMLReflowState {
struct ReflowStateFlags {
PRUint16 mSpecialHeightReflow:1; // used by tables to communicate special reflow (in process) to handle
// percent height frames inside cells which may not have computed heights
PRUint16 mTableDerivedComputedWidth:1; // Computed width is due to a table cell's final width, not style
// on the frame itself. Restrictions apply.
PRUint16 mIsTopOfPage:1; // is the current context at the top of a page?
PRUint16 mBlinks:1; // Keep track of text-decoration: blink
PRUint16 mVisualBidiFormControl:1; // Keep track of descendants of form controls on Visual Bidi pages
PRUint16 mUnused:12; // for future use
PRUint16 mUnused:11; // for future use
} mFlags;
#ifdef IBMBIDI

View File

@ -121,7 +121,6 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
: mReflowDepth(0)
{
NS_PRECONDITION(nsnull != aRenderingContext, "no rendering context");
mFlags.mSpecialHeightReflow = mFlags.mUnused = 0;
parentReflowState = nsnull;
frame = aFrame;
reason = aReason;
@ -131,7 +130,10 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
rendContext = aRenderingContext;
mSpaceManager = nsnull;
mLineLayout = nsnull;
mFlags.mSpecialHeightReflow = PR_FALSE;
mFlags.mTableDerivedComputedWidth = PR_FALSE;
mFlags.mIsTopOfPage = PR_FALSE;
mFlags.mUnused = 0;
mPercentHeightObserver = nsnull;
mPercentHeightReflowInitiator = nsnull;
Init(aPresContext);
@ -152,7 +154,6 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
{
NS_PRECONDITION(nsnull != aRenderingContext, "no rendering context");
mFlags.mSpecialHeightReflow = mFlags.mUnused = 0;
reason = eReflowReason_Incremental;
path = aReflowPath;
parentReflowState = nsnull;
@ -162,7 +163,10 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
rendContext = aRenderingContext;
mSpaceManager = nsnull;
mLineLayout = nsnull;
mFlags.mSpecialHeightReflow = PR_FALSE;
mFlags.mTableDerivedComputedWidth = PR_FALSE;
mFlags.mIsTopOfPage = PR_FALSE;
mFlags.mUnused = 0;
mPercentHeightObserver = nsnull;
mPercentHeightReflowInitiator = nsnull;
Init(aPresContext);
@ -344,6 +348,9 @@ void nsHTMLReflowState::InitCBReflowState()
parentReflowState->frame->GetFrameType(getter_AddRefs(fType));
if (IS_TABLE_CELL(fType.get())) {
mCBReflowState = parentReflowState;
// Set mFlags.mTableDerivedComputedWidth to true for a cell block. Its default
// value was set to what the parent reflow state has.
mFlags.mTableDerivedComputedWidth = PR_TRUE;
return;
}
}
@ -1661,6 +1668,35 @@ static eNormalLineHeightControl GetNormalLineHeightCalcControl(void)
return sNormalLineHeightControl;
}
// Reset mFlags.mTableDerivedComputedWidth if there is a non percent style width
// or if there is a percent style width and the parent has a style width.
// This function assumes that aWidthUnit is never Auto or Inherit and that aState's
// mFlags.mTableDerivedComputedWidth is set.
static void
CheckResetTableDerivedComputedWidth(nsHTMLReflowState& aState,
nsStyleUnit aWidthUnit)
{
if (eStyleUnit_Percent == aWidthUnit) {
// If the parent isn't a table cell and has a style width reset the flag
if (aState.parentReflowState) {
nsCOMPtr<nsIAtom> parentType;
aState.parentReflowState->frame->GetFrameType(getter_AddRefs(parentType));
if (!IS_TABLE_CELL(parentType)) {
nsStyleUnit parentUnit = aState.parentReflowState->mStylePosition->mWidth.GetUnit();
if ((eStyleUnit_Inherit != parentUnit) &&
(eStyleUnit_Auto != parentUnit)) {
aState.mFlags.mTableDerivedComputedWidth = PR_FALSE;
}
}
}
}
else {
// always reset the flag if there is a fixed width
aState.mFlags.mTableDerivedComputedWidth = PR_FALSE;
}
}
// XXX refactor this code to have methods for each set of properties
// we are computing: width,height,line-height; margin; offsets
@ -1835,9 +1871,10 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
// A specified value of 'auto' uses the element's intrinsic width
mComputedWidth = NS_INTRINSICSIZE;
} else {
if (mFlags.mTableDerivedComputedWidth)
CheckResetTableDerivedComputedWidth(*this, widthUnit);
ComputeHorizontalValue(aContainingBlockWidth, widthUnit,
mStylePosition->mWidth,
mComputedWidth);
mStylePosition->mWidth, mComputedWidth);
}
AdjustComputedWidth();
@ -1893,9 +1930,10 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
}
} else {
if (mFlags.mTableDerivedComputedWidth)
CheckResetTableDerivedComputedWidth(*this, widthUnit);
ComputeHorizontalValue(aContainingBlockWidth, widthUnit,
mStylePosition->mWidth,
mComputedWidth);
mStylePosition->mWidth, mComputedWidth);
}
// Take into account minimum and maximum sizes
@ -1938,9 +1976,10 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
}
} else {
if (mFlags.mTableDerivedComputedWidth)
CheckResetTableDerivedComputedWidth(*this, widthUnit);
ComputeHorizontalValue(aContainingBlockWidth, widthUnit,
mStylePosition->mWidth,
mComputedWidth);
mStylePosition->mWidth, mComputedWidth);
}
// Calculate the computed height
@ -2089,6 +2128,8 @@ nsHTMLReflowState::ComputeBlockBoxData(nsIPresContext* aPresContext,
}
}
else {
if (mFlags.mTableDerivedComputedWidth)
CheckResetTableDerivedComputedWidth(*this, aWidthUnit);
ComputeHorizontalValue(aContainingBlockWidth, aWidthUnit,
mStylePosition->mWidth, mComputedWidth);
}
@ -2747,6 +2788,16 @@ void nsHTMLReflowState::AdjustComputedWidth(void)
// NS_ASSERTION(mComputedWidth>=0, "Negative Width Result - very bad");
// if it did go bozo, set to 0
if(mComputedWidth<0) mComputedWidth = 0;
// Tables allow enough width for cells without considering percent based constraints
// of content within the cells. Since such content could exceed the available width,
// we don't allow that to happen.
if (mFlags.mTableDerivedComputedWidth) {
nscoord borderPadding = mComputedBorderPadding.left + mComputedBorderPadding.right;
if (borderPadding + mComputedWidth > availableWidth) {
mComputedWidth = PR_MAX(0, availableWidth - borderPadding);
}
}
}
}
#ifdef IBMBIDI

View File

@ -0,0 +1,25 @@
<!doctype html public "-//w3c//dtd html 3.2//en">
<html>
<head>
<title>testcase 2</title>
<meta name="GENERATOR" content="Arachnophilia 4.0">
<meta name="FORMATTER" content="Arachnophilia 4.0">
</head>
<body bgcolor="#ffffff" text="#000000" link="#0000ff" vlink="#800080" alink="#ff0000">
<table border>
<tr>
<td width="300">
<div style="width:30%; border: solid purple">
<div style="width:200%; border:solid blue">
foo
</div>
</div>
</td></tr></table>
</body>
</html>

View File

@ -23,6 +23,7 @@ file:///s|/mozilla/layout/html/tests/table/bugs/bug17138.html
file:///s|/mozilla/layout/html/tests/table/bugs/bug1725.html
file:///s|/mozilla/layout/html/tests/table/bugs/bug17548.html
file:///s|/mozilla/layout/html/tests/table/bugs/bug17168.html
file:///s|/mozilla/layout/html/tests/table/bugs/bug175455-4.html
file:///s|/mozilla/layout/html/tests/table/bugs/bug17587.html
file:///s|/mozilla/layout/html/tests/table/bugs/bug17826.html
file:///s|/mozilla/layout/html/tests/table/bugs/bug178855.xml

View File

@ -0,0 +1,19 @@
<html>
<head>
<title>bug 175455</title>
<style>
a.freesubtype {display: block; width: 100%; padding-left: 16px;}
a.freesubtype:hover {font-weight: bold;}
</style>
</head>
<body>
<table border="1">
<tr>
<td>
<a class='freesubtype'>Classic</a>
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,33 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Bug 175455 testcase</title>
<style type="text/css">
/* All of these rules seem to be required to trigger this bug */
a.xxx {
display: block;
width: 100%;
padding-left: 16px;
background-color: silver;
}
a.xxx:hover {
font-weight: bold;
}
</style>
</head>
<body>
<h1>Bug 175455 testcase</h1>
<table>
<tr>
<td style="background-color: lime">
<a href="" class='xxx'>Hover on me, then move your mouse off again...</a>
</td>
<td style="background-color: green">
...and watch this cell move!
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,16 @@
<html><head><title>bug 175455</title>
<style>
a.freesubtype {display: block; width: 100%; padding-left: 16px;}
a.freesubtype:hover {font-weight: bold;}
</style></head>
<body>
<table border="1">
<tbody><tr>
<td><i>
<a class="freesubtype">Classic</a></i>
</td>
</tr>
</tbody></table>
</body></html>