much better backwards compatibility for autowidth tables

now autowidth columns as assigned a width starting from their minimum.  The remaining
space is proportionately divided among them, never allowing a column to go over its max (for
autowidth tables only.)
This commit is contained in:
buster@netscape.com
1998-10-01 18:39:31 +00:00
parent b37dc18ad1
commit e7900d487d
4 changed files with 138 additions and 244 deletions

View File

@@ -1921,7 +1921,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( const nsReflowState&
break;
}
/* set the column width, knowing that the table fits in the available space */
/* set the column width, knowing that the table is constrained */
if (0==specifiedProportionColumnWidth || 0.0==specifiedPercentageColWidth)
{ // col width is specified to be the minimum
mTableFrame->SetColumnWidth(colIndex, minColWidth);
@@ -1940,7 +1940,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( const nsReflowState&
}
else if (PR_TRUE==isAutoWidth)
{ // column's width is determined by its content, done in post-processing
mTableFrame->SetColumnWidth(colIndex, 0); // set to 0 width for now
mTableFrame->SetColumnWidth(colIndex, minColWidth); // reserve the column's min width
atLeastOneAutoWidthColumn = PR_TRUE;
}
else if (-1!=specifiedProportionColumnWidth)
@@ -2016,7 +2016,9 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( const nsReflowState&
// first, assign autoWidth columns a width
if (PR_TRUE==atLeastOneAutoWidthColumn)
{ // proportionately distribute the remaining space to autowidth columns
DistributeRemainingSpace(aMaxWidth, tableWidth, aTableIsAutoWidth);
// "0" for the last param tells DistributeRemainingSpace that this is the top (non-recursive) call
PRInt32 topRecursiveControl=0;
DistributeRemainingSpace(aMaxWidth, tableWidth, aTableIsAutoWidth, topRecursiveControl);
}
// second, fix up tables where column width attributes give us a table that is too wide or too narrow
@@ -2090,12 +2092,20 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( const nsReflowState&
return result;
}
static const PRInt32 kRecursionLimit=10; // backwards compatible with Nav4
// take the remaining space in the table and distribute it proportionately
// to the auto-width cells in the table (based on desired width)
void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth,
nscoord aComputedTableWidth,
PRBool aTableIsAutoWidth)
nscoord &aComputedTableWidth,
PRBool aTableIsAutoWidth,
PRInt32 &aRecursionControl)
{
aRecursionControl++;
if (kRecursionLimit<=aRecursionControl) // only allow kRecursionLimit iterations, as per Nav4. See laytable.c
return;
nscoord sumOfMinWidths = 0; // sum of min widths of each auto column
nscoord aStartingComputedTableWidth = aComputedTableWidth; // remember this so we can see if we're making any progress
if (PR_TRUE==gsDebug)
printf ("DistributeRemainingSpace: fixed width %d > computed table width %d\n",
aTableSpecifiedWidth, aComputedTableWidth);
@@ -2105,6 +2115,7 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified
mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns);
if (0!=numAutoColumns)
{
PRInt32 numColumnsToBeResized=0;
// there's at least one auto-width column, so give it (them) the extra space
// proportionately distributed extra space, based on the column's desired size
nscoord totalEffectiveWidthOfAutoColumns = 0;
@@ -2112,12 +2123,18 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified
PRInt32 i;
for (i = 0; i<numAutoColumns; i++)
{
PRInt32 colIndex = autoColumns[i];
nsTableColFrame *colFrame = mTableFrame->GetColFrame(autoColumns[i]);
nscoord startingColWidth = mTableFrame->GetColumnWidth(colIndex);
nscoord maxEffectiveColWidth = colFrame->GetEffectiveMaxColWidth();
if (0!=maxEffectiveColWidth)
totalEffectiveWidthOfAutoColumns += maxEffectiveColWidth;
else
totalEffectiveWidthOfAutoColumns += mTableFrame->GetColumnWidth(autoColumns[i]);
if ((PR_FALSE==aTableIsAutoWidth)||(startingColWidth<maxEffectiveColWidth))
{
numColumnsToBeResized++;
if (0!=maxEffectiveColWidth)
totalEffectiveWidthOfAutoColumns += maxEffectiveColWidth;
else
totalEffectiveWidthOfAutoColumns += mTableFrame->GetColumnWidth(autoColumns[i]);
}
}
// availWidth is the difference between the total available width and the
// amount of space already assigned, assuming auto col widths were assigned 0.
@@ -2132,46 +2149,52 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified
{
PRInt32 colIndex = autoColumns[i];
nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex);
nscoord startingColWidth = mTableFrame->GetColumnWidth(colIndex);
nscoord maxEffectiveColWidth = colFrame->GetEffectiveMaxColWidth();
// if we actually have room to distribute, do it here
// otherwise, the auto columns will remain 0-width until expanded to their minimum in EnsureCellMinWidths
// otherwise, the auto columns already are set to their minimum
if (0<availWidth)
{
float percent;
if (0!=aTableSpecifiedWidth)
percent = ((float)(colFrame->GetEffectiveMaxColWidth()))/((float)totalEffectiveWidthOfAutoColumns);
else
percent = ((float)1)/((float)numAutoColumns);
nscoord colWidth = (nscoord)(availWidth*percent);
// in an auto width table, the column cannot be wider than its max width
if (PR_TRUE==aTableIsAutoWidth)
{ // since the table shrinks to the content width, don't be wider than the content max width
colWidth = PR_MIN(colWidth, colFrame->GetMaxColWidth()); // XXX can this legally be 0?
if ((PR_FALSE==aTableIsAutoWidth)||(startingColWidth<maxEffectiveColWidth))
{
float percent;
if (0!=aTableSpecifiedWidth)
percent = ((float)maxEffectiveColWidth)/((float)totalEffectiveWidthOfAutoColumns);
else
percent = ((float)1)/((float)numColumnsToBeResized);
nscoord colWidth = startingColWidth + (nscoord)(availWidth*percent);
if (PR_TRUE==gsDebug)
printf(" colWidth = %d from startingColWidth %d plus %d percent of availWidth %d\n",
colWidth, startingColWidth, (nscoord)((float)100*percent), availWidth);
// in an auto width table, the column cannot be wider than its max width
if (PR_TRUE==aTableIsAutoWidth)
{ // since the table shrinks to the content width, don't be wider than the content max width
nscoord newColWidth = PR_MIN(colWidth, colFrame->GetMaxColWidth());
aComputedTableWidth += newColWidth-colWidth;
colWidth = newColWidth;
}
else
aComputedTableWidth += colWidth - startingColWidth;
if (gsDebug==PR_TRUE)
printf(" distribute width to auto columns: column %d was %d, now set to %d\n",
colIndex, colFrame->GetEffectiveMaxColWidth(), colWidth);
mTableFrame->SetColumnWidth(colIndex, colWidth);
}
if (gsDebug==PR_TRUE)
printf(" distribute width to auto columns: column %d was %d, now set to %d\n",
colIndex, colFrame->GetEffectiveMaxColWidth(), colWidth);
mTableFrame->SetColumnWidth(colIndex, colWidth);
}
}
if (PR_TRUE==gsDebug)
{
nscoord tableWidth=0;
printf("before EnsureCellMinWidth: ");
for (PRInt32 i=0; i<mNumCols; i++)
if (aComputedTableWidth!=aStartingComputedTableWidth)
{ // othewise we made no progress and shouldn't continue
if (aComputedTableWidth<aTableSpecifiedWidth)
{
tableWidth += mTableFrame->GetColumnWidth(i);
printf(" %d ", mTableFrame->GetColumnWidth(i));
DistributeRemainingSpace(aTableSpecifiedWidth, aComputedTableWidth, aTableIsAutoWidth, aRecursionControl);
}
printf ("\n computed table width is %d\n",tableWidth);
}
EnsureCellMinWidths(PR_FALSE);
}
if (PR_TRUE==gsDebug)
{
nscoord tableWidth=0;
printf("after EnsureCellMinWidth: ");
printf("at end of DistributeRemainingSpace: ");
for (PRInt32 i=0; i<mNumCols; i++)
{
tableWidth += mTableFrame->GetColumnWidth(i);
@@ -2181,84 +2204,6 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified
}
}
void BasicTableLayoutStrategy::EnsureCellMinWidths(PRBool aShrinkFixedWidthCells)
{
PRBool atLeastOne = PR_TRUE;
PRBool *colsToRemoveFrom = new PRBool[mNumCols];
for (PRInt32 i=0; i<mNumCols; i++)
colsToRemoveFrom[i] = PR_TRUE;
if (PR_FALSE==aShrinkFixedWidthCells)
{
PRInt32 numFixedColumns=0;
PRInt32 *fixedColumns=nsnull;
mTableFrame->GetColumnsByType(eStyleUnit_Coord, numFixedColumns, fixedColumns);
for (PRInt32 i=0; i<numFixedColumns; i++)
colsToRemoveFrom[fixedColumns[i]]=PR_FALSE;
}
while (PR_TRUE==atLeastOne)
{
atLeastOne=PR_FALSE;
PRInt32 colIndex;
nscoord addedWidth = 0;
// first, bump up cells that are below their min to their min width
for (colIndex=0; colIndex<mNumCols; colIndex++)
{
nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex);
nscoord minColWidth = colFrame->GetMinColWidth();
nscoord colWidth = mTableFrame->GetColumnWidth(colIndex);
if (colWidth<minColWidth)
{
addedWidth += (minColWidth-colWidth);
mTableFrame->SetColumnWidth(colIndex, minColWidth);
atLeastOne=PR_TRUE;
}
}
// second, remove the added space from cells that can afford to slim down
//QQQ boy is this slow! there has to be a faster way that is still guaranteed to be accurate...
while ((addedWidth>0))
{ // while we still have some extra space, and last time we were able to take some off...
PRInt32 startingAddedWidth = addedWidth;
for (colIndex=0; colIndex<mNumCols; colIndex++)
{
nsTableColFrame *colFrame = mTableFrame->GetColFrame(colIndex);
nscoord minColWidth = colFrame->GetMinColWidth();
nscoord colWidth = mTableFrame->GetColumnWidth(colIndex);
if ((colWidth>minColWidth) && (PR_TRUE==colsToRemoveFrom[colIndex]))
{
mTableFrame->SetColumnWidth(colIndex, colWidth-1);
addedWidth--;
if (0==addedWidth)
{ // we're run out of extra space
break; // for (colIndex=0; colIndex<mNumCols; colIndex++)
}
}
}
if (startingAddedWidth==addedWidth)
{ // we we unable to find any columns to remove space from
PRBool okToContinue=PR_FALSE;
for (PRInt32 i=0; i<mNumCols; i++)
{
if (PR_FALSE==colsToRemoveFrom[i])
{
colsToRemoveFrom[i] = PR_TRUE;
okToContinue=PR_TRUE;
}
}
if (PR_FALSE==okToContinue)
break; // while ((addedWidth>0))
}
}
if (0<addedWidth)
{ // all our cells are at their min width, so no use doing anything else
break; // while (PR_TRUE==atLeastOne)
}
}
delete [] colsToRemoveFrom;
}
void BasicTableLayoutStrategy::AdjustTableThatIsTooWide(nscoord aComputedWidth,
nscoord aTableWidth, PRBool aShrinkFixedCols)