From 703e798b0652af6d134250e207dba46f9ad9ede9 Mon Sep 17 00:00:00 2001 From: "karnaze%netscape.com" Date: Wed, 26 May 1999 22:22:23 +0000 Subject: [PATCH] Rewrote DistributeRemainingSpace a 2nd time and added compat mode. bug 6068, 6933. nsTableRowGroupFrame::CalculateRowHeights - changed row spans to consider top and bottom margins during height calculations. Calculations using percentages ensure that the sum of rows sum exactly to excess. bug 6404 BasicTableLayoutStrategy::BalanceColumnsConstrained cols in span other than 1st col was not getting additional allocations from cell. ::DistributeRemainSpace uses max width of col instead of max effective width. Also added checks for negative value during percentage calculations. git-svn-id: svn://10.0.0.236/trunk@32755 18797224-902f-48f8-a5cc-f745e15eee43 --- .../table/src/BasicTableLayoutStrategy.cpp | 271 ++++++++++++++---- .../html/table/src/BasicTableLayoutStrategy.h | 4 +- .../layout/html/table/src/nsTableColFrame.h | 16 ++ .../layout/html/table/src/nsTableFrame.cpp | 4 +- .../html/table/src/nsTableRowGroupFrame.cpp | 55 ++-- .../tables/BasicTableLayoutStrategy.cpp | 271 ++++++++++++++---- .../layout/tables/BasicTableLayoutStrategy.h | 4 +- mozilla/layout/tables/nsTableColFrame.h | 16 ++ mozilla/layout/tables/nsTableFrame.cpp | 4 +- .../layout/tables/nsTableRowGroupFrame.cpp | 55 ++-- 10 files changed, 532 insertions(+), 168 deletions(-) diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp index 6627d57e0b7..7712953e951 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -217,14 +217,15 @@ PRBool BasicTableLayoutStrategy::IsFixedWidth(const nsStylePosition* aStylePosit } -BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame) +BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame, PRBool aIsNavQuirks) { NS_ASSERTION(nsnull != aFrame, "bad frame arg"); - mTableFrame = aFrame; - mMinTableWidth = 0; - mMaxTableWidth = 0; - mFixedTableWidth = 0; + mTableFrame = aFrame; + mMinTableWidth = 0; + mMaxTableWidth = 0; + mFixedTableWidth = 0; + mIsNavQuirksMode = aIsNavQuirks; } BasicTableLayoutStrategy::~BasicTableLayoutStrategy() @@ -416,9 +417,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() nscoord effectiveMaxColumnWidth = 0; // max col width ignoring cells with colspans nscoord specifiedFixedColWidth = 0; // the width of the column if given stylistically (or via cell Width attribute) // only applicable if haveColWidth==PR_TRUE - PRBool haveColWidth = PR_FALSE; // if true, the column has a width either from HTML width attribute, - // from a style rule on the column, - // or from a width attr/style on a cell that has colspan==1 + horPadding[colIndex] = 0; // Get column information nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); @@ -433,7 +432,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() // Get fixed column width if it has one if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { - haveColWidth = PR_TRUE; + colFrame->SetHasConstrainedWidth(PR_TRUE); specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); horPadding[colIndex] = CalcHorizontalPadding(colIndex); specifiedFixedColWidth += horPadding[colIndex]; @@ -489,7 +488,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() rowIndex, colSpan, cellMinSize.width, cellMinSize.height, cellDesiredSize.width, cellDesiredSize.height); - if (PR_TRUE == haveColWidth) { + if (colFrame->HasConstrainedWidth()) { // This col has a specified coord 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) // factoring in the min width of the prior cells (stored in minColWidth) @@ -594,13 +593,13 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() } // end for (rowIndex = 0; rowIndex < numRows; rowIndex++) // adjust the "fixed" width for content that is too wide - if (haveColWidth && (effectiveMinColumnWidth > specifiedFixedColWidth)) { + if (colFrame->HasConstrainedWidth() && (effectiveMinColumnWidth > specifiedFixedColWidth)) { specifiedFixedColWidth = effectiveMinColumnWidth; } // do all the global bookkeeping, factoring in margins nscoord colInset = mTableFrame->GetCellSpacingX(); // keep a running total of the amount of space taken up by all fixed-width columns - if ((PR_TRUE == haveColWidth) && + if ((colFrame->HasConstrainedWidth()) && (nsTableColFrame::eWIDTH_SOURCE_CELL == colFrame->GetWidthSource())) { mFixedTableWidth += specifiedFixedColWidth + colInset; if (0 == colIndex) { @@ -616,7 +615,7 @@ 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 ((colFrame->HasConstrainedWidth()) && (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=colFrame->GetWidthSource())) { mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); } @@ -1740,9 +1739,7 @@ PRBool BasicTableLayoutStrategy:: if (PR_FALSE == IsFixedWidth(colPosition, colTableStyle)) { // compute the spanning cell's contribution to the column min width nscoord spanCellMinWidth; - PRBool needsExtraMinWidth = PR_FALSE; - //if (spanInfo->effectiveMinWidthOfSpannedColscellMinWidth) - // needsExtraMinWidth = PR_TRUE; + PRBool needsExtraMinWidth = (spanInfo->effectiveMinWidthOfSpannedCols < spanInfo->cellMinWidth); if (PR_TRUE == needsExtraMinWidth) { if (0 != spanInfo->effectiveMinWidthOfSpannedCols) { spanCellMinWidth = (spanInfo->cellMinWidth * colFrame->GetEffectiveMinColWidth()) / @@ -1951,7 +1948,7 @@ PRBool BasicTableLayoutStrategy:: colIndex, mTableFrame->GetColumnWidth(colIndex), aAvailWidth, colInset); } else if (PR_TRUE==isAutoWidth) { // column's width is determined by its content, done in post-processing - mTableFrame->SetColumnWidth(colIndex, minColWidth); // reserve the column's min width + mTableFrame->SetColumnWidth(colIndex, minColWidth); // reserve the column's min width atLeastOneAutoWidthColumn = PR_TRUE; } else if (-1 != specifiedProportionColumnWidth) { @@ -2080,36 +2077,200 @@ PRBool BasicTableLayoutStrategy:: } struct nsColInfo { - nsColInfo(nsTableColFrame* aColFrame, - PRInt32 aColIndex, - PRInt32 aColWidth, - float aMaximizeFactor) - : mColFrame(aColFrame), mColIndex(aColIndex), mColWidth(aColWidth), - mMaximizeFactor(aMaximizeFactor) - {} - nsTableColFrame* mColFrame; - PRInt32 mColIndex; - PRInt32 mColWidth; - float mMaximizeFactor; + nsColInfo(nsTableColFrame* aFrame, + PRInt32 aIndex, + PRInt32 aMinWidth, + PRInt32 aWidth, + PRInt32 aMaxEffWidth, + PRInt32 aMaxWidth) + : mFrame(aFrame), mIndex(aIndex), mMinWidth(aMinWidth), + mWidth(aWidth), mMaxEffWidth(aMaxEffWidth), mMaxWidth(aMaxWidth), mWeight(0) + {} + nsTableColFrame* mFrame; + PRInt32 mIndex; + PRInt32 mMinWidth; + PRInt32 mWidth; + PRInt32 mMaxEffWidth; + PRInt32 mMaxWidth; + float mWeight; }; void -DistributeRemainingSpaceCleanup(PRInt32 aNumItems, nsColInfo** aInfoArray) +DRS_Wrapup(nsTableFrame* aTableFrame, + PRInt32 aNumItems, + nsColInfo** aColInfo) { for (int i = 0; i < aNumItems; i++) { - delete aInfoArray[i]; + aTableFrame->SetColumnWidth(aColInfo[i]->mIndex, aColInfo[i]->mWidth); + delete aColInfo[i]; + } + delete [] aColInfo; +} + +void +DRS_Increase(PRInt32 aNumAutoCols, + nsColInfo** aColInfo, + PRInt32 aDivisor, + PRBool aDontGoOverMax, + PRInt32& aAvailWidth) +{ + for (PRInt32 i = 0; i < aNumAutoCols; i++) { + if ((aAvailWidth <= 0) || (aDivisor <= 0)) { + break; + } + //float percent = ((float)aColInfo[i]->mMaxEffWidth) / (float)aDivisor; + float percent = ((float)aColInfo[i]->mMaxWidth) / (float)aDivisor; + //aDivisor -= aColInfo[i]->mWidth; + aDivisor -= aColInfo[i]->mMaxWidth; + nscoord addition = PR_MIN(aAvailWidth, NSToCoordRound(((float)(aAvailWidth)) * percent)); + if (aDontGoOverMax) { + addition = PR_MIN(addition, aColInfo[i]->mMaxWidth - aColInfo[i]->mWidth); + } + // don't let the total additions exceed what is available + if (i == aNumAutoCols - 1) { + addition = PR_MIN(addition, aAvailWidth); + } + aColInfo[i]->mWidth += addition; + aAvailWidth -= addition; + } +} + +void +DRS_Decrease(PRInt32 aNumAutoCols, + nsColInfo** aColInfo, + PRInt32 aDivisor, + PRInt32& aExcess) +{ + for (PRInt32 i = 0; i < aNumAutoCols; i++) { + if ((aExcess <= 0) || (aDivisor <= 0)) { + break; + } + //float percent = ((float)aColInfo[i]->mMaxEffWidth) / (float)aDivisor; + float percent = ((float)aColInfo[i]->mMaxWidth) / (float)aDivisor; + //aDivisor -= aColInfo[i]->mWidth; + aDivisor -= aColInfo[i]->mMaxWidth; + nscoord reduction = PR_MIN(aExcess, NSToCoordRound(((float)(aExcess)) * percent)); + // don't go over the col min + reduction = PR_MIN(reduction, aColInfo[i]->mWidth - aColInfo[i]->mMinWidth); + // don't let the total reductions exceed what is available + if (i == aNumAutoCols - 1) { + reduction = PR_MIN(reduction, aExcess); + } + aColInfo[i]->mWidth -= reduction; + aExcess -= reduction; + } +} + + +void +DSR_Sort(nsColInfo** aColInfo, PRInt32 aNumCols) +{ + // sort the cols based on the Weight + for (PRInt32 j = aNumCols - 1; j > 0; j--) { + for (PRInt32 i = 0; i < j; i++) { + if (aColInfo[i]->mWeight < aColInfo[i+1]->mWeight) { // swap them + nsColInfo* save = aColInfo[i]; + aColInfo[i] = aColInfo[i+1]; + aColInfo[i+1] = save; + } + } } - delete [] aInfoArray; } // Take the remaining space in the table and distribute it to the auto-width cols -// in the table. If a col reaches its desired width, stop at that width unless all -// other cols have reached their desired widths. +// in the table. +void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth, + nscoord& aComputedTableWidth, + PRBool aTableIsAutoWidth) +{ + // availWidth is the difference between the total available width and the + // amount of space already assigned. + nscoord availWidth = PR_MAX(aTableSpecifiedWidth - aComputedTableWidth, 0); + TDBG_SDD(" aTableSpecifiedWidth specified as %d, availWidth is = %d\n", aTableSpecifiedWidth, availWidth); + if ((0 == availWidth) || (aTableSpecifiedWidth <= 0)) { + return; + } -// This algorithm has been reworked from the orignal to fix bugs (e.g. bug 6184) -// and remove the recursion. For auto width tables it uses colFrame->GetMaxColSize() -// instead of GetMaxEffectiveColSize, so for some auto width tables with colspans -// it claculates more like IE5 than Nav4.5, which appears to be more reasonable. + // Get the auto width cols. Only they get adjusted. + PRInt32 numAutoCols = 0; + PRInt32* autoCols = nsnull; + mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoCols, autoCols); + if (0 == numAutoCols) { + return; + } + nsColInfo** colInfo = new nsColInfo*[numAutoCols]; + + nscoord totalDivisor = 0; + nscoord totalAutoWidthGiven = 0; + PRInt32 i; + + // start out by giving each col its max effective width (or adj width if it is greater) + // for standard mode and its min width for nav quirks mode + for (i = 0; i < numAutoCols; i++) { + PRInt32 colIndex = autoCols[i]; + nsTableColFrame* colFrame = mTableFrame->GetColFrame(autoCols[i]); + nscoord origWidth = mTableFrame->GetColumnWidth(autoCols[i]); + nscoord minWidth = PR_MAX(colFrame->GetAdjustedMinColWidth(), origWidth); + nscoord maxEffWidth = PR_MAX(colFrame->GetEffectiveMaxColWidth(), minWidth); + nscoord maxWidth = colFrame->GetMaxColWidth(); + nscoord startWidth = (mIsNavQuirksMode) ? minWidth : maxWidth; + colInfo[i] = new nsColInfo(colFrame, autoCols[i], minWidth, startWidth, maxEffWidth, maxWidth); +// totalDivisor += maxEffWidth; + totalDivisor += maxWidth; + totalAutoWidthGiven += startWidth - origWidth; + } + + availWidth = aTableSpecifiedWidth - aComputedTableWidth - totalAutoWidthGiven; + + if (availWidth >= 0) { // have more space to allocate + for (i = 0; i < numAutoCols; i++) { + // the weight here is a relative metric for determining when cols reach their max. + // A col with a larger weight will reach its max before one with a smaller value. + nscoord delta = colInfo[i]->mMaxWidth - colInfo[i]->mWidth; + colInfo[i]->mWeight = (delta <= 0) + ? 1000000 // cols which have already reached their max get a large value + : ((float)colInfo[i]->mMaxWidth) / ((float)delta); + } + + // sort the cols based on the weight so that in one pass cols with higher + // weights will get their max earlier than ones with lower weights + // This is an innefficient bubble sort, but unless there are an unlikely + // large number of cols, it is not an issue. + DSR_Sort(colInfo, numAutoCols); + + // compute the proportion to be added to each column, don't go beyond the col's + // max. This algorithm assumes that the Weight works as stated above + DRS_Increase(numAutoCols, colInfo, totalDivisor, PR_TRUE, availWidth); + // if every col got its max and there is more to go, allocate a 2nd time + if (!aTableIsAutoWidth && (availWidth > 0)) { + DRS_Increase(numAutoCols, colInfo, totalDivisor, PR_FALSE, availWidth); + } + aComputedTableWidth = aTableSpecifiedWidth - availWidth; + } + else { // reduce each col width if appropriate + for (i = 0; i < numAutoCols; i++) { + // the weight here is a relative metric for determining when cols reach their min. + // A col with a larger weight will reach its min before one with a smaller value. + nscoord delta = colInfo[i]->mWidth - colInfo[i]->mMinWidth; + colInfo[i]->mWeight = (delta <= 0) + ? 1000000 // cols which have already reached their min get a large value + : ((float)colInfo[i]->mWidth) / ((float)delta); + } + + // sort the cols based on the Weight + DSR_Sort(colInfo, numAutoCols); + + // compute the proportion to be subtracted from each column, don't go beyond + // the col's min. This algorithm assumes that the Weight works as stated above + PRInt32 totalExcessGiven = -availWidth; + DRS_Decrease(numAutoCols, colInfo, totalDivisor, totalExcessGiven); + aComputedTableWidth = aTableSpecifiedWidth + totalExcessGiven; + } + DRS_Wrapup(mTableFrame, numAutoCols, colInfo); + TDBG_WIDTHS4("at end of DistributeRemainingSpace: ",PR_FALSE,PR_FALSE); +} + +#if 0 void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth, nscoord& aComputedTableWidth, PRBool aTableIsAutoWidth) @@ -2141,21 +2302,19 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified PRInt32 colIndex = autoColumns[i]; nsTableColFrame* colFrame = mTableFrame->GetColFrame(autoColumns[i]); nscoord startingColWidth = mTableFrame->GetColumnWidth(colIndex); - nscoord maxColWidth = (PR_FALSE == aTableIsAutoWidth) - ? colFrame->GetEffectiveMaxColWidth() : colFrame->GetMaxColWidth(); - if ((PR_FALSE == aTableIsAutoWidth) || (startingColWidth < maxColWidth)) { - if (0 == maxColWidth) - maxColWidth = startingColWidth; - totalResizeColWidth += maxColWidth; - // the maximizeFactor is a relative metric for determining when cols reach their max. - // A col with a smaller value will reach its max before one with a larger value. - nscoord delta = maxColWidth - startingColWidth; - float maximizeFactor = (0 == delta) - ? 1000000 : ((float)maxColWidth) / ((float)(maxColWidth - startingColWidth)); - resizeCols[numResizeCols] = new nsColInfo(colFrame, colIndex, startingColWidth, - maximizeFactor); - numResizeCols++; - } + nscoord maxColWidth = colFrame->GetMaxColWidth(); + if (0 == maxColWidth) + maxColWidth = startingColWidth; + totalResizeColWidth += maxColWidth; + // the maximizeFactor is a relative metric for determining when cols reach their max. + // A col with a smaller value will reach its max before one with a larger value. + nscoord delta = maxColWidth - startingColWidth; + float maximizeFactor = (0 >= delta) + ? 1000000 // cols which have already reached their max get a large value + : ((float)maxColWidth) / ((float)(maxColWidth - startingColWidth)); + resizeCols[numResizeCols] = new nsColInfo(colFrame, colIndex, startingColWidth, + maximizeFactor); + numResizeCols++; } if (totalResizeColWidth <= 0) { NS_ASSERTION(PR_TRUE, "need to handle this case"); @@ -2187,10 +2346,7 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified } nsTableColFrame* colFrame = resizeCols[i]->mColFrame; nscoord startingColWidth = resizeCols[i]->mColWidth; - nscoord maxColWidth = (PR_FALSE == aTableIsAutoWidth) - ? colFrame->GetEffectiveMaxColWidth() : colFrame->GetMaxColWidth(); - // if we actually have room to distribute, do it here - // otherwise, the auto columns already are set to their minimum + nscoord maxColWidth = colFrame->GetMaxColWidth(); float percent = ((float)maxColWidth) / (float)totalResizeColWidthRemaining; nscoord delta = PR_MIN(availWidth, NSToCoordRound(((float)(availWidth)) * percent)); // don't go over the col max right now @@ -2214,7 +2370,7 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified } nsTableColFrame* colFrame = resizeCols[i]->mColFrame; nscoord startingColWidth = resizeCols[i]->mColWidth; - nscoord maxColWidth = colFrame->GetEffectiveMaxColWidth(); + nscoord maxColWidth = colFrame->GetMaxColWidth(); // if we actually have room to distribute, do it here float percent = ((float)maxColWidth) / (float)totalResizeColWidth; nscoord delta = PR_MIN(availWidth, NSToCoordRound(((float)(availWidth)) * percent)); @@ -2229,6 +2385,7 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified DistributeRemainingSpaceCleanup(numResizeCols, resizeCols); TDBG_WIDTHS4("at end of DistributeRemainingSpace: ",PR_FALSE,PR_FALSE); } +#endif void BasicTableLayoutStrategy::AdjustTableThatIsTooWide(nscoord aComputedWidth, nscoord aTableWidth, diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h index 121c4baafd5..375d82ae4fc 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h @@ -80,7 +80,8 @@ public: /** Public constructor. * @paran aFrame the table frame for which this delegate will do layout */ - BasicTableLayoutStrategy(nsTableFrame *aFrame); + BasicTableLayoutStrategy(nsTableFrame *aFrame, + PRBool aIsNavQuirksMode = PR_TRUE); /** destructor */ virtual ~BasicTableLayoutStrategy(); @@ -288,6 +289,7 @@ protected: nscoord mMinTableWidth; // the smallest size for the table nscoord mMaxTableWidth; // the "natural" size for the table, if unconstrained nscoord mFixedTableWidth; // the amount of space taken up by fixed-width columns + PRBool mIsNavQuirksMode; }; diff --git a/mozilla/layout/html/table/src/nsTableColFrame.h b/mozilla/layout/html/table/src/nsTableColFrame.h index 704088a0ece..876b321160d 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.h +++ b/mozilla/layout/html/table/src/nsTableColFrame.h @@ -79,9 +79,17 @@ public: nscoord GetEffectiveMinColWidth(); void SetEffectiveMinColWidth(nscoord aMinColWidth); + // return the min width for this column after provisions for col spans have + // been included. The adj min width is >= the min width. nscoord GetAdjustedMinColWidth(); void SetAdjustedMinColWidth(nscoord aMinColWidth); + // Return true if the column has a width either from HTML width attribute, + // from a style rule on the column, from a width attr/style on a cell + // that has colspan==1. + PRBool HasConstrainedWidth(); + void SetHasConstrainedWidth(PRBool aIsConstrained); + PRInt32 GetWidthSource(); void SetWidthSource(PRInt32 aMinColWidth); @@ -106,6 +114,8 @@ protected: nscoord mMinAdjustedColWidth; + PRBool mHasConstrainedWidth; + PRInt32 mWidthSource; }; @@ -150,6 +160,12 @@ inline void nsTableColFrame::SetEffectiveMinColWidth(nscoord aMinEffectiveColWid inline nscoord nsTableColFrame::GetAdjustedMinColWidth() { return mMinAdjustedColWidth; } +inline PRBool nsTableColFrame::HasConstrainedWidth() +{ return mHasConstrainedWidth; } + +inline void nsTableColFrame::SetHasConstrainedWidth(PRBool aIsConstrained) +{ mHasConstrainedWidth = aIsConstrained; } + inline void nsTableColFrame::SetAdjustedMinColWidth(nscoord aMinAdjustedColWidth) { mMinAdjustedColWidth = aMinAdjustedColWidth; } diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index 97b62c57bfd..2511a145cbf 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -3965,10 +3965,12 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext& aPresContext, // based on the compatibility mode, create a table layout strategy if (nsnull==mTableLayoutStrategy) { + nsCompatibility mode; + aPresContext.GetCompatibilityMode(&mode); if (PR_FALSE==RequiresPass1Layout()) mTableLayoutStrategy = new FixedTableLayoutStrategy(this); else - mTableLayoutStrategy = new BasicTableLayoutStrategy(this); + mTableLayoutStrategy = new BasicTableLayoutStrategy(this, eCompatibility_NavQuirks == mode); mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount()); mColumnWidthsValid=PR_TRUE; } diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 72840825e02..86234b517e6 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -524,6 +524,13 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState) { if (gsDebug) printf("TRGF CalculateRowHeights begin\n"); + nsTableFrame *tableFrame=nsnull; + nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); + if (NS_FAILED(rv) || nsnull==tableFrame) + return; + // all table cells have the same top and bottom margins, namely cellSpacingY + nscoord cellSpacingY = tableFrame->GetCellSpacingY(); + // iterate children and for each row get its height PRInt32 numRows; GetRowCount(numRows); @@ -549,22 +556,24 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) { // get the height of the tallest cell in the row (excluding cells that span rows) + // XXX GetChildMaxTopMargin and GetChildMaxBottomMargin should be removed/simplified because + // according to CSS, all table cells must have the same top/bottom and left/right margins. nscoord maxCellHeight = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); nscoord maxCellTopMargin = ((nsTableRowFrame*)rowFrame)->GetChildMaxTopMargin(); nscoord maxCellBottomMargin = ((nsTableRowFrame*)rowFrame)->GetChildMaxBottomMargin(); nscoord maxRowHeight = maxCellHeight + maxCellTopMargin + maxCellBottomMargin; - if (gsDebug) printf("TRGF CalcRowH: for row %d(%p), maxCellH=%d, maxCTopMargin=%d, maxCBM=%d\n", - rowIndex + startRowIndex, rowFrame, maxCellHeight, maxCellTopMargin, maxCellBottomMargin); + // only the top row has a top margin. Other rows start at the bottom of the prev row's bottom margin. + if (gsDebug) printf("TRGF CalcRowH: for row %d(%p), maxCellH=%d, spacingY=%d, d\n", + rowIndex + startRowIndex, rowFrame, maxCellHeight, cellSpacingY); if (gsDebug) printf(" rowHeight=%d\n", maxRowHeight); // save the row height for pass 2 below rowHeights[rowIndex] = maxRowHeight; - // Update top and bottom inner margin if applicable rowIndex++; } // Get the next row rowFrame->GetNextSibling(&rowFrame); - } + } /* Step 2: Now account for cells that span rows. * A spanning cell's height is the sum of the heights of the rows it spans, @@ -582,11 +591,6 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, * 1. optimization, if (PR_TRUE==atLeastOneRowSpanningCell) ... otherwise skip this step entirely * we can get this info trivially from the cell map */ - nsTableFrame *tableFrame=nsnull; - nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_FAILED(rv) || nsnull==tableFrame) - return; - nscoord cellSpacingY = tableFrame->GetCellSpacingY(); PRInt32 rowGroupHeight; for (PRInt32 counter=0; counter<2; counter++) @@ -622,22 +626,18 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, for (i = 0; i < rowSpan; i++) { heightOfRowsSpanned += rowHeights[rowIndex + i]; } - // need to reduce by cell spacing, twice that if it is the top row - heightOfRowsSpanned -= cellSpacingY; - if (0 == rowIndex) { - heightOfRowsSpanned -= cellSpacingY; - } - - if (gsDebug) printf("TRGF CalcRowH: heightOfRowsSpanned=%d\n", heightOfRowsSpanned); + // the avail height needs to reduce by top and bottom margins + nscoord availHeightOfRowsSpanned = heightOfRowsSpanned - cellSpacingY - cellSpacingY; + if (gsDebug) printf("TRGF CalcRowH: availHeightOfRowsSpanned=%d\n", availHeightOfRowsSpanned); /* if the cell height fits in the rows, expand the spanning cell's height and slap it in */ nsSize cellFrameSize; cellFrame->GetSize(cellFrameSize); - if (heightOfRowsSpanned > cellFrameSize.height) + if (availHeightOfRowsSpanned > cellFrameSize.height) { if (gsDebug) printf("TRGF CalcRowH: spanning cell fits in rows spanned, had h=%d, expanded to %d\n", - cellFrameSize.height, heightOfRowsSpanned); - cellFrame->SizeTo(cellFrameSize.width, heightOfRowsSpanned); + cellFrameSize.height, availHeightOfRowsSpanned); + cellFrame->SizeTo(cellFrameSize.width, availHeightOfRowsSpanned); // Realign cell content based on new height ((nsTableCellFrame*)cellFrame)->VerticallyAlignChild(); } @@ -646,20 +646,25 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, */ else { - PRInt32 excessHeight = cellFrameSize.height - heightOfRowsSpanned; + PRInt32 excessHeight = cellFrameSize.height - availHeightOfRowsSpanned; if (gsDebug) printf("TRGF CalcRowH: excessHeight=%d\n", excessHeight); // for every row starting at the row with the spanning cell... nsTableRowFrame *rowFrameToBeResized = (nsTableRowFrame *)rowFrame; PRInt32 *excessForRow = new PRInt32[numRows]; nsCRT::memset (excessForRow, 0, numRows*sizeof(PRInt32)); - for (i = rowIndex; i < numRows; i++) - { + nscoord excessAllocated = 0; + for (i = rowIndex; i < numRows; i++) { if (gsDebug) printf("TRGF CalcRowH: for row index=%d\n", i); // if the row is within the spanned range, resize the row - if (i < (rowIndex + rowSpan)) - { + if (i < (rowIndex + rowSpan)) { + //float percent = ((float)rowHeights[i]) / ((float)availHeightOfRowsSpanned); + //excessForRow[i] = NSToCoordRound(((float)(excessHeight)) * percent); float percent = ((float)rowHeights[i]) / ((float)heightOfRowsSpanned); - excessForRow[i] = NSToCoordRound(((float)(excessHeight)) * percent); + // give rows their percentage, except the last row gets the remainder + excessForRow[i] = ((i - 1) == (rowIndex + rowSpan)) + ? excessHeight - excessAllocated + : NSToCoordRound(((float)(excessHeight)) * percent); + excessAllocated += excessForRow[i]; if (gsDebug) printf("TRGF CalcRowH: for row %d, excessHeight=%d from percent %f\n", i, excessForRow[i], percent); // update the row height diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp index 6627d57e0b7..7712953e951 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp @@ -217,14 +217,15 @@ PRBool BasicTableLayoutStrategy::IsFixedWidth(const nsStylePosition* aStylePosit } -BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame) +BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame, PRBool aIsNavQuirks) { NS_ASSERTION(nsnull != aFrame, "bad frame arg"); - mTableFrame = aFrame; - mMinTableWidth = 0; - mMaxTableWidth = 0; - mFixedTableWidth = 0; + mTableFrame = aFrame; + mMinTableWidth = 0; + mMaxTableWidth = 0; + mFixedTableWidth = 0; + mIsNavQuirksMode = aIsNavQuirks; } BasicTableLayoutStrategy::~BasicTableLayoutStrategy() @@ -416,9 +417,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() nscoord effectiveMaxColumnWidth = 0; // max col width ignoring cells with colspans nscoord specifiedFixedColWidth = 0; // the width of the column if given stylistically (or via cell Width attribute) // only applicable if haveColWidth==PR_TRUE - PRBool haveColWidth = PR_FALSE; // if true, the column has a width either from HTML width attribute, - // from a style rule on the column, - // or from a width attr/style on a cell that has colspan==1 + horPadding[colIndex] = 0; // Get column information nsTableColFrame* colFrame = mTableFrame->GetColFrame(colIndex); @@ -433,7 +432,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() // Get fixed column width if it has one if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { - haveColWidth = PR_TRUE; + colFrame->SetHasConstrainedWidth(PR_TRUE); specifiedFixedColWidth = colPosition->mWidth.GetCoordValue(); horPadding[colIndex] = CalcHorizontalPadding(colIndex); specifiedFixedColWidth += horPadding[colIndex]; @@ -489,7 +488,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() rowIndex, colSpan, cellMinSize.width, cellMinSize.height, cellDesiredSize.width, cellDesiredSize.height); - if (PR_TRUE == haveColWidth) { + if (colFrame->HasConstrainedWidth()) { // This col has a specified coord 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) // factoring in the min width of the prior cells (stored in minColWidth) @@ -594,13 +593,13 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths() } // end for (rowIndex = 0; rowIndex < numRows; rowIndex++) // adjust the "fixed" width for content that is too wide - if (haveColWidth && (effectiveMinColumnWidth > specifiedFixedColWidth)) { + if (colFrame->HasConstrainedWidth() && (effectiveMinColumnWidth > specifiedFixedColWidth)) { specifiedFixedColWidth = effectiveMinColumnWidth; } // do all the global bookkeeping, factoring in margins nscoord colInset = mTableFrame->GetCellSpacingX(); // keep a running total of the amount of space taken up by all fixed-width columns - if ((PR_TRUE == haveColWidth) && + if ((colFrame->HasConstrainedWidth()) && (nsTableColFrame::eWIDTH_SOURCE_CELL == colFrame->GetWidthSource())) { mFixedTableWidth += specifiedFixedColWidth + colInset; if (0 == colIndex) { @@ -616,7 +615,7 @@ 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 ((colFrame->HasConstrainedWidth()) && (nsTableColFrame::eWIDTH_SOURCE_CELL_WITH_SPAN!=colFrame->GetWidthSource())) { mTableFrame->SetColumnWidth(colIndex, specifiedFixedColWidth); } @@ -1740,9 +1739,7 @@ PRBool BasicTableLayoutStrategy:: if (PR_FALSE == IsFixedWidth(colPosition, colTableStyle)) { // compute the spanning cell's contribution to the column min width nscoord spanCellMinWidth; - PRBool needsExtraMinWidth = PR_FALSE; - //if (spanInfo->effectiveMinWidthOfSpannedColscellMinWidth) - // needsExtraMinWidth = PR_TRUE; + PRBool needsExtraMinWidth = (spanInfo->effectiveMinWidthOfSpannedCols < spanInfo->cellMinWidth); if (PR_TRUE == needsExtraMinWidth) { if (0 != spanInfo->effectiveMinWidthOfSpannedCols) { spanCellMinWidth = (spanInfo->cellMinWidth * colFrame->GetEffectiveMinColWidth()) / @@ -1951,7 +1948,7 @@ PRBool BasicTableLayoutStrategy:: colIndex, mTableFrame->GetColumnWidth(colIndex), aAvailWidth, colInset); } else if (PR_TRUE==isAutoWidth) { // column's width is determined by its content, done in post-processing - mTableFrame->SetColumnWidth(colIndex, minColWidth); // reserve the column's min width + mTableFrame->SetColumnWidth(colIndex, minColWidth); // reserve the column's min width atLeastOneAutoWidthColumn = PR_TRUE; } else if (-1 != specifiedProportionColumnWidth) { @@ -2080,36 +2077,200 @@ PRBool BasicTableLayoutStrategy:: } struct nsColInfo { - nsColInfo(nsTableColFrame* aColFrame, - PRInt32 aColIndex, - PRInt32 aColWidth, - float aMaximizeFactor) - : mColFrame(aColFrame), mColIndex(aColIndex), mColWidth(aColWidth), - mMaximizeFactor(aMaximizeFactor) - {} - nsTableColFrame* mColFrame; - PRInt32 mColIndex; - PRInt32 mColWidth; - float mMaximizeFactor; + nsColInfo(nsTableColFrame* aFrame, + PRInt32 aIndex, + PRInt32 aMinWidth, + PRInt32 aWidth, + PRInt32 aMaxEffWidth, + PRInt32 aMaxWidth) + : mFrame(aFrame), mIndex(aIndex), mMinWidth(aMinWidth), + mWidth(aWidth), mMaxEffWidth(aMaxEffWidth), mMaxWidth(aMaxWidth), mWeight(0) + {} + nsTableColFrame* mFrame; + PRInt32 mIndex; + PRInt32 mMinWidth; + PRInt32 mWidth; + PRInt32 mMaxEffWidth; + PRInt32 mMaxWidth; + float mWeight; }; void -DistributeRemainingSpaceCleanup(PRInt32 aNumItems, nsColInfo** aInfoArray) +DRS_Wrapup(nsTableFrame* aTableFrame, + PRInt32 aNumItems, + nsColInfo** aColInfo) { for (int i = 0; i < aNumItems; i++) { - delete aInfoArray[i]; + aTableFrame->SetColumnWidth(aColInfo[i]->mIndex, aColInfo[i]->mWidth); + delete aColInfo[i]; + } + delete [] aColInfo; +} + +void +DRS_Increase(PRInt32 aNumAutoCols, + nsColInfo** aColInfo, + PRInt32 aDivisor, + PRBool aDontGoOverMax, + PRInt32& aAvailWidth) +{ + for (PRInt32 i = 0; i < aNumAutoCols; i++) { + if ((aAvailWidth <= 0) || (aDivisor <= 0)) { + break; + } + //float percent = ((float)aColInfo[i]->mMaxEffWidth) / (float)aDivisor; + float percent = ((float)aColInfo[i]->mMaxWidth) / (float)aDivisor; + //aDivisor -= aColInfo[i]->mWidth; + aDivisor -= aColInfo[i]->mMaxWidth; + nscoord addition = PR_MIN(aAvailWidth, NSToCoordRound(((float)(aAvailWidth)) * percent)); + if (aDontGoOverMax) { + addition = PR_MIN(addition, aColInfo[i]->mMaxWidth - aColInfo[i]->mWidth); + } + // don't let the total additions exceed what is available + if (i == aNumAutoCols - 1) { + addition = PR_MIN(addition, aAvailWidth); + } + aColInfo[i]->mWidth += addition; + aAvailWidth -= addition; + } +} + +void +DRS_Decrease(PRInt32 aNumAutoCols, + nsColInfo** aColInfo, + PRInt32 aDivisor, + PRInt32& aExcess) +{ + for (PRInt32 i = 0; i < aNumAutoCols; i++) { + if ((aExcess <= 0) || (aDivisor <= 0)) { + break; + } + //float percent = ((float)aColInfo[i]->mMaxEffWidth) / (float)aDivisor; + float percent = ((float)aColInfo[i]->mMaxWidth) / (float)aDivisor; + //aDivisor -= aColInfo[i]->mWidth; + aDivisor -= aColInfo[i]->mMaxWidth; + nscoord reduction = PR_MIN(aExcess, NSToCoordRound(((float)(aExcess)) * percent)); + // don't go over the col min + reduction = PR_MIN(reduction, aColInfo[i]->mWidth - aColInfo[i]->mMinWidth); + // don't let the total reductions exceed what is available + if (i == aNumAutoCols - 1) { + reduction = PR_MIN(reduction, aExcess); + } + aColInfo[i]->mWidth -= reduction; + aExcess -= reduction; + } +} + + +void +DSR_Sort(nsColInfo** aColInfo, PRInt32 aNumCols) +{ + // sort the cols based on the Weight + for (PRInt32 j = aNumCols - 1; j > 0; j--) { + for (PRInt32 i = 0; i < j; i++) { + if (aColInfo[i]->mWeight < aColInfo[i+1]->mWeight) { // swap them + nsColInfo* save = aColInfo[i]; + aColInfo[i] = aColInfo[i+1]; + aColInfo[i+1] = save; + } + } } - delete [] aInfoArray; } // Take the remaining space in the table and distribute it to the auto-width cols -// in the table. If a col reaches its desired width, stop at that width unless all -// other cols have reached their desired widths. +// in the table. +void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth, + nscoord& aComputedTableWidth, + PRBool aTableIsAutoWidth) +{ + // availWidth is the difference between the total available width and the + // amount of space already assigned. + nscoord availWidth = PR_MAX(aTableSpecifiedWidth - aComputedTableWidth, 0); + TDBG_SDD(" aTableSpecifiedWidth specified as %d, availWidth is = %d\n", aTableSpecifiedWidth, availWidth); + if ((0 == availWidth) || (aTableSpecifiedWidth <= 0)) { + return; + } -// This algorithm has been reworked from the orignal to fix bugs (e.g. bug 6184) -// and remove the recursion. For auto width tables it uses colFrame->GetMaxColSize() -// instead of GetMaxEffectiveColSize, so for some auto width tables with colspans -// it claculates more like IE5 than Nav4.5, which appears to be more reasonable. + // Get the auto width cols. Only they get adjusted. + PRInt32 numAutoCols = 0; + PRInt32* autoCols = nsnull; + mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoCols, autoCols); + if (0 == numAutoCols) { + return; + } + nsColInfo** colInfo = new nsColInfo*[numAutoCols]; + + nscoord totalDivisor = 0; + nscoord totalAutoWidthGiven = 0; + PRInt32 i; + + // start out by giving each col its max effective width (or adj width if it is greater) + // for standard mode and its min width for nav quirks mode + for (i = 0; i < numAutoCols; i++) { + PRInt32 colIndex = autoCols[i]; + nsTableColFrame* colFrame = mTableFrame->GetColFrame(autoCols[i]); + nscoord origWidth = mTableFrame->GetColumnWidth(autoCols[i]); + nscoord minWidth = PR_MAX(colFrame->GetAdjustedMinColWidth(), origWidth); + nscoord maxEffWidth = PR_MAX(colFrame->GetEffectiveMaxColWidth(), minWidth); + nscoord maxWidth = colFrame->GetMaxColWidth(); + nscoord startWidth = (mIsNavQuirksMode) ? minWidth : maxWidth; + colInfo[i] = new nsColInfo(colFrame, autoCols[i], minWidth, startWidth, maxEffWidth, maxWidth); +// totalDivisor += maxEffWidth; + totalDivisor += maxWidth; + totalAutoWidthGiven += startWidth - origWidth; + } + + availWidth = aTableSpecifiedWidth - aComputedTableWidth - totalAutoWidthGiven; + + if (availWidth >= 0) { // have more space to allocate + for (i = 0; i < numAutoCols; i++) { + // the weight here is a relative metric for determining when cols reach their max. + // A col with a larger weight will reach its max before one with a smaller value. + nscoord delta = colInfo[i]->mMaxWidth - colInfo[i]->mWidth; + colInfo[i]->mWeight = (delta <= 0) + ? 1000000 // cols which have already reached their max get a large value + : ((float)colInfo[i]->mMaxWidth) / ((float)delta); + } + + // sort the cols based on the weight so that in one pass cols with higher + // weights will get their max earlier than ones with lower weights + // This is an innefficient bubble sort, but unless there are an unlikely + // large number of cols, it is not an issue. + DSR_Sort(colInfo, numAutoCols); + + // compute the proportion to be added to each column, don't go beyond the col's + // max. This algorithm assumes that the Weight works as stated above + DRS_Increase(numAutoCols, colInfo, totalDivisor, PR_TRUE, availWidth); + // if every col got its max and there is more to go, allocate a 2nd time + if (!aTableIsAutoWidth && (availWidth > 0)) { + DRS_Increase(numAutoCols, colInfo, totalDivisor, PR_FALSE, availWidth); + } + aComputedTableWidth = aTableSpecifiedWidth - availWidth; + } + else { // reduce each col width if appropriate + for (i = 0; i < numAutoCols; i++) { + // the weight here is a relative metric for determining when cols reach their min. + // A col with a larger weight will reach its min before one with a smaller value. + nscoord delta = colInfo[i]->mWidth - colInfo[i]->mMinWidth; + colInfo[i]->mWeight = (delta <= 0) + ? 1000000 // cols which have already reached their min get a large value + : ((float)colInfo[i]->mWidth) / ((float)delta); + } + + // sort the cols based on the Weight + DSR_Sort(colInfo, numAutoCols); + + // compute the proportion to be subtracted from each column, don't go beyond + // the col's min. This algorithm assumes that the Weight works as stated above + PRInt32 totalExcessGiven = -availWidth; + DRS_Decrease(numAutoCols, colInfo, totalDivisor, totalExcessGiven); + aComputedTableWidth = aTableSpecifiedWidth + totalExcessGiven; + } + DRS_Wrapup(mTableFrame, numAutoCols, colInfo); + TDBG_WIDTHS4("at end of DistributeRemainingSpace: ",PR_FALSE,PR_FALSE); +} + +#if 0 void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecifiedWidth, nscoord& aComputedTableWidth, PRBool aTableIsAutoWidth) @@ -2141,21 +2302,19 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified PRInt32 colIndex = autoColumns[i]; nsTableColFrame* colFrame = mTableFrame->GetColFrame(autoColumns[i]); nscoord startingColWidth = mTableFrame->GetColumnWidth(colIndex); - nscoord maxColWidth = (PR_FALSE == aTableIsAutoWidth) - ? colFrame->GetEffectiveMaxColWidth() : colFrame->GetMaxColWidth(); - if ((PR_FALSE == aTableIsAutoWidth) || (startingColWidth < maxColWidth)) { - if (0 == maxColWidth) - maxColWidth = startingColWidth; - totalResizeColWidth += maxColWidth; - // the maximizeFactor is a relative metric for determining when cols reach their max. - // A col with a smaller value will reach its max before one with a larger value. - nscoord delta = maxColWidth - startingColWidth; - float maximizeFactor = (0 == delta) - ? 1000000 : ((float)maxColWidth) / ((float)(maxColWidth - startingColWidth)); - resizeCols[numResizeCols] = new nsColInfo(colFrame, colIndex, startingColWidth, - maximizeFactor); - numResizeCols++; - } + nscoord maxColWidth = colFrame->GetMaxColWidth(); + if (0 == maxColWidth) + maxColWidth = startingColWidth; + totalResizeColWidth += maxColWidth; + // the maximizeFactor is a relative metric for determining when cols reach their max. + // A col with a smaller value will reach its max before one with a larger value. + nscoord delta = maxColWidth - startingColWidth; + float maximizeFactor = (0 >= delta) + ? 1000000 // cols which have already reached their max get a large value + : ((float)maxColWidth) / ((float)(maxColWidth - startingColWidth)); + resizeCols[numResizeCols] = new nsColInfo(colFrame, colIndex, startingColWidth, + maximizeFactor); + numResizeCols++; } if (totalResizeColWidth <= 0) { NS_ASSERTION(PR_TRUE, "need to handle this case"); @@ -2187,10 +2346,7 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified } nsTableColFrame* colFrame = resizeCols[i]->mColFrame; nscoord startingColWidth = resizeCols[i]->mColWidth; - nscoord maxColWidth = (PR_FALSE == aTableIsAutoWidth) - ? colFrame->GetEffectiveMaxColWidth() : colFrame->GetMaxColWidth(); - // if we actually have room to distribute, do it here - // otherwise, the auto columns already are set to their minimum + nscoord maxColWidth = colFrame->GetMaxColWidth(); float percent = ((float)maxColWidth) / (float)totalResizeColWidthRemaining; nscoord delta = PR_MIN(availWidth, NSToCoordRound(((float)(availWidth)) * percent)); // don't go over the col max right now @@ -2214,7 +2370,7 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified } nsTableColFrame* colFrame = resizeCols[i]->mColFrame; nscoord startingColWidth = resizeCols[i]->mColWidth; - nscoord maxColWidth = colFrame->GetEffectiveMaxColWidth(); + nscoord maxColWidth = colFrame->GetMaxColWidth(); // if we actually have room to distribute, do it here float percent = ((float)maxColWidth) / (float)totalResizeColWidth; nscoord delta = PR_MIN(availWidth, NSToCoordRound(((float)(availWidth)) * percent)); @@ -2229,6 +2385,7 @@ void BasicTableLayoutStrategy::DistributeRemainingSpace(nscoord aTableSpecified DistributeRemainingSpaceCleanup(numResizeCols, resizeCols); TDBG_WIDTHS4("at end of DistributeRemainingSpace: ",PR_FALSE,PR_FALSE); } +#endif void BasicTableLayoutStrategy::AdjustTableThatIsTooWide(nscoord aComputedWidth, nscoord aTableWidth, diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.h b/mozilla/layout/tables/BasicTableLayoutStrategy.h index 121c4baafd5..375d82ae4fc 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.h +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.h @@ -80,7 +80,8 @@ public: /** Public constructor. * @paran aFrame the table frame for which this delegate will do layout */ - BasicTableLayoutStrategy(nsTableFrame *aFrame); + BasicTableLayoutStrategy(nsTableFrame *aFrame, + PRBool aIsNavQuirksMode = PR_TRUE); /** destructor */ virtual ~BasicTableLayoutStrategy(); @@ -288,6 +289,7 @@ protected: nscoord mMinTableWidth; // the smallest size for the table nscoord mMaxTableWidth; // the "natural" size for the table, if unconstrained nscoord mFixedTableWidth; // the amount of space taken up by fixed-width columns + PRBool mIsNavQuirksMode; }; diff --git a/mozilla/layout/tables/nsTableColFrame.h b/mozilla/layout/tables/nsTableColFrame.h index 704088a0ece..876b321160d 100644 --- a/mozilla/layout/tables/nsTableColFrame.h +++ b/mozilla/layout/tables/nsTableColFrame.h @@ -79,9 +79,17 @@ public: nscoord GetEffectiveMinColWidth(); void SetEffectiveMinColWidth(nscoord aMinColWidth); + // return the min width for this column after provisions for col spans have + // been included. The adj min width is >= the min width. nscoord GetAdjustedMinColWidth(); void SetAdjustedMinColWidth(nscoord aMinColWidth); + // Return true if the column has a width either from HTML width attribute, + // from a style rule on the column, from a width attr/style on a cell + // that has colspan==1. + PRBool HasConstrainedWidth(); + void SetHasConstrainedWidth(PRBool aIsConstrained); + PRInt32 GetWidthSource(); void SetWidthSource(PRInt32 aMinColWidth); @@ -106,6 +114,8 @@ protected: nscoord mMinAdjustedColWidth; + PRBool mHasConstrainedWidth; + PRInt32 mWidthSource; }; @@ -150,6 +160,12 @@ inline void nsTableColFrame::SetEffectiveMinColWidth(nscoord aMinEffectiveColWid inline nscoord nsTableColFrame::GetAdjustedMinColWidth() { return mMinAdjustedColWidth; } +inline PRBool nsTableColFrame::HasConstrainedWidth() +{ return mHasConstrainedWidth; } + +inline void nsTableColFrame::SetHasConstrainedWidth(PRBool aIsConstrained) +{ mHasConstrainedWidth = aIsConstrained; } + inline void nsTableColFrame::SetAdjustedMinColWidth(nscoord aMinAdjustedColWidth) { mMinAdjustedColWidth = aMinAdjustedColWidth; } diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index 97b62c57bfd..2511a145cbf 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -3965,10 +3965,12 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext& aPresContext, // based on the compatibility mode, create a table layout strategy if (nsnull==mTableLayoutStrategy) { + nsCompatibility mode; + aPresContext.GetCompatibilityMode(&mode); if (PR_FALSE==RequiresPass1Layout()) mTableLayoutStrategy = new FixedTableLayoutStrategy(this); else - mTableLayoutStrategy = new BasicTableLayoutStrategy(this); + mTableLayoutStrategy = new BasicTableLayoutStrategy(this, eCompatibility_NavQuirks == mode); mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount()); mColumnWidthsValid=PR_TRUE; } diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index 72840825e02..86234b517e6 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -524,6 +524,13 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState) { if (gsDebug) printf("TRGF CalculateRowHeights begin\n"); + nsTableFrame *tableFrame=nsnull; + nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); + if (NS_FAILED(rv) || nsnull==tableFrame) + return; + // all table cells have the same top and bottom margins, namely cellSpacingY + nscoord cellSpacingY = tableFrame->GetCellSpacingY(); + // iterate children and for each row get its height PRInt32 numRows; GetRowCount(numRows); @@ -549,22 +556,24 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) { // get the height of the tallest cell in the row (excluding cells that span rows) + // XXX GetChildMaxTopMargin and GetChildMaxBottomMargin should be removed/simplified because + // according to CSS, all table cells must have the same top/bottom and left/right margins. nscoord maxCellHeight = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); nscoord maxCellTopMargin = ((nsTableRowFrame*)rowFrame)->GetChildMaxTopMargin(); nscoord maxCellBottomMargin = ((nsTableRowFrame*)rowFrame)->GetChildMaxBottomMargin(); nscoord maxRowHeight = maxCellHeight + maxCellTopMargin + maxCellBottomMargin; - if (gsDebug) printf("TRGF CalcRowH: for row %d(%p), maxCellH=%d, maxCTopMargin=%d, maxCBM=%d\n", - rowIndex + startRowIndex, rowFrame, maxCellHeight, maxCellTopMargin, maxCellBottomMargin); + // only the top row has a top margin. Other rows start at the bottom of the prev row's bottom margin. + if (gsDebug) printf("TRGF CalcRowH: for row %d(%p), maxCellH=%d, spacingY=%d, d\n", + rowIndex + startRowIndex, rowFrame, maxCellHeight, cellSpacingY); if (gsDebug) printf(" rowHeight=%d\n", maxRowHeight); // save the row height for pass 2 below rowHeights[rowIndex] = maxRowHeight; - // Update top and bottom inner margin if applicable rowIndex++; } // Get the next row rowFrame->GetNextSibling(&rowFrame); - } + } /* Step 2: Now account for cells that span rows. * A spanning cell's height is the sum of the heights of the rows it spans, @@ -582,11 +591,6 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, * 1. optimization, if (PR_TRUE==atLeastOneRowSpanningCell) ... otherwise skip this step entirely * we can get this info trivially from the cell map */ - nsTableFrame *tableFrame=nsnull; - nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if (NS_FAILED(rv) || nsnull==tableFrame) - return; - nscoord cellSpacingY = tableFrame->GetCellSpacingY(); PRInt32 rowGroupHeight; for (PRInt32 counter=0; counter<2; counter++) @@ -622,22 +626,18 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, for (i = 0; i < rowSpan; i++) { heightOfRowsSpanned += rowHeights[rowIndex + i]; } - // need to reduce by cell spacing, twice that if it is the top row - heightOfRowsSpanned -= cellSpacingY; - if (0 == rowIndex) { - heightOfRowsSpanned -= cellSpacingY; - } - - if (gsDebug) printf("TRGF CalcRowH: heightOfRowsSpanned=%d\n", heightOfRowsSpanned); + // the avail height needs to reduce by top and bottom margins + nscoord availHeightOfRowsSpanned = heightOfRowsSpanned - cellSpacingY - cellSpacingY; + if (gsDebug) printf("TRGF CalcRowH: availHeightOfRowsSpanned=%d\n", availHeightOfRowsSpanned); /* if the cell height fits in the rows, expand the spanning cell's height and slap it in */ nsSize cellFrameSize; cellFrame->GetSize(cellFrameSize); - if (heightOfRowsSpanned > cellFrameSize.height) + if (availHeightOfRowsSpanned > cellFrameSize.height) { if (gsDebug) printf("TRGF CalcRowH: spanning cell fits in rows spanned, had h=%d, expanded to %d\n", - cellFrameSize.height, heightOfRowsSpanned); - cellFrame->SizeTo(cellFrameSize.width, heightOfRowsSpanned); + cellFrameSize.height, availHeightOfRowsSpanned); + cellFrame->SizeTo(cellFrameSize.width, availHeightOfRowsSpanned); // Realign cell content based on new height ((nsTableCellFrame*)cellFrame)->VerticallyAlignChild(); } @@ -646,20 +646,25 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, */ else { - PRInt32 excessHeight = cellFrameSize.height - heightOfRowsSpanned; + PRInt32 excessHeight = cellFrameSize.height - availHeightOfRowsSpanned; if (gsDebug) printf("TRGF CalcRowH: excessHeight=%d\n", excessHeight); // for every row starting at the row with the spanning cell... nsTableRowFrame *rowFrameToBeResized = (nsTableRowFrame *)rowFrame; PRInt32 *excessForRow = new PRInt32[numRows]; nsCRT::memset (excessForRow, 0, numRows*sizeof(PRInt32)); - for (i = rowIndex; i < numRows; i++) - { + nscoord excessAllocated = 0; + for (i = rowIndex; i < numRows; i++) { if (gsDebug) printf("TRGF CalcRowH: for row index=%d\n", i); // if the row is within the spanned range, resize the row - if (i < (rowIndex + rowSpan)) - { + if (i < (rowIndex + rowSpan)) { + //float percent = ((float)rowHeights[i]) / ((float)availHeightOfRowsSpanned); + //excessForRow[i] = NSToCoordRound(((float)(excessHeight)) * percent); float percent = ((float)rowHeights[i]) / ((float)heightOfRowsSpanned); - excessForRow[i] = NSToCoordRound(((float)(excessHeight)) * percent); + // give rows their percentage, except the last row gets the remainder + excessForRow[i] = ((i - 1) == (rowIndex + rowSpan)) + ? excessHeight - excessAllocated + : NSToCoordRound(((float)(excessHeight)) * percent); + excessAllocated += excessForRow[i]; if (gsDebug) printf("TRGF CalcRowH: for row %d, excessHeight=%d from percent %f\n", i, excessForRow[i], percent); // update the row height