diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp index fcac1b2da49..78503a6aba0 100644 --- a/mozilla/layout/html/table/src/nsCellMap.cpp +++ b/mozilla/layout/html/table/src/nsCellMap.cpp @@ -30,11 +30,15 @@ static const PRBool gsDebug = PR_FALSE; nsCellMap::nsCellMap(int aRowCount, int aColCount) : mRowCount(0), mColCount(0), - mTotalRowCount(0) + mTotalRowCount(0), + mNumCollapsedRows(0), + mNumCollapsedCols(0) { mRows = nsnull; mColFrames = nsnull; mMinColSpans = nsnull; + mIsCollapsedRows = nsnull; + mIsCollapsedCols = nsnull; Reset(aRowCount, aColCount); } @@ -62,6 +66,16 @@ nsCellMap::~nsCellMap() // mMinColSpans may be null, it is only set for tables that need it if (nsnull != mMinColSpans) delete [] mMinColSpans; + if (nsnull != mIsCollapsedRows) { + delete [] mIsCollapsedRows; + mIsCollapsedRows = nsnull; + mNumCollapsedRows = 0; + } + if (nsnull != mIsCollapsedCols) { + delete [] mIsCollapsedCols; + mIsCollapsedCols = nsnull; + mNumCollapsedCols = 0; + } mRows = nsnull; mColFrames = nsnull; mMinColSpans = nsnull; @@ -97,19 +111,20 @@ void nsCellMap::Reset(int aRowCount, int aColCount) // if the number of rows has increased, add the extra rows PRInt32 newRows = aRowCount-mTotalRowCount; // (new row count) - (total row allocation) - for ( ; newRows>0; newRows--) - { + for ( ; newRows > 0; newRows--) { nsVoidArray *row; - if (0!=aColCount) + if (0 != aColCount) { row = new nsVoidArray(aColCount); - else + } else { row = new nsVoidArray(); + } mRows->AppendElement(row); } mRowCount = aRowCount; mTotalRowCount = PR_MAX(mTotalRowCount, mRowCount); mColCount = aColCount; + if (gsDebug) printf("leaving Reset with mRC=%d, mCC=%d, mTRC=%d\n", mRowCount, mColCount, mTotalRowCount); } @@ -413,5 +428,73 @@ PRBool nsCellMap::ColHasSpanningCells(PRInt32 aColIndex) return result; } +PRInt32 nsCellMap::GetNumCollapsedRows() +{ + return mNumCollapsedRows; +} +PRBool nsCellMap::IsRowCollapsedAt(PRInt32 aRow) +{ + if ((aRow >= 0) && (aRow < mTotalRowCount)) { + if (mIsCollapsedRows) { + return mIsCollapsedRows[aRow]; + } + } + return PR_FALSE; +} + +void nsCellMap::SetRowCollapsedAt(PRInt32 aRow, PRBool aValue) +{ + if ((aRow >= 0) && (aRow < mRowCount)) { + if (nsnull == mIsCollapsedRows) { + mIsCollapsedRows = new PRBool[mRowCount]; + for (PRInt32 i = 0; i < mRowCount; i++) { + mIsCollapsedRows[i] = PR_FALSE; + } + } + if (mIsCollapsedRows[aRow] != aValue) { + if (PR_TRUE == aValue) { + mNumCollapsedRows++; + } else { + mNumCollapsedRows--; + } + mIsCollapsedRows[aRow] = aValue; + } + } +} + +PRInt32 nsCellMap::GetNumCollapsedCols() +{ + return mNumCollapsedCols; +} + +PRBool nsCellMap::IsColCollapsedAt(PRInt32 aCol) +{ + if ((aCol >= 0) && (aCol < mColCount)) { + if (mIsCollapsedCols) { + return mIsCollapsedCols[aCol]; + } + } + return PR_FALSE; +} + +void nsCellMap::SetColCollapsedAt(PRInt32 aCol, PRBool aValue) +{ + if ((aCol >= 0) && (aCol < mColCount)) { + if (nsnull == mIsCollapsedCols) { + mIsCollapsedCols = new PRBool[mColCount]; + for (PRInt32 i = 0; i < mColCount; i++) { + mIsCollapsedCols[i] = PR_FALSE; + } + } + if (mIsCollapsedCols[aCol] != aValue) { + if (PR_TRUE == aValue) { + mNumCollapsedCols++; + } else { + mNumCollapsedCols--; + } + mIsCollapsedCols[aCol] = aValue; + } + } +} diff --git a/mozilla/layout/html/table/src/nsCellMap.h b/mozilla/layout/html/table/src/nsCellMap.h index 723536e3aad..800855c2f73 100644 --- a/mozilla/layout/html/table/src/nsCellMap.h +++ b/mozilla/layout/html/table/src/nsCellMap.h @@ -53,6 +53,14 @@ protected: /** a cache of the column frames, by col index */ nsVoidArray * mColFrames; + // an array of booleans where the ith element indicates if the ith row is collapsed + PRBool* mIsCollapsedRows; + PRInt32 mNumCollapsedRows; + + // an array of booleans where the ith element indicates if the ith col is collapsed + PRBool* mIsCollapsedCols; + PRInt32 mNumCollapsedCols; + /** the number of rows. mRows[0] - mRows[mRowCount-1] are non-null. */ PRInt32 mRowCount; @@ -86,6 +94,14 @@ public: /** assign aCellData to the cell at (aRow,aColumn) */ void SetCellAt(CellData *aCellData, PRInt32 aRow, PRInt32 aColumn); + PRInt32 GetNumCollapsedRows(); + PRBool IsRowCollapsedAt(PRInt32 aRow); + void SetRowCollapsedAt(PRInt32 aRow, PRBool aValue); + + PRInt32 GetNumCollapsedCols(); + PRBool IsColCollapsedAt(PRInt32 aCol); + void SetColCollapsedAt(PRInt32 aCol, PRBool aValue); + /** expand the CellMap to have aRowCount rows. The number of columns remains the same */ void GrowToRow(PRInt32 aRowCount); diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp index 3831cad5f78..dbd105b8f83 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp @@ -86,6 +86,7 @@ void nsTableCellFrame::InitCellFrame(PRInt32 aColIndex) mBorderEdges.mEdges[NS_SIDE_BOTTOM].AppendElement(borderToAdd); } } + mCollapseOffset = nsPoint(0,0); } } @@ -168,7 +169,21 @@ NS_METHOD nsTableCellFrame::Paint(nsIPresContext& aPresContext, aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); } + + // if the cell originates in a row and/or col that is collapsed, the bottom and/or + // right portion of the cell is painted by translating the rendering context. + // XXX What about content that can leak outside the cell? + PRBool clipState; + aRenderingContext.PushState(); + nsPoint offset = mCollapseOffset; + if ((0 != offset.x) || (0 != offset.y)) { + aRenderingContext.Translate(offset.x, offset.y); + } + aRenderingContext.SetClipRect(nsRect(-offset.x, -offset.y, mRect.width, mRect.height), + nsClipCombine_kIntersect, clipState); PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); + aRenderingContext.PopState(clipState); + return NS_OK; } @@ -1062,3 +1077,19 @@ nsTableCellFrame::GetFrameName(nsString& aResult) const { return MakeFrameName("TableCell", aResult); } + +void nsTableCellFrame::SetCollapseOffsetX(nscoord aXOffset) +{ + mCollapseOffset.x = aXOffset; +} + +void nsTableCellFrame::SetCollapseOffsetY(nscoord aYOffset) +{ + mCollapseOffset.y = aYOffset; +} + +nsPoint nsTableCellFrame::GetCollapseOffset() +{ + return mCollapseOffset; +} + diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.h b/mozilla/layout/html/table/src/nsTableCellFrame.h index 80a42c7c2b8..36467382139 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.h +++ b/mozilla/layout/html/table/src/nsTableCellFrame.h @@ -143,6 +143,11 @@ public: PRBool GetContentEmpty(); void SetContentEmpty(PRBool aContentEmpty); + // The collapse offset is (0,0) except for cells originating in a row/col which is collapsed + void SetCollapseOffsetX(nscoord aXOffset); + void SetCollapseOffsetY(nscoord aYOffset); + nsPoint GetCollapseOffset(); + protected: /** implement abstract method on nsHTMLContainerFrame */ virtual PRIntn GetSkipSides() const; @@ -211,6 +216,9 @@ protected: PRBool mIsContentEmpty; // PR_TRUE if the cell's contents take up no space //XXX: mIsContentEmpty should get yanked in favor of using free a bit on the frame base class // the FrameState slot (mState; GetFrameState/SetFrameState) + + nsPoint mCollapseOffset; + public: nsBorderEdges mBorderEdges; // one list of border segments for each side of the table frame // used only for the collapsing border model diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp index e748b1d1fd0..2394597fbfe 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp @@ -634,21 +634,22 @@ nsTableColFrame * nsTableColGroupFrame::GetNextColumn(nsIFrame *aChildFrame) nsTableColFrame * nsTableColGroupFrame::GetColumnAt (PRInt32 aColIndex) { nsTableColFrame *result = nsnull; - PRInt32 count=0; + PRInt32 count = 0; nsIFrame *childFrame = mFrames.FirstChild(); - while (nsnull!=childFrame) - { + + while (nsnull!=childFrame) { const nsStyleDisplay *childDisplay; childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == childDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_COLUMN == childDisplay->mDisplay) { nsTableColFrame *col = (nsTableColFrame *)childFrame; count += col->GetSpan(); - if (aColIndex<=count) + if (aColIndex<=count) { result = col; + } } childFrame->GetNextSibling(&childFrame); } + return result; } diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index 009989a2d54..d80d8ac0486 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -385,13 +385,14 @@ NS_IMETHODIMP nsTableFrame::DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFra { const nsStyleDisplay *rowDisplay; nextRow->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowDisplay); - if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) { rv = ((nsTableRowFrame *)nextRow)->InitChildren(); - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } } } + return rv; } @@ -947,74 +948,77 @@ NS_METHOD nsTableFrame::ReBuildCellMap() void nsTableFrame::DumpCellMap () { printf("dumping CellMap:\n"); - if (nsnull != mCellMap) - { + if (nsnull != mCellMap) { PRInt32 colIndex; PRInt32 rowCount = mCellMap->GetRowCount(); PRInt32 colCount = mCellMap->GetColCount(); printf("rowCount=%d, colCount=%d\n", rowCount, colCount); - for (PRInt32 rowIndex = 0; rowIndex < rowCount; rowIndex++) - { - if (gsDebug==PR_TRUE) - { printf("row %d", rowIndex); - printf(": "); - } - for (colIndex = 0; colIndex < colCount; colIndex++) - { - CellData *cd =mCellMap->GetCellAt(rowIndex, colIndex); - if (cd != nsnull) - { - if (cd->mCell != nsnull) - { - printf("C%d,%d ", rowIndex, colIndex); - printf(" "); - } - else - { - nsTableCellFrame *cell = cd->mRealCell->mCell; - nsTableRowFrame *row; - cell->GetParent((nsIFrame **)&row); - int rr = row->GetRowIndex (); + + for (PRInt32 rowIndex = 0; rowIndex < rowCount; rowIndex++) { + printf("row %d : ", rowIndex); + for (colIndex = 0; colIndex < colCount; colIndex++) { + CellData* cd = mCellMap->GetCellAt(rowIndex, colIndex); + if (cd != nsnull) { + if (cd->mCell != nsnull) { + printf("C%d,%d ", rowIndex, colIndex); + } else { + nsTableCellFrame* cell = cd->mRealCell->mCell; + nsTableRowFrame* row; + cell->GetParent((nsIFrame**)&row); + int rr = row->GetRowIndex(); int cc; cell->GetColIndex(cc); - printf("S%d,%d ", rr, cc); - if (cd->mOverlap != nsnull) - { + printf("S%d,%d ", rr, cc); + if (cd->mOverlap != nsnull){ cell = cd->mOverlap->mCell; nsTableRowFrame* row2; - cell->GetParent((nsIFrame **)&row2); - rr = row2->GetRowIndex (); - cell->GetColIndex (cc); + cell->GetParent((nsIFrame**)&row2); + rr = row2->GetRowIndex(); + cell->GetColIndex(cc); printf("O%d,%c ", rr, cc); - } - else - printf(" "); + } } - } - else + } else { printf("---- "); + } } PRBool spanners = RowHasSpanningCells(rowIndex); PRBool spannedInto = RowIsSpannedInto(rowIndex); printf (" spanners=%s spannedInto=%s\n", spanners?"T":"F", spannedInto?"T":"F"); } + + // output info mapping Ci,j to cell address + PRInt32 cellCount = 0; + for (PRInt32 rIndex = 0; rIndex < rowCount; rIndex++) { + for (colIndex = 0; colIndex < colCount; colIndex++) { + CellData* cd = mCellMap->GetCellAt(rIndex, colIndex); + if (cd != nsnull) { + if (cd->mCell != nsnull) { + printf("C%d,%d=%p ", rIndex, colIndex, cd->mCell); + cellCount++; + } + } + if (0 == (cellCount % 4)) { + printf("\n"); + } + } + } + // output colspan info - for (colIndex=0; colIndexGetColumnFrame(colIndex); printf ("col index %d has frame=%p\n", colIndex, colFrame); } - } - else + } else { printf ("[nsnull]"); + } } #endif @@ -2636,7 +2640,10 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext& aPresContext, aDesiredSize.width = ComputeDesiredWidth(aReflowState); nscoord defaultHeight = state.y + borderPadding.top + borderPadding.bottom; aDesiredSize.height = ComputeDesiredHeight(aPresContext, aReflowState, defaultHeight); - + + AdjustForCollapsingRows(aPresContext, aDesiredSize.height); + AdjustForCollapsingCols(aPresContext, aDesiredSize.width); + // once horizontal borders are computed and all row heights are set, // we need to fix up length of vertical edges // XXX need to figure start row and end row correctly @@ -2651,6 +2658,224 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext& aPresContext, } +// collapsing row groups, rows, col groups and cols are accounted for after both passes of +// reflow so that it has no effect on the calculations of reflow. +NS_METHOD nsTableFrame::AdjustForCollapsingRows(nsIPresContext& aPresContext, + nscoord& aHeight) +{ + // determine which row groups and rows are collapsed + nsIFrame* childFrame; + FirstChild(nsnull, &childFrame); + while (nsnull != childFrame) { + const nsStyleDisplay* groupDisplay; + childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)groupDisplay)); + if (IsRowGroup(groupDisplay->mDisplay)) { + PRBool groupIsCollapsed = (NS_STYLE_VISIBILITY_COLLAPSE == groupDisplay->mVisible); + + nsTableRowFrame* rowFrame = nsnull; + childFrame->FirstChild(nsnull, (nsIFrame**)&rowFrame); + PRInt32 rowX = 0; + while (nsnull != rowFrame) { + const nsStyleDisplay *rowDisplay; + rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { + if (groupIsCollapsed || (NS_STYLE_VISIBILITY_COLLAPSE == rowDisplay->mVisible)) { + mCellMap->SetRowCollapsedAt(rowX, PR_TRUE); + } + } + rowFrame->GetNextSibling((nsIFrame**)&rowFrame); + rowX++; + } + } + childFrame->GetNextSibling(&childFrame); + } + + if (mCellMap->GetNumCollapsedRows() <= 0) { + return NS_OK; // no collapsed rows, we're done + } + + // collapse the rows and/or row groups + nsIFrame* groupFrame = mFrames.FirstChild(); + nscoord yGroupOffset = 0; // total offset among rows within a single row group + nscoord yTotalOffset = 0; // total offset among all rows in all row groups + PRInt32 rowX = 0; + PRBool collapseGroup; + + while (nsnull != groupFrame) { + const nsStyleDisplay* groupDisplay; + groupFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)groupDisplay)); + if (IsRowGroup(groupDisplay->mDisplay)) { + collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupDisplay->mVisible); + nsIFrame* rowFrame; + groupFrame->FirstChild(nsnull, &rowFrame); + + while (nsnull != rowFrame) { + const nsStyleDisplay* rowDisplay; + rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { + nsRect rowRect; + rowFrame->GetRect(rowRect); + if (collapseGroup || (NS_STYLE_VISIBILITY_COLLAPSE == rowDisplay->mVisible)) { + yGroupOffset += rowRect.height; + rowRect.height = 0; + rowFrame->SetRect(rowRect); + nsIFrame* cellFrame; + rowFrame->FirstChild(nsnull, &cellFrame); + while (nsnull != cellFrame) { + const nsStyleDisplay* cellDisplay; + cellFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)cellDisplay)); + if (NS_STYLE_DISPLAY_TABLE_CELL == cellDisplay->mDisplay) { + nsTableCellFrame* cFrame = (nsTableCellFrame*)cellFrame; + nsRect cRect; + cFrame->GetRect(cRect); + cRect.height -= rowRect.height; + cFrame->SetCollapseOffsetY(-yGroupOffset); + cFrame->SetRect(cRect); + } + cellFrame->GetNextSibling(&cellFrame); + } + // check if a cell above spans into here + //if (!collapseGroup) { + PRInt32 numCols = mCellMap->GetColCount(); + nsTableCellFrame* lastCell = nsnull; + for (int colX = 0; colX < numCols; colX++) { + CellData* cellData = mCellMap->GetCellAt(rowX, colX); + if (cellData && !cellData->mCell) { // a cell above is spanning into here + // adjust the real cell's rect only once + nsTableCellFrame* realCell = cellData->mRealCell->mCell; + if (realCell != lastCell) { + nsRect realRect; + realCell->GetRect(realRect); + realRect.height -= rowRect.height; + realCell->SetRect(realRect); + } + lastCell = realCell; + } + } + //} + } else { // row is not collapsed but needs to be adjusted by those that are + rowRect.y -= yGroupOffset; + rowFrame->SetRect(rowRect); + } + rowX++; + } + rowFrame->GetNextSibling(&rowFrame); + } // end row frame while + } + nsRect groupRect; + groupFrame->GetRect(groupRect); + groupRect.height -= yGroupOffset; + groupRect.y -= yTotalOffset; + groupFrame->SetRect(groupRect); + + yTotalOffset += yGroupOffset; + yGroupOffset = 0; + groupFrame->GetNextSibling(&groupFrame); + } // end group frame while + + aHeight -= yTotalOffset; + + return NS_OK; +} + +NS_METHOD nsTableFrame::AdjustForCollapsingCols(nsIPresContext& aPresContext, + nscoord& aWidth) +{ + // determine which col groups and cols are collapsed + nsIFrame* childFrame = mColGroups.FirstChild(); + while (nsnull != childFrame) { + const nsStyleDisplay* groupDisplay; + GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)groupDisplay)); + PRBool groupIsCollapsed = (NS_STYLE_VISIBILITY_COLLAPSE == groupDisplay->mVisible); + + nsTableColFrame* colFrame = nsnull; + childFrame->FirstChild(nsnull, (nsIFrame**)&colFrame); + PRInt32 colX = 0; + while (nsnull != colFrame) { + const nsStyleDisplay *colDisplay; + colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) { + if (groupIsCollapsed || (NS_STYLE_VISIBILITY_COLLAPSE == colDisplay->mVisible)) { + mCellMap->SetColCollapsedAt(colX, PR_TRUE); + } + } + colFrame->GetNextSibling((nsIFrame**)&colFrame); + colX++; + } + childFrame->GetNextSibling(&childFrame); + } + + if (mCellMap->GetNumCollapsedCols() <= 0) { + return NS_OK; // no collapsed cols, we're done + } + + // collapse the cols and/or col groups + PRInt32 numRows = mCellMap->GetRowCount(); + nsIFrame* groupFrame = mColGroups.FirstChild(); + nscoord cellSpacingX = GetCellSpacingX(); + nscoord xOffset = 0; + PRInt32 colX = 0; + while (nsnull != groupFrame) { + const nsStyleDisplay* groupDisplay; + groupFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)groupDisplay)); + PRBool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupDisplay->mVisible); + nsRect zeroRect(0, 0, 0, 0); + nsIFrame* colFrame; + groupFrame->FirstChild(nsnull, &colFrame); + while (nsnull != colFrame) { + const nsStyleDisplay* colDisplay; + colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) { + PRBool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colDisplay->mVisible); + PRInt32 colSpan = ((nsTableColFrame*)colFrame)->GetSpan(); + for (PRInt32 spanX = 0; spanX < colSpan; spanX++) { + PRInt32 colWidth = GetColumnWidth(colX+spanX); + if (collapseGroup || collapseCol) { + xOffset += colWidth + cellSpacingX; + } + nsTableCellFrame* lastCell = nsnull; + nsTableCellFrame* cellFrame = nsnull; + for (PRInt32 rowX = 0; rowX < numRows; rowX++) { + CellData* cellData = mCellMap->GetCellAt(rowX, colX+spanX); + nsRect cellRect; + if (cellData) { + cellFrame = cellData->mCell; + if (cellFrame) { // the cell originates at (rowX, colX) + cellFrame->GetRect(cellRect); + if (collapseGroup || collapseCol) { + if (lastCell != cellFrame) { // do it only once if there is a row span + cellRect.width -= colWidth; + cellFrame->SetCollapseOffsetX(-xOffset); + } + } else { // the cell is not in a collapsed col but needs to move + cellRect.x -= xOffset; + } + cellFrame->SetRect(cellRect); + // if the cell does not originate at (rowX, colX), adjust the real cells width + } else if (collapseGroup || collapseCol) { + cellFrame = cellData->mRealCell->mCell; + if ((cellFrame) && (lastCell != cellFrame)) { + cellFrame->GetRect(cellRect); + cellRect.width -= colWidth + cellSpacingX; + cellFrame->SetRect(cellRect); + } + } + } + lastCell = cellFrame; + } + } + colX += colSpan; + } + colFrame->GetNextSibling(&colFrame); + } // inner while + groupFrame->GetNextSibling(&groupFrame); + } // outer while + + aWidth -= xOffset; + + return NS_OK; +} + NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h index bc3762a9690..c3982d83d9c 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.h +++ b/mozilla/layout/html/table/src/nsTableFrame.h @@ -560,6 +560,12 @@ protected: InnerTableReflowState& aReflowState, nsIFrame* aKidFrame, nscoord aDeltaY); + + NS_METHOD AdjustForCollapsingRows(nsIPresContext& aPresContext, + nscoord& aHeight); + + NS_METHOD AdjustForCollapsingCols(nsIPresContext& aPresContext, + nscoord& aWidth); // end incremental reflow methods /** return the desired width of this table accounting for the current diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index 20e5b752f82..6d7df14e439 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -1421,16 +1421,6 @@ nsTableRowFrame::Reflow(nsIPresContext& aPresContext, break; } - // check the visibility in the final pass. If it is collapse, set our desired size to 0 - if (nsTableFrame::IsFinalPass(aReflowState)) { - const nsStyleDisplay *display; - GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - if (NS_STYLE_VISIBILITY_COLLAPSE == display->mVisible) { - aDesiredSize.width = 0; - aDesiredSize.height = 0; - } - } - // XXX TROY #if 0 diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index b1185b488af..a0cad0ea58b 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -643,8 +643,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, { const nsStyleDisplay *childDisplay; rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if ((NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) && - (NS_STYLE_VISIBILITY_COLLAPSE != childDisplay->mVisible)) + if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) { // get the height of the tallest cell in the row (excluding cells that span rows) nscoord maxCellHeight = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); @@ -1031,16 +1030,6 @@ nsTableRowGroupFrame::Reflow(nsIPresContext& aPresContext, } } - // check the visibility in the final pass. If it is collapse, set our desired size to 0 - if (nsTableFrame::IsFinalPass(aReflowState)) { - const nsStyleDisplay *display; - GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - if (NS_STYLE_VISIBILITY_COLLAPSE == display->mVisible) { - aDesiredSize.width = 0; - aDesiredSize.height = 0; - } - } - if (gsDebug==PR_TRUE) { if (nsnull!=aDesiredSize.maxElementSize) diff --git a/mozilla/layout/tables/nsCellMap.cpp b/mozilla/layout/tables/nsCellMap.cpp index fcac1b2da49..78503a6aba0 100644 --- a/mozilla/layout/tables/nsCellMap.cpp +++ b/mozilla/layout/tables/nsCellMap.cpp @@ -30,11 +30,15 @@ static const PRBool gsDebug = PR_FALSE; nsCellMap::nsCellMap(int aRowCount, int aColCount) : mRowCount(0), mColCount(0), - mTotalRowCount(0) + mTotalRowCount(0), + mNumCollapsedRows(0), + mNumCollapsedCols(0) { mRows = nsnull; mColFrames = nsnull; mMinColSpans = nsnull; + mIsCollapsedRows = nsnull; + mIsCollapsedCols = nsnull; Reset(aRowCount, aColCount); } @@ -62,6 +66,16 @@ nsCellMap::~nsCellMap() // mMinColSpans may be null, it is only set for tables that need it if (nsnull != mMinColSpans) delete [] mMinColSpans; + if (nsnull != mIsCollapsedRows) { + delete [] mIsCollapsedRows; + mIsCollapsedRows = nsnull; + mNumCollapsedRows = 0; + } + if (nsnull != mIsCollapsedCols) { + delete [] mIsCollapsedCols; + mIsCollapsedCols = nsnull; + mNumCollapsedCols = 0; + } mRows = nsnull; mColFrames = nsnull; mMinColSpans = nsnull; @@ -97,19 +111,20 @@ void nsCellMap::Reset(int aRowCount, int aColCount) // if the number of rows has increased, add the extra rows PRInt32 newRows = aRowCount-mTotalRowCount; // (new row count) - (total row allocation) - for ( ; newRows>0; newRows--) - { + for ( ; newRows > 0; newRows--) { nsVoidArray *row; - if (0!=aColCount) + if (0 != aColCount) { row = new nsVoidArray(aColCount); - else + } else { row = new nsVoidArray(); + } mRows->AppendElement(row); } mRowCount = aRowCount; mTotalRowCount = PR_MAX(mTotalRowCount, mRowCount); mColCount = aColCount; + if (gsDebug) printf("leaving Reset with mRC=%d, mCC=%d, mTRC=%d\n", mRowCount, mColCount, mTotalRowCount); } @@ -413,5 +428,73 @@ PRBool nsCellMap::ColHasSpanningCells(PRInt32 aColIndex) return result; } +PRInt32 nsCellMap::GetNumCollapsedRows() +{ + return mNumCollapsedRows; +} +PRBool nsCellMap::IsRowCollapsedAt(PRInt32 aRow) +{ + if ((aRow >= 0) && (aRow < mTotalRowCount)) { + if (mIsCollapsedRows) { + return mIsCollapsedRows[aRow]; + } + } + return PR_FALSE; +} + +void nsCellMap::SetRowCollapsedAt(PRInt32 aRow, PRBool aValue) +{ + if ((aRow >= 0) && (aRow < mRowCount)) { + if (nsnull == mIsCollapsedRows) { + mIsCollapsedRows = new PRBool[mRowCount]; + for (PRInt32 i = 0; i < mRowCount; i++) { + mIsCollapsedRows[i] = PR_FALSE; + } + } + if (mIsCollapsedRows[aRow] != aValue) { + if (PR_TRUE == aValue) { + mNumCollapsedRows++; + } else { + mNumCollapsedRows--; + } + mIsCollapsedRows[aRow] = aValue; + } + } +} + +PRInt32 nsCellMap::GetNumCollapsedCols() +{ + return mNumCollapsedCols; +} + +PRBool nsCellMap::IsColCollapsedAt(PRInt32 aCol) +{ + if ((aCol >= 0) && (aCol < mColCount)) { + if (mIsCollapsedCols) { + return mIsCollapsedCols[aCol]; + } + } + return PR_FALSE; +} + +void nsCellMap::SetColCollapsedAt(PRInt32 aCol, PRBool aValue) +{ + if ((aCol >= 0) && (aCol < mColCount)) { + if (nsnull == mIsCollapsedCols) { + mIsCollapsedCols = new PRBool[mColCount]; + for (PRInt32 i = 0; i < mColCount; i++) { + mIsCollapsedCols[i] = PR_FALSE; + } + } + if (mIsCollapsedCols[aCol] != aValue) { + if (PR_TRUE == aValue) { + mNumCollapsedCols++; + } else { + mNumCollapsedCols--; + } + mIsCollapsedCols[aCol] = aValue; + } + } +} diff --git a/mozilla/layout/tables/nsCellMap.h b/mozilla/layout/tables/nsCellMap.h index 723536e3aad..800855c2f73 100644 --- a/mozilla/layout/tables/nsCellMap.h +++ b/mozilla/layout/tables/nsCellMap.h @@ -53,6 +53,14 @@ protected: /** a cache of the column frames, by col index */ nsVoidArray * mColFrames; + // an array of booleans where the ith element indicates if the ith row is collapsed + PRBool* mIsCollapsedRows; + PRInt32 mNumCollapsedRows; + + // an array of booleans where the ith element indicates if the ith col is collapsed + PRBool* mIsCollapsedCols; + PRInt32 mNumCollapsedCols; + /** the number of rows. mRows[0] - mRows[mRowCount-1] are non-null. */ PRInt32 mRowCount; @@ -86,6 +94,14 @@ public: /** assign aCellData to the cell at (aRow,aColumn) */ void SetCellAt(CellData *aCellData, PRInt32 aRow, PRInt32 aColumn); + PRInt32 GetNumCollapsedRows(); + PRBool IsRowCollapsedAt(PRInt32 aRow); + void SetRowCollapsedAt(PRInt32 aRow, PRBool aValue); + + PRInt32 GetNumCollapsedCols(); + PRBool IsColCollapsedAt(PRInt32 aCol); + void SetColCollapsedAt(PRInt32 aCol, PRBool aValue); + /** expand the CellMap to have aRowCount rows. The number of columns remains the same */ void GrowToRow(PRInt32 aRowCount); diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp index 3831cad5f78..dbd105b8f83 100644 --- a/mozilla/layout/tables/nsTableCellFrame.cpp +++ b/mozilla/layout/tables/nsTableCellFrame.cpp @@ -86,6 +86,7 @@ void nsTableCellFrame::InitCellFrame(PRInt32 aColIndex) mBorderEdges.mEdges[NS_SIDE_BOTTOM].AppendElement(borderToAdd); } } + mCollapseOffset = nsPoint(0,0); } } @@ -168,7 +169,21 @@ NS_METHOD nsTableCellFrame::Paint(nsIPresContext& aPresContext, aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); } + + // if the cell originates in a row and/or col that is collapsed, the bottom and/or + // right portion of the cell is painted by translating the rendering context. + // XXX What about content that can leak outside the cell? + PRBool clipState; + aRenderingContext.PushState(); + nsPoint offset = mCollapseOffset; + if ((0 != offset.x) || (0 != offset.y)) { + aRenderingContext.Translate(offset.x, offset.y); + } + aRenderingContext.SetClipRect(nsRect(-offset.x, -offset.y, mRect.width, mRect.height), + nsClipCombine_kIntersect, clipState); PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); + aRenderingContext.PopState(clipState); + return NS_OK; } @@ -1062,3 +1077,19 @@ nsTableCellFrame::GetFrameName(nsString& aResult) const { return MakeFrameName("TableCell", aResult); } + +void nsTableCellFrame::SetCollapseOffsetX(nscoord aXOffset) +{ + mCollapseOffset.x = aXOffset; +} + +void nsTableCellFrame::SetCollapseOffsetY(nscoord aYOffset) +{ + mCollapseOffset.y = aYOffset; +} + +nsPoint nsTableCellFrame::GetCollapseOffset() +{ + return mCollapseOffset; +} + diff --git a/mozilla/layout/tables/nsTableCellFrame.h b/mozilla/layout/tables/nsTableCellFrame.h index 80a42c7c2b8..36467382139 100644 --- a/mozilla/layout/tables/nsTableCellFrame.h +++ b/mozilla/layout/tables/nsTableCellFrame.h @@ -143,6 +143,11 @@ public: PRBool GetContentEmpty(); void SetContentEmpty(PRBool aContentEmpty); + // The collapse offset is (0,0) except for cells originating in a row/col which is collapsed + void SetCollapseOffsetX(nscoord aXOffset); + void SetCollapseOffsetY(nscoord aYOffset); + nsPoint GetCollapseOffset(); + protected: /** implement abstract method on nsHTMLContainerFrame */ virtual PRIntn GetSkipSides() const; @@ -211,6 +216,9 @@ protected: PRBool mIsContentEmpty; // PR_TRUE if the cell's contents take up no space //XXX: mIsContentEmpty should get yanked in favor of using free a bit on the frame base class // the FrameState slot (mState; GetFrameState/SetFrameState) + + nsPoint mCollapseOffset; + public: nsBorderEdges mBorderEdges; // one list of border segments for each side of the table frame // used only for the collapsing border model diff --git a/mozilla/layout/tables/nsTableColGroupFrame.cpp b/mozilla/layout/tables/nsTableColGroupFrame.cpp index e748b1d1fd0..2394597fbfe 100644 --- a/mozilla/layout/tables/nsTableColGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableColGroupFrame.cpp @@ -634,21 +634,22 @@ nsTableColFrame * nsTableColGroupFrame::GetNextColumn(nsIFrame *aChildFrame) nsTableColFrame * nsTableColGroupFrame::GetColumnAt (PRInt32 aColIndex) { nsTableColFrame *result = nsnull; - PRInt32 count=0; + PRInt32 count = 0; nsIFrame *childFrame = mFrames.FirstChild(); - while (nsnull!=childFrame) - { + + while (nsnull!=childFrame) { const nsStyleDisplay *childDisplay; childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == childDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_COLUMN == childDisplay->mDisplay) { nsTableColFrame *col = (nsTableColFrame *)childFrame; count += col->GetSpan(); - if (aColIndex<=count) + if (aColIndex<=count) { result = col; + } } childFrame->GetNextSibling(&childFrame); } + return result; } diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index 009989a2d54..d80d8ac0486 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -385,13 +385,14 @@ NS_IMETHODIMP nsTableFrame::DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFra { const nsStyleDisplay *rowDisplay; nextRow->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowDisplay); - if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) { rv = ((nsTableRowFrame *)nextRow)->InitChildren(); - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } } } + return rv; } @@ -947,74 +948,77 @@ NS_METHOD nsTableFrame::ReBuildCellMap() void nsTableFrame::DumpCellMap () { printf("dumping CellMap:\n"); - if (nsnull != mCellMap) - { + if (nsnull != mCellMap) { PRInt32 colIndex; PRInt32 rowCount = mCellMap->GetRowCount(); PRInt32 colCount = mCellMap->GetColCount(); printf("rowCount=%d, colCount=%d\n", rowCount, colCount); - for (PRInt32 rowIndex = 0; rowIndex < rowCount; rowIndex++) - { - if (gsDebug==PR_TRUE) - { printf("row %d", rowIndex); - printf(": "); - } - for (colIndex = 0; colIndex < colCount; colIndex++) - { - CellData *cd =mCellMap->GetCellAt(rowIndex, colIndex); - if (cd != nsnull) - { - if (cd->mCell != nsnull) - { - printf("C%d,%d ", rowIndex, colIndex); - printf(" "); - } - else - { - nsTableCellFrame *cell = cd->mRealCell->mCell; - nsTableRowFrame *row; - cell->GetParent((nsIFrame **)&row); - int rr = row->GetRowIndex (); + + for (PRInt32 rowIndex = 0; rowIndex < rowCount; rowIndex++) { + printf("row %d : ", rowIndex); + for (colIndex = 0; colIndex < colCount; colIndex++) { + CellData* cd = mCellMap->GetCellAt(rowIndex, colIndex); + if (cd != nsnull) { + if (cd->mCell != nsnull) { + printf("C%d,%d ", rowIndex, colIndex); + } else { + nsTableCellFrame* cell = cd->mRealCell->mCell; + nsTableRowFrame* row; + cell->GetParent((nsIFrame**)&row); + int rr = row->GetRowIndex(); int cc; cell->GetColIndex(cc); - printf("S%d,%d ", rr, cc); - if (cd->mOverlap != nsnull) - { + printf("S%d,%d ", rr, cc); + if (cd->mOverlap != nsnull){ cell = cd->mOverlap->mCell; nsTableRowFrame* row2; - cell->GetParent((nsIFrame **)&row2); - rr = row2->GetRowIndex (); - cell->GetColIndex (cc); + cell->GetParent((nsIFrame**)&row2); + rr = row2->GetRowIndex(); + cell->GetColIndex(cc); printf("O%d,%c ", rr, cc); - } - else - printf(" "); + } } - } - else + } else { printf("---- "); + } } PRBool spanners = RowHasSpanningCells(rowIndex); PRBool spannedInto = RowIsSpannedInto(rowIndex); printf (" spanners=%s spannedInto=%s\n", spanners?"T":"F", spannedInto?"T":"F"); } + + // output info mapping Ci,j to cell address + PRInt32 cellCount = 0; + for (PRInt32 rIndex = 0; rIndex < rowCount; rIndex++) { + for (colIndex = 0; colIndex < colCount; colIndex++) { + CellData* cd = mCellMap->GetCellAt(rIndex, colIndex); + if (cd != nsnull) { + if (cd->mCell != nsnull) { + printf("C%d,%d=%p ", rIndex, colIndex, cd->mCell); + cellCount++; + } + } + if (0 == (cellCount % 4)) { + printf("\n"); + } + } + } + // output colspan info - for (colIndex=0; colIndexGetColumnFrame(colIndex); printf ("col index %d has frame=%p\n", colIndex, colFrame); } - } - else + } else { printf ("[nsnull]"); + } } #endif @@ -2636,7 +2640,10 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext& aPresContext, aDesiredSize.width = ComputeDesiredWidth(aReflowState); nscoord defaultHeight = state.y + borderPadding.top + borderPadding.bottom; aDesiredSize.height = ComputeDesiredHeight(aPresContext, aReflowState, defaultHeight); - + + AdjustForCollapsingRows(aPresContext, aDesiredSize.height); + AdjustForCollapsingCols(aPresContext, aDesiredSize.width); + // once horizontal borders are computed and all row heights are set, // we need to fix up length of vertical edges // XXX need to figure start row and end row correctly @@ -2651,6 +2658,224 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext& aPresContext, } +// collapsing row groups, rows, col groups and cols are accounted for after both passes of +// reflow so that it has no effect on the calculations of reflow. +NS_METHOD nsTableFrame::AdjustForCollapsingRows(nsIPresContext& aPresContext, + nscoord& aHeight) +{ + // determine which row groups and rows are collapsed + nsIFrame* childFrame; + FirstChild(nsnull, &childFrame); + while (nsnull != childFrame) { + const nsStyleDisplay* groupDisplay; + childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)groupDisplay)); + if (IsRowGroup(groupDisplay->mDisplay)) { + PRBool groupIsCollapsed = (NS_STYLE_VISIBILITY_COLLAPSE == groupDisplay->mVisible); + + nsTableRowFrame* rowFrame = nsnull; + childFrame->FirstChild(nsnull, (nsIFrame**)&rowFrame); + PRInt32 rowX = 0; + while (nsnull != rowFrame) { + const nsStyleDisplay *rowDisplay; + rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { + if (groupIsCollapsed || (NS_STYLE_VISIBILITY_COLLAPSE == rowDisplay->mVisible)) { + mCellMap->SetRowCollapsedAt(rowX, PR_TRUE); + } + } + rowFrame->GetNextSibling((nsIFrame**)&rowFrame); + rowX++; + } + } + childFrame->GetNextSibling(&childFrame); + } + + if (mCellMap->GetNumCollapsedRows() <= 0) { + return NS_OK; // no collapsed rows, we're done + } + + // collapse the rows and/or row groups + nsIFrame* groupFrame = mFrames.FirstChild(); + nscoord yGroupOffset = 0; // total offset among rows within a single row group + nscoord yTotalOffset = 0; // total offset among all rows in all row groups + PRInt32 rowX = 0; + PRBool collapseGroup; + + while (nsnull != groupFrame) { + const nsStyleDisplay* groupDisplay; + groupFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)groupDisplay)); + if (IsRowGroup(groupDisplay->mDisplay)) { + collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupDisplay->mVisible); + nsIFrame* rowFrame; + groupFrame->FirstChild(nsnull, &rowFrame); + + while (nsnull != rowFrame) { + const nsStyleDisplay* rowDisplay; + rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { + nsRect rowRect; + rowFrame->GetRect(rowRect); + if (collapseGroup || (NS_STYLE_VISIBILITY_COLLAPSE == rowDisplay->mVisible)) { + yGroupOffset += rowRect.height; + rowRect.height = 0; + rowFrame->SetRect(rowRect); + nsIFrame* cellFrame; + rowFrame->FirstChild(nsnull, &cellFrame); + while (nsnull != cellFrame) { + const nsStyleDisplay* cellDisplay; + cellFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)cellDisplay)); + if (NS_STYLE_DISPLAY_TABLE_CELL == cellDisplay->mDisplay) { + nsTableCellFrame* cFrame = (nsTableCellFrame*)cellFrame; + nsRect cRect; + cFrame->GetRect(cRect); + cRect.height -= rowRect.height; + cFrame->SetCollapseOffsetY(-yGroupOffset); + cFrame->SetRect(cRect); + } + cellFrame->GetNextSibling(&cellFrame); + } + // check if a cell above spans into here + //if (!collapseGroup) { + PRInt32 numCols = mCellMap->GetColCount(); + nsTableCellFrame* lastCell = nsnull; + for (int colX = 0; colX < numCols; colX++) { + CellData* cellData = mCellMap->GetCellAt(rowX, colX); + if (cellData && !cellData->mCell) { // a cell above is spanning into here + // adjust the real cell's rect only once + nsTableCellFrame* realCell = cellData->mRealCell->mCell; + if (realCell != lastCell) { + nsRect realRect; + realCell->GetRect(realRect); + realRect.height -= rowRect.height; + realCell->SetRect(realRect); + } + lastCell = realCell; + } + } + //} + } else { // row is not collapsed but needs to be adjusted by those that are + rowRect.y -= yGroupOffset; + rowFrame->SetRect(rowRect); + } + rowX++; + } + rowFrame->GetNextSibling(&rowFrame); + } // end row frame while + } + nsRect groupRect; + groupFrame->GetRect(groupRect); + groupRect.height -= yGroupOffset; + groupRect.y -= yTotalOffset; + groupFrame->SetRect(groupRect); + + yTotalOffset += yGroupOffset; + yGroupOffset = 0; + groupFrame->GetNextSibling(&groupFrame); + } // end group frame while + + aHeight -= yTotalOffset; + + return NS_OK; +} + +NS_METHOD nsTableFrame::AdjustForCollapsingCols(nsIPresContext& aPresContext, + nscoord& aWidth) +{ + // determine which col groups and cols are collapsed + nsIFrame* childFrame = mColGroups.FirstChild(); + while (nsnull != childFrame) { + const nsStyleDisplay* groupDisplay; + GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)groupDisplay)); + PRBool groupIsCollapsed = (NS_STYLE_VISIBILITY_COLLAPSE == groupDisplay->mVisible); + + nsTableColFrame* colFrame = nsnull; + childFrame->FirstChild(nsnull, (nsIFrame**)&colFrame); + PRInt32 colX = 0; + while (nsnull != colFrame) { + const nsStyleDisplay *colDisplay; + colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) { + if (groupIsCollapsed || (NS_STYLE_VISIBILITY_COLLAPSE == colDisplay->mVisible)) { + mCellMap->SetColCollapsedAt(colX, PR_TRUE); + } + } + colFrame->GetNextSibling((nsIFrame**)&colFrame); + colX++; + } + childFrame->GetNextSibling(&childFrame); + } + + if (mCellMap->GetNumCollapsedCols() <= 0) { + return NS_OK; // no collapsed cols, we're done + } + + // collapse the cols and/or col groups + PRInt32 numRows = mCellMap->GetRowCount(); + nsIFrame* groupFrame = mColGroups.FirstChild(); + nscoord cellSpacingX = GetCellSpacingX(); + nscoord xOffset = 0; + PRInt32 colX = 0; + while (nsnull != groupFrame) { + const nsStyleDisplay* groupDisplay; + groupFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)groupDisplay)); + PRBool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupDisplay->mVisible); + nsRect zeroRect(0, 0, 0, 0); + nsIFrame* colFrame; + groupFrame->FirstChild(nsnull, &colFrame); + while (nsnull != colFrame) { + const nsStyleDisplay* colDisplay; + colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) { + PRBool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colDisplay->mVisible); + PRInt32 colSpan = ((nsTableColFrame*)colFrame)->GetSpan(); + for (PRInt32 spanX = 0; spanX < colSpan; spanX++) { + PRInt32 colWidth = GetColumnWidth(colX+spanX); + if (collapseGroup || collapseCol) { + xOffset += colWidth + cellSpacingX; + } + nsTableCellFrame* lastCell = nsnull; + nsTableCellFrame* cellFrame = nsnull; + for (PRInt32 rowX = 0; rowX < numRows; rowX++) { + CellData* cellData = mCellMap->GetCellAt(rowX, colX+spanX); + nsRect cellRect; + if (cellData) { + cellFrame = cellData->mCell; + if (cellFrame) { // the cell originates at (rowX, colX) + cellFrame->GetRect(cellRect); + if (collapseGroup || collapseCol) { + if (lastCell != cellFrame) { // do it only once if there is a row span + cellRect.width -= colWidth; + cellFrame->SetCollapseOffsetX(-xOffset); + } + } else { // the cell is not in a collapsed col but needs to move + cellRect.x -= xOffset; + } + cellFrame->SetRect(cellRect); + // if the cell does not originate at (rowX, colX), adjust the real cells width + } else if (collapseGroup || collapseCol) { + cellFrame = cellData->mRealCell->mCell; + if ((cellFrame) && (lastCell != cellFrame)) { + cellFrame->GetRect(cellRect); + cellRect.width -= colWidth + cellSpacingX; + cellFrame->SetRect(cellRect); + } + } + } + lastCell = cellFrame; + } + } + colX += colSpan; + } + colFrame->GetNextSibling(&colFrame); + } // inner while + groupFrame->GetNextSibling(&groupFrame); + } // outer while + + aWidth -= xOffset; + + return NS_OK; +} + NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h index bc3762a9690..c3982d83d9c 100644 --- a/mozilla/layout/tables/nsTableFrame.h +++ b/mozilla/layout/tables/nsTableFrame.h @@ -560,6 +560,12 @@ protected: InnerTableReflowState& aReflowState, nsIFrame* aKidFrame, nscoord aDeltaY); + + NS_METHOD AdjustForCollapsingRows(nsIPresContext& aPresContext, + nscoord& aHeight); + + NS_METHOD AdjustForCollapsingCols(nsIPresContext& aPresContext, + nscoord& aWidth); // end incremental reflow methods /** return the desired width of this table accounting for the current diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index 20e5b752f82..6d7df14e439 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -1421,16 +1421,6 @@ nsTableRowFrame::Reflow(nsIPresContext& aPresContext, break; } - // check the visibility in the final pass. If it is collapse, set our desired size to 0 - if (nsTableFrame::IsFinalPass(aReflowState)) { - const nsStyleDisplay *display; - GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - if (NS_STYLE_VISIBILITY_COLLAPSE == display->mVisible) { - aDesiredSize.width = 0; - aDesiredSize.height = 0; - } - } - // XXX TROY #if 0 diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index b1185b488af..a0cad0ea58b 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -643,8 +643,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext& aPresContext, { const nsStyleDisplay *childDisplay; rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if ((NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) && - (NS_STYLE_VISIBILITY_COLLAPSE != childDisplay->mVisible)) + if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) { // get the height of the tallest cell in the row (excluding cells that span rows) nscoord maxCellHeight = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); @@ -1031,16 +1030,6 @@ nsTableRowGroupFrame::Reflow(nsIPresContext& aPresContext, } } - // check the visibility in the final pass. If it is collapse, set our desired size to 0 - if (nsTableFrame::IsFinalPass(aReflowState)) { - const nsStyleDisplay *display; - GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - if (NS_STYLE_VISIBILITY_COLLAPSE == display->mVisible) { - aDesiredSize.width = 0; - aDesiredSize.height = 0; - } - } - if (gsDebug==PR_TRUE) { if (nsnull!=aDesiredSize.maxElementSize)