From f286a1e3c4c6c8aa4b19f0d33ccdd0784d16caa2 Mon Sep 17 00:00:00 2001 From: "karnaze%netscape.com" Date: Thu, 3 Jun 1999 02:42:33 +0000 Subject: [PATCH] bug 7243. Rewrote FixedTableLayoutStrategy::AssignPreliminaryColumnWidths git-svn-id: svn://10.0.0.236/trunk@33487 18797224-902f-48f8-a5cc-f745e15eee43 --- .../table/src/BasicTableLayoutStrategy.cpp | 7 +- .../html/table/src/BasicTableLayoutStrategy.h | 6 +- .../table/src/FixedTableLayoutStrategy.cpp | 168 ++++++++++-------- .../html/table/src/FixedTableLayoutStrategy.h | 2 +- .../html/table/src/nsITableLayoutStrategy.h | 3 +- .../layout/html/table/src/nsTableFrame.cpp | 15 +- .../tables/BasicTableLayoutStrategy.cpp | 7 +- .../layout/tables/BasicTableLayoutStrategy.h | 6 +- .../tables/FixedTableLayoutStrategy.cpp | 168 ++++++++++-------- .../layout/tables/FixedTableLayoutStrategy.h | 2 +- .../layout/tables/nsITableLayoutStrategy.h | 3 +- mozilla/layout/tables/nsTableFrame.cpp | 15 +- 12 files changed, 236 insertions(+), 166 deletions(-) diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp index 7712953e951..2f034b8c497 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -233,7 +233,8 @@ BasicTableLayoutStrategy::~BasicTableLayoutStrategy() } PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, - PRInt32 aNumCols) + PRInt32 aNumCols, + nscoord aMaxWidth) { #ifdef NS_DEBUG nsIFrame* tablePIF = nsnull; @@ -251,7 +252,7 @@ PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, mCols = mTableFrame->GetEffectiveCOLSAttribute(); // Step 1 - assign the width of all fixed-width columns - AssignPreliminaryColumnWidths(); + AssignPreliminaryColumnWidths(aMaxWidth); // set aMaxElementSize here because we compute mMinTableWidth in AssignPreliminaryColumnWidths if (nsnull != aMaxElementSize) { @@ -389,7 +390,7 @@ nscoord BasicTableLayoutStrategy::CalcHorizontalPadding(PRInt32 aColX) // Step 1 - assign the width of all fixed-width columns, all other columns get there max, // and calculate min/max table width -PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() +PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth) { TDBG_SP("** %p: AssignPreliminaryColumnWidths **\n", mTableFrame); nsVoidArray *spanList = nsnull; diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h index 375d82ae4fc..55c207a995a 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h @@ -91,7 +91,7 @@ public: * @param aMaxElementSize [OUT] if not null, the max element size is computed and returned in this param * @param aNumCols the total number of columns in the table */ - virtual PRBool Initialize(nsSize* aMaxElementSize, PRInt32 aNumCols); + virtual PRBool Initialize(nsSize* aMaxElementSize, PRInt32 aNumCols, nscoord aMaxSize); /** compute the max element size of the table. * assumes that Initialize has been called @@ -123,10 +123,12 @@ protected: * Computes the minimum and maximum table widths. * Set column width information in each column frame and in the table frame. * + * @param aMaxWidth - the computed width of the table or + * UNCONSTRAINED_SIZE if an auto width table * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error * */ - virtual PRBool AssignPreliminaryColumnWidths(); + virtual PRBool AssignPreliminaryColumnWidths(nscoord aComputedWidth); /** compute the min and max width of this table. Assumes AssignPreliminaryColumnWidths * has been called. Sets mMinTableWidth and mMaxTableWidth as a side effect. diff --git a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp index 1febd8256c5..31c01d07342 100644 --- a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp @@ -73,109 +73,135 @@ PRBool FixedTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext *aTableStyl return result; } -/* assign the width of all columns +/* + * assign the width of all columns * if there is a colframe with a width attribute, use it as the column width * otherwise if there is a cell in the first row and it has a width attribute, use it * if this cell includes a colspan, width is divided equally among spanned columns * otherwise the cell get a proportion of the remaining space * as determined by the table width attribute. If no table width attribute, it gets 0 width */ -PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths() +PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputedWidth) { + NS_ASSERTION(aComputedWidth != NS_UNCONSTRAINEDSIZE, "bad computed width"); if (gsDebug==PR_TRUE) printf ("** %p: AssignPreliminaryColumnWidths **\n", mTableFrame); - - PRInt32 colIndex; - PRInt32 specifiedColumns=0; // the number of columns whose width is given - nscoord totalWidth = 0; // the sum of the widths of the columns whose width is given - PRBool * autoWidthColumns = new PRBool[mNumCols]; - nsCRT::memset(autoWidthColumns, PR_TRUE, mNumCols*sizeof(PRBool)); + const nsStylePosition* tablePosition; + mTableFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)tablePosition); + PRBool tableIsFixedWidth = eStyleUnit_Coord == tablePosition->mWidth.GetUnit() || + eStyleUnit_Percent == tablePosition->mWidth.GetUnit(); + + const nsStyleSpacing* tableSpacing; + mTableFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)tableSpacing); + nsMargin borderPadding; + tableSpacing->CalcBorderPaddingFor(mTableFrame, borderPadding); + + PRInt32 colX; + // availWidth is used as the basis for percentage width columns. It is aComputedWidth + // minus table border, padding, & cellspacing + nscoord availWidth = aComputedWidth - borderPadding.left - borderPadding.right - + ((mNumCols + 1) * mTableFrame->GetCellSpacingX()); + + PRInt32 specifiedCols = 0; // the number of columns whose width is given + nscoord totalColWidth = 0; // the sum of the widths of the columns + + nscoord* colWidths = new PRBool[mNumCols]; + nsCRT::memset(colWidths, -1, mNumCols*sizeof(nscoord)); // for every column, determine it's specified width - for (colIndex = 0; colIndexGetColFrame(colIndex); - NS_ASSERTION(nsnull!=colFrame, "bad col frame"); + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + NS_ASSERTION(nsnull != colFrame, "bad col frame"); // Get the columns's style const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - // Get fixed column width if it has one - if (eStyleUnit_Coord==colPosition->mWidth.GetUnit()) - { - nscoord colWidth = colPosition->mWidth.GetCoordValue(); - mTableFrame->SetColumnWidth(colIndex, colWidth); - totalWidth += colWidth; - specifiedColumns++; - autoWidthColumns[colIndex]=PR_FALSE; - if (PR_TRUE==gsDebug) - printf ("from col, col %d set to width %d\n", colIndex, colWidth); + // get the fixed width if available + if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { + colWidths[colX] = colPosition->mWidth.GetCoordValue(); + } // get the percentage width + else if (eStyleUnit_Percent == colPosition->mWidth.GetUnit()) { + float percent = colPosition->mWidth.GetPercentValue(); + colWidths[colX] = NSToCoordRound(percent * (float)availWidth); } - else - { - nsTableCellFrame *cellFrame = mTableFrame->GetCellFrameAt(0, colIndex); - if (nsnull!=cellFrame) - { + else { // get width from the cell + nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(0, colX); + if (nsnull != cellFrame) { // Get the cell's style const nsStylePosition* cellPosition; cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - // Get fixed column width if it has one - if (eStyleUnit_Coord==cellPosition->mWidth.GetUnit()) - { - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); - nscoord effectiveWidth = cellPosition->mWidth.GetCoordValue()/colSpan; - mTableFrame->SetColumnWidth(colIndex, effectiveWidth); - totalWidth += effectiveWidth; - specifiedColumns++; - autoWidthColumns[colIndex]=PR_FALSE; - if (PR_TRUE==gsDebug) - printf ("from cell, col %d set to width %d\n", colIndex, effectiveWidth); + PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colX, cellFrame); + // Get fixed cell width if available + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { + colWidths[colX] = cellPosition->mWidth.GetCoordValue() / colSpan; + } + else if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { + float percent = cellPosition->mWidth.GetPercentValue(); + colWidths[colX] = NSToCoordRound(percent * (float)availWidth / (float)colSpan); } } } + if (colWidths[colX] >= 0) { + totalColWidth += colWidths[colX]; + specifiedCols++; + if (PR_TRUE==gsDebug) printf ("col %d set to width %d\n", colX, colWidths[colX]); + } } - - // for every column that did not have a specified width, compute its width from the remaining space - if (mNumCols > specifiedColumns) - { - // Get the table's style - const nsStylePosition* tablePosition; - mTableFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)tablePosition); - if (eStyleUnit_Coord==tablePosition->mWidth.GetUnit()) - { - nscoord specifiedTableWidth = tablePosition->mWidth.GetCoordValue(); - nscoord remainingTableWidth = specifiedTableWidth - totalWidth; - if (PR_TRUE==gsDebug) - printf ("%p: specifiedTW=%d, remainingTW=%d\n", - mTableFrame, specifiedTableWidth, remainingTableWidth); - if (0SetColumnWidth(colIndex, widthPerColumn); - totalWidth += widthPerColumn; - if (PR_TRUE==gsDebug) - printf ("auto col %d set to width %d\n", colIndex, widthPerColumn); - } + + nscoord lastColAllocated = -1; + nscoord remainingWidth = availWidth - totalColWidth; + if (tableIsFixedWidth && (0 < remainingWidth)) { + if (mNumCols > specifiedCols) { + // allocate the extra space to the columns which have no width specified + if (PR_TRUE == gsDebug) printf ("%p: remainingTW=%d\n", mTableFrame, remainingWidth); + nscoord colAlloc = NSToCoordRound( ((float)remainingWidth) / (((float)mNumCols) - ((float)specifiedCols))); + for (colX = 0; colX < mNumCols; colX++) { + if (-1 == colWidths[colX]) { + colWidths[colX] = colAlloc; + totalColWidth += colAlloc; + lastColAllocated = colX; + if (PR_TRUE == gsDebug) printf ("auto col %d set to width %d\n", colX, colAlloc); } } } + else { // allocate the extra space to the columns which have width specified + float divisor = (float)totalColWidth; + for (colX = 0; colX < mNumCols; colX++) { + if (colWidths[colX] > 0) { + nscoord colAlloc = NSToCoordRound(remainingWidth * colWidths[colX] / divisor); + colWidths[colX] += colAlloc; + totalColWidth += colAlloc; + lastColAllocated = colX; + if (PR_TRUE == gsDebug) printf ("col %d set to width %d\n", colX, colWidths[colX]); + } + } + } } - // min/MaxTW is max of (specified table width, sum of specified column(cell) widths) - mMinTableWidth = mMaxTableWidth = totalWidth; - if (PR_TRUE==gsDebug) - printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, mMinTableWidth, mMaxTableWidth); + + nscoord overAllocation = (availWidth >= 0) + ? totalColWidth - availWidth : 0; + // set the column widths + for (colX = 0; colX < mNumCols; colX++) { + if (colWidths[colX] < 0) + colWidths[colX] = 0; + // if there was too much allocated due to rounding, remove it from the last col + if ((colX == lastColAllocated) && (overAllocation != 0)) { + colWidths[colX] += overAllocation; + colWidths[colX] = PR_MAX(0, colWidths[colX]); + } + mTableFrame->SetColumnWidth(colX, colWidths[colX]); + } + + // min/max TW is min/max of (specified table width, sum of specified column(cell) widths) + mMinTableWidth = mMaxTableWidth = totalColWidth; + if (PR_TRUE == gsDebug) printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, mMinTableWidth, mMaxTableWidth); // clean up - if (nsnull!=autoWidthColumns) - { - delete [] autoWidthColumns; + if (nsnull != colWidths) { + delete [] colWidths; } return PR_TRUE; diff --git a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h index 5dc239b197b..d012b2a86de 100644 --- a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h @@ -72,7 +72,7 @@ protected: * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error * */ - virtual PRBool AssignPreliminaryColumnWidths(); + virtual PRBool AssignPreliminaryColumnWidths(nscoord aComputedWidth); }; diff --git a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h index 0e4df637a33..4221ccd187b 100644 --- a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h @@ -32,8 +32,9 @@ public: /** call once every time any table thing changes (content, structure, or style) * @param aMaxElementSize [OUT] if not null, the max element size is computed and returned in this param * @param aNumCols the total number of columns in the table + * @param aComputedWidth the computed size of the table */ - virtual PRBool Initialize(nsSize* aMaxElementSize, PRInt32 aNumCols)=0; + virtual PRBool Initialize(nsSize* aMaxElementSize, PRInt32 aNumCols, nscoord aComputedWidth)=0; /** compute the max-element-size for the table * @param aMaxElementSize [OUT] width field set to the min legal width of the table diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index 20726aed9fa..7c43d94931f 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -2497,7 +2497,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext, if (nsnull!=mTableLayoutStrategy) { if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: Re-init layout strategy\n"); - mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount()); + mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount(), aReflowState.computedWidth); mColumnWidthsValid=PR_TRUE; //so we don't do this a second time below } } @@ -2506,7 +2506,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext, if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: Re-init layout strategy\n"); if (nsnull!=mTableLayoutStrategy) { - mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount()); + mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount(), aReflowState.computedWidth); mColumnWidthsValid=PR_TRUE; } } @@ -3972,17 +3972,22 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext& aPresContext, this, maxWidth, aMaxSize.width, aMaxSize.height); // based on the compatibility mode, create a table layout strategy - if (nsnull==mTableLayoutStrategy) - { + if (nsnull == mTableLayoutStrategy) { nsCompatibility mode; aPresContext.GetCompatibilityMode(&mode); if (PR_FALSE==RequiresPass1Layout()) mTableLayoutStrategy = new FixedTableLayoutStrategy(this); else mTableLayoutStrategy = new BasicTableLayoutStrategy(this, eCompatibility_NavQuirks == mode); - mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount()); + mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount(), aReflowState.computedWidth); mColumnWidthsValid=PR_TRUE; } + // fixed-layout tables need to reinitialize the layout strategy. When there are scroll bars + // reflow gets called twice and the 2nd time has the correct space available. + else if (!RequiresPass1Layout()) { + mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount(), aReflowState.computedWidth); + } + mTableLayoutStrategy->BalanceColumnWidths(mStyleContext, aReflowState, maxWidth); mColumnWidthsSet=PR_TRUE; diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp index 7712953e951..2f034b8c497 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp @@ -233,7 +233,8 @@ BasicTableLayoutStrategy::~BasicTableLayoutStrategy() } PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, - PRInt32 aNumCols) + PRInt32 aNumCols, + nscoord aMaxWidth) { #ifdef NS_DEBUG nsIFrame* tablePIF = nsnull; @@ -251,7 +252,7 @@ PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, mCols = mTableFrame->GetEffectiveCOLSAttribute(); // Step 1 - assign the width of all fixed-width columns - AssignPreliminaryColumnWidths(); + AssignPreliminaryColumnWidths(aMaxWidth); // set aMaxElementSize here because we compute mMinTableWidth in AssignPreliminaryColumnWidths if (nsnull != aMaxElementSize) { @@ -389,7 +390,7 @@ nscoord BasicTableLayoutStrategy::CalcHorizontalPadding(PRInt32 aColX) // Step 1 - assign the width of all fixed-width columns, all other columns get there max, // and calculate min/max table width -PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() +PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth) { TDBG_SP("** %p: AssignPreliminaryColumnWidths **\n", mTableFrame); nsVoidArray *spanList = nsnull; diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.h b/mozilla/layout/tables/BasicTableLayoutStrategy.h index 375d82ae4fc..55c207a995a 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.h +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.h @@ -91,7 +91,7 @@ public: * @param aMaxElementSize [OUT] if not null, the max element size is computed and returned in this param * @param aNumCols the total number of columns in the table */ - virtual PRBool Initialize(nsSize* aMaxElementSize, PRInt32 aNumCols); + virtual PRBool Initialize(nsSize* aMaxElementSize, PRInt32 aNumCols, nscoord aMaxSize); /** compute the max element size of the table. * assumes that Initialize has been called @@ -123,10 +123,12 @@ protected: * Computes the minimum and maximum table widths. * Set column width information in each column frame and in the table frame. * + * @param aMaxWidth - the computed width of the table or + * UNCONSTRAINED_SIZE if an auto width table * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error * */ - virtual PRBool AssignPreliminaryColumnWidths(); + virtual PRBool AssignPreliminaryColumnWidths(nscoord aComputedWidth); /** compute the min and max width of this table. Assumes AssignPreliminaryColumnWidths * has been called. Sets mMinTableWidth and mMaxTableWidth as a side effect. diff --git a/mozilla/layout/tables/FixedTableLayoutStrategy.cpp b/mozilla/layout/tables/FixedTableLayoutStrategy.cpp index 1febd8256c5..31c01d07342 100644 --- a/mozilla/layout/tables/FixedTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/FixedTableLayoutStrategy.cpp @@ -73,109 +73,135 @@ PRBool FixedTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext *aTableStyl return result; } -/* assign the width of all columns +/* + * assign the width of all columns * if there is a colframe with a width attribute, use it as the column width * otherwise if there is a cell in the first row and it has a width attribute, use it * if this cell includes a colspan, width is divided equally among spanned columns * otherwise the cell get a proportion of the remaining space * as determined by the table width attribute. If no table width attribute, it gets 0 width */ -PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths() +PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputedWidth) { + NS_ASSERTION(aComputedWidth != NS_UNCONSTRAINEDSIZE, "bad computed width"); if (gsDebug==PR_TRUE) printf ("** %p: AssignPreliminaryColumnWidths **\n", mTableFrame); - - PRInt32 colIndex; - PRInt32 specifiedColumns=0; // the number of columns whose width is given - nscoord totalWidth = 0; // the sum of the widths of the columns whose width is given - PRBool * autoWidthColumns = new PRBool[mNumCols]; - nsCRT::memset(autoWidthColumns, PR_TRUE, mNumCols*sizeof(PRBool)); + const nsStylePosition* tablePosition; + mTableFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)tablePosition); + PRBool tableIsFixedWidth = eStyleUnit_Coord == tablePosition->mWidth.GetUnit() || + eStyleUnit_Percent == tablePosition->mWidth.GetUnit(); + + const nsStyleSpacing* tableSpacing; + mTableFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)tableSpacing); + nsMargin borderPadding; + tableSpacing->CalcBorderPaddingFor(mTableFrame, borderPadding); + + PRInt32 colX; + // availWidth is used as the basis for percentage width columns. It is aComputedWidth + // minus table border, padding, & cellspacing + nscoord availWidth = aComputedWidth - borderPadding.left - borderPadding.right - + ((mNumCols + 1) * mTableFrame->GetCellSpacingX()); + + PRInt32 specifiedCols = 0; // the number of columns whose width is given + nscoord totalColWidth = 0; // the sum of the widths of the columns + + nscoord* colWidths = new PRBool[mNumCols]; + nsCRT::memset(colWidths, -1, mNumCols*sizeof(nscoord)); // for every column, determine it's specified width - for (colIndex = 0; colIndexGetColFrame(colIndex); - NS_ASSERTION(nsnull!=colFrame, "bad col frame"); + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + NS_ASSERTION(nsnull != colFrame, "bad col frame"); // Get the columns's style const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - // Get fixed column width if it has one - if (eStyleUnit_Coord==colPosition->mWidth.GetUnit()) - { - nscoord colWidth = colPosition->mWidth.GetCoordValue(); - mTableFrame->SetColumnWidth(colIndex, colWidth); - totalWidth += colWidth; - specifiedColumns++; - autoWidthColumns[colIndex]=PR_FALSE; - if (PR_TRUE==gsDebug) - printf ("from col, col %d set to width %d\n", colIndex, colWidth); + // get the fixed width if available + if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { + colWidths[colX] = colPosition->mWidth.GetCoordValue(); + } // get the percentage width + else if (eStyleUnit_Percent == colPosition->mWidth.GetUnit()) { + float percent = colPosition->mWidth.GetPercentValue(); + colWidths[colX] = NSToCoordRound(percent * (float)availWidth); } - else - { - nsTableCellFrame *cellFrame = mTableFrame->GetCellFrameAt(0, colIndex); - if (nsnull!=cellFrame) - { + else { // get width from the cell + nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(0, colX); + if (nsnull != cellFrame) { // Get the cell's style const nsStylePosition* cellPosition; cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - // Get fixed column width if it has one - if (eStyleUnit_Coord==cellPosition->mWidth.GetUnit()) - { - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); - nscoord effectiveWidth = cellPosition->mWidth.GetCoordValue()/colSpan; - mTableFrame->SetColumnWidth(colIndex, effectiveWidth); - totalWidth += effectiveWidth; - specifiedColumns++; - autoWidthColumns[colIndex]=PR_FALSE; - if (PR_TRUE==gsDebug) - printf ("from cell, col %d set to width %d\n", colIndex, effectiveWidth); + PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colX, cellFrame); + // Get fixed cell width if available + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { + colWidths[colX] = cellPosition->mWidth.GetCoordValue() / colSpan; + } + else if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { + float percent = cellPosition->mWidth.GetPercentValue(); + colWidths[colX] = NSToCoordRound(percent * (float)availWidth / (float)colSpan); } } } + if (colWidths[colX] >= 0) { + totalColWidth += colWidths[colX]; + specifiedCols++; + if (PR_TRUE==gsDebug) printf ("col %d set to width %d\n", colX, colWidths[colX]); + } } - - // for every column that did not have a specified width, compute its width from the remaining space - if (mNumCols > specifiedColumns) - { - // Get the table's style - const nsStylePosition* tablePosition; - mTableFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)tablePosition); - if (eStyleUnit_Coord==tablePosition->mWidth.GetUnit()) - { - nscoord specifiedTableWidth = tablePosition->mWidth.GetCoordValue(); - nscoord remainingTableWidth = specifiedTableWidth - totalWidth; - if (PR_TRUE==gsDebug) - printf ("%p: specifiedTW=%d, remainingTW=%d\n", - mTableFrame, specifiedTableWidth, remainingTableWidth); - if (0SetColumnWidth(colIndex, widthPerColumn); - totalWidth += widthPerColumn; - if (PR_TRUE==gsDebug) - printf ("auto col %d set to width %d\n", colIndex, widthPerColumn); - } + + nscoord lastColAllocated = -1; + nscoord remainingWidth = availWidth - totalColWidth; + if (tableIsFixedWidth && (0 < remainingWidth)) { + if (mNumCols > specifiedCols) { + // allocate the extra space to the columns which have no width specified + if (PR_TRUE == gsDebug) printf ("%p: remainingTW=%d\n", mTableFrame, remainingWidth); + nscoord colAlloc = NSToCoordRound( ((float)remainingWidth) / (((float)mNumCols) - ((float)specifiedCols))); + for (colX = 0; colX < mNumCols; colX++) { + if (-1 == colWidths[colX]) { + colWidths[colX] = colAlloc; + totalColWidth += colAlloc; + lastColAllocated = colX; + if (PR_TRUE == gsDebug) printf ("auto col %d set to width %d\n", colX, colAlloc); } } } + else { // allocate the extra space to the columns which have width specified + float divisor = (float)totalColWidth; + for (colX = 0; colX < mNumCols; colX++) { + if (colWidths[colX] > 0) { + nscoord colAlloc = NSToCoordRound(remainingWidth * colWidths[colX] / divisor); + colWidths[colX] += colAlloc; + totalColWidth += colAlloc; + lastColAllocated = colX; + if (PR_TRUE == gsDebug) printf ("col %d set to width %d\n", colX, colWidths[colX]); + } + } + } } - // min/MaxTW is max of (specified table width, sum of specified column(cell) widths) - mMinTableWidth = mMaxTableWidth = totalWidth; - if (PR_TRUE==gsDebug) - printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, mMinTableWidth, mMaxTableWidth); + + nscoord overAllocation = (availWidth >= 0) + ? totalColWidth - availWidth : 0; + // set the column widths + for (colX = 0; colX < mNumCols; colX++) { + if (colWidths[colX] < 0) + colWidths[colX] = 0; + // if there was too much allocated due to rounding, remove it from the last col + if ((colX == lastColAllocated) && (overAllocation != 0)) { + colWidths[colX] += overAllocation; + colWidths[colX] = PR_MAX(0, colWidths[colX]); + } + mTableFrame->SetColumnWidth(colX, colWidths[colX]); + } + + // min/max TW is min/max of (specified table width, sum of specified column(cell) widths) + mMinTableWidth = mMaxTableWidth = totalColWidth; + if (PR_TRUE == gsDebug) printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, mMinTableWidth, mMaxTableWidth); // clean up - if (nsnull!=autoWidthColumns) - { - delete [] autoWidthColumns; + if (nsnull != colWidths) { + delete [] colWidths; } return PR_TRUE; diff --git a/mozilla/layout/tables/FixedTableLayoutStrategy.h b/mozilla/layout/tables/FixedTableLayoutStrategy.h index 5dc239b197b..d012b2a86de 100644 --- a/mozilla/layout/tables/FixedTableLayoutStrategy.h +++ b/mozilla/layout/tables/FixedTableLayoutStrategy.h @@ -72,7 +72,7 @@ protected: * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error * */ - virtual PRBool AssignPreliminaryColumnWidths(); + virtual PRBool AssignPreliminaryColumnWidths(nscoord aComputedWidth); }; diff --git a/mozilla/layout/tables/nsITableLayoutStrategy.h b/mozilla/layout/tables/nsITableLayoutStrategy.h index 0e4df637a33..4221ccd187b 100644 --- a/mozilla/layout/tables/nsITableLayoutStrategy.h +++ b/mozilla/layout/tables/nsITableLayoutStrategy.h @@ -32,8 +32,9 @@ public: /** call once every time any table thing changes (content, structure, or style) * @param aMaxElementSize [OUT] if not null, the max element size is computed and returned in this param * @param aNumCols the total number of columns in the table + * @param aComputedWidth the computed size of the table */ - virtual PRBool Initialize(nsSize* aMaxElementSize, PRInt32 aNumCols)=0; + virtual PRBool Initialize(nsSize* aMaxElementSize, PRInt32 aNumCols, nscoord aComputedWidth)=0; /** compute the max-element-size for the table * @param aMaxElementSize [OUT] width field set to the min legal width of the table diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index 20726aed9fa..7c43d94931f 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -2497,7 +2497,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext, if (nsnull!=mTableLayoutStrategy) { if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: Re-init layout strategy\n"); - mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount()); + mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount(), aReflowState.computedWidth); mColumnWidthsValid=PR_TRUE; //so we don't do this a second time below } } @@ -2506,7 +2506,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext, if (PR_TRUE==gsDebug || PR_TRUE==gsDebugIR) printf("TIF Reflow: Re-init layout strategy\n"); if (nsnull!=mTableLayoutStrategy) { - mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount()); + mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount(), aReflowState.computedWidth); mColumnWidthsValid=PR_TRUE; } } @@ -3972,17 +3972,22 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext& aPresContext, this, maxWidth, aMaxSize.width, aMaxSize.height); // based on the compatibility mode, create a table layout strategy - if (nsnull==mTableLayoutStrategy) - { + if (nsnull == mTableLayoutStrategy) { nsCompatibility mode; aPresContext.GetCompatibilityMode(&mode); if (PR_FALSE==RequiresPass1Layout()) mTableLayoutStrategy = new FixedTableLayoutStrategy(this); else mTableLayoutStrategy = new BasicTableLayoutStrategy(this, eCompatibility_NavQuirks == mode); - mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount()); + mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount(), aReflowState.computedWidth); mColumnWidthsValid=PR_TRUE; } + // fixed-layout tables need to reinitialize the layout strategy. When there are scroll bars + // reflow gets called twice and the 2nd time has the correct space available. + else if (!RequiresPass1Layout()) { + mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount(), aReflowState.computedWidth); + } + mTableLayoutStrategy->BalanceColumnWidths(mStyleContext, aReflowState, maxWidth); mColumnWidthsSet=PR_TRUE;