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 d75cb80e9a
commit 3e596fc26a
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;
}
}
}

View File

@ -23,6 +23,7 @@
#include "nsITableLayoutStrategy.h"
#include "nsCoord.h"
class nsVoidArray;
class nsTableFrame;
struct nsStylePosition;
@ -164,18 +165,31 @@ public:
nscoord aMinTableWidth,
nscoord aMaxTableWidth);
/** 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);
/** starting with a partially balanced table, compute the amount
* of space to pad each column by to completely balance the table.
* set the column widths in mTableFrame based on these computations.
*
* @param aTableFixedWidth the specified width of the table. If there is none,
* this param is 0
* @param aComputedTableWidth the width of the table before this final step.
* @param aAvailWidth the space still to be allocated within the table
* @param aTableWidth the sum of all columns widths
* @param aWidthOfFixedTableColumns the sum of the widths of fixed-width columns
* @param aColWidths the effective column widths (ignoring col span cells)
*
* @return void
*/
virtual void DistributeExcessSpace(nscoord aTableFixedWidth,
nscoord aComputedTableWidth,
virtual void DistributeExcessSpace(nscoord aAvailWidth,
nscoord aTableWidth,
nscoord aWidthOfFixedTableColumns,
nscoord *aColWidths);
/** starting with a partially balanced table, compute the amount
@ -193,6 +207,11 @@ public:
nscoord *aMinColWidths,
nscoord *aMaxColWidths);
/** 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);
/** return true if the style indicates that the width is a specific width
* for the purposes of column width determination.
* return false if the width changes based on content, parent size, etc.

View File

@ -24,18 +24,17 @@ LIBRARY_NAME = raptorhtmltable_s
# Note the sophisticated alphabetical ordering :-|
CPPSRCS = \
BasicTableLayoutStrategy.cpp \
nsCellLayoutData.cpp \
nsCellMap.cpp \
nsColLayoutData.cpp \
nsTableCaption.cpp \
nsTableCell.cpp \
nsTableCellFrame.cpp \
nsTableCellFrame.cpp \
nsTableCol.cpp \
nsTableColFrame.cpp \
nsTableColGroup.cpp \
nsTableColGroupFrame.cpp \
nsTableContent.cpp \
nsTableFrame.cpp \
nsTableOuterFrame.cpp \
nsTableOuterFrame.cpp \
nsTablePart.cpp \
nsTableRow.cpp \
nsTableRowFrame.cpp \

View File

@ -23,18 +23,21 @@ REQUIRES=xpcom raptor js
DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN
CPPSRCS=nsCellLayoutData.cpp nsCellMap.cpp nsColLayoutData.cpp \
nsTableCaption.cpp nsTableCell.cpp \
nsTableCellFrame.cpp nsTableCol.cpp nsTableColGroup.cpp \
nsTableColGroupFrame.cpp nsTableContent.cpp nsTableFrame.cpp \
nsTableOuterFrame.cpp nsTablePart.cpp nsTableRow.cpp \
nsTableRowFrame.cpp nsTableRowGroup.cpp nsTableRowGroupFrame.cpp \
CPPSRCS= nsCellMap.cpp \
nsTableCaption.cpp \
nsTableCell.cpp nsTableCol.cpp \
nsTableCellFrame.cpp nsTableColFrame.cpp \
nsTableColGroup.cpp nsTableColGroupFrame.cpp \
nsTableContent.cpp nsTableFrame.cpp \
nsTableOuterFrame.cpp nsTablePart.cpp \
nsTableRow.cpp nsTableRowFrame.cpp \
nsTableRowGroup.cpp nsTableRowGroupFrame.cpp \
BasicTableLayoutStrategy.cpp
CPP_OBJS=.\$(OBJDIR)\nsCellLayoutData.obj .\$(OBJDIR)\nsCellMap.obj \
.\$(OBJDIR)\nsColLayoutData.obj .\$(OBJDIR)\nsTableCaption.obj \
.\$(OBJDIR)\nsTableCell.obj \
.\$(OBJDIR)\nsTableCellFrame.obj .\$(OBJDIR)\nsTableCol.obj \
CPP_OBJS= .\$(OBJDIR)\nsCellMap.obj \
.\$(OBJDIR)\nsTableCaption.obj \
.\$(OBJDIR)\nsTableCell.obj .\$(OBJDIR)\nsTableCol.obj \
.\$(OBJDIR)\nsTableCellFrame.obj .\$(OBJDIR)\nsTableColFrame.obj \
.\$(OBJDIR)\nsTableColGroup.obj .\$(OBJDIR)\nsTableColGroupFrame.obj \
.\$(OBJDIR)\nsTableContent.obj .\$(OBJDIR)\nsTableFrame.obj \
.\$(OBJDIR)\nsTableOuterFrame.obj .\$(OBJDIR)\nsTablePart.obj \

View File

@ -1,573 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsCellLayoutData.h"
#include "nsTableCellFrame.h" // should be removed, make only generic nsIFrame calls
#include "nsCRT.h"
#include "nsSize.h"
#include "nsVoidArray.h"
#include "nsIFrame.h"
#include "nsIStyleContext.h"
#include "nsIPtr.h"
#include <stdio.h>/* XXX */ // for printf
nsCellLayoutData::nsCellLayoutData(nsTableCellFrame *aCellFrame,
nsReflowMetrics * aDesiredSize, nsSize * aMaxElementSize)
: mDesiredSize(nsnull)
{
// IMPORTANT: Always intialize instance variables to null
mColLayoutData = nsnull;
mCellFrame = nsnull;
mMargin.top = mMargin.bottom = mMargin.left = mMargin.right = 0;
for (PRInt32 i = 0; i < 4; i++)
mBorderFrame[i] = nsnull;
// IMPORTANT: call setters: this
// guarentees addrefs/releases are called if needed - gpk
SetCellFrame(aCellFrame);
SetDesiredSize(aDesiredSize);
SetMaxElementSize(aMaxElementSize);
mCalculated = NS_ERROR_NOT_INITIALIZED;
}
// don't delete mCellFrame, I didn't allocate it
nsCellLayoutData::~nsCellLayoutData()
{
mCellFrame = nsnull;
mColLayoutData = nsnull;
}
/**
* Get the style context for this object (determined, by
* asking for the frame
*
**/
nsIStyleContext* nsCellLayoutData::GetStyleContext()
{
if (mCellFrame != nsnull) {
nsIStyleContext* styleContext;
mCellFrame->GetStyleContext(nsnull, styleContext);
return styleContext;
}
return nsnull;
}
/**
* Given a list of nsCellLayoutData and a index, get the style context for
* that element in the list
*
**/
nsIFrame* nsCellLayoutData::GetFrameAt(nsVoidArray* aList, PRInt32 aIndex)
{
nsIFrame* result = nsnull;
if (aList != nsnull)
{
nsCellLayoutData* data = (nsCellLayoutData*)aList->ElementAt(aIndex);
if (data != nsnull)
result = data->GetCellFrame();
}
return result;
}
/**
* Given a frame and an edge, find the margin
*
**/
nscoord nsCellLayoutData::GetMargin(nsIFrame* aFrame, PRUint8 aEdge) const
{
nscoord result = 0;
if (aFrame)
{
const nsStyleSpacing* spacing;
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
nsMargin margin;
spacing->CalcMarginFor(aFrame, margin);
switch (aEdge)
{
case NS_SIDE_TOP:
result = margin.top;
break;
case NS_SIDE_RIGHT:
result = margin.right;
break;
case NS_SIDE_BOTTOM:
result = margin.bottom;
break;
case NS_SIDE_LEFT:
result = margin.left;
break;
}
}
return result;
}
/**
* Given a style context and an edge, find the border width
*
**/
nscoord nsCellLayoutData::GetBorderWidth(nsIFrame* aFrame, PRUint8 aEdge) const
{
nscoord result = 0;
if (aFrame)
{
const nsStyleSpacing* spacing;
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
nsMargin border;
spacing->CalcBorderFor(aFrame, border);
switch (aEdge)
{
case NS_SIDE_TOP:
result = border.top;
break;
case NS_SIDE_RIGHT:
result = border.right;
break;
case NS_SIDE_BOTTOM:
result = border.bottom;
break;
case NS_SIDE_LEFT:
result = border.left;
break;
}
}
return result;
}
/**
* Given a style context and an edge, find the padding
*
**/
nscoord nsCellLayoutData::GetPadding(nsIFrame* aFrame, PRUint8 aEdge) const
{
nscoord result = 0;
if (aFrame)
{
const nsStyleSpacing* spacing;
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
nsMargin padding;
spacing->CalcPaddingFor(aFrame, padding);
switch (aEdge)
{
case NS_SIDE_TOP:
result = padding.top;
break;
case NS_SIDE_RIGHT:
result = padding.right;
break;
case NS_SIDE_BOTTOM:
result = padding.bottom;
break;
case NS_SIDE_LEFT:
result = padding.left;
break;
}
}
return result;
}
/**
* Given an Edge, find the opposing edge (top<-->bottom, left<-->right)
*
**/
PRUint8 nsCellLayoutData::GetOpposingEdge(PRUint8 aEdge)
{
PRUint8 result;
switch (aEdge)
{
case NS_SIDE_LEFT:
result = NS_SIDE_RIGHT;
break;
case NS_SIDE_RIGHT:
result = NS_SIDE_LEFT;
break;
case NS_SIDE_TOP:
result = NS_SIDE_BOTTOM;
break;
case NS_SIDE_BOTTOM:
result = NS_SIDE_TOP;
break;
default:
result = NS_SIDE_TOP;
}
return result;
}
/*
*
* Determine border style for two cells.
*
1.If the adjacent elements are of the same type, the wider of the two borders is used.
"Wider" takes into account the border-style of 'none', so a "1px solid" border
will take precedence over a "20px none" border.
2.If there are two or more with the same width, but different style,
then the one with a style near the start of the following list will be drawn:
'blank', 'double', 'solid', 'dashed', 'dotted', 'ridge', 'groove', 'none'
3.If the borders are of the same width, the border on the element occurring first is used.
First is defined as aStyle for this method.
NOTE: This assumes left-to-right, top-to-bottom bias. -- gpk
*
*/
nsIFrame* nsCellLayoutData::CompareCellBorders(nsIFrame* aFrame1,
PRUint8 aEdge1,
nsIFrame* aFrame2,
PRUint8 aEdge2)
{
PRInt32 width1 = GetBorderWidth(aFrame1,aEdge1);
PRInt32 width2 = GetBorderWidth(aFrame2,aEdge2);
nsIFrame* result = nsnull;
if (width1 > width2)
result = aFrame1;
else if (width1 < width2)
result = aFrame2;
else // width1 == width2
{
const nsStyleSpacing* border1;
const nsStyleSpacing* border2;
aFrame1->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)border1);
aFrame2->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)border2);
if (border1->mBorderStyle[aEdge1] >= border2->mBorderStyle[aEdge2])
result = aFrame1;
else
result = aFrame2;
}
return result;
}
/**
* Given a List of cell layout data, compare the edges to see which has the
* border with the highest precidence.
*
**/
nsIFrame* nsCellLayoutData::FindHighestPrecedentBorder(nsVoidArray* aList,
PRUint8 aEdge)
{
nsIFrame* result = nsnull;
PRInt32 index = 0;
PRInt32 count = 0;
NS_ASSERTION(aList,"a List must be valid");
count = aList->Count();
if (count)
{
nsIFrame* frame1;
nsIFrame* frame2;
frame1 = GetFrameAt(aList,index++);
while (index < count)
{
frame2 = GetFrameAt(aList,index++);
if (GetMargin(frame2,aEdge) == 0) {
frame1 = CompareCellBorders(frame1, aEdge, frame2, aEdge);
}
}
if ((nsnull != frame1) && (GetMargin(frame1, aEdge) != 0))
result = frame1;
}
return result;
}
nsIFrame* nsCellLayoutData::FindInnerBorder(nsVoidArray* aList, PRUint8 aEdge)
{
nsIFrame* result = nsnull;
PRUint8 opposite = GetOpposingEdge(aEdge);
if (GetMargin(mCellFrame, aEdge) == 0)
{
nsIFrame* altFrame = FindHighestPrecedentBorder(aList,opposite);
if (nsnull != altFrame)
result = CompareCellBorders(mCellFrame, aEdge, altFrame, opposite);
else
result = mCellFrame;
}
return result;
}
/*
*
* FindRelevantBorder recursively searches up the frame hierarchy for the border
* style that is applicable to the cell. If at any point the frame has a margin
* or the parent frame has padding, then the outer frame for this object takes
* presendence over the inner frame.
1.Borders on 'table' elements take precedence over borders on any other table elements.
2.Borders on 'row-groups' take precedence over borders on 'rows',
and likewise borders on 'column-groups' take precedence over borders on 'columns'.
3.Borders on any other type of table element take precedence over 'table-cell' elements.
*
* NOTE: This method assumes that the table cell potentially shares a border.
* It should not be called for internal cells
*
* NOTE: COLUMNS AND COLGROUPS NEED TO BE FIGURED INTO THE ALGORITHM -- GPK!!!
*
*
*/
nsIFrame* nsCellLayoutData::FindOuterBorder( nsTableFrame* aTableFrame,
PRUint8 aEdge)
{
nsIFrame* frame = mCellFrame; // By default, return our frame
PRBool done = PR_FALSE;
// The table frame is the outer most frame we test against
while (done == PR_FALSE)
{
done = PR_TRUE; // where done unless the frame's margin is zero
// and the parent's padding is zero
nscoord margin = GetMargin(frame,aEdge);
// if the margin for this style is zero then check to see if the paddding
// for the parent frame is also zero
if (margin == 0)
{
nsIFrame* parentFrame;
frame->GetGeometricParent(parentFrame);
// if the padding for the parent style is zero just
// recursively call this routine
PRInt32 padding = GetPadding(parentFrame,aEdge);
if ((nsnull != parentFrame) && (padding == 0))
{
frame = parentFrame;
// If this frame represents the table frame then
// the table style is used
done = PRBool(frame != (nsIFrame*)aTableFrame);
continue;
}
}
}
return frame;
}
/*
Border Resolution
1.Borders on 'table' elements take precedence over borders on any other table elements.
2.Borders on 'row-groups' take precedence over borders on 'rows', and likewise borders on 'column-groups' take
precedence over borders on 'columns'.
3.Borders on any other type of table element take precedence over 'table-cell' elements.
4.If the adjacent elements are of the same type, the wider of the two borders is used. "Wider" takes into account
the border-style of 'none', so a "1px solid" border will take precedence over a "20px none" border.
5.If the borders are of the same width, the border on the element occurring first is used.
How to compare
1.Those of the one or two cells that have an edge here.
Less than two can occur at the edge of the table, but also
at the edges of "holes" (unoccupied grid cells).
2.Those of the columns that have an edge here.
3.Those of the column groups that have an edge here.
4.Those of the rows that have an edge here.
5.Those of the row groups that have an edge here.
6.Those of the table, if this is the edge of the table.
*
* @param aIsFirst -- TRUE if this is the first cell in the row
* @param aIsLast -- TRUE if this is the last cell in the row
* @param aIsTop -- TRUE if this is the top cell in the column
* @param aIsBottom -- TRUE if this is the last cell in the column
*/
nsIFrame* nsCellLayoutData::FindBorderFrame(nsTableFrame* aTableFrame,
nsVoidArray* aList,
PRUint8 aEdge)
{
nsIFrame* frame = nsnull;
if (aList && aList->Count() == 0)
frame = FindOuterBorder(aTableFrame, aEdge);
else
frame = FindInnerBorder(aList, aEdge);
if (! frame)
frame = mCellFrame;
return frame;
}
/**
* Given a List of cell layout data, compare the edges to see which has the
* border with the highest precidence.
*
**/
nscoord nsCellLayoutData::FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge)
{
nscoord result = 0;
PRInt32 index = 0;
PRInt32 count = 0;
NS_ASSERTION(aList,"a List must be valid");
count = aList->Count();
if (count)
{
nsIFrame* frame;
nscoord value = 0;
while (index < count)
{
frame = GetFrameAt(aList,index++);
value = GetMargin(frame, aEdge);
if (value > result)
result = value;
}
}
return result;
}
void nsCellLayoutData::CalculateMargins(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4])
{
// By default the margin is just the margin found in the
// table cells style
const nsStyleSpacing* spacing;
mCellFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
spacing->CalcMarginFor(mCellFrame, mMargin);
// Left and Top Margins are collapsed with their neightbors
// Right and Bottom Margins are simple left as they are
nscoord value;
// The left and top sides margins are the difference between
// their inherint value and the value of the margin of the
// object to the left or right of them.
value = FindLargestMargin(aBoundaryCells[NS_SIDE_LEFT],NS_SIDE_RIGHT);
if (value > mMargin.left)
mMargin.left = 0;
else
mMargin.left -= value;
value = FindLargestMargin(aBoundaryCells[NS_SIDE_TOP],NS_SIDE_BOTTOM);
if (value > mMargin.top)
mMargin.top = 0;
else
mMargin.top -= value;
}
void nsCellLayoutData::RecalcLayoutData(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4])
{
CalculateBorders(aTableFrame, aBoundaryCells);
CalculateMargins(aTableFrame, aBoundaryCells);
mCalculated = NS_OK;
}
void nsCellLayoutData::List(FILE* out, PRInt32 aIndent) const
{
PRInt32 indent;
nsIContent* cell;
mCellFrame->GetContent(cell);
if (cell != nsnull)
{
/*
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
fprintf(out,"RowSpan = %d ColSpan = %d \n",cell->GetRowSpan(),cell->GetColSpan());
*/
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
fprintf(out,"Margin -- Top: %d Left: %d Bottom: %d Right: %d \n",
NS_TWIPS_TO_POINTS_INT(mMargin.top),
NS_TWIPS_TO_POINTS_INT(mMargin.left),
NS_TWIPS_TO_POINTS_INT(mMargin.bottom),
NS_TWIPS_TO_POINTS_INT(mMargin.right));
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
nscoord top,left,bottom,right;
top = (mBorderFrame[NS_SIDE_TOP] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_TOP], NS_SIDE_TOP) : 0);
left = (mBorderFrame[NS_SIDE_LEFT] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_LEFT], NS_SIDE_LEFT) : 0);
bottom = (mBorderFrame[NS_SIDE_BOTTOM] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_BOTTOM], NS_SIDE_BOTTOM) : 0);
right = (mBorderFrame[NS_SIDE_RIGHT] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_RIGHT], NS_SIDE_RIGHT) : 0);
fprintf(out,"Border -- Top: %d Left: %d Bottom: %d Right: %d \n",
NS_TWIPS_TO_POINTS_INT(top),
NS_TWIPS_TO_POINTS_INT(left),
NS_TWIPS_TO_POINTS_INT(bottom),
NS_TWIPS_TO_POINTS_INT(right));
cell->List(out,aIndent);
NS_RELEASE(cell);
}
}

View File

@ -1,197 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsCellLayoutData_h__
#define nsCellLayoutData_h__
#include "nscore.h"
#include "nsSize.h"
#include "nsIFrame.h"
class nsTableCellFrame;
class nsColLayoutData;
class nsTableFrame;
class nsIStyleContext;
class nsVoidArray;
struct nsStyleSpacing;
/** Simple data class that represents in-process reflow information about a cell.
* Each cell is represented by a nsTableCellFrame together with the results
* of the "first pass" layout results (where "first pass" means the cell was told
* to lay itself out with unrestricted height and width.)
* There is one nsCellLayoutData object per nsTableFrame for each cell.
*
* TODO: All methods will be inline.
*/
class nsCellLayoutData
{
public:
/** public constructor. Does not allocate any of its own data.
* @param aCellFrame the frame representing the cell
* @param aDesiredSize the max size of the cell if given infinite height and width
* @param aMaxElementSize the min size of the largest indivisible element within the cell
*/
nsCellLayoutData(nsTableCellFrame *aCellFrame,
nsReflowMetrics * aDesiredSize, nsSize * aMaxElementSize);
/** destructor, not responsible for destroying any of the stored data */
virtual ~nsCellLayoutData();
/** return the frame mapping the cell */
nsTableCellFrame * GetCellFrame();
/** set the frame mapping the cell */
void SetCellFrame(nsTableCellFrame * aCellFrame);
/** return the max size of the cell if given infinite height and width */
nsReflowMetrics * GetDesiredSize();
/** set the max size of the cell if given infinite height and width.
* called after pass 1 of table reflow is complete.
*/
void SetDesiredSize(nsReflowMetrics * aDesiredSize);
/** get the min size of the largest indivisible element within the cell */
nsSize * GetMaxElementSize();
/** set the min size of the largest indivisible element within the cell.
* called after pass 1 of table reflow is complete.
*/
void SetMaxElementSize(nsSize * aMaxElementSize);
/** debug method outputs data about this cell to FILE *out */
void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
/** returns the style context associated with this cell */
nsIStyleContext* GetStyleContext();
private:
// All these methods are support methods for RecalcLayoutData
nsIFrame* GetFrameAt(nsVoidArray* aList, PRInt32 aIndex);
nscoord GetMargin(nsIFrame* aFrame, PRUint8 aEdge) const;
nscoord GetBorderWidth(nsIFrame* aFrame, PRUint8 aEdge) const;
nscoord GetPadding(nsIFrame* aFrame, PRUint8 aEdge) const;
PRUint8 GetOpposingEdge(PRUint8 aEdge);
nsIFrame* CompareCellBorders(nsIFrame* aFrame1,
PRUint8 aEdge1,
nsIFrame* aFrame2,
PRUint8 aEdge2);
nsIFrame* FindHighestPrecedentBorder(nsVoidArray* aList,
PRUint8 aEdge);
nsIFrame* FindInnerBorder( nsVoidArray* aList,
PRUint8 aEdge);
nsIFrame* FindOuterBorder( nsTableFrame* aTableFrame,
PRUint8 aEdge);
nsIFrame* FindBorderFrame(nsTableFrame* aTableFrame,
nsVoidArray* aCellList,
PRUint8 aEdge);
void CalculateBorders(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4]);
nscoord FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge);
void CalculateMargins(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4]);
public:
void RecalcLayoutData(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4]);
NS_IMETHOD GetMargin(nsMargin& aMargin);
private:
#if 0 // these come on line when we do character-based cell content alignment
/** the kinds of width information stored */
enum {WIDTH_NORMAL=0, WIDTH_LEFT_ALIGNED=1, WIDTH_RIGHT_ALIGNED=2};
/** the width information for a cell */
PRInt32 mWidth[3];
#endif
nsColLayoutData *mColLayoutData;
nsTableCellFrame *mCellFrame;
nsReflowMetrics mDesiredSize;
nsSize mMaxElementSize;
nsresult mCalculated;
nsMargin mMargin;
nsIFrame* mBorderFrame[4]; // the frame whose border is used
};
inline nsTableCellFrame * nsCellLayoutData::GetCellFrame()
{ return mCellFrame; }
inline void nsCellLayoutData::SetCellFrame(nsTableCellFrame * aCellFrame)
{ mCellFrame = aCellFrame; }
inline nsReflowMetrics * nsCellLayoutData::GetDesiredSize()
{ return &mDesiredSize; }
inline void nsCellLayoutData::SetDesiredSize(nsReflowMetrics * aDesiredSize)
{
if (nsnull!=aDesiredSize)
mDesiredSize = *aDesiredSize;
}
inline nsSize * nsCellLayoutData::GetMaxElementSize()
{ return &mMaxElementSize; }
inline void nsCellLayoutData::SetMaxElementSize(nsSize * aMaxElementSize)
{
if (nsnull!=aMaxElementSize)
mMaxElementSize = *aMaxElementSize;
}
inline void nsCellLayoutData::CalculateBorders(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4])
{
for (PRInt32 edge = 0; edge < 4; edge++)
mBorderFrame[edge] = FindBorderFrame(aTableFrame, aBoundaryCells[edge], edge);
}
inline NS_METHOD nsCellLayoutData::GetMargin(nsMargin& aMargin)
{
if (mCalculated == NS_OK)
{
aMargin = mMargin;
return NS_OK;
}
return NS_ERROR_NOT_INITIALIZED;
}
#endif

