From 382b9863de6c5ab6acaf78d2c5efa617a3292457 Mon Sep 17 00:00:00 2001 From: "karnaze%netscape.com" Date: Wed, 28 Jul 1999 08:09:02 +0000 Subject: [PATCH] new nsCellMap, BasicTableLayoutStrategy, plus various fixes to table frames while testing the new cell map and strategy git-svn-id: svn://10.0.0.236/trunk@41454 18797224-902f-48f8-a5cc-f745e15eee43 --- .../table/src/BasicTableLayoutStrategy.cpp | 3332 +++++------------ .../html/table/src/BasicTableLayoutStrategy.h | 208 +- .../table/src/FixedTableLayoutStrategy.cpp | 36 +- .../html/table/src/FixedTableLayoutStrategy.h | 6 +- mozilla/layout/html/table/src/celldata.h | 30 +- mozilla/layout/html/table/src/nsCellMap.cpp | 730 ++-- mozilla/layout/html/table/src/nsCellMap.h | 260 +- .../html/table/src/nsITableLayoutStrategy.h | 14 +- .../html/table/src/nsTableCellFrame.cpp | 134 +- .../layout/html/table/src/nsTableCellFrame.h | 1 + .../layout/html/table/src/nsTableColFrame.cpp | 73 +- .../layout/html/table/src/nsTableColFrame.h | 129 +- .../html/table/src/nsTableColGroupFrame.cpp | 5 + .../html/table/src/nsTableColGroupFrame.h | 2 + .../layout/html/table/src/nsTableFrame.cpp | 767 ++-- mozilla/layout/html/table/src/nsTableFrame.h | 115 +- .../layout/html/table/src/nsTableRowFrame.cpp | 157 +- .../layout/html/table/src/nsTableRowFrame.h | 2 +- .../html/table/src/nsTableRowGroupFrame.cpp | 15 +- .../layout/html/tests/table/bugs/bug1800.html | 55 +- .../layout/html/tests/table/bugs/bug2763.html | 10 + .../html/tests/table/bugs/file_list.txt | 1 + .../html/tests/table/core/bloomberg.html | 112 + .../html/tests/table/core/col_span.html | 16 +- .../html/tests/table/core/col_span2.html | 101 +- .../html/tests/table/core/file_list.txt | 2 + .../html/tests/table/core/table_widths.html | 29 + .../html/tests/table/other/nestedTables.html | 14 + .../tables/BasicTableLayoutStrategy.cpp | 3332 +++++------------ .../layout/tables/BasicTableLayoutStrategy.h | 208 +- .../tables/FixedTableLayoutStrategy.cpp | 36 +- .../layout/tables/FixedTableLayoutStrategy.h | 6 +- mozilla/layout/tables/celldata.h | 30 +- mozilla/layout/tables/nsCellMap.cpp | 730 ++-- mozilla/layout/tables/nsCellMap.h | 260 +- .../layout/tables/nsITableLayoutStrategy.h | 14 +- mozilla/layout/tables/nsTableCellFrame.cpp | 134 +- mozilla/layout/tables/nsTableCellFrame.h | 1 + mozilla/layout/tables/nsTableColFrame.cpp | 73 +- mozilla/layout/tables/nsTableColFrame.h | 129 +- .../layout/tables/nsTableColGroupFrame.cpp | 5 + mozilla/layout/tables/nsTableColGroupFrame.h | 2 + mozilla/layout/tables/nsTableFrame.cpp | 767 ++-- mozilla/layout/tables/nsTableFrame.h | 115 +- mozilla/layout/tables/nsTableRowFrame.cpp | 157 +- mozilla/layout/tables/nsTableRowFrame.h | 2 +- .../layout/tables/nsTableRowGroupFrame.cpp | 15 +- mozilla/layout/xul/base/src/nsTreeFrame.cpp | 6 +- 48 files changed, 4757 insertions(+), 7621 deletions(-) create mode 100644 mozilla/layout/html/tests/table/bugs/bug2763.html create mode 100644 mozilla/layout/html/tests/table/core/bloomberg.html create mode 100644 mozilla/layout/html/tests/table/core/table_widths.html diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp index 463ec16a47d..1e8d95e0d59 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -26,182 +26,9 @@ #include "nsHTMLIIDs.h" static const PRBool gsDebug = PR_FALSE; - -const nscoord gBigSpace = 100000; // a fudge constant used when the table is laid out with unconstrained width - -// these macros are defined to improve the readability of the main code -#define TDBG_S(str) \ - if (gsDebug) { \ - printf((str)); \ - } - -#define TDBG_SP(str,ptr) \ - if (gsDebug) { \ - printf((str),(ptr)); \ - } - -#define TDBG_SPD(str,ptr,dec) \ - if (gsDebug) { \ - printf((str),(ptr),(dec)); \ - } - -#define TDBG_SPDD(str,ptr,dec1,dec2) \ - if (gsDebug) { \ - printf((str),(ptr),(dec1),(dec2)); \ - } - -#define TDBG_SFDD(str,flt,dec1,dec2) \ - if (gsDebug) { \ - printf((str),(flt),(dec1),(dec2)); \ - } - -#define TDBG_SDF(str,dec,flt) \ - if (gsDebug) { \ - printf((str),(dec),(flt)); \ - } - -#define TDBG_SDFDDD(str,dec1,flt,dec2,dec3,dec4) \ - if (gsDebug) { \ - printf((str),(dec1),(flt),(dec2),(dec3),(dec4)); \ - } - -#define TDBG_SD(str,dec) \ - if (gsDebug) { \ - printf((str),(dec)); \ - } - -#define TDBG_SDD(str,dec1,dec2) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2)); \ - } - -#define TDBG_SDDD(str,dec1,dec2,dec3) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(dec3)); \ - } - -#define TDBG_SDFD(str,dec1,flt,dec2) \ - if (gsDebug) { \ - printf((str),(dec1),(flt),(dec2)); \ - } - -#define TDBG_SDDF(str,dec1,dec2,flt) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(flt)); \ - } - -#define TDBG_SDDDD(str,dec1,dec2,dec3,dec4) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(dec3),(dec4)); \ - } - -#define TDBG_SDDDF(str,dec1,dec2,dec3,flt) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(dec3),(flt)); \ - } - -#define TDBG_SDDDDD(str,dec1,dec2,dec3,dec4,dec5) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(dec3),(dec4),(dec5)); \ - } - -#define TDBG_SDDDDDD(str,dec1,dec2,dec3,dec4,dec5,dec6) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(dec3),(dec4),(dec5),(dec6)); \ - } - -#define TDBG_SDD_SDD(str1,dec1a,dec1b,str2,dec2a,dec2b) \ - if (gsDebug) { \ - printf((str1),(dec1a),(dec1b)); \ - printf((str2),(dec2a),(dec2b)); \ - } - -#define TDBG_SDS_SDD_SD(str1a,dec1,str1b,str2,dec2a,dec2b,str3,dec3) \ - if (gsDebug) { \ - printf((str1a),(dec1),(str1b)); \ - printf((str2),(dec2a),(dec2b)); \ - printf((str3),(dec3)); \ - } - -#define TDBG_SDS_SD(str1a,dec1,str1b,str2,dec2) \ - if (gsDebug) { \ - printf((str1a),(dec1),(str1b)); \ - printf((str2),(dec2)); \ - } - -#define TDBG_WIDTHS1() \ - if (PR_TRUE == gsDebug) { \ - printf ("BalanceColumnWidths with aMaxWidth = %d, availWidth = %d\n", aMaxWidth, availWidth); \ - printf ("\t\t specifiedTW = %d, min/maxTW = %d %d\n", specifiedTableWidth, mMinTableWidth, mMaxTableWidth); \ - printf ("\t\t reflow reason = %d\n", aReflowState.reason); \ - } - -#define TDBG_WIDTHS2(string) \ - if (PR_TRUE == gsDebug) { \ - printf("\n%p: %s\n", (string), mTableFrame); \ - for (PRInt32 i=0; iGetColumnWidth(i)); \ - } \ - printf("\n"); \ - } - -#define TDBG_WIDTHS4(string,haveShrinkFit,shrinkFit) \ - if (PR_TRUE == gsDebug) { \ - nscoord tableWidth = 0; \ - printf((string)); \ - for (PRInt32 i = 0; i < mNumCols; i++) { \ - tableWidth += mTableFrame->GetColumnWidth(i); \ - printf(" %d ", mTableFrame->GetColumnWidth(i)); \ - } \ - printf ("\n computed table width is %d",tableWidth); \ - if ((haveShrinkFit)) { \ - printf(" with aShrinkFixedCols = %s", shrinkFit ? "TRUE" : "FALSE"); \ - } \ - printf("\n"); \ - } - -/* ---------- ProportionalColumnLayoutStruct ---------- */ -// TODO: make public so other subclasses can use it - -/** useful info about a column for layout of tables with colspans */ -struct ProportionalColumnLayoutStruct -{ - ProportionalColumnLayoutStruct(PRInt32 aColIndex, - nscoord aMinColWidth, - nscoord aMaxColWidth, - PRInt32 aProportion) - { - mColIndex = aColIndex; - mMinColWidth = aMinColWidth; - mMaxColWidth = aMaxColWidth; - mProportion = aProportion; - }; - - PRInt32 mColIndex; - nscoord mMinColWidth; - nscoord mMaxColWidth; - PRInt32 mProportion; -}; - - -/* ---------- ColSpanStruct ---------- */ -/** useful info about a column for layout of tables with colspans */ -struct ColSpanStruct -{ - PRInt32 colIndex; - PRInt32 colSpan; - nscoord width; - - ColSpanStruct(PRInt32 aSpan, PRInt32 aIndex, nscoord aWidth) - { - colSpan = aSpan; - colIndex = aIndex; - width = aWidth; - } -}; - - - +#ifdef gsDebug +static PRInt32 debugCount = 0; +#endif /* ---------- BasicTableLayoutStrategy ---------- */ @@ -221,11 +48,11 @@ BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame, PRBool { NS_ASSERTION(nsnull != aFrame, "bad frame arg"); - mTableFrame = aFrame; - mMinTableWidth = 0; - mMaxTableWidth = 0; - mFixedTableWidth = 0; - mIsNavQuirksMode = aIsNavQuirks; + mTableFrame = aFrame; + mMinTableContentWidth = 0; + mMaxTableContentWidth = 0; + mCellSpacingTotal = 0; + mIsNavQuirksMode = aIsNavQuirks; } BasicTableLayoutStrategy::~BasicTableLayoutStrategy() @@ -236,22 +63,18 @@ PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, PRInt32 aNumCols, nscoord aMaxWidth) { -#ifdef NS_DEBUG - nsIFrame* tablePIF = nsnull; - mTableFrame->GetPrevInFlow(&tablePIF); - NS_ASSERTION(nsnull == tablePIF, "never ever call me on a continuing frame!"); -#endif + ContinuingFrameCheck(); PRBool result = PR_TRUE; // re-init instance variables - mNumCols = aNumCols; - mMinTableWidth = 0; - mMaxTableWidth = 0; - mFixedTableWidth = 0; - mCols = mTableFrame->GetEffectiveCOLSAttribute(); + mNumCols = aNumCols; + mMinTableContentWidth = 0; + mMaxTableContentWidth = 0; + mCellSpacingTotal = 0; + mCols = mTableFrame->GetEffectiveCOLSAttribute(); - // Step 1 - assign the width of all fixed-width columns + // assign the width of all fixed-width columns AssignPreliminaryColumnWidths(aMaxWidth); // set aMaxElementSize here because we compute mMinTableWidth in AssignPreliminaryColumnWidths @@ -275,1853 +98,978 @@ void BasicTableLayoutStrategy::SetMaxElementSize(nsSize* aMaxElementSize) nsMargin padding; tableSpacing->GetPadding(padding); borderPadding += padding; + nscoord horBorderPadding = borderPadding.left + borderPadding.right; if (tablePosition->mWidth.GetUnit() == eStyleUnit_Coord) { aMaxElementSize->width = tablePosition->mWidth.GetCoordValue(); - aMaxElementSize->width = PR_MAX(aMaxElementSize->width, mMinTableWidth); - //XXX: need to factor in borderpadding here! + if (mMinTableContentWidth + horBorderPadding > aMaxElementSize->width) { + aMaxElementSize->width = mMinTableContentWidth + horBorderPadding; + } } else { - aMaxElementSize->width = mMinTableWidth + borderPadding.left + borderPadding.right; + aMaxElementSize->width = mMinTableContentWidth + horBorderPadding; } - TDBG_SPD("%p BTLS::Init setting aMaxElementSize->width = %d\n", mTableFrame, aMaxElementSize->width); } } -PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableStyle, - const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth) +void BasicTableLayoutStrategy::ContinuingFrameCheck() { #ifdef NS_DEBUG - nsIFrame *tablePIF = nsnull; + nsIFrame* tablePIF = nsnull; mTableFrame->GetPrevInFlow(&tablePIF); - NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!"); + NS_ASSERTION(!tablePIF, "never ever call me on a continuing frame!"); #endif - - PRBool result; - - NS_ASSERTION(nsnull != aTableStyle, "bad arg"); - if (nsnull==aTableStyle) { - return PR_FALSE; - } - - nscoord specifiedTableWidth = 0; // not cached as a data member because it can vary depending on aMaxWidth - PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(mTableFrame, aTableStyle, aReflowState, specifiedTableWidth); - // HACK! Fix TableIsAutoWidth to return the right width - specifiedTableWidth = PR_MIN(specifiedTableWidth,aMaxWidth); - if (NS_UNCONSTRAINEDSIZE == specifiedTableWidth) { - specifiedTableWidth = 0; - tableIsAutoWidth = PR_TRUE; - } - - // Step 2 - determine how much space is really available - nscoord availWidth = aMaxWidth; // start with the max width I've been given - if (NS_UNCONSTRAINEDSIZE != availWidth) { // if that's not infinite, subtract the fixed columns - availWidth -= mFixedTableWidth; - } // that have already been accounted for - if (PR_FALSE == tableIsAutoWidth) { // if the table has a specified width - availWidth = specifiedTableWidth - mFixedTableWidth; // use it, minus the fixed columns already accounted for - } - //if (0!=mMinTableWidth && mMinTableWidth>availWidth) // if the computed available size is too small - //availWidth = mMinTableWidth; // bump it up to the min - availWidth = PR_MAX(0,availWidth); // avail width can never be negative - - // Step 3 - assign the width of all proportional-width columns in the remaining space - TDBG_WIDTHS1(); - TDBG_WIDTHS2("BEGIN BALANCE COLUMN WIDTHS\n"); - - result = BalanceProportionalColumns(aReflowState, availWidth, aMaxWidth, - specifiedTableWidth, tableIsAutoWidth); - - TDBG_WIDTHS2("END BALANCE COLUMN WIDTHS\n"); - -#ifdef NS_DEBUG // sanity check for table column widths - for (PRInt32 i=0; iGetColumnFrame(i, colFrame); - nscoord minColWidth = colFrame->GetMinColWidth(); - nscoord assignedColWidth = mTableFrame->GetColumnWidth(i); - NS_ASSERTION(assignedColWidth >= minColWidth, "illegal width assignment"); - } -#endif - - return result; } -nscoord BasicTableLayoutStrategy::CalcHorizontalPadding(PRInt32 aColX) +PRBool BCW_Wrapup(BasicTableLayoutStrategy* aStrategy, + nsTableFrame* aTableFrame, + PRInt32* aAllocTypes) { - nscoord maxLeftPadding = 0; // max left padding for cells starting in this col - nscoord maxRightPadding = 0; // max right padding for cells ending in this col - PRInt32 numRows = mTableFrame->GetRowCount(); - - for (PRInt32 rowX = 0; rowX < numRows; rowX++) { - nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(rowX, aColX); - if (nsnull == cellFrame) { // there is no cell in this row that corresponds to this column - continue; - } - PRInt32 cellRowX; - cellFrame->GetRowIndex(cellRowX); - if (rowX != cellRowX) { // don't do anything except for 1st row this cell is in - continue; - } - const nsStyleSpacing* spacing; - cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); - nsMargin marg; - spacing->CalcPaddingFor(cellFrame, marg); - maxLeftPadding = PR_MAX(maxLeftPadding, marg.left); - - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(aColX, cellFrame); - - nsStyleCoord coord; - PRInt32 cellColX; - cellFrame->GetColIndex(cellColX); - if (aColX != cellColX) { // the cell does not originate in this col - if (-1 == aColX - cellColX - colSpan) { // the cell ends in this col - spacing->mPadding.GetLeft(coord); - maxRightPadding = PR_MAX(maxLeftPadding, marg.right); - } - continue; - } - if (1 == colSpan) { // the cell ends in this col - maxRightPadding = PR_MAX(maxLeftPadding, marg.right); - } - } - return maxLeftPadding + maxRightPadding; -} - -// 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(nscoord aMaxWidth) -{ - TDBG_SP("** %p: AssignPreliminaryColumnWidths **\n", mTableFrame); - nsVoidArray *spanList = nsnull; - nsVoidArray *colSpanList = nsnull; - - PRBool hasColsAttribute = (PRBool)(NS_STYLE_TABLE_COLS_NONE != mCols); - - PRInt32 *minColWidthArray = nsnull; // used for computing the effect of COLS attribute - PRInt32 *maxColWidthArray = nsnull; // used for computing the effect of COLS attribute - if (PR_TRUE == hasColsAttribute) { - minColWidthArray = new PRInt32[mNumCols]; - maxColWidthArray = new PRInt32[mNumCols]; - } - - PRInt32 numRows = mTableFrame->GetRowCount(); - PRInt32 colIndex, rowIndex; - PRInt32* horPadding = new PRInt32[mNumCols]; - - // for every column, determine it's min and max width, and keep track of the table width - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - nscoord minColWidth = 0; // min col width factoring in table attributes - nscoord minColContentWidth = 0; // min width of the col's contents, does not take into account table attributes - nscoord maxColWidth = 0; // max col width factoring in table attributes - nscoord effectiveMinColumnWidth = 0; // min col width ignoring cells with colspans - nscoord effectiveMaxColumnWidth = 0; // max col width ignoring cells with colspans - nscoord specifiedFixedColWidth = 0; // the width of the column if given stylistically (or via cell Width attribute) - // only applicable if haveColWidth==PR_TRUE - - horPadding[colIndex] = 0; - // Get column information - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - TDBG_SDD("BTLS::APCW - got colFrame %p for colIndex %d\n", colFrame, colIndex); - NS_ASSERTION(nsnull != colFrame, "bad col frame"); - - // Get the columns's style - const nsStylePosition* colPosition; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - const nsStyleTable* colTableStyle; - colFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct*&)colTableStyle); - - // Get fixed column width if it has one - if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { - colFrame->SetHasConstrainedWidth(PR_TRUE); - specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); - horPadding[colIndex] = CalcHorizontalPadding(colIndex); - specifiedFixedColWidth += horPadding[colIndex]; - TDBG_SD("BTLS::APCW - got specified col width = %d\n", specifiedFixedColWidth); - } - - /* Scan the column, simulatneously assigning column widths - * and computing the min/max column widths - */ - PRInt32 firstRowIndex = -1; - PRInt32 maxColSpan = 1; - PRBool cellGrantingWidth = PR_TRUE; - for (rowIndex = 0; rowIndex < numRows; rowIndex++) { - nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex); - if (nsnull == cellFrame) { // there is no cell in this row that corresponds to this column - continue; - } - if (-1 == firstRowIndex) { - firstRowIndex = rowIndex; - } - PRInt32 cellRowIndex; - cellFrame->GetRowIndex(cellRowIndex); - if (rowIndex != cellRowIndex) { - // For cells that span rows, we only figure it in once - NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check - continue; - } - - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); - maxColSpan = PR_MAX(maxColSpan,colSpan); - - PRInt32 cellColIndex; - cellFrame->GetColIndex(cellColIndex); - if (colIndex != cellColIndex) { - // For cells that span cols, we figure in the row using previously-built SpanInfo - NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match col span"); // sanity check - continue; - } - - nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); - nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); - nscoord cellDesiredWidth = cellDesiredSize.width; - nscoord cellMinWidth = cellMinSize.width; - - if (1 == colSpan) { - minColContentWidth = (0 == minColContentWidth) - ? cellMinWidth : PR_MAX(minColContentWidth, cellMinWidth); - } - else { - minColContentWidth = PR_MAX(minColContentWidth, cellMinWidth/colSpan); // no need to divide this proportionately - } - TDBG_SDDDDDD("for cell %d with colspan=%d, min = %d,%d and des = %d,%d\n", - rowIndex, colSpan, cellMinSize.width, cellMinSize.height, - cellDesiredSize.width, cellDesiredSize.height); - - if (colFrame->HasConstrainedWidth()) { - // This col has a specified coord fixed width, so set the min and max width to the larger of - // (specified width, largest max_element_size of the cells in the column) - // factoring in the min width of the prior cells (stored in minColWidth) - nscoord widthForThisCell = specifiedFixedColWidth; - if (0 == specifiedFixedColWidth) { // set to min - specifiedFixedColWidth = cellMinWidth; - } - widthForThisCell = PR_MAX(widthForThisCell, effectiveMinColumnWidth); - if (1 == colSpan) { - widthForThisCell = PR_MAX(widthForThisCell, cellMinWidth); - } - mTableFrame->SetColumnWidth(colIndex, widthForThisCell); - maxColWidth = widthForThisCell; - minColWidth = PR_MAX(minColWidth, cellMinWidth); - if (1 == colSpan) { - effectiveMaxColumnWidth = PR_MAX(effectiveMaxColumnWidth, widthForThisCell); - if (0 == effectiveMinColumnWidth) { - effectiveMinColumnWidth = cellMinWidth;//widthForThisCell; - } - else { - //effectiveMinColumnWidth = PR_MIN(effectiveMinColumnWidth, widthForThisCell); - //above line works for most tables, but it can't be right - effectiveMinColumnWidth = PR_MAX(effectiveMinColumnWidth, cellMinWidth); - //above line seems right and works for xT1, but breaks lots of other tables. - } - } - } - else { - if (maxColWidth < cellDesiredWidth) { - maxColWidth = cellDesiredWidth; - } - if ((1==colSpan) && (effectiveMaxColumnWidth < cellDesiredWidth)) { - effectiveMaxColumnWidth = cellDesiredWidth; - } - if (minColWidth < cellMinWidth) { - minColWidth = cellMinWidth; - } - // effectiveMinColumnWidth is the min width as if no cells with colspans existed - if ((1==colSpan) && (effectiveMinColumnWidth < cellMinWidth)) { - effectiveMinColumnWidth = cellMinWidth; - } - } - - if (1 < colSpan) { - // add the column to our list of post-process columns, if all of the intersected columns are auto - PRBool okToAdd = PR_TRUE; - if (numRows == 1 || (PR_FALSE == IsFixedWidth(colPosition, colTableStyle))) { - okToAdd = PR_FALSE; - } - else { - for (PRInt32 i = 1; i < colSpan; i++) { - nsTableColFrame* cf; - mTableFrame->GetColumnFrame(i+colIndex, cf); - const nsStylePosition* colPos; - cf->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPos); - if (colPos->mWidth.GetUnit() != eStyleUnit_Auto && - (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=cf->GetWidthSource())) { - okToAdd = PR_FALSE; - break; - } - } - } - - nscoord width = cellDesiredSize.width; // used below as the cell's "natural" width - if (eStyleUnit_Coord == colTableStyle->mSpanWidth.GetUnit()) { - width = colSpan * colTableStyle->mSpanWidth.GetCoordValue(); // "colSpan*" because table frame divided per column spanned - } - if (PR_TRUE == okToAdd) { - nscoord colwidth = PR_MAX(width, cellMinWidth); - ColSpanStruct* colSpanInfo = new ColSpanStruct(colSpan, colIndex, colwidth); - if (nsnull == colSpanList) { - colSpanList = new nsVoidArray(); - } - colSpanList->AppendElement(colSpanInfo); - } - - if (PR_TRUE == cellGrantingWidth) { - // add the cell to our list of spanning cells - SpanInfo* spanInfo = new SpanInfo(colIndex, colSpan, cellMinWidth, width); - if (nsnull == spanList) { - spanList = new nsVoidArray(); - } - spanList->AppendElement(spanInfo); - } - } - - // bookkeeping: is this the cell that gave the column it's fixed width attribute? - // must be done after "haveColWidth && cellGrantingWidth" used above - // since we want the biggest, I don't think this is valid anymore - // it made sense when the rule was to grab the first cell that contributed a width - //if (PR_TRUE==cellGrantingWidth) - //{ - // const nsStylePosition* cellPosition; - // cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); - // if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) - // cellGrantingWidth=PR_FALSE; //I've found the cell that gave the col it's width - //} - - // book 'em, Danno - TDBG_SDDD(" after cell %d, minColWidth = %d and maxColWidth = %d\n", - rowIndex, minColWidth, maxColWidth); - } // end for (rowIndex = 0; rowIndex < numRows; rowIndex++) - - // adjust the "fixed" width for content that is too wide - if (colFrame->HasConstrainedWidth() && (effectiveMinColumnWidth > specifiedFixedColWidth)) { - specifiedFixedColWidth = effectiveMinColumnWidth; - } - // do all the global bookkeeping, factoring in margins - nscoord colInset = mTableFrame->GetCellSpacingX(); - // keep a running total of the amount of space taken up by all fixed-width columns - if ((colFrame->HasConstrainedWidth()) && - (nsTableColFrame::eWIDTH_SOURCE_CELL == colFrame->GetWidthSource())) { - mFixedTableWidth += specifiedFixedColWidth + colInset; - if (0 == colIndex) { - mFixedTableWidth += colInset; - } - TDBG_SD("setting mFixedTableWidth=%d\n", mFixedTableWidth); - } - - // cache the computed column info - colFrame->SetMinColWidth(effectiveMinColumnWidth); - colFrame->SetMaxColWidth(effectiveMaxColumnWidth); - colFrame->SetEffectiveMinColWidth(effectiveMinColumnWidth); - colFrame->SetEffectiveMaxColWidth(effectiveMaxColumnWidth); - // this is the default, the real adjustment happens below where we deal with colspans - colFrame->SetAdjustedMinColWidth(effectiveMinColumnWidth); - if ((colFrame->HasConstrainedWidth()) && - (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=colFrame->GetWidthSource())) { - mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); - } - else { - mTableFrame->SetColumnWidth(colIndex, effectiveMaxColumnWidth); - } - TDBG_SDD("col %d, set col width to = %d\n", colIndex, mTableFrame->GetColumnWidth(colIndex)); - - if (PR_TRUE == hasColsAttribute) { - minColWidthArray[colIndex] = minColWidth; - maxColWidthArray[colIndex] = maxColWidth; - } - TDBG_SDDDD("after col %d, minColWidth=%d effectiveMinColumnWidth=%d\n\teffectiveMaxColumnWidth = %d\n", - colIndex, minColWidth, effectiveMinColumnWidth, effectiveMaxColumnWidth); - } - - // now, post-process the computed values based on the table attributes - - // first, factor in max values of spanning cells proportionately. - // We can't do this above in the first loop, because we don't have enough information - // to determine the proportion each column gets from spanners. - if (nsnull != spanList) { - // we only want to do this if there are auto-cells involved - // or if we have columns that are provisionally fixed-width with colspans - PRInt32 numAutoColumns=0; - PRInt32* autoColumns=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); - // for every column, handle spanning cells that impact that column - for (colIndex=0; colIndexCount(); - // go through the list backwards so we can delete easily - for (PRInt32 spanIndex = spanCount-1; 0 <= spanIndex; spanIndex--) { - // get each spanInfo struct and see if it impacts this column - SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex)); - // if the spanInfo is about a column before the current column, it effects - // the current column (otherwise it would have already been deleted.) - if (spanInfo->initialColIndex <= colIndex) { - if (-1 == spanInfo->effectiveMaxWidthOfSpannedCols) { - // if we have not yet computed effectiveMaxWidthOfSpannedCols, do it now - // first, initialize the sums - spanInfo->effectiveMaxWidthOfSpannedCols = 0; - spanInfo->effectiveMinWidthOfSpannedCols = 0; - // then compute the sums - for (PRInt32 span=0; span < spanInfo->initialColSpan; span++) { - nsTableColFrame* nextColFrame = mTableFrame->GetColFrame(colIndex+span); - if (nsnull==nextColFrame) { - break; - } - spanInfo->effectiveMaxWidthOfSpannedCols += nextColFrame->GetEffectiveMaxColWidth(); - spanInfo->effectiveMinWidthOfSpannedCols += nextColFrame->GetEffectiveMinColWidth(); - } - TDBG_SDD("effective min total = %d, max total = %d\n", - spanInfo->effectiveMinWidthOfSpannedCols, spanInfo->effectiveMaxWidthOfSpannedCols); - } - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - nscoord colMinWidth = colFrame->GetMinColWidth(); - - // compute the spanning cell's contribution to the column min width - // this is the "adjusted" column width, used in SetTableToMinWidth - nscoord spanCellMinWidth; - if (0 != spanInfo->effectiveMinWidthOfSpannedCols) { - float percent = ((float)(colFrame->GetEffectiveMinColWidth())) / - ((float)(spanInfo->effectiveMinWidthOfSpannedCols)); - spanCellMinWidth = NSToCoordRound(((float)(spanInfo->cellMinWidth)) * percent); - TDBG_SDFDDD("spanCellMinWidth portion = %d from percent=%f, cellMW=%d, effMinColW=%d, sum=%d\n", - spanCellMinWidth, percent, spanInfo->cellMinWidth, colFrame->GetEffectiveMinColWidth(), - spanInfo->effectiveMinWidthOfSpannedCols); - if (colMinWidth < spanCellMinWidth) { - colFrame->SetAdjustedMinColWidth(spanCellMinWidth); // set the new min width for the col - } - } - else { - spanCellMinWidth = spanInfo->cellMinWidth / spanInfo->initialColSpan; - if (colMinWidth < spanCellMinWidth) { - colFrame->SetAdjustedMinColWidth(spanCellMinWidth); - } - } - - // compute the spanning cell's contribution to the column max width - nscoord colMaxWidth = colFrame->GetMaxColWidth(); - nscoord spanCellMaxWidth; - if (0 != spanInfo->effectiveMaxWidthOfSpannedCols) { - float percent = ((float)(colFrame->GetEffectiveMaxColWidth())) / - ((float)(spanInfo->effectiveMaxWidthOfSpannedCols)); - spanCellMaxWidth = NSToCoordRound(((float)(spanInfo->cellDesiredWidth)) * percent); - TDBG_SDFDDD("spanCellMaxWidth portion = %d with percent = %f from cellDW = %d, effMaxColW=%d and sum=%d\n", - spanCellMaxWidth, percent, spanInfo->cellDesiredWidth, colFrame->GetEffectiveMaxColWidth(), - spanInfo->effectiveMaxWidthOfSpannedCols); - if (colMaxWidth < spanCellMaxWidth) { - // make sure we're at least as big as our min - spanCellMaxWidth = PR_MAX(spanCellMaxWidth, colMinWidth); - colFrame->SetMaxColWidth(spanCellMaxWidth); // set the new max width for the col - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); // set the column to the new desired max width - TDBG_SDDDD("for spanning cell into col %d with remaining span=%d, old max = %d, new max = %d\n", - colIndex, spanInfo->span, colMaxWidth, spanCellMaxWidth); - } - } - else { - spanCellMaxWidth = spanInfo->cellDesiredWidth / spanInfo->initialColSpan; - nscoord minColWidth = colFrame->GetMinColWidth(); - spanCellMaxWidth = PR_MAX(spanCellMaxWidth, minColWidth); - colFrame->SetMaxColWidth(spanCellMaxWidth); - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); - TDBG_SDDDD(" for spanning cell into col %d with remaining span=%d, old max = %d, new max = %d\n", - colIndex, spanInfo->span, colMaxWidth, spanCellMaxWidth); - } - - spanInfo->span--; - if (0==spanInfo->span) { - spanList->RemoveElementAt(spanIndex); - delete spanInfo; - } - - // begin code that respects column width attribute - /* the code below checks to see if the column has a width attribute (either it's own or a cell's) - * if so, if it fits within the constraints we computed above, we use it. - * why go through all that pain above, then? because the given width attribute might not - * be rational. So we need to act as if it doesn't exist and then fit it in if it makes sense. - * a shortcut that checks for a column width attribute and skips the above computations - * would not work without lots of extra computation that would lead you down the same path anyway. - */ - const nsStylePosition* colPosition; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - // Get fixed column width if it has one - if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { - if (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=colFrame->GetWidthSource()) { - nscoord specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); - specifiedFixedColWidth += horPadding[colIndex]; - if (specifiedFixedColWidth>=colFrame->GetEffectiveMinColWidth()) { - mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); - colFrame->SetMaxColWidth(specifiedFixedColWidth); - } - } - } - // end code that respects column width attribute - } - } - } - } - delete [] horPadding; - - // now set the min and max table widths - SetMinAndMaxTableWidths(); - - // then, handle the COLS attribute (equal column widths) - // if there is a COLS attribute, fix up mMinTableWidth and mMaxTableWidth - if (PR_TRUE == hasColsAttribute) { - TDBG_SD("has COLS attribute = %d\n", mCols); - // for every effected column, subtract out its prior contribution and add back in the new value - PRInt32 numColsEffected = mNumCols; - if (NS_STYLE_TABLE_COLS_ALL != mCols) { - numColsEffected = mCols; - } - PRInt32 maxOfMinColWidths = 0; - PRInt32 maxOfMaxColWidths = 0; - PRInt32 effectedColIndex; - for (effectedColIndex=0; effectedColIndexGetColumnFrame(effectedColIndex, colFrame); - colFrame->SetMaxColWidth(maxOfMaxColWidths); // cache the new column max width (min width is uneffected) - colFrame->SetEffectiveMaxColWidth(maxOfMaxColWidths); - TDBG_SDD("col %d now has max col width %d\n", effectedColIndex, maxOfMaxColWidths); - } - delete [] minColWidthArray; - delete [] maxColWidthArray; - } - if (nsnull != colSpanList) { - DistributeFixedSpace(colSpanList); - } - - TDBG_SPDD("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, mMinTableWidth, mMaxTableWidth); - - // clean up - if (nsnull != spanList) { - TDBG_S("BTLS::APCW...space leak, span list not empty\n"); - delete spanList; - } - if (nsnull != colSpanList) { - PRInt32 colSpanListCount = colSpanList->Count(); - for (PRInt32 i = 0; i < colSpanListCount; i++) { - ColSpanStruct * colSpanInfo = (ColSpanStruct *)(colSpanList->ElementAt(i)); - if (nsnull != colSpanInfo) { - delete colSpanInfo; - } - } - delete colSpanList; - } + delete [] aAllocTypes; + //aStrategy->Dump(0); + //aTableFrame->Dump(PR_TRUE, PR_FALSE); return PR_TRUE; } -void BasicTableLayoutStrategy::SetMinAndMaxTableWidths() +PRBool +BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableStyle, + const nsHTMLReflowState& aReflowState, + nscoord aMaxWidthIn) { - TDBG_S("SetMinAndMaxTableWidths\n"); - PRInt32 colIndex, rowIndex; - PRInt32 numRows = mTableFrame->GetRowCount(); - nscoord colInset = mTableFrame->GetCellSpacingX(); - for (rowIndex = 0; rowIndex < numRows; rowIndex++) { - TDBG_SD(" row %d\n", rowIndex); - nscoord rowMinWidth = colInset; - nscoord rowMaxWidth = colInset; - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - TDBG_SD(" col %d\n", colIndex); - nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex); - rowMinWidth += colInset; - rowMaxWidth += colInset; - if (nsnull == cellFrame) { // there is no cell in this row that corresponds to this column - TDBG_SD(" col %d skipped because there is no cell\n", colIndex); - continue; - } - PRInt32 cellColIndex; - cellFrame->GetColIndex(cellColIndex); - if (colIndex != cellColIndex) { - // For cells that span cols, we figured in the cell the first time we saw it - TDBG_SD(" col %d skipped because it has colspan so we've already added it in\n", colIndex); - continue; - } - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); - nscoord cellMinWidth = PR_MAX(cellMinSize.width, colFrame->GetEffectiveMinColWidth()); - nsSize cellMaxSize = cellFrame->GetPass1DesiredSize(); - nscoord cellMaxWidth = PR_MAX(cellMaxSize.width, colFrame->GetEffectiveMaxColWidth()); - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); - nscoord spanningCellMinWidth = (colSpan-1)*colInset; - TDBG_SDDD(" cellMin=%d, cellMax=%d, spanningCellMin=%d\n", - cellMinWidth, cellMaxWidth, spanningCellMinWidth); - // spanning cells must be at least as wide as the columns they span, including the cell spacing spanned. - if (NS_UNCONSTRAINEDSIZE != rowMinWidth) { - rowMinWidth += PR_MAX(cellMinWidth, spanningCellMinWidth); - } - if (NS_UNCONSTRAINEDSIZE != rowMaxWidth) { - rowMaxWidth += PR_MAX(cellMaxWidth, spanningCellMinWidth); - } - TDBG_SDD(" rowMinWidth=%d, rowMaxWidth=%d\n", rowMinWidth, rowMaxWidth); - } - TDBG_SDD(" rowMinWidth=%d, rowMaxWidth=%d\n", rowMinWidth, rowMaxWidth); - // the largest row widths are the table widths - mMinTableWidth = PR_MAX(mMinTableWidth, rowMinWidth); - mMaxTableWidth = PR_MAX(mMaxTableWidth, rowMaxWidth); - TDBG_SDD(" mMinTableWidth=%d, mMaxTableWidth=%d\n", mMinTableWidth, mMaxTableWidth); + //mTableFrame->Dump(PR_TRUE, PR_TRUE); + ContinuingFrameCheck(); + if (!aTableStyle) { + NS_ASSERTION(aTableStyle, "bad style arg"); + return PR_FALSE; } - // verify max of min row widths vs. sum of adjusted column min widths. bigger one wins - nscoord sumOfAdjustedColMinWidths = colInset; - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(colIndex, colFrame); - sumOfAdjustedColMinWidths += colFrame->GetAdjustedMinColWidth() + colInset; - TDBG_SDDDD(" col %d has amcw=%d, cellspacing=%d, sum=%d\n", - colIndex, colFrame->GetAdjustedMinColWidth(), colInset, sumOfAdjustedColMinWidths); + + // determine if the table is auto/fixed and get the fixed width if available + nscoord maxWidth = aMaxWidthIn; + nscoord specifiedTableWidth = 0; + PRBool tableIsAutoWidth = + nsTableFrame::TableIsAutoWidth(mTableFrame, aTableStyle, aReflowState, specifiedTableWidth); + // a specifiedTableWidth of <= 0 indicates percentage based + if (!tableIsAutoWidth && (specifiedTableWidth > 0)) { + maxWidth = PR_MIN(specifiedTableWidth, aMaxWidthIn); // specifiedWidth usually == aMaxWidthIn for fixed table } - TDBG_SD(" sumOfAdjustedColMinWidths=%d\n", sumOfAdjustedColMinWidths); - /* - mMinTableWidth = PR_MAX(mMinTableWidth, sumOfAdjustedColMinWidths); - mMaxTableWidth = PR_MAX(mMinTableWidth, mMaxTableWidth); - */ - TDBG_SDDD("end SetMinAndMaxTW: minTW=%d, maxTW=%d with DMCW=%d\n", mMinTableWidth, mMaxTableWidth, sumOfAdjustedColMinWidths); -} - -// take the fixed space spanned by the columns in aColSpanList -// and distribute it proportionately (based on desired width) -void BasicTableLayoutStrategy::DistributeFixedSpace(nsVoidArray *aColSpanList) -{ - TDBG_S("** DistributeFixedSpace:\n"); - // for all fixed-width columns, determine the amount of the specified width each column spanned recieves - PRInt32 numSpanningCells = aColSpanList->Count(); - for (PRInt32 nextSpanningCell = 0; nextSpanningCell < numSpanningCells; nextSpanningCell++) { // proportionately distributed extra space, based on the column's fixed width - ColSpanStruct* colInfo = (ColSpanStruct *)aColSpanList->ElementAt(nextSpanningCell); - PRInt32 colIndex = colInfo->colIndex; - PRInt32 colSpan = colInfo->colSpan; - nscoord totalColWidth = colInfo->width; - - // 1. get the sum of the effective widths of the columns in the span - nscoord totalEffectiveWidth=0; - nsTableColFrame* colFrame; - PRInt32 i; - for (i = 0; iGetColumnFrame(colIndex+i, colFrame); - totalEffectiveWidth += colFrame->GetColWidthForComputation(); - } - - // 2. next, compute the proportion to be added to each column, and add it - for (i = 0; iGetColumnFrame(colIndex+i, colFrame); - float percent; - percent = ((float)(colFrame->GetColWidthForComputation())) / ((float)totalEffectiveWidth); - nscoord newColWidth = NSToCoordRound(((float)totalColWidth)*percent); - nscoord minColWidth = colFrame->GetEffectiveMinColWidth(); - nscoord oldColWidth = mTableFrame->GetColumnWidth(colIndex+i); - if (newColWidth > minColWidth) { - TDBG_SDD_SDD(" assigning fixed col width for spanning cells: column %d set to %d\n", - colIndex+i, newColWidth, - " minCW = %d oldCW = %d\n", minColWidth, oldColWidth); - mTableFrame->SetColumnWidth(colIndex+i, newColWidth); - colFrame->SetEffectiveMaxColWidth(newColWidth); - } + // reduce the maxWidth by border and padding in some cases, since we will be dealing with content width + if (!tableIsAutoWidth && (maxWidth != NS_UNCONSTRAINEDSIZE)) { + const nsStylePosition* position; + mTableFrame->GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)position)); + if (eStyleUnit_Percent != position->mWidth.GetUnit()) { + const nsStyleSpacing* spacing; + mTableFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); + nsMargin borderPadding; + spacing->CalcBorderPaddingFor(mTableFrame, borderPadding); + maxWidth -= borderPadding.left + borderPadding.right; + maxWidth = PR_MAX(0, maxWidth); } } -} - -/* assign column widths to all non-fixed-width columns (adjusting fixed-width columns if absolutely necessary) - aAvailWidth is the amount of space left in the table to distribute after fixed-width columns are accounted for - aMaxWidth is the space the parent gave us (minus border & padding) to fit ourselves into - aTableIsAutoWidth is true if the table is auto-width, false if it is anything else (percent, fixed, etc) - */ -PRBool BasicTableLayoutStrategy:: - BalanceProportionalColumns (const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aTableSpecifiedWidth, - PRBool aTableIsAutoWidth) -{ - PRBool result = PR_TRUE; - - nscoord actualMaxWidth; // the real target width, depends on if we're auto or specified width - if (PR_TRUE == aTableIsAutoWidth) { - actualMaxWidth = aMaxWidth; - } else { - actualMaxWidth = PR_MIN(aMaxWidth, aTableSpecifiedWidth); - } - if (NS_UNCONSTRAINEDSIZE == aMaxWidth || NS_UNCONSTRAINEDSIZE == mMinTableWidth) { - // the max width of the table fits comfortably in the available space - TDBG_S(" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n"); - // nested tables are laid out with unconstrained width. But the underlying algorithms require a - // real width. So we pick a really big width here. It doesn't really matter, of course, because - // eventually the table will be laid out with a constrained width. - nscoord bigSpace = gBigSpace; - bigSpace = PR_MAX(bigSpace, mMaxTableWidth); - result = BalanceColumnsTableFits(aReflowState, bigSpace, bigSpace, - aTableSpecifiedWidth, aTableIsAutoWidth); - } - else if (mMinTableWidth > actualMaxWidth) { - // the table doesn't fit in the available space - TDBG_S(" * table minTW does not fit, calling BalanceColumnsTableDoesNotFit\n"); - result = BalanceColumnsTableDoesNotFit(); - } - else if (mMaxTableWidth <= actualMaxWidth) { - // the max width of the table fits comfortably in the available space - TDBG_S(" * table desired size fits, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aReflowState, aAvailWidth, aMaxWidth, - aTableSpecifiedWidth, aTableIsAutoWidth); - } - else { - // the table fits somewhere between its min and desired size - TDBG_S(" * table desired size does not fit, calling BalanceColumnsConstrained\n"); - result = BalanceColumnsConstrained(aReflowState, aAvailWidth, - actualMaxWidth, aTableIsAutoWidth); + // set the table's columns to the min width + // initialize the col percent and cell percent values to 0. + PRInt32 colX; + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord colMinWidth = colFrame->GetMinWidth(); + mTableFrame->SetColumnWidth(colX, colMinWidth); + colFrame->SetWidth(PCT, WIDTH_NOT_SET); + colFrame->SetWidth(PCT_ADJ, WIDTH_NOT_SET); } - return result; -} + // if the max width available is less than the min content width for fixed table, we're done + if (!tableIsAutoWidth && (maxWidth < mMinTableContentWidth)) { + return PR_FALSE; + } -// the table doesn't fit, so squeeze every column down to its minimum -PRBool BasicTableLayoutStrategy::BalanceColumnsTableDoesNotFit() -{ - PRBool result = PR_TRUE; + // set PCT and PCT_ADJ widths on col frames and for an auto table return + // a new table width based on percent cells/cols if they exist + nscoord perAdjTableWidth = (maxWidth != NS_UNCONSTRAINEDSIZE) + ? AssignPercentageColumnWidths(maxWidth - mCellSpacingTotal, tableIsAutoWidth) : 0; - PRBool hasColsAttribute = (PRBool)(NS_STYLE_TABLE_COLS_NONE!=mCols); + // if the max width available is less than the min content width for auto table + // that had no % cells/cols, we're done + if (tableIsAutoWidth && (maxWidth < mMinTableContentWidth) & (0 == perAdjTableWidth)) { + return PR_TRUE; + } + + PRInt32 cellSpacingTotal; + // the following are of size NUM_WIDTHS, but only MIN_CON, DES_CON, FIX, PCT + // are used and they account for colspan ADJusted values + PRInt32 totalWidths[NUM_WIDTHS]; // sum of col widths of a particular type + PRInt32 totalCounts[NUM_WIDTHS]; // num of cols of a particular type + PRInt32 minWidths[NUM_WIDTHS]; + PRInt32 num0Proportional; + + CalculateTotals(cellSpacingTotal, totalCounts, totalWidths, minWidths, num0Proportional); + // auto width table's adjusted width needs cell spacing + if (tableIsAutoWidth && perAdjTableWidth > 0) { + perAdjTableWidth = PR_MIN(perAdjTableWidth + cellSpacingTotal, maxWidth); + } + nscoord totalAllocated = totalWidths[MIN_CON] + cellSpacingTotal; - PRInt32* minColWidthArray = nsnull; - if (PR_TRUE == hasColsAttribute) { - minColWidthArray = new PRInt32[mNumCols]; - } - - for (PRInt32 colIndex = 0; colIndex < mNumCols; colIndex++) { - nscoord minAdjustedColWidth = 0; - TDBG_SD(" for col %d\n", colIndex); - - nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex); - NS_ASSERTION(nsnull != colFrame, "bad col frame"); - - // Get the columns's style - const nsStylePosition* colPosition; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - const nsStyleTable* colTableStyle; - colFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct*&)colTableStyle); - //if (PR_FALSE==IsFixedWidth(colPosition, colTableStyle)) - { - minAdjustedColWidth = colFrame->GetAdjustedMinColWidth(); - mTableFrame->SetColumnWidth(colIndex, minAdjustedColWidth); - if (PR_TRUE == hasColsAttribute) { - minColWidthArray[colIndex] = minAdjustedColWidth; - } - } - TDBG_SDD(" 2: col %d, set to width = %d\n", colIndex, mTableFrame->GetColumnWidth(colIndex)); - } - - // now, post-process the computed values based on the table attributes - // if there is a COLS attribute, fix up mMinTableWidth and mMaxTableWidth - if (PR_TRUE == hasColsAttribute) { // for every effected column, subtract out its prior contribution and add back in the new value - PRInt32 numColsEffected = mNumCols; - if (NS_STYLE_TABLE_COLS_ALL != mCols) { - numColsEffected = mCols; - } - nscoord maxOfEffectedColWidths = 0; - PRInt32 effectedColIndex; - // XXX need to fix this and all similar code if any fixed-width columns intersect COLS - for (effectedColIndex = 0; effectedColIndex < numColsEffected; effectedColIndex++) { - maxOfEffectedColWidths = PR_MAX(maxOfEffectedColWidths, minColWidthArray[effectedColIndex]); - } - for (effectedColIndex = 0; effectedColIndex < numColsEffected; effectedColIndex++) { - // set each effected column to the size of the largest column in the group - mTableFrame->SetColumnWidth(effectedColIndex, maxOfEffectedColWidths); - TDBG_SDD(" 2 (cols): setting %d to %d\n", effectedColIndex, maxOfEffectedColWidths); - } - // we're guaranteed here that minColWidthArray has been allocated, and that - // if we don't get here, it was never allocated - delete [] minColWidthArray; - } - return result; -} - -/* the table fits in the given space. Set all columns to their desired width, - * and if we are not an auto-width table add extra space to fluff out the total width - */ -PRBool BasicTableLayoutStrategy:: - BalanceColumnsTableFits(const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aTableSpecifiedWidth, - PRBool aTableIsAutoWidth) -{ - PRBool result = PR_TRUE; - nscoord tableWidth = 0; // the width of the table as a result of setting column widths - nscoord widthOfFixedTableColumns = 0; // the sum of the width of all fixed-width columns plus margins - // tableWidth - widthOfFixedTableColumns is the width of columns computed in this method - PRInt32 totalSlices = 0; // the total number of slices the proportional-width columns request - nsVoidArray* proportionalColumnsList = nsnull; // a list of the columns that are proportional-width - nsVoidArray* spanList = nsnull; // a list of the cells that span columns - PRInt32 numRows = mTableFrame->GetRowCount(); - nscoord colInset = mTableFrame->GetCellSpacingX(); - PRInt32 colIndex; - - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - TDBG_SD("for col %d\n", colIndex); - // Get column information - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - NS_ASSERTION(nsnull != colFrame, "bad col frame"); - PRInt32 minColWidth = colFrame->GetMinColWidth(); - PRInt32 maxColWidth = 0; - PRInt32 rowIndex; - PRInt32 firstRowIndex = -1; - - const nsStylePosition* colPosition; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - const nsStyleTable* colTableStyle; - colFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct*&)colTableStyle); - - // first, deal with any cells that span into this column from a pervious column - // go through the list backwards so we can delete easily - if (nsnull!=spanList) { - PRInt32 spanCount = spanList->Count(); - // go through the list backwards so we can delete easily - for (PRInt32 spanIndex = spanCount-1; 0 <= spanIndex; spanIndex--) { - SpanInfo* spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex)); - if (PR_FALSE == IsFixedWidth(colPosition, colTableStyle)) { - // compute the spanning cell's contribution to the column min width - nscoord spanCellMinWidth; - PRBool needsExtraMinWidth = PR_FALSE; - //if (spanInfo->effectiveMinWidthOfSpannedColscellMinWidth) - // needsExtraMinWidth = PR_TRUE; - if (PR_TRUE == needsExtraMinWidth) { - if (0 != spanInfo->effectiveMinWidthOfSpannedCols) { - spanCellMinWidth = (spanInfo->cellMinWidth * colFrame->GetEffectiveMinColWidth()) / - (spanInfo->effectiveMinWidthOfSpannedCols); - TDBG_SDD(" spanlist min: %d of %d\n", spanCellMinWidth, spanInfo->effectiveMaxWidthOfSpannedCols); - if (minColWidth < spanCellMinWidth) { - minColWidth = spanCellMinWidth; // set the new min width for the col - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new min = %d\n", - colIndex, spanInfo->span, minColWidth); - // if the new min width is greater than the desired width, bump up the desired width - maxColWidth = PR_MAX(maxColWidth, minColWidth); - TDBG_SD(" and maxColWidth = %d\n", maxColWidth); - } - } - else { - spanCellMinWidth = spanInfo->cellMinWidth / spanInfo->initialColSpan; - if (minColWidth < spanCellMinWidth) { - minColWidth = spanCellMinWidth; - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new min = %d\n", - colIndex, spanInfo->span, minColWidth); - // if the new min width is greater than the desired width, bump up the desired width - maxColWidth = PR_MAX(maxColWidth, minColWidth); - TDBG_SD(" and maxColWidth = %d\n", maxColWidth); - } - } - } - - - // compute the spanning cell's contribution to the column max width - nscoord spanCellMaxWidth; - if (0 != spanInfo->effectiveMaxWidthOfSpannedCols) { - spanCellMaxWidth = (spanInfo->cellDesiredWidth * colFrame->GetEffectiveMaxColWidth()) / - (spanInfo->effectiveMaxWidthOfSpannedCols); - TDBG_SDD(" spanlist max: %d of %d\n", spanCellMaxWidth, spanInfo->effectiveMaxWidthOfSpannedCols); - if (maxColWidth < spanCellMaxWidth) { - spanCellMaxWidth = PR_MAX(spanCellMaxWidth, minColWidth); - maxColWidth = spanCellMaxWidth; // set the new max width for the col - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); // set the column to the new desired max width - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new max = %d\n", - colIndex, spanInfo->span, maxColWidth); - } - } - else { - spanCellMaxWidth = spanInfo->cellDesiredWidth / spanInfo->initialColSpan; - maxColWidth = spanCellMaxWidth; - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new max = %d\n", - colIndex, spanInfo->span, maxColWidth); - } - } - spanInfo->span--; - if (0 == spanInfo->span) { - spanList->RemoveElementAt(spanIndex); - delete spanInfo; - } - } - } - - // second, process non-fixed-width columns - if (PR_FALSE==IsFixedWidth(colPosition, colTableStyle)) { - for (rowIndex = 0; rowIndex < numRows; rowIndex++) { - // this col has proportional width, so determine its width requirements - nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex); - if (nsnull == cellFrame) { - // there is no cell in this row that corresponds to this column - continue; - } - if (-1 == firstRowIndex) { - firstRowIndex = rowIndex; - } - PRInt32 cellRowIndex; - cellFrame->GetRowIndex(cellRowIndex); - if (rowIndex != cellRowIndex) { - // For cells that span rows, we only figure it in once - NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check - continue; - } - PRInt32 cellColIndex; - cellFrame->GetColIndex(cellColIndex); - if (colIndex != cellColIndex) { - // For cells that span cols, we figure in the row using previously-built SpanInfo - NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match row span"); // sanity check - continue; - } + // allocate and initialize arrays indicating what col gets set + PRInt32* allocTypes = new PRInt32[mNumCols]; + if (!allocTypes) return PR_FALSE; - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); - nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); - nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); - nscoord cellMinWidth=colFrame->GetMinColWidth(); - nscoord cellDesiredWidth=colFrame->GetMaxColWidth(); - // then get the desired size info factoring in the cell style attributes - if (1 == colSpan) { - cellMinWidth = cellMinSize.width; - cellDesiredWidth = cellDesiredSize.width; - nscoord specifiedCellWidth = -1; - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - if (eStyleUnit_Percent==cellPosition->mWidth.GetUnit()) { - if (PR_FALSE == aTableIsAutoWidth) { - float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(aTableSpecifiedWidth * percent); - TDBG_SFDD("specified percent width %f of %d = %d\n", - percent, aTableSpecifiedWidth, specifiedCellWidth); - } - // otherwise we need to post-process, set to max for now - // do we want to set specifiedCellWidth off of aAvailWidth? aMaxWidth? XXX - } - if (-1 != specifiedCellWidth) { - if (specifiedCellWidth>cellMinWidth) { - TDBG_SDD("setting cellDesiredWidth from %d to %d\n", cellDesiredWidth, specifiedCellWidth); - cellDesiredWidth = specifiedCellWidth; - } - } - } - else { - // colSpan>1, get the proportion for this column - // then get the desired size info factoring in the cell style attributes - nscoord effectiveMaxWidthOfSpannedCols = colFrame->GetEffectiveMaxColWidth(); - nscoord effectiveMinWidthOfSpannedCols = colFrame->GetEffectiveMinColWidth(); - for (PRInt32 span = 1; span < colSpan; span++) { - nsTableColFrame* nextColFrame = mTableFrame->GetColFrame(colIndex+span); - if (nsnull == nextColFrame) { - break; - } - effectiveMaxWidthOfSpannedCols += nextColFrame->GetEffectiveMaxColWidth(); - effectiveMinWidthOfSpannedCols += nextColFrame->GetEffectiveMinColWidth(); - } - nscoord specifiedCellWidth = -1; - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { - //XXX what if table is auto width? - float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(aTableSpecifiedWidth*percent); - TDBG_SFDD("specified percent width %f of %d = %d\n", - percent, aTableSpecifiedWidth, specifiedCellWidth); - } - if (-1 != specifiedCellWidth) { - float percentForThisCol = (float)(cellDesiredSize.width * colFrame->GetEffectiveMaxColWidth()) / - (float)effectiveMaxWidthOfSpannedCols; - nscoord cellWidthForThisCol = (nscoord)(specifiedCellWidth * percentForThisCol); - if (cellWidthForThisCol>cellMinWidth) { - TDBG_SDD("setting cellDesiredWidth from %d to %d\n", cellDesiredWidth, cellWidthForThisCol); - cellDesiredWidth = cellWidthForThisCol; - } - } - // otherwise it's already been factored in. - // now, if this column holds the cell, create a spanInfo struct for the cell - // so subsequent columns can take a proportion of this cell's space into account - cellFrame->GetColIndex(cellColIndex); - if (cellColIndex == colIndex) { - // add this cell to span list iff we are currently processing the column the cell starts in - SpanInfo* spanInfo = new SpanInfo(colIndex, colSpan-1, cellMinSize.width, cellDesiredSize.width); - spanInfo->effectiveMaxWidthOfSpannedCols = effectiveMaxWidthOfSpannedCols; - spanInfo->effectiveMinWidthOfSpannedCols = effectiveMinWidthOfSpannedCols; - if (nsnull == spanList) { - spanList = new nsVoidArray(); - } - spanList->AppendElement(spanInfo); - } - } - - TDBG_SDDDD("factoring in cell %d with colSpan=%d\n factoring in min=%d and desired=%d\n", - rowIndex, colSpan, cellMinWidth, cellDesiredWidth); - maxColWidth = PR_MAX(maxColWidth, cellDesiredWidth); - TDBG_SDDDDD(" after cell %d, minColWidth=%d maxColWidth=%d effColWidth[%d]=%d\n", - rowIndex, minColWidth, maxColWidth, - colIndex, colFrame->GetEffectiveMaxColWidth()); - } // end looping through cells in the column - - TDBG_SDS_SDD_SD(" for determining width of col %d %s:\n", - colIndex, !IsFixedWidth(colPosition, colTableStyle)? "(P)":"(A)", - " minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth, - " aAvailWidth = %d\n", aAvailWidth); - - // Get column width if it has one - nscoord specifiedProportionColumnWidth = -1; - float specifiedPercentageColWidth = -1.0f; - PRBool isAutoWidth = PR_FALSE; - switch (colPosition->mWidth.GetUnit()) { - case eStyleUnit_Percent: - specifiedPercentageColWidth = colPosition->mWidth.GetPercentValue(); - TDBG_SDF("column %d has specified percent width = %f\n", colIndex, specifiedPercentageColWidth); - break; - case eStyleUnit_Proportional: - specifiedProportionColumnWidth = colPosition->mWidth.GetIntValue(); - TDBG_SDD("column %d has specified percent width = %d\n", colIndex, specifiedProportionColumnWidth); - break; - case eStyleUnit_Auto: - isAutoWidth = PR_TRUE; - break; - default: - break; - } - - // set the column width, knowing that the table fits in the available space - if (0 == specifiedProportionColumnWidth || 0.0==specifiedPercentageColWidth) { - // col width is specified to be the minimum - mTableFrame->SetColumnWidth(colIndex, minColWidth); - TDBG_SDD(" 3 min: col %d set to min width = %d because style set proportionalWidth=0\n", - colIndex, mTableFrame->GetColumnWidth(colIndex)); - } - else if ((PR_TRUE == isAutoWidth) || - ((PR_TRUE==aTableIsAutoWidth) && (-1==specifiedProportionColumnWidth))) { - // col width is determined by the cells' content, - // so give each remaining column it's desired width (because we know we fit.) - // if there is width left over, we'll factor that in after this loop is complete - // the OR clause is because we fix up percentage widths as a post-process - // in auto-width tables - mTableFrame->SetColumnWidth(colIndex, maxColWidth); - TDBG_SDDD(" 3 auto: col %d with availWidth %d, set to width = %d\n", - colIndex, aAvailWidth, mTableFrame->GetColumnWidth(colIndex)); - } - else if (-1 != specifiedProportionColumnWidth) - { // we need to save these and do them after all other columns have been calculated - // the calculation will be: - // sum up n, the total number of slices for the columns with proportional width - // compute the table "required" width, fixed-width + percentage-width + - // the sum of the proportional column's max widths (especially because in this routine I know the table fits) - // compute the remaining width: the required width - the used width (fixed + percentage) - // compute the width per slice - // set the width of each proportional-width column to it's number of slices * width per slice - mTableFrame->SetColumnWidth(colIndex, 0); // set the column width to 0, since it isn't computed yet - if (nsnull == proportionalColumnsList) { - proportionalColumnsList = new nsVoidArray(); - } - ProportionalColumnLayoutStruct* info = - new ProportionalColumnLayoutStruct(colIndex, minColWidth, - maxColWidth, specifiedProportionColumnWidth); - proportionalColumnsList->AppendElement(info); - totalSlices += specifiedProportionColumnWidth; // keep track of the total number of proportions - TDBG_SDDDD(" 3 proportional: col %d with availWidth %d, gets %d slices with %d slices so far.\n", - colIndex, aAvailWidth, specifiedProportionColumnWidth, totalSlices); - } - else { // give the column a percentage of the remaining space - PRInt32 percentage = -1; - if (NS_UNCONSTRAINEDSIZE == aAvailWidth) { - // since the "remaining space" is infinite, give the column it's max requested size - mTableFrame->SetColumnWidth(colIndex, maxColWidth); - } - else { - if (-1.0f != specifiedPercentageColWidth) { - percentage = (PRInt32)(specifiedPercentageColWidth * 100.0f); // TODO: rounding errors? - // base the % on the total specified fixed width of the table - mTableFrame->SetColumnWidth(colIndex, (percentage*aTableSpecifiedWidth) / 100); - TDBG_SDDDD(" 3 percent specified: col %d given %d percent of aTableSpecifiedWidth %d, set to width = %d\n", - colIndex, percentage, aTableSpecifiedWidth, mTableFrame->GetColumnWidth(colIndex)); - } - if (-1 == percentage) { - percentage = 100 / mNumCols; - // base the % on the remaining available width - mTableFrame->SetColumnWidth(colIndex, (percentage*aAvailWidth) / 100); - TDBG_SDDDD(" 3 percent default: col %d given %d percent of aAvailWidth %d, set to width = %d\n", - colIndex, percentage, aAvailWidth, mTableFrame->GetColumnWidth(colIndex)); - } - // if the column was computed to be too small, enlarge the column - if (mTableFrame->GetColumnWidth(colIndex) <= minColWidth) { - mTableFrame->SetColumnWidth(colIndex, minColWidth); - TDBG_SD(" enlarging column to it's minimum = %d\n", minColWidth); - } - } - } - } - else { // need to maintain this so we know how much we have left over at the end - nscoord maxEffectiveColWidth = colFrame->GetEffectiveMaxColWidth(); - mTableFrame->SetColumnWidth(colIndex, maxEffectiveColWidth); - widthOfFixedTableColumns += maxEffectiveColWidth + colInset; - } - tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset; - } - tableWidth += colInset; - - /* --- post-process if necessary --- */ - - // XXX the following implementation does not account for borders, cell spacing, cell padding - - // first, assign column widths in auto-width tables - PRInt32 numPercentColumns = 0; - PRInt32* percentColumns=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Percent, numPercentColumns, percentColumns); - if ((PR_TRUE == aTableIsAutoWidth) && (0 != numPercentColumns)) { - // variables common to lots of code in this block - nscoord colWidth; - float percent; - const nsStylePosition* colPosition; - nsTableColFrame* colFrame; - if (numPercentColumns != mNumCols) { - TDBG_S("assigning widths to percent colums in auto-width table\n"); - nscoord widthOfPercentCells = 0; // the total width of those percent-width cells that have been given a width - nscoord widthOfOtherCells = 0; // the total width of those non-percent-width cells that have been given a width - float sumOfPercentColumns = 0.0f; // the total of the percent widths - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - // every column contributes to either widthOfOtherCells or widthOfPercentCells, but not both - if (PR_TRUE == IsColumnInList(colIndex, percentColumns, numPercentColumns)) { - colFrame = mTableFrame->GetColFrame(colIndex); - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - percent = colPosition->mWidth.GetPercentValue(); // we know this will work - sumOfPercentColumns += percent; - if (sumOfPercentColumns > 1.0f) { // values greater than 100% are meaningless - sumOfPercentColumns = 1.0f; - } - widthOfPercentCells += mTableFrame->GetColumnWidth(colIndex); - } - else { - widthOfOtherCells += mTableFrame->GetColumnWidth(colIndex); - } - } - if (0 == widthOfOtherCells) { - widthOfOtherCells = aMaxWidth; - } - TDBG_SDDF(" widthOfOtherCells=%d widthOfPercentCells = %d sumOfPercentColumns=%f\n", - widthOfOtherCells, widthOfPercentCells, sumOfPercentColumns); - float remainingPercent = 1.0f - sumOfPercentColumns; - nscoord newTableWidth; // the table width after all cells have been resized - if (1.0f == sumOfPercentColumns) { // this definately seems like a QUIRK! - newTableWidth = aMaxWidth; - } - else { // the newTableWidth is the larger of the calculation from the percent cells and non-percent cells - nscoord percentWidth = (nscoord)((1.0f/sumOfPercentColumns)*((float)(widthOfPercentCells))); - nscoord otherWidth = (nscoord)((1.0f/remainingPercent)*((float)(widthOfOtherCells))); - TDBG_SDD(" percentWidth=%d otherWidth=%d\n", percentWidth, otherWidth); - newTableWidth = PR_MAX(percentWidth, otherWidth); // the table width is the larger of the two computations - newTableWidth = PR_MIN(newTableWidth, aMaxWidth); // an auto-width table can't normally be wider than it's parent - newTableWidth = PR_MIN(newTableWidth, mMaxTableWidth);// an auto-width table can't normally be wider than it's own computed max width - } - nscoord excess = newTableWidth-mFixedTableWidth; // the amount of new space that needs to be - // accounted for in the non-fixed columns - TDBG_SD(" newTableWidth=%d \n", newTableWidth); - PRInt32 i; // just a counter - for (i = 0; i < numPercentColumns; i++) { - colIndex = percentColumns[i]; - colFrame = mTableFrame->GetColFrame(colIndex); - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - percent = colPosition->mWidth.GetPercentValue(); // we know this will work - colWidth = (nscoord)((percent) * ((float)newTableWidth)); - nscoord minColWidth = colFrame->GetEffectiveMinColWidth(); - colWidth = PR_MAX(colWidth, minColWidth); - mTableFrame->SetColumnWidth(colIndex, colWidth); - TDBG_SDFD(" col %d with percentwidth=%f set to %d\n", colIndex, percent, colWidth); - excess -= colWidth; - } - if (0 < excess) { - PRInt32 numAutoColumns=0; - PRInt32* autoColumns=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); - TDBG_SDD(" excess=%d with %d autoColumns\n", excess, numAutoColumns); - if (0 < numAutoColumns) { - nscoord excessPerColumn = excess / numAutoColumns; - for (i = 0; i < numAutoColumns; i++) { - colIndex = autoColumns[i]; - nscoord newWidth = PR_MAX(excessPerColumn, mTableFrame->GetColumnWidth(colIndex)); - TDBG_SDDD(" col %d was %d set to %d\n", - colIndex, mTableFrame->GetColumnWidth(colIndex), newWidth); - mTableFrame->SetColumnWidth(colIndex, newWidth); - excess -= excessPerColumn; - } - // handle division underflow - if (0 < excess) { - TDBG_SD(" after first pass through auto-width columns, excess=%d\n", excess); - for (i = 0; i < numAutoColumns; i++) { - colIndex = autoColumns[i]; - nscoord newWidth = 1 + mTableFrame->GetColumnWidth(colIndex); - mTableFrame->SetColumnWidth(colIndex, newWidth); - } - } - } - } - } - else { - // all columns have a percent width. Each already has its desired width. - // find the smallest percentage and base the widths of the others off that - PRInt32 indexOfSmallest; - nscoord colWidthOfSmallest; - float smallestPercent = 2.0f; // an illegal large number - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - colFrame = mTableFrame->GetColFrame(colIndex); - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - percent = colPosition->mWidth.GetPercentValue(); // we know this will work - if (percent < smallestPercent) { - smallestPercent=percent; - indexOfSmallest=colIndex; - colWidthOfSmallest = mTableFrame->GetColumnWidth(colIndex); - } - else if (percent==smallestPercent) { - // the largest desired size among equal-percent columns wins - colWidth = mTableFrame->GetColumnWidth(colIndex); - if (colWidth > colWidthOfSmallest) { - indexOfSmallest = colIndex; - colWidthOfSmallest = colWidth; - } - } - } - // now that we know which column to base the other columns' widths off of, do it! - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - colFrame = mTableFrame->GetColFrame(colIndex); - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - percent = colPosition->mWidth.GetPercentValue(); // we know this will work - if (percent == smallestPercent) { // set col width to the max width of all columns that shared the smallest percent-width - mTableFrame->SetColumnWidth(colIndex, colWidthOfSmallest); - } - else { - colWidth = (nscoord)((percent/smallestPercent) * ((float)colWidthOfSmallest)); - nscoord minColWidth = colFrame->GetEffectiveMinColWidth(); - colWidth = PR_MAX(colWidth, minColWidth); - mTableFrame->SetColumnWidth(colIndex, colWidth); - } - TDBG_SDFD(" col %d with percentwidth=%f set to %d\n", colIndex, percent, colWidth); - } - } + for (colX = 0; colX < mNumCols; colX++) { + allocTypes[colX] = -1; } - // second, assign column widths to proportional-width columns - if (nsnull != proportionalColumnsList) { - // first, figure out the amount of space per slice - nscoord maxWidthForTable = (0 != aTableSpecifiedWidth) ? aTableSpecifiedWidth : aMaxWidth; - if (NS_UNCONSTRAINEDSIZE != maxWidthForTable) { - nscoord widthRemaining = maxWidthForTable - tableWidth; - nscoord widthPerSlice = widthRemaining/totalSlices; - PRInt32 numSpecifiedProportionalColumns = proportionalColumnsList->Count(); - for (PRInt32 i = 0; i < numSpecifiedProportionalColumns; i++) { - // for every proportionally-sized column, set the col width to the computed width - ProportionalColumnLayoutStruct* info = - (ProportionalColumnLayoutStruct *)(proportionalColumnsList->ElementAt(i)); - // verify that the computed width is at least the minimum width - nscoord computedColWidth = info->mProportion*widthPerSlice; - // compute the requested proportional width - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(info->mColIndex, colFrame); - nscoord minColWidth = colFrame->GetMinColWidth(); - computedColWidth = PR_MAX(computedColWidth, minColWidth); - mTableFrame->SetColumnWidth(info->mColIndex, computedColWidth); - TDBG_SDDDD(" 3 proportional step 2: col %d given %d proportion of remaining space %d, set to width = %d\n", - info->mColIndex, info->mProportion, widthRemaining, computedColWidth); - tableWidth += computedColWidth; - delete info; - } - } - else { - // we're in an unconstrained situation, so give each column the max of the max column widths - PRInt32 numSpecifiedProportionalColumns = proportionalColumnsList->Count(); - PRInt32 maxOfMaxColWidths = 0; - PRInt32 i; - for (i = 0; i < numSpecifiedProportionalColumns; i++) { - ProportionalColumnLayoutStruct* info = - (ProportionalColumnLayoutStruct *)(proportionalColumnsList->ElementAt(i)); - maxOfMaxColWidths = PR_MAX(maxOfMaxColWidths, info->mMaxColWidth); - } - for (i = 0; i < numSpecifiedProportionalColumns; i++) { - ProportionalColumnLayoutStruct* info = - (ProportionalColumnLayoutStruct *)(proportionalColumnsList->ElementAt(i)); - mTableFrame->SetColumnWidth(info->mColIndex, maxOfMaxColWidths); - TDBG_SDD(" 3 proportional step 2 (unconstrained!): col %d set to width = %d\n", - info->mColIndex, maxOfMaxColWidths); - tableWidth += maxOfMaxColWidths; - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(info->mColIndex, colFrame); - colFrame->SetEffectiveMaxColWidth(maxOfMaxColWidths); - delete info; - } - } - delete proportionalColumnsList; - } - - // next, account for table width constraints - // if the caption min width is wider than than the table, expand the table - nscoord captionMinWidth = mTableFrame->GetMinCaptionWidth(); - if (captionMinWidth > tableWidth) { - DistributeExcessSpace(captionMinWidth, tableWidth, widthOfFixedTableColumns); - } - else { - // else, if the caption min width is not an issue... - // if the specified width of the table is greater than the table's computed width, expand the - // table's computed width to match the specified width, giving the extra space to proportionately-sized - // columns if possible. - if ((PR_FALSE == aTableIsAutoWidth) && (aAvailWidth > (tableWidth-widthOfFixedTableColumns)) && - (gBigSpace != aAvailWidth)) { - DistributeExcessSpace(aAvailWidth, tableWidth, widthOfFixedTableColumns); - } - // IFF the table is NOT (auto-width && all columns have fixed width) - PRInt32 numFixedColumns=0; - PRInt32* fixedColumns=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); - if (!((PR_TRUE == aTableIsAutoWidth) && (numFixedColumns == mNumCols))) { - nscoord computedWidth = 0; - for (PRInt32 i = 0; i < mNumCols; i++) { - computedWidth += mTableFrame->GetColumnWidth(i) + colInset; - } - if (computedWidth > aMaxWidth) { - AdjustTableThatIsTooWide(computedWidth, aMaxWidth, PR_FALSE); - } - } - } - - // cleanup - if (nsnull != spanList) { - TDBG_S("BTLS::BCTFits...space leak, span list not empty"); - delete spanList; - } - return result; -} - -// take the extra space in the table and distribute it proportionately (based on desired width) -// give extra space to auto-width cells first, or if there are none to all cells -void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, - nscoord aTableWidth, - nscoord aWidthOfFixedTableColumns) -{ - nscoord excess = 0; - TDBG_SDDD("DistributeExcessSpace: fixed width %d > computed table width %d, woftc=%d\n", - aAvailWidth, aTableWidth, aWidthOfFixedTableColumns); - nscoord widthMinusFixedColumns = aTableWidth - aWidthOfFixedTableColumns; - // if there are auto-sized columns, give them the extra space - // the trick here is to do the math excluding non-auto width columns - PRInt32 numAutoColumns=0; - PRInt32* autoColumns=nsnull; - GetColumnsThatActLikeAutoWidth(numAutoColumns, autoColumns); // allocates autoColumns, be sure to delete it - if (0 != numAutoColumns) { - // there's at least one auto-width column, so give it (them) the extra space - // proportionately distributed extra space, based on the column's desired size - nscoord totalEffectiveWidthOfAutoColumns = 0; - // 1. first, get the total width of the auto columns - PRInt32 i; - for (i = 0; i < numAutoColumns; i++) { - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(autoColumns[i], colFrame); - nscoord effectiveColWidth = colFrame->GetEffectiveMaxColWidth(); - if (0 != effectiveColWidth) { - totalEffectiveWidthOfAutoColumns += effectiveColWidth; - } - else { - totalEffectiveWidthOfAutoColumns += mTableFrame->GetColumnWidth(autoColumns[i]); - } - } - // excess is the amount of space that was available minus the computed available width - // XXX shouldn't it just be aMaxWidth - aTableWidth??? - TDBG_SDD(" aAvailWidth specified as %d, expanding columns by excess = %d\n", aAvailWidth, excess); - excess = aAvailWidth - widthMinusFixedColumns; - - // 2. next, compute the proportion to be added to each column, and add it - nscoord totalAdded=0; - for (i = 0; i < numAutoColumns; i++) { - PRInt32 colIndex = autoColumns[i]; - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(colIndex, colFrame); - nscoord oldColWidth = mTableFrame->GetColumnWidth(colIndex); - float percent; - if (0 != totalEffectiveWidthOfAutoColumns) { - percent = ((float)(colFrame->GetEffectiveMaxColWidth())) / ((float)totalEffectiveWidthOfAutoColumns); - } - else { - percent = ((float)1 )/ ((float)numAutoColumns); - } - nscoord excessForThisColumn = (nscoord)(excess * percent); - totalAdded += excessForThisColumn; - nscoord colWidth = excessForThisColumn+oldColWidth; - TDBG_SDDD(" distribute excess to auto columns: column %d was %d, now set to %d\n", - colIndex, oldColWidth, colWidth); - mTableFrame->SetColumnWidth(colIndex, colWidth); - } - TDBG_SDD("lost a few twips due to rounding errors: excess=%d, totalAdded=%d\n", excess, totalAdded); - } - // otherwise, distribute the space between all the columns - // (they must be all fixed and percentage-width columns, or we would have gone into the block above) - else { - excess = aAvailWidth - widthMinusFixedColumns; - TDBG_SDD(" aAvailWidth specified as %d, expanding columns by excess = %d\n", aAvailWidth, excess); - nscoord totalAdded=0; - for (PRInt32 colIndex = 0; colIndex < mNumCols; colIndex++) { - nscoord oldColWidth=0; - if (0 == oldColWidth) { - oldColWidth = mTableFrame->GetColumnWidth(colIndex); - } - float percent; - if (0 != aTableWidth) { - percent = (float)oldColWidth/(float)aTableWidth; - } - else { - percent = (float)1 / (float)mNumCols; - } - nscoord excessForThisColumn = (nscoord)(NSToCoordRound(excess * percent)); - totalAdded += excessForThisColumn; - nscoord colWidth = excessForThisColumn + oldColWidth; - TDBG_SDDDF(" distribute excess: column %d was %d, now %d from %=%f\n", - colIndex, oldColWidth, colWidth, percent); - mTableFrame->SetColumnWidth(colIndex, colWidth); - } - TDBG_SDD("lost a few twips due to rounding errors: excess=%d, totalAdded=%d\n", excess, totalAdded); - } - if (nsnull != autoColumns) { - delete [] autoColumns; - } -} - -/* assign columns widths for a table whose max size doesn't fit in the available space - */ -PRBool BasicTableLayoutStrategy:: - BalanceColumnsConstrained(const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - PRBool aTableIsAutoWidth) -{ -#ifdef NS_DEBUG - nsIFrame* tablePIF=nsnull; - mTableFrame->GetPrevInFlow(&tablePIF); - NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!"); -#endif - - PRBool result = PR_TRUE; - PRInt32 maxOfAllMinColWidths = 0; // for the case where we have equal column widths, this is the smallest a column can be - nscoord tableWidth = 0; // the width of the table as a result of setting column widths - PRInt32 totalSlices = 0; // the total number of slices the proportional-width columns request - nsVoidArray* proportionalColumnsList=nsnull; // a list of the columns that are proportional-width - PRBool equalWidthColumns = PR_TRUE; // remember if we're in the special case where all - // proportional-width columns are equal (if any are anything other than 1) - PRBool atLeastOneAutoWidthColumn = PR_FALSE; // true if at least one column is auto-width, requiring us to post-process - nsVoidArray* spanList=nsnull; // a list of the cells that span columns - PRInt32 numRows = mTableFrame->GetRowCount(); - nscoord colInset = mTableFrame->GetCellSpacingX(); - - for (PRInt32 colIndex = 0; colIndex < mNumCols; colIndex++) { - TDBG_SD(" for col %d\n", colIndex); - nscoord minColWidth = 0; - nscoord maxColWidth = 0; - - // Get column information - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - NS_ASSERTION(nsnull != colFrame, "bad col frame"); - // Get the columns's style and margins - PRInt32 rowIndex; - PRInt32 firstRowIndex = -1; - const nsStylePosition* colPosition; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - const nsStyleTable* colTableStyle; - colFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct*&)colTableStyle); - - // first, deal with any cells that span into this column from a pervious column - // go through the list backwards so we can delete easily - if (nsnull != spanList) { - PRInt32 spanCount = spanList->Count(); - // go through the list backwards so we can delete easily - for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--) { - SpanInfo* spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex)); - if (PR_FALSE == IsFixedWidth(colPosition, colTableStyle)) { - // compute the spanning cell's contribution to the column min width - nscoord spanCellMinWidth; - PRBool needsExtraMinWidth = (spanInfo->effectiveMinWidthOfSpannedCols < spanInfo->cellMinWidth); - if (PR_TRUE == needsExtraMinWidth) { - if (0 != spanInfo->effectiveMinWidthOfSpannedCols) { - spanCellMinWidth = (spanInfo->cellMinWidth * colFrame->GetEffectiveMinColWidth()) / - (spanInfo->effectiveMinWidthOfSpannedCols); - TDBG_SDD(" spanlist min: %d of %d\n", spanCellMinWidth, spanInfo->effectiveMaxWidthOfSpannedCols); - if (minColWidth < spanCellMinWidth) { - minColWidth = spanCellMinWidth; // set the new min width for the col - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new min = %d\n", - colIndex, spanInfo->span, minColWidth); - maxColWidth = PR_MAX(maxColWidth, minColWidth); - TDBG_SD(" maxColWidth = %d\n", maxColWidth); - } - } - else { - spanCellMinWidth = spanInfo->cellMinWidth / spanInfo->initialColSpan; - if (minColWidth < spanCellMinWidth) { - minColWidth = spanCellMinWidth; - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new min = %d\n", - colIndex, spanInfo->span, minColWidth); - maxColWidth = PR_MAX(maxColWidth, minColWidth); - TDBG_SD(" maxColWidth = %d\n", maxColWidth); - } - } - } - - - // compute the spanning cell's contribution to the column max width - nscoord spanCellMaxWidth; - if (0 != spanInfo->effectiveMaxWidthOfSpannedCols) { - spanCellMaxWidth = (spanInfo->cellDesiredWidth * colFrame->GetEffectiveMinColWidth()) / - (spanInfo->effectiveMaxWidthOfSpannedCols); - TDBG_SDD(" spanlist max: %d of %d\n", spanCellMaxWidth, spanInfo->effectiveMaxWidthOfSpannedCols); - if (maxColWidth < spanCellMaxWidth) { - maxColWidth = spanCellMaxWidth; // set the new max width for the col - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); // set the column to the new desired max width - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new max = %d\n", - colIndex, spanInfo->span, maxColWidth); - } - } - else { - spanCellMaxWidth = spanInfo->cellDesiredWidth/spanInfo->initialColSpan; - maxColWidth = spanCellMaxWidth; - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new max = %d\n", - colIndex, spanInfo->span, maxColWidth); - } - } - spanInfo->span--; - if (0 == spanInfo->span) { - spanList->RemoveElementAt(spanIndex); - delete spanInfo; - } - } - } - - // second, process non-fixed-width columns - if (PR_FALSE == IsFixedWidth(colPosition, colTableStyle)) { - for (rowIndex = 0; rowIndex < numRows; rowIndex++) { - nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex); - if (nsnull == cellFrame) { // there is no cell in this row that corresponds to this column - continue; - } - PRInt32 cellRowIndex; - cellFrame->GetRowIndex(cellRowIndex); - if (rowIndex!=cellRowIndex) { - // For cells that span rows, we only figure it in once - NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check - continue; - } - PRInt32 cellColIndex; - cellFrame->GetColIndex(cellColIndex); - if (colIndex!=cellColIndex) { - // For cells that span cols, we figure in the row using previously-built SpanInfo - NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match row span"); // sanity check - continue; - } - - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); - nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); - nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); - - nscoord cellMinWidth=colFrame->GetAdjustedMinColWidth(); - nscoord cellDesiredWidth=colFrame->GetMaxColWidth(); - if (1 == colSpan) { - cellMinWidth = cellMinSize.width; - cellDesiredWidth = cellDesiredSize.width; - nscoord specifiedCellWidth = -1; - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - if (eStyleUnit_Percent==cellPosition->mWidth.GetUnit()) { - float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(aMaxWidth * percent); - TDBG_SFDD("specified percent width %f of %d = %d\n", percent, aMaxWidth, specifiedCellWidth); - } - if (-1 != specifiedCellWidth) { - if (specifiedCellWidth>cellMinWidth) { - TDBG_SDD("setting cellDesiredWidth from %d to %d\n", cellDesiredWidth, specifiedCellWidth); - cellDesiredWidth = specifiedCellWidth; - } - } - } - else { // colSpan>1, get the proportion for this column - // then get the desired size info factoring in the cell style attributes - nscoord effectiveMaxWidthOfSpannedCols = colFrame->GetEffectiveMaxColWidth(); - nscoord effectiveMinWidthOfSpannedCols = colFrame->GetEffectiveMinColWidth(); - for (PRInt32 span = 1; span < colSpan; span++) { - nsTableColFrame* nextColFrame = mTableFrame->GetColFrame(colIndex+span); - if (nsnull == nextColFrame) { - break; - } - effectiveMaxWidthOfSpannedCols += nextColFrame->GetEffectiveMaxColWidth(); - effectiveMinWidthOfSpannedCols += nextColFrame->GetEffectiveMinColWidth(); - } - nscoord specifiedCellWidth = -1; - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { - //XXX what if table is auto width? - float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(aMaxWidth * percent); - TDBG_SFDD("specified percent width %f of %d = %d\n", percent, aMaxWidth, specifiedCellWidth); - } - if (-1 != specifiedCellWidth) { - float percentForThisCol = (float)(cellDesiredSize.width * colFrame->GetEffectiveMaxColWidth()) / - (float)effectiveMaxWidthOfSpannedCols; - nscoord cellWidthForThisCol = (nscoord)(specifiedCellWidth * percentForThisCol); - if (cellWidthForThisCol>cellMinWidth) { - TDBG_SDD("setting cellDesiredWidth from %d to %d\n", cellDesiredWidth, cellWidthForThisCol); - cellDesiredWidth = cellWidthForThisCol; - } - } - // otherwise it's already been factored in. - // now, if this column holds the cell, create a spanInfo struct for the cell - // so subsequent columns can take a proportion of this cell's space into account - cellFrame->GetColIndex(cellColIndex); - if (cellColIndex == colIndex) { - // add this cell to span list iff we are currently processing the column the cell starts in - SpanInfo* spanInfo = new SpanInfo(colIndex, colSpan-1, cellMinSize.width, cellDesiredSize.width); - spanInfo->effectiveMaxWidthOfSpannedCols = effectiveMaxWidthOfSpannedCols; - spanInfo->effectiveMinWidthOfSpannedCols = effectiveMinWidthOfSpannedCols; - if (nsnull == spanList) { - spanList = new nsVoidArray(); - } - spanList->AppendElement(spanInfo); - } - } - - TDBG_SDDDD("factoring in cell %d with colSpan=%d\n factoring in min=%d and desired=%d\n", - rowIndex, colSpan, cellMinWidth, cellDesiredWidth); - // remember the widest min cell width - minColWidth = PR_MAX(minColWidth, cellMinWidth); - // remember the max desired cell width - maxColWidth = PR_MAX(maxColWidth, cellDesiredWidth); - // effectiveMaxColumnWidth is the width as if no cells with colspans existed - // if ((1==colSpan) && (colFrame->GetEffectiveMaxColWidth() < maxColWidth)) - // colFrame->SetEffectiveMaxColWidth(cellDesiredWidth); - TDBG_SDDDDDD(" after cell %d, minColWidth=%d maxColWidth=%d effColWidth[%d]=%d,%d\n", - rowIndex, minColWidth, maxColWidth, colIndex, - colFrame->GetEffectiveMinColWidth(), colFrame->GetEffectiveMaxColWidth()); - } - if (PR_TRUE == gsDebug) { - printf (" for determining width of col %d %s:\n", - colIndex, !IsFixedWidth(colPosition, colTableStyle)? "(P)":"(A)"); - printf (" minTableWidth = %d and maxTableWidth = %d\n", - mMinTableWidth, mMaxTableWidth); - printf (" minColWidth = %d, maxColWidth = %d, eff=%d,%d\n", - minColWidth, maxColWidth, colFrame->GetEffectiveMinColWidth(), - colFrame->GetEffectiveMaxColWidth()); - printf (" aAvailWidth = %d\n", aAvailWidth); - } - - - // Get column width if it has one - nscoord specifiedProportionColumnWidth = -1; - float specifiedPercentageColWidth = -1.0f; - PRBool isAutoWidth = PR_FALSE; - switch (colPosition->mWidth.GetUnit()) { - case eStyleUnit_Percent: - specifiedPercentageColWidth = colPosition->mWidth.GetPercentValue(); - TDBG_SDF("column %d has specified percent width = %f\n", colIndex, specifiedPercentageColWidth); - break; - case eStyleUnit_Proportional: - specifiedProportionColumnWidth = colPosition->mWidth.GetIntValue(); - TDBG_SDD("column %d has specified percent width = %d\n", colIndex, specifiedProportionColumnWidth); - break; - case eStyleUnit_Auto: - isAutoWidth = PR_TRUE; - break; - default: - break; - } - - // set the column width, knowing that the table is constrained - if (0 == specifiedProportionColumnWidth || 0.0 == specifiedPercentageColWidth) { - // col width is specified to be the minimum - mTableFrame->SetColumnWidth(colIndex, minColWidth); - TDBG_SDD(" 4 (0): col %d set to min width = %d because style set proportionalWidth=0\n", - colIndex, mTableFrame->GetColumnWidth(colIndex)); - } - else if (1 == mNumCols) { // there is only one column, and we know that it's desired width doesn't fit - // so the column should be as wide as the available space allows it to be minus cell spacing - nscoord colWidth = aAvailWidth - (2*colInset); - mTableFrame->SetColumnWidth(colIndex, colWidth); - TDBG_SDDDD(" 4 one-col: col %d set to width = %d from available width %d and cell spacing %d\n", - colIndex, mTableFrame->GetColumnWidth(colIndex), aAvailWidth, colInset); - } - else if (PR_TRUE==isAutoWidth) { // column's width is determined by its content, done in post-processing - mTableFrame->SetColumnWidth(colIndex, minColWidth); // reserve the column's min width - atLeastOneAutoWidthColumn = PR_TRUE; - } - else if (-1 != specifiedProportionColumnWidth) { - // we need to save these and do them after all other columns have been calculated - // the calculation will be: - // sum up n, the total number of slices for the columns with proportional width - // compute the table "required" width, fixed-width + percentage-width + - // the sum of the proportional column's max widths (especially because in this routine I know the table fits) - // compute the remaining width: the required width - the used width (fixed + percentage) - // compute the width per slice - // set the width of each proportional-width column to it's number of slices * width per slice - mTableFrame->SetColumnWidth(colIndex, 0); // set the column width to 0, since it isn't computed yet - if (nsnull == proportionalColumnsList) { - proportionalColumnsList = new nsVoidArray(); - } - ProportionalColumnLayoutStruct* info = - new ProportionalColumnLayoutStruct(colIndex, minColWidth, maxColWidth, specifiedProportionColumnWidth); - proportionalColumnsList->AppendElement(info); - totalSlices += specifiedProportionColumnWidth; - if (1 != specifiedProportionColumnWidth) { - equalWidthColumns = PR_FALSE; - } - } - else { // give the column a percentage of the remaining space - PRInt32 percentage = -1; - if (NS_UNCONSTRAINEDSIZE == aAvailWidth) { - // since the "remaining space" is infinite, give the column it's max requested size - mTableFrame->SetColumnWidth(colIndex, maxColWidth); - } - else { - if (-1.0f != specifiedPercentageColWidth) { - percentage = (PRInt32)(specifiedPercentageColWidth * 100.0f); // TODO: rounding errors? - // base the % on the total specified fixed width of the table - mTableFrame->SetColumnWidth(colIndex, (percentage*aMaxWidth)/100); - TDBG_SDDDD(" 4 percent specified: col %d given %d percent of aMaxWidth %d, set to width = %d\n", - colIndex, percentage, aMaxWidth, mTableFrame->GetColumnWidth(colIndex)); - } - if (-1 == percentage) { - percentage = 100 / mNumCols; - // base the % on the remaining available width - mTableFrame->SetColumnWidth(colIndex, (percentage * aAvailWidth) / 100); - TDBG_SDDDD(" 4 percent default: col %d given %d percent of aAvailWidth %d, set to width = %d\n", - colIndex, percentage, aAvailWidth, mTableFrame->GetColumnWidth(colIndex)); - } - // if the column was computed to be too small, enlarge the column - if (mTableFrame->GetColumnWidth(colIndex) <= minColWidth) { - mTableFrame->SetColumnWidth(colIndex, minColWidth); - TDBG_SD(" enlarging column to it's minimum = %d\n", minColWidth); - if (maxOfAllMinColWidths < minColWidth) { - maxOfAllMinColWidths = minColWidth; - TDBG_SD(" and setting maxOfAllMins to %d\n", maxOfAllMinColWidths); - } - } - } - } + // allocate percentage cols + if (totalCounts[PCT] > 0) { + if (totalAllocated + totalWidths[PCT] - minWidths[PCT] <= maxWidth) { + AllocateFully(totalAllocated, allocTypes, PCT); + NS_ASSERTION(totalAllocated <= maxWidth, "over allocated"); } else { - mTableFrame->SetColumnWidth(colIndex, colFrame->GetMaxColWidth()); + AllocateConstrained(maxWidth - totalAllocated, PCT, totalCounts[PCT], + totalWidths[PCT], PR_FALSE, allocTypes); + return BCW_Wrapup(this, mTableFrame, allocTypes); } - tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset; } - tableWidth += colInset; - // --- post-process if necessary --- / - // first, assign autoWidth columns a width - if (PR_TRUE == atLeastOneAutoWidthColumn) { - // proportionately distribute the remaining space to autowidth columns - DistributeRemainingSpace(aMaxWidth, tableWidth, aTableIsAutoWidth); + // allocate fixed cols + if (totalAllocated < maxWidth && totalCounts[FIX] > 0) { + if (totalAllocated + totalWidths[FIX] - minWidths[FIX] <= maxWidth) { + AllocateFully(totalAllocated, allocTypes, FIX); + NS_ASSERTION(totalAllocated <= maxWidth, "over allocated"); + } + else { + AllocateConstrained(maxWidth - totalAllocated, FIX, totalCounts[FIX], + totalWidths[FIX], PR_TRUE, allocTypes); + return BCW_Wrapup(this, mTableFrame, allocTypes); + } } + // allocate proportional cols up to their min proportional value + if (totalAllocated < maxWidth && totalCounts[MIN_PRO] > 0) { + if (totalAllocated + totalWidths[MIN_PRO] - minWidths[MIN_PRO] <= maxWidth) { + AllocateFully(totalAllocated, allocTypes, MIN_PRO, PR_FALSE); + NS_ASSERTION(totalAllocated <= maxWidth, "over allocated"); + } + else { + AllocateConstrained(maxWidth - totalAllocated, MIN_PRO, totalCounts[MIN_PRO], + totalWidths[MIN_PRO], PR_FALSE, allocTypes); + return BCW_Wrapup(this, mTableFrame, allocTypes); + } + } + + // allocate auto cols, considering even those that are proportional + if (totalAllocated < maxWidth && totalCounts[DES_CON] > 0) { + if (totalAllocated + totalWidths[DES_CON] - minWidths[DES_CON]<= maxWidth) { + AllocateFully(totalAllocated, allocTypes, DES_CON); + NS_ASSERTION(totalAllocated <= maxWidth, "over allocated"); + } + else { + AllocateConstrained(maxWidth - totalAllocated, DES_CON, totalCounts[DES_CON], + totalWidths[DES_CON], PR_FALSE, allocTypes); + return BCW_Wrapup(this, mTableFrame, allocTypes); + } + } + + // if this is a nested table and pass1 reflow, we are done + if (maxWidth == NS_UNCONSTRAINEDSIZE) { + return PR_TRUE; + } + + // allocate the rest unconstrained + PRBool skip0Proportional = totalCounts[DES_CON] > num0Proportional; + if ( (tableIsAutoWidth && (perAdjTableWidth - totalAllocated > 0)) || + (!tableIsAutoWidth && (totalAllocated < maxWidth)) ) { + if (totalCounts[PCT] != mNumCols) { + PRBool onlyAuto = (totalCounts[DES_CON] > 0) && !mIsNavQuirksMode; + for (colX = 0; colX < mNumCols; colX++) { + if (PCT == allocTypes[colX]) { + allocTypes[colX] = -1; + } + else if ((FIX == allocTypes[colX]) && onlyAuto) { + allocTypes[colX] = -1; + } + } + } + if (tableIsAutoWidth) { + AllocateUnconstrained(perAdjTableWidth - totalAllocated, allocTypes, skip0Proportional); + } + else { + AllocateUnconstrained(maxWidth - totalAllocated, allocTypes, skip0Proportional); + } + } + // give the proportional cols the rest up to the max width in quirks mode + else if (tableIsAutoWidth && mIsNavQuirksMode && (totalCounts[MIN_PRO] > 0)) { + for (colX = 0; colX < mNumCols; colX++) { + if (DES_CON != allocTypes[colX]) { + allocTypes[colX] = -1; + } + } + AllocateUnconstrained(maxWidth - totalAllocated, allocTypes, skip0Proportional); + } + + + return BCW_Wrapup(this, mTableFrame, allocTypes); +} + + +// Allocate aWidthType values to all cols available in aIsAllocated +void BasicTableLayoutStrategy::AllocateFully(nscoord& aTotalAllocated, + PRInt32* aAllocTypes, + PRInt32 aWidthType, + PRBool aMarkAllocated) +{ + for (PRInt32 colX = 0; colX < mNumCols; colX++) { + if (-1 != aAllocTypes[colX]) { + continue; + } + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord oldWidth = mTableFrame->GetColumnWidth(colX); + nscoord newWidth = colFrame->GetWidth(aWidthType); + // account for col span overrides with DES_CON and FIX + if (DES_CON == aWidthType) { + newWidth = PR_MAX(newWidth, colFrame->GetWidth(DES_ADJ)); + } + else if (FIX == aWidthType) { + newWidth = PR_MAX(newWidth, colFrame->GetWidth(FIX_ADJ)); + } + else if (PCT == aWidthType) { + newWidth = PR_MAX(newWidth, colFrame->GetWidth(PCT_ADJ)); + } + if (WIDTH_NOT_SET == newWidth) { + continue; + } + if (newWidth > oldWidth) { + mTableFrame->SetColumnWidth(colX, newWidth); + aTotalAllocated += newWidth - oldWidth; + } + if (aMarkAllocated) { + aAllocTypes[colX] = aWidthType; + } + } +} + +void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount, + PRInt32* aAllocTypes, + PRBool aSkip0Proportional) +{ + nscoord divisor = 0; + PRInt32 numAvail = 0; + PRInt32 colX; + for (colX = 0; colX < mNumCols; colX++) { + if (-1 != aAllocTypes[colX]) { + divisor += mTableFrame->GetColumnWidth(colX); + numAvail++; + } + } + for (colX = 0; colX < mNumCols; colX++) { + if (-1 != aAllocTypes[colX]) { + if (aSkip0Proportional) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + if (e0ProportionConstraint == colFrame->GetConstraint()) { + continue; + } + } + nscoord oldWidth = mTableFrame->GetColumnWidth(colX); + float percent = (divisor == 0) + ? (1.0f / ((float)numAvail)) + : ((float)oldWidth) / ((float)divisor); + nscoord addition = NSToCoordRound(((float)aAllocAmount) * percent); + mTableFrame->SetColumnWidth(colX, oldWidth + addition); + } + } +} + +// Determine min, desired, fixed, and proportional sizes for the cols and +// and calculate min/max table width +PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth) +{ + PRBool rv = PR_FALSE; + PRInt32 numRows = mTableFrame->GetRowCount(); + nscoord spacingX = mTableFrame->GetCellSpacingX(); + PRInt32 colX, rowX; + PRUint32 widthX; + mCellSpacingTotal = 0; + + PRInt32 propTotal = 0; // total of numbers of the type 1*, 2*, etc + PRInt32 propTotalMin = 0; + PRInt32 numColsForColsAttr = 0; // Nav Quirks cols attribute for equal width cols + if (NS_STYLE_TABLE_COLS_NONE != mCols) { + numColsForColsAttr = (NS_STYLE_TABLE_COLS_ALL == mCols) ? mNumCols : mCols; + } + + // For every column, determine it's min and desired width based on cell style + // base on cells which do not span cols. Also, determine mCellSpacingTotal + for (colX = 0; colX < mNumCols; colX++) { + nscoord minWidth = 0; + nscoord desWidth = 0; + nscoord fixWidth = WIDTH_NOT_SET; + + // Get column information + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + NS_ASSERTION(nsnull != colFrame, "bad col frame"); + colFrame->SetConstraint(eNoConstraint); + + if (mTableFrame->GetNumCellsOriginatingIn(colX) > 0) { + mCellSpacingTotal += spacingX; + } + + // Scan the cells in the col that have colspan = 1 and find the maximum + // min, desired, and fixed cells. + for (rowX = 0; rowX < numRows; rowX++) { + nsTableCellFrame* cellFrame; + PRBool originates; + PRInt32 colSpan; + mTableFrame->GetCellInfoAt(rowX, colX, cellFrame, originates, colSpan); + // skip cells that don't originate at (rowX, colX); colspans are handled in the + // next pass, row spans don't need to be handled + if (!cellFrame || !originates || (colSpan > 1)) { + continue; + } + // these values include borders and padding + minWidth = PR_MAX(minWidth, cellFrame->GetPass1MaxElementSize().width); + desWidth = PR_MAX(desWidth, cellFrame->GetPass1DesiredSize().width); + // see if the cell has a style width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { + nscoord coordValue = cellPosition->mWidth.GetCoordValue(); + if (coordValue > 0) { // ignore if width == 0 + // need to add padding into fixed width + const nsStyleSpacing* spacing; + cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); + nsMargin paddingMargin; + spacing->CalcPaddingFor(cellFrame, paddingMargin); + nscoord padding = paddingMargin.left + paddingMargin.right; + fixWidth = PR_MAX(fixWidth, coordValue + padding); + fixWidth = PR_MAX(fixWidth, minWidth); + } + } + } + + desWidth = PR_MAX(desWidth, minWidth); + + // cache the computed column info + colFrame->SetWidth(MIN_CON, minWidth); + colFrame->SetWidth(DES_CON, desWidth); + if (fixWidth > 0) { + colFrame->SetWidth(FIX, PR_MAX(fixWidth, minWidth)); + } + + // determine if there is a proportional column either from html4 + // proportional width on a col or Nav Quirks cols attr + if (fixWidth <= 0) { + nscoord proportion = WIDTH_NOT_SET; + const nsStylePosition* colPosition; + colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); + if (eStyleUnit_Proportional == colPosition->mWidth.GetUnit()) { + proportion = colPosition->mWidth.GetIntValue(); + } + else if (colX < numColsForColsAttr) { + proportion = 1; + if ((eStyleUnit_Percent == colPosition->mWidth.GetUnit()) && + (colPosition->mWidth.GetPercentValue() > 0.0f)) { + proportion = WIDTH_NOT_SET; + } + } + if (proportion >= 0) { + colFrame->SetWidth(MIN_PRO, proportion); + if (proportion > 0) { + propTotal += proportion; + colFrame->SetConstraint(eProportionConstraint); + } + else { + colFrame->SetConstraint(e0ProportionConstraint); + // override the desired, proportional widths + nscoord minWidth = colFrame->GetWidth(MIN_CON); + colFrame->SetWidth(DES_CON, minWidth); + colFrame->SetWidth(MIN_PRO, minWidth); + } + } + } + } + if (mCellSpacingTotal > 0) { + mCellSpacingTotal += spacingX; // add last cell spacing on right + } + + // figure the proportional width for porportional cols + if (propTotal > 0) { + nscoord minPropTotal = 0; + nscoord desPropTotal = 0; + // figure the totals of all proportional cols which support every min and desired width + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord colProp = colFrame->GetWidth(MIN_PRO); + if (colProp > 0) { + nscoord minWidth = colFrame->GetWidth(MIN_CON); + nscoord desWidth = colFrame->GetWidth(DES_CON); + minPropTotal = PR_MAX(minPropTotal, NSToCoordRound(((float)propTotal * minWidth) / (float)colProp)); + desPropTotal = PR_MAX(desPropTotal, NSToCoordRound(((float)propTotal * desWidth) / (float)colProp)); + } + } + // store a ratio to allow going from a min to a desired proportional width + if (minPropTotal > 0) { + mMinToDesProportionRatio = ((float)desPropTotal) / ((float)minPropTotal); + } + // figure the cols proportional min width based on the new totals + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord colProp = colFrame->GetWidth(MIN_PRO); + if (colProp > 0) { + nscoord minWidth = colFrame->GetWidth(MIN_CON); + nscoord minProp = NSToCoordRound(((float)colProp * minPropTotal) / (float)propTotal); + colFrame->SetWidth(MIN_PRO, minProp); + colFrame->SetWidth(DES_CON, NSToCoordRound(((float)minProp) * mMinToDesProportionRatio)); + } + } + } + + // For each col, consider the cells originating in it with colspans > 1. + // Adjust the cols that each cell spans if necessary. Iterate backwards + // so that nested and/or overlaping col spans handle the inner ones first, + // ensuring more accurated calculations. + for (colX = mNumCols - 1; colX >= 0; colX--) { + for (rowX = 0; rowX < numRows; rowX++) { + nsTableCellFrame* cellFrame; + PRBool originates; + PRInt32 colSpan; + mTableFrame->GetCellInfoAt(rowX, colX, cellFrame, originates, colSpan); + if (!originates || (1 == colSpan)) { + continue; + } + nscoord cellWidths[NUM_WIDTHS]; + cellWidths[MIN_CON] = cellFrame->GetPass1MaxElementSize().width; + cellWidths[DES_CON] = cellFrame->GetPass1DesiredSize().width; + cellWidths[FIX] = WIDTH_NOT_SET; + // see if the cell has a style width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { + // need to add padding into fixed width + const nsStyleSpacing* spacing; + cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); + nsMargin paddingMargin; + spacing->CalcPaddingFor(cellFrame, paddingMargin); + nscoord padding = paddingMargin.left + paddingMargin.right; + cellWidths[FIX] = cellPosition->mWidth.GetCoordValue() + padding; + cellWidths[FIX] = PR_MAX(cellWidths[FIX], cellWidths[MIN_CON]); + } + + // set MIN_ADJ, DES_ADJ + nscoord spanCellSpacing = 0; + for (widthX = 0; widthX < NUM_MAJOR_WIDTHS; widthX++) { + // skip des if there is a fix + if ((DES_CON == widthX) && (cellWidths[FIX] > 0)) + continue; + nscoord spanTotal = 0; + nscoord divisor = 0; + for (PRInt32 spanX = 0; spanX < colSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); + nscoord colWidth = colFrame->GetWidth(widthX); + // need to get a contribution for every cell + colWidth = PR_MAX(colWidth, colFrame->GetMinWidth()); + spanTotal += colWidth; + // accumulate divisor + if (widthX == FIX) { + colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); + } + else if (widthX == DES_CON) { + nscoord fixWidth = colFrame->GetFixWidth(); + if (fixWidth > 0) { + colWidth = fixWidth; + } + //colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); + } + else if (widthX == MIN_CON) { + colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); + } + divisor += colWidth; + if ((0 == widthX) && (spanX > 0) && (mTableFrame->GetNumCellsOriginatingIn(colX + spanX) > 0)) { + spanCellSpacing += spacingX; + } + } + spanTotal -= spanCellSpacing; + nscoord cellWidth = cellWidths[widthX] - spanCellSpacing; + if ((cellWidth > 0) && !((widthX == MIN_CON) && (cellWidth <= spanTotal))) { + for (spanX = 0; spanX < colSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); + nscoord colWidth = colFrame->GetWidth(widthX); + nscoord minWidth = colFrame->GetMinWidth(); + // accumulate numerator similarly to divisor + colWidth = PR_MAX(colWidth, colFrame->GetMinWidth()); + if (widthX == FIX) { + colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); + } + else if (widthX == DES_CON) { + nscoord fixWidth = colFrame->GetFixWidth(); + if (fixWidth > 0) { + colWidth = fixWidth; + } + //colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); + } + else if (widthX == MIN_CON) { + colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); + } + nscoord colAdjWidth = colFrame->GetWidth(widthX + NUM_MAJOR_WIDTHS); + nscoord newColAdjWidth = (0 >= spanTotal) + ? NSToCoordRound( ((float)cellWidth) / ((float)colSpan) ) + : NSToCoordRound( (((float)colWidth) / ((float)divisor)) * cellWidth); + if ((newColAdjWidth > colAdjWidth) && (newColAdjWidth > 0)) { + newColAdjWidth = PR_MAX(newColAdjWidth, minWidth); + if (FIX != widthX) + colFrame->SetWidth(widthX + NUM_MAJOR_WIDTHS, newColAdjWidth); + // the following ensures that a spanned cell will reach its full desired width + // in an auto table, since allocations are done on fixed cols before auto cols + if (DES_CON == widthX) { + nscoord fixWidth = colFrame->GetFixWidth(); + if ((fixWidth > 0) && (newColAdjWidth > fixWidth) && (newColAdjWidth > 0)) { + colFrame->SetWidth(FIX_ADJ, newColAdjWidth); + } + } + else if (FIX == widthX) { + nscoord desWidth = colFrame->GetDesWidth(); + if ((newColAdjWidth > desWidth) && (newColAdjWidth > 0)) { + colFrame->SetWidth(DES_ADJ, newColAdjWidth); + } + } + } + } + } + } + } + } + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord desAdjWidth = colFrame->GetWidth(DES_ADJ); + nscoord fixWidth = colFrame->GetWidth(FIX); + if ((fixWidth >= 0) && (desAdjWidth > fixWidth)) { + colFrame->SetWidth(FIX, WIDTH_NOT_SET); + } + } + + // Set the col's fixed width if present + // Set the table col width for each col to the content min. + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord fixColWidth = colFrame->GetWidth(FIX); + // use the style width of a col only if the col hasn't gotten a fixed width from any cell + if (fixColWidth <= 0) { + const nsStylePosition* colPosition; + colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); + if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { + fixColWidth = colPosition->mWidth.GetCoordValue(); + if (fixColWidth > 0) { + colFrame->SetWidth(FIX, fixColWidth); + } + } + } + nscoord minWidth = colFrame->GetMinWidth(); + mTableFrame->SetColumnWidth(colX, minWidth); + } + SetMinAndMaxTableContentWidths(); + + return rv; +} + + +// Determine percentage col widths for each col frame +nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, + PRBool aTableIsAutoWidth) +{ + PRInt32 numRows = mTableFrame->GetRowCount(); + nscoord spacingX = mTableFrame->GetCellSpacingX(); + PRInt32 colX, rowX; + nscoord basis = aBasisIn; + // For an auto table, determine the potentially new percent adjusted width based + // on percent cells/cols. + if (aTableIsAutoWidth) { + nscoord fixWidthTotal = 0; + basis = 0; + PRInt32 numPerCols = 0; + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord colBasis = -1; + // Scan the cells in the col + for (rowX = 0; rowX < numRows; rowX++) { + nsTableCellFrame* cellFrame; + PRBool originates; + PRInt32 colSpan; + mTableFrame->GetCellInfoAt(rowX, colX, cellFrame, originates, colSpan); + if (!originates) { // skip cells that don't originate in the col + continue; + } + // see if the cell has a style percent width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { + float percent = cellPosition->mWidth.GetPercentValue(); + colBasis = 0; + if (percent > 0.0f) { + nscoord desWidth = colFrame->GetDesWidth(); + if (colSpan > 1) { // sum up the DES_ADJ widths of the spanned cols + for (PRInt32 spanX = 1; spanX < colSpan; spanX++) { + nsTableColFrame* spanFrame = mTableFrame->GetColFrame(colX + spanX); + desWidth += spanFrame->GetWidth(DES_ADJ); + } + } + colBasis = NSToCoordRound((float)desWidth / percent); + } + } + } + if (-1 == colBasis) { + // see if the col has a style percent width specified + const nsStylePosition* colPosition; + colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); + if (eStyleUnit_Percent == colPosition->mWidth.GetUnit()) { + float percent = colPosition->mWidth.GetPercentValue(); + colBasis = 0; + if (percent > 0.0f) { + nscoord desWidth = colFrame->GetDesWidth(); + colBasis = NSToCoordRound((float)desWidth / percent); + } + } + } + basis = PR_MAX(basis, colBasis); + if (colBasis >= 0) { + numPerCols++; + } + fixWidthTotal += colFrame->GetFixWidth(); + } // end for (colX .. + // If there is only one col and it is % based, it won't affect anything + if ((1 == mNumCols) && (mNumCols == numPerCols)) { + return 0; + } + basis = PR_MAX(basis, fixWidthTotal); + basis = PR_MIN(basis, aBasisIn); + } + + nscoord colPctTotal = 0; + nscoord* colPcts = new nscoord[mNumCols]; + if (!colPcts) return 0; - // second, fix up tables where column width attributes give us a table that is too wide or too narrow - nscoord computedWidth = colInset; - for (PRInt32 i = 0; i < mNumCols; i++) { - computedWidth += mTableFrame->GetColumnWidth(i) + colInset; - } - if (computedWidth= 0; colX--) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord maxColPctWidth = WIDTH_NOT_SET; + float maxColPct = 0.0f; + colPcts[colX] = 0; + + // Scan the cells in the col that have colspan = 1; assign PER widths + for (rowX = 0; rowX < numRows; rowX++) { + nsTableCellFrame* cellFrame; + PRBool originates; + PRInt32 colSpan; + mTableFrame->GetCellInfoAt(rowX, colX, cellFrame, originates, colSpan); + // skip cells that don't originate at (rowX, colX); colspans are handled in the + // next pass, row spans don't need to be handled + if (!cellFrame || !originates || (colSpan > 1)) { + continue; + } + // see if the cell has a style percent width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { + float percent = cellPosition->mWidth.GetPercentValue(); + if (percent > maxColPct) { + maxColPct = percent; + maxColPctWidth = NSToCoordRound( ((float)basis) * maxColPct ); + if (!mIsNavQuirksMode) { + // need to add padding + const nsStyleSpacing* spacing; + cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); + nsMargin paddingMargin; + spacing->CalcPaddingFor(cellFrame, paddingMargin); + maxColPctWidth += paddingMargin.left + paddingMargin.right; + } + } + } } - } - else if (computedWidth>aMaxWidth) { - // then shrink the table width because its too wide - AdjustTableThatIsTooWide(computedWidth, aMaxWidth, PR_FALSE); - } - - - // finally, assign a width to proportional-width columns - if (nsnull!=proportionalColumnsList) { - // first, figure out the amount of space per slice - nscoord widthRemaining = aMaxWidth - tableWidth; - nscoord widthPerSlice = widthRemaining / totalSlices; - PRInt32 numSpecifiedProportionalColumns = proportionalColumnsList->Count(); - for (PRInt32 i = 0; i < numSpecifiedProportionalColumns; i++) { - ProportionalColumnLayoutStruct* info = - (ProportionalColumnLayoutStruct *)(proportionalColumnsList->ElementAt(i)); - if (PR_TRUE == equalWidthColumns && 0 != maxOfAllMinColWidths) { - TDBG_SDD(" EqualColWidths specified and some column couldn't fit, so setting col %d width to %d\n", - info->mColIndex, maxOfAllMinColWidths); - mTableFrame->SetColumnWidth(info->mColIndex, maxOfAllMinColWidths); + if (WIDTH_NOT_SET == maxColPctWidth) { + // see if the col has a style percent width specified + const nsStylePosition* colPosition; + colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); + if (eStyleUnit_Percent == colPosition->mWidth.GetUnit()) { + maxColPct = colPosition->mWidth.GetPercentValue(); + maxColPctWidth = NSToCoordRound( ((float)basis) * maxColPct ); + } + } + // conflicting pct/fixed widths are recorded. Nav 4.x may be changing the + // fixed width value if it exceeds the pct value and not recording the pct + // value. This is not being done and IE5 doesn't do it either. + if (maxColPctWidth > 0) { + nscoord minWidth = colFrame->GetMinWidth(); + if (minWidth > maxColPctWidth) { + maxColPctWidth = minWidth; + colPcts[colX] = NSToCoordRound( 100.0f * ((float)maxColPctWidth) / ((float)basis) ); } else { - // compute the requested proportional width - nscoord computedColWidth = info->mProportion * widthPerSlice; - // verify that the computed width is at least the minimum width - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(info->mColIndex, colFrame); - nscoord minColWidth = colFrame->GetMinColWidth(); - computedColWidth = PR_MAX(computedColWidth, minColWidth); - mTableFrame->SetColumnWidth(info->mColIndex, computedColWidth); - TDBG_SDDDD(" 4 proportion: col %d given %d proportion of remaining space %d, set to width = %d\n", - info->mColIndex, info->mProportion, widthRemaining, computedColWidth); + colPcts[colX] = NSToCoordRound(maxColPct * 100.0f); } - delete info; + colFrame->SetWidth(PCT, maxColPctWidth); + colPctTotal += colPcts[colX]; } - delete proportionalColumnsList; } - // clean up - if (nsnull != spanList) { - TDBG_S("BTLS::BCTConstrained...space leak, span list not empty"); - delete spanList; + // For each col, consider the cells originating in it with colspans > 1. + // Adjust the cols that each cell spans if necessary. + for (colX = 0; colX < mNumCols; colX++) { + for (rowX = 0; rowX < numRows; rowX++) { + nsTableCellFrame* cellFrame; + PRBool originates; + PRInt32 colSpan; + mTableFrame->GetCellInfoAt(rowX, colX, cellFrame, originates, colSpan); + if (!originates || (1 == colSpan)) { + continue; + } + nscoord cellPctWidth = WIDTH_NOT_SET; + // see if the cell has a style percentage width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + float cellPct = 0.0f; + if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { + cellPct = cellPosition->mWidth.GetPercentValue(); + cellPctWidth = NSToCoordRound( ((float)basis) * cellPct ); + if (!mIsNavQuirksMode) { + // need to add padding + const nsStyleSpacing* spacing; + cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); + nsMargin paddingMargin; + spacing->CalcPaddingFor(cellFrame, paddingMargin); + cellPctWidth += paddingMargin.left + paddingMargin.right; + } + } + if (cellPctWidth > 0) { + nscoord spanCellSpacing = 0; + nscoord spanTotal = 0; + nscoord colPctWidthTotal = 0; + // accumulate the spanTotal as the max of MIN, DES, FIX, PCT + for (PRInt32 spanX = 0; spanX < colSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); + nscoord colPctWidth = colFrame->GetWidth(PCT); + if (colPctWidth > 0) { // skip pct cols + colPctWidthTotal += colPctWidth; + continue; + } + nscoord colWidth = PR_MAX(colFrame->GetMinWidth(), colFrame->GetFixWidth()); + colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); + //colWidth = PR_MAX(colWidth, colFrame->GetPctWidth()); + spanTotal += colWidth; + if ((spanX > 0) && (mTableFrame->GetNumCellsOriginatingIn(colX + spanX) > 0)) { + spanCellSpacing += spacingX; + } + } + cellPctWidth += spanCellSpacing; // add it back in since it was subtracted from aBasisIn + if (cellPctWidth <= 0) { + continue; + } + if (colPctWidthTotal < cellPctWidth) { + // record the percent contributions for the spanned cols + for (spanX = 0; spanX < colSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); + if (colFrame->GetWidth(PCT) > 0) { // skip pct cols + continue; + } + nscoord minWidth = colFrame->GetMinWidth(); + nscoord colWidth = PR_MAX(minWidth, colFrame->GetFixWidth()); + colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); + float colPctAdj = (0 == spanTotal) + ? cellPctWidth / ((float) colSpan) + : cellPct * ((float)colWidth) / (float)spanTotal; + if (colPctAdj > 0) { + nscoord colPctAdjWidth = colFrame->GetWidth(PCT_ADJ); + nscoord newColPctAdjWidth = NSToCoordRound(colPctAdj * (float)basis); + if (newColPctAdjWidth > colPctAdjWidth) { + if (colPctAdjWidth > 0) { // remove its contribution + colPctTotal -= colPcts[colX + spanX]; + } + if (minWidth > newColPctAdjWidth) { + newColPctAdjWidth = minWidth; + colPcts[colX + spanX] = NSToCoordRound( 100.0f * ((float)newColPctAdjWidth) / ((float)basis) ); + } + else { + colPcts[colX + spanX] = NSToCoordRound( 100.0f * colPctAdj ); + } + colFrame->SetWidth(PCT_ADJ, newColPctAdjWidth); + colPctTotal += colPcts[colX + spanX]; + } + } + } + } + } + } // end for (rowX .. + } // end for (colX .. + + // if the percent total went over 100%, adjustments need to be made to right most cols + if (colPctTotal > 100) { + for (colX = mNumCols - 1; colX >= 0; colX--) { + if (colPcts[colX] > 0) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord fixWidth = colFrame->GetFixWidth(); + nscoord pctWidth = colFrame->GetWidth(PCT); + nscoord pctAdjWidth = colFrame->GetWidth(PCT_ADJ); + nscoord newPct = colPcts[colX] - (colPctTotal - 100); + if (newPct > 0) { // this col has enough percent alloc to handle it + nscoord newPctWidth = NSToCoordRound( ((float)basis) * ((float)newPct) / 100.0f ); + newPctWidth = PR_MAX(newPctWidth, colFrame->GetMinWidth()); + // since we don't care which one contributed, set both + colFrame->SetWidth(PCT, newPctWidth); + colFrame->SetWidth(PCT_ADJ, newPctWidth); + break; + } + else { // this col cannot handle all the reduction, reduce it down to zero + colFrame->SetWidth(PCT, WIDTH_NOT_SET); + colFrame->SetWidth(PCT_ADJ, WIDTH_NOT_SET); + colPctTotal -= colPcts[colX]; + if (colPctTotal <= 100) { + break; + } + } + } + } } - return result; + delete [] colPcts; + return basis; } +void BasicTableLayoutStrategy::SetMinAndMaxTableContentWidths() +{ + mMinTableContentWidth = 0; + mMaxTableContentWidth = 0; + + nscoord spacingX = mTableFrame->GetCellSpacingX(); + for (PRInt32 colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + mMinTableContentWidth += colFrame->GetMinWidth(); + mMaxTableContentWidth += colFrame->GetDesWidth(); + if (mTableFrame->GetNumCellsOriginatingIn(colX) > 0) { + mMaxTableContentWidth += spacingX; + mMinTableContentWidth += spacingX; + } + } + // if it is not a degenerate table, add the last spacing on the right + if (mMinTableContentWidth > 0) { + mMinTableContentWidth += spacingX; + mMaxTableContentWidth += spacingX; + } +} + +// calculate totals by width type. A width type of a higher precedence will +// preclude one of a lower precedence for all types except MIN_CON +void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, + PRInt32* aTotalCounts, + PRInt32* aTotalWidths, + PRInt32* aMinWidths, + PRInt32& a0ProportionalCount) +{ + //mTableFrame->Dump(PR_TRUE, PR_FALSE); + aCellSpacing = 0; + for (PRInt32 widthX = 0; widthX < NUM_WIDTHS; widthX++) { + aTotalCounts[widthX] = 0; + aTotalWidths[widthX] = 0; + aMinWidths[widthX] = 0; + } + a0ProportionalCount = 0; + + nscoord spacingX = mTableFrame->GetCellSpacingX(); + for (PRInt32 colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + if (mTableFrame->GetNumCellsOriginatingIn(colX) > 0) { + aCellSpacing += spacingX; + } + nscoord minCol = colFrame->GetMinWidth(); + aTotalCounts[MIN_CON]++; + aTotalWidths[MIN_CON] += minCol; + + if (e0ProportionConstraint == colFrame->GetConstraint()) { + a0ProportionalCount++; + } + + nscoord pctCol = colFrame->GetPctWidth(); + nscoord fixCol = colFrame->GetFixWidth(); + // pct wins in conflict with fix + if (pctCol > 0) { + aTotalCounts[PCT]++; + aTotalWidths[PCT] += pctCol; + aMinWidths[PCT] += minCol; + continue; + } + else if (fixCol > 0) { + aTotalCounts[FIX]++; + aTotalWidths[FIX] += fixCol; + aMinWidths[FIX] += minCol; + continue; + } + + if (eProportionConstraint == colFrame->GetConstraint()) { + nscoord minProp = colFrame->GetWidth(MIN_PRO); + aTotalCounts[MIN_PRO]++; + aTotalWidths[MIN_PRO] += minProp; + aTotalCounts[DES_CON]++; + aTotalWidths[DES_CON] += NSToCoordRound(((float)minProp) * mMinToDesProportionRatio); + aMinWidths[MIN_PRO] += minCol; + aMinWidths[DES_CON] += minProp; + } + else { + nscoord desCol = colFrame->GetDesWidth(); + aTotalCounts[DES_CON]++; + aTotalWidths[DES_CON] += desCol; + aMinWidths[DES_CON] += minCol; + } + } + // if it is not a degenerate table, add the last spacing on the right + if (mNumCols > 0) { + aCellSpacing += spacingX; + } +} + + + + struct nsColInfo { nsColInfo(nsTableColFrame* aFrame, PRInt32 aIndex, PRInt32 aMinWidth, PRInt32 aWidth, - PRInt32 aMaxEffWidth, PRInt32 aMaxWidth) : mFrame(aFrame), mIndex(aIndex), mMinWidth(aMinWidth), - mWidth(aWidth), mMaxEffWidth(aMaxEffWidth), mMaxWidth(aMaxWidth), mWeight(0) + mWidth(aWidth), mMaxWidth(aMaxWidth), mWeight(0) {} nsTableColFrame* mFrame; PRInt32 mIndex; PRInt32 mMinWidth; PRInt32 mWidth; - PRInt32 mMaxEffWidth; PRInt32 mMaxWidth; float mWeight; }; void -DRS_Wrapup(nsTableFrame* aTableFrame, +AC_Wrapup(nsTableFrame* aTableFrame, PRInt32 aNumItems, - nsColInfo** aColInfo) + nsColInfo** aColInfo, + PRBool aAbort = PR_FALSE) { - for (int i = 0; i < aNumItems; i++) { - aTableFrame->SetColumnWidth(aColInfo[i]->mIndex, aColInfo[i]->mWidth); - delete aColInfo[i]; + if (aColInfo) { + for (PRInt32 i = 0; i < aNumItems; i++) { + if (aColInfo[i]) { + if (!aAbort) { + aTableFrame->SetColumnWidth(aColInfo[i]->mIndex, aColInfo[i]->mWidth); + } + delete aColInfo[i]; + } + } + delete [] aColInfo; } - delete [] aColInfo; } void -DRS_Increase(PRInt32 aNumAutoCols, +AC_Increase(PRInt32 aNumAutoCols, nsColInfo** aColInfo, PRInt32 aDivisor, - PRBool aDontGoOverMax, PRInt32& aAvailWidth) { for (PRInt32 i = 0; i < aNumAutoCols; i++) { if ((aAvailWidth <= 0) || (aDivisor <= 0)) { break; } - //float percent = ((float)aColInfo[i]->mMaxEffWidth) / (float)aDivisor; float percent = ((float)aColInfo[i]->mMaxWidth) / (float)aDivisor; - //aDivisor -= aColInfo[i]->mWidth; aDivisor -= aColInfo[i]->mMaxWidth; nscoord addition = PR_MIN(aAvailWidth, NSToCoordRound(((float)(aAvailWidth)) * percent)); - if (aDontGoOverMax) { - addition = PR_MIN(addition, aColInfo[i]->mMaxWidth - aColInfo[i]->mWidth); - } + addition = PR_MIN(addition, aColInfo[i]->mMaxWidth - aColInfo[i]->mWidth); // don't let the total additions exceed what is available if (i == aNumAutoCols - 1) { addition = PR_MIN(addition, aAvailWidth); @@ -2132,7 +1080,7 @@ DRS_Increase(PRInt32 aNumAutoCols, } void -DRS_Decrease(PRInt32 aNumAutoCols, +AC_Decrease(PRInt32 aNumAutoCols, nsColInfo** aColInfo, PRInt32 aDivisor, PRInt32& aExcess) @@ -2141,9 +1089,7 @@ DRS_Decrease(PRInt32 aNumAutoCols, if ((aExcess <= 0) || (aDivisor <= 0)) { break; } - //float percent = ((float)aColInfo[i]->mMaxEffWidth) / (float)aDivisor; float percent = ((float)aColInfo[i]->mMaxWidth) / (float)aDivisor; - //aDivisor -= aColInfo[i]->mWidth; aDivisor -= aColInfo[i]->mMaxWidth; nscoord reduction = PR_MIN(aExcess, NSToCoordRound(((float)(aExcess)) * percent)); // don't go over the col min @@ -2159,7 +1105,7 @@ DRS_Decrease(PRInt32 aNumAutoCols, void -DSR_Sort(nsColInfo** aColInfo, PRInt32 aNumCols) +AC_Sort(nsColInfo** aColInfo, PRInt32 aNumCols) { // sort the cols based on the Weight for (PRInt32 j = aNumCols - 1; j > 0; j--) { @@ -2173,54 +1119,71 @@ DSR_Sort(nsColInfo** aColInfo, PRInt32 aNumCols) } } -// Take the remaining space in the table and distribute it to the auto-width cols -// in the table. -void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth, - nscoord& aComputedTableWidth, - PRBool aTableIsAutoWidth) +// this assumes that the table has set the width for each col to be its min +void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, + PRInt32 aWidthType, + PRInt32 aNumConstrainedCols, + PRInt32 aSumMaxConstraints, + PRBool aStartAtMin, + PRInt32* aAllocTypes) { - // availWidth is the difference between the total available width and the - // amount of space already assigned. - nscoord availWidth = PR_MAX(aTableSpecifiedWidth - aComputedTableWidth, 0); - TDBG_SDD(" aTableSpecifiedWidth specified as %d, availWidth is = %d\n", aTableSpecifiedWidth, availWidth); - if ((0 == availWidth) || (aTableSpecifiedWidth <= 0)) { + if ((0 == aAvailWidth) || (aWidthType < 0) || (aWidthType >= NUM_WIDTHS) || + (aNumConstrainedCols <= 0) || (aSumMaxConstraints <= 0)) { + NS_ASSERTION(PR_TRUE, "invalid args to AllocateConstrained"); return; } - // Get the auto width cols. Only they get adjusted. - PRInt32 numAutoCols = 0; - PRInt32* autoCols = nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoCols, autoCols); - if (0 == numAutoCols) { + // allocate storage for the affected cols. Only they get adjusted. + nsColInfo** colInfo = new nsColInfo*[aNumConstrainedCols]; + if (!colInfo) { return; } - nsColInfo** colInfo = new nsColInfo*[numAutoCols]; - - nscoord totalDivisor = 0; - nscoord totalAutoWidthGiven = 0; + PRInt32 maxMinDiff = 0; + PRInt32 constrColX = 0; + // set the col info entries for each constrained col + for (PRInt32 colX = 0; colX < mNumCols; colX++) { + if (-1 != aAllocTypes[colX]) { + continue; + } + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + //nscoord minWidth = colFrame->GetMinWidth(); + nscoord minWidth = mTableFrame->GetColumnWidth(colX); + nscoord maxWidth = colFrame->GetWidth(aWidthType); + if (DES_CON == aWidthType) { + maxWidth = PR_MAX(maxWidth, colFrame->GetWidth(DES_ADJ)); + } + else if (FIX == aWidthType) { + maxWidth = PR_MAX(maxWidth, colFrame->GetWidth(FIX_ADJ)); + } + else if (PCT == aWidthType) { + maxWidth = PR_MAX(maxWidth, colFrame->GetWidth(PCT_ADJ)); + } + if (maxWidth <= 0) { + continue; + } + if (constrColX >= aNumConstrainedCols) { + NS_ASSERTION(PR_FALSE, "AllocateConstrained called incorrectly"); + break; + } + maxWidth = PR_MAX(maxWidth, minWidth); + maxMinDiff += maxWidth - minWidth; + nscoord startWidth = (aStartAtMin) ? minWidth : maxWidth; + colInfo[constrColX++] = new nsColInfo(colFrame, colX, minWidth, startWidth, maxWidth); + if (!colInfo[constrColX]) { + AC_Wrapup(mTableFrame, aNumConstrainedCols, colInfo, PR_TRUE); + return; + } + aAllocTypes[colX] = aWidthType; + } + if (constrColX < aNumConstrainedCols) { + // some of the constrainted cols might have been 0 and skipped + aNumConstrainedCols = constrColX; + } PRInt32 i; - - // start out by giving each col its max effective width (or adj width if it is greater) - // for standard mode and its min width for nav quirks mode - for (i = 0; i < numAutoCols; i++) { - PRInt32 colIndex = autoCols[i]; - nsTableColFrame* colFrame = mTableFrame->GetColFrame(autoCols[i]); - nscoord origWidth = mTableFrame->GetColumnWidth(autoCols[i]); - nscoord minWidth = PR_MAX(colFrame->GetAdjustedMinColWidth(), origWidth); - nscoord maxEffWidth = PR_MAX(colFrame->GetEffectiveMaxColWidth(), minWidth); - nscoord maxWidth = colFrame->GetMaxColWidth(); - nscoord startWidth = (mIsNavQuirksMode) ? minWidth : maxWidth; - colInfo[i] = new nsColInfo(colFrame, autoCols[i], minWidth, startWidth, maxEffWidth, maxWidth); -// totalDivisor += maxEffWidth; - totalDivisor += maxWidth; - totalAutoWidthGiven += startWidth - origWidth; - } - - availWidth = aTableSpecifiedWidth - aComputedTableWidth - totalAutoWidthGiven; - - if (availWidth >= 0) { // have more space to allocate - for (i = 0; i < numAutoCols; i++) { - // the weight here is a relative metric for determining when cols reach their max. + if (aStartAtMin) { // allocate extra space + nscoord availWidth = aAvailWidth; + for (i = 0; i < aNumConstrainedCols; i++) { + // the weight here is a relative metric for determining when cols reach their max constraint. // A col with a larger weight will reach its max before one with a smaller value. nscoord delta = colInfo[i]->mMaxWidth - colInfo[i]->mWidth; colInfo[i]->mWeight = (delta <= 0) @@ -2232,19 +1195,20 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified // weights will get their max earlier than ones with lower weights // This is an innefficient bubble sort, but unless there are an unlikely // large number of cols, it is not an issue. - DSR_Sort(colInfo, numAutoCols); + AC_Sort(colInfo, aNumConstrainedCols); // compute the proportion to be added to each column, don't go beyond the col's // max. This algorithm assumes that the Weight works as stated above - DRS_Increase(numAutoCols, colInfo, totalDivisor, PR_TRUE, availWidth); - // if every col got its max and there is more to go, allocate a 2nd time - if (!aTableIsAutoWidth && (availWidth > 0)) { - DRS_Increase(numAutoCols, colInfo, totalDivisor, PR_FALSE, availWidth); - } - aComputedTableWidth = aTableSpecifiedWidth - availWidth; + AC_Increase(aNumConstrainedCols, colInfo, aSumMaxConstraints, availWidth); } - else { // reduce each col width if appropriate - for (i = 0; i < numAutoCols; i++) { + else { // reduce each col width + nscoord reduceWidth = maxMinDiff - aAvailWidth; + if (reduceWidth < 0) { + NS_ASSERTION(PR_TRUE, "AllocateConstrained called incorrectly"); + AC_Wrapup(mTableFrame, aNumConstrainedCols, colInfo, PR_TRUE); + return; + } + for (i = 0; i < aNumConstrainedCols; i++) { // the weight here is a relative metric for determining when cols reach their min. // A col with a larger weight will reach its min before one with a smaller value. nscoord delta = colInfo[i]->mWidth - colInfo[i]->mMinWidth; @@ -2254,301 +1218,15 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified } // sort the cols based on the Weight - DSR_Sort(colInfo, numAutoCols); + AC_Sort(colInfo, aNumConstrainedCols); // compute the proportion to be subtracted from each column, don't go beyond // the col's min. This algorithm assumes that the Weight works as stated above - PRInt32 totalExcessGiven = -availWidth; - DRS_Decrease(numAutoCols, colInfo, totalDivisor, totalExcessGiven); - aComputedTableWidth = aTableSpecifiedWidth + totalExcessGiven; + AC_Decrease(aNumConstrainedCols, colInfo, aSumMaxConstraints, reduceWidth); } - DRS_Wrapup(mTableFrame, numAutoCols, colInfo); - TDBG_WIDTHS4("at end of DistributeRemainingSpace: ",PR_FALSE,PR_FALSE); + AC_Wrapup(mTableFrame, aNumConstrainedCols, colInfo); } -#if 0 -void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth, - nscoord& aComputedTableWidth, - PRBool aTableIsAutoWidth) -{ - // availWidth is the difference between the total available width and the - // amount of space already assigned, assuming auto col widths were assigned 0. - nscoord availWidth = PR_MAX(aTableSpecifiedWidth - aComputedTableWidth, 0); - TDBG_SDD(" aTableSpecifiedWidth specified as %d, availWidth is = %d\n", aTableSpecifiedWidth, availWidth); - if ((0 == availWidth) || (aTableSpecifiedWidth <= 0)) { - return; - } - nscoord sumOfMinWidths = 0; // sum of min widths of each auto column - nscoord startingComputedTableWidth = aComputedTableWidth; // remember this so we can see if we're making any progress - TDBG_SDD("DistributeRemainingSpace: fixed width %d > computed table width %d\n", - aTableSpecifiedWidth, aComputedTableWidth); - // if there are auto-sized columns, give them the extra space - PRInt32 numAutoColumns = 0; - PRInt32* autoColumns = nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); - if (0 == numAutoColumns) { - return; - } - nscoord totalResizeColWidth = 0; - // populate an array of col info for cols that qualify for being increased in width - PRInt32 numResizeCols = 0; - nsColInfo** resizeCols = new nsColInfo*[numAutoColumns]; - PRInt32 i; - for (i = 0; i < numAutoColumns; i++) { - PRInt32 colIndex = autoColumns[i]; - nsTableColFrame* colFrame = mTableFrame->GetColFrame(autoColumns[i]); - nscoord startingColWidth = mTableFrame->GetColumnWidth(colIndex); - nscoord maxColWidth = colFrame->GetMaxColWidth(); - if (0 == maxColWidth) - maxColWidth = startingColWidth; - totalResizeColWidth += maxColWidth; - // the maximizeFactor is a relative metric for determining when cols reach their max. - // A col with a smaller value will reach its max before one with a larger value. - nscoord delta = maxColWidth - startingColWidth; - float maximizeFactor = (0 >= delta) - ? 1000000 // cols which have already reached their max get a large value - : ((float)maxColWidth) / ((float)(maxColWidth - startingColWidth)); - resizeCols[numResizeCols] = new nsColInfo(colFrame, colIndex, startingColWidth, - maximizeFactor); - numResizeCols++; - } - if (totalResizeColWidth <= 0) { - NS_ASSERTION(PR_TRUE, "need to handle this case"); - DistributeRemainingSpaceCleanup(numResizeCols, resizeCols); - return; - } - - // sort the cols based on the maximizeFactor so that in one pass cols that reach their - // max earlier will get their max earlier and allow the other cols to reach their max. - // This is an innefficient bubble sort, but unless there are an unlikely large number of - // cols, it is not an issue. - for (int j = numResizeCols - 1; j > 0; j--) { - for (i = 0; i < j; i++) { - if (resizeCols[i]->mMaximizeFactor < resizeCols[i+1]->mMaximizeFactor) { // swap them - nsColInfo* save = resizeCols[i]; - resizeCols[i] = resizeCols[i+1]; - resizeCols[i+1] = save; - } - } - } - - - // compute the proportion to be added to each column, don't go beyond the col's max - // at this stage - PRInt32 totalResizeColWidthRemaining = totalResizeColWidth; - for (i = 0; i < numResizeCols; i++) { - if ((availWidth <= 0) || (totalResizeColWidthRemaining <= 0)) { - break; - } - nsTableColFrame* colFrame = resizeCols[i]->mColFrame; - nscoord startingColWidth = resizeCols[i]->mColWidth; - nscoord maxColWidth = colFrame->GetMaxColWidth(); - float percent = ((float)maxColWidth) / (float)totalResizeColWidthRemaining; - nscoord delta = PR_MIN(availWidth, NSToCoordRound(((float)(availWidth)) * percent)); - // don't go over the col max right now - nscoord excess = (startingColWidth + delta) - maxColWidth; - if (excess > 0) { - delta -= excess; - } - resizeCols[i]->mColWidth += delta; - availWidth -= delta; - totalResizeColWidthRemaining -= maxColWidth; - mTableFrame->SetColumnWidth(resizeCols[i]->mColIndex, resizeCols[i]->mColWidth); - TDBG_SDDDD(" DSR-1 colX=%d went from %d to %d based on percent=%d \n", resizeCols[i]->mColIndex, - startingColWidth, resizeCols[i]->mColWidth, (nscoord)((float)100*percent)); - } - // Auto width tables have reached their max at this point. If there is any remaining space - // in a fixed width table, allocate it to the cols based on max width, - if ((availWidth > 0) && (PR_FALSE == aTableIsAutoWidth)) { - for (i = 0; i < numResizeCols; i++) { - if (availWidth <= 0) { - break; - } - nsTableColFrame* colFrame = resizeCols[i]->mColFrame; - nscoord startingColWidth = resizeCols[i]->mColWidth; - nscoord maxColWidth = colFrame->GetMaxColWidth(); - // if we actually have room to distribute, do it here - float percent = ((float)maxColWidth) / (float)totalResizeColWidth; - nscoord delta = PR_MIN(availWidth, NSToCoordRound(((float)(availWidth)) * percent)); - nscoord newWidth = resizeCols[i]->mColWidth + delta; - mTableFrame->SetColumnWidth(resizeCols[i]->mColIndex, newWidth); - availWidth -= delta; - TDBG_SDDDD(" DSR-2 colX=%d went from %d to %d based on percent=%d \n", resizeCols[i]->mColIndex, - startingColWidth, resizeCols[i]->mColWidth, (nscoord)((float)100*percent)); - } - } - aComputedTableWidth = aTableSpecifiedWidth - availWidth; - DistributeRemainingSpaceCleanup(numResizeCols, resizeCols); - TDBG_WIDTHS4("at end of DistributeRemainingSpace: ",PR_FALSE,PR_FALSE); -} -#endif - -void BasicTableLayoutStrategy::AdjustTableThatIsTooWide(nscoord aComputedWidth, - nscoord aTableWidth, - PRBool aShrinkFixedCols) -{ - TDBG_WIDTHS4("before AdjustTableThatIsTooWide: ",PR_FALSE,PR_FALSE); - - PRInt32 numFixedColumns = 0; - PRInt32* fixedColumns = nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); - PRInt32 numAutoColumns = 0; - PRInt32* autoColumns = nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); - nscoord excess = aComputedWidth - aTableWidth; - nscoord minDiff; // the smallest non-zero delta between a column's current width and its min width - PRInt32* colsToShrink = new PRInt32[mNumCols]; - // while there is still extra computed space in the table - while (0 < excess) { - // reinit state variables - PRInt32 colIndex; - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - colsToShrink[colIndex] = 0; - } - minDiff = 0; - - // determine what columns we can remove width from - PRInt32 numColsToShrink = 0; - PRBool shrinkAutoOnly = PR_TRUE; - PRBool keepLooking = PR_TRUE; - while (PR_TRUE == keepLooking) { - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - nscoord currentColWidth = mTableFrame->GetColumnWidth(colIndex); - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(colIndex, colFrame); - nscoord minColWidth = colFrame->GetAdjustedMinColWidth(); - if (currentColWidth == minColWidth) { - continue; - } - if ((PR_FALSE==aShrinkFixedCols) && - (PR_TRUE==IsColumnInList(colIndex, fixedColumns, numFixedColumns))) { - continue; - } - if ((PR_TRUE==shrinkAutoOnly) && - (PR_FALSE==IsColumnInList(colIndex, autoColumns, numAutoColumns))) { - continue; - } - colsToShrink[numColsToShrink] = colIndex; - numColsToShrink++; - nscoord diff = currentColWidth - minColWidth; - if ((0 == minDiff) || (diff < minDiff)) { - minDiff = diff; - } - } - if (PR_FALSE == shrinkAutoOnly) { - keepLooking = PR_FALSE; // we've looked everywhere, so bail. this breaks us out of the loop - } - if (0 != numColsToShrink) { - keepLooking = PR_FALSE; // we found at least one column to shrink, so bail. this breaks us out of the loop - } - shrinkAutoOnly = PR_FALSE;// this guarantees we'll go through this loop only one more time - } - // if there are no columns we can remove space from, we're done - if (0 == numColsToShrink) { - break; - } - - // determine the amount to remove from each column - nscoord excessPerColumn; - if (excess < numColsToShrink) { - excessPerColumn = 1; - } - else { - excessPerColumn = excess / numColsToShrink; // guess we can remove as much as we want - } - if (excessPerColumn > minDiff) { // then adjust for minimum col widths - excessPerColumn = minDiff; - } - // remove excessPerColumn from every column we've determined we can remove width from - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - if ((PR_TRUE == IsColumnInList(colIndex, colsToShrink, numColsToShrink))) { - nscoord colWidth = mTableFrame->GetColumnWidth(colIndex); - colWidth -= excessPerColumn; - mTableFrame->SetColumnWidth(colIndex, colWidth); - excess -= excessPerColumn; - if (0 == excess) { - break; - } - } - } - } // end while (0 < excess) - TDBG_WIDTHS4("after AdjustTableThatIsTooWide: ",PR_TRUE,aShrinkFixedCols); - - delete [] colsToShrink; - - // deal with any excess left over - if ((PR_FALSE == aShrinkFixedCols) && (0 != excess)) { - // if there's any excess left, we know we've shrunk every non-fixed column to its min - // so we have to shrink fixed width columns if possible - AdjustTableThatIsTooWide(aComputedWidth, aTableWidth, PR_TRUE); - } - // otherwise we've shrunk the table to its min, and that's all we can do -} - - -void BasicTableLayoutStrategy::AdjustTableThatIsTooNarrow(nscoord aComputedWidth, - nscoord aTableWidth) -{ - TDBG_WIDTHS4("before AdjustTableThatIsTooNarrow: ",PR_FALSE,PR_FALSE); - - PRInt32 numFixedColumns=0; - PRInt32* fixedColumns=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); - nscoord excess = aTableWidth - aComputedWidth; - while (0 < excess) { - PRInt32 colIndex; - PRInt32* colsToGrow = new PRInt32[mNumCols]; - // determine what columns we can take add width to - PRInt32 numColsToGrow = 0; - PRBool expandFixedCols = PRBool(mNumCols == numFixedColumns); - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - if ((PR_FALSE == expandFixedCols) && - (PR_TRUE == IsColumnInList(colIndex, fixedColumns, numFixedColumns))) { - // skip fixed-width cells if we're told to - continue; - } - if (PR_TRUE == ColIsSpecifiedAsMinimumWidth(colIndex)) { - // skip columns that are forced by their attributes to be their minimum width - continue; - } - colsToGrow[numColsToGrow] = colIndex; - numColsToGrow++; - } - if (0 != numColsToGrow) { - nscoord excessPerColumn; - if (excessGetColFrame(colIndex); - nscoord colWidth = mTableFrame->GetColumnWidth(colIndex); - colWidth += excessPerColumn; - if (colWidth > colFrame->GetMinColWidth()) { - excess -= excessPerColumn; - mTableFrame->SetColumnWidth(colIndex, colWidth); - } - else { - excess -= mTableFrame->GetColumnWidth(colIndex) - colFrame->GetMinColWidth(); - mTableFrame->SetColumnWidth(colIndex, colFrame->GetMinColWidth()); - } - if (0 >= excess) { - break; - } - } - } - } - delete [] colsToGrow; - if (0 == numColsToGrow) { - break; - } - } // end while (0 < excess) - - TDBG_WIDTHS4("after AdjustTableThatIsTooNarrow: ",PR_FALSE,PR_FALSE); -} PRBool BasicTableLayoutStrategy::IsColumnInList(const PRInt32 colIndex, PRInt32* colIndexes, @@ -2603,51 +1281,19 @@ PRBool BasicTableLayoutStrategy::ColIsSpecifiedAsMinimumWidth(PRInt32 aColIndex) return result; } -// returns a list and count of all columns that behave like they have width=auto -// this includes columns with no width specified, and columns whose fixed width comes from a span -void BasicTableLayoutStrategy::GetColumnsThatActLikeAutoWidth(PRInt32& aNumCols, - PRInt32*& aColList) +void BasicTableLayoutStrategy::Dump(PRInt32 aIndent) { - // initialize out params - aNumCols = 0; - aColList = nsnull; - - // get the auto columns - PRInt32 numAutoCols=0; - PRInt32* autoColList=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoCols, autoColList); - - // XXX: have to do next step for %-width as well? - - // get the fixed columns - PRInt32 numFixedCols=0; - PRInt32* fixedColList=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedCols, fixedColList); - - if (0 < numAutoCols+numFixedCols) { - // allocate the out param aColList to the biggest it could be (usually a little wasteful, but it's - // temp space and the numbers here are small, even for very big tables - aColList = new PRInt32[numAutoCols+numFixedCols]; - - // transfer the auto columns to aColList - PRInt32 i; - for (i = 0; i < numAutoCols; i++) { - aColList[i] = autoColList[i]; - aNumCols++; - } - - // get the columns whose fixed width is due to a colspan and transfer them to aColList - for (i = 0; i < numFixedCols; i++) { - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(fixedColList[i], colFrame); - if (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN==colFrame->GetWidthSource()) { - aColList[aNumCols] = fixedColList[i]; - aNumCols++; - } - } + char* indent = new char[aIndent + 1]; + for (PRInt32 i = 0; i < aIndent + 1; i++) { + indent[i] = ' '; } + indent[aIndent] = 0; - return; + printf("%s**START BASIC STRATEGY DUMP** table=%X cols=%d numCols=%d", + indent, mTableFrame, mCols, mNumCols); + printf("\n%s minConWidth=%d maxConWidth=%d cellSpacing=%d propRatio=%.2f navQuirks=%d", + indent, mMinTableContentWidth, mMaxTableContentWidth, mCellSpacingTotal, mMinToDesProportionRatio, mIsNavQuirksMode); + printf(" **END BASIC STRATEGY DUMP** \n"); + delete [] indent; } - diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h index 55c207a995a..ced57d07290 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h @@ -28,44 +28,8 @@ class nsTableFrame; struct nsStylePosition; struct nsStyleTable; -/* ----------- SpanInfo ---------- */ - -/** SpanInfo is a transient data structure that holds info about - * cells that have col spans. Used during column balancing. - */ -// TODO: collapse this data structure with ColSpanStruct. They both (incompletely) describe -// the same situation with slightly different data. -struct SpanInfo -{ - PRInt32 span; - const PRInt32 initialColSpan; - const PRInt32 initialColIndex; - nscoord cellMinWidth; - nscoord cellDesiredWidth; - nscoord effectiveMinWidthOfSpannedCols; - nscoord effectiveMaxWidthOfSpannedCols; - - SpanInfo(PRInt32 aColIndex, PRInt32 aSpan, nscoord aMinWidth, nscoord aDesiredWidth); - ~SpanInfo() {}; - -}; - static const PRInt32 kUninitialized=-1; -inline SpanInfo::SpanInfo(PRInt32 aColIndex, PRInt32 aSpan, - nscoord aMinWidth, nscoord aDesiredWidth) - : initialColSpan(aSpan), - initialColIndex(aColIndex) -{ - span = aSpan; - cellMinWidth = aMinWidth; - cellDesiredWidth = aDesiredWidth; - effectiveMinWidthOfSpannedCols=kUninitialized; - effectiveMaxWidthOfSpannedCols=kUninitialized; -} - - - /* ---------- BasicTableLayoutStrategy ---------- */ /** Implementation of Nav4 compatible HTML browser table layout. @@ -98,21 +62,23 @@ public: */ virtual void SetMaxElementSize(nsSize* aMaxElementSize); + void SetMinAndMaxTableContentWidths(); + /** Called during resize reflow to determine the new column widths * @param aTableStyle - the resolved style for mTableFrame * @param aReflowState - the reflow state for mTableFrame * @param aMaxWidth - the computed max width for columns to fit into */ - virtual PRBool BalanceColumnWidths(nsIStyleContext * aTableStyle, + virtual PRBool BalanceColumnWidths(nsIStyleContext* aTableStyle, const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth); + nscoord aMaxWidth); // these accessors are mostly for debugging purposes - nscoord GetTableMinWidth() const; - nscoord GetTableMaxWidth() const; - nscoord GetTableFixedWidth() const; + nscoord GetTableMinContentWidth() const; + nscoord GetTableMaxContentWidth() const; nscoord GetCOLSAttribute() const; nscoord GetNumCols() const; + void Dump(PRInt32 aIndent); protected: @@ -130,125 +96,30 @@ protected: */ 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. - */ - virtual void SetMinAndMaxTableWidths(); + nscoord AssignPercentageColumnWidths(nscoord aBasis, + PRBool aTableIsAutoWidth); - /** assign widths for each column within a particular context. - * The context is given by each of the parameters. - * Sets mTableFrame->mColumnWidths as a side effect. - * - * @param aReflowState the reflow state - * @param aAvailWidth the remaining amount of horizontal space available - * @param aMaxWidth the total amount of horizontal space available - * @param aTableSpecifiedWidth the width of the table based on its attributes and its parent's width - * @param aTableIsAutoWidth PR_TRUE if the table is auto-width - * - * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error - * - */ - virtual PRBool BalanceProportionalColumns(const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aTableSpecifiedWidth, - PRBool aTableIsAutoWidth); + void CalculateTotals(PRInt32& aCellSpacing, + PRInt32* aTotalCounts, + PRInt32* aTotalWidths, + PRInt32* aMinWidths, + PRInt32& a0ProportionalCount); - /** assign the minimum legal width for each column that has proportional width. - * Typically called when the min table width doesn't fit in the available space. - * Sets mTableFrame->mColumnWidths as a side effect. - * - * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error - */ - virtual PRBool BalanceColumnsTableDoesNotFit(); + void AllocateFully(nscoord& aTotalAllocated, + PRInt32* aAllocTypes, + PRInt32 aWidthType, + PRBool aMarkAllocated = PR_TRUE); - /** assign the maximum allowed width for each column. - * Typically called when the desired max table width is less than or equal to the available space. - * Sets mTableFrame->mColumnWidths as a side effect. - * - * @param aReflowState the reflow state - * @param aAvailWidth the remaining amount of horizontal space available - * @param aMaxWidth the total amount of horizontal space available - * @param aTableSpecifiedWidth the specified width of the table. If there is none, - * this param is 0 - * @param aTableIsAutoWidth PR_TRUE if the table is auto-width - * - * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error - */ - virtual PRBool BalanceColumnsTableFits(const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aTableSpecifiedWidth, - PRBool aTableIsAutoWidth); + void AllocateConstrained(PRInt32 aAvailWidth, + PRInt32 aWidthType, + PRInt32 aNumConstrainedCols, + PRInt32 aSumMaxConstraints, + PRBool aStartAtMin, + PRInt32* aAllocTypes); - /** for each column, assign a width between the column's minimum and maximum width. - * Typically called when the desired max table width is greater the available space. - * Sets mTableFrame->mColumnWidths as a side effect. - * - * @param aReflowState the reflow state - * @param aAvailWidth the remaining amount of horizontal space available - * @param aMaxWidth the total amount of horizontal space available - * @param aTableIsAutoWidth PR_TRUE if the table is auto-width - * - * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error - * - */ - virtual PRBool BalanceColumnsConstrained(const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - PRBool aTableIsAutoWidth); - - /** post-process to AssignFixedColumnWidths - * - * @param aColSpanList a list of fixed-width columns that have colspans - * - * NOTE: does not yet properly handle overlapping col spans in all cases - * - * @return void - */ - virtual void DistributeFixedSpace(nsVoidArray *aColSpanList); - - /** starting with a partially balanced table, compute the amount - * of space to pad each column by to completely balance the table. - * Sets mTableFrame->mColumnWidths as a side effect. - * - * @param aAvailWidth the space still to be allocated within the table - * @param aTableWidth the sum of all columns widths - * @param aWidthOfFixedTableColumns the sum of the widths of fixed-width columns - * - * @return void - */ - virtual void DistributeExcessSpace(nscoord aAvailWidth, - nscoord aTableWidth, - nscoord aWidthOfFixedTableColumns); - - /** starting with a partially balanced table, compute the amount - * of space to allocate to each column to completely balance the table. - * set the column widths in mTableFrame based on these computations. - * assumes auto-width columns have been set to their minimum width. - * must be called with a PRInt32 variable initialized to 0 for aRecursionControl. - * - * @param aTableFixedWidth the specified width of the table. If there is none, - * this param is 0 - * @param aComputedTableWidth IN: the width of the table before this step. - * OUT:the width of the table after this step. - * @param aTableIsAutoWidth TRUE if the table style indicates it is autoWidth - * @param aRecursionControl IN: must be a PRInt32 set to 0 - * OUT: the number of iterations. Not generally useful to the caller, - * but useful for limiting the number of iterations in bizarre cases. - * - * @return void - */ - virtual void DistributeRemainingSpace(nscoord aTableFixedWidth, - nscoord &aComputedTableWidth, - PRBool aTableIsAutoWidth); - - virtual void AdjustTableThatIsTooWide(nscoord aComputedWidth, - nscoord aTableWidth, - PRBool aShrinkFixedCols); - - virtual void AdjustTableThatIsTooNarrow(nscoord aComputedWidth, - nscoord aTableWidth); + void AllocateUnconstrained(PRInt32 aAllocAmount, + PRInt32* aAllocTypes, + PRBool aSkip0Proportional); /** return true if the style indicates that the width is a specific width * for the purposes of column width determination. @@ -279,31 +150,26 @@ protected: */ void GetColumnsThatActLikeAutoWidth(PRInt32& aOutNumColumns, PRInt32*& aOutColumnIndexes); - - nscoord CalcHorizontalPadding(PRInt32 aColX); - + void ContinuingFrameCheck(); protected: nsTableFrame * mTableFrame; PRInt32 mCols; PRInt32 mNumCols; // cached data - nscoord mMinTableWidth; // the smallest size for the table - nscoord mMaxTableWidth; // the "natural" size for the table, if unconstrained - nscoord mFixedTableWidth; // the amount of space taken up by fixed-width columns - PRBool mIsNavQuirksMode; - + nscoord mMinTableContentWidth; // the smallest size for the table (excluding border and padding) + nscoord mMaxTableContentWidth; // the "natural" size for the table, if unconstrained (excluding border and padding) + nscoord mCellSpacingTotal; // all of the cellspacing for all of the cols + float mMinToDesProportionRatio; + PRPackedBool mIsNavQuirksMode; }; // these accessors are mostly for debugging purposes -inline nscoord BasicTableLayoutStrategy::GetTableMinWidth() const -{ return mMinTableWidth; }; +inline nscoord BasicTableLayoutStrategy::GetTableMinContentWidth() const +{ return mMinTableContentWidth; }; -inline nscoord BasicTableLayoutStrategy::GetTableMaxWidth() const -{ return mMaxTableWidth; }; - -inline nscoord BasicTableLayoutStrategy::GetTableFixedWidth() const -{ return mFixedTableWidth; }; +inline nscoord BasicTableLayoutStrategy::GetTableMaxContentWidth() const +{ return mMaxTableContentWidth; }; inline nscoord BasicTableLayoutStrategy::GetCOLSAttribute() const { return mCols; }; diff --git a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp index 3176567187e..5abc56bf826 100644 --- a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp @@ -44,33 +44,17 @@ FixedTableLayoutStrategy::~FixedTableLayoutStrategy() { } -PRBool FixedTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext *aTableStyle, +PRBool FixedTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableStyle, const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth) + nscoord aMaxWidth) { -#ifdef NS_DEBUG - nsIFrame *tablePIF=nsnull; - mTableFrame->GetPrevInFlow(&tablePIF); - NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!"); -#endif - - PRBool result = PR_TRUE; - - NS_ASSERTION(nsnull!=aTableStyle, "bad arg"); - if (nsnull==aTableStyle) - return PR_FALSE; - - - if (PR_TRUE==gsDebug) - { + if (PR_TRUE==gsDebug) { printf("\n%p: BALANCE COLUMN WIDTHS\n", mTableFrame); for (PRInt32 i=0; iGetColumnWidth(i)); printf("\n"); } - - // XXX Hey Cujo, result has never been initialized... - return result; + return PR_TRUE; } /* @@ -112,8 +96,10 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed for (colX = 0; colX < mNumCols; colX++) { // Get column information nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); - NS_ASSERTION(nsnull != colFrame, "bad col frame"); - if (!colFrame) return PR_FALSE; + if (!colFrame) { + NS_ASSERTION(PR_FALSE, "bad col frame"); + return PR_FALSE; + } // Get the columns's style const nsStylePosition* colPosition; @@ -136,7 +122,7 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed const nsStylePosition* cellPosition; cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colX, cellFrame); + PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(cellFrame); // Get fixed cell width if available if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { colWidths[colX] = cellPosition->mWidth.GetCoordValue() / colSpan; @@ -205,8 +191,8 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed } // 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); + mMinTableContentWidth = mMaxTableContentWidth = totalColWidth; + if (PR_TRUE == gsDebug) printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, mMinTableContentWidth, mMaxTableContentWidth); // clean up if (nsnull != colWidths) { diff --git a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h index d012b2a86de..3e1c7442b96 100644 --- a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.h @@ -54,9 +54,9 @@ public: * @param aReflowState - the reflow state for mTableFrame * @param aMaxWidth - the computed max width for columns to fit into */ - virtual PRBool BalanceColumnWidths(nsIStyleContext * aTableStyle, - const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth); + virtual PRBool BalanceColumnWidths(nsIStyleContext* aTableStyle, + const nsHTMLReflowState& aReflowState, + nscoord aMaxWidth); protected: /* assign the width of all columns diff --git a/mozilla/layout/html/table/src/celldata.h b/mozilla/layout/html/table/src/celldata.h index 29134571b65..f739ea4e7e4 100644 --- a/mozilla/layout/html/table/src/celldata.h +++ b/mozilla/layout/html/table/src/celldata.h @@ -21,9 +21,8 @@ class nsTableCellFrame; /** Data stored by nsCellMap to rationalize rowspan and colspan cells. - * if mCell is null then mRealCell will be the rowspan/colspan source - * in addition, if fOverlap is non-null then it will point to the - * other cell that overlaps this position + * if mOrigCell is null then mSpanCell will be the rowspan/colspan source. + * if mSpanCell2 is non-null then it will point to a 2nd cell that overlaps this position * @see nsCellMap * @see nsTableFrame::BuildCellMap * @see nsTableFrame::GrowCellMap @@ -33,17 +32,26 @@ class nsTableCellFrame; class CellData { public: - /** if not null, the cell that this CellData maps. - * if null, mRealCell points to the CellData that holds the - * mapped cell frame. - */ - nsTableCellFrame *mCell; - CellData *mRealCell; - CellData *mOverlap; - CellData(); + CellData(nsTableCellFrame* aOrigCell, CellData* aSpanData, CellData* aSpanData2) + : mOrigCell(aOrigCell), mSpanData(aSpanData), mSpanData2(aSpanData2) + {} ~CellData(); + PRBool IsSpannedBy(nsTableCellFrame* aCellFrame) + { + return (mSpanData && mSpanData->mOrigCell == aCellFrame) || + (mSpanData2 && mSpanData2->mOrigCell == aCellFrame); + } + PRBool IsOccupiedBy(nsTableCellFrame* aCellFrame) + { + return (mOrigCell == aCellFrame) || IsSpannedBy(aCellFrame); + } + + nsTableCellFrame* mOrigCell; // mCell + CellData* mSpanData; // mRealCell + CellData* mSpanData2; // mOverlap + }; #endif diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp index e95eb7c1569..ac9300882ae 100644 --- a/mozilla/layout/html/table/src/nsCellMap.cpp +++ b/mozilla/layout/html/table/src/nsCellMap.cpp @@ -28,44 +28,39 @@ static const PRBool gsDebug = PR_FALSE; #endif nsCellMap::nsCellMap(int aRowCount, int aColCount) - : mRows(nsnull), - mMinColSpans(nsnull), - mColFrames(nsnull), - mRowCount(0), - mTotalRowCount(0), - mColCount(0), - mIsCollapsedRows(nsnull), + : mRowCount(0), mNumCollapsedRows(0), - mIsCollapsedCols(nsnull), - mNumCollapsedCols(0) + mNumCollapsedCols(0), + mNextAvailRowIndex(0) { - Reset(aRowCount, aColCount); + mIsCollapsedRows = nsnull; + mIsCollapsedCols = nsnull; + + Grow(aRowCount, aColCount); } nsCellMap::~nsCellMap() { - if (nsnull!=mRows) - { - for (int i=mTotalRowCount-1; 0<=i; i--) - { - nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(i)); - for (int j=mColCount-1; 0<=j ;j--) - { - CellData* data = (CellData *)(row->ElementAt(j)); - if (data != nsnull) - { - delete data; - } + PRInt32 mapRowCount = mRows.Count(); + PRInt32 colCount = mNumCellsInCol.Count(); + PRInt32 colX; + for (PRInt32 rowX = 0; rowX < mapRowCount; rowX++) { + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(rowX)); + for (colX = 0; colX <= colCount; colX++) { + CellData* data = (CellData *)(row->ElementAt(colX)); + if (data) { + delete data; } - delete row; } - delete mRows; + delete row; } - if (nsnull != mColFrames) - delete mColFrames; - // mMinColSpans may be null, it is only set for tables that need it - if (nsnull != mMinColSpans) - delete [] mMinColSpans; + for (colX = 0; colX < colCount; colX++) { + PRInt32* val = (PRInt32 *)mNumCellsInCol.ElementAt(colX); + if (val) { + delete [] val; + } + } + if (nsnull != mIsCollapsedRows) { delete [] mIsCollapsedRows; mIsCollapsedRows = nsnull; @@ -76,171 +71,379 @@ nsCellMap::~nsCellMap() mIsCollapsedCols = nsnull; mNumCollapsedCols = 0; } - mRows = nsnull; - mColFrames = nsnull; - mMinColSpans = nsnull; }; - -void nsCellMap::Reset(int aRowCount, int aColCount) +void nsCellMap::AddColsAtEnd(PRUint32 aNumCols) { - if (gsDebug) printf("calling Reset(%d,%d) with mRC=%d, mCC=%d, mTRC=%d\n", - aRowCount, aColCount, mRowCount, mColCount, mTotalRowCount); - if (nsnull==mColFrames) - { - mColFrames = new nsVoidArray(); // don't give the array a count, because null col frames are illegal (unlike null cell entries in a row) - } - - if (nsnull==mRows) - { - mRows = new nsVoidArray(); // don't give the array a count, because null rows are illegal (unlike null cell entries in a row) - } - - // void arrays force the caller to handle null padding elements themselves - // so if the number of columns has increased, we need to add extra cols to each row - for (PRInt32 rowIndex=0; rowIndexElementAt(rowIndex)); - const PRInt32 colsInRow = row->Count(); - if (colsInRow == aColCount) - break; // we already have enough columns in each row - for (PRInt32 colIndex = colsInRow; colIndexAppendElement(nsnull); - } - - // if the number of rows has increased, add the extra rows - PRInt32 newRows = aRowCount-mTotalRowCount; // (new row count) - (total row allocation) - for ( ; newRows > 0; newRows--) { - nsVoidArray *row; - if (0 != aColCount) { - row = new nsVoidArray(aColCount); - } else { - row = new nsVoidArray(); - } - mRows->AppendElement(row); - } - - mRowCount = aRowCount; - mTotalRowCount = PR_MAX(mTotalRowCount, mRowCount); - mColCount = aColCount; - - if (gsDebug) printf("leaving Reset with mRC=%d, mCC=%d, mTRC=%d\n", - mRowCount, mColCount, mTotalRowCount); + Grow(mRowCount, mNumCellsInCol.Count() + aNumCols); } -void nsCellMap::DumpCellMap() const +PRInt32 nsCellMap::GetNextAvailRowIndex() { - if (gsDebug==PR_TRUE) - { - printf("Cell Map =\n"); - for (int rowIndex=0; rowIndexElementAt(rowIndex)); - for (int colIndex=0; colIndexElementAt(colIndex)); - printf("Cell [%d,%d] = %p\n", rowIndex, colIndex, data); + return mNextAvailRowIndex++; +} + +void nsCellMap::Grow(PRInt32 aNumMapRows, + PRInt32 aNumCols) +{ + if (gsDebug) printf("calling Grow(%d,%d) with mapRC=%d, RC=%d, CC=%d\n", aNumMapRows, aNumCols, mRows.Count(), mRowCount, mNumCellsInCol.Count()); + PRInt32 origNumMapRows = mRows.Count(); + PRInt32 origNumCols = mNumCellsInCol.Count(); + + // if the number of columns has increased, we need to add extra cols to mNumColsOriginating and + // each row in mRows. + if (origNumCols < aNumCols) { + PRInt32 colX; + for (PRInt32 rowX = 0; rowX < origNumMapRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(rowX)); + const PRInt32 colsInRow = row->Count(); + for (colX = colsInRow; colX < aNumCols; colX++) { + row->AppendElement(nsnull); + } + } + // update the col array + for (colX = origNumCols; colX < aNumCols; colX++) { + PRInt32* val = new PRInt32[2]; + val[0] = val[1] = 0; + mNumCellsInCol.AppendElement(val); + } + } + + // if the number of rows has increased, add the extra rows. the new + // rows get the new number of cols + PRInt32 newRows = aNumMapRows - origNumMapRows; + for ( ; newRows > 0; newRows--) { + nsVoidArray* row; + row = (0 == aNumCols) ? new nsVoidArray() : new nsVoidArray(aNumCols); + mRows.AppendElement(row); + } + if (gsDebug) printf("leaving Grow with TRC=%d, TCC=%d\n", mRows.Count(), mNumCellsInCol.Count()); +} + +PRInt32 nsCellMap::AppendCell(nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) +{ + NS_ASSERTION(aCellFrame, "bad cell frame"); + + PRInt32 origNumMapRows = mRows.Count(); + PRInt32 origNumCols = mNumCellsInCol.Count(); + + // get the first null CellData in the desired row. It may be 1 past the end if there are none + PRInt32 startColIndex; + if (aRowIndex < origNumMapRows) { + for (startColIndex = 0; startColIndex < origNumCols; startColIndex++) { + CellData* data = GetMapCellAt(aRowIndex, startColIndex); + if (!data) { + break; // we found the col } } } -} - -void nsCellMap::GrowToRow(PRInt32 aRowCount) -{ - Reset(aRowCount, mColCount); -} - -void nsCellMap::GrowToCol(PRInt32 aColCount) -{ - Reset(mRowCount, aColCount); -} - -void nsCellMap::SetCellAt(CellData *aCell, int aRowIndex, int aColIndex) -{ - NS_PRECONDITION(nsnull!=aCell, "bad aCell"); - PRInt32 newRows = (aRowIndex+1)-mTotalRowCount; // add 1 to the "index" to get a "count" - if (00; newRows--) - { - nsVoidArray *row = new nsVoidArray(mColCount); - mRows->AppendElement(row); - } - mTotalRowCount = aRowIndex+1; // remember to always add 1 to an index when you want a count + else { + startColIndex = 0; } - CellData* cell = GetCellAt(aRowIndex,aColIndex); - if (cell != nsnull) - delete cell; - nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex)); - row->ReplaceElementAt(aCell, aColIndex); - if (gsDebug) printf("leaving SetCellAt(%p,%d,%d) with mRC=%d, mCC=%d, mTRC=%d\n", - aCell, aRowIndex, aColIndex, mRowCount, mColCount, mTotalRowCount); + mRowCount = PR_MAX(mRowCount, aRowIndex + 1); + + PRInt32 rowSpan = aCellFrame->GetRowSpan(); + PRInt32 colSpan = aCellFrame->GetColSpan(); + if (gsDebug) printf("AppendCell: rowSpan = %d, colSpan = %d\n", rowSpan, colSpan); + // Grow. we may need to add new rows/cols + PRInt32 spanNumRows = aRowIndex + rowSpan; + PRInt32 spanNumCols = startColIndex + colSpan; + if ((spanNumRows >= origNumMapRows) || (spanNumCols >= origNumCols)) { + Grow(spanNumRows, spanNumCols); + } + + // Setup CellData for this cell + CellData* origData = new CellData(aCellFrame, nsnull, nsnull); + if (gsDebug) printf("AppendCell: calling SetMapCellAt(data, %d, %d)\n", aRowIndex, startColIndex); + SetMapCellAt(*origData, aRowIndex, startColIndex); + + // reset the col index of the cell frame + PRInt32 oldColIndex; + aCellFrame->GetColIndex(oldColIndex); + if (startColIndex != oldColIndex) { + // only do this if they are different since it changes content + aCellFrame->SetColIndex(startColIndex); + } + + // Create CellData objects for the rows that this cell spans. Set + // their mOrigCell to nsnull and their mSpanData to point to data. + for (PRInt32 rowX = aRowIndex; rowX < spanNumRows; rowX++) { + for (PRInt32 colX = startColIndex; colX < spanNumCols; colX++) { + if ((rowX != aRowIndex) || (colX != startColIndex)) { // skip orig cell data done above + CellData* cellData = GetMapCellAt(rowX, colX); + if (cellData) { + NS_ASSERTION(!cellData->mOrigCell, "cannot overlap originating cell"); + if (cellData->mSpanData) { + NS_ASSERTION(!cellData->mSpanData2, "too many overlaps"); + cellData->mSpanData2 = origData; + } + else { + cellData->mSpanData = origData; + } + } + else { + cellData = new CellData(nsnull, origData, nsnull); + SetMapCellAt(*cellData, rowX, colX); + } + } + } + } + return startColIndex; } +void nsCellMap::RemoveCell(nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) +{ + // XXX write me. For now the cell map is recalculate from scratch when a cell is deleted +} + +PRInt32 nsCellMap::GetNumCellsIn(PRInt32 aColIndex, PRBool aOriginating) +{ + PRInt32 colCount = mNumCellsInCol.Count(); + if ((aColIndex >= 0) && (aColIndex < colCount)) { + PRInt32* numCellsArray = (PRInt32 *)mNumCellsInCol.ElementAt(aColIndex); + PRInt32 numCells = (aOriginating) ? *numCellsArray : *(numCellsArray + 1); + return numCells; + } + else { + NS_ASSERTION(PR_FALSE, "nsCellMap::GetNumCellsIn - bad col index"); + return 0; + } +} + +PRInt32 nsCellMap::GetNumCellsIn(PRInt32 aColIndex) +{ + return GetNumCellsIn(aColIndex, 1); +} + +PRInt32 nsCellMap::GetNumCellsOriginatingIn(PRInt32 aColIndex) +{ + return GetNumCellsIn(aColIndex, 0); +} + +#ifdef NS_DEBUG +void nsCellMap::Dump() const +{ + printf("***** start CellMap Dump *****\n"); + PRInt32 mapRowCount = mRows.Count(); + PRInt32 colCount = mNumCellsInCol.Count(); + PRInt32 colIndex; + printf("mapRowCount=%d tableRowCount=%d, colCount=%d \n", mapRowCount, mRowCount, colCount); + + for (PRInt32 rowIndex = 0; rowIndex < mapRowCount; rowIndex++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowIndex); + printf("row %d : ", rowIndex); + for (colIndex = 0; colIndex < colCount; colIndex++) { + CellData* cd = (CellData *)row->ElementAt(colIndex); + if (cd) { + if (cd->mOrigCell) { + printf("C%d,%d ", rowIndex, colIndex); + } else { + nsTableCellFrame* cell = cd->mSpanData->mOrigCell; + nsTableRowFrame* row; + cell->GetParent((nsIFrame**)&row); + int rr = row->GetRowIndex(); + int cc; + cell->GetColIndex(cc); + printf("S%d,%d ", rr, cc); + if (cd->mSpanData2){ + cell = cd->mSpanData2->mOrigCell; + nsTableRowFrame* row2; + cell->GetParent((nsIFrame**)&row2); + rr = row2->GetRowIndex(); + cell->GetColIndex(cc); + printf("O%d,%c ", rr, cc); + } + } + } else { + printf("---- "); + } + } + printf("\n"); + } + + // output info mapping Ci,j to cell address + PRInt32 cellCount = 0; + for (PRInt32 rIndex = 0; rIndex < mapRowCount; rIndex++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rIndex); + for (colIndex = 0; colIndex < colCount; colIndex++) { + CellData* cd = (CellData *)row->ElementAt(colIndex); + if (cd) { + if (cd->mOrigCell) { + nsTableCellFrame* cellFrame = cd->mOrigCell; + PRInt32 cellFrameColIndex; + cellFrame->GetColIndex(cellFrameColIndex); + printf("C%d,%d=%p(%d) ", rIndex, colIndex, cellFrame, cellFrameColIndex); + cellCount++; + } + } + } + printf("\n"); + } + + // output col frame info + printf("\n col frames ->"); + for (colIndex = 0; colIndex < mColFrames.Count(); colIndex++) { + nsTableColFrame* colFrame = (nsTableColFrame *)mColFrames.ElementAt(colIndex); + if (0 == (colIndex % 8)) + printf("\n"); + printf ("%d=%p ", colIndex, colFrame); + } + // output cells originating in cols + printf ("\ncells in/originating in cols array -> "); + for (colIndex = 0; colIndex < colCount; colIndex++) { + PRInt32* numCells = (PRInt32 *)mNumCellsInCol.ElementAt(colIndex); + printf ("%d=%d,%d ", colIndex, *numCells, *(numCells + 1)); + } + printf("\n"); + printf("\n***** end CellMap Dump *****\n"); +} +#endif + +// only called if the cell at aMapRowIndex, aColIndex is null +void nsCellMap::SetMapCellAt(CellData& aNewCell, + PRInt32 aMapRowIndex, + PRInt32 aColIndex) +{ + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(aMapRowIndex)); + row->ReplaceElementAt(&aNewCell, aColIndex); + // update the col array + PRInt32* numCells = (PRInt32 *)mNumCellsInCol.ElementAt(aColIndex); + if (aNewCell.mOrigCell) { // cell originates in this col + (*numCells)++; + } + (*(numCells + 1))++; // cell occupies this col +} + +PRInt32 nsCellMap::GetEffectiveColSpan(PRInt32 aColIndex, nsTableCellFrame* aCell) +{ + NS_PRECONDITION(nsnull != aCell, "bad cell arg"); + + PRInt32 initialRowX; + aCell->GetRowIndex(initialRowX); + + PRInt32 effColSpan = 0; + PRInt32 colCount = mNumCellsInCol.Count(); + for (PRInt32 colX = aColIndex; colX < colCount; colX++) { + CellData* cellData = GetCellAt(initialRowX, colX); + if (cellData && cellData->IsOccupiedBy(aCell)) { + effColSpan++; + } + else { + break; + } + } + if (effColSpan == 0) { + //Dump(); + printf("hello"); + } + NS_ASSERTION(effColSpan > 0, "invalid col span or col index"); + return effColSpan; +} + +void nsCellMap::GetCellInfoAt(PRInt32 aRowX, + PRInt32 aColX, + nsTableCellFrame*& aCellFrame, + PRBool& aOriginates, + PRInt32& aColSpan) +{ + aCellFrame = GetCellFrameAt(aRowX, aColX); + if (aCellFrame) { + aOriginates = PR_TRUE; + PRInt32 initialColIndex; + aCellFrame->GetColIndex(initialColIndex); + aColSpan = GetEffectiveColSpan(initialColIndex, aCellFrame); + } + else { + aOriginates = PR_FALSE; + aColSpan = 0; + } +} + + + nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex) const { - NS_ASSERTION(nsnull!=mColFrames, "bad state"); - return (nsTableColFrame *)(mColFrames->ElementAt(aColIndex)); + return (nsTableColFrame *)(mColFrames.ElementAt(aColIndex)); } - -void nsCellMap::SetMinColSpan(PRInt32 aColIndex, PRBool aColSpan) +PRInt32 nsCellMap::GetNumCollapsedRows() { - NS_ASSERTION(aColIndex=1, "bad aColSpan"); - - // initialize the data structure if not already done - if (nsnull==mMinColSpans) - { - mMinColSpans = new PRInt32[mColCount]; - for (PRInt32 i=0; i mColCount) - { - result = aColIndex; - } - else - { - if (aRowIndex < mRowCount) - { - result = aColIndex; - nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex)); - PRInt32 count = row->Count(); - for (PRInt32 colIndex=aColIndex; colIndexElementAt(colIndex); - if (nsnull==data) - { - result = colIndex; - break; - } - result++; - } + if ((aRow >= 0) && (aRow < mRowCount)) { + if (mIsCollapsedRows) { + return mIsCollapsedRows[aRow]; } } - return result; + return PR_FALSE; } +void nsCellMap::SetRowCollapsedAt(PRInt32 aRow, PRBool aValue) +{ + if ((aRow >= 0) && (aRow < mRowCount)) { + if (nsnull == mIsCollapsedRows) { + mIsCollapsedRows = new PRPackedBool[mRowCount]; + for (PRInt32 i = 0; i < mRowCount; i++) { + mIsCollapsedRows[i] = PR_FALSE; + } + } + if (mIsCollapsedRows[aRow] != aValue) { + if (PR_TRUE == aValue) { + mNumCollapsedRows++; + } else { + mNumCollapsedRows--; + } + mIsCollapsedRows[aRow] = aValue; + } + } +} + +PRInt32 nsCellMap::GetNumCollapsedCols() +{ + return mNumCollapsedCols; +} + +PRBool nsCellMap::IsColCollapsedAt(PRInt32 aCol) +{ + PRInt32 colCount = mNumCellsInCol.Count(); + if ((aCol >= 0) && (aCol < colCount)) { + if (mIsCollapsedCols) { + return mIsCollapsedCols[aCol]; + } + } + return PR_FALSE; +} + +void nsCellMap::SetColCollapsedAt(PRInt32 aCol, PRBool aValue) +{ + PRInt32 colCount = mNumCellsInCol.Count(); + if ((aCol >= 0) && (aCol < colCount)) { + if (nsnull == mIsCollapsedCols) { + mIsCollapsedCols = new PRPackedBool[colCount]; + for (PRInt32 i = 0; i < colCount; i++) { + mIsCollapsedCols[i] = PR_FALSE; + } + } + if (mIsCollapsedCols[aCol] != aValue) { + if (PR_TRUE == aValue) { + mNumCollapsedCols++; + } else { + mNumCollapsedCols--; + } + mIsCollapsedCols[aCol] = aValue; + } + } +} + +// The following are not used and may not work. They have been removed from +// nsTableFrame and nsCellMap headers but retained here if needed in the future. +#if 0 /** returns PR_TRUE if the row at aRowIndex has any cells that are the result * of a row-spanning cell above it. So, given this table:
*
@@ -259,22 +462,18 @@ PRInt32 nsCellMap::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) co
 // whenever a row|col|cell is added/deleted, or a span attribute is changed.
 PRBool nsCellMap::RowIsSpannedInto(PRInt32 aRowIndex)
 {
-  NS_PRECONDITION (0<=aRowIndex && aRowIndexmCell)
-			{ // the cell at (aRowIndex, colIndex) is the result of a span
-				nsTableCellFrame *cell = cd->mRealCell->mCell;
-				NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
+	for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++) {
+		CellData* cd = GetCellAt(aRowIndex, colIndex);
+		if (cd) { // there's really a cell at (aRowIndex, colIndex)
+			if (!cd->mOrigCell) { // the cell at (aRowIndex, colIndex) is the result of a span
+				nsTableCellFrame* cell = cd->mSpanData->mOrigCell;
+				NS_ASSERTION(cell, "bad cell map state, missing real cell");
 				PRInt32 realRowIndex;
         cell->GetRowIndex (realRowIndex);
-				if (realRowIndex!=aRowIndex)
-				{ // the span is caused by a rowspan
+				if (realRowIndex != aRowIndex) { // the span is caused by a rowspan
 					result = PR_TRUE;
 					break;
 				}
@@ -299,31 +498,24 @@ PRBool nsCellMap::RowIsSpannedInto(PRInt32 aRowIndex)
   */
 PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex)
 {
-  NS_PRECONDITION (0<=aRowIndex && aRowIndexmCell)
-        { // the cell at (nextRowIndex, colIndex) is the result of a span
-          nsTableCellFrame *cell = cd->mRealCell->mCell;
-          NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
+  PRInt32 colCount = mTableColToMapCol.Count();
+  if (aRowIndex != mRowCount - 1) {
+    // aRowIndex is not the last row, so we check the next row after aRowIndex for spanners
+    for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++) {
+      PRInt32 nextRowIndex = aRowIndex + 1;
+      CellData* cd = GetCellAt(nextRowIndex, colIndex);
+      if (cd) { // there's really a cell at (nextRowIndex, colIndex)
+        if (!cd->mOrigCell) { // the cell at (nextRowIndex, colIndex) is the result of a span
+          nsTableCellFrame* cell = cd->mSpanData->mOrigCell;
+          NS_ASSERTION(cell, "bad cell map state, missing real cell");
           PRInt32 realRowIndex;
           cell->GetRowIndex (realRowIndex);
-          if (realRowIndex!=nextRowIndex)
-          { // the span is caused by a rowspan
-            CellData *spanningCell = GetCellAt(aRowIndex, colIndex);
-            if (nsnull!=spanningCell)
-            { // there's really a cell at (aRowIndex, colIndex)
-              if (nsnull!=spanningCell->mCell)
-              { // aRowIndex is where the rowspan originated
+          if (realRowIndex != nextRowIndex) { // the span is caused by a rowspan
+            CellData* spanningCell = GetCellAt(aRowIndex, colIndex);
+            if (spanningCell) { // there's really a cell at (aRowIndex, colIndex)
+              if (spanningCell->mOrigCell) { // aRowIndex is where the rowspan originated
                 result = PR_TRUE;
                 break;
               }
@@ -336,7 +528,6 @@ PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex)
   return result;
 }
 
-
 /** returns PR_TRUE if the col at aColIndex has any cells that are the result
   * of a col-spanning cell.  So, given this table:
*
@@ -352,23 +543,18 @@ PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex)
   */
 PRBool nsCellMap::ColIsSpannedInto(PRInt32 aColIndex)
 {
-  PRInt32 colCount = GetColCount();
-  NS_PRECONDITION (0<=aColIndex && aColIndexmCell)
-      { // the cell at (rowIndex, aColIndex) is the result of a span
-        nsTableCellFrame *cell = cd->mRealCell->mCell;
-        NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
+  for (PRInt32 rowIndex = 0; rowIndex < mRowCount; rowIndex++) {
+    CellData* cd = GetCellAt(rowIndex, aColIndex);
+    if (cd) { // there's really a cell at (aRowIndex, aColIndex)
+      if (!cd->mOrigCell) { // the cell at (rowIndex, aColIndex) is the result of a span
+        nsTableCellFrame* cell = cd->mSpanData->mOrigCell;
+        NS_ASSERTION(cell, "bad cell map state, missing real cell");
         PRInt32 realColIndex;
-        cell->GetColIndex (realColIndex);
-        if (realColIndex!=aColIndex)
-        { // the span is caused by a colspan
+        cell->GetColIndex(realColIndex);
+        if (realColIndex != aColIndex) { // the span is caused by a colspan
           result = PR_TRUE;
           break;
         }
@@ -392,29 +578,22 @@ PRBool nsCellMap::ColIsSpannedInto(PRInt32 aColIndex)
 PRBool nsCellMap::ColHasSpanningCells(PRInt32 aColIndex)
 {
   PRBool result = PR_FALSE;
-  const PRInt32 colCount = GetColCount();
-  if (aColIndexmCell)
-        { // the cell at (rowIndex, nextColIndex) is the result of a span
-          nsTableCellFrame *cell = cd->mRealCell->mCell;
-          NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
+      CellData* cd = GetCellAt(rowIndex, nextColIndex);
+      if (cd) { // there's really a cell at (rowIndex, nextColIndex)
+        if (!cd->mOrigCell) { // the cell at (rowIndex, nextColIndex) is the result of a span
+          nsTableCellFrame* cell = cd->mSpanData->mOrigCell;
+          NS_ASSERTION(cell, "bad cell map state, missing real cell");
           PRInt32 realColIndex;
-          cell->GetColIndex (realColIndex);
-          if (realColIndex!=nextColIndex)
-          { // the span is caused by a colspan
-            CellData *spanningCell =GetCellAt(rowIndex, aColIndex);
-            if (nsnull!=spanningCell)
-            { // there's really a cell at (rowIndex, aColIndex)
-              if (nsnull!=spanningCell->mCell)
-              { // aCowIndex is where the cowspan originated
+          cell->GetColIndex(realColIndex);
+          if (realColIndex != nextColIndex) { // the span is caused by a colspan
+            CellData* spanningCell = GetCellAtInternal(rowIndex, aColIndex);
+            if (spanningCell) { // there's really a cell at (rowIndex, aColIndex)
+              if (spanningCell->mOrigCell) { // aCowIndex is where the cowspan originated
                 result = PR_TRUE;
                 break;
               }
@@ -427,73 +606,6 @@ PRBool nsCellMap::ColHasSpanningCells(PRInt32 aColIndex)
   return result;
 }
 
-PRInt32 nsCellMap::GetNumCollapsedRows()
-{
-  return mNumCollapsedRows;
-}
+#endif
 
-PRBool nsCellMap::IsRowCollapsedAt(PRInt32 aRow)
-{
-  if ((aRow >= 0) && (aRow < mTotalRowCount)) {
-    if (mIsCollapsedRows) {
-      return mIsCollapsedRows[aRow];
-    }
-  }
-  return PR_FALSE;
-}
-
-void nsCellMap::SetRowCollapsedAt(PRInt32 aRow, PRBool aValue)
-{
-  if ((aRow >= 0) && (aRow < mRowCount)) {
-    if (nsnull == mIsCollapsedRows) {
-      mIsCollapsedRows = new PRBool[mRowCount];
-      for (PRInt32 i = 0; i < mRowCount; i++) {
-        mIsCollapsedRows[i] = PR_FALSE;
-      }
-    }
-    if (mIsCollapsedRows[aRow] != aValue) {
-      if (PR_TRUE == aValue) {
-        mNumCollapsedRows++;
-      } else {
-        mNumCollapsedRows--;
-      }
-      mIsCollapsedRows[aRow] = aValue; 
-    }
-  }
-}
-
-PRInt32 nsCellMap::GetNumCollapsedCols()
-{
-  return mNumCollapsedCols;
-}
-
-PRBool nsCellMap::IsColCollapsedAt(PRInt32 aCol)
-{
-  if ((aCol >= 0) && (aCol < mColCount)) {
-    if (mIsCollapsedCols) {
-      return mIsCollapsedCols[aCol];
-    }
-  }
-  return PR_FALSE;
-}
-
-void nsCellMap::SetColCollapsedAt(PRInt32 aCol, PRBool aValue)
-{
-  if ((aCol >= 0) && (aCol < mColCount)) {
-    if (nsnull == mIsCollapsedCols) {
-      mIsCollapsedCols = new PRBool[mColCount];
-      for (PRInt32 i = 0; i < mColCount; i++) {
-        mIsCollapsedCols[i] = PR_FALSE;
-      }
-    }
-    if (mIsCollapsedCols[aCol] != aValue) {
-      if (PR_TRUE == aValue) {
-        mNumCollapsedCols++;
-      } else {
-        mNumCollapsedCols--;
-      }
-      mIsCollapsedCols[aCol] = aValue; 
-    }
-  }
-}
 
diff --git a/mozilla/layout/html/table/src/nsCellMap.h b/mozilla/layout/html/table/src/nsCellMap.h
index aa3f208ef8a..4fbb71d053c 100644
--- a/mozilla/layout/html/table/src/nsCellMap.h
+++ b/mozilla/layout/html/table/src/nsCellMap.h
@@ -40,73 +40,52 @@ class nsTableCellFrame;
   */
 class nsCellMap
 {
-protected:
-  /** storage for rows */
-  nsVoidArray *mRows;       
-
-  /** storage for min col span info, just an int that gives the smallest
-    * colspan for all cells originating in each column.  If allocated,
-    * each entry must be >= 1.
-    */
-  PRInt32 *mMinColSpans;
-
-  /** a cache of the column frames, by col index */
-  nsVoidArray * mColFrames;
-
-  /** the number of rows.  mRows[0] - mRows[mRowCount-1] are non-null. */
-  PRInt32 mRowCount;
-
-  /** the number of rows allocated (due to cells having rowspans extending beyond the end of the table */
-  PRInt32 mTotalRowCount;
-
-  /** the number of columns (the max of all row lengths) */
-  PRInt32 mColCount;
-
-  // an array of booleans where the ith element indicates if the ith row is collapsed
-  PRBool* mIsCollapsedRows;
-  PRInt32 mNumCollapsedRows;
-
-  // an array of booleans where the ith element indicates if the ith col is collapsed
-  PRBool* mIsCollapsedCols;
-  PRInt32 mNumCollapsedCols;
-
 public:
   /** constructor 
-    * @param aRows - initial number of rows
-	  * @param aColumns - initial number of columns
+    * @param aNumRows - initial number of rows
+	  * @param aNumColumns - initial number of columns
 	  */
-  nsCellMap(PRInt32 aRows, PRInt32 aColumns);
+  nsCellMap(PRInt32 aNumRows, 
+            PRInt32 aNumCols);
 
   /** destructor
     * NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED  
-	*/
+	  */
   ~nsCellMap();
 
-  /** set the CellMap to (aRows x aColumns) */
-  void Reset(PRInt32 aRows, PRInt32 aColumns);
+  /** return the CellData for the cell at (aTableRowIndex, aTableColIndex) */
+  CellData* GetCellAt(PRInt32 aRowIndex, 
+                      PRInt32 aColIndex) const;
 
-  /** return the CellData for the cell at (aRowIndex,aColIndex) */
-  CellData * GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const;
+  /** return the nsTableCellFrame for the cell at (aTableRowIndex, aTableColIndex) */
+  nsTableCellFrame* GetCellFrameAt(PRInt32 aRowIndex, 
+                                   PRInt32 aColIndex) const;
 
-  /** return the nsTableCellFrame for the cell at (aRowIndex, aColIndex) */
-  nsTableCellFrame * GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex) const;
+  /** append the cellFrame at the end of the row at aRowIndex and return the col index
+    */
+  PRInt32 AppendCell(nsTableCellFrame* aCellFrame, 
+                     PRInt32           aRowIndex);
 
-  /** assign aCellData to the cell at (aRow,aColumn) */
-  void SetCellAt(CellData *aCellData, PRInt32 aRow, PRInt32 aColumn);
+  void RemoveCell(nsTableCellFrame* aCellFrame,
+                  PRInt32           aRowIndex);
+
+  PRInt32 GetNextAvailRowIndex();
+
+  PRInt32 GetEffectiveColSpan(PRInt32           aColIndex, 
+                              nsTableCellFrame* aCell);
+
+  PRInt32 GetNumCellsIn(PRInt32 aColIndex);
+  PRInt32 GetNumCellsOriginatingIn(PRInt32 aColIndex);
 
   PRInt32 GetNumCollapsedRows();
-  PRBool IsRowCollapsedAt(PRInt32 aRow);
-  void SetRowCollapsedAt(PRInt32 aRow, PRBool aValue);
+  PRBool IsRowCollapsedAt(PRInt32 aRowIndex);
+  void SetRowCollapsedAt(PRInt32 aRowIndex, 
+                         PRBool  aValue);
 
   PRInt32 GetNumCollapsedCols();
-  PRBool IsColCollapsedAt(PRInt32 aCol);
-  void SetColCollapsedAt(PRInt32 aCol, PRBool aValue);
-
-  /** expand the CellMap to have aRowCount rows.  The number of columns remains the same */
-  void GrowToRow(PRInt32 aRowCount);
-
-  /** expand the CellMap to have aColCount columns.  The number of rows remains the same */
-  void GrowToCol(PRInt32 aColCount);
+  PRBool IsColCollapsedAt(PRInt32 aColIndex);
+  void SetColCollapsedAt(PRInt32 aColIndex, 
+                         PRBool aValue);
 
   /** return the total number of columns in the table represented by this CellMap */
   PRInt32 GetColCount() const;
@@ -115,20 +94,7 @@ public:
   PRInt32 GetRowCount() const;
 
   /** return the column frame associated with aColIndex */
-  nsTableColFrame * GetColumnFrame(PRInt32 aColIndex) const;
-
-  /** return the index of the next column in aRowIndex after aColIndex 
-    * that does not have a cell assigned to it.
-    * If aColIndex is past the end of the row, it is returned.
-    * If the row is not initialized in the cell map, 0 is returned.
-    */
-  PRInt32 GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const;
-
-  /** cache the min col span for all cells in aColIndex */ 
-  void    SetMinColSpan(PRInt32 aColIndex, PRBool  aColSpan);
-
-  /** get the cached min col span for aColIndex */
-  PRInt32 GetMinColSpan(PRInt32 aColIndex) const;
+  nsTableColFrame* GetColumnFrame(PRInt32 aColIndex) const;
 
   /** add a column frame to the list of column frames
     * column frames must be added in order
@@ -138,102 +104,105 @@ public:
   /** empty the column frame cache */
   void ClearColumnCache();
 
-	/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
-		* of a row-spanning cell above it.  So, given this table:
- *
-		* TABLE
-		*   TR
-		*    TD ROWSPAN=2
-		*    TD
-		*   TR
-		*    TD
-		* 
- * RowIsSpannedInto(0) returns PR_FALSE, and RowIsSpannedInto(1) returns PR_TRUE. - * @see RowHasSpanningCells - */ - PRBool RowIsSpannedInto(PRInt32 aRowIndex); - - /** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1 - * So, given this table:
- *
-		* TABLE
-		*   TR
-		*    TD ROWSPAN=2
-		*    TD
-		*   TR
-		*    TD
-		* 
- * RowHasSpanningCells(0) returns PR_TRUE, and RowHasSpanningCells(1) returns PR_FALSE. - * @see RowIsSpannedInto - */ - PRBool RowHasSpanningCells(PRInt32 aRowIndex); - - /** returns PR_TRUE if the col at aColIndex has any cells that are the result - * of a col-spanning cell. So, given this table:
- *
-		* TABLE
-		*   TR
-		*    TD COLSPAN=2
-		*    TD
-		*    TD
-		* 
- * ColIsSpannedInto(0) returns PR_FALSE, ColIsSpannedInto(1) returns PR_TRUE, - * and ColIsSpannedInto(2) returns PR_FALSE. - * @see ColHasSpanningCells - */ - PRBool ColIsSpannedInto(PRInt32 aColIndex); - - /** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1 - * So, given this table:
- *
-		* TABLE
-		*   TR
-		*    TD COLSPAN=2
-		*    TD
-		* 
- * ColHasSpanningCells(0) returns PR_TRUE, and ColHasSpanningCells(1) returns PR_FALSE. - * @see ColIsSpannedInto - */ - PRBool ColHasSpanningCells(PRInt32 aColIndex); + void GetCellInfoAt(PRInt32 aRowX, + PRInt32 aColX, + nsTableCellFrame*& aCellFrame, + PRBool& aOriginates, + PRInt32& aColSpan); + void AddColsAtEnd(PRUint32 aNumCols); /** dump a representation of the cell map to stdout for debugging */ - void DumpCellMap() const; +#ifdef NS_DEBUG + void Dump() const; +#endif +protected: + /** set the CellMap to (aNumRows x aNumColumns) */ + void Grow(PRInt32 aNumMapRows, + PRInt32 aNumCols); + + /** assign aCellData to the cell at (aRow,aColumn) */ + void SetMapCellAt(CellData& aCellData, + PRInt32 aMapRowIndex, + PRInt32 aColIndex); + + CellData* GetMapCellAt(PRInt32 aMapRowIndex, + PRInt32 aColIndex) const; + + PRInt32 GetNumCellsIn(PRInt32 aColIndex, PRBool aOriginating); + + /** an array containing col array. It can be larger than mRowCount due to + * row spans extending beyond the table */ + nsVoidArray mRows; + + /** an array of col frames. It is as large as mRowCount */ + nsVoidArray mColFrames; + + /** an array of PRInt32[2] indexed by col and giving the number of cells originating + * and occupying each col. */ + nsVoidArray mNumCellsInCol; + + // an array of booleans where the ith element indicates if the ith row is collapsed + PRPackedBool* mIsCollapsedRows; + PRInt32 mNumCollapsedRows; + + // an array of booleans where the ith element indicates if the ith col is collapsed + PRPackedBool* mIsCollapsedCols; + PRInt32 mNumCollapsedCols; + + /** the number of rows in the table which is <= the number of rows in the cell map + * due to row spans extending beyond the end of the table (dead rows) */ + PRInt32 mRowCount; + + PRInt32 mNextAvailRowIndex; }; /* ----- inline methods ----- */ - -inline CellData * nsCellMap::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const +inline CellData* nsCellMap::GetCellAt(PRInt32 aRowIndex, + PRInt32 aColIndex) const { - NS_PRECONDITION(0<=aRowIndex, "bad aRowIndex arg"); - NS_PRECONDITION(0<=aColIndex, "bad aColIndex arg"); - // don't check index vs. count for row or col, because it's ok to ask for a cell that doesn't yet exist - NS_PRECONDITION(nsnull!=mRows, "bad mRows"); - - CellData *result = nsnull; - nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex)); - if (nsnull!=row) + NS_PRECONDITION((0 <= aRowIndex) && (aRowIndex < mRowCount), "GetCellAt: bad row index"); + PRInt32 colCount = mNumCellsInCol.Count(); + NS_PRECONDITION((0 <= aColIndex) && (aColIndex < colCount), "GetCellAt: bad col index"); + + CellData* result = nsnull; + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(aRowIndex)); + if (row) result = (CellData *)(row->ElementAt(aColIndex)); return result; } -inline nsTableCellFrame * nsCellMap::GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex) const +inline CellData* nsCellMap::GetMapCellAt(PRInt32 aMapRowIndex, + PRInt32 aColIndex) const { - NS_PRECONDITION(0<=aRowIndex, "bad aRowIndex arg"); - // don't check aRowIndex vs. mRowCount, because it's ok to ask for a cell in a row that doesn't yet exist - NS_PRECONDITION(0<=aColIndex && aColIndex < mColCount, "bad aColIndex arg"); + NS_PRECONDITION((0 <= aMapRowIndex) && (aMapRowIndex < mRows.Count()), "GetMapCellAt: bad row index"); + NS_PRECONDITION((0 <= aColIndex) && (aColIndex < mNumCellsInCol.Count()), "GetMapCellAt: bad col index"); - nsTableCellFrame *result = nsnull; - CellData * cellData = GetCellAt(aRowIndex, aColIndex); - if (nsnull!=cellData) - result = cellData->mCell; + CellData* result = nsnull; + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(aMapRowIndex)); + if (row) + result = (CellData *)(row->ElementAt(aColIndex)); + return result; +} + +inline nsTableCellFrame* nsCellMap::GetCellFrameAt(PRInt32 aRowIndex, + PRInt32 aColIndex) const +{ + NS_PRECONDITION((0 <= aRowIndex) && (aRowIndex < mRowCount), "GetCellFrameAt: bad row index"); + PRInt32 colCount = mNumCellsInCol.Count(); + NS_PRECONDITION((0 <= aColIndex) && (aColIndex < colCount), "GetCellFrameAt: bad col index"); + + nsTableCellFrame* result = nsnull; + CellData* cellData = GetCellAt(aRowIndex, aColIndex); + if (cellData) + result = cellData->mOrigCell; return result; } inline PRInt32 nsCellMap::GetColCount() const { - return mColCount; + return mNumCellsInCol.Count(); } inline PRInt32 nsCellMap::GetRowCount() const @@ -243,13 +212,12 @@ inline PRInt32 nsCellMap::GetRowCount() const inline void nsCellMap::AppendColumnFrame(nsTableColFrame *aColFrame) { - mColFrames->AppendElement(aColFrame); + mColFrames.AppendElement(aColFrame); } inline void nsCellMap::ClearColumnCache() { - if (nsnull!=mColFrames) - mColFrames->Clear(); + mColFrames.Clear(); } diff --git a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h index 4221ccd187b..7630fe3468f 100644 --- a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h @@ -48,9 +48,9 @@ public: * @param aMaxWidth the width constraint */ - virtual PRBool BalanceColumnWidths(nsIStyleContext *aTableStyle, + virtual PRBool BalanceColumnWidths(nsIStyleContext* aTableStyle, const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth)=0; + nscoord aMaxWidth)=0; /** return the computed max "natural" size of the table. * this is the sum of the desired size of the content taking into account table @@ -58,7 +58,7 @@ public: * the actual table width in a given situation will depend on the available size * provided by the parent (especially for percent-width tables.) */ - virtual nscoord GetTableMaxWidth() const = 0; + virtual nscoord GetTableMaxContentWidth() const = 0; /** return the computed minimum possible size of the table. * this is the sum of the minimum sizes of the content taking into account table @@ -66,13 +66,7 @@ public: * the actual table width in a given situation will depend on the available size * provided by the parent (especially for percent-width tables.) */ - virtual nscoord GetTableMinWidth() const = 0; - - /** return the portion of the table width that is specified as "fixed" aka - * the amount of table width that does not vary with available width or other - * inputs to the table balancing algorithm. - */ - virtual nscoord GetTableFixedWidth() const = 0; + virtual nscoord GetTableMinContentWidth() const = 0; /** return the value of the COLS attribute, used for balancing column widths */ virtual nscoord GetCOLSAttribute() const = 0; diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp index bf038a1fb7a..cf7b1d657ab 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp @@ -36,9 +36,11 @@ #include "nsIView.h" #include "nsStyleUtil.h" #include "nsLayoutAtoms.h" +#include "nsCOMPtr.h" +#include "nsIHTMLTableCellElement.h" NS_DEF_PTR(nsIStyleContext); - +static NS_DEFINE_IID(kIHTMLTableCellElementIID, NS_IHTMLTABLECELLELEMENT_IID); #ifdef NS_DEBUG static PRBool gsDebug = PR_FALSE; @@ -78,7 +80,7 @@ nsTableCellFrame::Init(nsIPresContext& aPresContext, void nsTableCellFrame::InitCellFrame(PRInt32 aColIndex) { NS_PRECONDITION(0<=aColIndex, "bad col index arg"); - mColIndex = aColIndex; + SetColIndex(aColIndex); // this also sets the contents col index mBorderEdges.mOutsideEdge=PR_FALSE; nsTableFrame* tableFrame=nsnull; // I should be checking my own style context, but border-collapse isn't inheriting correctly nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); @@ -110,6 +112,33 @@ void nsTableCellFrame::InitCellFrame(PRInt32 aColIndex) } } +nsresult nsTableCellFrame::SetColIndex(PRInt32 aColIndex) +{ + mColIndex = aColIndex; + // for style context optimization, set the content's column index if possible. + // this can only be done if we really have an nsTableCell. + // other tags mapped to table cell display won't benefit from this optimization + // see nsHTMLStyleSheet::RulesMatching + + //nsIContent* cell; + //kidFrame->GetContent(&cell); + nsCOMPtr cell; + nsresult rv = GetContent(getter_AddRefs(cell)); + if (NS_FAILED(rv) || !cell) + return rv; + + nsIHTMLTableCellElement* cellContent = nsnull; + rv = cell->QueryInterface(kIHTMLTableCellElementIID, + (void **)&cellContent); // cellContent: REFCNT++ + if (cellContent && NS_SUCCEEDED(rv)) { // it's a table cell + cellContent->SetColIndex(aColIndex); + if (gsDebug) printf("%p : set cell content %p to col index = %d\n", this, cellContent, aColIndex); + NS_RELEASE(cellContent); + } + return rv; +} + + void nsTableCellFrame::SetBorderEdgeLength(PRUint8 aSide, PRInt32 aIndex, nscoord aLength) @@ -325,52 +354,49 @@ void nsTableCellFrame::VerticallyAlignChild() /* XXX: remove tableFrame when border-collapse inherits */ nsTableFrame* tableFrame=nsnull; nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_SUCCEEDED(rv) && tableFrame) - { - nsMargin borderPadding; - GetCellBorder (borderPadding, tableFrame); - nsMargin padding; - spacing->GetPadding(padding); - borderPadding += padding; + nsMargin borderPadding; + GetCellBorder (borderPadding, tableFrame); + nsMargin padding; + spacing->GetPadding(padding); + borderPadding += padding; - nscoord topInset = borderPadding.top; - nscoord bottomInset = borderPadding.bottom; - PRUint8 verticalAlignFlags = NS_STYLE_VERTICAL_ALIGN_MIDDLE; - if (textStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated) { - verticalAlignFlags = textStyle->mVerticalAlign.GetIntValue(); - } - nscoord height = mRect.height; - nsRect kidRect; - nsIFrame* firstKid = mFrames.FirstChild(); - firstKid->GetRect(kidRect); - nscoord childHeight = kidRect.height; - - - // Vertically align the child - nscoord kidYTop = 0; - switch (verticalAlignFlags) - { - case NS_STYLE_VERTICAL_ALIGN_BASELINE: - // Align the child's baseline at the max baseline - //kidYTop = aMaxAscent - kidAscent; - break; - - case NS_STYLE_VERTICAL_ALIGN_TOP: - // Align the top of the child frame with the top of the box, - // minus the top padding - kidYTop = topInset; - break; - - case NS_STYLE_VERTICAL_ALIGN_BOTTOM: - kidYTop = height - childHeight - bottomInset; - break; - - default: - case NS_STYLE_VERTICAL_ALIGN_MIDDLE: - kidYTop = height/2 - childHeight/2; - } - firstKid->MoveTo(kidRect.x, kidYTop); + nscoord topInset = borderPadding.top; + nscoord bottomInset = borderPadding.bottom; + PRUint8 verticalAlignFlags = NS_STYLE_VERTICAL_ALIGN_MIDDLE; + if (textStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated) { + verticalAlignFlags = textStyle->mVerticalAlign.GetIntValue(); } + nscoord height = mRect.height; + nsRect kidRect; + nsIFrame* firstKid = mFrames.FirstChild(); + firstKid->GetRect(kidRect); + nscoord childHeight = kidRect.height; + + + // Vertically align the child + nscoord kidYTop = 0; + switch (verticalAlignFlags) + { + case NS_STYLE_VERTICAL_ALIGN_BASELINE: + // Align the child's baseline at the max baseline + //kidYTop = aMaxAscent - kidAscent; + break; + + case NS_STYLE_VERTICAL_ALIGN_TOP: + // Align the top of the child frame with the top of the box, + // minus the top padding + kidYTop = topInset; + break; + + case NS_STYLE_VERTICAL_ALIGN_BOTTOM: + kidYTop = height - childHeight - bottomInset; + break; + + default: + case NS_STYLE_VERTICAL_ALIGN_MIDDLE: + kidYTop = height/2 - childHeight/2; + } + firstKid->MoveTo(kidRect.x, kidYTop); } PRInt32 nsTableCellFrame::GetRowSpan() @@ -486,7 +512,6 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext& aPresContext, /* XXX: remove tableFrame when border-collapse inherits */ nsTableFrame* tableFrame=nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_FAILED(rv)) { return rv; } nsMargin borderPadding; spacing->GetPadding(borderPadding); nsMargin border; @@ -527,7 +552,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext& aPresContext, aReflowState.reflowCommand->GetType(type); if (nsIReflowCommand::StyleChanged==type) { - rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus); + nsresult rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus); aStatus = NS_FRAME_COMPLETE; return rv; } @@ -674,7 +699,12 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext& aPresContext, // So here all we have to do is tell the table to rebalance. if (eReflowReason_Incremental == aReflowState.reason) { - tableFrame->InvalidateColumnWidths(); + nsTableFrame* tableFrame=nsnull; + rv = nsTableFrame::GetTableFrame(this, tableFrame); + if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) + { + tableFrame->InvalidateColumnWidths(); + } } @@ -1082,7 +1112,7 @@ PRUint8 nsTableCellFrame::GetOpposingEdge(PRUint8 aEdge) nscoord nsTableCellFrame::FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge) { nscoord result = 0; - PRInt32 theIndex = 0; + PRInt32 index = 0; PRInt32 count = 0; @@ -1093,9 +1123,9 @@ nscoord nsTableCellFrame::FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge) nsIFrame* frame; nscoord value = 0; - while (theIndex < count) + while (index < count) { - frame = (nsIFrame*)(aList->ElementAt(theIndex++)); + frame = (nsIFrame*)(aList->ElementAt(index++)); value = GetMargin(frame, aEdge); if (value > result) result = value; diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.h b/mozilla/layout/html/table/src/nsTableCellFrame.h index 5489878638c..c068d4c6aef 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.h +++ b/mozilla/layout/html/table/src/nsTableCellFrame.h @@ -124,6 +124,7 @@ public: /** return the cell's column index (starting at 0 for the first column) */ virtual nsresult GetColIndex(PRInt32 &aColIndex); + virtual nsresult SetColIndex(PRInt32 aColIndex); /** return the available width given to this frame during its last reflow */ virtual nscoord GetPriorAvailWidth(); diff --git a/mozilla/layout/html/table/src/nsTableColFrame.cpp b/mozilla/layout/html/table/src/nsTableColFrame.cpp index 5178a9c5747..98ee10562b1 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableColFrame.cpp @@ -32,10 +32,16 @@ static const PRBool gsDebug = PR_FALSE; #endif nsTableColFrame::nsTableColFrame() - : nsFrame() + : nsFrame(), mIsAnonymous(PR_FALSE), mProportion(WIDTH_NOT_SET) { // note that all fields are initialized to 0 by nsFrame::operator new - mWidthSource = eWIDTH_SOURCE_NONE; + for (PRInt32 widthX = 0; widthX < NUM_WIDTHS; widthX++) { + mWidths[widthX] = WIDTH_NOT_SET; + } +} + +nsTableColFrame::~nsTableColFrame() +{ } NS_METHOD nsTableColFrame::Paint(nsIPresContext& aPresContext, @@ -89,14 +95,63 @@ PRInt32 nsTableColFrame::GetSpan() return tableStyle->mSpan; } -nscoord nsTableColFrame::GetColWidthForComputation() +nscoord nsTableColFrame::GetWidth(PRUint32 aWidthType) { - const nsStylePosition* position; - GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)position)); - if (eStyleUnit_Coord==position->mWidth.GetUnit()) - return position->mWidth.GetCoordValue(); - else - return GetEffectiveMaxColWidth(); + NS_ASSERTION(aWidthType < NUM_WIDTHS, "GetWidth: bad width type"); + return mWidths[aWidthType]; +} + +void nsTableColFrame::SetWidth(PRUint32 aWidthType, + nscoord aWidth) +{ + NS_ASSERTION(aWidthType < NUM_WIDTHS, "SetWidth: bad width type"); + mWidths[aWidthType] = aWidth; +#ifdef MY_DEBUG + if (aWidth > 0) { + nscoord minWidth = GetMinWidth(); + if ((MIN_CON != aWidthType) && (aWidth < minWidth)) { + printf("non min width set to lower than min \n"); + } + } +#endif +} + +nscoord nsTableColFrame::GetMinWidth() +{ + return PR_MAX(mWidths[MIN_CON], mWidths[MIN_ADJ]); +} + +nscoord nsTableColFrame::GetDesWidth() +{ + return PR_MAX(mWidths[DES_CON], mWidths[DES_ADJ]); +} + +nscoord nsTableColFrame::GetFixWidth() +{ + return PR_MAX(mWidths[FIX], mWidths[FIX_ADJ]); +} + +nscoord nsTableColFrame::GetPctWidth() +{ + return PR_MAX(mWidths[PCT], mWidths[PCT_ADJ]); +} + +void nsTableColFrame::Dump(PRInt32 aIndent) +{ + char* indent = new char[aIndent + 1]; + for (PRInt32 i = 0; i < aIndent + 1; i++) { + indent[i] = ' '; + } + indent[aIndent] = 0; + + printf("%s**START COL DUMP** colIndex=%d isAnonymous=%d constraint=%d", + indent, mColIndex, mIsAnonymous, mConstraint); + printf("\n%s widths=", indent); + for (PRInt32 widthX = 0; widthX < NUM_WIDTHS; widthX++) { + printf("%d ", mWidths[widthX]); + } + printf(" **END COL DUMP** "); + delete [] indent; } /* ----- global methods ----- */ diff --git a/mozilla/layout/html/table/src/nsTableColFrame.h b/mozilla/layout/html/table/src/nsTableColFrame.h index 876b321160d..3bb204d4fb1 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.h +++ b/mozilla/layout/html/table/src/nsTableColFrame.h @@ -20,9 +20,36 @@ #include "nscore.h" #include "nsContainerFrame.h" +#include "nsTableFrame.h" class nsVoidArray; +// this is used to index arrays of widths in nsColFrame and to group important widths +// for calculations. It is important that the order: min, desired, fixed be maintained +// for each category (con, adj). +// XXX MIN_ADJ, DES_ADJ, PCT_ADJ, DES_PRO can probably go away and be replaced +// by MIN_CON, DES_CON, PCT_CON, DES_CON saving 16 bytes per col frame +#define WIDTH_NOT_SET -1 +#define NUM_WIDTHS 9 +#define NUM_MAJOR_WIDTHS 3 // MIN, DES, FIX +#define MIN_CON 0 // minimum width required of the content + padding +#define DES_CON 1 // desired width of the content + padding +#define FIX 2 // fixed width either from the content or cell, col, etc. + padding +#define MIN_ADJ 3 // minimum width + padding due to col spans +#define DES_ADJ 4 // desired width + padding due to col spans +#define FIX_ADJ 5 // fixed width + padding due to col spans +#define PCT 6 // percent width of cell or col +#define PCT_ADJ 7 // percent width of cell or col from percent colspan +#define MIN_PRO 8 // desired width due to proportional s or cols attribute + +enum nsColConstraint { + eNoConstraint = 0, + ePixelConstraint = 1, // pixel width + ePercentConstraint = 2, // percent width + eProportionConstraint = 3, // 1*, 2*, etc. cols attribute assigns 1* + e0ProportionConstraint = 4 // 0*, means to force to min width +}; + class nsTableColFrame : public nsFrame { public: @@ -67,57 +94,48 @@ public: /** convenience method, calls into cellmap */ nsVoidArray * GetCells(); - nscoord GetMaxColWidth(); - void SetMaxColWidth(nscoord aMaxColWidth); - - nscoord GetMinColWidth(); - void SetMinColWidth(nscoord aMinColWidth); - - nscoord GetEffectiveMaxColWidth(); - void SetEffectiveMaxColWidth(nscoord aMaxColWidth); - - nscoord GetEffectiveMinColWidth(); - void SetEffectiveMinColWidth(nscoord aMinColWidth); - // return the min width for this column after provisions for col spans have // been included. The adj min width is >= the min width. nscoord GetAdjustedMinColWidth(); void SetAdjustedMinColWidth(nscoord aMinColWidth); - // Return true if the column has a width either from HTML width attribute, - // from a style rule on the column, from a width attr/style on a cell - // that has colspan==1. - PRBool HasConstrainedWidth(); - void SetHasConstrainedWidth(PRBool aIsConstrained); + nscoord GetWidth(PRUint32 aWidthType); + void GetWidths(nscoord* aWidths); + void SetWidth(PRUint32 aWidthType, + nscoord aWidth); + nscoord GetMinWidth(); + nscoord GetDesWidth(); + nscoord GetFixWidth(); + nscoord GetPctWidth(); - PRInt32 GetWidthSource(); - void SetWidthSource(PRInt32 aMinColWidth); - - nscoord GetColWidthForComputation(); + void SetConstraint(nsColConstraint aConstraint); + nsColConstraint GetConstraint() const; /** convenience method, calls into cellmap */ PRInt32 Count() const; + /** Return true if this col was constructed implicitly due to cells needing a col. + * Return false if this col was constructed due to content having display type of table-col + */ + PRBool IsAnonymous(); + void SetIsAnonymous(PRBool aValue); + + void Dump(PRInt32 aIndent); + protected: nsTableColFrame(); + ~nsTableColFrame(); /** the starting index of the column (starting at 0) that this col object represents */ PRInt32 mColIndex; + PRBool mIsAnonymous; - nscoord mMaxColWidth; - nscoord mMinColWidth; - - nscoord mMaxEffectiveColWidth; - nscoord mMinEffectiveColWidth; - - nscoord mMinAdjustedColWidth; - - PRBool mHasConstrainedWidth; - - PRInt32 mWidthSource; - + // Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ + nscoord mWidths[NUM_WIDTHS]; + nscoord mProportion; // proportion for porportional width col + nsColConstraint mConstraint; }; @@ -133,46 +151,17 @@ inline PRInt32 nsTableColFrame::GetColumnIndex() inline void nsTableColFrame::SetColumnIndex (int aColIndex) { mColIndex = aColIndex;} -inline nscoord nsTableColFrame::GetMaxColWidth() -{ return mMaxColWidth; } +inline nsColConstraint nsTableColFrame::GetConstraint() const +{ return mConstraint; } -inline void nsTableColFrame::SetMaxColWidth(nscoord aMaxColWidth) -{ mMaxColWidth = aMaxColWidth; } +inline void nsTableColFrame::SetConstraint(nsColConstraint aConstraint) +{ mConstraint = aConstraint;} -inline nscoord nsTableColFrame::GetMinColWidth() -{ return mMinColWidth; } +inline PRBool nsTableColFrame::IsAnonymous() +{ return mIsAnonymous; } -inline void nsTableColFrame::SetMinColWidth(nscoord aMinColWidth) -{ mMinColWidth = aMinColWidth; } +inline void nsTableColFrame::SetIsAnonymous(PRBool aIsAnonymous) +{ mIsAnonymous = aIsAnonymous; } -inline nscoord nsTableColFrame::GetEffectiveMaxColWidth() -{ return mMaxEffectiveColWidth; } - -inline void nsTableColFrame::SetEffectiveMaxColWidth(nscoord aMaxColWidth) -{ mMaxEffectiveColWidth = aMaxColWidth; } - -inline nscoord nsTableColFrame::GetEffectiveMinColWidth() -{ return mMinEffectiveColWidth; } - -inline void nsTableColFrame::SetEffectiveMinColWidth(nscoord aMinEffectiveColWidth) -{ mMinEffectiveColWidth = aMinEffectiveColWidth; } - -inline nscoord nsTableColFrame::GetAdjustedMinColWidth() -{ return mMinAdjustedColWidth; } - -inline PRBool nsTableColFrame::HasConstrainedWidth() -{ return mHasConstrainedWidth; } - -inline void nsTableColFrame::SetHasConstrainedWidth(PRBool aIsConstrained) -{ mHasConstrainedWidth = aIsConstrained; } - -inline void nsTableColFrame::SetAdjustedMinColWidth(nscoord aMinAdjustedColWidth) -{ mMinAdjustedColWidth = aMinAdjustedColWidth; } - -inline PRInt32 nsTableColFrame::GetWidthSource() -{ return mWidthSource; } - -inline void nsTableColFrame::SetWidthSource(PRInt32 aWidthSource) -{ mWidthSource = aWidthSource; } #endif diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp index bc427d65155..23558781024 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp @@ -712,6 +712,11 @@ PRInt32 nsTableColGroupFrame::SetStartColumnIndex (int aIndex) return result; } +void nsTableColGroupFrame::DeleteColFrame(nsIPresContext& aPresContext, nsTableColFrame* aColFrame) +{ + mFrames.DestroyFrame(aPresContext, aColFrame); +} + /* ----- global methods ----- */ nsresult diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.h b/mozilla/layout/html/table/src/nsTableColGroupFrame.h index 767c339c2df..cea8f0a8b3c 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.h +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.h @@ -94,6 +94,8 @@ public: */ //PRBool IsManufactured(); + void DeleteColFrame(nsIPresContext& aPresContext, nsTableColFrame* aColFrame); + protected: /** implement abstract method on nsHTMLContainerFrame */ diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index 69698d5e2bf..3dd8a71ac09 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -75,9 +75,9 @@ static const PRInt32 kColumnWidthIncrement=100; /* CellData is the info stored in the cell map */ CellData::CellData() { - mCell = nsnull; - mRealCell = nsnull; - mOverlap = nsnull; + mOrigCell = nsnull; + mSpanData = nsnull; + mSpanData2 = nsnull; } CellData::~CellData() @@ -284,7 +284,6 @@ nsTableFrame::nsTableFrame() mColCache(nsnull), mTableLayoutStrategy(nsnull) { - mEffectiveColCount = -1; // -1 means uninitialized mColumnWidthsSet=PR_FALSE; mColumnWidthsLength = kColumnWidthIncrement; mColumnWidths = new PRInt32[mColumnWidthsLength]; @@ -401,8 +400,10 @@ nsTableFrame::SetInitialChildList(nsIPresContext& aPresContext, if (nsnull!=prevColGroupChild) prevColGroupChild->SetNextSibling(nsnull); - if (NS_SUCCEEDED(rv)) + if (NS_SUCCEEDED(rv)) { + //mCellMap->Dump(); EnsureColumns(aPresContext); + } return rv; } @@ -439,15 +440,14 @@ NS_IMETHODIMP nsTableFrame::DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFra /* counts columns in column groups */ PRInt32 nsTableFrame::GetSpecifiedColumnCount () { - mColCount=0; + PRInt32 colCount = 0; nsIFrame * childFrame = mColGroups.FirstChild(); - while (nsnull!=childFrame) - { - mColCount += ((nsTableColGroupFrame *)childFrame)->GetColumnCount(); + while (nsnull!=childFrame) { + colCount += ((nsTableColGroupFrame *)childFrame)->GetColumnCount(); childFrame->GetNextSibling(&childFrame); } - if (PR_TRUE==gsDebug) printf("TIF GetSpecifiedColumnCount: returning %d\n", mColCount); - return mColCount; + if (PR_TRUE==gsDebug) printf("TIF GetSpecifiedColumnCount: returning %d\n", colCount); + return colCount; } PRInt32 nsTableFrame::GetRowCount () const @@ -463,46 +463,14 @@ PRInt32 nsTableFrame::GetRowCount () const /* return the effective col count */ PRInt32 nsTableFrame::GetColCount () { - nsCellMap *cellMap = GetCellMap(); - NS_ASSERTION(nsnull!=cellMap, "GetColCount null cellmap"); - - if (nsnull!=cellMap) - { - //if (-1==mEffectiveColCount) - SetEffectiveColCount(); - } - return mEffectiveColCount; + PRInt32 colCount = 0; + nsCellMap* cellMap = GetCellMap(); + NS_ASSERTION(nsnull != cellMap, "GetColCount null cellmap"); + if (nsnull != cellMap) + colCount = cellMap->GetColCount(); + return colCount; } -void nsTableFrame::SetEffectiveColCount() -{ - nsCellMap *cellMap = GetCellMap(); - NS_ASSERTION(nsnull!=cellMap, "SetEffectiveColCount null cellmap"); - if (nsnull!=cellMap) - { - PRInt32 colCount = cellMap->GetColCount(); - mEffectiveColCount = colCount; - PRInt32 rowCount = cellMap->GetRowCount(); - for (PRInt32 colIndex=colCount-1; colIndex>0; colIndex--) - { - PRBool deleteCol=PR_TRUE; - for (PRInt32 rowIndex=0; rowIndexGetCellAt(rowIndex, colIndex); - if ((nsnull!=cell) && (cell->mCell != nsnull)) - { // found a real cell, so we're done - deleteCol = PR_FALSE; - break; - } - } - if (PR_TRUE==deleteCol) - mEffectiveColCount--; - else - break; - } - } - if (PR_TRUE==gsDebug) printf("TIF SetEffectiveColumnCount: returning %d\n", mEffectiveColCount); -} nsTableColFrame * nsTableFrame::GetColFrame(PRInt32 aColIndex) { @@ -525,79 +493,14 @@ nsTableCellFrame * nsTableFrame::GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColI CellData * cellData = cellMap->GetCellAt(aRowIndex, aColIndex); if (nsnull!=cellData) { - result = cellData->mCell; + result = cellData->mOrigCell; if (nsnull==result) - result = cellData->mRealCell->mCell; + result = cellData->mSpanData->mOrigCell; } } return result; } -/** returns PR_TRUE if the row at aRowIndex has any cells that are the result - * of a row-spanning cell. - * @see nsCellMap::RowIsSpannedInto - */ -PRBool nsTableFrame::RowIsSpannedInto(PRInt32 aRowIndex) -{ - NS_PRECONDITION (0<=aRowIndex && aRowIndexRowIsSpannedInto(aRowIndex); - } - return result; -} - -/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1 - * @see nsCellMap::RowHasSpanningCells - */ -PRBool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex) -{ - NS_PRECONDITION (0<=aRowIndex && aRowIndexRowHasSpanningCells(aRowIndex); - } - return result; -} - - -/** returns PR_TRUE if the col at aColIndex has any cells that are the result - * of a col-spanning cell. - * @see nsCellMap::ColIsSpannedInto - */ -PRBool nsTableFrame::ColIsSpannedInto(PRInt32 aColIndex) -{ - PRBool result = PR_FALSE; - nsCellMap * cellMap = GetCellMap(); - NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated."); - if (nsnull!=cellMap) - { - result = cellMap->ColIsSpannedInto(aColIndex); - } - return result; -} - -/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1 - * @see nsCellMap::ColHasSpanningCells - */ -PRBool nsTableFrame::ColHasSpanningCells(PRInt32 aColIndex) -{ - PRBool result = PR_FALSE; - nsCellMap * cellMap = GetCellMap(); - NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated."); - if (nsnull!=cellMap) - { - result = cellMap->ColHasSpanningCells(aColIndex); - } - return result; -} - // return the number of rows spanned by aCell starting at aRowIndex // note that this is different from just the rowspan of aCell // (that would be GetEffectiveRowSpan (indexOfRowThatContains_aCell, aCell) @@ -642,54 +545,38 @@ PRInt32 nsTableFrame::GetEffectiveRowSpan (PRInt32 aRowIndex, nsTableCellFrame * #endif } -// return the number of cols spanned by aCell starting at aColIndex -// note that this is different from just the colspan of aCell -// (that would be GetEffectiveColSpan (indexOfColThatContains_aCell, aCell) +PRInt32 nsTableFrame::GetEffectiveRowSpan(nsTableCellFrame *aCell) +{ + PRInt32 startRow; + aCell->GetRowIndex(startRow); + return GetEffectiveRowSpan(startRow, aCell); +} + + +// Return the number of cols spanned by aCell starting at aColIndex +// This is different from the colspan of aCell. If the cell spans no +// dead cells then the colSpan of the cell would be +// GetEffectiveColSpan (indexOfColThatContains_aCell, aCell) // // XXX Should be moved to colgroup, as GetEffectiveRowSpan should be moved to rowgroup? -PRInt32 nsTableFrame::GetEffectiveColSpan (PRInt32 aColIndex, nsTableCellFrame *aCell) +PRInt32 nsTableFrame::GetEffectiveColSpan(PRInt32 aColIndex, nsTableCellFrame* aCell) { - NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); - nsCellMap *cellMap = GetCellMap(); - NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated."); - PRInt32 colCount = GetColCount(); - NS_PRECONDITION (0<=aColIndex && aColIndexGetRowCount()==1) - return 1; - */ - PRInt32 colSpan = aCell->GetColSpan(); - if (colCount < (aColIndex + colSpan)) - result = colCount - aColIndex; - else - { - result = colSpan; - // check for case where all cells in a column have a colspan - PRInt32 initialColIndex; - aCell->GetColIndex(initialColIndex); - PRInt32 minColSpanForCol = cellMap->GetMinColSpan(initialColIndex); - result -= (minColSpanForCol - 1); // minColSpanForCol is always at least 1 - // and we want to treat default as 0 (no effect) - } -#ifdef NS_DEBUG - if (0>=result) - { - printf("ERROR!\n"); - DumpCellMap(); - PRInt32 initialColIndex; - aCell->GetColIndex(initialColIndex); - printf("aColIndex=%d, cell->colIndex=%d\n", aColIndex, initialColIndex); - printf("aCell->colSpan=%d\n", aCell->GetColSpan()); - printf("colCount=%d\n", mCellMap->GetColCount()); - } -#endif -NS_ASSERTION(0GetEffectiveColSpan(aColIndex, aCell); +} + +PRInt32 nsTableFrame::GetEffectiveColSpan(nsTableCellFrame* aCell) +{ + NS_PRECONDITION (nsnull != aCell, "bad cell arg"); + nsCellMap* cellMap = GetCellMap(); + NS_PRECONDITION (nsnull != cellMap, "bad call, cellMap not yet allocated."); + + PRInt32 initialColIndex; + aCell->GetColIndex(initialColIndex); + return cellMap->GetEffectiveColSpan(initialColIndex, aCell); } PRInt32 nsTableFrame::GetEffectiveCOLSAttribute() @@ -714,9 +601,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) { if (PR_TRUE==gsDebug) printf("TIF EnsureColumns\n"); NS_PRECONDITION(nsnull!=mCellMap, "bad state: null cellmap"); - // XXX sec should only be called on firstInFlow - SetMinColSpanForTable(); - if (nsnull==mCellMap) + if (nsnull == mCellMap) return; // no info yet, so nothing useful to do // make sure we've accounted for the COLS attribute @@ -726,8 +611,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) PRInt32 actualColumns = 0; nsTableColGroupFrame *lastColGroupFrame = nsnull; nsIFrame* childFrame = mColGroups.FirstChild(); - while (nsnull!=childFrame) - { + while (nsnull!=childFrame) { ((nsTableColGroupFrame*)childFrame)->SetStartColumnIndex(actualColumns); PRInt32 numCols = ((nsTableColGroupFrame*)childFrame)->GetColumnCount(); actualColumns += numCols; @@ -739,20 +623,17 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) // if we have fewer column frames than we need, create some implicit column frames PRInt32 colCount = mCellMap->GetColCount(); if (PR_TRUE==gsDebug) printf("EC: actual = %d, colCount=%d\n", actualColumns, colCount); - if (actualColumns < colCount) - { + if (actualColumns < colCount) { if (PR_TRUE==gsDebug) printf("TIF EnsureColumns: actual %d < colCount %d\n", actualColumns, colCount); nsIContent *lastColGroupElement = nsnull; - if (nsnull==lastColGroupFrame) - { // there are no col groups, so create an implicit colgroup frame + if (nsnull==lastColGroupFrame) { // there are no col groups, so create an implicit colgroup frame if (PR_TRUE==gsDebug) printf("EnsureColumns:creating colgroup frame\n"); // Resolve style for the colgroup frame // first, need to get the nearest containing content object GetContent(&lastColGroupElement); // ADDREF a: lastColGroupElement++ (either here or in the loop below) nsIFrame *parentFrame; GetParent(&parentFrame); - while (nsnull==lastColGroupElement) - { + while (nsnull==lastColGroupElement) { parentFrame->GetContent(&lastColGroupElement); if (nsnull==lastColGroupElement) parentFrame->GetParent(&parentFrame); @@ -775,8 +656,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) // hook lastColGroupFrame into child list mColGroups.SetFrames(lastColGroupFrame); } - else - { + else { lastColGroupFrame->GetContent(&lastColGroupElement); // ADDREF b: lastColGroupElement++ } @@ -789,8 +669,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) nsIFrame* lastNewColFrame = nsnull; nsIStyleContextPtr lastColGroupStyle; lastColGroupFrame->GetStyleContext(lastColGroupStyle.AssignPtr()); - for ( ; excessColumns > 0; excessColumns--) - { + for ( ; excessColumns > 0; excessColumns--) { // Create a new col frame nsIFrame* colFrame; // note we pass in PR_TRUE here to force unique style contexts. @@ -805,6 +684,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) colStyleContext, nsnull); NS_RELEASE(colStyleContext); colFrame->SetInitialChildList(aPresContext, nsnull, nsnull); + ((nsTableColFrame *)colFrame)->SetIsAnonymous(PR_TRUE); // Add it to our list if (nsnull == lastNewColFrame) { @@ -817,6 +697,13 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) lastColGroupFrame->SetInitialChildList(aPresContext, nsnull, firstNewColFrame); NS_RELEASE(lastColGroupElement); // ADDREF: lastColGroupElement-- } + else if (actualColumns > colCount) { // the cell map needs to grow to accomodate extra cols + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + cellMap->AddColsAtEnd(actualColumns - colCount); + } + } + } @@ -838,26 +725,12 @@ PRInt32 nsTableFrame::GetNextAvailRowIndex() const PRInt32 result=0; nsCellMap *cellMap = GetCellMap(); NS_PRECONDITION (nsnull!=cellMap, "null cellMap."); - if (nsnull!=cellMap) - { - result = cellMap->GetRowCount(); // the next index is the current count - cellMap->GrowToRow(result+1); // expand the cell map to include this new row + if (nsnull!=cellMap) { + result = cellMap->GetNextAvailRowIndex(); } return result; } -/** return the index of the next column in aRowIndex that does not have a cell assigned to it */ -PRInt32 nsTableFrame::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const -{ - PRInt32 result=0; - nsCellMap *cellMap = GetCellMap(); - NS_PRECONDITION (nsnull!=cellMap, "null cellMap."); - if (nsnull!=cellMap) - result = cellMap->GetNextAvailColIndex(aRowIndex, aColIndex); - if (gsDebug==PR_TRUE) printf("TIF: GetNextAvailColIndex returning %d\n", result); - return result; -} - /** Get the cell map for this table frame. It is not always mCellMap. * Only the firstInFlow has a legit cell map */ @@ -871,89 +744,34 @@ nsCellMap * nsTableFrame::GetCellMap() const return mCellMap; } -void nsTableFrame::SetMinColSpanForTable() -{ // XXX: must be called ONLY on first-in-flow - // set the minColSpan for each column - PRInt32 rowCount = mCellMap->GetRowCount(); - PRInt32 colCount = mCellMap->GetColCount(); - for (PRInt32 colIndex=0; colIndexGetCellFrameAt(rowIndex, colIndex); - if (nsnull!=cellFrame) - { - PRInt32 colSpan = cellFrame->GetColSpan(); - if (0==minColSpan) - minColSpan = colSpan; - else - minColSpan = PR_MIN(minColSpan, colSpan); - } - } - if (1SetMinColSpan(colIndex, minColSpan); -#ifdef NS_DEBUG - if (gsDebug==PR_TRUE) - { - printf("minColSpan for col %d set to %d\n", colIndex, minColSpan); - DumpCellMap(); - } -#endif - } - } -} - -void nsTableFrame::AddCellToTable (nsTableRowFrame *aRowFrame, - nsTableCellFrame *aCellFrame, - PRBool aAddRow) +PRInt32 nsTableFrame::AddCellToTable(nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) { - NS_ASSERTION(nsnull!=aRowFrame, "bad aRowFrame arg"); - NS_ASSERTION(nsnull!=aCellFrame, "bad aCellFrame arg"); - NS_PRECONDITION(nsnull!=mCellMap, "bad cellMap"); + NS_ASSERTION(nsnull != aCellFrame, "bad aCellFrame arg"); + NS_ASSERTION(nsnull != mCellMap, "bad cellMap"); // XXX: must be called only on first-in-flow! if (gsDebug==PR_TRUE) printf("TIF AddCellToTable: frame %p\n", aCellFrame); - // Make an educated guess as to how many columns we have. It's - // only a guess because we can't know exactly until we have - // processed the last row. - if (0 == mColCount) - mColCount = GetSpecifiedColumnCount(); - if (0 == mColCount) // no column parts - { - mColCount = aRowFrame->GetMaxColumns(); - } + return mCellMap->AppendCell(aCellFrame, aRowIndex); +} - PRInt32 rowIndex; - // also determine the index of aRowFrame and set it if necessary - if (0==mCellMap->GetRowCount()) - { // this is the first time we've ever been called - rowIndex = 0; - if (gsDebug==PR_TRUE) printf("rowFrame %p set to index %d\n", aRowFrame, rowIndex); +void nsTableFrame::RemoveCellFromTable(nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) +{ + nsCellMap* cellMap = GetCellMap(); + PRInt32 numCols = cellMap->GetColCount(); + cellMap->RemoveCell(aCellFrame, aRowIndex); + if (numCols != cellMap->GetColCount()) { + // XXX need to remove the anonymous col frames at the end + //nsTableColFrame* colFrame = nsnull; + //GetColumnFrame(colIndex, colFrame); + //if (colFrame && colFrame->IsAnonymous()) { + // nsTableColGroupFrame* colGroupFrame = nsnull; + //colFrame->GetParent((nsIFrame **)&colGroupFrame); + //if (colGroupFrame) { + // colGroupFrame->DeleteColFrame(aPresContext, colFrame); } - else - { - rowIndex = mCellMap->GetRowCount() - 1; // rowIndex is 0-indexed, rowCount is 1-indexed - } - - PRInt32 colIndex=0; - while (PR_TRUE) - { - CellData *data = mCellMap->GetCellAt(rowIndex, colIndex); - if (nsnull == data) - { - BuildCellIntoMap(aCellFrame, rowIndex, colIndex); - break; - } - colIndex++; - } - -#ifdef NS_DEBUG - if (gsDebug==PR_TRUE) - DumpCellMap (); -#endif } static nsresult BuildCellMapForRowGroup(nsIFrame* rowGroupFrame) @@ -997,166 +815,6 @@ NS_METHOD nsTableFrame::ReBuildCellMap() return rv; } -#ifdef NS_DEBUG -void nsTableFrame::DumpCellMap () -{ - printf("dumping CellMap:\n"); - if (nsnull != mCellMap) { - PRInt32 colIndex; - PRInt32 rowCount = mCellMap->GetRowCount(); - PRInt32 colCount = mCellMap->GetColCount(); - printf("rowCount=%d, colCount=%d\n", rowCount, colCount); - - for (PRInt32 rowIndex = 0; rowIndex < rowCount; rowIndex++) { - printf("row %d : ", rowIndex); - for (colIndex = 0; colIndex < colCount; colIndex++) { - CellData* cd = mCellMap->GetCellAt(rowIndex, colIndex); - if (cd != nsnull) { - if (cd->mCell != nsnull) { - printf("C%d,%d ", rowIndex, colIndex); - } else { - nsTableCellFrame* cell = cd->mRealCell->mCell; - nsTableRowFrame* row; - cell->GetParent((nsIFrame**)&row); - int rr = row->GetRowIndex(); - int cc; - cell->GetColIndex(cc); - printf("S%d,%d ", rr, cc); - if (cd->mOverlap != nsnull){ - cell = cd->mOverlap->mCell; - nsTableRowFrame* row2; - cell->GetParent((nsIFrame**)&row2); - rr = row2->GetRowIndex(); - cell->GetColIndex(cc); - printf("O%d,%c ", rr, cc); - } - } - } else { - printf("---- "); - } - } - PRBool spanners = RowHasSpanningCells(rowIndex); - PRBool spannedInto = RowIsSpannedInto(rowIndex); - printf (" spanners=%s spannedInto=%s\n", spanners?"T":"F", spannedInto?"T":"F"); - } - - // output info mapping Ci,j to cell address - PRInt32 cellCount = 0; - for (PRInt32 rIndex = 0; rIndex < rowCount; rIndex++) { - for (colIndex = 0; colIndex < colCount; colIndex++) { - CellData* cd = mCellMap->GetCellAt(rIndex, colIndex); - if (cd != nsnull) { - if (cd->mCell != nsnull) { - printf("C%d,%d=%p ", rIndex, colIndex, cd->mCell); - cellCount++; - } - } - if (0 == (cellCount % 4)) { - printf("\n"); - } - } - } - - // output colspan info - for (colIndex=0; colIndexGetColumnFrame(colIndex); - printf ("col index %d has frame=%p\n", colIndex, colFrame); - } - } else { - printf ("[nsnull]"); - } -} -#endif - -void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex) -{ - NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); - NS_PRECONDITION (0 <= aColIndex, "bad column index arg"); - NS_PRECONDITION (0 <= aRowIndex, "bad row index arg"); - - // Setup CellMap for this cell - int rowSpan = aCell->GetRowSpan(); - int colSpan = aCell->GetColSpan(); - if (gsDebug==PR_TRUE) printf("BCIM: rowSpan = %d, colSpan = %d\n", rowSpan, colSpan); - - // Grow the mCellMap array if we will end up addressing - // some new columns. - if (mCellMap->GetColCount() < (aColIndex + colSpan)) - { - if (gsDebug==PR_TRUE) - printf("BCIM: calling GrowCellMap(%d)\n", aColIndex+colSpan); - GrowCellMap (aColIndex + colSpan); - } - - if (mCellMap->GetRowCount() < (aRowIndex+1)) - { - printf("BCIM: calling GrowToRow(%d)\n", aRowIndex+1); - mCellMap->GrowToRow(aRowIndex+1); - } - - // Setup CellMap for this cell in the table - CellData *data = new CellData (); - data->mCell = aCell; - data->mRealCell = data; - if (gsDebug==PR_TRUE) printf("BCIM: calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex); - mCellMap->SetCellAt(data, aRowIndex, aColIndex); - - // Create CellData objects for the rows that this cell spans. Set - // their mCell to nsnull and their mRealCell to point to data. If - // there were no column overlaps then we could use the same - // CellData object for each row that we span... - if ((1 < rowSpan) || (1 < colSpan)) - { - if (gsDebug==PR_TRUE) printf("BCIM: spans\n"); - for (int rowIndex = 0; rowIndex < rowSpan; rowIndex++) - { - if (gsDebug==PR_TRUE) printf("BCIM: rowIndex = %d\n", rowIndex); - int workRow = aRowIndex + rowIndex; - if (gsDebug==PR_TRUE) printf("BCIM: workRow = %d\n", workRow); - for (int colIndex = 0; colIndex < colSpan; colIndex++) - { - if (gsDebug==PR_TRUE) printf("BCIM: colIndex = %d\n", colIndex); - int workCol = aColIndex + colIndex; - if (gsDebug==PR_TRUE) printf("BCIM: workCol = %d\n", workCol); - CellData *testData = mCellMap->GetCellAt(workRow, workCol); - if (nsnull == testData) - { - CellData *spanData = new CellData (); - spanData->mRealCell = data; - if (gsDebug==PR_TRUE) printf("BCIM: null GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol); - mCellMap->SetCellAt(spanData, workRow, workCol); - } - else if ((0 < rowIndex) || (0 < colIndex)) - { // we overlap, replace existing data, it might be shared - if (gsDebug==PR_TRUE) printf("BCIM: overlapping Cell from GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol); - CellData *overlap = new CellData (); - overlap->mCell = testData->mCell; - overlap->mRealCell = testData->mRealCell; - overlap->mOverlap = data; - mCellMap->SetCellAt(overlap, workRow, workCol); - } - } - } - } -} - -void nsTableFrame::GrowCellMap (PRInt32 aColCount) -{ - if (nsnull!=mCellMap) - { - mCellMap->GrowToCol(aColCount); - mColCount = aColCount; - } -} - - /* ***** Column Layout Data methods ***** */ /* @@ -1243,7 +901,7 @@ void nsTableFrame::DidComputeHorizontalCollapsingBorders(nsIPresContext& aPresCo { CellData *cellData = mCellMap->GetCellAt(0, 0); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } nsRect rowRect(0,0,0,0); if (nsnull!=cellFrame) @@ -1267,7 +925,7 @@ void nsTableFrame::DidComputeHorizontalCollapsingBorders(nsIPresContext& aPresCo { CellData *cellData = mCellMap->GetCellAt(lastRowIndex, 0); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } nsRect rowRect(0,0,0,0); if (nsnull!=cellFrame) @@ -1405,7 +1063,7 @@ void nsTableFrame::ComputeLeftBorderForEdgeAt(nsIPresContext& aPresContext, { CellData *cellData = mCellMap->GetCellAt(aRowIndex, aColIndex); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } nsRect rowRect(0,0,0,0); if (nsnull!=cellFrame) @@ -1481,21 +1139,21 @@ void nsTableFrame::ComputeRightBorderForEdgeAt(nsIPresContext& aPresContext, CellData *cd = mCellMap->GetCellAt(aRowIndex, colIndex); if (cd != nsnull) { // there's really a cell at (aRowIndex, colIndex) - if (nsnull==cd->mCell) + if (nsnull==cd->mOrigCell) { // the cell at (aRowIndex, colIndex) is the result of a span - nsTableCellFrame *cell = cd->mRealCell->mCell; + nsTableCellFrame *cell = cd->mSpanData->mOrigCell; NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell"); PRInt32 realRowIndex; cell->GetRowIndex (realRowIndex); if (realRowIndex!=aRowIndex) { // the span is caused by a rowspan - rightNeighborFrame = cd->mRealCell->mCell; + rightNeighborFrame = cd->mSpanData->mOrigCell; break; } } else { - rightNeighborFrame = cd->mCell; + rightNeighborFrame = cd->mOrigCell; break; } } @@ -1522,7 +1180,7 @@ void nsTableFrame::ComputeRightBorderForEdgeAt(nsIPresContext& aPresContext, { CellData *cellData = mCellMap->GetCellAt(aRowIndex, aColIndex); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } nsRect rowRect(0,0,0,0); if (nsnull!=cellFrame) @@ -1623,7 +1281,7 @@ void nsTableFrame::ComputeTopBorderForEdgeAt(nsIPresContext& aPresContext, { CellData *cellData = mCellMap->GetCellAt(aRowIndex, aColIndex); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } if (nsnull!=cellFrame) { @@ -1704,21 +1362,21 @@ void nsTableFrame::ComputeBottomBorderForEdgeAt(nsIPresContext& aPresContext, CellData *cd = mCellMap->GetCellAt(rowIndex, aColIndex); if (cd != nsnull) { // there's really a cell at (rowIndex, aColIndex) - if (nsnull==cd->mCell) + if (nsnull==cd->mOrigCell) { // the cell at (rowIndex, aColIndex) is the result of a span - nsTableCellFrame *cell = cd->mRealCell->mCell; + nsTableCellFrame *cell = cd->mSpanData->mOrigCell; NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell"); PRInt32 realColIndex; cell->GetColIndex (realColIndex); if (realColIndex!=aColIndex) { // the span is caused by a colspan - bottomNeighborFrame = cd->mRealCell->mCell; + bottomNeighborFrame = cd->mSpanData->mOrigCell; break; } } else { - bottomNeighborFrame = cd->mCell; + bottomNeighborFrame = cd->mOrigCell; break; } } @@ -1746,7 +1404,7 @@ void nsTableFrame::ComputeBottomBorderForEdgeAt(nsIPresContext& aPresContext, { CellData *cellData = mCellMap->GetCellAt(aRowIndex, aColIndex); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } nsRect rowRect(0,0,0,0); if (nsnull!=cellFrame) @@ -2091,7 +1749,7 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) CellData* cellData = cellMap->GetCellAt(row,col); if (cellData) - cell = cellData->mCell; + cell = cellData->mOrigCell; if (nsnull==cell) continue; @@ -2113,7 +1771,8 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) { cellData = cellMap->GetCellAt(row-1,col); if (nsnull != cellData) - above = cellData->mRealCell->mCell; +// XXX was above = cellData->mSpanData->mOrigCell; + above = (cellData->mOrigCell) ? cellData->mOrigCell : cellData->mSpanData->mOrigCell; // Does the cell data point to the same cell? // If it is, then continue @@ -2128,7 +1787,8 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) { cellData = cellMap->GetCellAt(row,col-1); if (cellData != nsnull) - left = cellData->mRealCell->mCell; +// XXX was left = cellData->mSpanData->mOrigCell; +left = (cellData->mOrigCell) ? cellData->mOrigCell : cellData->mSpanData->mOrigCell; if ((nsnull != left) && (left == cell)) continue; @@ -2158,9 +1818,9 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) if (c != col) { cellData = cellMap->GetCellAt(r1,c); - if ((cellData != nsnull) && (cellData->mCell != above)) + if ((cellData != nsnull) && (cellData->mOrigCell != above)) { - above = cellData->mCell; + above = cellData->mOrigCell; if (above != nsnull) AppendLayoutData(boundaryCells[NS_SIDE_TOP],above); } @@ -2175,9 +1835,9 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) { // Add bottom edge cells cellData = cellMap->GetCellAt(r2,c); - if ((cellData != nsnull) && cellData->mCell != below) + if ((cellData != nsnull) && cellData->mOrigCell != below) { - below = cellData->mCell; + below = cellData->mOrigCell; if (below != nsnull) AppendLayoutData(boundaryCells[NS_SIDE_BOTTOM],below); } @@ -2200,9 +1860,9 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) if (r != row) { cellData = cellMap->GetCellAt(r,c1); - if ((cellData != nsnull) && (cellData->mCell != left)) + if ((cellData != nsnull) && (cellData->mOrigCell != left)) { - left = cellData->mCell; + left = cellData->mOrigCell; if (left != nsnull) AppendLayoutData(boundaryCells[NS_SIDE_LEFT],left); } @@ -2217,9 +1877,9 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) { // Add right edge cells cellData = cellMap->GetCellAt(r,c2); - if ((cellData != nsnull) && (cellData->mCell != right)) + if ((cellData != nsnull) && (cellData->mOrigCell != right)) { - right = cellData->mCell; + right = cellData->mOrigCell; if (right != nsnull) AppendLayoutData(boundaryCells[NS_SIDE_RIGHT],right); } @@ -2443,20 +2103,25 @@ void nsTableFrame::SetColumnDimensions(nscoord aHeight) nsIFrame* colGroupFrame = mColGroups.FirstChild(); PRInt32 colX = 0; nsPoint colGroupOrigin(borderPadding.left, borderPadding.top); + PRInt32 numCols = GetColCount(); while (nsnull != colGroupFrame) { nscoord colGroupWidth = 0; nsIFrame* colFrame = nsnull; colGroupFrame->FirstChild(nsnull, &colFrame); nsPoint colOrigin(0, 0); while (nsnull != colFrame) { - NS_ASSERTION(colX < mColCount, "invalid number of columns"); - nscoord colWidth = mColumnWidths[colX] + cellSpacingX; - if (mColCount == 1) { + NS_ASSERTION(colX < numCols, "invalid number of columns"); + nscoord colWidth = mColumnWidths[colX]; + if (numCols == 1) { + colWidth += cellSpacingX + cellSpacingX; + } + else if ((0 == colX) || (numCols - 1 == colX)) { + colWidth += cellSpacingX + halfCellSpacingX; + } + else if (GetNumCellsOriginatingIn(colX) > 0) { colWidth += cellSpacingX; } - else if ((0 == colX) || (mColCount - 1 == colX)) { - colWidth += halfCellSpacingX; - } + colGroupWidth += colWidth; nsRect colRect(colOrigin.x, colOrigin.y, colWidth, colHeight); colFrame->SetRect(colRect); @@ -2523,8 +2188,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext, #ifdef NS_DEBUG if (PR_TRUE==gsDebugIR) { - DumpCellMap(); - printf("tableFrame thinks colCount is %d\n", mEffectiveColCount); + if (mCellMap) mCellMap->Dump(); } #endif needsRecalc=PR_TRUE; @@ -2599,10 +2263,6 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext, // set aDesiredSize and aMaxElementSize } - // DumpCellMap is useful for debugging the results of an incremental reflow. But it's noisy, - // so this module should not be checked in with the call enabled. - //DumpCellMap(); - if (PR_TRUE==gsDebug || PR_TRUE==gsDebugNT) { if (nsnull!=aDesiredSize.maxElementSize) @@ -2939,6 +2599,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext& aPresContext, NS_METHOD nsTableFrame::AdjustForCollapsingRowGroup(nsIFrame* aRowGroupFrame, PRInt32& aRowX) { + nsCellMap* cellMap = GetCellMap(); // XXX is this right const nsStyleDisplay* groupDisplay; aRowGroupFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)groupDisplay)); PRBool groupIsCollapsed = (NS_STYLE_VISIBILITY_COLLAPSE == groupDisplay->mVisible); @@ -2950,7 +2611,7 @@ NS_METHOD nsTableFrame::AdjustForCollapsingRowGroup(nsIFrame* aRowGroupFrame, rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { if (groupIsCollapsed || (NS_STYLE_VISIBILITY_COLLAPSE == rowDisplay->mVisible)) { - mCellMap->SetRowCollapsedAt(aRowX, PR_TRUE); + cellMap->SetRowCollapsedAt(aRowX, PR_TRUE); } aRowX++; } @@ -3009,9 +2670,9 @@ NS_METHOD nsTableFrame::CollapseRowGroup(nsIFrame* aRowGroupFrame, nsTableCellFrame* lastCell = nsnull; for (int colX = 0; colX < numCols; colX++) { CellData* cellData = mCellMap->GetCellAt(aRowX, colX); - if (cellData && !cellData->mCell) { // a cell above is spanning into here + if (cellData && !cellData->mOrigCell) { // a cell above is spanning into here // adjust the real cell's rect only once - nsTableCellFrame* realCell = cellData->mRealCell->mCell; + nsTableCellFrame* realCell = cellData->mSpanData->mOrigCell; if (realCell != lastCell) { nsRect realRect; realCell->GetRect(realRect); @@ -3147,7 +2808,7 @@ NS_METHOD nsTableFrame::AdjustForCollapsingCols(nsIPresContext& aPresContext, CellData* cellData = mCellMap->GetCellAt(rowX, col2X); nsRect cellRect; if (cellData) { - cellFrame = cellData->mCell; + cellFrame = cellData->mOrigCell; if (cellFrame) { // the cell originates at (rowX, colX) cellFrame->GetRect(cellRect); if (collapseGroup || collapseCol) { @@ -3161,7 +2822,7 @@ NS_METHOD nsTableFrame::AdjustForCollapsingCols(nsIPresContext& aPresContext, cellFrame->SetRect(cellRect); // if the cell does not originate at (rowX, colX), adjust the real cells width } else if (collapseGroup || collapseCol) { - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; if ((cellFrame) && (lastCell != cellFrame)) { cellFrame->GetRect(cellRect); cellRect.width -= colWidth + cellSpacingX; @@ -3674,7 +3335,7 @@ nscoord nsTableFrame::ComputeDesiredWidth(const nsHTMLReflowState& aReflowState) nsTableFrame* table = (nsTableFrame*)GetFirstInFlow(); tableLayoutStrategy = table->mTableLayoutStrategy; } - desiredWidth = tableLayoutStrategy->GetTableMaxWidth(); + desiredWidth = tableLayoutStrategy->GetTableMaxContentWidth(); } return desiredWidth; } @@ -4112,6 +3773,7 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext& aPresContext, } mTableLayoutStrategy->BalanceColumnWidths(mStyleContext, aReflowState, maxWidth); + //Dump(PR_TRUE, PR_TRUE); mColumnWidthsSet=PR_TRUE; // if collapsing borders, compute the top and bottom edges now that we have column widths @@ -4136,18 +3798,28 @@ void nsTableFrame::SetTableWidth(nsIPresContext& aPresContext) nscoord cellSpacing = GetCellSpacingX(); if (gsDebug==PR_TRUE) printf ("SetTableWidth with cellSpacing = %d ", cellSpacing); - PRInt32 tableWidth = cellSpacing; + PRInt32 tableWidth = 0; PRInt32 numCols = GetColCount(); - for (PRInt32 colIndex = 0; colIndex 0) { // skip degenerate cols + totalColWidth += cellSpacing; // add cell spacing to left of col + } + if (gsDebug == PR_TRUE) printf (" += %d ", totalColWidth); tableWidth += totalColWidth; } + if (numCols > 0) { + tableWidth += cellSpacing; // add last cellspacing + } + else if (0 == tableWidth) { + nsRect tableRect = mRect; + tableRect.width = 0; + SetRect(tableRect); + return; + } + // Compute the insets (sum of border and padding) const nsStyleSpacing* spacing = (const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing); @@ -4402,6 +4074,8 @@ nscoord nsTableFrame::ComputeDesiredHeight(nsIPresContext& aPresContext, void nsTableFrame::AdjustColumnsForCOLSAttribute() { +// XXX this is not right, +#if 0 nsCellMap *cellMap = GetCellMap(); NS_ASSERTION(nsnull!=cellMap, "bad cell map"); @@ -4431,6 +4105,7 @@ void nsTableFrame::AdjustColumnsForCOLSAttribute() } } } +#endif } /* @@ -4440,11 +4115,16 @@ void nsTableFrame::AdjustColumnsForCOLSAttribute() because specified widths tell us what proportion of the span width to give to each column (in their absence, we use the desired width of the cell.) */ + +// XXX this is being phased out. cells with colspans will potentially overwrite +// col info stored by cells that don't span just because they are a bigger value. +// The fixed width column info should be gotten from nsTableColFrame::GetFixedWidth NS_METHOD nsTableFrame::SetColumnStyleFromCell(nsIPresContext & aPresContext, nsTableCellFrame* aCellFrame, nsTableRowFrame * aRowFrame) { +#if 0 // if the cell has a colspan, the width is used provisionally, divided equally among // the spanned columns until the table layout strategy computes the real column width. if (PR_TRUE==gsDebug) printf("TIF SetCSFromCell: cell %p in row %p\n", aCellFrame, aRowFrame); @@ -4535,6 +4215,7 @@ nsTableFrame::SetColumnStyleFromCell(nsIPresContext & aPresContext, } } } +#endif return NS_OK; } @@ -4703,7 +4384,7 @@ void nsTableFrame::CacheColFramesInCellMap() PRInt32 repeat = colFrame->GetSpan(); for (PRInt32 i=0; iGetColumnFrame(colIndex+i); + nsTableColFrame *cachedColFrame = mCellMap->GetColumnFrame(colIndex+i); if (nsnull==cachedColFrame) { if (gsDebug) @@ -5392,12 +5073,10 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, const nsHTMLReflowState& aReflowState, nscoord& aSpecifiedTableWidth) { - NS_ASSERTION(nsnull!=aTableStyle, "bad arg - aTableStyle"); + NS_ASSERTION(nsnull != aTableStyle, "bad arg - aTableStyle"); PRBool result = PR_TRUE; // the default - if (nsnull!=aTableStyle) - { + if (aTableStyle) { nsStylePosition* tablePosition = (nsStylePosition*)aTableStyle->GetStyleData(eStyleStruct_Position); - nsMargin borderPadding; const nsStyleSpacing* spacing; switch (tablePosition->mWidth.GetUnit()) { case eStyleUnit_Auto: // specified auto width @@ -5413,12 +5092,8 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, { nscoord coordWidth = tablePosition->mWidth.GetCoordValue(); // NAV4 compatibility. If coord width is 0, do nothing so we get same result as "auto" - if (0!=coordWidth) - { + if (0 != coordWidth) { aSpecifiedTableWidth = coordWidth; - aReflowState.frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); - spacing->CalcBorderPaddingFor(aReflowState.frame, borderPadding); //XXX: COLLAPSE - aSpecifiedTableWidth -= (borderPadding.right + borderPadding.left); result = PR_FALSE; } } @@ -5429,9 +5104,9 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, // set aSpecifiedTableWidth to be the given percent of the parent. // first, get the effective parent width (parent width - insets) nscoord parentWidth = nsTableFrame::GetTableContainerWidth(aReflowState); - if (NS_UNCONSTRAINEDSIZE!=parentWidth) - { + if (NS_UNCONSTRAINEDSIZE != parentWidth) { aReflowState.frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); + nsMargin borderPadding; spacing->CalcBorderPaddingFor(aReflowState.frame, borderPadding); //XXX: COLLAPSE parentWidth -= (borderPadding.right + borderPadding.left); @@ -5442,8 +5117,7 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, printf("%p: TableIsAutoWidth setting aSpecifiedTableWidth = %d with parentWidth = %d and percent = %f\n", aTableFrame, aSpecifiedTableWidth, parentWidth, percent); } - else - { + else { aSpecifiedTableWidth=parentWidth; if (PR_TRUE==gsDebug || PR_TRUE==gsDebugNT) printf("%p: TableIsAutoWidth setting aSpecifiedTableWidth = %d with parentWidth = %d\n", @@ -5469,20 +5143,20 @@ nscoord nsTableFrame::GetMinCaptionWidth() } /** return the minimum width of the table. Return 0 if the min width is unknown. */ -nscoord nsTableFrame::GetMinTableWidth() +nscoord nsTableFrame::GetMinTableContentWidth() { nscoord result = 0; if (nsnull!=mTableLayoutStrategy) - result = mTableLayoutStrategy->GetTableMinWidth(); + result = mTableLayoutStrategy->GetTableMinContentWidth(); return result; } /** return the maximum width of the table. Return 0 if the max width is unknown. */ -nscoord nsTableFrame::GetMaxTableWidth() +nscoord nsTableFrame::GetMaxTableContentWidth() { nscoord result = 0; if (nsnull!=mTableLayoutStrategy) - result = mTableLayoutStrategy->GetTableMaxWidth(); + result = mTableLayoutStrategy->GetTableMaxContentWidth(); return result; } @@ -5533,6 +5207,29 @@ nsTableFrame::IsFinalPass(const nsReflowState& aState) (NS_UNCONSTRAINEDSIZE != aState.availableHeight); } +void nsTableFrame::Dump(PRBool aDumpCols, PRBool aDumpCellMap) +{ + printf("***START TABLE DUMP***, \n colWidths="); + PRInt32 colX; + PRInt32 numCols = GetColCount(); + for (colX = 0; colX < numCols; colX++) { + printf("%d ", mColumnWidths[colX]); + } + if (aDumpCols) { + for (colX = 0; colX < numCols; colX++) { + printf("\n"); + nsTableColFrame* colFrame = GetColFrame(colX); + colFrame->Dump(1); + } + } + if (aDumpCellMap) { + printf("\n"); + nsCellMap* cellMap = GetCellMap(); + cellMap->Dump(); + } + printf(" ***END TABLE DUMP*** \n"); +} + // nsTableIterator nsTableIterator::nsTableIterator(nsIFrame& aSource, nsTableIteration aType) @@ -5632,4 +5329,86 @@ PRInt32 nsTableIterator::Count() return mCount; } +void nsTableFrame::GetCellInfoAt(PRInt32 aRowX, + PRInt32 aColX, + nsTableCellFrame*& aCellFrame, + PRBool& aOriginates, + PRInt32& aColSpan) +{ + nsCellMap* cellMap = GetCellMap(); + cellMap->GetCellInfoAt(aRowX, aColX, aCellFrame, aOriginates, aColSpan); +} +PRInt32 nsTableFrame::GetNumCellsOriginatingIn(PRInt32 aColIndex) +{ + nsCellMap* cellMap = GetCellMap(); + return cellMap->GetNumCellsOriginatingIn(aColIndex); +} + +// The following are not used anywhere, but have been retained here just in case. +#if 0 +/** returns PR_TRUE if the row at aRowIndex has any cells that are the result + * of a row-spanning cell. + * @see nsCellMap::RowIsSpannedInto + */ +PRBool nsTableFrame::RowIsSpannedInto(PRInt32 aRowIndex) +{ + NS_PRECONDITION (0<=aRowIndex && aRowIndexRowIsSpannedInto(aRowIndex); + } + return result; +} + +/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1 + * @see nsCellMap::RowHasSpanningCells + */ +PRBool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex) +{ + NS_PRECONDITION (0<=aRowIndex && aRowIndexRowHasSpanningCells(aRowIndex); + } + return result; +} + + +/** returns PR_TRUE if the col at aColIndex has any cells that are the result + * of a col-spanning cell. + * @see nsCellMap::ColIsSpannedInto + */ +PRBool nsTableFrame::ColIsSpannedInto(PRInt32 aColIndex) +{ + PRBool result = PR_FALSE; + nsCellMap * cellMap = GetCellMap(); + NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated."); + if (nsnull!=cellMap) + { + result = cellMap->ColIsSpannedInto(aColIndex); + } + return result; +} + +/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1 + * @see nsCellMap::ColHasSpanningCells + */ +PRBool nsTableFrame::ColHasSpanningCells(PRInt32 aColIndex) +{ + PRBool result = PR_FALSE; + nsCellMap * cellMap = GetCellMap(); + NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated."); + if (nsnull!=cellMap) + { + result = cellMap->ColHasSpanningCells(aColIndex); + } + return result; +} +#endif diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h index c9f7184012e..328ec1a8e92 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.h +++ b/mozilla/layout/html/table/src/nsTableFrame.h @@ -47,6 +47,7 @@ struct nsStyleSpacing; #define NS_TABLE_FRAME_COLGROUP_LIST_INDEX 0 #define NS_TABLE_FRAME_LAST_LIST_INDEX NS_TABLE_FRAME_COLGROUP_LIST_INDEX + /* ============================================================================ */ /** nsTableFrame maps the inner portion of a table (everything except captions.) @@ -91,14 +92,6 @@ public: /** @see nsIFrame::Destroy */ NS_IMETHOD Destroy(nsIPresContext& aPresContext); - /** helper method for determining if this is a nested table or not - * @param aReflowState The reflow state for this inner table frame - * @param aPosition [OUT] The position style struct for the parent table, if nested. - * If not nested, undefined. - * @return PR_TRUE if this table is nested inside another table. - */ - PRBool IsNested(const nsHTMLReflowState& aReflowState, const nsStylePosition *& aPosition) const; - /** helper method to find the table parent of any table frame object */ // TODO: today, this depends on display types. This should be changed to rely // on stronger criteria, like an inner table frame atom @@ -377,6 +370,7 @@ public: * of the table. */ virtual PRInt32 GetEffectiveRowSpan(PRInt32 aRowIndex, nsTableCellFrame *aCell); + virtual PRInt32 GetEffectiveRowSpan(nsTableCellFrame *aCell); /** return the col span of a cell, taking into account col span magic at the edge * of a table. @@ -388,6 +382,7 @@ public: * of the table. */ virtual PRInt32 GetEffectiveColSpan(PRInt32 aColIndex, nsTableCellFrame *aCell); + virtual PRInt32 GetEffectiveColSpan(nsTableCellFrame *aCell); /** return the value of the COLS attribute, adjusted for the * actual number of columns in the table @@ -399,23 +394,24 @@ public: */ PRInt32 GetNextAvailRowIndex() const; - /** return the index of the next column in aRowIndex after aColIndex - * that does not have a cell assigned to it. - * If aColIndex is past the end of the row, it is returned. - * If the row is not initialized, 0 is returned. - */ - PRInt32 GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const; - /** build as much of the CellMap as possible from the info we have so far */ - virtual void AddCellToTable (nsTableRowFrame *aRowFrame, - nsTableCellFrame *aCellFrame, - PRBool aAddRow); + virtual PRInt32 AddCellToTable (nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex); + virtual void RemoveCellFromTable (nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex); virtual void AddColumnFrame (nsTableColFrame *aColFrame); static PRBool IsFinalPass(const nsReflowState& aReflowState); + void GetCellInfoAt(PRInt32 aRowX, + PRInt32 aColX, + nsTableCellFrame*& aCellFrame, + PRBool& aOriginates, + PRInt32& aColSpan); + PRInt32 GetNumCellsOriginatingIn(PRInt32 aColIndex); + NS_METHOD GetBorderPlusMarginPadding(nsMargin& aResult); protected: @@ -433,6 +429,14 @@ protected: virtual PRBool ParentDisablesSelection() const; //override default behavior + /** helper method for determining if this is a nested table or not + * @param aReflowState The reflow state for this inner table frame + * @param aPosition [OUT] The position style struct for the parent table, if nested. + * If not nested, undefined. + * @return PR_TRUE if this table is nested inside another table. + */ + PRBool IsNested(const nsHTMLReflowState& aReflowState, const nsStylePosition *& aPosition) const; + public: /** first pass of ResizeReflow. * lays out all table content with aMaxSize(NS_UNCONSTRAINEDSIZE,NS_UNCONSTRAINEDSIZE) and @@ -700,14 +704,15 @@ protected: void MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBorderWidth); PRBool ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult); - /** called whenever the number of columns changes, to increase the storage in mCellMap - */ - virtual void GrowCellMap(PRInt32 aColCount); - /** returns PR_TRUE if the cached pass 1 data is still valid */ virtual PRBool IsCellMapValid() const; public: + /** Get the cell map for this table frame. It is not always mCellMap. + * Only the firstInFlow has a legit cell map + */ + virtual nsCellMap *GetCellMap() const; + /** ResetCellMap is called when the cell structure of the table is changed. * Call with caution, only when changing the structure of the table such as * inserting or removing rows, changing the rowspan or colspan attribute of a cell, etc. @@ -718,19 +723,9 @@ protected: /** iterates all child frames and creates a new cell map */ NS_IMETHOD ReBuildCellMap(); - /** Get the cell map for this table frame. It is not always mCellMap. - * Only the firstInFlow has a legit cell map - */ - virtual nsCellMap *GetCellMap() const; - void SetColumnDimensions(nscoord aHeight); #ifdef NS_DEBUG - /** for debugging only - * prints out information about the cell map - */ - void DumpCellMap(); - /** for debugging only * prints out info about the table layout state, printing columns and their cells */ @@ -743,9 +738,6 @@ protected: */ virtual void EnsureColumns (nsIPresContext& aPresContext); - /** Set the min col span for every column in the table. Scans the whole table. */ - virtual void SetMinColSpanForTable(); - virtual void BuildColumnCache(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -756,16 +748,6 @@ protected: virtual void CacheColFramesInCellMap(); - /** called every time we discover we have a new cell to add to the table. - * This could be because we got actual cell content, because of rowspan/colspan attributes, etc. - * This method changes mCellMap as necessary to account for the new cell. - * - * @param aCell the content object created for the cell - * @param aRowIndex the row into which the cell is to be inserted - * @param aColIndex the col into which the cell is to be inserted - */ - virtual void BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex); - /** return the number of columns as specified by the input. * has 2 side effects:
* calls SetStartColumnIndex on each nsTableColumn
@@ -786,13 +768,9 @@ public: /* ----- Cell Map public methods ----- */ */ virtual PRInt32 GetRowCount() const; - /** returns the number of columns in this table. */ - virtual PRInt32 GetColCount(); - - /** adjust the col count for screwy table attributes. - * currently just handles excess colspan at end of table + /** returns the number of columns in this table after redundant columns have been removed */ - virtual void SetEffectiveColCount(); + virtual PRInt32 GetColCount(); /** return the column frame at colIndex. * returns nsnull if the col frame has not yet been allocated, or if aColIndex is out of range @@ -805,37 +783,16 @@ public: /* ----- Cell Map public methods ----- */ */ nsTableCellFrame * GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex); - /** returns PR_TRUE if the row at aRowIndex has any cells that are the result - * of a row-spanning cell above it. - * @see nsCellMap::RowIsSpannedInto - */ - PRBool RowIsSpannedInto(PRInt32 aRowIndex); - - /** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1 - * that originate in aRowIndex. - * @see nsCellMap::RowHasSpanningCells - */ - PRBool RowHasSpanningCells(PRInt32 aRowIndex); - - /** returns PR_TRUE if the col at aColIndex has any cells that are the result - * of a col-spanning cell. - * @see nsCellMap::ColIsSpannedInto - */ - PRBool ColIsSpannedInto(PRInt32 aColIndex); - - /** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1 - * @see nsCellMap::ColHasSpanningCells - */ - PRBool ColHasSpanningCells(PRInt32 aColIndex); - /** return the minimum width of the table caption. Return 0 if there is no caption. */ nscoord GetMinCaptionWidth(); - /** return the minimum width of the table. Return 0 if the min width is unknown. */ - nscoord GetMinTableWidth(); + /** return the minimum contend width of the table (excludes borders and padding). + Return 0 if the min width is unknown. */ + nscoord GetMinTableContentWidth(); - /** return the maximum width of the table caption. Return 0 if the max width is unknown. */ - nscoord GetMaxTableWidth(); + /** return the maximum content width of the table (excludes borders and padding). + Return 0 if the max width is unknown. */ + nscoord GetMaxTableContentWidth(); /** compute the max-element-size for the table * @param aMaxElementSize [OUT] width field set to the min legal width of the table @@ -847,6 +804,7 @@ public: /* ----- Cell Map public methods ----- */ public: static nsIAtom* gColGroupAtom; + void Dump(PRBool aDumpCols, PRBool aDumpCellMap); protected: void DebugPrintCount() const; // Debugging routine @@ -862,7 +820,6 @@ protected: PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change PRBool mHasScrollableRowGroup; // PR_TRUE if any section has overflow == "auto" or "scroll" PRInt32 mColCount; // the number of columns in this table - PRInt32 mEffectiveColCount; // the number of columns in this table adjusted for weird table attributes nsCellMap* mCellMap; // maintains the relationships between rows, cols, and cells ColumnInfoCache *mColCache; // cached information about the table columns nsITableLayoutStrategy * mTableLayoutStrategy; // the layout strategy for this frame diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index 82ed2a40cbf..fccb0a19cee 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -17,6 +17,7 @@ */ #include "nsTableRowFrame.h" #include "nsIRenderingContext.h" +#include "nsIPresShell.h" #include "nsIPresContext.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" @@ -31,6 +32,10 @@ #include "nsCSSRendering.h" #include "nsHTMLIIDs.h" #include "nsLayoutAtoms.h" +#include "nsHTMLParts.h" +#include "nsTableColGroupFrame.h" +#include "nsTableColFrame.h" +#include "nsCOMPtr.h" // the following header files are required for style optimizations that work only when the child content is really a cell #include "nsIHTMLTableCellElement.h" static NS_DEFINE_IID(kIHTMLTableCellElementIID, NS_IHTMLTABLECELLELEMENT_IID); @@ -117,7 +122,7 @@ nsTableRowFrame::Init(nsIPresContext& aPresContext, } NS_IMETHODIMP -nsTableRowFrame::InitChildren(PRInt32 aRowIndex) +nsTableRowFrame::InitChildren() { if (gsDebug) printf("Row InitChildren: begin\n"); nsTableFrame* table = nsnull; @@ -132,11 +137,7 @@ nsTableRowFrame::InitChildren(PRInt32 aRowIndex) if ((NS_OK==result) && (table != nsnull)) { mInitializedChildren=PR_TRUE; - PRInt32 rowIndex; - if (-1==aRowIndex) - rowIndex = table->GetNextAvailRowIndex(); - else - rowIndex = aRowIndex; + PRInt32 rowIndex = table->GetNextAvailRowIndex(); SetRowIndex(rowIndex); if (gsDebug) printf("Row InitChildren: set row index to %d\n", rowIndex); PRInt32 colIndex = 0; @@ -146,33 +147,14 @@ nsTableRowFrame::InitChildren(PRInt32 aRowIndex) kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { + // add the cell frame to the table's cell map and get its col index + PRInt32 colIndex; + colIndex = table->AddCellToTable((nsTableCellFrame *)kidFrame, rowIndex); // what column does this cell belong to? - colIndex = table->GetNextAvailColIndex(mRowIndex, colIndex); - if (gsDebug) printf("Row InitChildren: cell given colIndex %d\n", colIndex); - /* for style context optimization, set the content's column index if possible. - * this can only be done if we really have an nsTableCell. - * other tags mapped to table cell display won't benefit from this optimization - * see nsHTMLStyleSheet::RulesMatching - */ - nsIContent* cell; - kidFrame->GetContent(&cell); - nsIHTMLTableCellElement *cellContent = nsnull; - nsresult rv = cell->QueryInterface(kIHTMLTableCellElementIID, - (void **)&cellContent); // cellContent: REFCNT++ - NS_RELEASE(cell); - if (NS_SUCCEEDED(rv)) - { // we know it's a table cell - cellContent->SetColIndex(colIndex); - if (gsDebug) printf("%p : set cell content %p to col index = %d\n", this, cellContent, colIndex); - NS_RELEASE(cellContent); - } - + if (gsDebug) printf("Row InitChildren: cell given colIndex %d\n", colIndex); // this sets the frame's notion of it's column index ((nsTableCellFrame *)kidFrame)->InitCellFrame(colIndex); - if (gsDebug) printf("%p : set cell frame %p to col index = %d\n", this, kidFrame, colIndex); - // add the cell frame to the table's cell map - if (gsDebug) printf("Row InitChildren: calling AddCellToTable...\n"); - table->AddCellToTable(this, (nsTableCellFrame *)kidFrame, kidFrame == mFrames.FirstChild()); + if (gsDebug) printf("%p : set cell frame %p to col index = %d\n", this, kidFrame, colIndex); } } } @@ -515,17 +497,16 @@ void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext, aReflowState.x += aKidRect.width; // Update the maximum element size - PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan(mRowIndex, - ((nsTableCellFrame*)aKidFrame)); - if (nsnull != aMaxElementSize) - { + PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan((nsTableCellFrame*)aKidFrame); + if (nsnull != aMaxElementSize) { aMaxElementSize->width += aKidMaxElementSize->width; - if ((mMinRowSpan==rowSpan) && (aKidMaxElementSize->height>aMaxElementSize->height)) - { - aMaxElementSize->height = aKidMaxElementSize->height; + if (1 == rowSpan) { + aMaxElementSize->height = PR_MAX(aMaxElementSize->height, aKidMaxElementSize->height); } } +// XXX this will be fixed when row spans deal with dead rows +#if 0 // this accounts for cases where all cells in a row have a rowspan>1 // XXX "numColsInThisRow==numColsInTable" probably isn't the right metric to use here // the point is to skip a cell who's span effects another row, maybe use cellmap? @@ -548,6 +529,23 @@ void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext, aReflowState.maxCellVertSpace = height; } } +#else + if (1 == rowSpan) { + // Update maxCellHeight + if (aKidRect.height > aReflowState.maxCellHeight) + aReflowState.maxCellHeight = aKidRect.height; + + // Update maxCellVertSpace + nsMargin margin; + + if (aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)aKidFrame, margin) == NS_OK) { + nscoord height = aKidRect.height + margin.top + margin.bottom; + + if (height > aReflowState.maxCellVertSpace) + aReflowState.maxCellVertSpace = height; + } + } +#endif } /** @@ -615,7 +613,9 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, if (prevColIndex != (cellColIndex - 1)) { for (PRInt32 colIndex = prevColIndex + 1; cellColIndex > colIndex; colIndex++) { aReflowState.x += aReflowState.tableFrame->GetColumnWidth(colIndex); - aReflowState.x += cellSpacingX; + if (aReflowState.tableFrame->GetNumCellsOriginatingIn(colIndex) > 0) { + aReflowState.x += cellSpacingX; + } if (PR_TRUE==gsDebug) printf(" Row: in loop, aReflowState.x set to %d from cellSpacing %d and col width %d\n", aReflowState.x, cellSpacingX, aReflowState.tableFrame->GetColumnWidth(colIndex)); @@ -627,7 +627,9 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, PRInt32 lastCol = cellColIndex + cellColSpan - 1; for (PRInt32 colIndex = prevColIndex - 1; colIndex > lastCol; colIndex--) { aReflowState.x += aReflowState.tableFrame->GetColumnWidth(colIndex); - aReflowState.x += cellSpacingX; + if (aReflowState.tableFrame->GetNumCellsOriginatingIn(colIndex) > 0) { + aReflowState.x += cellSpacingX; + } if (PR_TRUE==gsDebug) printf(" Row: in loop, aReflowState.x set to %d from cellSpacing %d and col width %d\n", aReflowState.x, cellSpacingX, aReflowState.tableFrame->GetColumnWidth(colIndex)); @@ -641,16 +643,15 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, // at this point, we know the column widths. // so we get the avail width from the known column widths nscoord availWidth = 0; - for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellColIndex+numColSpan); - if (numColSpan != 0) - { + if ((numColSpan != 0) && (aReflowState.tableFrame->GetNumCellsOriginatingIn(cellColIndex + numColSpan) > 0)) { availWidth += cellSpacingX; } - if (PR_TRUE==gsDebug) + if (PR_TRUE==gsDebug) { printf(" Row: in loop, availWidth set to %d from colIndex %d width %d and cellSpacing\n", availWidth, cellColIndex, aReflowState.tableFrame->GetColumnWidth(cellColIndex+numColSpan)); + } } if (PR_TRUE==gsDebug) printf(" Row: availWidth for this cell is %d\n", availWidth); // remember the rightmost (ltr) or leftmost (rtl) column this cell spans into @@ -777,21 +778,21 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, // we were given by the row group frame aDesiredSize.width = aReflowState.x; aDesiredSize.height = aReflowState.maxCellVertSpace; +#ifdef DEBUG + nscoord overAllocated = aDesiredSize.width - aReflowState.reflowState.availableWidth; + if (overAllocated > 0) { + float p2t; + aPresContext.GetScaledPixelsToTwips(&p2t); + if (overAllocated > p2t) { + printf("row over allocated by %d twips", overAllocated); + } + } +#endif if (gsDebug) printf("Row: RR -- row %p width = %d from maxSize %d\n", this, aDesiredSize.width, aReflowState.reflowState.availableWidth); - if (aDesiredSize.width > aReflowState.reflowState.availableWidth) - { - if (gsDebug) - { - printf ("Row %p error case, desired width = %d, maxSize=%d\n", - this, aDesiredSize.width, aReflowState.reflowState.availableWidth); - fflush (stdout); - } - } - NS_ASSERTION(aDesiredSize.width <= aReflowState.reflowState.availableWidth, "row calculated to be too wide."); return rv; } @@ -1153,6 +1154,7 @@ NS_METHOD nsTableRowFrame::IR_CellInserted(nsIPresContext& aPresContext, if (NS_FAILED(rv) || nsnull==tableFrame) return rv; +#if 0 // do a pass-1 layout of the cell if (PR_TRUE==tableFrame->RequiresPass1Layout()) { @@ -1161,6 +1163,7 @@ NS_METHOD nsTableRowFrame::IR_CellInserted(nsIPresContext& aPresContext, if (NS_FAILED(rv)) return rv; } +#endif // set row state GetMinRowSpan(tableFrame); @@ -1169,6 +1172,7 @@ NS_METHOD nsTableRowFrame::IR_CellInserted(nsIPresContext& aPresContext, // set table state tableFrame->InvalidateCellMap(); tableFrame->InvalidateColumnCache(); + tableFrame->InvalidateColumnWidths(); return rv; } @@ -1184,7 +1188,7 @@ NS_METHOD nsTableRowFrame::IR_CellAppended(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, RowReflowState& aReflowState, nsReflowStatus& aStatus, - nsTableCellFrame * aAppendedFrame) + nsTableCellFrame* aAppendedFrame) { if (PR_TRUE==gsDebugIR) printf("\nTRF IR: IR_CellInserted\n"); @@ -1197,6 +1201,7 @@ NS_METHOD nsTableRowFrame::IR_CellAppended(nsIPresContext& aPresContext, if (NS_FAILED(rv) || nsnull==tableFrame) return rv; + tableFrame->AddCellToTable(aAppendedFrame, GetRowIndex()); // do a pass-1 layout of the cell if (PR_TRUE==tableFrame->RequiresPass1Layout()) { @@ -1260,9 +1265,33 @@ NS_METHOD nsTableRowFrame::IR_CellRemoved(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, RowReflowState& aReflowState, nsReflowStatus& aStatus, - nsTableCellFrame * aDeletedFrame) + nsTableCellFrame* aDeletedFrame) { if (PR_TRUE==gsDebugIR) printf("\nRow IR: IR_RowRemoved\n"); + + nsTableFrame* tableFrame=nsnull; + nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); + if (NS_FAILED(rv) || nsnull == tableFrame) + return rv; + + PRInt32 colIndex; + aDeletedFrame->GetColIndex(colIndex); + tableFrame->RemoveCellFromTable(aDeletedFrame, GetRowIndex()); + rv = mFrames.DestroyFrame(aPresContext, (nsIFrame*)aDeletedFrame); + if (NS_FAILED(rv)) + return rv; + + ResetMaxChildHeight(); + + // set row state + GetMinRowSpan(tableFrame); + FixMinCellHeight(tableFrame); + + // set table state + tableFrame->InvalidateCellMap(); + tableFrame->InvalidateColumnCache(); + +#if 0 nsresult rv = mFrames.DestroyFrame(aPresContext, (nsIFrame*)aDeletedFrame); if (NS_SUCCEEDED(rv)) { @@ -1271,19 +1300,11 @@ NS_METHOD nsTableRowFrame::IR_CellRemoved(nsIPresContext& aPresContext, rv = nsTableFrame::GetTableFrame(this, tableFrame); if (NS_FAILED(rv) || nsnull==tableFrame) return rv; +#endif - // set row state - GetMinRowSpan(tableFrame); - FixMinCellHeight(tableFrame); - - // set table state - tableFrame->InvalidateCellMap(); - tableFrame->InvalidateColumnCache(); - - // if any column widths have to change due to this, rebalance column widths - //XXX need to calculate this, but for now just do it - tableFrame->InvalidateColumnWidths(); - } + // if any column widths have to change due to this, rebalance column widths + //XXX need to calculate this, but for now just do it + tableFrame->InvalidateColumnWidths(); return rv; } diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.h b/mozilla/layout/html/table/src/nsTableRowFrame.h index dbb1535c4b9..cddb6b6b175 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowFrame.h @@ -45,7 +45,7 @@ public: nsIFrame* aPrevInFlow); /** Initialization of data */ - NS_IMETHOD InitChildren(PRInt32 aRowIndex=-1); + NS_IMETHOD InitChildren(); void ResetInitChildren(); diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 6611c38338e..00394daff15 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -468,15 +468,13 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext& aPresC kidRect.height); PRInt32 colCount = aReflowState.tableFrame->GetColCount(); PRInt32 colIndex = 0; - nsIFrame *cellFrame = aReflowState.tableFrame->GetCellFrameAt(rowIndex, colIndex); - while (colIndexGetCellFrameAt(rowIndex, colIndex); + if (cellFrame) { const nsStyleDisplay *cellDisplay; cellFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)cellDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == cellDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_CELL == cellDisplay->mDisplay) { ((nsTableCellFrame *)(cellFrame))->SetBorderEdgeLength(NS_SIDE_LEFT, rowIndex, kidRect.height); @@ -485,8 +483,6 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext& aPresC kidRect.height); } } - colIndex++; - cellFrame = aReflowState.tableFrame->GetCellFrameAt(rowIndex, colIndex); } } } @@ -668,7 +664,6 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, // the avail height needs to reduce by top and bottom margins nscoord availHeightOfRowsSpanned = heightOfRowsSpanned - cellSpacingY - cellSpacingY; if (gsDebug) printf("TRGF CalcRowH: availHeightOfRowsSpanned=%d\n", availHeightOfRowsSpanned); - /* if the cell height fits in the rows, expand the spanning cell's height and slap it in */ nsSize cellFrameSize; cellFrame->GetSize(cellFrameSize); diff --git a/mozilla/layout/html/tests/table/bugs/bug1800.html b/mozilla/layout/html/tests/table/bugs/bug1800.html index 72f4900a8a4..d9cdaaa7140 100644 --- a/mozilla/layout/html/tests/table/bugs/bug1800.html +++ b/mozilla/layout/html/tests/table/bugs/bug1800.html @@ -1,10 +1,49 @@ - - + + + + +
-cell of outer table -
- - -
cell of nested table
-
+ cell of outer table
+ + + +
cell of nested table
+
+
+
+nested table width includes border + + + +
+ + + +
200 nested table
+
+nested table width includes border + + + +
+ + + +
auto nested table
+
+nested table width includes border + + + +
100% width table
+
+nested table width includes border + + +
+ + + +
100% nested table
diff --git a/mozilla/layout/html/tests/table/bugs/bug2763.html b/mozilla/layout/html/tests/table/bugs/bug2763.html new file mode 100644 index 00000000000..774ca8b582e --- /dev/null +++ b/mozilla/layout/html/tests/table/bugs/bug2763.html @@ -0,0 +1,10 @@ +two and words should be on the same line + + + + + + + + +
two wordsblah
blah
diff --git a/mozilla/layout/html/tests/table/bugs/file_list.txt b/mozilla/layout/html/tests/table/bugs/file_list.txt index 7439ad94e7a..a0b9b15ef48 100644 --- a/mozilla/layout/html/tests/table/bugs/file_list.txt +++ b/mozilla/layout/html/tests/table/bugs/file_list.txt @@ -31,6 +31,7 @@ file://s:/mozilla/layout/html/tests/table/bugs/bug2469.html file://s:/mozilla/layout/html/tests/table/bugs/bug2516.html file://s:/mozilla/layout/html/tests/table/bugs/bug2585.html file://s:/mozilla/layout/html/tests/table/bugs/bug2757.html +file://s:/mozilla/layout/html/tests/table/bugs/bug2763.html file://s:/mozilla/layout/html/tests/table/bugs/bug2962.html file://s:/mozilla/layout/html/tests/table/bugs/bug2981-1.html file://s:/mozilla/layout/html/tests/table/bugs/bug2981-2.html diff --git a/mozilla/layout/html/tests/table/core/bloomberg.html b/mozilla/layout/html/tests/table/core/bloomberg.html new file mode 100644 index 00000000000..1c982cb9262 --- /dev/null +++ b/mozilla/layout/html/tests/table/core/bloomberg.html @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + +
+MARKETS
+News
+Stocks
+Tech Stocks
+Stocks on the Move
+IPO Center
+World Indices
+Rates & Bonds
+U.S. Treasuries
+Currencies
+Currency Calculator
+Commodities
+
+ +MONEY
+Mutual Funds
+Portfolio
+Loan Center
+Mortgage Calculator
+Investing
+Retirement
+Negocios Bloomberg
+
+MAGAZINES
+Personal Finance
+Wealth Manager
+
+BUSINESS CENTER
+Small Business
+
+CAREERS
+
+LIFE
+The Finer Things
+Sports
+Charlie Rose
+B-Commerce

+
+To Advertise

+The Loan Center brought to you by Lending Tree + + +Market Monitor + + +Tue, 27 Jul 1999, 2:47pm EDT
+Market Snapshot
+
+ +Visa Small Business + +Financial Market Update
+AUDIO  |   VIDEO + +
+
+ +
+ +Apply for a loan with Lending Tree + +
+Today's Feature

+Looking for a new approach to investing? How about a portfolio where every holding has a word for its stock symbol? +
+More... +
What's New
+ +Use BLOOMBERG.com to Find a New Job
+Whether you know what you're looking for or just know you're looking, the new career page offers better searches, news, and calculators than ever before.
+ +Bloomberg News on Rocket eBook
+Bloomberg's Top Financial News is now available for download on your Rocket eBook. Get tomorrow's news today with Bloomberg's summary of the day's top stories. Bloomberg daily RocketEditions are FREE until September 1.
+ +Bloomberg News to Go
+Get tomorrow's news today. FREE weekday email report of the top stories in business & finance from BLOOMBERG NEWS at 5pm EST.
+ +Bloomberg Year 2000 Letters
+For Y2K information on BLOOMBERG, download our customer letters now.
+ + +
+

+©1999 Bloomberg L.P. All rights reserved. Terms of Service, Privacy Policy and Trademarks. + + + + diff --git a/mozilla/layout/html/tests/table/core/col_span.html b/mozilla/layout/html/tests/table/core/col_span.html index 076f62f5c6e..d9ffbbe58cd 100644 --- a/mozilla/layout/html/tests/table/core/col_span.html +++ b/mozilla/layout/html/tests/table/core/col_span.html @@ -1,8 +1,20 @@ + + + + +
10030% width
+
+ + + + +
100 100 100 100 100 10050% width
+
- +
100 no width givena percent width
30% width
500 colspan=3
@@ -29,7 +41,7 @@ - +

This is colspan=2

Blah Blah Blah Blah Blah BlahBlah Blah Blah Blah Blah Blah Blah Blah Blah
diff --git a/mozilla/layout/html/tests/table/core/col_span2.html b/mozilla/layout/html/tests/table/core/col_span2.html index 5906c05ee96..3d9df210b22 100644 --- a/mozilla/layout/html/tests/table/core/col_span2.html +++ b/mozilla/layout/html/tests/table/core/col_span2.html @@ -129,16 +129,24 @@ this fixes a bug foo

- - - + +
foo
foo - bar - foo - bar
100 + 100 + 400
+
+ + + + + +
600auto
auto + auto + auto + auto
fixed table - spanned cols based on fix widths
@@ -492,3 +500,84 @@ PERCENT COLSPANS auto auto +min colspan is based on min with no fix involved - IE uses max(min,des) + + + + + + +
xxxxxxxxxxxxxxxxxxx
x x x xxxx
+
+min colspan is based on max(min,des) but must exceed min with no fix involved + + + + + + +
xxxxxxxxxxxxxxxxxxxyyyyyyy
x x x x x x xxxxxxxxxxxxxxxxxxx
+
+min colspan is based on max(min,des,fix) + + + + + + +
xxxxxxxxxxxxxxxxxxx
x x x100
+
+ + + + + + +
xx
x x xauto
+
+ + + + + + +
300
400 400auto
+
+ + + + + + +
300 300
100auto auto auto
+
+ + + + + + +
300 300 300 300 300 300 300 300 300 300 300 300 300 300 300300 300 300 300 300
100auto auto auto auto auto auto auto auto auto auto auto auto
+
+ + + + + + +
300
100auto
+
+ + + + + + +
auto auto auto auto auto auto auto
100auto auto auto
+fixed table looks more like IE than Nav +
+ + + + +
100auto auto auto auto auto auto auto auto auto auto auto auto
diff --git a/mozilla/layout/html/tests/table/core/file_list.txt b/mozilla/layout/html/tests/table/core/file_list.txt index 18129095123..5cd49c9b34b 100644 --- a/mozilla/layout/html/tests/table/core/file_list.txt +++ b/mozilla/layout/html/tests/table/core/file_list.txt @@ -1,4 +1,5 @@ file://s:/mozilla/layout/html/tests/table/core/backgrounds.html +file://s:/mozilla/layout/html/tests/table/core/bloomberg.html file://s:/mozilla/layout/html/tests/table/core/one_row.html file://s:/mozilla/layout/html/tests/table/core/col_span.html file://s:/mozilla/layout/html/tests/table/core/col_widths.html @@ -8,4 +9,5 @@ file://s:/mozilla/layout/html/tests/table/core/col_widths2.html file://s:/mozilla/layout/html/tests/table/core/misc.html file://s:/mozilla/layout/html/tests/table/core/row_span.html file://s:/mozilla/layout/html/tests/table/core/col_span2.html +file://s:/mozilla/layout/html/tests/table/core/table_widths.html diff --git a/mozilla/layout/html/tests/table/core/table_widths.html b/mozilla/layout/html/tests/table/core/table_widths.html new file mode 100644 index 00000000000..bf070294c18 --- /dev/null +++ b/mozilla/layout/html/tests/table/core/table_widths.html @@ -0,0 +1,29 @@ +table width includes border +


+ + + +
200 table
+
+ +nested table width includes border + + + +
+ + + +
200 nested table
+ +nested table width includes border + + + +
+ + + +
100% nested table
+ + diff --git a/mozilla/layout/html/tests/table/other/nestedTables.html b/mozilla/layout/html/tests/table/other/nestedTables.html index 78f7cbe008b..055b51af6df 100644 --- a/mozilla/layout/html/tests/table/other/nestedTables.html +++ b/mozilla/layout/html/tests/table/other/nestedTables.html @@ -333,5 +333,19 @@   +
+the following text should display on one line + + + +
+ + + + + + +
AlphaLinux Distributions
+
diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp index 463ec16a47d..1e8d95e0d59 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp @@ -26,182 +26,9 @@ #include "nsHTMLIIDs.h" static const PRBool gsDebug = PR_FALSE; - -const nscoord gBigSpace = 100000; // a fudge constant used when the table is laid out with unconstrained width - -// these macros are defined to improve the readability of the main code -#define TDBG_S(str) \ - if (gsDebug) { \ - printf((str)); \ - } - -#define TDBG_SP(str,ptr) \ - if (gsDebug) { \ - printf((str),(ptr)); \ - } - -#define TDBG_SPD(str,ptr,dec) \ - if (gsDebug) { \ - printf((str),(ptr),(dec)); \ - } - -#define TDBG_SPDD(str,ptr,dec1,dec2) \ - if (gsDebug) { \ - printf((str),(ptr),(dec1),(dec2)); \ - } - -#define TDBG_SFDD(str,flt,dec1,dec2) \ - if (gsDebug) { \ - printf((str),(flt),(dec1),(dec2)); \ - } - -#define TDBG_SDF(str,dec,flt) \ - if (gsDebug) { \ - printf((str),(dec),(flt)); \ - } - -#define TDBG_SDFDDD(str,dec1,flt,dec2,dec3,dec4) \ - if (gsDebug) { \ - printf((str),(dec1),(flt),(dec2),(dec3),(dec4)); \ - } - -#define TDBG_SD(str,dec) \ - if (gsDebug) { \ - printf((str),(dec)); \ - } - -#define TDBG_SDD(str,dec1,dec2) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2)); \ - } - -#define TDBG_SDDD(str,dec1,dec2,dec3) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(dec3)); \ - } - -#define TDBG_SDFD(str,dec1,flt,dec2) \ - if (gsDebug) { \ - printf((str),(dec1),(flt),(dec2)); \ - } - -#define TDBG_SDDF(str,dec1,dec2,flt) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(flt)); \ - } - -#define TDBG_SDDDD(str,dec1,dec2,dec3,dec4) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(dec3),(dec4)); \ - } - -#define TDBG_SDDDF(str,dec1,dec2,dec3,flt) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(dec3),(flt)); \ - } - -#define TDBG_SDDDDD(str,dec1,dec2,dec3,dec4,dec5) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(dec3),(dec4),(dec5)); \ - } - -#define TDBG_SDDDDDD(str,dec1,dec2,dec3,dec4,dec5,dec6) \ - if (gsDebug) { \ - printf((str),(dec1),(dec2),(dec3),(dec4),(dec5),(dec6)); \ - } - -#define TDBG_SDD_SDD(str1,dec1a,dec1b,str2,dec2a,dec2b) \ - if (gsDebug) { \ - printf((str1),(dec1a),(dec1b)); \ - printf((str2),(dec2a),(dec2b)); \ - } - -#define TDBG_SDS_SDD_SD(str1a,dec1,str1b,str2,dec2a,dec2b,str3,dec3) \ - if (gsDebug) { \ - printf((str1a),(dec1),(str1b)); \ - printf((str2),(dec2a),(dec2b)); \ - printf((str3),(dec3)); \ - } - -#define TDBG_SDS_SD(str1a,dec1,str1b,str2,dec2) \ - if (gsDebug) { \ - printf((str1a),(dec1),(str1b)); \ - printf((str2),(dec2)); \ - } - -#define TDBG_WIDTHS1() \ - if (PR_TRUE == gsDebug) { \ - printf ("BalanceColumnWidths with aMaxWidth = %d, availWidth = %d\n", aMaxWidth, availWidth); \ - printf ("\t\t specifiedTW = %d, min/maxTW = %d %d\n", specifiedTableWidth, mMinTableWidth, mMaxTableWidth); \ - printf ("\t\t reflow reason = %d\n", aReflowState.reason); \ - } - -#define TDBG_WIDTHS2(string) \ - if (PR_TRUE == gsDebug) { \ - printf("\n%p: %s\n", (string), mTableFrame); \ - for (PRInt32 i=0; iGetColumnWidth(i)); \ - } \ - printf("\n"); \ - } - -#define TDBG_WIDTHS4(string,haveShrinkFit,shrinkFit) \ - if (PR_TRUE == gsDebug) { \ - nscoord tableWidth = 0; \ - printf((string)); \ - for (PRInt32 i = 0; i < mNumCols; i++) { \ - tableWidth += mTableFrame->GetColumnWidth(i); \ - printf(" %d ", mTableFrame->GetColumnWidth(i)); \ - } \ - printf ("\n computed table width is %d",tableWidth); \ - if ((haveShrinkFit)) { \ - printf(" with aShrinkFixedCols = %s", shrinkFit ? "TRUE" : "FALSE"); \ - } \ - printf("\n"); \ - } - -/* ---------- ProportionalColumnLayoutStruct ---------- */ -// TODO: make public so other subclasses can use it - -/** useful info about a column for layout of tables with colspans */ -struct ProportionalColumnLayoutStruct -{ - ProportionalColumnLayoutStruct(PRInt32 aColIndex, - nscoord aMinColWidth, - nscoord aMaxColWidth, - PRInt32 aProportion) - { - mColIndex = aColIndex; - mMinColWidth = aMinColWidth; - mMaxColWidth = aMaxColWidth; - mProportion = aProportion; - }; - - PRInt32 mColIndex; - nscoord mMinColWidth; - nscoord mMaxColWidth; - PRInt32 mProportion; -}; - - -/* ---------- ColSpanStruct ---------- */ -/** useful info about a column for layout of tables with colspans */ -struct ColSpanStruct -{ - PRInt32 colIndex; - PRInt32 colSpan; - nscoord width; - - ColSpanStruct(PRInt32 aSpan, PRInt32 aIndex, nscoord aWidth) - { - colSpan = aSpan; - colIndex = aIndex; - width = aWidth; - } -}; - - - +#ifdef gsDebug +static PRInt32 debugCount = 0; +#endif /* ---------- BasicTableLayoutStrategy ---------- */ @@ -221,11 +48,11 @@ BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame, PRBool { NS_ASSERTION(nsnull != aFrame, "bad frame arg"); - mTableFrame = aFrame; - mMinTableWidth = 0; - mMaxTableWidth = 0; - mFixedTableWidth = 0; - mIsNavQuirksMode = aIsNavQuirks; + mTableFrame = aFrame; + mMinTableContentWidth = 0; + mMaxTableContentWidth = 0; + mCellSpacingTotal = 0; + mIsNavQuirksMode = aIsNavQuirks; } BasicTableLayoutStrategy::~BasicTableLayoutStrategy() @@ -236,22 +63,18 @@ PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, PRInt32 aNumCols, nscoord aMaxWidth) { -#ifdef NS_DEBUG - nsIFrame* tablePIF = nsnull; - mTableFrame->GetPrevInFlow(&tablePIF); - NS_ASSERTION(nsnull == tablePIF, "never ever call me on a continuing frame!"); -#endif + ContinuingFrameCheck(); PRBool result = PR_TRUE; // re-init instance variables - mNumCols = aNumCols; - mMinTableWidth = 0; - mMaxTableWidth = 0; - mFixedTableWidth = 0; - mCols = mTableFrame->GetEffectiveCOLSAttribute(); + mNumCols = aNumCols; + mMinTableContentWidth = 0; + mMaxTableContentWidth = 0; + mCellSpacingTotal = 0; + mCols = mTableFrame->GetEffectiveCOLSAttribute(); - // Step 1 - assign the width of all fixed-width columns + // assign the width of all fixed-width columns AssignPreliminaryColumnWidths(aMaxWidth); // set aMaxElementSize here because we compute mMinTableWidth in AssignPreliminaryColumnWidths @@ -275,1853 +98,978 @@ void BasicTableLayoutStrategy::SetMaxElementSize(nsSize* aMaxElementSize) nsMargin padding; tableSpacing->GetPadding(padding); borderPadding += padding; + nscoord horBorderPadding = borderPadding.left + borderPadding.right; if (tablePosition->mWidth.GetUnit() == eStyleUnit_Coord) { aMaxElementSize->width = tablePosition->mWidth.GetCoordValue(); - aMaxElementSize->width = PR_MAX(aMaxElementSize->width, mMinTableWidth); - //XXX: need to factor in borderpadding here! + if (mMinTableContentWidth + horBorderPadding > aMaxElementSize->width) { + aMaxElementSize->width = mMinTableContentWidth + horBorderPadding; + } } else { - aMaxElementSize->width = mMinTableWidth + borderPadding.left + borderPadding.right; + aMaxElementSize->width = mMinTableContentWidth + horBorderPadding; } - TDBG_SPD("%p BTLS::Init setting aMaxElementSize->width = %d\n", mTableFrame, aMaxElementSize->width); } } -PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableStyle, - const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth) +void BasicTableLayoutStrategy::ContinuingFrameCheck() { #ifdef NS_DEBUG - nsIFrame *tablePIF = nsnull; + nsIFrame* tablePIF = nsnull; mTableFrame->GetPrevInFlow(&tablePIF); - NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!"); + NS_ASSERTION(!tablePIF, "never ever call me on a continuing frame!"); #endif - - PRBool result; - - NS_ASSERTION(nsnull != aTableStyle, "bad arg"); - if (nsnull==aTableStyle) { - return PR_FALSE; - } - - nscoord specifiedTableWidth = 0; // not cached as a data member because it can vary depending on aMaxWidth - PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(mTableFrame, aTableStyle, aReflowState, specifiedTableWidth); - // HACK! Fix TableIsAutoWidth to return the right width - specifiedTableWidth = PR_MIN(specifiedTableWidth,aMaxWidth); - if (NS_UNCONSTRAINEDSIZE == specifiedTableWidth) { - specifiedTableWidth = 0; - tableIsAutoWidth = PR_TRUE; - } - - // Step 2 - determine how much space is really available - nscoord availWidth = aMaxWidth; // start with the max width I've been given - if (NS_UNCONSTRAINEDSIZE != availWidth) { // if that's not infinite, subtract the fixed columns - availWidth -= mFixedTableWidth; - } // that have already been accounted for - if (PR_FALSE == tableIsAutoWidth) { // if the table has a specified width - availWidth = specifiedTableWidth - mFixedTableWidth; // use it, minus the fixed columns already accounted for - } - //if (0!=mMinTableWidth && mMinTableWidth>availWidth) // if the computed available size is too small - //availWidth = mMinTableWidth; // bump it up to the min - availWidth = PR_MAX(0,availWidth); // avail width can never be negative - - // Step 3 - assign the width of all proportional-width columns in the remaining space - TDBG_WIDTHS1(); - TDBG_WIDTHS2("BEGIN BALANCE COLUMN WIDTHS\n"); - - result = BalanceProportionalColumns(aReflowState, availWidth, aMaxWidth, - specifiedTableWidth, tableIsAutoWidth); - - TDBG_WIDTHS2("END BALANCE COLUMN WIDTHS\n"); - -#ifdef NS_DEBUG // sanity check for table column widths - for (PRInt32 i=0; iGetColumnFrame(i, colFrame); - nscoord minColWidth = colFrame->GetMinColWidth(); - nscoord assignedColWidth = mTableFrame->GetColumnWidth(i); - NS_ASSERTION(assignedColWidth >= minColWidth, "illegal width assignment"); - } -#endif - - return result; } -nscoord BasicTableLayoutStrategy::CalcHorizontalPadding(PRInt32 aColX) +PRBool BCW_Wrapup(BasicTableLayoutStrategy* aStrategy, + nsTableFrame* aTableFrame, + PRInt32* aAllocTypes) { - nscoord maxLeftPadding = 0; // max left padding for cells starting in this col - nscoord maxRightPadding = 0; // max right padding for cells ending in this col - PRInt32 numRows = mTableFrame->GetRowCount(); - - for (PRInt32 rowX = 0; rowX < numRows; rowX++) { - nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(rowX, aColX); - if (nsnull == cellFrame) { // there is no cell in this row that corresponds to this column - continue; - } - PRInt32 cellRowX; - cellFrame->GetRowIndex(cellRowX); - if (rowX != cellRowX) { // don't do anything except for 1st row this cell is in - continue; - } - const nsStyleSpacing* spacing; - cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); - nsMargin marg; - spacing->CalcPaddingFor(cellFrame, marg); - maxLeftPadding = PR_MAX(maxLeftPadding, marg.left); - - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(aColX, cellFrame); - - nsStyleCoord coord; - PRInt32 cellColX; - cellFrame->GetColIndex(cellColX); - if (aColX != cellColX) { // the cell does not originate in this col - if (-1 == aColX - cellColX - colSpan) { // the cell ends in this col - spacing->mPadding.GetLeft(coord); - maxRightPadding = PR_MAX(maxLeftPadding, marg.right); - } - continue; - } - if (1 == colSpan) { // the cell ends in this col - maxRightPadding = PR_MAX(maxLeftPadding, marg.right); - } - } - return maxLeftPadding + maxRightPadding; -} - -// 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(nscoord aMaxWidth) -{ - TDBG_SP("** %p: AssignPreliminaryColumnWidths **\n", mTableFrame); - nsVoidArray *spanList = nsnull; - nsVoidArray *colSpanList = nsnull; - - PRBool hasColsAttribute = (PRBool)(NS_STYLE_TABLE_COLS_NONE != mCols); - - PRInt32 *minColWidthArray = nsnull; // used for computing the effect of COLS attribute - PRInt32 *maxColWidthArray = nsnull; // used for computing the effect of COLS attribute - if (PR_TRUE == hasColsAttribute) { - minColWidthArray = new PRInt32[mNumCols]; - maxColWidthArray = new PRInt32[mNumCols]; - } - - PRInt32 numRows = mTableFrame->GetRowCount(); - PRInt32 colIndex, rowIndex; - PRInt32* horPadding = new PRInt32[mNumCols]; - - // for every column, determine it's min and max width, and keep track of the table width - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - nscoord minColWidth = 0; // min col width factoring in table attributes - nscoord minColContentWidth = 0; // min width of the col's contents, does not take into account table attributes - nscoord maxColWidth = 0; // max col width factoring in table attributes - nscoord effectiveMinColumnWidth = 0; // min col width ignoring cells with colspans - nscoord effectiveMaxColumnWidth = 0; // max col width ignoring cells with colspans - nscoord specifiedFixedColWidth = 0; // the width of the column if given stylistically (or via cell Width attribute) - // only applicable if haveColWidth==PR_TRUE - - horPadding[colIndex] = 0; - // Get column information - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - TDBG_SDD("BTLS::APCW - got colFrame %p for colIndex %d\n", colFrame, colIndex); - NS_ASSERTION(nsnull != colFrame, "bad col frame"); - - // Get the columns's style - const nsStylePosition* colPosition; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - const nsStyleTable* colTableStyle; - colFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct*&)colTableStyle); - - // Get fixed column width if it has one - if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { - colFrame->SetHasConstrainedWidth(PR_TRUE); - specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); - horPadding[colIndex] = CalcHorizontalPadding(colIndex); - specifiedFixedColWidth += horPadding[colIndex]; - TDBG_SD("BTLS::APCW - got specified col width = %d\n", specifiedFixedColWidth); - } - - /* Scan the column, simulatneously assigning column widths - * and computing the min/max column widths - */ - PRInt32 firstRowIndex = -1; - PRInt32 maxColSpan = 1; - PRBool cellGrantingWidth = PR_TRUE; - for (rowIndex = 0; rowIndex < numRows; rowIndex++) { - nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex); - if (nsnull == cellFrame) { // there is no cell in this row that corresponds to this column - continue; - } - if (-1 == firstRowIndex) { - firstRowIndex = rowIndex; - } - PRInt32 cellRowIndex; - cellFrame->GetRowIndex(cellRowIndex); - if (rowIndex != cellRowIndex) { - // For cells that span rows, we only figure it in once - NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check - continue; - } - - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); - maxColSpan = PR_MAX(maxColSpan,colSpan); - - PRInt32 cellColIndex; - cellFrame->GetColIndex(cellColIndex); - if (colIndex != cellColIndex) { - // For cells that span cols, we figure in the row using previously-built SpanInfo - NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match col span"); // sanity check - continue; - } - - nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); - nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); - nscoord cellDesiredWidth = cellDesiredSize.width; - nscoord cellMinWidth = cellMinSize.width; - - if (1 == colSpan) { - minColContentWidth = (0 == minColContentWidth) - ? cellMinWidth : PR_MAX(minColContentWidth, cellMinWidth); - } - else { - minColContentWidth = PR_MAX(minColContentWidth, cellMinWidth/colSpan); // no need to divide this proportionately - } - TDBG_SDDDDDD("for cell %d with colspan=%d, min = %d,%d and des = %d,%d\n", - rowIndex, colSpan, cellMinSize.width, cellMinSize.height, - cellDesiredSize.width, cellDesiredSize.height); - - if (colFrame->HasConstrainedWidth()) { - // This col has a specified coord fixed width, so set the min and max width to the larger of - // (specified width, largest max_element_size of the cells in the column) - // factoring in the min width of the prior cells (stored in minColWidth) - nscoord widthForThisCell = specifiedFixedColWidth; - if (0 == specifiedFixedColWidth) { // set to min - specifiedFixedColWidth = cellMinWidth; - } - widthForThisCell = PR_MAX(widthForThisCell, effectiveMinColumnWidth); - if (1 == colSpan) { - widthForThisCell = PR_MAX(widthForThisCell, cellMinWidth); - } - mTableFrame->SetColumnWidth(colIndex, widthForThisCell); - maxColWidth = widthForThisCell; - minColWidth = PR_MAX(minColWidth, cellMinWidth); - if (1 == colSpan) { - effectiveMaxColumnWidth = PR_MAX(effectiveMaxColumnWidth, widthForThisCell); - if (0 == effectiveMinColumnWidth) { - effectiveMinColumnWidth = cellMinWidth;//widthForThisCell; - } - else { - //effectiveMinColumnWidth = PR_MIN(effectiveMinColumnWidth, widthForThisCell); - //above line works for most tables, but it can't be right - effectiveMinColumnWidth = PR_MAX(effectiveMinColumnWidth, cellMinWidth); - //above line seems right and works for xT1, but breaks lots of other tables. - } - } - } - else { - if (maxColWidth < cellDesiredWidth) { - maxColWidth = cellDesiredWidth; - } - if ((1==colSpan) && (effectiveMaxColumnWidth < cellDesiredWidth)) { - effectiveMaxColumnWidth = cellDesiredWidth; - } - if (minColWidth < cellMinWidth) { - minColWidth = cellMinWidth; - } - // effectiveMinColumnWidth is the min width as if no cells with colspans existed - if ((1==colSpan) && (effectiveMinColumnWidth < cellMinWidth)) { - effectiveMinColumnWidth = cellMinWidth; - } - } - - if (1 < colSpan) { - // add the column to our list of post-process columns, if all of the intersected columns are auto - PRBool okToAdd = PR_TRUE; - if (numRows == 1 || (PR_FALSE == IsFixedWidth(colPosition, colTableStyle))) { - okToAdd = PR_FALSE; - } - else { - for (PRInt32 i = 1; i < colSpan; i++) { - nsTableColFrame* cf; - mTableFrame->GetColumnFrame(i+colIndex, cf); - const nsStylePosition* colPos; - cf->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPos); - if (colPos->mWidth.GetUnit() != eStyleUnit_Auto && - (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=cf->GetWidthSource())) { - okToAdd = PR_FALSE; - break; - } - } - } - - nscoord width = cellDesiredSize.width; // used below as the cell's "natural" width - if (eStyleUnit_Coord == colTableStyle->mSpanWidth.GetUnit()) { - width = colSpan * colTableStyle->mSpanWidth.GetCoordValue(); // "colSpan*" because table frame divided per column spanned - } - if (PR_TRUE == okToAdd) { - nscoord colwidth = PR_MAX(width, cellMinWidth); - ColSpanStruct* colSpanInfo = new ColSpanStruct(colSpan, colIndex, colwidth); - if (nsnull == colSpanList) { - colSpanList = new nsVoidArray(); - } - colSpanList->AppendElement(colSpanInfo); - } - - if (PR_TRUE == cellGrantingWidth) { - // add the cell to our list of spanning cells - SpanInfo* spanInfo = new SpanInfo(colIndex, colSpan, cellMinWidth, width); - if (nsnull == spanList) { - spanList = new nsVoidArray(); - } - spanList->AppendElement(spanInfo); - } - } - - // bookkeeping: is this the cell that gave the column it's fixed width attribute? - // must be done after "haveColWidth && cellGrantingWidth" used above - // since we want the biggest, I don't think this is valid anymore - // it made sense when the rule was to grab the first cell that contributed a width - //if (PR_TRUE==cellGrantingWidth) - //{ - // const nsStylePosition* cellPosition; - // cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); - // if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) - // cellGrantingWidth=PR_FALSE; //I've found the cell that gave the col it's width - //} - - // book 'em, Danno - TDBG_SDDD(" after cell %d, minColWidth = %d and maxColWidth = %d\n", - rowIndex, minColWidth, maxColWidth); - } // end for (rowIndex = 0; rowIndex < numRows; rowIndex++) - - // adjust the "fixed" width for content that is too wide - if (colFrame->HasConstrainedWidth() && (effectiveMinColumnWidth > specifiedFixedColWidth)) { - specifiedFixedColWidth = effectiveMinColumnWidth; - } - // do all the global bookkeeping, factoring in margins - nscoord colInset = mTableFrame->GetCellSpacingX(); - // keep a running total of the amount of space taken up by all fixed-width columns - if ((colFrame->HasConstrainedWidth()) && - (nsTableColFrame::eWIDTH_SOURCE_CELL == colFrame->GetWidthSource())) { - mFixedTableWidth += specifiedFixedColWidth + colInset; - if (0 == colIndex) { - mFixedTableWidth += colInset; - } - TDBG_SD("setting mFixedTableWidth=%d\n", mFixedTableWidth); - } - - // cache the computed column info - colFrame->SetMinColWidth(effectiveMinColumnWidth); - colFrame->SetMaxColWidth(effectiveMaxColumnWidth); - colFrame->SetEffectiveMinColWidth(effectiveMinColumnWidth); - colFrame->SetEffectiveMaxColWidth(effectiveMaxColumnWidth); - // this is the default, the real adjustment happens below where we deal with colspans - colFrame->SetAdjustedMinColWidth(effectiveMinColumnWidth); - if ((colFrame->HasConstrainedWidth()) && - (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=colFrame->GetWidthSource())) { - mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); - } - else { - mTableFrame->SetColumnWidth(colIndex, effectiveMaxColumnWidth); - } - TDBG_SDD("col %d, set col width to = %d\n", colIndex, mTableFrame->GetColumnWidth(colIndex)); - - if (PR_TRUE == hasColsAttribute) { - minColWidthArray[colIndex] = minColWidth; - maxColWidthArray[colIndex] = maxColWidth; - } - TDBG_SDDDD("after col %d, minColWidth=%d effectiveMinColumnWidth=%d\n\teffectiveMaxColumnWidth = %d\n", - colIndex, minColWidth, effectiveMinColumnWidth, effectiveMaxColumnWidth); - } - - // now, post-process the computed values based on the table attributes - - // first, factor in max values of spanning cells proportionately. - // We can't do this above in the first loop, because we don't have enough information - // to determine the proportion each column gets from spanners. - if (nsnull != spanList) { - // we only want to do this if there are auto-cells involved - // or if we have columns that are provisionally fixed-width with colspans - PRInt32 numAutoColumns=0; - PRInt32* autoColumns=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); - // for every column, handle spanning cells that impact that column - for (colIndex=0; colIndexCount(); - // go through the list backwards so we can delete easily - for (PRInt32 spanIndex = spanCount-1; 0 <= spanIndex; spanIndex--) { - // get each spanInfo struct and see if it impacts this column - SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex)); - // if the spanInfo is about a column before the current column, it effects - // the current column (otherwise it would have already been deleted.) - if (spanInfo->initialColIndex <= colIndex) { - if (-1 == spanInfo->effectiveMaxWidthOfSpannedCols) { - // if we have not yet computed effectiveMaxWidthOfSpannedCols, do it now - // first, initialize the sums - spanInfo->effectiveMaxWidthOfSpannedCols = 0; - spanInfo->effectiveMinWidthOfSpannedCols = 0; - // then compute the sums - for (PRInt32 span=0; span < spanInfo->initialColSpan; span++) { - nsTableColFrame* nextColFrame = mTableFrame->GetColFrame(colIndex+span); - if (nsnull==nextColFrame) { - break; - } - spanInfo->effectiveMaxWidthOfSpannedCols += nextColFrame->GetEffectiveMaxColWidth(); - spanInfo->effectiveMinWidthOfSpannedCols += nextColFrame->GetEffectiveMinColWidth(); - } - TDBG_SDD("effective min total = %d, max total = %d\n", - spanInfo->effectiveMinWidthOfSpannedCols, spanInfo->effectiveMaxWidthOfSpannedCols); - } - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - nscoord colMinWidth = colFrame->GetMinColWidth(); - - // compute the spanning cell's contribution to the column min width - // this is the "adjusted" column width, used in SetTableToMinWidth - nscoord spanCellMinWidth; - if (0 != spanInfo->effectiveMinWidthOfSpannedCols) { - float percent = ((float)(colFrame->GetEffectiveMinColWidth())) / - ((float)(spanInfo->effectiveMinWidthOfSpannedCols)); - spanCellMinWidth = NSToCoordRound(((float)(spanInfo->cellMinWidth)) * percent); - TDBG_SDFDDD("spanCellMinWidth portion = %d from percent=%f, cellMW=%d, effMinColW=%d, sum=%d\n", - spanCellMinWidth, percent, spanInfo->cellMinWidth, colFrame->GetEffectiveMinColWidth(), - spanInfo->effectiveMinWidthOfSpannedCols); - if (colMinWidth < spanCellMinWidth) { - colFrame->SetAdjustedMinColWidth(spanCellMinWidth); // set the new min width for the col - } - } - else { - spanCellMinWidth = spanInfo->cellMinWidth / spanInfo->initialColSpan; - if (colMinWidth < spanCellMinWidth) { - colFrame->SetAdjustedMinColWidth(spanCellMinWidth); - } - } - - // compute the spanning cell's contribution to the column max width - nscoord colMaxWidth = colFrame->GetMaxColWidth(); - nscoord spanCellMaxWidth; - if (0 != spanInfo->effectiveMaxWidthOfSpannedCols) { - float percent = ((float)(colFrame->GetEffectiveMaxColWidth())) / - ((float)(spanInfo->effectiveMaxWidthOfSpannedCols)); - spanCellMaxWidth = NSToCoordRound(((float)(spanInfo->cellDesiredWidth)) * percent); - TDBG_SDFDDD("spanCellMaxWidth portion = %d with percent = %f from cellDW = %d, effMaxColW=%d and sum=%d\n", - spanCellMaxWidth, percent, spanInfo->cellDesiredWidth, colFrame->GetEffectiveMaxColWidth(), - spanInfo->effectiveMaxWidthOfSpannedCols); - if (colMaxWidth < spanCellMaxWidth) { - // make sure we're at least as big as our min - spanCellMaxWidth = PR_MAX(spanCellMaxWidth, colMinWidth); - colFrame->SetMaxColWidth(spanCellMaxWidth); // set the new max width for the col - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); // set the column to the new desired max width - TDBG_SDDDD("for spanning cell into col %d with remaining span=%d, old max = %d, new max = %d\n", - colIndex, spanInfo->span, colMaxWidth, spanCellMaxWidth); - } - } - else { - spanCellMaxWidth = spanInfo->cellDesiredWidth / spanInfo->initialColSpan; - nscoord minColWidth = colFrame->GetMinColWidth(); - spanCellMaxWidth = PR_MAX(spanCellMaxWidth, minColWidth); - colFrame->SetMaxColWidth(spanCellMaxWidth); - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); - TDBG_SDDDD(" for spanning cell into col %d with remaining span=%d, old max = %d, new max = %d\n", - colIndex, spanInfo->span, colMaxWidth, spanCellMaxWidth); - } - - spanInfo->span--; - if (0==spanInfo->span) { - spanList->RemoveElementAt(spanIndex); - delete spanInfo; - } - - // begin code that respects column width attribute - /* the code below checks to see if the column has a width attribute (either it's own or a cell's) - * if so, if it fits within the constraints we computed above, we use it. - * why go through all that pain above, then? because the given width attribute might not - * be rational. So we need to act as if it doesn't exist and then fit it in if it makes sense. - * a shortcut that checks for a column width attribute and skips the above computations - * would not work without lots of extra computation that would lead you down the same path anyway. - */ - const nsStylePosition* colPosition; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - // Get fixed column width if it has one - if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { - if (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=colFrame->GetWidthSource()) { - nscoord specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); - specifiedFixedColWidth += horPadding[colIndex]; - if (specifiedFixedColWidth>=colFrame->GetEffectiveMinColWidth()) { - mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); - colFrame->SetMaxColWidth(specifiedFixedColWidth); - } - } - } - // end code that respects column width attribute - } - } - } - } - delete [] horPadding; - - // now set the min and max table widths - SetMinAndMaxTableWidths(); - - // then, handle the COLS attribute (equal column widths) - // if there is a COLS attribute, fix up mMinTableWidth and mMaxTableWidth - if (PR_TRUE == hasColsAttribute) { - TDBG_SD("has COLS attribute = %d\n", mCols); - // for every effected column, subtract out its prior contribution and add back in the new value - PRInt32 numColsEffected = mNumCols; - if (NS_STYLE_TABLE_COLS_ALL != mCols) { - numColsEffected = mCols; - } - PRInt32 maxOfMinColWidths = 0; - PRInt32 maxOfMaxColWidths = 0; - PRInt32 effectedColIndex; - for (effectedColIndex=0; effectedColIndexGetColumnFrame(effectedColIndex, colFrame); - colFrame->SetMaxColWidth(maxOfMaxColWidths); // cache the new column max width (min width is uneffected) - colFrame->SetEffectiveMaxColWidth(maxOfMaxColWidths); - TDBG_SDD("col %d now has max col width %d\n", effectedColIndex, maxOfMaxColWidths); - } - delete [] minColWidthArray; - delete [] maxColWidthArray; - } - if (nsnull != colSpanList) { - DistributeFixedSpace(colSpanList); - } - - TDBG_SPDD("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, mMinTableWidth, mMaxTableWidth); - - // clean up - if (nsnull != spanList) { - TDBG_S("BTLS::APCW...space leak, span list not empty\n"); - delete spanList; - } - if (nsnull != colSpanList) { - PRInt32 colSpanListCount = colSpanList->Count(); - for (PRInt32 i = 0; i < colSpanListCount; i++) { - ColSpanStruct * colSpanInfo = (ColSpanStruct *)(colSpanList->ElementAt(i)); - if (nsnull != colSpanInfo) { - delete colSpanInfo; - } - } - delete colSpanList; - } + delete [] aAllocTypes; + //aStrategy->Dump(0); + //aTableFrame->Dump(PR_TRUE, PR_FALSE); return PR_TRUE; } -void BasicTableLayoutStrategy::SetMinAndMaxTableWidths() +PRBool +BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableStyle, + const nsHTMLReflowState& aReflowState, + nscoord aMaxWidthIn) { - TDBG_S("SetMinAndMaxTableWidths\n"); - PRInt32 colIndex, rowIndex; - PRInt32 numRows = mTableFrame->GetRowCount(); - nscoord colInset = mTableFrame->GetCellSpacingX(); - for (rowIndex = 0; rowIndex < numRows; rowIndex++) { - TDBG_SD(" row %d\n", rowIndex); - nscoord rowMinWidth = colInset; - nscoord rowMaxWidth = colInset; - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - TDBG_SD(" col %d\n", colIndex); - nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex); - rowMinWidth += colInset; - rowMaxWidth += colInset; - if (nsnull == cellFrame) { // there is no cell in this row that corresponds to this column - TDBG_SD(" col %d skipped because there is no cell\n", colIndex); - continue; - } - PRInt32 cellColIndex; - cellFrame->GetColIndex(cellColIndex); - if (colIndex != cellColIndex) { - // For cells that span cols, we figured in the cell the first time we saw it - TDBG_SD(" col %d skipped because it has colspan so we've already added it in\n", colIndex); - continue; - } - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); - nscoord cellMinWidth = PR_MAX(cellMinSize.width, colFrame->GetEffectiveMinColWidth()); - nsSize cellMaxSize = cellFrame->GetPass1DesiredSize(); - nscoord cellMaxWidth = PR_MAX(cellMaxSize.width, colFrame->GetEffectiveMaxColWidth()); - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); - nscoord spanningCellMinWidth = (colSpan-1)*colInset; - TDBG_SDDD(" cellMin=%d, cellMax=%d, spanningCellMin=%d\n", - cellMinWidth, cellMaxWidth, spanningCellMinWidth); - // spanning cells must be at least as wide as the columns they span, including the cell spacing spanned. - if (NS_UNCONSTRAINEDSIZE != rowMinWidth) { - rowMinWidth += PR_MAX(cellMinWidth, spanningCellMinWidth); - } - if (NS_UNCONSTRAINEDSIZE != rowMaxWidth) { - rowMaxWidth += PR_MAX(cellMaxWidth, spanningCellMinWidth); - } - TDBG_SDD(" rowMinWidth=%d, rowMaxWidth=%d\n", rowMinWidth, rowMaxWidth); - } - TDBG_SDD(" rowMinWidth=%d, rowMaxWidth=%d\n", rowMinWidth, rowMaxWidth); - // the largest row widths are the table widths - mMinTableWidth = PR_MAX(mMinTableWidth, rowMinWidth); - mMaxTableWidth = PR_MAX(mMaxTableWidth, rowMaxWidth); - TDBG_SDD(" mMinTableWidth=%d, mMaxTableWidth=%d\n", mMinTableWidth, mMaxTableWidth); + //mTableFrame->Dump(PR_TRUE, PR_TRUE); + ContinuingFrameCheck(); + if (!aTableStyle) { + NS_ASSERTION(aTableStyle, "bad style arg"); + return PR_FALSE; } - // verify max of min row widths vs. sum of adjusted column min widths. bigger one wins - nscoord sumOfAdjustedColMinWidths = colInset; - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(colIndex, colFrame); - sumOfAdjustedColMinWidths += colFrame->GetAdjustedMinColWidth() + colInset; - TDBG_SDDDD(" col %d has amcw=%d, cellspacing=%d, sum=%d\n", - colIndex, colFrame->GetAdjustedMinColWidth(), colInset, sumOfAdjustedColMinWidths); + + // determine if the table is auto/fixed and get the fixed width if available + nscoord maxWidth = aMaxWidthIn; + nscoord specifiedTableWidth = 0; + PRBool tableIsAutoWidth = + nsTableFrame::TableIsAutoWidth(mTableFrame, aTableStyle, aReflowState, specifiedTableWidth); + // a specifiedTableWidth of <= 0 indicates percentage based + if (!tableIsAutoWidth && (specifiedTableWidth > 0)) { + maxWidth = PR_MIN(specifiedTableWidth, aMaxWidthIn); // specifiedWidth usually == aMaxWidthIn for fixed table } - TDBG_SD(" sumOfAdjustedColMinWidths=%d\n", sumOfAdjustedColMinWidths); - /* - mMinTableWidth = PR_MAX(mMinTableWidth, sumOfAdjustedColMinWidths); - mMaxTableWidth = PR_MAX(mMinTableWidth, mMaxTableWidth); - */ - TDBG_SDDD("end SetMinAndMaxTW: minTW=%d, maxTW=%d with DMCW=%d\n", mMinTableWidth, mMaxTableWidth, sumOfAdjustedColMinWidths); -} - -// take the fixed space spanned by the columns in aColSpanList -// and distribute it proportionately (based on desired width) -void BasicTableLayoutStrategy::DistributeFixedSpace(nsVoidArray *aColSpanList) -{ - TDBG_S("** DistributeFixedSpace:\n"); - // for all fixed-width columns, determine the amount of the specified width each column spanned recieves - PRInt32 numSpanningCells = aColSpanList->Count(); - for (PRInt32 nextSpanningCell = 0; nextSpanningCell < numSpanningCells; nextSpanningCell++) { // proportionately distributed extra space, based on the column's fixed width - ColSpanStruct* colInfo = (ColSpanStruct *)aColSpanList->ElementAt(nextSpanningCell); - PRInt32 colIndex = colInfo->colIndex; - PRInt32 colSpan = colInfo->colSpan; - nscoord totalColWidth = colInfo->width; - - // 1. get the sum of the effective widths of the columns in the span - nscoord totalEffectiveWidth=0; - nsTableColFrame* colFrame; - PRInt32 i; - for (i = 0; iGetColumnFrame(colIndex+i, colFrame); - totalEffectiveWidth += colFrame->GetColWidthForComputation(); - } - - // 2. next, compute the proportion to be added to each column, and add it - for (i = 0; iGetColumnFrame(colIndex+i, colFrame); - float percent; - percent = ((float)(colFrame->GetColWidthForComputation())) / ((float)totalEffectiveWidth); - nscoord newColWidth = NSToCoordRound(((float)totalColWidth)*percent); - nscoord minColWidth = colFrame->GetEffectiveMinColWidth(); - nscoord oldColWidth = mTableFrame->GetColumnWidth(colIndex+i); - if (newColWidth > minColWidth) { - TDBG_SDD_SDD(" assigning fixed col width for spanning cells: column %d set to %d\n", - colIndex+i, newColWidth, - " minCW = %d oldCW = %d\n", minColWidth, oldColWidth); - mTableFrame->SetColumnWidth(colIndex+i, newColWidth); - colFrame->SetEffectiveMaxColWidth(newColWidth); - } + // reduce the maxWidth by border and padding in some cases, since we will be dealing with content width + if (!tableIsAutoWidth && (maxWidth != NS_UNCONSTRAINEDSIZE)) { + const nsStylePosition* position; + mTableFrame->GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)position)); + if (eStyleUnit_Percent != position->mWidth.GetUnit()) { + const nsStyleSpacing* spacing; + mTableFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); + nsMargin borderPadding; + spacing->CalcBorderPaddingFor(mTableFrame, borderPadding); + maxWidth -= borderPadding.left + borderPadding.right; + maxWidth = PR_MAX(0, maxWidth); } } -} - -/* assign column widths to all non-fixed-width columns (adjusting fixed-width columns if absolutely necessary) - aAvailWidth is the amount of space left in the table to distribute after fixed-width columns are accounted for - aMaxWidth is the space the parent gave us (minus border & padding) to fit ourselves into - aTableIsAutoWidth is true if the table is auto-width, false if it is anything else (percent, fixed, etc) - */ -PRBool BasicTableLayoutStrategy:: - BalanceProportionalColumns (const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aTableSpecifiedWidth, - PRBool aTableIsAutoWidth) -{ - PRBool result = PR_TRUE; - - nscoord actualMaxWidth; // the real target width, depends on if we're auto or specified width - if (PR_TRUE == aTableIsAutoWidth) { - actualMaxWidth = aMaxWidth; - } else { - actualMaxWidth = PR_MIN(aMaxWidth, aTableSpecifiedWidth); - } - if (NS_UNCONSTRAINEDSIZE == aMaxWidth || NS_UNCONSTRAINEDSIZE == mMinTableWidth) { - // the max width of the table fits comfortably in the available space - TDBG_S(" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n"); - // nested tables are laid out with unconstrained width. But the underlying algorithms require a - // real width. So we pick a really big width here. It doesn't really matter, of course, because - // eventually the table will be laid out with a constrained width. - nscoord bigSpace = gBigSpace; - bigSpace = PR_MAX(bigSpace, mMaxTableWidth); - result = BalanceColumnsTableFits(aReflowState, bigSpace, bigSpace, - aTableSpecifiedWidth, aTableIsAutoWidth); - } - else if (mMinTableWidth > actualMaxWidth) { - // the table doesn't fit in the available space - TDBG_S(" * table minTW does not fit, calling BalanceColumnsTableDoesNotFit\n"); - result = BalanceColumnsTableDoesNotFit(); - } - else if (mMaxTableWidth <= actualMaxWidth) { - // the max width of the table fits comfortably in the available space - TDBG_S(" * table desired size fits, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aReflowState, aAvailWidth, aMaxWidth, - aTableSpecifiedWidth, aTableIsAutoWidth); - } - else { - // the table fits somewhere between its min and desired size - TDBG_S(" * table desired size does not fit, calling BalanceColumnsConstrained\n"); - result = BalanceColumnsConstrained(aReflowState, aAvailWidth, - actualMaxWidth, aTableIsAutoWidth); + // set the table's columns to the min width + // initialize the col percent and cell percent values to 0. + PRInt32 colX; + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord colMinWidth = colFrame->GetMinWidth(); + mTableFrame->SetColumnWidth(colX, colMinWidth); + colFrame->SetWidth(PCT, WIDTH_NOT_SET); + colFrame->SetWidth(PCT_ADJ, WIDTH_NOT_SET); } - return result; -} + // if the max width available is less than the min content width for fixed table, we're done + if (!tableIsAutoWidth && (maxWidth < mMinTableContentWidth)) { + return PR_FALSE; + } -// the table doesn't fit, so squeeze every column down to its minimum -PRBool BasicTableLayoutStrategy::BalanceColumnsTableDoesNotFit() -{ - PRBool result = PR_TRUE; + // set PCT and PCT_ADJ widths on col frames and for an auto table return + // a new table width based on percent cells/cols if they exist + nscoord perAdjTableWidth = (maxWidth != NS_UNCONSTRAINEDSIZE) + ? AssignPercentageColumnWidths(maxWidth - mCellSpacingTotal, tableIsAutoWidth) : 0; - PRBool hasColsAttribute = (PRBool)(NS_STYLE_TABLE_COLS_NONE!=mCols); + // if the max width available is less than the min content width for auto table + // that had no % cells/cols, we're done + if (tableIsAutoWidth && (maxWidth < mMinTableContentWidth) & (0 == perAdjTableWidth)) { + return PR_TRUE; + } + + PRInt32 cellSpacingTotal; + // the following are of size NUM_WIDTHS, but only MIN_CON, DES_CON, FIX, PCT + // are used and they account for colspan ADJusted values + PRInt32 totalWidths[NUM_WIDTHS]; // sum of col widths of a particular type + PRInt32 totalCounts[NUM_WIDTHS]; // num of cols of a particular type + PRInt32 minWidths[NUM_WIDTHS]; + PRInt32 num0Proportional; + + CalculateTotals(cellSpacingTotal, totalCounts, totalWidths, minWidths, num0Proportional); + // auto width table's adjusted width needs cell spacing + if (tableIsAutoWidth && perAdjTableWidth > 0) { + perAdjTableWidth = PR_MIN(perAdjTableWidth + cellSpacingTotal, maxWidth); + } + nscoord totalAllocated = totalWidths[MIN_CON] + cellSpacingTotal; - PRInt32* minColWidthArray = nsnull; - if (PR_TRUE == hasColsAttribute) { - minColWidthArray = new PRInt32[mNumCols]; - } - - for (PRInt32 colIndex = 0; colIndex < mNumCols; colIndex++) { - nscoord minAdjustedColWidth = 0; - TDBG_SD(" for col %d\n", colIndex); - - nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex); - NS_ASSERTION(nsnull != colFrame, "bad col frame"); - - // Get the columns's style - const nsStylePosition* colPosition; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - const nsStyleTable* colTableStyle; - colFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct*&)colTableStyle); - //if (PR_FALSE==IsFixedWidth(colPosition, colTableStyle)) - { - minAdjustedColWidth = colFrame->GetAdjustedMinColWidth(); - mTableFrame->SetColumnWidth(colIndex, minAdjustedColWidth); - if (PR_TRUE == hasColsAttribute) { - minColWidthArray[colIndex] = minAdjustedColWidth; - } - } - TDBG_SDD(" 2: col %d, set to width = %d\n", colIndex, mTableFrame->GetColumnWidth(colIndex)); - } - - // now, post-process the computed values based on the table attributes - // if there is a COLS attribute, fix up mMinTableWidth and mMaxTableWidth - if (PR_TRUE == hasColsAttribute) { // for every effected column, subtract out its prior contribution and add back in the new value - PRInt32 numColsEffected = mNumCols; - if (NS_STYLE_TABLE_COLS_ALL != mCols) { - numColsEffected = mCols; - } - nscoord maxOfEffectedColWidths = 0; - PRInt32 effectedColIndex; - // XXX need to fix this and all similar code if any fixed-width columns intersect COLS - for (effectedColIndex = 0; effectedColIndex < numColsEffected; effectedColIndex++) { - maxOfEffectedColWidths = PR_MAX(maxOfEffectedColWidths, minColWidthArray[effectedColIndex]); - } - for (effectedColIndex = 0; effectedColIndex < numColsEffected; effectedColIndex++) { - // set each effected column to the size of the largest column in the group - mTableFrame->SetColumnWidth(effectedColIndex, maxOfEffectedColWidths); - TDBG_SDD(" 2 (cols): setting %d to %d\n", effectedColIndex, maxOfEffectedColWidths); - } - // we're guaranteed here that minColWidthArray has been allocated, and that - // if we don't get here, it was never allocated - delete [] minColWidthArray; - } - return result; -} - -/* the table fits in the given space. Set all columns to their desired width, - * and if we are not an auto-width table add extra space to fluff out the total width - */ -PRBool BasicTableLayoutStrategy:: - BalanceColumnsTableFits(const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aTableSpecifiedWidth, - PRBool aTableIsAutoWidth) -{ - PRBool result = PR_TRUE; - nscoord tableWidth = 0; // the width of the table as a result of setting column widths - nscoord widthOfFixedTableColumns = 0; // the sum of the width of all fixed-width columns plus margins - // tableWidth - widthOfFixedTableColumns is the width of columns computed in this method - PRInt32 totalSlices = 0; // the total number of slices the proportional-width columns request - nsVoidArray* proportionalColumnsList = nsnull; // a list of the columns that are proportional-width - nsVoidArray* spanList = nsnull; // a list of the cells that span columns - PRInt32 numRows = mTableFrame->GetRowCount(); - nscoord colInset = mTableFrame->GetCellSpacingX(); - PRInt32 colIndex; - - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - TDBG_SD("for col %d\n", colIndex); - // Get column information - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - NS_ASSERTION(nsnull != colFrame, "bad col frame"); - PRInt32 minColWidth = colFrame->GetMinColWidth(); - PRInt32 maxColWidth = 0; - PRInt32 rowIndex; - PRInt32 firstRowIndex = -1; - - const nsStylePosition* colPosition; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - const nsStyleTable* colTableStyle; - colFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct*&)colTableStyle); - - // first, deal with any cells that span into this column from a pervious column - // go through the list backwards so we can delete easily - if (nsnull!=spanList) { - PRInt32 spanCount = spanList->Count(); - // go through the list backwards so we can delete easily - for (PRInt32 spanIndex = spanCount-1; 0 <= spanIndex; spanIndex--) { - SpanInfo* spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex)); - if (PR_FALSE == IsFixedWidth(colPosition, colTableStyle)) { - // compute the spanning cell's contribution to the column min width - nscoord spanCellMinWidth; - PRBool needsExtraMinWidth = PR_FALSE; - //if (spanInfo->effectiveMinWidthOfSpannedColscellMinWidth) - // needsExtraMinWidth = PR_TRUE; - if (PR_TRUE == needsExtraMinWidth) { - if (0 != spanInfo->effectiveMinWidthOfSpannedCols) { - spanCellMinWidth = (spanInfo->cellMinWidth * colFrame->GetEffectiveMinColWidth()) / - (spanInfo->effectiveMinWidthOfSpannedCols); - TDBG_SDD(" spanlist min: %d of %d\n", spanCellMinWidth, spanInfo->effectiveMaxWidthOfSpannedCols); - if (minColWidth < spanCellMinWidth) { - minColWidth = spanCellMinWidth; // set the new min width for the col - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new min = %d\n", - colIndex, spanInfo->span, minColWidth); - // if the new min width is greater than the desired width, bump up the desired width - maxColWidth = PR_MAX(maxColWidth, minColWidth); - TDBG_SD(" and maxColWidth = %d\n", maxColWidth); - } - } - else { - spanCellMinWidth = spanInfo->cellMinWidth / spanInfo->initialColSpan; - if (minColWidth < spanCellMinWidth) { - minColWidth = spanCellMinWidth; - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new min = %d\n", - colIndex, spanInfo->span, minColWidth); - // if the new min width is greater than the desired width, bump up the desired width - maxColWidth = PR_MAX(maxColWidth, minColWidth); - TDBG_SD(" and maxColWidth = %d\n", maxColWidth); - } - } - } - - - // compute the spanning cell's contribution to the column max width - nscoord spanCellMaxWidth; - if (0 != spanInfo->effectiveMaxWidthOfSpannedCols) { - spanCellMaxWidth = (spanInfo->cellDesiredWidth * colFrame->GetEffectiveMaxColWidth()) / - (spanInfo->effectiveMaxWidthOfSpannedCols); - TDBG_SDD(" spanlist max: %d of %d\n", spanCellMaxWidth, spanInfo->effectiveMaxWidthOfSpannedCols); - if (maxColWidth < spanCellMaxWidth) { - spanCellMaxWidth = PR_MAX(spanCellMaxWidth, minColWidth); - maxColWidth = spanCellMaxWidth; // set the new max width for the col - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); // set the column to the new desired max width - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new max = %d\n", - colIndex, spanInfo->span, maxColWidth); - } - } - else { - spanCellMaxWidth = spanInfo->cellDesiredWidth / spanInfo->initialColSpan; - maxColWidth = spanCellMaxWidth; - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new max = %d\n", - colIndex, spanInfo->span, maxColWidth); - } - } - spanInfo->span--; - if (0 == spanInfo->span) { - spanList->RemoveElementAt(spanIndex); - delete spanInfo; - } - } - } - - // second, process non-fixed-width columns - if (PR_FALSE==IsFixedWidth(colPosition, colTableStyle)) { - for (rowIndex = 0; rowIndex < numRows; rowIndex++) { - // this col has proportional width, so determine its width requirements - nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex); - if (nsnull == cellFrame) { - // there is no cell in this row that corresponds to this column - continue; - } - if (-1 == firstRowIndex) { - firstRowIndex = rowIndex; - } - PRInt32 cellRowIndex; - cellFrame->GetRowIndex(cellRowIndex); - if (rowIndex != cellRowIndex) { - // For cells that span rows, we only figure it in once - NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check - continue; - } - PRInt32 cellColIndex; - cellFrame->GetColIndex(cellColIndex); - if (colIndex != cellColIndex) { - // For cells that span cols, we figure in the row using previously-built SpanInfo - NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match row span"); // sanity check - continue; - } + // allocate and initialize arrays indicating what col gets set + PRInt32* allocTypes = new PRInt32[mNumCols]; + if (!allocTypes) return PR_FALSE; - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); - nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); - nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); - nscoord cellMinWidth=colFrame->GetMinColWidth(); - nscoord cellDesiredWidth=colFrame->GetMaxColWidth(); - // then get the desired size info factoring in the cell style attributes - if (1 == colSpan) { - cellMinWidth = cellMinSize.width; - cellDesiredWidth = cellDesiredSize.width; - nscoord specifiedCellWidth = -1; - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - if (eStyleUnit_Percent==cellPosition->mWidth.GetUnit()) { - if (PR_FALSE == aTableIsAutoWidth) { - float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(aTableSpecifiedWidth * percent); - TDBG_SFDD("specified percent width %f of %d = %d\n", - percent, aTableSpecifiedWidth, specifiedCellWidth); - } - // otherwise we need to post-process, set to max for now - // do we want to set specifiedCellWidth off of aAvailWidth? aMaxWidth? XXX - } - if (-1 != specifiedCellWidth) { - if (specifiedCellWidth>cellMinWidth) { - TDBG_SDD("setting cellDesiredWidth from %d to %d\n", cellDesiredWidth, specifiedCellWidth); - cellDesiredWidth = specifiedCellWidth; - } - } - } - else { - // colSpan>1, get the proportion for this column - // then get the desired size info factoring in the cell style attributes - nscoord effectiveMaxWidthOfSpannedCols = colFrame->GetEffectiveMaxColWidth(); - nscoord effectiveMinWidthOfSpannedCols = colFrame->GetEffectiveMinColWidth(); - for (PRInt32 span = 1; span < colSpan; span++) { - nsTableColFrame* nextColFrame = mTableFrame->GetColFrame(colIndex+span); - if (nsnull == nextColFrame) { - break; - } - effectiveMaxWidthOfSpannedCols += nextColFrame->GetEffectiveMaxColWidth(); - effectiveMinWidthOfSpannedCols += nextColFrame->GetEffectiveMinColWidth(); - } - nscoord specifiedCellWidth = -1; - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { - //XXX what if table is auto width? - float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(aTableSpecifiedWidth*percent); - TDBG_SFDD("specified percent width %f of %d = %d\n", - percent, aTableSpecifiedWidth, specifiedCellWidth); - } - if (-1 != specifiedCellWidth) { - float percentForThisCol = (float)(cellDesiredSize.width * colFrame->GetEffectiveMaxColWidth()) / - (float)effectiveMaxWidthOfSpannedCols; - nscoord cellWidthForThisCol = (nscoord)(specifiedCellWidth * percentForThisCol); - if (cellWidthForThisCol>cellMinWidth) { - TDBG_SDD("setting cellDesiredWidth from %d to %d\n", cellDesiredWidth, cellWidthForThisCol); - cellDesiredWidth = cellWidthForThisCol; - } - } - // otherwise it's already been factored in. - // now, if this column holds the cell, create a spanInfo struct for the cell - // so subsequent columns can take a proportion of this cell's space into account - cellFrame->GetColIndex(cellColIndex); - if (cellColIndex == colIndex) { - // add this cell to span list iff we are currently processing the column the cell starts in - SpanInfo* spanInfo = new SpanInfo(colIndex, colSpan-1, cellMinSize.width, cellDesiredSize.width); - spanInfo->effectiveMaxWidthOfSpannedCols = effectiveMaxWidthOfSpannedCols; - spanInfo->effectiveMinWidthOfSpannedCols = effectiveMinWidthOfSpannedCols; - if (nsnull == spanList) { - spanList = new nsVoidArray(); - } - spanList->AppendElement(spanInfo); - } - } - - TDBG_SDDDD("factoring in cell %d with colSpan=%d\n factoring in min=%d and desired=%d\n", - rowIndex, colSpan, cellMinWidth, cellDesiredWidth); - maxColWidth = PR_MAX(maxColWidth, cellDesiredWidth); - TDBG_SDDDDD(" after cell %d, minColWidth=%d maxColWidth=%d effColWidth[%d]=%d\n", - rowIndex, minColWidth, maxColWidth, - colIndex, colFrame->GetEffectiveMaxColWidth()); - } // end looping through cells in the column - - TDBG_SDS_SDD_SD(" for determining width of col %d %s:\n", - colIndex, !IsFixedWidth(colPosition, colTableStyle)? "(P)":"(A)", - " minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth, - " aAvailWidth = %d\n", aAvailWidth); - - // Get column width if it has one - nscoord specifiedProportionColumnWidth = -1; - float specifiedPercentageColWidth = -1.0f; - PRBool isAutoWidth = PR_FALSE; - switch (colPosition->mWidth.GetUnit()) { - case eStyleUnit_Percent: - specifiedPercentageColWidth = colPosition->mWidth.GetPercentValue(); - TDBG_SDF("column %d has specified percent width = %f\n", colIndex, specifiedPercentageColWidth); - break; - case eStyleUnit_Proportional: - specifiedProportionColumnWidth = colPosition->mWidth.GetIntValue(); - TDBG_SDD("column %d has specified percent width = %d\n", colIndex, specifiedProportionColumnWidth); - break; - case eStyleUnit_Auto: - isAutoWidth = PR_TRUE; - break; - default: - break; - } - - // set the column width, knowing that the table fits in the available space - if (0 == specifiedProportionColumnWidth || 0.0==specifiedPercentageColWidth) { - // col width is specified to be the minimum - mTableFrame->SetColumnWidth(colIndex, minColWidth); - TDBG_SDD(" 3 min: col %d set to min width = %d because style set proportionalWidth=0\n", - colIndex, mTableFrame->GetColumnWidth(colIndex)); - } - else if ((PR_TRUE == isAutoWidth) || - ((PR_TRUE==aTableIsAutoWidth) && (-1==specifiedProportionColumnWidth))) { - // col width is determined by the cells' content, - // so give each remaining column it's desired width (because we know we fit.) - // if there is width left over, we'll factor that in after this loop is complete - // the OR clause is because we fix up percentage widths as a post-process - // in auto-width tables - mTableFrame->SetColumnWidth(colIndex, maxColWidth); - TDBG_SDDD(" 3 auto: col %d with availWidth %d, set to width = %d\n", - colIndex, aAvailWidth, mTableFrame->GetColumnWidth(colIndex)); - } - else if (-1 != specifiedProportionColumnWidth) - { // we need to save these and do them after all other columns have been calculated - // the calculation will be: - // sum up n, the total number of slices for the columns with proportional width - // compute the table "required" width, fixed-width + percentage-width + - // the sum of the proportional column's max widths (especially because in this routine I know the table fits) - // compute the remaining width: the required width - the used width (fixed + percentage) - // compute the width per slice - // set the width of each proportional-width column to it's number of slices * width per slice - mTableFrame->SetColumnWidth(colIndex, 0); // set the column width to 0, since it isn't computed yet - if (nsnull == proportionalColumnsList) { - proportionalColumnsList = new nsVoidArray(); - } - ProportionalColumnLayoutStruct* info = - new ProportionalColumnLayoutStruct(colIndex, minColWidth, - maxColWidth, specifiedProportionColumnWidth); - proportionalColumnsList->AppendElement(info); - totalSlices += specifiedProportionColumnWidth; // keep track of the total number of proportions - TDBG_SDDDD(" 3 proportional: col %d with availWidth %d, gets %d slices with %d slices so far.\n", - colIndex, aAvailWidth, specifiedProportionColumnWidth, totalSlices); - } - else { // give the column a percentage of the remaining space - PRInt32 percentage = -1; - if (NS_UNCONSTRAINEDSIZE == aAvailWidth) { - // since the "remaining space" is infinite, give the column it's max requested size - mTableFrame->SetColumnWidth(colIndex, maxColWidth); - } - else { - if (-1.0f != specifiedPercentageColWidth) { - percentage = (PRInt32)(specifiedPercentageColWidth * 100.0f); // TODO: rounding errors? - // base the % on the total specified fixed width of the table - mTableFrame->SetColumnWidth(colIndex, (percentage*aTableSpecifiedWidth) / 100); - TDBG_SDDDD(" 3 percent specified: col %d given %d percent of aTableSpecifiedWidth %d, set to width = %d\n", - colIndex, percentage, aTableSpecifiedWidth, mTableFrame->GetColumnWidth(colIndex)); - } - if (-1 == percentage) { - percentage = 100 / mNumCols; - // base the % on the remaining available width - mTableFrame->SetColumnWidth(colIndex, (percentage*aAvailWidth) / 100); - TDBG_SDDDD(" 3 percent default: col %d given %d percent of aAvailWidth %d, set to width = %d\n", - colIndex, percentage, aAvailWidth, mTableFrame->GetColumnWidth(colIndex)); - } - // if the column was computed to be too small, enlarge the column - if (mTableFrame->GetColumnWidth(colIndex) <= minColWidth) { - mTableFrame->SetColumnWidth(colIndex, minColWidth); - TDBG_SD(" enlarging column to it's minimum = %d\n", minColWidth); - } - } - } - } - else { // need to maintain this so we know how much we have left over at the end - nscoord maxEffectiveColWidth = colFrame->GetEffectiveMaxColWidth(); - mTableFrame->SetColumnWidth(colIndex, maxEffectiveColWidth); - widthOfFixedTableColumns += maxEffectiveColWidth + colInset; - } - tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset; - } - tableWidth += colInset; - - /* --- post-process if necessary --- */ - - // XXX the following implementation does not account for borders, cell spacing, cell padding - - // first, assign column widths in auto-width tables - PRInt32 numPercentColumns = 0; - PRInt32* percentColumns=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Percent, numPercentColumns, percentColumns); - if ((PR_TRUE == aTableIsAutoWidth) && (0 != numPercentColumns)) { - // variables common to lots of code in this block - nscoord colWidth; - float percent; - const nsStylePosition* colPosition; - nsTableColFrame* colFrame; - if (numPercentColumns != mNumCols) { - TDBG_S("assigning widths to percent colums in auto-width table\n"); - nscoord widthOfPercentCells = 0; // the total width of those percent-width cells that have been given a width - nscoord widthOfOtherCells = 0; // the total width of those non-percent-width cells that have been given a width - float sumOfPercentColumns = 0.0f; // the total of the percent widths - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - // every column contributes to either widthOfOtherCells or widthOfPercentCells, but not both - if (PR_TRUE == IsColumnInList(colIndex, percentColumns, numPercentColumns)) { - colFrame = mTableFrame->GetColFrame(colIndex); - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - percent = colPosition->mWidth.GetPercentValue(); // we know this will work - sumOfPercentColumns += percent; - if (sumOfPercentColumns > 1.0f) { // values greater than 100% are meaningless - sumOfPercentColumns = 1.0f; - } - widthOfPercentCells += mTableFrame->GetColumnWidth(colIndex); - } - else { - widthOfOtherCells += mTableFrame->GetColumnWidth(colIndex); - } - } - if (0 == widthOfOtherCells) { - widthOfOtherCells = aMaxWidth; - } - TDBG_SDDF(" widthOfOtherCells=%d widthOfPercentCells = %d sumOfPercentColumns=%f\n", - widthOfOtherCells, widthOfPercentCells, sumOfPercentColumns); - float remainingPercent = 1.0f - sumOfPercentColumns; - nscoord newTableWidth; // the table width after all cells have been resized - if (1.0f == sumOfPercentColumns) { // this definately seems like a QUIRK! - newTableWidth = aMaxWidth; - } - else { // the newTableWidth is the larger of the calculation from the percent cells and non-percent cells - nscoord percentWidth = (nscoord)((1.0f/sumOfPercentColumns)*((float)(widthOfPercentCells))); - nscoord otherWidth = (nscoord)((1.0f/remainingPercent)*((float)(widthOfOtherCells))); - TDBG_SDD(" percentWidth=%d otherWidth=%d\n", percentWidth, otherWidth); - newTableWidth = PR_MAX(percentWidth, otherWidth); // the table width is the larger of the two computations - newTableWidth = PR_MIN(newTableWidth, aMaxWidth); // an auto-width table can't normally be wider than it's parent - newTableWidth = PR_MIN(newTableWidth, mMaxTableWidth);// an auto-width table can't normally be wider than it's own computed max width - } - nscoord excess = newTableWidth-mFixedTableWidth; // the amount of new space that needs to be - // accounted for in the non-fixed columns - TDBG_SD(" newTableWidth=%d \n", newTableWidth); - PRInt32 i; // just a counter - for (i = 0; i < numPercentColumns; i++) { - colIndex = percentColumns[i]; - colFrame = mTableFrame->GetColFrame(colIndex); - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - percent = colPosition->mWidth.GetPercentValue(); // we know this will work - colWidth = (nscoord)((percent) * ((float)newTableWidth)); - nscoord minColWidth = colFrame->GetEffectiveMinColWidth(); - colWidth = PR_MAX(colWidth, minColWidth); - mTableFrame->SetColumnWidth(colIndex, colWidth); - TDBG_SDFD(" col %d with percentwidth=%f set to %d\n", colIndex, percent, colWidth); - excess -= colWidth; - } - if (0 < excess) { - PRInt32 numAutoColumns=0; - PRInt32* autoColumns=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); - TDBG_SDD(" excess=%d with %d autoColumns\n", excess, numAutoColumns); - if (0 < numAutoColumns) { - nscoord excessPerColumn = excess / numAutoColumns; - for (i = 0; i < numAutoColumns; i++) { - colIndex = autoColumns[i]; - nscoord newWidth = PR_MAX(excessPerColumn, mTableFrame->GetColumnWidth(colIndex)); - TDBG_SDDD(" col %d was %d set to %d\n", - colIndex, mTableFrame->GetColumnWidth(colIndex), newWidth); - mTableFrame->SetColumnWidth(colIndex, newWidth); - excess -= excessPerColumn; - } - // handle division underflow - if (0 < excess) { - TDBG_SD(" after first pass through auto-width columns, excess=%d\n", excess); - for (i = 0; i < numAutoColumns; i++) { - colIndex = autoColumns[i]; - nscoord newWidth = 1 + mTableFrame->GetColumnWidth(colIndex); - mTableFrame->SetColumnWidth(colIndex, newWidth); - } - } - } - } - } - else { - // all columns have a percent width. Each already has its desired width. - // find the smallest percentage and base the widths of the others off that - PRInt32 indexOfSmallest; - nscoord colWidthOfSmallest; - float smallestPercent = 2.0f; // an illegal large number - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - colFrame = mTableFrame->GetColFrame(colIndex); - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - percent = colPosition->mWidth.GetPercentValue(); // we know this will work - if (percent < smallestPercent) { - smallestPercent=percent; - indexOfSmallest=colIndex; - colWidthOfSmallest = mTableFrame->GetColumnWidth(colIndex); - } - else if (percent==smallestPercent) { - // the largest desired size among equal-percent columns wins - colWidth = mTableFrame->GetColumnWidth(colIndex); - if (colWidth > colWidthOfSmallest) { - indexOfSmallest = colIndex; - colWidthOfSmallest = colWidth; - } - } - } - // now that we know which column to base the other columns' widths off of, do it! - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - colFrame = mTableFrame->GetColFrame(colIndex); - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - percent = colPosition->mWidth.GetPercentValue(); // we know this will work - if (percent == smallestPercent) { // set col width to the max width of all columns that shared the smallest percent-width - mTableFrame->SetColumnWidth(colIndex, colWidthOfSmallest); - } - else { - colWidth = (nscoord)((percent/smallestPercent) * ((float)colWidthOfSmallest)); - nscoord minColWidth = colFrame->GetEffectiveMinColWidth(); - colWidth = PR_MAX(colWidth, minColWidth); - mTableFrame->SetColumnWidth(colIndex, colWidth); - } - TDBG_SDFD(" col %d with percentwidth=%f set to %d\n", colIndex, percent, colWidth); - } - } + for (colX = 0; colX < mNumCols; colX++) { + allocTypes[colX] = -1; } - // second, assign column widths to proportional-width columns - if (nsnull != proportionalColumnsList) { - // first, figure out the amount of space per slice - nscoord maxWidthForTable = (0 != aTableSpecifiedWidth) ? aTableSpecifiedWidth : aMaxWidth; - if (NS_UNCONSTRAINEDSIZE != maxWidthForTable) { - nscoord widthRemaining = maxWidthForTable - tableWidth; - nscoord widthPerSlice = widthRemaining/totalSlices; - PRInt32 numSpecifiedProportionalColumns = proportionalColumnsList->Count(); - for (PRInt32 i = 0; i < numSpecifiedProportionalColumns; i++) { - // for every proportionally-sized column, set the col width to the computed width - ProportionalColumnLayoutStruct* info = - (ProportionalColumnLayoutStruct *)(proportionalColumnsList->ElementAt(i)); - // verify that the computed width is at least the minimum width - nscoord computedColWidth = info->mProportion*widthPerSlice; - // compute the requested proportional width - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(info->mColIndex, colFrame); - nscoord minColWidth = colFrame->GetMinColWidth(); - computedColWidth = PR_MAX(computedColWidth, minColWidth); - mTableFrame->SetColumnWidth(info->mColIndex, computedColWidth); - TDBG_SDDDD(" 3 proportional step 2: col %d given %d proportion of remaining space %d, set to width = %d\n", - info->mColIndex, info->mProportion, widthRemaining, computedColWidth); - tableWidth += computedColWidth; - delete info; - } - } - else { - // we're in an unconstrained situation, so give each column the max of the max column widths - PRInt32 numSpecifiedProportionalColumns = proportionalColumnsList->Count(); - PRInt32 maxOfMaxColWidths = 0; - PRInt32 i; - for (i = 0; i < numSpecifiedProportionalColumns; i++) { - ProportionalColumnLayoutStruct* info = - (ProportionalColumnLayoutStruct *)(proportionalColumnsList->ElementAt(i)); - maxOfMaxColWidths = PR_MAX(maxOfMaxColWidths, info->mMaxColWidth); - } - for (i = 0; i < numSpecifiedProportionalColumns; i++) { - ProportionalColumnLayoutStruct* info = - (ProportionalColumnLayoutStruct *)(proportionalColumnsList->ElementAt(i)); - mTableFrame->SetColumnWidth(info->mColIndex, maxOfMaxColWidths); - TDBG_SDD(" 3 proportional step 2 (unconstrained!): col %d set to width = %d\n", - info->mColIndex, maxOfMaxColWidths); - tableWidth += maxOfMaxColWidths; - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(info->mColIndex, colFrame); - colFrame->SetEffectiveMaxColWidth(maxOfMaxColWidths); - delete info; - } - } - delete proportionalColumnsList; - } - - // next, account for table width constraints - // if the caption min width is wider than than the table, expand the table - nscoord captionMinWidth = mTableFrame->GetMinCaptionWidth(); - if (captionMinWidth > tableWidth) { - DistributeExcessSpace(captionMinWidth, tableWidth, widthOfFixedTableColumns); - } - else { - // else, if the caption min width is not an issue... - // if the specified width of the table is greater than the table's computed width, expand the - // table's computed width to match the specified width, giving the extra space to proportionately-sized - // columns if possible. - if ((PR_FALSE == aTableIsAutoWidth) && (aAvailWidth > (tableWidth-widthOfFixedTableColumns)) && - (gBigSpace != aAvailWidth)) { - DistributeExcessSpace(aAvailWidth, tableWidth, widthOfFixedTableColumns); - } - // IFF the table is NOT (auto-width && all columns have fixed width) - PRInt32 numFixedColumns=0; - PRInt32* fixedColumns=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); - if (!((PR_TRUE == aTableIsAutoWidth) && (numFixedColumns == mNumCols))) { - nscoord computedWidth = 0; - for (PRInt32 i = 0; i < mNumCols; i++) { - computedWidth += mTableFrame->GetColumnWidth(i) + colInset; - } - if (computedWidth > aMaxWidth) { - AdjustTableThatIsTooWide(computedWidth, aMaxWidth, PR_FALSE); - } - } - } - - // cleanup - if (nsnull != spanList) { - TDBG_S("BTLS::BCTFits...space leak, span list not empty"); - delete spanList; - } - return result; -} - -// take the extra space in the table and distribute it proportionately (based on desired width) -// give extra space to auto-width cells first, or if there are none to all cells -void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, - nscoord aTableWidth, - nscoord aWidthOfFixedTableColumns) -{ - nscoord excess = 0; - TDBG_SDDD("DistributeExcessSpace: fixed width %d > computed table width %d, woftc=%d\n", - aAvailWidth, aTableWidth, aWidthOfFixedTableColumns); - nscoord widthMinusFixedColumns = aTableWidth - aWidthOfFixedTableColumns; - // if there are auto-sized columns, give them the extra space - // the trick here is to do the math excluding non-auto width columns - PRInt32 numAutoColumns=0; - PRInt32* autoColumns=nsnull; - GetColumnsThatActLikeAutoWidth(numAutoColumns, autoColumns); // allocates autoColumns, be sure to delete it - if (0 != numAutoColumns) { - // there's at least one auto-width column, so give it (them) the extra space - // proportionately distributed extra space, based on the column's desired size - nscoord totalEffectiveWidthOfAutoColumns = 0; - // 1. first, get the total width of the auto columns - PRInt32 i; - for (i = 0; i < numAutoColumns; i++) { - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(autoColumns[i], colFrame); - nscoord effectiveColWidth = colFrame->GetEffectiveMaxColWidth(); - if (0 != effectiveColWidth) { - totalEffectiveWidthOfAutoColumns += effectiveColWidth; - } - else { - totalEffectiveWidthOfAutoColumns += mTableFrame->GetColumnWidth(autoColumns[i]); - } - } - // excess is the amount of space that was available minus the computed available width - // XXX shouldn't it just be aMaxWidth - aTableWidth??? - TDBG_SDD(" aAvailWidth specified as %d, expanding columns by excess = %d\n", aAvailWidth, excess); - excess = aAvailWidth - widthMinusFixedColumns; - - // 2. next, compute the proportion to be added to each column, and add it - nscoord totalAdded=0; - for (i = 0; i < numAutoColumns; i++) { - PRInt32 colIndex = autoColumns[i]; - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(colIndex, colFrame); - nscoord oldColWidth = mTableFrame->GetColumnWidth(colIndex); - float percent; - if (0 != totalEffectiveWidthOfAutoColumns) { - percent = ((float)(colFrame->GetEffectiveMaxColWidth())) / ((float)totalEffectiveWidthOfAutoColumns); - } - else { - percent = ((float)1 )/ ((float)numAutoColumns); - } - nscoord excessForThisColumn = (nscoord)(excess * percent); - totalAdded += excessForThisColumn; - nscoord colWidth = excessForThisColumn+oldColWidth; - TDBG_SDDD(" distribute excess to auto columns: column %d was %d, now set to %d\n", - colIndex, oldColWidth, colWidth); - mTableFrame->SetColumnWidth(colIndex, colWidth); - } - TDBG_SDD("lost a few twips due to rounding errors: excess=%d, totalAdded=%d\n", excess, totalAdded); - } - // otherwise, distribute the space between all the columns - // (they must be all fixed and percentage-width columns, or we would have gone into the block above) - else { - excess = aAvailWidth - widthMinusFixedColumns; - TDBG_SDD(" aAvailWidth specified as %d, expanding columns by excess = %d\n", aAvailWidth, excess); - nscoord totalAdded=0; - for (PRInt32 colIndex = 0; colIndex < mNumCols; colIndex++) { - nscoord oldColWidth=0; - if (0 == oldColWidth) { - oldColWidth = mTableFrame->GetColumnWidth(colIndex); - } - float percent; - if (0 != aTableWidth) { - percent = (float)oldColWidth/(float)aTableWidth; - } - else { - percent = (float)1 / (float)mNumCols; - } - nscoord excessForThisColumn = (nscoord)(NSToCoordRound(excess * percent)); - totalAdded += excessForThisColumn; - nscoord colWidth = excessForThisColumn + oldColWidth; - TDBG_SDDDF(" distribute excess: column %d was %d, now %d from %=%f\n", - colIndex, oldColWidth, colWidth, percent); - mTableFrame->SetColumnWidth(colIndex, colWidth); - } - TDBG_SDD("lost a few twips due to rounding errors: excess=%d, totalAdded=%d\n", excess, totalAdded); - } - if (nsnull != autoColumns) { - delete [] autoColumns; - } -} - -/* assign columns widths for a table whose max size doesn't fit in the available space - */ -PRBool BasicTableLayoutStrategy:: - BalanceColumnsConstrained(const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - PRBool aTableIsAutoWidth) -{ -#ifdef NS_DEBUG - nsIFrame* tablePIF=nsnull; - mTableFrame->GetPrevInFlow(&tablePIF); - NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!"); -#endif - - PRBool result = PR_TRUE; - PRInt32 maxOfAllMinColWidths = 0; // for the case where we have equal column widths, this is the smallest a column can be - nscoord tableWidth = 0; // the width of the table as a result of setting column widths - PRInt32 totalSlices = 0; // the total number of slices the proportional-width columns request - nsVoidArray* proportionalColumnsList=nsnull; // a list of the columns that are proportional-width - PRBool equalWidthColumns = PR_TRUE; // remember if we're in the special case where all - // proportional-width columns are equal (if any are anything other than 1) - PRBool atLeastOneAutoWidthColumn = PR_FALSE; // true if at least one column is auto-width, requiring us to post-process - nsVoidArray* spanList=nsnull; // a list of the cells that span columns - PRInt32 numRows = mTableFrame->GetRowCount(); - nscoord colInset = mTableFrame->GetCellSpacingX(); - - for (PRInt32 colIndex = 0; colIndex < mNumCols; colIndex++) { - TDBG_SD(" for col %d\n", colIndex); - nscoord minColWidth = 0; - nscoord maxColWidth = 0; - - // Get column information - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); - NS_ASSERTION(nsnull != colFrame, "bad col frame"); - // Get the columns's style and margins - PRInt32 rowIndex; - PRInt32 firstRowIndex = -1; - const nsStylePosition* colPosition; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); - const nsStyleTable* colTableStyle; - colFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct*&)colTableStyle); - - // first, deal with any cells that span into this column from a pervious column - // go through the list backwards so we can delete easily - if (nsnull != spanList) { - PRInt32 spanCount = spanList->Count(); - // go through the list backwards so we can delete easily - for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--) { - SpanInfo* spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex)); - if (PR_FALSE == IsFixedWidth(colPosition, colTableStyle)) { - // compute the spanning cell's contribution to the column min width - nscoord spanCellMinWidth; - PRBool needsExtraMinWidth = (spanInfo->effectiveMinWidthOfSpannedCols < spanInfo->cellMinWidth); - if (PR_TRUE == needsExtraMinWidth) { - if (0 != spanInfo->effectiveMinWidthOfSpannedCols) { - spanCellMinWidth = (spanInfo->cellMinWidth * colFrame->GetEffectiveMinColWidth()) / - (spanInfo->effectiveMinWidthOfSpannedCols); - TDBG_SDD(" spanlist min: %d of %d\n", spanCellMinWidth, spanInfo->effectiveMaxWidthOfSpannedCols); - if (minColWidth < spanCellMinWidth) { - minColWidth = spanCellMinWidth; // set the new min width for the col - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new min = %d\n", - colIndex, spanInfo->span, minColWidth); - maxColWidth = PR_MAX(maxColWidth, minColWidth); - TDBG_SD(" maxColWidth = %d\n", maxColWidth); - } - } - else { - spanCellMinWidth = spanInfo->cellMinWidth / spanInfo->initialColSpan; - if (minColWidth < spanCellMinWidth) { - minColWidth = spanCellMinWidth; - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new min = %d\n", - colIndex, spanInfo->span, minColWidth); - maxColWidth = PR_MAX(maxColWidth, minColWidth); - TDBG_SD(" maxColWidth = %d\n", maxColWidth); - } - } - } - - - // compute the spanning cell's contribution to the column max width - nscoord spanCellMaxWidth; - if (0 != spanInfo->effectiveMaxWidthOfSpannedCols) { - spanCellMaxWidth = (spanInfo->cellDesiredWidth * colFrame->GetEffectiveMinColWidth()) / - (spanInfo->effectiveMaxWidthOfSpannedCols); - TDBG_SDD(" spanlist max: %d of %d\n", spanCellMaxWidth, spanInfo->effectiveMaxWidthOfSpannedCols); - if (maxColWidth < spanCellMaxWidth) { - maxColWidth = spanCellMaxWidth; // set the new max width for the col - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); // set the column to the new desired max width - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new max = %d\n", - colIndex, spanInfo->span, maxColWidth); - } - } - else { - spanCellMaxWidth = spanInfo->cellDesiredWidth/spanInfo->initialColSpan; - maxColWidth = spanCellMaxWidth; - mTableFrame->SetColumnWidth(colIndex, spanCellMaxWidth); - TDBG_SDDD(" for spanning cell into col %d with remaining span=%d, new max = %d\n", - colIndex, spanInfo->span, maxColWidth); - } - } - spanInfo->span--; - if (0 == spanInfo->span) { - spanList->RemoveElementAt(spanIndex); - delete spanInfo; - } - } - } - - // second, process non-fixed-width columns - if (PR_FALSE == IsFixedWidth(colPosition, colTableStyle)) { - for (rowIndex = 0; rowIndex < numRows; rowIndex++) { - nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(rowIndex, colIndex); - if (nsnull == cellFrame) { // there is no cell in this row that corresponds to this column - continue; - } - PRInt32 cellRowIndex; - cellFrame->GetRowIndex(cellRowIndex); - if (rowIndex!=cellRowIndex) { - // For cells that span rows, we only figure it in once - NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check - continue; - } - PRInt32 cellColIndex; - cellFrame->GetColIndex(cellColIndex); - if (colIndex!=cellColIndex) { - // For cells that span cols, we figure in the row using previously-built SpanInfo - NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match row span"); // sanity check - continue; - } - - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); - nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); - nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); - - nscoord cellMinWidth=colFrame->GetAdjustedMinColWidth(); - nscoord cellDesiredWidth=colFrame->GetMaxColWidth(); - if (1 == colSpan) { - cellMinWidth = cellMinSize.width; - cellDesiredWidth = cellDesiredSize.width; - nscoord specifiedCellWidth = -1; - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - if (eStyleUnit_Percent==cellPosition->mWidth.GetUnit()) { - float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(aMaxWidth * percent); - TDBG_SFDD("specified percent width %f of %d = %d\n", percent, aMaxWidth, specifiedCellWidth); - } - if (-1 != specifiedCellWidth) { - if (specifiedCellWidth>cellMinWidth) { - TDBG_SDD("setting cellDesiredWidth from %d to %d\n", cellDesiredWidth, specifiedCellWidth); - cellDesiredWidth = specifiedCellWidth; - } - } - } - else { // colSpan>1, get the proportion for this column - // then get the desired size info factoring in the cell style attributes - nscoord effectiveMaxWidthOfSpannedCols = colFrame->GetEffectiveMaxColWidth(); - nscoord effectiveMinWidthOfSpannedCols = colFrame->GetEffectiveMinColWidth(); - for (PRInt32 span = 1; span < colSpan; span++) { - nsTableColFrame* nextColFrame = mTableFrame->GetColFrame(colIndex+span); - if (nsnull == nextColFrame) { - break; - } - effectiveMaxWidthOfSpannedCols += nextColFrame->GetEffectiveMaxColWidth(); - effectiveMinWidthOfSpannedCols += nextColFrame->GetEffectiveMinColWidth(); - } - nscoord specifiedCellWidth = -1; - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { - //XXX what if table is auto width? - float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(aMaxWidth * percent); - TDBG_SFDD("specified percent width %f of %d = %d\n", percent, aMaxWidth, specifiedCellWidth); - } - if (-1 != specifiedCellWidth) { - float percentForThisCol = (float)(cellDesiredSize.width * colFrame->GetEffectiveMaxColWidth()) / - (float)effectiveMaxWidthOfSpannedCols; - nscoord cellWidthForThisCol = (nscoord)(specifiedCellWidth * percentForThisCol); - if (cellWidthForThisCol>cellMinWidth) { - TDBG_SDD("setting cellDesiredWidth from %d to %d\n", cellDesiredWidth, cellWidthForThisCol); - cellDesiredWidth = cellWidthForThisCol; - } - } - // otherwise it's already been factored in. - // now, if this column holds the cell, create a spanInfo struct for the cell - // so subsequent columns can take a proportion of this cell's space into account - cellFrame->GetColIndex(cellColIndex); - if (cellColIndex == colIndex) { - // add this cell to span list iff we are currently processing the column the cell starts in - SpanInfo* spanInfo = new SpanInfo(colIndex, colSpan-1, cellMinSize.width, cellDesiredSize.width); - spanInfo->effectiveMaxWidthOfSpannedCols = effectiveMaxWidthOfSpannedCols; - spanInfo->effectiveMinWidthOfSpannedCols = effectiveMinWidthOfSpannedCols; - if (nsnull == spanList) { - spanList = new nsVoidArray(); - } - spanList->AppendElement(spanInfo); - } - } - - TDBG_SDDDD("factoring in cell %d with colSpan=%d\n factoring in min=%d and desired=%d\n", - rowIndex, colSpan, cellMinWidth, cellDesiredWidth); - // remember the widest min cell width - minColWidth = PR_MAX(minColWidth, cellMinWidth); - // remember the max desired cell width - maxColWidth = PR_MAX(maxColWidth, cellDesiredWidth); - // effectiveMaxColumnWidth is the width as if no cells with colspans existed - // if ((1==colSpan) && (colFrame->GetEffectiveMaxColWidth() < maxColWidth)) - // colFrame->SetEffectiveMaxColWidth(cellDesiredWidth); - TDBG_SDDDDDD(" after cell %d, minColWidth=%d maxColWidth=%d effColWidth[%d]=%d,%d\n", - rowIndex, minColWidth, maxColWidth, colIndex, - colFrame->GetEffectiveMinColWidth(), colFrame->GetEffectiveMaxColWidth()); - } - if (PR_TRUE == gsDebug) { - printf (" for determining width of col %d %s:\n", - colIndex, !IsFixedWidth(colPosition, colTableStyle)? "(P)":"(A)"); - printf (" minTableWidth = %d and maxTableWidth = %d\n", - mMinTableWidth, mMaxTableWidth); - printf (" minColWidth = %d, maxColWidth = %d, eff=%d,%d\n", - minColWidth, maxColWidth, colFrame->GetEffectiveMinColWidth(), - colFrame->GetEffectiveMaxColWidth()); - printf (" aAvailWidth = %d\n", aAvailWidth); - } - - - // Get column width if it has one - nscoord specifiedProportionColumnWidth = -1; - float specifiedPercentageColWidth = -1.0f; - PRBool isAutoWidth = PR_FALSE; - switch (colPosition->mWidth.GetUnit()) { - case eStyleUnit_Percent: - specifiedPercentageColWidth = colPosition->mWidth.GetPercentValue(); - TDBG_SDF("column %d has specified percent width = %f\n", colIndex, specifiedPercentageColWidth); - break; - case eStyleUnit_Proportional: - specifiedProportionColumnWidth = colPosition->mWidth.GetIntValue(); - TDBG_SDD("column %d has specified percent width = %d\n", colIndex, specifiedProportionColumnWidth); - break; - case eStyleUnit_Auto: - isAutoWidth = PR_TRUE; - break; - default: - break; - } - - // set the column width, knowing that the table is constrained - if (0 == specifiedProportionColumnWidth || 0.0 == specifiedPercentageColWidth) { - // col width is specified to be the minimum - mTableFrame->SetColumnWidth(colIndex, minColWidth); - TDBG_SDD(" 4 (0): col %d set to min width = %d because style set proportionalWidth=0\n", - colIndex, mTableFrame->GetColumnWidth(colIndex)); - } - else if (1 == mNumCols) { // there is only one column, and we know that it's desired width doesn't fit - // so the column should be as wide as the available space allows it to be minus cell spacing - nscoord colWidth = aAvailWidth - (2*colInset); - mTableFrame->SetColumnWidth(colIndex, colWidth); - TDBG_SDDDD(" 4 one-col: col %d set to width = %d from available width %d and cell spacing %d\n", - colIndex, mTableFrame->GetColumnWidth(colIndex), aAvailWidth, colInset); - } - else if (PR_TRUE==isAutoWidth) { // column's width is determined by its content, done in post-processing - mTableFrame->SetColumnWidth(colIndex, minColWidth); // reserve the column's min width - atLeastOneAutoWidthColumn = PR_TRUE; - } - else if (-1 != specifiedProportionColumnWidth) { - // we need to save these and do them after all other columns have been calculated - // the calculation will be: - // sum up n, the total number of slices for the columns with proportional width - // compute the table "required" width, fixed-width + percentage-width + - // the sum of the proportional column's max widths (especially because in this routine I know the table fits) - // compute the remaining width: the required width - the used width (fixed + percentage) - // compute the width per slice - // set the width of each proportional-width column to it's number of slices * width per slice - mTableFrame->SetColumnWidth(colIndex, 0); // set the column width to 0, since it isn't computed yet - if (nsnull == proportionalColumnsList) { - proportionalColumnsList = new nsVoidArray(); - } - ProportionalColumnLayoutStruct* info = - new ProportionalColumnLayoutStruct(colIndex, minColWidth, maxColWidth, specifiedProportionColumnWidth); - proportionalColumnsList->AppendElement(info); - totalSlices += specifiedProportionColumnWidth; - if (1 != specifiedProportionColumnWidth) { - equalWidthColumns = PR_FALSE; - } - } - else { // give the column a percentage of the remaining space - PRInt32 percentage = -1; - if (NS_UNCONSTRAINEDSIZE == aAvailWidth) { - // since the "remaining space" is infinite, give the column it's max requested size - mTableFrame->SetColumnWidth(colIndex, maxColWidth); - } - else { - if (-1.0f != specifiedPercentageColWidth) { - percentage = (PRInt32)(specifiedPercentageColWidth * 100.0f); // TODO: rounding errors? - // base the % on the total specified fixed width of the table - mTableFrame->SetColumnWidth(colIndex, (percentage*aMaxWidth)/100); - TDBG_SDDDD(" 4 percent specified: col %d given %d percent of aMaxWidth %d, set to width = %d\n", - colIndex, percentage, aMaxWidth, mTableFrame->GetColumnWidth(colIndex)); - } - if (-1 == percentage) { - percentage = 100 / mNumCols; - // base the % on the remaining available width - mTableFrame->SetColumnWidth(colIndex, (percentage * aAvailWidth) / 100); - TDBG_SDDDD(" 4 percent default: col %d given %d percent of aAvailWidth %d, set to width = %d\n", - colIndex, percentage, aAvailWidth, mTableFrame->GetColumnWidth(colIndex)); - } - // if the column was computed to be too small, enlarge the column - if (mTableFrame->GetColumnWidth(colIndex) <= minColWidth) { - mTableFrame->SetColumnWidth(colIndex, minColWidth); - TDBG_SD(" enlarging column to it's minimum = %d\n", minColWidth); - if (maxOfAllMinColWidths < minColWidth) { - maxOfAllMinColWidths = minColWidth; - TDBG_SD(" and setting maxOfAllMins to %d\n", maxOfAllMinColWidths); - } - } - } - } + // allocate percentage cols + if (totalCounts[PCT] > 0) { + if (totalAllocated + totalWidths[PCT] - minWidths[PCT] <= maxWidth) { + AllocateFully(totalAllocated, allocTypes, PCT); + NS_ASSERTION(totalAllocated <= maxWidth, "over allocated"); } else { - mTableFrame->SetColumnWidth(colIndex, colFrame->GetMaxColWidth()); + AllocateConstrained(maxWidth - totalAllocated, PCT, totalCounts[PCT], + totalWidths[PCT], PR_FALSE, allocTypes); + return BCW_Wrapup(this, mTableFrame, allocTypes); } - tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset; } - tableWidth += colInset; - // --- post-process if necessary --- / - // first, assign autoWidth columns a width - if (PR_TRUE == atLeastOneAutoWidthColumn) { - // proportionately distribute the remaining space to autowidth columns - DistributeRemainingSpace(aMaxWidth, tableWidth, aTableIsAutoWidth); + // allocate fixed cols + if (totalAllocated < maxWidth && totalCounts[FIX] > 0) { + if (totalAllocated + totalWidths[FIX] - minWidths[FIX] <= maxWidth) { + AllocateFully(totalAllocated, allocTypes, FIX); + NS_ASSERTION(totalAllocated <= maxWidth, "over allocated"); + } + else { + AllocateConstrained(maxWidth - totalAllocated, FIX, totalCounts[FIX], + totalWidths[FIX], PR_TRUE, allocTypes); + return BCW_Wrapup(this, mTableFrame, allocTypes); + } } + // allocate proportional cols up to their min proportional value + if (totalAllocated < maxWidth && totalCounts[MIN_PRO] > 0) { + if (totalAllocated + totalWidths[MIN_PRO] - minWidths[MIN_PRO] <= maxWidth) { + AllocateFully(totalAllocated, allocTypes, MIN_PRO, PR_FALSE); + NS_ASSERTION(totalAllocated <= maxWidth, "over allocated"); + } + else { + AllocateConstrained(maxWidth - totalAllocated, MIN_PRO, totalCounts[MIN_PRO], + totalWidths[MIN_PRO], PR_FALSE, allocTypes); + return BCW_Wrapup(this, mTableFrame, allocTypes); + } + } + + // allocate auto cols, considering even those that are proportional + if (totalAllocated < maxWidth && totalCounts[DES_CON] > 0) { + if (totalAllocated + totalWidths[DES_CON] - minWidths[DES_CON]<= maxWidth) { + AllocateFully(totalAllocated, allocTypes, DES_CON); + NS_ASSERTION(totalAllocated <= maxWidth, "over allocated"); + } + else { + AllocateConstrained(maxWidth - totalAllocated, DES_CON, totalCounts[DES_CON], + totalWidths[DES_CON], PR_FALSE, allocTypes); + return BCW_Wrapup(this, mTableFrame, allocTypes); + } + } + + // if this is a nested table and pass1 reflow, we are done + if (maxWidth == NS_UNCONSTRAINEDSIZE) { + return PR_TRUE; + } + + // allocate the rest unconstrained + PRBool skip0Proportional = totalCounts[DES_CON] > num0Proportional; + if ( (tableIsAutoWidth && (perAdjTableWidth - totalAllocated > 0)) || + (!tableIsAutoWidth && (totalAllocated < maxWidth)) ) { + if (totalCounts[PCT] != mNumCols) { + PRBool onlyAuto = (totalCounts[DES_CON] > 0) && !mIsNavQuirksMode; + for (colX = 0; colX < mNumCols; colX++) { + if (PCT == allocTypes[colX]) { + allocTypes[colX] = -1; + } + else if ((FIX == allocTypes[colX]) && onlyAuto) { + allocTypes[colX] = -1; + } + } + } + if (tableIsAutoWidth) { + AllocateUnconstrained(perAdjTableWidth - totalAllocated, allocTypes, skip0Proportional); + } + else { + AllocateUnconstrained(maxWidth - totalAllocated, allocTypes, skip0Proportional); + } + } + // give the proportional cols the rest up to the max width in quirks mode + else if (tableIsAutoWidth && mIsNavQuirksMode && (totalCounts[MIN_PRO] > 0)) { + for (colX = 0; colX < mNumCols; colX++) { + if (DES_CON != allocTypes[colX]) { + allocTypes[colX] = -1; + } + } + AllocateUnconstrained(maxWidth - totalAllocated, allocTypes, skip0Proportional); + } + + + return BCW_Wrapup(this, mTableFrame, allocTypes); +} + + +// Allocate aWidthType values to all cols available in aIsAllocated +void BasicTableLayoutStrategy::AllocateFully(nscoord& aTotalAllocated, + PRInt32* aAllocTypes, + PRInt32 aWidthType, + PRBool aMarkAllocated) +{ + for (PRInt32 colX = 0; colX < mNumCols; colX++) { + if (-1 != aAllocTypes[colX]) { + continue; + } + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord oldWidth = mTableFrame->GetColumnWidth(colX); + nscoord newWidth = colFrame->GetWidth(aWidthType); + // account for col span overrides with DES_CON and FIX + if (DES_CON == aWidthType) { + newWidth = PR_MAX(newWidth, colFrame->GetWidth(DES_ADJ)); + } + else if (FIX == aWidthType) { + newWidth = PR_MAX(newWidth, colFrame->GetWidth(FIX_ADJ)); + } + else if (PCT == aWidthType) { + newWidth = PR_MAX(newWidth, colFrame->GetWidth(PCT_ADJ)); + } + if (WIDTH_NOT_SET == newWidth) { + continue; + } + if (newWidth > oldWidth) { + mTableFrame->SetColumnWidth(colX, newWidth); + aTotalAllocated += newWidth - oldWidth; + } + if (aMarkAllocated) { + aAllocTypes[colX] = aWidthType; + } + } +} + +void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount, + PRInt32* aAllocTypes, + PRBool aSkip0Proportional) +{ + nscoord divisor = 0; + PRInt32 numAvail = 0; + PRInt32 colX; + for (colX = 0; colX < mNumCols; colX++) { + if (-1 != aAllocTypes[colX]) { + divisor += mTableFrame->GetColumnWidth(colX); + numAvail++; + } + } + for (colX = 0; colX < mNumCols; colX++) { + if (-1 != aAllocTypes[colX]) { + if (aSkip0Proportional) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + if (e0ProportionConstraint == colFrame->GetConstraint()) { + continue; + } + } + nscoord oldWidth = mTableFrame->GetColumnWidth(colX); + float percent = (divisor == 0) + ? (1.0f / ((float)numAvail)) + : ((float)oldWidth) / ((float)divisor); + nscoord addition = NSToCoordRound(((float)aAllocAmount) * percent); + mTableFrame->SetColumnWidth(colX, oldWidth + addition); + } + } +} + +// Determine min, desired, fixed, and proportional sizes for the cols and +// and calculate min/max table width +PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth) +{ + PRBool rv = PR_FALSE; + PRInt32 numRows = mTableFrame->GetRowCount(); + nscoord spacingX = mTableFrame->GetCellSpacingX(); + PRInt32 colX, rowX; + PRUint32 widthX; + mCellSpacingTotal = 0; + + PRInt32 propTotal = 0; // total of numbers of the type 1*, 2*, etc + PRInt32 propTotalMin = 0; + PRInt32 numColsForColsAttr = 0; // Nav Quirks cols attribute for equal width cols + if (NS_STYLE_TABLE_COLS_NONE != mCols) { + numColsForColsAttr = (NS_STYLE_TABLE_COLS_ALL == mCols) ? mNumCols : mCols; + } + + // For every column, determine it's min and desired width based on cell style + // base on cells which do not span cols. Also, determine mCellSpacingTotal + for (colX = 0; colX < mNumCols; colX++) { + nscoord minWidth = 0; + nscoord desWidth = 0; + nscoord fixWidth = WIDTH_NOT_SET; + + // Get column information + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + NS_ASSERTION(nsnull != colFrame, "bad col frame"); + colFrame->SetConstraint(eNoConstraint); + + if (mTableFrame->GetNumCellsOriginatingIn(colX) > 0) { + mCellSpacingTotal += spacingX; + } + + // Scan the cells in the col that have colspan = 1 and find the maximum + // min, desired, and fixed cells. + for (rowX = 0; rowX < numRows; rowX++) { + nsTableCellFrame* cellFrame; + PRBool originates; + PRInt32 colSpan; + mTableFrame->GetCellInfoAt(rowX, colX, cellFrame, originates, colSpan); + // skip cells that don't originate at (rowX, colX); colspans are handled in the + // next pass, row spans don't need to be handled + if (!cellFrame || !originates || (colSpan > 1)) { + continue; + } + // these values include borders and padding + minWidth = PR_MAX(minWidth, cellFrame->GetPass1MaxElementSize().width); + desWidth = PR_MAX(desWidth, cellFrame->GetPass1DesiredSize().width); + // see if the cell has a style width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { + nscoord coordValue = cellPosition->mWidth.GetCoordValue(); + if (coordValue > 0) { // ignore if width == 0 + // need to add padding into fixed width + const nsStyleSpacing* spacing; + cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); + nsMargin paddingMargin; + spacing->CalcPaddingFor(cellFrame, paddingMargin); + nscoord padding = paddingMargin.left + paddingMargin.right; + fixWidth = PR_MAX(fixWidth, coordValue + padding); + fixWidth = PR_MAX(fixWidth, minWidth); + } + } + } + + desWidth = PR_MAX(desWidth, minWidth); + + // cache the computed column info + colFrame->SetWidth(MIN_CON, minWidth); + colFrame->SetWidth(DES_CON, desWidth); + if (fixWidth > 0) { + colFrame->SetWidth(FIX, PR_MAX(fixWidth, minWidth)); + } + + // determine if there is a proportional column either from html4 + // proportional width on a col or Nav Quirks cols attr + if (fixWidth <= 0) { + nscoord proportion = WIDTH_NOT_SET; + const nsStylePosition* colPosition; + colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); + if (eStyleUnit_Proportional == colPosition->mWidth.GetUnit()) { + proportion = colPosition->mWidth.GetIntValue(); + } + else if (colX < numColsForColsAttr) { + proportion = 1; + if ((eStyleUnit_Percent == colPosition->mWidth.GetUnit()) && + (colPosition->mWidth.GetPercentValue() > 0.0f)) { + proportion = WIDTH_NOT_SET; + } + } + if (proportion >= 0) { + colFrame->SetWidth(MIN_PRO, proportion); + if (proportion > 0) { + propTotal += proportion; + colFrame->SetConstraint(eProportionConstraint); + } + else { + colFrame->SetConstraint(e0ProportionConstraint); + // override the desired, proportional widths + nscoord minWidth = colFrame->GetWidth(MIN_CON); + colFrame->SetWidth(DES_CON, minWidth); + colFrame->SetWidth(MIN_PRO, minWidth); + } + } + } + } + if (mCellSpacingTotal > 0) { + mCellSpacingTotal += spacingX; // add last cell spacing on right + } + + // figure the proportional width for porportional cols + if (propTotal > 0) { + nscoord minPropTotal = 0; + nscoord desPropTotal = 0; + // figure the totals of all proportional cols which support every min and desired width + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord colProp = colFrame->GetWidth(MIN_PRO); + if (colProp > 0) { + nscoord minWidth = colFrame->GetWidth(MIN_CON); + nscoord desWidth = colFrame->GetWidth(DES_CON); + minPropTotal = PR_MAX(minPropTotal, NSToCoordRound(((float)propTotal * minWidth) / (float)colProp)); + desPropTotal = PR_MAX(desPropTotal, NSToCoordRound(((float)propTotal * desWidth) / (float)colProp)); + } + } + // store a ratio to allow going from a min to a desired proportional width + if (minPropTotal > 0) { + mMinToDesProportionRatio = ((float)desPropTotal) / ((float)minPropTotal); + } + // figure the cols proportional min width based on the new totals + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord colProp = colFrame->GetWidth(MIN_PRO); + if (colProp > 0) { + nscoord minWidth = colFrame->GetWidth(MIN_CON); + nscoord minProp = NSToCoordRound(((float)colProp * minPropTotal) / (float)propTotal); + colFrame->SetWidth(MIN_PRO, minProp); + colFrame->SetWidth(DES_CON, NSToCoordRound(((float)minProp) * mMinToDesProportionRatio)); + } + } + } + + // For each col, consider the cells originating in it with colspans > 1. + // Adjust the cols that each cell spans if necessary. Iterate backwards + // so that nested and/or overlaping col spans handle the inner ones first, + // ensuring more accurated calculations. + for (colX = mNumCols - 1; colX >= 0; colX--) { + for (rowX = 0; rowX < numRows; rowX++) { + nsTableCellFrame* cellFrame; + PRBool originates; + PRInt32 colSpan; + mTableFrame->GetCellInfoAt(rowX, colX, cellFrame, originates, colSpan); + if (!originates || (1 == colSpan)) { + continue; + } + nscoord cellWidths[NUM_WIDTHS]; + cellWidths[MIN_CON] = cellFrame->GetPass1MaxElementSize().width; + cellWidths[DES_CON] = cellFrame->GetPass1DesiredSize().width; + cellWidths[FIX] = WIDTH_NOT_SET; + // see if the cell has a style width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { + // need to add padding into fixed width + const nsStyleSpacing* spacing; + cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); + nsMargin paddingMargin; + spacing->CalcPaddingFor(cellFrame, paddingMargin); + nscoord padding = paddingMargin.left + paddingMargin.right; + cellWidths[FIX] = cellPosition->mWidth.GetCoordValue() + padding; + cellWidths[FIX] = PR_MAX(cellWidths[FIX], cellWidths[MIN_CON]); + } + + // set MIN_ADJ, DES_ADJ + nscoord spanCellSpacing = 0; + for (widthX = 0; widthX < NUM_MAJOR_WIDTHS; widthX++) { + // skip des if there is a fix + if ((DES_CON == widthX) && (cellWidths[FIX] > 0)) + continue; + nscoord spanTotal = 0; + nscoord divisor = 0; + for (PRInt32 spanX = 0; spanX < colSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); + nscoord colWidth = colFrame->GetWidth(widthX); + // need to get a contribution for every cell + colWidth = PR_MAX(colWidth, colFrame->GetMinWidth()); + spanTotal += colWidth; + // accumulate divisor + if (widthX == FIX) { + colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); + } + else if (widthX == DES_CON) { + nscoord fixWidth = colFrame->GetFixWidth(); + if (fixWidth > 0) { + colWidth = fixWidth; + } + //colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); + } + else if (widthX == MIN_CON) { + colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); + } + divisor += colWidth; + if ((0 == widthX) && (spanX > 0) && (mTableFrame->GetNumCellsOriginatingIn(colX + spanX) > 0)) { + spanCellSpacing += spacingX; + } + } + spanTotal -= spanCellSpacing; + nscoord cellWidth = cellWidths[widthX] - spanCellSpacing; + if ((cellWidth > 0) && !((widthX == MIN_CON) && (cellWidth <= spanTotal))) { + for (spanX = 0; spanX < colSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); + nscoord colWidth = colFrame->GetWidth(widthX); + nscoord minWidth = colFrame->GetMinWidth(); + // accumulate numerator similarly to divisor + colWidth = PR_MAX(colWidth, colFrame->GetMinWidth()); + if (widthX == FIX) { + colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); + } + else if (widthX == DES_CON) { + nscoord fixWidth = colFrame->GetFixWidth(); + if (fixWidth > 0) { + colWidth = fixWidth; + } + //colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); + } + else if (widthX == MIN_CON) { + colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); + } + nscoord colAdjWidth = colFrame->GetWidth(widthX + NUM_MAJOR_WIDTHS); + nscoord newColAdjWidth = (0 >= spanTotal) + ? NSToCoordRound( ((float)cellWidth) / ((float)colSpan) ) + : NSToCoordRound( (((float)colWidth) / ((float)divisor)) * cellWidth); + if ((newColAdjWidth > colAdjWidth) && (newColAdjWidth > 0)) { + newColAdjWidth = PR_MAX(newColAdjWidth, minWidth); + if (FIX != widthX) + colFrame->SetWidth(widthX + NUM_MAJOR_WIDTHS, newColAdjWidth); + // the following ensures that a spanned cell will reach its full desired width + // in an auto table, since allocations are done on fixed cols before auto cols + if (DES_CON == widthX) { + nscoord fixWidth = colFrame->GetFixWidth(); + if ((fixWidth > 0) && (newColAdjWidth > fixWidth) && (newColAdjWidth > 0)) { + colFrame->SetWidth(FIX_ADJ, newColAdjWidth); + } + } + else if (FIX == widthX) { + nscoord desWidth = colFrame->GetDesWidth(); + if ((newColAdjWidth > desWidth) && (newColAdjWidth > 0)) { + colFrame->SetWidth(DES_ADJ, newColAdjWidth); + } + } + } + } + } + } + } + } + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord desAdjWidth = colFrame->GetWidth(DES_ADJ); + nscoord fixWidth = colFrame->GetWidth(FIX); + if ((fixWidth >= 0) && (desAdjWidth > fixWidth)) { + colFrame->SetWidth(FIX, WIDTH_NOT_SET); + } + } + + // Set the col's fixed width if present + // Set the table col width for each col to the content min. + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord fixColWidth = colFrame->GetWidth(FIX); + // use the style width of a col only if the col hasn't gotten a fixed width from any cell + if (fixColWidth <= 0) { + const nsStylePosition* colPosition; + colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); + if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { + fixColWidth = colPosition->mWidth.GetCoordValue(); + if (fixColWidth > 0) { + colFrame->SetWidth(FIX, fixColWidth); + } + } + } + nscoord minWidth = colFrame->GetMinWidth(); + mTableFrame->SetColumnWidth(colX, minWidth); + } + SetMinAndMaxTableContentWidths(); + + return rv; +} + + +// Determine percentage col widths for each col frame +nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, + PRBool aTableIsAutoWidth) +{ + PRInt32 numRows = mTableFrame->GetRowCount(); + nscoord spacingX = mTableFrame->GetCellSpacingX(); + PRInt32 colX, rowX; + nscoord basis = aBasisIn; + // For an auto table, determine the potentially new percent adjusted width based + // on percent cells/cols. + if (aTableIsAutoWidth) { + nscoord fixWidthTotal = 0; + basis = 0; + PRInt32 numPerCols = 0; + for (colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord colBasis = -1; + // Scan the cells in the col + for (rowX = 0; rowX < numRows; rowX++) { + nsTableCellFrame* cellFrame; + PRBool originates; + PRInt32 colSpan; + mTableFrame->GetCellInfoAt(rowX, colX, cellFrame, originates, colSpan); + if (!originates) { // skip cells that don't originate in the col + continue; + } + // see if the cell has a style percent width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { + float percent = cellPosition->mWidth.GetPercentValue(); + colBasis = 0; + if (percent > 0.0f) { + nscoord desWidth = colFrame->GetDesWidth(); + if (colSpan > 1) { // sum up the DES_ADJ widths of the spanned cols + for (PRInt32 spanX = 1; spanX < colSpan; spanX++) { + nsTableColFrame* spanFrame = mTableFrame->GetColFrame(colX + spanX); + desWidth += spanFrame->GetWidth(DES_ADJ); + } + } + colBasis = NSToCoordRound((float)desWidth / percent); + } + } + } + if (-1 == colBasis) { + // see if the col has a style percent width specified + const nsStylePosition* colPosition; + colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); + if (eStyleUnit_Percent == colPosition->mWidth.GetUnit()) { + float percent = colPosition->mWidth.GetPercentValue(); + colBasis = 0; + if (percent > 0.0f) { + nscoord desWidth = colFrame->GetDesWidth(); + colBasis = NSToCoordRound((float)desWidth / percent); + } + } + } + basis = PR_MAX(basis, colBasis); + if (colBasis >= 0) { + numPerCols++; + } + fixWidthTotal += colFrame->GetFixWidth(); + } // end for (colX .. + // If there is only one col and it is % based, it won't affect anything + if ((1 == mNumCols) && (mNumCols == numPerCols)) { + return 0; + } + basis = PR_MAX(basis, fixWidthTotal); + basis = PR_MIN(basis, aBasisIn); + } + + nscoord colPctTotal = 0; + nscoord* colPcts = new nscoord[mNumCols]; + if (!colPcts) return 0; - // second, fix up tables where column width attributes give us a table that is too wide or too narrow - nscoord computedWidth = colInset; - for (PRInt32 i = 0; i < mNumCols; i++) { - computedWidth += mTableFrame->GetColumnWidth(i) + colInset; - } - if (computedWidth= 0; colX--) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord maxColPctWidth = WIDTH_NOT_SET; + float maxColPct = 0.0f; + colPcts[colX] = 0; + + // Scan the cells in the col that have colspan = 1; assign PER widths + for (rowX = 0; rowX < numRows; rowX++) { + nsTableCellFrame* cellFrame; + PRBool originates; + PRInt32 colSpan; + mTableFrame->GetCellInfoAt(rowX, colX, cellFrame, originates, colSpan); + // skip cells that don't originate at (rowX, colX); colspans are handled in the + // next pass, row spans don't need to be handled + if (!cellFrame || !originates || (colSpan > 1)) { + continue; + } + // see if the cell has a style percent width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { + float percent = cellPosition->mWidth.GetPercentValue(); + if (percent > maxColPct) { + maxColPct = percent; + maxColPctWidth = NSToCoordRound( ((float)basis) * maxColPct ); + if (!mIsNavQuirksMode) { + // need to add padding + const nsStyleSpacing* spacing; + cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); + nsMargin paddingMargin; + spacing->CalcPaddingFor(cellFrame, paddingMargin); + maxColPctWidth += paddingMargin.left + paddingMargin.right; + } + } + } } - } - else if (computedWidth>aMaxWidth) { - // then shrink the table width because its too wide - AdjustTableThatIsTooWide(computedWidth, aMaxWidth, PR_FALSE); - } - - - // finally, assign a width to proportional-width columns - if (nsnull!=proportionalColumnsList) { - // first, figure out the amount of space per slice - nscoord widthRemaining = aMaxWidth - tableWidth; - nscoord widthPerSlice = widthRemaining / totalSlices; - PRInt32 numSpecifiedProportionalColumns = proportionalColumnsList->Count(); - for (PRInt32 i = 0; i < numSpecifiedProportionalColumns; i++) { - ProportionalColumnLayoutStruct* info = - (ProportionalColumnLayoutStruct *)(proportionalColumnsList->ElementAt(i)); - if (PR_TRUE == equalWidthColumns && 0 != maxOfAllMinColWidths) { - TDBG_SDD(" EqualColWidths specified and some column couldn't fit, so setting col %d width to %d\n", - info->mColIndex, maxOfAllMinColWidths); - mTableFrame->SetColumnWidth(info->mColIndex, maxOfAllMinColWidths); + if (WIDTH_NOT_SET == maxColPctWidth) { + // see if the col has a style percent width specified + const nsStylePosition* colPosition; + colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); + if (eStyleUnit_Percent == colPosition->mWidth.GetUnit()) { + maxColPct = colPosition->mWidth.GetPercentValue(); + maxColPctWidth = NSToCoordRound( ((float)basis) * maxColPct ); + } + } + // conflicting pct/fixed widths are recorded. Nav 4.x may be changing the + // fixed width value if it exceeds the pct value and not recording the pct + // value. This is not being done and IE5 doesn't do it either. + if (maxColPctWidth > 0) { + nscoord minWidth = colFrame->GetMinWidth(); + if (minWidth > maxColPctWidth) { + maxColPctWidth = minWidth; + colPcts[colX] = NSToCoordRound( 100.0f * ((float)maxColPctWidth) / ((float)basis) ); } else { - // compute the requested proportional width - nscoord computedColWidth = info->mProportion * widthPerSlice; - // verify that the computed width is at least the minimum width - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(info->mColIndex, colFrame); - nscoord minColWidth = colFrame->GetMinColWidth(); - computedColWidth = PR_MAX(computedColWidth, minColWidth); - mTableFrame->SetColumnWidth(info->mColIndex, computedColWidth); - TDBG_SDDDD(" 4 proportion: col %d given %d proportion of remaining space %d, set to width = %d\n", - info->mColIndex, info->mProportion, widthRemaining, computedColWidth); + colPcts[colX] = NSToCoordRound(maxColPct * 100.0f); } - delete info; + colFrame->SetWidth(PCT, maxColPctWidth); + colPctTotal += colPcts[colX]; } - delete proportionalColumnsList; } - // clean up - if (nsnull != spanList) { - TDBG_S("BTLS::BCTConstrained...space leak, span list not empty"); - delete spanList; + // For each col, consider the cells originating in it with colspans > 1. + // Adjust the cols that each cell spans if necessary. + for (colX = 0; colX < mNumCols; colX++) { + for (rowX = 0; rowX < numRows; rowX++) { + nsTableCellFrame* cellFrame; + PRBool originates; + PRInt32 colSpan; + mTableFrame->GetCellInfoAt(rowX, colX, cellFrame, originates, colSpan); + if (!originates || (1 == colSpan)) { + continue; + } + nscoord cellPctWidth = WIDTH_NOT_SET; + // see if the cell has a style percentage width specified + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + float cellPct = 0.0f; + if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) { + cellPct = cellPosition->mWidth.GetPercentValue(); + cellPctWidth = NSToCoordRound( ((float)basis) * cellPct ); + if (!mIsNavQuirksMode) { + // need to add padding + const nsStyleSpacing* spacing; + cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); + nsMargin paddingMargin; + spacing->CalcPaddingFor(cellFrame, paddingMargin); + cellPctWidth += paddingMargin.left + paddingMargin.right; + } + } + if (cellPctWidth > 0) { + nscoord spanCellSpacing = 0; + nscoord spanTotal = 0; + nscoord colPctWidthTotal = 0; + // accumulate the spanTotal as the max of MIN, DES, FIX, PCT + for (PRInt32 spanX = 0; spanX < colSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); + nscoord colPctWidth = colFrame->GetWidth(PCT); + if (colPctWidth > 0) { // skip pct cols + colPctWidthTotal += colPctWidth; + continue; + } + nscoord colWidth = PR_MAX(colFrame->GetMinWidth(), colFrame->GetFixWidth()); + colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); + //colWidth = PR_MAX(colWidth, colFrame->GetPctWidth()); + spanTotal += colWidth; + if ((spanX > 0) && (mTableFrame->GetNumCellsOriginatingIn(colX + spanX) > 0)) { + spanCellSpacing += spacingX; + } + } + cellPctWidth += spanCellSpacing; // add it back in since it was subtracted from aBasisIn + if (cellPctWidth <= 0) { + continue; + } + if (colPctWidthTotal < cellPctWidth) { + // record the percent contributions for the spanned cols + for (spanX = 0; spanX < colSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); + if (colFrame->GetWidth(PCT) > 0) { // skip pct cols + continue; + } + nscoord minWidth = colFrame->GetMinWidth(); + nscoord colWidth = PR_MAX(minWidth, colFrame->GetFixWidth()); + colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); + float colPctAdj = (0 == spanTotal) + ? cellPctWidth / ((float) colSpan) + : cellPct * ((float)colWidth) / (float)spanTotal; + if (colPctAdj > 0) { + nscoord colPctAdjWidth = colFrame->GetWidth(PCT_ADJ); + nscoord newColPctAdjWidth = NSToCoordRound(colPctAdj * (float)basis); + if (newColPctAdjWidth > colPctAdjWidth) { + if (colPctAdjWidth > 0) { // remove its contribution + colPctTotal -= colPcts[colX + spanX]; + } + if (minWidth > newColPctAdjWidth) { + newColPctAdjWidth = minWidth; + colPcts[colX + spanX] = NSToCoordRound( 100.0f * ((float)newColPctAdjWidth) / ((float)basis) ); + } + else { + colPcts[colX + spanX] = NSToCoordRound( 100.0f * colPctAdj ); + } + colFrame->SetWidth(PCT_ADJ, newColPctAdjWidth); + colPctTotal += colPcts[colX + spanX]; + } + } + } + } + } + } // end for (rowX .. + } // end for (colX .. + + // if the percent total went over 100%, adjustments need to be made to right most cols + if (colPctTotal > 100) { + for (colX = mNumCols - 1; colX >= 0; colX--) { + if (colPcts[colX] > 0) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + nscoord fixWidth = colFrame->GetFixWidth(); + nscoord pctWidth = colFrame->GetWidth(PCT); + nscoord pctAdjWidth = colFrame->GetWidth(PCT_ADJ); + nscoord newPct = colPcts[colX] - (colPctTotal - 100); + if (newPct > 0) { // this col has enough percent alloc to handle it + nscoord newPctWidth = NSToCoordRound( ((float)basis) * ((float)newPct) / 100.0f ); + newPctWidth = PR_MAX(newPctWidth, colFrame->GetMinWidth()); + // since we don't care which one contributed, set both + colFrame->SetWidth(PCT, newPctWidth); + colFrame->SetWidth(PCT_ADJ, newPctWidth); + break; + } + else { // this col cannot handle all the reduction, reduce it down to zero + colFrame->SetWidth(PCT, WIDTH_NOT_SET); + colFrame->SetWidth(PCT_ADJ, WIDTH_NOT_SET); + colPctTotal -= colPcts[colX]; + if (colPctTotal <= 100) { + break; + } + } + } + } } - return result; + delete [] colPcts; + return basis; } +void BasicTableLayoutStrategy::SetMinAndMaxTableContentWidths() +{ + mMinTableContentWidth = 0; + mMaxTableContentWidth = 0; + + nscoord spacingX = mTableFrame->GetCellSpacingX(); + for (PRInt32 colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + mMinTableContentWidth += colFrame->GetMinWidth(); + mMaxTableContentWidth += colFrame->GetDesWidth(); + if (mTableFrame->GetNumCellsOriginatingIn(colX) > 0) { + mMaxTableContentWidth += spacingX; + mMinTableContentWidth += spacingX; + } + } + // if it is not a degenerate table, add the last spacing on the right + if (mMinTableContentWidth > 0) { + mMinTableContentWidth += spacingX; + mMaxTableContentWidth += spacingX; + } +} + +// calculate totals by width type. A width type of a higher precedence will +// preclude one of a lower precedence for all types except MIN_CON +void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, + PRInt32* aTotalCounts, + PRInt32* aTotalWidths, + PRInt32* aMinWidths, + PRInt32& a0ProportionalCount) +{ + //mTableFrame->Dump(PR_TRUE, PR_FALSE); + aCellSpacing = 0; + for (PRInt32 widthX = 0; widthX < NUM_WIDTHS; widthX++) { + aTotalCounts[widthX] = 0; + aTotalWidths[widthX] = 0; + aMinWidths[widthX] = 0; + } + a0ProportionalCount = 0; + + nscoord spacingX = mTableFrame->GetCellSpacingX(); + for (PRInt32 colX = 0; colX < mNumCols; colX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + if (mTableFrame->GetNumCellsOriginatingIn(colX) > 0) { + aCellSpacing += spacingX; + } + nscoord minCol = colFrame->GetMinWidth(); + aTotalCounts[MIN_CON]++; + aTotalWidths[MIN_CON] += minCol; + + if (e0ProportionConstraint == colFrame->GetConstraint()) { + a0ProportionalCount++; + } + + nscoord pctCol = colFrame->GetPctWidth(); + nscoord fixCol = colFrame->GetFixWidth(); + // pct wins in conflict with fix + if (pctCol > 0) { + aTotalCounts[PCT]++; + aTotalWidths[PCT] += pctCol; + aMinWidths[PCT] += minCol; + continue; + } + else if (fixCol > 0) { + aTotalCounts[FIX]++; + aTotalWidths[FIX] += fixCol; + aMinWidths[FIX] += minCol; + continue; + } + + if (eProportionConstraint == colFrame->GetConstraint()) { + nscoord minProp = colFrame->GetWidth(MIN_PRO); + aTotalCounts[MIN_PRO]++; + aTotalWidths[MIN_PRO] += minProp; + aTotalCounts[DES_CON]++; + aTotalWidths[DES_CON] += NSToCoordRound(((float)minProp) * mMinToDesProportionRatio); + aMinWidths[MIN_PRO] += minCol; + aMinWidths[DES_CON] += minProp; + } + else { + nscoord desCol = colFrame->GetDesWidth(); + aTotalCounts[DES_CON]++; + aTotalWidths[DES_CON] += desCol; + aMinWidths[DES_CON] += minCol; + } + } + // if it is not a degenerate table, add the last spacing on the right + if (mNumCols > 0) { + aCellSpacing += spacingX; + } +} + + + + struct nsColInfo { nsColInfo(nsTableColFrame* aFrame, PRInt32 aIndex, PRInt32 aMinWidth, PRInt32 aWidth, - PRInt32 aMaxEffWidth, PRInt32 aMaxWidth) : mFrame(aFrame), mIndex(aIndex), mMinWidth(aMinWidth), - mWidth(aWidth), mMaxEffWidth(aMaxEffWidth), mMaxWidth(aMaxWidth), mWeight(0) + mWidth(aWidth), mMaxWidth(aMaxWidth), mWeight(0) {} nsTableColFrame* mFrame; PRInt32 mIndex; PRInt32 mMinWidth; PRInt32 mWidth; - PRInt32 mMaxEffWidth; PRInt32 mMaxWidth; float mWeight; }; void -DRS_Wrapup(nsTableFrame* aTableFrame, +AC_Wrapup(nsTableFrame* aTableFrame, PRInt32 aNumItems, - nsColInfo** aColInfo) + nsColInfo** aColInfo, + PRBool aAbort = PR_FALSE) { - for (int i = 0; i < aNumItems; i++) { - aTableFrame->SetColumnWidth(aColInfo[i]->mIndex, aColInfo[i]->mWidth); - delete aColInfo[i]; + if (aColInfo) { + for (PRInt32 i = 0; i < aNumItems; i++) { + if (aColInfo[i]) { + if (!aAbort) { + aTableFrame->SetColumnWidth(aColInfo[i]->mIndex, aColInfo[i]->mWidth); + } + delete aColInfo[i]; + } + } + delete [] aColInfo; } - delete [] aColInfo; } void -DRS_Increase(PRInt32 aNumAutoCols, +AC_Increase(PRInt32 aNumAutoCols, nsColInfo** aColInfo, PRInt32 aDivisor, - PRBool aDontGoOverMax, PRInt32& aAvailWidth) { for (PRInt32 i = 0; i < aNumAutoCols; i++) { if ((aAvailWidth <= 0) || (aDivisor <= 0)) { break; } - //float percent = ((float)aColInfo[i]->mMaxEffWidth) / (float)aDivisor; float percent = ((float)aColInfo[i]->mMaxWidth) / (float)aDivisor; - //aDivisor -= aColInfo[i]->mWidth; aDivisor -= aColInfo[i]->mMaxWidth; nscoord addition = PR_MIN(aAvailWidth, NSToCoordRound(((float)(aAvailWidth)) * percent)); - if (aDontGoOverMax) { - addition = PR_MIN(addition, aColInfo[i]->mMaxWidth - aColInfo[i]->mWidth); - } + addition = PR_MIN(addition, aColInfo[i]->mMaxWidth - aColInfo[i]->mWidth); // don't let the total additions exceed what is available if (i == aNumAutoCols - 1) { addition = PR_MIN(addition, aAvailWidth); @@ -2132,7 +1080,7 @@ DRS_Increase(PRInt32 aNumAutoCols, } void -DRS_Decrease(PRInt32 aNumAutoCols, +AC_Decrease(PRInt32 aNumAutoCols, nsColInfo** aColInfo, PRInt32 aDivisor, PRInt32& aExcess) @@ -2141,9 +1089,7 @@ DRS_Decrease(PRInt32 aNumAutoCols, if ((aExcess <= 0) || (aDivisor <= 0)) { break; } - //float percent = ((float)aColInfo[i]->mMaxEffWidth) / (float)aDivisor; float percent = ((float)aColInfo[i]->mMaxWidth) / (float)aDivisor; - //aDivisor -= aColInfo[i]->mWidth; aDivisor -= aColInfo[i]->mMaxWidth; nscoord reduction = PR_MIN(aExcess, NSToCoordRound(((float)(aExcess)) * percent)); // don't go over the col min @@ -2159,7 +1105,7 @@ DRS_Decrease(PRInt32 aNumAutoCols, void -DSR_Sort(nsColInfo** aColInfo, PRInt32 aNumCols) +AC_Sort(nsColInfo** aColInfo, PRInt32 aNumCols) { // sort the cols based on the Weight for (PRInt32 j = aNumCols - 1; j > 0; j--) { @@ -2173,54 +1119,71 @@ DSR_Sort(nsColInfo** aColInfo, PRInt32 aNumCols) } } -// Take the remaining space in the table and distribute it to the auto-width cols -// in the table. -void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth, - nscoord& aComputedTableWidth, - PRBool aTableIsAutoWidth) +// this assumes that the table has set the width for each col to be its min +void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, + PRInt32 aWidthType, + PRInt32 aNumConstrainedCols, + PRInt32 aSumMaxConstraints, + PRBool aStartAtMin, + PRInt32* aAllocTypes) { - // availWidth is the difference between the total available width and the - // amount of space already assigned. - nscoord availWidth = PR_MAX(aTableSpecifiedWidth - aComputedTableWidth, 0); - TDBG_SDD(" aTableSpecifiedWidth specified as %d, availWidth is = %d\n", aTableSpecifiedWidth, availWidth); - if ((0 == availWidth) || (aTableSpecifiedWidth <= 0)) { + if ((0 == aAvailWidth) || (aWidthType < 0) || (aWidthType >= NUM_WIDTHS) || + (aNumConstrainedCols <= 0) || (aSumMaxConstraints <= 0)) { + NS_ASSERTION(PR_TRUE, "invalid args to AllocateConstrained"); return; } - // Get the auto width cols. Only they get adjusted. - PRInt32 numAutoCols = 0; - PRInt32* autoCols = nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoCols, autoCols); - if (0 == numAutoCols) { + // allocate storage for the affected cols. Only they get adjusted. + nsColInfo** colInfo = new nsColInfo*[aNumConstrainedCols]; + if (!colInfo) { return; } - nsColInfo** colInfo = new nsColInfo*[numAutoCols]; - - nscoord totalDivisor = 0; - nscoord totalAutoWidthGiven = 0; + PRInt32 maxMinDiff = 0; + PRInt32 constrColX = 0; + // set the col info entries for each constrained col + for (PRInt32 colX = 0; colX < mNumCols; colX++) { + if (-1 != aAllocTypes[colX]) { + continue; + } + nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); + //nscoord minWidth = colFrame->GetMinWidth(); + nscoord minWidth = mTableFrame->GetColumnWidth(colX); + nscoord maxWidth = colFrame->GetWidth(aWidthType); + if (DES_CON == aWidthType) { + maxWidth = PR_MAX(maxWidth, colFrame->GetWidth(DES_ADJ)); + } + else if (FIX == aWidthType) { + maxWidth = PR_MAX(maxWidth, colFrame->GetWidth(FIX_ADJ)); + } + else if (PCT == aWidthType) { + maxWidth = PR_MAX(maxWidth, colFrame->GetWidth(PCT_ADJ)); + } + if (maxWidth <= 0) { + continue; + } + if (constrColX >= aNumConstrainedCols) { + NS_ASSERTION(PR_FALSE, "AllocateConstrained called incorrectly"); + break; + } + maxWidth = PR_MAX(maxWidth, minWidth); + maxMinDiff += maxWidth - minWidth; + nscoord startWidth = (aStartAtMin) ? minWidth : maxWidth; + colInfo[constrColX++] = new nsColInfo(colFrame, colX, minWidth, startWidth, maxWidth); + if (!colInfo[constrColX]) { + AC_Wrapup(mTableFrame, aNumConstrainedCols, colInfo, PR_TRUE); + return; + } + aAllocTypes[colX] = aWidthType; + } + if (constrColX < aNumConstrainedCols) { + // some of the constrainted cols might have been 0 and skipped + aNumConstrainedCols = constrColX; + } PRInt32 i; - - // start out by giving each col its max effective width (or adj width if it is greater) - // for standard mode and its min width for nav quirks mode - for (i = 0; i < numAutoCols; i++) { - PRInt32 colIndex = autoCols[i]; - nsTableColFrame* colFrame = mTableFrame->GetColFrame(autoCols[i]); - nscoord origWidth = mTableFrame->GetColumnWidth(autoCols[i]); - nscoord minWidth = PR_MAX(colFrame->GetAdjustedMinColWidth(), origWidth); - nscoord maxEffWidth = PR_MAX(colFrame->GetEffectiveMaxColWidth(), minWidth); - nscoord maxWidth = colFrame->GetMaxColWidth(); - nscoord startWidth = (mIsNavQuirksMode) ? minWidth : maxWidth; - colInfo[i] = new nsColInfo(colFrame, autoCols[i], minWidth, startWidth, maxEffWidth, maxWidth); -// totalDivisor += maxEffWidth; - totalDivisor += maxWidth; - totalAutoWidthGiven += startWidth - origWidth; - } - - availWidth = aTableSpecifiedWidth - aComputedTableWidth - totalAutoWidthGiven; - - if (availWidth >= 0) { // have more space to allocate - for (i = 0; i < numAutoCols; i++) { - // the weight here is a relative metric for determining when cols reach their max. + if (aStartAtMin) { // allocate extra space + nscoord availWidth = aAvailWidth; + for (i = 0; i < aNumConstrainedCols; i++) { + // the weight here is a relative metric for determining when cols reach their max constraint. // A col with a larger weight will reach its max before one with a smaller value. nscoord delta = colInfo[i]->mMaxWidth - colInfo[i]->mWidth; colInfo[i]->mWeight = (delta <= 0) @@ -2232,19 +1195,20 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified // weights will get their max earlier than ones with lower weights // This is an innefficient bubble sort, but unless there are an unlikely // large number of cols, it is not an issue. - DSR_Sort(colInfo, numAutoCols); + AC_Sort(colInfo, aNumConstrainedCols); // compute the proportion to be added to each column, don't go beyond the col's // max. This algorithm assumes that the Weight works as stated above - DRS_Increase(numAutoCols, colInfo, totalDivisor, PR_TRUE, availWidth); - // if every col got its max and there is more to go, allocate a 2nd time - if (!aTableIsAutoWidth && (availWidth > 0)) { - DRS_Increase(numAutoCols, colInfo, totalDivisor, PR_FALSE, availWidth); - } - aComputedTableWidth = aTableSpecifiedWidth - availWidth; + AC_Increase(aNumConstrainedCols, colInfo, aSumMaxConstraints, availWidth); } - else { // reduce each col width if appropriate - for (i = 0; i < numAutoCols; i++) { + else { // reduce each col width + nscoord reduceWidth = maxMinDiff - aAvailWidth; + if (reduceWidth < 0) { + NS_ASSERTION(PR_TRUE, "AllocateConstrained called incorrectly"); + AC_Wrapup(mTableFrame, aNumConstrainedCols, colInfo, PR_TRUE); + return; + } + for (i = 0; i < aNumConstrainedCols; i++) { // the weight here is a relative metric for determining when cols reach their min. // A col with a larger weight will reach its min before one with a smaller value. nscoord delta = colInfo[i]->mWidth - colInfo[i]->mMinWidth; @@ -2254,301 +1218,15 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified } // sort the cols based on the Weight - DSR_Sort(colInfo, numAutoCols); + AC_Sort(colInfo, aNumConstrainedCols); // compute the proportion to be subtracted from each column, don't go beyond // the col's min. This algorithm assumes that the Weight works as stated above - PRInt32 totalExcessGiven = -availWidth; - DRS_Decrease(numAutoCols, colInfo, totalDivisor, totalExcessGiven); - aComputedTableWidth = aTableSpecifiedWidth + totalExcessGiven; + AC_Decrease(aNumConstrainedCols, colInfo, aSumMaxConstraints, reduceWidth); } - DRS_Wrapup(mTableFrame, numAutoCols, colInfo); - TDBG_WIDTHS4("at end of DistributeRemainingSpace: ",PR_FALSE,PR_FALSE); + AC_Wrapup(mTableFrame, aNumConstrainedCols, colInfo); } -#if 0 -void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth, - nscoord& aComputedTableWidth, - PRBool aTableIsAutoWidth) -{ - // availWidth is the difference between the total available width and the - // amount of space already assigned, assuming auto col widths were assigned 0. - nscoord availWidth = PR_MAX(aTableSpecifiedWidth - aComputedTableWidth, 0); - TDBG_SDD(" aTableSpecifiedWidth specified as %d, availWidth is = %d\n", aTableSpecifiedWidth, availWidth); - if ((0 == availWidth) || (aTableSpecifiedWidth <= 0)) { - return; - } - nscoord sumOfMinWidths = 0; // sum of min widths of each auto column - nscoord startingComputedTableWidth = aComputedTableWidth; // remember this so we can see if we're making any progress - TDBG_SDD("DistributeRemainingSpace: fixed width %d > computed table width %d\n", - aTableSpecifiedWidth, aComputedTableWidth); - // if there are auto-sized columns, give them the extra space - PRInt32 numAutoColumns = 0; - PRInt32* autoColumns = nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); - if (0 == numAutoColumns) { - return; - } - nscoord totalResizeColWidth = 0; - // populate an array of col info for cols that qualify for being increased in width - PRInt32 numResizeCols = 0; - nsColInfo** resizeCols = new nsColInfo*[numAutoColumns]; - PRInt32 i; - for (i = 0; i < numAutoColumns; i++) { - PRInt32 colIndex = autoColumns[i]; - nsTableColFrame* colFrame = mTableFrame->GetColFrame(autoColumns[i]); - nscoord startingColWidth = mTableFrame->GetColumnWidth(colIndex); - nscoord maxColWidth = colFrame->GetMaxColWidth(); - if (0 == maxColWidth) - maxColWidth = startingColWidth; - totalResizeColWidth += maxColWidth; - // the maximizeFactor is a relative metric for determining when cols reach their max. - // A col with a smaller value will reach its max before one with a larger value. - nscoord delta = maxColWidth - startingColWidth; - float maximizeFactor = (0 >= delta) - ? 1000000 // cols which have already reached their max get a large value - : ((float)maxColWidth) / ((float)(maxColWidth - startingColWidth)); - resizeCols[numResizeCols] = new nsColInfo(colFrame, colIndex, startingColWidth, - maximizeFactor); - numResizeCols++; - } - if (totalResizeColWidth <= 0) { - NS_ASSERTION(PR_TRUE, "need to handle this case"); - DistributeRemainingSpaceCleanup(numResizeCols, resizeCols); - return; - } - - // sort the cols based on the maximizeFactor so that in one pass cols that reach their - // max earlier will get their max earlier and allow the other cols to reach their max. - // This is an innefficient bubble sort, but unless there are an unlikely large number of - // cols, it is not an issue. - for (int j = numResizeCols - 1; j > 0; j--) { - for (i = 0; i < j; i++) { - if (resizeCols[i]->mMaximizeFactor < resizeCols[i+1]->mMaximizeFactor) { // swap them - nsColInfo* save = resizeCols[i]; - resizeCols[i] = resizeCols[i+1]; - resizeCols[i+1] = save; - } - } - } - - - // compute the proportion to be added to each column, don't go beyond the col's max - // at this stage - PRInt32 totalResizeColWidthRemaining = totalResizeColWidth; - for (i = 0; i < numResizeCols; i++) { - if ((availWidth <= 0) || (totalResizeColWidthRemaining <= 0)) { - break; - } - nsTableColFrame* colFrame = resizeCols[i]->mColFrame; - nscoord startingColWidth = resizeCols[i]->mColWidth; - nscoord maxColWidth = colFrame->GetMaxColWidth(); - float percent = ((float)maxColWidth) / (float)totalResizeColWidthRemaining; - nscoord delta = PR_MIN(availWidth, NSToCoordRound(((float)(availWidth)) * percent)); - // don't go over the col max right now - nscoord excess = (startingColWidth + delta) - maxColWidth; - if (excess > 0) { - delta -= excess; - } - resizeCols[i]->mColWidth += delta; - availWidth -= delta; - totalResizeColWidthRemaining -= maxColWidth; - mTableFrame->SetColumnWidth(resizeCols[i]->mColIndex, resizeCols[i]->mColWidth); - TDBG_SDDDD(" DSR-1 colX=%d went from %d to %d based on percent=%d \n", resizeCols[i]->mColIndex, - startingColWidth, resizeCols[i]->mColWidth, (nscoord)((float)100*percent)); - } - // Auto width tables have reached their max at this point. If there is any remaining space - // in a fixed width table, allocate it to the cols based on max width, - if ((availWidth > 0) && (PR_FALSE == aTableIsAutoWidth)) { - for (i = 0; i < numResizeCols; i++) { - if (availWidth <= 0) { - break; - } - nsTableColFrame* colFrame = resizeCols[i]->mColFrame; - nscoord startingColWidth = resizeCols[i]->mColWidth; - nscoord maxColWidth = colFrame->GetMaxColWidth(); - // if we actually have room to distribute, do it here - float percent = ((float)maxColWidth) / (float)totalResizeColWidth; - nscoord delta = PR_MIN(availWidth, NSToCoordRound(((float)(availWidth)) * percent)); - nscoord newWidth = resizeCols[i]->mColWidth + delta; - mTableFrame->SetColumnWidth(resizeCols[i]->mColIndex, newWidth); - availWidth -= delta; - TDBG_SDDDD(" DSR-2 colX=%d went from %d to %d based on percent=%d \n", resizeCols[i]->mColIndex, - startingColWidth, resizeCols[i]->mColWidth, (nscoord)((float)100*percent)); - } - } - aComputedTableWidth = aTableSpecifiedWidth - availWidth; - DistributeRemainingSpaceCleanup(numResizeCols, resizeCols); - TDBG_WIDTHS4("at end of DistributeRemainingSpace: ",PR_FALSE,PR_FALSE); -} -#endif - -void BasicTableLayoutStrategy::AdjustTableThatIsTooWide(nscoord aComputedWidth, - nscoord aTableWidth, - PRBool aShrinkFixedCols) -{ - TDBG_WIDTHS4("before AdjustTableThatIsTooWide: ",PR_FALSE,PR_FALSE); - - PRInt32 numFixedColumns = 0; - PRInt32* fixedColumns = nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); - PRInt32 numAutoColumns = 0; - PRInt32* autoColumns = nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); - nscoord excess = aComputedWidth - aTableWidth; - nscoord minDiff; // the smallest non-zero delta between a column's current width and its min width - PRInt32* colsToShrink = new PRInt32[mNumCols]; - // while there is still extra computed space in the table - while (0 < excess) { - // reinit state variables - PRInt32 colIndex; - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - colsToShrink[colIndex] = 0; - } - minDiff = 0; - - // determine what columns we can remove width from - PRInt32 numColsToShrink = 0; - PRBool shrinkAutoOnly = PR_TRUE; - PRBool keepLooking = PR_TRUE; - while (PR_TRUE == keepLooking) { - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - nscoord currentColWidth = mTableFrame->GetColumnWidth(colIndex); - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(colIndex, colFrame); - nscoord minColWidth = colFrame->GetAdjustedMinColWidth(); - if (currentColWidth == minColWidth) { - continue; - } - if ((PR_FALSE==aShrinkFixedCols) && - (PR_TRUE==IsColumnInList(colIndex, fixedColumns, numFixedColumns))) { - continue; - } - if ((PR_TRUE==shrinkAutoOnly) && - (PR_FALSE==IsColumnInList(colIndex, autoColumns, numAutoColumns))) { - continue; - } - colsToShrink[numColsToShrink] = colIndex; - numColsToShrink++; - nscoord diff = currentColWidth - minColWidth; - if ((0 == minDiff) || (diff < minDiff)) { - minDiff = diff; - } - } - if (PR_FALSE == shrinkAutoOnly) { - keepLooking = PR_FALSE; // we've looked everywhere, so bail. this breaks us out of the loop - } - if (0 != numColsToShrink) { - keepLooking = PR_FALSE; // we found at least one column to shrink, so bail. this breaks us out of the loop - } - shrinkAutoOnly = PR_FALSE;// this guarantees we'll go through this loop only one more time - } - // if there are no columns we can remove space from, we're done - if (0 == numColsToShrink) { - break; - } - - // determine the amount to remove from each column - nscoord excessPerColumn; - if (excess < numColsToShrink) { - excessPerColumn = 1; - } - else { - excessPerColumn = excess / numColsToShrink; // guess we can remove as much as we want - } - if (excessPerColumn > minDiff) { // then adjust for minimum col widths - excessPerColumn = minDiff; - } - // remove excessPerColumn from every column we've determined we can remove width from - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - if ((PR_TRUE == IsColumnInList(colIndex, colsToShrink, numColsToShrink))) { - nscoord colWidth = mTableFrame->GetColumnWidth(colIndex); - colWidth -= excessPerColumn; - mTableFrame->SetColumnWidth(colIndex, colWidth); - excess -= excessPerColumn; - if (0 == excess) { - break; - } - } - } - } // end while (0 < excess) - TDBG_WIDTHS4("after AdjustTableThatIsTooWide: ",PR_TRUE,aShrinkFixedCols); - - delete [] colsToShrink; - - // deal with any excess left over - if ((PR_FALSE == aShrinkFixedCols) && (0 != excess)) { - // if there's any excess left, we know we've shrunk every non-fixed column to its min - // so we have to shrink fixed width columns if possible - AdjustTableThatIsTooWide(aComputedWidth, aTableWidth, PR_TRUE); - } - // otherwise we've shrunk the table to its min, and that's all we can do -} - - -void BasicTableLayoutStrategy::AdjustTableThatIsTooNarrow(nscoord aComputedWidth, - nscoord aTableWidth) -{ - TDBG_WIDTHS4("before AdjustTableThatIsTooNarrow: ",PR_FALSE,PR_FALSE); - - PRInt32 numFixedColumns=0; - PRInt32* fixedColumns=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); - nscoord excess = aTableWidth - aComputedWidth; - while (0 < excess) { - PRInt32 colIndex; - PRInt32* colsToGrow = new PRInt32[mNumCols]; - // determine what columns we can take add width to - PRInt32 numColsToGrow = 0; - PRBool expandFixedCols = PRBool(mNumCols == numFixedColumns); - for (colIndex = 0; colIndex < mNumCols; colIndex++) { - if ((PR_FALSE == expandFixedCols) && - (PR_TRUE == IsColumnInList(colIndex, fixedColumns, numFixedColumns))) { - // skip fixed-width cells if we're told to - continue; - } - if (PR_TRUE == ColIsSpecifiedAsMinimumWidth(colIndex)) { - // skip columns that are forced by their attributes to be their minimum width - continue; - } - colsToGrow[numColsToGrow] = colIndex; - numColsToGrow++; - } - if (0 != numColsToGrow) { - nscoord excessPerColumn; - if (excessGetColFrame(colIndex); - nscoord colWidth = mTableFrame->GetColumnWidth(colIndex); - colWidth += excessPerColumn; - if (colWidth > colFrame->GetMinColWidth()) { - excess -= excessPerColumn; - mTableFrame->SetColumnWidth(colIndex, colWidth); - } - else { - excess -= mTableFrame->GetColumnWidth(colIndex) - colFrame->GetMinColWidth(); - mTableFrame->SetColumnWidth(colIndex, colFrame->GetMinColWidth()); - } - if (0 >= excess) { - break; - } - } - } - } - delete [] colsToGrow; - if (0 == numColsToGrow) { - break; - } - } // end while (0 < excess) - - TDBG_WIDTHS4("after AdjustTableThatIsTooNarrow: ",PR_FALSE,PR_FALSE); -} PRBool BasicTableLayoutStrategy::IsColumnInList(const PRInt32 colIndex, PRInt32* colIndexes, @@ -2603,51 +1281,19 @@ PRBool BasicTableLayoutStrategy::ColIsSpecifiedAsMinimumWidth(PRInt32 aColIndex) return result; } -// returns a list and count of all columns that behave like they have width=auto -// this includes columns with no width specified, and columns whose fixed width comes from a span -void BasicTableLayoutStrategy::GetColumnsThatActLikeAutoWidth(PRInt32& aNumCols, - PRInt32*& aColList) +void BasicTableLayoutStrategy::Dump(PRInt32 aIndent) { - // initialize out params - aNumCols = 0; - aColList = nsnull; - - // get the auto columns - PRInt32 numAutoCols=0; - PRInt32* autoColList=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoCols, autoColList); - - // XXX: have to do next step for %-width as well? - - // get the fixed columns - PRInt32 numFixedCols=0; - PRInt32* fixedColList=nsnull; - mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedCols, fixedColList); - - if (0 < numAutoCols+numFixedCols) { - // allocate the out param aColList to the biggest it could be (usually a little wasteful, but it's - // temp space and the numbers here are small, even for very big tables - aColList = new PRInt32[numAutoCols+numFixedCols]; - - // transfer the auto columns to aColList - PRInt32 i; - for (i = 0; i < numAutoCols; i++) { - aColList[i] = autoColList[i]; - aNumCols++; - } - - // get the columns whose fixed width is due to a colspan and transfer them to aColList - for (i = 0; i < numFixedCols; i++) { - nsTableColFrame* colFrame; - mTableFrame->GetColumnFrame(fixedColList[i], colFrame); - if (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN==colFrame->GetWidthSource()) { - aColList[aNumCols] = fixedColList[i]; - aNumCols++; - } - } + char* indent = new char[aIndent + 1]; + for (PRInt32 i = 0; i < aIndent + 1; i++) { + indent[i] = ' '; } + indent[aIndent] = 0; - return; + printf("%s**START BASIC STRATEGY DUMP** table=%X cols=%d numCols=%d", + indent, mTableFrame, mCols, mNumCols); + printf("\n%s minConWidth=%d maxConWidth=%d cellSpacing=%d propRatio=%.2f navQuirks=%d", + indent, mMinTableContentWidth, mMaxTableContentWidth, mCellSpacingTotal, mMinToDesProportionRatio, mIsNavQuirksMode); + printf(" **END BASIC STRATEGY DUMP** \n"); + delete [] indent; } - diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.h b/mozilla/layout/tables/BasicTableLayoutStrategy.h index 55c207a995a..ced57d07290 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.h +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.h @@ -28,44 +28,8 @@ class nsTableFrame; struct nsStylePosition; struct nsStyleTable; -/* ----------- SpanInfo ---------- */ - -/** SpanInfo is a transient data structure that holds info about - * cells that have col spans. Used during column balancing. - */ -// TODO: collapse this data structure with ColSpanStruct. They both (incompletely) describe -// the same situation with slightly different data. -struct SpanInfo -{ - PRInt32 span; - const PRInt32 initialColSpan; - const PRInt32 initialColIndex; - nscoord cellMinWidth; - nscoord cellDesiredWidth; - nscoord effectiveMinWidthOfSpannedCols; - nscoord effectiveMaxWidthOfSpannedCols; - - SpanInfo(PRInt32 aColIndex, PRInt32 aSpan, nscoord aMinWidth, nscoord aDesiredWidth); - ~SpanInfo() {}; - -}; - static const PRInt32 kUninitialized=-1; -inline SpanInfo::SpanInfo(PRInt32 aColIndex, PRInt32 aSpan, - nscoord aMinWidth, nscoord aDesiredWidth) - : initialColSpan(aSpan), - initialColIndex(aColIndex) -{ - span = aSpan; - cellMinWidth = aMinWidth; - cellDesiredWidth = aDesiredWidth; - effectiveMinWidthOfSpannedCols=kUninitialized; - effectiveMaxWidthOfSpannedCols=kUninitialized; -} - - - /* ---------- BasicTableLayoutStrategy ---------- */ /** Implementation of Nav4 compatible HTML browser table layout. @@ -98,21 +62,23 @@ public: */ virtual void SetMaxElementSize(nsSize* aMaxElementSize); + void SetMinAndMaxTableContentWidths(); + /** Called during resize reflow to determine the new column widths * @param aTableStyle - the resolved style for mTableFrame * @param aReflowState - the reflow state for mTableFrame * @param aMaxWidth - the computed max width for columns to fit into */ - virtual PRBool BalanceColumnWidths(nsIStyleContext * aTableStyle, + virtual PRBool BalanceColumnWidths(nsIStyleContext* aTableStyle, const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth); + nscoord aMaxWidth); // these accessors are mostly for debugging purposes - nscoord GetTableMinWidth() const; - nscoord GetTableMaxWidth() const; - nscoord GetTableFixedWidth() const; + nscoord GetTableMinContentWidth() const; + nscoord GetTableMaxContentWidth() const; nscoord GetCOLSAttribute() const; nscoord GetNumCols() const; + void Dump(PRInt32 aIndent); protected: @@ -130,125 +96,30 @@ protected: */ 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. - */ - virtual void SetMinAndMaxTableWidths(); + nscoord AssignPercentageColumnWidths(nscoord aBasis, + PRBool aTableIsAutoWidth); - /** assign widths for each column within a particular context. - * The context is given by each of the parameters. - * Sets mTableFrame->mColumnWidths as a side effect. - * - * @param aReflowState the reflow state - * @param aAvailWidth the remaining amount of horizontal space available - * @param aMaxWidth the total amount of horizontal space available - * @param aTableSpecifiedWidth the width of the table based on its attributes and its parent's width - * @param aTableIsAutoWidth PR_TRUE if the table is auto-width - * - * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error - * - */ - virtual PRBool BalanceProportionalColumns(const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aTableSpecifiedWidth, - PRBool aTableIsAutoWidth); + void CalculateTotals(PRInt32& aCellSpacing, + PRInt32* aTotalCounts, + PRInt32* aTotalWidths, + PRInt32* aMinWidths, + PRInt32& a0ProportionalCount); - /** assign the minimum legal width for each column that has proportional width. - * Typically called when the min table width doesn't fit in the available space. - * Sets mTableFrame->mColumnWidths as a side effect. - * - * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error - */ - virtual PRBool BalanceColumnsTableDoesNotFit(); + void AllocateFully(nscoord& aTotalAllocated, + PRInt32* aAllocTypes, + PRInt32 aWidthType, + PRBool aMarkAllocated = PR_TRUE); - /** assign the maximum allowed width for each column. - * Typically called when the desired max table width is less than or equal to the available space. - * Sets mTableFrame->mColumnWidths as a side effect. - * - * @param aReflowState the reflow state - * @param aAvailWidth the remaining amount of horizontal space available - * @param aMaxWidth the total amount of horizontal space available - * @param aTableSpecifiedWidth the specified width of the table. If there is none, - * this param is 0 - * @param aTableIsAutoWidth PR_TRUE if the table is auto-width - * - * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error - */ - virtual PRBool BalanceColumnsTableFits(const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aTableSpecifiedWidth, - PRBool aTableIsAutoWidth); + void AllocateConstrained(PRInt32 aAvailWidth, + PRInt32 aWidthType, + PRInt32 aNumConstrainedCols, + PRInt32 aSumMaxConstraints, + PRBool aStartAtMin, + PRInt32* aAllocTypes); - /** for each column, assign a width between the column's minimum and maximum width. - * Typically called when the desired max table width is greater the available space. - * Sets mTableFrame->mColumnWidths as a side effect. - * - * @param aReflowState the reflow state - * @param aAvailWidth the remaining amount of horizontal space available - * @param aMaxWidth the total amount of horizontal space available - * @param aTableIsAutoWidth PR_TRUE if the table is auto-width - * - * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error - * - */ - virtual PRBool BalanceColumnsConstrained(const nsHTMLReflowState& aReflowState, - nscoord aAvailWidth, - nscoord aMaxWidth, - PRBool aTableIsAutoWidth); - - /** post-process to AssignFixedColumnWidths - * - * @param aColSpanList a list of fixed-width columns that have colspans - * - * NOTE: does not yet properly handle overlapping col spans in all cases - * - * @return void - */ - virtual void DistributeFixedSpace(nsVoidArray *aColSpanList); - - /** starting with a partially balanced table, compute the amount - * of space to pad each column by to completely balance the table. - * Sets mTableFrame->mColumnWidths as a side effect. - * - * @param aAvailWidth the space still to be allocated within the table - * @param aTableWidth the sum of all columns widths - * @param aWidthOfFixedTableColumns the sum of the widths of fixed-width columns - * - * @return void - */ - virtual void DistributeExcessSpace(nscoord aAvailWidth, - nscoord aTableWidth, - nscoord aWidthOfFixedTableColumns); - - /** starting with a partially balanced table, compute the amount - * of space to allocate to each column to completely balance the table. - * set the column widths in mTableFrame based on these computations. - * assumes auto-width columns have been set to their minimum width. - * must be called with a PRInt32 variable initialized to 0 for aRecursionControl. - * - * @param aTableFixedWidth the specified width of the table. If there is none, - * this param is 0 - * @param aComputedTableWidth IN: the width of the table before this step. - * OUT:the width of the table after this step. - * @param aTableIsAutoWidth TRUE if the table style indicates it is autoWidth - * @param aRecursionControl IN: must be a PRInt32 set to 0 - * OUT: the number of iterations. Not generally useful to the caller, - * but useful for limiting the number of iterations in bizarre cases. - * - * @return void - */ - virtual void DistributeRemainingSpace(nscoord aTableFixedWidth, - nscoord &aComputedTableWidth, - PRBool aTableIsAutoWidth); - - virtual void AdjustTableThatIsTooWide(nscoord aComputedWidth, - nscoord aTableWidth, - PRBool aShrinkFixedCols); - - virtual void AdjustTableThatIsTooNarrow(nscoord aComputedWidth, - nscoord aTableWidth); + void AllocateUnconstrained(PRInt32 aAllocAmount, + PRInt32* aAllocTypes, + PRBool aSkip0Proportional); /** return true if the style indicates that the width is a specific width * for the purposes of column width determination. @@ -279,31 +150,26 @@ protected: */ void GetColumnsThatActLikeAutoWidth(PRInt32& aOutNumColumns, PRInt32*& aOutColumnIndexes); - - nscoord CalcHorizontalPadding(PRInt32 aColX); - + void ContinuingFrameCheck(); protected: nsTableFrame * mTableFrame; PRInt32 mCols; PRInt32 mNumCols; // cached data - nscoord mMinTableWidth; // the smallest size for the table - nscoord mMaxTableWidth; // the "natural" size for the table, if unconstrained - nscoord mFixedTableWidth; // the amount of space taken up by fixed-width columns - PRBool mIsNavQuirksMode; - + nscoord mMinTableContentWidth; // the smallest size for the table (excluding border and padding) + nscoord mMaxTableContentWidth; // the "natural" size for the table, if unconstrained (excluding border and padding) + nscoord mCellSpacingTotal; // all of the cellspacing for all of the cols + float mMinToDesProportionRatio; + PRPackedBool mIsNavQuirksMode; }; // these accessors are mostly for debugging purposes -inline nscoord BasicTableLayoutStrategy::GetTableMinWidth() const -{ return mMinTableWidth; }; +inline nscoord BasicTableLayoutStrategy::GetTableMinContentWidth() const +{ return mMinTableContentWidth; }; -inline nscoord BasicTableLayoutStrategy::GetTableMaxWidth() const -{ return mMaxTableWidth; }; - -inline nscoord BasicTableLayoutStrategy::GetTableFixedWidth() const -{ return mFixedTableWidth; }; +inline nscoord BasicTableLayoutStrategy::GetTableMaxContentWidth() const +{ return mMaxTableContentWidth; }; inline nscoord BasicTableLayoutStrategy::GetCOLSAttribute() const { return mCols; }; diff --git a/mozilla/layout/tables/FixedTableLayoutStrategy.cpp b/mozilla/layout/tables/FixedTableLayoutStrategy.cpp index 3176567187e..5abc56bf826 100644 --- a/mozilla/layout/tables/FixedTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/FixedTableLayoutStrategy.cpp @@ -44,33 +44,17 @@ FixedTableLayoutStrategy::~FixedTableLayoutStrategy() { } -PRBool FixedTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext *aTableStyle, +PRBool FixedTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableStyle, const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth) + nscoord aMaxWidth) { -#ifdef NS_DEBUG - nsIFrame *tablePIF=nsnull; - mTableFrame->GetPrevInFlow(&tablePIF); - NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!"); -#endif - - PRBool result = PR_TRUE; - - NS_ASSERTION(nsnull!=aTableStyle, "bad arg"); - if (nsnull==aTableStyle) - return PR_FALSE; - - - if (PR_TRUE==gsDebug) - { + if (PR_TRUE==gsDebug) { printf("\n%p: BALANCE COLUMN WIDTHS\n", mTableFrame); for (PRInt32 i=0; iGetColumnWidth(i)); printf("\n"); } - - // XXX Hey Cujo, result has never been initialized... - return result; + return PR_TRUE; } /* @@ -112,8 +96,10 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed for (colX = 0; colX < mNumCols; colX++) { // Get column information nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); - NS_ASSERTION(nsnull != colFrame, "bad col frame"); - if (!colFrame) return PR_FALSE; + if (!colFrame) { + NS_ASSERTION(PR_FALSE, "bad col frame"); + return PR_FALSE; + } // Get the columns's style const nsStylePosition* colPosition; @@ -136,7 +122,7 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed const nsStylePosition* cellPosition; cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colX, cellFrame); + PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(cellFrame); // Get fixed cell width if available if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { colWidths[colX] = cellPosition->mWidth.GetCoordValue() / colSpan; @@ -205,8 +191,8 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed } // 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); + mMinTableContentWidth = mMaxTableContentWidth = totalColWidth; + if (PR_TRUE == gsDebug) printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, mMinTableContentWidth, mMaxTableContentWidth); // clean up if (nsnull != colWidths) { diff --git a/mozilla/layout/tables/FixedTableLayoutStrategy.h b/mozilla/layout/tables/FixedTableLayoutStrategy.h index d012b2a86de..3e1c7442b96 100644 --- a/mozilla/layout/tables/FixedTableLayoutStrategy.h +++ b/mozilla/layout/tables/FixedTableLayoutStrategy.h @@ -54,9 +54,9 @@ public: * @param aReflowState - the reflow state for mTableFrame * @param aMaxWidth - the computed max width for columns to fit into */ - virtual PRBool BalanceColumnWidths(nsIStyleContext * aTableStyle, - const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth); + virtual PRBool BalanceColumnWidths(nsIStyleContext* aTableStyle, + const nsHTMLReflowState& aReflowState, + nscoord aMaxWidth); protected: /* assign the width of all columns diff --git a/mozilla/layout/tables/celldata.h b/mozilla/layout/tables/celldata.h index 29134571b65..f739ea4e7e4 100644 --- a/mozilla/layout/tables/celldata.h +++ b/mozilla/layout/tables/celldata.h @@ -21,9 +21,8 @@ class nsTableCellFrame; /** Data stored by nsCellMap to rationalize rowspan and colspan cells. - * if mCell is null then mRealCell will be the rowspan/colspan source - * in addition, if fOverlap is non-null then it will point to the - * other cell that overlaps this position + * if mOrigCell is null then mSpanCell will be the rowspan/colspan source. + * if mSpanCell2 is non-null then it will point to a 2nd cell that overlaps this position * @see nsCellMap * @see nsTableFrame::BuildCellMap * @see nsTableFrame::GrowCellMap @@ -33,17 +32,26 @@ class nsTableCellFrame; class CellData { public: - /** if not null, the cell that this CellData maps. - * if null, mRealCell points to the CellData that holds the - * mapped cell frame. - */ - nsTableCellFrame *mCell; - CellData *mRealCell; - CellData *mOverlap; - CellData(); + CellData(nsTableCellFrame* aOrigCell, CellData* aSpanData, CellData* aSpanData2) + : mOrigCell(aOrigCell), mSpanData(aSpanData), mSpanData2(aSpanData2) + {} ~CellData(); + PRBool IsSpannedBy(nsTableCellFrame* aCellFrame) + { + return (mSpanData && mSpanData->mOrigCell == aCellFrame) || + (mSpanData2 && mSpanData2->mOrigCell == aCellFrame); + } + PRBool IsOccupiedBy(nsTableCellFrame* aCellFrame) + { + return (mOrigCell == aCellFrame) || IsSpannedBy(aCellFrame); + } + + nsTableCellFrame* mOrigCell; // mCell + CellData* mSpanData; // mRealCell + CellData* mSpanData2; // mOverlap + }; #endif diff --git a/mozilla/layout/tables/nsCellMap.cpp b/mozilla/layout/tables/nsCellMap.cpp index e95eb7c1569..ac9300882ae 100644 --- a/mozilla/layout/tables/nsCellMap.cpp +++ b/mozilla/layout/tables/nsCellMap.cpp @@ -28,44 +28,39 @@ static const PRBool gsDebug = PR_FALSE; #endif nsCellMap::nsCellMap(int aRowCount, int aColCount) - : mRows(nsnull), - mMinColSpans(nsnull), - mColFrames(nsnull), - mRowCount(0), - mTotalRowCount(0), - mColCount(0), - mIsCollapsedRows(nsnull), + : mRowCount(0), mNumCollapsedRows(0), - mIsCollapsedCols(nsnull), - mNumCollapsedCols(0) + mNumCollapsedCols(0), + mNextAvailRowIndex(0) { - Reset(aRowCount, aColCount); + mIsCollapsedRows = nsnull; + mIsCollapsedCols = nsnull; + + Grow(aRowCount, aColCount); } nsCellMap::~nsCellMap() { - if (nsnull!=mRows) - { - for (int i=mTotalRowCount-1; 0<=i; i--) - { - nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(i)); - for (int j=mColCount-1; 0<=j ;j--) - { - CellData* data = (CellData *)(row->ElementAt(j)); - if (data != nsnull) - { - delete data; - } + PRInt32 mapRowCount = mRows.Count(); + PRInt32 colCount = mNumCellsInCol.Count(); + PRInt32 colX; + for (PRInt32 rowX = 0; rowX < mapRowCount; rowX++) { + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(rowX)); + for (colX = 0; colX <= colCount; colX++) { + CellData* data = (CellData *)(row->ElementAt(colX)); + if (data) { + delete data; } - delete row; } - delete mRows; + delete row; } - if (nsnull != mColFrames) - delete mColFrames; - // mMinColSpans may be null, it is only set for tables that need it - if (nsnull != mMinColSpans) - delete [] mMinColSpans; + for (colX = 0; colX < colCount; colX++) { + PRInt32* val = (PRInt32 *)mNumCellsInCol.ElementAt(colX); + if (val) { + delete [] val; + } + } + if (nsnull != mIsCollapsedRows) { delete [] mIsCollapsedRows; mIsCollapsedRows = nsnull; @@ -76,171 +71,379 @@ nsCellMap::~nsCellMap() mIsCollapsedCols = nsnull; mNumCollapsedCols = 0; } - mRows = nsnull; - mColFrames = nsnull; - mMinColSpans = nsnull; }; - -void nsCellMap::Reset(int aRowCount, int aColCount) +void nsCellMap::AddColsAtEnd(PRUint32 aNumCols) { - if (gsDebug) printf("calling Reset(%d,%d) with mRC=%d, mCC=%d, mTRC=%d\n", - aRowCount, aColCount, mRowCount, mColCount, mTotalRowCount); - if (nsnull==mColFrames) - { - mColFrames = new nsVoidArray(); // don't give the array a count, because null col frames are illegal (unlike null cell entries in a row) - } - - if (nsnull==mRows) - { - mRows = new nsVoidArray(); // don't give the array a count, because null rows are illegal (unlike null cell entries in a row) - } - - // void arrays force the caller to handle null padding elements themselves - // so if the number of columns has increased, we need to add extra cols to each row - for (PRInt32 rowIndex=0; rowIndexElementAt(rowIndex)); - const PRInt32 colsInRow = row->Count(); - if (colsInRow == aColCount) - break; // we already have enough columns in each row - for (PRInt32 colIndex = colsInRow; colIndexAppendElement(nsnull); - } - - // if the number of rows has increased, add the extra rows - PRInt32 newRows = aRowCount-mTotalRowCount; // (new row count) - (total row allocation) - for ( ; newRows > 0; newRows--) { - nsVoidArray *row; - if (0 != aColCount) { - row = new nsVoidArray(aColCount); - } else { - row = new nsVoidArray(); - } - mRows->AppendElement(row); - } - - mRowCount = aRowCount; - mTotalRowCount = PR_MAX(mTotalRowCount, mRowCount); - mColCount = aColCount; - - if (gsDebug) printf("leaving Reset with mRC=%d, mCC=%d, mTRC=%d\n", - mRowCount, mColCount, mTotalRowCount); + Grow(mRowCount, mNumCellsInCol.Count() + aNumCols); } -void nsCellMap::DumpCellMap() const +PRInt32 nsCellMap::GetNextAvailRowIndex() { - if (gsDebug==PR_TRUE) - { - printf("Cell Map =\n"); - for (int rowIndex=0; rowIndexElementAt(rowIndex)); - for (int colIndex=0; colIndexElementAt(colIndex)); - printf("Cell [%d,%d] = %p\n", rowIndex, colIndex, data); + return mNextAvailRowIndex++; +} + +void nsCellMap::Grow(PRInt32 aNumMapRows, + PRInt32 aNumCols) +{ + if (gsDebug) printf("calling Grow(%d,%d) with mapRC=%d, RC=%d, CC=%d\n", aNumMapRows, aNumCols, mRows.Count(), mRowCount, mNumCellsInCol.Count()); + PRInt32 origNumMapRows = mRows.Count(); + PRInt32 origNumCols = mNumCellsInCol.Count(); + + // if the number of columns has increased, we need to add extra cols to mNumColsOriginating and + // each row in mRows. + if (origNumCols < aNumCols) { + PRInt32 colX; + for (PRInt32 rowX = 0; rowX < origNumMapRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(rowX)); + const PRInt32 colsInRow = row->Count(); + for (colX = colsInRow; colX < aNumCols; colX++) { + row->AppendElement(nsnull); + } + } + // update the col array + for (colX = origNumCols; colX < aNumCols; colX++) { + PRInt32* val = new PRInt32[2]; + val[0] = val[1] = 0; + mNumCellsInCol.AppendElement(val); + } + } + + // if the number of rows has increased, add the extra rows. the new + // rows get the new number of cols + PRInt32 newRows = aNumMapRows - origNumMapRows; + for ( ; newRows > 0; newRows--) { + nsVoidArray* row; + row = (0 == aNumCols) ? new nsVoidArray() : new nsVoidArray(aNumCols); + mRows.AppendElement(row); + } + if (gsDebug) printf("leaving Grow with TRC=%d, TCC=%d\n", mRows.Count(), mNumCellsInCol.Count()); +} + +PRInt32 nsCellMap::AppendCell(nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) +{ + NS_ASSERTION(aCellFrame, "bad cell frame"); + + PRInt32 origNumMapRows = mRows.Count(); + PRInt32 origNumCols = mNumCellsInCol.Count(); + + // get the first null CellData in the desired row. It may be 1 past the end if there are none + PRInt32 startColIndex; + if (aRowIndex < origNumMapRows) { + for (startColIndex = 0; startColIndex < origNumCols; startColIndex++) { + CellData* data = GetMapCellAt(aRowIndex, startColIndex); + if (!data) { + break; // we found the col } } } -} - -void nsCellMap::GrowToRow(PRInt32 aRowCount) -{ - Reset(aRowCount, mColCount); -} - -void nsCellMap::GrowToCol(PRInt32 aColCount) -{ - Reset(mRowCount, aColCount); -} - -void nsCellMap::SetCellAt(CellData *aCell, int aRowIndex, int aColIndex) -{ - NS_PRECONDITION(nsnull!=aCell, "bad aCell"); - PRInt32 newRows = (aRowIndex+1)-mTotalRowCount; // add 1 to the "index" to get a "count" - if (00; newRows--) - { - nsVoidArray *row = new nsVoidArray(mColCount); - mRows->AppendElement(row); - } - mTotalRowCount = aRowIndex+1; // remember to always add 1 to an index when you want a count + else { + startColIndex = 0; } - CellData* cell = GetCellAt(aRowIndex,aColIndex); - if (cell != nsnull) - delete cell; - nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex)); - row->ReplaceElementAt(aCell, aColIndex); - if (gsDebug) printf("leaving SetCellAt(%p,%d,%d) with mRC=%d, mCC=%d, mTRC=%d\n", - aCell, aRowIndex, aColIndex, mRowCount, mColCount, mTotalRowCount); + mRowCount = PR_MAX(mRowCount, aRowIndex + 1); + + PRInt32 rowSpan = aCellFrame->GetRowSpan(); + PRInt32 colSpan = aCellFrame->GetColSpan(); + if (gsDebug) printf("AppendCell: rowSpan = %d, colSpan = %d\n", rowSpan, colSpan); + // Grow. we may need to add new rows/cols + PRInt32 spanNumRows = aRowIndex + rowSpan; + PRInt32 spanNumCols = startColIndex + colSpan; + if ((spanNumRows >= origNumMapRows) || (spanNumCols >= origNumCols)) { + Grow(spanNumRows, spanNumCols); + } + + // Setup CellData for this cell + CellData* origData = new CellData(aCellFrame, nsnull, nsnull); + if (gsDebug) printf("AppendCell: calling SetMapCellAt(data, %d, %d)\n", aRowIndex, startColIndex); + SetMapCellAt(*origData, aRowIndex, startColIndex); + + // reset the col index of the cell frame + PRInt32 oldColIndex; + aCellFrame->GetColIndex(oldColIndex); + if (startColIndex != oldColIndex) { + // only do this if they are different since it changes content + aCellFrame->SetColIndex(startColIndex); + } + + // Create CellData objects for the rows that this cell spans. Set + // their mOrigCell to nsnull and their mSpanData to point to data. + for (PRInt32 rowX = aRowIndex; rowX < spanNumRows; rowX++) { + for (PRInt32 colX = startColIndex; colX < spanNumCols; colX++) { + if ((rowX != aRowIndex) || (colX != startColIndex)) { // skip orig cell data done above + CellData* cellData = GetMapCellAt(rowX, colX); + if (cellData) { + NS_ASSERTION(!cellData->mOrigCell, "cannot overlap originating cell"); + if (cellData->mSpanData) { + NS_ASSERTION(!cellData->mSpanData2, "too many overlaps"); + cellData->mSpanData2 = origData; + } + else { + cellData->mSpanData = origData; + } + } + else { + cellData = new CellData(nsnull, origData, nsnull); + SetMapCellAt(*cellData, rowX, colX); + } + } + } + } + return startColIndex; } +void nsCellMap::RemoveCell(nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) +{ + // XXX write me. For now the cell map is recalculate from scratch when a cell is deleted +} + +PRInt32 nsCellMap::GetNumCellsIn(PRInt32 aColIndex, PRBool aOriginating) +{ + PRInt32 colCount = mNumCellsInCol.Count(); + if ((aColIndex >= 0) && (aColIndex < colCount)) { + PRInt32* numCellsArray = (PRInt32 *)mNumCellsInCol.ElementAt(aColIndex); + PRInt32 numCells = (aOriginating) ? *numCellsArray : *(numCellsArray + 1); + return numCells; + } + else { + NS_ASSERTION(PR_FALSE, "nsCellMap::GetNumCellsIn - bad col index"); + return 0; + } +} + +PRInt32 nsCellMap::GetNumCellsIn(PRInt32 aColIndex) +{ + return GetNumCellsIn(aColIndex, 1); +} + +PRInt32 nsCellMap::GetNumCellsOriginatingIn(PRInt32 aColIndex) +{ + return GetNumCellsIn(aColIndex, 0); +} + +#ifdef NS_DEBUG +void nsCellMap::Dump() const +{ + printf("***** start CellMap Dump *****\n"); + PRInt32 mapRowCount = mRows.Count(); + PRInt32 colCount = mNumCellsInCol.Count(); + PRInt32 colIndex; + printf("mapRowCount=%d tableRowCount=%d, colCount=%d \n", mapRowCount, mRowCount, colCount); + + for (PRInt32 rowIndex = 0; rowIndex < mapRowCount; rowIndex++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowIndex); + printf("row %d : ", rowIndex); + for (colIndex = 0; colIndex < colCount; colIndex++) { + CellData* cd = (CellData *)row->ElementAt(colIndex); + if (cd) { + if (cd->mOrigCell) { + printf("C%d,%d ", rowIndex, colIndex); + } else { + nsTableCellFrame* cell = cd->mSpanData->mOrigCell; + nsTableRowFrame* row; + cell->GetParent((nsIFrame**)&row); + int rr = row->GetRowIndex(); + int cc; + cell->GetColIndex(cc); + printf("S%d,%d ", rr, cc); + if (cd->mSpanData2){ + cell = cd->mSpanData2->mOrigCell; + nsTableRowFrame* row2; + cell->GetParent((nsIFrame**)&row2); + rr = row2->GetRowIndex(); + cell->GetColIndex(cc); + printf("O%d,%c ", rr, cc); + } + } + } else { + printf("---- "); + } + } + printf("\n"); + } + + // output info mapping Ci,j to cell address + PRInt32 cellCount = 0; + for (PRInt32 rIndex = 0; rIndex < mapRowCount; rIndex++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rIndex); + for (colIndex = 0; colIndex < colCount; colIndex++) { + CellData* cd = (CellData *)row->ElementAt(colIndex); + if (cd) { + if (cd->mOrigCell) { + nsTableCellFrame* cellFrame = cd->mOrigCell; + PRInt32 cellFrameColIndex; + cellFrame->GetColIndex(cellFrameColIndex); + printf("C%d,%d=%p(%d) ", rIndex, colIndex, cellFrame, cellFrameColIndex); + cellCount++; + } + } + } + printf("\n"); + } + + // output col frame info + printf("\n col frames ->"); + for (colIndex = 0; colIndex < mColFrames.Count(); colIndex++) { + nsTableColFrame* colFrame = (nsTableColFrame *)mColFrames.ElementAt(colIndex); + if (0 == (colIndex % 8)) + printf("\n"); + printf ("%d=%p ", colIndex, colFrame); + } + // output cells originating in cols + printf ("\ncells in/originating in cols array -> "); + for (colIndex = 0; colIndex < colCount; colIndex++) { + PRInt32* numCells = (PRInt32 *)mNumCellsInCol.ElementAt(colIndex); + printf ("%d=%d,%d ", colIndex, *numCells, *(numCells + 1)); + } + printf("\n"); + printf("\n***** end CellMap Dump *****\n"); +} +#endif + +// only called if the cell at aMapRowIndex, aColIndex is null +void nsCellMap::SetMapCellAt(CellData& aNewCell, + PRInt32 aMapRowIndex, + PRInt32 aColIndex) +{ + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(aMapRowIndex)); + row->ReplaceElementAt(&aNewCell, aColIndex); + // update the col array + PRInt32* numCells = (PRInt32 *)mNumCellsInCol.ElementAt(aColIndex); + if (aNewCell.mOrigCell) { // cell originates in this col + (*numCells)++; + } + (*(numCells + 1))++; // cell occupies this col +} + +PRInt32 nsCellMap::GetEffectiveColSpan(PRInt32 aColIndex, nsTableCellFrame* aCell) +{ + NS_PRECONDITION(nsnull != aCell, "bad cell arg"); + + PRInt32 initialRowX; + aCell->GetRowIndex(initialRowX); + + PRInt32 effColSpan = 0; + PRInt32 colCount = mNumCellsInCol.Count(); + for (PRInt32 colX = aColIndex; colX < colCount; colX++) { + CellData* cellData = GetCellAt(initialRowX, colX); + if (cellData && cellData->IsOccupiedBy(aCell)) { + effColSpan++; + } + else { + break; + } + } + if (effColSpan == 0) { + //Dump(); + printf("hello"); + } + NS_ASSERTION(effColSpan > 0, "invalid col span or col index"); + return effColSpan; +} + +void nsCellMap::GetCellInfoAt(PRInt32 aRowX, + PRInt32 aColX, + nsTableCellFrame*& aCellFrame, + PRBool& aOriginates, + PRInt32& aColSpan) +{ + aCellFrame = GetCellFrameAt(aRowX, aColX); + if (aCellFrame) { + aOriginates = PR_TRUE; + PRInt32 initialColIndex; + aCellFrame->GetColIndex(initialColIndex); + aColSpan = GetEffectiveColSpan(initialColIndex, aCellFrame); + } + else { + aOriginates = PR_FALSE; + aColSpan = 0; + } +} + + + nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex) const { - NS_ASSERTION(nsnull!=mColFrames, "bad state"); - return (nsTableColFrame *)(mColFrames->ElementAt(aColIndex)); + return (nsTableColFrame *)(mColFrames.ElementAt(aColIndex)); } - -void nsCellMap::SetMinColSpan(PRInt32 aColIndex, PRBool aColSpan) +PRInt32 nsCellMap::GetNumCollapsedRows() { - NS_ASSERTION(aColIndex=1, "bad aColSpan"); - - // initialize the data structure if not already done - if (nsnull==mMinColSpans) - { - mMinColSpans = new PRInt32[mColCount]; - for (PRInt32 i=0; i mColCount) - { - result = aColIndex; - } - else - { - if (aRowIndex < mRowCount) - { - result = aColIndex; - nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex)); - PRInt32 count = row->Count(); - for (PRInt32 colIndex=aColIndex; colIndexElementAt(colIndex); - if (nsnull==data) - { - result = colIndex; - break; - } - result++; - } + if ((aRow >= 0) && (aRow < mRowCount)) { + if (mIsCollapsedRows) { + return mIsCollapsedRows[aRow]; } } - return result; + return PR_FALSE; } +void nsCellMap::SetRowCollapsedAt(PRInt32 aRow, PRBool aValue) +{ + if ((aRow >= 0) && (aRow < mRowCount)) { + if (nsnull == mIsCollapsedRows) { + mIsCollapsedRows = new PRPackedBool[mRowCount]; + for (PRInt32 i = 0; i < mRowCount; i++) { + mIsCollapsedRows[i] = PR_FALSE; + } + } + if (mIsCollapsedRows[aRow] != aValue) { + if (PR_TRUE == aValue) { + mNumCollapsedRows++; + } else { + mNumCollapsedRows--; + } + mIsCollapsedRows[aRow] = aValue; + } + } +} + +PRInt32 nsCellMap::GetNumCollapsedCols() +{ + return mNumCollapsedCols; +} + +PRBool nsCellMap::IsColCollapsedAt(PRInt32 aCol) +{ + PRInt32 colCount = mNumCellsInCol.Count(); + if ((aCol >= 0) && (aCol < colCount)) { + if (mIsCollapsedCols) { + return mIsCollapsedCols[aCol]; + } + } + return PR_FALSE; +} + +void nsCellMap::SetColCollapsedAt(PRInt32 aCol, PRBool aValue) +{ + PRInt32 colCount = mNumCellsInCol.Count(); + if ((aCol >= 0) && (aCol < colCount)) { + if (nsnull == mIsCollapsedCols) { + mIsCollapsedCols = new PRPackedBool[colCount]; + for (PRInt32 i = 0; i < colCount; i++) { + mIsCollapsedCols[i] = PR_FALSE; + } + } + if (mIsCollapsedCols[aCol] != aValue) { + if (PR_TRUE == aValue) { + mNumCollapsedCols++; + } else { + mNumCollapsedCols--; + } + mIsCollapsedCols[aCol] = aValue; + } + } +} + +// The following are not used and may not work. They have been removed from +// nsTableFrame and nsCellMap headers but retained here if needed in the future. +#if 0 /** returns PR_TRUE if the row at aRowIndex has any cells that are the result * of a row-spanning cell above it. So, given this table:
*
@@ -259,22 +462,18 @@ PRInt32 nsCellMap::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) co
 // whenever a row|col|cell is added/deleted, or a span attribute is changed.
 PRBool nsCellMap::RowIsSpannedInto(PRInt32 aRowIndex)
 {
-  NS_PRECONDITION (0<=aRowIndex && aRowIndexmCell)
-			{ // the cell at (aRowIndex, colIndex) is the result of a span
-				nsTableCellFrame *cell = cd->mRealCell->mCell;
-				NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
+	for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++) {
+		CellData* cd = GetCellAt(aRowIndex, colIndex);
+		if (cd) { // there's really a cell at (aRowIndex, colIndex)
+			if (!cd->mOrigCell) { // the cell at (aRowIndex, colIndex) is the result of a span
+				nsTableCellFrame* cell = cd->mSpanData->mOrigCell;
+				NS_ASSERTION(cell, "bad cell map state, missing real cell");
 				PRInt32 realRowIndex;
         cell->GetRowIndex (realRowIndex);
-				if (realRowIndex!=aRowIndex)
-				{ // the span is caused by a rowspan
+				if (realRowIndex != aRowIndex) { // the span is caused by a rowspan
 					result = PR_TRUE;
 					break;
 				}
@@ -299,31 +498,24 @@ PRBool nsCellMap::RowIsSpannedInto(PRInt32 aRowIndex)
   */
 PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex)
 {
-  NS_PRECONDITION (0<=aRowIndex && aRowIndexmCell)
-        { // the cell at (nextRowIndex, colIndex) is the result of a span
-          nsTableCellFrame *cell = cd->mRealCell->mCell;
-          NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
+  PRInt32 colCount = mTableColToMapCol.Count();
+  if (aRowIndex != mRowCount - 1) {
+    // aRowIndex is not the last row, so we check the next row after aRowIndex for spanners
+    for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++) {
+      PRInt32 nextRowIndex = aRowIndex + 1;
+      CellData* cd = GetCellAt(nextRowIndex, colIndex);
+      if (cd) { // there's really a cell at (nextRowIndex, colIndex)
+        if (!cd->mOrigCell) { // the cell at (nextRowIndex, colIndex) is the result of a span
+          nsTableCellFrame* cell = cd->mSpanData->mOrigCell;
+          NS_ASSERTION(cell, "bad cell map state, missing real cell");
           PRInt32 realRowIndex;
           cell->GetRowIndex (realRowIndex);
-          if (realRowIndex!=nextRowIndex)
-          { // the span is caused by a rowspan
-            CellData *spanningCell = GetCellAt(aRowIndex, colIndex);
-            if (nsnull!=spanningCell)
-            { // there's really a cell at (aRowIndex, colIndex)
-              if (nsnull!=spanningCell->mCell)
-              { // aRowIndex is where the rowspan originated
+          if (realRowIndex != nextRowIndex) { // the span is caused by a rowspan
+            CellData* spanningCell = GetCellAt(aRowIndex, colIndex);
+            if (spanningCell) { // there's really a cell at (aRowIndex, colIndex)
+              if (spanningCell->mOrigCell) { // aRowIndex is where the rowspan originated
                 result = PR_TRUE;
                 break;
               }
@@ -336,7 +528,6 @@ PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex)
   return result;
 }
 
-
 /** returns PR_TRUE if the col at aColIndex has any cells that are the result
   * of a col-spanning cell.  So, given this table:
*
@@ -352,23 +543,18 @@ PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex)
   */
 PRBool nsCellMap::ColIsSpannedInto(PRInt32 aColIndex)
 {
-  PRInt32 colCount = GetColCount();
-  NS_PRECONDITION (0<=aColIndex && aColIndexmCell)
-      { // the cell at (rowIndex, aColIndex) is the result of a span
-        nsTableCellFrame *cell = cd->mRealCell->mCell;
-        NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
+  for (PRInt32 rowIndex = 0; rowIndex < mRowCount; rowIndex++) {
+    CellData* cd = GetCellAt(rowIndex, aColIndex);
+    if (cd) { // there's really a cell at (aRowIndex, aColIndex)
+      if (!cd->mOrigCell) { // the cell at (rowIndex, aColIndex) is the result of a span
+        nsTableCellFrame* cell = cd->mSpanData->mOrigCell;
+        NS_ASSERTION(cell, "bad cell map state, missing real cell");
         PRInt32 realColIndex;
-        cell->GetColIndex (realColIndex);
-        if (realColIndex!=aColIndex)
-        { // the span is caused by a colspan
+        cell->GetColIndex(realColIndex);
+        if (realColIndex != aColIndex) { // the span is caused by a colspan
           result = PR_TRUE;
           break;
         }
@@ -392,29 +578,22 @@ PRBool nsCellMap::ColIsSpannedInto(PRInt32 aColIndex)
 PRBool nsCellMap::ColHasSpanningCells(PRInt32 aColIndex)
 {
   PRBool result = PR_FALSE;
-  const PRInt32 colCount = GetColCount();
-  if (aColIndexmCell)
-        { // the cell at (rowIndex, nextColIndex) is the result of a span
-          nsTableCellFrame *cell = cd->mRealCell->mCell;
-          NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell");
+      CellData* cd = GetCellAt(rowIndex, nextColIndex);
+      if (cd) { // there's really a cell at (rowIndex, nextColIndex)
+        if (!cd->mOrigCell) { // the cell at (rowIndex, nextColIndex) is the result of a span
+          nsTableCellFrame* cell = cd->mSpanData->mOrigCell;
+          NS_ASSERTION(cell, "bad cell map state, missing real cell");
           PRInt32 realColIndex;
-          cell->GetColIndex (realColIndex);
-          if (realColIndex!=nextColIndex)
-          { // the span is caused by a colspan
-            CellData *spanningCell =GetCellAt(rowIndex, aColIndex);
-            if (nsnull!=spanningCell)
-            { // there's really a cell at (rowIndex, aColIndex)
-              if (nsnull!=spanningCell->mCell)
-              { // aCowIndex is where the cowspan originated
+          cell->GetColIndex(realColIndex);
+          if (realColIndex != nextColIndex) { // the span is caused by a colspan
+            CellData* spanningCell = GetCellAtInternal(rowIndex, aColIndex);
+            if (spanningCell) { // there's really a cell at (rowIndex, aColIndex)
+              if (spanningCell->mOrigCell) { // aCowIndex is where the cowspan originated
                 result = PR_TRUE;
                 break;
               }
@@ -427,73 +606,6 @@ PRBool nsCellMap::ColHasSpanningCells(PRInt32 aColIndex)
   return result;
 }
 
-PRInt32 nsCellMap::GetNumCollapsedRows()
-{
-  return mNumCollapsedRows;
-}
+#endif
 
-PRBool nsCellMap::IsRowCollapsedAt(PRInt32 aRow)
-{
-  if ((aRow >= 0) && (aRow < mTotalRowCount)) {
-    if (mIsCollapsedRows) {
-      return mIsCollapsedRows[aRow];
-    }
-  }
-  return PR_FALSE;
-}
-
-void nsCellMap::SetRowCollapsedAt(PRInt32 aRow, PRBool aValue)
-{
-  if ((aRow >= 0) && (aRow < mRowCount)) {
-    if (nsnull == mIsCollapsedRows) {
-      mIsCollapsedRows = new PRBool[mRowCount];
-      for (PRInt32 i = 0; i < mRowCount; i++) {
-        mIsCollapsedRows[i] = PR_FALSE;
-      }
-    }
-    if (mIsCollapsedRows[aRow] != aValue) {
-      if (PR_TRUE == aValue) {
-        mNumCollapsedRows++;
-      } else {
-        mNumCollapsedRows--;
-      }
-      mIsCollapsedRows[aRow] = aValue; 
-    }
-  }
-}
-
-PRInt32 nsCellMap::GetNumCollapsedCols()
-{
-  return mNumCollapsedCols;
-}
-
-PRBool nsCellMap::IsColCollapsedAt(PRInt32 aCol)
-{
-  if ((aCol >= 0) && (aCol < mColCount)) {
-    if (mIsCollapsedCols) {
-      return mIsCollapsedCols[aCol];
-    }
-  }
-  return PR_FALSE;
-}
-
-void nsCellMap::SetColCollapsedAt(PRInt32 aCol, PRBool aValue)
-{
-  if ((aCol >= 0) && (aCol < mColCount)) {
-    if (nsnull == mIsCollapsedCols) {
-      mIsCollapsedCols = new PRBool[mColCount];
-      for (PRInt32 i = 0; i < mColCount; i++) {
-        mIsCollapsedCols[i] = PR_FALSE;
-      }
-    }
-    if (mIsCollapsedCols[aCol] != aValue) {
-      if (PR_TRUE == aValue) {
-        mNumCollapsedCols++;
-      } else {
-        mNumCollapsedCols--;
-      }
-      mIsCollapsedCols[aCol] = aValue; 
-    }
-  }
-}
 
diff --git a/mozilla/layout/tables/nsCellMap.h b/mozilla/layout/tables/nsCellMap.h
index aa3f208ef8a..4fbb71d053c 100644
--- a/mozilla/layout/tables/nsCellMap.h
+++ b/mozilla/layout/tables/nsCellMap.h
@@ -40,73 +40,52 @@ class nsTableCellFrame;
   */
 class nsCellMap
 {
-protected:
-  /** storage for rows */
-  nsVoidArray *mRows;       
-
-  /** storage for min col span info, just an int that gives the smallest
-    * colspan for all cells originating in each column.  If allocated,
-    * each entry must be >= 1.
-    */
-  PRInt32 *mMinColSpans;
-
-  /** a cache of the column frames, by col index */
-  nsVoidArray * mColFrames;
-
-  /** the number of rows.  mRows[0] - mRows[mRowCount-1] are non-null. */
-  PRInt32 mRowCount;
-
-  /** the number of rows allocated (due to cells having rowspans extending beyond the end of the table */
-  PRInt32 mTotalRowCount;
-
-  /** the number of columns (the max of all row lengths) */
-  PRInt32 mColCount;
-
-  // an array of booleans where the ith element indicates if the ith row is collapsed
-  PRBool* mIsCollapsedRows;
-  PRInt32 mNumCollapsedRows;
-
-  // an array of booleans where the ith element indicates if the ith col is collapsed
-  PRBool* mIsCollapsedCols;
-  PRInt32 mNumCollapsedCols;
-
 public:
   /** constructor 
-    * @param aRows - initial number of rows
-	  * @param aColumns - initial number of columns
+    * @param aNumRows - initial number of rows
+	  * @param aNumColumns - initial number of columns
 	  */
-  nsCellMap(PRInt32 aRows, PRInt32 aColumns);
+  nsCellMap(PRInt32 aNumRows, 
+            PRInt32 aNumCols);
 
   /** destructor
     * NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED  
-	*/
+	  */
   ~nsCellMap();
 
-  /** set the CellMap to (aRows x aColumns) */
-  void Reset(PRInt32 aRows, PRInt32 aColumns);
+  /** return the CellData for the cell at (aTableRowIndex, aTableColIndex) */
+  CellData* GetCellAt(PRInt32 aRowIndex, 
+                      PRInt32 aColIndex) const;
 
-  /** return the CellData for the cell at (aRowIndex,aColIndex) */
-  CellData * GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const;
+  /** return the nsTableCellFrame for the cell at (aTableRowIndex, aTableColIndex) */
+  nsTableCellFrame* GetCellFrameAt(PRInt32 aRowIndex, 
+                                   PRInt32 aColIndex) const;
 
-  /** return the nsTableCellFrame for the cell at (aRowIndex, aColIndex) */
-  nsTableCellFrame * GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex) const;
+  /** append the cellFrame at the end of the row at aRowIndex and return the col index
+    */
+  PRInt32 AppendCell(nsTableCellFrame* aCellFrame, 
+                     PRInt32           aRowIndex);
 
-  /** assign aCellData to the cell at (aRow,aColumn) */
-  void SetCellAt(CellData *aCellData, PRInt32 aRow, PRInt32 aColumn);
+  void RemoveCell(nsTableCellFrame* aCellFrame,
+                  PRInt32           aRowIndex);
+
+  PRInt32 GetNextAvailRowIndex();
+
+  PRInt32 GetEffectiveColSpan(PRInt32           aColIndex, 
+                              nsTableCellFrame* aCell);
+
+  PRInt32 GetNumCellsIn(PRInt32 aColIndex);
+  PRInt32 GetNumCellsOriginatingIn(PRInt32 aColIndex);
 
   PRInt32 GetNumCollapsedRows();
-  PRBool IsRowCollapsedAt(PRInt32 aRow);
-  void SetRowCollapsedAt(PRInt32 aRow, PRBool aValue);
+  PRBool IsRowCollapsedAt(PRInt32 aRowIndex);
+  void SetRowCollapsedAt(PRInt32 aRowIndex, 
+                         PRBool  aValue);
 
   PRInt32 GetNumCollapsedCols();
-  PRBool IsColCollapsedAt(PRInt32 aCol);
-  void SetColCollapsedAt(PRInt32 aCol, PRBool aValue);
-
-  /** expand the CellMap to have aRowCount rows.  The number of columns remains the same */
-  void GrowToRow(PRInt32 aRowCount);
-
-  /** expand the CellMap to have aColCount columns.  The number of rows remains the same */
-  void GrowToCol(PRInt32 aColCount);
+  PRBool IsColCollapsedAt(PRInt32 aColIndex);
+  void SetColCollapsedAt(PRInt32 aColIndex, 
+                         PRBool aValue);
 
   /** return the total number of columns in the table represented by this CellMap */
   PRInt32 GetColCount() const;
@@ -115,20 +94,7 @@ public:
   PRInt32 GetRowCount() const;
 
   /** return the column frame associated with aColIndex */
-  nsTableColFrame * GetColumnFrame(PRInt32 aColIndex) const;
-
-  /** return the index of the next column in aRowIndex after aColIndex 
-    * that does not have a cell assigned to it.
-    * If aColIndex is past the end of the row, it is returned.
-    * If the row is not initialized in the cell map, 0 is returned.
-    */
-  PRInt32 GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const;
-
-  /** cache the min col span for all cells in aColIndex */ 
-  void    SetMinColSpan(PRInt32 aColIndex, PRBool  aColSpan);
-
-  /** get the cached min col span for aColIndex */
-  PRInt32 GetMinColSpan(PRInt32 aColIndex) const;
+  nsTableColFrame* GetColumnFrame(PRInt32 aColIndex) const;
 
   /** add a column frame to the list of column frames
     * column frames must be added in order
@@ -138,102 +104,105 @@ public:
   /** empty the column frame cache */
   void ClearColumnCache();
 
-	/** returns PR_TRUE if the row at aRowIndex has any cells that are the result
-		* of a row-spanning cell above it.  So, given this table:
- *
-		* TABLE
-		*   TR
-		*    TD ROWSPAN=2
-		*    TD
-		*   TR
-		*    TD
-		* 
- * RowIsSpannedInto(0) returns PR_FALSE, and RowIsSpannedInto(1) returns PR_TRUE. - * @see RowHasSpanningCells - */ - PRBool RowIsSpannedInto(PRInt32 aRowIndex); - - /** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1 - * So, given this table:
- *
-		* TABLE
-		*   TR
-		*    TD ROWSPAN=2
-		*    TD
-		*   TR
-		*    TD
-		* 
- * RowHasSpanningCells(0) returns PR_TRUE, and RowHasSpanningCells(1) returns PR_FALSE. - * @see RowIsSpannedInto - */ - PRBool RowHasSpanningCells(PRInt32 aRowIndex); - - /** returns PR_TRUE if the col at aColIndex has any cells that are the result - * of a col-spanning cell. So, given this table:
- *
-		* TABLE
-		*   TR
-		*    TD COLSPAN=2
-		*    TD
-		*    TD
-		* 
- * ColIsSpannedInto(0) returns PR_FALSE, ColIsSpannedInto(1) returns PR_TRUE, - * and ColIsSpannedInto(2) returns PR_FALSE. - * @see ColHasSpanningCells - */ - PRBool ColIsSpannedInto(PRInt32 aColIndex); - - /** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1 - * So, given this table:
- *
-		* TABLE
-		*   TR
-		*    TD COLSPAN=2
-		*    TD
-		* 
- * ColHasSpanningCells(0) returns PR_TRUE, and ColHasSpanningCells(1) returns PR_FALSE. - * @see ColIsSpannedInto - */ - PRBool ColHasSpanningCells(PRInt32 aColIndex); + void GetCellInfoAt(PRInt32 aRowX, + PRInt32 aColX, + nsTableCellFrame*& aCellFrame, + PRBool& aOriginates, + PRInt32& aColSpan); + void AddColsAtEnd(PRUint32 aNumCols); /** dump a representation of the cell map to stdout for debugging */ - void DumpCellMap() const; +#ifdef NS_DEBUG + void Dump() const; +#endif +protected: + /** set the CellMap to (aNumRows x aNumColumns) */ + void Grow(PRInt32 aNumMapRows, + PRInt32 aNumCols); + + /** assign aCellData to the cell at (aRow,aColumn) */ + void SetMapCellAt(CellData& aCellData, + PRInt32 aMapRowIndex, + PRInt32 aColIndex); + + CellData* GetMapCellAt(PRInt32 aMapRowIndex, + PRInt32 aColIndex) const; + + PRInt32 GetNumCellsIn(PRInt32 aColIndex, PRBool aOriginating); + + /** an array containing col array. It can be larger than mRowCount due to + * row spans extending beyond the table */ + nsVoidArray mRows; + + /** an array of col frames. It is as large as mRowCount */ + nsVoidArray mColFrames; + + /** an array of PRInt32[2] indexed by col and giving the number of cells originating + * and occupying each col. */ + nsVoidArray mNumCellsInCol; + + // an array of booleans where the ith element indicates if the ith row is collapsed + PRPackedBool* mIsCollapsedRows; + PRInt32 mNumCollapsedRows; + + // an array of booleans where the ith element indicates if the ith col is collapsed + PRPackedBool* mIsCollapsedCols; + PRInt32 mNumCollapsedCols; + + /** the number of rows in the table which is <= the number of rows in the cell map + * due to row spans extending beyond the end of the table (dead rows) */ + PRInt32 mRowCount; + + PRInt32 mNextAvailRowIndex; }; /* ----- inline methods ----- */ - -inline CellData * nsCellMap::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const +inline CellData* nsCellMap::GetCellAt(PRInt32 aRowIndex, + PRInt32 aColIndex) const { - NS_PRECONDITION(0<=aRowIndex, "bad aRowIndex arg"); - NS_PRECONDITION(0<=aColIndex, "bad aColIndex arg"); - // don't check index vs. count for row or col, because it's ok to ask for a cell that doesn't yet exist - NS_PRECONDITION(nsnull!=mRows, "bad mRows"); - - CellData *result = nsnull; - nsVoidArray *row = (nsVoidArray *)(mRows->ElementAt(aRowIndex)); - if (nsnull!=row) + NS_PRECONDITION((0 <= aRowIndex) && (aRowIndex < mRowCount), "GetCellAt: bad row index"); + PRInt32 colCount = mNumCellsInCol.Count(); + NS_PRECONDITION((0 <= aColIndex) && (aColIndex < colCount), "GetCellAt: bad col index"); + + CellData* result = nsnull; + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(aRowIndex)); + if (row) result = (CellData *)(row->ElementAt(aColIndex)); return result; } -inline nsTableCellFrame * nsCellMap::GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex) const +inline CellData* nsCellMap::GetMapCellAt(PRInt32 aMapRowIndex, + PRInt32 aColIndex) const { - NS_PRECONDITION(0<=aRowIndex, "bad aRowIndex arg"); - // don't check aRowIndex vs. mRowCount, because it's ok to ask for a cell in a row that doesn't yet exist - NS_PRECONDITION(0<=aColIndex && aColIndex < mColCount, "bad aColIndex arg"); + NS_PRECONDITION((0 <= aMapRowIndex) && (aMapRowIndex < mRows.Count()), "GetMapCellAt: bad row index"); + NS_PRECONDITION((0 <= aColIndex) && (aColIndex < mNumCellsInCol.Count()), "GetMapCellAt: bad col index"); - nsTableCellFrame *result = nsnull; - CellData * cellData = GetCellAt(aRowIndex, aColIndex); - if (nsnull!=cellData) - result = cellData->mCell; + CellData* result = nsnull; + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(aMapRowIndex)); + if (row) + result = (CellData *)(row->ElementAt(aColIndex)); + return result; +} + +inline nsTableCellFrame* nsCellMap::GetCellFrameAt(PRInt32 aRowIndex, + PRInt32 aColIndex) const +{ + NS_PRECONDITION((0 <= aRowIndex) && (aRowIndex < mRowCount), "GetCellFrameAt: bad row index"); + PRInt32 colCount = mNumCellsInCol.Count(); + NS_PRECONDITION((0 <= aColIndex) && (aColIndex < colCount), "GetCellFrameAt: bad col index"); + + nsTableCellFrame* result = nsnull; + CellData* cellData = GetCellAt(aRowIndex, aColIndex); + if (cellData) + result = cellData->mOrigCell; return result; } inline PRInt32 nsCellMap::GetColCount() const { - return mColCount; + return mNumCellsInCol.Count(); } inline PRInt32 nsCellMap::GetRowCount() const @@ -243,13 +212,12 @@ inline PRInt32 nsCellMap::GetRowCount() const inline void nsCellMap::AppendColumnFrame(nsTableColFrame *aColFrame) { - mColFrames->AppendElement(aColFrame); + mColFrames.AppendElement(aColFrame); } inline void nsCellMap::ClearColumnCache() { - if (nsnull!=mColFrames) - mColFrames->Clear(); + mColFrames.Clear(); } diff --git a/mozilla/layout/tables/nsITableLayoutStrategy.h b/mozilla/layout/tables/nsITableLayoutStrategy.h index 4221ccd187b..7630fe3468f 100644 --- a/mozilla/layout/tables/nsITableLayoutStrategy.h +++ b/mozilla/layout/tables/nsITableLayoutStrategy.h @@ -48,9 +48,9 @@ public: * @param aMaxWidth the width constraint */ - virtual PRBool BalanceColumnWidths(nsIStyleContext *aTableStyle, + virtual PRBool BalanceColumnWidths(nsIStyleContext* aTableStyle, const nsHTMLReflowState& aReflowState, - nscoord aMaxWidth)=0; + nscoord aMaxWidth)=0; /** return the computed max "natural" size of the table. * this is the sum of the desired size of the content taking into account table @@ -58,7 +58,7 @@ public: * the actual table width in a given situation will depend on the available size * provided by the parent (especially for percent-width tables.) */ - virtual nscoord GetTableMaxWidth() const = 0; + virtual nscoord GetTableMaxContentWidth() const = 0; /** return the computed minimum possible size of the table. * this is the sum of the minimum sizes of the content taking into account table @@ -66,13 +66,7 @@ public: * the actual table width in a given situation will depend on the available size * provided by the parent (especially for percent-width tables.) */ - virtual nscoord GetTableMinWidth() const = 0; - - /** return the portion of the table width that is specified as "fixed" aka - * the amount of table width that does not vary with available width or other - * inputs to the table balancing algorithm. - */ - virtual nscoord GetTableFixedWidth() const = 0; + virtual nscoord GetTableMinContentWidth() const = 0; /** return the value of the COLS attribute, used for balancing column widths */ virtual nscoord GetCOLSAttribute() const = 0; diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp index bf038a1fb7a..cf7b1d657ab 100644 --- a/mozilla/layout/tables/nsTableCellFrame.cpp +++ b/mozilla/layout/tables/nsTableCellFrame.cpp @@ -36,9 +36,11 @@ #include "nsIView.h" #include "nsStyleUtil.h" #include "nsLayoutAtoms.h" +#include "nsCOMPtr.h" +#include "nsIHTMLTableCellElement.h" NS_DEF_PTR(nsIStyleContext); - +static NS_DEFINE_IID(kIHTMLTableCellElementIID, NS_IHTMLTABLECELLELEMENT_IID); #ifdef NS_DEBUG static PRBool gsDebug = PR_FALSE; @@ -78,7 +80,7 @@ nsTableCellFrame::Init(nsIPresContext& aPresContext, void nsTableCellFrame::InitCellFrame(PRInt32 aColIndex) { NS_PRECONDITION(0<=aColIndex, "bad col index arg"); - mColIndex = aColIndex; + SetColIndex(aColIndex); // this also sets the contents col index mBorderEdges.mOutsideEdge=PR_FALSE; nsTableFrame* tableFrame=nsnull; // I should be checking my own style context, but border-collapse isn't inheriting correctly nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); @@ -110,6 +112,33 @@ void nsTableCellFrame::InitCellFrame(PRInt32 aColIndex) } } +nsresult nsTableCellFrame::SetColIndex(PRInt32 aColIndex) +{ + mColIndex = aColIndex; + // for style context optimization, set the content's column index if possible. + // this can only be done if we really have an nsTableCell. + // other tags mapped to table cell display won't benefit from this optimization + // see nsHTMLStyleSheet::RulesMatching + + //nsIContent* cell; + //kidFrame->GetContent(&cell); + nsCOMPtr cell; + nsresult rv = GetContent(getter_AddRefs(cell)); + if (NS_FAILED(rv) || !cell) + return rv; + + nsIHTMLTableCellElement* cellContent = nsnull; + rv = cell->QueryInterface(kIHTMLTableCellElementIID, + (void **)&cellContent); // cellContent: REFCNT++ + if (cellContent && NS_SUCCEEDED(rv)) { // it's a table cell + cellContent->SetColIndex(aColIndex); + if (gsDebug) printf("%p : set cell content %p to col index = %d\n", this, cellContent, aColIndex); + NS_RELEASE(cellContent); + } + return rv; +} + + void nsTableCellFrame::SetBorderEdgeLength(PRUint8 aSide, PRInt32 aIndex, nscoord aLength) @@ -325,52 +354,49 @@ void nsTableCellFrame::VerticallyAlignChild() /* XXX: remove tableFrame when border-collapse inherits */ nsTableFrame* tableFrame=nsnull; nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_SUCCEEDED(rv) && tableFrame) - { - nsMargin borderPadding; - GetCellBorder (borderPadding, tableFrame); - nsMargin padding; - spacing->GetPadding(padding); - borderPadding += padding; + nsMargin borderPadding; + GetCellBorder (borderPadding, tableFrame); + nsMargin padding; + spacing->GetPadding(padding); + borderPadding += padding; - nscoord topInset = borderPadding.top; - nscoord bottomInset = borderPadding.bottom; - PRUint8 verticalAlignFlags = NS_STYLE_VERTICAL_ALIGN_MIDDLE; - if (textStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated) { - verticalAlignFlags = textStyle->mVerticalAlign.GetIntValue(); - } - nscoord height = mRect.height; - nsRect kidRect; - nsIFrame* firstKid = mFrames.FirstChild(); - firstKid->GetRect(kidRect); - nscoord childHeight = kidRect.height; - - - // Vertically align the child - nscoord kidYTop = 0; - switch (verticalAlignFlags) - { - case NS_STYLE_VERTICAL_ALIGN_BASELINE: - // Align the child's baseline at the max baseline - //kidYTop = aMaxAscent - kidAscent; - break; - - case NS_STYLE_VERTICAL_ALIGN_TOP: - // Align the top of the child frame with the top of the box, - // minus the top padding - kidYTop = topInset; - break; - - case NS_STYLE_VERTICAL_ALIGN_BOTTOM: - kidYTop = height - childHeight - bottomInset; - break; - - default: - case NS_STYLE_VERTICAL_ALIGN_MIDDLE: - kidYTop = height/2 - childHeight/2; - } - firstKid->MoveTo(kidRect.x, kidYTop); + nscoord topInset = borderPadding.top; + nscoord bottomInset = borderPadding.bottom; + PRUint8 verticalAlignFlags = NS_STYLE_VERTICAL_ALIGN_MIDDLE; + if (textStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated) { + verticalAlignFlags = textStyle->mVerticalAlign.GetIntValue(); } + nscoord height = mRect.height; + nsRect kidRect; + nsIFrame* firstKid = mFrames.FirstChild(); + firstKid->GetRect(kidRect); + nscoord childHeight = kidRect.height; + + + // Vertically align the child + nscoord kidYTop = 0; + switch (verticalAlignFlags) + { + case NS_STYLE_VERTICAL_ALIGN_BASELINE: + // Align the child's baseline at the max baseline + //kidYTop = aMaxAscent - kidAscent; + break; + + case NS_STYLE_VERTICAL_ALIGN_TOP: + // Align the top of the child frame with the top of the box, + // minus the top padding + kidYTop = topInset; + break; + + case NS_STYLE_VERTICAL_ALIGN_BOTTOM: + kidYTop = height - childHeight - bottomInset; + break; + + default: + case NS_STYLE_VERTICAL_ALIGN_MIDDLE: + kidYTop = height/2 - childHeight/2; + } + firstKid->MoveTo(kidRect.x, kidYTop); } PRInt32 nsTableCellFrame::GetRowSpan() @@ -486,7 +512,6 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext& aPresContext, /* XXX: remove tableFrame when border-collapse inherits */ nsTableFrame* tableFrame=nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_FAILED(rv)) { return rv; } nsMargin borderPadding; spacing->GetPadding(borderPadding); nsMargin border; @@ -527,7 +552,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext& aPresContext, aReflowState.reflowCommand->GetType(type); if (nsIReflowCommand::StyleChanged==type) { - rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus); + nsresult rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus); aStatus = NS_FRAME_COMPLETE; return rv; } @@ -674,7 +699,12 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext& aPresContext, // So here all we have to do is tell the table to rebalance. if (eReflowReason_Incremental == aReflowState.reason) { - tableFrame->InvalidateColumnWidths(); + nsTableFrame* tableFrame=nsnull; + rv = nsTableFrame::GetTableFrame(this, tableFrame); + if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) + { + tableFrame->InvalidateColumnWidths(); + } } @@ -1082,7 +1112,7 @@ PRUint8 nsTableCellFrame::GetOpposingEdge(PRUint8 aEdge) nscoord nsTableCellFrame::FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge) { nscoord result = 0; - PRInt32 theIndex = 0; + PRInt32 index = 0; PRInt32 count = 0; @@ -1093,9 +1123,9 @@ nscoord nsTableCellFrame::FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge) nsIFrame* frame; nscoord value = 0; - while (theIndex < count) + while (index < count) { - frame = (nsIFrame*)(aList->ElementAt(theIndex++)); + frame = (nsIFrame*)(aList->ElementAt(index++)); value = GetMargin(frame, aEdge); if (value > result) result = value; diff --git a/mozilla/layout/tables/nsTableCellFrame.h b/mozilla/layout/tables/nsTableCellFrame.h index 5489878638c..c068d4c6aef 100644 --- a/mozilla/layout/tables/nsTableCellFrame.h +++ b/mozilla/layout/tables/nsTableCellFrame.h @@ -124,6 +124,7 @@ public: /** return the cell's column index (starting at 0 for the first column) */ virtual nsresult GetColIndex(PRInt32 &aColIndex); + virtual nsresult SetColIndex(PRInt32 aColIndex); /** return the available width given to this frame during its last reflow */ virtual nscoord GetPriorAvailWidth(); diff --git a/mozilla/layout/tables/nsTableColFrame.cpp b/mozilla/layout/tables/nsTableColFrame.cpp index 5178a9c5747..98ee10562b1 100644 --- a/mozilla/layout/tables/nsTableColFrame.cpp +++ b/mozilla/layout/tables/nsTableColFrame.cpp @@ -32,10 +32,16 @@ static const PRBool gsDebug = PR_FALSE; #endif nsTableColFrame::nsTableColFrame() - : nsFrame() + : nsFrame(), mIsAnonymous(PR_FALSE), mProportion(WIDTH_NOT_SET) { // note that all fields are initialized to 0 by nsFrame::operator new - mWidthSource = eWIDTH_SOURCE_NONE; + for (PRInt32 widthX = 0; widthX < NUM_WIDTHS; widthX++) { + mWidths[widthX] = WIDTH_NOT_SET; + } +} + +nsTableColFrame::~nsTableColFrame() +{ } NS_METHOD nsTableColFrame::Paint(nsIPresContext& aPresContext, @@ -89,14 +95,63 @@ PRInt32 nsTableColFrame::GetSpan() return tableStyle->mSpan; } -nscoord nsTableColFrame::GetColWidthForComputation() +nscoord nsTableColFrame::GetWidth(PRUint32 aWidthType) { - const nsStylePosition* position; - GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)position)); - if (eStyleUnit_Coord==position->mWidth.GetUnit()) - return position->mWidth.GetCoordValue(); - else - return GetEffectiveMaxColWidth(); + NS_ASSERTION(aWidthType < NUM_WIDTHS, "GetWidth: bad width type"); + return mWidths[aWidthType]; +} + +void nsTableColFrame::SetWidth(PRUint32 aWidthType, + nscoord aWidth) +{ + NS_ASSERTION(aWidthType < NUM_WIDTHS, "SetWidth: bad width type"); + mWidths[aWidthType] = aWidth; +#ifdef MY_DEBUG + if (aWidth > 0) { + nscoord minWidth = GetMinWidth(); + if ((MIN_CON != aWidthType) && (aWidth < minWidth)) { + printf("non min width set to lower than min \n"); + } + } +#endif +} + +nscoord nsTableColFrame::GetMinWidth() +{ + return PR_MAX(mWidths[MIN_CON], mWidths[MIN_ADJ]); +} + +nscoord nsTableColFrame::GetDesWidth() +{ + return PR_MAX(mWidths[DES_CON], mWidths[DES_ADJ]); +} + +nscoord nsTableColFrame::GetFixWidth() +{ + return PR_MAX(mWidths[FIX], mWidths[FIX_ADJ]); +} + +nscoord nsTableColFrame::GetPctWidth() +{ + return PR_MAX(mWidths[PCT], mWidths[PCT_ADJ]); +} + +void nsTableColFrame::Dump(PRInt32 aIndent) +{ + char* indent = new char[aIndent + 1]; + for (PRInt32 i = 0; i < aIndent + 1; i++) { + indent[i] = ' '; + } + indent[aIndent] = 0; + + printf("%s**START COL DUMP** colIndex=%d isAnonymous=%d constraint=%d", + indent, mColIndex, mIsAnonymous, mConstraint); + printf("\n%s widths=", indent); + for (PRInt32 widthX = 0; widthX < NUM_WIDTHS; widthX++) { + printf("%d ", mWidths[widthX]); + } + printf(" **END COL DUMP** "); + delete [] indent; } /* ----- global methods ----- */ diff --git a/mozilla/layout/tables/nsTableColFrame.h b/mozilla/layout/tables/nsTableColFrame.h index 876b321160d..3bb204d4fb1 100644 --- a/mozilla/layout/tables/nsTableColFrame.h +++ b/mozilla/layout/tables/nsTableColFrame.h @@ -20,9 +20,36 @@ #include "nscore.h" #include "nsContainerFrame.h" +#include "nsTableFrame.h" class nsVoidArray; +// this is used to index arrays of widths in nsColFrame and to group important widths +// for calculations. It is important that the order: min, desired, fixed be maintained +// for each category (con, adj). +// XXX MIN_ADJ, DES_ADJ, PCT_ADJ, DES_PRO can probably go away and be replaced +// by MIN_CON, DES_CON, PCT_CON, DES_CON saving 16 bytes per col frame +#define WIDTH_NOT_SET -1 +#define NUM_WIDTHS 9 +#define NUM_MAJOR_WIDTHS 3 // MIN, DES, FIX +#define MIN_CON 0 // minimum width required of the content + padding +#define DES_CON 1 // desired width of the content + padding +#define FIX 2 // fixed width either from the content or cell, col, etc. + padding +#define MIN_ADJ 3 // minimum width + padding due to col spans +#define DES_ADJ 4 // desired width + padding due to col spans +#define FIX_ADJ 5 // fixed width + padding due to col spans +#define PCT 6 // percent width of cell or col +#define PCT_ADJ 7 // percent width of cell or col from percent colspan +#define MIN_PRO 8 // desired width due to proportional s or cols attribute + +enum nsColConstraint { + eNoConstraint = 0, + ePixelConstraint = 1, // pixel width + ePercentConstraint = 2, // percent width + eProportionConstraint = 3, // 1*, 2*, etc. cols attribute assigns 1* + e0ProportionConstraint = 4 // 0*, means to force to min width +}; + class nsTableColFrame : public nsFrame { public: @@ -67,57 +94,48 @@ public: /** convenience method, calls into cellmap */ nsVoidArray * GetCells(); - nscoord GetMaxColWidth(); - void SetMaxColWidth(nscoord aMaxColWidth); - - nscoord GetMinColWidth(); - void SetMinColWidth(nscoord aMinColWidth); - - nscoord GetEffectiveMaxColWidth(); - void SetEffectiveMaxColWidth(nscoord aMaxColWidth); - - nscoord GetEffectiveMinColWidth(); - void SetEffectiveMinColWidth(nscoord aMinColWidth); - // return the min width for this column after provisions for col spans have // been included. The adj min width is >= the min width. nscoord GetAdjustedMinColWidth(); void SetAdjustedMinColWidth(nscoord aMinColWidth); - // Return true if the column has a width either from HTML width attribute, - // from a style rule on the column, from a width attr/style on a cell - // that has colspan==1. - PRBool HasConstrainedWidth(); - void SetHasConstrainedWidth(PRBool aIsConstrained); + nscoord GetWidth(PRUint32 aWidthType); + void GetWidths(nscoord* aWidths); + void SetWidth(PRUint32 aWidthType, + nscoord aWidth); + nscoord GetMinWidth(); + nscoord GetDesWidth(); + nscoord GetFixWidth(); + nscoord GetPctWidth(); - PRInt32 GetWidthSource(); - void SetWidthSource(PRInt32 aMinColWidth); - - nscoord GetColWidthForComputation(); + void SetConstraint(nsColConstraint aConstraint); + nsColConstraint GetConstraint() const; /** convenience method, calls into cellmap */ PRInt32 Count() const; + /** Return true if this col was constructed implicitly due to cells needing a col. + * Return false if this col was constructed due to content having display type of table-col + */ + PRBool IsAnonymous(); + void SetIsAnonymous(PRBool aValue); + + void Dump(PRInt32 aIndent); + protected: nsTableColFrame(); + ~nsTableColFrame(); /** the starting index of the column (starting at 0) that this col object represents */ PRInt32 mColIndex; + PRBool mIsAnonymous; - nscoord mMaxColWidth; - nscoord mMinColWidth; - - nscoord mMaxEffectiveColWidth; - nscoord mMinEffectiveColWidth; - - nscoord mMinAdjustedColWidth; - - PRBool mHasConstrainedWidth; - - PRInt32 mWidthSource; - + // Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ + nscoord mWidths[NUM_WIDTHS]; + nscoord mProportion; // proportion for porportional width col + nsColConstraint mConstraint; }; @@ -133,46 +151,17 @@ inline PRInt32 nsTableColFrame::GetColumnIndex() inline void nsTableColFrame::SetColumnIndex (int aColIndex) { mColIndex = aColIndex;} -inline nscoord nsTableColFrame::GetMaxColWidth() -{ return mMaxColWidth; } +inline nsColConstraint nsTableColFrame::GetConstraint() const +{ return mConstraint; } -inline void nsTableColFrame::SetMaxColWidth(nscoord aMaxColWidth) -{ mMaxColWidth = aMaxColWidth; } +inline void nsTableColFrame::SetConstraint(nsColConstraint aConstraint) +{ mConstraint = aConstraint;} -inline nscoord nsTableColFrame::GetMinColWidth() -{ return mMinColWidth; } +inline PRBool nsTableColFrame::IsAnonymous() +{ return mIsAnonymous; } -inline void nsTableColFrame::SetMinColWidth(nscoord aMinColWidth) -{ mMinColWidth = aMinColWidth; } +inline void nsTableColFrame::SetIsAnonymous(PRBool aIsAnonymous) +{ mIsAnonymous = aIsAnonymous; } -inline nscoord nsTableColFrame::GetEffectiveMaxColWidth() -{ return mMaxEffectiveColWidth; } - -inline void nsTableColFrame::SetEffectiveMaxColWidth(nscoord aMaxColWidth) -{ mMaxEffectiveColWidth = aMaxColWidth; } - -inline nscoord nsTableColFrame::GetEffectiveMinColWidth() -{ return mMinEffectiveColWidth; } - -inline void nsTableColFrame::SetEffectiveMinColWidth(nscoord aMinEffectiveColWidth) -{ mMinEffectiveColWidth = aMinEffectiveColWidth; } - -inline nscoord nsTableColFrame::GetAdjustedMinColWidth() -{ return mMinAdjustedColWidth; } - -inline PRBool nsTableColFrame::HasConstrainedWidth() -{ return mHasConstrainedWidth; } - -inline void nsTableColFrame::SetHasConstrainedWidth(PRBool aIsConstrained) -{ mHasConstrainedWidth = aIsConstrained; } - -inline void nsTableColFrame::SetAdjustedMinColWidth(nscoord aMinAdjustedColWidth) -{ mMinAdjustedColWidth = aMinAdjustedColWidth; } - -inline PRInt32 nsTableColFrame::GetWidthSource() -{ return mWidthSource; } - -inline void nsTableColFrame::SetWidthSource(PRInt32 aWidthSource) -{ mWidthSource = aWidthSource; } #endif diff --git a/mozilla/layout/tables/nsTableColGroupFrame.cpp b/mozilla/layout/tables/nsTableColGroupFrame.cpp index bc427d65155..23558781024 100644 --- a/mozilla/layout/tables/nsTableColGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableColGroupFrame.cpp @@ -712,6 +712,11 @@ PRInt32 nsTableColGroupFrame::SetStartColumnIndex (int aIndex) return result; } +void nsTableColGroupFrame::DeleteColFrame(nsIPresContext& aPresContext, nsTableColFrame* aColFrame) +{ + mFrames.DestroyFrame(aPresContext, aColFrame); +} + /* ----- global methods ----- */ nsresult diff --git a/mozilla/layout/tables/nsTableColGroupFrame.h b/mozilla/layout/tables/nsTableColGroupFrame.h index 767c339c2df..cea8f0a8b3c 100644 --- a/mozilla/layout/tables/nsTableColGroupFrame.h +++ b/mozilla/layout/tables/nsTableColGroupFrame.h @@ -94,6 +94,8 @@ public: */ //PRBool IsManufactured(); + void DeleteColFrame(nsIPresContext& aPresContext, nsTableColFrame* aColFrame); + protected: /** implement abstract method on nsHTMLContainerFrame */ diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index 69698d5e2bf..3dd8a71ac09 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -75,9 +75,9 @@ static const PRInt32 kColumnWidthIncrement=100; /* CellData is the info stored in the cell map */ CellData::CellData() { - mCell = nsnull; - mRealCell = nsnull; - mOverlap = nsnull; + mOrigCell = nsnull; + mSpanData = nsnull; + mSpanData2 = nsnull; } CellData::~CellData() @@ -284,7 +284,6 @@ nsTableFrame::nsTableFrame() mColCache(nsnull), mTableLayoutStrategy(nsnull) { - mEffectiveColCount = -1; // -1 means uninitialized mColumnWidthsSet=PR_FALSE; mColumnWidthsLength = kColumnWidthIncrement; mColumnWidths = new PRInt32[mColumnWidthsLength]; @@ -401,8 +400,10 @@ nsTableFrame::SetInitialChildList(nsIPresContext& aPresContext, if (nsnull!=prevColGroupChild) prevColGroupChild->SetNextSibling(nsnull); - if (NS_SUCCEEDED(rv)) + if (NS_SUCCEEDED(rv)) { + //mCellMap->Dump(); EnsureColumns(aPresContext); + } return rv; } @@ -439,15 +440,14 @@ NS_IMETHODIMP nsTableFrame::DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFra /* counts columns in column groups */ PRInt32 nsTableFrame::GetSpecifiedColumnCount () { - mColCount=0; + PRInt32 colCount = 0; nsIFrame * childFrame = mColGroups.FirstChild(); - while (nsnull!=childFrame) - { - mColCount += ((nsTableColGroupFrame *)childFrame)->GetColumnCount(); + while (nsnull!=childFrame) { + colCount += ((nsTableColGroupFrame *)childFrame)->GetColumnCount(); childFrame->GetNextSibling(&childFrame); } - if (PR_TRUE==gsDebug) printf("TIF GetSpecifiedColumnCount: returning %d\n", mColCount); - return mColCount; + if (PR_TRUE==gsDebug) printf("TIF GetSpecifiedColumnCount: returning %d\n", colCount); + return colCount; } PRInt32 nsTableFrame::GetRowCount () const @@ -463,46 +463,14 @@ PRInt32 nsTableFrame::GetRowCount () const /* return the effective col count */ PRInt32 nsTableFrame::GetColCount () { - nsCellMap *cellMap = GetCellMap(); - NS_ASSERTION(nsnull!=cellMap, "GetColCount null cellmap"); - - if (nsnull!=cellMap) - { - //if (-1==mEffectiveColCount) - SetEffectiveColCount(); - } - return mEffectiveColCount; + PRInt32 colCount = 0; + nsCellMap* cellMap = GetCellMap(); + NS_ASSERTION(nsnull != cellMap, "GetColCount null cellmap"); + if (nsnull != cellMap) + colCount = cellMap->GetColCount(); + return colCount; } -void nsTableFrame::SetEffectiveColCount() -{ - nsCellMap *cellMap = GetCellMap(); - NS_ASSERTION(nsnull!=cellMap, "SetEffectiveColCount null cellmap"); - if (nsnull!=cellMap) - { - PRInt32 colCount = cellMap->GetColCount(); - mEffectiveColCount = colCount; - PRInt32 rowCount = cellMap->GetRowCount(); - for (PRInt32 colIndex=colCount-1; colIndex>0; colIndex--) - { - PRBool deleteCol=PR_TRUE; - for (PRInt32 rowIndex=0; rowIndexGetCellAt(rowIndex, colIndex); - if ((nsnull!=cell) && (cell->mCell != nsnull)) - { // found a real cell, so we're done - deleteCol = PR_FALSE; - break; - } - } - if (PR_TRUE==deleteCol) - mEffectiveColCount--; - else - break; - } - } - if (PR_TRUE==gsDebug) printf("TIF SetEffectiveColumnCount: returning %d\n", mEffectiveColCount); -} nsTableColFrame * nsTableFrame::GetColFrame(PRInt32 aColIndex) { @@ -525,79 +493,14 @@ nsTableCellFrame * nsTableFrame::GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColI CellData * cellData = cellMap->GetCellAt(aRowIndex, aColIndex); if (nsnull!=cellData) { - result = cellData->mCell; + result = cellData->mOrigCell; if (nsnull==result) - result = cellData->mRealCell->mCell; + result = cellData->mSpanData->mOrigCell; } } return result; } -/** returns PR_TRUE if the row at aRowIndex has any cells that are the result - * of a row-spanning cell. - * @see nsCellMap::RowIsSpannedInto - */ -PRBool nsTableFrame::RowIsSpannedInto(PRInt32 aRowIndex) -{ - NS_PRECONDITION (0<=aRowIndex && aRowIndexRowIsSpannedInto(aRowIndex); - } - return result; -} - -/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1 - * @see nsCellMap::RowHasSpanningCells - */ -PRBool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex) -{ - NS_PRECONDITION (0<=aRowIndex && aRowIndexRowHasSpanningCells(aRowIndex); - } - return result; -} - - -/** returns PR_TRUE if the col at aColIndex has any cells that are the result - * of a col-spanning cell. - * @see nsCellMap::ColIsSpannedInto - */ -PRBool nsTableFrame::ColIsSpannedInto(PRInt32 aColIndex) -{ - PRBool result = PR_FALSE; - nsCellMap * cellMap = GetCellMap(); - NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated."); - if (nsnull!=cellMap) - { - result = cellMap->ColIsSpannedInto(aColIndex); - } - return result; -} - -/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1 - * @see nsCellMap::ColHasSpanningCells - */ -PRBool nsTableFrame::ColHasSpanningCells(PRInt32 aColIndex) -{ - PRBool result = PR_FALSE; - nsCellMap * cellMap = GetCellMap(); - NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated."); - if (nsnull!=cellMap) - { - result = cellMap->ColHasSpanningCells(aColIndex); - } - return result; -} - // return the number of rows spanned by aCell starting at aRowIndex // note that this is different from just the rowspan of aCell // (that would be GetEffectiveRowSpan (indexOfRowThatContains_aCell, aCell) @@ -642,54 +545,38 @@ PRInt32 nsTableFrame::GetEffectiveRowSpan (PRInt32 aRowIndex, nsTableCellFrame * #endif } -// return the number of cols spanned by aCell starting at aColIndex -// note that this is different from just the colspan of aCell -// (that would be GetEffectiveColSpan (indexOfColThatContains_aCell, aCell) +PRInt32 nsTableFrame::GetEffectiveRowSpan(nsTableCellFrame *aCell) +{ + PRInt32 startRow; + aCell->GetRowIndex(startRow); + return GetEffectiveRowSpan(startRow, aCell); +} + + +// Return the number of cols spanned by aCell starting at aColIndex +// This is different from the colspan of aCell. If the cell spans no +// dead cells then the colSpan of the cell would be +// GetEffectiveColSpan (indexOfColThatContains_aCell, aCell) // // XXX Should be moved to colgroup, as GetEffectiveRowSpan should be moved to rowgroup? -PRInt32 nsTableFrame::GetEffectiveColSpan (PRInt32 aColIndex, nsTableCellFrame *aCell) +PRInt32 nsTableFrame::GetEffectiveColSpan(PRInt32 aColIndex, nsTableCellFrame* aCell) { - NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); - nsCellMap *cellMap = GetCellMap(); - NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated."); - PRInt32 colCount = GetColCount(); - NS_PRECONDITION (0<=aColIndex && aColIndexGetRowCount()==1) - return 1; - */ - PRInt32 colSpan = aCell->GetColSpan(); - if (colCount < (aColIndex + colSpan)) - result = colCount - aColIndex; - else - { - result = colSpan; - // check for case where all cells in a column have a colspan - PRInt32 initialColIndex; - aCell->GetColIndex(initialColIndex); - PRInt32 minColSpanForCol = cellMap->GetMinColSpan(initialColIndex); - result -= (minColSpanForCol - 1); // minColSpanForCol is always at least 1 - // and we want to treat default as 0 (no effect) - } -#ifdef NS_DEBUG - if (0>=result) - { - printf("ERROR!\n"); - DumpCellMap(); - PRInt32 initialColIndex; - aCell->GetColIndex(initialColIndex); - printf("aColIndex=%d, cell->colIndex=%d\n", aColIndex, initialColIndex); - printf("aCell->colSpan=%d\n", aCell->GetColSpan()); - printf("colCount=%d\n", mCellMap->GetColCount()); - } -#endif -NS_ASSERTION(0GetEffectiveColSpan(aColIndex, aCell); +} + +PRInt32 nsTableFrame::GetEffectiveColSpan(nsTableCellFrame* aCell) +{ + NS_PRECONDITION (nsnull != aCell, "bad cell arg"); + nsCellMap* cellMap = GetCellMap(); + NS_PRECONDITION (nsnull != cellMap, "bad call, cellMap not yet allocated."); + + PRInt32 initialColIndex; + aCell->GetColIndex(initialColIndex); + return cellMap->GetEffectiveColSpan(initialColIndex, aCell); } PRInt32 nsTableFrame::GetEffectiveCOLSAttribute() @@ -714,9 +601,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) { if (PR_TRUE==gsDebug) printf("TIF EnsureColumns\n"); NS_PRECONDITION(nsnull!=mCellMap, "bad state: null cellmap"); - // XXX sec should only be called on firstInFlow - SetMinColSpanForTable(); - if (nsnull==mCellMap) + if (nsnull == mCellMap) return; // no info yet, so nothing useful to do // make sure we've accounted for the COLS attribute @@ -726,8 +611,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) PRInt32 actualColumns = 0; nsTableColGroupFrame *lastColGroupFrame = nsnull; nsIFrame* childFrame = mColGroups.FirstChild(); - while (nsnull!=childFrame) - { + while (nsnull!=childFrame) { ((nsTableColGroupFrame*)childFrame)->SetStartColumnIndex(actualColumns); PRInt32 numCols = ((nsTableColGroupFrame*)childFrame)->GetColumnCount(); actualColumns += numCols; @@ -739,20 +623,17 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) // if we have fewer column frames than we need, create some implicit column frames PRInt32 colCount = mCellMap->GetColCount(); if (PR_TRUE==gsDebug) printf("EC: actual = %d, colCount=%d\n", actualColumns, colCount); - if (actualColumns < colCount) - { + if (actualColumns < colCount) { if (PR_TRUE==gsDebug) printf("TIF EnsureColumns: actual %d < colCount %d\n", actualColumns, colCount); nsIContent *lastColGroupElement = nsnull; - if (nsnull==lastColGroupFrame) - { // there are no col groups, so create an implicit colgroup frame + if (nsnull==lastColGroupFrame) { // there are no col groups, so create an implicit colgroup frame if (PR_TRUE==gsDebug) printf("EnsureColumns:creating colgroup frame\n"); // Resolve style for the colgroup frame // first, need to get the nearest containing content object GetContent(&lastColGroupElement); // ADDREF a: lastColGroupElement++ (either here or in the loop below) nsIFrame *parentFrame; GetParent(&parentFrame); - while (nsnull==lastColGroupElement) - { + while (nsnull==lastColGroupElement) { parentFrame->GetContent(&lastColGroupElement); if (nsnull==lastColGroupElement) parentFrame->GetParent(&parentFrame); @@ -775,8 +656,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) // hook lastColGroupFrame into child list mColGroups.SetFrames(lastColGroupFrame); } - else - { + else { lastColGroupFrame->GetContent(&lastColGroupElement); // ADDREF b: lastColGroupElement++ } @@ -789,8 +669,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) nsIFrame* lastNewColFrame = nsnull; nsIStyleContextPtr lastColGroupStyle; lastColGroupFrame->GetStyleContext(lastColGroupStyle.AssignPtr()); - for ( ; excessColumns > 0; excessColumns--) - { + for ( ; excessColumns > 0; excessColumns--) { // Create a new col frame nsIFrame* colFrame; // note we pass in PR_TRUE here to force unique style contexts. @@ -805,6 +684,7 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) colStyleContext, nsnull); NS_RELEASE(colStyleContext); colFrame->SetInitialChildList(aPresContext, nsnull, nsnull); + ((nsTableColFrame *)colFrame)->SetIsAnonymous(PR_TRUE); // Add it to our list if (nsnull == lastNewColFrame) { @@ -817,6 +697,13 @@ void nsTableFrame::EnsureColumns(nsIPresContext& aPresContext) lastColGroupFrame->SetInitialChildList(aPresContext, nsnull, firstNewColFrame); NS_RELEASE(lastColGroupElement); // ADDREF: lastColGroupElement-- } + else if (actualColumns > colCount) { // the cell map needs to grow to accomodate extra cols + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + cellMap->AddColsAtEnd(actualColumns - colCount); + } + } + } @@ -838,26 +725,12 @@ PRInt32 nsTableFrame::GetNextAvailRowIndex() const PRInt32 result=0; nsCellMap *cellMap = GetCellMap(); NS_PRECONDITION (nsnull!=cellMap, "null cellMap."); - if (nsnull!=cellMap) - { - result = cellMap->GetRowCount(); // the next index is the current count - cellMap->GrowToRow(result+1); // expand the cell map to include this new row + if (nsnull!=cellMap) { + result = cellMap->GetNextAvailRowIndex(); } return result; } -/** return the index of the next column in aRowIndex that does not have a cell assigned to it */ -PRInt32 nsTableFrame::GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const -{ - PRInt32 result=0; - nsCellMap *cellMap = GetCellMap(); - NS_PRECONDITION (nsnull!=cellMap, "null cellMap."); - if (nsnull!=cellMap) - result = cellMap->GetNextAvailColIndex(aRowIndex, aColIndex); - if (gsDebug==PR_TRUE) printf("TIF: GetNextAvailColIndex returning %d\n", result); - return result; -} - /** Get the cell map for this table frame. It is not always mCellMap. * Only the firstInFlow has a legit cell map */ @@ -871,89 +744,34 @@ nsCellMap * nsTableFrame::GetCellMap() const return mCellMap; } -void nsTableFrame::SetMinColSpanForTable() -{ // XXX: must be called ONLY on first-in-flow - // set the minColSpan for each column - PRInt32 rowCount = mCellMap->GetRowCount(); - PRInt32 colCount = mCellMap->GetColCount(); - for (PRInt32 colIndex=0; colIndexGetCellFrameAt(rowIndex, colIndex); - if (nsnull!=cellFrame) - { - PRInt32 colSpan = cellFrame->GetColSpan(); - if (0==minColSpan) - minColSpan = colSpan; - else - minColSpan = PR_MIN(minColSpan, colSpan); - } - } - if (1SetMinColSpan(colIndex, minColSpan); -#ifdef NS_DEBUG - if (gsDebug==PR_TRUE) - { - printf("minColSpan for col %d set to %d\n", colIndex, minColSpan); - DumpCellMap(); - } -#endif - } - } -} - -void nsTableFrame::AddCellToTable (nsTableRowFrame *aRowFrame, - nsTableCellFrame *aCellFrame, - PRBool aAddRow) +PRInt32 nsTableFrame::AddCellToTable(nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) { - NS_ASSERTION(nsnull!=aRowFrame, "bad aRowFrame arg"); - NS_ASSERTION(nsnull!=aCellFrame, "bad aCellFrame arg"); - NS_PRECONDITION(nsnull!=mCellMap, "bad cellMap"); + NS_ASSERTION(nsnull != aCellFrame, "bad aCellFrame arg"); + NS_ASSERTION(nsnull != mCellMap, "bad cellMap"); // XXX: must be called only on first-in-flow! if (gsDebug==PR_TRUE) printf("TIF AddCellToTable: frame %p\n", aCellFrame); - // Make an educated guess as to how many columns we have. It's - // only a guess because we can't know exactly until we have - // processed the last row. - if (0 == mColCount) - mColCount = GetSpecifiedColumnCount(); - if (0 == mColCount) // no column parts - { - mColCount = aRowFrame->GetMaxColumns(); - } + return mCellMap->AppendCell(aCellFrame, aRowIndex); +} - PRInt32 rowIndex; - // also determine the index of aRowFrame and set it if necessary - if (0==mCellMap->GetRowCount()) - { // this is the first time we've ever been called - rowIndex = 0; - if (gsDebug==PR_TRUE) printf("rowFrame %p set to index %d\n", aRowFrame, rowIndex); +void nsTableFrame::RemoveCellFromTable(nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) +{ + nsCellMap* cellMap = GetCellMap(); + PRInt32 numCols = cellMap->GetColCount(); + cellMap->RemoveCell(aCellFrame, aRowIndex); + if (numCols != cellMap->GetColCount()) { + // XXX need to remove the anonymous col frames at the end + //nsTableColFrame* colFrame = nsnull; + //GetColumnFrame(colIndex, colFrame); + //if (colFrame && colFrame->IsAnonymous()) { + // nsTableColGroupFrame* colGroupFrame = nsnull; + //colFrame->GetParent((nsIFrame **)&colGroupFrame); + //if (colGroupFrame) { + // colGroupFrame->DeleteColFrame(aPresContext, colFrame); } - else - { - rowIndex = mCellMap->GetRowCount() - 1; // rowIndex is 0-indexed, rowCount is 1-indexed - } - - PRInt32 colIndex=0; - while (PR_TRUE) - { - CellData *data = mCellMap->GetCellAt(rowIndex, colIndex); - if (nsnull == data) - { - BuildCellIntoMap(aCellFrame, rowIndex, colIndex); - break; - } - colIndex++; - } - -#ifdef NS_DEBUG - if (gsDebug==PR_TRUE) - DumpCellMap (); -#endif } static nsresult BuildCellMapForRowGroup(nsIFrame* rowGroupFrame) @@ -997,166 +815,6 @@ NS_METHOD nsTableFrame::ReBuildCellMap() return rv; } -#ifdef NS_DEBUG -void nsTableFrame::DumpCellMap () -{ - printf("dumping CellMap:\n"); - if (nsnull != mCellMap) { - PRInt32 colIndex; - PRInt32 rowCount = mCellMap->GetRowCount(); - PRInt32 colCount = mCellMap->GetColCount(); - printf("rowCount=%d, colCount=%d\n", rowCount, colCount); - - for (PRInt32 rowIndex = 0; rowIndex < rowCount; rowIndex++) { - printf("row %d : ", rowIndex); - for (colIndex = 0; colIndex < colCount; colIndex++) { - CellData* cd = mCellMap->GetCellAt(rowIndex, colIndex); - if (cd != nsnull) { - if (cd->mCell != nsnull) { - printf("C%d,%d ", rowIndex, colIndex); - } else { - nsTableCellFrame* cell = cd->mRealCell->mCell; - nsTableRowFrame* row; - cell->GetParent((nsIFrame**)&row); - int rr = row->GetRowIndex(); - int cc; - cell->GetColIndex(cc); - printf("S%d,%d ", rr, cc); - if (cd->mOverlap != nsnull){ - cell = cd->mOverlap->mCell; - nsTableRowFrame* row2; - cell->GetParent((nsIFrame**)&row2); - rr = row2->GetRowIndex(); - cell->GetColIndex(cc); - printf("O%d,%c ", rr, cc); - } - } - } else { - printf("---- "); - } - } - PRBool spanners = RowHasSpanningCells(rowIndex); - PRBool spannedInto = RowIsSpannedInto(rowIndex); - printf (" spanners=%s spannedInto=%s\n", spanners?"T":"F", spannedInto?"T":"F"); - } - - // output info mapping Ci,j to cell address - PRInt32 cellCount = 0; - for (PRInt32 rIndex = 0; rIndex < rowCount; rIndex++) { - for (colIndex = 0; colIndex < colCount; colIndex++) { - CellData* cd = mCellMap->GetCellAt(rIndex, colIndex); - if (cd != nsnull) { - if (cd->mCell != nsnull) { - printf("C%d,%d=%p ", rIndex, colIndex, cd->mCell); - cellCount++; - } - } - if (0 == (cellCount % 4)) { - printf("\n"); - } - } - } - - // output colspan info - for (colIndex=0; colIndexGetColumnFrame(colIndex); - printf ("col index %d has frame=%p\n", colIndex, colFrame); - } - } else { - printf ("[nsnull]"); - } -} -#endif - -void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex) -{ - NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); - NS_PRECONDITION (0 <= aColIndex, "bad column index arg"); - NS_PRECONDITION (0 <= aRowIndex, "bad row index arg"); - - // Setup CellMap for this cell - int rowSpan = aCell->GetRowSpan(); - int colSpan = aCell->GetColSpan(); - if (gsDebug==PR_TRUE) printf("BCIM: rowSpan = %d, colSpan = %d\n", rowSpan, colSpan); - - // Grow the mCellMap array if we will end up addressing - // some new columns. - if (mCellMap->GetColCount() < (aColIndex + colSpan)) - { - if (gsDebug==PR_TRUE) - printf("BCIM: calling GrowCellMap(%d)\n", aColIndex+colSpan); - GrowCellMap (aColIndex + colSpan); - } - - if (mCellMap->GetRowCount() < (aRowIndex+1)) - { - printf("BCIM: calling GrowToRow(%d)\n", aRowIndex+1); - mCellMap->GrowToRow(aRowIndex+1); - } - - // Setup CellMap for this cell in the table - CellData *data = new CellData (); - data->mCell = aCell; - data->mRealCell = data; - if (gsDebug==PR_TRUE) printf("BCIM: calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex); - mCellMap->SetCellAt(data, aRowIndex, aColIndex); - - // Create CellData objects for the rows that this cell spans. Set - // their mCell to nsnull and their mRealCell to point to data. If - // there were no column overlaps then we could use the same - // CellData object for each row that we span... - if ((1 < rowSpan) || (1 < colSpan)) - { - if (gsDebug==PR_TRUE) printf("BCIM: spans\n"); - for (int rowIndex = 0; rowIndex < rowSpan; rowIndex++) - { - if (gsDebug==PR_TRUE) printf("BCIM: rowIndex = %d\n", rowIndex); - int workRow = aRowIndex + rowIndex; - if (gsDebug==PR_TRUE) printf("BCIM: workRow = %d\n", workRow); - for (int colIndex = 0; colIndex < colSpan; colIndex++) - { - if (gsDebug==PR_TRUE) printf("BCIM: colIndex = %d\n", colIndex); - int workCol = aColIndex + colIndex; - if (gsDebug==PR_TRUE) printf("BCIM: workCol = %d\n", workCol); - CellData *testData = mCellMap->GetCellAt(workRow, workCol); - if (nsnull == testData) - { - CellData *spanData = new CellData (); - spanData->mRealCell = data; - if (gsDebug==PR_TRUE) printf("BCIM: null GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol); - mCellMap->SetCellAt(spanData, workRow, workCol); - } - else if ((0 < rowIndex) || (0 < colIndex)) - { // we overlap, replace existing data, it might be shared - if (gsDebug==PR_TRUE) printf("BCIM: overlapping Cell from GetCellFrameAt(%d, %d) so setting to spanData\n", workRow, workCol); - CellData *overlap = new CellData (); - overlap->mCell = testData->mCell; - overlap->mRealCell = testData->mRealCell; - overlap->mOverlap = data; - mCellMap->SetCellAt(overlap, workRow, workCol); - } - } - } - } -} - -void nsTableFrame::GrowCellMap (PRInt32 aColCount) -{ - if (nsnull!=mCellMap) - { - mCellMap->GrowToCol(aColCount); - mColCount = aColCount; - } -} - - /* ***** Column Layout Data methods ***** */ /* @@ -1243,7 +901,7 @@ void nsTableFrame::DidComputeHorizontalCollapsingBorders(nsIPresContext& aPresCo { CellData *cellData = mCellMap->GetCellAt(0, 0); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } nsRect rowRect(0,0,0,0); if (nsnull!=cellFrame) @@ -1267,7 +925,7 @@ void nsTableFrame::DidComputeHorizontalCollapsingBorders(nsIPresContext& aPresCo { CellData *cellData = mCellMap->GetCellAt(lastRowIndex, 0); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } nsRect rowRect(0,0,0,0); if (nsnull!=cellFrame) @@ -1405,7 +1063,7 @@ void nsTableFrame::ComputeLeftBorderForEdgeAt(nsIPresContext& aPresContext, { CellData *cellData = mCellMap->GetCellAt(aRowIndex, aColIndex); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } nsRect rowRect(0,0,0,0); if (nsnull!=cellFrame) @@ -1481,21 +1139,21 @@ void nsTableFrame::ComputeRightBorderForEdgeAt(nsIPresContext& aPresContext, CellData *cd = mCellMap->GetCellAt(aRowIndex, colIndex); if (cd != nsnull) { // there's really a cell at (aRowIndex, colIndex) - if (nsnull==cd->mCell) + if (nsnull==cd->mOrigCell) { // the cell at (aRowIndex, colIndex) is the result of a span - nsTableCellFrame *cell = cd->mRealCell->mCell; + nsTableCellFrame *cell = cd->mSpanData->mOrigCell; NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell"); PRInt32 realRowIndex; cell->GetRowIndex (realRowIndex); if (realRowIndex!=aRowIndex) { // the span is caused by a rowspan - rightNeighborFrame = cd->mRealCell->mCell; + rightNeighborFrame = cd->mSpanData->mOrigCell; break; } } else { - rightNeighborFrame = cd->mCell; + rightNeighborFrame = cd->mOrigCell; break; } } @@ -1522,7 +1180,7 @@ void nsTableFrame::ComputeRightBorderForEdgeAt(nsIPresContext& aPresContext, { CellData *cellData = mCellMap->GetCellAt(aRowIndex, aColIndex); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } nsRect rowRect(0,0,0,0); if (nsnull!=cellFrame) @@ -1623,7 +1281,7 @@ void nsTableFrame::ComputeTopBorderForEdgeAt(nsIPresContext& aPresContext, { CellData *cellData = mCellMap->GetCellAt(aRowIndex, aColIndex); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } if (nsnull!=cellFrame) { @@ -1704,21 +1362,21 @@ void nsTableFrame::ComputeBottomBorderForEdgeAt(nsIPresContext& aPresContext, CellData *cd = mCellMap->GetCellAt(rowIndex, aColIndex); if (cd != nsnull) { // there's really a cell at (rowIndex, aColIndex) - if (nsnull==cd->mCell) + if (nsnull==cd->mOrigCell) { // the cell at (rowIndex, aColIndex) is the result of a span - nsTableCellFrame *cell = cd->mRealCell->mCell; + nsTableCellFrame *cell = cd->mSpanData->mOrigCell; NS_ASSERTION(nsnull!=cell, "bad cell map state, missing real cell"); PRInt32 realColIndex; cell->GetColIndex (realColIndex); if (realColIndex!=aColIndex) { // the span is caused by a colspan - bottomNeighborFrame = cd->mRealCell->mCell; + bottomNeighborFrame = cd->mSpanData->mOrigCell; break; } } else { - bottomNeighborFrame = cd->mCell; + bottomNeighborFrame = cd->mOrigCell; break; } } @@ -1746,7 +1404,7 @@ void nsTableFrame::ComputeBottomBorderForEdgeAt(nsIPresContext& aPresContext, { CellData *cellData = mCellMap->GetCellAt(aRowIndex, aColIndex); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } nsRect rowRect(0,0,0,0); if (nsnull!=cellFrame) @@ -2091,7 +1749,7 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) CellData* cellData = cellMap->GetCellAt(row,col); if (cellData) - cell = cellData->mCell; + cell = cellData->mOrigCell; if (nsnull==cell) continue; @@ -2113,7 +1771,8 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) { cellData = cellMap->GetCellAt(row-1,col); if (nsnull != cellData) - above = cellData->mRealCell->mCell; +// XXX was above = cellData->mSpanData->mOrigCell; + above = (cellData->mOrigCell) ? cellData->mOrigCell : cellData->mSpanData->mOrigCell; // Does the cell data point to the same cell? // If it is, then continue @@ -2128,7 +1787,8 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) { cellData = cellMap->GetCellAt(row,col-1); if (cellData != nsnull) - left = cellData->mRealCell->mCell; +// XXX was left = cellData->mSpanData->mOrigCell; +left = (cellData->mOrigCell) ? cellData->mOrigCell : cellData->mSpanData->mOrigCell; if ((nsnull != left) && (left == cell)) continue; @@ -2158,9 +1818,9 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) if (c != col) { cellData = cellMap->GetCellAt(r1,c); - if ((cellData != nsnull) && (cellData->mCell != above)) + if ((cellData != nsnull) && (cellData->mOrigCell != above)) { - above = cellData->mCell; + above = cellData->mOrigCell; if (above != nsnull) AppendLayoutData(boundaryCells[NS_SIDE_TOP],above); } @@ -2175,9 +1835,9 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) { // Add bottom edge cells cellData = cellMap->GetCellAt(r2,c); - if ((cellData != nsnull) && cellData->mCell != below) + if ((cellData != nsnull) && cellData->mOrigCell != below) { - below = cellData->mCell; + below = cellData->mOrigCell; if (below != nsnull) AppendLayoutData(boundaryCells[NS_SIDE_BOTTOM],below); } @@ -2200,9 +1860,9 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) if (r != row) { cellData = cellMap->GetCellAt(r,c1); - if ((cellData != nsnull) && (cellData->mCell != left)) + if ((cellData != nsnull) && (cellData->mOrigCell != left)) { - left = cellData->mCell; + left = cellData->mOrigCell; if (left != nsnull) AppendLayoutData(boundaryCells[NS_SIDE_LEFT],left); } @@ -2217,9 +1877,9 @@ void nsTableFrame::RecalcLayoutData(nsIPresContext& aPresContext) { // Add right edge cells cellData = cellMap->GetCellAt(r,c2); - if ((cellData != nsnull) && (cellData->mCell != right)) + if ((cellData != nsnull) && (cellData->mOrigCell != right)) { - right = cellData->mCell; + right = cellData->mOrigCell; if (right != nsnull) AppendLayoutData(boundaryCells[NS_SIDE_RIGHT],right); } @@ -2443,20 +2103,25 @@ void nsTableFrame::SetColumnDimensions(nscoord aHeight) nsIFrame* colGroupFrame = mColGroups.FirstChild(); PRInt32 colX = 0; nsPoint colGroupOrigin(borderPadding.left, borderPadding.top); + PRInt32 numCols = GetColCount(); while (nsnull != colGroupFrame) { nscoord colGroupWidth = 0; nsIFrame* colFrame = nsnull; colGroupFrame->FirstChild(nsnull, &colFrame); nsPoint colOrigin(0, 0); while (nsnull != colFrame) { - NS_ASSERTION(colX < mColCount, "invalid number of columns"); - nscoord colWidth = mColumnWidths[colX] + cellSpacingX; - if (mColCount == 1) { + NS_ASSERTION(colX < numCols, "invalid number of columns"); + nscoord colWidth = mColumnWidths[colX]; + if (numCols == 1) { + colWidth += cellSpacingX + cellSpacingX; + } + else if ((0 == colX) || (numCols - 1 == colX)) { + colWidth += cellSpacingX + halfCellSpacingX; + } + else if (GetNumCellsOriginatingIn(colX) > 0) { colWidth += cellSpacingX; } - else if ((0 == colX) || (mColCount - 1 == colX)) { - colWidth += halfCellSpacingX; - } + colGroupWidth += colWidth; nsRect colRect(colOrigin.x, colOrigin.y, colWidth, colHeight); colFrame->SetRect(colRect); @@ -2523,8 +2188,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext, #ifdef NS_DEBUG if (PR_TRUE==gsDebugIR) { - DumpCellMap(); - printf("tableFrame thinks colCount is %d\n", mEffectiveColCount); + if (mCellMap) mCellMap->Dump(); } #endif needsRecalc=PR_TRUE; @@ -2599,10 +2263,6 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext, // set aDesiredSize and aMaxElementSize } - // DumpCellMap is useful for debugging the results of an incremental reflow. But it's noisy, - // so this module should not be checked in with the call enabled. - //DumpCellMap(); - if (PR_TRUE==gsDebug || PR_TRUE==gsDebugNT) { if (nsnull!=aDesiredSize.maxElementSize) @@ -2939,6 +2599,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext& aPresContext, NS_METHOD nsTableFrame::AdjustForCollapsingRowGroup(nsIFrame* aRowGroupFrame, PRInt32& aRowX) { + nsCellMap* cellMap = GetCellMap(); // XXX is this right const nsStyleDisplay* groupDisplay; aRowGroupFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)groupDisplay)); PRBool groupIsCollapsed = (NS_STYLE_VISIBILITY_COLLAPSE == groupDisplay->mVisible); @@ -2950,7 +2611,7 @@ NS_METHOD nsTableFrame::AdjustForCollapsingRowGroup(nsIFrame* aRowGroupFrame, rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { if (groupIsCollapsed || (NS_STYLE_VISIBILITY_COLLAPSE == rowDisplay->mVisible)) { - mCellMap->SetRowCollapsedAt(aRowX, PR_TRUE); + cellMap->SetRowCollapsedAt(aRowX, PR_TRUE); } aRowX++; } @@ -3009,9 +2670,9 @@ NS_METHOD nsTableFrame::CollapseRowGroup(nsIFrame* aRowGroupFrame, nsTableCellFrame* lastCell = nsnull; for (int colX = 0; colX < numCols; colX++) { CellData* cellData = mCellMap->GetCellAt(aRowX, colX); - if (cellData && !cellData->mCell) { // a cell above is spanning into here + if (cellData && !cellData->mOrigCell) { // a cell above is spanning into here // adjust the real cell's rect only once - nsTableCellFrame* realCell = cellData->mRealCell->mCell; + nsTableCellFrame* realCell = cellData->mSpanData->mOrigCell; if (realCell != lastCell) { nsRect realRect; realCell->GetRect(realRect); @@ -3147,7 +2808,7 @@ NS_METHOD nsTableFrame::AdjustForCollapsingCols(nsIPresContext& aPresContext, CellData* cellData = mCellMap->GetCellAt(rowX, col2X); nsRect cellRect; if (cellData) { - cellFrame = cellData->mCell; + cellFrame = cellData->mOrigCell; if (cellFrame) { // the cell originates at (rowX, colX) cellFrame->GetRect(cellRect); if (collapseGroup || collapseCol) { @@ -3161,7 +2822,7 @@ NS_METHOD nsTableFrame::AdjustForCollapsingCols(nsIPresContext& aPresContext, cellFrame->SetRect(cellRect); // if the cell does not originate at (rowX, colX), adjust the real cells width } else if (collapseGroup || collapseCol) { - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; if ((cellFrame) && (lastCell != cellFrame)) { cellFrame->GetRect(cellRect); cellRect.width -= colWidth + cellSpacingX; @@ -3674,7 +3335,7 @@ nscoord nsTableFrame::ComputeDesiredWidth(const nsHTMLReflowState& aReflowState) nsTableFrame* table = (nsTableFrame*)GetFirstInFlow(); tableLayoutStrategy = table->mTableLayoutStrategy; } - desiredWidth = tableLayoutStrategy->GetTableMaxWidth(); + desiredWidth = tableLayoutStrategy->GetTableMaxContentWidth(); } return desiredWidth; } @@ -4112,6 +3773,7 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext& aPresContext, } mTableLayoutStrategy->BalanceColumnWidths(mStyleContext, aReflowState, maxWidth); + //Dump(PR_TRUE, PR_TRUE); mColumnWidthsSet=PR_TRUE; // if collapsing borders, compute the top and bottom edges now that we have column widths @@ -4136,18 +3798,28 @@ void nsTableFrame::SetTableWidth(nsIPresContext& aPresContext) nscoord cellSpacing = GetCellSpacingX(); if (gsDebug==PR_TRUE) printf ("SetTableWidth with cellSpacing = %d ", cellSpacing); - PRInt32 tableWidth = cellSpacing; + PRInt32 tableWidth = 0; PRInt32 numCols = GetColCount(); - for (PRInt32 colIndex = 0; colIndex 0) { // skip degenerate cols + totalColWidth += cellSpacing; // add cell spacing to left of col + } + if (gsDebug == PR_TRUE) printf (" += %d ", totalColWidth); tableWidth += totalColWidth; } + if (numCols > 0) { + tableWidth += cellSpacing; // add last cellspacing + } + else if (0 == tableWidth) { + nsRect tableRect = mRect; + tableRect.width = 0; + SetRect(tableRect); + return; + } + // Compute the insets (sum of border and padding) const nsStyleSpacing* spacing = (const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing); @@ -4402,6 +4074,8 @@ nscoord nsTableFrame::ComputeDesiredHeight(nsIPresContext& aPresContext, void nsTableFrame::AdjustColumnsForCOLSAttribute() { +// XXX this is not right, +#if 0 nsCellMap *cellMap = GetCellMap(); NS_ASSERTION(nsnull!=cellMap, "bad cell map"); @@ -4431,6 +4105,7 @@ void nsTableFrame::AdjustColumnsForCOLSAttribute() } } } +#endif } /* @@ -4440,11 +4115,16 @@ void nsTableFrame::AdjustColumnsForCOLSAttribute() because specified widths tell us what proportion of the span width to give to each column (in their absence, we use the desired width of the cell.) */ + +// XXX this is being phased out. cells with colspans will potentially overwrite +// col info stored by cells that don't span just because they are a bigger value. +// The fixed width column info should be gotten from nsTableColFrame::GetFixedWidth NS_METHOD nsTableFrame::SetColumnStyleFromCell(nsIPresContext & aPresContext, nsTableCellFrame* aCellFrame, nsTableRowFrame * aRowFrame) { +#if 0 // if the cell has a colspan, the width is used provisionally, divided equally among // the spanned columns until the table layout strategy computes the real column width. if (PR_TRUE==gsDebug) printf("TIF SetCSFromCell: cell %p in row %p\n", aCellFrame, aRowFrame); @@ -4535,6 +4215,7 @@ nsTableFrame::SetColumnStyleFromCell(nsIPresContext & aPresContext, } } } +#endif return NS_OK; } @@ -4703,7 +4384,7 @@ void nsTableFrame::CacheColFramesInCellMap() PRInt32 repeat = colFrame->GetSpan(); for (PRInt32 i=0; iGetColumnFrame(colIndex+i); + nsTableColFrame *cachedColFrame = mCellMap->GetColumnFrame(colIndex+i); if (nsnull==cachedColFrame) { if (gsDebug) @@ -5392,12 +5073,10 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, const nsHTMLReflowState& aReflowState, nscoord& aSpecifiedTableWidth) { - NS_ASSERTION(nsnull!=aTableStyle, "bad arg - aTableStyle"); + NS_ASSERTION(nsnull != aTableStyle, "bad arg - aTableStyle"); PRBool result = PR_TRUE; // the default - if (nsnull!=aTableStyle) - { + if (aTableStyle) { nsStylePosition* tablePosition = (nsStylePosition*)aTableStyle->GetStyleData(eStyleStruct_Position); - nsMargin borderPadding; const nsStyleSpacing* spacing; switch (tablePosition->mWidth.GetUnit()) { case eStyleUnit_Auto: // specified auto width @@ -5413,12 +5092,8 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, { nscoord coordWidth = tablePosition->mWidth.GetCoordValue(); // NAV4 compatibility. If coord width is 0, do nothing so we get same result as "auto" - if (0!=coordWidth) - { + if (0 != coordWidth) { aSpecifiedTableWidth = coordWidth; - aReflowState.frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); - spacing->CalcBorderPaddingFor(aReflowState.frame, borderPadding); //XXX: COLLAPSE - aSpecifiedTableWidth -= (borderPadding.right + borderPadding.left); result = PR_FALSE; } } @@ -5429,9 +5104,9 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, // set aSpecifiedTableWidth to be the given percent of the parent. // first, get the effective parent width (parent width - insets) nscoord parentWidth = nsTableFrame::GetTableContainerWidth(aReflowState); - if (NS_UNCONSTRAINEDSIZE!=parentWidth) - { + if (NS_UNCONSTRAINEDSIZE != parentWidth) { aReflowState.frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); + nsMargin borderPadding; spacing->CalcBorderPaddingFor(aReflowState.frame, borderPadding); //XXX: COLLAPSE parentWidth -= (borderPadding.right + borderPadding.left); @@ -5442,8 +5117,7 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, printf("%p: TableIsAutoWidth setting aSpecifiedTableWidth = %d with parentWidth = %d and percent = %f\n", aTableFrame, aSpecifiedTableWidth, parentWidth, percent); } - else - { + else { aSpecifiedTableWidth=parentWidth; if (PR_TRUE==gsDebug || PR_TRUE==gsDebugNT) printf("%p: TableIsAutoWidth setting aSpecifiedTableWidth = %d with parentWidth = %d\n", @@ -5469,20 +5143,20 @@ nscoord nsTableFrame::GetMinCaptionWidth() } /** return the minimum width of the table. Return 0 if the min width is unknown. */ -nscoord nsTableFrame::GetMinTableWidth() +nscoord nsTableFrame::GetMinTableContentWidth() { nscoord result = 0; if (nsnull!=mTableLayoutStrategy) - result = mTableLayoutStrategy->GetTableMinWidth(); + result = mTableLayoutStrategy->GetTableMinContentWidth(); return result; } /** return the maximum width of the table. Return 0 if the max width is unknown. */ -nscoord nsTableFrame::GetMaxTableWidth() +nscoord nsTableFrame::GetMaxTableContentWidth() { nscoord result = 0; if (nsnull!=mTableLayoutStrategy) - result = mTableLayoutStrategy->GetTableMaxWidth(); + result = mTableLayoutStrategy->GetTableMaxContentWidth(); return result; } @@ -5533,6 +5207,29 @@ nsTableFrame::IsFinalPass(const nsReflowState& aState) (NS_UNCONSTRAINEDSIZE != aState.availableHeight); } +void nsTableFrame::Dump(PRBool aDumpCols, PRBool aDumpCellMap) +{ + printf("***START TABLE DUMP***, \n colWidths="); + PRInt32 colX; + PRInt32 numCols = GetColCount(); + for (colX = 0; colX < numCols; colX++) { + printf("%d ", mColumnWidths[colX]); + } + if (aDumpCols) { + for (colX = 0; colX < numCols; colX++) { + printf("\n"); + nsTableColFrame* colFrame = GetColFrame(colX); + colFrame->Dump(1); + } + } + if (aDumpCellMap) { + printf("\n"); + nsCellMap* cellMap = GetCellMap(); + cellMap->Dump(); + } + printf(" ***END TABLE DUMP*** \n"); +} + // nsTableIterator nsTableIterator::nsTableIterator(nsIFrame& aSource, nsTableIteration aType) @@ -5632,4 +5329,86 @@ PRInt32 nsTableIterator::Count() return mCount; } +void nsTableFrame::GetCellInfoAt(PRInt32 aRowX, + PRInt32 aColX, + nsTableCellFrame*& aCellFrame, + PRBool& aOriginates, + PRInt32& aColSpan) +{ + nsCellMap* cellMap = GetCellMap(); + cellMap->GetCellInfoAt(aRowX, aColX, aCellFrame, aOriginates, aColSpan); +} +PRInt32 nsTableFrame::GetNumCellsOriginatingIn(PRInt32 aColIndex) +{ + nsCellMap* cellMap = GetCellMap(); + return cellMap->GetNumCellsOriginatingIn(aColIndex); +} + +// The following are not used anywhere, but have been retained here just in case. +#if 0 +/** returns PR_TRUE if the row at aRowIndex has any cells that are the result + * of a row-spanning cell. + * @see nsCellMap::RowIsSpannedInto + */ +PRBool nsTableFrame::RowIsSpannedInto(PRInt32 aRowIndex) +{ + NS_PRECONDITION (0<=aRowIndex && aRowIndexRowIsSpannedInto(aRowIndex); + } + return result; +} + +/** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1 + * @see nsCellMap::RowHasSpanningCells + */ +PRBool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex) +{ + NS_PRECONDITION (0<=aRowIndex && aRowIndexRowHasSpanningCells(aRowIndex); + } + return result; +} + + +/** returns PR_TRUE if the col at aColIndex has any cells that are the result + * of a col-spanning cell. + * @see nsCellMap::ColIsSpannedInto + */ +PRBool nsTableFrame::ColIsSpannedInto(PRInt32 aColIndex) +{ + PRBool result = PR_FALSE; + nsCellMap * cellMap = GetCellMap(); + NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated."); + if (nsnull!=cellMap) + { + result = cellMap->ColIsSpannedInto(aColIndex); + } + return result; +} + +/** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1 + * @see nsCellMap::ColHasSpanningCells + */ +PRBool nsTableFrame::ColHasSpanningCells(PRInt32 aColIndex) +{ + PRBool result = PR_FALSE; + nsCellMap * cellMap = GetCellMap(); + NS_PRECONDITION (nsnull!=cellMap, "bad call, cellMap not yet allocated."); + if (nsnull!=cellMap) + { + result = cellMap->ColHasSpanningCells(aColIndex); + } + return result; +} +#endif diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h index c9f7184012e..328ec1a8e92 100644 --- a/mozilla/layout/tables/nsTableFrame.h +++ b/mozilla/layout/tables/nsTableFrame.h @@ -47,6 +47,7 @@ struct nsStyleSpacing; #define NS_TABLE_FRAME_COLGROUP_LIST_INDEX 0 #define NS_TABLE_FRAME_LAST_LIST_INDEX NS_TABLE_FRAME_COLGROUP_LIST_INDEX + /* ============================================================================ */ /** nsTableFrame maps the inner portion of a table (everything except captions.) @@ -91,14 +92,6 @@ public: /** @see nsIFrame::Destroy */ NS_IMETHOD Destroy(nsIPresContext& aPresContext); - /** helper method for determining if this is a nested table or not - * @param aReflowState The reflow state for this inner table frame - * @param aPosition [OUT] The position style struct for the parent table, if nested. - * If not nested, undefined. - * @return PR_TRUE if this table is nested inside another table. - */ - PRBool IsNested(const nsHTMLReflowState& aReflowState, const nsStylePosition *& aPosition) const; - /** helper method to find the table parent of any table frame object */ // TODO: today, this depends on display types. This should be changed to rely // on stronger criteria, like an inner table frame atom @@ -377,6 +370,7 @@ public: * of the table. */ virtual PRInt32 GetEffectiveRowSpan(PRInt32 aRowIndex, nsTableCellFrame *aCell); + virtual PRInt32 GetEffectiveRowSpan(nsTableCellFrame *aCell); /** return the col span of a cell, taking into account col span magic at the edge * of a table. @@ -388,6 +382,7 @@ public: * of the table. */ virtual PRInt32 GetEffectiveColSpan(PRInt32 aColIndex, nsTableCellFrame *aCell); + virtual PRInt32 GetEffectiveColSpan(nsTableCellFrame *aCell); /** return the value of the COLS attribute, adjusted for the * actual number of columns in the table @@ -399,23 +394,24 @@ public: */ PRInt32 GetNextAvailRowIndex() const; - /** return the index of the next column in aRowIndex after aColIndex - * that does not have a cell assigned to it. - * If aColIndex is past the end of the row, it is returned. - * If the row is not initialized, 0 is returned. - */ - PRInt32 GetNextAvailColIndex(PRInt32 aRowIndex, PRInt32 aColIndex) const; - /** build as much of the CellMap as possible from the info we have so far */ - virtual void AddCellToTable (nsTableRowFrame *aRowFrame, - nsTableCellFrame *aCellFrame, - PRBool aAddRow); + virtual PRInt32 AddCellToTable (nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex); + virtual void RemoveCellFromTable (nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex); virtual void AddColumnFrame (nsTableColFrame *aColFrame); static PRBool IsFinalPass(const nsReflowState& aReflowState); + void GetCellInfoAt(PRInt32 aRowX, + PRInt32 aColX, + nsTableCellFrame*& aCellFrame, + PRBool& aOriginates, + PRInt32& aColSpan); + PRInt32 GetNumCellsOriginatingIn(PRInt32 aColIndex); + NS_METHOD GetBorderPlusMarginPadding(nsMargin& aResult); protected: @@ -433,6 +429,14 @@ protected: virtual PRBool ParentDisablesSelection() const; //override default behavior + /** helper method for determining if this is a nested table or not + * @param aReflowState The reflow state for this inner table frame + * @param aPosition [OUT] The position style struct for the parent table, if nested. + * If not nested, undefined. + * @return PR_TRUE if this table is nested inside another table. + */ + PRBool IsNested(const nsHTMLReflowState& aReflowState, const nsStylePosition *& aPosition) const; + public: /** first pass of ResizeReflow. * lays out all table content with aMaxSize(NS_UNCONSTRAINEDSIZE,NS_UNCONSTRAINEDSIZE) and @@ -700,14 +704,15 @@ protected: void MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBorderWidth); PRBool ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult); - /** called whenever the number of columns changes, to increase the storage in mCellMap - */ - virtual void GrowCellMap(PRInt32 aColCount); - /** returns PR_TRUE if the cached pass 1 data is still valid */ virtual PRBool IsCellMapValid() const; public: + /** Get the cell map for this table frame. It is not always mCellMap. + * Only the firstInFlow has a legit cell map + */ + virtual nsCellMap *GetCellMap() const; + /** ResetCellMap is called when the cell structure of the table is changed. * Call with caution, only when changing the structure of the table such as * inserting or removing rows, changing the rowspan or colspan attribute of a cell, etc. @@ -718,19 +723,9 @@ protected: /** iterates all child frames and creates a new cell map */ NS_IMETHOD ReBuildCellMap(); - /** Get the cell map for this table frame. It is not always mCellMap. - * Only the firstInFlow has a legit cell map - */ - virtual nsCellMap *GetCellMap() const; - void SetColumnDimensions(nscoord aHeight); #ifdef NS_DEBUG - /** for debugging only - * prints out information about the cell map - */ - void DumpCellMap(); - /** for debugging only * prints out info about the table layout state, printing columns and their cells */ @@ -743,9 +738,6 @@ protected: */ virtual void EnsureColumns (nsIPresContext& aPresContext); - /** Set the min col span for every column in the table. Scans the whole table. */ - virtual void SetMinColSpanForTable(); - virtual void BuildColumnCache(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -756,16 +748,6 @@ protected: virtual void CacheColFramesInCellMap(); - /** called every time we discover we have a new cell to add to the table. - * This could be because we got actual cell content, because of rowspan/colspan attributes, etc. - * This method changes mCellMap as necessary to account for the new cell. - * - * @param aCell the content object created for the cell - * @param aRowIndex the row into which the cell is to be inserted - * @param aColIndex the col into which the cell is to be inserted - */ - virtual void BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex); - /** return the number of columns as specified by the input. * has 2 side effects:
* calls SetStartColumnIndex on each nsTableColumn
@@ -786,13 +768,9 @@ public: /* ----- Cell Map public methods ----- */ */ virtual PRInt32 GetRowCount() const; - /** returns the number of columns in this table. */ - virtual PRInt32 GetColCount(); - - /** adjust the col count for screwy table attributes. - * currently just handles excess colspan at end of table + /** returns the number of columns in this table after redundant columns have been removed */ - virtual void SetEffectiveColCount(); + virtual PRInt32 GetColCount(); /** return the column frame at colIndex. * returns nsnull if the col frame has not yet been allocated, or if aColIndex is out of range @@ -805,37 +783,16 @@ public: /* ----- Cell Map public methods ----- */ */ nsTableCellFrame * GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex); - /** returns PR_TRUE if the row at aRowIndex has any cells that are the result - * of a row-spanning cell above it. - * @see nsCellMap::RowIsSpannedInto - */ - PRBool RowIsSpannedInto(PRInt32 aRowIndex); - - /** returns PR_TRUE if the row at aRowIndex has any cells that have a rowspan>1 - * that originate in aRowIndex. - * @see nsCellMap::RowHasSpanningCells - */ - PRBool RowHasSpanningCells(PRInt32 aRowIndex); - - /** returns PR_TRUE if the col at aColIndex has any cells that are the result - * of a col-spanning cell. - * @see nsCellMap::ColIsSpannedInto - */ - PRBool ColIsSpannedInto(PRInt32 aColIndex); - - /** returns PR_TRUE if the row at aColIndex has any cells that have a colspan>1 - * @see nsCellMap::ColHasSpanningCells - */ - PRBool ColHasSpanningCells(PRInt32 aColIndex); - /** return the minimum width of the table caption. Return 0 if there is no caption. */ nscoord GetMinCaptionWidth(); - /** return the minimum width of the table. Return 0 if the min width is unknown. */ - nscoord GetMinTableWidth(); + /** return the minimum contend width of the table (excludes borders and padding). + Return 0 if the min width is unknown. */ + nscoord GetMinTableContentWidth(); - /** return the maximum width of the table caption. Return 0 if the max width is unknown. */ - nscoord GetMaxTableWidth(); + /** return the maximum content width of the table (excludes borders and padding). + Return 0 if the max width is unknown. */ + nscoord GetMaxTableContentWidth(); /** compute the max-element-size for the table * @param aMaxElementSize [OUT] width field set to the min legal width of the table @@ -847,6 +804,7 @@ public: /* ----- Cell Map public methods ----- */ public: static nsIAtom* gColGroupAtom; + void Dump(PRBool aDumpCols, PRBool aDumpCellMap); protected: void DebugPrintCount() const; // Debugging routine @@ -862,7 +820,6 @@ protected: PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change PRBool mHasScrollableRowGroup; // PR_TRUE if any section has overflow == "auto" or "scroll" PRInt32 mColCount; // the number of columns in this table - PRInt32 mEffectiveColCount; // the number of columns in this table adjusted for weird table attributes nsCellMap* mCellMap; // maintains the relationships between rows, cols, and cells ColumnInfoCache *mColCache; // cached information about the table columns nsITableLayoutStrategy * mTableLayoutStrategy; // the layout strategy for this frame diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index 82ed2a40cbf..fccb0a19cee 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -17,6 +17,7 @@ */ #include "nsTableRowFrame.h" #include "nsIRenderingContext.h" +#include "nsIPresShell.h" #include "nsIPresContext.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" @@ -31,6 +32,10 @@ #include "nsCSSRendering.h" #include "nsHTMLIIDs.h" #include "nsLayoutAtoms.h" +#include "nsHTMLParts.h" +#include "nsTableColGroupFrame.h" +#include "nsTableColFrame.h" +#include "nsCOMPtr.h" // the following header files are required for style optimizations that work only when the child content is really a cell #include "nsIHTMLTableCellElement.h" static NS_DEFINE_IID(kIHTMLTableCellElementIID, NS_IHTMLTABLECELLELEMENT_IID); @@ -117,7 +122,7 @@ nsTableRowFrame::Init(nsIPresContext& aPresContext, } NS_IMETHODIMP -nsTableRowFrame::InitChildren(PRInt32 aRowIndex) +nsTableRowFrame::InitChildren() { if (gsDebug) printf("Row InitChildren: begin\n"); nsTableFrame* table = nsnull; @@ -132,11 +137,7 @@ nsTableRowFrame::InitChildren(PRInt32 aRowIndex) if ((NS_OK==result) && (table != nsnull)) { mInitializedChildren=PR_TRUE; - PRInt32 rowIndex; - if (-1==aRowIndex) - rowIndex = table->GetNextAvailRowIndex(); - else - rowIndex = aRowIndex; + PRInt32 rowIndex = table->GetNextAvailRowIndex(); SetRowIndex(rowIndex); if (gsDebug) printf("Row InitChildren: set row index to %d\n", rowIndex); PRInt32 colIndex = 0; @@ -146,33 +147,14 @@ nsTableRowFrame::InitChildren(PRInt32 aRowIndex) kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { + // add the cell frame to the table's cell map and get its col index + PRInt32 colIndex; + colIndex = table->AddCellToTable((nsTableCellFrame *)kidFrame, rowIndex); // what column does this cell belong to? - colIndex = table->GetNextAvailColIndex(mRowIndex, colIndex); - if (gsDebug) printf("Row InitChildren: cell given colIndex %d\n", colIndex); - /* for style context optimization, set the content's column index if possible. - * this can only be done if we really have an nsTableCell. - * other tags mapped to table cell display won't benefit from this optimization - * see nsHTMLStyleSheet::RulesMatching - */ - nsIContent* cell; - kidFrame->GetContent(&cell); - nsIHTMLTableCellElement *cellContent = nsnull; - nsresult rv = cell->QueryInterface(kIHTMLTableCellElementIID, - (void **)&cellContent); // cellContent: REFCNT++ - NS_RELEASE(cell); - if (NS_SUCCEEDED(rv)) - { // we know it's a table cell - cellContent->SetColIndex(colIndex); - if (gsDebug) printf("%p : set cell content %p to col index = %d\n", this, cellContent, colIndex); - NS_RELEASE(cellContent); - } - + if (gsDebug) printf("Row InitChildren: cell given colIndex %d\n", colIndex); // this sets the frame's notion of it's column index ((nsTableCellFrame *)kidFrame)->InitCellFrame(colIndex); - if (gsDebug) printf("%p : set cell frame %p to col index = %d\n", this, kidFrame, colIndex); - // add the cell frame to the table's cell map - if (gsDebug) printf("Row InitChildren: calling AddCellToTable...\n"); - table->AddCellToTable(this, (nsTableCellFrame *)kidFrame, kidFrame == mFrames.FirstChild()); + if (gsDebug) printf("%p : set cell frame %p to col index = %d\n", this, kidFrame, colIndex); } } } @@ -515,17 +497,16 @@ void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext, aReflowState.x += aKidRect.width; // Update the maximum element size - PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan(mRowIndex, - ((nsTableCellFrame*)aKidFrame)); - if (nsnull != aMaxElementSize) - { + PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan((nsTableCellFrame*)aKidFrame); + if (nsnull != aMaxElementSize) { aMaxElementSize->width += aKidMaxElementSize->width; - if ((mMinRowSpan==rowSpan) && (aKidMaxElementSize->height>aMaxElementSize->height)) - { - aMaxElementSize->height = aKidMaxElementSize->height; + if (1 == rowSpan) { + aMaxElementSize->height = PR_MAX(aMaxElementSize->height, aKidMaxElementSize->height); } } +// XXX this will be fixed when row spans deal with dead rows +#if 0 // this accounts for cases where all cells in a row have a rowspan>1 // XXX "numColsInThisRow==numColsInTable" probably isn't the right metric to use here // the point is to skip a cell who's span effects another row, maybe use cellmap? @@ -548,6 +529,23 @@ void nsTableRowFrame::PlaceChild(nsIPresContext& aPresContext, aReflowState.maxCellVertSpace = height; } } +#else + if (1 == rowSpan) { + // Update maxCellHeight + if (aKidRect.height > aReflowState.maxCellHeight) + aReflowState.maxCellHeight = aKidRect.height; + + // Update maxCellVertSpace + nsMargin margin; + + if (aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)aKidFrame, margin) == NS_OK) { + nscoord height = aKidRect.height + margin.top + margin.bottom; + + if (height > aReflowState.maxCellVertSpace) + aReflowState.maxCellVertSpace = height; + } + } +#endif } /** @@ -615,7 +613,9 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, if (prevColIndex != (cellColIndex - 1)) { for (PRInt32 colIndex = prevColIndex + 1; cellColIndex > colIndex; colIndex++) { aReflowState.x += aReflowState.tableFrame->GetColumnWidth(colIndex); - aReflowState.x += cellSpacingX; + if (aReflowState.tableFrame->GetNumCellsOriginatingIn(colIndex) > 0) { + aReflowState.x += cellSpacingX; + } if (PR_TRUE==gsDebug) printf(" Row: in loop, aReflowState.x set to %d from cellSpacing %d and col width %d\n", aReflowState.x, cellSpacingX, aReflowState.tableFrame->GetColumnWidth(colIndex)); @@ -627,7 +627,9 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, PRInt32 lastCol = cellColIndex + cellColSpan - 1; for (PRInt32 colIndex = prevColIndex - 1; colIndex > lastCol; colIndex--) { aReflowState.x += aReflowState.tableFrame->GetColumnWidth(colIndex); - aReflowState.x += cellSpacingX; + if (aReflowState.tableFrame->GetNumCellsOriginatingIn(colIndex) > 0) { + aReflowState.x += cellSpacingX; + } if (PR_TRUE==gsDebug) printf(" Row: in loop, aReflowState.x set to %d from cellSpacing %d and col width %d\n", aReflowState.x, cellSpacingX, aReflowState.tableFrame->GetColumnWidth(colIndex)); @@ -641,16 +643,15 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, // at this point, we know the column widths. // so we get the avail width from the known column widths nscoord availWidth = 0; - for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellColIndex+numColSpan); - if (numColSpan != 0) - { + if ((numColSpan != 0) && (aReflowState.tableFrame->GetNumCellsOriginatingIn(cellColIndex + numColSpan) > 0)) { availWidth += cellSpacingX; } - if (PR_TRUE==gsDebug) + if (PR_TRUE==gsDebug) { printf(" Row: in loop, availWidth set to %d from colIndex %d width %d and cellSpacing\n", availWidth, cellColIndex, aReflowState.tableFrame->GetColumnWidth(cellColIndex+numColSpan)); + } } if (PR_TRUE==gsDebug) printf(" Row: availWidth for this cell is %d\n", availWidth); // remember the rightmost (ltr) or leftmost (rtl) column this cell spans into @@ -777,21 +778,21 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, // we were given by the row group frame aDesiredSize.width = aReflowState.x; aDesiredSize.height = aReflowState.maxCellVertSpace; +#ifdef DEBUG + nscoord overAllocated = aDesiredSize.width - aReflowState.reflowState.availableWidth; + if (overAllocated > 0) { + float p2t; + aPresContext.GetScaledPixelsToTwips(&p2t); + if (overAllocated > p2t) { + printf("row over allocated by %d twips", overAllocated); + } + } +#endif if (gsDebug) printf("Row: RR -- row %p width = %d from maxSize %d\n", this, aDesiredSize.width, aReflowState.reflowState.availableWidth); - if (aDesiredSize.width > aReflowState.reflowState.availableWidth) - { - if (gsDebug) - { - printf ("Row %p error case, desired width = %d, maxSize=%d\n", - this, aDesiredSize.width, aReflowState.reflowState.availableWidth); - fflush (stdout); - } - } - NS_ASSERTION(aDesiredSize.width <= aReflowState.reflowState.availableWidth, "row calculated to be too wide."); return rv; } @@ -1153,6 +1154,7 @@ NS_METHOD nsTableRowFrame::IR_CellInserted(nsIPresContext& aPresContext, if (NS_FAILED(rv) || nsnull==tableFrame) return rv; +#if 0 // do a pass-1 layout of the cell if (PR_TRUE==tableFrame->RequiresPass1Layout()) { @@ -1161,6 +1163,7 @@ NS_METHOD nsTableRowFrame::IR_CellInserted(nsIPresContext& aPresContext, if (NS_FAILED(rv)) return rv; } +#endif // set row state GetMinRowSpan(tableFrame); @@ -1169,6 +1172,7 @@ NS_METHOD nsTableRowFrame::IR_CellInserted(nsIPresContext& aPresContext, // set table state tableFrame->InvalidateCellMap(); tableFrame->InvalidateColumnCache(); + tableFrame->InvalidateColumnWidths(); return rv; } @@ -1184,7 +1188,7 @@ NS_METHOD nsTableRowFrame::IR_CellAppended(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, RowReflowState& aReflowState, nsReflowStatus& aStatus, - nsTableCellFrame * aAppendedFrame) + nsTableCellFrame* aAppendedFrame) { if (PR_TRUE==gsDebugIR) printf("\nTRF IR: IR_CellInserted\n"); @@ -1197,6 +1201,7 @@ NS_METHOD nsTableRowFrame::IR_CellAppended(nsIPresContext& aPresContext, if (NS_FAILED(rv) || nsnull==tableFrame) return rv; + tableFrame->AddCellToTable(aAppendedFrame, GetRowIndex()); // do a pass-1 layout of the cell if (PR_TRUE==tableFrame->RequiresPass1Layout()) { @@ -1260,9 +1265,33 @@ NS_METHOD nsTableRowFrame::IR_CellRemoved(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, RowReflowState& aReflowState, nsReflowStatus& aStatus, - nsTableCellFrame * aDeletedFrame) + nsTableCellFrame* aDeletedFrame) { if (PR_TRUE==gsDebugIR) printf("\nRow IR: IR_RowRemoved\n"); + + nsTableFrame* tableFrame=nsnull; + nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); + if (NS_FAILED(rv) || nsnull == tableFrame) + return rv; + + PRInt32 colIndex; + aDeletedFrame->GetColIndex(colIndex); + tableFrame->RemoveCellFromTable(aDeletedFrame, GetRowIndex()); + rv = mFrames.DestroyFrame(aPresContext, (nsIFrame*)aDeletedFrame); + if (NS_FAILED(rv)) + return rv; + + ResetMaxChildHeight(); + + // set row state + GetMinRowSpan(tableFrame); + FixMinCellHeight(tableFrame); + + // set table state + tableFrame->InvalidateCellMap(); + tableFrame->InvalidateColumnCache(); + +#if 0 nsresult rv = mFrames.DestroyFrame(aPresContext, (nsIFrame*)aDeletedFrame); if (NS_SUCCEEDED(rv)) { @@ -1271,19 +1300,11 @@ NS_METHOD nsTableRowFrame::IR_CellRemoved(nsIPresContext& aPresContext, rv = nsTableFrame::GetTableFrame(this, tableFrame); if (NS_FAILED(rv) || nsnull==tableFrame) return rv; +#endif - // set row state - GetMinRowSpan(tableFrame); - FixMinCellHeight(tableFrame); - - // set table state - tableFrame->InvalidateCellMap(); - tableFrame->InvalidateColumnCache(); - - // if any column widths have to change due to this, rebalance column widths - //XXX need to calculate this, but for now just do it - tableFrame->InvalidateColumnWidths(); - } + // if any column widths have to change due to this, rebalance column widths + //XXX need to calculate this, but for now just do it + tableFrame->InvalidateColumnWidths(); return rv; } diff --git a/mozilla/layout/tables/nsTableRowFrame.h b/mozilla/layout/tables/nsTableRowFrame.h index dbb1535c4b9..cddb6b6b175 100644 --- a/mozilla/layout/tables/nsTableRowFrame.h +++ b/mozilla/layout/tables/nsTableRowFrame.h @@ -45,7 +45,7 @@ public: nsIFrame* aPrevInFlow); /** Initialization of data */ - NS_IMETHOD InitChildren(PRInt32 aRowIndex=-1); + NS_IMETHOD InitChildren(); void ResetInitChildren(); diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index 6611c38338e..00394daff15 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -468,15 +468,13 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext& aPresC kidRect.height); PRInt32 colCount = aReflowState.tableFrame->GetColCount(); PRInt32 colIndex = 0; - nsIFrame *cellFrame = aReflowState.tableFrame->GetCellFrameAt(rowIndex, colIndex); - while (colIndexGetCellFrameAt(rowIndex, colIndex); + if (cellFrame) { const nsStyleDisplay *cellDisplay; cellFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)cellDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == cellDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_CELL == cellDisplay->mDisplay) { ((nsTableCellFrame *)(cellFrame))->SetBorderEdgeLength(NS_SIDE_LEFT, rowIndex, kidRect.height); @@ -485,8 +483,6 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext& aPresC kidRect.height); } } - colIndex++; - cellFrame = aReflowState.tableFrame->GetCellFrameAt(rowIndex, colIndex); } } } @@ -668,7 +664,6 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, // the avail height needs to reduce by top and bottom margins nscoord availHeightOfRowsSpanned = heightOfRowsSpanned - cellSpacingY - cellSpacingY; if (gsDebug) printf("TRGF CalcRowH: availHeightOfRowsSpanned=%d\n", availHeightOfRowsSpanned); - /* if the cell height fits in the rows, expand the spanning cell's height and slap it in */ nsSize cellFrameSize; cellFrame->GetSize(cellFrameSize); diff --git a/mozilla/layout/xul/base/src/nsTreeFrame.cpp b/mozilla/layout/xul/base/src/nsTreeFrame.cpp index 666a632a5e6..ea92d374587 100644 --- a/mozilla/layout/xul/base/src/nsTreeFrame.cpp +++ b/mozilla/layout/xul/base/src/nsTreeFrame.cpp @@ -97,7 +97,7 @@ void nsTreeFrame::ToggleSelection(nsIPresContext& aPresContext, nsTreeCellFrame* { CellData *cellData = mCellMap->GetCellAt(rowIndex, colIndex); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } // Select this cell frame. @@ -150,7 +150,7 @@ void nsTreeFrame::RangedSelection(nsIPresContext& aPresContext, nsTreeCellFrame* { CellData *cellData = mCellMap->GetCellAt(i, colIndex); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } // We now have the cell that should be selected. @@ -251,7 +251,7 @@ void nsTreeFrame::MoveToRowCol(nsIPresContext& aPresContext, PRInt32 row, PRInt3 { CellData *cellData = mCellMap->GetCellAt(row, col); if (nsnull!=cellData) - cellFrame = cellData->mRealCell->mCell; + cellFrame = cellData->mSpanData->mOrigCell; } // We now have the cell that should be selected.