From 51fe86ee7980f5ecee899a320648caba8cff16d5 Mon Sep 17 00:00:00 2001 From: "buster%netscape.com" Date: Thu, 16 Jul 1998 23:23:31 +0000 Subject: [PATCH] fundemental overhaul of the BasicTableLayoutStrategy We now cache lots of useful info in the colframes we now properly account for margins just as uniform cellspacing --- .../table/src/BasicTableLayoutStrategy.cpp | 939 ++++++++---------- .../html/table/src/BasicTableLayoutStrategy.h | 122 +-- .../html/table/src/nsITableLayoutStrategy.h | 21 +- layout/html/table/src/nsTableCellFrame.cpp | 8 +- layout/html/table/src/nsTableColFrame.cpp | 7 +- layout/html/table/src/nsTableColFrame.h | 46 +- layout/html/table/src/nsTableFrame.cpp | 103 +- layout/html/table/src/nsTableFrame.h | 20 +- layout/html/table/src/nsTableRowFrame.cpp | 36 +- layout/tables/BasicTableLayoutStrategy.cpp | 939 ++++++++---------- layout/tables/BasicTableLayoutStrategy.h | 122 +-- layout/tables/nsITableLayoutStrategy.h | 21 +- layout/tables/nsTableCellFrame.cpp | 8 +- layout/tables/nsTableColFrame.cpp | 7 +- layout/tables/nsTableColFrame.h | 46 +- layout/tables/nsTableFrame.cpp | 103 +- layout/tables/nsTableFrame.h | 20 +- layout/tables/nsTableRowFrame.cpp | 36 +- 18 files changed, 1324 insertions(+), 1280 deletions(-) diff --git a/layout/html/table/src/BasicTableLayoutStrategy.cpp b/layout/html/table/src/BasicTableLayoutStrategy.cpp index 34be3091e71a..168b3c0606bf 100644 --- a/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -89,39 +89,14 @@ PRBool BasicTableLayoutStrategy::IsFixedWidth(const nsStylePosition* aStylePosit PRBool result = PR_FALSE; // assume that it is not fixed width PRInt32 unitType; if (nsnull == aStylePosition) { - unitType = eStyleUnit_Auto; + result=PR_TRUE; } else { unitType = aStylePosition->mWidth.GetUnit(); + if (eStyleUnit_Coord==unitType) + result=PR_TRUE; } - switch (unitType) { - case eStyleUnit_Coord: - result = PR_TRUE; - - case eStyleUnit_Auto: - case eStyleUnit_Proportional: - case eStyleUnit_Percent: - break; - - // TODO - case eStyleUnit_Inherit: - break; - - default: - NS_ASSERTION(PR_FALSE, "illegal style type in IsFixedWidth"); - break; - } - return result; -} - -PRBool BasicTableLayoutStrategy::IsAutoWidth(const nsStylePosition* aStylePosition) -{ - PRBool result = PR_TRUE; // assume that it is - if (nsnull!=aStylePosition) - { - result = (PRBool)(eStyleUnit_Auto==aStylePosition->mWidth.GetUnit()); - } return result; } @@ -132,6 +107,10 @@ BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame, PRInt32 mTableFrame = aFrame; mNumCols = aNumCols; + mMinTableWidth=0; + mMaxTableWidth=0; + mFixedTableWidth=0; + //cache the value of the cols attribute nsIFrame * tableFrame = mTableFrame; // begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! XXX @@ -146,93 +125,7 @@ BasicTableLayoutStrategy::~BasicTableLayoutStrategy() { } -PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext *aTableStyle, - const nsReflowState& aReflowState, - nscoord aMaxWidth, - nscoord &aTotalFixedWidth, - nscoord &aMinTableWidth, - nscoord &aMaxTableWidth, - nsSize* aMaxElementSize) -{ - PRBool result = PR_TRUE; - // initialize out parameters - aTotalFixedWidth=aMinTableWidth=aMaxTableWidth=0; - - // Step 1 - assign the width of all fixed-width columns - AssignFixedColumnWidths(aPresContext, aMaxWidth, aTotalFixedWidth, aMinTableWidth, aMaxTableWidth); - - if (nsnull!=aMaxElementSize) - { // this is where we initialize maxElementSize if it is non-null - aMaxElementSize->height = 0; - aMaxElementSize->width = aMinTableWidth; - if (gsDebug) printf(" setting aMaxElementSize->width = %d\n", aMaxElementSize->width); - } - else - { - if (gsDebug) printf(" nsnull aMaxElementSize\n"); - } - - // Step 2 - determine how much space is really available - PRInt32 availWidth = aMaxWidth - aTotalFixedWidth; - nscoord tableWidth = 0; - PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(mTableFrame, aTableStyle, aReflowState, tableWidth); - if (PR_FALSE==tableIsAutoWidth) - availWidth = tableWidth - aTotalFixedWidth; - - // Step 3 - assign the width of all proportional-width columns in the remaining space - if (gsDebug==PR_TRUE) printf ("Step 2...\n availWidth = %d\n", availWidth); - result = BalanceProportionalColumns(aPresContext, aReflowState, - availWidth, aMaxWidth, - aMinTableWidth, aMaxTableWidth, - tableWidth, tableIsAutoWidth); - return result; -} - -/* -STEP 1 -for every col - if the col has a fixed width - set the width to max(fixed width, maxElementSize) - if the cell spans columns, divide the cell width between the columns - else skip it for now - -take borders and padding into account - -STEP 2 -determine the min and max size for the table width -if col is proportionately specified - if (col width specified to 0) - col width = minColWidth - else if (minTableWidth >= aMaxSize.width) - set col widths to min, install a hor. scroll bar - else if (maxTableWidth <= aMaxSize.width) - set each col to its max size - else - W = aMaxSize.width - minTableWidth - D = maxTableWidth - minTableWidth - for each col - d = maxColWidth - minColWidth - col width = minColWidth + ((d*W)/D) - -STEP 3 -if there is space left over - for every col - if col is proportionately specified - add space to col width until it is that proportion of the table width - do this non-destructively in case there isn't enough space - if there isn't enough space as determined in the prior step, - add space in proportion to the proportionate width attribute - */ - - -// Step 1 - assign the width of all fixed-width columns, -// and calculate min/max table width -PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresContext, - nscoord aMaxWidth, - nscoord &aTotalFixedWidth, - nscoord &aMinTableWidth, - nscoord &aMaxTableWidth) +PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize) { #ifdef DEBUG nsIFrame *tablePIF=nsnull; @@ -240,18 +133,87 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!"); #endif - if (gsDebug==PR_TRUE) printf (" AssignFixedColumnWidths\n"); + PRBool result = PR_TRUE; + + // Step 1 - assign the width of all fixed-width columns + AssignPreliminaryColumnWidths(); + + // set aMaxElementSize here because we compute mMinTableWidth in AssignPreliminaryColumnWidths + if (nsnull!=aMaxElementSize) + { + aMaxElementSize->height = 0; + aMaxElementSize->width = mMinTableWidth; + if (PR_TRUE==gsDebug) printf("BTLS::Init setting aMaxElementSize->width = %d\n", aMaxElementSize->width); + } + + return result; +} + +PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext *aTableStyle, + const nsReflowState& aReflowState, + nscoord aMaxWidth) +{ +#ifdef DEBUG + nsIFrame *tablePIF=nsnull; + mTableFrame->GetPrevInFlow(tablePIF); + NS_ASSERTION(nsnull==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); + + // Step 2 - determine how much space is really available + PRInt32 availWidth = aMaxWidth - mFixedTableWidth; + if (PR_FALSE==tableIsAutoWidth) + availWidth = specifiedTableWidth - mFixedTableWidth; + + // Step 3 - assign the width of all proportional-width columns in the remaining space + 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); + } + if (PR_TRUE==gsDebug) + { + printf("\n%p: BEGIN BALANCE COLUMN WIDTHS\n", mTableFrame); + for (PRInt32 i=0; iGetColumnWidth(i)); + printf("\n"); + } + result = BalanceProportionalColumns(aReflowState, availWidth, aMaxWidth, + specifiedTableWidth, tableIsAutoWidth); + + if (PR_TRUE==gsDebug) + { + printf("\n%p: END BALANCE COLUMN WIDTHS\n", mTableFrame); + for (PRInt32 i=0; iGetColumnWidth(i)); + printf("\n"); + } + return result; +} + +// 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() +{ + if (gsDebug==PR_TRUE) printf ("** %p: AssignPreliminaryColumnWidths **\n", mTableFrame); nsVoidArray *spanList=nsnull; nsVoidArray *colSpanList=nsnull; - nscoord * effectiveColumnWidths = new nscoord[mNumCols]; // used for Nav4 compatible table fluffing - nsCRT::memset (effectiveColumnWidths, 0, mNumCols*sizeof(PRInt32)); PRBool hasColsAttribute = (PRBool)(NS_STYLE_TABLE_COLS_NONE!=mCols); - PRInt32 *minColWidthArray = nsnull; - PRInt32 *maxColWidthArray = nsnull; + 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]; } @@ -261,11 +223,10 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo // for every column, determine it's min and max width, and keep track of the table width for (PRInt32 colIndex = 0; colIndexGetColFrame(colIndex); @@ -275,22 +236,16 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition); - // Get column width if it has one + // Get fixed column width if it has one PRBool haveColWidth = PR_FALSE; nscoord specifiedFixedColWidth=0; - switch (colPosition->mWidth.GetUnit()) { - case eStyleUnit_Coord: - haveColWidth = PR_TRUE; - specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); - mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); - break; - - default: - break; + if (eStyleUnit_Coord==colPosition->mWidth.GetUnit()) + { + haveColWidth = PR_TRUE; + specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); } - // TODO - use specifiedFixedColWidth to influence the width when both col span and fixed col width are given - /* Scan the column, simulatneously assigning fixed column widths + /* Scan the column, simulatneously assigning column widths * and computing the min/max column widths */ // first, deal with any cells that span into this column from a pervious column @@ -301,14 +256,16 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--) { SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex)); - if (minColWidth < spanInfo->cellMinWidth) - minColWidth = spanInfo->cellMinWidth; - if (maxColWidth < spanInfo->cellDesiredWidth) - maxColWidth = spanInfo->cellDesiredWidth; + nscoord cellMinWidth = (spanInfo->cellMinWidth)/(spanInfo->initialColSpan); + if (minColWidth < cellMinWidth) + minColWidth = cellMinWidth; + nscoord cellDesiredWidth = (spanInfo->cellDesiredWidth)/(spanInfo->initialColSpan); + if (maxColWidth < cellDesiredWidth) + maxColWidth = cellDesiredWidth; spanInfo->span--; if (gsDebug==PR_TRUE) printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n", - spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth); + spanIndex, spanInfo->span, cellMinWidth, cellDesiredWidth); if (0==spanInfo->span) { spanList->RemoveElementAt(spanIndex); @@ -318,6 +275,7 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo } PRInt32 firstRowIndex = -1; + PRInt32 maxColSpan = 1; for (PRInt32 rowIndex = 0; rowIndexGetCellAt(rowIndex, colIndex); @@ -332,55 +290,52 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check continue; } + PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); + if (colSpan>maxColSpan) + maxColSpan = colSpan; if (colIndex!=cellFrame->GetColIndex()) { - // For cells that span rows, we only figure it in once + // 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; } nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); - PRInt32 colSpan = cellFrame->GetColSpan(); + nscoord cellDesiredWidth = cellDesiredSize.width/colSpan; if (gsDebug==PR_TRUE) - printf (" for cell %d with colspan=%d, min = %d,%d and des = %d,%d\n", + printf (" for cell %d with colspan=%d, min = %d,%d and des = %d,%d\n", rowIndex, colSpan, cellMinSize.width, cellMinSize.height, cellDesiredSize.width, cellDesiredSize.height); - switch (colPosition->mWidth.GetUnit()) + if (PR_TRUE==haveColWidth) { - case eStyleUnit_Coord: - { - // This col has a fixed width, so set the cell's width to the - // larger of (specified width, largest max_element_size of the - // cells in the column) - nscoord widthForThisCell = PR_MAX(cellMinSize.width, colPosition->mWidth.GetCoordValue()); - widthForThisCell = widthForThisCell/colSpan; - nscoord widthFromCol = mTableFrame->GetColumnWidth(colIndex); - if (widthFromCol < widthForThisCell) - { - if (gsDebug) printf (" setting fixed width to %d\n",widthForThisCell); - mTableFrame->SetColumnWidth(colIndex, widthForThisCell); - maxColWidth = widthForThisCell; - } - } - break; - - default: - break; - + // This col has a specified fixed width so set the minand max width to the larger of + // (specified width, largest max_element_size of the cells in the column) + nscoord widthForThisCell = PR_MAX(cellMinSize.width, colPosition->mWidth.GetCoordValue()); + widthForThisCell = widthForThisCell/colSpan; + mTableFrame->SetColumnWidth(colIndex, widthForThisCell); + maxColWidth = widthForThisCell; + minColWidth = widthForThisCell; + if ((1==colSpan) && (effectiveMaxColumnWidth < widthForThisCell)) + effectiveMaxColumnWidth = widthForThisCell; + if (gsDebug) + printf (" setting min and max col width to specified fixed width %d\n", widthForThisCell); + } + else + { + if (maxColWidth < cellDesiredWidth) + maxColWidth = cellDesiredWidth; + if ((1==colSpan) && (effectiveMaxColumnWidth < maxColWidth)) + effectiveMaxColumnWidth = cellDesiredWidth; } - // regardless of the width specification, keep track of the - // min/max column widths + // cellMinWidth can override fixed width, so factor it in here nscoord cellMinWidth = cellMinSize.width/colSpan; - nscoord cellDesiredWidth = cellDesiredSize.width/colSpan; if (minColWidth < cellMinWidth) minColWidth = cellMinWidth; - if (maxColWidth < cellDesiredWidth) - maxColWidth = cellDesiredWidth; - // effectiveColumnWidth is the width as if no cells with colspans existed - if ((1==colSpan) && (effectiveColumnWidths[colIndex] < maxColWidth)) - effectiveColumnWidths[colIndex] = cellDesiredWidth; + // effectiveMinColumnWidth is the min width as if no cells with colspans existed + if ((1==colSpan) && (effectiveMinColumnWidth < cellMinWidth)) + effectiveMinColumnWidth = cellMinWidth; if (1GetCellAt(firstRowIndex, colIndex); - nsMargin colMargin; - firstCellInColumn->GetMargin(colMargin); - nscoord colInset = colMargin.left + colMargin.right; + nscoord colInset = mTableFrame->GetCellSpacing(); // keep a running total of the amount of space taken up by all fixed-width columns if (PR_TRUE==haveColWidth) - aTotalFixedWidth += mTableFrame->GetColumnWidth(colIndex) + colInset; - + mFixedTableWidth += specifiedFixedColWidth + (colInset*maxColSpan); if (gsDebug) { - printf (" after col %d, aTotalFixedWidth = %d\n", - colIndex, aTotalFixedWidth); + printf (" after col %d, mFixedTableWidth = %d\n", colIndex, mFixedTableWidth); } + + // cache the computed column info + colFrame->SetMinColWidth(minColWidth); + colFrame->SetMaxColWidth(maxColWidth); + colFrame->SetEffectiveMinColWidth(effectiveMinColumnWidth); + colFrame->SetEffectiveMaxColWidth(effectiveMaxColumnWidth); + mTableFrame->SetColumnWidth(colIndex, maxColWidth); + // add col[i] metrics to the running totals for the table min/max width - if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth) - aMinTableWidth += minColWidth + colInset; - if (aMinTableWidth<=0) - aMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow - if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth) - aMaxTableWidth += maxColWidth + colInset; - if (aMaxTableWidth<=0) - aMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow + if (NS_UNCONSTRAINEDSIZE!=mMinTableWidth) + mMinTableWidth += minColWidth + colInset; + if (mMinTableWidth<=0) + mMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow + if (NS_UNCONSTRAINEDSIZE!=mMaxTableWidth) + mMaxTableWidth += maxColWidth + colInset; + if (mMaxTableWidth<=0) + mMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow if (PR_TRUE==hasColsAttribute) { minColWidthArray[colIndex] = minColWidth; @@ -430,12 +388,11 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo } if (gsDebug==PR_TRUE) printf (" after col %d, minTableWidth = %d and maxTableWidth = %d\n", - colIndex, aMinTableWidth, aMaxTableWidth); - - } // end Step 1 for fixed-width columns + colIndex, mMinTableWidth, mMaxTableWidth); + } // now, post-process the computed values based on the table attributes - // if there is a COLS attribute, fix up aMinTableWidth and aMaxTableWidth + // 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 @@ -456,29 +413,31 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo { // subtract out the prior contributions of this column // and add back in the adjusted value - if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth) + if (NS_UNCONSTRAINEDSIZE!=mMinTableWidth) { - aMinTableWidth -= minColWidthArray[effectedColIndex]; - aMinTableWidth += maxOfMinColWidths; + mMinTableWidth -= minColWidthArray[effectedColIndex]; + mMinTableWidth += maxOfMinColWidths; } - if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth) + if (NS_UNCONSTRAINEDSIZE!=mMaxTableWidth) { - aMaxTableWidth -= maxColWidthArray[effectedColIndex]; - aMaxTableWidth += maxOfMaxColWidths; + mMaxTableWidth -= maxColWidthArray[effectedColIndex]; + mMaxTableWidth += maxOfMaxColWidths; } + nsTableColFrame *colFrame; + mTableFrame->GetColumnFrame(effectedColIndex, colFrame); + colFrame->SetMaxColWidth(maxOfMaxColWidths); // cache the new column max width (min width is uneffected) + colFrame->SetEffectiveMaxColWidth(maxOfMaxColWidths); } delete [] minColWidthArray; delete [] maxColWidthArray; } if (nsnull!=colSpanList) - DistributeFixedSpace(colSpanList, effectiveColumnWidths); - // today we always allocate effectiveColumnWidths, but tomorrow we might be smarter, so leave the check in - if (nsnull!=effectiveColumnWidths) - delete [] effectiveColumnWidths; + DistributeFixedSpace(colSpanList); if (PR_TRUE==gsDebug) - printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, aMinTableWidth, aMaxTableWidth); - + printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, mMinTableWidth, mMaxTableWidth); + + // clean up if (nsnull!=spanList) delete spanList; if (nsnull!=colSpanList) @@ -497,10 +456,10 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo // take the fixed space spanned by the columns in aColSpanList // and distribute it proportionately (based on desired width) -void BasicTableLayoutStrategy::DistributeFixedSpace(nsVoidArray *aColSpanList, nscoord *aColWidths) +void BasicTableLayoutStrategy::DistributeFixedSpace(nsVoidArray *aColSpanList) { nscoord excess = 0; - if (PR_TRUE==gsDebug) printf ("DistributeFixedSpace:\n"); + if (PR_TRUE==gsDebug) printf ("** 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; nextSpanningCellGetColumnFrame(colIndex+i, colFrame); + totalEffectiveWidth += colFrame->GetEffectiveMaxColWidth(); } // 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)(aColWidths[colIndex+i]))/((float)totalEffectiveWidth); + percent = ((float)(colFrame->GetEffectiveMaxColWidth()))/((float)totalEffectiveWidth); nscoord colWidth = (nscoord)(totalColWidth*percent); if (gsDebug==PR_TRUE) printf(" assigning fixed col width for spanning cells: column %d set to %d\n", colIndex+i, colWidth); mTableFrame->SetColumnWidth(colIndex+i, colWidth); + colFrame->SetMaxColWidth(colWidth); } } } -PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, +/* 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 nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, - nscoord aMinTableWidth, - nscoord aMaxTableWidth, - nscoord aTableFixedWidth, + nscoord aTableSpecifiedWidth, PRBool aTableIsAutoWidth) { PRBool result = PR_TRUE; - if (0==aTableFixedWidth) - { - if (NS_UNCONSTRAINEDSIZE==aMaxWidth || NS_UNCONSTRAINEDSIZE==aMinTableWidth) - { // the max width of the table fits comfortably in the available space - if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, - aMaxWidth, aTableFixedWidth, aTableIsAutoWidth); - } - else if (aMinTableWidth > aMaxWidth) - { // the table doesn't fit in the available space - if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n"); - result = SetColumnsToMinWidth(aPresContext); - } - else if (aMaxTableWidth <= aMaxWidth) - { // the max width of the table fits comfortably in the available space - if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, - aMaxWidth, aTableFixedWidth, aTableIsAutoWidth); - } - else - { // the table fits somewhere between its min and desired size - if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsConstrained\n"); - result = BalanceColumnsConstrained(aPresContext, aReflowState, aAvailWidth, - aMaxWidth, aMinTableWidth, aMaxTableWidth); - } + nscoord actualMaxWidth; // the real target width, depends on if we're auto or specified width + if (PR_TRUE==aTableIsAutoWidth) + actualMaxWidth = aMaxWidth; + else + actualMaxWidth = aTableSpecifiedWidth; + + if (NS_UNCONSTRAINEDSIZE==aMaxWidth || NS_UNCONSTRAINEDSIZE==mMinTableWidth) + { // the max width of the table fits comfortably in the available space + if (gsDebug) printf (" * auto table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n"); + result = BalanceColumnsTableFits(aReflowState, aAvailWidth, + aMaxWidth, aTableSpecifiedWidth, aTableIsAutoWidth); + } + else if (mMinTableWidth > actualMaxWidth) + { // the table doesn't fit in the available space + if (gsDebug) printf (" * auto table minTW does not fit, calling SetColumnsToMinWidth\n"); + result = SetColumnsToMinWidth(); + } + else if (mMaxTableWidth <= actualMaxWidth) + { // the max width of the table fits comfortably in the available space + if (gsDebug) printf (" * auto table desired size fits, calling BalanceColumnsTableFits\n"); + result = BalanceColumnsTableFits(aReflowState, aAvailWidth, + aMaxWidth, aTableSpecifiedWidth, aTableIsAutoWidth); } else - { // tables with fixed-width have their own rules - if (NS_UNCONSTRAINEDSIZE==aMinTableWidth) - { // the table has empty content, and needs to be streched to the specified width - if (gsDebug) printf (" * specified width table > maxTableWidth, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, - aMaxWidth, aTableFixedWidth, aTableIsAutoWidth); - } - else if ((aTableFixedWidth= its max width, so give each column its max requested size - if (gsDebug) printf (" * specified width table > maxTableWidth, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, - aMaxWidth, aTableFixedWidth, aTableIsAutoWidth); - } + { // the table fits somewhere between its min and desired size + if (gsDebug) printf (" * auto table desired size does not fit, calling BalanceColumnsConstrained\n"); + result = BalanceColumnsConstrained(aReflowState, aAvailWidth, + actualMaxWidth); } + return result; } -PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresContext) +// the table doesn't fit, so squeeze every column down to its minimum +PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth() { PRBool result = PR_TRUE; @@ -626,48 +569,21 @@ PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresConte colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition); if (PR_FALSE==IsFixedWidth(colPosition)) { - for (PRInt32 rowIndex = 0; rowIndexGetCellAt(rowIndex, colIndex); - if (nsnull==cellFrame) - { // there is no cell in this row that corresponds to this column - continue; - } - if (rowIndex!=cellFrame->GetRowIndex()) { - // 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; - } - - nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); - PRInt32 colSpan = cellFrame->GetColSpan(); - nscoord cellMinWidth = cellMinSize.width/colSpan; - if (minColWidth < cellMinWidth) - minColWidth = cellMinWidth; - } + minColWidth = colFrame->GetMinColWidth(); + mTableFrame->SetColumnWidth(colIndex, minColWidth); if (PR_TRUE==hasColsAttribute) { minColWidthArray[colIndex] = minColWidth; } - - if (gsDebug==PR_TRUE) - { - printf (" for determining width of col %d %s:\n", - colIndex, !IsFixedWidth(colPosition)? "(P)":"(A)"); - printf (" minColWidth = %d\n", minColWidth); - } - - mTableFrame->SetColumnWidth(colIndex, minColWidth); - if (gsDebug==PR_TRUE) - printf (" 2: col %d, set to width = %d\n", colIndex, mTableFrame->GetColumnWidth(colIndex)); } + if (gsDebug==PR_TRUE) + printf (" 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 aMinTableWidth and aMaxTableWidth + // 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 + { // 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; @@ -686,40 +602,34 @@ PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresConte if (PR_TRUE==gsDebug) printf(" 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; } -PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, +/* 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 nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, - nscoord aTableFixedWidth, + nscoord aTableSpecifiedWidth, PRBool aTableIsAutoWidth) { -#ifdef DEBUG - nsIFrame *tablePIF=nsnull; - mTableFrame->GetPrevInFlow(tablePIF); - NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!"); -#endif - 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 + 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 - nscoord * effectiveColumnWidths = new nscoord[mNumCols]; // used for Nav4 compatible table fluffing - nsCRT::memset (effectiveColumnWidths, 0, mNumCols*sizeof(PRInt32)); PRInt32 numRows = mTableFrame->GetRowCount(); for (PRInt32 colIndex = 0; colIndexGetCellAt(rowIndex, colIndex); - if (nsnull!=firstCellInColumn) - break; - } - nsMargin colMargin; - nscoord colInset = 0; - if (nsnull!=firstCellInColumn) - { - firstCellInColumn->GetMargin(colMargin); - colInset = colMargin.left + colMargin.right; - } + nscoord colInset = mTableFrame->GetCellSpacing(); const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition); @@ -784,43 +681,30 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check continue; } + if (colIndex!=cellFrame->GetColIndex()) { + // 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 = cellFrame->GetColSpan(); + PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); // distribute a portion of the spanning cell's min and max width to this column nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); - PRInt32 cellMinWidth = cellMinSize.width/colSpan; + nscoord cellMinWidth = cellMinSize.width/colSpan; // first get the desired size info from reflow pass 1 - PRInt32 cellDesiredWidth = cellDesiredSize.width/colSpan; + nscoord cellDesiredWidth = cellDesiredSize.width/colSpan; // then get the desired size info factoring in the cell style attributes nscoord specifiedCellWidth=-1; const nsStylePosition* cellPosition; cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - switch (cellPosition->mWidth.GetUnit()) { - case eStyleUnit_Coord: - specifiedCellWidth = cellPosition->mWidth.GetCoordValue(); - if (gsDebug) printf("cell has specified coord width = %d\n", specifiedCellWidth); - break; - - case eStyleUnit_Percent: - { - nscoord tableWidth=0; - nsIStyleContextPtr tableSC; - mTableFrame->GetStyleContext(aPresContext, tableSC.AssignRef()); - PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(mTableFrame, tableSC, aReflowState, tableWidth); - float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(tableWidth*percent); - if (gsDebug) printf("specified percent width %f of %d = %d\n", - percent, tableWidth, specifiedCellWidth); - break; - } - - case eStyleUnit_Inherit: - // XXX for now, do nothing - default: - case eStyleUnit_Auto: - break; + if (eStyleUnit_Percent==cellPosition->mWidth.GetUnit()) + { //QQQ what if table is auto width? + float percent = cellPosition->mWidth.GetPercentValue(); + specifiedCellWidth = (PRInt32)(aTableSpecifiedWidth*percent); + if (gsDebug) printf("specified percent width %f of %d = %d\n", + percent, aTableSpecifiedWidth, specifiedCellWidth); } if (-1!=specifiedCellWidth) { @@ -828,7 +712,8 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo { if (gsDebug) printf("setting cellDesiredWidth from %d to %d\n", cellDesiredWidth, specifiedCellWidth/colSpan); - cellDesiredWidth = specifiedCellWidth/colSpan; // TODO: some math needed here for colspans + cellDesiredWidth = specifiedCellWidth/colSpan; + //QQQ should be proportionately distributed as a post-process } } @@ -839,13 +724,10 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo minColWidth = cellMinWidth; if (maxColWidth < cellDesiredWidth) maxColWidth = cellDesiredWidth; - // effectiveColumnWidth is the width as if no cells with colspans existed - if ((1==colSpan) && (effectiveColumnWidths[colIndex] < maxColWidth)) - effectiveColumnWidths[colIndex] = cellDesiredWidth; if (gsDebug==PR_TRUE) printf (" after cell %d, minColWidth=%d maxColWidth=%d effColWidth[%d]=%d\n", rowIndex, minColWidth, maxColWidth, - colIndex, effectiveColumnWidths[colIndex]); + colIndex, colFrame->GetEffectiveMaxColWidth()); if ((1GetColIndex()==colIndex)) { // add this cell to span list iff we are currently processing the column the cell starts in SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth); @@ -853,7 +735,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo spanList = new nsVoidArray(); spanList->AppendElement(spanInfo); } - } + } // end looping through cells in the column if (gsDebug==PR_TRUE) { @@ -869,10 +751,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo nscoord specifiedFixedColumnWidth = -1; PRBool isAutoWidth = PR_FALSE; switch (colPosition->mWidth.GetUnit()) { - case eStyleUnit_Coord: - specifiedFixedColumnWidth = colPosition->mWidth.GetCoordValue(); - if (gsDebug) printf("column %d has specified coord width = %d\n", colIndex, specifiedFixedColumnWidth); - break; case eStyleUnit_Percent: specifiedPercentageColWidth = colPosition->mWidth.GetPercentValue(); if (gsDebug) printf("column %d has specified percent width = %f\n", colIndex, specifiedPercentageColWidth); @@ -927,16 +805,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo printf (" 3 proportional: col %d with availWidth %d, gets %d slices with %d slices so far.\n", colIndex, aAvailWidth, specifiedProportionColumnWidth, totalSlices); } - else if (-1!=specifiedFixedColumnWidth) - { // the column has a specified pixel width - // if the column was computed to be too small, enlarge the column - nscoord resolvedWidth = specifiedFixedColumnWidth; - if (specifiedFixedColumnWidth <= minColWidth) - resolvedWidth = minColWidth; - mTableFrame->SetColumnWidth(colIndex, resolvedWidth); - if (gsDebug==PR_TRUE) - printf (" 3 fixed: col %d given %d\n", colIndex, resolvedWidth); - } else { // give the column a percentage of the remaining space PRInt32 percentage = -1; @@ -950,10 +818,10 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo { percentage = (PRInt32)(specifiedPercentageColWidth*100.0f); // TODO: rounding errors? // base the % on the total specified fixed width of the table - mTableFrame->SetColumnWidth(colIndex, (percentage*aTableFixedWidth)/100); + mTableFrame->SetColumnWidth(colIndex, (percentage*aTableSpecifiedWidth)/100); if (gsDebug==PR_TRUE) - printf (" 3 percent specified: col %d given %d percent of aTableFixedWidth %d, set to width = %d\n", - colIndex, percentage, aTableFixedWidth, mTableFrame->GetColumnWidth(colIndex)); + printf (" 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) { @@ -975,7 +843,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo } else { // need to maintain this so we know how much we have left over at the end - widthOfFixedTableColumns += mTableFrame->GetColumnWidth(colIndex) + colInset; + widthOfFixedTableColumns += colFrame->GetMaxColWidth() + colInset; } tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset; } @@ -985,7 +853,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo if (nsnull!=proportionalColumnsList) { // first, figure out the amount of space per slice - nscoord maxWidthForTable = (0!=aTableFixedWidth) ? aTableFixedWidth : aMaxWidth; + nscoord maxWidthForTable = (0!=aTableSpecifiedWidth) ? aTableSpecifiedWidth : aMaxWidth; if (NS_UNCONSTRAINEDSIZE!=maxWidthForTable) { nscoord widthRemaining = maxWidthForTable - tableWidth; @@ -1001,7 +869,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo printf (" 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; - effectiveColumnWidths[info->mColIndex] = computedColWidth; +// effectiveColumnWidth = computedColWidth; delete info; } } @@ -1026,7 +894,9 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo printf (" 3 proportional step 2 (unconstrained!): col %d set to width = %d\n", info->mColIndex, maxOfMaxColWidths); tableWidth += maxOfMaxColWidths; - effectiveColumnWidths[info->mColIndex] = maxOfMaxColWidths; + nsTableColFrame *colFrame; + mTableFrame->GetColumnFrame(info->mColIndex, colFrame); + colFrame->SetEffectiveMaxColWidth(maxOfMaxColWidths); delete info; } } @@ -1038,11 +908,8 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo // columns if possible. if ((PR_FALSE==aTableIsAutoWidth) && (aAvailWidth > (tableWidth-widthOfFixedTableColumns))) { - DistributeExcessSpace(aAvailWidth, tableWidth, widthOfFixedTableColumns, effectiveColumnWidths); + DistributeExcessSpace(aAvailWidth, tableWidth, widthOfFixedTableColumns); } - // today we always allocate effectiveColumnWidths, but tomorrow we might be smarter, so leave the check in - if (nsnull!=effectiveColumnWidths) - delete [] effectiveColumnWidths; if (nsnull!=spanList) delete spanList; return result; @@ -1052,12 +919,12 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo // 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 *aColWidths) + nscoord aWidthOfFixedTableColumns) { nscoord excess = 0; if (PR_TRUE==gsDebug) printf ("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; @@ -1065,7 +932,6 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); if (0!=numAutoColumns) { - nscoord computedTableWidth = aTableWidth - aWidthOfFixedTableColumns; // 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; @@ -1075,27 +941,35 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, PRInt32 i; for (i = 0; iGetColumnFrame(autoColumns[i], colFrame); + nscoord effectiveColWidth = colFrame->GetEffectiveMaxColWidth(); + if (0!=effectiveColWidth) + totalEffectiveWidthOfAutoColumns += effectiveColWidth; else totalEffectiveWidthOfAutoColumns += mTableFrame->GetColumnWidth(autoColumns[i]); } - excess = aAvailWidth - computedTableWidth; + // excess is the amount of space that was available minus the computed available width + // QQQ shouldn't it just be aMaxWidth - aTableWidth??? + excess = aAvailWidth - widthMinusFixedColumns; + // 2. next, compute the proportion to be added to each column, and add it for (i = 0; iGetColumnWidth(colIndex);//aColWidths[colIndex]; + nsTableColFrame *colFrame; + mTableFrame->GetColumnFrame(colIndex, colFrame); + nscoord oldColWidth = mTableFrame->GetColumnWidth(colIndex); float percent; if (0!=totalEffectiveWidthOfAutoColumns) - percent = ((float)(aColWidths[colIndex]))/((float)totalEffectiveWidthOfAutoColumns); + percent = ((float)(colFrame->GetEffectiveMaxColWidth()))/((float)totalEffectiveWidthOfAutoColumns); else percent = ((float)1)/((float)numAutoColumns); nscoord excessForThisColumn = (nscoord)(excess*percent); nscoord colWidth = excessForThisColumn+oldColWidth; if (gsDebug==PR_TRUE) printf(" distribute excess to auto columns: column %d was %d, now set to %d\n", - colIndex, aColWidths[colIndex], colWidth); + colIndex, oldColWidth, colWidth); mTableFrame->SetColumnWidth(colIndex, colWidth); } } @@ -1103,13 +977,13 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, // (they must be all fixed and percentage-width columns, or we would have gone into the block above) else { - excess = aAvailWidth - (aTableWidth-aWidthOfFixedTableColumns); + excess = aAvailWidth - widthMinusFixedColumns; if (gsDebug==PR_TRUE) printf(" aAvailWidth specified as %d, expanding columns by excess = %d\n", aAvailWidth, excess); for (PRInt32 colIndex = 0; colIndexGetColumnWidth(colIndex); float percent; @@ -1127,15 +1001,11 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, } } -/* this method is very similar to BalanaceColumnsTableFits, but there are enough - * subtle differences that code reuse is impractical. it's a shame. +/* assign columns widths for a table whose max size doesn't fit in the available space */ -PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPresContext, - const nsReflowState& aReflowState, +PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( const nsReflowState& aReflowState, nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aMinTableWidth, - nscoord aMaxTableWidth) + nscoord aMaxWidth) { #ifdef DEBUG nsIFrame *tablePIF=nsnull; @@ -1145,17 +1015,14 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre 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 + nscoord tableWidth; // the width of the table as a result of setting column widths + tableWidth = aMaxWidth-aAvailWidth; // the starting table width is the sum of fixed-width columns 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 - nscoord * effectiveMaxColumnWidths = new nscoord[mNumCols]; // used for Nav4 compatible table fluffing - nsCRT::memset (effectiveMaxColumnWidths, 0, mNumCols*sizeof(PRInt32)); - nscoord * effectiveMinColumnWidths = new nscoord[mNumCols]; // used for Nav4 compatible table fluffing - nsCRT::memset (effectiveMinColumnWidths, 0, mNumCols*sizeof(PRInt32)); PRInt32 numRows = mTableFrame->GetRowCount(); for (PRInt32 colIndex = 0; colIndexGetCellAt(rowIndex, colIndex); - if (nsnull!=firstCellInColumn) - break; - } - nsMargin colMargin; - nscoord colInset = 0; - if (nsnull!=firstCellInColumn) - { - firstCellInColumn->GetMargin(colMargin); - colInset = colMargin.left + colMargin.right; - } + nscoord colInset = mTableFrame->GetCellSpacing(); const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition); @@ -1224,8 +1078,13 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check continue; } + if (colIndex!=cellFrame->GetColIndex()) { + // 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 = cellFrame->GetColSpan(); + PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); @@ -1237,29 +1096,15 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre const nsStylePosition* cellPosition; cellFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)cellPosition); switch (cellPosition->mWidth.GetUnit()) { - case eStyleUnit_Coord: - specifiedCellWidth = cellPosition->mWidth.GetCoordValue(); - if (gsDebug) printf("cell has specified coord width = %d\n", specifiedCellWidth); - break; - case eStyleUnit_Percent: { nscoord knownTableWidth=0; - nsIStyleContextPtr tableSC; - mTableFrame->GetStyleContext(aPresContext, tableSC.AssignRef()); - PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(mTableFrame, tableSC, aReflowState, knownTableWidth); float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(knownTableWidth*percent); + specifiedCellWidth = (PRInt32)(aMaxWidth*percent); if (gsDebug) printf("specified percent width %f of %d = %d\n", - percent, knownTableWidth, specifiedCellWidth); + percent, aMaxWidth, specifiedCellWidth); break; } - - case eStyleUnit_Inherit: - // XXX for now, do nothing - default: - case eStyleUnit_Auto: - break; } if (-1!=specifiedCellWidth) { @@ -1277,19 +1122,16 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre // remember the widest min cell width if (minColWidth < cellMinWidth) minColWidth = cellMinWidth; - // effectiveMinColumnWidth is the width as if no cells with colspans existed - if ((1==colSpan) && (effectiveMinColumnWidths[colIndex] < minColWidth)) - effectiveMinColumnWidths[colIndex] = cellMinWidth; // remember the max desired cell width if (maxColWidth < cellDesiredWidth) maxColWidth = cellDesiredWidth; // effectiveMaxColumnWidth is the width as if no cells with colspans existed - if ((1==colSpan) && (effectiveMaxColumnWidths[colIndex] < maxColWidth)) - effectiveMaxColumnWidths[colIndex] = cellDesiredWidth; + if ((1==colSpan) && (colFrame->GetEffectiveMaxColWidth() < maxColWidth)) + colFrame->SetEffectiveMaxColWidth(cellDesiredWidth); if (gsDebug==PR_TRUE) printf (" after cell %d, minColWidth=%d maxColWidth=%d effColWidth[%d]=%d,%d\n", rowIndex, minColWidth, maxColWidth, - colIndex, effectiveMaxColumnWidths[colIndex], effectiveMaxColumnWidths[colIndex]); + colIndex, colFrame->GetEffectiveMinColWidth(), colFrame->GetEffectiveMaxColWidth()); if ((1GetColIndex()==colIndex)) { // if this cell spans columns and we are processing the column that owns the cell // add the cell to our list of spanners @@ -1305,10 +1147,10 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre printf (" for determining width of col %d %s:\n", colIndex, !IsFixedWidth(colPosition)? "(P)":"(A)"); printf (" minTableWidth = %d and maxTableWidth = %d\n", - aMinTableWidth, aMaxTableWidth); + mMinTableWidth, mMaxTableWidth); printf (" minColWidth = %d, maxColWidth = %d, eff=%d,%d\n", - minColWidth, maxColWidth, effectiveMinColumnWidths[colIndex], - effectiveMaxColumnWidths[colIndex]); + minColWidth, maxColWidth, colFrame->GetEffectiveMinColWidth(), + colFrame->GetEffectiveMaxColWidth()); printf (" aAvailWidth = %d\n", aAvailWidth); } @@ -1318,10 +1160,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre nscoord specifiedFixedColumnWidth = -1; PRBool isAutoWidth = PR_FALSE; switch (colPosition->mWidth.GetUnit()) { - case eStyleUnit_Coord: - specifiedFixedColumnWidth = colPosition->mWidth.GetCoordValue(); - if (gsDebug) printf("column %d has specified coord width = %d\n", colIndex, specifiedFixedColumnWidth); - break; case eStyleUnit_Percent: specifiedPercentageColWidth = colPosition->mWidth.GetPercentValue(); if (gsDebug) printf("column %d has specified percent width = %f\n", colIndex, specifiedPercentageColWidth); @@ -1379,16 +1217,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre if (1!=specifiedProportionColumnWidth) equalWidthColumns = PR_FALSE; } - else if (-1!=specifiedFixedColumnWidth) - { // the column has a specified pixel width - // if the column was computed to be too small, enlarge the column - nscoord resolvedWidth = specifiedFixedColumnWidth; - if (specifiedFixedColumnWidth <= minColWidth) - resolvedWidth = minColWidth; - mTableFrame->SetColumnWidth(colIndex, resolvedWidth); - if (gsDebug==PR_TRUE) - printf (" 4 fixed: col %d given %d\n", colIndex, resolvedWidth); - } else { // give the column a percentage of the remaining space PRInt32 percentage = -1; @@ -1430,14 +1258,30 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre } } } + tableWidth += mTableFrame->GetColumnWidth(colIndex); } } /* --- post-process if necessary --- */ + // first, assign autoWidth columns a width if (PR_TRUE==atLeastOneAutoWidthColumn) { // proportionately distribute the remaining space to autowidth columns - DistributeRemainingSpace(aAvailWidth, tableWidth, effectiveMinColumnWidths, effectiveMaxColumnWidths); + DistributeRemainingSpace(aAvailWidth, tableWidth); } - // second, assign a width to proportional-width columns + + // second, fix up tables where column width attributes give us a table that is too wide or too narrow + nscoord computedWidth=0; + for (PRInt32 i=0; iGetColumnWidth(i); + } + if (computedWidthaMaxWidth) { + AdjustTableThatIsTooWide(computedWidth, aMaxWidth); + } + + + // finally, assign a width to proportional-width columns if (nsnull!=proportionalColumnsList) { // first, figure out the amount of space per slice @@ -1469,11 +1313,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre } // clean up - // today we always allocate effectiveColumnWidths, but tomorrow we might be smarter, so leave the check in - if (nsnull!=effectiveMinColumnWidths) - delete [] effectiveMinColumnWidths; - if (nsnull!=effectiveMaxColumnWidths) - delete [] effectiveMaxColumnWidths; if (nsnull!=spanList) { NS_ASSERTION(0==spanList->Count(), "space leak, span list not empty"); @@ -1486,20 +1325,18 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre //XXX: make sure aTFW takes into account fixed width cells already assigned // take the remaining space in the table and distribute it proportionately // to the auto-width cells in the table (based on desired width) -void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableFixedWidth, - nscoord aComputedTableWidth, - nscoord *aMinColWidths, - nscoord *aMaxColWidths) +void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth, + nscoord aComputedTableWidth) { if (PR_TRUE==gsDebug) printf ("DistributeRemainingSpace: fixed width %d > computed table width %d\n", - aTableFixedWidth, aComputedTableWidth); + aTableSpecifiedWidth, aComputedTableWidth); // if there are auto-sized columns, give them the extra space PRInt32 numAutoColumns=0; PRInt32 *autoColumns=nsnull; // 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 = aTableFixedWidth - aComputedTableWidth; + nscoord availWidth = aTableSpecifiedWidth - aComputedTableWidth; mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); if (0!=numAutoColumns) { @@ -1510,37 +1347,67 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableFixedWidt PRInt32 i; for (i = 0; iGetColFrame(autoColumns[i]); + nscoord maxEffectiveColWidth = colFrame->GetEffectiveMaxColWidth(); + if (0!=maxEffectiveColWidth) + totalEffectiveWidthOfAutoColumns += maxEffectiveColWidth; else totalEffectiveWidthOfAutoColumns += mTableFrame->GetColumnWidth(autoColumns[i]); } if (gsDebug==PR_TRUE) - printf(" aTableFixedWidth specified as %d, availWidth is = %d\n", - aTableFixedWidth, availWidth); + printf(" aTableSpecifiedWidth specified as %d, availWidth is = %d\n", + aTableSpecifiedWidth, availWidth); // 2. next, compute the proportion to be added to each column, and add it for (i = 0; iSetColumnWidth(colIndex, colWidth); + nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex); + // if we actually have room to distribute, do it here + // otherwise, the auto columns will remain 0-width until expanded to their minimum in EnsureCellMinWidths + if (0GetEffectiveMaxColWidth()))/((float)totalEffectiveWidthOfAutoColumns); + else + percent = ((float)1)/((float)numAutoColumns); + nscoord colWidth = (nscoord)(availWidth*percent); + if (gsDebug==PR_TRUE) + printf(" distribute width to auto columns: column %d was %d, now set to %d\n", + colIndex, colFrame->GetEffectiveMaxColWidth(), colWidth); + mTableFrame->SetColumnWidth(colIndex, colWidth); + } } - EnsureCellMinWidths(aMinColWidths); + + if (PR_TRUE==gsDebug) + { + nscoord tableWidth=0; + for (PRInt32 i=0; iGetColumnWidth(i); + printf ("before EnsureCellMinWidth, computed table width is %d\n",tableWidth); + } + + EnsureCellMinWidths(); + } + if (PR_TRUE==gsDebug) + { + nscoord tableWidth=0; + for (PRInt32 i=0; iGetColumnWidth(i); + printf ("after EnsureCellMinWidth, computed table width is %d\n",tableWidth); } } -void BasicTableLayoutStrategy::EnsureCellMinWidths(nscoord *aMinColWidths) +void BasicTableLayoutStrategy::EnsureCellMinWidths() { PRBool atLeastOne = PR_TRUE; + /* XXX we'll use this if it turns out that fixed-width cells + XXX should NOT be shrunk to accomodate table width + PRInt32 numFixedColumns; + PRInt32 *fixedColumns=nsnull; + mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); + */ while (PR_TRUE==atLeastOne) { atLeastOne=PR_FALSE; @@ -1549,11 +1416,13 @@ void BasicTableLayoutStrategy::EnsureCellMinWidths(nscoord *aMinColWidths) // first, bump up cells that are below their min to their min width for (colIndex=0; colIndexGetColFrame(colIndex); + nscoord minEffectiveColWidth = colFrame->GetEffectiveMinColWidth(); nscoord colWidth = mTableFrame->GetColumnWidth(colIndex); - if (colWidthSetColumnWidth(colIndex, aMinColWidths[colIndex]); + addedWidth += (minEffectiveColWidth-colWidth); + mTableFrame->SetColumnWidth(colIndex, minEffectiveColWidth); atLeastOne=PR_TRUE; } } @@ -1561,21 +1430,93 @@ void BasicTableLayoutStrategy::EnsureCellMinWidths(nscoord *aMinColWidths) //QQQ boy is this slow! there has to be a faster way that is still guaranteed to be accurate... while ((addedWidth>0)) { // while we still have some extra space, and last time we were able to take some off... + PRInt32 startingAddedWidth = addedWidth; for (colIndex=0; colIndexGetColFrame(colIndex); + nscoord minEffectiveColWidth = colFrame->GetEffectiveMinColWidth(); nscoord colWidth = mTableFrame->GetColumnWidth(colIndex); - if (colWidth>aMinColWidths[colIndex]) + if (colWidth>minEffectiveColWidth) { mTableFrame->SetColumnWidth(colIndex, colWidth-1); addedWidth--; + if (0==addedWidth) + { // we're run out of extra space + break; // for (colIndex=0; colIndex0)) + } } if (0GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); + nscoord excess = aComputedWidth - aTableWidth; + if (0GetColumnWidth(colIndex); + colWidth -= excessPerColumn; + nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex); + if (colWidth > colFrame->GetEffectiveMinColWidth()) + mTableFrame->SetColumnWidth(colIndex, colWidth); + else + mTableFrame->SetColumnWidth(colIndex, colFrame->GetEffectiveMinColWidth()); + } + } + } +} + +void BasicTableLayoutStrategy::AdjustTableThatIsTooNarrow(nscoord aComputedWidth, + nscoord aTableWidth) +{ + PRInt32 numFixedColumns=0; + PRInt32 *fixedColumns=nsnull; + //XXX todo: exclude fixed width columns + //mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); + nscoord excess = aTableWidth - aComputedWidth; + if (0GetColumnWidth(colIndex); + colWidth += excessPerColumn; + nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex); + if (colWidth >colFrame->GetEffectiveMinColWidth()) + mTableFrame->SetColumnWidth(colIndex, colWidth); + else + mTableFrame->SetColumnWidth(colIndex, colFrame->GetEffectiveMinColWidth()); + } + } + } +} + +//PRBool BasicTableLayoutStrategy::IsFixedWidthColumn(PRInt32 colIndex, PRInt32 *colIndexes) + diff --git a/layout/html/table/src/BasicTableLayoutStrategy.h b/layout/html/table/src/BasicTableLayoutStrategy.h index 1bca0687bafa..0ea87b4d5cac 100644 --- a/layout/html/table/src/BasicTableLayoutStrategy.h +++ b/layout/html/table/src/BasicTableLayoutStrategy.h @@ -31,20 +31,24 @@ struct nsStylePosition; struct SpanInfo { - nscoord span; + PRInt32 span; + const PRInt32 initialColSpan; nscoord cellMinWidth; nscoord cellDesiredWidth; - SpanInfo(nscoord aSpan, nscoord aMinWidth, nscoord aDesiredWidth) - { - span = aSpan; - cellMinWidth = aMinWidth; - cellDesiredWidth = aDesiredWidth; - }; - + SpanInfo(PRInt32 aSpan, nscoord aMinWidth, nscoord aDesiredWidth); ~SpanInfo() {}; }; +inline SpanInfo::SpanInfo(PRInt32 aSpan, nscoord aMinWidth, nscoord aDesiredWidth) + : initialColSpan(aSpan) +{ + span = aSpan; + cellMinWidth = aMinWidth; + cellDesiredWidth = aDesiredWidth; +} + + /* ---------- BasicTableLayoutStrategy ---------- */ @@ -60,86 +64,69 @@ public: ~BasicTableLayoutStrategy(); - virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext *aTableStyle, - const nsReflowState& aReflowState, - nscoord aMaxWidth, - nscoord &aTotalFixedWidth, - nscoord &aMinTableWidth, - nscoord &aMaxTableWidth, - nsSize* aMaxElementSize); + /** call once every time any table thing changes (content, structure, or style) */ + virtual PRBool Initialize(nsSize* aMaxElementSize); - /** assign widths for each column that has fixed width. + virtual PRBool BalanceColumnWidths(nsIStyleContext * aTableStyle, + const nsReflowState& aReflowState, + nscoord aMaxWidth); + + /** assign widths for each column. + * if the column has a fixed coord width, use it. + * if the column includes col spanning cells, + * then distribute the fixed space between cells proportionately. * Computes the minimum and maximum table widths. - * Sets mColumnWidths as a side effect. - * - * @param aPresContext the presentation context - * @param aMaxWidth the maximum width of the table - * @param aTableStyle the resolved style for the table - * @param aTotalFixedWidth out param, the sum of the fixed width columns - * @param aMinTableWidth out param, the min possible table width - * @param aMaxTableWidth out param, the max table width + * Set column width information in each column frame and in the table frame. * * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error * - * TODO: should be renamed to "AssignKnownWidthInformation */ - virtual PRBool AssignFixedColumnWidths(nsIPresContext* aPresContext, - nscoord aMaxWidth, - nscoord & aTotalFixedWidth, - nscoord & aMinTableWidth, - nscoord & aMaxTableWidth); + virtual PRBool AssignPreliminaryColumnWidths(); /** assign widths for each column that has proportional width inside a table that * has auto width (width set by the content and available space.) * Sets mColumnWidths as a side effect. * - * @param aPresContext the presentation context - * @param aTableStyle the resolved style for the table - * @param aAvailWidth the remaining amount of horizontal space available - * @param aMaxWidth the total amount of horizontal space available - * @param aMinTableWidth the min possible table width - * @param aMaxTableWidth the max table width + * @param aTableStyle the resolved style for the table + * @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(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, + virtual PRBool BalanceProportionalColumns(const nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, - nscoord aMinTableWidth, - nscoord aMaxTableWidth, - nscoord aTableFixedWidth, + nscoord aTableSpecifiedWidth, PRBool aTableIsAutoWidth); /** assign the minimum allowed width for each column that has proportional width. * Typically called when the min table width doesn't fit in the available space. * Sets mColumnWidths as a side effect. * - * @param aPresContext the presentation context * * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error */ - virtual PRBool SetColumnsToMinWidth(nsIPresContext* aPresContext); + virtual PRBool SetColumnsToMinWidth(); /** assign the maximum allowed width for each column that has proportional width. * Typically called when the desired max table width fits in the available space. * Sets mColumnWidths as a side effect. * - * @param aPresContext the presentation context - * @param aAvailWidth the remaining amount of horizontal space available - * @param aMaxWidth the total amount of horizontal space available - * @param aTableFixedWidth the specified width of the table. If there is none, - * this param is 0 + * @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(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, + virtual PRBool BalanceColumnsTableFits(const nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, - nscoord aTableFixedWidth, + nscoord aTableSpecifiedWidth, PRBool aTableIsAutoWidth); /** assign widths for each column that has proportional width inside a table that @@ -147,7 +134,6 @@ public: * HTML 4 specification. * Sets mColumnWidths as a side effect. * - * @param aPresContext the presentation context * @param aTableStyle the resolved style for the table * @param aAvailWidth the remaining amount of horizontal space available * @param aMaxWidth the total amount of horizontal space available @@ -158,23 +144,19 @@ public: * * TODO: rename this method to reflect that it is a Nav4 compatibility method */ - virtual PRBool BalanceColumnsConstrained(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, + virtual PRBool BalanceColumnsConstrained(const nsReflowState& aReflowState, nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aMinTableWidth, - nscoord aMaxTableWidth); + nscoord aMaxWidth); /** post-process to AssignFixedColumnWidths * * @param aColSpanList a list of fixed-width columns that have colspans - * @param aColWidths the effective column widths (ignoring col span cells) * * NOTE: does not yet properly handle overlapping col spans * * @return void */ - virtual void DistributeFixedSpace(nsVoidArray *aColSpanList, nscoord *aColWidths); + 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. @@ -189,8 +171,7 @@ public: */ virtual void DistributeExcessSpace(nscoord aAvailWidth, nscoord aTableWidth, - nscoord aWidthOfFixedTableColumns, - nscoord *aColWidths); + nscoord aWidthOfFixedTableColumns); /** starting with a partially balanced table, compute the amount * of space to remove from each column to completely balance the table. @@ -203,14 +184,18 @@ public: * @return void */ virtual void DistributeRemainingSpace(nscoord aTableFixedWidth, - nscoord aComputedTableWidth, - nscoord *aMinColWidths, - nscoord *aMaxColWidths); + nscoord aComputedTableWidth); /** force all cells to be at least their minimum width, removing any excess space * created in the process from fat cells that can afford to lose a little tonnage. */ - virtual void EnsureCellMinWidths(nscoord *aMinColWidths); + virtual void EnsureCellMinWidths(); + + virtual void AdjustTableThatIsTooWide(nscoord aComputedWidth, + nscoord aTableWidth); + + virtual void AdjustTableThatIsTooNarrow(nscoord aComputedWidth, + nscoord aTableWidth); /** return true if the style indicates that the width is a specific width * for the purposes of column width determination. @@ -218,12 +203,15 @@ public: */ virtual PRBool IsFixedWidth(const nsStylePosition* aStylePosition); - virtual PRBool IsAutoWidth(const nsStylePosition* aStylePosition); protected: nsTableFrame * mTableFrame; PRInt32 mCols; PRInt32 mNumCols; + // cached data + nscoord mMinTableWidth; // the absolute smallest width 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 }; diff --git a/layout/html/table/src/nsITableLayoutStrategy.h b/layout/html/table/src/nsITableLayoutStrategy.h index 861aa290f3b5..543235dbf917 100644 --- a/layout/html/table/src/nsITableLayoutStrategy.h +++ b/layout/html/table/src/nsITableLayoutStrategy.h @@ -22,7 +22,6 @@ #include "nscore.h" #include "nsSize.h" -class nsIPresContext; class nsIStyleContext; struct nsReflowState; @@ -30,25 +29,21 @@ class nsITableLayoutStrategy { public: + /** call once every time any table thing changes (content, structure, or style) + * @param aMaxElementSize [OUT] the min possible size of the table + */ + virtual PRBool Initialize(nsSize* aMaxElementSize)=0; + /** assign widths for each column, taking into account the table content, the effective style, * the layout constraints, and the compatibility mode. Sets mColumnWidths as a side effect. - * @param aPresContext the presentation context * @param aTableStyle the resolved style for the table * @param aReflowState the reflow state for the calling table frame * @param aMaxWidth the width constraint - * @param aTotalFixedWidth [OUT] the computed fixed width of the table - * @param aMinTableWidth [OUT] the computed min width of the table - * @param aMinTableWidth [OUT] the computed max width of the table - * @param aMaxElementSize [OUT] the min size of the largest indivisible object + */ - virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext *aTableStyle, + virtual PRBool BalanceColumnWidths(nsIStyleContext *aTableStyle, const nsReflowState& aReflowState, - nscoord aMaxWidth, - nscoord &aTotalFixedWidth, - nscoord &aMinTableWidth, - nscoord &aMaxTableWidth, - nsSize* aMaxElementSize)=0; + nscoord aMaxWidth)=0; }; #endif diff --git a/layout/html/table/src/nsTableCellFrame.cpp b/layout/html/table/src/nsTableCellFrame.cpp index 3615f2b3ccf9..3ff92ad013ea 100644 --- a/layout/html/table/src/nsTableCellFrame.cpp +++ b/layout/html/table/src/nsTableCellFrame.cpp @@ -511,10 +511,10 @@ void nsTableCellFrame::MapBorderMarginPadding(nsIPresContext* aPresContext) return; // get the table frame style context, and from it get cellpadding, cellspacing, and border info - nsIStyleContextPtr tableSC; - tableFrame->GetStyleContext(aPresContext, tableSC.AssignRef()); - nsStyleTable* tableStyle = (nsStyleTable*)tableSC->GetStyleData(eStyleStruct_Table); - nsStyleSpacing* tableSpacingStyle = (nsStyleSpacing*)tableSC->GetStyleData(eStyleStruct_Spacing); + nsStyleTable* tableStyle; + tableFrame->GetStyleData(eStyleStruct_Table, (nsStyleStruct *&)tableStyle); + nsStyleSpacing* tableSpacingStyle; + tableFrame->GetStyleData(eStyleStruct_Spacing,(nsStyleStruct *&)tableSpacingStyle); nsStyleSpacing* spacingData = (nsStyleSpacing*)mStyleContext->GetMutableStyleData(eStyleStruct_Spacing); // check to see if cellpadding or cellspacing is defined diff --git a/layout/html/table/src/nsTableColFrame.cpp b/layout/html/table/src/nsTableColFrame.cpp index 4745bd68b5a7..4fe0f13656b6 100644 --- a/layout/html/table/src/nsTableColFrame.cpp +++ b/layout/html/table/src/nsTableColFrame.cpp @@ -38,6 +38,10 @@ nsTableColFrame::nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame) { mColIndex = 0; mRepeat = 0; + mMaxColWidth = 0; + mMinColWidth = 0; + mMaxEffectiveColWidth = 0; + mMinEffectiveColWidth = 0; } @@ -55,11 +59,12 @@ NS_METHOD nsTableColFrame::Paint(nsIPresContext& aPresContext, } -NS_METHOD nsTableColFrame::Reflow(nsIPresContext& aPresContext, +NS_METHOD nsTableColFrame::Reflow(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, nsReflowStatus& aStatus) { + NS_ASSERTION(nsnull!=aPresContext, "bad arg"); aDesiredSize.width=0; aDesiredSize.height=0; if (nsnull!=aDesiredSize.maxElementSize) diff --git a/layout/html/table/src/nsTableColFrame.h b/layout/html/table/src/nsTableColFrame.h index 3c70a7955b89..13b8b66691a9 100644 --- a/layout/html/table/src/nsTableColFrame.h +++ b/layout/html/table/src/nsTableColFrame.h @@ -34,7 +34,7 @@ public: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); - NS_IMETHOD Reflow(nsIPresContext& aPresContext, + NS_IMETHOD Reflow(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, nsReflowStatus& aStatus); @@ -51,6 +51,18 @@ 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); + /** convenience method, calls into cellmap */ PRInt32 Count() const; @@ -66,11 +78,11 @@ protected: /** the number of columns that the attributes of this column extend to */ PRInt32 mRepeat; - nscoord mMaxWidth; - nscoord mMinWidth; + nscoord mMaxColWidth; + nscoord mMinColWidth; - nscoord mMaxEffectiveWidth; - nscoord mMinEffectiveWidth; + nscoord mMaxEffectiveColWidth; + nscoord mMinEffectiveColWidth; }; @@ -93,5 +105,29 @@ inline nsTableColFrame::GetRepeat() inline void nsTableColFrame::SetColumnIndex (int aColIndex) { mColIndex = aColIndex;} +inline nscoord nsTableColFrame::GetMaxColWidth() +{ return mMaxColWidth; } + +inline void nsTableColFrame::SetMaxColWidth(nscoord aMaxColWidth) +{ mMaxColWidth = aMaxColWidth; } + +inline nscoord nsTableColFrame::GetMinColWidth() +{ return mMinColWidth; } + +inline void nsTableColFrame::SetMinColWidth(nscoord aMinColWidth) +{ mMinColWidth = aMinColWidth; } + +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 aMinColWidth) +{ mMinEffectiveColWidth = aMinColWidth; } + #endif diff --git a/layout/html/table/src/nsTableFrame.cpp b/layout/html/table/src/nsTableFrame.cpp index 4be7370650a7..6c7d634f5640 100644 --- a/layout/html/table/src/nsTableFrame.cpp +++ b/layout/html/table/src/nsTableFrame.cpp @@ -396,7 +396,7 @@ nsTableCellFrame * nsTableFrame::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) } -// return the rows spanned by aCell starting at aRowIndex +// 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) // @@ -416,6 +416,24 @@ PRInt32 nsTableFrame::GetEffectiveRowSpan (PRInt32 aRowIndex, nsTableCellFrame * return rowSpan; } +// 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) +// +// XXX Should be moved to colgroup, as GetEffectiveRowSpan should be moved to rowgroup? +PRInt32 nsTableFrame::GetEffectiveColSpan (PRInt32 aColIndex, nsTableCellFrame *aCell) +{ + NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); + NS_PRECONDITION (nsnull!=mCellMap, "bad call, mCellMap not yet allocated."); + NS_PRECONDITION (0<=aColIndex && aColIndexGetColCount(), "bad col index arg"); + + int colSpan = aCell->GetColSpan(); + int colCount = mCellMap->GetColCount(); + if (colCount < (aColIndex + colSpan)) + return (colCount - aColIndex); + return colSpan; +} + /* call when the cell structure has changed. mCellMap will be rebuilt on demand. */ void nsTableFrame::ResetCellMap () { @@ -1198,6 +1216,11 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext, // XXX For the time being just fall through and treat it like a // pass 2 reflow... mPass = kPASS_SECOND; + // calling intialize here resets all the cached info based on new table content + if (nsnull!=mTableLayoutStrategy) + { + mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize); + } #else // XXX Hack... AdjustSiblingsAfterReflow(&aPresContext, state, kidFrame, desiredSize.height - @@ -2231,9 +2254,6 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, { NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); - if (gsDebug) - printf ("BalanceColumnWidths...\n"); - if (nsnull==mCellMap) return; // we don't have any information yet, so we can't do any useful work @@ -2244,11 +2264,6 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, nsCRT::memset (mColumnWidths, 0, numCols*sizeof(PRInt32)); } - // need to track min and max table widths - PRInt32 minTableWidth = 0; - PRInt32 maxTableWidth = 0; - PRInt32 totalFixedWidth = 0; - const nsStyleSpacing* spacing = (const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing); nsMargin borderPadding; @@ -2308,13 +2323,9 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, if (nsnull==mTableLayoutStrategy) { // TODO: build a different strategy based on the compatibility mode mTableLayoutStrategy = new BasicTableLayoutStrategy(this, numCols); + mTableLayoutStrategy->Initialize(aMaxElementSize); } - mTableLayoutStrategy->BalanceColumnWidths(aPresContext, mStyleContext, - aReflowState, maxWidth, - totalFixedWidth, - minTableWidth, maxTableWidth, - aMaxElementSize); - + mTableLayoutStrategy->BalanceColumnWidths(mStyleContext, aReflowState, maxWidth); } /** @@ -2608,7 +2619,7 @@ nsTableFrame::CreateContinuingFrame(nsIPresContext& aPresContext, nsIStyleContext* kidStyleContext = aPresContext.ResolveStyleContextFor(content, cf); // kidStyleContext: REFCNT++ nsIContentDelegate* kidDel = nsnull; - kidDel = content->GetDelegate(&aPresContext); // kidDel: REFCNT++ + kidDel = content->GetDelegate(&aPresContext); // kidDel: REFCNT++ nsIFrame* duplicateFrame; nsresult rv = kidDel->CreateFrame(&aPresContext, content, cf, kidStyleContext, duplicateFrame); @@ -2825,6 +2836,19 @@ NS_METHOD nsTableFrame::GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& return result; } +nscoord nsTableFrame::GetCellSpacing() +{ + nsTableFrame* tableFrame = this; + //XXX remove when table style is fully resolved! + GetGeometricParent((nsIFrame *&)tableFrame); // get the outer frame + nsStyleTable* tableStyle; + tableFrame->GetStyleData(eStyleStruct_Table, (nsStyleStruct *&)tableStyle); + nscoord cellSpacing = 0; + if (tableStyle->mCellSpacing.GetUnit() == eStyleUnit_Coord) + cellSpacing = tableStyle->mCellSpacing.GetCoordValue(); + return cellSpacing; +} + void nsTableFrame::GetColumnsByType(const nsStyleUnit aType, PRInt32& aOutNumColumns, PRInt32 *& aOutColumnIndexes) @@ -2989,27 +3013,34 @@ nscoord nsTableFrame::GetTableContainerWidth(const nsReflowState& aReflowState) } else { - nsSize tableSize; - table->GetSize(tableSize); - parentWidth = tableSize.width; - spacing->CalcBorderPaddingFor(rs->frame, borderPadding); - parentWidth -= (borderPadding.right + borderPadding.left); - // same for the row group - childFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); - spacing->CalcBorderPaddingFor(childFrame, borderPadding); - parentWidth -= (borderPadding.right + borderPadding.left); - // same for the row - grandchildFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); - spacing->CalcBorderPaddingFor(grandchildFrame, borderPadding); - parentWidth -= (borderPadding.right + borderPadding.left); - // same for the cell - greatgrandchildFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); - spacing->CalcBorderPaddingFor(greatgrandchildFrame, borderPadding); - parentWidth -= (borderPadding.right + borderPadding.left); - + if (nsnull!=((nsTableFrame*)table)->mColumnWidths) + { + PRInt32 colIndex = ((nsTableCellFrame*)greatgrandchildFrame)->GetColIndex(); + parentWidth = ((nsTableFrame*)table)->GetColumnWidth(colIndex); + } + else + { + nsSize tableSize; + table->GetSize(tableSize); + parentWidth = tableSize.width; + spacing->CalcBorderPaddingFor(rs->frame, borderPadding); + parentWidth -= (borderPadding.right + borderPadding.left); + // same for the row group + childFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); + spacing->CalcBorderPaddingFor(childFrame, borderPadding); + parentWidth -= (borderPadding.right + borderPadding.left); + // same for the row + grandchildFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); + spacing->CalcBorderPaddingFor(grandchildFrame, borderPadding); + parentWidth -= (borderPadding.right + borderPadding.left); + // same for the cell + greatgrandchildFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); + spacing->CalcBorderPaddingFor(greatgrandchildFrame, borderPadding); + parentWidth -= (borderPadding.right + borderPadding.left); + } if (PR_TRUE==gsDebugNT) - printf("%p: found a table frame %p, returning parentWidth %d from frame width %d\n", - aReflowState.frame, table, parentWidth, tableSize.width); + printf("%p: found a table frame %p, returning parentWidth %d \n", + aReflowState.frame, table, parentWidth); } break; } diff --git a/layout/html/table/src/nsTableFrame.h b/layout/html/table/src/nsTableFrame.h index c59004e4dddc..9ffdaf42d7ef 100644 --- a/layout/html/table/src/nsTableFrame.h +++ b/layout/html/table/src/nsTableFrame.h @@ -142,6 +142,9 @@ public: /** set the width of the column at aColIndex to aWidth */ virtual void SetColumnWidth(PRInt32 aColIndex, nscoord aWidth); + + /** helper to get the cell spacing style value */ + virtual nscoord GetCellSpacing(); /** * Calculate Layout Information @@ -167,13 +170,26 @@ public: /** return the row span of a cell, taking into account row span magic at the bottom * of a table. - * @param aRowIndex the first row that contains the cell - * @param aCell the content object representing the cell + * + * @param aRowIndex the row from which to measure effective row span + * @param aCell the cell + * * @return the row span, correcting for row spans that extend beyond the bottom * of the table. */ virtual PRInt32 GetEffectiveRowSpan(PRInt32 aRowIndex, nsTableCellFrame *aCell); + /** return the col span of a cell, taking into account col span magic at the edge + * of a table. + * + * @param aColIndex the column from which to measure effective col span + * @param aCell the cell + * + * @return the col span, correcting for col spans that extend beyond the edge + * of the table. + */ + virtual PRInt32 GetEffectiveColSpan(PRInt32 aColIndex, nsTableCellFrame *aCell); + // For DEBUGGING Purposes Only NS_IMETHOD MoveTo(nscoord aX, nscoord aY); NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); diff --git a/layout/html/table/src/nsTableRowFrame.cpp b/layout/html/table/src/nsTableRowFrame.cpp index cd47a83a684a..93c77d2ec557 100644 --- a/layout/html/table/src/nsTableRowFrame.cpp +++ b/layout/html/table/src/nsTableRowFrame.cpp @@ -336,19 +336,22 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, nscoord maxCellTopMargin = 0; nscoord maxCellBottomMargin = 0; + if (PR_TRUE==gsDebug1) printf("%p: RR\n", this); + // Reflow each of our existing cell frames - for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { - // Get the frame's margins, and compare the top and bottom margin - // against our current max values - nsMargin kidMargin; + for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) + { + + nscoord cellSpacing = aState.tableFrame->GetCellSpacing(); + +// just cellSpacing? QQQ + nsMargin kidMargin; aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame,kidMargin); if (kidMargin.top > maxCellTopMargin) maxCellTopMargin = kidMargin.top; if (kidMargin.bottom > maxCellBottomMargin) maxCellBottomMargin = kidMargin.bottom; - // left and right margins already taken into account by table layout strategy - // Compute the x-origin for the child, taking into account straddlers (cells from prior // rows with rowspans > 1) PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex(); @@ -357,10 +360,14 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, for (PRInt32 colIndex=prevColIndex+1; colIndexGetColumnWidth(colIndex); - aState.x += kidMargin.left + kidMargin.right; + aState.x += cellSpacing; + if (PR_TRUE==gsDebug1) + printf(" in loop, aState.x set to %d from cellSpacing %d and col width\n", + aState.x, aState.tableFrame->GetColumnWidth(colIndex), cellSpacing); } } - aState.x += kidMargin.left; + aState.x += cellSpacing; + if (PR_TRUE==gsDebug1) printf(" past loop, aState.x set to %d\n", aState.x); // at this point, we know the column widths. // so we get the avail width from the known column widths @@ -369,13 +376,15 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellColIndex+numColSpan); - if (0GetColumnWidth(cellColIndex+numColSpan), cellSpacing); } + if (PR_TRUE==gsDebug1) printf(" availWidth for this cell is %d\n", availWidth); prevColIndex = cellColIndex + (cellColSpan-1); // remember the rightmost column this cell spans into @@ -461,7 +470,8 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, PlaceChild(aPresContext, aState, kidFrame, kidRect, aDesiredSize.maxElementSize, pKidMaxElementSize); - aState.x += kidMargin.right; // add in right margin only after cell has been placed + + if (PR_TRUE==gsDebug1) printf(" past PlaceChild, aState.x set to %d\n", aState.x); // Get the next child kidFrame->GetNextSibling(kidFrame); diff --git a/layout/tables/BasicTableLayoutStrategy.cpp b/layout/tables/BasicTableLayoutStrategy.cpp index 34be3091e71a..168b3c0606bf 100644 --- a/layout/tables/BasicTableLayoutStrategy.cpp +++ b/layout/tables/BasicTableLayoutStrategy.cpp @@ -89,39 +89,14 @@ PRBool BasicTableLayoutStrategy::IsFixedWidth(const nsStylePosition* aStylePosit PRBool result = PR_FALSE; // assume that it is not fixed width PRInt32 unitType; if (nsnull == aStylePosition) { - unitType = eStyleUnit_Auto; + result=PR_TRUE; } else { unitType = aStylePosition->mWidth.GetUnit(); + if (eStyleUnit_Coord==unitType) + result=PR_TRUE; } - switch (unitType) { - case eStyleUnit_Coord: - result = PR_TRUE; - - case eStyleUnit_Auto: - case eStyleUnit_Proportional: - case eStyleUnit_Percent: - break; - - // TODO - case eStyleUnit_Inherit: - break; - - default: - NS_ASSERTION(PR_FALSE, "illegal style type in IsFixedWidth"); - break; - } - return result; -} - -PRBool BasicTableLayoutStrategy::IsAutoWidth(const nsStylePosition* aStylePosition) -{ - PRBool result = PR_TRUE; // assume that it is - if (nsnull!=aStylePosition) - { - result = (PRBool)(eStyleUnit_Auto==aStylePosition->mWidth.GetUnit()); - } return result; } @@ -132,6 +107,10 @@ BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame, PRInt32 mTableFrame = aFrame; mNumCols = aNumCols; + mMinTableWidth=0; + mMaxTableWidth=0; + mFixedTableWidth=0; + //cache the value of the cols attribute nsIFrame * tableFrame = mTableFrame; // begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! XXX @@ -146,93 +125,7 @@ BasicTableLayoutStrategy::~BasicTableLayoutStrategy() { } -PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext *aTableStyle, - const nsReflowState& aReflowState, - nscoord aMaxWidth, - nscoord &aTotalFixedWidth, - nscoord &aMinTableWidth, - nscoord &aMaxTableWidth, - nsSize* aMaxElementSize) -{ - PRBool result = PR_TRUE; - // initialize out parameters - aTotalFixedWidth=aMinTableWidth=aMaxTableWidth=0; - - // Step 1 - assign the width of all fixed-width columns - AssignFixedColumnWidths(aPresContext, aMaxWidth, aTotalFixedWidth, aMinTableWidth, aMaxTableWidth); - - if (nsnull!=aMaxElementSize) - { // this is where we initialize maxElementSize if it is non-null - aMaxElementSize->height = 0; - aMaxElementSize->width = aMinTableWidth; - if (gsDebug) printf(" setting aMaxElementSize->width = %d\n", aMaxElementSize->width); - } - else - { - if (gsDebug) printf(" nsnull aMaxElementSize\n"); - } - - // Step 2 - determine how much space is really available - PRInt32 availWidth = aMaxWidth - aTotalFixedWidth; - nscoord tableWidth = 0; - PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(mTableFrame, aTableStyle, aReflowState, tableWidth); - if (PR_FALSE==tableIsAutoWidth) - availWidth = tableWidth - aTotalFixedWidth; - - // Step 3 - assign the width of all proportional-width columns in the remaining space - if (gsDebug==PR_TRUE) printf ("Step 2...\n availWidth = %d\n", availWidth); - result = BalanceProportionalColumns(aPresContext, aReflowState, - availWidth, aMaxWidth, - aMinTableWidth, aMaxTableWidth, - tableWidth, tableIsAutoWidth); - return result; -} - -/* -STEP 1 -for every col - if the col has a fixed width - set the width to max(fixed width, maxElementSize) - if the cell spans columns, divide the cell width between the columns - else skip it for now - -take borders and padding into account - -STEP 2 -determine the min and max size for the table width -if col is proportionately specified - if (col width specified to 0) - col width = minColWidth - else if (minTableWidth >= aMaxSize.width) - set col widths to min, install a hor. scroll bar - else if (maxTableWidth <= aMaxSize.width) - set each col to its max size - else - W = aMaxSize.width - minTableWidth - D = maxTableWidth - minTableWidth - for each col - d = maxColWidth - minColWidth - col width = minColWidth + ((d*W)/D) - -STEP 3 -if there is space left over - for every col - if col is proportionately specified - add space to col width until it is that proportion of the table width - do this non-destructively in case there isn't enough space - if there isn't enough space as determined in the prior step, - add space in proportion to the proportionate width attribute - */ - - -// Step 1 - assign the width of all fixed-width columns, -// and calculate min/max table width -PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresContext, - nscoord aMaxWidth, - nscoord &aTotalFixedWidth, - nscoord &aMinTableWidth, - nscoord &aMaxTableWidth) +PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize) { #ifdef DEBUG nsIFrame *tablePIF=nsnull; @@ -240,18 +133,87 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!"); #endif - if (gsDebug==PR_TRUE) printf (" AssignFixedColumnWidths\n"); + PRBool result = PR_TRUE; + + // Step 1 - assign the width of all fixed-width columns + AssignPreliminaryColumnWidths(); + + // set aMaxElementSize here because we compute mMinTableWidth in AssignPreliminaryColumnWidths + if (nsnull!=aMaxElementSize) + { + aMaxElementSize->height = 0; + aMaxElementSize->width = mMinTableWidth; + if (PR_TRUE==gsDebug) printf("BTLS::Init setting aMaxElementSize->width = %d\n", aMaxElementSize->width); + } + + return result; +} + +PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext *aTableStyle, + const nsReflowState& aReflowState, + nscoord aMaxWidth) +{ +#ifdef DEBUG + nsIFrame *tablePIF=nsnull; + mTableFrame->GetPrevInFlow(tablePIF); + NS_ASSERTION(nsnull==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); + + // Step 2 - determine how much space is really available + PRInt32 availWidth = aMaxWidth - mFixedTableWidth; + if (PR_FALSE==tableIsAutoWidth) + availWidth = specifiedTableWidth - mFixedTableWidth; + + // Step 3 - assign the width of all proportional-width columns in the remaining space + 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); + } + if (PR_TRUE==gsDebug) + { + printf("\n%p: BEGIN BALANCE COLUMN WIDTHS\n", mTableFrame); + for (PRInt32 i=0; iGetColumnWidth(i)); + printf("\n"); + } + result = BalanceProportionalColumns(aReflowState, availWidth, aMaxWidth, + specifiedTableWidth, tableIsAutoWidth); + + if (PR_TRUE==gsDebug) + { + printf("\n%p: END BALANCE COLUMN WIDTHS\n", mTableFrame); + for (PRInt32 i=0; iGetColumnWidth(i)); + printf("\n"); + } + return result; +} + +// 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() +{ + if (gsDebug==PR_TRUE) printf ("** %p: AssignPreliminaryColumnWidths **\n", mTableFrame); nsVoidArray *spanList=nsnull; nsVoidArray *colSpanList=nsnull; - nscoord * effectiveColumnWidths = new nscoord[mNumCols]; // used for Nav4 compatible table fluffing - nsCRT::memset (effectiveColumnWidths, 0, mNumCols*sizeof(PRInt32)); PRBool hasColsAttribute = (PRBool)(NS_STYLE_TABLE_COLS_NONE!=mCols); - PRInt32 *minColWidthArray = nsnull; - PRInt32 *maxColWidthArray = nsnull; + 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]; } @@ -261,11 +223,10 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo // for every column, determine it's min and max width, and keep track of the table width for (PRInt32 colIndex = 0; colIndexGetColFrame(colIndex); @@ -275,22 +236,16 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition); - // Get column width if it has one + // Get fixed column width if it has one PRBool haveColWidth = PR_FALSE; nscoord specifiedFixedColWidth=0; - switch (colPosition->mWidth.GetUnit()) { - case eStyleUnit_Coord: - haveColWidth = PR_TRUE; - specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); - mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); - break; - - default: - break; + if (eStyleUnit_Coord==colPosition->mWidth.GetUnit()) + { + haveColWidth = PR_TRUE; + specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); } - // TODO - use specifiedFixedColWidth to influence the width when both col span and fixed col width are given - /* Scan the column, simulatneously assigning fixed column widths + /* Scan the column, simulatneously assigning column widths * and computing the min/max column widths */ // first, deal with any cells that span into this column from a pervious column @@ -301,14 +256,16 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--) { SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex)); - if (minColWidth < spanInfo->cellMinWidth) - minColWidth = spanInfo->cellMinWidth; - if (maxColWidth < spanInfo->cellDesiredWidth) - maxColWidth = spanInfo->cellDesiredWidth; + nscoord cellMinWidth = (spanInfo->cellMinWidth)/(spanInfo->initialColSpan); + if (minColWidth < cellMinWidth) + minColWidth = cellMinWidth; + nscoord cellDesiredWidth = (spanInfo->cellDesiredWidth)/(spanInfo->initialColSpan); + if (maxColWidth < cellDesiredWidth) + maxColWidth = cellDesiredWidth; spanInfo->span--; if (gsDebug==PR_TRUE) printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n", - spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth); + spanIndex, spanInfo->span, cellMinWidth, cellDesiredWidth); if (0==spanInfo->span) { spanList->RemoveElementAt(spanIndex); @@ -318,6 +275,7 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo } PRInt32 firstRowIndex = -1; + PRInt32 maxColSpan = 1; for (PRInt32 rowIndex = 0; rowIndexGetCellAt(rowIndex, colIndex); @@ -332,55 +290,52 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check continue; } + PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); + if (colSpan>maxColSpan) + maxColSpan = colSpan; if (colIndex!=cellFrame->GetColIndex()) { - // For cells that span rows, we only figure it in once + // 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; } nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); - PRInt32 colSpan = cellFrame->GetColSpan(); + nscoord cellDesiredWidth = cellDesiredSize.width/colSpan; if (gsDebug==PR_TRUE) - printf (" for cell %d with colspan=%d, min = %d,%d and des = %d,%d\n", + printf (" for cell %d with colspan=%d, min = %d,%d and des = %d,%d\n", rowIndex, colSpan, cellMinSize.width, cellMinSize.height, cellDesiredSize.width, cellDesiredSize.height); - switch (colPosition->mWidth.GetUnit()) + if (PR_TRUE==haveColWidth) { - case eStyleUnit_Coord: - { - // This col has a fixed width, so set the cell's width to the - // larger of (specified width, largest max_element_size of the - // cells in the column) - nscoord widthForThisCell = PR_MAX(cellMinSize.width, colPosition->mWidth.GetCoordValue()); - widthForThisCell = widthForThisCell/colSpan; - nscoord widthFromCol = mTableFrame->GetColumnWidth(colIndex); - if (widthFromCol < widthForThisCell) - { - if (gsDebug) printf (" setting fixed width to %d\n",widthForThisCell); - mTableFrame->SetColumnWidth(colIndex, widthForThisCell); - maxColWidth = widthForThisCell; - } - } - break; - - default: - break; - + // This col has a specified fixed width so set the minand max width to the larger of + // (specified width, largest max_element_size of the cells in the column) + nscoord widthForThisCell = PR_MAX(cellMinSize.width, colPosition->mWidth.GetCoordValue()); + widthForThisCell = widthForThisCell/colSpan; + mTableFrame->SetColumnWidth(colIndex, widthForThisCell); + maxColWidth = widthForThisCell; + minColWidth = widthForThisCell; + if ((1==colSpan) && (effectiveMaxColumnWidth < widthForThisCell)) + effectiveMaxColumnWidth = widthForThisCell; + if (gsDebug) + printf (" setting min and max col width to specified fixed width %d\n", widthForThisCell); + } + else + { + if (maxColWidth < cellDesiredWidth) + maxColWidth = cellDesiredWidth; + if ((1==colSpan) && (effectiveMaxColumnWidth < maxColWidth)) + effectiveMaxColumnWidth = cellDesiredWidth; } - // regardless of the width specification, keep track of the - // min/max column widths + // cellMinWidth can override fixed width, so factor it in here nscoord cellMinWidth = cellMinSize.width/colSpan; - nscoord cellDesiredWidth = cellDesiredSize.width/colSpan; if (minColWidth < cellMinWidth) minColWidth = cellMinWidth; - if (maxColWidth < cellDesiredWidth) - maxColWidth = cellDesiredWidth; - // effectiveColumnWidth is the width as if no cells with colspans existed - if ((1==colSpan) && (effectiveColumnWidths[colIndex] < maxColWidth)) - effectiveColumnWidths[colIndex] = cellDesiredWidth; + // effectiveMinColumnWidth is the min width as if no cells with colspans existed + if ((1==colSpan) && (effectiveMinColumnWidth < cellMinWidth)) + effectiveMinColumnWidth = cellMinWidth; if (1GetCellAt(firstRowIndex, colIndex); - nsMargin colMargin; - firstCellInColumn->GetMargin(colMargin); - nscoord colInset = colMargin.left + colMargin.right; + nscoord colInset = mTableFrame->GetCellSpacing(); // keep a running total of the amount of space taken up by all fixed-width columns if (PR_TRUE==haveColWidth) - aTotalFixedWidth += mTableFrame->GetColumnWidth(colIndex) + colInset; - + mFixedTableWidth += specifiedFixedColWidth + (colInset*maxColSpan); if (gsDebug) { - printf (" after col %d, aTotalFixedWidth = %d\n", - colIndex, aTotalFixedWidth); + printf (" after col %d, mFixedTableWidth = %d\n", colIndex, mFixedTableWidth); } + + // cache the computed column info + colFrame->SetMinColWidth(minColWidth); + colFrame->SetMaxColWidth(maxColWidth); + colFrame->SetEffectiveMinColWidth(effectiveMinColumnWidth); + colFrame->SetEffectiveMaxColWidth(effectiveMaxColumnWidth); + mTableFrame->SetColumnWidth(colIndex, maxColWidth); + // add col[i] metrics to the running totals for the table min/max width - if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth) - aMinTableWidth += minColWidth + colInset; - if (aMinTableWidth<=0) - aMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow - if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth) - aMaxTableWidth += maxColWidth + colInset; - if (aMaxTableWidth<=0) - aMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow + if (NS_UNCONSTRAINEDSIZE!=mMinTableWidth) + mMinTableWidth += minColWidth + colInset; + if (mMinTableWidth<=0) + mMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow + if (NS_UNCONSTRAINEDSIZE!=mMaxTableWidth) + mMaxTableWidth += maxColWidth + colInset; + if (mMaxTableWidth<=0) + mMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow if (PR_TRUE==hasColsAttribute) { minColWidthArray[colIndex] = minColWidth; @@ -430,12 +388,11 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo } if (gsDebug==PR_TRUE) printf (" after col %d, minTableWidth = %d and maxTableWidth = %d\n", - colIndex, aMinTableWidth, aMaxTableWidth); - - } // end Step 1 for fixed-width columns + colIndex, mMinTableWidth, mMaxTableWidth); + } // now, post-process the computed values based on the table attributes - // if there is a COLS attribute, fix up aMinTableWidth and aMaxTableWidth + // 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 @@ -456,29 +413,31 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo { // subtract out the prior contributions of this column // and add back in the adjusted value - if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth) + if (NS_UNCONSTRAINEDSIZE!=mMinTableWidth) { - aMinTableWidth -= minColWidthArray[effectedColIndex]; - aMinTableWidth += maxOfMinColWidths; + mMinTableWidth -= minColWidthArray[effectedColIndex]; + mMinTableWidth += maxOfMinColWidths; } - if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth) + if (NS_UNCONSTRAINEDSIZE!=mMaxTableWidth) { - aMaxTableWidth -= maxColWidthArray[effectedColIndex]; - aMaxTableWidth += maxOfMaxColWidths; + mMaxTableWidth -= maxColWidthArray[effectedColIndex]; + mMaxTableWidth += maxOfMaxColWidths; } + nsTableColFrame *colFrame; + mTableFrame->GetColumnFrame(effectedColIndex, colFrame); + colFrame->SetMaxColWidth(maxOfMaxColWidths); // cache the new column max width (min width is uneffected) + colFrame->SetEffectiveMaxColWidth(maxOfMaxColWidths); } delete [] minColWidthArray; delete [] maxColWidthArray; } if (nsnull!=colSpanList) - DistributeFixedSpace(colSpanList, effectiveColumnWidths); - // today we always allocate effectiveColumnWidths, but tomorrow we might be smarter, so leave the check in - if (nsnull!=effectiveColumnWidths) - delete [] effectiveColumnWidths; + DistributeFixedSpace(colSpanList); if (PR_TRUE==gsDebug) - printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, aMinTableWidth, aMaxTableWidth); - + printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, mMinTableWidth, mMaxTableWidth); + + // clean up if (nsnull!=spanList) delete spanList; if (nsnull!=colSpanList) @@ -497,10 +456,10 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo // take the fixed space spanned by the columns in aColSpanList // and distribute it proportionately (based on desired width) -void BasicTableLayoutStrategy::DistributeFixedSpace(nsVoidArray *aColSpanList, nscoord *aColWidths) +void BasicTableLayoutStrategy::DistributeFixedSpace(nsVoidArray *aColSpanList) { nscoord excess = 0; - if (PR_TRUE==gsDebug) printf ("DistributeFixedSpace:\n"); + if (PR_TRUE==gsDebug) printf ("** 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; nextSpanningCellGetColumnFrame(colIndex+i, colFrame); + totalEffectiveWidth += colFrame->GetEffectiveMaxColWidth(); } // 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)(aColWidths[colIndex+i]))/((float)totalEffectiveWidth); + percent = ((float)(colFrame->GetEffectiveMaxColWidth()))/((float)totalEffectiveWidth); nscoord colWidth = (nscoord)(totalColWidth*percent); if (gsDebug==PR_TRUE) printf(" assigning fixed col width for spanning cells: column %d set to %d\n", colIndex+i, colWidth); mTableFrame->SetColumnWidth(colIndex+i, colWidth); + colFrame->SetMaxColWidth(colWidth); } } } -PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, +/* 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 nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, - nscoord aMinTableWidth, - nscoord aMaxTableWidth, - nscoord aTableFixedWidth, + nscoord aTableSpecifiedWidth, PRBool aTableIsAutoWidth) { PRBool result = PR_TRUE; - if (0==aTableFixedWidth) - { - if (NS_UNCONSTRAINEDSIZE==aMaxWidth || NS_UNCONSTRAINEDSIZE==aMinTableWidth) - { // the max width of the table fits comfortably in the available space - if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, - aMaxWidth, aTableFixedWidth, aTableIsAutoWidth); - } - else if (aMinTableWidth > aMaxWidth) - { // the table doesn't fit in the available space - if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n"); - result = SetColumnsToMinWidth(aPresContext); - } - else if (aMaxTableWidth <= aMaxWidth) - { // the max width of the table fits comfortably in the available space - if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, - aMaxWidth, aTableFixedWidth, aTableIsAutoWidth); - } - else - { // the table fits somewhere between its min and desired size - if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsConstrained\n"); - result = BalanceColumnsConstrained(aPresContext, aReflowState, aAvailWidth, - aMaxWidth, aMinTableWidth, aMaxTableWidth); - } + nscoord actualMaxWidth; // the real target width, depends on if we're auto or specified width + if (PR_TRUE==aTableIsAutoWidth) + actualMaxWidth = aMaxWidth; + else + actualMaxWidth = aTableSpecifiedWidth; + + if (NS_UNCONSTRAINEDSIZE==aMaxWidth || NS_UNCONSTRAINEDSIZE==mMinTableWidth) + { // the max width of the table fits comfortably in the available space + if (gsDebug) printf (" * auto table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n"); + result = BalanceColumnsTableFits(aReflowState, aAvailWidth, + aMaxWidth, aTableSpecifiedWidth, aTableIsAutoWidth); + } + else if (mMinTableWidth > actualMaxWidth) + { // the table doesn't fit in the available space + if (gsDebug) printf (" * auto table minTW does not fit, calling SetColumnsToMinWidth\n"); + result = SetColumnsToMinWidth(); + } + else if (mMaxTableWidth <= actualMaxWidth) + { // the max width of the table fits comfortably in the available space + if (gsDebug) printf (" * auto table desired size fits, calling BalanceColumnsTableFits\n"); + result = BalanceColumnsTableFits(aReflowState, aAvailWidth, + aMaxWidth, aTableSpecifiedWidth, aTableIsAutoWidth); } else - { // tables with fixed-width have their own rules - if (NS_UNCONSTRAINEDSIZE==aMinTableWidth) - { // the table has empty content, and needs to be streched to the specified width - if (gsDebug) printf (" * specified width table > maxTableWidth, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, - aMaxWidth, aTableFixedWidth, aTableIsAutoWidth); - } - else if ((aTableFixedWidth= its max width, so give each column its max requested size - if (gsDebug) printf (" * specified width table > maxTableWidth, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, - aMaxWidth, aTableFixedWidth, aTableIsAutoWidth); - } + { // the table fits somewhere between its min and desired size + if (gsDebug) printf (" * auto table desired size does not fit, calling BalanceColumnsConstrained\n"); + result = BalanceColumnsConstrained(aReflowState, aAvailWidth, + actualMaxWidth); } + return result; } -PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresContext) +// the table doesn't fit, so squeeze every column down to its minimum +PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth() { PRBool result = PR_TRUE; @@ -626,48 +569,21 @@ PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresConte colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition); if (PR_FALSE==IsFixedWidth(colPosition)) { - for (PRInt32 rowIndex = 0; rowIndexGetCellAt(rowIndex, colIndex); - if (nsnull==cellFrame) - { // there is no cell in this row that corresponds to this column - continue; - } - if (rowIndex!=cellFrame->GetRowIndex()) { - // 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; - } - - nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); - PRInt32 colSpan = cellFrame->GetColSpan(); - nscoord cellMinWidth = cellMinSize.width/colSpan; - if (minColWidth < cellMinWidth) - minColWidth = cellMinWidth; - } + minColWidth = colFrame->GetMinColWidth(); + mTableFrame->SetColumnWidth(colIndex, minColWidth); if (PR_TRUE==hasColsAttribute) { minColWidthArray[colIndex] = minColWidth; } - - if (gsDebug==PR_TRUE) - { - printf (" for determining width of col %d %s:\n", - colIndex, !IsFixedWidth(colPosition)? "(P)":"(A)"); - printf (" minColWidth = %d\n", minColWidth); - } - - mTableFrame->SetColumnWidth(colIndex, minColWidth); - if (gsDebug==PR_TRUE) - printf (" 2: col %d, set to width = %d\n", colIndex, mTableFrame->GetColumnWidth(colIndex)); } + if (gsDebug==PR_TRUE) + printf (" 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 aMinTableWidth and aMaxTableWidth + // 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 + { // 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; @@ -686,40 +602,34 @@ PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresConte if (PR_TRUE==gsDebug) printf(" 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; } -PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, +/* 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 nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, - nscoord aTableFixedWidth, + nscoord aTableSpecifiedWidth, PRBool aTableIsAutoWidth) { -#ifdef DEBUG - nsIFrame *tablePIF=nsnull; - mTableFrame->GetPrevInFlow(tablePIF); - NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!"); -#endif - 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 + 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 - nscoord * effectiveColumnWidths = new nscoord[mNumCols]; // used for Nav4 compatible table fluffing - nsCRT::memset (effectiveColumnWidths, 0, mNumCols*sizeof(PRInt32)); PRInt32 numRows = mTableFrame->GetRowCount(); for (PRInt32 colIndex = 0; colIndexGetCellAt(rowIndex, colIndex); - if (nsnull!=firstCellInColumn) - break; - } - nsMargin colMargin; - nscoord colInset = 0; - if (nsnull!=firstCellInColumn) - { - firstCellInColumn->GetMargin(colMargin); - colInset = colMargin.left + colMargin.right; - } + nscoord colInset = mTableFrame->GetCellSpacing(); const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition); @@ -784,43 +681,30 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check continue; } + if (colIndex!=cellFrame->GetColIndex()) { + // 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 = cellFrame->GetColSpan(); + PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); // distribute a portion of the spanning cell's min and max width to this column nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); - PRInt32 cellMinWidth = cellMinSize.width/colSpan; + nscoord cellMinWidth = cellMinSize.width/colSpan; // first get the desired size info from reflow pass 1 - PRInt32 cellDesiredWidth = cellDesiredSize.width/colSpan; + nscoord cellDesiredWidth = cellDesiredSize.width/colSpan; // then get the desired size info factoring in the cell style attributes nscoord specifiedCellWidth=-1; const nsStylePosition* cellPosition; cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition); - switch (cellPosition->mWidth.GetUnit()) { - case eStyleUnit_Coord: - specifiedCellWidth = cellPosition->mWidth.GetCoordValue(); - if (gsDebug) printf("cell has specified coord width = %d\n", specifiedCellWidth); - break; - - case eStyleUnit_Percent: - { - nscoord tableWidth=0; - nsIStyleContextPtr tableSC; - mTableFrame->GetStyleContext(aPresContext, tableSC.AssignRef()); - PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(mTableFrame, tableSC, aReflowState, tableWidth); - float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(tableWidth*percent); - if (gsDebug) printf("specified percent width %f of %d = %d\n", - percent, tableWidth, specifiedCellWidth); - break; - } - - case eStyleUnit_Inherit: - // XXX for now, do nothing - default: - case eStyleUnit_Auto: - break; + if (eStyleUnit_Percent==cellPosition->mWidth.GetUnit()) + { //QQQ what if table is auto width? + float percent = cellPosition->mWidth.GetPercentValue(); + specifiedCellWidth = (PRInt32)(aTableSpecifiedWidth*percent); + if (gsDebug) printf("specified percent width %f of %d = %d\n", + percent, aTableSpecifiedWidth, specifiedCellWidth); } if (-1!=specifiedCellWidth) { @@ -828,7 +712,8 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo { if (gsDebug) printf("setting cellDesiredWidth from %d to %d\n", cellDesiredWidth, specifiedCellWidth/colSpan); - cellDesiredWidth = specifiedCellWidth/colSpan; // TODO: some math needed here for colspans + cellDesiredWidth = specifiedCellWidth/colSpan; + //QQQ should be proportionately distributed as a post-process } } @@ -839,13 +724,10 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo minColWidth = cellMinWidth; if (maxColWidth < cellDesiredWidth) maxColWidth = cellDesiredWidth; - // effectiveColumnWidth is the width as if no cells with colspans existed - if ((1==colSpan) && (effectiveColumnWidths[colIndex] < maxColWidth)) - effectiveColumnWidths[colIndex] = cellDesiredWidth; if (gsDebug==PR_TRUE) printf (" after cell %d, minColWidth=%d maxColWidth=%d effColWidth[%d]=%d\n", rowIndex, minColWidth, maxColWidth, - colIndex, effectiveColumnWidths[colIndex]); + colIndex, colFrame->GetEffectiveMaxColWidth()); if ((1GetColIndex()==colIndex)) { // add this cell to span list iff we are currently processing the column the cell starts in SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth); @@ -853,7 +735,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo spanList = new nsVoidArray(); spanList->AppendElement(spanInfo); } - } + } // end looping through cells in the column if (gsDebug==PR_TRUE) { @@ -869,10 +751,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo nscoord specifiedFixedColumnWidth = -1; PRBool isAutoWidth = PR_FALSE; switch (colPosition->mWidth.GetUnit()) { - case eStyleUnit_Coord: - specifiedFixedColumnWidth = colPosition->mWidth.GetCoordValue(); - if (gsDebug) printf("column %d has specified coord width = %d\n", colIndex, specifiedFixedColumnWidth); - break; case eStyleUnit_Percent: specifiedPercentageColWidth = colPosition->mWidth.GetPercentValue(); if (gsDebug) printf("column %d has specified percent width = %f\n", colIndex, specifiedPercentageColWidth); @@ -927,16 +805,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo printf (" 3 proportional: col %d with availWidth %d, gets %d slices with %d slices so far.\n", colIndex, aAvailWidth, specifiedProportionColumnWidth, totalSlices); } - else if (-1!=specifiedFixedColumnWidth) - { // the column has a specified pixel width - // if the column was computed to be too small, enlarge the column - nscoord resolvedWidth = specifiedFixedColumnWidth; - if (specifiedFixedColumnWidth <= minColWidth) - resolvedWidth = minColWidth; - mTableFrame->SetColumnWidth(colIndex, resolvedWidth); - if (gsDebug==PR_TRUE) - printf (" 3 fixed: col %d given %d\n", colIndex, resolvedWidth); - } else { // give the column a percentage of the remaining space PRInt32 percentage = -1; @@ -950,10 +818,10 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo { percentage = (PRInt32)(specifiedPercentageColWidth*100.0f); // TODO: rounding errors? // base the % on the total specified fixed width of the table - mTableFrame->SetColumnWidth(colIndex, (percentage*aTableFixedWidth)/100); + mTableFrame->SetColumnWidth(colIndex, (percentage*aTableSpecifiedWidth)/100); if (gsDebug==PR_TRUE) - printf (" 3 percent specified: col %d given %d percent of aTableFixedWidth %d, set to width = %d\n", - colIndex, percentage, aTableFixedWidth, mTableFrame->GetColumnWidth(colIndex)); + printf (" 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) { @@ -975,7 +843,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo } else { // need to maintain this so we know how much we have left over at the end - widthOfFixedTableColumns += mTableFrame->GetColumnWidth(colIndex) + colInset; + widthOfFixedTableColumns += colFrame->GetMaxColWidth() + colInset; } tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset; } @@ -985,7 +853,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo if (nsnull!=proportionalColumnsList) { // first, figure out the amount of space per slice - nscoord maxWidthForTable = (0!=aTableFixedWidth) ? aTableFixedWidth : aMaxWidth; + nscoord maxWidthForTable = (0!=aTableSpecifiedWidth) ? aTableSpecifiedWidth : aMaxWidth; if (NS_UNCONSTRAINEDSIZE!=maxWidthForTable) { nscoord widthRemaining = maxWidthForTable - tableWidth; @@ -1001,7 +869,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo printf (" 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; - effectiveColumnWidths[info->mColIndex] = computedColWidth; +// effectiveColumnWidth = computedColWidth; delete info; } } @@ -1026,7 +894,9 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo printf (" 3 proportional step 2 (unconstrained!): col %d set to width = %d\n", info->mColIndex, maxOfMaxColWidths); tableWidth += maxOfMaxColWidths; - effectiveColumnWidths[info->mColIndex] = maxOfMaxColWidths; + nsTableColFrame *colFrame; + mTableFrame->GetColumnFrame(info->mColIndex, colFrame); + colFrame->SetEffectiveMaxColWidth(maxOfMaxColWidths); delete info; } } @@ -1038,11 +908,8 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo // columns if possible. if ((PR_FALSE==aTableIsAutoWidth) && (aAvailWidth > (tableWidth-widthOfFixedTableColumns))) { - DistributeExcessSpace(aAvailWidth, tableWidth, widthOfFixedTableColumns, effectiveColumnWidths); + DistributeExcessSpace(aAvailWidth, tableWidth, widthOfFixedTableColumns); } - // today we always allocate effectiveColumnWidths, but tomorrow we might be smarter, so leave the check in - if (nsnull!=effectiveColumnWidths) - delete [] effectiveColumnWidths; if (nsnull!=spanList) delete spanList; return result; @@ -1052,12 +919,12 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo // 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 *aColWidths) + nscoord aWidthOfFixedTableColumns) { nscoord excess = 0; if (PR_TRUE==gsDebug) printf ("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; @@ -1065,7 +932,6 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); if (0!=numAutoColumns) { - nscoord computedTableWidth = aTableWidth - aWidthOfFixedTableColumns; // 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; @@ -1075,27 +941,35 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, PRInt32 i; for (i = 0; iGetColumnFrame(autoColumns[i], colFrame); + nscoord effectiveColWidth = colFrame->GetEffectiveMaxColWidth(); + if (0!=effectiveColWidth) + totalEffectiveWidthOfAutoColumns += effectiveColWidth; else totalEffectiveWidthOfAutoColumns += mTableFrame->GetColumnWidth(autoColumns[i]); } - excess = aAvailWidth - computedTableWidth; + // excess is the amount of space that was available minus the computed available width + // QQQ shouldn't it just be aMaxWidth - aTableWidth??? + excess = aAvailWidth - widthMinusFixedColumns; + // 2. next, compute the proportion to be added to each column, and add it for (i = 0; iGetColumnWidth(colIndex);//aColWidths[colIndex]; + nsTableColFrame *colFrame; + mTableFrame->GetColumnFrame(colIndex, colFrame); + nscoord oldColWidth = mTableFrame->GetColumnWidth(colIndex); float percent; if (0!=totalEffectiveWidthOfAutoColumns) - percent = ((float)(aColWidths[colIndex]))/((float)totalEffectiveWidthOfAutoColumns); + percent = ((float)(colFrame->GetEffectiveMaxColWidth()))/((float)totalEffectiveWidthOfAutoColumns); else percent = ((float)1)/((float)numAutoColumns); nscoord excessForThisColumn = (nscoord)(excess*percent); nscoord colWidth = excessForThisColumn+oldColWidth; if (gsDebug==PR_TRUE) printf(" distribute excess to auto columns: column %d was %d, now set to %d\n", - colIndex, aColWidths[colIndex], colWidth); + colIndex, oldColWidth, colWidth); mTableFrame->SetColumnWidth(colIndex, colWidth); } } @@ -1103,13 +977,13 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, // (they must be all fixed and percentage-width columns, or we would have gone into the block above) else { - excess = aAvailWidth - (aTableWidth-aWidthOfFixedTableColumns); + excess = aAvailWidth - widthMinusFixedColumns; if (gsDebug==PR_TRUE) printf(" aAvailWidth specified as %d, expanding columns by excess = %d\n", aAvailWidth, excess); for (PRInt32 colIndex = 0; colIndexGetColumnWidth(colIndex); float percent; @@ -1127,15 +1001,11 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, } } -/* this method is very similar to BalanaceColumnsTableFits, but there are enough - * subtle differences that code reuse is impractical. it's a shame. +/* assign columns widths for a table whose max size doesn't fit in the available space */ -PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPresContext, - const nsReflowState& aReflowState, +PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( const nsReflowState& aReflowState, nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aMinTableWidth, - nscoord aMaxTableWidth) + nscoord aMaxWidth) { #ifdef DEBUG nsIFrame *tablePIF=nsnull; @@ -1145,17 +1015,14 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre 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 + nscoord tableWidth; // the width of the table as a result of setting column widths + tableWidth = aMaxWidth-aAvailWidth; // the starting table width is the sum of fixed-width columns 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 - nscoord * effectiveMaxColumnWidths = new nscoord[mNumCols]; // used for Nav4 compatible table fluffing - nsCRT::memset (effectiveMaxColumnWidths, 0, mNumCols*sizeof(PRInt32)); - nscoord * effectiveMinColumnWidths = new nscoord[mNumCols]; // used for Nav4 compatible table fluffing - nsCRT::memset (effectiveMinColumnWidths, 0, mNumCols*sizeof(PRInt32)); PRInt32 numRows = mTableFrame->GetRowCount(); for (PRInt32 colIndex = 0; colIndexGetCellAt(rowIndex, colIndex); - if (nsnull!=firstCellInColumn) - break; - } - nsMargin colMargin; - nscoord colInset = 0; - if (nsnull!=firstCellInColumn) - { - firstCellInColumn->GetMargin(colMargin); - colInset = colMargin.left + colMargin.right; - } + nscoord colInset = mTableFrame->GetCellSpacing(); const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition); @@ -1224,8 +1078,13 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check continue; } + if (colIndex!=cellFrame->GetColIndex()) { + // 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 = cellFrame->GetColSpan(); + PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(colIndex, cellFrame); nsSize cellMinSize = cellFrame->GetPass1MaxElementSize(); nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize(); @@ -1237,29 +1096,15 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre const nsStylePosition* cellPosition; cellFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)cellPosition); switch (cellPosition->mWidth.GetUnit()) { - case eStyleUnit_Coord: - specifiedCellWidth = cellPosition->mWidth.GetCoordValue(); - if (gsDebug) printf("cell has specified coord width = %d\n", specifiedCellWidth); - break; - case eStyleUnit_Percent: { nscoord knownTableWidth=0; - nsIStyleContextPtr tableSC; - mTableFrame->GetStyleContext(aPresContext, tableSC.AssignRef()); - PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(mTableFrame, tableSC, aReflowState, knownTableWidth); float percent = cellPosition->mWidth.GetPercentValue(); - specifiedCellWidth = (PRInt32)(knownTableWidth*percent); + specifiedCellWidth = (PRInt32)(aMaxWidth*percent); if (gsDebug) printf("specified percent width %f of %d = %d\n", - percent, knownTableWidth, specifiedCellWidth); + percent, aMaxWidth, specifiedCellWidth); break; } - - case eStyleUnit_Inherit: - // XXX for now, do nothing - default: - case eStyleUnit_Auto: - break; } if (-1!=specifiedCellWidth) { @@ -1277,19 +1122,16 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre // remember the widest min cell width if (minColWidth < cellMinWidth) minColWidth = cellMinWidth; - // effectiveMinColumnWidth is the width as if no cells with colspans existed - if ((1==colSpan) && (effectiveMinColumnWidths[colIndex] < minColWidth)) - effectiveMinColumnWidths[colIndex] = cellMinWidth; // remember the max desired cell width if (maxColWidth < cellDesiredWidth) maxColWidth = cellDesiredWidth; // effectiveMaxColumnWidth is the width as if no cells with colspans existed - if ((1==colSpan) && (effectiveMaxColumnWidths[colIndex] < maxColWidth)) - effectiveMaxColumnWidths[colIndex] = cellDesiredWidth; + if ((1==colSpan) && (colFrame->GetEffectiveMaxColWidth() < maxColWidth)) + colFrame->SetEffectiveMaxColWidth(cellDesiredWidth); if (gsDebug==PR_TRUE) printf (" after cell %d, minColWidth=%d maxColWidth=%d effColWidth[%d]=%d,%d\n", rowIndex, minColWidth, maxColWidth, - colIndex, effectiveMaxColumnWidths[colIndex], effectiveMaxColumnWidths[colIndex]); + colIndex, colFrame->GetEffectiveMinColWidth(), colFrame->GetEffectiveMaxColWidth()); if ((1GetColIndex()==colIndex)) { // if this cell spans columns and we are processing the column that owns the cell // add the cell to our list of spanners @@ -1305,10 +1147,10 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre printf (" for determining width of col %d %s:\n", colIndex, !IsFixedWidth(colPosition)? "(P)":"(A)"); printf (" minTableWidth = %d and maxTableWidth = %d\n", - aMinTableWidth, aMaxTableWidth); + mMinTableWidth, mMaxTableWidth); printf (" minColWidth = %d, maxColWidth = %d, eff=%d,%d\n", - minColWidth, maxColWidth, effectiveMinColumnWidths[colIndex], - effectiveMaxColumnWidths[colIndex]); + minColWidth, maxColWidth, colFrame->GetEffectiveMinColWidth(), + colFrame->GetEffectiveMaxColWidth()); printf (" aAvailWidth = %d\n", aAvailWidth); } @@ -1318,10 +1160,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre nscoord specifiedFixedColumnWidth = -1; PRBool isAutoWidth = PR_FALSE; switch (colPosition->mWidth.GetUnit()) { - case eStyleUnit_Coord: - specifiedFixedColumnWidth = colPosition->mWidth.GetCoordValue(); - if (gsDebug) printf("column %d has specified coord width = %d\n", colIndex, specifiedFixedColumnWidth); - break; case eStyleUnit_Percent: specifiedPercentageColWidth = colPosition->mWidth.GetPercentValue(); if (gsDebug) printf("column %d has specified percent width = %f\n", colIndex, specifiedPercentageColWidth); @@ -1379,16 +1217,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre if (1!=specifiedProportionColumnWidth) equalWidthColumns = PR_FALSE; } - else if (-1!=specifiedFixedColumnWidth) - { // the column has a specified pixel width - // if the column was computed to be too small, enlarge the column - nscoord resolvedWidth = specifiedFixedColumnWidth; - if (specifiedFixedColumnWidth <= minColWidth) - resolvedWidth = minColWidth; - mTableFrame->SetColumnWidth(colIndex, resolvedWidth); - if (gsDebug==PR_TRUE) - printf (" 4 fixed: col %d given %d\n", colIndex, resolvedWidth); - } else { // give the column a percentage of the remaining space PRInt32 percentage = -1; @@ -1430,14 +1258,30 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre } } } + tableWidth += mTableFrame->GetColumnWidth(colIndex); } } /* --- post-process if necessary --- */ + // first, assign autoWidth columns a width if (PR_TRUE==atLeastOneAutoWidthColumn) { // proportionately distribute the remaining space to autowidth columns - DistributeRemainingSpace(aAvailWidth, tableWidth, effectiveMinColumnWidths, effectiveMaxColumnWidths); + DistributeRemainingSpace(aAvailWidth, tableWidth); } - // second, assign a width to proportional-width columns + + // second, fix up tables where column width attributes give us a table that is too wide or too narrow + nscoord computedWidth=0; + for (PRInt32 i=0; iGetColumnWidth(i); + } + if (computedWidthaMaxWidth) { + AdjustTableThatIsTooWide(computedWidth, aMaxWidth); + } + + + // finally, assign a width to proportional-width columns if (nsnull!=proportionalColumnsList) { // first, figure out the amount of space per slice @@ -1469,11 +1313,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre } // clean up - // today we always allocate effectiveColumnWidths, but tomorrow we might be smarter, so leave the check in - if (nsnull!=effectiveMinColumnWidths) - delete [] effectiveMinColumnWidths; - if (nsnull!=effectiveMaxColumnWidths) - delete [] effectiveMaxColumnWidths; if (nsnull!=spanList) { NS_ASSERTION(0==spanList->Count(), "space leak, span list not empty"); @@ -1486,20 +1325,18 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre //XXX: make sure aTFW takes into account fixed width cells already assigned // take the remaining space in the table and distribute it proportionately // to the auto-width cells in the table (based on desired width) -void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableFixedWidth, - nscoord aComputedTableWidth, - nscoord *aMinColWidths, - nscoord *aMaxColWidths) +void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth, + nscoord aComputedTableWidth) { if (PR_TRUE==gsDebug) printf ("DistributeRemainingSpace: fixed width %d > computed table width %d\n", - aTableFixedWidth, aComputedTableWidth); + aTableSpecifiedWidth, aComputedTableWidth); // if there are auto-sized columns, give them the extra space PRInt32 numAutoColumns=0; PRInt32 *autoColumns=nsnull; // 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 = aTableFixedWidth - aComputedTableWidth; + nscoord availWidth = aTableSpecifiedWidth - aComputedTableWidth; mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); if (0!=numAutoColumns) { @@ -1510,37 +1347,67 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableFixedWidt PRInt32 i; for (i = 0; iGetColFrame(autoColumns[i]); + nscoord maxEffectiveColWidth = colFrame->GetEffectiveMaxColWidth(); + if (0!=maxEffectiveColWidth) + totalEffectiveWidthOfAutoColumns += maxEffectiveColWidth; else totalEffectiveWidthOfAutoColumns += mTableFrame->GetColumnWidth(autoColumns[i]); } if (gsDebug==PR_TRUE) - printf(" aTableFixedWidth specified as %d, availWidth is = %d\n", - aTableFixedWidth, availWidth); + printf(" aTableSpecifiedWidth specified as %d, availWidth is = %d\n", + aTableSpecifiedWidth, availWidth); // 2. next, compute the proportion to be added to each column, and add it for (i = 0; iSetColumnWidth(colIndex, colWidth); + nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex); + // if we actually have room to distribute, do it here + // otherwise, the auto columns will remain 0-width until expanded to their minimum in EnsureCellMinWidths + if (0GetEffectiveMaxColWidth()))/((float)totalEffectiveWidthOfAutoColumns); + else + percent = ((float)1)/((float)numAutoColumns); + nscoord colWidth = (nscoord)(availWidth*percent); + if (gsDebug==PR_TRUE) + printf(" distribute width to auto columns: column %d was %d, now set to %d\n", + colIndex, colFrame->GetEffectiveMaxColWidth(), colWidth); + mTableFrame->SetColumnWidth(colIndex, colWidth); + } } - EnsureCellMinWidths(aMinColWidths); + + if (PR_TRUE==gsDebug) + { + nscoord tableWidth=0; + for (PRInt32 i=0; iGetColumnWidth(i); + printf ("before EnsureCellMinWidth, computed table width is %d\n",tableWidth); + } + + EnsureCellMinWidths(); + } + if (PR_TRUE==gsDebug) + { + nscoord tableWidth=0; + for (PRInt32 i=0; iGetColumnWidth(i); + printf ("after EnsureCellMinWidth, computed table width is %d\n",tableWidth); } } -void BasicTableLayoutStrategy::EnsureCellMinWidths(nscoord *aMinColWidths) +void BasicTableLayoutStrategy::EnsureCellMinWidths() { PRBool atLeastOne = PR_TRUE; + /* XXX we'll use this if it turns out that fixed-width cells + XXX should NOT be shrunk to accomodate table width + PRInt32 numFixedColumns; + PRInt32 *fixedColumns=nsnull; + mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); + */ while (PR_TRUE==atLeastOne) { atLeastOne=PR_FALSE; @@ -1549,11 +1416,13 @@ void BasicTableLayoutStrategy::EnsureCellMinWidths(nscoord *aMinColWidths) // first, bump up cells that are below their min to their min width for (colIndex=0; colIndexGetColFrame(colIndex); + nscoord minEffectiveColWidth = colFrame->GetEffectiveMinColWidth(); nscoord colWidth = mTableFrame->GetColumnWidth(colIndex); - if (colWidthSetColumnWidth(colIndex, aMinColWidths[colIndex]); + addedWidth += (minEffectiveColWidth-colWidth); + mTableFrame->SetColumnWidth(colIndex, minEffectiveColWidth); atLeastOne=PR_TRUE; } } @@ -1561,21 +1430,93 @@ void BasicTableLayoutStrategy::EnsureCellMinWidths(nscoord *aMinColWidths) //QQQ boy is this slow! there has to be a faster way that is still guaranteed to be accurate... while ((addedWidth>0)) { // while we still have some extra space, and last time we were able to take some off... + PRInt32 startingAddedWidth = addedWidth; for (colIndex=0; colIndexGetColFrame(colIndex); + nscoord minEffectiveColWidth = colFrame->GetEffectiveMinColWidth(); nscoord colWidth = mTableFrame->GetColumnWidth(colIndex); - if (colWidth>aMinColWidths[colIndex]) + if (colWidth>minEffectiveColWidth) { mTableFrame->SetColumnWidth(colIndex, colWidth-1); addedWidth--; + if (0==addedWidth) + { // we're run out of extra space + break; // for (colIndex=0; colIndex0)) + } } if (0GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); + nscoord excess = aComputedWidth - aTableWidth; + if (0GetColumnWidth(colIndex); + colWidth -= excessPerColumn; + nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex); + if (colWidth > colFrame->GetEffectiveMinColWidth()) + mTableFrame->SetColumnWidth(colIndex, colWidth); + else + mTableFrame->SetColumnWidth(colIndex, colFrame->GetEffectiveMinColWidth()); + } + } + } +} + +void BasicTableLayoutStrategy::AdjustTableThatIsTooNarrow(nscoord aComputedWidth, + nscoord aTableWidth) +{ + PRInt32 numFixedColumns=0; + PRInt32 *fixedColumns=nsnull; + //XXX todo: exclude fixed width columns + //mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns); + nscoord excess = aTableWidth - aComputedWidth; + if (0GetColumnWidth(colIndex); + colWidth += excessPerColumn; + nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex); + if (colWidth >colFrame->GetEffectiveMinColWidth()) + mTableFrame->SetColumnWidth(colIndex, colWidth); + else + mTableFrame->SetColumnWidth(colIndex, colFrame->GetEffectiveMinColWidth()); + } + } + } +} + +//PRBool BasicTableLayoutStrategy::IsFixedWidthColumn(PRInt32 colIndex, PRInt32 *colIndexes) + diff --git a/layout/tables/BasicTableLayoutStrategy.h b/layout/tables/BasicTableLayoutStrategy.h index 1bca0687bafa..0ea87b4d5cac 100644 --- a/layout/tables/BasicTableLayoutStrategy.h +++ b/layout/tables/BasicTableLayoutStrategy.h @@ -31,20 +31,24 @@ struct nsStylePosition; struct SpanInfo { - nscoord span; + PRInt32 span; + const PRInt32 initialColSpan; nscoord cellMinWidth; nscoord cellDesiredWidth; - SpanInfo(nscoord aSpan, nscoord aMinWidth, nscoord aDesiredWidth) - { - span = aSpan; - cellMinWidth = aMinWidth; - cellDesiredWidth = aDesiredWidth; - }; - + SpanInfo(PRInt32 aSpan, nscoord aMinWidth, nscoord aDesiredWidth); ~SpanInfo() {}; }; +inline SpanInfo::SpanInfo(PRInt32 aSpan, nscoord aMinWidth, nscoord aDesiredWidth) + : initialColSpan(aSpan) +{ + span = aSpan; + cellMinWidth = aMinWidth; + cellDesiredWidth = aDesiredWidth; +} + + /* ---------- BasicTableLayoutStrategy ---------- */ @@ -60,86 +64,69 @@ public: ~BasicTableLayoutStrategy(); - virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext *aTableStyle, - const nsReflowState& aReflowState, - nscoord aMaxWidth, - nscoord &aTotalFixedWidth, - nscoord &aMinTableWidth, - nscoord &aMaxTableWidth, - nsSize* aMaxElementSize); + /** call once every time any table thing changes (content, structure, or style) */ + virtual PRBool Initialize(nsSize* aMaxElementSize); - /** assign widths for each column that has fixed width. + virtual PRBool BalanceColumnWidths(nsIStyleContext * aTableStyle, + const nsReflowState& aReflowState, + nscoord aMaxWidth); + + /** assign widths for each column. + * if the column has a fixed coord width, use it. + * if the column includes col spanning cells, + * then distribute the fixed space between cells proportionately. * Computes the minimum and maximum table widths. - * Sets mColumnWidths as a side effect. - * - * @param aPresContext the presentation context - * @param aMaxWidth the maximum width of the table - * @param aTableStyle the resolved style for the table - * @param aTotalFixedWidth out param, the sum of the fixed width columns - * @param aMinTableWidth out param, the min possible table width - * @param aMaxTableWidth out param, the max table width + * Set column width information in each column frame and in the table frame. * * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error * - * TODO: should be renamed to "AssignKnownWidthInformation */ - virtual PRBool AssignFixedColumnWidths(nsIPresContext* aPresContext, - nscoord aMaxWidth, - nscoord & aTotalFixedWidth, - nscoord & aMinTableWidth, - nscoord & aMaxTableWidth); + virtual PRBool AssignPreliminaryColumnWidths(); /** assign widths for each column that has proportional width inside a table that * has auto width (width set by the content and available space.) * Sets mColumnWidths as a side effect. * - * @param aPresContext the presentation context - * @param aTableStyle the resolved style for the table - * @param aAvailWidth the remaining amount of horizontal space available - * @param aMaxWidth the total amount of horizontal space available - * @param aMinTableWidth the min possible table width - * @param aMaxTableWidth the max table width + * @param aTableStyle the resolved style for the table + * @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(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, + virtual PRBool BalanceProportionalColumns(const nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, - nscoord aMinTableWidth, - nscoord aMaxTableWidth, - nscoord aTableFixedWidth, + nscoord aTableSpecifiedWidth, PRBool aTableIsAutoWidth); /** assign the minimum allowed width for each column that has proportional width. * Typically called when the min table width doesn't fit in the available space. * Sets mColumnWidths as a side effect. * - * @param aPresContext the presentation context * * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error */ - virtual PRBool SetColumnsToMinWidth(nsIPresContext* aPresContext); + virtual PRBool SetColumnsToMinWidth(); /** assign the maximum allowed width for each column that has proportional width. * Typically called when the desired max table width fits in the available space. * Sets mColumnWidths as a side effect. * - * @param aPresContext the presentation context - * @param aAvailWidth the remaining amount of horizontal space available - * @param aMaxWidth the total amount of horizontal space available - * @param aTableFixedWidth the specified width of the table. If there is none, - * this param is 0 + * @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(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, + virtual PRBool BalanceColumnsTableFits(const nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, - nscoord aTableFixedWidth, + nscoord aTableSpecifiedWidth, PRBool aTableIsAutoWidth); /** assign widths for each column that has proportional width inside a table that @@ -147,7 +134,6 @@ public: * HTML 4 specification. * Sets mColumnWidths as a side effect. * - * @param aPresContext the presentation context * @param aTableStyle the resolved style for the table * @param aAvailWidth the remaining amount of horizontal space available * @param aMaxWidth the total amount of horizontal space available @@ -158,23 +144,19 @@ public: * * TODO: rename this method to reflect that it is a Nav4 compatibility method */ - virtual PRBool BalanceColumnsConstrained(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, + virtual PRBool BalanceColumnsConstrained(const nsReflowState& aReflowState, nscoord aAvailWidth, - nscoord aMaxWidth, - nscoord aMinTableWidth, - nscoord aMaxTableWidth); + nscoord aMaxWidth); /** post-process to AssignFixedColumnWidths * * @param aColSpanList a list of fixed-width columns that have colspans - * @param aColWidths the effective column widths (ignoring col span cells) * * NOTE: does not yet properly handle overlapping col spans * * @return void */ - virtual void DistributeFixedSpace(nsVoidArray *aColSpanList, nscoord *aColWidths); + 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. @@ -189,8 +171,7 @@ public: */ virtual void DistributeExcessSpace(nscoord aAvailWidth, nscoord aTableWidth, - nscoord aWidthOfFixedTableColumns, - nscoord *aColWidths); + nscoord aWidthOfFixedTableColumns); /** starting with a partially balanced table, compute the amount * of space to remove from each column to completely balance the table. @@ -203,14 +184,18 @@ public: * @return void */ virtual void DistributeRemainingSpace(nscoord aTableFixedWidth, - nscoord aComputedTableWidth, - nscoord *aMinColWidths, - nscoord *aMaxColWidths); + nscoord aComputedTableWidth); /** force all cells to be at least their minimum width, removing any excess space * created in the process from fat cells that can afford to lose a little tonnage. */ - virtual void EnsureCellMinWidths(nscoord *aMinColWidths); + virtual void EnsureCellMinWidths(); + + virtual void AdjustTableThatIsTooWide(nscoord aComputedWidth, + nscoord aTableWidth); + + virtual void AdjustTableThatIsTooNarrow(nscoord aComputedWidth, + nscoord aTableWidth); /** return true if the style indicates that the width is a specific width * for the purposes of column width determination. @@ -218,12 +203,15 @@ public: */ virtual PRBool IsFixedWidth(const nsStylePosition* aStylePosition); - virtual PRBool IsAutoWidth(const nsStylePosition* aStylePosition); protected: nsTableFrame * mTableFrame; PRInt32 mCols; PRInt32 mNumCols; + // cached data + nscoord mMinTableWidth; // the absolute smallest width 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 }; diff --git a/layout/tables/nsITableLayoutStrategy.h b/layout/tables/nsITableLayoutStrategy.h index 861aa290f3b5..543235dbf917 100644 --- a/layout/tables/nsITableLayoutStrategy.h +++ b/layout/tables/nsITableLayoutStrategy.h @@ -22,7 +22,6 @@ #include "nscore.h" #include "nsSize.h" -class nsIPresContext; class nsIStyleContext; struct nsReflowState; @@ -30,25 +29,21 @@ class nsITableLayoutStrategy { public: + /** call once every time any table thing changes (content, structure, or style) + * @param aMaxElementSize [OUT] the min possible size of the table + */ + virtual PRBool Initialize(nsSize* aMaxElementSize)=0; + /** assign widths for each column, taking into account the table content, the effective style, * the layout constraints, and the compatibility mode. Sets mColumnWidths as a side effect. - * @param aPresContext the presentation context * @param aTableStyle the resolved style for the table * @param aReflowState the reflow state for the calling table frame * @param aMaxWidth the width constraint - * @param aTotalFixedWidth [OUT] the computed fixed width of the table - * @param aMinTableWidth [OUT] the computed min width of the table - * @param aMinTableWidth [OUT] the computed max width of the table - * @param aMaxElementSize [OUT] the min size of the largest indivisible object + */ - virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext, - nsIStyleContext *aTableStyle, + virtual PRBool BalanceColumnWidths(nsIStyleContext *aTableStyle, const nsReflowState& aReflowState, - nscoord aMaxWidth, - nscoord &aTotalFixedWidth, - nscoord &aMinTableWidth, - nscoord &aMaxTableWidth, - nsSize* aMaxElementSize)=0; + nscoord aMaxWidth)=0; }; #endif diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index 3615f2b3ccf9..3ff92ad013ea 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -511,10 +511,10 @@ void nsTableCellFrame::MapBorderMarginPadding(nsIPresContext* aPresContext) return; // get the table frame style context, and from it get cellpadding, cellspacing, and border info - nsIStyleContextPtr tableSC; - tableFrame->GetStyleContext(aPresContext, tableSC.AssignRef()); - nsStyleTable* tableStyle = (nsStyleTable*)tableSC->GetStyleData(eStyleStruct_Table); - nsStyleSpacing* tableSpacingStyle = (nsStyleSpacing*)tableSC->GetStyleData(eStyleStruct_Spacing); + nsStyleTable* tableStyle; + tableFrame->GetStyleData(eStyleStruct_Table, (nsStyleStruct *&)tableStyle); + nsStyleSpacing* tableSpacingStyle; + tableFrame->GetStyleData(eStyleStruct_Spacing,(nsStyleStruct *&)tableSpacingStyle); nsStyleSpacing* spacingData = (nsStyleSpacing*)mStyleContext->GetMutableStyleData(eStyleStruct_Spacing); // check to see if cellpadding or cellspacing is defined diff --git a/layout/tables/nsTableColFrame.cpp b/layout/tables/nsTableColFrame.cpp index 4745bd68b5a7..4fe0f13656b6 100644 --- a/layout/tables/nsTableColFrame.cpp +++ b/layout/tables/nsTableColFrame.cpp @@ -38,6 +38,10 @@ nsTableColFrame::nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame) { mColIndex = 0; mRepeat = 0; + mMaxColWidth = 0; + mMinColWidth = 0; + mMaxEffectiveColWidth = 0; + mMinEffectiveColWidth = 0; } @@ -55,11 +59,12 @@ NS_METHOD nsTableColFrame::Paint(nsIPresContext& aPresContext, } -NS_METHOD nsTableColFrame::Reflow(nsIPresContext& aPresContext, +NS_METHOD nsTableColFrame::Reflow(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, nsReflowStatus& aStatus) { + NS_ASSERTION(nsnull!=aPresContext, "bad arg"); aDesiredSize.width=0; aDesiredSize.height=0; if (nsnull!=aDesiredSize.maxElementSize) diff --git a/layout/tables/nsTableColFrame.h b/layout/tables/nsTableColFrame.h index 3c70a7955b89..13b8b66691a9 100644 --- a/layout/tables/nsTableColFrame.h +++ b/layout/tables/nsTableColFrame.h @@ -34,7 +34,7 @@ public: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); - NS_IMETHOD Reflow(nsIPresContext& aPresContext, + NS_IMETHOD Reflow(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, nsReflowStatus& aStatus); @@ -51,6 +51,18 @@ 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); + /** convenience method, calls into cellmap */ PRInt32 Count() const; @@ -66,11 +78,11 @@ protected: /** the number of columns that the attributes of this column extend to */ PRInt32 mRepeat; - nscoord mMaxWidth; - nscoord mMinWidth; + nscoord mMaxColWidth; + nscoord mMinColWidth; - nscoord mMaxEffectiveWidth; - nscoord mMinEffectiveWidth; + nscoord mMaxEffectiveColWidth; + nscoord mMinEffectiveColWidth; }; @@ -93,5 +105,29 @@ inline nsTableColFrame::GetRepeat() inline void nsTableColFrame::SetColumnIndex (int aColIndex) { mColIndex = aColIndex;} +inline nscoord nsTableColFrame::GetMaxColWidth() +{ return mMaxColWidth; } + +inline void nsTableColFrame::SetMaxColWidth(nscoord aMaxColWidth) +{ mMaxColWidth = aMaxColWidth; } + +inline nscoord nsTableColFrame::GetMinColWidth() +{ return mMinColWidth; } + +inline void nsTableColFrame::SetMinColWidth(nscoord aMinColWidth) +{ mMinColWidth = aMinColWidth; } + +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 aMinColWidth) +{ mMinEffectiveColWidth = aMinColWidth; } + #endif diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 4be7370650a7..6c7d634f5640 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -396,7 +396,7 @@ nsTableCellFrame * nsTableFrame::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) } -// return the rows spanned by aCell starting at aRowIndex +// 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) // @@ -416,6 +416,24 @@ PRInt32 nsTableFrame::GetEffectiveRowSpan (PRInt32 aRowIndex, nsTableCellFrame * return rowSpan; } +// 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) +// +// XXX Should be moved to colgroup, as GetEffectiveRowSpan should be moved to rowgroup? +PRInt32 nsTableFrame::GetEffectiveColSpan (PRInt32 aColIndex, nsTableCellFrame *aCell) +{ + NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); + NS_PRECONDITION (nsnull!=mCellMap, "bad call, mCellMap not yet allocated."); + NS_PRECONDITION (0<=aColIndex && aColIndexGetColCount(), "bad col index arg"); + + int colSpan = aCell->GetColSpan(); + int colCount = mCellMap->GetColCount(); + if (colCount < (aColIndex + colSpan)) + return (colCount - aColIndex); + return colSpan; +} + /* call when the cell structure has changed. mCellMap will be rebuilt on demand. */ void nsTableFrame::ResetCellMap () { @@ -1198,6 +1216,11 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext& aPresContext, // XXX For the time being just fall through and treat it like a // pass 2 reflow... mPass = kPASS_SECOND; + // calling intialize here resets all the cached info based on new table content + if (nsnull!=mTableLayoutStrategy) + { + mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize); + } #else // XXX Hack... AdjustSiblingsAfterReflow(&aPresContext, state, kidFrame, desiredSize.height - @@ -2231,9 +2254,6 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, { NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); - if (gsDebug) - printf ("BalanceColumnWidths...\n"); - if (nsnull==mCellMap) return; // we don't have any information yet, so we can't do any useful work @@ -2244,11 +2264,6 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, nsCRT::memset (mColumnWidths, 0, numCols*sizeof(PRInt32)); } - // need to track min and max table widths - PRInt32 minTableWidth = 0; - PRInt32 maxTableWidth = 0; - PRInt32 totalFixedWidth = 0; - const nsStyleSpacing* spacing = (const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing); nsMargin borderPadding; @@ -2308,13 +2323,9 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, if (nsnull==mTableLayoutStrategy) { // TODO: build a different strategy based on the compatibility mode mTableLayoutStrategy = new BasicTableLayoutStrategy(this, numCols); + mTableLayoutStrategy->Initialize(aMaxElementSize); } - mTableLayoutStrategy->BalanceColumnWidths(aPresContext, mStyleContext, - aReflowState, maxWidth, - totalFixedWidth, - minTableWidth, maxTableWidth, - aMaxElementSize); - + mTableLayoutStrategy->BalanceColumnWidths(mStyleContext, aReflowState, maxWidth); } /** @@ -2608,7 +2619,7 @@ nsTableFrame::CreateContinuingFrame(nsIPresContext& aPresContext, nsIStyleContext* kidStyleContext = aPresContext.ResolveStyleContextFor(content, cf); // kidStyleContext: REFCNT++ nsIContentDelegate* kidDel = nsnull; - kidDel = content->GetDelegate(&aPresContext); // kidDel: REFCNT++ + kidDel = content->GetDelegate(&aPresContext); // kidDel: REFCNT++ nsIFrame* duplicateFrame; nsresult rv = kidDel->CreateFrame(&aPresContext, content, cf, kidStyleContext, duplicateFrame); @@ -2825,6 +2836,19 @@ NS_METHOD nsTableFrame::GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& return result; } +nscoord nsTableFrame::GetCellSpacing() +{ + nsTableFrame* tableFrame = this; + //XXX remove when table style is fully resolved! + GetGeometricParent((nsIFrame *&)tableFrame); // get the outer frame + nsStyleTable* tableStyle; + tableFrame->GetStyleData(eStyleStruct_Table, (nsStyleStruct *&)tableStyle); + nscoord cellSpacing = 0; + if (tableStyle->mCellSpacing.GetUnit() == eStyleUnit_Coord) + cellSpacing = tableStyle->mCellSpacing.GetCoordValue(); + return cellSpacing; +} + void nsTableFrame::GetColumnsByType(const nsStyleUnit aType, PRInt32& aOutNumColumns, PRInt32 *& aOutColumnIndexes) @@ -2989,27 +3013,34 @@ nscoord nsTableFrame::GetTableContainerWidth(const nsReflowState& aReflowState) } else { - nsSize tableSize; - table->GetSize(tableSize); - parentWidth = tableSize.width; - spacing->CalcBorderPaddingFor(rs->frame, borderPadding); - parentWidth -= (borderPadding.right + borderPadding.left); - // same for the row group - childFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); - spacing->CalcBorderPaddingFor(childFrame, borderPadding); - parentWidth -= (borderPadding.right + borderPadding.left); - // same for the row - grandchildFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); - spacing->CalcBorderPaddingFor(grandchildFrame, borderPadding); - parentWidth -= (borderPadding.right + borderPadding.left); - // same for the cell - greatgrandchildFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); - spacing->CalcBorderPaddingFor(greatgrandchildFrame, borderPadding); - parentWidth -= (borderPadding.right + borderPadding.left); - + if (nsnull!=((nsTableFrame*)table)->mColumnWidths) + { + PRInt32 colIndex = ((nsTableCellFrame*)greatgrandchildFrame)->GetColIndex(); + parentWidth = ((nsTableFrame*)table)->GetColumnWidth(colIndex); + } + else + { + nsSize tableSize; + table->GetSize(tableSize); + parentWidth = tableSize.width; + spacing->CalcBorderPaddingFor(rs->frame, borderPadding); + parentWidth -= (borderPadding.right + borderPadding.left); + // same for the row group + childFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); + spacing->CalcBorderPaddingFor(childFrame, borderPadding); + parentWidth -= (borderPadding.right + borderPadding.left); + // same for the row + grandchildFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); + spacing->CalcBorderPaddingFor(grandchildFrame, borderPadding); + parentWidth -= (borderPadding.right + borderPadding.left); + // same for the cell + greatgrandchildFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); + spacing->CalcBorderPaddingFor(greatgrandchildFrame, borderPadding); + parentWidth -= (borderPadding.right + borderPadding.left); + } if (PR_TRUE==gsDebugNT) - printf("%p: found a table frame %p, returning parentWidth %d from frame width %d\n", - aReflowState.frame, table, parentWidth, tableSize.width); + printf("%p: found a table frame %p, returning parentWidth %d \n", + aReflowState.frame, table, parentWidth); } break; } diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index c59004e4dddc..9ffdaf42d7ef 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -142,6 +142,9 @@ public: /** set the width of the column at aColIndex to aWidth */ virtual void SetColumnWidth(PRInt32 aColIndex, nscoord aWidth); + + /** helper to get the cell spacing style value */ + virtual nscoord GetCellSpacing(); /** * Calculate Layout Information @@ -167,13 +170,26 @@ public: /** return the row span of a cell, taking into account row span magic at the bottom * of a table. - * @param aRowIndex the first row that contains the cell - * @param aCell the content object representing the cell + * + * @param aRowIndex the row from which to measure effective row span + * @param aCell the cell + * * @return the row span, correcting for row spans that extend beyond the bottom * of the table. */ virtual PRInt32 GetEffectiveRowSpan(PRInt32 aRowIndex, nsTableCellFrame *aCell); + /** return the col span of a cell, taking into account col span magic at the edge + * of a table. + * + * @param aColIndex the column from which to measure effective col span + * @param aCell the cell + * + * @return the col span, correcting for col spans that extend beyond the edge + * of the table. + */ + virtual PRInt32 GetEffectiveColSpan(PRInt32 aColIndex, nsTableCellFrame *aCell); + // For DEBUGGING Purposes Only NS_IMETHOD MoveTo(nscoord aX, nscoord aY); NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index cd47a83a684a..93c77d2ec557 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -336,19 +336,22 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, nscoord maxCellTopMargin = 0; nscoord maxCellBottomMargin = 0; + if (PR_TRUE==gsDebug1) printf("%p: RR\n", this); + // Reflow each of our existing cell frames - for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { - // Get the frame's margins, and compare the top and bottom margin - // against our current max values - nsMargin kidMargin; + for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) + { + + nscoord cellSpacing = aState.tableFrame->GetCellSpacing(); + +// just cellSpacing? QQQ + nsMargin kidMargin; aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame,kidMargin); if (kidMargin.top > maxCellTopMargin) maxCellTopMargin = kidMargin.top; if (kidMargin.bottom > maxCellBottomMargin) maxCellBottomMargin = kidMargin.bottom; - // left and right margins already taken into account by table layout strategy - // Compute the x-origin for the child, taking into account straddlers (cells from prior // rows with rowspans > 1) PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex(); @@ -357,10 +360,14 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, for (PRInt32 colIndex=prevColIndex+1; colIndexGetColumnWidth(colIndex); - aState.x += kidMargin.left + kidMargin.right; + aState.x += cellSpacing; + if (PR_TRUE==gsDebug1) + printf(" in loop, aState.x set to %d from cellSpacing %d and col width\n", + aState.x, aState.tableFrame->GetColumnWidth(colIndex), cellSpacing); } } - aState.x += kidMargin.left; + aState.x += cellSpacing; + if (PR_TRUE==gsDebug1) printf(" past loop, aState.x set to %d\n", aState.x); // at this point, we know the column widths. // so we get the avail width from the known column widths @@ -369,13 +376,15 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellColIndex+numColSpan); - if (0GetColumnWidth(cellColIndex+numColSpan), cellSpacing); } + if (PR_TRUE==gsDebug1) printf(" availWidth for this cell is %d\n", availWidth); prevColIndex = cellColIndex + (cellColSpan-1); // remember the rightmost column this cell spans into @@ -461,7 +470,8 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext& aPresContext, PlaceChild(aPresContext, aState, kidFrame, kidRect, aDesiredSize.maxElementSize, pKidMaxElementSize); - aState.x += kidMargin.right; // add in right margin only after cell has been placed + + if (PR_TRUE==gsDebug1) printf(" past PlaceChild, aState.x set to %d\n", aState.x); // Get the next child kidFrame->GetNextSibling(kidFrame);