View File

@ -15,7 +15,9 @@
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsCRT.h"
#include "nsVoidArray.h"
#include "nsCellMap.h"
#include "nsTableFrame.h"
@ -25,38 +27,50 @@ static PRBool gsDebug1 = PR_FALSE;
static const PRBool gsDebug1 = PR_FALSE;
#endif
static PRInt32 gBytesPerPointer = sizeof(PRInt32);
static const PRInt32 gBytesPerPointer = sizeof(PRInt32);
nsCellMap::nsCellMap(int aRows, int aColumns)
: mRowCount(aRows),
mColCount(aColumns)
{
mCells = nsnull;
mColFrames = nsnull;
Reset(aRows, aColumns);
}
nsCellMap::~nsCellMap()
{
for (int i=0;i<mRowCount;i++)
if (nsnull!=mCells)
{
for (int j=0;j<mColCount;j++)
for (int i=0;i<mRowCount;i++)
{
int index = (i*mColCount)+j;
CellData* data = (CellData*)mCells[index];
if (data != nsnull)
for (int j=0;j<mColCount;j++)
{
delete data;
mCells[index] = 0;
}
}
int index = (i*mColCount)+j;
CellData* data = (CellData*)mCells[index];
if (data != nsnull)
{
delete data;
mCells[index] = 0;
}
}
}
delete [] mCells;
}
delete [] mCells;
if (nsnull!= mColFrames)
delete mColFrames;
mCells = nsnull;
mColFrames = nsnull;
};
void nsCellMap::Reset(int aRows, int aColumns)
{
if (nsnull==mColFrames)
{
mColFrames = new nsVoidArray();
}
// needs to be more efficient, to reuse space if possible
if (nsnull!=mCells)
{
@ -67,6 +81,7 @@ void nsCellMap::Reset(int aRows, int aColumns)
mColCount = aColumns;
mCells = new PRInt32 [mRowCount*mColCount*gBytesPerPointer];
nsCRT::memset (mCells, 0, (mRowCount*mColCount)*gBytesPerPointer);
}
void nsCellMap::GrowTo(int aColCount)
@ -110,4 +125,9 @@ void nsCellMap::SetCellAt(CellData *aCell, int aRow, int aColumn)
mCells[index] = (PRInt32)aCell;
}
nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex)
{
return (nsTableColFrame *)(mColFrames->ElementAt(aColIndex));
}

View File

@ -19,8 +19,11 @@
#define nsCellMap_h__
#include "nscore.h"
#include "CellData.h"
class CellData;
class nsVoidArray;
class nsTableColFrame;
class nsTableCellFrame;
/** nsCellMap is a support class for nsTablePart.
* It maintains an Rows x Columns grid onto which the cells of the table are mapped.
@ -40,55 +43,94 @@ protected:
/** storage for CellData pointers */
PRInt32 *mCells; ///XXX CellData *?
/** a cache of the column frames, by col index */
nsVoidArray * mColFrames;
/** the number of rows */
int mRowCount; // in java, we could just do fCellMap.length;
PRInt32 mRowCount; // in java, we could just do fCellMap.length;
/** the number of columns (the max of all row lengths) */
int mColCount; // in java, we could just do fCellMap[i].length
PRInt32 mColCount;
public:
nsCellMap(int aRows, int aColumns);
nsCellMap(PRInt32 aRows, PRInt32 aColumns);
// NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
~nsCellMap();
/** initialize the CellMap to (aRows x aColumns) */
void Reset(int aRows, int aColumns);
void Reset(PRInt32 aRows, PRInt32 aColumns);
/** return the CellData for the cell at (aRow,aColumn) */
CellData * GetCellAt(int aRow, int aColumn) const;
/** return the CellData for the cell at (aRowIndex,aColIndex) */
CellData * GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const;
/** return the nsTableCellFrame for the cell at (aRowIndex, aColIndex) */
nsTableCellFrame * GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex) const;
/** assign aCellData to the cell at (aRow,aColumn) */
void SetCellAt(CellData *aCellData, int aRow, int aColumn);
void SetCellAt(CellData *aCellData, PRInt32 aRow, PRInt32 aColumn);
/** expand the CellMap to have aColCount columns. The number of rows remains the same */
void GrowTo(int aColCount);
void GrowTo(PRInt32 aColCount);
/** return the total number of columns in the table represented by this CellMap */
int GetColCount() const;
PRInt32 GetColCount() const;
/** return the total number of rows in the table represented by this CellMap */
int GetRowCount() const;
PRInt32 GetRowCount() const;
/** for debugging, print out this CellMap */
nsTableColFrame * GetColumnFrame(PRInt32 aColIndex);
void AppendColumnFrame(nsTableColFrame *aColFrame);
PRBool RowImpactedBySpanningCell(PRInt32 aRowIndex);
PRBool ColumnImpactedBySpanningCell(PRInt32 aColIndex);
/** for debugging */
void DumpCellMap() const;
};
inline CellData * nsCellMap::GetCellAt(int aRow, int aColumn) const
/* ----- inline methods ----- */
inline CellData * nsCellMap::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const
{
int index = (aRow*mColCount)+aColumn;
NS_PRECONDITION(0<=aRowIndex && aRowIndex < mRowCount, "bad aRowIndex arg");
NS_PRECONDITION(0<=aColIndex && aColIndex < mColCount, "bad aColIndex arg");
PRInt32 index = (aRowIndex*mColCount)+aColIndex;
return (CellData *)mCells[index];
}
inline int nsCellMap::GetColCount() const
inline nsTableCellFrame * nsCellMap::GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex) const
{
NS_PRECONDITION(0<=aRowIndex && aRowIndex < mRowCount, "bad aRowIndex arg");
NS_PRECONDITION(0<=aColIndex && aColIndex < mColCount, "bad aColIndex arg");
nsTableCellFrame *result = nsnull;
CellData * cellData = GetCellAt(aRowIndex, aColIndex);
if (nsnull!=cellData)
result = cellData->mCell;
return result;
}
inline PRInt32 nsCellMap::GetColCount() const
{
return mColCount;
}
inline int nsCellMap::GetRowCount() const
inline PRInt32 nsCellMap::GetRowCount() const
{
return mRowCount;
}
inline void nsCellMap::AppendColumnFrame(nsTableColFrame *aColFrame)
{
mColFrames->AppendElement(aColFrame);
// sanity check
NS_ASSERTION(mColFrames->Count()<=mColCount, "too many columns appended to CellMap");
}
#endif

View File

@ -1,109 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsColLayoutData.h"
#include "nsVoidArray.h"
#include "nsCellLayoutData.h"
#include "nsTableCellFrame.h"
nsColLayoutData::nsColLayoutData(nsTableColFrame* aColFrame, PRInt32 aNumRows)
{
mColFrame = aColFrame;
mCells = new nsVoidArray(aNumRows);
}
nsColLayoutData::~nsColLayoutData()
{
if (nsnull!=mCells)
{
PRInt32 count = mCells->Count();
for (PRInt32 i = 0; i < count; i++)
{
nsCellLayoutData *data = (nsCellLayoutData *)(mCells->ElementAt(i));
delete data;
}
delete mCells;
}
mCells = 0;
}
PRInt32 nsColLayoutData::IndexOf(nsIContent* aCell) const
{
PRInt32 count = this->Count();
PRInt32 result = -1;
if (aCell != nsnull)
{
for (PRInt32 index = 0; index < count; index++)
{
nsCellLayoutData* cellData = ElementAt(index);
if (cellData != nsnull)
{
nsTableCellFrame* frame = cellData->GetCellFrame();
if (frame != nsnull)
{
nsIContent* cell;
frame->GetContent(cell);
if (cell == aCell)
{
result = index;
NS_RELEASE(cell);
break;
}
NS_IF_RELEASE(cell);
}
}
}
}
return result;
}
nsCellLayoutData* nsColLayoutData::GetNext(nsCellLayoutData* aCellLayoutData) const
{
PRInt32 index = IndexOf(aCellLayoutData);
if (index != -1)
return ElementAt(index+1);
return (nsCellLayoutData*)nsnull;
}
nsCellLayoutData* nsColLayoutData::GetPrevious(nsCellLayoutData* aCellLayoutData) const
{
PRInt32 index = IndexOf(aCellLayoutData);
if (index != -1)
return ElementAt(index-1);
return (nsCellLayoutData*)nsnull;
}
void nsColLayoutData::List(FILE* out, PRInt32 aIndent) const
{
if (nsnull!=mCells)
{
PRInt32 count = mCells->Count();
for (PRInt32 i = 0; i < count; i++)
{
for (PRInt32 indent = aIndent; --indent >= 0; ) fputs(" ", out);
fprintf(out,"Cell Data [%d] \n",i);
nsCellLayoutData *data = (nsCellLayoutData *)(mCells->ElementAt(i));
data->List(out,aIndent+1);
}
}
}

View File

@ -1,99 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsColLayoutData_h__
#define nsColLayoutData_h__
#include "nscore.h"
#include "nsSize.h"
#include "nsIFrame.h"
#include "nsVoidArray.h"
class nsCellLayoutData;
class nsTableFrame;
class nsTableColFrame;
class nsIContent;
/** Simple data class that represents in-process reflow information about a column.
*/
class nsColLayoutData
{
public:
nsColLayoutData(nsTableColFrame* aColFrame, PRInt32 aNumRows);
// NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
~nsColLayoutData();
nsTableColFrame *GetColFrame();
nsVoidArray * GetCells();
PRInt32 Count() const;
nsCellLayoutData* ElementAt(PRInt32 aIndex) const;
PRInt32 IndexOf(nsCellLayoutData* aCellLayoutData) const;
PRInt32 IndexOf(nsIContent* aTableCell) const;
nsCellLayoutData* GetNext(nsCellLayoutData* aCellLayoutData) const;
nsCellLayoutData* GetPrevious(nsCellLayoutData* aCellLayoutData) const;
PRBool AppendElement(nsCellLayoutData* aCellLayoutData);
PRBool ReplaceElementAt(nsCellLayoutData* aCellLayoutData, PRInt32 aIndex);
void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
private:
nsTableColFrame *mColFrame;
nsVoidArray *mCells;
};
/* ---------- inlines ---------- */
inline nsTableColFrame * nsColLayoutData::GetColFrame()
{ return mColFrame;}
inline nsCellLayoutData* nsColLayoutData::ElementAt(PRInt32 aIndex) const
{ return (nsCellLayoutData*)mCells->ElementAt(aIndex);}
inline PRBool nsColLayoutData::AppendElement(nsCellLayoutData* aCellLayoutData)
{ return mCells->AppendElement((void*)aCellLayoutData);}
inline PRBool nsColLayoutData::ReplaceElementAt(nsCellLayoutData* aCellLayoutData, PRInt32 aIndex)
{ return mCells->ReplaceElementAt((void*)aCellLayoutData,aIndex);}
inline nsVoidArray * nsColLayoutData::GetCells()
{ return mCells; }
inline PRInt32 nsColLayoutData::Count() const
{ return mCells->Count(); }
inline PRInt32 nsColLayoutData::IndexOf(nsCellLayoutData* aCellLayoutData) const
{ return mCells->IndexOf((void*)aCellLayoutData);}
#endif

View File

@ -16,7 +16,6 @@
* Reserved.
*/
#include "nsTableCellFrame.h"
#include "nsCellLayoutData.h"
#include "nsBodyFrame.h"
#include "nsIReflowCommand.h"
#include "nsIStyleContext.h"
@ -53,21 +52,24 @@ static const PRBool gsDebugNT = PR_FALSE;
*/
nsTableCellFrame::nsTableCellFrame(nsIContent* aContent,
nsIFrame* aParentFrame)
: nsContainerFrame(aContent, aParentFrame),
mCellLayoutData(nsnull)
: nsContainerFrame(aContent, aParentFrame)
{
mRowSpan=1;
mColSpan=1;
mColIndex=0;
mPriorAvailWidth=0;
mPriorDesiredSize.width=0;
mPriorDesiredSize.height=0;
mDesiredSize.width=0;
mDesiredSize.height=0;
mMaxElementSize.width=0;
mMaxElementSize.height=0;
mPass1DesiredSize.width=0;
mPass1DesiredSize.height=0;
mPass1MaxElementSize.width=0;
mPass1MaxElementSize.height=0;
}
nsTableCellFrame::~nsTableCellFrame()
{
if (nsnull!=mCellLayoutData)
delete mCellLayoutData;
}
NS_METHOD nsTableCellFrame::Paint(nsIPresContext& aPresContext,
@ -291,7 +293,6 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
mFirstChild->WillReflow(*aPresContext);
mFirstChild->MoveTo(leftInset, topInset);
aStatus = ReflowChild(mFirstChild, aPresContext, kidSize, kidReflowState);
SetPriorDesiredSize(kidSize);
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugNT)
{
@ -325,10 +326,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
// first, compute the height
// the height can be set w/o being restricted by aMaxSize.height
nscoord cellHeight = kidSize.height;
if (NS_UNCONSTRAINEDSIZE!=aReflowState.maxSize.height)
{
cellHeight += topInset + bottomInset;
}
cellHeight += topInset + bottomInset;
if (PR_TRUE==gsDebugNT)
printf(" %p cellFrame height set to %d from kidSize=%d and insets %d,%d\n",
this, cellHeight, kidSize.height, topInset, bottomInset);
@ -369,6 +367,9 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
aDesiredSize.maxElementSize->height += topInset + bottomInset;
aDesiredSize.maxElementSize->width += leftInset + rightInset;
}
SetDesiredSize(aDesiredSize);
if (nsnull!=aDesiredSize.maxElementSize)
SetMaxElementSize(*(aDesiredSize.maxElementSize));
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugNT)
printf(" %p cellFrame returning aDesiredSize=%d,%d\n",
@ -590,6 +591,505 @@ nsresult nsTableCellFrame::NewFrame(nsIFrame** aInstancePtrResult,
}
/* ----- methods from CellLayoutData ----- */
/**
* Given a frame and an edge, find the margin
*
**/
nscoord nsTableCellFrame::GetMargin(nsIFrame* aFrame, PRUint8 aEdge) const
{
nscoord result = 0;
if (aFrame)
{
const nsStyleSpacing* spacing;
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
nsMargin margin;
spacing->CalcMarginFor(aFrame, margin);
switch (aEdge)
{
case NS_SIDE_TOP:
result = margin.top;
break;
case NS_SIDE_RIGHT:
result = margin.right;
break;
case NS_SIDE_BOTTOM:
result = margin.bottom;
break;
case NS_SIDE_LEFT:
result = margin.left;
break;
}
}
return result;
}
/**
* Given a style context and an edge, find the border width
*
**/
nscoord nsTableCellFrame::GetBorderWidth(nsIFrame* aFrame, PRUint8 aEdge) const
{
nscoord result = 0;
if (aFrame)
{
const nsStyleSpacing* spacing;
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
nsMargin border;
spacing->CalcBorderFor(aFrame, border);
switch (aEdge)
{
case NS_SIDE_TOP:
result = border.top;
break;
case NS_SIDE_RIGHT:
result = border.right;
break;
case NS_SIDE_BOTTOM:
result = border.bottom;
break;
case NS_SIDE_LEFT:
result = border.left;
break;
}
}
return result;
}
/**
* Given a style context and an edge, find the padding
*
**/
nscoord nsTableCellFrame::GetPadding(nsIFrame* aFrame, PRUint8 aEdge) const
{
nscoord result = 0;
if (aFrame)
{
const nsStyleSpacing* spacing;
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
nsMargin padding;
spacing->CalcPaddingFor(aFrame, padding);
switch (aEdge)
{
case NS_SIDE_TOP:
result = padding.top;
break;
case NS_SIDE_RIGHT:
result = padding.right;
break;
case NS_SIDE_BOTTOM:
result = padding.bottom;
break;
case NS_SIDE_LEFT:
result = padding.left;
break;
}
}
return result;
}
/**
* Given an Edge, find the opposing edge (top<-->bottom, left<-->right)
*
**/
PRUint8 nsTableCellFrame::GetOpposingEdge(PRUint8 aEdge)
{
PRUint8 result;
switch (aEdge)
{
case NS_SIDE_LEFT:
result = NS_SIDE_RIGHT;
break;
case NS_SIDE_RIGHT:
result = NS_SIDE_LEFT;
break;
case NS_SIDE_TOP:
result = NS_SIDE_BOTTOM;
break;
case NS_SIDE_BOTTOM:
result = NS_SIDE_TOP;
break;
default:
result = NS_SIDE_TOP;
}
return result;
}
/*
*
* Determine border style for two cells.
*
1.If the adjacent elements are of the same type, the wider of the two borders is used.
"Wider" takes into account the border-style of 'none', so a "1px solid" border
will take precedence over a "20px none" border.
2.If there are two or more with the same width, but different style,
then the one with a style near the start of the following list will be drawn:
'blank', 'double', 'solid', 'dashed', 'dotted', 'ridge', 'groove', 'none'
3.If the borders are of the same width, the border on the element occurring first is used.
First is defined as aStyle for this method.
NOTE: This assumes left-to-right, top-to-bottom bias. -- gpk
*
*/
nsIFrame* nsTableCellFrame::CompareCellBorders(nsIFrame* aFrame1,
PRUint8 aEdge1,
nsIFrame* aFrame2,
PRUint8 aEdge2)
{
PRInt32 width1 = GetBorderWidth(aFrame1,aEdge1);
PRInt32 width2 = GetBorderWidth(aFrame2,aEdge2);
nsIFrame* result = nsnull;
if (width1 > width2)
result = aFrame1;
else if (width1 < width2)
result = aFrame2;
else // width1 == width2
{
const nsStyleSpacing* border1;
const nsStyleSpacing* border2;
aFrame1->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)border1);
aFrame2->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)border2);
if (border1->mBorderStyle[aEdge1] >= border2->mBorderStyle[aEdge2])
result = aFrame1;
else
result = aFrame2;
}
return result;
}
/**
* Given a List of cell layout data, compare the edges to see which has the
* border with the highest precidence.
*
**/
nsIFrame* nsTableCellFrame::FindHighestPrecedentBorder(nsVoidArray* aList,
PRUint8 aEdge)
{
nsIFrame* result = nsnull;
PRInt32 index = 0;
PRInt32 count = 0;
NS_ASSERTION(aList,"a List must be valid");
count = aList->Count();
if (count)
{
nsIFrame* frame1;
nsIFrame* frame2;
frame1 = (nsIFrame*)(aList->ElementAt(index++));
while (index < count)
{
frame2 = (nsIFrame*)(aList->ElementAt(index++));
if (GetMargin(frame2,aEdge) == 0) {
frame1 = CompareCellBorders(frame1, aEdge, frame2, aEdge);
}
}
if ((nsnull != frame1) && (GetMargin(frame1, aEdge) != 0))
result = frame1;
}
return result;
}
nsIFrame* nsTableCellFrame::FindInnerBorder(nsVoidArray* aList, PRUint8 aEdge)
{
nsIFrame* result = nsnull;
PRUint8 opposite = GetOpposingEdge(aEdge);
if (GetMargin(this, aEdge) == 0)
{
nsIFrame* altFrame = FindHighestPrecedentBorder(aList,opposite);
if (nsnull != altFrame)
result = CompareCellBorders(this, aEdge, altFrame, opposite);
else
result = this;
}
return result;
}
/*
*
* FindRelevantBorder recursively searches up the frame hierarchy for the border
* style that is applicable to the cell. If at any point the frame has a margin
* or the parent frame has padding, then the outer frame for this object takes
* presendence over the inner frame.
1.Borders on 'table' elements take precedence over borders on any other table elements.
2.Borders on 'row-groups' take precedence over borders on 'rows',
and likewise borders on 'column-groups' take precedence over borders on 'columns'.
3.Borders on any other type of table element take precedence over 'table-cell' elements.
*
* NOTE: This method assumes that the table cell potentially shares a border.
* It should not be called for internal cells
*
* NOTE: COLUMNS AND COLGROUPS NEED TO BE FIGURED INTO THE ALGORITHM -- GPK!!!
*
*
*/
nsIFrame* nsTableCellFrame::FindOuterBorder( nsTableFrame* aTableFrame,
PRUint8 aEdge)
{
nsIFrame* frame = this; // By default, return our frame
PRBool done = PR_FALSE;
// The table frame is the outer most frame we test against
while (done == PR_FALSE)
{
done = PR_TRUE; // where done unless the frame's margin is zero
// and the parent's padding is zero
nscoord margin = GetMargin(frame,aEdge);
// if the margin for this style is zero then check to see if the paddding
// for the parent frame is also zero
if (margin == 0)
{
nsIFrame* parentFrame;
frame->GetGeometricParent(parentFrame);
// if the padding for the parent style is zero just
// recursively call this routine
PRInt32 padding = GetPadding(parentFrame,aEdge);
if ((nsnull != parentFrame) && (padding == 0))
{
frame = parentFrame;
// If this frame represents the table frame then
// the table style is used
done = PRBool(frame != (nsIFrame*)aTableFrame);
continue;
}
}
}
return frame;
}
/*
Border Resolution
1.Borders on 'table' elements take precedence over borders on any other table elements.
2.Borders on 'row-groups' take precedence over borders on 'rows', and likewise borders on 'column-groups' take
precedence over borders on 'columns'.
3.Borders on any other type of table element take precedence over 'table-cell' elements.
4.If the adjacent elements are of the same type, the wider of the two borders is used. "Wider" takes into account
the border-style of 'none', so a "1px solid" border will take precedence over a "20px none" border.
5.If the borders are of the same width, the border on the element occurring first is used.
How to compare
1.Those of the one or two cells that have an edge here.
Less than two can occur at the edge of the table, but also
at the edges of "holes" (unoccupied grid cells).
2.Those of the columns that have an edge here.
3.Those of the column groups that have an edge here.
4.Those of the rows that have an edge here.
5.Those of the row groups that have an edge here.
6.Those of the table, if this is the edge of the table.
*
* @param aIsFirst -- TRUE if this is the first cell in the row
* @param aIsLast -- TRUE if this is the last cell in the row
* @param aIsTop -- TRUE if this is the top cell in the column
* @param aIsBottom -- TRUE if this is the last cell in the column
*/
nsIFrame* nsTableCellFrame::FindBorderFrame(nsTableFrame* aTableFrame,
nsVoidArray* aList,
PRUint8 aEdge)
{
nsIFrame* frame = nsnull;
if (aList && aList->Count() == 0)
frame = FindOuterBorder(aTableFrame, aEdge);
else
frame = FindInnerBorder(aList, aEdge);
if (! frame)
frame = this;
return frame;
}
/**
* Given a List of cell layout data, compare the edges to see which has the
* border with the highest precidence.
*
**/
nscoord nsTableCellFrame::FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge)
{
nscoord result = 0;
PRInt32 index = 0;
PRInt32 count = 0;
NS_ASSERTION(aList,"a List must be valid");
count = aList->Count();
if (count)
{
nsIFrame* frame;
nscoord value = 0;
while (index < count)
{
frame = (nsIFrame*)(aList->ElementAt(index++));
value = GetMargin(frame, aEdge);
if (value > result)
result = value;
}
}
return result;
}
void nsTableCellFrame::CalculateMargins(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4])
{
// By default the margin is just the margin found in the
// table cells style
const nsStyleSpacing* spacing;
GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
spacing->CalcMarginFor(this, mMargin);
// Left and Top Margins are collapsed with their neightbors
// Right and Bottom Margins are simple left as they are
nscoord value;
// The left and top sides margins are the difference between
// their inherint value and the value of the margin of the
// object to the left or right of them.
value = FindLargestMargin(aBoundaryCells[NS_SIDE_LEFT],NS_SIDE_RIGHT);
if (value > mMargin.left)
mMargin.left = 0;
else
mMargin.left -= value;
value = FindLargestMargin(aBoundaryCells[NS_SIDE_TOP],NS_SIDE_BOTTOM);
if (value > mMargin.top)
mMargin.top = 0;
else
mMargin.top -= value;
}
void nsTableCellFrame::RecalcLayoutData(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4])
{
CalculateBorders(aTableFrame, aBoundaryCells);
CalculateMargins(aTableFrame, aBoundaryCells);
mCalculated = NS_OK;
}
#if 0 //QQQ
void nsTableCellFrame::List(FILE* out, PRInt32 aIndent) const
{
PRInt32 indent;
nsIContent* cell;
this->GetContent(cell);
if (cell != nsnull)
{
/*
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
fprintf(out,"RowSpan = %d ColSpan = %d \n",cell->GetRowSpan(),cell->GetColSpan());
*/
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
fprintf(out,"Margin -- Top: %d Left: %d Bottom: %d Right: %d \n",
NS_TWIPS_TO_POINTS_INT(mMargin.top),
NS_TWIPS_TO_POINTS_INT(mMargin.left),
NS_TWIPS_TO_POINTS_INT(mMargin.bottom),
NS_TWIPS_TO_POINTS_INT(mMargin.right));
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
nscoord top,left,bottom,right;
top = (mBorderFrame[NS_SIDE_TOP] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_TOP], NS_SIDE_TOP) : 0);
left = (mBorderFrame[NS_SIDE_LEFT] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_LEFT], NS_SIDE_LEFT) : 0);
bottom = (mBorderFrame[NS_SIDE_BOTTOM] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_BOTTOM], NS_SIDE_BOTTOM) : 0);
right = (mBorderFrame[NS_SIDE_RIGHT] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_RIGHT], NS_SIDE_RIGHT) : 0);
fprintf(out,"Border -- Top: %d Left: %d Bottom: %d Right: %d \n",
NS_TWIPS_TO_POINTS_INT(top),
NS_TWIPS_TO_POINTS_INT(left),
NS_TWIPS_TO_POINTS_INT(bottom),
NS_TWIPS_TO_POINTS_INT(right));
cell->List(out,aIndent);
NS_RELEASE(cell);
}
}
#endif
/* ----- debug only methods, to be removed ----- */
// For Debugging ONLY
NS_METHOD nsTableCellFrame::MoveTo(nscoord aX, nscoord aY)
{

View File

@ -21,8 +21,8 @@
#include "nscore.h"
#include "nsContainerFrame.h"
#include "nsTableFrame.h"
#include "nsTableRowFrame.h" // need to actually include this here to inline GetRowIndex
class nsCellLayoutData;
struct nsStyleSpacing;
/* eb42f7b0-079e-11d2-8f37-006008159b0c */
@ -72,34 +72,124 @@ public:
/** return the mapped cell's row span. Always >= 1. */
virtual PRInt32 GetRowSpan();
// there is no set row index because row index depends on the cell's parent row only
/** return the mapped cell's row index (starting at 0 for the first row) */
virtual PRInt32 GetRowIndex();
/** return the mapped cell's col span. Always >= 1. */
virtual PRInt32 GetColSpan();
/** return the mapped cell's column index (starting at 0 for the first column) */
virtual PRInt32 GetColIndex();
/** set the index of the column belonging to this cell */
// XXX should be removed, use cell map?
virtual void SetColIndex (int aColIndex);
/** return the available width given to this frame during its last reflow */
virtual nscoord GetPriorAvailWidth();
/** set the available width given to this frame during its last reflow */
virtual void SetPriorAvailWidth(nscoord aPriorAvailWidth);
virtual nsSize GetPriorDesiredSize();
/** return the desired size returned by this frame during its last reflow */
virtual nsSize GetDesiredSize();
virtual void SetPriorDesiredSize(const nsReflowMetrics & aDesiredSize);
/** set the desired size returned by this frame during its last reflow */
virtual void SetDesiredSize(const nsReflowMetrics & aDesiredSize);
virtual ~nsTableCellFrame();
/** return the MaxElement size returned by this frame during its last reflow
* not counting reflows where MaxElementSize is not requested.
* That is, the cell frame will always remember the last non-null MaxElementSize
*/
virtual nsSize GetMaxElementSize();
// Get the TableFrame that contains this cell frame
/** set the MaxElement size returned by this frame during its last reflow.
* should never be called with a null MaxElementSize
*/
virtual void SetMaxElementSize(const nsSize & aMaxElementSize);
/** return the desired size returned by this frame during its last reflow */
virtual nsSize GetPass1DesiredSize();
/** set the desired size returned by this frame during its last reflow */
virtual void SetPass1DesiredSize(const nsReflowMetrics & aDesiredSize);
/** return the MaxElement size returned by this frame during its last reflow
* not counting reflows where MaxElementSize is not requested.
* That is, the cell frame will always remember the last non-null MaxElementSize
*/
virtual nsSize GetPass1MaxElementSize();
/** set the MaxElement size returned by this frame during its last reflow.
* should never be called with a null MaxElementSize
*/
virtual void SetPass1MaxElementSize(const nsSize & aMaxElementSize);
/** Get the TableFrame that contains this cell frame */
virtual nsTableFrame* GetTableFrame();
nsCellLayoutData * GetCellLayoutData();
void SetCellLayoutData(nsCellLayoutData *aData);
void RecalcLayoutData(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4]);
// For DEBUGGING Purposes Only
NS_IMETHOD GetMargin(nsMargin& aMargin);
/** destructor */
virtual ~nsTableCellFrame();
// For DEBUGGING Purposes Only, to be removed
NS_IMETHOD MoveTo(nscoord aX, nscoord aY);
NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight);
private:
// All these methods are support methods for RecalcLayoutData
nsIFrame* GetFrameAt(nsVoidArray* aList, PRInt32 aIndex);
nscoord GetMargin(nsIFrame* aFrame, PRUint8 aEdge) const;
nscoord GetBorderWidth(nsIFrame* aFrame, PRUint8 aEdge) const;
nscoord GetPadding(nsIFrame* aFrame, PRUint8 aEdge) const;
PRUint8 GetOpposingEdge(PRUint8 aEdge);
nsIFrame* CompareCellBorders(nsIFrame* aFrame1,
PRUint8 aEdge1,
nsIFrame* aFrame2,
PRUint8 aEdge2);
nsIFrame* FindHighestPrecedentBorder(nsVoidArray* aList,
PRUint8 aEdge);
nsIFrame* FindInnerBorder( nsVoidArray* aList,
PRUint8 aEdge);
nsIFrame* FindOuterBorder( nsTableFrame* aTableFrame,
PRUint8 aEdge);
nsIFrame* FindBorderFrame(nsTableFrame* aTableFrame,
nsVoidArray* aCellList,
PRUint8 aEdge);
void CalculateBorders(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4]);
nscoord FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge);
void CalculateMargins(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4]);
protected:
/** protected constructor.
@ -132,9 +222,17 @@ protected:
/** the available width we were given in our previous reflow */
nscoord mPriorAvailWidth;
nsSize mPriorDesiredSize;
/** these are the last computed desired and max element sizes */
nsSize mDesiredSize;
nsSize mMaxElementSize;
nsCellLayoutData *mCellLayoutData;
/** these are the Pass 1 unconstrained desired and max element sizes */
nsSize mPass1DesiredSize;
nsSize mPass1MaxElementSize;
nsresult mCalculated;
nsMargin mMargin;
nsIFrame* mBorderFrame[4]; // the frame whose border is used
};
@ -151,6 +249,16 @@ inline void nsTableCellFrame::Init(PRInt32 aRowSpan, PRInt32 aColSpan, PRInt32 a
inline PRInt32 nsTableCellFrame::GetRowSpan()
{ return mRowSpan;}
inline PRInt32 nsTableCellFrame::GetRowIndex()
{
nsTableRowFrame * row;
GetContentParent((nsIFrame *&)row);
if (nsnull!=row)
return row->GetRowIndex();
else
return 0;
}
inline PRInt32 nsTableCellFrame::GetColSpan()
{ return mColSpan;}
@ -163,25 +271,64 @@ inline void nsTableCellFrame::SetColIndex (int aColIndex)
mColIndex = aColIndex;
}
inline nsCellLayoutData * nsTableCellFrame::GetCellLayoutData()
{ return mCellLayoutData;}
inline void nsTableCellFrame::SetCellLayoutData(nsCellLayoutData *aData)
{ mCellLayoutData = aData;}
inline nscoord nsTableCellFrame::GetPriorAvailWidth()
{ return mPriorAvailWidth;}
inline void nsTableCellFrame::SetPriorAvailWidth(nscoord aPriorAvailWidth)
{ mPriorAvailWidth = aPriorAvailWidth;}
inline nsSize nsTableCellFrame::GetPriorDesiredSize()
{ return mPriorDesiredSize; }
inline nsSize nsTableCellFrame::GetDesiredSize()
{ return mDesiredSize; }
inline void nsTableCellFrame::SetPriorDesiredSize(const nsReflowMetrics & aDesiredSize)
inline void nsTableCellFrame::SetDesiredSize(const nsReflowMetrics & aDesiredSize)
{
mPriorDesiredSize.width = aDesiredSize.width;
mPriorDesiredSize.height = aDesiredSize.height;
mDesiredSize.width = aDesiredSize.width;
mDesiredSize.height = aDesiredSize.height;
}
inline nsSize nsTableCellFrame::GetMaxElementSize()
{ return mMaxElementSize; }
inline void nsTableCellFrame::SetMaxElementSize(const nsSize & aMaxElementSize)
{
mMaxElementSize.width = aMaxElementSize.width;
mMaxElementSize.height = aMaxElementSize.height;
}
inline nsSize nsTableCellFrame::GetPass1DesiredSize()
{ return mPass1DesiredSize; }
inline void nsTableCellFrame::SetPass1DesiredSize(const nsReflowMetrics & aDesiredSize)
{
mPass1DesiredSize.width = aDesiredSize.width;
mPass1DesiredSize.height = aDesiredSize.height;
}
inline nsSize nsTableCellFrame::GetPass1MaxElementSize()
{ return mPass1MaxElementSize; }
inline void nsTableCellFrame::SetPass1MaxElementSize(const nsSize & aMaxElementSize)
{
mPass1MaxElementSize.width = aMaxElementSize.width;
mPass1MaxElementSize.height = aMaxElementSize.height;
}
inline void nsTableCellFrame::CalculateBorders(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4])
{
for (PRInt32 edge = 0; edge < 4; edge++)
mBorderFrame[edge] = FindBorderFrame(aTableFrame, aBoundaryCells[edge], edge);
}
inline NS_METHOD nsTableCellFrame::GetMargin(nsMargin& aMargin)
{
if (mCalculated == NS_OK)
{
aMargin = mMargin;
return NS_OK;
}
return NS_ERROR_NOT_INITIALIZED;
}
#endif

