major hackage to the table data structures. slimmer, simpler, faster

this work exposed a few bugs and slow spots, which have been fixed
for the aol page, I added some additional backwards compatibility code
to proportionately distribute width when a fixed-width cell has colspans
This commit is contained in:
buster
1998-07-11 00:00:31 +00:00
parent e4231e34cc
commit 0f3a064a10
32 changed files with 3018 additions and 2485 deletions

View File

@@ -19,16 +19,13 @@
#include "BasicTableLayoutStrategy.h"
#include "nsTableFrame.h"
#include "nsTableColFrame.h"
#include "nsColLayoutData.h"
#include "nsCellLayoutData.h"
#include "nsTableCol.h"
#include "nsTableCellFrame.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
#include "nsVoidArray.h"
#include "nsIPtr.h"
#include "nsHTMLIIDs.h"
NS_DEF_PTR(nsTableCol);
NS_DEF_PTR(nsIStyleContext);
@@ -64,6 +61,23 @@ struct ProportionalColumnLayoutStruct
};
/* ---------- ColSpanStruct ---------- */
struct ColSpanStruct
{
PRInt32 colIndex;
PRInt32 colSpan;
nscoord width;
ColSpanStruct(PRInt32 aSpan, PRInt32 aIndex, nscoord aWidth)
{
colSpan = aSpan;
colIndex = aIndex;
width = aWidth;
}
};
/* ---------- BasicTableLayoutStrategy ---------- */
@@ -228,7 +242,9 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo
if (gsDebug==PR_TRUE) printf (" AssignFixedColumnWidths\n");
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);
@@ -240,26 +256,24 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo
maxColWidthArray = new PRInt32[mNumCols];
}
PRInt32 numRows = mTableFrame->GetRowCount();
// for every column, determine it's min and max width, and keep track of the table width
for (PRInt32 colIndex = 0; colIndex<mNumCols; colIndex++)
{
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
NS_ASSERTION(nsnull != colData, "bad column data");
nsTableColFrame *colFrame = colData->GetColFrame();
NS_ASSERTION(nsnull!=colFrame, "bad col frame");
// need to track min/max column width for setting min/max table widths
// QQQ: Eventually, this will be cached in col frame
// We'll just ask the column frame to compute this, and it'll use cached info if available
PRInt32 minColWidth = 0;
PRInt32 maxColWidth = 0;
nsVoidArray *cells = colData->GetCells();
PRInt32 numCells = cells->Count();
if (gsDebug==PR_TRUE) printf (" for column %d numCells = %d\n", colIndex, numCells);
// Get column information
nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex);
NS_ASSERTION(nsnull!=colFrame, "bad col frame");
// Get the columns's style
nsIStyleContextPtr colSC;
colFrame->GetStyleContext(aPresContext, colSC.AssignRef());
const nsStylePosition* colPosition = (const nsStylePosition*) colSC->GetStyleData(eStyleStruct_Position);
const nsStylePosition* colPosition;
colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition);
// Get column width if it has one
PRBool haveColWidth = PR_FALSE;
@@ -268,7 +282,7 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo
case eStyleUnit_Coord:
haveColWidth = PR_TRUE;
specifiedFixedColWidth = colPosition->mWidth.GetCoordValue();
mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); //QQQ add in margins?
mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth);
break;
default:
@@ -303,38 +317,49 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
PRInt32 firstRowIndex = -1;
for (PRInt32 rowIndex = 0; rowIndex<numRows; rowIndex++)
{
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
if (nsnull == data) {
// For cells that span rows there's only cell layout data for the first row
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
if (nsnull==cellFrame)
{ // there is no cell in this row that corresponds to this column
continue;
}
if (-1==firstRowIndex)
firstRowIndex = rowIndex;
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;
}
if (colIndex!=cellFrame->GetColIndex()) {
// For cells that span rows, we only figure it in once
NS_ASSERTION(1 != cellFrame->GetColSpan(), "col index does not match row span"); // sanity check
continue;
}
nsMargin margin;
nsresult result = data->GetMargin(margin);
nsSize * cellMinSize = data->GetMaxElementSize();
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
PRInt32 colSpan = data->GetCellFrame()->GetColSpan();
nsSize cellMinSize = cellFrame->GetPass1MaxElementSize();
nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize();
PRInt32 colSpan = cellFrame->GetColSpan();
if (gsDebug==PR_TRUE)
printf (" for cell %d with colspan=%d, min = %d,%d and des = %d,%d, margins %d %d\n",
cellIndex, colSpan, cellMinSize->width, cellMinSize->height,
cellDesiredSize->width, cellDesiredSize->height,
margin.left, margin.right);
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()) {
switch (colPosition->mWidth.GetUnit())
{
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)
PRInt32 widthForThisCell = PR_MAX(cellMinSize->width, colPosition->mWidth.GetCoordValue());
if (mTableFrame->GetColumnWidth(colIndex) < widthForThisCell)
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); //QQQ add in margins?
mTableFrame->SetColumnWidth(colIndex, widthForThisCell);
maxColWidth = widthForThisCell;
}
}
@@ -347,24 +372,24 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo
// regardless of the width specification, keep track of the
// min/max column widths
nscoord cellMinWidth = cellMinSize->width/colSpan;
nscoord cellDesiredWidth = cellDesiredSize->width/colSpan;
if (aMaxWidth!=cellDesiredSize->width)
{
if (NS_UNCONSTRAINEDSIZE!=cellMinWidth)
cellMinWidth += margin.left + margin.right;
if (NS_UNCONSTRAINEDSIZE!=cellDesiredWidth)
cellDesiredWidth += margin.left + margin.right;
}
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;
if (1<colSpan)
{
// add the cell to our list of spanners
// add the column to our list of post-process columns
ColSpanStruct *colSpanInfo = new ColSpanStruct(colSpan, colIndex, cellDesiredSize.width);
if (nsnull==colSpanList)
colSpanList = new nsVoidArray();
colSpanList->AppendElement(colSpanInfo);
// add the cell to our list of spanning cells
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
@@ -372,26 +397,30 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo
}
if (gsDebug) {
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
rowIndex, minColWidth, maxColWidth);
}
}
// do all the global bookkeeping, factoring in margins
nsTableCellFrame * firstCellInColumn = mTableFrame->GetCellAt(firstRowIndex, colIndex);
nsMargin colMargin;
firstCellInColumn->GetMargin(colMargin);
nscoord colInset = colMargin.left + colMargin.right;
// keep a running total of the amount of space taken up by all fixed-width columns
if (PR_TRUE==haveColWidth)
aTotalFixedWidth += mTableFrame->GetColumnWidth(colIndex);
aTotalFixedWidth += mTableFrame->GetColumnWidth(colIndex) + colInset;
if (gsDebug) {
printf (" after col %d, aTotalFixedWidth = %d\n",
colIndex, aTotalFixedWidth);
}
// add col[i] metrics to the running totals for the table min/max width
if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth)
aMinTableWidth += minColWidth; // SEC: insets!
aMinTableWidth += minColWidth + colInset;
if (aMinTableWidth<=0)
aMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth)
aMaxTableWidth += maxColWidth; // SEC: insets!
aMaxTableWidth += maxColWidth + colInset;
if (aMaxTableWidth<=0)
aMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
if (PR_TRUE==hasColsAttribute)
@@ -441,15 +470,59 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo
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;
if (PR_TRUE==gsDebug)
printf ("%p: aMinTW=%d, aMaxTW=%d\n", mTableFrame, aMinTableWidth, aMaxTableWidth);
if (nsnull!=spanList)
delete spanList;
if (nsnull!=colSpanList)
delete colSpanList;
return PR_TRUE;
}
// 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)
{
nscoord excess = 0;
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; nextSpanningCell<numSpanningCells; nextSpanningCell++)
{ // proportionately distributed extra space, based on the column's fixed width
ColSpanStruct * colInfo = (ColSpanStruct *)aColSpanList->ElementAt(nextSpanningCell);
PRInt32 colIndex = colInfo->colIndex;
PRInt32 colSpan = colInfo->colSpan;
nscoord totalColWidth = colInfo->width;
// 1. get the sum of the effective widths of the columns in the span
nscoord totalEffectiveWidth=0;
PRInt32 i;
for (i = 0; i<colSpan; i++)
{
totalEffectiveWidth += aColWidths[colIndex+i];
}
// 2. next, compute the proportion to be added to each column, and add it
for (i = 0; i<colSpan; i++)
{
float percent;
percent = ((float)(aColWidths[colIndex+i]))/((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);
}
}
}
PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPresContext,
const nsReflowState& aReflowState,
nscoord aAvailWidth,
@@ -529,35 +602,37 @@ PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresConte
minColWidthArray = new PRInt32[mNumCols];
}
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
PRInt32 numRows = mTableFrame->GetRowCount();
for (PRInt32 colIndex = 0; colIndex<mNumCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsVoidArray *cells = colData->GetCells();
PRInt32 minColWidth = 0;
PRInt32 maxColWidth = 0;
PRInt32 numCells = cells->Count();
if (gsDebug==PR_TRUE) printf (" for col %d\n", colIndex);
// XXX need column frame to ask this question
const nsStylePosition* colPosition = nsnull;
nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex);
NS_ASSERTION(nsnull!=colFrame, "bad col frame");
// Get the columns's style
const nsStylePosition* colPosition;
colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition);
if (PR_FALSE==IsFixedWidth(colPosition))
{
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
if (nsnull==data)
{ // For cells that span rows there's only cell layout data for the first row
for (PRInt32 rowIndex = 0; rowIndex<numRows; rowIndex++)
{ // this col has non-fixed width, so determine its width requirements
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
if (nsnull==cellFrame)
{ // there is no cell in this row that corresponds to this column
continue;
}
nsMargin margin;
data->GetMargin(margin);
nsSize * cellMinSize = data->GetMaxElementSize();
NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize");
nscoord cellMinWidth = cellMinSize->width; // do we need to take into account colSpan here?
cellMinWidth += margin.left + margin.right;
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;
}
@@ -624,32 +699,42 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo
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
// 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
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
nscoord * effectiveColumnWidths = new nscoord[numCols]; // used for Nav4 compatible table fluffing
nsCRT::memset (effectiveColumnWidths, 0, numCols*sizeof(PRInt32));
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
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; colIndex<mNumCols; colIndex++)
{
if (gsDebug==PR_TRUE) printf (" for col %d\n", colIndex);
PRInt32 minColWidth = 0;
PRInt32 maxColWidth = 0;
// Get column information
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsVoidArray *cells = colData->GetCells();
PRInt32 numCells = cells->Count();
// Get the columns's style
nsTableColFrame *colFrame = colData->GetColFrame();
nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex);
NS_ASSERTION(nsnull!=colFrame, "bad col frame");
nsIStyleContextPtr colSC;
colFrame->GetStyleContext(aPresContext, colSC.AssignRef());
const nsStylePosition* colPosition = (const nsStylePosition*) colSC->GetStyleData(eStyleStruct_Position);
if (gsDebug) printf("col %d has frame %p with style %p and pos %p\n",
colIndex, colFrame, (nsIStyleContext *)colSC, colPosition);
PRInt32 rowIndex;
PRInt32 firstRowIndex = -1;
nsTableCellFrame * firstCellInColumn;
for (rowIndex=0; rowIndex<numRows; rowIndex++)
{
firstCellInColumn = mTableFrame->GetCellAt(rowIndex, colIndex);
if (nsnull!=firstCellInColumn)
break;
}
nsMargin colMargin;
nscoord colInset = 0;
if (nsnull!=firstCellInColumn)
{
firstCellInColumn->GetMargin(colMargin);
colInset = colMargin.left + colMargin.right;
}
const nsStylePosition* colPosition;
colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition);
if (PR_FALSE==IsFixedWidth(colPosition))
{
// first, deal with any cells that span into this column from a pervious column
@@ -676,33 +761,33 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
for (rowIndex = 0; rowIndex<numRows; rowIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
if (nsnull == data) {
// For cells that span columns there's only cell layout data for the first column
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(rowIndex, colIndex);
if (nsnull==cellFrame)
{ // there is no cell in this row that corresponds to this column
continue;
}
if (-1==firstRowIndex)
firstRowIndex = rowIndex;
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;
}
PRInt32 colSpan = data->GetCellFrame()->GetColSpan();
PRInt32 colSpan = cellFrame->GetColSpan();
// distribute a portion of the spanning cell's min and max width to this column
nsSize * cellMinSize = data->GetMaxElementSize();
NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize");
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
nsSize cellMinSize = cellFrame->GetPass1MaxElementSize();
nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize();
nsMargin margin;
nsresult result = data->GetMargin(margin);
nscoord marginWidth = margin.left + margin.right;
PRInt32 cellMinWidth = cellMinSize->width/colSpan + marginWidth;
PRInt32 cellMinWidth = cellMinSize.width/colSpan;
// first get the desired size info from reflow pass 1
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan + marginWidth;
PRInt32 cellDesiredWidth = cellDesiredSize.width/colSpan;
// then get the desired size info factoring in the cell style attributes
nscoord specifiedCellWidth=-1;
nsIStyleContextPtr cellSC;
data->GetCellFrame()->GetStyleContext(aPresContext, cellSC.AssignRef());
const nsStylePosition* cellPosition = (const nsStylePosition*)
cellSC->GetStyleData(eStyleStruct_Position);
const nsStylePosition* cellPosition;
cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)cellPosition);
switch (cellPosition->mWidth.GetUnit()) {
case eStyleUnit_Coord:
specifiedCellWidth = cellPosition->mWidth.GetCoordValue();
@@ -730,17 +815,17 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo
}
if (-1!=specifiedCellWidth)
{
if (specifiedCellWidth>cellMinWidth)
if (specifiedCellWidth/colSpan>cellMinWidth)
{
if (gsDebug) printf("setting cellDesiredWidth from %d to %d\n",
cellDesiredWidth, specifiedCellWidth);
cellDesiredWidth = specifiedCellWidth; // TODO: some math needed here for colspans
cellDesiredWidth, specifiedCellWidth/colSpan);
cellDesiredWidth = specifiedCellWidth/colSpan; // TODO: some math needed here for colspans
}
}
if (PR_TRUE==gsDebug)
printf("factoring in cell %d with colSpan=%d\n factoring in min=%d and desired=%d\n",
cellIndex, colSpan, cellMinWidth, cellDesiredWidth);
rowIndex, colSpan, cellMinWidth, cellDesiredWidth);
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
@@ -750,10 +835,10 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo
effectiveColumnWidths[colIndex] = cellDesiredWidth;
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth=%d maxColWidth=%d effColWidth[%d]=%d\n",
cellIndex, minColWidth, maxColWidth,
rowIndex, minColWidth, maxColWidth,
colIndex, effectiveColumnWidths[colIndex]);
if (1<colSpan)
{ // add the cell to our list of spanners
if ((1<colSpan) && (cellFrame->GetColIndex()==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);
if (nsnull==spanList)
spanList = new nsVoidArray();
@@ -863,7 +948,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo
}
if (-1==percentage)
{
percentage = 100/numCols;
percentage = 100/mNumCols;
// base the % on the remaining available width
mTableFrame->SetColumnWidth(colIndex, (percentage*aAvailWidth)/100);
if (gsDebug==PR_TRUE)
@@ -879,7 +964,11 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo
}
}
}
tableWidth += mTableFrame->GetColumnWidth(colIndex);
else
{ // need to maintain this so we know how much we have left over at the end
widthOfFixedTableColumns += mTableFrame->GetColumnWidth(colIndex) + colInset;
}
tableWidth += mTableFrame->GetColumnWidth(colIndex) + colInset;
}
/* --- post-process if necessary --- */
@@ -938,9 +1027,9 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo
// next, if the specified width of the table is greater than the table's computed width, expand the
// table's computed width to match the specified width, giving the extra space to proportionately-sized
// columns if possible.
if ((PR_FALSE==aTableIsAutoWidth) && (aAvailWidth > tableWidth))
if ((PR_FALSE==aTableIsAutoWidth) && (aAvailWidth > (tableWidth-widthOfFixedTableColumns)))
{
DistributeExcessSpace(aAvailWidth, tableWidth, effectiveColumnWidths);
DistributeExcessSpace(aAvailWidth, tableWidth, widthOfFixedTableColumns, effectiveColumnWidths);
}
// today we always allocate effectiveColumnWidths, but tomorrow we might be smarter, so leave the check in
if (nsnull!=effectiveColumnWidths)
@@ -952,24 +1041,27 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo
// take the extra space in the table and distribute it proportionately (based on desired width)
// give extra space to auto-width cells first, or if there are none to all cells
void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aTableFixedWidth,
nscoord aComputedTableWidth,
void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth,
nscoord aTableWidth,
nscoord aWidthOfFixedTableColumns,
nscoord *aColWidths)
{
nscoord excess = 0;
if (PR_TRUE==gsDebug) printf ("DistributeExcessSpace: fixed width %d > computed table width %d\n",
aTableFixedWidth, aComputedTableWidth);
if (PR_TRUE==gsDebug) printf ("DistributeExcessSpace: fixed width %d > computed table width %d, woftc=%d\n",
aAvailWidth, aTableWidth, aWidthOfFixedTableColumns);
// if there are auto-sized columns, give them the extra space
// the trick here is to do the math excluding non-auto width columns
PRInt32 numAutoColumns=0;
PRInt32 *autoColumns=nsnull;
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;
if (gsDebug==PR_TRUE)
printf(" aTableFixedWidth specified as %d, expanding columns by excess = %d\n", aTableFixedWidth, excess);
printf(" aAvailWidth specified as %d, expanding columns by excess = %d\n", aAvailWidth, excess);
// 1. first, get the total width of the auto columns
PRInt32 i;
for (i = 0; i<numAutoColumns; i++)
@@ -979,12 +1071,12 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aTableFixedWidth,
else
totalEffectiveWidthOfAutoColumns += mTableFrame->GetColumnWidth(autoColumns[i]);
}
excess = aTableFixedWidth - aComputedTableWidth;
excess = aAvailWidth - computedTableWidth;
// 2. next, compute the proportion to be added to each column, and add it
for (i = 0; i<numAutoColumns; i++)
{
PRInt32 colIndex = autoColumns[i];
nscoord oldColWidth = aColWidths[colIndex];
nscoord oldColWidth = mTableFrame->GetColumnWidth(colIndex);//aColWidths[colIndex];
float percent;
if (0!=totalEffectiveWidthOfAutoColumns)
percent = ((float)(aColWidths[colIndex]))/((float)totalEffectiveWidthOfAutoColumns);
@@ -1002,25 +1094,25 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aTableFixedWidth,
// (they must be all fixed and percentage-width columns, or we would have gone into the block above)
else
{
excess = aTableFixedWidth - aComputedTableWidth;
nscoord excessPerColumn = excess/mNumCols;
excess = aAvailWidth - (aTableWidth-aWidthOfFixedTableColumns);
if (gsDebug==PR_TRUE)
printf(" aTableFixedWidth specified as %d, expanding columns by excess = %d\n", aTableFixedWidth, excess);
printf(" aAvailWidth specified as %d, expanding columns by excess = %d\n",
aAvailWidth, excess);
for (PRInt32 colIndex = 0; colIndex<mNumCols; colIndex++)
{
nscoord oldColWidth = aColWidths[colIndex];
nscoord oldColWidth=0;// = aColWidths[colIndex];
if (0==oldColWidth)
oldColWidth = mTableFrame->GetColumnWidth(colIndex);
float percent;
if (0!=aComputedTableWidth)
percent = (float)oldColWidth/(float)aComputedTableWidth;
if (0!=aTableWidth)
percent = (float)oldColWidth/(float)aTableWidth;
else
percent = (float)1/(float)mNumCols;
nscoord excessForThisColumn = (nscoord)(excess*percent);
nscoord colWidth = excessForThisColumn+oldColWidth;
if (gsDebug==PR_TRUE)
printf(" distribute excess to all columns: column %d was %d, now set to %d\n",
colIndex, aColWidths[colIndex], colWidth);
printf(" distribute excess to all columns: column %d was %d, now set to %d from % = %f\n",
colIndex, oldColWidth, colWidth, percent);
mTableFrame->SetColumnWidth(colIndex, colWidth);
}
}
@@ -1051,29 +1143,40 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre
// 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
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
nscoord * effectiveMaxColumnWidths = new nscoord[numCols]; // used for Nav4 compatible table fluffing
nsCRT::memset (effectiveMaxColumnWidths, 0, numCols*sizeof(PRInt32));
nscoord * effectiveMinColumnWidths = new nscoord[numCols]; // used for Nav4 compatible table fluffing
nsCRT::memset (effectiveMinColumnWidths, 0, numCols*sizeof(PRInt32));
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
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; colIndex<mNumCols; colIndex++)
{
if (gsDebug==PR_TRUE) printf (" for col %d\n", colIndex);
nscoord minColWidth = 0;
nscoord maxColWidth = 0;
// Get column information
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsVoidArray *cells = colData->GetCells();
PRInt32 numCells = cells->Count();
// Get the columns's style
nsTableColFrame *colFrame = colData->GetColFrame();
nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex);
NS_ASSERTION(nsnull!=colFrame, "bad col frame");
nsIStyleContextPtr colSC;
colFrame->GetStyleContext(aPresContext, colSC.AssignRef());
const nsStylePosition* colPosition = (const nsStylePosition*) colSC->GetStyleData(eStyleStruct_Position);
// Get the columns's style and margins
PRInt32 rowIndex;
PRInt32 firstRowIndex = -1;
nsTableCellFrame * firstCellInColumn;
for (rowIndex=0; rowIndex<numRows; rowIndex++)
{
firstCellInColumn = mTableFrame->GetCellAt(rowIndex, colIndex);
if (nsnull!=firstCellInColumn)
break;
}
nsMargin colMargin;
nscoord colInset = 0;
if (nsnull!=firstCellInColumn)
{
firstCellInColumn->GetMargin(colMargin);
colInset = colMargin.left + colMargin.right;
}
const nsStylePosition* colPosition;
colFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPosition);
if (PR_FALSE==IsFixedWidth(colPosition))
{
@@ -1100,33 +1203,30 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
if (nsnull == data) {
// For cells that span rows there's only cell layout data for the first row
for (rowIndex = 0; rowIndex<numRows; rowIndex++)
{
nsTableCellFrame * cellFrame = mTableFrame->GetCellAt(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;
}
PRInt32 colSpan = data->GetCellFrame()->GetColSpan();
nsSize * cellMinSize = data->GetMaxElementSize();
NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize");
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
PRInt32 colSpan = cellFrame->GetColSpan();
nsSize cellMinSize = cellFrame->GetPass1MaxElementSize();
nsSize cellDesiredSize = cellFrame->GetPass1DesiredSize();
nsMargin margin;
nsresult result = data->GetMargin(margin);
nscoord marginWidth = margin.left + margin.right;
PRInt32 cellMinWidth = cellMinSize->width/colSpan + marginWidth;
PRInt32 cellMinWidth = cellMinSize.width/colSpan;
// first get the desired size info from reflow pass 1
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan + marginWidth;
PRInt32 cellDesiredWidth = cellDesiredSize.width/colSpan;
// then get the desired size info factoring in the cell style attributes
nscoord specifiedCellWidth=-1;
nsIStyleContextPtr cellSC;
data->GetCellFrame()->GetStyleContext(aPresContext, cellSC.AssignRef());
const nsStylePosition* cellPosition = (const nsStylePosition*)
cellSC->GetStyleData(eStyleStruct_Position);
const nsStylePosition* cellPosition;
cellFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)cellPosition);
switch (cellPosition->mWidth.GetUnit()) {
case eStyleUnit_Coord:
specifiedCellWidth = cellPosition->mWidth.GetCoordValue();
@@ -1164,7 +1264,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre
if (PR_TRUE==gsDebug)
printf("factoring in cell %d with colSpan=%d\n factoring in min=%d and desired=%d\n",
cellIndex, colSpan, cellMinWidth, cellDesiredWidth);
rowIndex, colSpan, cellMinWidth, cellDesiredWidth);
// remember the widest min cell width
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
@@ -1179,7 +1279,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre
effectiveMaxColumnWidths[colIndex] = cellDesiredWidth;
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth=%d maxColWidth=%d effColWidth[%d]=%d,%d\n",
cellIndex, minColWidth, maxColWidth,
rowIndex, minColWidth, maxColWidth,
colIndex, effectiveMaxColumnWidths[colIndex], effectiveMaxColumnWidths[colIndex]);
if (1<colSpan)
{
@@ -1236,7 +1336,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre
printf (" 4 (0): col %d set to min width = %d because style set proportionalWidth=0\n",
colIndex, mTableFrame->GetColumnWidth(colIndex));
}
else if (1==numCols)
else if (1==mNumCols)
{ // there is only one column, and we know that it's desired width doesn't fit
// so the column should be as wide as the available space allows it to be
if (gsDebug==PR_TRUE) printf (" 4 one-column: col %d set to width = %d\n", colIndex, aAvailWidth);
@@ -1300,7 +1400,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre
}
if (-1==percentage)
{
percentage = 100/numCols;
percentage = 100/mNumCols;
// base the % on the remaining available width
mTableFrame->SetColumnWidth(colIndex, (percentage*aAvailWidth)/100);
if (gsDebug==PR_TRUE)
@@ -1417,16 +1517,52 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableFixedWidt
else
percent = ((float)1)/((float)numAutoColumns);
nscoord colWidth = (nscoord)(availWidth*percent);
if (colWidth<aMinColWidths[colIndex])
{
availWidth -= (aMinColWidths[colIndex]-colWidth);
colWidth=aMinColWidths[colIndex];
}
if (gsDebug==PR_TRUE)
printf(" distribute width to auto columns: column %d was %d, now set to %d\n",
colIndex, aMaxColWidths[colIndex], colWidth);
mTableFrame->SetColumnWidth(colIndex, colWidth);
}
EnsureCellMinWidths(aMinColWidths);
}
}
void BasicTableLayoutStrategy::EnsureCellMinWidths(nscoord *aMinColWidths)
{
PRBool atLeastOne = PR_TRUE;
while (PR_TRUE==atLeastOne)
{
atLeastOne=PR_FALSE;
PRInt32 colIndex;
nscoord addedWidth = 0;
// first, bump up cells that are below their min to their min width
for (colIndex=0; colIndex<mNumCols; colIndex++)
{
nscoord colWidth = mTableFrame->GetColumnWidth(colIndex);
if (colWidth<aMinColWidths[colIndex])
{
addedWidth += (aMinColWidths[colIndex]-colWidth);
mTableFrame->SetColumnWidth(colIndex, aMinColWidths[colIndex]);
atLeastOne=PR_TRUE;
}
}
// second, remove the added space from cells that can afford to slim down
//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...
for (colIndex=0; colIndex<mNumCols; colIndex++)
{
nscoord colWidth = mTableFrame->GetColumnWidth(colIndex);
if (colWidth>aMinColWidths[colIndex])
{
mTableFrame->SetColumnWidth(colIndex, colWidth-1);
addedWidth--;
}
}
}
if (0<addedWidth)
{ // all our cells are at their min width, so no use doing anything else
break;
}
}
}