added nsITableLayoutStrategy as the interface for objects that manage

table column balancing.  Implemented in BasicTableLayoutStrategy (HTML4-spec).
nsTableFrame instantiates a strategy depending on the compatibility mode.
This commit is contained in:
buster 1998-04-30 17:57:09 +00:00
parent 3b7fcc1c7a
commit a972bb8d29
12 changed files with 2353 additions and 1748 deletions

View File

@ -0,0 +1,821 @@
/* -*- 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 <stdio.h>
#include "BasicTableLayoutStrategy.h"
#include "nsTableFrame.h"
#include "nsColLayoutData.h"
#include "nsCellLayoutData.h"
#include "nsTableCol.h"
#include "nsTableCellFrame.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
#include "nsIPtr.h"
NS_DEF_PTR(nsTableCol);
NS_DEF_PTR(nsTableCell);
NS_DEF_PTR(nsIStyleContext);
static NS_DEFINE_IID(kStyleBorderSID, NS_STYLEBORDER_SID);
static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID);
static NS_DEFINE_IID(kStylePositionSID, NS_STYLEPOSITION_SID);
static NS_DEFINE_IID(kStyleSpacingSID, NS_STYLESPACING_SID);
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
static PRBool gsDebugCLD = PR_FALSE;
static PRBool gsTiming = PR_FALSE;
static PRBool gsDebugMBP = PR_FALSE;
#else
static const PRBool gsDebug = PR_FALSE;
static const PRBool gsDebugCLD = PR_FALSE;
static const PRBool gsTiming = PR_FALSE;
static const PRBool gsDebugMBP = PR_FALSE;
#endif
//ZZZ TOTAL HACK
PRBool isTableAutoWidth = PR_TRUE;
PRBool isAutoColumnWidths = PR_TRUE;
PRBool TableIsAutoWidth()
{ // ZZZ: TOTAL HACK
return isTableAutoWidth;
}
PRBool AutoColumnWidths()
{ // ZZZ: TOTAL HACK
return isAutoColumnWidths;
}
BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame)
{
mTableFrame = aFrame;
}
BasicTableLayoutStrategy::~BasicTableLayoutStrategy()
{
}
PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresContext,
PRInt32 aMaxWidth,
PRInt32 aNumCols,
PRInt32 &aTotalFixedWidth,
PRInt32 &aMinTableWidth,
PRInt32 &aMaxTableWidth,
nsSize* aMaxElementSize)
{
PRBool result = PR_TRUE;
// Step 1 - assign the width of all fixed-width columns
AssignFixedColumnWidths(aPresContext, aMaxWidth, aNumCols,
aTotalFixedWidth, aMinTableWidth, aMaxTableWidth);
if (nsnull!=aMaxElementSize)
{
aMaxElementSize->width = aMinTableWidth;
if (gsDebug) printf(" setting aMaxElementSize->width = %d\n", aMaxElementSize->width);
}
else
{
if (gsDebug) printf(" nsnull aMaxElementSize\n");
}
// Step 2 - assign the width of all proportional-width columns in the remaining space
PRInt32 availWidth = aMaxWidth - aTotalFixedWidth;
if (gsDebug==PR_TRUE) printf ("Step 2...\n availWidth = %d\n", availWidth);
if (TableIsAutoWidth())
{
if (gsDebug==PR_TRUE) printf (" calling BalanceProportionalColumnsForAutoWidthTable\n");
result = BalanceProportionalColumnsForAutoWidthTable(aPresContext,
availWidth, aMaxWidth,
aMinTableWidth, aMaxTableWidth);
}
else
{
if (gsDebug==PR_TRUE) printf (" calling BalanceProportionalColumnsForSpecifiedWidthTable\n");
result = BalanceProportionalColumnsForSpecifiedWidthTable(aPresContext,
availWidth, aMaxWidth,
aMinTableWidth, aMaxTableWidth);
}
return result;
}
/*
STEP 1
for every col
if the col has a fixed width
set the width to max(fixed width, maxElementSize)
if the cell spans columns, divide the cell width between the columns
else skip it for now
take borders and padding into account
STEP 2
determine the min and max size for the table width
if col is proportionately specified
if (col width specified to 0)
col width = minColWidth
else if (minTableWidth >= aMaxSize.width)
set col widths to min, install a hor. scroll bar
else if (maxTableWidth <= aMaxSize.width)
set each col to its max size
else
W = aMaxSize.width - minTableWidth
D = maxTableWidth - minTableWidth
for each col
d = maxColWidth - minColWidth
col width = minColWidth + ((d*W)/D)
STEP 3
if there is space left over
for every col
if col is proportionately specified
add space to col width until it is that proportion of the table width
do this non-destructively in case there isn't enough space
if there isn't enough space as determined in the prior step,
add space in proportion to the proportionate width attribute
*/
// Step 1 - assign the width of all fixed-width columns,
// and calculate min/max table width
PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresContext,
PRInt32 maxWidth,
PRInt32 aNumCols,
PRInt32 &aTotalFixedWidth,
PRInt32 &aMinTableWidth,
PRInt32 &aMaxTableWidth)
{
#ifdef DEBUG
nsIFrame *tablePIF=nsnull;
mTableFrame->GetPrevInFlow(tablePIF);
NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!");
#endif
if (gsDebug==PR_TRUE) printf (" AssignFixedColumnWidths\n");
nsVoidArray *spanList=nsnull;
for (PRInt32 colIndex = 0; colIndex<aNumCols; colIndex++)
{
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
NS_ASSERTION(nsnull != colData, "bad column data");
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
NS_ASSERTION(col.IsNotNull(), "bad col");
// need to track min/max column width for setting min/max table widths
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);
#if XXX_need_access_to_column_frame_help
// Get the columns's style
nsIStyleContextPtr colSC;
colFrame->GetStyleContext(aPresContext, colSC.AssignRef());
nsStylePosition* colPosition = (nsStylePosition*)
colSC->GetData(kStylePositionSID);
// Get column width if it has one
PRBool haveColWidth = PR_FALSE;
nscoord colWidth;
switch (colPosition->mWidthFlags) {
default:
case NS_STYLE_POSITION_VALUE_AUTO:
case NS_STYLE_POSITION_VALUE_INHERIT:
break;
case NS_STYLE_POSITION_VALUE_LENGTH:
haveColWidth = PR_TRUE;
colWidth = colPosition->mWidth;
break;
case NS_STYLE_POSITION_VALUE_PCT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
//XXX haveColWidth = PR_TRUE;
//XXX colWidth = colPosition->mWidthPCT * something;
break;
}
#endif
/* Scan the column, simulatneously assigning fixed column widths
* and computing the min/max column widths
*/
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
nsSize * cellMinSize = data->GetMaxElementSize();
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
PRInt32 colSpan = data->GetCellFrame()->GetColSpan();
if (gsDebug==PR_TRUE)
printf (" for cell %d with colspan=%d, min = %d,%d and des = %d,%d\n",
cellIndex, colSpan, cellMinSize->width, cellMinSize->height,
cellDesiredSize->width, cellDesiredSize->height);
PRBool haveCellWidth = PR_FALSE;
nscoord cellWidth;
/*
* The first cell in a column (in row 0) has special standing.
* if the first cell has a width specification, it overrides the
* COL width
*/
if (0==cellIndex)
{
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(0));
nsTableCellFrame *cellFrame = data->GetCellFrame();
nsTableCellPtr cell;
cellFrame->GetContent((nsIContent*&)(cell.AssignRef())); // cell: REFCNT++
// Get the cell's style
nsIStyleContextPtr cellSC;
cellFrame->GetStyleContext(aPresContext, cellSC.AssignRef());
nsStylePosition* cellPosition = (nsStylePosition*)
cellSC->GetData(kStylePositionSID);
switch (cellPosition->mWidthFlags) {
case NS_STYLE_POSITION_VALUE_LENGTH:
haveCellWidth = PR_TRUE;
cellWidth = cellPosition->mWidth;
break;
case NS_STYLE_POSITION_VALUE_PERCENT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
// XXX write me when pct/proportional are supported
// XXX haveCellWidth = PR_TRUE;
// XXX cellWidth = cellPosition->mWidth;
break;
default:
case NS_STYLE_POSITION_VALUE_INHERIT:
case NS_STYLE_POSITION_VALUE_AUTO:
break;
}
}
#if XXX_need_access_to_column_frame_help
switch (colPosition->mWidthFlags) {
default:
case NS_STYLE_POSITION_VALUE_AUTO:
case NS_STYLE_POSITION_VALUE_INHERIT:
break;
case NS_STYLE_POSITION_VALUE_LENGTH:
{
// 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 = max(cellMinSize->width, colPosition->mWidth);
if (mTableFrame->GetColumnWidth(colIndex) < widthForThisCell)
{
if (gsDebug) printf (" setting fixed width to %d\n",widthForThisCell);
mTableFrame->SetColumnWidth(colIndex, widthForThisCell);
maxColWidth = widthForThisCell;
}
}
break;
case NS_STYLE_POSITION_VALUE_PCT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
// XXX write me when pct/proportional are supported
break;
}
#endif
// regardless of the width specification, keep track of the
// min/max column widths
PRInt32 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (1<colSpan)
{
// add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
if (gsDebug) {
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
}
}
#if 0
// if the col is fixed-width, expand the col to the specified
// fixed width if necessary
if (colStyle->fixedWidth > mTableFrame->GetColumnWidth(colIndex))
mTableFrame->SetColumnWidth(colIndex, colStyle->fixedWidth);
// keep a running total of the amount of space taken up by all
// fixed-width columns
aTotalFixedWidth += mTableFrame->GetColumnWidths(colIndex);
if (gsDebug) {
printf (" after col %d, aTotalFixedWidth = %d\n",
colIndex, aTotalFixedWidth);
}
#endif
// add col[i] metrics to the running totals for the table min/max width
if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth)
aMinTableWidth += minColWidth; // SEC: insets!
if (aMinTableWidth<=0)
aMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth)
aMaxTableWidth += maxColWidth; // SEC: insets!
if (aMaxTableWidth<=0)
aMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
if (gsDebug==PR_TRUE)
printf (" after this col, minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth);
} // end Step 1 for fixed-width columns
if (nsnull!=spanList)
delete spanList;
return PR_TRUE;
}
PRBool BasicTableLayoutStrategy::BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
#ifdef DEBUG
nsIFrame *tablePIF=nsnull;
mTableFrame->GetPrevInFlow(tablePIF);
NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!");
#endif
PRBool result = PR_TRUE;
if (NS_UNCONSTRAINEDSIZE==aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else if (aMinTableWidth > aMaxWidth)
{ // the table doesn't fit in the available space
if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n");
result = SetColumnsToMinWidth(aPresContext);
}
else if (aMaxTableWidth <= aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else
{ // the table fits somewhere between its min and desired size
if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n");
result = BalanceColumnsHTML4Constrained(aPresContext, aAvailWidth,
aMaxWidth, aMinTableWidth, aMaxTableWidth);
}
return result;
}
PRBool BasicTableLayoutStrategy::BalanceProportionalColumnsForAutoWidthTable( nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
PRBool result = PR_TRUE;
if (NS_UNCONSTRAINEDSIZE==aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else if (aMinTableWidth > aMaxWidth)
{ // the table doesn't fit in the available space
if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n");
result = SetColumnsToMinWidth(aPresContext);
}
else if (aMaxTableWidth <= aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else
{ // the table fits somewhere between its min and desired size
if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n");
result = BalanceColumnsHTML4Constrained(aPresContext, aAvailWidth,
aMaxWidth, aMinTableWidth, aMaxTableWidth);
}
return result;
}
PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresContext)
{
PRBool result = PR_TRUE;
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
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
nsStylePosition* colPosition = nsnull;
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
nsSize * cellMinSize = data->GetMaxElementSize();
NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize");
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
if (minColWidth < cellMinSize->width)
minColWidth = cellMinSize->width;
if (maxColWidth < cellDesiredSize->width)
maxColWidth = cellDesiredSize->width;
/*
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
*/
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",
colIndex, mTableFrame->IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
mTableFrame->SetColumnWidth(colIndex, minColWidth);
if (gsDebug==PR_TRUE)
printf (" 2: col %d, set to width = %d\n", colIndex, mTableFrame->GetColumnWidth(colIndex));
}
}
}
return result;
}
PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresContext,
PRInt32 aAvailWidth)
{
#ifdef DEBUG
nsIFrame *tablePIF=nsnull;
mTableFrame->GetPrevInFlow(tablePIF);
NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!");
#endif
PRBool result = PR_TRUE;
nsVoidArray *spanList=nsnull;
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
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 columnFrame to ask the style question
nsStylePosition* colPosition = nsnull;
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
PRInt32 colSpan = data->GetCellFrame()->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");
PRInt32 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
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);
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
if (1<colSpan)
{ // add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",
colIndex, mTableFrame->IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
printf (" aAvailWidth = %d\n", aAvailWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
#if XXX_bug_kipp_about_this
if (0==colStyle->proportionalWidth)
{ // col width is specified to be the minimum
mTableFrame->SetColumnWidth(colIndex, minColWidth);
if (gsDebug==PR_TRUE)
printf (" 3 (0): col %d set to min width = %d because style set proportionalWidth=0\n",
colIndex, mTableFrame->GetColumnWidth(colIndex));
}
else // BUG? else? other code below has the else
#endif
if (PR_TRUE==AutoColumnWidths())
{ // give each remaining column it's desired width
// if there is width left over, we'll factor that in after this loop is complete
mTableFrame->SetColumnWidth(colIndex, maxColWidth);
if (gsDebug==PR_TRUE)
printf (" 3a: col %d with availWidth %d, set to width = %d\n",
colIndex, aAvailWidth, mTableFrame->GetColumnWidth(colIndex));
}
else
{ // give each remaining column an equal percentage of the remaining space
PRInt32 percentage = -1;
if (NS_UNCONSTRAINEDSIZE==aAvailWidth)
{
mTableFrame->SetColumnWidth(colIndex, maxColWidth);
}
else
{
#if XXX_bug_kipp_about_this
percentage = colStyle->proportionalWidth;
if (-1==percentage)
#endif
percentage = 100/numCols;
mTableFrame->SetColumnWidth(colIndex, (percentage*aAvailWidth)/100);
// if the column was computed to be too small, enlarge the column
if (mTableFrame->GetColumnWidth(colIndex) <= minColWidth)
mTableFrame->SetColumnWidth(colIndex, minColWidth);
}
if (gsDebug==PR_TRUE)
printf (" 3b: col %d given %d percent of availWidth %d, set to width = %d\n",
colIndex, percentage, aAvailWidth, mTableFrame->GetColumnWidth(colIndex));
}
}
}
}
if (nsnull!=spanList)
delete spanList;
return result;
}
PRBool BasicTableLayoutStrategy::BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
#ifdef DEBUG
nsIFrame *tablePIF=nsnull;
mTableFrame->GetPrevInFlow(tablePIF);
NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!");
#endif
PRBool result = PR_TRUE;
PRInt32 maxOfAllMinColWidths = 0;
nsVoidArray *spanList=nsnull;
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
#if XXX_bug_kipp_about_this
// XXX BUG: mStyleContext is for the table frame not for the column.
nsStyleMolecule* colStyle =
(nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
#else
nsStylePosition* colPosition = nsnull;
#endif
nsVoidArray *cells = colData->GetCells();
PRInt32 minColWidth = 0;
PRInt32 maxColWidth = 0;
PRInt32 numCells = cells->Count();
if (gsDebug==PR_TRUE) printf (" for col %d\n", colIndex);
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
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 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (1<colSpan)
{
// add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",
colIndex, mTableFrame->IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth);
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
printf (" aAvailWidth = %d\n", aAvailWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
// the table fits in the space somewhere between its min and max size
// so dole out the available space appropriately
#if XXX_bug_kipp_about_this
if (0==colStyle->proportionalWidth)
{ // col width is specified to be the minimum
mTableFrame->SetColumnWidth(colIndex, minColWidth);
if (gsDebug==PR_TRUE)
printf (" 4 (0): col %d set to min width = %d because style set proportionalWidth=0\n",
colIndex, mTableFrame->GetColumnWidth(colIndex));
}
else
#endif
if (AutoColumnWidths())
{
PRInt32 W = aMaxWidth - aMinTableWidth;
PRInt32 D = aMaxTableWidth - aMinTableWidth;
PRInt32 d = maxColWidth - minColWidth;
mTableFrame->SetColumnWidth(colIndex, minColWidth + ((d*W)/D));
if (gsDebug==PR_TRUE)
printf (" 4 auto-width: col %d W=%d D=%d d=%d, set to width = %d\n",
colIndex, W, D, d, mTableFrame->GetColumnWidth(colIndex));
}
else
{ // give each remaining column an equal percentage of the remaining space
#if XXX_bug_kipp_about_this
PRInt32 percentage = colStyle->proportionalWidth;
if (-1==percentage)
#endif
PRInt32 percentage = 100/numCols;
mTableFrame->SetColumnWidth(colIndex, (percentage*aAvailWidth)/100);
// if the column was computed to be too small, enlarge the column
if (mTableFrame->GetColumnWidth(colIndex) <= minColWidth)
{
mTableFrame->SetColumnWidth(colIndex, minColWidth);
if (maxOfAllMinColWidths < minColWidth)
maxOfAllMinColWidths = minColWidth;
}
if (gsDebug==PR_TRUE)
{
printf (" 4 equal width: col %d given %d percent of availWidth %d, set to width = %d\n",
colIndex, percentage, aAvailWidth, mTableFrame->GetColumnWidth(colIndex));
if (0!=maxOfAllMinColWidths)
printf(" and setting maxOfAllMins to %d\n", maxOfAllMinColWidths);
}
}
}
}
}
// post-process if necessary
// if columns have equal width, and some column's content couldn't squeeze into the computed size,
// then expand every column to the min size of the column with the largest min size
if (!AutoColumnWidths() && 0!=maxOfAllMinColWidths)
{
if (gsDebug==PR_TRUE) printf(" EqualColWidths specified, so setting all col widths to %d\n", maxOfAllMinColWidths);
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
mTableFrame->SetColumnWidth(colIndex, maxOfAllMinColWidths);
}
if (nsnull!=spanList)
delete spanList;
return result;
}