View File

@ -21,8 +21,6 @@
#include "nsTablePart.h"
#include "nsHTMLParts.h"
#include "nsHTMLContainer.h"
#include "nsContainerFrame.h"
#include "nsIReflowCommand.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
#include "nsIPresContext.h"
@ -38,66 +36,6 @@ static const PRBool gsNoisyRefs = PR_FALSE;
#endif
nsTableColFrame::nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame)
: nsFrame(aContent, aParentFrame)
{
mColIndex = 0;
mRepeat = 0;
}
nsTableColFrame::~nsTableColFrame()
{
}
NS_METHOD nsTableColFrame::Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
{
if (gsDebug==PR_TRUE)
printf("nsTableColFrame::Paint\n");
return NS_OK;
}
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)
{
aDesiredSize.maxElementSize->width=0;
aDesiredSize.maxElementSize->height=0;
}
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
/* ----- static methods ------ */
nsresult nsTableColFrame::NewFrame(nsIFrame** aInstancePtrResult,
nsIContent* aContent,
nsIFrame* aParent)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
if (nsnull == aInstancePtrResult) {
return NS_ERROR_NULL_POINTER;
}
nsIFrame* it = new nsTableColFrame(aContent, aParent);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
*aInstancePtrResult = it;
return NS_OK;
}
//---------------------- nsTableCol implementation -----------------------------------
nsTableCol::nsTableCol(nsIAtom* aTag)
: nsTableContent(aTag),
mColGroup(0),

View File

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsTableColFrame.h"
#include "nsContainerFrame.h"
#include "nsIReflowCommand.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
#include "nsIPresContext.h"
#include "nsHTMLIIDs.h"
#include "nsHTMLAtoms.h"
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
static PRBool gsNoisyRefs = PR_FALSE;
#else
static const PRBool gsDebug = PR_FALSE;
static const PRBool gsNoisyRefs = PR_FALSE;
#endif
nsTableColFrame::nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame)
: nsFrame(aContent, aParentFrame)
{
mColIndex = 0;
mRepeat = 0;
}
nsTableColFrame::~nsTableColFrame()
{
}
NS_METHOD nsTableColFrame::Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
{
if (gsDebug==PR_TRUE)
printf("nsTableColFrame::Paint\n");
return NS_OK;
}
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)
{
aDesiredSize.maxElementSize->width=0;
aDesiredSize.maxElementSize->height=0;
}
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
/* ----- static methods ------ */
nsresult nsTableColFrame::NewFrame(nsIFrame** aInstancePtrResult,
nsIContent* aContent,
nsIFrame* aParent)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
if (nsnull == aInstancePtrResult) {
return NS_ERROR_NULL_POINTER;
}
nsIFrame* it = new nsTableColFrame(aContent, aParent);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
*aInstancePtrResult = it;
return NS_OK;
}

View File

@ -48,6 +48,12 @@ public:
/** set the index of the column this content object represents. must be >= 0 */
virtual void SetColumnIndex (int aColIndex);
/** convenience method, calls into cellmap */
nsVoidArray * GetCells();
/** convenience method, calls into cellmap */
PRInt32 Count() const;
protected:
nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame);
@ -55,10 +61,16 @@ protected:
~nsTableColFrame();
/** the starting index of the column (starting at 0) that this col object represents */
PRInt32 mColIndex;
PRInt32 mColIndex;
/** the number of columns that the attributes of this column extend to */
PRInt32 mRepeat;
PRInt32 mRepeat;
nscoord mMaxWidth;
nscoord mMinWidth;
nscoord mMaxEffectiveWidth;
nscoord mMinEffectiveWidth;
};

View File

