From 7e8cc1207bc59f4f0c4ceb73cd82414155ae9235 Mon Sep 17 00:00:00 2001 From: buster Date: Sat, 11 Jul 1998 00:00:31 +0000 Subject: [PATCH] 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 git-svn-id: svn://10.0.0.236/trunk@5322 18797224-902f-48f8-a5cc-f745e15eee43 --- .../table/src/BasicTableLayoutStrategy.cpp | 492 +++++++++------ .../html/table/src/BasicTableLayoutStrategy.h | 29 +- mozilla/layout/html/table/src/Makefile | 7 +- mozilla/layout/html/table/src/makefile.win | 23 +- .../html/table/src/nsCellLayoutData.cpp | 573 ------------------ .../layout/html/table/src/nsCellLayoutData.h | 197 ------ mozilla/layout/html/table/src/nsCellMap.cpp | 42 +- mozilla/layout/html/table/src/nsCellMap.h | 74 ++- .../layout/html/table/src/nsColLayoutData.cpp | 109 ---- .../layout/html/table/src/nsColLayoutData.h | 99 --- .../html/table/src/nsTableCellFrame.cpp | 524 +++++++++++++++- .../layout/html/table/src/nsTableCellFrame.h | 191 +++++- mozilla/layout/html/table/src/nsTableCol.cpp | 62 -- .../layout/html/table/src/nsTableColFrame.cpp | 93 +++ .../layout/html/table/src/nsTableColFrame.h | 16 +- .../layout/html/table/src/nsTableFrame.cpp | 437 +++++-------- mozilla/layout/html/table/src/nsTableFrame.h | 91 +-- mozilla/layout/html/table/src/nsTableRow.cpp | 1 - .../layout/html/table/src/nsTableRowFrame.cpp | 211 ++++--- .../html/table/src/nsTableRowGroupFrame.cpp | 16 +- .../tables/BasicTableLayoutStrategy.cpp | 492 +++++++++------ .../layout/tables/BasicTableLayoutStrategy.h | 29 +- mozilla/layout/tables/nsCellMap.cpp | 42 +- mozilla/layout/tables/nsCellMap.h | 74 ++- mozilla/layout/tables/nsTableCellFrame.cpp | 524 +++++++++++++++- mozilla/layout/tables/nsTableCellFrame.h | 191 +++++- mozilla/layout/tables/nsTableColFrame.cpp | 93 +++ mozilla/layout/tables/nsTableColFrame.h | 16 +- mozilla/layout/tables/nsTableFrame.cpp | 437 +++++-------- mozilla/layout/tables/nsTableFrame.h | 91 +-- mozilla/layout/tables/nsTableRowFrame.cpp | 211 ++++--- .../layout/tables/nsTableRowGroupFrame.cpp | 16 +- 32 files changed, 3018 insertions(+), 2485 deletions(-) delete mode 100644 mozilla/layout/html/table/src/nsCellLayoutData.cpp delete mode 100644 mozilla/layout/html/table/src/nsCellLayoutData.h delete mode 100644 mozilla/layout/html/table/src/nsColLayoutData.cpp delete mode 100644 mozilla/layout/html/table/src/nsColLayoutData.h create mode 100644 mozilla/layout/html/table/src/nsTableColFrame.cpp create mode 100644 mozilla/layout/tables/nsTableColFrame.cpp diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp index baadba77204..1101961df05 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -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; colIndexGetColumnLayoutData(); - 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; cellIndexElementAt(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 (1AppendElement(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; nextSpanningCellElementAt(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; iSetColumnWidth(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; colIndexGetRowCount(); + for (PRInt32 colIndex = 0; colIndexElementAt(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; cellIndexElementAt(cellIndex)); - if (nsnull==data) - { // For cells that span rows there's only cell layout data for the first row + for (PRInt32 rowIndex = 0; rowIndexGetCellAt(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; colIndexGetRowCount(); + + for (PRInt32 colIndex = 0; colIndexElementAt(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; rowIndexGetCellAt(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; cellIndexElementAt(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 (1GetColIndex()==colIndex)) + { // add this cell to span list iff we are currently processing the column the cell starts in SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth); 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; iGetColumnWidth(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; iGetColumnWidth(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; colIndexGetColumnWidth(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; colIndexGetRowCount(); + + for (PRInt32 colIndex = 0; colIndexElementAt(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; rowIndexGetCellAt(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; cellIndexElementAt(cellIndex)); - if (nsnull == data) { - // For cells that span rows there's only cell layout data for the first row + for (rowIndex = 0; rowIndexGetCellAt(rowIndex, colIndex); + if (nsnull==cellFrame) + { // there is no cell in this row that corresponds to this column + continue; + } + if (rowIndex!=cellFrame->GetRowIndex()) { + // For cells that span rows, we only figure it in once + NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check continue; } - 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 (1GetColumnWidth(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 (colWidthSetColumnWidth(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; colIndexGetColumnWidth(colIndex); + if (colWidthSetColumnWidth(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; colIndexGetColumnWidth(colIndex); + if (colWidth>aMinColWidths[colIndex]) + { + mTableFrame->SetColumnWidth(colIndex, colWidth-1); + addedWidth--; + } + } + } + if (0/* 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); - } -} - diff --git a/mozilla/layout/html/table/src/nsCellLayoutData.h b/mozilla/layout/html/table/src/nsCellLayoutData.h deleted file mode 100644 index 8d7d9eda77c..00000000000 --- a/mozilla/layout/html/table/src/nsCellLayoutData.h +++ /dev/null @@ -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 diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp index 3098842597e..21c9569e049 100644 --- a/mozilla/layout/html/table/src/nsCellMap.cpp +++ b/mozilla/layout/html/table/src/nsCellMap.cpp @@ -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;iElementAt(aColIndex)); +} + diff --git a/mozilla/layout/html/table/src/nsCellMap.h b/mozilla/layout/html/table/src/nsCellMap.h index 15f9e6c441a..998b53feac9 100644 --- a/mozilla/layout/html/table/src/nsCellMap.h +++ b/mozilla/layout/html/table/src/nsCellMap.h @@ -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 diff --git a/mozilla/layout/html/table/src/nsColLayoutData.cpp b/mozilla/layout/html/table/src/nsColLayoutData.cpp deleted file mode 100644 index 5a64d0944af..00000000000 --- a/mozilla/layout/html/table/src/nsColLayoutData.cpp +++ /dev/null @@ -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); - } - } -} - - diff --git a/mozilla/layout/html/table/src/nsColLayoutData.h b/mozilla/layout/html/table/src/nsColLayoutData.h deleted file mode 100644 index f9059469da9..00000000000 --- a/mozilla/layout/html/table/src/nsColLayoutData.h +++ /dev/null @@ -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 diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp index 3e3c60a90cd..6c19957a4fb 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp @@ -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) { diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.h b/mozilla/layout/html/table/src/nsTableCellFrame.h index ecdf04fce00..514edc5d33f 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.h +++ b/mozilla/layout/html/table/src/nsTableCellFrame.h @@ -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 diff --git a/mozilla/layout/html/table/src/nsTableCol.cpp b/mozilla/layout/html/table/src/nsTableCol.cpp index 157043324eb..9b966c09a43 100644 --- a/mozilla/layout/html/table/src/nsTableCol.cpp +++ b/mozilla/layout/html/table/src/nsTableCol.cpp @@ -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), diff --git a/mozilla/layout/html/table/src/nsTableColFrame.cpp b/mozilla/layout/html/table/src/nsTableColFrame.cpp new file mode 100644 index 00000000000..c628ea33e86 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableColFrame.cpp @@ -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; +} + diff --git a/mozilla/layout/html/table/src/nsTableColFrame.h b/mozilla/layout/html/table/src/nsTableColFrame.h index e06d27b313f..ed72fb5a4a6 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.h +++ b/mozilla/layout/html/table/src/nsTableColFrame.h @@ -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; }; diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index c983dd63f94..95b9a970da0 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -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; iElementAt(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; iGetColCount(); + PRInt32 numRows = mCellMap->GetRowCount(); + for (PRInt32 colIndex = 0; colIndexElementAt(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; iGetColCount(); + for (PRInt32 colIndex = 0; colIndexmColumnLayoutData) + 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; iGetStyleData(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; iGetMaxElementSize(); - 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; colIndexElementAt(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) { diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h index 9d15f173543..a87477a86e6 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.h +++ b/mozilla/layout/html/table/src/nsTableFrame.h @@ -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.
- * 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:
* calls SetStartColumnIndex on each nsTableColumn
@@ -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.
+ * 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? diff --git a/mozilla/layout/html/table/src/nsTableRow.cpp b/mozilla/layout/html/table/src/nsTableRow.cpp index 0c07cf1c1c9..d4cf2ea67f2 100644 --- a/mozilla/layout/html/table/src/nsTableRow.cpp +++ b/mozilla/layout/html/table/src/nsTableRow.cpp @@ -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" diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index 8505f4a296d..06480059afc 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -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; colIndexGetColumnWidth(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; numColSpanGetColumnWidth(cellColIndex+numColSpan); + if (0GetPriorAvailWidth()) { // 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; colIndexGetColumnWidth(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; numColSpanGetColumnWidth(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, diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 8c977341c19..f2b547638d2 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -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; } diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp index baadba77204..1101961df05 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp @@ -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; colIndexGetColumnLayoutData(); - 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; cellIndexElementAt(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 (1AppendElement(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; nextSpanningCellElementAt(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; iSetColumnWidth(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; colIndexGetRowCount(); + for (PRInt32 colIndex = 0; colIndexElementAt(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; cellIndexElementAt(cellIndex)); - if (nsnull==data) - { // For cells that span rows there's only cell layout data for the first row + for (PRInt32 rowIndex = 0; rowIndexGetCellAt(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; colIndexGetRowCount(); + + for (PRInt32 colIndex = 0; colIndexElementAt(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; rowIndexGetCellAt(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; cellIndexElementAt(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 (1GetColIndex()==colIndex)) + { // add this cell to span list iff we are currently processing the column the cell starts in SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth); 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; iGetColumnWidth(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; iGetColumnWidth(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; colIndexGetColumnWidth(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; colIndexGetRowCount(); + + for (PRInt32 colIndex = 0; colIndexElementAt(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; rowIndexGetCellAt(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; cellIndexElementAt(cellIndex)); - if (nsnull == data) { - // For cells that span rows there's only cell layout data for the first row + for (rowIndex = 0; rowIndexGetCellAt(rowIndex, colIndex); + if (nsnull==cellFrame) + { // there is no cell in this row that corresponds to this column + continue; + } + if (rowIndex!=cellFrame->GetRowIndex()) { + // For cells that span rows, we only figure it in once + NS_ASSERTION(1 != cellFrame->GetRowSpan(), "row index does not match row span"); // sanity check continue; } - 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 (1GetColumnWidth(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 (colWidthSetColumnWidth(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; colIndexGetColumnWidth(colIndex); + if (colWidthSetColumnWidth(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; colIndexGetColumnWidth(colIndex); + if (colWidth>aMinColWidths[colIndex]) + { + mTableFrame->SetColumnWidth(colIndex, colWidth-1); + addedWidth--; + } + } + } + if (0ElementAt(aColIndex)); +} + diff --git a/mozilla/layout/tables/nsCellMap.h b/mozilla/layout/tables/nsCellMap.h index 15f9e6c441a..998b53feac9 100644 --- a/mozilla/layout/tables/nsCellMap.h +++ b/mozilla/layout/tables/nsCellMap.h @@ -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 diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp index 3e3c60a90cd..6c19957a4fb 100644 --- a/mozilla/layout/tables/nsTableCellFrame.cpp +++ b/mozilla/layout/tables/nsTableCellFrame.cpp @@ -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) { diff --git a/mozilla/layout/tables/nsTableCellFrame.h b/mozilla/layout/tables/nsTableCellFrame.h index ecdf04fce00..514edc5d33f 100644 --- a/mozilla/layout/tables/nsTableCellFrame.h +++ b/mozilla/layout/tables/nsTableCellFrame.h @@ -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 diff --git a/mozilla/layout/tables/nsTableColFrame.cpp b/mozilla/layout/tables/nsTableColFrame.cpp new file mode 100644 index 00000000000..c628ea33e86 --- /dev/null +++ b/mozilla/layout/tables/nsTableColFrame.cpp @@ -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; +} + diff --git a/mozilla/layout/tables/nsTableColFrame.h b/mozilla/layout/tables/nsTableColFrame.h index e06d27b313f..ed72fb5a4a6 100644 --- a/mozilla/layout/tables/nsTableColFrame.h +++ b/mozilla/layout/tables/nsTableColFrame.h @@ -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; }; diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index c983dd63f94..95b9a970da0 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -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; iElementAt(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; iGetColCount(); + PRInt32 numRows = mCellMap->GetRowCount(); + for (PRInt32 colIndex = 0; colIndexElementAt(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; iGetColCount(); + for (PRInt32 colIndex = 0; colIndexmColumnLayoutData) + 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; iGetStyleData(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; iGetMaxElementSize(); - 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; colIndexElementAt(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) { diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h index 9d15f173543..a87477a86e6 100644 --- a/mozilla/layout/tables/nsTableFrame.h +++ b/mozilla/layout/tables/nsTableFrame.h @@ -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.
- * 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:
* calls SetStartColumnIndex on each nsTableColumn
@@ -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.
+ * 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? diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index 8505f4a296d..06480059afc 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -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; colIndexGetColumnWidth(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; numColSpanGetColumnWidth(cellColIndex+numColSpan); + if (0GetPriorAvailWidth()) { // 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; colIndexGetColumnWidth(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; numColSpanGetColumnWidth(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, diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index 8c977341c19..f2b547638d2 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -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; }