View File

@ -0,0 +1,179 @@
/* -*- 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 BasicTableLayoutStrategy_h__
#define BasicTableLayoutStrategy_h__
#include "nscore.h"
#include "nsITableLayoutStrategy.h"
class nsTableFrame;
/* ----------- SpanInfo ---------- */
struct SpanInfo
{
PRInt32 span;
PRInt32 cellMinWidth;
PRInt32 cellDesiredWidth;
SpanInfo(PRInt32 aSpan, PRInt32 aMinWidth, PRInt32 aDesiredWidth)
{
span = aSpan;
cellMinWidth = aMinWidth;
cellDesiredWidth = aDesiredWidth;
};
~SpanInfo() {};
};
/* ---------- BasicTableLayoutStrategy ---------- */
class BasicTableLayoutStrategy : public nsITableLayoutStrategy
{
public:
BasicTableLayoutStrategy(nsTableFrame *aFrame);
~BasicTableLayoutStrategy();
virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext,
PRInt32 aMaxWidth,
PRInt32 aNumCols,
PRInt32 &aTotalFixedWidth,
PRInt32 &aMinTableWidth,
PRInt32 &aMaxTableWidth,
nsSize* aMaxElementSize);
/** assign widths for each column that has fixed width.
* Computes the minimum and maximum table widths.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aMaxWidth the maximum width of the table
* @param aNumCols the total number of columns in the table
* @param aTableStyle the resolved style for the table
* @param aTotalFixedWidth out param, the sum of the fixed width columns
* @param aMinTableWidth out param, the min possible table width
* @param aMaxTableWidth out param, the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: should be renamed to "AssignKnownWidthInformation
*/
virtual PRBool AssignFixedColumnWidths(nsIPresContext* aPresContext,
PRInt32 aMaxWidth,
PRInt32 aNumCols,
PRInt32 & aTotalFixedWidth,
PRInt32 & aMinTableWidth,
PRInt32 & aMaxTableWidth);
/** assign widths for each column that has proportional width inside a table that
* has a fixed width.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space.)
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForAutoWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
/** assign the minimum allowed width for each column that has proportional width.
* Typically called when the min table width doesn't fit in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool SetColumnsToMinWidth(nsIPresContext* aPresContext);
/** assign the maximum allowed width for each column that has proportional width.
* Typically called when the desired max table width fits in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool BalanceColumnsTableFits(nsIPresContext* aPresContext,
PRInt32 aAvailWidth);
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space) according to the
* HTML 4 specification.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
protected:
nsTableFrame * mTableFrame;
};
#endif

View File

@ -23,6 +23,7 @@ LIBRARY_NAME = raptorhtmltable_s
# Note the sophisticated alphabetical ordering :-|
CPPSRCS = \
BasicTableLayoutStrategy.cpp \
nsCellLayoutData.cpp \
nsCellMap.cpp \
nsColLayoutData.cpp \

View File

@ -29,7 +29,8 @@ CPPSRCS=nsCellLayoutData.cpp nsCellMap.cpp nsColLayoutData.cpp \
nsTableCellFrame.cpp nsTableCol.cpp nsTableColGroup.cpp \
nsTableColGroupFrame.cpp nsTableContent.cpp nsTableFrame.cpp \
nsTableOuterFrame.cpp nsTablePart.cpp nsTableRow.cpp \
nsTableRowFrame.cpp nsTableRowGroup.cpp nsTableRowGroupFrame.cpp
nsTableRowFrame.cpp nsTableRowGroup.cpp nsTableRowGroupFrame.cpp \
BasicTableLayoutStrategy.cpp
CPP_OBJS=.\$(OBJDIR)\nsCellLayoutData.obj .\$(OBJDIR)\nsCellMap.obj \
.\$(OBJDIR)\nsColLayoutData.obj .\$(OBJDIR)\nsTableCaption.obj \
@ -39,7 +40,8 @@ CPP_OBJS=.\$(OBJDIR)\nsCellLayoutData.obj .\$(OBJDIR)\nsCellMap.obj \
.\$(OBJDIR)\nsTableContent.obj .\$(OBJDIR)\nsTableFrame.obj \
.\$(OBJDIR)\nsTableOuterFrame.obj .\$(OBJDIR)\nsTablePart.obj \
.\$(OBJDIR)\nsTableRow.obj .\$(OBJDIR)\nsTableRowFrame.obj \
.\$(OBJDIR)\nsTableRowGroup.obj .\$(OBJDIR)\nsTableRowGroupFrame.obj
.\$(OBJDIR)\nsTableRowGroup.obj .\$(OBJDIR)\nsTableRowGroupFrame.obj \
.\$(OBJDIR)\BasicTableLayoutStrategy.obj
LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor \
-I..\..\base\src -I..\..\style\src \

View File

@ -0,0 +1,159 @@
/* -*- 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 nsITableLayoutStrategy_h__
#define nsITableLayoutStrategy_h__
#include "nscore.h"
#include "nsSize.h"
class nsIPresContext;
class nsITableLayoutStrategy
{
public:
/** assign widths for each column, taking into account the table content, the effective style,
* the layout constraints, and the compatibility mode. Sets mColumnWidths as a side effect.
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aMaxSize the height and width constraints
* @param aMaxElementSize the min size of the largest indivisible object
*/
virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext,
PRInt32 maxWidth,
PRInt32 aNumCols,
PRInt32 &aTotalFixedWidth,
PRInt32 &aMinTableWidth,
PRInt32 &aMaxTableWidth,
nsSize* aMaxElementSize)=0;
/** assign widths for each column that has fixed width.
* Computes the minimum and maximum table widths.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aMaxWidth the maximum width of the table
* @param aNumCols the total number of columns in the table
* @param aTableStyle the resolved style for the table
* @param aTotalFixedWidth out param, the sum of the fixed width columns
* @param aMinTableWidth out param, the min possible table width
* @param aMaxTableWidth out param, the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: should be renamed to "AssignKnownWidthInformation
*/
virtual PRBool AssignFixedColumnWidths(nsIPresContext* aPresContext,
PRInt32 aMaxWidth,
PRInt32 aNumCols,
PRInt32 & aTotalFixedWidth,
PRInt32 & aMinTableWidth,
PRInt32 & aMaxTableWidth)=0;
/** assign widths for each column that has proportional width inside a table that
* has a fixed width.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)=0;
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space.)
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForAutoWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)=0;
/** assign the minimum allowed width for each column that has proportional width.
* Typically called when the min table width doesn't fit in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool SetColumnsToMinWidth(nsIPresContext* aPresContext)=0;
/** assign the maximum allowed width for each column that has proportional width.
* Typically called when the desired max table width fits in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool BalanceColumnsTableFits(nsIPresContext* aPresContext,
PRInt32 aAvailWidth)=0;
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space) according to the
* HTML 4 specification.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)=0;
};
#endif

View File

@ -29,6 +29,9 @@
#include "nsTableRowFrame.h"
#include "nsTableRowGroupFrame.h"
#include "nsColLayoutData.h"
#include "BasicTableLayoutStrategy.h"
#include "nsIPresContext.h"
#include "nsCSSRendering.h"
#include "nsStyleConsts.h"
@ -135,26 +138,6 @@ struct InnerTableReflowState {
/* ----------- SpanInfo ---------- */
struct SpanInfo
{
PRInt32 span;
PRInt32 cellMinWidth;
PRInt32 cellDesiredWidth;
SpanInfo(PRInt32 aSpan, PRInt32 aMinWidth, PRInt32 aDesiredWidth)
{
span = aSpan;
cellMinWidth = aMinWidth;
cellDesiredWidth = aDesiredWidth;
};
~SpanInfo() {};
};
/* ----------- nsTableFrame ---------- */
@ -164,6 +147,7 @@ nsTableFrame::nsTableFrame(nsIContent* aContent,
: nsContainerFrame(aContent, aIndexInParent, aParentFrame),
mColumnLayoutData(nsnull),
mColumnWidths(nsnull),
mTableLayoutStrategy(nsnull),
mFirstPassValid(PR_FALSE),
mPass(kPASS_UNDEFINED),
mIsInvariantWidth(PR_FALSE)
@ -194,6 +178,8 @@ nsTableFrame::~nsTableFrame()
DeleteColumnLayoutData();
if (nsnull!=mColumnWidths)
delete [] mColumnWidths;
if (nsnull!=mTableLayoutStrategy)
delete mTableLayoutStrategy;
}
@ -1561,725 +1547,17 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
if (gsDebug) printf (" maxWidth=%d from aMaxSize=%d,%d\n", maxWidth, aMaxSize.width, aMaxSize.height);
// Step 1 - assign the width of all fixed-width columns
AssignFixedColumnWidths(aPresContext, maxWidth, numCols,
totalFixedWidth, minTableWidth, maxTableWidth);
if (nsnull!=aMaxElementSize)
{
aMaxElementSize->width = minTableWidth;
if (gsDebug) printf(" setting aMaxElementSize->width = %d\n", aMaxElementSize->width);
// based on the compatibility mode, create a table layout strategy
if (nsnull==mTableLayoutStrategy)
{ // TODO: build a different strategy based on the compatibility mode
mTableLayoutStrategy = new BasicTableLayoutStrategy(this);
}
else
{
if (gsDebug) printf(" nsnull aMaxElementSize\n");
}
// Step 2 - assign the width of all proportional-width columns in the remaining space
PRInt32 availWidth=maxWidth - totalFixedWidth;
if (gsDebug==PR_TRUE) printf ("Step 2...\n availWidth = %d\n", availWidth);
if (TableIsAutoWidth())
{
if (gsDebug==PR_TRUE) printf (" calling BalanceProportionalColumnsForAutoWidthTable\n");
BalanceProportionalColumnsForAutoWidthTable(aPresContext,
availWidth, maxWidth,
minTableWidth, maxTableWidth);
}
else
{
if (gsDebug==PR_TRUE) printf (" calling BalanceProportionalColumnsForSpecifiedWidthTable\n");
BalanceProportionalColumnsForSpecifiedWidthTable(aPresContext,
availWidth, maxWidth,
minTableWidth, maxTableWidth);
}
/*
STEP 1
for every col
if the col has a fixed width
set the width to max(fixed width, maxElementSize)
if the cell spans columns, divide the cell width between the columns
else skip it for now
take borders and padding into account
STEP 2
determine the min and max size for the table width
if col is proportionately specified
if (col width specified to 0)
col width = minColWidth
else if (minTableWidth >= aMaxSize.width)
set col widths to min, install a hor. scroll bar
else if (maxTableWidth <= aMaxSize.width)
set each col to its max size
else
W = aMaxSize.width - minTableWidth
D = maxTableWidth - minTableWidth
for each col
d = maxColWidth - minColWidth
col width = minColWidth + ((d*W)/D)
STEP 3
if there is space left over
for every col
if col is proportionately specified
add space to col width until it is that proportion of the table width
do this non-destructively in case there isn't enough space
if there isn't enough space as determined in the prior step,
add space in proportion to the proportionate width attribute
*/
mTableLayoutStrategy->BalanceColumnWidths(aPresContext, maxWidth, numCols,
totalFixedWidth, minTableWidth, maxTableWidth,
aMaxElementSize);
}
// Step 1 - assign the width of all fixed-width columns,
// and calculate min/max table width
PRBool nsTableFrame::AssignFixedColumnWidths(nsIPresContext* aPresContext,
PRInt32 maxWidth,
PRInt32 aNumCols,
PRInt32 &aTotalFixedWidth,
PRInt32 &aMinTableWidth,
PRInt32 &aMaxTableWidth)
{
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
if (gsDebug==PR_TRUE) printf (" AssignFixedColumnWidths\n");
nsVoidArray *spanList=nsnull;
for (PRInt32 colIndex = 0; colIndex<aNumCols; colIndex++)
{
nsVoidArray *columnLayoutData = GetColumnLayoutData();
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
NS_ASSERTION(nsnull != colData, "bad column data");
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
NS_ASSERTION(col.IsNotNull(), "bad col");
// need to track min/max column width for setting min/max table widths
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);
#if XXX_need_access_to_column_frame_help
// Get the columns's style
nsIStyleContextPtr colSC;
colFrame->GetStyleContext(aPresContext, colSC.AssignRef());
nsStylePosition* colPosition = (nsStylePosition*)
colSC->GetData(kStylePositionSID);
// Get column width if it has one
PRBool haveColWidth = PR_FALSE;
nscoord colWidth;
switch (colPosition->mWidthFlags) {
default:
case NS_STYLE_POSITION_VALUE_AUTO:
case NS_STYLE_POSITION_VALUE_INHERIT:
break;
case NS_STYLE_POSITION_VALUE_LENGTH:
haveColWidth = PR_TRUE;
colWidth = colPosition->mWidth;
break;
case NS_STYLE_POSITION_VALUE_PCT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
//XXX haveColWidth = PR_TRUE;
//XXX colWidth = colPosition->mWidthPCT * something;
break;
}
#endif
/* Scan the column, simulatneously assigning fixed column widths
* and computing the min/max column widths
*/
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
nsSize * cellMinSize = data->GetMaxElementSize();
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
PRInt32 colSpan = data->GetCellFrame()->GetColSpan();
if (gsDebug==PR_TRUE)
printf (" for cell %d with colspan=%d, min = %d,%d and des = %d,%d\n",
cellIndex, colSpan, cellMinSize->width, cellMinSize->height,
cellDesiredSize->width, cellDesiredSize->height);
PRBool haveCellWidth = PR_FALSE;
nscoord cellWidth;
/*
* The first cell in a column (in row 0) has special standing.
* if the first cell has a width specification, it overrides the
* COL width
*/
if (0==cellIndex)
{
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(0));
nsTableCellFrame *cellFrame = data->GetCellFrame();
nsTableCellPtr cell;
cellFrame->GetContent((nsIContent*&)(cell.AssignRef())); // cell: REFCNT++
// Get the cell's style
nsIStyleContextPtr cellSC;
cellFrame->GetStyleContext(aPresContext, cellSC.AssignRef());
nsStylePosition* cellPosition = (nsStylePosition*)
cellSC->GetData(kStylePositionSID);
switch (cellPosition->mWidthFlags) {
case NS_STYLE_POSITION_VALUE_LENGTH:
haveCellWidth = PR_TRUE;
cellWidth = cellPosition->mWidth;
break;
case NS_STYLE_POSITION_VALUE_PERCENT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
// XXX write me when pct/proportional are supported
// XXX haveCellWidth = PR_TRUE;
// XXX cellWidth = cellPosition->mWidth;
break;
default:
case NS_STYLE_POSITION_VALUE_INHERIT:
case NS_STYLE_POSITION_VALUE_AUTO:
break;
}
}
#if XXX_need_access_to_column_frame_help
switch (colPosition->mWidthFlags) {
default:
case NS_STYLE_POSITION_VALUE_AUTO:
case NS_STYLE_POSITION_VALUE_INHERIT:
break;
case NS_STYLE_POSITION_VALUE_LENGTH:
{
// 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 = max(cellMinSize->width, colPosition->mWidth);
if (mColumnWidths[colIndex] < widthForThisCell)
{
if (gsDebug) printf (" setting fixed width to %d\n",widthForThisCell);
mColumnWidths[colIndex] = widthForThisCell;
maxColWidth = widthForThisCell;
}
}
break;
case NS_STYLE_POSITION_VALUE_PCT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
// XXX write me when pct/proportional are supported
break;
}
#endif
// regardless of the width specification, keep track of the
// min/max column widths
PRInt32 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (1<colSpan)
{
// add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
if (gsDebug) {
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
}
}
#if 0
// if the col is fixed-width, expand the col to the specified
// fixed width if necessary
if (colStyle->fixedWidth > mColumnWidths[colIndex])
mColumnWidths[colIndex] = colStyle->fixedWidth;
// keep a running total of the amount of space taken up by all
// fixed-width columns
aTotalFixedWidth += mColumnWidths[colIndex];
if (gsDebug) {
printf (" after col %d, aTotalFixedWidth = %d\n",
colIndex, aTotalFixedWidth);
}
#endif
// add col[i] metrics to the running totals for the table min/max width
if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth)
aMinTableWidth += minColWidth; // SEC: insets!
if (aMinTableWidth<=0)
aMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth)
aMaxTableWidth += maxColWidth; // SEC: insets!
if (aMaxTableWidth<=0)
aMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
if (gsDebug==PR_TRUE)
printf (" after this col, minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth);
} // end Step 1 for fixed-width columns
if (nsnull!=spanList)
delete spanList;
return PR_TRUE;
}
PRBool nsTableFrame::BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
PRBool result = PR_TRUE;
if (NS_UNCONSTRAINEDSIZE==aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else if (aMinTableWidth > aMaxWidth)
{ // the table doesn't fit in the available space
if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n");
result = SetColumnsToMinWidth(aPresContext);
}
else if (aMaxTableWidth <= aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else
{ // the table fits somewhere between its min and desired size
if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n");
result = BalanceColumnsHTML4Constrained(aPresContext, aAvailWidth,
aMaxWidth, aMinTableWidth, aMaxTableWidth);
}
return result;
}
PRBool nsTableFrame::BalanceProportionalColumnsForAutoWidthTable( nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
PRBool result = PR_TRUE;
if (NS_UNCONSTRAINEDSIZE==aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else if (aMinTableWidth > aMaxWidth)
{ // the table doesn't fit in the available space
if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n");
result = SetColumnsToMinWidth(aPresContext);
}
else if (aMaxTableWidth <= aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else
{ // the table fits somewhere between its min and desired size
if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n");
result = BalanceColumnsHTML4Constrained(aPresContext, aAvailWidth,
aMaxWidth, aMinTableWidth, aMaxTableWidth);
}
return result;
}
PRBool nsTableFrame::SetColumnsToMinWidth(nsIPresContext* aPresContext)
{
PRBool result = PR_TRUE;
nsVoidArray *columnLayoutData = GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
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
nsStylePosition* colPosition = nsnull;
if (PR_TRUE==IsProportionalWidth(colPosition))
{
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
nsSize * cellMinSize = data->GetMaxElementSize();
NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize");
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
if (minColWidth < cellMinSize->width)
minColWidth = cellMinSize->width;
if (maxColWidth < cellDesiredSize->width)
maxColWidth = cellDesiredSize->width;
/*
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
*/
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
mColumnWidths[colIndex] = minColWidth;
if (gsDebug==PR_TRUE)
printf (" 2: col %d, set to width = %d\n", colIndex, mColumnWidths[colIndex]);
}
}
}
return result;
}
PRBool nsTableFrame::BalanceColumnsTableFits(nsIPresContext* aPresContext,
PRInt32 aAvailWidth)
{
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
PRBool result = PR_TRUE;
nsVoidArray *spanList=nsnull;
nsVoidArray *columnLayoutData = GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
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 columnFrame to ask the style question
nsStylePosition* colPosition = nsnull;
if (PR_TRUE==IsProportionalWidth(colPosition))
{
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
PRInt32 colSpan = data->GetCellFrame()->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");
PRInt32 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
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);
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
if (1<colSpan)
{ // add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
printf (" aAvailWidth = %d\n", aAvailWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
#if XXX_bug_kipp_about_this
if (0==colStyle->proportionalWidth)
{ // col width is specified to be the minimum
mColumnWidths[colIndex] = minColWidth;
if (gsDebug==PR_TRUE)
printf (" 3 (0): col %d set to min width = %d because style set proportionalWidth=0\n",
colIndex, mColumnWidths[colIndex]);
}
else // BUG? else? other code below has the else
#endif
if (PR_TRUE==AutoColumnWidths())
{ // give each remaining column it's desired width
// if there is width left over, we'll factor that in after this loop is complete
mColumnWidths[colIndex] = maxColWidth;
if (gsDebug==PR_TRUE)
printf (" 3a: col %d with availWidth %d, set to width = %d\n",
colIndex, aAvailWidth, mColumnWidths[colIndex]);
}
else
{ // give each remaining column an equal percentage of the remaining space
PRInt32 percentage = -1;
if (NS_UNCONSTRAINEDSIZE==aAvailWidth)
{
mColumnWidths[colIndex] = maxColWidth;
}
else
{
#if XXX_bug_kipp_about_this
percentage = colStyle->proportionalWidth;
if (-1==percentage)
#endif
percentage = 100/numCols;
mColumnWidths[colIndex] = (percentage*aAvailWidth)/100;
// if the column was computed to be too small, enlarge the column
if (mColumnWidths[colIndex] <= minColWidth)
mColumnWidths[colIndex] = minColWidth;
}
if (gsDebug==PR_TRUE)
printf (" 3b: col %d given %d percent of availWidth %d, set to width = %d\n",
colIndex, percentage, aAvailWidth, mColumnWidths[colIndex]);
}
}
}
}
if (nsnull!=spanList)
delete spanList;
return result;
}
PRBool nsTableFrame::BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
PRBool result = PR_TRUE;
PRInt32 maxOfAllMinColWidths = 0;
nsVoidArray *spanList=nsnull;
nsVoidArray *columnLayoutData = GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
#if XXX_bug_kipp_about_this
// XXX BUG: mStyleContext is for the table frame not for the column.
nsStyleMolecule* colStyle =
(nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
#else
nsStylePosition* colPosition = nsnull;
#endif
nsVoidArray *cells = colData->GetCells();
PRInt32 minColWidth = 0;
PRInt32 maxColWidth = 0;
PRInt32 numCells = cells->Count();
if (gsDebug==PR_TRUE) printf (" for col %d\n", colIndex);
if (PR_TRUE==IsProportionalWidth(colPosition))
{
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
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 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (1<colSpan)
{
// add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth);
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
printf (" aAvailWidth = %d\n", aAvailWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
// the table fits in the space somewhere between its min and max size
// so dole out the available space appropriately
#if XXX_bug_kipp_about_this
if (0==colStyle->proportionalWidth)
{ // col width is specified to be the minimum
mColumnWidths[colIndex] = minColWidth;
if (gsDebug==PR_TRUE)
printf (" 4 (0): col %d set to min width = %d because style set proportionalWidth=0\n",
colIndex, mColumnWidths[colIndex]);
}
else
#endif
if (AutoColumnWidths())
{
PRInt32 W = aMaxWidth - aMinTableWidth;
PRInt32 D = aMaxTableWidth - aMinTableWidth;
PRInt32 d = maxColWidth - minColWidth;
mColumnWidths[colIndex] = minColWidth + ((d*W)/D);
if (gsDebug==PR_TRUE)
printf (" 4 auto-width: col %d W=%d D=%d d=%d, set to width = %d\n",
colIndex, W, D, d, mColumnWidths[colIndex]);
}
else
{ // give each remaining column an equal percentage of the remaining space
#if XXX_bug_kipp_about_this
PRInt32 percentage = colStyle->proportionalWidth;
if (-1==percentage)
#endif
PRInt32 percentage = 100/numCols;
mColumnWidths[colIndex] = (percentage*aAvailWidth)/100;
// if the column was computed to be too small, enlarge the column
if (mColumnWidths[colIndex] <= minColWidth)
{
mColumnWidths[colIndex] = minColWidth;
if (maxOfAllMinColWidths < minColWidth)
maxOfAllMinColWidths = minColWidth;
}
if (gsDebug==PR_TRUE)
{
printf (" 4 equal width: col %d given %d percent of availWidth %d, set to width = %d\n",
colIndex, percentage, aAvailWidth, mColumnWidths[colIndex]);
if (0!=maxOfAllMinColWidths)
printf(" and setting maxOfAllMins to %d\n", maxOfAllMinColWidths);
}
}
}
}
}
// post-process if necessary
// if columns have equal width, and some column's content couldn't squeeze into the computed size,
// then expand every column to the min size of the column with the largest min size
if (!AutoColumnWidths() && 0!=maxOfAllMinColWidths)
{
if (gsDebug==PR_TRUE) printf(" EqualColWidths specified, so setting all col widths to %d\n", maxOfAllMinColWidths);
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
mColumnWidths[colIndex] = maxOfAllMinColWidths;
}
if (nsnull!=spanList)
delete spanList;
return result;
}
/**
sum the width of each column
add in table insets
@ -2762,20 +2040,6 @@ PRBool nsTableFrame::IsFirstPassValid() const
return firstInFlow->mFirstPassValid;
}
//ZZZ TOTAL HACK
PRBool isTableAutoWidth = PR_TRUE;
PRBool isAutoColumnWidths = PR_TRUE;
PRBool nsTableFrame::TableIsAutoWidth()
{ // ZZZ: TOTAL HACK
return isTableAutoWidth;
}
PRBool nsTableFrame::AutoColumnWidths()
{ // ZZZ: TOTAL HACK
return isAutoColumnWidths;
}
NS_METHOD nsTableFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
nsIFrame* aParent,
nsIFrame*& aContinuingFrame)

View File

@ -26,6 +26,7 @@ class nsTableCell;
class nsVoidArray;
class nsTableCellFrame;
class CellData;
class nsITableLayoutStrategy;
struct InnerTableReflowState;
struct nsStylePosition;
struct nsStyleSpacing;
@ -152,7 +153,6 @@ public:
void SetColumnWidth(PRInt32 aColIndex, PRInt32 aWidth);
/**
* Calculate Layout Information
*
@ -275,116 +275,6 @@ protected:
const nsSize& aMaxSize,
nsSize* aMaxElementSize);
/** assign widths for each column that has fixed width.
* Computes the minimum and maximum table widths.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aMaxWidth the maximum width of the table
* @param aNumCols the total number of columns in the table
* @param aTableStyle the resolved style for the table
* @param aTotalFixedWidth out param, the sum of the fixed width columns
* @param aMinTableWidth out param, the min possible table width
* @param aMaxTableWidth out param, the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: should be renamed to "AssignKnownWidthInformation
*/
virtual PRBool AssignFixedColumnWidths(nsIPresContext* aPresContext,
PRInt32 aMaxWidth,
PRInt32 aNumCols,
PRInt32 & aTotalFixedWidth,
PRInt32 & aMinTableWidth,
PRInt32 & aMaxTableWidth);
/** assign widths for each column that has proportional width inside a table that
* has a fixed width.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space.)
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForAutoWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
/** assign the minimum allowed width for each column that has proportional width.
* Typically called when the min table width doesn't fit in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool SetColumnsToMinWidth(nsIPresContext* aPresContext);
/** assign the maximum allowed width for each column that has proportional width.
* Typically called when the desired max table width fits in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool BalanceColumnsTableFits(nsIPresContext* aPresContext,
PRInt32 aAvailWidth);
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space) according to the
* HTML 4 specification.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
/** sets the width of the table according to the computed widths of each column. */
virtual void SetTableWidth(nsIPresContext* aPresContext);
@ -395,18 +285,6 @@ protected:
nscoord aMaxAscent,
nscoord aMaxHeight);
/** support routine returns PR_TRUE if the table should be sized "automatically"
* according to its content.
* In NAV4, this is the default (no WIDTH, no COLS).
*/
virtual PRBool TableIsAutoWidth();
/** support routine returns PR_TRUE if the table columns should be sized "automatically"
* according to its content.
* In NAV4, this is when there is a COLS attribute on the table.
*/
virtual PRBool AutoColumnWidths();
/** given the new parent size, do I really need to do a reflow? */
virtual PRBool NeedsReflow(const nsSize& aMaxSize);
@ -433,7 +311,7 @@ private:
PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit
PRInt32 mPass; // which Reflow pass are we currently in?
PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change
nsITableLayoutStrategy * mTableLayoutStrategy; // the layout strategy for this frame
};
#endif