@ -29,14 +29,12 @@
#include "nsTableColGroupFrame.h"
#include "nsTableRowFrame.h"
#include "nsTableRowGroupFrame.h"
#include "nsColLayoutData.h"
#include "BasicTableLayoutStrategy.h"
#include "nsIPresContext.h"
#include "nsCSSRendering.h"
#include "nsStyleConsts.h"
#include "nsCellLayoutData.h"
#include "nsVoidArray.h"
#include "nsIPtr.h"
#include "nsIView.h"
@ -269,7 +267,6 @@ void ColumnInfoCache::GetColumnsByType(const nsStyleUnit aType,
nsTableFrame::nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame)
: nsContainerFrame(aContent, aParentFrame),
mCellMap(nsnull),
mColumnLayoutData(nsnull),
mColCache(nsnull),
mColumnWidths(nsnull),
mTableLayoutStrategy(nsnull),
@ -279,32 +276,11 @@ nsTableFrame::nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame)
{
}
/**
* Method to delete all owned objects assoicated
* with the ColumnLayoutObject instance variable
*/
void nsTableFrame::DeleteColumnLayoutData()
{
if (nsnull!=mColumnLayoutData)
{
PRInt32 numCols = mColumnLayoutData->Count();
for (PRInt32 i = 0; i<numCols; i++)
{
nsColLayoutData *colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(i));
delete colData;
}
delete mColumnLayoutData;
mColumnLayoutData = nsnull;
}
}
nsTableFrame::~nsTableFrame()
{
if (nsnull!=mCellMap)
delete mCellMap;
DeleteColumnLayoutData();
if (nsnull!=mColumnWidths)
delete [] mColumnWidths;
@ -351,8 +327,7 @@ nsTableRowGroupFrame* nsTableFrame::NextRowGroupFrame(nsTableRowGroupFrame* aRow
PRInt32 nsTableFrame::GetSpecifiedColumnCount ()
{
mColCount=0;
nsIFrame * colGroup;
ChildAt (0, (nsIFrame *&)colGroup);
nsIFrame * colGroup = mFirstChild;
while (nsnull!=colGroup)
{
const nsStyleDisplay *childDisplay;
@ -379,8 +354,7 @@ PRInt32 nsTableFrame::GetRowCount ()
if (nsnull != mCellMap)
return mCellMap->GetRowCount();
nsIFrame *child=nsnull;
ChildAt(0, child);
nsIFrame *child=mFirstChild;
while (nsnull!=child)
{
const nsStyleDisplay *childDisplay;
@ -393,6 +367,35 @@ PRInt32 nsTableFrame::GetRowCount ()
}
return rowCount;
}
nsTableColFrame * nsTableFrame::GetColFrame(PRInt32 aColIndex)
{
nsTableColFrame *result = nsnull;
if (nsnull!=mCellMap)
{
result = mCellMap->GetColumnFrame(aColIndex);
}
return result;
}
// can return nsnull
nsTableCellFrame * nsTableFrame::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex)
{
nsTableCellFrame *result = nsnull;
if (nsnull!=mCellMap)
{
CellData * cellData = mCellMap->GetCellAt(aRowIndex, aColIndex);
if (nsnull!=cellData)
{
result = cellData->mCell;
if (nsnull==result)
result = cellData->mRealCell->mCell;
}
}
return result;
}
// return the 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)
@ -413,13 +416,6 @@ PRInt32 nsTableFrame::GetEffectiveRowSpan (PRInt32 aRowIndex, nsTableCellFrame *
return rowSpan;
}
// returns the actual cell map, not a copy, so don't mess with it!
nsCellMap* nsTableFrame::GetCellMap() const
{
return mCellMap;
}
/* call when the cell structure has changed. mCellMap will be rebuilt on demand. */
void nsTableFrame::ResetCellMap ()
{
@ -449,10 +445,9 @@ void nsTableFrame::EnsureColumns(nsIPresContext* aPresContext,
PRInt32 actualColumns = 0;
nsTableColGroupFrame *lastColGroupFrame = nsnull;
nsIFrame * childFrame=nsnull;
nsIFrame * firstRowGroupFrame=nsnull;
nsIFrame * prevSibFrame=nsnull;
ChildAt (0, (nsIFrame *&)childFrame);
nsIFrame * childFrame=mFirstChild;
while (nsnull!=childFrame)
{
const nsStyleDisplay *childDisplay;
@ -795,35 +790,67 @@ void nsTableFrame::GrowCellMap (PRInt32 aColCount)
*/
void nsTableFrame::ListColumnLayoutData(FILE* out, PRInt32 aIndent) const
{
// if this is a continuing frame, there will be no output
if (nsnull!=mColumnLayoutData)
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
if (this!=firstInFlow)
{
firstInFlow->ListColumnLayoutData(out, aIndent);
return;
}
if (nsnull!=mCellMap)
{
fprintf(out,"Column Layout Data \n");
PRInt32 numCols = mColumnLayoutData->Count();
for (PRInt32 i = 0; i<numCols; i++)
PRInt32 numCols = mCellMap->GetColCount();
PRInt32 numRows = mCellMap->GetRowCount();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData *colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(i));
for (PRInt32 indent = aIndent; --indent >= 0; )
fputs(" ", out);
fprintf(out,"Column Data [%d] \n",colIndex);
for (PRInt32 rowIndex = 0; rowIndex < numRows; rowIndex++)
{
nsTableCellFrame *cellFrame = mCellMap->GetCellFrameAt(rowIndex, colIndex);
PRInt32 rowIndent;
for (rowIndent = aIndent+2; --rowIndent >= 0; ) fputs(" ", out);
fprintf(out,"Cell Data [%d] \n",rowIndex);
for (rowIndent = aIndent+2; --rowIndent >= 0; ) fputs(" ", out);
nsMargin margin;
cellFrame->GetMargin(margin);
fprintf(out,"Margin -- Top: %d Left: %d Bottom: %d Right: %d \n",
NS_TWIPS_TO_POINTS_INT(margin.top),
NS_TWIPS_TO_POINTS_INT(margin.left),
NS_TWIPS_TO_POINTS_INT(margin.bottom),
NS_TWIPS_TO_POINTS_INT(margin.right));
for (rowIndent = aIndent+2; --rowIndent >= 0; ) fputs(" ", out);
for (PRInt32 indent = aIndent; --indent >= 0; ) fputs(" ", out);
fprintf(out,"Column Data [%d] \n",i);
colData->List(out,aIndent+2);
nscoord top,left,bottom,right;
/*
top = (mBorderFrame[NS_SIDE_TOP] ? cellFrame->GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_TOP], NS_SIDE_TOP) : 0);
left = (mBorderFrame[NS_SIDE_LEFT] ? cellFrame->GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_LEFT], NS_SIDE_LEFT) : 0);
bottom = (mBorderFrame[NS_SIDE_BOTTOM] ? cellFrame->GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_BOTTOM], NS_SIDE_BOTTOM) : 0);
right = (mBorderFrame[NS_SIDE_RIGHT] ? cellFrame->GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_RIGHT], NS_SIDE_RIGHT) : 0);
*/
fprintf(out,"Border -- Top: %d Left: %d Bottom: %d Right: %d \n",
NS_TWIPS_TO_POINTS_INT(top),
NS_TWIPS_TO_POINTS_INT(left),
NS_TWIPS_TO_POINTS_INT(bottom),
NS_TWIPS_TO_POINTS_INT(right));
}
}
}
}
/**
* For the TableCell in CellData, find the CellLayoutData assocated
* and add it to the list
**/
* For the TableCell in CellData, add it to the list
*/
void nsTableFrame::AppendLayoutData(nsVoidArray* aList, nsTableCellFrame* aTableCell)
{
if (aTableCell != nsnull)
{
nsCellLayoutData* layoutData = GetCellLayoutData(aTableCell);
if (layoutData != nsnull)
aList->AppendElement((void*)layoutData);
aList->AppendElement((void*)aTableCell);
}
}
@ -996,9 +1023,7 @@ void nsTableFrame::RecalcLayoutData()
r++;
}
nsCellLayoutData* cellLayoutData = GetCellLayoutData(cell);
if (cellLayoutData != nsnull)
cellLayoutData->RecalcLayoutData(this,boundaryCells);
cell->RecalcLayoutData(this,boundaryCells);
}
}
}
@ -1310,7 +1335,7 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext,
if (nsnull!=prevKidFrame)
prevKidFrame->GetNextSibling(kidFrame); // no need to check for an error, just see if it returned null...
else
ChildAt(0, kidFrame);
kidFrame=mFirstChild;
// if this is the first time, allocate the frame
if (nsnull==kidFrame)
@ -2210,11 +2235,10 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
if (gsDebug)
printf ("BalanceColumnWidths...\n");
nsVoidArray *columnLayoutData = GetColumnLayoutData();
if (nsnull==columnLayoutData)
if (nsnull==mCellMap)
return; // we don't have any information yet, so we can't do any useful work
PRInt32 numCols = columnLayoutData->Count();
PRInt32 numCols = mCellMap->GetColCount();
if (nsnull==mColumnWidths)
{
mColumnWidths = new PRInt32[numCols];
@ -2233,9 +2257,22 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
// need to figure out the overall table width constraint
// default case, get 100% of available space
// begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED!
nsIFrame * outerTableFrame = nsnull;
const nsStylePosition* position;
GetGeometricParent(outerTableFrame);
outerTableFrame->GetStyleData(eStyleStruct_Position, ((nsStyleStruct *&)position));
// end REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED
PRInt32 maxWidth;
/*
const nsStylePosition* position =
(const nsStylePosition*)mStyleContext->GetStyleData(eStyleStruct_Position);
use this line when tableFrame contains its own position style info
*/
switch (position->mWidth.GetUnit()) {
case eStyleUnit_Coord:
maxWidth = position->mWidth.GetCoordValue();
@ -2251,7 +2288,6 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
// XXX for now these fall through
default:
maxWidth = aMaxSize.width;
break;
}
@ -2293,16 +2329,20 @@ void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext)
if (gsDebug==PR_TRUE) printf ("SetTableWidth...");
PRInt32 tableWidth = 0;
nsVoidArray *columnLayoutData = GetColumnLayoutData();
if (nsnull==columnLayoutData)
if (nsnull==mCellMap)
return; // no info, so nothing to do
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 i = 0; i<numCols; i++)
PRInt32 numCols = mCellMap->GetColCount();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
tableWidth += mColumnWidths[i];
nscoord totalColWidth = mColumnWidths[colIndex];
nsTableCellFrame * cellFrame = GetCellAt(0, colIndex);
nsMargin colMargin;
GetCellMarginData(cellFrame,colMargin);
totalColWidth += colMargin.left + colMargin.right;
if (gsDebug==PR_TRUE)
printf (" += %d ", mColumnWidths[i]);
printf (" += %d ", totalColWidth);
tableWidth += totalColWidth;
}
// Compute the insets (sum of border and padding)
@ -2384,12 +2424,9 @@ NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aCol
{
aColFrame = nsnull; // initialize out parameter
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
if (nsnull!=firstInFlow->mColumnLayoutData)
if (nsnull!=firstInFlow->mCellMap)
{ // hooray, we get to do this the easy way because the info is cached
nsColLayoutData * colData = (nsColLayoutData *)
(firstInFlow->mColumnLayoutData->ElementAt(aColIndex));
NS_ASSERTION(nsnull != colData, "bad column data");
aColFrame = colData->GetColFrame();
aColFrame = firstInFlow->mCellMap->GetColumnFrame(aColIndex);
NS_ASSERTION(nsnull!=aColFrame, "bad col frame");
}
else
@ -2443,31 +2480,46 @@ void nsTableFrame::BuildColumnCache( nsIPresContext* aPresContext,
mColCache = new ColumnInfoCache(mColCount);
nsIFrame * childFrame = mFirstChild;
while (nsnull!=childFrame)
{ // for every child, if it's a col group then get the columns
{ // in this loop, we cache column info and set column style info from cells in first row
const nsStyleDisplay *childDisplay;
childFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay ||
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{ // if it's a col group then get the columns and cache them in the CellMap
nsTableColFrame *colFrame=nsnull;
childFrame->FirstChild((nsIFrame *&)colFrame);
while (nsnull!=colFrame)
{
mCellMap->AppendColumnFrame(colFrame);
colFrame->GetNextSibling((nsIFrame *&)colFrame);
}
}
else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay )
{ // for every cell in every row, call SetCellLayoutData with the cached info
// QQQ we can probably just leave the info in the table cell frame, not cache it here
{ // if it's a row group, get the cells and set the column style if appropriate
nsIFrame *rowFrame;
childFrame->ChildAt(0, rowFrame);
nsIFrame *cellFrame;
rowFrame->ChildAt(0, cellFrame);
while (nsnull!=cellFrame)
childFrame->FirstChild(rowFrame);
if (nsnull!=rowFrame)
{
/* this is the first time we are guaranteed to have both the cell frames
* and the column frames, so it's a good time to
* set the column style from the cell's width attribute (if this is the first row)
*/
SetColumnStyleFromCell(aPresContext, (nsTableCellFrame *)cellFrame, (nsTableRowFrame *)rowFrame);
cellFrame->GetNextSibling(cellFrame);
nsIFrame *cellFrame;
rowFrame->FirstChild(cellFrame);
while (nsnull!=cellFrame)
{
/* this is the first time we are guaranteed to have both the cell frames
* and the column frames, so it's a good time to
* set the column style from the cell's width attribute (if this is the first row)
*/
SetColumnStyleFromCell(aPresContext, (nsTableCellFrame *)cellFrame, (nsTableRowFrame *)rowFrame);
cellFrame->GetNextSibling(cellFrame);
}
}
}
childFrame->GetNextSibling(childFrame);
}
// second time through, set column cache info for each column
// we can't do this until the loop above has set the column style info from the cells in the first row
childFrame = mFirstChild;
while (nsnull!=childFrame)
{ // for every child, if it's a col group then get the columns
@ -2476,7 +2528,7 @@ void nsTableFrame::BuildColumnCache( nsIPresContext* aPresContext,
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
nsTableColFrame *colFrame=nsnull;
childFrame->ChildAt(0, (nsIFrame *&)colFrame);
childFrame->FirstChild((nsIFrame *&)colFrame);
while (nsnull!=colFrame)
{ // for every column, create an entry in the column cache
// assumes that the col style has been twiddled to account for first cell width attribute
@ -2489,176 +2541,14 @@ void nsTableFrame::BuildColumnCache( nsIPresContext* aPresContext,
else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay )
{ // for every cell in every row, call SetCellLayoutData with the cached info
// QQQ we can probably just leave the info in the table cell frame, not cache it here
nsIFrame *rowFrame;
childFrame->ChildAt(0, rowFrame);
while (nsnull!=rowFrame)
{
nsIFrame *cellFrame;
rowFrame->ChildAt(0, cellFrame);
while (nsnull!=cellFrame)
{
nsCellLayoutData *cld = ((nsTableCellFrame*)cellFrame)->GetCellLayoutData();
SetCellLayoutData(aPresContext, cld, (nsTableCellFrame*)cellFrame);
cellFrame->GetNextSibling(cellFrame);
}
rowFrame->GetNextSibling(rowFrame);
}
{
break; // once we hit a row group, we're done
}
childFrame->GetNextSibling(childFrame);
}
}
}
// nsnull is a valid return value. This is for empty tables.
nsVoidArray * nsTableFrame::GetColumnLayoutData()
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
return firstInFlow->mColumnLayoutData;
}
/** Associate aData with the cell at (aRow,aCol)
* @return PR_TRUE if the data was successfully associated with a Cell
* PR_FALSE if there was an error, such as aRow or aCol being invalid
*/
PRBool nsTableFrame::SetCellLayoutData(nsIPresContext* aPresContext,
nsCellLayoutData * aData, nsTableCellFrame *aCell)
{
NS_ASSERTION(nsnull != aPresContext, "bad arg aPresContext");
NS_ASSERTION(nsnull != aData, "bad arg aData");
NS_ASSERTION(nsnull != aCell, "bad arg aCell");
PRBool result = PR_TRUE;
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
if (this!=firstInFlow)
result = firstInFlow->SetCellLayoutData(aPresContext, aData, aCell);
else
{
if ((kPASS_FIRST==GetReflowPass()) || (kPASS_INCREMENTAL==GetReflowPass()))
{
if (nsnull==mColumnLayoutData)
{
PRInt32 rows = GetRowCount();
mColumnLayoutData = new nsVoidArray();
NS_ASSERTION(nsnull != mColumnLayoutData, "bad alloc");
PRInt32 tableKidCount = mContent->ChildCount();
nsIFrame * colGroupFrame = mFirstChild;
for (PRInt32 i=0; i<tableKidCount; ) // notice increment of i is done just before ChildAt call
{
const nsStyleDisplay *childDisplay;
colGroupFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
nsTableColFrame *colFrame=nsnull;
colGroupFrame->ChildAt(0, (nsIFrame *&)colFrame);
while (nsnull!=colFrame)
{
// TODO: unify these 2 kinds of column data
// TODO: cache more column data, like the mWidth.GetUnit and what its value
nsColLayoutData *colData = new nsColLayoutData(colFrame, rows);
mColumnLayoutData->AppendElement((void *)colData);
colFrame->GetNextSibling((nsIFrame *&)colFrame);
}
}
// can't have col groups after row groups, so stop if you find a row group
else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay )
{
break;
}
i++;
ChildAt(i, colGroupFrame); // can't use colGroupFrame->GetNextSibling because it hasn't been set yet
}
}
PRInt32 firstColIndex = aCell->GetColIndex();
nsTableRowFrame *row;
aCell->GetGeometricParent((nsIFrame*&)row);
PRInt32 rowIndex = row->GetRowIndex();
PRInt32 colSpan = aCell->GetColSpan();
nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex));
nsVoidArray *col = colData->GetCells();
if (gsDebugCLD) printf (" ~ SetCellLayoutData with row = %d, firstCol = %d, colSpan = %d, colData = %ld, col=%ld\n",
rowIndex, firstColIndex, colSpan, colData, col);
/* this logic looks wrong wrong wrong
it seems to add an entries in col (the array of cells for a column) for aCell
based on colspan. This is weird, because you would expect one entry in each
column spanned for aCell, not multiple entries in the same col.
*/
for (PRInt32 i=0; i<colSpan; i++)
{
nsSize * cellSize = aData->GetMaxElementSize();
nsSize partialCellSize(*cellSize);
partialCellSize.width = (cellSize->width)/colSpan;
// This method will copy the nsReflowMetrics pointed at by aData->GetDesiredSize()
nsCellLayoutData * kidLayoutData = new nsCellLayoutData(aData->GetCellFrame(),
aData->GetDesiredSize(),
&partialCellSize);
NS_ASSERTION(col->Count() > rowIndex, "unexpected count");
if (gsDebugCLD) printf (" ~ replacing rowIndex = %d\n", rowIndex);
nsCellLayoutData* data = (nsCellLayoutData*)col->ElementAt(rowIndex);
col->ReplaceElementAt((void *)kidLayoutData, rowIndex);
if (data != nsnull) {
delete data;
}
}
}
else
result = PR_FALSE;
}
return result;
}
/** Get the layout data associated with the cell at (aRow,aCol)
* @return nsnull if there was an error, such as aRow or aCol being invalid
* otherwise, the data is returned.
*/
nsCellLayoutData * nsTableFrame::GetCellLayoutData(nsTableCellFrame *aCell)
{
NS_ASSERTION(nsnull != aCell, "bad arg");
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
nsCellLayoutData *result = nsnull;
if (this!=firstInFlow)
result = firstInFlow->GetCellLayoutData(aCell);
else
{
if (nsnull!=mColumnLayoutData)
{
PRInt32 firstColIndex = aCell->GetColIndex();
nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex));
nsTableRowFrame *rowFrame;
aCell->GetGeometricParent((nsIFrame *&)rowFrame);
PRInt32 rowIndex = rowFrame->GetRowIndex();
result = colData->ElementAt(rowIndex);
#ifdef NS_DEBUG
// Do some sanity checking
if (nsnull != result) {
nsIContent* inputContent;
nsIContent* resultContent;
result->GetCellFrame()->GetContent(resultContent);
aCell->GetContent(inputContent);
NS_ASSERTION(resultContent == inputContent, "unexpected cell");
NS_IF_RELEASE(inputContent);
NS_IF_RELEASE(resultContent);
}
#endif
}
}
return result;
}
PRInt32 nsTableFrame::GetReflowPass() const
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
@ -2698,7 +2588,7 @@ nsTableFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
// add headers and footers to cf
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
nsIFrame * rg = nsnull;
firstInFlow->ChildAt(0, rg);
firstInFlow->FirstChild(rg);
NS_ASSERTION (nsnull!=rg, "previous frame has no children");
nsIAtom * tHeadTag = NS_NewAtom(nsTablePart::kRowGroupHeadTagString); // tHeadTag: REFCNT++
nsIAtom * tFootTag = NS_NewAtom(nsTablePart::kRowGroupFootTagString); // tFootTag: REFCNT++
@ -2758,9 +2648,8 @@ PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex)
{
NS_ASSERTION(nsnull!=mColumnWidths, "illegal state");
#ifdef DEBUG
nsVoidArray *cld = GetColumnLayoutData();
NS_ASSERTION(nsnull!=cld, "no column layout data");
PRInt32 numCols = cld->Count();
NS_ASSERTION(nsnull!=mCellMap, "no column layout data");
PRInt32 numCols = mCellMap->GetColCount();
NS_ASSERTION (numCols > aColIndex, "bad arg, col index out of bounds");
#endif
if (nsnull!=mColumnWidths)
@ -2770,11 +2659,6 @@ PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex)
//printf("GET_COL_WIDTH: %p, FIF=%p getting col %d and returning %d\n", this, firstInFlow, aColIndex, result);
// XXX hack
#if 0
if (result <= 0) {
result = 100;
}
#endif
return result;
}
@ -2936,9 +2820,7 @@ NS_METHOD nsTableFrame::GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin&
if (nsnull != aKidFrame)
{
nsCellLayoutData* layoutData = GetCellLayoutData(aKidFrame);
if (layoutData)
result = layoutData->GetMargin(aMargin);
result = aKidFrame->GetMargin(aMargin);
}
return result;
@ -3218,37 +3100,6 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame,
return result;
}
/* valuable code not yet used anywhere
// since the table is a specified width, we need to expand the columns to fill the table
nsVoidArray *columnLayoutData = GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
PRInt32 spaceUsed = 0;
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
spaceUsed += mColumnWidths[colIndex];
PRInt32 spaceRemaining = spaceUsed - aMaxWidth;
PRInt32 additionalSpaceAdded = 0;
if (0<spaceRemaining)
{
for (colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
nsStyleMolecule* colStyle =
(nsStyleMolecule*)mStyleContext->GetData(eStyleStruct_Molecule);
if (PR_TRUE==IsProportionalWidth(colStyle))
{
PRInt32 percentage = (100*mColumnWidths[colIndex]) / aMaxWidth;
PRInt32 additionalSpace = (spaceRemaining*percentage)/100;
mColumnWidths[colIndex] += additionalSpace;
additionalSpaceAdded += additionalSpace;
}
}
if (spaceUsed+additionalSpaceAdded < aMaxTableWidth)
mColumnWidths[numCols-1] += (aMaxTableWidth - (spaceUsed+additionalSpaceAdded));
}
*/
// For Debugging ONLY
NS_METHOD nsTableFrame::MoveTo(nscoord aX, nscoord aY)
{

View File

@ -23,7 +23,6 @@
#include "nsStyleCoord.h"
class nsCellMap;
class nsCellLayoutData;
class nsVoidArray;
class nsTableCellFrame;
class nsTableColFrame;
@ -42,29 +41,6 @@ struct nsStyleSpacing;
extern const nsIID kTableFrameCID;
/** Data stored by nsCellMap to rationalize rowspan and colspan cells.
* if mCell is null then mRealCell will be the rowspan/colspan source
* in addition, if fOverlap is non-null then it will point to the
* other cell that overlaps this position
* @see nsCellMap
* @see nsTableFrame::BuildCellMap
* @see nsTableFrame::GrowCellMap
* @see nsTableFrame::BuildCellIntoMap
*
*/
class CellData
{
public:
nsTableCellFrame *mCell;
CellData *mRealCell;
CellData *mOverlap;
CellData();
~CellData();
};
/* ============================================================================ */
/** nsTableFrame maps the inner portion of a table (everything except captions.)
@ -153,36 +129,12 @@ public:
*/
NS_METHOD GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame);
/** return the column layout data for this inner table frame.
* if this is a continuing frame, return the first-in-flow's column layout data.
* @return the column layout data array, or null if there is no info yet.
*/
virtual nsVoidArray *GetColumnLayoutData();
/** Associate aData with the cell at (aRow,aCol)
*
* @param aPresContext -- used to resolve style when initializing caches
* @param aData -- the info to cache
* @param aCell -- the content object for which layout info is being cached
*
* @return PR_TRUE if the data was successfully associated with a Cell
* PR_FALSE if there was an error, such as aRow or aCol being invalid
*/
virtual PRBool SetCellLayoutData(nsIPresContext * aPresContext,
nsCellLayoutData * aData,
nsTableCellFrame * aCell);
/** Get the layout data associated with the cell at (aRow,aCol)
* @return PR_NULL if there was an error, such as aRow or aCol being invalid
* otherwise, the data is returned.
*/
virtual nsCellLayoutData * GetCellLayoutData(nsTableCellFrame *aCell);
/**
* DEBUG METHOD
*
*/
virtual void ListColumnLayoutData(FILE* out = stdout, PRInt32 aIndent = 0) const;
//virtual void ListColumnLayoutData(FILE* out = stdout, PRInt32 aIndent = 0) const;
/** return the width of the column at aColIndex */
@ -236,11 +188,6 @@ protected:
/** destructor, responsible for mColumnLayoutData and mColumnWidths */
virtual ~nsTableFrame();
/** helper method to delete contents of mColumnLayoutData
* should be called with care (ie, only by destructor)
*/
virtual void DeleteColumnLayoutData();
/** first pass of ResizeReflow.
* lays out all table content with aMaxSize(NS_UNCONSTRAINEDSIZE,NS_UNCONSTRAINEDSIZE) and
* a non-null aMaxElementSize so we get all the metrics we need to do column balancing.
@ -380,6 +327,16 @@ protected:
*/
virtual void ResetCellMap ();
/** for debugging only
* prints out information about the cell map
*/
void DumpCellMap() const;
/** for debugging only
* prints out info about the table layout state, printing columns and their cells
*/
void ListColumnLayoutData(FILE* out, PRInt32 aIndent) const;
/** ResetColumns is called when the column structure of the table is changed.
* Call with caution, only when adding or removing columns, changing
* column attributes, changing the rowspan or colspan attribute of a cell, etc.
@ -418,13 +375,6 @@ protected:
*/
virtual nsTableRowGroupFrame* NextRowGroupFrame (nsTableRowGroupFrame*);
/** returns the number of rows in this table.
* if mCellMap has been created, it is asked for the number of rows.<br>
* otherwise, the content is enumerated and the rows are counted.
*/
virtual PRInt32 GetRowCount();
/** return the number of columns as specified by the input.
* has 2 side effects:<br>
* calls SetStartColumnIndex on each nsTableColumn<br>
@ -432,9 +382,18 @@ protected:
*/
virtual PRInt32 GetSpecifiedColumnCount ();
public:
virtual void DumpCellMap() const;
virtual nsCellMap* GetCellMap() const;
public: /* ----- Cell Map public methods ----- */
/** returns the number of rows in this table.
* if mCellMap has been created, it is asked for the number of rows.<br>
* otherwise, the content is enumerated and the rows are counted.
*/
virtual PRInt32 GetRowCount();
nsTableColFrame * GetColFrame(PRInt32 aColIndex);
nsTableCellFrame * GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex);
private:
@ -446,9 +405,7 @@ private:
*/
enum {kPASS_UNDEFINED=0, kPASS_FIRST=1, kPASS_SECOND=2, kPASS_THIRD=3, kPASS_INCREMENTAL=4};
nsVoidArray *mColumnLayoutData; // array of array of cellLayoutData's
PRInt32 *mColumnWidths; // widths of each column
//TODO: move all column info into this object
ColumnInfoCache *mColCache; // cached information about the table columns
PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit
PRInt32 mPass; // which Reflow pass are we currently in?

View File

@ -20,7 +20,6 @@
#include "nsTableRowGroup.h"
#include "nsTableCell.h"
#include "nsTableFrame.h"
#include "nsCellLayoutData.h"
#include "nsHTMLParts.h"
#include "nsHTMLContainer.h"
#include "nsTableRowFrame.h"

View File

