From 49e55fa057f6e776692c43852c740db8ee93a744 Mon Sep 17 00:00:00 2001 From: "karnaze%netscape.com" Date: Fri, 5 Nov 1999 22:36:59 +0000 Subject: [PATCH] bugs 17138, 17168 and others - col allocation involving colspans honors constraints; pct colspans were allocating incorrectly if pct cols existed. git-svn-id: svn://10.0.0.236/trunk@52879 18797224-902f-48f8-a5cc-f745e15eee43 --- .../table/src/BasicTableLayoutStrategy.cpp | 440 ++++++++++++------ .../html/table/src/BasicTableLayoutStrategy.h | 33 ++ .../tables/BasicTableLayoutStrategy.cpp | 440 ++++++++++++------ .../layout/tables/BasicTableLayoutStrategy.h | 33 ++ 4 files changed, 660 insertions(+), 286 deletions(-) diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp index 3dc01683b31..1714d4490f8 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -35,12 +35,15 @@ static PRBool gsDebugBalance = PR_TRUE; PRBool CanAllocate(PRInt32 aTypeToAllocate, PRInt32 aTypeAlreadyAllocated, - nsTableColFrame* aColFrame) + nsTableColFrame* aColFrame, + PRBool& aConsiderAdj) { + aConsiderAdj = PR_TRUE; if ((aTypeToAllocate == FIX_ADJ) && (aTypeAlreadyAllocated == FIX)) { return PR_TRUE; } if ((aTypeToAllocate == DES_CON) && (aTypeAlreadyAllocated == FIX_ADJ)) { + aConsiderAdj = PR_FALSE; return PR_TRUE; } if ((aTypeToAllocate == DES_CON) && (aTypeAlreadyAllocated == FIX) && @@ -229,12 +232,12 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty // if the max width available is less than the min content width for auto table // that had no % cells/cols, we're done - if (tableIsAutoWidth && (maxWidth < mMinTableContentWidth) & (0 == perAdjTableWidth)) { + if (tableIsAutoWidth && (maxWidth < mMinTableContentWidth) && (0 == perAdjTableWidth)) { return BCW_Wrapup(this, mTableFrame, nsnull); } PRInt32 cellSpacingTotal; - // the following are of size NUM_WIDTHS, but only MIN_CON, DES_CON, FIX, PCT + // the following are of size NUM_WIDTHS, but only MIN_CON, DES_CON, FIX, FIX_ADJ, PCT // are used and they account for colspan ADJusted values PRInt32 totalWidths[NUM_WIDTHS]; // sum of col widths of a particular type PRInt32 totalAvailWidths[NUM_WIDTHS]; @@ -367,13 +370,14 @@ void BasicTableLayoutStrategy::AllocateFully(nscoord& aTotalAllocated, nscoord oldWidth = mTableFrame->GetColumnWidth(colX); nscoord newWidth = colFrame->GetWidth(aWidthType); - if (-1 != aAllocTypes[colX]) { - if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) { + PRBool useAdj; + if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame, useAdj)) { + if (-1 != aAllocTypes[colX]) { continue; } } // account for col span overrides with DES_CON and FIX - if (DES_CON == aWidthType) { + if ((DES_CON == aWidthType) && useAdj) { newWidth = PR_MAX(newWidth, colFrame->GetWidth(DES_ADJ)); } else if (PCT == aWidthType) { @@ -429,6 +433,268 @@ void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount, } } +nscoord GetConstrainedWidth(nsTableColFrame* colFrame, + PRBool aConsiderPct) + +{ + nscoord conWidth = WIDTH_NOT_SET; + if (aConsiderPct) { + nscoord conWidth = colFrame->GetPctWidth(); + } + if (conWidth <= 0 ) { + conWidth = colFrame->GetFixWidth(); + } + return conWidth; +} + +#define LIMIT_DES 0 +#define LIMIT_CON 1 +#define LIMIT_NONE 2 + +void +BasicTableLayoutStrategy::ComputeColspanWidths(PRInt32 aWidthIndex, + nsTableCellFrame* aCellFrame, + PRInt32 aColIndex, + PRInt32 aColSpan, + PRBool aConsiderPct) +{ + if (!aCellFrame || (aColIndex < 0) || (aColIndex < 0) || (aColSpan < 0)) { + NS_ASSERTION(PR_FALSE, "ComputeColspanWidths called incorrectly"); + return; + } + + nscoord cellWidth = 0; + if (MIN_CON == aWidthIndex) { + cellWidth = aCellFrame->GetPass1MaxElementSize().width; + } + else if (DES_CON == aWidthIndex) { + cellWidth = aCellFrame->GetPass1DesiredSize().width; + } + else { // FIX width + // see if the cell has a style width specified + const nsStylePosition* cellPosition; + aCellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { + // need to add padding into fixed width + const nsStyleSpacing* spacing; + aCellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); + nsMargin paddingMargin; + spacing->CalcPaddingFor(aCellFrame, paddingMargin); + nscoord padding = paddingMargin.left + paddingMargin.right; + cellWidth = cellPosition->mWidth.GetCoordValue() + padding; + cellWidth = PR_MAX(cellWidth, aCellFrame->GetPass1MaxElementSize().width); + } + } + + if (0 >= cellWidth) { + return; + } + + if (MIN_CON == aWidthIndex) { + // for min width, first allocate fixed cells up to their fixed value, then if + // necessary allocate auto cells up to their auto value, then if necessary + // allocate auto cells. + for (PRInt32 limitX = LIMIT_CON; limitX <= LIMIT_NONE; limitX++) { + if (ComputeColspanWidths(aWidthIndex, aCellFrame, cellWidth, + aColIndex, aColSpan, aConsiderPct, limitX)) { + return; + } + } + } else { + // for des width, just allocate auto cells + ComputeColspanWidths(aWidthIndex, aCellFrame, cellWidth, + aColIndex, aColSpan, aConsiderPct, LIMIT_NONE); + } +} + + +PRBool +BasicTableLayoutStrategy::ComputeColspanWidths(PRInt32 aWidthIndex, + nsTableCellFrame* aCellFrame, + nscoord aCellWidth, + PRInt32 aColIndex, + PRInt32 aColSpan, + PRBool aConsiderPct, + PRInt32 aLimitType) +{ + PRBool result = PR_TRUE; + // skip DES_CON if there is a FIX since FIX is really the desired size + //if ((DES_CON == widthX) && (cellWidths[FIX] > 0)) + nscoord spanCellSpacing = 0; // total cell spacing cells being spanned + nscoord spanTotal = 0; // total width of type aWidthIndex of spanned cells + nscoord divisorCon = 0; // the sum of constrained (fix or pct if specified) widths of spanned cells + nscoord divisorDes = 0; // the sum of desired widths + // the following are only used for MIN_CON calculations. Takings differences between + // actual and target values allows target values to be reached and not exceeded. This + // is not as accurate as the method in AllocateConstrained, but it is a lot cheaper. + nscoord divisorConLimit = 0; // the sum of differences between constrained width and min width + nscoord divisorDesLimit = 0; // the sum of differences between desired width and min width + + nscoord spacingX = mTableFrame->GetCellSpacingX(); + PRInt32 spanX; + // accumulate the various divisors to be used later + for (spanX = 0; spanX < aColSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX); + nscoord colWidth = PR_MAX(colFrame->GetWidth(aWidthIndex), + colFrame->GetWidth(aWidthIndex + NUM_MAJOR_WIDTHS)); + colWidth = PR_MAX(colWidth, 0); + if (aWidthIndex == DES_CON) { + nscoord conWidth = GetConstrainedWidth(colFrame, aConsiderPct); + if (conWidth <= 0) { + divisorDes += colWidth; + spanTotal += colWidth; + } + else { + divisorCon += conWidth; + spanTotal += conWidth; + } + } + else if (aWidthIndex == MIN_CON) { + nscoord conWidth = GetConstrainedWidth(colFrame, aConsiderPct); + nscoord desWidth = colFrame->GetDesWidth(); + if (conWidth > 0) { + divisorCon += conWidth; + divisorConLimit += PR_MAX(conWidth - colWidth, 0); + } + else { + divisorDes += desWidth; + divisorDesLimit += PR_MAX(desWidth - colWidth, 0); + } + spanTotal += colWidth; + } + else { // FIX width + if (colWidth > 0) { + divisorCon += colWidth; + } + else { + divisorDes += colFrame->GetDesWidth(); + } + spanTotal += colWidth; + } + if ((spanX > 0) && (mTableFrame->GetNumCellsOriginatingInCol(aColIndex + spanX) > 0)) { + spanCellSpacing += spacingX; + } + } + + if (MIN_CON != aWidthIndex) { + aLimitType = LIMIT_NONE; // just in case we were called incorrectly + } + else { + // this method gets called up to 3 times, first to let fixed cols reach their + // target, 2nd to let auto cols reach their target and 3rd to let auto cols + // fill out the remainder. Below are some optimizations which can skip steps. + + // if there are no constrained cols to focus on, focus on auto cols + if ((LIMIT_CON == aLimitType) && (0 == divisorConLimit)) { + aLimitType = LIMIT_DES; + } + // if there are no auto cols to focus on, focus on nothing + if ((LIMIT_DES == aLimitType) && (0 == divisorDesLimit)) { + aLimitType = LIMIT_NONE; + } + } + + nscoord availWidth = aCellWidth - spanTotal - spanCellSpacing; + // there are 2 cases where the target will not be reached + if ((LIMIT_CON == aLimitType) && (divisorConLimit < availWidth)) { + availWidth = divisorConLimit; + result = PR_FALSE; + } + if ((LIMIT_DES == aLimitType) && (divisorDesLimit < availWidth)) { + availWidth = divisorDesLimit; + result = PR_FALSE; + } + if (availWidth > 0) { + // get the correct numerator in a similar fashion to getting the divisor + for (spanX = 0; spanX < aColSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX); + nscoord colWidth = PR_MAX(colFrame->GetWidth(aWidthIndex), + colFrame->GetWidth(aWidthIndex + NUM_MAJOR_WIDTHS)); + nscoord minWidth = colFrame->GetMinWidth(); + + colWidth = PR_MAX(colWidth, 0); + nscoord numeratorDes = 0; + nscoord numeratorCon = 0; + nscoord numeratorConLimit = 0; + nscoord numeratorDesLimit = 0; + if (aWidthIndex == DES_CON) { + nscoord conWidth = GetConstrainedWidth(colFrame, aConsiderPct); + if (conWidth <= 0) { + numeratorDes = colWidth; + } + else { + numeratorCon = conWidth; + } + } + else if (aWidthIndex == MIN_CON) { + nscoord conWidth = GetConstrainedWidth(colFrame, aConsiderPct); + nscoord desWidth = colFrame->GetDesWidth(); + if (conWidth > 0) { + numeratorCon = conWidth; + numeratorConLimit = PR_MAX(conWidth - colWidth, 0); + } + else { + numeratorDes = desWidth; + numeratorDesLimit = PR_MAX(desWidth - colWidth, 0); + } + } + else { // FIX width + if (colWidth <= 0) { + numeratorDes = colFrame->GetDesWidth(); + } + else { + numeratorCon = colWidth; + } + } + + nscoord divisor; + nscoord numerator; + if (divisorDes > 0) { // there were auto cols + divisor = divisorDes; + numerator = numeratorDes; + } + else { // there were only constrained cols + divisor = divisorCon; + numerator = numeratorCon; + } + // let constrained cols reach their target + if (LIMIT_CON == aLimitType) { + if (divisorConLimit > 0) { + divisor = divisorConLimit; + numerator = numeratorConLimit; + } + } + // let auto cols reach their target + else if (LIMIT_DES == aLimitType) { + if (divisorDesLimit > 0) { + divisor = divisorDesLimit; + numerator = numeratorDesLimit; + } + } + + // calculate the amount of additional width the col will get + nscoord addition = (0 >= divisor) + ? NSToCoordRound( ((float)availWidth) / ((float)aColSpan) ) + : NSToCoordRound( (((float)numerator) / ((float)divisor)) * availWidth); + if (addition > 0) { + nscoord newColAdjWidth = colWidth + addition; + if (newColAdjWidth > minWidth) { + if (FIX == aWidthIndex) { + // a colspan cannot fix a column below what a cell desires on its own + nscoord desCon = colFrame->GetWidth(DES_CON); // do not consider DES_ADJ + if (desCon > newColAdjWidth) { + newColAdjWidth = desCon; + } + } + colFrame->SetWidth(aWidthIndex + NUM_MAJOR_WIDTHS, newColAdjWidth); + colFrame->SetConstrainingCell(aCellFrame); // XXX is this right? + } + } + } + } + return result; +} + // Determine min, desired, fixed, and proportional sizes for the cols and // and calculate min/max table width PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth) @@ -599,94 +865,9 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth if (!originates || (1 == colSpan)) { continue; } - nscoord cellWidths[NUM_WIDTHS]; - cellWidths[MIN_CON] = cellFrame->GetPass1MaxElementSize().width; - cellWidths[DES_CON] = cellFrame->GetPass1DesiredSize().width; - cellWidths[FIX] = WIDTH_NOT_SET; - // see if the cell has a style width specified - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); - if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { - // need to add padding into fixed width - const nsStyleSpacing* spacing; - cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); - nsMargin paddingMargin; - spacing->CalcPaddingFor(cellFrame, paddingMargin); - nscoord padding = paddingMargin.left + paddingMargin.right; - cellWidths[FIX] = cellPosition->mWidth.GetCoordValue() + padding; - cellWidths[FIX] = PR_MAX(cellWidths[FIX], cellWidths[MIN_CON]); - } - // set MIN_ADJ, DES_ADJ, FIX_ADJ - nscoord spanCellSpacing = 0; for (PRInt32 widthX = 0; widthX < NUM_MAJOR_WIDTHS; widthX++) { - // skip DES_CON if there is a FIX since FIX is really the desired size - if ((DES_CON == widthX) && (cellWidths[FIX] > 0)) - continue; - nscoord spanTotal = 0; - nscoord divisor = 0; - PRInt32 spanX; - for (spanX = 0; spanX < colSpan; spanX++) { - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); - nscoord colWidth = PR_MAX(colFrame->GetWidth(widthX), - colFrame->GetWidth(widthX + NUM_MAJOR_WIDTHS)); - // need to get a contribution for every cell - colWidth = PR_MAX(colWidth, colFrame->GetMinWidth()); - spanTotal += colWidth; - // accumulate divisor - if (widthX == FIX) { - colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); - } - else if (widthX == DES_CON) { - nscoord fixWidth = colFrame->GetFixWidth(); - if (fixWidth > 0) { - colWidth = fixWidth; - } - } - else if (widthX == MIN_CON) { - colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); - } - divisor += colWidth; - if ((0 == widthX) && (spanX > 0) && (mTableFrame->GetNumCellsOriginatingInCol(colX + spanX) > 0)) { - spanCellSpacing += spacingX; - } - } - spanTotal -= spanCellSpacing; - nscoord cellWidth = cellWidths[widthX] - spanCellSpacing; - if ((cellWidth > 0) && !((widthX == MIN_CON) && (cellWidth <= spanTotal))) { - for (spanX = 0; spanX < colSpan; spanX++) { - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); - nscoord colWidth = PR_MAX(colFrame->GetWidth(widthX), - colFrame->GetWidth(widthX + NUM_MAJOR_WIDTHS)); - nscoord minWidth = colFrame->GetMinWidth(); - // accumulate numerator similarly to divisor - colWidth = PR_MAX(colWidth, colFrame->GetMinWidth()); - if (widthX == FIX) { - colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); - } - else if (widthX == DES_CON) { - nscoord fixWidth = colFrame->GetFixWidth(); - if (fixWidth > 0) { - colWidth = fixWidth; - } - //colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); - } - else if (widthX == MIN_CON) { - colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); - } - nscoord colAdjWidth = colFrame->GetWidth(widthX + NUM_MAJOR_WIDTHS); - nscoord newColAdjWidth = (0 >= spanTotal) - ? NSToCoordRound( ((float)cellWidth) / ((float)colSpan) ) - : NSToCoordRound( (((float)colWidth) / ((float)divisor)) * cellWidth); - if ((newColAdjWidth > colAdjWidth) && (newColAdjWidth > 0)) { - newColAdjWidth = PR_MAX(newColAdjWidth, minWidth); - if (newColAdjWidth > colFrame->GetWidth(widthX)) { - colFrame->SetWidth(widthX + NUM_MAJOR_WIDTHS, newColAdjWidth); - colFrame->SetConstrainingCell(cellFrame); // XXX is this right? - } - } - } - } + ComputeColspanWidths(widthX, cellFrame, colX, colSpan, PR_FALSE); } } } @@ -731,7 +912,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, nscoord fixWidthTotal = 0; // total of fixed widths of all cols float perTotal = 0.0f; // total of percentage constrained cols and/or cells in cols PRInt32 numPerCols = 0; // number of colums that have percentage constraints - nscoord desWidthTotal = 0; // total of desired widths of cols that don't have percentage constraints + nscoord prefWidthTotal = 0;// total of des/fix widths of cols that don't have percentage constraints basis = 0; // basis to use for percentages, computed considering percentage values for (colX = 0; colX < mNumCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); @@ -777,14 +958,19 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, } } basis = PR_MAX(basis, colBasis); + nscoord fixWidth = colFrame->GetFixWidth(); + fixWidthTotal += fixWidth; if (colBasis >= 0) { numPerCols++; } else { - desWidthTotal += colFrame->GetDesWidth(); + prefWidthTotal += (fixWidth > 0) ? fixWidth : colFrame->GetDesWidth(); } - fixWidthTotal += colFrame->GetFixWidth(); } // end for (colX .. + // If there are no pct cells or cols, there is nothing to do. + if (0 == numPerCols) { + return 0; + } // If there is only one col and it is % based, it won't affect anything if ((1 == mNumCols) && (mNumCols == numPerCols)) { return 0; @@ -792,11 +978,11 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, // compute a basis considering total percentages and the desired width of everything else if (perTotal < 1.0f) { if (perTotal > 0.0f) { - nscoord otherBasis = NSToCoordRound((float)desWidthTotal / (1.0f - perTotal)); + nscoord otherBasis = NSToCoordRound((float)prefWidthTotal / (1.0f - perTotal)); basis = PR_MAX(basis, otherBasis); } } - else if (desWidthTotal > 0) { // make the basis as big as possible + else if (prefWidthTotal > 0) { // make the basis as big as possible basis = aBasisIn; } @@ -936,9 +1122,13 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, nscoord minWidth = colFrame->GetMinWidth(); nscoord colWidth = PR_MAX(minWidth, colFrame->GetFixWidth()); colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); // XXX check this + //float colPctAdj = (0 == spanTotal) + // ? cellPctWidth / ((float) colSpan) + // : cellPct * ((float)colWidth) / (float)spanTotal; + float avail = (float)PR_MAX(cellPctWidth - colPctWidthTotal, 0); float colPctAdj = (0 == spanTotal) - ? cellPctWidth / ((float) colSpan) - : cellPct * ((float)colWidth) / (float)spanTotal; + ? avail / ((float) colSpan) + : (avail / (float)basis) * (((float)colWidth) / (float)spanTotal); if (colPctAdj > 0) { nscoord colPctAdjWidth = colFrame->GetWidth(PCT_ADJ); nscoord newColPctAdjWidth = NSToCoordRound(colPctAdj * (float)basis); @@ -1059,42 +1249,7 @@ PRBool BasicTableLayoutStrategy::RecomputeAdjMinIfNecessary() } if (cellSpansPercent) { - // recompute the ADJ_MIN width for every spanned col - nscoord spanTotal = 0; - nscoord divisor = 0; - nscoord spanCellSpacing = 0; - - for (spanX = 0; spanX < colSpan; spanX++) { - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); - nscoord colWidth = colFrame->GetWidth(MIN_CON); - spanTotal += colWidth; - colWidth = PR_MAX(colWidth, colFrame->GetWidth(FIX)); - colWidth = PR_MAX(colWidth, colFrame->GetWidth(PCT)); - divisor += colWidth; - if ((spanX > 0) && (mTableFrame->GetNumCellsOriginatingInCol(colX + spanX) > 0)) { - spanCellSpacing += spacingX; - } - } - spanTotal -= spanCellSpacing; - nscoord cellWidth = cellFrame->GetPass1MaxElementSize().width; - if ((cellWidth > 0) && (cellWidth > spanTotal)) { - for (spanX = 0; spanX < colSpan; spanX++) { - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); - nscoord minWidth = colFrame->GetWidth(MIN_CON); - nscoord colWidth = PR_MAX(minWidth, colFrame->GetWidth(FIX)); - colWidth = PR_MAX(colWidth, colFrame->GetWidth(PCT)); - nscoord colAdjWidth = colFrame->GetWidth(MIN_ADJ); - nscoord newColAdjWidth = (0 >= spanTotal) - ? NSToCoordRound( ((float)cellWidth) / ((float)colSpan) ) - : NSToCoordRound( (((float)colWidth) / ((float)divisor)) * cellWidth); - if ((newColAdjWidth > colAdjWidth) && (newColAdjWidth > 0)) { - newColAdjWidth = PR_MAX(newColAdjWidth, minWidth); - if (newColAdjWidth > minWidth) { - colFrame->SetWidth(MIN_ADJ, newColAdjWidth); - } - } - } - } + ComputeColspanWidths(MIN_CON, cellFrame, colX, colSpan, PR_TRUE); } } } @@ -1234,8 +1389,6 @@ void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, } - - struct nsColInfo { nsColInfo(nsTableColFrame* aFrame, PRInt32 aIndex, @@ -1353,17 +1506,18 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, PRInt32 numConstrainedCols = 0; nscoord sumMaxConstraints = 0; + PRBool useAdj = PR_TRUE; PRInt32 colX; for (colX = 0; colX < mNumCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); - if (-1 != aAllocTypes[colX]) { - if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) { + if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame, useAdj)) { + if (-1 != aAllocTypes[colX]) { continue; } } numConstrainedCols++; nscoord width = colFrame->GetWidth(aWidthType); - if (DES_CON == aWidthType) { + if ((DES_CON == aWidthType) && useAdj) { width = PR_MAX(width, colFrame->GetWidth(DES_ADJ)); } else if (PCT == aWidthType) { @@ -1383,14 +1537,14 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, // set the col info entries for each constrained col for (colX = 0; colX < mNumCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); - if (-1 != aAllocTypes[colX]) { - if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) { + if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame, useAdj)) { + if (-1 != aAllocTypes[colX]) { continue; } } nscoord minWidth = mTableFrame->GetColumnWidth(colX); nscoord maxWidth = colFrame->GetWidth(aWidthType); - if (DES_CON == aWidthType) { + if ((DES_CON == aWidthType) && useAdj) { maxWidth = PR_MAX(maxWidth, colFrame->GetWidth(DES_ADJ)); } else if (PCT == aWidthType) { diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h index 30aad97c318..53e3585fb64 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h @@ -98,6 +98,39 @@ protected: */ virtual PRBool AssignPreliminaryColumnWidths(nscoord aComputedWidth); + /** + * Calculate the adjusted widths (min, desired, fixed, or pct) for a cell + * spanning multiple columns. + * @param aWidthIndex - the width to calculate (see nsTableColFrame.h for enums) + * @param aCellFrame - the frame of the cell with a colspan + * @param aColIndex - the column index of the cell in the table + * @param aColSpan - the colspan of the cell + * @param aConsiderPct - if true, consider columns that have pct widths and are spanned by the cell + */ + void ComputeColspanWidths(PRInt32 aWidthIndex, + nsTableCellFrame* aCellFrame, + PRInt32 aColIndex, + PRInt32 aColSpan, + PRBool aConsiderPct); + + /** + * main helper for above. For min width calculations, it can get called up to + * 3 times, 1st to let constrained (fix or pct) cols reach their limit, 2nd + * to let auto cols reach their limit and 3rd to spread any remainder among + * auto cols. If there are no auto cols then only constrained cols are considered. + * @param aCellWidth - the width of the cell + * @param aLimitType - value indicating which type of width is being targeted + * to reach a limit + * @return - true if the computation completed, false otherwise + */ + PRBool ComputeColspanWidths(PRInt32 aWidthIndex, + nsTableCellFrame* aCellFrame, + nscoord aCellWidth, + PRInt32 aColIndex, + PRInt32 aColSpan, + PRBool aConsiderPct, + PRInt32 aLimitType); + nscoord AssignPercentageColumnWidths(nscoord aBasis, PRBool aTableIsAutoWidth); diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp index 3dc01683b31..1714d4490f8 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp @@ -35,12 +35,15 @@ static PRBool gsDebugBalance = PR_TRUE; PRBool CanAllocate(PRInt32 aTypeToAllocate, PRInt32 aTypeAlreadyAllocated, - nsTableColFrame* aColFrame) + nsTableColFrame* aColFrame, + PRBool& aConsiderAdj) { + aConsiderAdj = PR_TRUE; if ((aTypeToAllocate == FIX_ADJ) && (aTypeAlreadyAllocated == FIX)) { return PR_TRUE; } if ((aTypeToAllocate == DES_CON) && (aTypeAlreadyAllocated == FIX_ADJ)) { + aConsiderAdj = PR_FALSE; return PR_TRUE; } if ((aTypeToAllocate == DES_CON) && (aTypeAlreadyAllocated == FIX) && @@ -229,12 +232,12 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty // if the max width available is less than the min content width for auto table // that had no % cells/cols, we're done - if (tableIsAutoWidth && (maxWidth < mMinTableContentWidth) & (0 == perAdjTableWidth)) { + if (tableIsAutoWidth && (maxWidth < mMinTableContentWidth) && (0 == perAdjTableWidth)) { return BCW_Wrapup(this, mTableFrame, nsnull); } PRInt32 cellSpacingTotal; - // the following are of size NUM_WIDTHS, but only MIN_CON, DES_CON, FIX, PCT + // the following are of size NUM_WIDTHS, but only MIN_CON, DES_CON, FIX, FIX_ADJ, PCT // are used and they account for colspan ADJusted values PRInt32 totalWidths[NUM_WIDTHS]; // sum of col widths of a particular type PRInt32 totalAvailWidths[NUM_WIDTHS]; @@ -367,13 +370,14 @@ void BasicTableLayoutStrategy::AllocateFully(nscoord& aTotalAllocated, nscoord oldWidth = mTableFrame->GetColumnWidth(colX); nscoord newWidth = colFrame->GetWidth(aWidthType); - if (-1 != aAllocTypes[colX]) { - if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) { + PRBool useAdj; + if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame, useAdj)) { + if (-1 != aAllocTypes[colX]) { continue; } } // account for col span overrides with DES_CON and FIX - if (DES_CON == aWidthType) { + if ((DES_CON == aWidthType) && useAdj) { newWidth = PR_MAX(newWidth, colFrame->GetWidth(DES_ADJ)); } else if (PCT == aWidthType) { @@ -429,6 +433,268 @@ void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount, } } +nscoord GetConstrainedWidth(nsTableColFrame* colFrame, + PRBool aConsiderPct) + +{ + nscoord conWidth = WIDTH_NOT_SET; + if (aConsiderPct) { + nscoord conWidth = colFrame->GetPctWidth(); + } + if (conWidth <= 0 ) { + conWidth = colFrame->GetFixWidth(); + } + return conWidth; +} + +#define LIMIT_DES 0 +#define LIMIT_CON 1 +#define LIMIT_NONE 2 + +void +BasicTableLayoutStrategy::ComputeColspanWidths(PRInt32 aWidthIndex, + nsTableCellFrame* aCellFrame, + PRInt32 aColIndex, + PRInt32 aColSpan, + PRBool aConsiderPct) +{ + if (!aCellFrame || (aColIndex < 0) || (aColIndex < 0) || (aColSpan < 0)) { + NS_ASSERTION(PR_FALSE, "ComputeColspanWidths called incorrectly"); + return; + } + + nscoord cellWidth = 0; + if (MIN_CON == aWidthIndex) { + cellWidth = aCellFrame->GetPass1MaxElementSize().width; + } + else if (DES_CON == aWidthIndex) { + cellWidth = aCellFrame->GetPass1DesiredSize().width; + } + else { // FIX width + // see if the cell has a style width specified + const nsStylePosition* cellPosition; + aCellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { + // need to add padding into fixed width + const nsStyleSpacing* spacing; + aCellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); + nsMargin paddingMargin; + spacing->CalcPaddingFor(aCellFrame, paddingMargin); + nscoord padding = paddingMargin.left + paddingMargin.right; + cellWidth = cellPosition->mWidth.GetCoordValue() + padding; + cellWidth = PR_MAX(cellWidth, aCellFrame->GetPass1MaxElementSize().width); + } + } + + if (0 >= cellWidth) { + return; + } + + if (MIN_CON == aWidthIndex) { + // for min width, first allocate fixed cells up to their fixed value, then if + // necessary allocate auto cells up to their auto value, then if necessary + // allocate auto cells. + for (PRInt32 limitX = LIMIT_CON; limitX <= LIMIT_NONE; limitX++) { + if (ComputeColspanWidths(aWidthIndex, aCellFrame, cellWidth, + aColIndex, aColSpan, aConsiderPct, limitX)) { + return; + } + } + } else { + // for des width, just allocate auto cells + ComputeColspanWidths(aWidthIndex, aCellFrame, cellWidth, + aColIndex, aColSpan, aConsiderPct, LIMIT_NONE); + } +} + + +PRBool +BasicTableLayoutStrategy::ComputeColspanWidths(PRInt32 aWidthIndex, + nsTableCellFrame* aCellFrame, + nscoord aCellWidth, + PRInt32 aColIndex, + PRInt32 aColSpan, + PRBool aConsiderPct, + PRInt32 aLimitType) +{ + PRBool result = PR_TRUE; + // skip DES_CON if there is a FIX since FIX is really the desired size + //if ((DES_CON == widthX) && (cellWidths[FIX] > 0)) + nscoord spanCellSpacing = 0; // total cell spacing cells being spanned + nscoord spanTotal = 0; // total width of type aWidthIndex of spanned cells + nscoord divisorCon = 0; // the sum of constrained (fix or pct if specified) widths of spanned cells + nscoord divisorDes = 0; // the sum of desired widths + // the following are only used for MIN_CON calculations. Takings differences between + // actual and target values allows target values to be reached and not exceeded. This + // is not as accurate as the method in AllocateConstrained, but it is a lot cheaper. + nscoord divisorConLimit = 0; // the sum of differences between constrained width and min width + nscoord divisorDesLimit = 0; // the sum of differences between desired width and min width + + nscoord spacingX = mTableFrame->GetCellSpacingX(); + PRInt32 spanX; + // accumulate the various divisors to be used later + for (spanX = 0; spanX < aColSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX); + nscoord colWidth = PR_MAX(colFrame->GetWidth(aWidthIndex), + colFrame->GetWidth(aWidthIndex + NUM_MAJOR_WIDTHS)); + colWidth = PR_MAX(colWidth, 0); + if (aWidthIndex == DES_CON) { + nscoord conWidth = GetConstrainedWidth(colFrame, aConsiderPct); + if (conWidth <= 0) { + divisorDes += colWidth; + spanTotal += colWidth; + } + else { + divisorCon += conWidth; + spanTotal += conWidth; + } + } + else if (aWidthIndex == MIN_CON) { + nscoord conWidth = GetConstrainedWidth(colFrame, aConsiderPct); + nscoord desWidth = colFrame->GetDesWidth(); + if (conWidth > 0) { + divisorCon += conWidth; + divisorConLimit += PR_MAX(conWidth - colWidth, 0); + } + else { + divisorDes += desWidth; + divisorDesLimit += PR_MAX(desWidth - colWidth, 0); + } + spanTotal += colWidth; + } + else { // FIX width + if (colWidth > 0) { + divisorCon += colWidth; + } + else { + divisorDes += colFrame->GetDesWidth(); + } + spanTotal += colWidth; + } + if ((spanX > 0) && (mTableFrame->GetNumCellsOriginatingInCol(aColIndex + spanX) > 0)) { + spanCellSpacing += spacingX; + } + } + + if (MIN_CON != aWidthIndex) { + aLimitType = LIMIT_NONE; // just in case we were called incorrectly + } + else { + // this method gets called up to 3 times, first to let fixed cols reach their + // target, 2nd to let auto cols reach their target and 3rd to let auto cols + // fill out the remainder. Below are some optimizations which can skip steps. + + // if there are no constrained cols to focus on, focus on auto cols + if ((LIMIT_CON == aLimitType) && (0 == divisorConLimit)) { + aLimitType = LIMIT_DES; + } + // if there are no auto cols to focus on, focus on nothing + if ((LIMIT_DES == aLimitType) && (0 == divisorDesLimit)) { + aLimitType = LIMIT_NONE; + } + } + + nscoord availWidth = aCellWidth - spanTotal - spanCellSpacing; + // there are 2 cases where the target will not be reached + if ((LIMIT_CON == aLimitType) && (divisorConLimit < availWidth)) { + availWidth = divisorConLimit; + result = PR_FALSE; + } + if ((LIMIT_DES == aLimitType) && (divisorDesLimit < availWidth)) { + availWidth = divisorDesLimit; + result = PR_FALSE; + } + if (availWidth > 0) { + // get the correct numerator in a similar fashion to getting the divisor + for (spanX = 0; spanX < aColSpan; spanX++) { + nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX); + nscoord colWidth = PR_MAX(colFrame->GetWidth(aWidthIndex), + colFrame->GetWidth(aWidthIndex + NUM_MAJOR_WIDTHS)); + nscoord minWidth = colFrame->GetMinWidth(); + + colWidth = PR_MAX(colWidth, 0); + nscoord numeratorDes = 0; + nscoord numeratorCon = 0; + nscoord numeratorConLimit = 0; + nscoord numeratorDesLimit = 0; + if (aWidthIndex == DES_CON) { + nscoord conWidth = GetConstrainedWidth(colFrame, aConsiderPct); + if (conWidth <= 0) { + numeratorDes = colWidth; + } + else { + numeratorCon = conWidth; + } + } + else if (aWidthIndex == MIN_CON) { + nscoord conWidth = GetConstrainedWidth(colFrame, aConsiderPct); + nscoord desWidth = colFrame->GetDesWidth(); + if (conWidth > 0) { + numeratorCon = conWidth; + numeratorConLimit = PR_MAX(conWidth - colWidth, 0); + } + else { + numeratorDes = desWidth; + numeratorDesLimit = PR_MAX(desWidth - colWidth, 0); + } + } + else { // FIX width + if (colWidth <= 0) { + numeratorDes = colFrame->GetDesWidth(); + } + else { + numeratorCon = colWidth; + } + } + + nscoord divisor; + nscoord numerator; + if (divisorDes > 0) { // there were auto cols + divisor = divisorDes; + numerator = numeratorDes; + } + else { // there were only constrained cols + divisor = divisorCon; + numerator = numeratorCon; + } + // let constrained cols reach their target + if (LIMIT_CON == aLimitType) { + if (divisorConLimit > 0) { + divisor = divisorConLimit; + numerator = numeratorConLimit; + } + } + // let auto cols reach their target + else if (LIMIT_DES == aLimitType) { + if (divisorDesLimit > 0) { + divisor = divisorDesLimit; + numerator = numeratorDesLimit; + } + } + + // calculate the amount of additional width the col will get + nscoord addition = (0 >= divisor) + ? NSToCoordRound( ((float)availWidth) / ((float)aColSpan) ) + : NSToCoordRound( (((float)numerator) / ((float)divisor)) * availWidth); + if (addition > 0) { + nscoord newColAdjWidth = colWidth + addition; + if (newColAdjWidth > minWidth) { + if (FIX == aWidthIndex) { + // a colspan cannot fix a column below what a cell desires on its own + nscoord desCon = colFrame->GetWidth(DES_CON); // do not consider DES_ADJ + if (desCon > newColAdjWidth) { + newColAdjWidth = desCon; + } + } + colFrame->SetWidth(aWidthIndex + NUM_MAJOR_WIDTHS, newColAdjWidth); + colFrame->SetConstrainingCell(aCellFrame); // XXX is this right? + } + } + } + } + return result; +} + // Determine min, desired, fixed, and proportional sizes for the cols and // and calculate min/max table width PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth) @@ -599,94 +865,9 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth if (!originates || (1 == colSpan)) { continue; } - nscoord cellWidths[NUM_WIDTHS]; - cellWidths[MIN_CON] = cellFrame->GetPass1MaxElementSize().width; - cellWidths[DES_CON] = cellFrame->GetPass1DesiredSize().width; - cellWidths[FIX] = WIDTH_NOT_SET; - // see if the cell has a style width specified - const nsStylePosition* cellPosition; - cellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); - if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) { - // need to add padding into fixed width - const nsStyleSpacing* spacing; - cellFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct *&)spacing); - nsMargin paddingMargin; - spacing->CalcPaddingFor(cellFrame, paddingMargin); - nscoord padding = paddingMargin.left + paddingMargin.right; - cellWidths[FIX] = cellPosition->mWidth.GetCoordValue() + padding; - cellWidths[FIX] = PR_MAX(cellWidths[FIX], cellWidths[MIN_CON]); - } - // set MIN_ADJ, DES_ADJ, FIX_ADJ - nscoord spanCellSpacing = 0; for (PRInt32 widthX = 0; widthX < NUM_MAJOR_WIDTHS; widthX++) { - // skip DES_CON if there is a FIX since FIX is really the desired size - if ((DES_CON == widthX) && (cellWidths[FIX] > 0)) - continue; - nscoord spanTotal = 0; - nscoord divisor = 0; - PRInt32 spanX; - for (spanX = 0; spanX < colSpan; spanX++) { - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); - nscoord colWidth = PR_MAX(colFrame->GetWidth(widthX), - colFrame->GetWidth(widthX + NUM_MAJOR_WIDTHS)); - // need to get a contribution for every cell - colWidth = PR_MAX(colWidth, colFrame->GetMinWidth()); - spanTotal += colWidth; - // accumulate divisor - if (widthX == FIX) { - colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); - } - else if (widthX == DES_CON) { - nscoord fixWidth = colFrame->GetFixWidth(); - if (fixWidth > 0) { - colWidth = fixWidth; - } - } - else if (widthX == MIN_CON) { - colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); - } - divisor += colWidth; - if ((0 == widthX) && (spanX > 0) && (mTableFrame->GetNumCellsOriginatingInCol(colX + spanX) > 0)) { - spanCellSpacing += spacingX; - } - } - spanTotal -= spanCellSpacing; - nscoord cellWidth = cellWidths[widthX] - spanCellSpacing; - if ((cellWidth > 0) && !((widthX == MIN_CON) && (cellWidth <= spanTotal))) { - for (spanX = 0; spanX < colSpan; spanX++) { - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); - nscoord colWidth = PR_MAX(colFrame->GetWidth(widthX), - colFrame->GetWidth(widthX + NUM_MAJOR_WIDTHS)); - nscoord minWidth = colFrame->GetMinWidth(); - // accumulate numerator similarly to divisor - colWidth = PR_MAX(colWidth, colFrame->GetMinWidth()); - if (widthX == FIX) { - colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); - } - else if (widthX == DES_CON) { - nscoord fixWidth = colFrame->GetFixWidth(); - if (fixWidth > 0) { - colWidth = fixWidth; - } - //colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); - } - else if (widthX == MIN_CON) { - colWidth = PR_MAX(colWidth, colFrame->GetFixWidth()); - } - nscoord colAdjWidth = colFrame->GetWidth(widthX + NUM_MAJOR_WIDTHS); - nscoord newColAdjWidth = (0 >= spanTotal) - ? NSToCoordRound( ((float)cellWidth) / ((float)colSpan) ) - : NSToCoordRound( (((float)colWidth) / ((float)divisor)) * cellWidth); - if ((newColAdjWidth > colAdjWidth) && (newColAdjWidth > 0)) { - newColAdjWidth = PR_MAX(newColAdjWidth, minWidth); - if (newColAdjWidth > colFrame->GetWidth(widthX)) { - colFrame->SetWidth(widthX + NUM_MAJOR_WIDTHS, newColAdjWidth); - colFrame->SetConstrainingCell(cellFrame); // XXX is this right? - } - } - } - } + ComputeColspanWidths(widthX, cellFrame, colX, colSpan, PR_FALSE); } } } @@ -731,7 +912,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, nscoord fixWidthTotal = 0; // total of fixed widths of all cols float perTotal = 0.0f; // total of percentage constrained cols and/or cells in cols PRInt32 numPerCols = 0; // number of colums that have percentage constraints - nscoord desWidthTotal = 0; // total of desired widths of cols that don't have percentage constraints + nscoord prefWidthTotal = 0;// total of des/fix widths of cols that don't have percentage constraints basis = 0; // basis to use for percentages, computed considering percentage values for (colX = 0; colX < mNumCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); @@ -777,14 +958,19 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, } } basis = PR_MAX(basis, colBasis); + nscoord fixWidth = colFrame->GetFixWidth(); + fixWidthTotal += fixWidth; if (colBasis >= 0) { numPerCols++; } else { - desWidthTotal += colFrame->GetDesWidth(); + prefWidthTotal += (fixWidth > 0) ? fixWidth : colFrame->GetDesWidth(); } - fixWidthTotal += colFrame->GetFixWidth(); } // end for (colX .. + // If there are no pct cells or cols, there is nothing to do. + if (0 == numPerCols) { + return 0; + } // If there is only one col and it is % based, it won't affect anything if ((1 == mNumCols) && (mNumCols == numPerCols)) { return 0; @@ -792,11 +978,11 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, // compute a basis considering total percentages and the desired width of everything else if (perTotal < 1.0f) { if (perTotal > 0.0f) { - nscoord otherBasis = NSToCoordRound((float)desWidthTotal / (1.0f - perTotal)); + nscoord otherBasis = NSToCoordRound((float)prefWidthTotal / (1.0f - perTotal)); basis = PR_MAX(basis, otherBasis); } } - else if (desWidthTotal > 0) { // make the basis as big as possible + else if (prefWidthTotal > 0) { // make the basis as big as possible basis = aBasisIn; } @@ -936,9 +1122,13 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, nscoord minWidth = colFrame->GetMinWidth(); nscoord colWidth = PR_MAX(minWidth, colFrame->GetFixWidth()); colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); // XXX check this + //float colPctAdj = (0 == spanTotal) + // ? cellPctWidth / ((float) colSpan) + // : cellPct * ((float)colWidth) / (float)spanTotal; + float avail = (float)PR_MAX(cellPctWidth - colPctWidthTotal, 0); float colPctAdj = (0 == spanTotal) - ? cellPctWidth / ((float) colSpan) - : cellPct * ((float)colWidth) / (float)spanTotal; + ? avail / ((float) colSpan) + : (avail / (float)basis) * (((float)colWidth) / (float)spanTotal); if (colPctAdj > 0) { nscoord colPctAdjWidth = colFrame->GetWidth(PCT_ADJ); nscoord newColPctAdjWidth = NSToCoordRound(colPctAdj * (float)basis); @@ -1059,42 +1249,7 @@ PRBool BasicTableLayoutStrategy::RecomputeAdjMinIfNecessary() } if (cellSpansPercent) { - // recompute the ADJ_MIN width for every spanned col - nscoord spanTotal = 0; - nscoord divisor = 0; - nscoord spanCellSpacing = 0; - - for (spanX = 0; spanX < colSpan; spanX++) { - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); - nscoord colWidth = colFrame->GetWidth(MIN_CON); - spanTotal += colWidth; - colWidth = PR_MAX(colWidth, colFrame->GetWidth(FIX)); - colWidth = PR_MAX(colWidth, colFrame->GetWidth(PCT)); - divisor += colWidth; - if ((spanX > 0) && (mTableFrame->GetNumCellsOriginatingInCol(colX + spanX) > 0)) { - spanCellSpacing += spacingX; - } - } - spanTotal -= spanCellSpacing; - nscoord cellWidth = cellFrame->GetPass1MaxElementSize().width; - if ((cellWidth > 0) && (cellWidth > spanTotal)) { - for (spanX = 0; spanX < colSpan; spanX++) { - nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); - nscoord minWidth = colFrame->GetWidth(MIN_CON); - nscoord colWidth = PR_MAX(minWidth, colFrame->GetWidth(FIX)); - colWidth = PR_MAX(colWidth, colFrame->GetWidth(PCT)); - nscoord colAdjWidth = colFrame->GetWidth(MIN_ADJ); - nscoord newColAdjWidth = (0 >= spanTotal) - ? NSToCoordRound( ((float)cellWidth) / ((float)colSpan) ) - : NSToCoordRound( (((float)colWidth) / ((float)divisor)) * cellWidth); - if ((newColAdjWidth > colAdjWidth) && (newColAdjWidth > 0)) { - newColAdjWidth = PR_MAX(newColAdjWidth, minWidth); - if (newColAdjWidth > minWidth) { - colFrame->SetWidth(MIN_ADJ, newColAdjWidth); - } - } - } - } + ComputeColspanWidths(MIN_CON, cellFrame, colX, colSpan, PR_TRUE); } } } @@ -1234,8 +1389,6 @@ void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, } - - struct nsColInfo { nsColInfo(nsTableColFrame* aFrame, PRInt32 aIndex, @@ -1353,17 +1506,18 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, PRInt32 numConstrainedCols = 0; nscoord sumMaxConstraints = 0; + PRBool useAdj = PR_TRUE; PRInt32 colX; for (colX = 0; colX < mNumCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); - if (-1 != aAllocTypes[colX]) { - if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) { + if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame, useAdj)) { + if (-1 != aAllocTypes[colX]) { continue; } } numConstrainedCols++; nscoord width = colFrame->GetWidth(aWidthType); - if (DES_CON == aWidthType) { + if ((DES_CON == aWidthType) && useAdj) { width = PR_MAX(width, colFrame->GetWidth(DES_ADJ)); } else if (PCT == aWidthType) { @@ -1383,14 +1537,14 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, // set the col info entries for each constrained col for (colX = 0; colX < mNumCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); - if (-1 != aAllocTypes[colX]) { - if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) { + if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame, useAdj)) { + if (-1 != aAllocTypes[colX]) { continue; } } nscoord minWidth = mTableFrame->GetColumnWidth(colX); nscoord maxWidth = colFrame->GetWidth(aWidthType); - if (DES_CON == aWidthType) { + if ((DES_CON == aWidthType) && useAdj) { maxWidth = PR_MAX(maxWidth, colFrame->GetWidth(DES_ADJ)); } else if (PCT == aWidthType) { diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.h b/mozilla/layout/tables/BasicTableLayoutStrategy.h index 30aad97c318..53e3585fb64 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.h +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.h @@ -98,6 +98,39 @@ protected: */ virtual PRBool AssignPreliminaryColumnWidths(nscoord aComputedWidth); + /** + * Calculate the adjusted widths (min, desired, fixed, or pct) for a cell + * spanning multiple columns. + * @param aWidthIndex - the width to calculate (see nsTableColFrame.h for enums) + * @param aCellFrame - the frame of the cell with a colspan + * @param aColIndex - the column index of the cell in the table + * @param aColSpan - the colspan of the cell + * @param aConsiderPct - if true, consider columns that have pct widths and are spanned by the cell + */ + void ComputeColspanWidths(PRInt32 aWidthIndex, + nsTableCellFrame* aCellFrame, + PRInt32 aColIndex, + PRInt32 aColSpan, + PRBool aConsiderPct); + + /** + * main helper for above. For min width calculations, it can get called up to + * 3 times, 1st to let constrained (fix or pct) cols reach their limit, 2nd + * to let auto cols reach their limit and 3rd to spread any remainder among + * auto cols. If there are no auto cols then only constrained cols are considered. + * @param aCellWidth - the width of the cell + * @param aLimitType - value indicating which type of width is being targeted + * to reach a limit + * @return - true if the computation completed, false otherwise + */ + PRBool ComputeColspanWidths(PRInt32 aWidthIndex, + nsTableCellFrame* aCellFrame, + nscoord aCellWidth, + PRInt32 aColIndex, + PRInt32 aColSpan, + PRBool aConsiderPct, + PRInt32 aLimitType); + nscoord AssignPercentageColumnWidths(nscoord aBasis, PRBool aTableIsAutoWidth);