View File

@ -0,0 +1,821 @@
/* -*- 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 <stdio.h>
#include "BasicTableLayoutStrategy.h"
#include "nsTableFrame.h"
#include "nsColLayoutData.h"
#include "nsCellLayoutData.h"
#include "nsTableCol.h"
#include "nsTableCellFrame.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
#include "nsIPtr.h"
NS_DEF_PTR(nsTableCol);
NS_DEF_PTR(nsTableCell);
NS_DEF_PTR(nsIStyleContext);
static NS_DEFINE_IID(kStyleBorderSID, NS_STYLEBORDER_SID);
static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID);
static NS_DEFINE_IID(kStylePositionSID, NS_STYLEPOSITION_SID);
static NS_DEFINE_IID(kStyleSpacingSID, NS_STYLESPACING_SID);
#ifdef NS_DEBUG
static PRBool gsDebug = PR_FALSE;
static PRBool gsDebugCLD = PR_FALSE;
static PRBool gsTiming = PR_FALSE;
static PRBool gsDebugMBP = PR_FALSE;
#else
static const PRBool gsDebug = PR_FALSE;
static const PRBool gsDebugCLD = PR_FALSE;
static const PRBool gsTiming = PR_FALSE;
static const PRBool gsDebugMBP = PR_FALSE;
#endif
//ZZZ TOTAL HACK
PRBool isTableAutoWidth = PR_TRUE;
PRBool isAutoColumnWidths = PR_TRUE;
PRBool TableIsAutoWidth()
{ // ZZZ: TOTAL HACK
return isTableAutoWidth;
}
PRBool AutoColumnWidths()
{ // ZZZ: TOTAL HACK
return isAutoColumnWidths;
}
BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame)
{
mTableFrame = aFrame;
}
BasicTableLayoutStrategy::~BasicTableLayoutStrategy()
{
}
PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresContext,
PRInt32 aMaxWidth,
PRInt32 aNumCols,
PRInt32 &aTotalFixedWidth,
PRInt32 &aMinTableWidth,
PRInt32 &aMaxTableWidth,
nsSize* aMaxElementSize)
{
PRBool result = PR_TRUE;
// Step 1 - assign the width of all fixed-width columns
AssignFixedColumnWidths(aPresContext, aMaxWidth, aNumCols,
aTotalFixedWidth, aMinTableWidth, aMaxTableWidth);
if (nsnull!=aMaxElementSize)
{
aMaxElementSize->width = aMinTableWidth;
if (gsDebug) printf(" setting aMaxElementSize->width = %d\n", aMaxElementSize->width);
}
else
{
if (gsDebug) printf(" nsnull aMaxElementSize\n");
}
// Step 2 - assign the width of all proportional-width columns in the remaining space
PRInt32 availWidth = aMaxWidth - aTotalFixedWidth;
if (gsDebug==PR_TRUE) printf ("Step 2...\n availWidth = %d\n", availWidth);
if (TableIsAutoWidth())
{
if (gsDebug==PR_TRUE) printf (" calling BalanceProportionalColumnsForAutoWidthTable\n");
result = BalanceProportionalColumnsForAutoWidthTable(aPresContext,
availWidth, aMaxWidth,
aMinTableWidth, aMaxTableWidth);
}
else
{
if (gsDebug==PR_TRUE) printf (" calling BalanceProportionalColumnsForSpecifiedWidthTable\n");
result = BalanceProportionalColumnsForSpecifiedWidthTable(aPresContext,
availWidth, aMaxWidth,
aMinTableWidth, aMaxTableWidth);
}
return result;
}
/*
STEP 1
for every col
if the col has a fixed width
set the width to max(fixed width, maxElementSize)
if the cell spans columns, divide the cell width between the columns
else skip it for now
take borders and padding into account
STEP 2
determine the min and max size for the table width
if col is proportionately specified
if (col width specified to 0)
col width = minColWidth
else if (minTableWidth >= aMaxSize.width)
set col widths to min, install a hor. scroll bar
else if (maxTableWidth <= aMaxSize.width)
set each col to its max size
else
W = aMaxSize.width - minTableWidth
D = maxTableWidth - minTableWidth
for each col
d = maxColWidth - minColWidth
col width = minColWidth + ((d*W)/D)
STEP 3
if there is space left over
for every col
if col is proportionately specified
add space to col width until it is that proportion of the table width
do this non-destructively in case there isn't enough space
if there isn't enough space as determined in the prior step,
add space in proportion to the proportionate width attribute
*/
// Step 1 - assign the width of all fixed-width columns,
// and calculate min/max table width
PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresContext,
PRInt32 maxWidth,
PRInt32 aNumCols,
PRInt32 &aTotalFixedWidth,
PRInt32 &aMinTableWidth,
PRInt32 &aMaxTableWidth)
{
#ifdef DEBUG
nsIFrame *tablePIF=nsnull;
mTableFrame->GetPrevInFlow(tablePIF);
NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!");
#endif
if (gsDebug==PR_TRUE) printf (" AssignFixedColumnWidths\n");
nsVoidArray *spanList=nsnull;
for (PRInt32 colIndex = 0; colIndex<aNumCols; colIndex++)
{
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
NS_ASSERTION(nsnull != colData, "bad column data");
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
NS_ASSERTION(col.IsNotNull(), "bad col");
// need to track min/max column width for setting min/max table widths
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);
#if XXX_need_access_to_column_frame_help
// Get the columns's style
nsIStyleContextPtr colSC;
colFrame->GetStyleContext(aPresContext, colSC.AssignRef());
nsStylePosition* colPosition = (nsStylePosition*)
colSC->GetData(kStylePositionSID);
// Get column width if it has one
PRBool haveColWidth = PR_FALSE;
nscoord colWidth;
switch (colPosition->mWidthFlags) {
default:
case NS_STYLE_POSITION_VALUE_AUTO:
case NS_STYLE_POSITION_VALUE_INHERIT:
break;
case NS_STYLE_POSITION_VALUE_LENGTH:
haveColWidth = PR_TRUE;
colWidth = colPosition->mWidth;
break;
case NS_STYLE_POSITION_VALUE_PCT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
//XXX haveColWidth = PR_TRUE;
//XXX colWidth = colPosition->mWidthPCT * something;
break;
}
#endif
/* Scan the column, simulatneously assigning fixed column widths
* and computing the min/max column widths
*/
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
nsSize * cellMinSize = data->GetMaxElementSize();
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
PRInt32 colSpan = data->GetCellFrame()->GetColSpan();
if (gsDebug==PR_TRUE)
printf (" for cell %d with colspan=%d, min = %d,%d and des = %d,%d\n",
cellIndex, colSpan, cellMinSize->width, cellMinSize->height,
cellDesiredSize->width, cellDesiredSize->height);
PRBool haveCellWidth = PR_FALSE;
nscoord cellWidth;
/*
* The first cell in a column (in row 0) has special standing.
* if the first cell has a width specification, it overrides the
* COL width
*/
if (0==cellIndex)
{
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(0));
nsTableCellFrame *cellFrame = data->GetCellFrame();
nsTableCellPtr cell;
cellFrame->GetContent((nsIContent*&)(cell.AssignRef())); // cell: REFCNT++
// Get the cell's style
nsIStyleContextPtr cellSC;
cellFrame->GetStyleContext(aPresContext, cellSC.AssignRef());
nsStylePosition* cellPosition = (nsStylePosition*)
cellSC->GetData(kStylePositionSID);
switch (cellPosition->mWidthFlags) {
case NS_STYLE_POSITION_VALUE_LENGTH:
haveCellWidth = PR_TRUE;
cellWidth = cellPosition->mWidth;
break;
case NS_STYLE_POSITION_VALUE_PERCENT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
// XXX write me when pct/proportional are supported
// XXX haveCellWidth = PR_TRUE;
// XXX cellWidth = cellPosition->mWidth;
break;
default:
case NS_STYLE_POSITION_VALUE_INHERIT:
case NS_STYLE_POSITION_VALUE_AUTO:
break;
}
}
#if XXX_need_access_to_column_frame_help
switch (colPosition->mWidthFlags) {
default:
case NS_STYLE_POSITION_VALUE_AUTO:
case NS_STYLE_POSITION_VALUE_INHERIT:
break;
case NS_STYLE_POSITION_VALUE_LENGTH:
{
// 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 = max(cellMinSize->width, colPosition->mWidth);
if (mTableFrame->GetColumnWidth(colIndex) < widthForThisCell)
{
if (gsDebug) printf (" setting fixed width to %d\n",widthForThisCell);
mTableFrame->SetColumnWidth(colIndex, widthForThisCell);
maxColWidth = widthForThisCell;
}
}
break;
case NS_STYLE_POSITION_VALUE_PCT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
// XXX write me when pct/proportional are supported
break;
}
#endif
// regardless of the width specification, keep track of the
// min/max column widths
PRInt32 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (1<colSpan)
{
// add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
if (gsDebug) {
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
}
}
#if 0
// if the col is fixed-width, expand the col to the specified
// fixed width if necessary
if (colStyle->fixedWidth > mTableFrame->GetColumnWidth(colIndex))
mTableFrame->SetColumnWidth(colIndex, colStyle->fixedWidth);
// keep a running total of the amount of space taken up by all
// fixed-width columns
aTotalFixedWidth += mTableFrame->GetColumnWidths(colIndex);
if (gsDebug) {
printf (" after col %d, aTotalFixedWidth = %d\n",
colIndex, aTotalFixedWidth);
}
#endif
// add col[i] metrics to the running totals for the table min/max width
if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth)
aMinTableWidth += minColWidth; // SEC: insets!
if (aMinTableWidth<=0)
aMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth)
aMaxTableWidth += maxColWidth; // SEC: insets!
if (aMaxTableWidth<=0)
aMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
if (gsDebug==PR_TRUE)
printf (" after this col, minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth);
} // end Step 1 for fixed-width columns
if (nsnull!=spanList)
delete spanList;
return PR_TRUE;
}
PRBool BasicTableLayoutStrategy::BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
#ifdef DEBUG
nsIFrame *tablePIF=nsnull;
mTableFrame->GetPrevInFlow(tablePIF);
NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!");
#endif
PRBool result = PR_TRUE;
if (NS_UNCONSTRAINEDSIZE==aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else if (aMinTableWidth > aMaxWidth)
{ // the table doesn't fit in the available space
if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n");
result = SetColumnsToMinWidth(aPresContext);
}
else if (aMaxTableWidth <= aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else
{ // the table fits somewhere between its min and desired size
if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n");
result = BalanceColumnsHTML4Constrained(aPresContext, aAvailWidth,
aMaxWidth, aMinTableWidth, aMaxTableWidth);
}
return result;
}
PRBool BasicTableLayoutStrategy::BalanceProportionalColumnsForAutoWidthTable( nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
PRBool result = PR_TRUE;
if (NS_UNCONSTRAINEDSIZE==aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else if (aMinTableWidth > aMaxWidth)
{ // the table doesn't fit in the available space
if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n");
result = SetColumnsToMinWidth(aPresContext);
}
else if (aMaxTableWidth <= aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else
{ // the table fits somewhere between its min and desired size
if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n");
result = BalanceColumnsHTML4Constrained(aPresContext, aAvailWidth,
aMaxWidth, aMinTableWidth, aMaxTableWidth);
}
return result;
}
PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresContext)
{
PRBool result = PR_TRUE;
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
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
nsStylePosition* colPosition = nsnull;
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
nsSize * cellMinSize = data->GetMaxElementSize();
NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize");
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
if (minColWidth < cellMinSize->width)
minColWidth = cellMinSize->width;
if (maxColWidth < cellDesiredSize->width)
maxColWidth = cellDesiredSize->width;
/*
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
*/
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",
colIndex, mTableFrame->IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
mTableFrame->SetColumnWidth(colIndex, minColWidth);
if (gsDebug==PR_TRUE)
printf (" 2: col %d, set to width = %d\n", colIndex, mTableFrame->GetColumnWidth(colIndex));
}
}
}
return result;
}
PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresContext,
PRInt32 aAvailWidth)
{
#ifdef DEBUG
nsIFrame *tablePIF=nsnull;
mTableFrame->GetPrevInFlow(tablePIF);
NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!");
#endif
PRBool result = PR_TRUE;
nsVoidArray *spanList=nsnull;
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
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 columnFrame to ask the style question
nsStylePosition* colPosition = nsnull;
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
PRInt32 colSpan = data->GetCellFrame()->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");
PRInt32 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
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);
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
if (1<colSpan)
{ // add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",
colIndex, mTableFrame->IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
printf (" aAvailWidth = %d\n", aAvailWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
#if XXX_bug_kipp_about_this
if (0==colStyle->proportionalWidth)
{ // col width is specified to be the minimum
mTableFrame->SetColumnWidth(colIndex, minColWidth);
if (gsDebug==PR_TRUE)
printf (" 3 (0): col %d set to min width = %d because style set proportionalWidth=0\n",
colIndex, mTableFrame->GetColumnWidth(colIndex));
}
else // BUG? else? other code below has the else
#endif
if (PR_TRUE==AutoColumnWidths())
{ // give each remaining column it's desired width
// if there is width left over, we'll factor that in after this loop is complete
mTableFrame->SetColumnWidth(colIndex, maxColWidth);
if (gsDebug==PR_TRUE)
printf (" 3a: col %d with availWidth %d, set to width = %d\n",
colIndex, aAvailWidth, mTableFrame->GetColumnWidth(colIndex));
}
else
{ // give each remaining column an equal percentage of the remaining space
PRInt32 percentage = -1;
if (NS_UNCONSTRAINEDSIZE==aAvailWidth)
{
mTableFrame->SetColumnWidth(colIndex, maxColWidth);
}
else
{
#if XXX_bug_kipp_about_this
percentage = colStyle->proportionalWidth;
if (-1==percentage)
#endif
percentage = 100/numCols;
mTableFrame->SetColumnWidth(colIndex, (percentage*aAvailWidth)/100);
// if the column was computed to be too small, enlarge the column
if (mTableFrame->GetColumnWidth(colIndex) <= minColWidth)
mTableFrame->SetColumnWidth(colIndex, minColWidth);
}
if (gsDebug==PR_TRUE)
printf (" 3b: col %d given %d percent of availWidth %d, set to width = %d\n",
colIndex, percentage, aAvailWidth, mTableFrame->GetColumnWidth(colIndex));
}
}
}
}
if (nsnull!=spanList)
delete spanList;
return result;
}
PRBool BasicTableLayoutStrategy::BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
#ifdef DEBUG
nsIFrame *tablePIF=nsnull;
mTableFrame->GetPrevInFlow(tablePIF);
NS_ASSERTION(nsnull==tablePIF, "never ever call me on a continuing frame!");
#endif
PRBool result = PR_TRUE;
PRInt32 maxOfAllMinColWidths = 0;
nsVoidArray *spanList=nsnull;
nsVoidArray *columnLayoutData = mTableFrame->GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
#if XXX_bug_kipp_about_this
// XXX BUG: mStyleContext is for the table frame not for the column.
nsStyleMolecule* colStyle =
(nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
#else
nsStylePosition* colPosition = nsnull;
#endif
nsVoidArray *cells = colData->GetCells();
PRInt32 minColWidth = 0;
PRInt32 maxColWidth = 0;
PRInt32 numCells = cells->Count();
if (gsDebug==PR_TRUE) printf (" for col %d\n", colIndex);
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
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 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (1<colSpan)
{
// add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",
colIndex, mTableFrame->IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth);
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
printf (" aAvailWidth = %d\n", aAvailWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==mTableFrame->IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
// the table fits in the space somewhere between its min and max size
// so dole out the available space appropriately
#if XXX_bug_kipp_about_this
if (0==colStyle->proportionalWidth)
{ // col width is specified to be the minimum
mTableFrame->SetColumnWidth(colIndex, minColWidth);
if (gsDebug==PR_TRUE)
printf (" 4 (0): col %d set to min width = %d because style set proportionalWidth=0\n",
colIndex, mTableFrame->GetColumnWidth(colIndex));
}
else
#endif
if (AutoColumnWidths())
{
PRInt32 W = aMaxWidth - aMinTableWidth;
PRInt32 D = aMaxTableWidth - aMinTableWidth;
PRInt32 d = maxColWidth - minColWidth;
mTableFrame->SetColumnWidth(colIndex, minColWidth + ((d*W)/D));
if (gsDebug==PR_TRUE)
printf (" 4 auto-width: col %d W=%d D=%d d=%d, set to width = %d\n",
colIndex, W, D, d, mTableFrame->GetColumnWidth(colIndex));
}
else
{ // give each remaining column an equal percentage of the remaining space
#if XXX_bug_kipp_about_this
PRInt32 percentage = colStyle->proportionalWidth;
if (-1==percentage)
#endif
PRInt32 percentage = 100/numCols;
mTableFrame->SetColumnWidth(colIndex, (percentage*aAvailWidth)/100);
// if the column was computed to be too small, enlarge the column
if (mTableFrame->GetColumnWidth(colIndex) <= minColWidth)
{
mTableFrame->SetColumnWidth(colIndex, minColWidth);
if (maxOfAllMinColWidths < minColWidth)
maxOfAllMinColWidths = minColWidth;
}
if (gsDebug==PR_TRUE)
{
printf (" 4 equal width: col %d given %d percent of availWidth %d, set to width = %d\n",
colIndex, percentage, aAvailWidth, mTableFrame->GetColumnWidth(colIndex));
if (0!=maxOfAllMinColWidths)
printf(" and setting maxOfAllMins to %d\n", maxOfAllMinColWidths);
}
}
}
}
}
// post-process if necessary
// if columns have equal width, and some column's content couldn't squeeze into the computed size,
// then expand every column to the min size of the column with the largest min size
if (!AutoColumnWidths() && 0!=maxOfAllMinColWidths)
{
if (gsDebug==PR_TRUE) printf(" EqualColWidths specified, so setting all col widths to %d\n", maxOfAllMinColWidths);
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
mTableFrame->SetColumnWidth(colIndex, maxOfAllMinColWidths);
}
if (nsnull!=spanList)
delete spanList;
return result;
}