@ -25,8 +25,6 @@
#include "nsTableFrame.h"
#include "nsTableColFrame.h"
#include "nsTableCellFrame.h"
#include "nsCellLayoutData.h"
#include "nsColLayoutData.h"
#include "nsIView.h"
#include "nsIPtr.h"
#include "nsIReflowCommand.h"
@ -37,6 +35,7 @@ NS_DEF_PTR(nsIStyleContext);
static PRBool gsDebug1 = PR_FALSE;
static PRBool gsDebug2 = PR_FALSE;
//#define NOISY
//#define NOISY_FLOW
#else
static const PRBool gsDebug1 = PR_FALSE;
static const PRBool gsDebug2 = PR_FALSE;
@ -51,6 +50,9 @@ struct RowReflowState {
// The body's available size (computed from the body's parent)
nsSize availSize;
// the running x-offset
nscoord x;
// Height of tallest cell (excluding cells with rowspan > 1)
nscoord maxCellHeight; // just the height of the cell frame
nscoord maxCellVertSpace; // the maximum MAX(cellheight + topMargin + bottomMargin)
@ -68,6 +70,7 @@ struct RowReflowState {
maxCellHeight = 0;
maxCellVertSpace = 0;
tableFrame = aTableFrame;
x=0;
}
~RowReflowState() {
@ -111,12 +114,12 @@ nsTableRowFrame::DidReflow(nsIPresContext& aPresContext,
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(mRowIndex, cellFrame);
if (1==rowSpan)
{
// Resize the cell's height
// resize the cell's height
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
cellFrame->SizeTo(cellFrameSize.width, cellHeight);
// Realign cell content based on the new height
// realign cell content based on the new height
cellFrame->VerticallyAlignChild(&aPresContext);
}
@ -287,6 +290,9 @@ void nsTableRowFrame::PlaceChild(nsIPresContext* aPresContext,
// Place and size the child
aKidFrame->SetRect(aKidRect);
// update the running total for the row width
aState.x += aKidRect.width;
// Update the maximum element size
PRInt32 rowSpan = ((nsTableCellFrame*)aKidFrame)->GetRowSpan();
if (nsnull != aMaxElementSize)
@ -328,6 +334,8 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
NS_PRECONDITION(nsnull != mFirstChild, "no children");
nsSize kidMaxElementSize;
PRBool result = PR_TRUE;
PRInt32 prevColIndex = -1; // remember the col index of the previous cell to handle rowspans into this row
nsSize* pKidMaxElementSize = (nsnull != aDesiredSize.maxElementSize) ?
&kidMaxElementSize : nsnull;
nscoord maxCellTopMargin = 0;
@ -335,6 +343,13 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
// Reflow each of our existing cell frames
for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) {
nsSize kidAvailSize(aState.availSize);
if (0>=kidAvailSize.height)
kidAvailSize.height = 1; // XXX: HaCk - we don't handle negative heights yet
nsReflowMetrics desiredSize(pKidMaxElementSize);
desiredSize.width=desiredSize.height=desiredSize.ascent=desiredSize.descent=0;
// Get the frame's margins, and compare the top and bottom margin
// against our current max values
nsMargin kidMargin;
@ -344,15 +359,49 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
if (kidMargin.bottom > maxCellBottomMargin)
maxCellBottomMargin = kidMargin.bottom;
// Figure out the amount of available size for the child (subtract
// off the top margin we are going to apply to it)
//XXX TROY??? unconstrainedHeight was removed from aState, what should happen here?
/*
if (PR_FALSE == aState.unconstrainedHeight)
{
kidAvailSize.height -= kidMargin.top + kidMargin.bottom;
}
*/
// left and right margins already taken into account by table layout strategy
// Compute the x-origin for the child
//
// XXX Having to re-compute the value each time from scratch is very inefficent...
nscoord x = ComputeCellXOffset(aState, kidFrame, kidMargin);
// Compute the x-origin for the child, taking into account straddlers (cells from prior
// rows with rowspans > 1)
PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
if (prevColIndex != (cellColIndex-1))
{ // if this cell is not immediately adjacent to the previous cell, factor in missing col info
for (PRInt32 colIndex=prevColIndex+1; colIndex<cellColIndex; colIndex++)
{
aState.x += aState.tableFrame->GetColumnWidth(colIndex);
aState.x += kidMargin.left + kidMargin.right;
}
}
aState.x += kidMargin.left;
// at this point, we know the column widths.
// so we get the avail width from the known column widths
PRInt32 cellColSpan = ((nsTableCellFrame *)kidFrame)->GetColSpan();
nscoord availWidth = 0;
for (PRInt32 numColSpan=0; numColSpan<cellColSpan; numColSpan++)
{
availWidth += aState.tableFrame->GetColumnWidth(cellColIndex+numColSpan);
if (0<numColSpan)
{
availWidth += kidMargin.right;
if (0!=cellColIndex)
availWidth += kidMargin.left;
}
}
prevColIndex = cellColIndex + (cellColSpan-1); // remember the rightmost column this cell spans into
// Compute the cell available width from the column widths
nscoord availWidth = ComputeCellAvailWidth(aState, kidFrame);
// If the available width is the same as last time we reflowed the cell,
// then just use the previous desired size
@ -360,17 +409,16 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
// XXX Wouldn't it be cleaner (but slightly less efficient) for the row to
// just reflow the cell, and have the cell decide whether it could use the
// cached value rather than having the row make that determination?
nsReflowMetrics desiredSize(pKidMaxElementSize);
if (availWidth != ((nsTableCellFrame *)kidFrame)->GetPriorAvailWidth())
{
// Always let the cell be as high as it wants. We ignore the height that's
// passed in and always place the entire row. Let the row group decide
// whether we fit or wehther the entire row is pushed
nsSize kidAvailSize(availWidth, NS_UNCONSTRAINEDSIZE);
// Reflow the child
kidFrame->WillReflow(*aPresContext);
kidFrame->MoveTo(x, kidMargin.top);
kidFrame->MoveTo(aState.x, kidMargin.top);
kidAvailSize.width = availWidth;
nsReflowState kidReflowState(kidFrame, aState.reflowState, kidAvailSize,
eReflowReason_Resize);
@ -393,12 +441,12 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
}
else
{
nsSize priorSize = ((nsTableCellFrame *)kidFrame)->GetPriorDesiredSize();
nsSize priorSize = ((nsTableCellFrame *)kidFrame)->GetDesiredSize();
desiredSize.width = priorSize.width;
desiredSize.height = priorSize.height;
}
// Place the child after taking into account its margin and attributes
// Place the child after taking into account it's margin and attributes
nscoord specifiedHeight = 0;
nscoord cellHeight = desiredSize.height;
nsIStyleContextPtr kidSC;
@ -423,19 +471,20 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
// begin special Nav4 compatibility code
if (0==cellWidth)
{
PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
cellWidth = aState.tableFrame->GetColumnWidth(cellColIndex);
}
// end special Nav4 compatibility code
// Place the child
nsRect kidRect (x, kidMargin.top, cellWidth, cellHeight);
nsRect kidRect (aState.x, kidMargin.top, cellWidth, cellHeight);
PlaceChild(aPresContext, aState, kidFrame, kidRect, aDesiredSize.maxElementSize,
pKidMaxElementSize);
aState.x += kidMargin.right; // add in right margin only after cell has been placed
// Get the next child
kidFrame->GetNextSibling(kidFrame);
}
SetMaxChildHeight(aState.maxCellHeight,maxCellTopMargin, maxCellBottomMargin); // remember height of tallest child who doesn't have a row span
@ -448,42 +497,6 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
return NS_OK;
}
// Compute the x-origin for the child by summing up the width of each
// prior column. This correctly handles cells from prior rows with rowspans
// > 1
nscoord nsTableRowFrame::ComputeCellXOffset(const RowReflowState& aState,
nsIFrame* aKidFrame,
const nsMargin& aKidMargin) const
{
nscoord x = aKidMargin.left;
PRInt32 cellColIndex = ((nsTableCellFrame *)aKidFrame)->GetColIndex();
for (PRInt32 colIndex = 0; colIndex < cellColIndex; colIndex++)
{
x += aState.tableFrame->GetColumnWidth(colIndex);
}
return x;
}
// Computes the avail width for the cell. Takes into account column
// spans
nscoord nsTableRowFrame::ComputeCellAvailWidth(const RowReflowState& aState,
nsIFrame* aKidFrame) const
{
nscoord availWidth = 0;
nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCellFrame *)aKidFrame);
PRInt32 cellStartingCol = ((nsTableCellFrame *)aKidFrame)->GetColIndex();
PRInt32 cellColSpan = ((nsTableCellFrame *)aKidFrame)->GetColSpan();
for (PRInt32 numColSpan = 0; numColSpan < cellColSpan; numColSpan++)
{
availWidth += aState.tableFrame->GetColumnWidth(cellStartingCol + numColSpan);
}
return availWidth;
}
/**
* Called for the initial reflow. Creates each table cell frame, and
* reflows it to gets its minimum and maximum sizes
@ -570,13 +583,10 @@ nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext,
kidFrame->WillReflow(*aPresContext);
status = ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState);
((nsTableCellFrame *)kidFrame)->SetPass1DesiredSize(kidSize);
((nsTableCellFrame *)kidFrame)->SetPass1MaxElementSize(kidMaxElementSize);
NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "unexpected child reflow status");
// Allocate and set the cell layout data
nsCellLayoutData *kidLayoutData = new nsCellLayoutData((nsTableCellFrame *)kidFrame,
&kidSize, &kidMaxElementSize);
((nsTableCellFrame *)kidFrame)->SetCellLayoutData(kidLayoutData);
if (gsDebug1)
{
printf("reflow of cell returned result = %s with desired=%d,%d, min = %d,%d\n",
@ -630,13 +640,12 @@ nsresult nsTableRowFrame::RecoverState(RowReflowState& aState,
for (nsIFrame* frame = mFirstChild; frame != aKidFrame;) {
PRInt32 rowSpan = ((nsTableCellFrame*)frame)->GetRowSpan();
if (mMinRowSpan == rowSpan) {
// XXX This isn't quite right. We also need to check whether the cell
// has a height property that affects the cell...
nsSize desiredSize = ((nsTableCellFrame *)frame)->GetPriorDesiredSize();
nsRect rect;
frame->GetRect(rect);
// Update maxCellHeight
if (desiredSize.height > aState.maxCellHeight) {
aState.maxCellHeight = desiredSize.height;
if (rect.height > aState.maxCellHeight) {
aState.maxCellHeight = rect.height;
}
// Update maxCellVertHeight
@ -644,18 +653,14 @@ nsresult nsTableRowFrame::RecoverState(RowReflowState& aState,
if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, margin) == NS_OK)
{
nscoord height = desiredSize.height + margin.top + margin.bottom;
nscoord height = rect.height + margin.top + margin.bottom;
if (height > aState.maxCellVertSpace) {
aState.maxCellVertSpace = height;
}
}
}
// XXX We also need to recover the max element size if requested by the
// caller...
//
// We should be using GetReflowMetrics() to get information from the
// table cell, and that will include the max element size...
// XXX We also need to recover the max element size...
// Remember the frame that precedes aKidFrame
prevKidFrame = frame;
@ -687,20 +692,30 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
// Recover our reflow state
RecoverState(aState, kidFrame);
// Get the frame's margins
// Figure out the amount of available space for the child
nsMargin kidMargin;
aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame,kidMargin);
// Figure out the amount of available space for the child
// XXX Shakey...
nsSize kidAvailSize(aState.availSize);
nsSize kidAvailSize(aState.availSize); // XXX: top and bottom margins?
// Compute the x-origin for the child, taking into account straddlers (cells
// from prior rows with rowspans > 1)
nscoord x = ComputeCellXOffset(aState, kidFrame, kidMargin);
// Compute the x-origin for the child, taking into account straddlers (cells from prior
// rows with rowspans > 1)
nscoord x = kidMargin.left;
PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
for (PRInt32 colIndex=0; colIndex<cellColIndex; colIndex++)
{
x += aState.tableFrame->GetColumnWidth(colIndex);
}
// Compute the cell avail width from the column widths
nscoord availWidth = ComputeCellAvailWidth(aState, kidFrame);
// at this point, we know the column widths.
// so we get the avail width from the known column widths
PRInt32 cellStartingCol = ((nsTableCellFrame *)kidFrame)->GetColIndex();
PRInt32 cellColSpan = ((nsTableCellFrame *)kidFrame)->GetColSpan();
nscoord availWidth = 0;
for (PRInt32 numColSpan=0; numColSpan<cellColSpan; numColSpan++)
availWidth += aState.tableFrame->GetColumnWidth(cellStartingCol+numColSpan);
kidAvailSize.width = availWidth;
// Pass along the reflow command. Reflow the child with an unconstrained
@ -726,23 +741,16 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
kidReflowState.maxSize.width = NS_UNCONSTRAINEDSIZE;
status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState);
// Update the cell layout data. Note that we need to do this for both
// the data the cell maintains AND the data the table maintains...
nsCellLayoutData *kidLayoutData = ((nsTableCellFrame *)kidFrame)->GetCellLayoutData();
kidLayoutData->SetDesiredSize(&desiredSize);
kidLayoutData->SetMaxElementSize(&kidMaxElementSize);
kidLayoutData = aState.tableFrame->GetCellLayoutData((nsTableCellFrame*)kidFrame);
kidLayoutData->SetDesiredSize(&desiredSize);
kidLayoutData->SetMaxElementSize(&kidMaxElementSize);
// Update the cell layout data.
((nsTableCellFrame *)kidFrame)->SetPass1DesiredSize(desiredSize);
((nsTableCellFrame *)kidFrame)->SetPass1MaxElementSize(kidMaxElementSize);
// Now reflow the cell again this time constraining the width
// XXX Ignore for now the possibility that the column width has changed...
kidReflowState.maxSize.width = availWidth;
status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState);
// Place the child after taking into account its margin and attributes
// Place the child after taking into account it's margin and attributes
nscoord specifiedHeight = 0;
nscoord cellHeight = desiredSize.height;
nsIStyleContextPtr kidSC;
@ -767,7 +775,6 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
// begin special Nav4 compatibility code
if (0==cellWidth)
{
PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
cellWidth = aState.tableFrame->GetColumnWidth(cellColIndex);
}
// end special Nav4 compatibility code
@ -781,8 +788,8 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
// Now iterate over the remaining cells, and update our max cell
// height and our running x-offset
//
// We don't have to re-position the x-origin of any of the child frames
// that follow, because the column width hasn't changed...
// We don't have to re-position any of the child frames that follow, because
// the column width hasn't changed...
nscoord maxCellTopMargin = 0;
nscoord maxCellBottomMargin = 0;
kidFrame->GetNextSibling((nsIFrame*&)kidFrame);
@ -791,11 +798,9 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
nsRect rect;
kidFrame->GetRect(rect);
if (mMinRowSpan == rowSpan) {
nsSize desiredSize = ((nsTableCellFrame *)kidFrame)->GetPriorDesiredSize();
// Update maxCellHeight
if (desiredSize.height > aState.maxCellHeight) {
aState.maxCellHeight = desiredSize.height;
if (rect.height > aState.maxCellHeight) {
aState.maxCellHeight = rect.height;
}
// Update maxCellVertHeight
@ -803,7 +808,7 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, margin) == NS_OK)
{
nscoord height = desiredSize.height + margin.top + margin.bottom;
nscoord height = rect.height + margin.top + margin.bottom;
if (height > aState.maxCellVertSpace) {
aState.maxCellVertSpace = height;
}
@ -899,16 +904,22 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
return result;
}
NS_METHOD
nsTableRowFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
nsIFrame* aParent,
nsIStyleContext* aStyleContext,
nsIFrame*& aContinuingFrame)
{
// Because rows are always complete we should never be asked to create
// a continuing frame
NS_ERROR("Unexpected request");
return NS_ERROR_NOT_IMPLEMENTED;
if (gsDebug1==PR_TRUE) printf("nsTableRowFrame::CreateContinuingFrame\n");
nsTableRowFrame* cf = new nsTableRowFrame(mContent, aParent);
if (nsnull == cf) {
return NS_ERROR_OUT_OF_MEMORY;
}
PrepareContinuingFrame(aPresContext, aParent, aStyleContext, cf);
aContinuingFrame = cf;
return NS_OK;
}
nsresult nsTableRowFrame::NewFrame( nsIFrame** aInstancePtrResult,

View File

@ -29,13 +29,11 @@
#include "nsIReflowCommand.h"
#ifdef NS_DEBUG
static PRBool gsDebug1 = PR_FALSE;
static PRBool gsDebug2 = PR_FALSE;
static PRBool gsDebug = PR_FALSE;
//#define NOISY
//#define NOISY_FLOW
#else
static const PRBool gsDebug1 = PR_FALSE;
static const PRBool gsDebug2 = PR_FALSE;
static const PRBool gsDebug = PR_FALSE;
#endif
NS_DEF_PTR(nsIStyleContext);
@ -195,7 +193,7 @@ void nsTableRowGroupFrame::PlaceChild( nsIPresContext* aPresContext,
nsSize* aMaxElementSize,
nsSize& aKidMaxElementSize)
{
if (PR_TRUE==gsDebug1)
if (PR_TRUE==gsDebug)
printf ("rowgroup: placing row at %d, %d, %d, %d\n",
aKidRect.x, aKidRect.y, aKidRect.width, aKidRect.height);
@ -256,7 +254,7 @@ PRBool nsTableRowGroupFrame::ReflowMappedChildren( nsIPresContext* aPresCon
#endif
#endif
NS_PRECONDITION(nsnull != mFirstChild, "no children");
if (gsDebug) printf("\n\nREFLOWMAPPED FOR ROW GROUP FRAME\n");
PRInt32 childCount = 0;
nsIFrame* prevKidFrame = nsnull;
@ -1039,7 +1037,7 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
const nsReflowState& aReflowState,
nsReflowStatus& aStatus)
{
if (gsDebug1==PR_TRUE)
if (gsDebug==PR_TRUE)
printf("nsTableRowGroupFrame::Reflow - aMaxSize = %d, %d\n",
aReflowState.maxSize.width, aReflowState.maxSize.height);
#ifdef NS_DEBUG
@ -1153,7 +1151,7 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
PostReflowCheck(aStatus);
#endif
if (gsDebug1==PR_TRUE)
if (gsDebug==PR_TRUE)
{
if (nsnull!=aDesiredSize.maxElementSize)
printf("nsTableRowGroupFrame::RR returning: %s with aDesiredSize=%d,%d, aMES=%d,%d\n",
@ -1181,7 +1179,7 @@ nsTableRowGroupFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
return NS_ERROR_OUT_OF_MEMORY;
}
PrepareContinuingFrame(aPresContext, aParent, aStyleContext, cf);
if (PR_TRUE==gsDebug1) printf("nsTableRowGroupFrame::CCF parent = %p, this=%p, cf=%p\n", aParent, this, cf);
if (PR_TRUE==gsDebug) printf("nsTableRowGroupFrame::CCF parent = %p, this=%p, cf=%p\n", aParent, this, cf);
aContinuingFrame = cf;
return NS_OK;
}

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;
}
}
}

View File

@ -23,6 +23,7 @@
#include "nsITableLayoutStrategy.h"
#include "nsCoord.h"
class nsVoidArray;
class nsTableFrame;
struct nsStylePosition;
@ -164,18 +165,31 @@ public:
nscoord aMinTableWidth,
nscoord aMaxTableWidth);
/** 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);
/** starting with a partially balanced table, compute the amount
* of space to pad each column by to completely balance the table.
* set the column widths in mTableFrame based on these computations.
*
* @param aTableFixedWidth the specified width of the table. If there is none,
* this param is 0
* @param aComputedTableWidth the width of the table before this final step.
* @param aAvailWidth the space still to be allocated within the table
* @param aTableWidth the sum of all columns widths
* @param aWidthOfFixedTableColumns the sum of the widths of fixed-width columns
* @param aColWidths the effective column widths (ignoring col span cells)
*
* @return void
*/
virtual void DistributeExcessSpace(nscoord aTableFixedWidth,
nscoord aComputedTableWidth,
virtual void DistributeExcessSpace(nscoord aAvailWidth,
nscoord aTableWidth,
nscoord aWidthOfFixedTableColumns,
nscoord *aColWidths);
/** starting with a partially balanced table, compute the amount
@ -193,6 +207,11 @@ public:
nscoord *aMinColWidths,
nscoord *aMaxColWidths);
/** 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);
/** return true if the style indicates that the width is a specific width
* for the purposes of column width determination.
* return false if the width changes based on content, parent size, etc.

View File

@ -15,7 +15,9 @@
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsCRT.h"
#include "nsVoidArray.h"
#include "nsCellMap.h"
#include "nsTableFrame.h"
@ -25,38 +27,50 @@ static PRBool gsDebug1 = PR_FALSE;
static const PRBool gsDebug1 = PR_FALSE;
#endif
static PRInt32 gBytesPerPointer = sizeof(PRInt32);
static const PRInt32 gBytesPerPointer = sizeof(PRInt32);
nsCellMap::nsCellMap(int aRows, int aColumns)
: mRowCount(aRows),
mColCount(aColumns)
{
mCells = nsnull;
mColFrames = nsnull;
Reset(aRows, aColumns);
}
nsCellMap::~nsCellMap()
{
for (int i=0;i<mRowCount;i++)
if (nsnull!=mCells)
{
for (int j=0;j<mColCount;j++)
for (int i=0;i<mRowCount;i++)
{
int index = (i*mColCount)+j;
CellData* data = (CellData*)mCells[index];
if (data != nsnull)
for (int j=0;j<mColCount;j++)
{
delete data;
mCells[index] = 0;
}
}
int index = (i*mColCount)+j;
CellData* data = (CellData*)mCells[index];
if (data != nsnull)
{
delete data;
mCells[index] = 0;
}
}
}
delete [] mCells;
}
delete [] mCells;
if (nsnull!= mColFrames)
delete mColFrames;
mCells = nsnull;
mColFrames = nsnull;
};
void nsCellMap::Reset(int aRows, int aColumns)
{
if (nsnull==mColFrames)
{
mColFrames = new nsVoidArray();
}
// needs to be more efficient, to reuse space if possible
if (nsnull!=mCells)
{
@ -67,6 +81,7 @@ void nsCellMap::Reset(int aRows, int aColumns)
mColCount = aColumns;
mCells = new PRInt32 [mRowCount*mColCount*gBytesPerPointer];
nsCRT::memset (mCells, 0, (mRowCount*mColCount)*gBytesPerPointer);
}
void nsCellMap::GrowTo(int aColCount)
@ -110,4 +125,9 @@ void nsCellMap::SetCellAt(CellData *aCell, int aRow, int aColumn)
mCells[index] = (PRInt32)aCell;
}
nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex)
{
return (nsTableColFrame *)(mColFrames->ElementAt(aColIndex));
}

View File

@ -19,8 +19,11 @@
#define nsCellMap_h__
#include "nscore.h"
#include "CellData.h"
class CellData;
class nsVoidArray;
class nsTableColFrame;
class nsTableCellFrame;
/** nsCellMap is a support class for nsTablePart.
* It maintains an Rows x Columns grid onto which the cells of the table are mapped.
@ -40,55 +43,94 @@ protected:
/** storage for CellData pointers */
PRInt32 *mCells; ///XXX CellData *?
/** a cache of the column frames, by col index */
nsVoidArray * mColFrames;
/** the number of rows */
int mRowCount; // in java, we could just do fCellMap.length;
PRInt32 mRowCount; // in java, we could just do fCellMap.length;
/** the number of columns (the max of all row lengths) */
int mColCount; // in java, we could just do fCellMap[i].length
PRInt32 mColCount;
public:
nsCellMap(int aRows, int aColumns);
nsCellMap(PRInt32 aRows, PRInt32 aColumns);
// NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
~nsCellMap();
/** initialize the CellMap to (aRows x aColumns) */
void Reset(int aRows, int aColumns);
void Reset(PRInt32 aRows, PRInt32 aColumns);
/** return the CellData for the cell at (aRow,aColumn) */
CellData * GetCellAt(int aRow, int aColumn) const;
/** return the CellData for the cell at (aRowIndex,aColIndex) */
CellData * GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const;
/** return the nsTableCellFrame for the cell at (aRowIndex, aColIndex) */
nsTableCellFrame * GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex) const;
/** assign aCellData to the cell at (aRow,aColumn) */
void SetCellAt(CellData *aCellData, int aRow, int aColumn);
void SetCellAt(CellData *aCellData, PRInt32 aRow, PRInt32 aColumn);
/** expand the CellMap to have aColCount columns. The number of rows remains the same */
void GrowTo(int aColCount);
void GrowTo(PRInt32 aColCount);
/** return the total number of columns in the table represented by this CellMap */
int GetColCount() const;
PRInt32 GetColCount() const;
/** return the total number of rows in the table represented by this CellMap */
int GetRowCount() const;
PRInt32 GetRowCount() const;
/** for debugging, print out this CellMap */
nsTableColFrame * GetColumnFrame(PRInt32 aColIndex);
void AppendColumnFrame(nsTableColFrame *aColFrame);
PRBool RowImpactedBySpanningCell(PRInt32 aRowIndex);
PRBool ColumnImpactedBySpanningCell(PRInt32 aColIndex);
/** for debugging */
void DumpCellMap() const;
};
inline CellData * nsCellMap::GetCellAt(int aRow, int aColumn) const
/* ----- inline methods ----- */
inline CellData * nsCellMap::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const
{
int index = (aRow*mColCount)+aColumn;
NS_PRECONDITION(0<=aRowIndex && aRowIndex < mRowCount, "bad aRowIndex arg");
NS_PRECONDITION(0<=aColIndex && aColIndex < mColCount, "bad aColIndex arg");
PRInt32 index = (aRowIndex*mColCount)+aColIndex;
return (CellData *)mCells[index];
}
inline int nsCellMap::GetColCount() const
inline nsTableCellFrame * nsCellMap::GetCellFrameAt(PRInt32 aRowIndex, PRInt32 aColIndex) const
{
NS_PRECONDITION(0<=aRowIndex && aRowIndex < mRowCount, "bad aRowIndex arg");
NS_PRECONDITION(0<=aColIndex && aColIndex < mColCount, "bad aColIndex arg");
nsTableCellFrame *result = nsnull;
CellData * cellData = GetCellAt(aRowIndex, aColIndex);
if (nsnull!=cellData)
result = cellData->mCell;
return result;
}
inline PRInt32 nsCellMap::GetColCount() const
{
return mColCount;
}
inline int nsCellMap::GetRowCount() const
inline PRInt32 nsCellMap::GetRowCount() const
{
return mRowCount;
}
inline void nsCellMap::AppendColumnFrame(nsTableColFrame *aColFrame)
{
mColFrames->AppendElement(aColFrame);
// sanity check
NS_ASSERTION(mColFrames->Count()<=mColCount, "too many columns appended to CellMap");
}
#endif

View File

