From ad76084cb90f35912cf717e3ae917f4b54d1406a Mon Sep 17 00:00:00 2001 From: "buster%netscape.com" Date: Wed, 19 Aug 1998 15:43:51 +0000 Subject: [PATCH] improved colspan handling. cells with colspans and specified widths divide their width provisionally between the columns they span. This provisional division is ammended by any cell in any of the effected columns that: 1) has a colspan=1, and 2) has a width specified the widths of all other columns must be adjusted for cells like these. Further complicating matters is that it seems that if multiple colspanning cells intersect a column and each has a width specified such that the column would have a different width depending on which is used, only the first such cell is used . I can neither confirm nor deny this reading the mozilla code. I also taught the cell map how to deal with this situation: colspan=1 | colspan=2 | colspan=1 colspan=1 | colspan=2 | colspan=1 This table "really" has 4 columns, but the middle cells are treated as if they have no colspan. Trust me, it matters. The original colspan attributes can't simply be thrown away because Mr. DOM could come along at any time and add/remove a cell that would make them important. git-svn-id: svn://10.0.0.236/trunk@8185 18797224-902f-48f8-a5cc-f745e15eee43 --- .../table/src/BasicTableLayoutStrategy.cpp | 77 +++++++++++------- mozilla/layout/html/table/src/nsCellMap.cpp | 33 +++++++- mozilla/layout/html/table/src/nsCellMap.h | 6 ++ .../layout/html/table/src/nsTableFrame.cpp | 79 +++++++++++++------ .../tables/BasicTableLayoutStrategy.cpp | 77 +++++++++++------- mozilla/layout/tables/nsCellMap.cpp | 33 +++++++- mozilla/layout/tables/nsCellMap.h | 6 ++ mozilla/layout/tables/nsTableFrame.cpp | 79 +++++++++++++------ 8 files changed, 284 insertions(+), 106 deletions(-) diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp index bfbfb36a841..8c386257bb2 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -253,6 +253,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() if (gsDebug==PR_TRUE) printf ("** %p: AssignPreliminaryColumnWidths **\n", mTableFrame); nsVoidArray *spanList=nsnull; nsVoidArray *colSpanList=nsnull; + PRInt32 numProvisionalFixedColumns = 0; // used for assigning width from cell with colspan to columns that are spanned PRBool hasColsAttribute = (PRBool)(NS_STYLE_TABLE_COLS_NONE!=mCols); @@ -291,6 +292,8 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() { haveColWidth = PR_TRUE; specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); + if (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN==colFrame->GetWidthSource()) + numProvisionalFixedColumns++; } /* Scan the column, simulatneously assigning column widths @@ -341,7 +344,8 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() rowIndex, colSpan, cellMinSize.width, cellMinSize.height, cellDesiredSize.width, cellDesiredSize.height); - if (PR_TRUE==haveColWidth)// && PR_TRUE==cellGrantingWidth) + if ((PR_TRUE==haveColWidth) && + (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=colFrame->GetWidthSource())) { // This col has a specified fixed width so set the min and max width to the larger of // (specified width, largest max_element_size of the cells in the column) @@ -380,16 +384,6 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() effectiveMinColumnWidth = cellMinWidth; } - //bookkeeping: is this the cell that gave the column it's fixed width attribute? - // must be done after "haveColWidth && cellGrantingWidth" used above - if (PR_TRUE==cellGrantingWidth && 1==colSpan) - { - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); - if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) - cellGrantingWidth=PR_FALSE; //I've found the cell that gave the col it's width - } - if (1GetColumnFrame(i+colIndex, cf); const nsStylePosition* colPos; cf->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPos); - if (colPos->mWidth.GetUnit() != eStyleUnit_Auto) + if (colPos->mWidth.GetUnit() != eStyleUnit_Auto && + (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=cf->GetWidthSource())) { okToAdd = PR_FALSE; break; @@ -412,20 +407,39 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() } } + nscoord width = cellDesiredSize.width; // used below as the cell's "natural" width + if (PR_TRUE == haveColWidth) + width = colSpan*specifiedFixedColWidth; + if (PR_TRUE==okToAdd) { - ColSpanStruct *colSpanInfo = new ColSpanStruct(colSpan, colIndex, cellDesiredSize.width); + ColSpanStruct *colSpanInfo = new ColSpanStruct(colSpan, colIndex, width); if (nsnull==colSpanList) colSpanList = new nsVoidArray(); colSpanList->AppendElement(colSpanInfo); } - // add the cell to our list of spanning cells - SpanInfo *spanInfo = new SpanInfo(colIndex, colSpan, cellMinWidth, cellDesiredWidth); - if (nsnull==spanList) - spanList = new nsVoidArray(); - spanList->AppendElement(spanInfo); + if (PR_TRUE==cellGrantingWidth) + { + // add the cell to our list of spanning cells + SpanInfo *spanInfo = new SpanInfo(colIndex, colSpan, cellMinWidth, width); + if (nsnull==spanList) + spanList = new nsVoidArray(); + spanList->AppendElement(spanInfo); + } } + + //bookkeeping: is this the cell that gave the column it's fixed width attribute? + // must be done after "haveColWidth && cellGrantingWidth" used above + if (PR_TRUE==cellGrantingWidth) + { + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) + cellGrantingWidth=PR_FALSE; //I've found the cell that gave the col it's width + } + + // book 'em, Danno if (gsDebug) { printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n", rowIndex, minColWidth, maxColWidth); @@ -454,7 +468,8 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() colFrame->SetEffectiveMaxColWidth(effectiveMaxColumnWidth); // this is the default, the real adjustment happens below where we deal with colspans colFrame->SetAdjustedMinColWidth(effectiveMinColumnWidth); - if (PR_TRUE==haveColWidth) + if ((PR_TRUE==haveColWidth) && + (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=colFrame->GetWidthSource())) mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); else mTableFrame->SetColumnWidth(colIndex, effectiveMaxColumnWidth); @@ -467,8 +482,8 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() maxColWidthArray[colIndex] = maxColWidth; } if (gsDebug==PR_TRUE) - printf ("after col %d, minColWidth=%d effectiveMinColumnWidth=%d\n\tminTableWidth = %d and maxTableWidth = %d\n", - colIndex, minColWidth, effectiveMinColumnWidth, mMinTableWidth, mMaxTableWidth); + printf ("after col %d, minColWidth=%d effectiveMinColumnWidth=%d\n\teffectiveMaxColumnWidth = %d\n", + colIndex, minColWidth, effectiveMinColumnWidth, effectiveMaxColumnWidth); } // now, post-process the computed values based on the table attributes @@ -479,10 +494,11 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() if (nsnull!=spanList) { // we only want to do this if there are auto-cells involved + // or if we have columns that are provisionally fixed-width with colspans PRInt32 numAutoColumns=0; PRInt32 *autoColumns=nsnull; mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); - if (0==numAutoColumns) + if (0==numAutoColumns && 0==numProvisionalFixedColumns) { //table fully specified, so no need to do any extra work here PRInt32 spanCount = spanList->Count(); // go through the list backwards so we can delete easily @@ -494,21 +510,21 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() } } else - { + { // for every column, handle spanning cells that impact that column for (PRInt32 colIndex=0; colIndexCount(); // go through the list backwards so we can delete easily for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--) - { + { // get each spanInfo struct and see if it impacts this column SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex)); // if the spanInfo is about a column before the current column, it effects // the current column (otherwise it would have already been deleted.) if (spanInfo->initialColIndex <= colIndex) { if (0==spanInfo->effectiveMaxWidthOfSpannedCols) - { + { // if we have not yet computed effectiveMaxWidthOfSpannedCols, do it now for (PRInt32 span=0; spaninitialColSpan; span++) { nsTableColFrame *nextColFrame = mTableFrame->GetColFrame(colIndex+span); @@ -550,10 +566,13 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() nscoord spanCellMaxWidth; if (0!=spanInfo->effectiveMaxWidthOfSpannedCols) { - spanCellMaxWidth = (spanInfo->cellDesiredWidth * colFrame->GetEffectiveMaxColWidth()) / - (spanInfo->effectiveMaxWidthOfSpannedCols); + float percent = ((float)(colFrame->GetEffectiveMaxColWidth())) / + ((float)(spanInfo->effectiveMaxWidthOfSpannedCols)); + spanCellMaxWidth = (nscoord)(((float)(spanInfo->cellDesiredWidth)) * percent); if (gsDebug==PR_TRUE) - printf ("spanCellMaxWidth portion = %d\n", spanCellMaxWidth); + printf ("spanCellMaxWidth portion = %d with percent = %f from effMaxColW=%d and sum=%d\n", + spanCellMaxWidth, percent, colFrame->GetEffectiveMaxColWidth(), + spanInfo->effectiveMaxWidthOfSpannedCols); if (colMaxWidth < spanCellMaxWidth) { // make sure we're at least as big as our min @@ -1561,7 +1580,7 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, nscoord excessForThisColumn = (nscoord)(excess*percent); nscoord colWidth = excessForThisColumn+oldColWidth; if (gsDebug==PR_TRUE) - printf(" distribute excess to all columns: column %d was %d, now set to %d from % = %f\n", + printf(" distribute excess: column %d was %d, now %d from %=%f\n", colIndex, oldColWidth, colWidth, percent); mTableFrame->SetColumnWidth(colIndex, colWidth); } diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp index befaa3ddb40..daba16d32b5 100644 --- a/mozilla/layout/html/table/src/nsCellMap.cpp +++ b/mozilla/layout/html/table/src/nsCellMap.cpp @@ -35,6 +35,7 @@ nsCellMap::nsCellMap(int aRows, int aColumns) { mCells = nsnull; mColFrames = nsnull; + mMinColSpans = nsnull; Reset(aRows, aColumns); } @@ -57,10 +58,13 @@ nsCellMap::~nsCellMap() } delete [] mCells; } - if (nsnull!= mColFrames) + if (nsnull != mColFrames) delete mColFrames; + if (nsnull != mMinColSpans) + delete [] mMinColSpans; mCells = nsnull; mColFrames = nsnull; + mMinColSpans = nsnull; }; @@ -131,5 +135,32 @@ nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex) } +void nsCellMap::SetMinColSpan(PRInt32 aColIndex, PRBool aColSpan) +{ + NS_ASSERTION(aColIndex=0, "bad aColSpan"); + + // initialize the data structure if not already done + if (nsnull==mMinColSpans) + { + mMinColSpans = new PRInt32[mColCount]; + for (PRInt32 i=0; iGetRowCount()==1) return 1; PRInt32 colSpan = aCell->GetColSpan(); PRInt32 colCount = GetColCount(); if (colCount < (aColIndex + colSpan)) - return (colCount - aColIndex); - return colSpan; + result = colCount - aColIndex; + else + { + result = colSpan; + // check for case where all cells in a column have a colspan + PRInt32 initialColIndex = aCell->GetColIndex(); + PRInt32 minColSpanForCol = cellMap->GetMinColSpan(initialColIndex); + result -= (minColSpanForCol - 1); // minColSpanForCol is always at least 1 + // and we want to treat default as 0 (no effect) + } + + return result; } PRInt32 nsTableFrame::GetEffectiveCOLSAttribute() @@ -691,8 +702,6 @@ void nsTableFrame::BuildCellMap () PRInt32 colIndex = 0; nsIFrame* cellFrame; rowFrame->FirstChild(cellFrame); - if (gsDebug==PR_TRUE) - DumpCellMap(); while ((nsnull != cellFrame) && (colIndex < mColCount)) { @@ -745,6 +754,26 @@ void nsTableFrame::BuildCellMap () } if (gsDebug==PR_TRUE) DumpCellMap (); + // iterate through the columns setting the min col span if necessary + // it would be more efficient if we could do this in the above loop + for (PRInt32 colIndex=0; colIndexGetCellFrameAt(rowIndex, colIndex); + if (nsnull!=cellFrame) + { + PRInt32 colSpan = cellFrame->GetColSpan(); + if (0==rowIndex) + minColSpan = colSpan; + else + minColSpan = PR_MIN(minColSpan, colSpan); + } + } + if (1!=minColSpan) + mCellMap->SetMinColSpan(colIndex, minColSpan); + } } /** @@ -2529,27 +2558,31 @@ nsTableFrame::SetColumnStyleFromCell(nsIPresContext * aPresContext, GetColumnFrame(i+aCellFrame->GetColIndex(), colFrame); if (nsTableColFrame::eWIDTH_SOURCE_CELL != colFrame->GetWidthSource()) { - // get the column style and set the width attribute - nsIStyleContext *colSC; - colFrame->GetStyleContext(aPresContext, colSC); - nsStylePosition* colPosition = (nsStylePosition*) colSC->GetMutableStyleData(eStyleStruct_Position); - NS_RELEASE(colSC); - // set the column width attribute - if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) + if ((1==colSpan) || + (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN != colFrame->GetWidthSource())) { - nscoord width = cellPosition->mWidth.GetCoordValue(); - colPosition->mWidth.SetCoordValue(width/colSpan); + // get the column style and set the width attribute + nsIStyleContext *colSC; + colFrame->GetStyleContext(aPresContext, colSC); + nsStylePosition* colPosition = (nsStylePosition*) colSC->GetMutableStyleData(eStyleStruct_Position); + NS_RELEASE(colSC); + // set the column width attribute + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) + { + nscoord width = cellPosition->mWidth.GetCoordValue(); + colPosition->mWidth.SetCoordValue(width/colSpan); + } + else + { + float width = cellPosition->mWidth.GetPercentValue(); + colPosition->mWidth.SetPercentValue(width/colSpan); + } + // set the column width-set-type + if (1==colSpan) + colFrame->SetWidthSource(nsTableColFrame::eWIDTH_SOURCE_CELL); + else + colFrame->SetWidthSource(nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN); } - else - { - float width = cellPosition->mWidth.GetPercentValue(); - colPosition->mWidth.SetPercentValue(width/colSpan); - } - // set the column width-set-type - if (1==colSpan) - colFrame->SetWidthSource(nsTableColFrame::eWIDTH_SOURCE_CELL); - else - colFrame->SetWidthSource(nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN); } } } diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp index bfbfb36a841..8c386257bb2 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp @@ -253,6 +253,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() if (gsDebug==PR_TRUE) printf ("** %p: AssignPreliminaryColumnWidths **\n", mTableFrame); nsVoidArray *spanList=nsnull; nsVoidArray *colSpanList=nsnull; + PRInt32 numProvisionalFixedColumns = 0; // used for assigning width from cell with colspan to columns that are spanned PRBool hasColsAttribute = (PRBool)(NS_STYLE_TABLE_COLS_NONE!=mCols); @@ -291,6 +292,8 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() { haveColWidth = PR_TRUE; specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); + if (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN==colFrame->GetWidthSource()) + numProvisionalFixedColumns++; } /* Scan the column, simulatneously assigning column widths @@ -341,7 +344,8 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() rowIndex, colSpan, cellMinSize.width, cellMinSize.height, cellDesiredSize.width, cellDesiredSize.height); - if (PR_TRUE==haveColWidth)// && PR_TRUE==cellGrantingWidth) + if ((PR_TRUE==haveColWidth) && + (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=colFrame->GetWidthSource())) { // This col has a specified fixed width so set the min and max width to the larger of // (specified width, largest max_element_size of the cells in the column) @@ -380,16 +384,6 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() effectiveMinColumnWidth = cellMinWidth; } - //bookkeeping: is this the cell that gave the column it's fixed width attribute? - // must be done after "haveColWidth && cellGrantingWidth" used above - if (PR_TRUE==cellGrantingWidth && 1==colSpan) - { - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); - if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) - cellGrantingWidth=PR_FALSE; //I've found the cell that gave the col it's width - } - if (1GetColumnFrame(i+colIndex, cf); const nsStylePosition* colPos; cf->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)colPos); - if (colPos->mWidth.GetUnit() != eStyleUnit_Auto) + if (colPos->mWidth.GetUnit() != eStyleUnit_Auto && + (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=cf->GetWidthSource())) { okToAdd = PR_FALSE; break; @@ -412,20 +407,39 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() } } + nscoord width = cellDesiredSize.width; // used below as the cell's "natural" width + if (PR_TRUE == haveColWidth) + width = colSpan*specifiedFixedColWidth; + if (PR_TRUE==okToAdd) { - ColSpanStruct *colSpanInfo = new ColSpanStruct(colSpan, colIndex, cellDesiredSize.width); + ColSpanStruct *colSpanInfo = new ColSpanStruct(colSpan, colIndex, width); if (nsnull==colSpanList) colSpanList = new nsVoidArray(); colSpanList->AppendElement(colSpanInfo); } - // add the cell to our list of spanning cells - SpanInfo *spanInfo = new SpanInfo(colIndex, colSpan, cellMinWidth, cellDesiredWidth); - if (nsnull==spanList) - spanList = new nsVoidArray(); - spanList->AppendElement(spanInfo); + if (PR_TRUE==cellGrantingWidth) + { + // add the cell to our list of spanning cells + SpanInfo *spanInfo = new SpanInfo(colIndex, colSpan, cellMinWidth, width); + if (nsnull==spanList) + spanList = new nsVoidArray(); + spanList->AppendElement(spanInfo); + } } + + //bookkeeping: is this the cell that gave the column it's fixed width attribute? + // must be done after "haveColWidth && cellGrantingWidth" used above + if (PR_TRUE==cellGrantingWidth) + { + const nsStylePosition* cellPosition; + cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) + cellGrantingWidth=PR_FALSE; //I've found the cell that gave the col it's width + } + + // book 'em, Danno if (gsDebug) { printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n", rowIndex, minColWidth, maxColWidth); @@ -454,7 +468,8 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() colFrame->SetEffectiveMaxColWidth(effectiveMaxColumnWidth); // this is the default, the real adjustment happens below where we deal with colspans colFrame->SetAdjustedMinColWidth(effectiveMinColumnWidth); - if (PR_TRUE==haveColWidth) + if ((PR_TRUE==haveColWidth) && + (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=colFrame->GetWidthSource())) mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); else mTableFrame->SetColumnWidth(colIndex, effectiveMaxColumnWidth); @@ -467,8 +482,8 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() maxColWidthArray[colIndex] = maxColWidth; } if (gsDebug==PR_TRUE) - printf ("after col %d, minColWidth=%d effectiveMinColumnWidth=%d\n\tminTableWidth = %d and maxTableWidth = %d\n", - colIndex, minColWidth, effectiveMinColumnWidth, mMinTableWidth, mMaxTableWidth); + printf ("after col %d, minColWidth=%d effectiveMinColumnWidth=%d\n\teffectiveMaxColumnWidth = %d\n", + colIndex, minColWidth, effectiveMinColumnWidth, effectiveMaxColumnWidth); } // now, post-process the computed values based on the table attributes @@ -479,10 +494,11 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() if (nsnull!=spanList) { // we only want to do this if there are auto-cells involved + // or if we have columns that are provisionally fixed-width with colspans PRInt32 numAutoColumns=0; PRInt32 *autoColumns=nsnull; mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); - if (0==numAutoColumns) + if (0==numAutoColumns && 0==numProvisionalFixedColumns) { //table fully specified, so no need to do any extra work here PRInt32 spanCount = spanList->Count(); // go through the list backwards so we can delete easily @@ -494,21 +510,21 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() } } else - { + { // for every column, handle spanning cells that impact that column for (PRInt32 colIndex=0; colIndexCount(); // go through the list backwards so we can delete easily for (PRInt32 spanIndex=spanCount-1; 0<=spanIndex; spanIndex--) - { + { // get each spanInfo struct and see if it impacts this column SpanInfo *spanInfo = (SpanInfo *)(spanList->ElementAt(spanIndex)); // if the spanInfo is about a column before the current column, it effects // the current column (otherwise it would have already been deleted.) if (spanInfo->initialColIndex <= colIndex) { if (0==spanInfo->effectiveMaxWidthOfSpannedCols) - { + { // if we have not yet computed effectiveMaxWidthOfSpannedCols, do it now for (PRInt32 span=0; spaninitialColSpan; span++) { nsTableColFrame *nextColFrame = mTableFrame->GetColFrame(colIndex+span); @@ -550,10 +566,13 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() nscoord spanCellMaxWidth; if (0!=spanInfo->effectiveMaxWidthOfSpannedCols) { - spanCellMaxWidth = (spanInfo->cellDesiredWidth * colFrame->GetEffectiveMaxColWidth()) / - (spanInfo->effectiveMaxWidthOfSpannedCols); + float percent = ((float)(colFrame->GetEffectiveMaxColWidth())) / + ((float)(spanInfo->effectiveMaxWidthOfSpannedCols)); + spanCellMaxWidth = (nscoord)(((float)(spanInfo->cellDesiredWidth)) * percent); if (gsDebug==PR_TRUE) - printf ("spanCellMaxWidth portion = %d\n", spanCellMaxWidth); + printf ("spanCellMaxWidth portion = %d with percent = %f from effMaxColW=%d and sum=%d\n", + spanCellMaxWidth, percent, colFrame->GetEffectiveMaxColWidth(), + spanInfo->effectiveMaxWidthOfSpannedCols); if (colMaxWidth < spanCellMaxWidth) { // make sure we're at least as big as our min @@ -1561,7 +1580,7 @@ void BasicTableLayoutStrategy::DistributeExcessSpace(nscoord aAvailWidth, nscoord excessForThisColumn = (nscoord)(excess*percent); nscoord colWidth = excessForThisColumn+oldColWidth; if (gsDebug==PR_TRUE) - printf(" distribute excess to all columns: column %d was %d, now set to %d from % = %f\n", + printf(" distribute excess: column %d was %d, now %d from %=%f\n", colIndex, oldColWidth, colWidth, percent); mTableFrame->SetColumnWidth(colIndex, colWidth); } diff --git a/mozilla/layout/tables/nsCellMap.cpp b/mozilla/layout/tables/nsCellMap.cpp index befaa3ddb40..daba16d32b5 100644 --- a/mozilla/layout/tables/nsCellMap.cpp +++ b/mozilla/layout/tables/nsCellMap.cpp @@ -35,6 +35,7 @@ nsCellMap::nsCellMap(int aRows, int aColumns) { mCells = nsnull; mColFrames = nsnull; + mMinColSpans = nsnull; Reset(aRows, aColumns); } @@ -57,10 +58,13 @@ nsCellMap::~nsCellMap() } delete [] mCells; } - if (nsnull!= mColFrames) + if (nsnull != mColFrames) delete mColFrames; + if (nsnull != mMinColSpans) + delete [] mMinColSpans; mCells = nsnull; mColFrames = nsnull; + mMinColSpans = nsnull; }; @@ -131,5 +135,32 @@ nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex) } +void nsCellMap::SetMinColSpan(PRInt32 aColIndex, PRBool aColSpan) +{ + NS_ASSERTION(aColIndex=0, "bad aColSpan"); + + // initialize the data structure if not already done + if (nsnull==mMinColSpans) + { + mMinColSpans = new PRInt32[mColCount]; + for (PRInt32 i=0; iGetRowCount()==1) return 1; PRInt32 colSpan = aCell->GetColSpan(); PRInt32 colCount = GetColCount(); if (colCount < (aColIndex + colSpan)) - return (colCount - aColIndex); - return colSpan; + result = colCount - aColIndex; + else + { + result = colSpan; + // check for case where all cells in a column have a colspan + PRInt32 initialColIndex = aCell->GetColIndex(); + PRInt32 minColSpanForCol = cellMap->GetMinColSpan(initialColIndex); + result -= (minColSpanForCol - 1); // minColSpanForCol is always at least 1 + // and we want to treat default as 0 (no effect) + } + + return result; } PRInt32 nsTableFrame::GetEffectiveCOLSAttribute() @@ -691,8 +702,6 @@ void nsTableFrame::BuildCellMap () PRInt32 colIndex = 0; nsIFrame* cellFrame; rowFrame->FirstChild(cellFrame); - if (gsDebug==PR_TRUE) - DumpCellMap(); while ((nsnull != cellFrame) && (colIndex < mColCount)) { @@ -745,6 +754,26 @@ void nsTableFrame::BuildCellMap () } if (gsDebug==PR_TRUE) DumpCellMap (); + // iterate through the columns setting the min col span if necessary + // it would be more efficient if we could do this in the above loop + for (PRInt32 colIndex=0; colIndexGetCellFrameAt(rowIndex, colIndex); + if (nsnull!=cellFrame) + { + PRInt32 colSpan = cellFrame->GetColSpan(); + if (0==rowIndex) + minColSpan = colSpan; + else + minColSpan = PR_MIN(minColSpan, colSpan); + } + } + if (1!=minColSpan) + mCellMap->SetMinColSpan(colIndex, minColSpan); + } } /** @@ -2529,27 +2558,31 @@ nsTableFrame::SetColumnStyleFromCell(nsIPresContext * aPresContext, GetColumnFrame(i+aCellFrame->GetColIndex(), colFrame); if (nsTableColFrame::eWIDTH_SOURCE_CELL != colFrame->GetWidthSource()) { - // get the column style and set the width attribute - nsIStyleContext *colSC; - colFrame->GetStyleContext(aPresContext, colSC); - nsStylePosition* colPosition = (nsStylePosition*) colSC->GetMutableStyleData(eStyleStruct_Position); - NS_RELEASE(colSC); - // set the column width attribute - if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) + if ((1==colSpan) || + (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN != colFrame->GetWidthSource())) { - nscoord width = cellPosition->mWidth.GetCoordValue(); - colPosition->mWidth.SetCoordValue(width/colSpan); + // get the column style and set the width attribute + nsIStyleContext *colSC; + colFrame->GetStyleContext(aPresContext, colSC); + nsStylePosition* colPosition = (nsStylePosition*) colSC->GetMutableStyleData(eStyleStruct_Position); + NS_RELEASE(colSC); + // set the column width attribute + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) + { + nscoord width = cellPosition->mWidth.GetCoordValue(); + colPosition->mWidth.SetCoordValue(width/colSpan); + } + else + { + float width = cellPosition->mWidth.GetPercentValue(); + colPosition->mWidth.SetPercentValue(width/colSpan); + } + // set the column width-set-type + if (1==colSpan) + colFrame->SetWidthSource(nsTableColFrame::eWIDTH_SOURCE_CELL); + else + colFrame->SetWidthSource(nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN); } - else - { - float width = cellPosition->mWidth.GetPercentValue(); - colPosition->mWidth.SetPercentValue(width/colSpan); - } - // set the column width-set-type - if (1==colSpan) - colFrame->SetWidthSource(nsTableColFrame::eWIDTH_SOURCE_CELL); - else - colFrame->SetWidthSource(nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN); } } }