View File

@ -0,0 +1,179 @@
/* -*- 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 BasicTableLayoutStrategy_h__
#define BasicTableLayoutStrategy_h__
#include "nscore.h"
#include "nsITableLayoutStrategy.h"
class nsTableFrame;
/* ----------- SpanInfo ---------- */
struct SpanInfo
{
PRInt32 span;
PRInt32 cellMinWidth;
PRInt32 cellDesiredWidth;
SpanInfo(PRInt32 aSpan, PRInt32 aMinWidth, PRInt32 aDesiredWidth)
{
span = aSpan;
cellMinWidth = aMinWidth;
cellDesiredWidth = aDesiredWidth;
};
~SpanInfo() {};
};
/* ---------- BasicTableLayoutStrategy ---------- */
class BasicTableLayoutStrategy : public nsITableLayoutStrategy
{
public:
BasicTableLayoutStrategy(nsTableFrame *aFrame);
~BasicTableLayoutStrategy();
virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext,
PRInt32 aMaxWidth,
PRInt32 aNumCols,
PRInt32 &aTotalFixedWidth,
PRInt32 &aMinTableWidth,
PRInt32 &aMaxTableWidth,
nsSize* aMaxElementSize);
/** assign widths for each column that has fixed width.
* Computes the minimum and maximum table widths.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aMaxWidth the maximum width of the table
* @param aNumCols the total number of columns in the table
* @param aTableStyle the resolved style for the table
* @param aTotalFixedWidth out param, the sum of the fixed width columns
* @param aMinTableWidth out param, the min possible table width
* @param aMaxTableWidth out param, the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: should be renamed to "AssignKnownWidthInformation
*/
virtual PRBool AssignFixedColumnWidths(nsIPresContext* aPresContext,
PRInt32 aMaxWidth,
PRInt32 aNumCols,
PRInt32 & aTotalFixedWidth,
PRInt32 & aMinTableWidth,
PRInt32 & aMaxTableWidth);
/** assign widths for each column that has proportional width inside a table that
* has a fixed width.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space.)
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForAutoWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
/** assign the minimum allowed width for each column that has proportional width.
* Typically called when the min table width doesn't fit in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool SetColumnsToMinWidth(nsIPresContext* aPresContext);
/** assign the maximum allowed width for each column that has proportional width.
* Typically called when the desired max table width fits in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool BalanceColumnsTableFits(nsIPresContext* aPresContext,
PRInt32 aAvailWidth);
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space) according to the
* HTML 4 specification.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
protected:
nsTableFrame * mTableFrame;
};
#endif

View File

@ -0,0 +1,159 @@
/* -*- 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 nsITableLayoutStrategy_h__
#define nsITableLayoutStrategy_h__
#include "nscore.h"
#include "nsSize.h"
class nsIPresContext;
class nsITableLayoutStrategy
{
public:
/** assign widths for each column, taking into account the table content, the effective style,
* the layout constraints, and the compatibility mode. Sets mColumnWidths as a side effect.
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aMaxSize the height and width constraints
* @param aMaxElementSize the min size of the largest indivisible object
*/
virtual PRBool BalanceColumnWidths(nsIPresContext* aPresContext,
PRInt32 maxWidth,
PRInt32 aNumCols,
PRInt32 &aTotalFixedWidth,
PRInt32 &aMinTableWidth,
PRInt32 &aMaxTableWidth,
nsSize* aMaxElementSize)=0;
/** assign widths for each column that has fixed width.
* Computes the minimum and maximum table widths.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aMaxWidth the maximum width of the table
* @param aNumCols the total number of columns in the table
* @param aTableStyle the resolved style for the table
* @param aTotalFixedWidth out param, the sum of the fixed width columns
* @param aMinTableWidth out param, the min possible table width
* @param aMaxTableWidth out param, the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: should be renamed to "AssignKnownWidthInformation
*/
virtual PRBool AssignFixedColumnWidths(nsIPresContext* aPresContext,
PRInt32 aMaxWidth,
PRInt32 aNumCols,
PRInt32 & aTotalFixedWidth,
PRInt32 & aMinTableWidth,
PRInt32 & aMaxTableWidth)=0;
/** assign widths for each column that has proportional width inside a table that
* has a fixed width.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)=0;
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space.)
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForAutoWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)=0;
/** assign the minimum allowed width for each column that has proportional width.
* Typically called when the min table width doesn't fit in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool SetColumnsToMinWidth(nsIPresContext* aPresContext)=0;
/** assign the maximum allowed width for each column that has proportional width.
* Typically called when the desired max table width fits in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool BalanceColumnsTableFits(nsIPresContext* aPresContext,
PRInt32 aAvailWidth)=0;
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space) according to the
* HTML 4 specification.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)=0;
};
#endif

View File

@ -29,6 +29,9 @@
#include "nsTableRowFrame.h"
#include "nsTableRowGroupFrame.h"
#include "nsColLayoutData.h"
#include "BasicTableLayoutStrategy.h"
#include "nsIPresContext.h"
#include "nsCSSRendering.h"
#include "nsStyleConsts.h"
@ -135,26 +138,6 @@ struct InnerTableReflowState {
/* ----------- SpanInfo ---------- */
struct SpanInfo
{
PRInt32 span;
PRInt32 cellMinWidth;
PRInt32 cellDesiredWidth;
SpanInfo(PRInt32 aSpan, PRInt32 aMinWidth, PRInt32 aDesiredWidth)
{
span = aSpan;
cellMinWidth = aMinWidth;
cellDesiredWidth = aDesiredWidth;
};
~SpanInfo() {};
};
/* ----------- nsTableFrame ---------- */
@ -164,6 +147,7 @@ nsTableFrame::nsTableFrame(nsIContent* aContent,
: nsContainerFrame(aContent, aIndexInParent, aParentFrame),
mColumnLayoutData(nsnull),
mColumnWidths(nsnull),
mTableLayoutStrategy(nsnull),
mFirstPassValid(PR_FALSE),
mPass(kPASS_UNDEFINED),
mIsInvariantWidth(PR_FALSE)
@ -194,6 +178,8 @@ nsTableFrame::~nsTableFrame()
DeleteColumnLayoutData();
if (nsnull!=mColumnWidths)
delete [] mColumnWidths;
if (nsnull!=mTableLayoutStrategy)
delete mTableLayoutStrategy;
}
@ -1561,725 +1547,17 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
if (gsDebug) printf (" maxWidth=%d from aMaxSize=%d,%d\n", maxWidth, aMaxSize.width, aMaxSize.height);
// Step 1 - assign the width of all fixed-width columns
AssignFixedColumnWidths(aPresContext, maxWidth, numCols,
totalFixedWidth, minTableWidth, maxTableWidth);
if (nsnull!=aMaxElementSize)
{
aMaxElementSize->width = minTableWidth;
if (gsDebug) printf(" setting aMaxElementSize->width = %d\n", aMaxElementSize->width);
// based on the compatibility mode, create a table layout strategy
if (nsnull==mTableLayoutStrategy)
{ // TODO: build a different strategy based on the compatibility mode
mTableLayoutStrategy = new BasicTableLayoutStrategy(this);
}
else
{
if (gsDebug) printf(" nsnull aMaxElementSize\n");
}
// Step 2 - assign the width of all proportional-width columns in the remaining space
PRInt32 availWidth=maxWidth - totalFixedWidth;
if (gsDebug==PR_TRUE) printf ("Step 2...\n availWidth = %d\n", availWidth);
if (TableIsAutoWidth())
{
if (gsDebug==PR_TRUE) printf (" calling BalanceProportionalColumnsForAutoWidthTable\n");
BalanceProportionalColumnsForAutoWidthTable(aPresContext,
availWidth, maxWidth,
minTableWidth, maxTableWidth);
}
else
{
if (gsDebug==PR_TRUE) printf (" calling BalanceProportionalColumnsForSpecifiedWidthTable\n");
BalanceProportionalColumnsForSpecifiedWidthTable(aPresContext,
availWidth, maxWidth,
minTableWidth, maxTableWidth);
}
/*
STEP 1
for every col
if the col has a fixed width
set the width to max(fixed width, maxElementSize)
if the cell spans columns, divide the cell width between the columns
else skip it for now
take borders and padding into account
STEP 2
determine the min and max size for the table width
if col is proportionately specified
if (col width specified to 0)
col width = minColWidth
else if (minTableWidth >= aMaxSize.width)
set col widths to min, install a hor. scroll bar
else if (maxTableWidth <= aMaxSize.width)
set each col to its max size
else
W = aMaxSize.width - minTableWidth
D = maxTableWidth - minTableWidth
for each col
d = maxColWidth - minColWidth
col width = minColWidth + ((d*W)/D)
STEP 3
if there is space left over
for every col
if col is proportionately specified
add space to col width until it is that proportion of the table width
do this non-destructively in case there isn't enough space
if there isn't enough space as determined in the prior step,
add space in proportion to the proportionate width attribute
*/
mTableLayoutStrategy->BalanceColumnWidths(aPresContext, maxWidth, numCols,
totalFixedWidth, minTableWidth, maxTableWidth,
aMaxElementSize);
}
// Step 1 - assign the width of all fixed-width columns,
// and calculate min/max table width
PRBool nsTableFrame::AssignFixedColumnWidths(nsIPresContext* aPresContext,
PRInt32 maxWidth,
PRInt32 aNumCols,
PRInt32 &aTotalFixedWidth,
PRInt32 &aMinTableWidth,
PRInt32 &aMaxTableWidth)
{
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
if (gsDebug==PR_TRUE) printf (" AssignFixedColumnWidths\n");
nsVoidArray *spanList=nsnull;
for (PRInt32 colIndex = 0; colIndex<aNumCols; colIndex++)
{
nsVoidArray *columnLayoutData = GetColumnLayoutData();
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
NS_ASSERTION(nsnull != colData, "bad column data");
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
NS_ASSERTION(col.IsNotNull(), "bad col");
// need to track min/max column width for setting min/max table widths
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);
#if XXX_need_access_to_column_frame_help
// Get the columns's style
nsIStyleContextPtr colSC;
colFrame->GetStyleContext(aPresContext, colSC.AssignRef());
nsStylePosition* colPosition = (nsStylePosition*)
colSC->GetData(kStylePositionSID);
// Get column width if it has one
PRBool haveColWidth = PR_FALSE;
nscoord colWidth;
switch (colPosition->mWidthFlags) {
default:
case NS_STYLE_POSITION_VALUE_AUTO:
case NS_STYLE_POSITION_VALUE_INHERIT:
break;
case NS_STYLE_POSITION_VALUE_LENGTH:
haveColWidth = PR_TRUE;
colWidth = colPosition->mWidth;
break;
case NS_STYLE_POSITION_VALUE_PCT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
//XXX haveColWidth = PR_TRUE;
//XXX colWidth = colPosition->mWidthPCT * something;
break;
}
#endif
/* Scan the column, simulatneously assigning fixed column widths
* and computing the min/max column widths
*/
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
nsSize * cellMinSize = data->GetMaxElementSize();
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
PRInt32 colSpan = data->GetCellFrame()->GetColSpan();
if (gsDebug==PR_TRUE)
printf (" for cell %d with colspan=%d, min = %d,%d and des = %d,%d\n",
cellIndex, colSpan, cellMinSize->width, cellMinSize->height,
cellDesiredSize->width, cellDesiredSize->height);
PRBool haveCellWidth = PR_FALSE;
nscoord cellWidth;
/*
* The first cell in a column (in row 0) has special standing.
* if the first cell has a width specification, it overrides the
* COL width
*/
if (0==cellIndex)
{
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(0));
nsTableCellFrame *cellFrame = data->GetCellFrame();
nsTableCellPtr cell;
cellFrame->GetContent((nsIContent*&)(cell.AssignRef())); // cell: REFCNT++
// Get the cell's style
nsIStyleContextPtr cellSC;
cellFrame->GetStyleContext(aPresContext, cellSC.AssignRef());
nsStylePosition* cellPosition = (nsStylePosition*)
cellSC->GetData(kStylePositionSID);
switch (cellPosition->mWidthFlags) {
case NS_STYLE_POSITION_VALUE_LENGTH:
haveCellWidth = PR_TRUE;
cellWidth = cellPosition->mWidth;
break;
case NS_STYLE_POSITION_VALUE_PERCENT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
// XXX write me when pct/proportional are supported
// XXX haveCellWidth = PR_TRUE;
// XXX cellWidth = cellPosition->mWidth;
break;
default:
case NS_STYLE_POSITION_VALUE_INHERIT:
case NS_STYLE_POSITION_VALUE_AUTO:
break;
}
}
#if XXX_need_access_to_column_frame_help
switch (colPosition->mWidthFlags) {
default:
case NS_STYLE_POSITION_VALUE_AUTO:
case NS_STYLE_POSITION_VALUE_INHERIT:
break;
case NS_STYLE_POSITION_VALUE_LENGTH:
{
// 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 = max(cellMinSize->width, colPosition->mWidth);
if (mColumnWidths[colIndex] < widthForThisCell)
{
if (gsDebug) printf (" setting fixed width to %d\n",widthForThisCell);
mColumnWidths[colIndex] = widthForThisCell;
maxColWidth = widthForThisCell;
}
}
break;
case NS_STYLE_POSITION_VALUE_PCT:
case NS_STYLE_POSITION_VALUE_PROPORTIONAL:
// XXX write me when pct/proportional are supported
break;
}
#endif
// regardless of the width specification, keep track of the
// min/max column widths
PRInt32 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (1<colSpan)
{
// add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
if (gsDebug) {
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
}
}
#if 0
// if the col is fixed-width, expand the col to the specified
// fixed width if necessary
if (colStyle->fixedWidth > mColumnWidths[colIndex])
mColumnWidths[colIndex] = colStyle->fixedWidth;
// keep a running total of the amount of space taken up by all
// fixed-width columns
aTotalFixedWidth += mColumnWidths[colIndex];
if (gsDebug) {
printf (" after col %d, aTotalFixedWidth = %d\n",
colIndex, aTotalFixedWidth);
}
#endif
// add col[i] metrics to the running totals for the table min/max width
if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth)
aMinTableWidth += minColWidth; // SEC: insets!
if (aMinTableWidth<=0)
aMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth)
aMaxTableWidth += maxColWidth; // SEC: insets!
if (aMaxTableWidth<=0)
aMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
if (gsDebug==PR_TRUE)
printf (" after this col, minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth);
} // end Step 1 for fixed-width columns
if (nsnull!=spanList)
delete spanList;
return PR_TRUE;
}
PRBool nsTableFrame::BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
PRBool result = PR_TRUE;
if (NS_UNCONSTRAINEDSIZE==aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else if (aMinTableWidth > aMaxWidth)
{ // the table doesn't fit in the available space
if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n");
result = SetColumnsToMinWidth(aPresContext);
}
else if (aMaxTableWidth <= aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else
{ // the table fits somewhere between its min and desired size
if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n");
result = BalanceColumnsHTML4Constrained(aPresContext, aAvailWidth,
aMaxWidth, aMinTableWidth, aMaxTableWidth);
}
return result;
}
PRBool nsTableFrame::BalanceProportionalColumnsForAutoWidthTable( nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
PRBool result = PR_TRUE;
if (NS_UNCONSTRAINEDSIZE==aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else if (aMinTableWidth > aMaxWidth)
{ // the table doesn't fit in the available space
if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n");
result = SetColumnsToMinWidth(aPresContext);
}
else if (aMaxTableWidth <= aMaxWidth)
{ // the max width of the table fits comfortably in the available space
if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n");
result = BalanceColumnsTableFits(aPresContext, aAvailWidth);
}
else
{ // the table fits somewhere between its min and desired size
if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n");
result = BalanceColumnsHTML4Constrained(aPresContext, aAvailWidth,
aMaxWidth, aMinTableWidth, aMaxTableWidth);
}
return result;
}
PRBool nsTableFrame::SetColumnsToMinWidth(nsIPresContext* aPresContext)
{
PRBool result = PR_TRUE;
nsVoidArray *columnLayoutData = GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
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
nsStylePosition* colPosition = nsnull;
if (PR_TRUE==IsProportionalWidth(colPosition))
{
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
nsSize * cellMinSize = data->GetMaxElementSize();
NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize");
nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
if (minColWidth < cellMinSize->width)
minColWidth = cellMinSize->width;
if (maxColWidth < cellDesiredSize->width)
maxColWidth = cellDesiredSize->width;
/*
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
*/
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
mColumnWidths[colIndex] = minColWidth;
if (gsDebug==PR_TRUE)
printf (" 2: col %d, set to width = %d\n", colIndex, mColumnWidths[colIndex]);
}
}
}
return result;
}
PRBool nsTableFrame::BalanceColumnsTableFits(nsIPresContext* aPresContext,
PRInt32 aAvailWidth)
{
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
PRBool result = PR_TRUE;
nsVoidArray *spanList=nsnull;
nsVoidArray *columnLayoutData = GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
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 columnFrame to ask the style question
nsStylePosition* colPosition = nsnull;
if (PR_TRUE==IsProportionalWidth(colPosition))
{
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
PRInt32 colSpan = data->GetCellFrame()->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");
PRInt32 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
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);
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
if (1<colSpan)
{ // add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
printf (" aAvailWidth = %d\n", aAvailWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
#if XXX_bug_kipp_about_this
if (0==colStyle->proportionalWidth)
{ // col width is specified to be the minimum
mColumnWidths[colIndex] = minColWidth;
if (gsDebug==PR_TRUE)
printf (" 3 (0): col %d set to min width = %d because style set proportionalWidth=0\n",
colIndex, mColumnWidths[colIndex]);
}
else // BUG? else? other code below has the else
#endif
if (PR_TRUE==AutoColumnWidths())
{ // give each remaining column it's desired width
// if there is width left over, we'll factor that in after this loop is complete
mColumnWidths[colIndex] = maxColWidth;
if (gsDebug==PR_TRUE)
printf (" 3a: col %d with availWidth %d, set to width = %d\n",
colIndex, aAvailWidth, mColumnWidths[colIndex]);
}
else
{ // give each remaining column an equal percentage of the remaining space
PRInt32 percentage = -1;
if (NS_UNCONSTRAINEDSIZE==aAvailWidth)
{
mColumnWidths[colIndex] = maxColWidth;
}
else
{
#if XXX_bug_kipp_about_this
percentage = colStyle->proportionalWidth;
if (-1==percentage)
#endif
percentage = 100/numCols;
mColumnWidths[colIndex] = (percentage*aAvailWidth)/100;
// if the column was computed to be too small, enlarge the column
if (mColumnWidths[colIndex] <= minColWidth)
mColumnWidths[colIndex] = minColWidth;
}
if (gsDebug==PR_TRUE)
printf (" 3b: col %d given %d percent of availWidth %d, set to width = %d\n",
colIndex, percentage, aAvailWidth, mColumnWidths[colIndex]);
}
}
}
}
if (nsnull!=spanList)
delete spanList;
return result;
}
PRBool nsTableFrame::BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth)
{
NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
PRBool result = PR_TRUE;
PRInt32 maxOfAllMinColWidths = 0;
nsVoidArray *spanList=nsnull;
nsVoidArray *columnLayoutData = GetColumnLayoutData();
PRInt32 numCols = columnLayoutData->Count();
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
{
nsColLayoutData * colData = (nsColLayoutData *)(columnLayoutData->ElementAt(colIndex));
nsTableColPtr col = colData->GetCol(); // col: ADDREF++
#if XXX_bug_kipp_about_this
// XXX BUG: mStyleContext is for the table frame not for the column.
nsStyleMolecule* colStyle =
(nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
#else
nsStylePosition* colPosition = nsnull;
#endif
nsVoidArray *cells = colData->GetCells();
PRInt32 minColWidth = 0;
PRInt32 maxColWidth = 0;
PRInt32 numCells = cells->Count();
if (gsDebug==PR_TRUE) printf (" for col %d\n", colIndex);
if (PR_TRUE==IsProportionalWidth(colPosition))
{
// first, deal with any cells that span into this column from a pervious column
if (nsnull!=spanList)
{
PRInt32 spanCount = spanList->Count();
// go through the list backwards so we can delete easily
for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--)
{
SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex));
if (minColWidth < spanInfo->cellMinWidth)
minColWidth = spanInfo->cellMinWidth;
if (maxColWidth < spanInfo->cellDesiredWidth)
maxColWidth = spanInfo->cellDesiredWidth;
spanInfo->span--;
if (gsDebug==PR_TRUE)
printf (" for spanning cell %d with remaining span=%d, min = %d and des = %d\n",
spanIndex, spanInfo->span, spanInfo->cellMinWidth, spanInfo->cellDesiredWidth);
if (0==spanInfo->span)
{
spanList->RemoveElementAt(spanIndex);
delete spanInfo;
}
}
}
for (PRInt32 cellIndex = 0; cellIndex<numCells; cellIndex++)
{ // this col has proportional width, so determine its width requirements
nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(cellIndex));
NS_ASSERTION(nsnull != data, "bad data");
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 cellMinWidth = cellMinSize->width/colSpan;
PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan;
if (minColWidth < cellMinWidth)
minColWidth = cellMinWidth;
if (maxColWidth < cellDesiredWidth)
maxColWidth = cellDesiredWidth;
if (1<colSpan)
{
// add the cell to our list of spanners
SpanInfo *spanInfo = new SpanInfo(colSpan-1, cellMinWidth, cellDesiredWidth);
if (nsnull==spanList)
spanList = new nsVoidArray();
spanList->AppendElement(spanInfo);
}
if (gsDebug==PR_TRUE)
printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n",
cellIndex, minColWidth, maxColWidth);
}
if (gsDebug==PR_TRUE)
{
printf (" for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colPosition)? "(P)":"(A)");
printf (" minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth);
printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
printf (" aAvailWidth = %d\n", aAvailWidth);
}
// XXX BUG: why are we asking this again? this if is already in a
// IsProportionalWidth == PR_TRUE case!
if (PR_TRUE==IsProportionalWidth(colPosition))
{ // this col has proportional width, so set its width based on the table width
// the table fits in the space somewhere between its min and max size
// so dole out the available space appropriately
#if XXX_bug_kipp_about_this
if (0==colStyle->proportionalWidth)
{ // col width is specified to be the minimum
mColumnWidths[colIndex] = minColWidth;
if (gsDebug==PR_TRUE)
printf (" 4 (0): col %d set to min width = %d because style set proportionalWidth=0\n",
colIndex, mColumnWidths[colIndex]);
}
else
#endif
if (AutoColumnWidths())
{
PRInt32 W = aMaxWidth - aMinTableWidth;
PRInt32 D = aMaxTableWidth - aMinTableWidth;
PRInt32 d = maxColWidth - minColWidth;
mColumnWidths[colIndex] = minColWidth + ((d*W)/D);
if (gsDebug==PR_TRUE)
printf (" 4 auto-width: col %d W=%d D=%d d=%d, set to width = %d\n",
colIndex, W, D, d, mColumnWidths[colIndex]);
}
else
{ // give each remaining column an equal percentage of the remaining space
#if XXX_bug_kipp_about_this
PRInt32 percentage = colStyle->proportionalWidth;
if (-1==percentage)
#endif
PRInt32 percentage = 100/numCols;
mColumnWidths[colIndex] = (percentage*aAvailWidth)/100;
// if the column was computed to be too small, enlarge the column
if (mColumnWidths[colIndex] <= minColWidth)
{
mColumnWidths[colIndex] = minColWidth;
if (maxOfAllMinColWidths < minColWidth)
maxOfAllMinColWidths = minColWidth;
}
if (gsDebug==PR_TRUE)
{
printf (" 4 equal width: col %d given %d percent of availWidth %d, set to width = %d\n",
colIndex, percentage, aAvailWidth, mColumnWidths[colIndex]);
if (0!=maxOfAllMinColWidths)
printf(" and setting maxOfAllMins to %d\n", maxOfAllMinColWidths);
}
}
}
}
}
// post-process if necessary
// if columns have equal width, and some column's content couldn't squeeze into the computed size,
// then expand every column to the min size of the column with the largest min size
if (!AutoColumnWidths() && 0!=maxOfAllMinColWidths)
{
if (gsDebug==PR_TRUE) printf(" EqualColWidths specified, so setting all col widths to %d\n", maxOfAllMinColWidths);
for (PRInt32 colIndex = 0; colIndex<numCols; colIndex++)
mColumnWidths[colIndex] = maxOfAllMinColWidths;
}
if (nsnull!=spanList)
delete spanList;
return result;
}
/**
sum the width of each column
add in table insets
@ -2762,20 +2040,6 @@ PRBool nsTableFrame::IsFirstPassValid() const
return firstInFlow->mFirstPassValid;
}
//ZZZ TOTAL HACK
PRBool isTableAutoWidth = PR_TRUE;
PRBool isAutoColumnWidths = PR_TRUE;
PRBool nsTableFrame::TableIsAutoWidth()
{ // ZZZ: TOTAL HACK
return isTableAutoWidth;
}
PRBool nsTableFrame::AutoColumnWidths()
{ // ZZZ: TOTAL HACK
return isAutoColumnWidths;
}
NS_METHOD nsTableFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
nsIFrame* aParent,
nsIFrame*& aContinuingFrame)

View File

@ -26,6 +26,7 @@ class nsTableCell;
class nsVoidArray;
class nsTableCellFrame;
class CellData;
class nsITableLayoutStrategy;
struct InnerTableReflowState;
struct nsStylePosition;
struct nsStyleSpacing;
@ -152,7 +153,6 @@ public:
void SetColumnWidth(PRInt32 aColIndex, PRInt32 aWidth);
/**
* Calculate Layout Information
*
@ -275,116 +275,6 @@ protected:
const nsSize& aMaxSize,
nsSize* aMaxElementSize);
/** assign widths for each column that has fixed width.
* Computes the minimum and maximum table widths.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aMaxWidth the maximum width of the table
* @param aNumCols the total number of columns in the table
* @param aTableStyle the resolved style for the table
* @param aTotalFixedWidth out param, the sum of the fixed width columns
* @param aMinTableWidth out param, the min possible table width
* @param aMaxTableWidth out param, the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: should be renamed to "AssignKnownWidthInformation
*/
virtual PRBool AssignFixedColumnWidths(nsIPresContext* aPresContext,
PRInt32 aMaxWidth,
PRInt32 aNumCols,
PRInt32 & aTotalFixedWidth,
PRInt32 & aMinTableWidth,
PRInt32 & aMaxTableWidth);
/** assign widths for each column that has proportional width inside a table that
* has a fixed width.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space.)
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceProportionalColumnsForAutoWidthTable(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
/** assign the minimum allowed width for each column that has proportional width.
* Typically called when the min table width doesn't fit in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool SetColumnsToMinWidth(nsIPresContext* aPresContext);
/** assign the maximum allowed width for each column that has proportional width.
* Typically called when the desired max table width fits in the available space.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*/
virtual PRBool BalanceColumnsTableFits(nsIPresContext* aPresContext,
PRInt32 aAvailWidth);
/** assign widths for each column that has proportional width inside a table that
* has auto width (width set by the content and available space) according to the
* HTML 4 specification.
* Sets mColumnWidths as a side effect.
*
* @param aPresContext the presentation context
* @param aTableStyle the resolved style for the table
* @param aAvailWidth the remaining amount of horizontal space available
* @param aMaxWidth the total amount of horizontal space available
* @param aMinTableWidth the min possible table width
* @param aMaxTableWidth the max table width
*
* @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error
*
* TODO: rename this method to reflect that it is a Nav4 compatibility method
*/
virtual PRBool BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
PRInt32 aAvailWidth,
PRInt32 aMaxWidth,
PRInt32 aMinTableWidth,
PRInt32 aMaxTableWidth);
/** sets the width of the table according to the computed widths of each column. */
virtual void SetTableWidth(nsIPresContext* aPresContext);
@ -395,18 +285,6 @@ protected:
nscoord aMaxAscent,
nscoord aMaxHeight);
/** support routine returns PR_TRUE if the table should be sized "automatically"
* according to its content.
* In NAV4, this is the default (no WIDTH, no COLS).
*/
virtual PRBool TableIsAutoWidth();
/** support routine returns PR_TRUE if the table columns should be sized "automatically"
* according to its content.
* In NAV4, this is when there is a COLS attribute on the table.
*/
virtual PRBool AutoColumnWidths();
/** given the new parent size, do I really need to do a reflow? */
virtual PRBool NeedsReflow(const nsSize& aMaxSize);
@ -433,7 +311,7 @@ private:
PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit
PRInt32 mPass; // which Reflow pass are we currently in?
PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change
nsITableLayoutStrategy * mTableLayoutStrategy; // the layout strategy for this frame
};
#endif