@ -16,7 +16,6 @@
* Reserved.
*/
#include "nsTableCellFrame.h"
#include "nsCellLayoutData.h"
#include "nsBodyFrame.h"
#include "nsIReflowCommand.h"
#include "nsIStyleContext.h"
@ -53,21 +52,24 @@ static const PRBool gsDebugNT = PR_FALSE;
*/
nsTableCellFrame::nsTableCellFrame(nsIContent* aContent,
nsIFrame* aParentFrame)
: nsContainerFrame(aContent, aParentFrame),
mCellLayoutData(nsnull)
: nsContainerFrame(aContent, aParentFrame)
{
mRowSpan=1;
mColSpan=1;
mColIndex=0;
mPriorAvailWidth=0;
mPriorDesiredSize.width=0;
mPriorDesiredSize.height=0;
mDesiredSize.width=0;
mDesiredSize.height=0;
mMaxElementSize.width=0;
mMaxElementSize.height=0;
mPass1DesiredSize.width=0;
mPass1DesiredSize.height=0;
mPass1MaxElementSize.width=0;
mPass1MaxElementSize.height=0;
}
nsTableCellFrame::~nsTableCellFrame()
{
if (nsnull!=mCellLayoutData)
delete mCellLayoutData;
}
NS_METHOD nsTableCellFrame::Paint(nsIPresContext& aPresContext,
@ -291,7 +293,6 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
mFirstChild->WillReflow(*aPresContext);
mFirstChild->MoveTo(leftInset, topInset);
aStatus = ReflowChild(mFirstChild, aPresContext, kidSize, kidReflowState);
SetPriorDesiredSize(kidSize);
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugNT)
{
@ -325,10 +326,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
// first, compute the height
// the height can be set w/o being restricted by aMaxSize.height
nscoord cellHeight = kidSize.height;
if (NS_UNCONSTRAINEDSIZE!=aReflowState.maxSize.height)
{
cellHeight += topInset + bottomInset;
}
cellHeight += topInset + bottomInset;
if (PR_TRUE==gsDebugNT)
printf(" %p cellFrame height set to %d from kidSize=%d and insets %d,%d\n",
this, cellHeight, kidSize.height, topInset, bottomInset);
@ -369,6 +367,9 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
aDesiredSize.maxElementSize->height += topInset + bottomInset;
aDesiredSize.maxElementSize->width += leftInset + rightInset;
}
SetDesiredSize(aDesiredSize);
if (nsnull!=aDesiredSize.maxElementSize)
SetMaxElementSize(*(aDesiredSize.maxElementSize));
if (PR_TRUE==gsDebug || PR_TRUE==gsDebugNT)
printf(" %p cellFrame returning aDesiredSize=%d,%d\n",
@ -590,6 +591,505 @@ nsresult nsTableCellFrame::NewFrame(nsIFrame** aInstancePtrResult,
}
/* ----- methods from CellLayoutData ----- */
/**
* Given a frame and an edge, find the margin
*
**/
nscoord nsTableCellFrame::GetMargin(nsIFrame* aFrame, PRUint8 aEdge) const
{
nscoord result = 0;
if (aFrame)
{
const nsStyleSpacing* spacing;
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
nsMargin margin;
spacing->CalcMarginFor(aFrame, margin);
switch (aEdge)
{
case NS_SIDE_TOP:
result = margin.top;
break;
case NS_SIDE_RIGHT:
result = margin.right;
break;
case NS_SIDE_BOTTOM:
result = margin.bottom;
break;
case NS_SIDE_LEFT:
result = margin.left;
break;
}
}
return result;
}
/**
* Given a style context and an edge, find the border width
*
**/
nscoord nsTableCellFrame::GetBorderWidth(nsIFrame* aFrame, PRUint8 aEdge) const
{
nscoord result = 0;
if (aFrame)
{
const nsStyleSpacing* spacing;
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
nsMargin border;
spacing->CalcBorderFor(aFrame, border);
switch (aEdge)
{
case NS_SIDE_TOP:
result = border.top;
break;
case NS_SIDE_RIGHT:
result = border.right;
break;
case NS_SIDE_BOTTOM:
result = border.bottom;
break;
case NS_SIDE_LEFT:
result = border.left;
break;
}
}
return result;
}
/**
* Given a style context and an edge, find the padding
*
**/
nscoord nsTableCellFrame::GetPadding(nsIFrame* aFrame, PRUint8 aEdge) const
{
nscoord result = 0;
if (aFrame)
{
const nsStyleSpacing* spacing;
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
nsMargin padding;
spacing->CalcPaddingFor(aFrame, padding);
switch (aEdge)
{
case NS_SIDE_TOP:
result = padding.top;
break;
case NS_SIDE_RIGHT:
result = padding.right;
break;
case NS_SIDE_BOTTOM:
result = padding.bottom;
break;
case NS_SIDE_LEFT:
result = padding.left;
break;
}
}
return result;
}
/**
* Given an Edge, find the opposing edge (top<-->bottom, left<-->right)
*
**/
PRUint8 nsTableCellFrame::GetOpposingEdge(PRUint8 aEdge)
{
PRUint8 result;
switch (aEdge)
{
case NS_SIDE_LEFT:
result = NS_SIDE_RIGHT;
break;
case NS_SIDE_RIGHT:
result = NS_SIDE_LEFT;
break;
case NS_SIDE_TOP:
result = NS_SIDE_BOTTOM;
break;
case NS_SIDE_BOTTOM:
result = NS_SIDE_TOP;
break;
default:
result = NS_SIDE_TOP;
}
return result;
}
/*
*
* Determine border style for two cells.
*
1.If the adjacent elements are of the same type, the wider of the two borders is used.
"Wider" takes into account the border-style of 'none', so a "1px solid" border
will take precedence over a "20px none" border.
2.If there are two or more with the same width, but different style,
then the one with a style near the start of the following list will be drawn:
'blank', 'double', 'solid', 'dashed', 'dotted', 'ridge', 'groove', 'none'
3.If the borders are of the same width, the border on the element occurring first is used.
First is defined as aStyle for this method.
NOTE: This assumes left-to-right, top-to-bottom bias. -- gpk
*
*/
nsIFrame* nsTableCellFrame::CompareCellBorders(nsIFrame* aFrame1,
PRUint8 aEdge1,
nsIFrame* aFrame2,
PRUint8 aEdge2)
{
PRInt32 width1 = GetBorderWidth(aFrame1,aEdge1);
PRInt32 width2 = GetBorderWidth(aFrame2,aEdge2);
nsIFrame* result = nsnull;
if (width1 > width2)
result = aFrame1;
else if (width1 < width2)
result = aFrame2;
else // width1 == width2
{
const nsStyleSpacing* border1;
const nsStyleSpacing* border2;
aFrame1->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)border1);
aFrame2->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)border2);
if (border1->mBorderStyle[aEdge1] >= border2->mBorderStyle[aEdge2])
result = aFrame1;
else
result = aFrame2;
}
return result;
}
/**
* Given a List of cell layout data, compare the edges to see which has the
* border with the highest precidence.
*
**/
nsIFrame* nsTableCellFrame::FindHighestPrecedentBorder(nsVoidArray* aList,
PRUint8 aEdge)
{
nsIFrame* result = nsnull;
PRInt32 index = 0;
PRInt32 count = 0;
NS_ASSERTION(aList,"a List must be valid");
count = aList->Count();
if (count)
{
nsIFrame* frame1;
nsIFrame* frame2;
frame1 = (nsIFrame*)(aList->ElementAt(index++));
while (index < count)
{
frame2 = (nsIFrame*)(aList->ElementAt(index++));
if (GetMargin(frame2,aEdge) == 0) {
frame1 = CompareCellBorders(frame1, aEdge, frame2, aEdge);
}
}
if ((nsnull != frame1) && (GetMargin(frame1, aEdge) != 0))
result = frame1;
}
return result;
}
nsIFrame* nsTableCellFrame::FindInnerBorder(nsVoidArray* aList, PRUint8 aEdge)
{
nsIFrame* result = nsnull;
PRUint8 opposite = GetOpposingEdge(aEdge);
if (GetMargin(this, aEdge) == 0)
{
nsIFrame* altFrame = FindHighestPrecedentBorder(aList,opposite);
if (nsnull != altFrame)
result = CompareCellBorders(this, aEdge, altFrame, opposite);
else
result = this;
}
return result;
}
/*
*
* FindRelevantBorder recursively searches up the frame hierarchy for the border
* style that is applicable to the cell. If at any point the frame has a margin
* or the parent frame has padding, then the outer frame for this object takes
* presendence over the inner frame.
1.Borders on 'table' elements take precedence over borders on any other table elements.
2.Borders on 'row-groups' take precedence over borders on 'rows',
and likewise borders on 'column-groups' take precedence over borders on 'columns'.
3.Borders on any other type of table element take precedence over 'table-cell' elements.
*
* NOTE: This method assumes that the table cell potentially shares a border.
* It should not be called for internal cells
*
* NOTE: COLUMNS AND COLGROUPS NEED TO BE FIGURED INTO THE ALGORITHM -- GPK!!!
*
*
*/
nsIFrame* nsTableCellFrame::FindOuterBorder( nsTableFrame* aTableFrame,
PRUint8 aEdge)
{
nsIFrame* frame = this; // By default, return our frame
PRBool done = PR_FALSE;
// The table frame is the outer most frame we test against
while (done == PR_FALSE)
{
done = PR_TRUE; // where done unless the frame's margin is zero
// and the parent's padding is zero
nscoord margin = GetMargin(frame,aEdge);
// if the margin for this style is zero then check to see if the paddding
// for the parent frame is also zero
if (margin == 0)
{
nsIFrame* parentFrame;
frame->GetGeometricParent(parentFrame);
// if the padding for the parent style is zero just
// recursively call this routine
PRInt32 padding = GetPadding(parentFrame,aEdge);
if ((nsnull != parentFrame) && (padding == 0))
{
frame = parentFrame;
// If this frame represents the table frame then
// the table style is used
done = PRBool(frame != (nsIFrame*)aTableFrame);
continue;
}
}
}
return frame;
}
/*
Border Resolution
1.Borders on 'table' elements take precedence over borders on any other table elements.
2.Borders on 'row-groups' take precedence over borders on 'rows', and likewise borders on 'column-groups' take
precedence over borders on 'columns'.
3.Borders on any other type of table element take precedence over 'table-cell' elements.
4.If the adjacent elements are of the same type, the wider of the two borders is used. "Wider" takes into account
the border-style of 'none', so a "1px solid" border will take precedence over a "20px none" border.
5.If the borders are of the same width, the border on the element occurring first is used.
How to compare
1.Those of the one or two cells that have an edge here.
Less than two can occur at the edge of the table, but also
at the edges of "holes" (unoccupied grid cells).
2.Those of the columns that have an edge here.
3.Those of the column groups that have an edge here.
4.Those of the rows that have an edge here.
5.Those of the row groups that have an edge here.
6.Those of the table, if this is the edge of the table.
*
* @param aIsFirst -- TRUE if this is the first cell in the row
* @param aIsLast -- TRUE if this is the last cell in the row
* @param aIsTop -- TRUE if this is the top cell in the column
* @param aIsBottom -- TRUE if this is the last cell in the column
*/
nsIFrame* nsTableCellFrame::FindBorderFrame(nsTableFrame* aTableFrame,
nsVoidArray* aList,
PRUint8 aEdge)
{
nsIFrame* frame = nsnull;
if (aList && aList->Count() == 0)
frame = FindOuterBorder(aTableFrame, aEdge);
else
frame = FindInnerBorder(aList, aEdge);
if (! frame)
frame = this;
return frame;
}
/**
* Given a List of cell layout data, compare the edges to see which has the
* border with the highest precidence.
*
**/
nscoord nsTableCellFrame::FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge)
{
nscoord result = 0;
PRInt32 index = 0;
PRInt32 count = 0;
NS_ASSERTION(aList,"a List must be valid");
count = aList->Count();
if (count)
{
nsIFrame* frame;
nscoord value = 0;
while (index < count)
{
frame = (nsIFrame*)(aList->ElementAt(index++));
value = GetMargin(frame, aEdge);
if (value > result)
result = value;
}
}
return result;
}
void nsTableCellFrame::CalculateMargins(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4])
{
// By default the margin is just the margin found in the
// table cells style
const nsStyleSpacing* spacing;
GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
spacing->CalcMarginFor(this, mMargin);
// Left and Top Margins are collapsed with their neightbors
// Right and Bottom Margins are simple left as they are
nscoord value;
// The left and top sides margins are the difference between
// their inherint value and the value of the margin of the
// object to the left or right of them.
value = FindLargestMargin(aBoundaryCells[NS_SIDE_LEFT],NS_SIDE_RIGHT);
if (value > mMargin.left)
mMargin.left = 0;
else
mMargin.left -= value;
value = FindLargestMargin(aBoundaryCells[NS_SIDE_TOP],NS_SIDE_BOTTOM);
if (value > mMargin.top)
mMargin.top = 0;
else
mMargin.top -= value;
}
void nsTableCellFrame::RecalcLayoutData(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4])
{
CalculateBorders(aTableFrame, aBoundaryCells);
CalculateMargins(aTableFrame, aBoundaryCells);
mCalculated = NS_OK;
}
#if 0 //QQQ
void nsTableCellFrame::List(FILE* out, PRInt32 aIndent) const
{
PRInt32 indent;
nsIContent* cell;
this->GetContent(cell);
if (cell != nsnull)
{
/*
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
fprintf(out,"RowSpan = %d ColSpan = %d \n",cell->GetRowSpan(),cell->GetColSpan());
*/
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
fprintf(out,"Margin -- Top: %d Left: %d Bottom: %d Right: %d \n",
NS_TWIPS_TO_POINTS_INT(mMargin.top),
NS_TWIPS_TO_POINTS_INT(mMargin.left),
NS_TWIPS_TO_POINTS_INT(mMargin.bottom),
NS_TWIPS_TO_POINTS_INT(mMargin.right));
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
nscoord top,left,bottom,right;
top = (mBorderFrame[NS_SIDE_TOP] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_TOP], NS_SIDE_TOP) : 0);
left = (mBorderFrame[NS_SIDE_LEFT] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_LEFT], NS_SIDE_LEFT) : 0);
bottom = (mBorderFrame[NS_SIDE_BOTTOM] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_BOTTOM], NS_SIDE_BOTTOM) : 0);
right = (mBorderFrame[NS_SIDE_RIGHT] ? GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_RIGHT], NS_SIDE_RIGHT) : 0);
fprintf(out,"Border -- Top: %d Left: %d Bottom: %d Right: %d \n",
NS_TWIPS_TO_POINTS_INT(top),
NS_TWIPS_TO_POINTS_INT(left),
NS_TWIPS_TO_POINTS_INT(bottom),
NS_TWIPS_TO_POINTS_INT(right));
cell->List(out,aIndent);
NS_RELEASE(cell);
}
}
#endif
/* ----- debug only methods, to be removed ----- */
// For Debugging ONLY
NS_METHOD nsTableCellFrame::MoveTo(nscoord aX, nscoord aY)
{

View File

@ -21,8 +21,8 @@
#include "nscore.h"
#include "nsContainerFrame.h"
#include "nsTableFrame.h"
#include "nsTableRowFrame.h" // need to actually include this here to inline GetRowIndex
class nsCellLayoutData;
struct nsStyleSpacing;
/* eb42f7b0-079e-11d2-8f37-006008159b0c */
@ -72,34 +72,124 @@ public:
/** return the mapped cell's row span. Always >= 1. */
virtual PRInt32 GetRowSpan();
// there is no set row index because row index depends on the cell's parent row only
/** return the mapped cell's row index (starting at 0 for the first row) */
virtual PRInt32 GetRowIndex();
/** return the mapped cell's col span. Always >= 1. */
virtual PRInt32 GetColSpan();
/** return the mapped cell's column index (starting at 0 for the first column) */
virtual PRInt32 GetColIndex();
/** set the index of the column belonging to this cell */
// XXX should be removed, use cell map?
virtual void SetColIndex (int aColIndex);
/** return the available width given to this frame during its last reflow */
virtual nscoord GetPriorAvailWidth();
/** set the available width given to this frame during its last reflow */
virtual void SetPriorAvailWidth(nscoord aPriorAvailWidth);
virtual nsSize GetPriorDesiredSize();
/** return the desired size returned by this frame during its last reflow */
virtual nsSize GetDesiredSize();
virtual void SetPriorDesiredSize(const nsReflowMetrics & aDesiredSize);
/** set the desired size returned by this frame during its last reflow */
virtual void SetDesiredSize(const nsReflowMetrics & aDesiredSize);
virtual ~nsTableCellFrame();
/** return the MaxElement size returned by this frame during its last reflow
* not counting reflows where MaxElementSize is not requested.
* That is, the cell frame will always remember the last non-null MaxElementSize
*/
virtual nsSize GetMaxElementSize();
// Get the TableFrame that contains this cell frame
/** set the MaxElement size returned by this frame during its last reflow.
* should never be called with a null MaxElementSize
*/
virtual void SetMaxElementSize(const nsSize & aMaxElementSize);
/** return the desired size returned by this frame during its last reflow */
virtual nsSize GetPass1DesiredSize();
/** set the desired size returned by this frame during its last reflow */
virtual void SetPass1DesiredSize(const nsReflowMetrics & aDesiredSize);
/** return the MaxElement size returned by this frame during its last reflow
* not counting reflows where MaxElementSize is not requested.
* That is, the cell frame will always remember the last non-null MaxElementSize
*/
virtual nsSize GetPass1MaxElementSize();
/** set the MaxElement size returned by this frame during its last reflow.
* should never be called with a null MaxElementSize
*/
virtual void SetPass1MaxElementSize(const nsSize & aMaxElementSize);
/** Get the TableFrame that contains this cell frame */
virtual nsTableFrame* GetTableFrame();
nsCellLayoutData * GetCellLayoutData();
void SetCellLayoutData(nsCellLayoutData *aData);
void RecalcLayoutData(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4]);
// For DEBUGGING Purposes Only
NS_IMETHOD GetMargin(nsMargin& aMargin);
/** destructor */
virtual ~nsTableCellFrame();
// For DEBUGGING Purposes Only, to be removed
NS_IMETHOD MoveTo(nscoord aX, nscoord aY);
NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight);
private:
// All these methods are support methods for RecalcLayoutData
nsIFrame* GetFrameAt(nsVoidArray* aList, PRInt32 aIndex);
nscoord GetMargin(nsIFrame* aFrame, PRUint8 aEdge) const;
nscoord GetBorderWidth(nsIFrame* aFrame, PRUint8 aEdge) const;
nscoord GetPadding(nsIFrame* aFrame, PRUint8 aEdge) const;
PRUint8 GetOpposingEdge(PRUint8 aEdge);
nsIFrame* CompareCellBorders(nsIFrame* aFrame1,
PRUint8 aEdge1,
nsIFrame* aFrame2,
PRUint8 aEdge2);
nsIFrame* FindHighestPrecedentBorder(nsVoidArray* aList,
PRUint8 aEdge);
nsIFrame* FindInnerBorder( nsVoidArray* aList,
PRUint8 aEdge);
nsIFrame* FindOuterBorder( nsTableFrame* aTableFrame,
PRUint8 aEdge);
nsIFrame* FindBorderFrame(nsTableFrame* aTableFrame,
nsVoidArray* aCellList,
PRUint8 aEdge);
void CalculateBorders(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4]);
nscoord FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge);
void CalculateMargins(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4]);
protected:
/** protected constructor.
@ -132,9 +222,17 @@ protected:
/** the available width we were given in our previous reflow */
nscoord mPriorAvailWidth;
nsSize mPriorDesiredSize;
/** these are the last computed desired and max element sizes */
nsSize mDesiredSize;
nsSize mMaxElementSize;
nsCellLayoutData *mCellLayoutData;
/** these are the Pass 1 unconstrained desired and max element sizes */
nsSize mPass1DesiredSize;
nsSize mPass1MaxElementSize;
nsresult mCalculated;
nsMargin mMargin;
nsIFrame* mBorderFrame[4]; // the frame whose border is used
};
@ -151,6 +249,16 @@ inline void nsTableCellFrame::Init(PRInt32 aRowSpan, PRInt32 aColSpan, PRInt32 a
inline PRInt32 nsTableCellFrame::GetRowSpan()
{ return mRowSpan;}
inline PRInt32 nsTableCellFrame::GetRowIndex()
{
nsTableRowFrame * row;
GetContentParent((nsIFrame *&)row);
if (nsnull!=row)
return row->GetRowIndex();
else
return 0;
}
inline PRInt32 nsTableCellFrame::GetColSpan()
{ return mColSpan;}
@ -163,25 +271,64 @@ inline void nsTableCellFrame::SetColIndex (int aColIndex)
mColIndex = aColIndex;
}
inline nsCellLayoutData * nsTableCellFrame::GetCellLayoutData()
{ return mCellLayoutData;}
inline void nsTableCellFrame::SetCellLayoutData(nsCellLayoutData *aData)
{ mCellLayoutData = aData;}
inline nscoord nsTableCellFrame::GetPriorAvailWidth()
{ return mPriorAvailWidth;}
inline void nsTableCellFrame::SetPriorAvailWidth(nscoord aPriorAvailWidth)
{ mPriorAvailWidth = aPriorAvailWidth;}
inline nsSize nsTableCellFrame::GetPriorDesiredSize()
{ return mPriorDesiredSize; }
inline nsSize nsTableCellFrame::GetDesiredSize()
{ return mDesiredSize; }
inline void nsTableCellFrame::SetPriorDesiredSize(const nsReflowMetrics & aDesiredSize)
inline void nsTableCellFrame::SetDesiredSize(const nsReflowMetrics & aDesiredSize)
{
mPriorDesiredSize.width = aDesiredSize.width;
mPriorDesiredSize.height = aDesiredSize.height;
mDesiredSize.width = aDesiredSize.width;
mDesiredSize.height = aDesiredSize.height;
}
inline nsSize nsTableCellFrame::GetMaxElementSize()
{ return mMaxElementSize; }
inline void nsTableCellFrame::SetMaxElementSize(const nsSize & aMaxElementSize)
{
mMaxElementSize.width = aMaxElementSize.width;
mMaxElementSize.height = aMaxElementSize.height;
}
inline nsSize nsTableCellFrame::GetPass1DesiredSize()
{ return mPass1DesiredSize; }
inline void nsTableCellFrame::SetPass1DesiredSize(const nsReflowMetrics & aDesiredSize)
{
mPass1DesiredSize.width = aDesiredSize.width;
mPass1DesiredSize.height = aDesiredSize.height;
}
inline nsSize nsTableCellFrame::GetPass1MaxElementSize()
{ return mPass1MaxElementSize; }
inline void nsTableCellFrame::SetPass1MaxElementSize(const nsSize & aMaxElementSize)
{
mPass1MaxElementSize.width = aMaxElementSize.width;
mPass1MaxElementSize.height = aMaxElementSize.height;
}
inline void nsTableCellFrame::CalculateBorders(nsTableFrame* aTableFrame,
nsVoidArray* aBoundaryCells[4])
{
for (PRInt32 edge = 0; edge < 4; edge++)
mBorderFrame[edge] = FindBorderFrame(aTableFrame, aBoundaryCells[edge], edge);
}
inline NS_METHOD nsTableCellFrame::GetMargin(nsMargin& aMargin)
{
if (mCalculated == NS_OK)
{
aMargin = mMargin;
return NS_OK;
}
return NS_ERROR_NOT_INITIALIZED;
}
#endif

View File

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsTableColFrame.h"
#include "nsContainerFrame.h"
#include "nsIReflowCommand.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
#include "nsIPresContext.h"
#include "nsHTMLIIDs.h"
#include "nsHTMLAtoms.h"
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
static PRBool gsNoisyRefs = PR_FALSE;
#else
static const PRBool gsDebug = PR_FALSE;
static const PRBool gsNoisyRefs = PR_FALSE;
#endif
nsTableColFrame::nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame)
: nsFrame(aContent, aParentFrame)
{
mColIndex = 0;
mRepeat = 0;
}
nsTableColFrame::~nsTableColFrame()
{
}
NS_METHOD nsTableColFrame::Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
{
if (gsDebug==PR_TRUE)
printf("nsTableColFrame::Paint\n");
return NS_OK;
}
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)
{
aDesiredSize.maxElementSize->width=0;
aDesiredSize.maxElementSize->height=0;
}
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
/* ----- static methods ------ */
nsresult nsTableColFrame::NewFrame(nsIFrame** aInstancePtrResult,
nsIContent* aContent,
nsIFrame* aParent)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
if (nsnull == aInstancePtrResult) {
return NS_ERROR_NULL_POINTER;
}
nsIFrame* it = new nsTableColFrame(aContent, aParent);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
*aInstancePtrResult = it;
return NS_OK;
}

View File

@ -48,6 +48,12 @@ public:
/** set the index of the column this content object represents. must be >= 0 */
virtual void SetColumnIndex (int aColIndex);
/** convenience method, calls into cellmap */
nsVoidArray * GetCells();
/** convenience method, calls into cellmap */
PRInt32 Count() const;
protected:
nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame);
@ -55,10 +61,16 @@ protected:
~nsTableColFrame();
/** the starting index of the column (starting at 0) that this col object represents */
PRInt32 mColIndex;
PRInt32 mColIndex;
/** the number of columns that the attributes of this column extend to */
PRInt32 mRepeat;
PRInt32 mRepeat;
nscoord mMaxWidth;
nscoord mMinWidth;
nscoord mMaxEffectiveWidth;
nscoord mMinEffectiveWidth;
};

View File

@ -29,14 +29,12 @@
#include "nsTableColGroupFrame.h"
#include "nsTableRowFrame.h"
#include "nsTableRowGroupFrame.h"
#include "nsColLayoutData.h"
#include "BasicTableLayoutStrategy.h"
#include "nsIPresContext.h"
#include "nsCSSRendering.h"
#include "nsStyleConsts.h"
#include "nsCellLayoutData.h"
#include "nsVoidArray.h"
#include "nsIPtr.h"
#include "nsIView.h"
@ -269,7 +267,6 @@ void ColumnInfoCache::GetColumnsByType(const nsStyleUnit aType,
nsTableFrame::nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame)
: nsContainerFrame(aContent, aParentFrame),
mCellMap(nsnull),
mColumnLayoutData(nsnull),
mColCache(nsnull),
mColumnWidths(nsnull),
mTableLayoutStrategy(nsnull),
@ -279,32 +276,11 @@ nsTableFrame::nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame)
{
}
/**
* Method to delete all owned objects assoicated
* with the ColumnLayoutObject instance variable
*/
void nsTableFrame::DeleteColumnLayoutData()
{
if (nsnull!=mColumnLayoutData)
{
PRInt32 numCols = mColumnLayoutData->Count();
for (PRInt32 i = 0; i<numCols; i++)
{
nsColLayoutData *colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(i));
delete colData;
}
delete mColumnLayoutData;
mColumnLayoutData = nsnull;
}
}
nsTableFrame::~nsTableFrame()
{
if (nsnull!=mCellMap)
delete mCellMap;
DeleteColumnLayoutData();
if (nsnull!=mColumnWidths)
delete [] mColumnWidths;
@ -351,8 +327,7 @@ nsTableRowGroupFrame* nsTableFrame::NextRowGroupFrame(nsTableRowGroupFrame* aRow
PRInt32 nsTableFrame::GetSpecifiedColumnCount ()
{
mColCount=0;
nsIFrame * colGroup;
ChildAt (0, (nsIFrame *&)colGroup);
nsIFrame * colGroup = mFirstChild;
while (nsnull!=colGroup)
{
const nsStyleDisplay *childDisplay;
@ -379,8 +354,7 @@ PRInt32 nsTableFrame::GetRowCount ()
if (nsnull != mCellMap)
return mCellMap->GetRowCount();
nsIFrame *child=nsnull;
ChildAt(0, child);
nsIFrame *child=mFirstChild;
while (nsnull!=child)
{
const nsStyleDisplay *childDisplay;
@ -393,6 +367,35 @@ PRInt32 nsTableFrame::GetRowCount ()
}
return rowCount;
}
nsTableColFrame * nsTableFrame::GetColFrame(PRInt32 aColIndex)
{
nsTableColFrame *result = nsnull;
if (nsnull!=mCellMap)
{
result = mCellMap->GetColumnFrame(aColIndex);
}
return result;
}
// can return nsnull
nsTableCellFrame * nsTableFrame::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex)
{
nsTableCellFrame *result = nsnull;
if (nsnull!=mCellMap)
{
CellData * cellData = mCellMap->GetCellAt(aRowIndex, aColIndex);
if (nsnull!=cellData)
{
result = cellData->mCell;
if (nsnull==result)
result = cellData->mRealCell->mCell;
}
}
return result;
}
// return the 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)
@ -413,13 +416,6 @@ PRInt32 nsTableFrame::GetEffectiveRowSpan (PRInt32 aRowIndex, nsTableCellFrame *
return rowSpan;
}
// returns the actual cell map, not a copy, so don't mess with it!
nsCellMap* nsTableFrame::GetCellMap() const
{
return mCellMap;
}
/* call when the cell structure has changed. mCellMap will be rebuilt on demand. */
void nsTableFrame::ResetCellMap ()
{
@ -449,10 +445,9 @@ void nsTableFrame::EnsureColumns(nsIPresContext* aPresContext,
PRInt32 actualColumns = 0;
nsTableColGroupFrame *lastColGroupFrame = nsnull;
nsIFrame * childFrame=nsnull;
nsIFrame * firstRowGroupFrame=nsnull;
nsIFrame * prevSibFrame=nsnull;
ChildAt (0, (nsIFrame *&)childFrame);
nsIFrame * childFrame=mFirstChild;
while (nsnull!=childFrame)
{
const nsStyleDisplay *childDisplay;
@ -795,35 +790,67 @@ void nsTableFrame::GrowCellMap (PRInt32 aColCount)
*/
void nsTableFrame::ListColumnLayoutData(FILE* out, PRInt32 aIndent) const
{
// if this is a continuing frame, there will be no output
if (nsnull!=mColumnLayoutData)
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
if (this!=firstInFlow)
{
firstInFlow->ListColumnLayoutData(out, aIndent);
return;
}
if (nsnull!=mCellMap)
{
fprintf(out,"Column Layout Data \n");
PRInt32 numCols = mColumnLayoutData->Count();
for (PRInt32 i = 0; i<numCols; i++)
PRInt32 numCols = mCellMap->GetColCount();
PRInt32 numRows = mCellMap->GetRowCount();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData *colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(i));
for (PRInt32 indent = aIndent; --indent >= 0; )
fputs(" ", out);
fprintf(out,"Column Data [%d] \n",colIndex);
for (PRInt32 rowIndex = 0; rowIndex < numRows; rowIndex++)
{
nsTableCellFrame *cellFrame = mCellMap->GetCellFrameAt(rowIndex, colIndex);
PRInt32 rowIndent;
for (rowIndent = aIndent+2; --rowIndent >= 0; ) fputs(" ", out);
fprintf(out,"Cell Data [%d] \n",rowIndex);
for (rowIndent = aIndent+2; --rowIndent >= 0; ) fputs(" ", out);
nsMargin margin;
cellFrame->GetMargin(margin);
fprintf(out,"Margin -- Top: %d Left: %d Bottom: %d Right: %d \n",
NS_TWIPS_TO_POINTS_INT(margin.top),
NS_TWIPS_TO_POINTS_INT(margin.left),
NS_TWIPS_TO_POINTS_INT(margin.bottom),
NS_TWIPS_TO_POINTS_INT(margin.right));
for (rowIndent = aIndent+2; --rowIndent >= 0; ) fputs(" ", out);
for (PRInt32 indent = aIndent; --indent >= 0; ) fputs(" ", out);
fprintf(out,"Column Data [%d] \n",i);
colData->List(out,aIndent+2);
nscoord top,left,bottom,right;
/*
top = (mBorderFrame[NS_SIDE_TOP] ? cellFrame->GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_TOP], NS_SIDE_TOP) : 0);
left = (mBorderFrame[NS_SIDE_LEFT] ? cellFrame->GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_LEFT], NS_SIDE_LEFT) : 0);
bottom = (mBorderFrame[NS_SIDE_BOTTOM] ? cellFrame->GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_BOTTOM], NS_SIDE_BOTTOM) : 0);
right = (mBorderFrame[NS_SIDE_RIGHT] ? cellFrame->GetBorderWidth((nsIFrame*)mBorderFrame[NS_SIDE_RIGHT], NS_SIDE_RIGHT) : 0);
*/
fprintf(out,"Border -- Top: %d Left: %d Bottom: %d Right: %d \n",
NS_TWIPS_TO_POINTS_INT(top),
NS_TWIPS_TO_POINTS_INT(left),
NS_TWIPS_TO_POINTS_INT(bottom),
NS_TWIPS_TO_POINTS_INT(right));
}
}
}
}
/**
* For the TableCell in CellData, find the CellLayoutData assocated
* and add it to the list
**/
* For the TableCell in CellData, add it to the list
*/
void nsTableFrame::AppendLayoutData(nsVoidArray* aList, nsTableCellFrame* aTableCell)
{
if (aTableCell != nsnull)
{
nsCellLayoutData* layoutData = GetCellLayoutData(aTableCell);
if (layoutData != nsnull)
aList->AppendElement((void*)layoutData);
aList->AppendElement((void*)aTableCell);
}
}
@ -996,9 +1023,7 @@ void nsTableFrame::RecalcLayoutData()
r++;
}
nsCellLayoutData* cellLayoutData = GetCellLayoutData(cell);
if (cellLayoutData != nsnull)
cellLayoutData->RecalcLayoutData(this,boundaryCells);
cell->RecalcLayoutData(this,boundaryCells);
}
}
}
@ -1310,7 +1335,7 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext,
if (nsnull!=prevKidFrame)
prevKidFrame->GetNextSibling(kidFrame); // no need to check for an error, just see if it returned null...
else
ChildAt(0, kidFrame);
kidFrame=mFirstChild;
// if this is the first time, allocate the frame
if (nsnull==kidFrame)
@ -2210,11 +2235,10 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
if (gsDebug)
printf ("BalanceColumnWidths...\n");
nsVoidArray *columnLayoutData = GetColumnLayoutData();
if (nsnull==columnLayoutData)
if (nsnull==mCellMap)
return; // we don't have any information yet, so we can't do any useful work
PRInt32 numCols = columnLayoutData->Count();
PRInt32 numCols = mCellMap->GetColCount();
if (nsnull==mColumnWidths)
{
mColumnWidths = new PRInt32[numCols];
@ -2233,9 +2257,22 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
// need to figure out the overall table width constraint
// default case, get 100% of available space
// begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED!
nsIFrame * outerTableFrame = nsnull;
const nsStylePosition* position;
GetGeometricParent(outerTableFrame);
outerTableFrame->GetStyleData(eStyleStruct_Position, ((nsStyleStruct *&)position));
// end REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED
PRInt32 maxWidth;
/*
const nsStylePosition* position =
(const nsStylePosition*)mStyleContext->GetStyleData(eStyleStruct_Position);
use this line when tableFrame contains its own position style info
*/
switch (position->mWidth.GetUnit()) {
case eStyleUnit_Coord:
maxWidth = position->mWidth.GetCoordValue();
@ -2251,7 +2288,6 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
// XXX for now these fall through
default:
maxWidth = aMaxSize.width;
break;
}
@ -2293,16 +2329,20 @@ void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext)
if (gsDebug==PR_TRUE) printf ("SetTableWidth...");
PRInt32 tableWidth = 0;
nsVoidArray *columnLayoutData = GetColumnLayoutData();
if (nsnull==columnLayoutData)
if (nsnull==mCellMap)
return; // no info, so nothing to do
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 i = 0; i<numCols; i++)
PRInt32 numCols = mCellMap->GetColCount();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
tableWidth += mColumnWidths[i];
nscoord totalColWidth = mColumnWidths[colIndex];
nsTableCellFrame * cellFrame = GetCellAt(0, colIndex);
nsMargin colMargin;
GetCellMarginData(cellFrame,colMargin);
totalColWidth += colMargin.left + colMargin.right;
if (gsDebug==PR_TRUE)
printf (" += %d ", mColumnWidths[i]);
printf (" += %d ", totalColWidth);
tableWidth += totalColWidth;
}
// Compute the insets (sum of border and padding)
@ -2384,12 +2424,9 @@ NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aCol
{
aColFrame = nsnull; // initialize out parameter
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
if (nsnull!=firstInFlow->mColumnLayoutData)
if (nsnull!=firstInFlow->mCellMap)
{ // hooray, we get to do this the easy way because the info is cached
nsColLayoutData * colData = (nsColLayoutData *)
(firstInFlow->mColumnLayoutData->ElementAt(aColIndex));
NS_ASSERTION(nsnull != colData, "bad column data");
aColFrame = colData->GetColFrame();
aColFrame = firstInFlow->mCellMap->GetColumnFrame(aColIndex);
NS_ASSERTION(nsnull!=aColFrame, "bad col frame");
}
else
@ -2443,31 +2480,46 @@ void nsTableFrame::BuildColumnCache( nsIPresContext* aPresContext,
mColCache = new ColumnInfoCache(mColCount);
nsIFrame * childFrame = mFirstChild;
while (nsnull!=childFrame)
{ // for every child, if it's a col group then get the columns
{ // in this loop, we cache column info and set column style info from cells in first row
const nsStyleDisplay *childDisplay;
childFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay ||
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{ // if it's a col group then get the columns and cache them in the CellMap
nsTableColFrame *colFrame=nsnull;
childFrame->FirstChild((nsIFrame *&)colFrame);
while (nsnull!=colFrame)
{
mCellMap->AppendColumnFrame(colFrame);
colFrame->GetNextSibling((nsIFrame *&)colFrame);
}
}
else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay )
{ // for every cell in every row, call SetCellLayoutData with the cached info
// QQQ we can probably just leave the info in the table cell frame, not cache it here
{ // if it's a row group, get the cells and set the column style if appropriate
nsIFrame *rowFrame;
childFrame->ChildAt(0, rowFrame);
nsIFrame *cellFrame;
rowFrame->ChildAt(0, cellFrame);
while (nsnull!=cellFrame)
childFrame->FirstChild(rowFrame);
if (nsnull!=rowFrame)
{
/* this is the first time we are guaranteed to have both the cell frames
* and the column frames, so it's a good time to
* set the column style from the cell's width attribute (if this is the first row)
*/
SetColumnStyleFromCell(aPresContext, (nsTableCellFrame *)cellFrame, (nsTableRowFrame *)rowFrame);
cellFrame->GetNextSibling(cellFrame);
nsIFrame *cellFrame;
rowFrame->FirstChild(cellFrame);
while (nsnull!=cellFrame)
{
/* this is the first time we are guaranteed to have both the cell frames
* and the column frames, so it's a good time to
* set the column style from the cell's width attribute (if this is the first row)
*/
SetColumnStyleFromCell(aPresContext, (nsTableCellFrame *)cellFrame, (nsTableRowFrame *)rowFrame);
cellFrame->GetNextSibling(cellFrame);
}
}
}
childFrame->GetNextSibling(childFrame);
}
// second time through, set column cache info for each column
// we can't do this until the loop above has set the column style info from the cells in the first row
childFrame = mFirstChild;
while (nsnull!=childFrame)
{ // for every child, if it's a col group then get the columns
@ -2476,7 +2528,7 @@ void nsTableFrame::BuildColumnCache( nsIPresContext* aPresContext,
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
nsTableColFrame *colFrame=nsnull;
childFrame->ChildAt(0, (nsIFrame *&)colFrame);
childFrame->FirstChild((nsIFrame *&)colFrame);
while (nsnull!=colFrame)
{ // for every column, create an entry in the column cache
// assumes that the col style has been twiddled to account for first cell width attribute
@ -2489,176 +2541,14 @@ void nsTableFrame::BuildColumnCache( nsIPresContext* aPresContext,
else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay )
{ // for every cell in every row, call SetCellLayoutData with the cached info
// QQQ we can probably just leave the info in the table cell frame, not cache it here
nsIFrame *rowFrame;
childFrame->ChildAt(0, rowFrame);
while (nsnull!=rowFrame)
{
nsIFrame *cellFrame;
rowFrame->ChildAt(0, cellFrame);
while (nsnull!=cellFrame)
{
nsCellLayoutData *cld = ((nsTableCellFrame*)cellFrame)->GetCellLayoutData();
SetCellLayoutData(aPresContext, cld, (nsTableCellFrame*)cellFrame);
cellFrame->GetNextSibling(cellFrame);
}
rowFrame->GetNextSibling(rowFrame);
}
{
break; // once we hit a row group, we're done
}
childFrame->GetNextSibling(childFrame);
}
}
}
// nsnull is a valid return value. This is for empty tables.
nsVoidArray * nsTableFrame::GetColumnLayoutData()
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
return firstInFlow->mColumnLayoutData;
}
/** Associate aData with the cell at (aRow,aCol)
* @return PR_TRUE if the data was successfully associated with a Cell
* PR_FALSE if there was an error, such as aRow or aCol being invalid
*/
PRBool nsTableFrame::SetCellLayoutData(nsIPresContext* aPresContext,
nsCellLayoutData * aData, nsTableCellFrame *aCell)
{
NS_ASSERTION(nsnull != aPresContext, "bad arg aPresContext");
NS_ASSERTION(nsnull != aData, "bad arg aData");
NS_ASSERTION(nsnull != aCell, "bad arg aCell");
PRBool result = PR_TRUE;
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
if (this!=firstInFlow)
result = firstInFlow->SetCellLayoutData(aPresContext, aData, aCell);
else
{
if ((kPASS_FIRST==GetReflowPass()) || (kPASS_INCREMENTAL==GetReflowPass()))
{
if (nsnull==mColumnLayoutData)
{
PRInt32 rows = GetRowCount();
mColumnLayoutData = new nsVoidArray();
NS_ASSERTION(nsnull != mColumnLayoutData, "bad alloc");
PRInt32 tableKidCount = mContent->ChildCount();
nsIFrame * colGroupFrame = mFirstChild;
for (PRInt32 i=0; i<tableKidCount; ) // notice increment of i is done just before ChildAt call
{
const nsStyleDisplay *childDisplay;
colGroupFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay));
if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay)
{
nsTableColFrame *colFrame=nsnull;
colGroupFrame->ChildAt(0, (nsIFrame *&)colFrame);
while (nsnull!=colFrame)
{
// TODO: unify these 2 kinds of column data
// TODO: cache more column data, like the mWidth.GetUnit and what its value
nsColLayoutData *colData = new nsColLayoutData(colFrame, rows);
mColumnLayoutData->AppendElement((void *)colData);
colFrame->GetNextSibling((nsIFrame *&)colFrame);
}
}
// can't have col groups after row groups, so stop if you find a row group
else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay ||
NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay )
{
break;
}
i++;
ChildAt(i, colGroupFrame); // can't use colGroupFrame->GetNextSibling because it hasn't been set yet
}
}
PRInt32 firstColIndex = aCell->GetColIndex();
nsTableRowFrame *row;
aCell->GetGeometricParent((nsIFrame*&)row);
PRInt32 rowIndex = row->GetRowIndex();
PRInt32 colSpan = aCell->GetColSpan();
nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex));
nsVoidArray *col = colData->GetCells();
if (gsDebugCLD) printf (" ~ SetCellLayoutData with row = %d, firstCol = %d, colSpan = %d, colData = %ld, col=%ld\n",
rowIndex, firstColIndex, colSpan, colData, col);
/* this logic looks wrong wrong wrong
it seems to add an entries in col (the array of cells for a column) for aCell
based on colspan. This is weird, because you would expect one entry in each
column spanned for aCell, not multiple entries in the same col.
*/
for (PRInt32 i=0; i<colSpan; i++)
{
nsSize * cellSize = aData->GetMaxElementSize();
nsSize partialCellSize(*cellSize);
partialCellSize.width = (cellSize->width)/colSpan;
// This method will copy the nsReflowMetrics pointed at by aData->GetDesiredSize()
nsCellLayoutData * kidLayoutData = new nsCellLayoutData(aData->GetCellFrame(),
aData->GetDesiredSize(),
&partialCellSize);
NS_ASSERTION(col->Count() > rowIndex, "unexpected count");
if (gsDebugCLD) printf (" ~ replacing rowIndex = %d\n", rowIndex);
nsCellLayoutData* data = (nsCellLayoutData*)col->ElementAt(rowIndex);
col->ReplaceElementAt((void *)kidLayoutData, rowIndex);
if (data != nsnull) {
delete data;
}
}
}
else
result = PR_FALSE;
}
return result;
}
/** Get the layout data associated with the cell at (aRow,aCol)
* @return nsnull if there was an error, such as aRow or aCol being invalid
* otherwise, the data is returned.
*/
nsCellLayoutData * nsTableFrame::GetCellLayoutData(nsTableCellFrame *aCell)
{
NS_ASSERTION(nsnull != aCell, "bad arg");
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
nsCellLayoutData *result = nsnull;
if (this!=firstInFlow)
result = firstInFlow->GetCellLayoutData(aCell);
else
{
if (nsnull!=mColumnLayoutData)
{
PRInt32 firstColIndex = aCell->GetColIndex();
nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex));
nsTableRowFrame *rowFrame;
aCell->GetGeometricParent((nsIFrame *&)rowFrame);
PRInt32 rowIndex = rowFrame->GetRowIndex();
result = colData->ElementAt(rowIndex);
#ifdef NS_DEBUG
// Do some sanity checking
if (nsnull != result) {
nsIContent* inputContent;
nsIContent* resultContent;
result->GetCellFrame()->GetContent(resultContent);
aCell->GetContent(inputContent);
NS_ASSERTION(resultContent == inputContent, "unexpected cell");
NS_IF_RELEASE(inputContent);
NS_IF_RELEASE(resultContent);
}
#endif
}
}
return result;
}
PRInt32 nsTableFrame::GetReflowPass() const
{
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
@ -2698,7 +2588,7 @@ nsTableFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
// add headers and footers to cf
nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
nsIFrame * rg = nsnull;
firstInFlow->ChildAt(0, rg);
firstInFlow->FirstChild(rg);
NS_ASSERTION (nsnull!=rg, "previous frame has no children");
nsIAtom * tHeadTag = NS_NewAtom(nsTablePart::kRowGroupHeadTagString); // tHeadTag: REFCNT++
nsIAtom * tFootTag = NS_NewAtom(nsTablePart::kRowGroupFootTagString); // tFootTag: REFCNT++
@ -2758,9 +2648,8 @@ PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex)
{
NS_ASSERTION(nsnull!=mColumnWidths, "illegal state");
#ifdef DEBUG
nsVoidArray *cld = GetColumnLayoutData();
NS_ASSERTION(nsnull!=cld, "no column layout data");
PRInt32 numCols = cld->Count();
NS_ASSERTION(nsnull!=mCellMap, "no column layout data");
PRInt32 numCols = mCellMap->GetColCount();
NS_ASSERTION (numCols > aColIndex, "bad arg, col index out of bounds");
#endif
if (nsnull!=mColumnWidths)
@ -2770,11 +2659,6 @@ PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex)
//printf("GET_COL_WIDTH: %p, FIF=%p getting col %d and returning %d\n", this, firstInFlow, aColIndex, result);
// XXX hack
#if 0
if (result <= 0) {
result = 100;
}
#endif
return result;
}
@ -2936,9 +2820,7 @@ NS_METHOD nsTableFrame::GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin&
if (nsnull != aKidFrame)
{
nsCellLayoutData* layoutData = GetCellLayoutData(aKidFrame);
if (layoutData)
result = layoutData->GetMargin(aMargin);
result = aKidFrame->GetMargin(aMargin);
}
return result;
@ -3218,37 +3100,6 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame,
return result;
}
/* valuable code not yet used anywhere
// since the table is a specified width, we need to expand the columns to fill the table
nsVoidArray *columnLayoutData = GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
PRInt32 spaceUsed = 0;
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
spaceUsed += mColumnWidths[colIndex];
PRInt32 spaceRemaining = spaceUsed - aMaxWidth;
PRInt32 additionalSpaceAdded = 0;
if (0<spaceRemaining)
{
for (colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
nsStyleMolecule* colStyle =
(nsStyleMolecule*)mStyleContext->GetData(eStyleStruct_Molecule);
if (PR_TRUE==IsProportionalWidth(colStyle))
{
PRInt32 percentage = (100*mColumnWidths[colIndex]) / aMaxWidth;
PRInt32 additionalSpace = (spaceRemaining*percentage)/100;
mColumnWidths[colIndex] += additionalSpace;
additionalSpaceAdded += additionalSpace;
}
}
if (spaceUsed+additionalSpaceAdded < aMaxTableWidth)
mColumnWidths[numCols-1] += (aMaxTableWidth - (spaceUsed+additionalSpaceAdded));
}
*/
// For Debugging ONLY
NS_METHOD nsTableFrame::MoveTo(nscoord aX, nscoord aY)
{

View File

@ -23,7 +23,6 @@
#include "nsStyleCoord.h"
class nsCellMap;
class nsCellLayoutData;
class nsVoidArray;
class nsTableCellFrame;
class nsTableColFrame;
@ -42,29 +41,6 @@ struct nsStyleSpacing;
extern const nsIID kTableFrameCID;
/** Data stored by nsCellMap to rationalize rowspan and colspan cells.
* if mCell is null then mRealCell will be the rowspan/colspan source
* in addition, if fOverlap is non-null then it will point to the
* other cell that overlaps this position
* @see nsCellMap
* @see nsTableFrame::BuildCellMap
* @see nsTableFrame::GrowCellMap
* @see nsTableFrame::BuildCellIntoMap
*
*/
class CellData
{
public:
nsTableCellFrame *mCell;
CellData *mRealCell;
CellData *mOverlap;
CellData();
~CellData();
};
/* ============================================================================ */
/** nsTableFrame maps the inner portion of a table (everything except captions.)
@ -153,36 +129,12 @@ public:
*/
NS_METHOD GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame);
/** return the column layout data for this inner table frame.
* if this is a continuing frame, return the first-in-flow's column layout data.
* @return the column layout data array, or null if there is no info yet.
*/
virtual nsVoidArray *GetColumnLayoutData();
/** Associate aData with the cell at (aRow,aCol)
*
* @param aPresContext -- used to resolve style when initializing caches
* @param aData -- the info to cache
* @param aCell -- the content object for which layout info is being cached
*
* @return PR_TRUE if the data was successfully associated with a Cell
* PR_FALSE if there was an error, such as aRow or aCol being invalid
*/
virtual PRBool SetCellLayoutData(nsIPresContext * aPresContext,
nsCellLayoutData * aData,
nsTableCellFrame * aCell);
/** Get the layout data associated with the cell at (aRow,aCol)
* @return PR_NULL if there was an error, such as aRow or aCol being invalid
* otherwise, the data is returned.
*/
virtual nsCellLayoutData * GetCellLayoutData(nsTableCellFrame *aCell);
/**
* DEBUG METHOD
*
*/
virtual void ListColumnLayoutData(FILE* out = stdout, PRInt32 aIndent = 0) const;
//virtual void ListColumnLayoutData(FILE* out = stdout, PRInt32 aIndent = 0) const;
/** return the width of the column at aColIndex */
@ -236,11 +188,6 @@ protected:
/** destructor, responsible for mColumnLayoutData and mColumnWidths */
virtual ~nsTableFrame();
/** helper method to delete contents of mColumnLayoutData
* should be called with care (ie, only by destructor)
*/
virtual void DeleteColumnLayoutData();
/** first pass of ResizeReflow.
* lays out all table content with aMaxSize(NS_UNCONSTRAINEDSIZE,NS_UNCONSTRAINEDSIZE) and
* a non-null aMaxElementSize so we get all the metrics we need to do column balancing.
@ -380,6 +327,16 @@ protected:
*/
virtual void ResetCellMap ();
/** for debugging only
* prints out information about the cell map
*/
void DumpCellMap() const;
/** for debugging only
* prints out info about the table layout state, printing columns and their cells
*/
void ListColumnLayoutData(FILE* out, PRInt32 aIndent) const;
/** ResetColumns is called when the column structure of the table is changed.
* Call with caution, only when adding or removing columns, changing
* column attributes, changing the rowspan or colspan attribute of a cell, etc.
@ -418,13 +375,6 @@ protected:
*/
virtual nsTableRowGroupFrame* NextRowGroupFrame (nsTableRowGroupFrame*);
/** returns the number of rows in this table.
* if mCellMap has been created, it is asked for the number of rows.<br>
* otherwise, the content is enumerated and the rows are counted.
*/
virtual PRInt32 GetRowCount();
/** return the number of columns as specified by the input.
* has 2 side effects:<br>
* calls SetStartColumnIndex on each nsTableColumn<br>
@ -432,9 +382,18 @@ protected:
*/
virtual PRInt32 GetSpecifiedColumnCount ();
public:
virtual void DumpCellMap() const;
virtual nsCellMap* GetCellMap() const;
public: /* ----- Cell Map public methods ----- */
/** returns the number of rows in this table.
* if mCellMap has been created, it is asked for the number of rows.<br>
* otherwise, the content is enumerated and the rows are counted.
*/
virtual PRInt32 GetRowCount();
nsTableColFrame * GetColFrame(PRInt32 aColIndex);
nsTableCellFrame * GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex);
private:
@ -446,9 +405,7 @@ private:
*/
enum {kPASS_UNDEFINED=0, kPASS_FIRST=1, kPASS_SECOND=2, kPASS_THIRD=3, kPASS_INCREMENTAL=4};
nsVoidArray *mColumnLayoutData; // array of array of cellLayoutData's
PRInt32 *mColumnWidths; // widths of each column
//TODO: move all column info into this object
ColumnInfoCache *mColCache; // cached information about the table columns
PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit
PRInt32 mPass; // which Reflow pass are we currently in?

View File

@ -25,8 +25,6 @@
#include "nsTableFrame.h"
#include "nsTableColFrame.h"
#include "nsTableCellFrame.h"
#include "nsCellLayoutData.h"
#include "nsColLayoutData.h"
#include "nsIView.h"
#include "nsIPtr.h"
#include "nsIReflowCommand.h"
@ -37,6 +35,7 @@ NS_DEF_PTR(nsIStyleContext);
static PRBool gsDebug1 = PR_FALSE;
static PRBool gsDebug2 = PR_FALSE;
//#define NOISY
//#define NOISY_FLOW
#else
static const PRBool gsDebug1 = PR_FALSE;
static const PRBool gsDebug2 = PR_FALSE;
@ -51,6 +50,9 @@ struct RowReflowState {
// The body's available size (computed from the body's parent)
nsSize availSize;
// the running x-offset
nscoord x;
// Height of tallest cell (excluding cells with rowspan > 1)
nscoord maxCellHeight; // just the height of the cell frame
nscoord maxCellVertSpace; // the maximum MAX(cellheight + topMargin + bottomMargin)
@ -68,6 +70,7 @@ struct RowReflowState {
maxCellHeight = 0;
maxCellVertSpace = 0;
tableFrame = aTableFrame;
x=0;
}
~RowReflowState() {
@ -111,12 +114,12 @@ nsTableRowFrame::DidReflow(nsIPresContext& aPresContext,
PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(mRowIndex, cellFrame);
if (1==rowSpan)
{
// Resize the cell's height
// resize the cell's height
nsSize cellFrameSize;
cellFrame->GetSize(cellFrameSize);
cellFrame->SizeTo(cellFrameSize.width, cellHeight);
// Realign cell content based on the new height
// realign cell content based on the new height
cellFrame->VerticallyAlignChild(&aPresContext);
}
@ -287,6 +290,9 @@ void nsTableRowFrame::PlaceChild(nsIPresContext* aPresContext,
// Place and size the child
aKidFrame->SetRect(aKidRect);
// update the running total for the row width
aState.x += aKidRect.width;
// Update the maximum element size
PRInt32 rowSpan = ((nsTableCellFrame*)aKidFrame)->GetRowSpan();
if (nsnull != aMaxElementSize)
@ -328,6 +334,8 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
NS_PRECONDITION(nsnull != mFirstChild, "no children");
nsSize kidMaxElementSize;
PRBool result = PR_TRUE;
PRInt32 prevColIndex = -1; // remember the col index of the previous cell to handle rowspans into this row
nsSize* pKidMaxElementSize = (nsnull != aDesiredSize.maxElementSize) ?
&kidMaxElementSize : nsnull;
nscoord maxCellTopMargin = 0;
@ -335,6 +343,13 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
// Reflow each of our existing cell frames
for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) {
nsSize kidAvailSize(aState.availSize);
if (0>=kidAvailSize.height)
kidAvailSize.height = 1; // XXX: HaCk - we don't handle negative heights yet
nsReflowMetrics desiredSize(pKidMaxElementSize);
desiredSize.width=desiredSize.height=desiredSize.ascent=desiredSize.descent=0;
// Get the frame's margins, and compare the top and bottom margin
// against our current max values
nsMargin kidMargin;
@ -344,15 +359,49 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
if (kidMargin.bottom > maxCellBottomMargin)
maxCellBottomMargin = kidMargin.bottom;
// Figure out the amount of available size for the child (subtract
// off the top margin we are going to apply to it)
//XXX TROY??? unconstrainedHeight was removed from aState, what should happen here?
/*
if (PR_FALSE == aState.unconstrainedHeight)
{
kidAvailSize.height -= kidMargin.top + kidMargin.bottom;
}
*/
// left and right margins already taken into account by table layout strategy
// Compute the x-origin for the child
//
// XXX Having to re-compute the value each time from scratch is very inefficent...
nscoord x = ComputeCellXOffset(aState, kidFrame, kidMargin);
// Compute the x-origin for the child, taking into account straddlers (cells from prior
// rows with rowspans > 1)
PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
if (prevColIndex != (cellColIndex-1))
{ // if this cell is not immediately adjacent to the previous cell, factor in missing col info
for (PRInt32 colIndex=prevColIndex+1; colIndex<cellColIndex; colIndex++)
{
aState.x += aState.tableFrame->GetColumnWidth(colIndex);
aState.x += kidMargin.left + kidMargin.right;
}
}
aState.x += kidMargin.left;
// at this point, we know the column widths.
// so we get the avail width from the known column widths
PRInt32 cellColSpan = ((nsTableCellFrame *)kidFrame)->GetColSpan();
nscoord availWidth = 0;
for (PRInt32 numColSpan=0; numColSpan<cellColSpan; numColSpan++)
{
availWidth += aState.tableFrame->GetColumnWidth(cellColIndex+numColSpan);
if (0<numColSpan)
{
availWidth += kidMargin.right;
if (0!=cellColIndex)
availWidth += kidMargin.left;
}
}
prevColIndex = cellColIndex + (cellColSpan-1); // remember the rightmost column this cell spans into
// Compute the cell available width from the column widths
nscoord availWidth = ComputeCellAvailWidth(aState, kidFrame);
// If the available width is the same as last time we reflowed the cell,
// then just use the previous desired size
@ -360,17 +409,16 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
// XXX Wouldn't it be cleaner (but slightly less efficient) for the row to
// just reflow the cell, and have the cell decide whether it could use the
// cached value rather than having the row make that determination?
nsReflowMetrics desiredSize(pKidMaxElementSize);
if (availWidth != ((nsTableCellFrame *)kidFrame)->GetPriorAvailWidth())
{
// Always let the cell be as high as it wants. We ignore the height that's
// passed in and always place the entire row. Let the row group decide
// whether we fit or wehther the entire row is pushed
nsSize kidAvailSize(availWidth, NS_UNCONSTRAINEDSIZE);
// Reflow the child
kidFrame->WillReflow(*aPresContext);
kidFrame->MoveTo(x, kidMargin.top);
kidFrame->MoveTo(aState.x, kidMargin.top);
kidAvailSize.width = availWidth;
nsReflowState kidReflowState(kidFrame, aState.reflowState, kidAvailSize,
eReflowReason_Resize);
@ -393,12 +441,12 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
}
else
{
nsSize priorSize = ((nsTableCellFrame *)kidFrame)->GetPriorDesiredSize();
nsSize priorSize = ((nsTableCellFrame *)kidFrame)->GetDesiredSize();
desiredSize.width = priorSize.width;
desiredSize.height = priorSize.height;
}
// Place the child after taking into account its margin and attributes
// Place the child after taking into account it's margin and attributes
nscoord specifiedHeight = 0;
nscoord cellHeight = desiredSize.height;
nsIStyleContextPtr kidSC;
@ -423,19 +471,20 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
// begin special Nav4 compatibility code
if (0==cellWidth)
{
PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
cellWidth = aState.tableFrame->GetColumnWidth(cellColIndex);
}
// end special Nav4 compatibility code
// Place the child
nsRect kidRect (x, kidMargin.top, cellWidth, cellHeight);
nsRect kidRect (aState.x, kidMargin.top, cellWidth, cellHeight);
PlaceChild(aPresContext, aState, kidFrame, kidRect, aDesiredSize.maxElementSize,
pKidMaxElementSize);
aState.x += kidMargin.right; // add in right margin only after cell has been placed
// Get the next child
kidFrame->GetNextSibling(kidFrame);
}
SetMaxChildHeight(aState.maxCellHeight,maxCellTopMargin, maxCellBottomMargin); // remember height of tallest child who doesn't have a row span
@ -448,42 +497,6 @@ nsresult nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext,
return NS_OK;
}
// Compute the x-origin for the child by summing up the width of each
// prior column. This correctly handles cells from prior rows with rowspans
// > 1
nscoord nsTableRowFrame::ComputeCellXOffset(const RowReflowState& aState,
nsIFrame* aKidFrame,
const nsMargin& aKidMargin) const
{
nscoord x = aKidMargin.left;
PRInt32 cellColIndex = ((nsTableCellFrame *)aKidFrame)->GetColIndex();
for (PRInt32 colIndex = 0; colIndex < cellColIndex; colIndex++)
{
x += aState.tableFrame->GetColumnWidth(colIndex);
}
return x;
}
// Computes the avail width for the cell. Takes into account column
// spans
nscoord nsTableRowFrame::ComputeCellAvailWidth(const RowReflowState& aState,
nsIFrame* aKidFrame) const
{
nscoord availWidth = 0;
nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCellFrame *)aKidFrame);
PRInt32 cellStartingCol = ((nsTableCellFrame *)aKidFrame)->GetColIndex();
PRInt32 cellColSpan = ((nsTableCellFrame *)aKidFrame)->GetColSpan();
for (PRInt32 numColSpan = 0; numColSpan < cellColSpan; numColSpan++)
{
availWidth += aState.tableFrame->GetColumnWidth(cellStartingCol + numColSpan);
}
return availWidth;
}
/**
* Called for the initial reflow. Creates each table cell frame, and
* reflows it to gets its minimum and maximum sizes
@ -570,13 +583,10 @@ nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext,
kidFrame->WillReflow(*aPresContext);
status = ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState);
((nsTableCellFrame *)kidFrame)->SetPass1DesiredSize(kidSize);
((nsTableCellFrame *)kidFrame)->SetPass1MaxElementSize(kidMaxElementSize);
NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "unexpected child reflow status");
// Allocate and set the cell layout data
nsCellLayoutData *kidLayoutData = new nsCellLayoutData((nsTableCellFrame *)kidFrame,
&kidSize, &kidMaxElementSize);
((nsTableCellFrame *)kidFrame)->SetCellLayoutData(kidLayoutData);
if (gsDebug1)
{
printf("reflow of cell returned result = %s with desired=%d,%d, min = %d,%d\n",
@ -630,13 +640,12 @@ nsresult nsTableRowFrame::RecoverState(RowReflowState& aState,
for (nsIFrame* frame = mFirstChild; frame != aKidFrame;) {
PRInt32 rowSpan = ((nsTableCellFrame*)frame)->GetRowSpan();
if (mMinRowSpan == rowSpan) {
// XXX This isn't quite right. We also need to check whether the cell
// has a height property that affects the cell...
nsSize desiredSize = ((nsTableCellFrame *)frame)->GetPriorDesiredSize();
nsRect rect;
frame->GetRect(rect);
// Update maxCellHeight
if (desiredSize.height > aState.maxCellHeight) {
aState.maxCellHeight = desiredSize.height;
if (rect.height > aState.maxCellHeight) {
aState.maxCellHeight = rect.height;
}
// Update maxCellVertHeight
@ -644,18 +653,14 @@ nsresult nsTableRowFrame::RecoverState(RowReflowState& aState,
if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, margin) == NS_OK)
{
nscoord height = desiredSize.height + margin.top + margin.bottom;
nscoord height = rect.height + margin.top + margin.bottom;
if (height > aState.maxCellVertSpace) {
aState.maxCellVertSpace = height;
}
}
}
// XXX We also need to recover the max element size if requested by the
// caller...
//
// We should be using GetReflowMetrics() to get information from the
// table cell, and that will include the max element size...
// XXX We also need to recover the max element size...
// Remember the frame that precedes aKidFrame
prevKidFrame = frame;
@ -687,20 +692,30 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
// Recover our reflow state
RecoverState(aState, kidFrame);
// Get the frame's margins
// Figure out the amount of available space for the child
nsMargin kidMargin;
aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame,kidMargin);
// Figure out the amount of available space for the child
// XXX Shakey...
nsSize kidAvailSize(aState.availSize);
nsSize kidAvailSize(aState.availSize); // XXX: top and bottom margins?
// Compute the x-origin for the child, taking into account straddlers (cells
// from prior rows with rowspans > 1)
nscoord x = ComputeCellXOffset(aState, kidFrame, kidMargin);
// Compute the x-origin for the child, taking into account straddlers (cells from prior
// rows with rowspans > 1)
nscoord x = kidMargin.left;
PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
for (PRInt32 colIndex=0; colIndex<cellColIndex; colIndex++)
{
x += aState.tableFrame->GetColumnWidth(colIndex);
}
// Compute the cell avail width from the column widths
nscoord availWidth = ComputeCellAvailWidth(aState, kidFrame);
// at this point, we know the column widths.
// so we get the avail width from the known column widths
PRInt32 cellStartingCol = ((nsTableCellFrame *)kidFrame)->GetColIndex();
PRInt32 cellColSpan = ((nsTableCellFrame *)kidFrame)->GetColSpan();
nscoord availWidth = 0;
for (PRInt32 numColSpan=0; numColSpan<cellColSpan; numColSpan++)
availWidth += aState.tableFrame->GetColumnWidth(cellStartingCol+numColSpan);
kidAvailSize.width = availWidth;
// Pass along the reflow command. Reflow the child with an unconstrained
@ -726,23 +741,16 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
kidReflowState.maxSize.width = NS_UNCONSTRAINEDSIZE;
status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState);
// Update the cell layout data. Note that we need to do this for both
// the data the cell maintains AND the data the table maintains...
nsCellLayoutData *kidLayoutData = ((nsTableCellFrame *)kidFrame)->GetCellLayoutData();
kidLayoutData->SetDesiredSize(&desiredSize);
kidLayoutData->SetMaxElementSize(&kidMaxElementSize);
kidLayoutData = aState.tableFrame->GetCellLayoutData((nsTableCellFrame*)kidFrame);
kidLayoutData->SetDesiredSize(&desiredSize);
kidLayoutData->SetMaxElementSize(&kidMaxElementSize);
// Update the cell layout data.
((nsTableCellFrame *)kidFrame)->SetPass1DesiredSize(desiredSize);
((nsTableCellFrame *)kidFrame)->SetPass1MaxElementSize(kidMaxElementSize);
// Now reflow the cell again this time constraining the width
// XXX Ignore for now the possibility that the column width has changed...
kidReflowState.maxSize.width = availWidth;
status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState);
// Place the child after taking into account its margin and attributes
// Place the child after taking into account it's margin and attributes
nscoord specifiedHeight = 0;
nscoord cellHeight = desiredSize.height;
nsIStyleContextPtr kidSC;
@ -767,7 +775,6 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
// begin special Nav4 compatibility code
if (0==cellWidth)
{
PRInt32 cellColIndex = ((nsTableCellFrame *)kidFrame)->GetColIndex();
cellWidth = aState.tableFrame->GetColumnWidth(cellColIndex);
}
// end special Nav4 compatibility code
@ -781,8 +788,8 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
// Now iterate over the remaining cells, and update our max cell
// height and our running x-offset
//
// We don't have to re-position the x-origin of any of the child frames
// that follow, because the column width hasn't changed...
// We don't have to re-position any of the child frames that follow, because
// the column width hasn't changed...
nscoord maxCellTopMargin = 0;
nscoord maxCellBottomMargin = 0;
kidFrame->GetNextSibling((nsIFrame*&)kidFrame);
@ -791,11 +798,9 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
nsRect rect;
kidFrame->GetRect(rect);
if (mMinRowSpan == rowSpan) {
nsSize desiredSize = ((nsTableCellFrame *)kidFrame)->GetPriorDesiredSize();
// Update maxCellHeight
if (desiredSize.height > aState.maxCellHeight) {
aState.maxCellHeight = desiredSize.height;
if (rect.height > aState.maxCellHeight) {
aState.maxCellHeight = rect.height;
}
// Update maxCellVertHeight
@ -803,7 +808,7 @@ nsresult nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext,
if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, margin) == NS_OK)
{
nscoord height = desiredSize.height + margin.top + margin.bottom;
nscoord height = rect.height + margin.top + margin.bottom;
if (height > aState.maxCellVertSpace) {
aState.maxCellVertSpace = height;
}
@ -899,16 +904,22 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext,
return result;
}
NS_METHOD
nsTableRowFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
nsIFrame* aParent,
nsIStyleContext* aStyleContext,
nsIFrame*& aContinuingFrame)
{
// Because rows are always complete we should never be asked to create
// a continuing frame
NS_ERROR("Unexpected request");
return NS_ERROR_NOT_IMPLEMENTED;
if (gsDebug1==PR_TRUE) printf("nsTableRowFrame::CreateContinuingFrame\n");
nsTableRowFrame* cf = new nsTableRowFrame(mContent, aParent);
if (nsnull == cf) {
return NS_ERROR_OUT_OF_MEMORY;
}
PrepareContinuingFrame(aPresContext, aParent, aStyleContext, cf);
aContinuingFrame = cf;
return NS_OK;
}
nsresult nsTableRowFrame::NewFrame( nsIFrame** aInstancePtrResult,

View File

@ -29,13 +29,11 @@
#include "nsIReflowCommand.h"
#ifdef NS_DEBUG
static PRBool gsDebug1 = PR_FALSE;
static PRBool gsDebug2 = PR_FALSE;
static PRBool gsDebug = PR_FALSE;
//#define NOISY
//#define NOISY_FLOW
#else
static const PRBool gsDebug1 = PR_FALSE;
static const PRBool gsDebug2 = PR_FALSE;
static const PRBool gsDebug = PR_FALSE;
#endif
NS_DEF_PTR(nsIStyleContext);
@ -195,7 +193,7 @@ void nsTableRowGroupFrame::PlaceChild( nsIPresContext* aPresContext,
nsSize* aMaxElementSize,
nsSize& aKidMaxElementSize)
{
if (PR_TRUE==gsDebug1)
if (PR_TRUE==gsDebug)
printf ("rowgroup: placing row at %d, %d, %d, %d\n",
aKidRect.x, aKidRect.y, aKidRect.width, aKidRect.height);
@ -256,7 +254,7 @@ PRBool nsTableRowGroupFrame::ReflowMappedChildren( nsIPresContext* aPresCon
#endif
#endif
NS_PRECONDITION(nsnull != mFirstChild, "no children");
if (gsDebug) printf("\n\nREFLOWMAPPED FOR ROW GROUP FRAME\n");
PRInt32 childCount = 0;
nsIFrame* prevKidFrame = nsnull;
@ -1039,7 +1037,7 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
const nsReflowState& aReflowState,
nsReflowStatus& aStatus)
{
if (gsDebug1==PR_TRUE)
if (gsDebug==PR_TRUE)
printf("nsTableRowGroupFrame::Reflow - aMaxSize = %d, %d\n",
aReflowState.maxSize.width, aReflowState.maxSize.height);
#ifdef NS_DEBUG
@ -1153,7 +1151,7 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext,
PostReflowCheck(aStatus);
#endif
if (gsDebug1==PR_TRUE)
if (gsDebug==PR_TRUE)
{
if (nsnull!=aDesiredSize.maxElementSize)
printf("nsTableRowGroupFrame::RR returning: %s with aDesiredSize=%d,%d, aMES=%d,%d\n",
@ -1181,7 +1179,7 @@ nsTableRowGroupFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
return NS_ERROR_OUT_OF_MEMORY;
}
PrepareContinuingFrame(aPresContext, aParent, aStyleContext, cf);
if (PR_TRUE==gsDebug1) printf("nsTableRowGroupFrame::CCF parent = %p, this=%p, cf=%p\n", aParent, this, cf);
if (PR_TRUE==gsDebug) printf("nsTableRowGroupFrame::CCF parent = %p, this=%p, cf=%p\n", aParent, this, cf);
aContinuingFrame = cf;
return NS_OK;
}