From 6ffe908f3975179f498fa71439fa9bb0b5208a80 Mon Sep 17 00:00:00 2001 From: "karnaze%netscape.com" Date: Mon, 13 Dec 1999 22:56:31 +0000 Subject: [PATCH] incremental cell map, columns. Bugs 12122, 21544. r=troy,hyatt a=hofmann git-svn-id: svn://10.0.0.236/trunk@55939 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/base/nsCSSFrameConstructor.cpp | 42 +- mozilla/layout/generic/nsGfxScrollFrame.cpp | 5 +- .../layout/html/base/src/nsGfxScrollFrame.cpp | 5 +- .../html/style/src/nsCSSFrameConstructor.cpp | 42 +- .../table/src/BasicTableLayoutStrategy.cpp | 151 +- .../html/table/src/BasicTableLayoutStrategy.h | 18 +- .../table/src/FixedTableLayoutStrategy.cpp | 27 +- mozilla/layout/html/table/src/nsCellMap.cpp | 935 +++++++++--- mozilla/layout/html/table/src/nsCellMap.h | 124 +- .../html/table/src/nsITableLayoutStrategy.h | 5 - .../html/table/src/nsTableBorderCollapser.cpp | 8 +- .../html/table/src/nsTableCellFrame.cpp | 22 +- .../layout/html/table/src/nsTableColFrame.cpp | 49 + .../layout/html/table/src/nsTableColFrame.h | 40 +- .../html/table/src/nsTableColGroupFrame.cpp | 671 +++++---- .../html/table/src/nsTableColGroupFrame.h | 82 +- .../layout/html/table/src/nsTableFrame.cpp | 1279 ++++++++++------- mozilla/layout/html/table/src/nsTableFrame.h | 184 ++- .../layout/html/table/src/nsTableRowFrame.cpp | 158 +- .../layout/html/table/src/nsTableRowFrame.h | 14 - .../html/table/src/nsTableRowGroupFrame.cpp | 231 ++- .../html/table/src/nsTableRowGroupFrame.h | 4 - .../tables/BasicTableLayoutStrategy.cpp | 151 +- .../layout/tables/BasicTableLayoutStrategy.h | 18 +- .../tables/FixedTableLayoutStrategy.cpp | 27 +- mozilla/layout/tables/nsCellMap.cpp | 935 +++++++++--- mozilla/layout/tables/nsCellMap.h | 124 +- .../layout/tables/nsITableLayoutStrategy.h | 5 - mozilla/layout/tables/nsTableCellFrame.cpp | 22 +- mozilla/layout/tables/nsTableColFrame.cpp | 49 + mozilla/layout/tables/nsTableColFrame.h | 40 +- .../layout/tables/nsTableColGroupFrame.cpp | 671 +++++---- mozilla/layout/tables/nsTableColGroupFrame.h | 82 +- mozilla/layout/tables/nsTableFrame.cpp | 1279 ++++++++++------- mozilla/layout/tables/nsTableFrame.h | 184 ++- mozilla/layout/tables/nsTableRowFrame.cpp | 158 +- mozilla/layout/tables/nsTableRowFrame.h | 14 - .../layout/tables/nsTableRowGroupFrame.cpp | 231 ++- mozilla/layout/tables/nsTableRowGroupFrame.h | 4 - mozilla/layout/xul/base/src/nsTreeFrame.cpp | 2 - .../layout/xul/base/src/nsTreeRowFrame.cpp | 2 +- .../xul/base/src/nsTreeRowGroupFrame.cpp | 155 +- .../layout/xul/base/src/nsTreeRowGroupFrame.h | 12 +- 43 files changed, 5214 insertions(+), 3047 deletions(-) diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index 1e379f99c0c..84aa761da8f 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -37,6 +37,7 @@ #include "nsILinkHandler.h" #include "nsIDocument.h" #include "nsIHTMLTableCellElement.h" +#include "nsTableColGroupFrame.h" #include "nsTableColFrame.h" #include "nsHTMLIIDs.h" #include "nsIStyleFrameConstruction.h" @@ -1175,7 +1176,7 @@ nsCSSFrameConstructor::ConstructAnonymousTableFrame(nsIPresShell* aPresSh nsTableCreator& aTableCreator) { nsresult rv = NS_OK; - NS_WARNING("an anonymous table frame was created. \n"); + //NS_WARNING("an anonymous table frame was created. \n"); nsCOMPtr parentStyleContext; aParentFrame->GetStyleContext(getter_AddRefs(parentStyleContext)); const nsStyleDisplay* parentDisplay = @@ -1326,7 +1327,7 @@ nsCSSFrameConstructor::ConstructTableCaptionFrame(nsIPresShell* aPres // the caller is responsible for calling SetInitialChildList on the outer, inner frames aNewTopFrame = aNewCaptionFrame; } else { // parent is not a table, need to create a new table - NS_WARNING("a non table contains a table caption child. \n"); + //NS_WARNING("a non table contains a table caption child. \n"); nsIFrame* outerFrame; ConstructAnonymousTableFrame(aPresShell, aPresContext, aState, aContent, aParentFrame, aNewTopFrame, outerFrame, innerFrame, aTableCreator); @@ -1418,7 +1419,7 @@ nsCSSFrameConstructor::ConstructTableGroupFrame(nsIPresShell* aPresShell, styleContext, aIsRowGroup, aNewTopFrame, aNewGroupFrame, aTableCreator, contentDisplayIsGroup); } else { // construct anonymous frames - NS_WARNING("a non table contains a table row or col group child. \n"); + //NS_WARNING("a non table contains a table row or col group child. \n"); nsIFrame* innerFrame; nsIFrame* outerFrame; @@ -1639,9 +1640,8 @@ nsCSSFrameConstructor::ConstructTableRowFrameOnly(nsIPresShell* aPresShel return rv; } - nsresult -nsCSSFrameConstructor::ConstructTableColFrame(nsIPresShell* aPresShell, +nsCSSFrameConstructor::ConstructTableColFrame(nsIPresShell* aPresShell, nsIPresContext* aPresContext, nsFrameConstructorState& aState, nsIContent* aContent, @@ -1673,6 +1673,7 @@ nsCSSFrameConstructor::ConstructTableColFrame(nsIPresShell* aPresShell, rv = ConstructTableColFrameOnly(aPresShell, aPresContext, aState, aContent, groupFrame, styleContext, aNewColFrame, aTableCreator); if (NS_FAILED(rv)) return rv; + aState.mFrameManager->SetPrimaryFrameFor(aContent, aNewColFrame); groupFrame->SetInitialChildList(aPresContext, nsnull, aNewColFrame); // if an anoymous table got created, then set its initial child list @@ -1747,7 +1748,7 @@ nsCSSFrameConstructor::ConstructTableCellFrame(nsIPresShell* aPresShell, aTableCreator, aProcessChildren); aNewTopFrame = aNewCellFrame; } else { // the cell needs some ancestors to be fabricated - NS_WARNING("WARNING - a non table row contains a table cell child. \n"); + //NS_WARNING("WARNING - a non table row contains a table cell child. \n"); nsTableList toDo; nsIFrame* rowFrame; rv = ConstructTableRowFrame(aPresShell, aPresContext, aState, aContent, aParentFrame, @@ -5484,6 +5485,35 @@ nsCSSFrameConstructor::AppendFrames(nsIPresContext* aPresContext, aFrameList); } + // a col group or col appended to a table may result in an insert rather than an append + nsIAtom* parentType; + aParentFrame->GetFrameType(&parentType); + if (nsLayoutAtoms::tableFrame == parentType) { + nsTableFrame* tableFrame = (nsTableFrame *)aParentFrame; + nsIAtom* childType; + aFrameList->GetFrameType(&childType); + if (nsLayoutAtoms::tableColFrame == childType) { + nsIFrame* parentFrame = aParentFrame; + aFrameList->GetParent(&parentFrame); + return aFrameManager->AppendFrames(aPresContext, *aPresShell, parentFrame, + nsLayoutAtoms::colGroupList, aFrameList); + } + else if (nsLayoutAtoms::tableColGroupFrame == childType) { + nsIFrame* prevSibling; + PRBool doAppend = nsTableColGroupFrame::GetLastRealColGroup(tableFrame, &prevSibling); + if (doAppend) { + return aFrameManager->AppendFrames(aPresContext, *aPresShell, aParentFrame, + nsLayoutAtoms::colGroupList, aFrameList); + } + else { + return aFrameManager->InsertFrames(aPresContext, *aPresShell, aParentFrame, + nsLayoutAtoms::colGroupList, prevSibling, aFrameList); + } + } + NS_IF_RELEASE(childType); + } + NS_IF_RELEASE(parentType); + // Append the frames to the end of the parent's child list return aFrameManager->AppendFrames(aPresContext, *aPresShell, aParentFrame, nsnull, aFrameList); diff --git a/mozilla/layout/generic/nsGfxScrollFrame.cpp b/mozilla/layout/generic/nsGfxScrollFrame.cpp index 76dbdfacc93..7a0192f3c5e 100644 --- a/mozilla/layout/generic/nsGfxScrollFrame.cpp +++ b/mozilla/layout/generic/nsGfxScrollFrame.cpp @@ -675,7 +675,10 @@ nsGfxScrollFrame::GetSkipSides() const NS_IMETHODIMP nsGfxScrollFrame::GetFrameType(nsIAtom** aType) const { - return nsHTMLContainerFrame::GetFrameType(aType); + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::scrollFrame; + NS_ADDREF(*aType); + return NS_OK; } #ifdef NS_DEBUG diff --git a/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp b/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp index 76dbdfacc93..7a0192f3c5e 100644 --- a/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp +++ b/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp @@ -675,7 +675,10 @@ nsGfxScrollFrame::GetSkipSides() const NS_IMETHODIMP nsGfxScrollFrame::GetFrameType(nsIAtom** aType) const { - return nsHTMLContainerFrame::GetFrameType(aType); + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::scrollFrame; + NS_ADDREF(*aType); + return NS_OK; } #ifdef NS_DEBUG diff --git a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp index 1e379f99c0c..84aa761da8f 100644 --- a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -37,6 +37,7 @@ #include "nsILinkHandler.h" #include "nsIDocument.h" #include "nsIHTMLTableCellElement.h" +#include "nsTableColGroupFrame.h" #include "nsTableColFrame.h" #include "nsHTMLIIDs.h" #include "nsIStyleFrameConstruction.h" @@ -1175,7 +1176,7 @@ nsCSSFrameConstructor::ConstructAnonymousTableFrame(nsIPresShell* aPresSh nsTableCreator& aTableCreator) { nsresult rv = NS_OK; - NS_WARNING("an anonymous table frame was created. \n"); + //NS_WARNING("an anonymous table frame was created. \n"); nsCOMPtr parentStyleContext; aParentFrame->GetStyleContext(getter_AddRefs(parentStyleContext)); const nsStyleDisplay* parentDisplay = @@ -1326,7 +1327,7 @@ nsCSSFrameConstructor::ConstructTableCaptionFrame(nsIPresShell* aPres // the caller is responsible for calling SetInitialChildList on the outer, inner frames aNewTopFrame = aNewCaptionFrame; } else { // parent is not a table, need to create a new table - NS_WARNING("a non table contains a table caption child. \n"); + //NS_WARNING("a non table contains a table caption child. \n"); nsIFrame* outerFrame; ConstructAnonymousTableFrame(aPresShell, aPresContext, aState, aContent, aParentFrame, aNewTopFrame, outerFrame, innerFrame, aTableCreator); @@ -1418,7 +1419,7 @@ nsCSSFrameConstructor::ConstructTableGroupFrame(nsIPresShell* aPresShell, styleContext, aIsRowGroup, aNewTopFrame, aNewGroupFrame, aTableCreator, contentDisplayIsGroup); } else { // construct anonymous frames - NS_WARNING("a non table contains a table row or col group child. \n"); + //NS_WARNING("a non table contains a table row or col group child. \n"); nsIFrame* innerFrame; nsIFrame* outerFrame; @@ -1639,9 +1640,8 @@ nsCSSFrameConstructor::ConstructTableRowFrameOnly(nsIPresShell* aPresShel return rv; } - nsresult -nsCSSFrameConstructor::ConstructTableColFrame(nsIPresShell* aPresShell, +nsCSSFrameConstructor::ConstructTableColFrame(nsIPresShell* aPresShell, nsIPresContext* aPresContext, nsFrameConstructorState& aState, nsIContent* aContent, @@ -1673,6 +1673,7 @@ nsCSSFrameConstructor::ConstructTableColFrame(nsIPresShell* aPresShell, rv = ConstructTableColFrameOnly(aPresShell, aPresContext, aState, aContent, groupFrame, styleContext, aNewColFrame, aTableCreator); if (NS_FAILED(rv)) return rv; + aState.mFrameManager->SetPrimaryFrameFor(aContent, aNewColFrame); groupFrame->SetInitialChildList(aPresContext, nsnull, aNewColFrame); // if an anoymous table got created, then set its initial child list @@ -1747,7 +1748,7 @@ nsCSSFrameConstructor::ConstructTableCellFrame(nsIPresShell* aPresShell, aTableCreator, aProcessChildren); aNewTopFrame = aNewCellFrame; } else { // the cell needs some ancestors to be fabricated - NS_WARNING("WARNING - a non table row contains a table cell child. \n"); + //NS_WARNING("WARNING - a non table row contains a table cell child. \n"); nsTableList toDo; nsIFrame* rowFrame; rv = ConstructTableRowFrame(aPresShell, aPresContext, aState, aContent, aParentFrame, @@ -5484,6 +5485,35 @@ nsCSSFrameConstructor::AppendFrames(nsIPresContext* aPresContext, aFrameList); } + // a col group or col appended to a table may result in an insert rather than an append + nsIAtom* parentType; + aParentFrame->GetFrameType(&parentType); + if (nsLayoutAtoms::tableFrame == parentType) { + nsTableFrame* tableFrame = (nsTableFrame *)aParentFrame; + nsIAtom* childType; + aFrameList->GetFrameType(&childType); + if (nsLayoutAtoms::tableColFrame == childType) { + nsIFrame* parentFrame = aParentFrame; + aFrameList->GetParent(&parentFrame); + return aFrameManager->AppendFrames(aPresContext, *aPresShell, parentFrame, + nsLayoutAtoms::colGroupList, aFrameList); + } + else if (nsLayoutAtoms::tableColGroupFrame == childType) { + nsIFrame* prevSibling; + PRBool doAppend = nsTableColGroupFrame::GetLastRealColGroup(tableFrame, &prevSibling); + if (doAppend) { + return aFrameManager->AppendFrames(aPresContext, *aPresShell, aParentFrame, + nsLayoutAtoms::colGroupList, aFrameList); + } + else { + return aFrameManager->InsertFrames(aPresContext, *aPresShell, aParentFrame, + nsLayoutAtoms::colGroupList, prevSibling, aFrameList); + } + } + NS_IF_RELEASE(childType); + } + NS_IF_RELEASE(parentType); + // Append the frames to the end of the parent's child list return aFrameManager->AppendFrames(aPresContext, *aPresShell, aParentFrame, nsnull, aFrameList); diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp index 31e8f436ad2..d65fd9d665c 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -59,17 +59,6 @@ PRBool CanAllocate(PRInt32 aTypeToAllocate, /* ---------- BasicTableLayoutStrategy ---------- */ -/* return true if the style indicates that the width is fixed - * for the purposes of column width determination - */ -inline -PRBool BasicTableLayoutStrategy::IsFixedWidth(const nsStylePosition* aStylePosition, - const nsStyleTable* aStyleTable) -{ - return PRBool ((eStyleUnit_Coord==aStylePosition->mWidth.GetUnit()) || - (eStyleUnit_Coord==aStyleTable->mSpanWidth.GetUnit())); -} - MOZ_DECL_CTOR_COUNTER(BasicTableLayoutStrategy); @@ -90,8 +79,7 @@ BasicTableLayoutStrategy::~BasicTableLayoutStrategy() MOZ_COUNT_DTOR(BasicTableLayoutStrategy); } -PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, - PRInt32 aNumCols, +PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, nscoord aMaxWidth) { ContinuingFrameCheck(); @@ -99,12 +87,10 @@ PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, PRBool result = PR_TRUE; // re-init instance variables - mNumCols = aNumCols; mMinTableContentWidth = 0; mMaxTableContentWidth = 0; mCellSpacingTotal = 0; mCols = mTableFrame->GetEffectiveCOLSAttribute(); - // assign the width of all fixed-width columns AssignPreliminaryColumnWidths(aMaxWidth); @@ -157,7 +143,7 @@ PRBool BCW_Wrapup(BasicTableLayoutStrategy* aStrategy, { if (aAllocTypes) delete [] aAllocTypes; - if (gsDebugBalance) {printf("BalanceColumnWidths ex \n"); aTableFrame->Dump(PR_TRUE, PR_FALSE);} + if (gsDebugBalance) {printf("BalanceColumnWidths ex \n"); aTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);} return PR_TRUE; } @@ -176,7 +162,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty const nsHTMLReflowState& aReflowState, nscoord aMaxWidthIn) { - if (gsDebugBalance) {printf("BalanceColumnWidths en max=%d\n", aMaxWidthIn); mTableFrame->Dump(PR_TRUE, PR_FALSE);} + if (gsDebugBalance) {printf("BalanceColumnWidths en max=%d\n", aMaxWidthIn); mTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);} ContinuingFrameCheck(); if (!aTableStyle) { @@ -184,6 +170,8 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty return PR_FALSE; } + PRInt32 numCols = mTableFrame->GetColCount(); + // determine if the table is auto/fixed and get the fixed width if available nscoord maxWidth = aMaxWidthIn; nscoord specifiedTableWidth = 0; @@ -204,7 +192,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty } // initialize the col percent and cell percent values to 0. PRInt32 colX; - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); colFrame->SetWidth(PCT, WIDTH_NOT_SET); colFrame->SetWidth(PCT_ADJ, WIDTH_NOT_SET); @@ -220,7 +208,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty PRBool recomputedAdjMin = RecomputeAdjMinIfNecessary(); // set the table's columns to the min width - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord colMinWidth = colFrame->GetMinWidth(); mTableFrame->SetColumnWidth(colX, colMinWidth); @@ -257,10 +245,10 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty nscoord totalAllocated = totalWidths[MIN_CON] + cellSpacingTotal; // allocate and initialize arrays indicating what col gets set - PRInt32* allocTypes = new PRInt32[mNumCols]; + PRInt32* allocTypes = new PRInt32[numCols]; if (!allocTypes) return PR_FALSE; - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { allocTypes[colX] = -1; } @@ -330,9 +318,9 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty PRBool skip0Proportional = totalCounts[DES_CON] > num0Proportional; if ( (tableIsAutoWidth && (perAdjTableWidth - totalAllocated > 0)) || (!tableIsAutoWidth && (totalAllocated < maxWidth)) ) { - if (totalCounts[PCT] != mNumCols) { + if (totalCounts[PCT] != numCols) { //PRBool onlyAuto = (totalCounts[DES_CON] > 0) && !mIsNavQuirksMode; - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (PCT == allocTypes[colX]) { allocTypes[colX] = -1; } @@ -350,7 +338,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty } // give the proportional cols the rest up to the max width in quirks mode else if (tableIsAutoWidth && mIsNavQuirksMode && (totalCounts[MIN_PRO] > 0)) { - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (DES_CON != allocTypes[colX]) { allocTypes[colX] = -1; } @@ -369,7 +357,8 @@ void BasicTableLayoutStrategy::AllocateFully(nscoord& aTotalAllocated, PRInt32 aWidthType, PRBool aMarkAllocated) { - for (PRInt32 colX = 0; colX < mNumCols; colX++) { + PRInt32 numCols = mTableFrame->GetColCount(); + for (PRInt32 colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord oldWidth = mTableFrame->GetColumnWidth(colX); nscoord newWidth = colFrame->GetWidth(aWidthType); @@ -408,13 +397,14 @@ void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount, PRInt32 numColsAllocated = 0; PRInt32 totalAllocated = 0; PRInt32 colX; - for (colX = 0; colX < mNumCols; colX++) { + PRInt32 numCols = mTableFrame->GetColCount(); + for (colX = 0; colX < numCols; colX++) { if (-1 != aAllocTypes[colX]) { divisor += mTableFrame->GetColumnWidth(colX); numColsAllocated++; } } - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (-1 != aAllocTypes[colX]) { if (aSkip0Proportional) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); @@ -703,9 +693,10 @@ BasicTableLayoutStrategy::ComputeColspanWidths(PRInt32 aWidthIndex, // and calculate min/max table width PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth) { - if (gsDebugAssign) {printf("AssignPrelimColWidths en max=%d\n", aMaxWidth); mTableFrame->Dump(PR_TRUE, PR_FALSE);} + if (gsDebugAssign) {printf("AssignPrelimColWidths en max=%d\n", aMaxWidth); mTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);} PRBool rv = PR_FALSE; PRInt32 numRows = mTableFrame->GetRowCount(); + PRInt32 numCols = mTableFrame->GetColCount(); nscoord spacingX = mTableFrame->GetCellSpacingX(); PRInt32 colX, rowX; mCellSpacingTotal = 0; @@ -713,12 +704,12 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth PRInt32 propTotal = 0; // total of numbers of the type 1*, 2*, etc PRInt32 numColsForColsAttr = 0; // Nav Quirks cols attribute for equal width cols if (NS_STYLE_TABLE_COLS_NONE != mCols) { - numColsForColsAttr = (NS_STYLE_TABLE_COLS_ALL == mCols) ? mNumCols : mCols; + numColsForColsAttr = (NS_STYLE_TABLE_COLS_ALL == mCols) ? numCols : mCols; } // For every column, determine it's min and desired width based on cell style // base on cells which do not span cols. Also, determine mCellSpacingTotal - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nscoord minWidth = 0; nscoord desWidth = 0; nscoord fixWidth = WIDTH_NOT_SET; @@ -794,6 +785,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth // proportional width on a col or Nav Quirks cols attr if (fixWidth <= 0) { nscoord proportion = WIDTH_NOT_SET; +#ifdef foobar const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); if (eStyleUnit_Proportional == colPosition->mWidth.GetUnit()) { @@ -806,6 +798,19 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth proportion = WIDTH_NOT_SET; } } +#else + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + if (eStyleUnit_Proportional == colStyleWidth.GetUnit()) { + proportion = colStyleWidth.GetIntValue(); + } + else if (colX < numColsForColsAttr) { + proportion = 1; + if ((eStyleUnit_Percent == colStyleWidth.GetUnit()) && + (colStyleWidth.GetPercentValue() > 0.0f)) { + proportion = WIDTH_NOT_SET; + } + } +#endif if (proportion >= 0) { colFrame->SetWidth(MIN_PRO, proportion); if (proportion > 0) { @@ -831,7 +836,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth nscoord minPropTotal = 0; nscoord desPropTotal = 0; // figure the totals of all proportional cols which support every min and desired width - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord colProp = colFrame->GetWidth(MIN_PRO); if (colProp > 0) { @@ -846,7 +851,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth mMinToDesProportionRatio = ((float)desPropTotal) / ((float)minPropTotal); } // figure the cols proportional min width based on the new totals - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord colProp = colFrame->GetWidth(MIN_PRO); if (colProp > 0) { @@ -861,7 +866,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth // Adjust the cols that each cell spans if necessary. Iterate backwards // so that nested and/or overlaping col spans handle the inner ones first, // ensuring more accurated calculations. - for (colX = mNumCols - 1; colX >= 0; colX--) { + for (colX = numCols - 1; colX >= 0; colX--) { for (rowX = 0; rowX < numRows; rowX++) { PRBool originates; PRInt32 colSpan; @@ -878,11 +883,12 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth // Set the col's fixed width if present // Set the table col width for each col to the content min. - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord fixColWidth = colFrame->GetWidth(FIX); // use the style width of a col only if the col hasn't gotten a fixed width from any cell if (fixColWidth <= 0) { +#ifdef foobar const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { @@ -891,13 +897,22 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth colFrame->SetWidth(FIX, fixColWidth); } } +#else + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + if (eStyleUnit_Coord == colStyleWidth.GetUnit()) { + fixColWidth = colStyleWidth.GetCoordValue(); + if (fixColWidth > 0) { + colFrame->SetWidth(FIX, fixColWidth); + } + } +#endif } nscoord minWidth = colFrame->GetMinWidth(); mTableFrame->SetColumnWidth(colX, minWidth); } SetMinAndMaxTableContentWidths(); - if (gsDebugAssign) {printf("AssignPrelimColWidths ex\n"); mTableFrame->Dump(PR_TRUE, PR_FALSE);} + if (gsDebugAssign) {printf("AssignPrelimColWidths ex\n"); mTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);} return rv; } @@ -906,6 +921,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, PRBool aTableIsAutoWidth) { PRInt32 numRows = mTableFrame->GetRowCount(); + PRInt32 numCols = mTableFrame->GetColCount(); nscoord spacingX = mTableFrame->GetCellSpacingX(); PRInt32 colX, rowX; nscoord basis = aBasisIn; @@ -918,7 +934,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, PRInt32 numPerCols = 0; // number of colums that 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++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord colBasis = -1; // Scan the cells in the col @@ -950,6 +966,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, } if (-1 == colBasis) { // see if the col has a style percent width specified +#ifdef foobar const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); if (eStyleUnit_Percent == colPosition->mWidth.GetUnit()) { @@ -960,6 +977,17 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, colBasis = NSToCoordRound((float)desWidth / percent); } } +#else + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + if (eStyleUnit_Percent == colStyleWidth.GetUnit()) { + float percent = colStyleWidth.GetPercentValue(); + colBasis = 0; + if (percent > 0.0f) { + nscoord desWidth = colFrame->GetDesWidth(); + colBasis = NSToCoordRound((float)desWidth / percent); + } + } +#endif } basis = PR_MAX(basis, colBasis); nscoord fixWidth = colFrame->GetFixWidth(); @@ -976,7 +1004,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, return 0; } // If there is only one col and it is % based, it won't affect anything - if ((1 == mNumCols) && (mNumCols == numPerCols)) { + if ((1 == numCols) && (numCols == numPerCols)) { return 0; } // compute a basis considering total percentages and the desired width of everything else @@ -995,12 +1023,12 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, } nscoord colPctTotal = 0; - nscoord* colPcts = new nscoord[mNumCols]; + nscoord* colPcts = new nscoord[numCols]; if (!colPcts) return 0; // Determine the percentage contribution for cols and for cells with colspan = 1 // Iterate backwards, similarly to the reasoning in AssignPreliminaryColumnWidths - for (colX = mNumCols - 1; colX >= 0; colX--) { + for (colX = numCols - 1; colX >= 0; colX--) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord maxColPctWidth = WIDTH_NOT_SET; float maxColPct = 0.0f; @@ -1039,12 +1067,20 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, } if (WIDTH_NOT_SET == maxColPctWidth) { // see if the col has a style percent width specified +#ifdef foobar const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); if (eStyleUnit_Percent == colPosition->mWidth.GetUnit()) { maxColPct = colPosition->mWidth.GetPercentValue(); maxColPctWidth = NSToCoordRound( ((float)basis) * maxColPct ); } +#else + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + if (eStyleUnit_Percent == colStyleWidth.GetUnit()) { + maxColPct = colStyleWidth.GetPercentValue(); + maxColPctWidth = NSToCoordRound( ((float)basis) * maxColPct ); + } +#endif } // conflicting pct/fixed widths are recorded. Nav 4.x may be changing the // fixed width value if it exceeds the pct value and not recording the pct @@ -1066,7 +1102,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, // For each col, consider the cells originating in it with colspans > 1. // Adjust the cols that each cell spans if necessary. - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { for (rowX = 0; rowX < numRows; rowX++) { PRBool originates; PRInt32 colSpan; @@ -1162,7 +1198,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, // if the percent total went over 100%, adjustments need to be made to right most cols if (colPctTotal > 100) { - for (colX = mNumCols - 1; colX >= 0; colX--) { + for (colX = numCols - 1; colX >= 0; colX--) { if (colPcts[colX] > 0) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord newPct = colPcts[colX] - (colPctTotal - 100); @@ -1197,10 +1233,11 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, PRBool BasicTableLayoutStrategy::RecomputeAdjMinIfNecessary() { PRInt32 numRows = mTableFrame->GetRowCount(); + PRInt32 numCols = mTableFrame->GetColCount(); PRInt32 colX, rowX, spanX; PRBool spansPercent = PR_FALSE; - for (colX = mNumCols - 1; colX >= 0; colX--) { + for (colX = numCols - 1; colX >= 0; colX--) { for (rowX = 0; rowX < numRows; rowX++) { PRBool originates; PRInt32 colSpan; @@ -1233,7 +1270,7 @@ PRBool BasicTableLayoutStrategy::RecomputeAdjMinIfNecessary() nscoord spacingX = mTableFrame->GetCellSpacingX(); - for (colX = mNumCols - 1; colX >= 0; colX--) { + for (colX = numCols - 1; colX >= 0; colX--) { for (rowX = 0; rowX < numRows; rowX++) { PRBool originates; PRInt32 colSpan; @@ -1267,7 +1304,8 @@ void BasicTableLayoutStrategy::SetMinAndMaxTableContentWidths() mMaxTableContentWidth = 0; nscoord spacingX = mTableFrame->GetCellSpacingX(); - for (PRInt32 colX = 0; colX < mNumCols; colX++) { + PRInt32 numCols = mTableFrame->GetColCount(); + for (PRInt32 colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); mMinTableContentWidth += colFrame->GetMinWidth(); mMaxTableContentWidth += PR_MAX(colFrame->GetDesWidth(), colFrame->GetFixWidth()); @@ -1302,7 +1340,8 @@ void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, a0ProportionalCount = 0; nscoord spacingX = mTableFrame->GetCellSpacingX(); - for (PRInt32 colX = 0; colX < mNumCols; colX++) { + PRInt32 numCols = mTableFrame->GetColCount(); + for (PRInt32 colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (mTableFrame->GetNumCellsOriginatingInCol(colX) > 0) { aCellSpacing += spacingX; @@ -1387,7 +1426,7 @@ void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, aMinWidths[DES_CON] += minCol; } // if it is not a degenerate table, add the last spacing on the right - if (mNumCols > 0) { + if (numCols > 0) { aCellSpacing += spacingX; } } @@ -1508,11 +1547,12 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, return; } + PRInt32 numCols = mTableFrame->GetColCount(); PRInt32 numConstrainedCols = 0; nscoord sumMaxConstraints = 0; PRBool useAdj = PR_TRUE; PRInt32 colX; - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame, useAdj)) { if (-1 != aAllocTypes[colX]) { @@ -1539,7 +1579,7 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, PRInt32 maxMinDiff = 0; PRInt32 constrColX = 0; // set the col info entries for each constrained col - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame, useAdj)) { if (-1 != aAllocTypes[colX]) { @@ -1810,11 +1850,16 @@ PRBool BasicTableLayoutStrategy::ColIsSpecifiedAsMinimumWidth(PRInt32 aColIndex) PRBool result = PR_FALSE; nsTableColFrame* colFrame; mTableFrame->GetColumnFrame(aColIndex, colFrame); +#ifdef foobar const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); switch (colPosition->mWidth.GetUnit()) { +#else + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + switch (colStyleWidth.GetUnit()) { +#endif case eStyleUnit_Coord: - if (0 == colPosition->mWidth.GetCoordValue()) { + if (0 == colStyleWidth.GetCoordValue()) { result = PR_TRUE; } break; @@ -1823,14 +1868,14 @@ PRBool BasicTableLayoutStrategy::ColIsSpecifiedAsMinimumWidth(PRInt32 aColIndex) // total hack for now for 0% and 1% specifications // should compare percent to available parent width and see that it is below minimum // for this column - float percent = colPosition->mWidth.GetPercentValue(); + float percent = colStyleWidth.GetPercentValue(); if (0.0f == percent || 0.01f == percent) { result = PR_TRUE; } break; } case eStyleUnit_Proportional: - if (0 == colPosition->mWidth.GetIntValue()) { + if (0 == colStyleWidth.GetIntValue()) { result = PR_TRUE; } @@ -1849,8 +1894,8 @@ void BasicTableLayoutStrategy::Dump(PRInt32 aIndent) } indent[aIndent] = 0; - printf("%s**START BASIC STRATEGY DUMP** table=%p cols=%X numCols=%d", - indent, mTableFrame, mCols, mNumCols); + printf("%s**START BASIC STRATEGY DUMP** table=%p cols=%X", + indent, mTableFrame, mCols); printf("\n%s minConWidth=%d maxConWidth=%d cellSpacing=%d propRatio=%.2f navQuirks=%d", indent, mMinTableContentWidth, mMaxTableContentWidth, mCellSpacingTotal, mMinToDesProportionRatio, mIsNavQuirksMode); printf(" **END BASIC STRATEGY DUMP** \n"); diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h index 2c96231aa82..34186cc4d7d 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h @@ -57,11 +57,9 @@ public: /** call every time any table thing changes that might effect the width of any column * in the table (content, structure, or style) * @param aMaxElementSize [OUT] if not null, the max element size is computed and returned in this param - * @param aNumCols the total number of columns in the table */ - virtual PRBool Initialize(nsSize* aMaxElementSize, - PRInt32 aNumCols, - nscoord aMaxSize); + virtual PRBool Initialize(nsSize* aMaxElementSize, + nscoord aMaxSize); /** compute the max element size of the table. * assumes that Initialize has been called @@ -83,7 +81,6 @@ public: nscoord GetTableMinContentWidth() const; nscoord GetTableMaxContentWidth() const; nscoord GetCOLSAttribute() const; - nscoord GetNumCols() const; void Dump(PRInt32 aIndent); protected: @@ -159,13 +156,6 @@ protected: PRInt32* aAllocTypes, PRBool aSkip0Proportional); - /** return true if the style indicates that the width is a specific width - * for the purposes of column width determination. - * return false if the width changes based on content, parent size, etc. - */ - static PRBool IsFixedWidth(const nsStylePosition* aStylePosition, - const nsStyleTable* aStyleTable); - /** return true if the colIndex is in the list of colIndexes */ virtual PRBool IsColumnInList(const PRInt32 colIndex, PRInt32 *colIndexes, @@ -214,7 +204,6 @@ protected: protected: nsTableFrame * mTableFrame; PRInt32 mCols; - PRInt32 mNumCols; // cached data nscoord mMinTableContentWidth; // the smallest size for the table (excluding border and padding) nscoord mMaxTableContentWidth; // the "natural" size for the table, if unconstrained (excluding border and padding) @@ -233,9 +222,6 @@ inline nscoord BasicTableLayoutStrategy::GetTableMaxContentWidth() const inline nscoord BasicTableLayoutStrategy::GetCOLSAttribute() const { return mCols; }; -inline nscoord BasicTableLayoutStrategy::GetNumCols() const -{ return mNumCols; }; - #endif diff --git a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp index fb2e1eb9af3..54a017944e2 100644 --- a/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/FixedTableLayoutStrategy.cpp @@ -59,7 +59,6 @@ PRBool FixedTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aT PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputedWidth) { // NS_ASSERTION(aComputedWidth != NS_UNCONSTRAINEDSIZE, "bad computed width"); - const nsStylePosition* tablePosition; mTableFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)tablePosition); PRBool tableIsFixedWidth = eStyleUnit_Coord == tablePosition->mWidth.GetUnit() || @@ -70,24 +69,25 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed nsMargin borderPadding; tableSpacing->CalcBorderPaddingFor(mTableFrame, borderPadding); + PRInt32 numCols = mTableFrame->GetColCount(); PRInt32 colX; // availWidth is used as the basis for percentage width columns. It is aComputedWidth // minus table border, padding, & cellspacing nscoord availWidth = aComputedWidth - borderPadding.left - borderPadding.right - - ((mNumCols + 1) * mTableFrame->GetCellSpacingX()); + ((numCols + 1) * mTableFrame->GetCellSpacingX()); PRInt32 specifiedCols = 0; // the number of columns whose width is given nscoord totalColWidth = 0; // the sum of the widths of the columns - nscoord* colWidths = new PRBool[mNumCols]; - nsCRT::memset(colWidths, WIDTH_NOT_SET, mNumCols*sizeof(nscoord)); + nscoord* colWidths = new PRBool[numCols]; + nsCRT::memset(colWidths, WIDTH_NOT_SET, numCols*sizeof(nscoord)); - nscoord* propInfo = new PRBool[mNumCols]; - nsCRT::memset(propInfo, 0, mNumCols*sizeof(nscoord)); + nscoord* propInfo = new PRBool[numCols]; + nsCRT::memset(propInfo, 0, numCols*sizeof(nscoord)); nscoord propTotal = 0; // for every column, determine its specified width - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { // Get column information nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) { @@ -115,6 +115,7 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed propTotal += propInfo[colX]; } else { // get width from the cell + nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(0, colX); if (nsnull != cellFrame) { // Get the cell's style @@ -148,7 +149,7 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed if (0 < remainingWidth) { if (propTotal > 0) { - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (propInfo[colX] > 0) { // We're proportional float percent = ((float)propInfo[colX])/((float)propTotal); @@ -159,10 +160,10 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed } } else if (tableIsFixedWidth) { - if (mNumCols > specifiedCols) { + if (numCols > specifiedCols) { // allocate the extra space to the columns which have no width specified - nscoord colAlloc = NSToCoordRound( ((float)remainingWidth) / (((float)mNumCols) - ((float)specifiedCols))); - for (colX = 0; colX < mNumCols; colX++) { + nscoord colAlloc = NSToCoordRound( ((float)remainingWidth) / (((float)numCols) - ((float)specifiedCols))); + for (colX = 0; colX < numCols; colX++) { if (-1 == colWidths[colX]) { colWidths[colX] = colAlloc; totalColWidth += colAlloc; @@ -172,7 +173,7 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed } else { // allocate the extra space to the columns which have width specified float divisor = (float)totalColWidth; - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (colWidths[colX] > 0) { nscoord colAlloc = NSToCoordRound(remainingWidth * colWidths[colX] / divisor); colWidths[colX] += colAlloc; @@ -187,7 +188,7 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed nscoord overAllocation = (availWidth >= 0) ? totalColWidth - availWidth : 0; // set the column widths - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (colWidths[colX] < 0) colWidths[colX] = 0; // if there was too much allocated due to rounding, remove it from the last col diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp index ee21a1c4390..e6d444e54e4 100644 --- a/mozilla/layout/html/table/src/nsCellMap.cpp +++ b/mozilla/layout/html/table/src/nsCellMap.cpp @@ -20,6 +20,7 @@ * Contributor(s): */ +#include "nsLayoutAtoms.h" #include "nsVoidArray.h" #include "nsCellMap.h" #include "nsTableFrame.h" @@ -78,7 +79,7 @@ nsCellMap::~nsCellMap() MOZ_COUNT_DTOR(nsCellMap); PRInt32 mapRowCount = mRows.Count(); - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); PRInt32 colX; for (PRInt32 rowX = 0; rowX < mapRowCount; rowX++) { nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(rowX)); @@ -89,15 +90,11 @@ nsCellMap::~nsCellMap() } } delete row; - PRInt32* numOrig = (PRInt32 *)mNumCellsOrigInRow.ElementAt(rowX); - if (numOrig) { - delete numOrig; - } } for (colX = 0; colX < colCount; colX++) { - PRInt32* val = (PRInt32 *)mNumCellsOrigInCol.ElementAt(colX); - if (val) { - delete val; + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + if (colInfo) { + delete colInfo; } } @@ -115,7 +112,7 @@ nsCellMap::~nsCellMap() void nsCellMap::AddColsAtEnd(PRUint32 aNumCols) { - Grow(mRowCount, mNumCellsOrigInCol.Count() + aNumCols); + Grow(mRowCount, mCols.Count() + aNumCols); } PRInt32 nsCellMap::GetNextAvailRowIndex() @@ -127,7 +124,7 @@ void nsCellMap::Grow(PRInt32 aNumMapRows, PRInt32 aNumCols) { PRInt32 origNumMapRows = mRows.Count(); - PRInt32 origNumCols = mNumCellsOrigInCol.Count(); + PRInt32 origNumCols = mCols.Count(); // if the number of columns has increased, we need to add extra cols to mNumColsOriginating and // each row in mRows. @@ -142,9 +139,9 @@ void nsCellMap::Grow(PRInt32 aNumMapRows, } // update the col array for (colX = origNumCols; colX < aNumCols; colX++) { - PRInt32* val = new PRInt32(0); - if (val) { - mNumCellsOrigInCol.AppendElement(val); + nsColInfo* colInfo = new nsColInfo(); + if (colInfo) { + mCols.AppendElement(colInfo); } } } @@ -158,86 +155,91 @@ void nsCellMap::Grow(PRInt32 aNumMapRows, if (row) { mRows.AppendElement(row); } - PRInt32* val = new PRInt32(0); - if (val) { - mNumCellsOrigInRow.AppendElement(val); - } } } -void nsCellMap::InsertRowIntoMap(PRInt32 aRowIndex) +void +nsCellMap::InsertRows(nsVoidArray& aRows, + PRInt32 aFirstRowIndex, + PRBool aConsiderSpans) { - // XXX This function does not yet handle spans. - // XXX Does this function need to worry about adjusting the collapsed row/col arrays? - nsVoidArray* row; - PRInt32 origNumCols = mNumCellsOrigInCol.Count(); + PRInt32 numCols = mCols.Count(); - row = (0 == origNumCols) ? new nsVoidArray() : new nsVoidArray(origNumCols); - - if (row) { - mRows.InsertElementAt(row, aRowIndex); - if(mIsCollapsedRows) - InsertIntoCollapsedRows(aRowIndex); - } - - PRInt32* val = new PRInt32(0); - if (val) { - mNumCellsOrigInRow.InsertElementAt(val, aRowIndex); + if (aFirstRowIndex > mRowCount) { + NS_ASSERTION(PR_FALSE, "nsCellMap::InsertRows bad first row index"); + return; } - mRowCount++; - mNextAvailRowIndex++; + if (!aConsiderSpans) { + ExpandWithRows(aRows, aFirstRowIndex); + return; + } + + PRInt32 numMapRows = mRows.Count(); + + // if any cells span into or out of the row being inserted, then rebuild + PRBool spansCauseRebuild = CellsSpanInOrOut(aFirstRowIndex, aFirstRowIndex, + 0, numCols - 1); + + // if any of the new cells span out of the new rows being added, then rebuild + // XXX it would be better to only rebuild the portion of the map that follows the new rows + if (!spansCauseRebuild && (aFirstRowIndex < mRows.Count())) { + spansCauseRebuild = CellsSpanOut(aRows); + } + + if (spansCauseRebuild) { + RebuildConsideringRows(aFirstRowIndex, &aRows); + } + else { + ExpandWithRows(aRows, aFirstRowIndex); + } } -void nsCellMap::RemoveRowFromMap(PRInt32 aRowIndex) +void +nsCellMap::RemoveRows(PRInt32 aFirstRowIndex, + PRInt32 aNumRowsToRemove, + PRBool aConsiderSpans) { - // XXX This function does not yet handle spans. - // XXX Does this function need to worry about adjusting the collapsed row/col arrays? - - PRInt32 colCount = mNumCellsOrigInCol.Count(); - for (PRInt32 i = 0; i < colCount; i++) { - // Adjust the column counts. - PRInt32 span; - PRBool originates; - GetCellInfoAt(aRowIndex, i, &originates, &span); - if (originates) { - // Decrement the column count. - PRInt32* cols = (PRInt32*)(mNumCellsOrigInCol.ElementAt(i)); - *cols = *cols-1; - } + PRInt32 numRows = mRows.Count(); + PRInt32 numCols = mCols.Count(); + + if (aFirstRowIndex >= numRows) { + return; } + if (!aConsiderSpans) { + ShrinkWithoutRows(aFirstRowIndex, aNumRowsToRemove); + return; + } + PRInt32 endRowIndex = aFirstRowIndex + aNumRowsToRemove - 1; + if (endRowIndex >= numRows) { + NS_ASSERTION(PR_FALSE, "nsCellMap::RemoveRows tried to remove too many rows"); + endRowIndex = numRows - 1; + } + PRBool spansCauseRebuild = CellsSpanInOrOut(aFirstRowIndex, endRowIndex, + 0, numCols - 1); - // Delete the originating row info. - PRInt32* numOrig = (PRInt32 *)mNumCellsOrigInRow.ElementAt(aRowIndex); - mNumCellsOrigInRow.RemoveElementAt(aRowIndex); - if (numOrig) - delete numOrig; + if (spansCauseRebuild) { + RebuildConsideringRows(aFirstRowIndex, nsnull, aNumRowsToRemove); + } + else { + ShrinkWithoutRows(aFirstRowIndex, aNumRowsToRemove); + } +} - // Delete our row information. - nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(aRowIndex)); - for (PRInt32 colX = 0; colX < colCount; colX++) { - CellData* data = (CellData *)(row->ElementAt(colX)); - if (data) { - delete data; - } - } - mRows.RemoveElementAt(aRowIndex); - delete row; - if(mIsCollapsedRows) - RemoveFromCollapsedRows(aRowIndex); - - // Decrement our row and next available index counts. - mRowCount--; - mNextAvailRowIndex--; +void +nsCellMap::AppendCol() +{ + Grow(mRows.Count(), mCols.Count() + 1); } PRInt32 nsCellMap::AppendCell(nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex) + PRInt32 aRowIndex, + PRBool aRebuildIfNecessary) { NS_ASSERTION(aCellFrame, "bad cell frame"); PRInt32 origNumMapRows = mRows.Count(); - PRInt32 origNumCols = mNumCellsOrigInCol.Count(); + PRInt32 origNumCols = mCols.Count(); // get the first null CellData in the desired row. It may be 1 past the end if there are none PRInt32 startColIndex; @@ -253,10 +255,20 @@ PRInt32 nsCellMap::AppendCell(nsTableCellFrame* aCellFrame, startColIndex = 0; } - mRowCount = PR_MAX(mRowCount, aRowIndex + 1); - PRInt32 rowSpan = aCellFrame->GetRowSpan(); PRInt32 colSpan = aCellFrame->GetColSpan(); + + // if the new cell could potentially span into other rows and collide with + // originating cells there, we will play it safe and just rebuild the map + if (aRebuildIfNecessary && (aRowIndex < mRowCount - 1) && (rowSpan > 1)) { + nsVoidArray newCellArray; + newCellArray.AppendElement(aCellFrame); + RebuildConsideringCells(&newCellArray, aRowIndex, startColIndex, PR_TRUE); + return startColIndex; + } + + mRowCount = PR_MAX(mRowCount, aRowIndex + 1); + // Grow. we may need to add new rows/cols PRInt32 spanNumRows = aRowIndex + rowSpan; PRInt32 spanNumCols = startColIndex + colSpan; @@ -268,13 +280,8 @@ PRInt32 nsCellMap::AppendCell(nsTableCellFrame* aCellFrame, CellData* origData = new CellData(aCellFrame, nsnull, nsnull); SetMapCellAt(*origData, aRowIndex, startColIndex); - // reset the col index of the cell frame - PRInt32 oldColIndex; - aCellFrame->GetColIndex(oldColIndex); - if (startColIndex != oldColIndex) { - // only do this if they are different since it changes content - aCellFrame->SetColIndex(startColIndex); - } + // initialize the cell frame + aCellFrame->InitCellFrame(startColIndex); // Create CellData objects for the rows that this cell spans. Set // their mOrigCell to nsnull and their mSpanData to point to data. @@ -298,46 +305,662 @@ PRInt32 nsCellMap::AppendCell(nsTableCellFrame* aCellFrame, } else { cellData->mColSpanData = origData; + nsColInfo* colInfo = (nsColInfo *) mCols.ElementAt(colX); + colInfo->mNumCellsSpan++; } } } else { cellData = new CellData(nsnull, nsnull, nsnull); - if (rowX > aRowIndex) + if (rowX > aRowIndex) { cellData->mRowSpanData = origData; - if (colX > startColIndex) + } + if (colX > startColIndex) { cellData->mColSpanData = origData; + } SetMapCellAt(*cellData, rowX, colX); } } } } + //Dump(); return startColIndex; } -void nsCellMap::RemoveCell(nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex) +PRBool nsCellMap::CellsSpanOut(nsVoidArray& aRows) +{ + PRInt32 numNewRows = aRows.Count(); + for (PRInt32 rowX = 0; rowX < numNewRows; rowX++) { + nsIFrame* rowFrame = (nsIFrame *) aRows.ElementAt(rowX); + nsIFrame* cellFrame = nsnull; + rowFrame->FirstChild(nsnull, &cellFrame); + while (cellFrame) { + nsIAtom* frameType; + cellFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableCellFrame == frameType) { + PRInt32 rowSpan = ((nsTableCellFrame *)cellFrame)->GetRowSpan(); + if (rowX + rowSpan > numNewRows) { + NS_RELEASE(frameType); + return PR_TRUE; + } + } + NS_IF_RELEASE(frameType); + cellFrame->GetNextSibling(&cellFrame); + } + } + return PR_FALSE; +} + +// return PR_TRUE if any cells have rows spans into or out of the region +// defined by the row and col indices or any cells have colspans into the region +PRBool nsCellMap::CellsSpanInOrOut(PRInt32 aStartRowIndex, + PRInt32 aEndRowIndex, + PRInt32 aStartColIndex, + PRInt32 aEndColIndex) { - // XXX write me. For now the cell map is recalculate from scratch when a cell is deleted + for (PRInt32 colX = aStartColIndex; colX <= aEndColIndex; colX++) { + CellData* cellData; + if (aStartRowIndex > 0) { + cellData = GetMapCellAt(aStartRowIndex, colX); + if (cellData && (cellData->mRowSpanData)) { + return PR_TRUE; // a cell row spans into + } + } + if (aEndRowIndex < mRowCount - 1) { + cellData = GetMapCellAt(aEndRowIndex + 1, colX); + if ((cellData) && (cellData->mRowSpanData)) { + return PR_TRUE; // a cell row spans out + } + } + } + if (aStartColIndex > 0) { + for (PRInt32 rowX = aStartRowIndex; rowX <= aEndRowIndex; rowX++) { + CellData* cellData = GetMapCellAt(rowX, aStartColIndex); + if (cellData && (cellData->mColSpanData)) { + return PR_TRUE; + } + } + } + return PR_FALSE; } -PRInt32 nsCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const +void nsCellMap::InsertCells(nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndexBefore) { - PRInt32 rowCount = mNumCellsOrigInRow.Count(); - if ((aRowIndex >= 0) && (aRowIndex < rowCount)) { - return *((PRInt32 *)mNumCellsOrigInRow.ElementAt(aRowIndex)); + if (aCellFrames.Count() == 0) return; + PRInt32 numCols = mCols.Count(); + if (aColIndexBefore >= numCols) { + NS_ASSERTION(PR_FALSE, "bad arg in nsCellMap::InsertCellAt"); + return; + } + + // get the starting col index of the 1st new cells + PRInt32 startColIndex; + for (startColIndex = aColIndexBefore + 1; startColIndex < numCols; startColIndex++) { + CellData* data = GetMapCellAt(aRowIndex, startColIndex); + if (data && data->mOrigCell) { + break; // we found the col index + } + } + + // record whether inserted cells are going to cause complications due + // to existing row spans, col spans or table sizing. + PRBool spansCauseRebuild = PR_FALSE; + + // check that all cells have the same row span + PRInt32 numNewCells = aCellFrames.Count(); + PRInt32 rowSpan = 0; + for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) { + nsTableCellFrame* cell = (nsTableCellFrame*) aCellFrames.ElementAt(cellX); + PRInt32 rowSpan2 = cell->GetRowSpan(); + if (rowSpan == 0) { + rowSpan = rowSpan2; + } + else if (rowSpan != rowSpan2) { + spansCauseRebuild = PR_TRUE; + break; + } + } + + // check if the new cells will cause the table to add more rows + if (!spansCauseRebuild) { + if (mRows.Count() < aRowIndex + rowSpan) { + spansCauseRebuild = PR_TRUE; + } + } + + if (!spansCauseRebuild) { + spansCauseRebuild = CellsSpanInOrOut(aRowIndex, aRowIndex + rowSpan - 1, startColIndex, numCols - 1); + } + + if (spansCauseRebuild) { + RebuildConsideringCells(&aCellFrames, aRowIndex, startColIndex, PR_TRUE); } else { - NS_ASSERTION(PR_FALSE, "nsCellMap::GetNumCellsOriginatingInRow - bad row index"); - return 0; + ExpandWithCells(aCellFrames, aRowIndex, startColIndex, rowSpan); + } + +} + +PRBool +nsCellMap::CreateEmptyRow(PRInt32 aRowIndex, + PRInt32 aNumCols) +{ + nsVoidArray* row; + row = (0 == aNumCols) ? new nsVoidArray() : new nsVoidArray(aNumCols); + if (!row) { + return PR_FALSE; + } + mRows.InsertElementAt(row, aRowIndex); + + if(mIsCollapsedRows) { + InsertIntoCollapsedRows(aRowIndex); + } + return PR_TRUE; +} + + +void +nsCellMap::ExpandWithRows(nsVoidArray& aRowFrames, + PRInt32 aStartRowIndex) +{ + PRInt32 numNewRows = aRowFrames.Count();; + PRInt32 origNumCols = mCols.Count(); + PRInt32 endRowIndex = aStartRowIndex + numNewRows - 1; + PRInt32 numMapRows = mRows.Count(); + + // create the new rows first + PRInt32 newRowIndex = 0; + PRInt32 rowX; + for (rowX = aStartRowIndex; rowX <= endRowIndex; rowX++) { + if (!CreateEmptyRow(rowX, origNumCols)) { + return; + } + newRowIndex++; + } + mRowCount += numNewRows; + + newRowIndex = 0; + for (rowX = aStartRowIndex; rowX <= endRowIndex; rowX++) { + nsTableRowFrame* rFrame = (nsTableRowFrame *)aRowFrames.ElementAt(newRowIndex); + // append cells + nsIFrame* cFrame = nsnull; + rFrame->FirstChild(nsnull, &cFrame); + while (cFrame) { + nsIAtom* cFrameType; + cFrame->GetFrameType(&cFrameType); + if (nsLayoutAtoms::tableCellFrame == cFrameType) { + AppendCell((nsTableCellFrame *)cFrame, rowX, PR_FALSE); + } + NS_IF_RELEASE(cFrameType); + cFrame->GetNextSibling(&cFrame); + } + newRowIndex++; + } + mNextAvailRowIndex += numNewRows; +} + +void nsCellMap::ExpandWithCells(nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndex, + PRInt32 aRowSpan) +{ + PRInt32 endRowIndex = aRowIndex + aRowSpan - 1; + PRInt32 startColIndex = aColIndex; + PRInt32 endColIndex; + PRInt32 numCells = aCellFrames.Count(); + PRInt32 totalColSpan = 0; + + // add cellData entries for the space taken up by the new cells + for (PRInt32 cellX = 0; cellX < numCells; cellX++) { + nsTableCellFrame* cellFrame = (nsTableCellFrame*) aCellFrames.ElementAt(cellX); + CellData* origData = new CellData(cellFrame, nsnull, nsnull); // the originating cell + if (!origData) return; + + // set the starting and ending col index for the new cell + PRInt32 colSpan = cellFrame->GetColSpan(); + totalColSpan += colSpan; + if (cellX == 0) { + endColIndex = aColIndex + colSpan - 1; + } + else { + startColIndex = endColIndex + 1; + endColIndex = startColIndex + colSpan - 1; + } + + // add the originating cell data and any cell data corresponding to row/col spans + for (PRInt32 rowX = aRowIndex; rowX <= endRowIndex; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + for (PRInt32 colX = aColIndex; colX <= endColIndex; colX++) { + row->InsertElementAt(nsnull, colX); + CellData* data = origData; + if ((rowX != aRowIndex) || (colX != startColIndex)) { + data = new CellData(nsnull, nsnull, nsnull); + if (!data) return; + if (rowX > aRowIndex) { + data->mRowSpanData = origData; + } + if (colX > startColIndex) { + data->mColSpanData = origData; + } + } + SetMapCellAt(*data, rowX, colX); // this increments the mNumColsOrigInCol array + } + } + cellFrame->InitCellFrame(startColIndex); + } + + // if new columns were added to the rows occupied by the new cells, + // update the other rows to have the same number of cols + PRInt32 numNewCols = ((nsVoidArray*)mRows.ElementAt(aRowIndex))->Count() - mCols.Count(); + if (numNewCols > 0) { + Grow(mRows.Count(), mCols.Count() + numNewCols); + } + + // update the row and col info due to shifting + for (PRInt32 rowX = aRowIndex; rowX <= endRowIndex; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + PRInt32 numCols = row->Count(); + for (PRInt32 colX = aColIndex + totalColSpan; colX < numCols; colX++) { + CellData* data = (CellData*) row->ElementAt(colX); + if (data) { + if (data->mOrigCell) { + // a cell that gets moved needs adjustment as well as it new orignating col + data->mOrigCell->SetColIndex(colX); + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsOrig++; + } + else if (data->mColSpanData) { + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsSpan++; + } + } + data = (CellData*) row->ElementAt(colX - totalColSpan); + if (data) { + if (data->mOrigCell) { + // the old originating col of a moved cell needs adjustment + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX - totalColSpan); + colInfo->mNumCellsOrig--; + } + else if (data->mColSpanData) { + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsSpan--; + } + } + } + } +} + +void nsCellMap::ShrinkWithoutRows(PRInt32 aStartRowIndex, + PRInt32 aNumRowsToRemove) +{ + PRInt32 endRowIndex = aStartRowIndex + aNumRowsToRemove - 1; + PRInt32 colCount = mCols.Count(); + for (PRInt32 rowX = endRowIndex; rowX >= aStartRowIndex; rowX--) { + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(rowX)); + PRInt32 colX; + for (colX = 0; colX < colCount; colX++) { + CellData* data = (CellData *) row->ElementAt(colX); + if (data) { + // Adjust the column counts. + if (data->mOrigCell) { + // Decrement the column count. + nsColInfo* colInfo = (nsColInfo *)(mCols.ElementAt(colX)); + colInfo->mNumCellsOrig--; + } + else if (data->mColSpanData) { + nsColInfo* colInfo = (nsColInfo *)(mCols.ElementAt(colX)); + colInfo->mNumCellsSpan--; + } + } + } + + // Delete our row information. + for (colX = 0; colX < colCount; colX++) { + CellData* data = (CellData *)(row->ElementAt(colX)); + if (data) { + delete data; + } + } + + mRows.RemoveElementAt(rowX); + delete row; + if(mIsCollapsedRows) { + RemoveFromCollapsedRows(rowX); + } + + // Decrement our row and next available index counts. + mRowCount--; + mNextAvailRowIndex--; + + // remove cols that may not be needed any more due to the removal of the rows + RemoveUnusedCols(colCount); + } +} + +void nsCellMap::ShrinkWithoutCell(nsTableCellFrame& aCellFrame, + PRInt32 aRowIndex, + PRInt32 aColIndex) +{ + PRInt32 rowSpan = aCellFrame.GetRowSpan(); + PRInt32 colSpan = aCellFrame.GetColSpan(); + PRInt32 endRowIndex = aRowIndex + rowSpan - 1; + PRInt32 endColIndex = aColIndex + colSpan - 1; + + PRInt32 colX; + // adjust the col counts due to the deleted cell before removing it + for (colX = aColIndex; colX <= endColIndex; colX++) { + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + if (colX == aColIndex) { + colInfo->mNumCellsOrig--; + } + else { + colInfo->mNumCellsSpan--; + } + } + + // remove the deleted cell and cellData entries for it + PRInt32 rowX; + for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + PRInt32 colX; + for (colX = aColIndex; colX <= endColIndex; colX++) { + row->RemoveElementAt(colX); + } + // put back null entries in the row to make it the right size + for (colX = 0; colX < colSpan; colX++) { + row->AppendElement(nsnull); + } + } + + PRInt32 numCols = mCols.Count(); + PRInt32 numRows = mRows.Count(); + + // update the row and col info due to shifting + for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + for (PRInt32 colX = aColIndex; colX < numCols - colSpan; colX++) { + CellData* data = (CellData*) row->ElementAt(colX); + if (data) { + if (data->mOrigCell) { + // a cell that gets moved to the left needs adjustment in its new location + data->mOrigCell->SetColIndex(colX); + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsOrig++; + // a cell that gets moved to the left needs adjustment in its old location + colInfo = (nsColInfo *)mCols.ElementAt(colX + colSpan); + if (colInfo) { + colInfo->mNumCellsOrig--; + } + } + else if (data->mColSpanData) { + // a cell that gets moved to the left needs adjustment in its new location + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsSpan++; + // a cell that gets moved to the left needs adjustment in its old location + colInfo = (nsColInfo *)mCols.ElementAt(colX + colSpan); + if (colInfo) { + colInfo->mNumCellsSpan--; + } + } + } + } + } + + // remove cols that may not be needed any more due to the removal of the cell + RemoveUnusedCols(mCols.Count()); +} + +PRInt32 +nsCellMap::RemoveUnusedCols(PRInt32 aMaxToRemove) +{ + PRInt32 numColsRemoved = 0; + for (PRInt32 colX = mCols.Count() - 1; colX >= 0; colX--) { + nsColInfo* colInfo = (nsColInfo *) mCols.ElementAt(colX); + if (!colInfo || (colInfo->mNumCellsOrig > 0) || (colInfo->mNumCellsSpan > 0)) { + return numColsRemoved; + } + else { + // remove the col from the cols array + nsColInfo* colInfo = (nsColInfo *) mCols.ElementAt(colX); + delete colInfo; + mCols.RemoveElementAt(colX); + + PRInt32 numMapRows = mRows.Count(); + // remove the col from each of the rows + for (PRInt32 rowX = 0; rowX < numMapRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + CellData* data = (CellData*) row->ElementAt(colX); + delete data; + row->RemoveElementAt(colX); + } + numColsRemoved++; + if (numColsRemoved >= aMaxToRemove) { + return numColsRemoved; + } + } + } + return numColsRemoved; +} + + +void +nsCellMap::RebuildConsideringRows(PRInt32 aStartRowIndex, + nsVoidArray* aRowsToInsert, + PRBool aNumRowsToRemove) +{ + PRInt32 numNewRows = 0; + // copy the old cell map into a new array + PRInt32 numOrigRows = mRows.Count(); + PRInt32 numOrigCols = mCols.Count(); + void** origRows = new void*[numOrigRows]; + if (!origRows) return; + PRInt32 rowX; + // copy the orig rows + for (rowX = 0; rowX < numOrigRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + origRows[rowX] = row; + } + for (PRInt32 colX = 0; colX < numOrigCols; colX++) { + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsOrig = 0; + } + mRows.Clear(); + mRowCount = 0; + mNextAvailRowIndex = 0; + if (aRowsToInsert) { + Grow(numOrigRows, numOrigCols); + } + + // put back the rows before the affected ones just as before + for (rowX = 0; rowX < aStartRowIndex; rowX++) { + nsVoidArray* row = (nsVoidArray *)origRows[rowX]; + PRInt32 numCols = row->Count(); + for (PRInt32 colX = 0; colX < numCols; colX++) { + // put in the original cell from the cell map + CellData* data = (CellData*) row->ElementAt(colX); + if (data && data->mOrigCell) { + AppendCell(data->mOrigCell, rowX, PR_FALSE); + } + } + mNextAvailRowIndex++; + } + PRInt32 copyStartRowIndex; + if (aRowsToInsert) { + // add in the new cells and create rows if necessary + PRInt32 numNewRows = aRowsToInsert->Count(); + rowX = aStartRowIndex; + for (PRInt32 newRowX = 0; newRowX < numNewRows; newRowX++) { + nsTableRowFrame* rFrame = (nsTableRowFrame *)aRowsToInsert->ElementAt(newRowX); + nsIFrame* cFrame = nsnull; + rFrame->FirstChild(nsnull, &cFrame); + while (cFrame) { + nsIAtom* cFrameType; + cFrame->GetFrameType(&cFrameType); + if (nsLayoutAtoms::tableCellFrame == cFrameType) { + AppendCell((nsTableCellFrame *)cFrame, rowX, PR_FALSE); + } + NS_IF_RELEASE(cFrameType); + cFrame->GetNextSibling(&cFrame); + } + rowX++; + } + copyStartRowIndex = aStartRowIndex; + } + else { + rowX = aStartRowIndex; + copyStartRowIndex = aStartRowIndex + aNumRowsToRemove; + } + // put back the rows after the affected ones just as before + PRInt32 copyEndRowIndex = numOrigRows - 1; + for (PRInt32 copyRowX = copyStartRowIndex; copyRowX <= copyEndRowIndex; copyRowX++) { + nsVoidArray* row = (nsVoidArray *)origRows[copyRowX]; + PRInt32 numCols = row->Count(); + for (PRInt32 colX = 0; colX < numCols; colX++) { + // put in the original cell from the cell map + CellData* data = (CellData*) row->ElementAt(colX); + if (data && data->mOrigCell) { + AppendCell(data->mOrigCell, rowX, PR_FALSE); + } + } + rowX++; + } + + mNextAvailRowIndex = mRowCount; + + // delete the old cell map + for (rowX = 0; rowX < numOrigRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)origRows[rowX]; + PRInt32 len = row->Count(); + for (PRInt32 colX = 0; colX < len; colX++) { + CellData* data = (CellData*) row->ElementAt(colX); + delete data; + } + delete row; + } + delete [] origRows; +} + +void nsCellMap::RebuildConsideringCells(nsVoidArray* aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndex, + PRBool aInsert) +{ + // copy the old cell map into a new array + PRInt32 numOrigRows = mRows.Count(); + PRInt32 numOrigCols = mCols.Count(); + void** origRows = new void*[numOrigRows]; + if (!origRows) return; + PRInt32 rowX; + for (rowX = 0; rowX < numOrigRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + origRows[rowX] = row; + } + // reinitialize data members + mRows.Clear(); + mRowCount = 0; + mNextAvailRowIndex = numOrigRows; + Grow(numOrigRows, numOrigCols); + + PRInt32 numNewCells = (aCellFrames) ? aCellFrames->Count() : 0; + // build the new cell map + for (rowX = 0; rowX < numOrigRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)origRows[rowX]; + PRInt32 numCols = row->Count(); + for (PRInt32 colX = 0; colX < numCols; colX++) { + if ((rowX == aRowIndex) && (colX == aColIndex)) { + if (aInsert) { // put in the new cells + for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) { + nsTableCellFrame* cell = (nsTableCellFrame*)aCellFrames->ElementAt(cellX); + AppendCell(cell, rowX, PR_FALSE); + } + } + else { + continue; // do not put the deleted cell back + } + } + // put in the original cell from the cell map + CellData* data = (CellData*) row->ElementAt(colX); + if (data && data->mOrigCell) { + AppendCell(data->mOrigCell, rowX, PR_FALSE); + } + } + } + + // delete the old cell map + for (rowX = 0; rowX < numOrigRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)origRows[rowX]; + PRInt32 len = row->Count(); + for (PRInt32 colX = 0; colX < len; colX++) { + CellData* data = (CellData*) row->ElementAt(colX); + delete data; + } + delete row; + } + delete [] origRows; +} + +void nsCellMap::RemoveCell(nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) +{ + PRInt32 numRows = mRows.Count(); + if ((aRowIndex < 0) || (aRowIndex >= numRows)) { + NS_ASSERTION(PR_FALSE, "bad arg in nsCellMap::RemoveCell"); + return; + } + PRInt32 numCols = mCols.Count(); + + // get the starting col index of the cell to remove + PRInt32 startColIndex; + for (startColIndex = 0; startColIndex < numCols; startColIndex++) { + CellData* data = GetMapCellAt(aRowIndex, startColIndex); + if (data && (aCellFrame == data->mOrigCell)) { + break; // we found the col index + } + } + + PRInt32 rowSpan = aCellFrame->GetRowSpan(); + PRInt32 endRowIndex = aRowIndex + rowSpan - 1; + PRInt32 endColIndex = startColIndex + aCellFrame->GetColSpan() - 1; + // record whether removing the cells is going to cause complications due + // to existing row spans, col spans or table sizing. + PRBool spansCauseRebuild = PR_FALSE; + + // check if removing the cell will cause the table to reduce the number of rows + if (endRowIndex == numRows) { + spansCauseRebuild = PR_TRUE; + for (PRInt32 rowX = aRowIndex; rowX <= endRowIndex; rowX++) { + for (PRInt32 colX = 0; colX < numCols; colX++) { + if ((colX < startColIndex) || (colX > endColIndex)) { + CellData* data = GetMapCellAt(rowX, colX); + if (data) { + // there is either an originating or spanned cell in a row of the cell + spansCauseRebuild = PR_FALSE; + break; + } + } + } + } + } + + if (!spansCauseRebuild) { + spansCauseRebuild = CellsSpanInOrOut(aRowIndex, aRowIndex + rowSpan - 1, startColIndex, numCols - 1); + } + + if (spansCauseRebuild) { + RebuildConsideringCells(nsnull, aRowIndex, startColIndex, PR_FALSE); + } + else { + ShrinkWithoutCell(*aCellFrame, aRowIndex, startColIndex); } } PRInt32 nsCellMap::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const { - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); if ((aColIndex >= 0) && (aColIndex < colCount)) { - return *((PRInt32 *)mNumCellsOrigInCol.ElementAt(aColIndex)); + return ((nsColInfo *)mCols.ElementAt(aColIndex))->mNumCellsOrig; } else { NS_ASSERTION(PR_FALSE, "nsCellMap::GetNumCellsOriginatingInCol - bad col index"); @@ -348,9 +971,9 @@ PRInt32 nsCellMap::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const #ifdef NS_DEBUG void nsCellMap::Dump() const { - printf("***** start CellMap Dump *****\n"); + printf("***** START CELL MAP DUMP *****\n"); PRInt32 mapRowCount = mRows.Count(); - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); PRInt32 colIndex; printf("mapRowCount=%d tableRowCount=%d, colCount=%d \n", mapRowCount, mRowCount, colCount); PRInt32 rowIndex; @@ -365,26 +988,32 @@ void nsCellMap::Dump() const printf("C%d,%d ", rowIndex, colIndex); } else { nsTableCellFrame* cell = nsnull; - int rr, cc; if (cd->mRowSpanData) { cell = cd->mRowSpanData->mOrigCell; - nsTableRowFrame* rowFrame; - cell->GetParent((nsIFrame**)&rowFrame); - rr = rowFrame->GetRowIndex(); - cell->GetColIndex(cc); - printf("r%d,%d ", rr, cc); + // check the validity of the cell map + nsVoidArray* rowAbove = (nsVoidArray *)mRows.ElementAt(rowIndex - 1); + CellData* cdAbove = (CellData *)rowAbove->ElementAt(colIndex); + if ((cdAbove->mOrigCell != cell) && (cdAbove->mRowSpanData->mOrigCell != cell)) { + NS_ASSERTION(PR_FALSE, "bad row span data"); + } + printf("R "); } - if (cd->mColSpanData){ + if (cd->mColSpanData) { cell = cd->mColSpanData->mOrigCell; - nsTableRowFrame* row2; - cell->GetParent((nsIFrame**)&row2); - rr = row2->GetRowIndex(); - cell->GetColIndex(cc); - printf("c%d,%d ", rr, cc); + // check the validity of the cell map + CellData* cdBefore = (CellData *)row->ElementAt(colIndex - 1); + if ((cdBefore->mOrigCell != cell) && (cdBefore->mColSpanData->mOrigCell != cell)) { + NS_ASSERTION(PR_FALSE, "bad col span data"); + } + printf("C "); + } + if (!(cd->mRowSpanData && cd->mColSpanData)) { + printf(" "); } + printf(" "); } } else { - printf("---- "); + printf("---- "); } } printf("\n"); @@ -409,28 +1038,12 @@ void nsCellMap::Dump() const printf("\n"); } - // output cells originating in rows - printf ("\ncells originating in rows array -> "); - for (rowIndex = 0; rowIndex < mapRowCount; rowIndex++) { - PRInt32* numCells = (PRInt32 *)mNumCellsOrigInRow.ElementAt(rowIndex); - printf ("%d=%d ", rowIndex, *numCells); - } - printf("\n"); - // output col frame info - printf("\n col frames ->"); - for (colIndex = 0; colIndex < mColFrames.Count(); colIndex++) { - nsTableColFrame* colFrame = (nsTableColFrame *)mColFrames.ElementAt(colIndex); - if (0 == (colIndex % 8)) - printf("\n"); - printf ("%d=%p ", colIndex, colFrame); - } - // output cells originating in cols - printf ("\ncells originating in cols array -> "); + // output col info + printf ("\ncols array orig/span-> "); for (colIndex = 0; colIndex < colCount; colIndex++) { - PRInt32* numCells = (PRInt32 *)mNumCellsOrigInCol.ElementAt(colIndex); - printf ("%d=%d ", colIndex, *numCells); + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colIndex); + printf ("%d=%d/%d ", colIndex, colInfo->mNumCellsOrig, colInfo->mNumCellsSpan); } - printf("\n"); printf("\n***** end CellMap Dump *****\n"); } #endif @@ -443,11 +1056,12 @@ void nsCellMap::SetMapCellAt(CellData& aNewCell, nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(aMapRowIndex)); row->ReplaceElementAt(&aNewCell, aColIndex); // update the originating cell counts if cell originates in this row, col + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(aColIndex); if (aNewCell.mOrigCell) { - PRInt32* numCells = (PRInt32 *)mNumCellsOrigInCol.ElementAt(aColIndex); - (*numCells)++; - numCells = (PRInt32 *)mNumCellsOrigInRow.ElementAt(aMapRowIndex); - (*numCells)++; + colInfo->mNumCellsOrig++; + } + else if (aNewCell.mColSpanData) { + colInfo->mNumCellsSpan++; } } @@ -460,7 +1074,7 @@ PRInt32 nsCellMap::GetEffectiveColSpan(PRInt32 aColIndex, aCell->GetRowIndex(initialRowX); PRInt32 effColSpan = 0; - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); for (PRInt32 colX = aColIndex; colX < colCount; colX++) { PRBool found = PR_FALSE; CellData* cellData = GetCellAt(initialRowX, colX); @@ -482,6 +1096,10 @@ PRInt32 nsCellMap::GetEffectiveColSpan(PRInt32 aColIndex, break; } } + if (effColSpan == 0) { + printf("cell = %p \n", aCell); + Dump(); + } NS_ASSERTION(effColSpan > 0, "invalid col span or col index"); return effColSpan; } @@ -530,13 +1148,6 @@ nsTableCellFrame* nsCellMap::GetCellInfoAt(PRInt32 aRowX, return cellFrame; } - - -nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex) const -{ - return (nsTableColFrame *)(mColFrames.ElementAt(aColIndex)); -} - PRInt32 nsCellMap::GetNumCollapsedRows() const { return mNumCollapsedRows; @@ -575,27 +1186,27 @@ void nsCellMap::SetRowCollapsedAt(PRInt32 aRow, PRBool aValue) void nsCellMap::InsertIntoCollapsedRows(PRInt32 aRow) { - if(mIsCollapsedRows) { - if((mRowCount + 1) > mIsCollapsedRowsSize){ + if (mIsCollapsedRows) { + if ((mRowCount + 1) > mIsCollapsedRowsSize){ PRInt32 newSize = mRowCount + kIsCollapsedRowsGrowSize; PRPackedBool * newIsCollapsedRows = new PRPackedBool[newSize]; - if(!newIsCollapsedRows) - return; + if(!newIsCollapsedRows) + return; if(aRow != 0) nsCRT::memcpy(newIsCollapsedRows, mIsCollapsedRows, aRow * sizeof (PRPackedBool)); if(aRow != mRowCount) nsCRT::memcpy(newIsCollapsedRows + aRow + 1, mIsCollapsedRows + aRow, - (mRowCount - aRow) * sizeof(PRPackedBool)); + (mRowCount - aRow) * sizeof(PRPackedBool)); delete[] mIsCollapsedRows; mIsCollapsedRows = newIsCollapsedRows; mIsCollapsedRowsSize = newSize; - } + } else { if(aRow != mRowCount) nsCRT::memmove(mIsCollapsedRows + aRow + 1, mIsCollapsedRows + aRow, - (mRowCount - aRow) * sizeof(PRPackedBool)); - } + (mRowCount - aRow) * sizeof(PRPackedBool)); + } mIsCollapsedRows[aRow] = PR_FALSE; } } @@ -620,7 +1231,7 @@ PRInt32 nsCellMap::GetNumCollapsedCols() const PRBool nsCellMap::IsColCollapsedAt(PRInt32 aCol) const { - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); if ((aCol >= 0) && (aCol < colCount)) { if (mIsCollapsedCols) { return mIsCollapsedCols[aCol]; @@ -631,7 +1242,7 @@ PRBool nsCellMap::IsColCollapsedAt(PRInt32 aCol) const void nsCellMap::SetColCollapsedAt(PRInt32 aCol, PRBool aValue) { - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); if ((aCol >= 0) && (aCol < colCount)) { if (nsnull == mIsCollapsedCols) { mIsCollapsedCols = new PRPackedBool[colCount]; @@ -655,7 +1266,7 @@ PRBool nsCellMap::RowIsSpannedInto(PRInt32 aRowIndex) const if ((0 > aRowIndex) || (aRowIndex >= mRowCount)) { return PR_FALSE; } - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++) { CellData* cd = GetCellAt(aRowIndex, colIndex); if (cd) { // there's really a cell at (aRowIndex, colIndex) @@ -673,7 +1284,7 @@ PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex) const if ((0 > aRowIndex) || (aRowIndex >= mRowCount)) { return PR_FALSE; } - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); if (aRowIndex != mRowCount - 1) { // aRowIndex is not the last row, so we check the next row after aRowIndex for spanners for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++) { @@ -692,7 +1303,7 @@ PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex) const PRBool nsCellMap::ColIsSpannedInto(PRInt32 aColIndex) const { - if ((0 > aColIndex) || (aColIndex >= mNumCellsOrigInCol.Count())) { + if ((0 > aColIndex) || (aColIndex >= mCols.Count())) { return PR_FALSE; } for (PRInt32 rowIndex = 0; rowIndex < mRowCount; rowIndex++) { @@ -709,8 +1320,8 @@ PRBool nsCellMap::ColIsSpannedInto(PRInt32 aColIndex) const PRBool nsCellMap::ColHasSpanningCells(PRInt32 aColIndex) const { - NS_PRECONDITION (aColIndex < mNumCellsOrigInCol.Count(), "bad col index arg"); - PRInt32 colCount = mNumCellsOrigInCol.Count(); + NS_PRECONDITION (aColIndex < mCols.Count(), "bad col index arg"); + PRInt32 colCount = mCols.Count(); if ((0 > aColIndex) || (aColIndex >= colCount - 1)) return PR_FALSE; @@ -740,12 +1351,8 @@ void nsCellMap::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const mRows.SizeOf(aHandler, &voidArraySize); sum += voidArraySize - sizeof(mRows); - mColFrames.SizeOf(aHandler, &voidArraySize); - sum += voidArraySize - sizeof(mColFrames); - mNumCellsOrigInRow.SizeOf(aHandler, &voidArraySize); - sum += voidArraySize - sizeof(mNumCellsOrigInRow); - mNumCellsOrigInCol.SizeOf(aHandler, &voidArraySize); - sum += voidArraySize - sizeof(mNumCellsOrigInCol); + mCols.SizeOf(aHandler, &voidArraySize); + sum += voidArraySize - sizeof(mCols); // Add in the size of the collapsed rows and collapsed column // packed bool arrays @@ -753,7 +1360,7 @@ void nsCellMap::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const sum += mRowCount * sizeof(PRPackedBool); } if (mIsCollapsedCols) { - sum += mNumCellsOrigInCol.Count() * sizeof(PRPackedBool); + sum += mCols.Count() * sizeof(PRPackedBool); } *aResult = sum; diff --git a/mozilla/layout/html/table/src/nsCellMap.h b/mozilla/layout/html/table/src/nsCellMap.h index 3e058cfff44..4d84149c90a 100644 --- a/mozilla/layout/html/table/src/nsCellMap.h +++ b/mozilla/layout/html/table/src/nsCellMap.h @@ -27,6 +27,22 @@ #include "nsVoidArray.h" class nsTableColFrame; class nsTableCellFrame; +class nsIPresContext; + +// XXX the collapsing row and col data structures need to be moved +// into nsTableFrame. Collapsing cols are broken due to the recent +// incremental cell map methods which don't attempt to update +// collapsing col info here. + +struct nsColInfo +{ + PRInt32 mNumCellsOrig; // number of cells originating in the col + PRInt32 mNumCellsSpan; // number of cells spanning into the col via colspans (not rowspans) + + nsColInfo(); + nsColInfo(PRInt32 aNumCellsOrig, + PRInt32 aNumCellsSpan); +}; /** nsCellMap is a support class for nsTablePart. * It maintains an Rows x Columns grid onto which the cells of the table are mapped. @@ -60,23 +76,29 @@ public: CellData* GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const; - /** insert a new row into the map - makes a blank row and adjusts spans - */ - void InsertRowIntoMap(PRInt32 aRowIndex); - - /** removes a row from the map and adjusts spans - */ - void RemoveRowFromMap(PRInt32 aRowIndex); + void AppendCol(); /** append the cellFrame at the end of the row at aRowIndex and return the col index */ PRInt32 AppendCell(nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex); + PRInt32 aRowIndex, + PRBool aRebuildIfNecessary); + + void InsertCells(nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndexBefore); void RemoveCell(nsTableCellFrame* aCellFrame, PRInt32 aRowIndex); + void InsertRows(nsVoidArray& aRows, + PRInt32 aFirstRowIndex, + PRBool aConsiderSpans); + + void RemoveRows(PRInt32 aFirstRowIndex, + PRInt32 aNumRowsToRemove, + PRBool aConsiderSpans); + PRInt32 GetNextAvailRowIndex(); PRInt32 GetEffectiveColSpan(nsTableCellFrame* aCell) const; @@ -102,17 +124,6 @@ public: /** return the actual number of rows in the table represented by this CellMap */ PRInt32 GetRowCount() const; - /** return the column frame associated with aColIndex */ - nsTableColFrame* GetColumnFrame(PRInt32 aColIndex) const; - - /** add a column frame to the list of column frames - * column frames must be added in order - */ - void AppendColumnFrame(nsTableColFrame *aColFrame); - - /** empty the column frame cache */ - void ClearColumnCache(); - // temporary until nsTableFrame::GetCellData uses GetCellFrameAt nsTableCellFrame* GetCellFrameOriginatingAt(PRInt32 aRowX, PRInt32 aColX) const; @@ -123,6 +134,7 @@ public: PRInt32* aColSpan = nsnull) const; void AddColsAtEnd(PRUint32 aNumCols); + PRInt32 RemoveUnusedCols(PRInt32 aMaxNumToRemove); PRBool RowIsSpannedInto(PRInt32 aRowIndex) const; PRBool RowHasSpanningCells(PRInt32 aRowIndex) const; @@ -156,23 +168,48 @@ protected: CellData* GetMapCellAt(PRInt32 aMapRowIndex, PRInt32 aColIndex) const; - PRInt32 GetNumCellsIn(PRInt32 aColIndex, - PRBool aOriginating) const; + PRInt32 GetNumCellsIn(PRInt32 aColIndex) const; + void ExpandWithRows(nsVoidArray& aRowFrames, + PRInt32 aStartRowIndex); + + void ExpandWithCells(nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndex, + PRInt32 aRowSpan); + + void ShrinkWithoutRows(PRInt32 aFirstRowIndex, + PRInt32 aNumRowsToRemove); + + void ShrinkWithoutCell(nsTableCellFrame& aCellFrame, + PRInt32 aRowIndex, + PRInt32 aColIndex); + + void RebuildConsideringRows(PRInt32 aStartRowIndex, + nsVoidArray* aRowsToInsert, + PRInt32 aNumRowsToRemove = 0); + + void RebuildConsideringCells(nsVoidArray* aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndex, + PRBool aInsert); + + PRBool CellsSpanOut(nsVoidArray& aNewRows); + + PRBool CellsSpanInOrOut(PRInt32 aStartRowIndex, + PRInt32 aEndRowIndex, + PRInt32 aStartColIndex, + PRInt32 aEndColIndex); + + PRBool CreateEmptyRow(PRInt32 aRowIndex, + PRInt32 aNumCols); /** an array containing col array. It can be larger than mRowCount due to * row spans extending beyond the table */ nsVoidArray mRows; - /** an array of col frames. It is as large as mRowCount */ - nsVoidArray mColFrames; - - /** an array of PRInt32 indexed by row and giving the number of cells originating - * in each row. */ - nsVoidArray mNumCellsOrigInRow; - - /** an array of PRInt32 indexed by col and giving the number of cells originating - * in each col. */ - nsVoidArray mNumCellsOrigInCol; + /** an array of nsColInfo indexed by col and giving the number of + * cells originating and spanning each col. */ + nsVoidArray mCols; // an array of booleans where the ith element indicates if the ith row is collapsed PRPackedBool* mIsCollapsedRows; @@ -196,7 +233,7 @@ inline CellData* nsCellMap::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const { if ((0 > aRowIndex) || (aRowIndex >= mRowCount) || - (0 > aColIndex) || (aColIndex >= mNumCellsOrigInCol.Count())) { + (0 > aColIndex) || (aColIndex >= mCols.Count())) { //bug 9024 tickled this //printf("%s \n", "nsCellMap::GetCellAt called with invalid row or col index"); // XXX look at this when bug 10911 get fixed return nsnull; @@ -213,7 +250,7 @@ inline CellData* nsCellMap::GetMapCellAt(PRInt32 aMapRowIndex, PRInt32 aColIndex) const { if ((0 > aMapRowIndex) || (aMapRowIndex >= mRows.Count()) || - (0 > aColIndex) || (aColIndex >= mNumCellsOrigInCol.Count())) { + (0 > aColIndex) || (aColIndex >= mCols.Count())) { //see bug 9024 comments above //printf("%s \n", "nsCellMap::GetMapCellAt called with invalid row or col index"); // XXX look at this when bug 10911 get fixed return nsnull; @@ -228,7 +265,7 @@ inline CellData* nsCellMap::GetMapCellAt(PRInt32 aMapRowIndex, inline PRInt32 nsCellMap::GetColCount() const { - return mNumCellsOrigInCol.Count(); + return mCols.Count(); } inline PRInt32 nsCellMap::GetRowCount() const @@ -236,15 +273,16 @@ inline PRInt32 nsCellMap::GetRowCount() const return mRowCount; } -inline void nsCellMap::AppendColumnFrame(nsTableColFrame *aColFrame) -{ - mColFrames.AppendElement(aColFrame); -} +// nsColInfo -inline void nsCellMap::ClearColumnCache() -{ - mColFrames.Clear(); -} +inline nsColInfo::nsColInfo() + :mNumCellsOrig(0), mNumCellsSpan(0) +{} + +inline nsColInfo::nsColInfo(PRInt32 aNumCellsOrig, + PRInt32 aNumCellsSpan) + :mNumCellsOrig(aNumCellsOrig), mNumCellsSpan(aNumCellsSpan) +{} #endif diff --git a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h index def6c668195..e0720d881f8 100644 --- a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h +++ b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h @@ -38,11 +38,9 @@ public: /** call once every time any table thing changes (content, structure, or style) * @param aMaxElementSize [OUT] if not null, the max element size is computed and returned in this param - * @param aNumCols the total number of columns in the table * @param aComputedWidth the computed size of the table */ virtual PRBool Initialize(nsSize* aMaxElementSize, - PRInt32 aNumCols, nscoord aComputedWidth)=0; /** compute the max-element-size for the table @@ -80,9 +78,6 @@ public: /** return the value of the COLS attribute, used for balancing column widths */ virtual nscoord GetCOLSAttribute() const = 0; - /** return the total number of columns in the table */ - virtual nscoord GetNumCols() const = 0; - // see nsTableFrame::ColumnsCanBeInvalidatedBy virtual PRBool ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, const nsTableCellFrame& aCellFrame) const = 0; diff --git a/mozilla/layout/html/table/src/nsTableBorderCollapser.cpp b/mozilla/layout/html/table/src/nsTableBorderCollapser.cpp index d5371e9e80c..e90a82cba61 100644 --- a/mozilla/layout/html/table/src/nsTableBorderCollapser.cpp +++ b/mozilla/layout/html/table/src/nsTableBorderCollapser.cpp @@ -146,8 +146,6 @@ void nsTableBorderCollapser::ComputeVerticalBorders(nsIPresContext* aPresContext //if (nsnull == cellMap) // return; // no info yet, so nothing useful to do - mTableFrame.CacheColFrames(aPresContext); // XXX why here? - // compute all the collapsing border values for the entire table // XXX: we have to make this more incremental! @@ -305,7 +303,7 @@ void nsTableBorderCollapser::ComputeRightBorderForEdgeAt(nsIPresContext* aPresCo styles.AppendElement((void*)spacing); } // 2. colgroup //XXX: need to test if we're really on a colgroup border - nsTableColFrame* colFrame = cellMap->GetColumnFrame(aColIndex); + nsTableColFrame* colFrame = mTableFrame.GetColFrame(aColIndex); nsIFrame* colGroupFrame; colFrame->GetParent(&colGroupFrame); colGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing)); @@ -402,7 +400,7 @@ void nsTableBorderCollapser::ComputeTopBorderForEdgeAt(nsIPresContext* aPresCont mTableFrame.GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing)); styles.AppendElement((void*)spacing); // 2. colgroup - nsTableColFrame* colFrame = cellMap->GetColumnFrame(aColIndex); + nsTableColFrame* colFrame = mTableFrame.GetColFrame(aColIndex); nsIFrame* colGroupFrame; colFrame->GetParent(&colGroupFrame); colGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing)); @@ -521,7 +519,7 @@ void nsTableBorderCollapser::ComputeBottomBorderForEdgeAt(nsIPresContext* aPresC styles.AppendElement((void*)spacing); // 2. colgroup // XXX: need to deterine if we're on a colgroup boundary - nsTableColFrame* colFrame = cellMap->GetColumnFrame(aColIndex); + nsTableColFrame* colFrame = mTableFrame.GetColFrame(aColIndex); nsIFrame* colGroupFrame; colFrame->GetParent(&colGroupFrame); colGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing)); diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp index 08940515386..cf9dd330f23 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp @@ -71,10 +71,9 @@ nsTableCellFrame::Init(nsIPresContext* aPresContext, if (aPrevInFlow) { // Set the column index nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow; - PRInt32 baseColIndex; - - cellFrame->GetColIndex(baseColIndex); - InitCellFrame(baseColIndex); + PRInt32 colIndex; + cellFrame->GetColIndex(colIndex); + InitCellFrame(colIndex); } return rv; @@ -139,29 +138,24 @@ nsTableCellFrame::RemoveFrame(nsIPresContext* aPresContext, void nsTableCellFrame::InitCellFrame(PRInt32 aColIndex) { - NS_PRECONDITION(0<=aColIndex, "bad col index arg"); - SetColIndex(aColIndex); // this also sets the contents col index nsTableFrame* tableFrame=nsnull; // I should be checking my own style context, but border-collapse isn't inheriting correctly nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) - { - if (NS_STYLE_BORDER_COLLAPSE == tableFrame->GetBorderCollapseStyle()) - { + if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) { + SetColIndex(aColIndex); + if (NS_STYLE_BORDER_COLLAPSE == tableFrame->GetBorderCollapseStyle()) { mBorderEdges = new nsBorderEdges; mBorderEdges->mOutsideEdge=PR_FALSE; PRInt32 rowspan = GetRowSpan(); PRInt32 i; - for (i=0; imEdges[NS_SIDE_LEFT].AppendElement(borderToAdd); borderToAdd = new nsBorderEdge(); mBorderEdges->mEdges[NS_SIDE_RIGHT].AppendElement(borderToAdd); } PRInt32 colspan = GetColSpan(); - for (i=0; imEdges[NS_SIDE_TOP].AppendElement(borderToAdd); borderToAdd = new nsBorderEdge(); diff --git a/mozilla/layout/html/table/src/nsTableColFrame.cpp b/mozilla/layout/html/table/src/nsTableColFrame.cpp index c7dcfdf0ef7..e4cceb6f942 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableColFrame.cpp @@ -19,6 +19,7 @@ * * Contributor(s): */ +#include "nsCOMPtr.h" #include "nsTableColFrame.h" #include "nsContainerFrame.h" #include "nsIReflowCommand.h" @@ -30,6 +31,11 @@ #include "nsCSSRendering.h" #include "nsLayoutAtoms.h" +#define COL_TYPE_CONTENT 0x0 +#define COL_TYPE_ANONYMOUS_COL 0x1 +#define COL_TYPE_ANONYMOUS_COLGROUP 0x2 +#define COL_TYPE_ANONYMOUS_CELL 0x3 + nsTableColFrame::nsTableColFrame() : nsFrame(), mProportion(WIDTH_NOT_SET), @@ -38,12 +44,55 @@ nsTableColFrame::nsTableColFrame() { // note that all fields are initialized to 0 by nsFrame::operator new ResetSizingInfo(); + SetType(eColContent); } nsTableColFrame::~nsTableColFrame() { } +nsTableColType nsTableColFrame::GetType() const { + switch(mBits.mType) { + case COL_TYPE_ANONYMOUS_COL: + return eColAnonymousCol; + case COL_TYPE_ANONYMOUS_COLGROUP: + return eColAnonymousColGroup; + case COL_TYPE_ANONYMOUS_CELL: + return eColAnonymousCell; + default: + return eColContent; + } +} + +void nsTableColFrame::SetType(nsTableColType aType) { + mBits.mType = aType - eColContent; +} + +// XXX what about other style besides width +nsStyleCoord nsTableColFrame::GetStyleWidth() const +{ + nsStylePosition* position = nsnull; + position = (nsStylePosition*)mStyleContext->GetStyleData(eStyleStruct_Position); + nsStyleCoord styleWidth = position->mWidth; + // the following should not be necessary since html.css defines table-col and + // :table-col to inherit. However, :table-col is not inheriting properly + if (eStyleUnit_Auto == styleWidth.GetUnit()) { + nsIFrame* parent; + GetParent(&parent); + nsCOMPtr styleContext; + parent->GetStyleContext(getter_AddRefs(styleContext)); + if (styleContext) { + position = (nsStylePosition*)styleContext->GetStyleData(eStyleStruct_Position); + styleWidth = position->mWidth; + } + } + + nsStyleCoord returnWidth; + returnWidth.mUnit = styleWidth.mUnit; + returnWidth.mValue = styleWidth.mValue; + return returnWidth; +} + void nsTableColFrame::ResetSizingInfo() { nsCRT::memset(mWidths, WIDTH_NOT_SET, NUM_WIDTHS * sizeof(PRInt32)); diff --git a/mozilla/layout/html/table/src/nsTableColFrame.h b/mozilla/layout/html/table/src/nsTableColFrame.h index 9a0207cfbc9..3a50b6e2859 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.h +++ b/mozilla/layout/html/table/src/nsTableColFrame.h @@ -55,6 +55,13 @@ enum nsColConstraint { e0ProportionConstraint = 4 // 0*, means to force to min width }; +enum nsTableColType { + eColContent = 0, // there is real col content associated + eColAnonymousCol = 1, // the result of a span on a col + eColAnonymousColGroup = 2, // the result of a span on a col group + eColAnonymousCell = 3, // the result of a cell alone +}; + class nsTableColFrame : public nsFrame { public: @@ -63,7 +70,8 @@ public: eWIDTH_SOURCE_CELL_WITH_SPAN=2 // a cell implicitly specified a width via colspan }; - void InitColFrame(PRInt32 aColIndex); + nsTableColType GetType() const; + void nsTableColFrame::SetType(nsTableColType aType); /** instantiate a new instance of nsTableColFrame. * @param aResult the new object is returned in this out-param @@ -75,6 +83,12 @@ public: friend nsresult NS_NewTableColFrame(nsIPresShell* aPresShell, nsIFrame** aResult); + nsStyleCoord GetStyleWidth() const; + + PRInt32 GetColIndex() const; + + void SetColIndex (PRInt32 aColIndex); + NS_IMETHOD Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -97,15 +111,9 @@ public: NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const; #endif - /** return the index of the column the col represents. always >= 0 */ - virtual PRInt32 GetColumnIndex (); - /** return the number of the columns the col represents. always >= 0 */ virtual PRInt32 GetSpan (); - /** set the index of the column this content object represents. must be >= 0 */ - virtual void SetColumnIndex (int aColIndex); - /** convenience method, calls into cellmap */ nsVoidArray * GetCells(); @@ -138,6 +146,11 @@ public: protected: + struct ColBits { + unsigned int mType:4; + unsigned int mUnused:28; + } mBits; + nsTableColFrame(); ~nsTableColFrame(); @@ -153,18 +166,11 @@ protected: PRPackedBool mNonPercentSpansPercent; }; - -inline void nsTableColFrame::InitColFrame(PRInt32 aColIndex) -{ - NS_ASSERTION(0<=aColIndex, "bad col index param"); - mColIndex = aColIndex; -} - -inline PRInt32 nsTableColFrame::GetColumnIndex() +inline PRInt32 nsTableColFrame::GetColIndex() const { return mColIndex; } -inline void nsTableColFrame::SetColumnIndex (int aColIndex) -{ mColIndex = aColIndex;} +inline void nsTableColFrame::SetColIndex (PRInt32 aColIndex) +{ mColIndex = aColIndex; } inline nsColConstraint nsTableColFrame::GetConstraint() const { return mConstraint; } diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp index 0a1ecf5ef71..00ed27bcb09 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp @@ -23,6 +23,7 @@ #include "nsTableColFrame.h" #include "nsTableFrame.h" #include "nsIHTMLTableColElement.h" +#include "nsIDOMHTMLTableColElement.h" #include "nsIReflowCommand.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" @@ -40,101 +41,230 @@ NS_DEF_PTR(nsIContent); static NS_DEFINE_IID(kIHTMLTableColElementIID, NS_IHTMLTABLECOLELEMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLTableColElementIID, NS_IDOMHTMLTABLECOLELEMENT_IID); + +#define COLGROUP_TYPE_CONTENT 0x0 +#define COLGROUP_TYPE_ANONYMOUS_COL 0x1 +#define COLGROUP_TYPE_ANONYMOUS_CELL 0x2 + +nsTableColGroupType nsTableColGroupFrame::GetType() const { + switch(mBits.mType) { + case COLGROUP_TYPE_ANONYMOUS_COL: + return eColGroupAnonymousCol; + case COLGROUP_TYPE_ANONYMOUS_CELL: + return eColGroupAnonymousCell; + default: + return eColGroupContent; + } +} + +void nsTableColGroupFrame::SetType(nsTableColGroupType aType) { + mBits.mType = aType - eColGroupContent; +} + +void nsTableColGroupFrame::ResetColIndices(nsIFrame* aFirstColGroup, + PRInt32 aFirstColIndex, + nsIFrame* aStartColFrame) +{ + nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame*)aFirstColGroup; + PRInt32 colIndex = aFirstColIndex; + while (colGroupFrame) { + nsIAtom* cgType; + colGroupFrame->GetFrameType(&cgType); + if (nsLayoutAtoms::tableColGroupFrame == cgType) { + colGroupFrame->SetStartColumnIndex(colIndex); + nsIFrame* colFrame = aStartColFrame; + if (!colFrame || (colIndex != aFirstColIndex)) { + colGroupFrame->FirstChild(nsnull, &colFrame); + } + while (colFrame) { + nsIAtom* colType; + colFrame->GetFrameType(&colType); + if (nsLayoutAtoms::tableColFrame == colType) { + ((nsTableColFrame*)colFrame)->SetColIndex(colIndex); + colIndex++; + } + NS_IF_RELEASE(colType); + colFrame->GetNextSibling(&colFrame); + } + } + NS_IF_RELEASE(cgType); + colGroupFrame->GetNextSibling((nsIFrame**)&colGroupFrame); + } +} + NS_IMETHODIMP -nsTableColGroupFrame::InitNewFrames(nsIPresContext* aPresContext, nsIFrame* aChildList) +nsTableColGroupFrame::AddColsToTable(nsIPresContext& aPresContext, + PRInt32 aFirstColIndex, + PRBool aResetSubsequentColIndices, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame) { - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - nsresult rv=NS_OK; - nsTableFrame* tableFrame=nsnull; + nsresult rv = NS_OK; + nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) { - // Process the newly added column frames - for (nsIFrame* kidFrame = aChildList; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { - const nsStyleDisplay* display; - kidFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == display->mDisplay) { - // Set the preliminary values for the column frame - PRInt32 colIndex = mStartColIndex + mColCount; - ((nsTableColFrame *)(kidFrame))->InitColFrame (colIndex); - PRInt32 repeat = ((nsTableColFrame *)(kidFrame))->GetSpan(); - mColCount += repeat; - for (PRInt32 i=0; iAddColumnFrame((nsTableColFrame *)kidFrame); - } - } - } - // colgroup's span attribute is how many columns the group represents - // in the absence of any COL children - // Note that this is the correct, though perhaps unexpected, behavior for the span attribute. - // The spec says that if there are any COL children, the colgroup's span is ignored. - if (0==mColCount) - { - nsIFrame *firstImplicitColFrame=nsnull; - nsIFrame *prevColFrame=nsnull; - nsAutoString colTag; - nsHTMLAtoms::col->ToString(colTag); - mColCount = GetSpan(); - for (PRInt32 colIndex=0; colIndexAppendChildTo((nsIContent*)col, PR_FALSE); - - // Create a new col frame - nsIFrame* colFrame; - NS_NewTableColFrame(shell, &colFrame); - - // Set its style context - nsCOMPtr colStyleContext; - aPresContext->ResolveStyleContextFor(col, mStyleContext, - PR_TRUE, - getter_AddRefs(colStyleContext)); - colFrame->Init(aPresContext, col, this, colStyleContext, nsnull); - colFrame->SetInitialChildList(aPresContext, nsnull, nsnull); - - // Set nsColFrame-specific information - PRInt32 absColIndex = mStartColIndex + colIndex; - ((nsTableColFrame *)(colFrame))->InitColFrame (absColIndex); - ((nsTableColFrame *)colFrame)->SetColumnIndex(absColIndex); - tableFrame->AddColumnFrame((nsTableColFrame *)colFrame); - - //hook into list of children - if (nsnull==firstImplicitColFrame) - firstImplicitColFrame = colFrame; - else - prevColFrame->SetNextSibling(colFrame); - prevColFrame = colFrame; - } - - // hook new columns into col group child list - mFrames.AppendFrames(nsnull, firstImplicitColFrame); - } - SetStyleContextForFirstPass(aPresContext); + if (!(NS_SUCCEEDED(rv) && tableFrame && aFirstFrame)) { + return rv; } + + // set the col indices of the col frames and and add col info to the table + PRInt32 colIndex = aFirstColIndex; + nsIFrame* kidFrame = aFirstFrame; + PRBool foundLastFrame = PR_FALSE; + while (kidFrame) { + nsIAtom* kidType; + kidFrame->GetFrameType(&kidType); + if (nsLayoutAtoms::tableColFrame == kidType) { + ((nsTableColFrame*)kidFrame)->SetColIndex(colIndex); + if (!foundLastFrame) { + tableFrame->InsertCol(aPresContext, (nsTableColFrame &)*kidFrame, colIndex); + mColCount++; + } + colIndex++; + } + NS_IF_RELEASE(kidType); + if (kidFrame == aLastFrame) { + foundLastFrame = PR_TRUE; + } + kidFrame->GetNextSibling(&kidFrame); + } + + if (aResetSubsequentColIndices) { + nsIFrame* nextSibling; + GetNextSibling(&nextSibling); + if (nextSibling) { + ResetColIndices(nextSibling, colIndex); + } + } + return rv; } -NS_IMETHODIMP -nsTableColGroupFrame::AppendNewFrames(nsIPresContext* aPresContext, nsIFrame* aChildList) +// this is called when a col frame doesn't have an explicit col group parent. +nsTableColGroupFrame* +nsTableColGroupFrame::FindParentForAppendedCol(nsTableFrame* aTableFrame, + nsTableColType aColType) { - if (nsnull!=aChildList) - mFrames.AppendFrames(nsnull, aChildList); - return NS_OK; + nsVoidArray& cols = aTableFrame->GetColCache(); + PRInt32 numCols = cols.Count(); + nsIFrame* lastColGroup; + nsIFrame* lastCol = (nsIFrame*)cols.ElementAt(numCols - 1); + if (!lastCol) return nsnull; // no columns so no colgroups + lastCol->GetParent(&lastColGroup); + if (!lastColGroup) return nsnull; // shouldn't happen + + nsTableColGroupFrame* relevantColGroup = (nsTableColGroupFrame *)lastColGroup; + nsTableColGroupType relevantColGroupType = relevantColGroup->GetType(); + if (eColGroupAnonymousCell == relevantColGroupType) { + if (eColAnonymousCell == aColType) { + return relevantColGroup; + } + else { + // find the next to last col group + for (PRInt32 colX = numCols - 2; colX >= 0; colX--) { + nsTableColFrame* colFrame = (nsTableColFrame*)cols.ElementAt(colX); + nsTableColGroupFrame* colGroupFrame; + colFrame->GetParent((nsIFrame**)&colGroupFrame); + nsTableColGroupType cgType = colGroupFrame->GetType(); + if (cgType != relevantColGroupType) { + relevantColGroup = colGroupFrame; + relevantColGroupType = cgType; + break; + } + else if (0 == colX) { + return nsnull; + } + } + } + } + + if (eColGroupAnonymousCol == relevantColGroupType) { + if ((eColContent == aColType) || (eColAnonymousCol == aColType)) { + return relevantColGroup; + } + } + + return nsnull; } +PRBool +nsTableColGroupFrame::GetLastRealColGroup(nsTableFrame* aTableFrame, + nsIFrame** aLastColGroup) +{ + *aLastColGroup = nsnull; + nsFrameList colGroups = aTableFrame->GetColGroups(); + + nsIFrame* nextToLastColGroup = nsnull; + nsIFrame* lastColGroup = colGroups.FirstChild(); + while(lastColGroup) { + nsIFrame* next; + lastColGroup->GetNextSibling(&next); + if (next) { + nextToLastColGroup = lastColGroup; + lastColGroup = next; + } + else { + break; + } + } + + if (!lastColGroup) return PR_TRUE; // there are no col group frames + + nsTableColGroupType lastColGroupType = ((nsTableColGroupFrame *)lastColGroup)->GetType(); + if (eColGroupAnonymousCell == lastColGroupType) { + *aLastColGroup = nextToLastColGroup; + return PR_FALSE; + } + else { + *aLastColGroup = lastColGroup; + return PR_TRUE; + } +} + +// don't set mColCount here, it is done in AddColsToTable NS_IMETHODIMP nsTableColGroupFrame::SetInitialChildList(nsIPresContext* aPresContext, nsIAtom* aListName, nsIFrame* aChildList) { - nsresult result = AppendNewFrames(aPresContext, aChildList); - if (NS_OK==result) - result = InitNewFrames(aPresContext, aChildList); - return result; + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + if (!aChildList) { + nsIFrame* firstChild; + tableFrame->CreateAnonymousColFrames(*aPresContext, *this, GetSpan(), eColAnonymousColGroup, + PR_FALSE, nsnull, &firstChild); + if (firstChild) { + SetInitialChildList(aPresContext, aListName, firstChild); + } + return NS_OK; + } + + nsIFrame* kidFrame = aChildList; + while (kidFrame) { + nsIAtom* kidType; + kidFrame->GetFrameType(&kidType); + if (nsLayoutAtoms::tableColFrame == kidType) { + // Set the preliminary values for the column frame + PRInt32 span = ((nsTableColFrame*)kidFrame)->GetSpan(); + if (span > 1) { + nsTableColFrame* firstSpannedCol; + tableFrame->CreateAnonymousColFrames(*aPresContext, *this, span - 1, eColAnonymousCol, + PR_FALSE, (nsTableColFrame*)kidFrame, (nsIFrame **)&firstSpannedCol); + nsIFrame* spanner = kidFrame; + kidFrame->GetNextSibling(&kidFrame); // need to do this before we insert the new frames + nsFrameList newChildren(aChildList); // used as a convience to hook up siblings + newChildren.InsertFrames(this, (nsTableColFrame*)spanner, (nsIFrame *)firstSpannedCol); + NS_RELEASE(kidType); + continue; + } + } + NS_IF_RELEASE(kidType); + kidFrame->GetNextSibling(&kidFrame); + } + + mFrames.AppendFrames(this, aChildList); + return NS_OK; } // Helper function. It marks the table frame as dirty and generates @@ -173,35 +303,8 @@ nsTableColGroupFrame::AppendFrames(nsIPresContext* aPresContext, nsIAtom* aListName, nsIFrame* aFrameList) { - // Append the new frames to our child list - mFrames.AppendFrames(nsnull, aFrameList); - - // Reset the starting column index of the col groups that follow - PRInt32 startingColIndex = mStartColIndex; - startingColIndex += GetColumnCount(); // has the side effect of resetting all column indexes - - nsIFrame *nextColGroupFrame=nsnull; - GetNextSibling(&nextColGroupFrame); - while (nextColGroupFrame) - { - const nsStyleDisplay *display; - nextColGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) - { - startingColIndex += ((nsTableColGroupFrame *)nextColGroupFrame)->SetStartColumnIndex(startingColIndex); - } - nextColGroupFrame->GetNextSibling(&nextColGroupFrame); - } - - // Today we need to rebuild the whole column cache. - // If the table frame is ever recoded to build the column cache incrementally, - // we could take advantage of that here - nsTableFrame* tableFrame; - nsTableFrame::GetTableFrame(this, tableFrame); - tableFrame->InvalidateColumnCache(); - - // Generate a reflow command so we reflow the table - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); + mFrames.AppendFrames(this, aFrameList); + InsertColsReflow(*aPresContext, aPresShell, mColCount, aFrameList); return NS_OK; } @@ -209,76 +312,121 @@ NS_IMETHODIMP nsTableColGroupFrame::InsertFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, - nsIFrame* aPrevFrame, + nsIFrame* aPrevFrameIn, nsIFrame* aFrameList) { - // Insert the new frames into our child list - mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); + nsFrameList frames(aFrameList); // convience for getting last frame + nsIFrame* lastFrame = frames.LastChild(); - // Reset the starting column index of the col groups that follow - PRInt32 startingColIndex=mStartColIndex; - startingColIndex += GetColumnCount(); // has the side effect of resetting all column indexes + mFrames.InsertFrames(this, aPrevFrameIn, aFrameList); + nsIFrame* prevFrame = nsTableFrame::GetFrameAtOrBefore(this, aPrevFrameIn, + nsLayoutAtoms::tableColFrame); - nsIFrame *nextColGroupFrame=nsnull; - GetNextSibling(&nextColGroupFrame); - while (nextColGroupFrame) - { - const nsStyleDisplay *display; - nextColGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) - { - startingColIndex += ((nsTableColGroupFrame *)nextColGroupFrame)->SetStartColumnIndex(startingColIndex); - } - nextColGroupFrame->GetNextSibling(&nextColGroupFrame); - } + PRInt32 colIndex = (prevFrame) ? ((nsTableColFrame*)prevFrame)->GetColIndex() + 1 : 0; + InsertColsReflow(*aPresContext, aPresShell, colIndex, aFrameList, lastFrame); - // Today we need to rebuild the whole column cache. - // If the table frame is ever recoded to build the column cache incrementally, - // we could take advantage of that here. - nsTableFrame* tableFrame; - nsTableFrame::GetTableFrame(this, tableFrame); - tableFrame->InvalidateColumnCache(); - - // Generate a reflow command so we reflow the table - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); return NS_OK; } +void +nsTableColGroupFrame::InsertColsReflow(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + PRInt32 aColIndex, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame) +{ + AddColsToTable(aPresContext, aColIndex, PR_TRUE, aFirstFrame, aLastFrame); + + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + tableFrame->InvalidateColumnWidths(); + + // Generate a reflow command so we reflow the table + AddTableDirtyReflowCommand(&aPresContext, aPresShell, tableFrame); +} + +void +nsTableColGroupFrame::RemoveChild(nsIPresContext& aPresContext, + nsTableColFrame& aChild, + PRBool aResetColIndices) +{ + PRInt32 colIndex = 0; + nsIFrame* nextChild = nsnull; + if (aResetColIndices) { + colIndex = aChild.GetColIndex(); + aChild.GetNextSibling(&nextChild); + } + if (mFrames.DestroyFrame(&aPresContext, (nsIFrame*)&aChild)) { + mColCount--; + if (aResetColIndices) { + ResetColIndices(this, colIndex, nextChild); + } + } +} + +// this removes children form the last col group (eColGroupAnonymousCell) in the +// table only,so there is no need to reset col indices for subsequent col groups. +void +nsTableColGroupFrame::RemoveChildrenAtEnd(nsIPresContext& aPresContext, + PRInt32 aNumChildrenToRemove) +{ + PRInt32 numToRemove = aNumChildrenToRemove; + if (numToRemove > mColCount) { + NS_ASSERTION(PR_FALSE, "invalid arg to RemoveChildrenAtEnd"); + numToRemove = mColCount; + } + PRInt32 offsetOfFirstRemoval = mColCount - numToRemove; + PRInt32 offsetX = 0; + nsIFrame* kidFrame = mFrames.FirstChild(); + while(kidFrame) { + nsIAtom* kidType; + kidFrame->GetFrameType(&kidType); + if (nsLayoutAtoms::tableColFrame == kidType) { + offsetX++; + if (offsetX > offsetOfFirstRemoval) { + nsIFrame* byebye = kidFrame; + kidFrame->GetNextSibling(&kidFrame); + mFrames.DestroyFrame(&aPresContext, byebye); + NS_RELEASE(kidType); + continue; + } + } + NS_IF_RELEASE(kidType); + kidFrame->GetNextSibling(&kidFrame); + } +} + + NS_IMETHODIMP nsTableColGroupFrame::RemoveFrame(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aOldFrame) { - // Remove the frame from our child list - mFrames.DestroyFrame(aPresContext, aOldFrame); + if (!aOldFrame) return NS_OK; - // Reset the starting column index of the col groups that follow - PRInt32 startingColIndex=mStartColIndex; - startingColIndex += GetColumnCount(); // has the side effect of resetting all column indexes - - nsIFrame *nextColGroupFrame=nsnull; - GetNextSibling(&nextColGroupFrame); - while (nextColGroupFrame) - { - const nsStyleDisplay *display; - nextColGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) - { - startingColIndex += ((nsTableColGroupFrame *)nextColGroupFrame)->SetStartColumnIndex(startingColIndex); + nsIAtom* frameType = nsnull; + aOldFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableColFrame == frameType) { + nsTableColFrame* colFrame = (nsTableColFrame*)aOldFrame; + PRInt32 colIndex = colFrame->GetColIndex(); + RemoveChild(*aPresContext, *colFrame, PR_TRUE); + + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + if (tableFrame) { + tableFrame->RemoveCol(*aPresContext, this, colIndex, PR_TRUE, PR_TRUE); } - nextColGroupFrame->GetNextSibling(&nextColGroupFrame); + + tableFrame->InvalidateColumnWidths(); + // Generate a reflow command so we reflow the table + AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); } + else { + mFrames.DestroyFrame(aPresContext, aOldFrame); + } + NS_IF_RELEASE(frameType); - // Today we need to rebuild the whole column cache. - // If the table frame is ever recoded to build the column cache incrementally, - // we could take advantage of that here - nsTableFrame* tableFrame; - nsTableFrame::GetTableFrame(this, tableFrame); - tableFrame->InvalidateColumnCache(); - - // Generate a reflow command so we reflow the table - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); return NS_OK; } @@ -429,11 +577,10 @@ NS_METHOD nsTableColGroupFrame::IR_StyleChanged(nsIPresContext* aPresCo nsresult rv = NS_OK; // we presume that all the easy optimizations were done in the nsHTMLStyleSheet before we were called here // XXX: we can optimize this when we know which style attribute changed - nsTableFrame* tableFrame=nsnull; + nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) - { - tableFrame->InvalidateColumnCache(); + if ((NS_SUCCEEDED(rv)) && tableFrame) { + tableFrame->InvalidateColumnWidths(); tableFrame->InvalidateFirstPassCache(); } return rv; @@ -448,7 +595,7 @@ NS_METHOD nsTableColGroupFrame::IR_TargetIsChild(nsIPresContext* aPresC nsresult rv; // Remember the old col count - const PRInt32 oldColCount = GetColumnCount(); + const PRInt32 oldColCount = GetColCount(); // Pass along the reflow command nsHTMLReflowMetrics desiredSize(nsnull); @@ -462,136 +609,16 @@ NS_METHOD nsTableColGroupFrame::IR_TargetIsChild(nsIPresContext* aPresC nsTableFrame *tableFrame=nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) - { + if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) { // compare the new col count to the old col count. // If they are the same, we just need to rebalance column widths // If they differ, we need to fix up other column groups and the column cache - const PRInt32 newColCount = GetColumnCount(); // this will set the new column indexes if necessary - if (oldColCount==newColCount) - tableFrame->InvalidateColumnWidths(); - else - tableFrame->InvalidateColumnCache(); + const PRInt32 newColCount = GetColCount(); + tableFrame->InvalidateColumnWidths(); } return rv; } -// Subclass hook for style post processing -NS_METHOD nsTableColGroupFrame::SetStyleContextForFirstPass(nsIPresContext* aPresContext) -{ - // get the table frame - nsTableFrame* tableFrame=nsnull; - nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) - { - // get the style for the table frame - const nsStyleTable *tableStyle; - tableFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle); - - // if COLS is set, then map it into the COL frames - if (NS_STYLE_TABLE_COLS_NONE != tableStyle->mCols) - { - // set numCols to the number of columns effected by the COLS attribute - PRInt32 numCols=0; - if (NS_STYLE_TABLE_COLS_ALL == tableStyle->mCols) - numCols = mFrames.GetLength(); - else - numCols = tableStyle->mCols; - - // for every column effected, set its width style - PRInt32 colIndex=0; - nsIFrame *colFrame=mFrames.FirstChild(); - while (nsnull!=colFrame) - { - const nsStyleDisplay * colDisplay=nsnull; - colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) - { - nsCOMPtr colStyleContext; - nsStylePosition * colPosition=nsnull; - colFrame->GetStyleContext(getter_AddRefs(colStyleContext)); - colPosition = (nsStylePosition*)colStyleContext->GetMutableStyleData(eStyleStruct_Position); - if (colIndexmWidth = width; - } - else - { - colPosition->mWidth.SetCoordValue(0); - } - colStyleContext->RecalcAutomaticData(aPresContext); - colIndex++; - } - colFrame->GetNextSibling(&colFrame); - } - } - else - { - // propagate the colgroup width attribute down to the columns if they have no width of their own - nsStylePosition* position = (nsStylePosition*)mStyleContext->GetStyleData(eStyleStruct_Position); - if (eStyleUnit_Null!=position->mWidth.GetUnit()) - { - // now for every column that doesn't have it's own width, set the width style - nsIFrame *colFrame=mFrames.FirstChild(); - while (nsnull!=colFrame) - { - const nsStyleDisplay * colDisplay=nsnull; - colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) - { - nsCOMPtr colStyleContext; - const nsStylePosition * colPosition=nsnull; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); // get a read-only version of the style context - //XXX: how do I know this is auto because it's defaulted, vs. set explicitly to "auto"? - if (eStyleUnit_Auto==colPosition->mWidth.GetUnit()) - { - // notice how we defer getting a mutable style context until we're sure we really need one - colFrame->GetStyleContext(getter_AddRefs(colStyleContext)); - nsStylePosition * mutableColPosition = (nsStylePosition*)colStyleContext->GetMutableStyleData(eStyleStruct_Position); - mutableColPosition->mWidth = position->mWidth; - colStyleContext->RecalcAutomaticData(aPresContext); - } - } - colFrame->GetNextSibling(&colFrame); - } - } - } - //mStyleContext->RecalcAutomaticData(aPresContext); - } - return rv; -} - - -/** returns the number of columns represented by this group. - * if there are col children, count them (taking into account the span of each) - * else, check my own span attribute. - */ -int nsTableColGroupFrame::GetColumnCount () -{ - mColCount=0; - nsIFrame *childFrame = mFrames.FirstChild(); - while (nsnull!=childFrame) - { - const nsStyleDisplay *childDisplay; - childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == childDisplay->mDisplay) - { - nsTableColFrame *col = (nsTableColFrame *)childFrame; - col->SetColumnIndex (mStartColIndex + mColCount); - mColCount += col->GetSpan(); - } - childFrame->GetNextSibling(&childFrame); - } - if (0==mColCount) - { // there were no children of this colgroup that were columns. So use my span attribute - const nsStyleTable *tableStyle; - GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle); - mColCount = tableStyle->mSpan; - } - return mColCount; -} - nsTableColFrame * nsTableColGroupFrame::GetFirstColumn() { return GetNextColumn(nsnull); @@ -642,28 +669,26 @@ nsTableColFrame * nsTableColGroupFrame::GetColumnAt (PRInt32 aColIndex) PRInt32 nsTableColGroupFrame::GetSpan() { - PRInt32 span=1; - const nsStyleTable* tableStyle=nsnull; - GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle); - if (nsnull!=tableStyle) - { - span = tableStyle->mSpan; + PRInt32 span = 1; + nsCOMPtr iContent; + nsresult rv = GetContent(getter_AddRefs(iContent)); + if (NS_FAILED(rv) || !iContent) return rv; + + // col group element derives from col element + nsIDOMHTMLTableColElement* cgContent = nsnull; + rv = iContent->QueryInterface(kIDOMHTMLTableColElementIID, + (void **)&cgContent); + if (cgContent && NS_SUCCEEDED(rv)) { + cgContent->GetSpan(&span); + // XXX why does this work!! + if (span == -1) { + span = 1; + } + NS_RELEASE(cgContent); } return span; } -/* this may be needed when IsSynthetic is properly implemented -PRBool nsTableColGroupFrame::IsManufactured() -{ - PRBool result = PR_FALSE; - nsIFrame *firstCol = GetFirstColumn(); - if (nsTableFrame::IsSynthetic(this) && - ((nsnull==firstCol) || nsTableFrame::IsSynthetic(firstCol))) - result = PR_TRUE; - return result; -} -*/ - /** returns colcount because it is frequently used in the context of * shuffling relative colgroup order, and it's convenient to not have to * call GetColumnCount redundantly. @@ -671,15 +696,41 @@ PRBool nsTableColGroupFrame::IsManufactured() PRInt32 nsTableColGroupFrame::SetStartColumnIndex (int aIndex) { PRInt32 result = mColCount; - if (aIndex != mStartColIndex) - { + if (aIndex != mStartColIndex) { mStartColIndex = aIndex; - mColCount=0; - result = GetColumnCount(); // has the side effect of setting each column index based on new start index + result = GetColCount(); } return result; } + +// this could be optimized by using col group frame starting indicies, +// but typically there aren't enough very large col groups for the added complexity. +nsTableColGroupFrame* +nsTableColGroupFrame::GetColGroupFrameContaining(nsFrameList& aColGroupList, + nsTableColFrame& aColFrame) +{ + nsIFrame* childFrame = aColGroupList.FirstChild(); + while (childFrame) { + nsIAtom* frameType = nsnull; + childFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableColGroupFrame == frameType) { + nsTableColFrame* colFrame = nsnull; + childFrame->FirstChild(nsnull, (nsIFrame **)&colFrame); + while (colFrame) { + if (colFrame = &aColFrame) { + NS_RELEASE(frameType); + return (nsTableColGroupFrame *)childFrame; + } + colFrame->GetNextSibling((nsIFrame **)&colFrame); + } + } + NS_IF_RELEASE(frameType); + childFrame->GetNextSibling(&childFrame); + } + return nsnull; +} + void nsTableColGroupFrame::DeleteColFrame(nsIPresContext* aPresContext, nsTableColFrame* aColFrame) { mFrames.DestroyFrame(aPresContext, aColFrame); diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.h b/mozilla/layout/html/table/src/nsTableColGroupFrame.h index 98759866de6..93125656a53 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.h +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.h @@ -26,7 +26,14 @@ #include "nsHTMLContainerFrame.h" class nsTableColFrame; +class nsTableFrame; +enum nsTableColType; +enum nsTableColGroupType { + eColGroupContent = 0, // there is real col group content associated + eColGroupAnonymousCol = 1, // the result of a col + eColGroupAnonymousCell = 2, // the result of a cell alone +}; /** * nsTableColGroupFrame @@ -52,6 +59,16 @@ public: nsIAtom* aListName, nsIFrame* aChildList); + nsTableColGroupType GetType() const; + + void SetType(nsTableColGroupType aType); + + static PRBool GetLastRealColGroup(nsTableFrame* aTableFrame, + nsIFrame** aLastColGroup); + + static nsTableColGroupFrame* FindParentForAppendedCol(nsTableFrame* aTableFrame, + nsTableColType aColType); + NS_IMETHOD AppendFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, @@ -66,6 +83,13 @@ public: nsIAtom* aListName, nsIFrame* aOldFrame); + void RemoveChild(nsIPresContext& aPresContext, + nsTableColFrame& aLastChild, + PRBool aResetColIndices); + + void RemoveChildrenAtEnd(nsIPresContext& aPresContext, + PRInt32 aNumChildrenToRemove); + NS_IMETHOD Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -89,6 +113,12 @@ public: */ NS_IMETHOD GetFrameType(nsIAtom** aType) const; + NS_IMETHOD AddColsToTable(nsIPresContext& aPresContext, + PRInt32 aFirstColIndex, + PRBool aResetSubsequentColIndices, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame = nsnull); + #ifdef DEBUG NS_IMETHOD GetFrameName(nsString& aResult) const; NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const; @@ -98,7 +128,7 @@ public: * if there are col children, count them (taking into account the span of each) * else, check my own span attribute. */ - virtual PRInt32 GetColumnCount(); + virtual PRInt32 GetColCount() const; virtual nsTableColFrame * GetFirstColumn(); @@ -124,23 +154,25 @@ public: void DeleteColFrame(nsIPresContext* aPresContext, nsTableColFrame* aColFrame); -protected: + static nsTableColGroupFrame* GetColGroupFrameContaining(nsFrameList& aColGroupList, + nsTableColFrame& aColFrame); + nsFrameList& GetChildList(); + static void ResetColIndices(nsIFrame* aFirstColGroup, + PRInt32 aFirstColIndex, + nsIFrame* aStartColFrame = nsnull); +protected: nsTableColGroupFrame(); + void InsertColsReflow(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + PRInt32 aColIndex, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame = nsnull); + /** implement abstract method on nsHTMLContainerFrame */ virtual PRIntn GetSkipSides() const; - /** Hook for style post processing. - * Since we need to know the full column structure before the COLS attribute - * can be interpreted, we can't just use DidSetStyleContext - */ - NS_IMETHOD SetStyleContextForFirstPass(nsIPresContext* aPresContext); - - NS_IMETHOD InitNewFrames(nsIPresContext* aPresContext, nsIFrame* aChildList); - NS_IMETHOD AppendNewFrames(nsIPresContext* aPresContext, nsIFrame* aChildList); - - NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -174,13 +206,33 @@ protected: /** the starting column index this col group represents. Must be >= 0. */ PRInt32 mStartColIndex; + struct ColGroupBits { + unsigned int mType:4; + unsigned int mUnused:28; + } mBits; + }; inline nsTableColGroupFrame::nsTableColGroupFrame() : mColCount(0), mStartColIndex(0) -{} +{ + mBits.mType = 0; +} -inline int nsTableColGroupFrame::GetStartColumnIndex () -{ return mStartColIndex;} +inline PRInt32 nsTableColGroupFrame::GetStartColumnIndex() +{ + return mStartColIndex; +} + +inline PRInt32 nsTableColGroupFrame::GetColCount() const +{ + return mColCount; +} + +inline nsFrameList& nsTableColGroupFrame::GetChildList() +{ + return mFrames; +} #endif + diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index a7891ebbaba..199efa39f3b 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -20,6 +20,7 @@ * Contributor(s): */ #include "nsCOMPtr.h" +#include "nsVoidArray.h" #include "nsTableFrame.h" #include "nsTableBorderCollapser.h" #include "nsIRenderingContext.h" @@ -155,10 +156,7 @@ nsTableFrame::nsTableFrame() mBits.mColumnWidthsSet = PR_FALSE; mBits.mColumnWidthsValid = PR_FALSE; mBits.mFirstPassValid = PR_FALSE; - mBits.mColumnCacheValid = PR_FALSE; - mBits.mCellMapValid = PR_TRUE; mBits.mIsInvariantWidth = PR_FALSE; - mBits.mHasScrollableRowGroup = PR_FALSE; // XXX We really shouldn't do this, but if we don't then we'll have a // problem with the tree control... #if 0 @@ -248,6 +246,8 @@ nsTableFrame::Destroy(nsIPresContext* aPresContext) return nsHTMLContainerFrame::Destroy(aPresContext); } +// XXX this needs to be cleaned up so that the frame constructor breaks out col group +// frames into a separate child list. NS_IMETHODIMP nsTableFrame::SetInitialChildList(nsIPresContext* aPresContext, nsIAtom* aListName, @@ -263,17 +263,13 @@ nsTableFrame::SetInitialChildList(nsIPresContext* aPresContext, { const nsStyleDisplay *childDisplay; childFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)childDisplay); + // XXX this if should go away if (PR_TRUE==IsRowGroup(childDisplay->mDisplay)) { - if (mFrames.IsEmpty()) + if (mFrames.IsEmpty()) mFrames.SetFrames(childFrame); else prevMainChild->SetNextSibling(childFrame); - // If we have a prev-in-flow, then we're a table that has been split and - // so don't treat this like an append - if (!mPrevInFlow) { - rv = DidAppendRowGroup(GetRowGroupFrameFor(childFrame, childDisplay)); - } prevMainChild = childFrame; } else if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) @@ -301,9 +297,13 @@ nsTableFrame::SetInitialChildList(nsIPresContext* aPresContext, if (nsnull!=prevColGroupChild) prevColGroupChild->SetNextSibling(nsnull); - if (NS_SUCCEEDED(rv)) { - PRBool createdColFrames; - EnsureColumns(aPresContext, createdColFrames); + // If we have a prev-in-flow, then we're a table that has been split and + // so don't treat this like an append + if (!mPrevInFlow) { + // process col groups first so that real cols get constructed before + // anonymous ones due to cells in rows. + InsertColGroups(*aPresContext, 0, mColGroups.FirstChild()); + AppendRowGroups(*aPresContext, mFrames.FirstChild()); } if (HasGroupRules()) { @@ -313,32 +313,6 @@ nsTableFrame::SetInitialChildList(nsIPresContext* aPresContext, return rv; } -NS_IMETHODIMP nsTableFrame::DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFrame) -{ - nsresult rv=NS_OK; - nsIFrame *nextRow=nsnull; - aRowGroupFrame->FirstChild(nsnull, &nextRow); - for ( ; nsnull!=nextRow; nextRow->GetNextSibling(&nextRow)) - { - const nsStyleDisplay *rowDisplay; - nextRow->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowDisplay); - if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) { - rv = ((nsTableRowFrame *)nextRow)->InitChildren(); - if (NS_FAILED(rv)) { - return rv; - } - } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP==rowDisplay->mDisplay) { - rv = DidAppendRowGroup((nsTableRowGroupFrame*)nextRow); - if (NS_FAILED(rv)) { - return rv; - } - } - } - - return rv; -} - /* ****** CellMap methods ******* */ @@ -348,7 +322,7 @@ PRInt32 nsTableFrame::GetSpecifiedColumnCount () PRInt32 colCount = 0; nsIFrame * childFrame = mColGroups.FirstChild(); while (nsnull!=childFrame) { - colCount += ((nsTableColGroupFrame *)childFrame)->GetColumnCount(); + colCount += ((nsTableColGroupFrame *)childFrame)->GetColCount(); childFrame->GetNextSibling(&childFrame); } return colCount; @@ -376,15 +350,9 @@ PRInt32 nsTableFrame::GetColCount () } -nsTableColFrame * nsTableFrame::GetColFrame(PRInt32 aColIndex) +nsTableColFrame* nsTableFrame::GetColFrame(PRInt32 aColIndex) { - nsTableColFrame *result = nsnull; - nsCellMap *cellMap = GetCellMap(); - if (nsnull!=cellMap) - { - result = cellMap->GetColumnFrame(aColIndex); - } - return result; + return (nsTableColFrame *)mColFrames.ElementAt(aColIndex); } // can return nsnull @@ -545,6 +513,21 @@ void nsTableFrame::ProcessGroupRules(nsIPresContext* aPresContext) } +void nsTableFrame::AdjustRowIndices(PRInt32 aRowIndex, + PRInt32 aAdjustment) +{ + // Iterate over the row groups and adjust the row indices of all rows + // whose index is >= aRowIndex. + nsIFrame* rowGroupFrame = mFrames.FirstChild(); + for ( ; rowGroupFrame; rowGroupFrame->GetNextSibling(&rowGroupFrame)) { + const nsStyleDisplay *rowGroupDisplay; + rowGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowGroupDisplay); + if (IsRowGroup(rowGroupDisplay->mDisplay)) { + AdjustRowIndices(rowGroupFrame, aRowIndex, aAdjustment); + } + } +} + NS_IMETHODIMP nsTableFrame::AdjustRowIndices(nsIFrame* aRowGroup, PRInt32 aRowIndex, PRInt32 anAdjustment) @@ -570,179 +553,104 @@ NS_IMETHODIMP nsTableFrame::AdjustRowIndices(nsIFrame* aRowGroup, return rv; } -NS_IMETHODIMP nsTableFrame::RemoveRowFromMap(nsTableRowFrame* aRow, PRInt32 aRowIndex) + +void nsTableFrame::InsertColGroups(nsIPresContext& aPresContext, + PRInt32 aStartColIndex, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame) { - nsresult rv=NS_OK; - - // Create a new row in the cell map at the specified index. - mCellMap->RemoveRowFromMap(aRowIndex); - - // Iterate over our row groups and increment the row indices of all rows whose index - // is >= aRowIndex. - nsIFrame *rowGroupFrame=mFrames.FirstChild(); - for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(&rowGroupFrame)) - { - const nsStyleDisplay *rowGroupDisplay; - rowGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowGroupDisplay); - if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay)) - { - AdjustRowIndices(rowGroupFrame, aRowIndex, -1); + PRInt32 colIndex = aStartColIndex; + nsTableColGroupFrame* firstColGroupToReset = nsnull; + nsIFrame* kidFrame = aFirstFrame; + PRBool didLastFrame = PR_FALSE; + while (kidFrame) { + nsIAtom* kidType; + kidFrame->GetFrameType(&kidType); + if (nsLayoutAtoms::tableColGroupFrame == kidType) { + if (didLastFrame) { + firstColGroupToReset = (nsTableColGroupFrame*)kidFrame; + break; + } + else { + nsTableColGroupFrame* cgFrame = (nsTableColGroupFrame*)kidFrame; + cgFrame->SetStartColumnIndex(colIndex); + nsIFrame* firstCol; + kidFrame->FirstChild(nsnull, &firstCol); + cgFrame->AddColsToTable(aPresContext, colIndex, PR_FALSE, firstCol); + PRInt32 numCols = cgFrame->GetColCount(); + colIndex += numCols; + } } + NS_IF_RELEASE(kidType); + if (kidFrame == aLastFrame) { + didLastFrame = PR_TRUE; + } + kidFrame->GetNextSibling(&kidFrame); } - return rv; + if (firstColGroupToReset) { + nsTableColGroupFrame::ResetColIndices(firstColGroupToReset, aStartColIndex); + } } -NS_IMETHODIMP nsTableFrame::InsertRowIntoMap(nsTableRowFrame* aRow, PRInt32 aRowIndex) +void nsTableFrame::InsertCol(nsIPresContext& aPresContext, + nsTableColFrame& aColFrame, + PRInt32 aColIndex) { - nsresult rv=NS_OK; - - // Create a new row in the cell map at the specified index. - mCellMap->InsertRowIntoMap(aRowIndex); - - // Iterate over our row groups and increment the row indices of all rows whose index - // is >= aRowIndex. - nsIFrame *rowGroupFrame=mFrames.FirstChild(); - for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(&rowGroupFrame)) - { - const nsStyleDisplay *rowGroupDisplay; - rowGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowGroupDisplay); - if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay)) - { - AdjustRowIndices(rowGroupFrame, aRowIndex, 1); + mColFrames.InsertElementAt(&aColFrame, aColIndex); + nsTableColType insertedColType = aColFrame.GetType(); + PRInt32 numCacheCols = mColFrames.Count(); + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + PRInt32 numMapCols = cellMap->GetColCount(); + if (numCacheCols > numMapCols) { + PRBool removedFromCache = PR_FALSE; + if (eColAnonymousCell != insertedColType) { + nsTableColFrame* lastCol = (nsTableColFrame *)mColFrames.ElementAt(numCacheCols - 1); + if (lastCol) { + nsTableColType lastColType = lastCol->GetType(); + if (eColAnonymousCell == lastColType) { + // remove the col from the cache + mColFrames.RemoveElementAt(numCacheCols - 1); + // remove the col from the eColGroupAnonymousCell col group + nsTableColGroupFrame* lastColGroup = (nsTableColGroupFrame *)mColGroups.LastChild(); + if (lastColGroup) { + lastColGroup->RemoveChild(aPresContext, *lastCol, PR_FALSE); + } + // remove the col group if it is empty + if (lastColGroup->GetColCount() <= 0) { + mColGroups.DestroyFrame(&aPresContext, (nsIFrame*)lastColGroup); + } + removedFromCache = PR_TRUE; + } + } + } + if (!removedFromCache) { + cellMap->AppendCol(); + } } } - - // Init the row's index and add its cells to the cell map. - aRow->InitChildrenWithIndex(aRowIndex); - - return rv; } -/** sum the columns represented by all nsTableColGroup objects - * if the cell map says there are more columns than this, - * add extra implicit columns to the content tree. - */ -void nsTableFrame::EnsureColumns(nsIPresContext* aPresContext, - PRBool& aCreatedColFrames) +void nsTableFrame::RemoveCol(nsIPresContext& aPresContext, + nsTableColGroupFrame* aColGroupFrame, + PRInt32 aColIndex, + PRBool aRemoveFromCache, + PRBool aRemoveFromCellMap) { - NS_PRECONDITION(nsnull!=mCellMap, "bad state: null cellmap"); - - aCreatedColFrames = PR_FALSE; // initialize OUT parameter - if (nsnull == mCellMap) - return; // no info yet, so nothing useful to do - - // make sure we've accounted for the COLS attribute - AdjustColumnsForCOLSAttribute(); - - // count the number of column frames we already have - PRInt32 actualColumns = 0; - nsTableColGroupFrame *lastColGroupFrame = nsnull; - nsIFrame* childFrame = mColGroups.FirstChild(); - while (nsnull!=childFrame) { - ((nsTableColGroupFrame*)childFrame)->SetStartColumnIndex(actualColumns); - PRInt32 numCols = ((nsTableColGroupFrame*)childFrame)->GetColumnCount(); - actualColumns += numCols; - lastColGroupFrame = (nsTableColGroupFrame *)childFrame; - childFrame->GetNextSibling(&childFrame); + if (aRemoveFromCache) { + mColFrames.RemoveElementAt(aColIndex); } - - // if we have fewer column frames than we need, create some implicit column frames - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - - PRInt32 colCount = mCellMap->GetColCount(); - if (actualColumns < colCount) { - nsIContent *lastColGroupElement = nsnull; - if (nsnull==lastColGroupFrame) { // there are no col groups, so create an implicit colgroup frame - // Resolve style for the colgroup frame - // first, need to get the nearest containing content object - GetContent(&lastColGroupElement); // ADDREF a: lastColGroupElement++ (either here or in the loop below) - nsIFrame *parentFrame; - GetParent(&parentFrame); - while (nsnull==lastColGroupElement) { - parentFrame->GetContent(&lastColGroupElement); - if (nsnull==lastColGroupElement) - parentFrame->GetParent(&parentFrame); - } - // now we have a ref-counted "lastColGroupElement" content object - nsIStyleContext* colGroupStyleContext; - aPresContext->ResolvePseudoStyleContextFor (lastColGroupElement, - nsHTMLAtoms::tableColGroupPseudo, - mStyleContext, - PR_FALSE, - &colGroupStyleContext); // colGroupStyleContext: REFCNT++ - // Create a col group frame - nsIFrame* newFrame; - NS_NewTableColGroupFrame(shell, &newFrame); - newFrame->Init(aPresContext, lastColGroupElement, this, colGroupStyleContext, - nsnull); - lastColGroupFrame = (nsTableColGroupFrame*)newFrame; - NS_RELEASE(colGroupStyleContext); // kidStyleContenxt: REFCNT-- - - // hook lastColGroupFrame into child list - mColGroups.SetFrames(lastColGroupFrame); - } - else { - lastColGroupFrame->GetContent(&lastColGroupElement); // ADDREF b: lastColGroupElement++ - } - - // XXX It would be better to do this in the style code while constructing - // the table's frames. But we don't know how many columns we have at that point. - nsAutoString colTag; - nsHTMLAtoms::col->ToString(colTag); - PRInt32 excessColumns = colCount - actualColumns; - nsIFrame* firstNewColFrame = nsnull; - nsIFrame* lastNewColFrame = nsnull; - nsIStyleContextPtr lastColGroupStyle; - lastColGroupFrame->GetStyleContext(lastColGroupStyle.AssignPtr()); - for ( ; excessColumns > 0; excessColumns--) { - // Create a new col frame - nsIFrame* colFrame; - // note we pass in PR_TRUE here to force unique style contexts. - nsIStyleContext* colStyleContext; - aPresContext->ResolvePseudoStyleContextFor (lastColGroupElement, - nsHTMLAtoms::tableColPseudo, - lastColGroupStyle, - PR_TRUE, - &colStyleContext); // colStyleContext: REFCNT++ - aCreatedColFrames = PR_TRUE; // remember that we're creating implicit col frames - NS_NewTableColFrame(shell, &colFrame); - colFrame->Init(aPresContext, lastColGroupElement, lastColGroupFrame, - colStyleContext, nsnull); - NS_RELEASE(colStyleContext); - colFrame->SetInitialChildList(aPresContext, nsnull, nsnull); - ((nsTableColFrame *)colFrame)->SetIsAnonymous(PR_TRUE); - - // Add it to our list - if (nsnull == lastNewColFrame) { - firstNewColFrame = colFrame; - } else { - lastNewColFrame->SetNextSibling(colFrame); - } - lastNewColFrame = colFrame; - } - lastColGroupFrame->SetInitialChildList(aPresContext, nsnull, firstNewColFrame); - NS_RELEASE(lastColGroupElement); // ADDREF: lastColGroupElement-- - } - else if (actualColumns > colCount) { // the cell map needs to grow to accomodate extra cols + if (aRemoveFromCellMap) { nsCellMap* cellMap = GetCellMap(); if (cellMap) { - cellMap->AddColsAtEnd(actualColumns - colCount); + // check to see if the cell map can remove the col + if (cellMap->RemoveUnusedCols(1) < 1) { + // it couldn't be removed so we need a new anonymous col frame + CreateAnonymousColFrames(aPresContext, 1, eColAnonymousCell, PR_TRUE); + } } } - -} - - -void nsTableFrame::AddColumnFrame (nsTableColFrame *aColFrame) -{ - nsCellMap *cellMap = GetCellMap(); - NS_PRECONDITION (nsnull!=cellMap, "null cellMap."); - if (nsnull!=cellMap) - { - cellMap->AppendColumnFrame(aColFrame); - } } /** return the index of the next row that is not yet assigned */ @@ -770,72 +678,430 @@ nsCellMap * nsTableFrame::GetCellMap() const return mCellMap; } -PRInt32 nsTableFrame::AddCellToTable(nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex) +// XXX this needs to be moved to nsCSSFrameConstructor +nsTableColGroupFrame* +nsTableFrame::CreateAnonymousColGroupFrame(nsIPresContext& aPresContext, + nsTableColGroupType aColGroupType) { - NS_ASSERTION(nsnull != aCellFrame, "bad aCellFrame arg"); - NS_ASSERTION(nsnull != mCellMap, "bad cellMap"); + nsCOMPtr colGroupContent; + GetContent(getter_AddRefs(colGroupContent)); - // XXX: must be called only on first-in-flow! - return mCellMap->AppendCell(aCellFrame, aRowIndex); + nsCOMPtr colGroupStyle; + aPresContext.ResolvePseudoStyleContextFor(colGroupContent, + nsHTMLAtoms::tableColGroupPseudo, + mStyleContext, + PR_FALSE, + getter_AddRefs(colGroupStyle)); + // Create a col group frame + nsIFrame* newFrame; + nsCOMPtr presShell; + aPresContext.GetShell(getter_AddRefs(presShell)); + nsresult result = NS_NewTableColGroupFrame(presShell, &newFrame); + if (NS_SUCCEEDED(result) && newFrame) { + ((nsTableColGroupFrame *)newFrame)->SetType(aColGroupType); + newFrame->Init(&aPresContext, colGroupContent, this, colGroupStyle, nsnull); + } + return (nsTableColGroupFrame *)newFrame; } -void nsTableFrame::RemoveCellFromTable(nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex) +void +nsTableFrame::CreateAnonymousColFrames(nsIPresContext& aPresContext, + PRInt32 aNumColsToAdd, + nsTableColType aColType, + PRBool aDoAppend, + nsIFrame* aPrevColIn) +{ + // get the last col group frame + nsTableColGroupFrame* colGroupFrame = nsnull; + nsIFrame* childFrame = mColGroups.FirstChild(); + while (childFrame) { + nsIAtom* frameType = nsnull; + childFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableColGroupFrame == frameType) { + colGroupFrame = (nsTableColGroupFrame *)childFrame; + } + childFrame->GetNextSibling(&childFrame); + NS_IF_RELEASE(frameType); + } + + nsTableColGroupType lastColGroupType = eColGroupContent; + nsTableColGroupType newColGroupType = eColGroupContent; + if (colGroupFrame) { + lastColGroupType = colGroupFrame->GetType(); + } + if (eColAnonymousCell == aColType) { + if (eColGroupAnonymousCell != lastColGroupType) { + newColGroupType = eColGroupAnonymousCell; + } + } + else if (eColAnonymousCol == aColType) { + if (eColGroupAnonymousCol != lastColGroupType) { + newColGroupType = eColGroupAnonymousCol; + } + } + else { + NS_ASSERTION(PR_FALSE, "CreateAnonymousColFrames called incorrectly"); + return; + } + + if (eColGroupContent != newColGroupType) { + PRInt32 colIndex = (colGroupFrame) ? colGroupFrame->GetStartColumnIndex() + colGroupFrame->GetColCount() + : 0; + colGroupFrame = CreateAnonymousColGroupFrame(aPresContext, newColGroupType); + if (!colGroupFrame) { + return; + } + mColGroups.AppendFrame(this, colGroupFrame); // add the new frame to the child list + colGroupFrame->SetStartColumnIndex(colIndex); + } + + nsIFrame* prevCol = (aDoAppend) ? colGroupFrame->GetChildList().LastChild() : aPrevColIn; + + nsIFrame* firstNewFrame; + CreateAnonymousColFrames(aPresContext, *colGroupFrame, aNumColsToAdd, + aColType, PR_TRUE, prevCol, &firstNewFrame); +} + +// XXX this needs to be moved to nsCSSFrameConstructor +// Right now it only creates the col frames at the end +void +nsTableFrame::CreateAnonymousColFrames(nsIPresContext& aPresContext, + nsTableColGroupFrame& aColGroupFrame, + PRInt32 aNumColsToAdd, + nsTableColType aColType, + PRBool aAddToColGroupAndTable, + nsIFrame* aPrevFrameIn, + nsIFrame** aFirstNewFrame) +{ + *aFirstNewFrame = nsnull; + nsIFrame* lastColFrame = nsnull; + nsIFrame* childFrame; + + // Get the last col frame + aColGroupFrame.FirstChild(nsnull, &childFrame); + while (childFrame) { + nsIAtom* frameType = nsnull; + childFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableColFrame == frameType) { + lastColFrame = (nsTableColGroupFrame *)childFrame; + } + NS_IF_RELEASE(frameType); + childFrame->GetNextSibling(&childFrame); + } + + PRInt32 startIndex = mColFrames.Count(); + PRInt32 lastIndex = startIndex + aNumColsToAdd - 1; + + for (PRInt32 childX = startIndex; childX <= lastIndex; childX++) { + nsCOMPtr iContent; + nsCOMPtr styleContext; + + if ((aColType == eColAnonymousCol) && aPrevFrameIn) { + // a col due to a span in a previous col uses the style context of the col + aPrevFrameIn->GetStyleContext(getter_AddRefs(styleContext)); + } + else { + // all other anonymous cols use a pseudo style context of the col group + aColGroupFrame.GetContent(getter_AddRefs(iContent)); + aPresContext.ResolvePseudoStyleContextFor(iContent, nsHTMLAtoms::tableColPseudo, + styleContext, PR_FALSE, getter_AddRefs(styleContext)); + } + // create the new col frame + nsIFrame* colFrame; + nsCOMPtr presShell; + aPresContext.GetShell(getter_AddRefs(presShell)); + NS_NewTableColFrame(presShell, &colFrame); + ((nsTableColFrame *) colFrame)->SetType(aColType); + colFrame->Init(&aPresContext, iContent, &aColGroupFrame, + styleContext, nsnull); + colFrame->SetInitialChildList(&aPresContext, nsnull, nsnull); + ((nsTableColFrame *)colFrame)->SetType(aColType); + + // Add the col to the sibling chain + if (lastColFrame) { + lastColFrame->SetNextSibling(colFrame); + } + lastColFrame = colFrame; + if (childX == startIndex) { + *aFirstNewFrame = colFrame; + } + } + if (aAddToColGroupAndTable) { + nsFrameList& cols = aColGroupFrame.GetChildList(); + // the chain already exists, now add it to the col group child list + if (!aPrevFrameIn) { + cols.AppendFrames(&aColGroupFrame, *aFirstNewFrame); + } + // get the starting col index in the cache + PRInt32 startColIndex = aColGroupFrame.GetStartColumnIndex(); + if (aPrevFrameIn) { + nsTableColFrame* colFrame = + (nsTableColFrame*)nsTableFrame::GetFrameAtOrBefore((nsIFrame*)&aColGroupFrame, aPrevFrameIn, + nsLayoutAtoms::tableColFrame); + if (colFrame) { + startColIndex = colFrame->GetColIndex(); + } + } + aColGroupFrame.AddColsToTable(aPresContext, startColIndex, PR_TRUE, + *aFirstNewFrame, lastColFrame); + } +} + +PRInt32 nsTableFrame::AppendCell(nsIPresContext& aPresContext, + nsTableCellFrame& aCellFrame, + PRInt32 aRowIndex) +{ + PRInt32 colIndex = 0; + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + colIndex = cellMap->AppendCell(&aCellFrame, aRowIndex, PR_TRUE); + PRInt32 numColsInMap = GetColCount(); + PRInt32 numColsInCache = mColFrames.Count(); + PRInt32 numColsToAdd = numColsInMap - numColsInCache; + if (numColsToAdd > 0) { + // this sets the child list, updates the col cache and cell map + CreateAnonymousColFrames(aPresContext, numColsToAdd, eColAnonymousCell, PR_TRUE); + } + } + return colIndex; +} + +void nsTableFrame::InsertCells(nsIPresContext& aPresContext, + nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndexBefore) { nsCellMap* cellMap = GetCellMap(); - PRInt32 numCols = cellMap->GetColCount(); - cellMap->RemoveCell(aCellFrame, aRowIndex); - if (numCols != cellMap->GetColCount()) { - // XXX need to remove the anonymous col frames at the end - //nsTableColFrame* colFrame = nsnull; - //GetColumnFrame(colIndex, colFrame); - //if (colFrame && colFrame->IsAnonymous()) { - // nsTableColGroupFrame* colGroupFrame = nsnull; - //colFrame->GetParent((nsIFrame **)&colGroupFrame); - //if (colGroupFrame) { - // colGroupFrame->DeleteColFrame(aPresContext, colFrame); + if (cellMap) { + cellMap->InsertCells(aCellFrames, aRowIndex, aColIndexBefore); + PRInt32 numColsInMap = GetColCount(); + PRInt32 numColsInCache = mColFrames.Count(); + PRInt32 numColsToAdd = numColsInMap - numColsInCache; + if (numColsToAdd > 0) { + // this sets the child list, updates the col cache and cell map + CreateAnonymousColFrames(aPresContext, numColsToAdd, eColAnonymousCell, PR_TRUE); + } } } -static nsresult BuildCellMapForRowGroup(nsIFrame* rowGroupFrame) +// this removes the frames from the col group and table, but not the cell map +PRInt32 +nsTableFrame::DestroyAnonymousColFrames(nsIPresContext& aPresContext, + PRInt32 aNumFrames) { - nsresult rv = NS_OK; - nsIFrame *rowFrame; - rowGroupFrame->FirstChild(nsnull, &rowFrame); - for ( ; nsnull!=rowFrame; rowFrame->GetNextSibling(&rowFrame)) - { - const nsStyleDisplay *rowDisplay; - rowFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowDisplay); - if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) - { - rv = ((nsTableRowFrame *)rowFrame)->InitChildren(); - if (NS_FAILED(rv)) - return rv; + // only remove cols that are of type eTypeAnonymous cell (they are at the end) + PRInt32 endIndex = mColFrames.Count() - 1; + PRInt32 startIndex = (endIndex - aNumFrames) + 1; + PRInt32 numColsRemoved = 0; + for (PRInt32 colX = endIndex; colX >= startIndex; colX--) { + nsTableColFrame* colFrame = GetColFrame(colX); + if (colFrame && (eColAnonymousCell == colFrame->GetType())) { + nsTableColGroupFrame* cgFrame; + colFrame->GetParent((nsIFrame**)&cgFrame); + // remove the frame from the colgroup + cgFrame->RemoveChild(aPresContext, *colFrame, PR_FALSE); + // remove the frame from the cache, but not the cell map + RemoveCol(aPresContext, nsnull, colX, PR_TRUE, PR_FALSE); + numColsRemoved++; } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP==rowDisplay->mDisplay) - { - BuildCellMapForRowGroup(rowFrame); + else { + break; } } - return rv; + return (aNumFrames - numColsRemoved); } -NS_METHOD nsTableFrame::ReBuildCellMap() +void nsTableFrame::RemoveCell(nsIPresContext& aPresContext, + nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) { - nsresult rv=NS_OK; - nsIFrame *rowGroupFrame=mFrames.FirstChild(); - for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(&rowGroupFrame)) - { - const nsStyleDisplay *rowGroupDisplay; - rowGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowGroupDisplay); - if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay)) - { - BuildCellMapForRowGroup(rowGroupFrame); + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + cellMap->RemoveCell(aCellFrame, aRowIndex); + PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols + PRInt32 numColsInCache = mColFrames.Count(); + PRInt32 numColsNotRemoved = DestroyAnonymousColFrames(aPresContext, numColsInCache - numColsInMap); + // if the cell map has fewer cols than the cache, correct it + if (numColsNotRemoved > 0) { + cellMap->AddColsAtEnd(numColsNotRemoved); } } - mBits.mCellMapValid=PR_TRUE; - return rv; +} + +// this cannot extend beyond a single row group +void nsTableFrame::AppendRows(nsIPresContext& aPresContext, + nsVoidArray& aRowFrames) +{ + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + PRInt32 rowIndex = cellMap->GetRowCount(); + InsertRows(aPresContext, aRowFrames, rowIndex, PR_TRUE); + } +} + +PRInt32 +nsTableFrame::InsertRow(nsIPresContext& aPresContext, + nsIFrame& aRowFrame, + PRInt32 aRowIndex, + PRBool aConsiderSpans) +{ + nsVoidArray rows; + rows.AppendElement(&aRowFrame); + return InsertRows(aPresContext, rows, aRowIndex, aConsiderSpans); +} + +// this cannot extend beyond a single row group +PRInt32 +nsTableFrame::InsertRows(nsIPresContext& aPresContext, + nsVoidArray& aRowFrames, + PRInt32 aRowIndex, + PRBool aConsiderSpans) +{ + //printf("insertRowsBefore firstRow=%d \n", aRowIndex); + //Dump(PR_TRUE, PR_FALSE, PR_TRUE); + + PRInt32 numColsToAdd = 0; + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + PRInt32 origNumRows = cellMap->GetRowCount(); + PRInt32 numNewRows = aRowFrames.Count(); + cellMap->InsertRows(aRowFrames, aRowIndex, aConsiderSpans); + PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols + PRInt32 numColsInCache = mColFrames.Count(); + numColsToAdd = numColsInMap - numColsInCache; + if (numColsToAdd > 0) { + // this sets the child list, updates the col cache and cell map + CreateAnonymousColFrames(aPresContext, numColsToAdd, eColAnonymousCell, + PR_TRUE); + } + if (aRowIndex < origNumRows) { + PRInt32 numNewRows = aRowFrames.Count(); + AdjustRowIndices(aRowIndex, numNewRows); + } + // assign the correct row indices to the new rows. If they were adjusted above + // it may not have been done correctly because each row is constructed with index 0 + for (PRInt32 rowX = 0; rowX < numNewRows; rowX++) { + nsTableRowFrame* rowFrame = (nsTableRowFrame *) aRowFrames.ElementAt(rowX); + rowFrame->SetRowIndex(aRowIndex + rowX); + } + } + + //printf("insertRowsAfter \n"); + //Dump(PR_TRUE, PR_FALSE, PR_TRUE); + + return numColsToAdd; +} + +// this cannot extend beyond a single row group +void nsTableFrame::RemoveRows(nsIPresContext& aPresContext, + PRInt32 aFirstRowIndex, + PRInt32 aNumRowsToRemove, + PRBool aConsiderSpans) +{ + //printf("removeRowsBefore firstRow=%d numRows=%d\n", aFirstRowIndex, aNumRowsToRemove); + //Dump(PR_TRUE, PR_FALSE, PR_TRUE); + + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + cellMap->RemoveRows(aFirstRowIndex, aNumRowsToRemove, aConsiderSpans); + // only remove cols that are of type eTypeAnonymous cell (they are at the end) + PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols + PRInt32 numColsInCache = mColFrames.Count(); + PRInt32 numColsNotRemoved = DestroyAnonymousColFrames(aPresContext, numColsInCache - numColsInMap); + // if the cell map has fewer cols than the cache, correct it + if (numColsNotRemoved > 0) { + cellMap->AddColsAtEnd(numColsNotRemoved); + } + } + AdjustRowIndices(aFirstRowIndex, -aNumRowsToRemove); + //printf("removeRowsAfter\n"); + //Dump(PR_TRUE, PR_FALSE, PR_TRUE); +} + +void nsTableFrame::AppendRowGroups(nsIPresContext& aPresContext, + nsIFrame* aFirstRowGroupFrame) +{ + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + PRInt32 rowIndex = cellMap->GetRowCount(); + InsertRowGroups(aPresContext, aFirstRowGroupFrame, rowIndex); + } +} + +nsTableRowGroupFrame* +nsTableFrame::GetRowGroupFrame(nsIFrame* aFrame, + nsIAtom* aFrameTypeIn) +{ + nsIFrame* rgFrame = nsnull; + nsIAtom* frameType = aFrameTypeIn; + if (!aFrameTypeIn) { + aFrame->GetFrameType(&frameType); + } + if (nsLayoutAtoms::tableRowGroupFrame == frameType) { + rgFrame = aFrame; + } + else if (nsLayoutAtoms::scrollFrame == frameType) { + nsIScrollableFrame* scrollable = nsnull; + nsresult rv = aFrame->QueryInterface(kIScrollableFrameIID, (void **)&scrollable); + if (NS_SUCCEEDED(rv) && (scrollable)) { + nsIFrame* scrolledFrame; + scrollable->GetScrolledFrame(nsnull, scrolledFrame); + if (scrolledFrame) { + nsIAtom* scrolledType; + scrolledFrame->GetFrameType(&scrolledType); + if (nsLayoutAtoms::tableRowGroupFrame == scrolledType) { + rgFrame = scrolledFrame; + } + NS_IF_RELEASE(scrolledType); + } + } + } + if (!aFrameTypeIn) { + NS_IF_RELEASE(frameType); + } + return (nsTableRowGroupFrame*)rgFrame; +} + +// collect the rows ancestors of aFrame +void +nsTableFrame::CollectRows(nsIFrame* aFrame, + nsVoidArray& aCollection) +{ + if (!aFrame) return; + nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aFrame); + if (rgFrame) { + nsIFrame* childFrame = nsnull; + rgFrame->FirstChild(nsnull, &childFrame); + while (childFrame) { + nsIAtom* childType; + childFrame->GetFrameType(&childType); + if (nsLayoutAtoms::tableRowFrame == childType) { + aCollection.AppendElement(childFrame); + } + else { + CollectRows(childFrame, aCollection); + } + NS_IF_RELEASE(childType); + childFrame->GetNextSibling(&childFrame); + } + } +} + +void +nsTableFrame::InsertRowGroups(nsIPresContext& aPresContext, + nsIFrame* aFirstRowGroupFrame, + PRInt32 aRowIndex) +{ + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + // collect the new row frames in an array + nsVoidArray rows; + for (nsIFrame* kidFrame = aFirstRowGroupFrame; kidFrame; kidFrame->GetNextSibling(&kidFrame)) { + CollectRows(kidFrame, rows); + } + + InsertRows(aPresContext, rows, aRowIndex, PR_TRUE); + } } /* ***** Column Layout Data methods ***** */ @@ -1037,14 +1303,12 @@ PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState) if (mBits.mIsInvariantWidth) { result = PR_FALSE; - } else if ((eReflowReason_Incremental == aReflowState.reason) && (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight)) { // If it's an incremental reflow and we're in galley mode, then only // do a full reflow if we need to. We need to if the cell map is invalid, // or the column info is invalid, or if we need to do a pass-1 reflow - result = !(IsCellMapValid() && IsFirstPassValid() && - IsColumnCacheValid() && IsColumnWidthsValid()); + result = !(IsFirstPassValid() && IsColumnWidthsValid()); } return result; } @@ -1213,12 +1477,6 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, { if (nsDebugTable::gRflTable) nsTableFrame::DebugReflow("T::Rfl en", this, &aReflowState, nsnull); - // this is a temporary fix to prevent a recent crash due to incremental content - // sink changes. this will go away when the col cache and cell map are synchronized - if (!IsColumnCacheValid()) { - CacheColFrames(aPresContext, PR_TRUE); - } - // Initialize out parameter if (nsnull != aDesiredSize.maxElementSize) { aDesiredSize.maxElementSize->width = 0; @@ -1238,22 +1496,12 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, } // NeedsReflow and IsFirstPassValid take into account reflow type = Initial_Reflow - if (PR_TRUE==NeedsReflow(aReflowState)) - { - PRBool needsRecalc=PR_FALSE; - if (eReflowReason_Initial!=aReflowState.reason && PR_FALSE==IsCellMapValid()) - { - if (nsnull!=mCellMap) - delete mCellMap; - mCellMap = new nsCellMap(0,0); - ReBuildCellMap(); - needsRecalc=PR_TRUE; - } + if (NeedsReflow(aReflowState)) { + PRBool needsRecalc = PR_FALSE; if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) || - (PR_FALSE==IsFirstPassValid())) - { + (PR_FALSE==IsFirstPassValid())) { nsReflowReason reason = aReflowState.reason; - if (eReflowReason_Initial!=reason) + if (eReflowReason_Initial != reason) reason = eReflowReason_Resize; if (mBorderCollapser) { mBorderCollapser->ComputeVerticalBorders(aPresContext, 0, -1); @@ -1261,33 +1509,15 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus, nsnull, reason, PR_TRUE); if (NS_FAILED(rv)) return rv; - needsRecalc=PR_TRUE; + needsRecalc = PR_TRUE; } - if (PR_FALSE==IsColumnCacheValid()) - { - needsRecalc=PR_TRUE; - } - if (PR_TRUE==needsRecalc) - { - CacheColFrames(aPresContext, PR_TRUE); - // if we needed to rebuild the column cache, the data stored in the layout strategy is invalid - if (nsnull!=mTableLayoutStrategy) - { - mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount(), aReflowState.mComputedWidth); - mBits.mColumnWidthsValid=PR_TRUE; //so we don't do this a second time below - } - } - if (PR_FALSE==IsColumnWidthsValid()) - { - if (nsnull!=mTableLayoutStrategy) - { - mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount(), aReflowState.mComputedWidth); - mBits.mColumnWidthsValid=PR_TRUE; - } + if (mTableLayoutStrategy && (needsRecalc || !IsColumnWidthsValid())) { + mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, aReflowState.mComputedWidth); + mBits.mColumnWidthsValid = PR_TRUE; //so we don't do this a second time below } - if (nsnull==mPrevInFlow) - { // only do this for a first-in-flow table frame + if (!mPrevInFlow) { + // only do this for a first-in-flow table frame // assign column widths, and assign aMaxElementSize->width BalanceColumnWidths(aPresContext, aReflowState, nsSize(aReflowState.availableWidth, aReflowState.availableHeight), aDesiredSize.maxElementSize); @@ -1328,8 +1558,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, Invalidate(aPresContext, damageRect); } } - else - { + else { // set aDesiredSize and aMaxElementSize } @@ -1943,7 +2172,7 @@ nsTableFrame::CalculateStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFra colGroupFrame && (colGroupFrame != aColGroupFrame); colGroupFrame->GetNextSibling((nsIFrame**)&colGroupFrame)) { - index += colGroupFrame->GetColumnCount(); + index += colGroupFrame->GetColCount(); } return index; @@ -1955,11 +2184,11 @@ nsTableFrame::AppendFrames(nsIPresContext* aPresContext, nsIAtom* aListName, nsIFrame* aFrameList) { - PRInt32 startingColIndex = -1; - + PRInt32 startColIndex = 0; // Because we actually have two child lists, one for col group frames and one // for everything else, we need to look at each frame individually nsIFrame* f = aFrameList; + nsIFrame* firstAppendedColGroup = nsnull; while (f) { nsIFrame* next; @@ -1974,21 +2203,20 @@ nsTableFrame::AppendFrames(nsIPresContext* aPresContext, if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) { // Append the new col group frame mColGroups.AppendFrame(nsnull, f); - - // Set its starting column index - if (-1 == startingColIndex) { - startingColIndex = CalculateStartingColumnIndexFor((nsTableColGroupFrame*)f); + if (!firstAppendedColGroup) { + firstAppendedColGroup = f; + nsIFrame* lastChild = mFrames.LastChild(); + nsTableColGroupFrame* lastColGroup = + (nsTableColGroupFrame*)GetFrameAtOrBefore(this, lastChild, nsLayoutAtoms::tableColGroupFrame); + startColIndex = (lastColGroup) + ? lastColGroup->GetStartColumnIndex() + lastColGroup->GetColCount() : 0; } - ((nsTableColGroupFrame*)f)->SetStartColumnIndex(startingColIndex); - startingColIndex += ((nsTableColGroupFrame *)f)->GetColumnCount(); - } else if (IsRowGroup(display->mDisplay)) { - // Append the new row group frame - mFrames.AppendFrame(nsnull, f); - - // Add the content of the row group to the cell map - DidAppendRowGroup((nsTableRowGroupFrame*)f); + // insert the rows into the table + InsertRowGroups(*aPresContext, aFrameList, GetRowCount()); + // Append the new row group frame to the sibling chain + mFrames.AppendFrame(nsnull, f); } else { // Nothing special to do, just add the frame to our child list mFrames.AppendFrame(nsnull, f); @@ -1998,18 +2226,17 @@ nsTableFrame::AppendFrames(nsIPresContext* aPresContext, f = next; } - // We'll need to do a pass-1 layout of all cells in all the rows of the - // rowgroup - InvalidateFirstPassCache(); - - // If we've added any columns, we need to rebuild the column cache. - InvalidateColumnCache(); - - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - InvalidateColumnWidths(); + if (firstAppendedColGroup) { + InsertColGroups(*aPresContext, startColIndex, firstAppendedColGroup); + } + // We'll need to do a pass-1 layout of all cells in all the rows of the + // rowgroup. XXX - fix this + InvalidateFirstPassCache(); + + // Because the number of columns may have changed invalidate them + InvalidateColumnWidths(); + // Mark the table as dirty and generate a reflow command targeted at the // outer table frame nsIReflowCommand* reflowCmd; @@ -2023,7 +2250,7 @@ nsTableFrame::AppendFrames(nsIPresContext* aPresContext, NS_RELEASE(reflowCmd); } - return rv; + return NS_OK; } NS_IMETHODIMP @@ -2048,38 +2275,42 @@ nsTableFrame::InsertFrames(nsIPresContext* aPresContext, if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) { // Insert the column group frame + nsFrameList frames(aFrameList); // convience for getting last frame + nsIFrame* lastFrame = frames.LastChild(); mColGroups.InsertFrame(nsnull, aPrevFrame, aFrameList); - - // Set its starting column index and adjust the index of the - // col group frames that follow - SetStartingColumnIndexFor((nsTableColGroupFrame*)aFrameList, - CalculateStartingColumnIndexFor((nsTableColGroupFrame*)aFrameList)); - + // find the starting col index for the first new col group + PRInt32 startColIndex = 0; + if (aPrevFrame) { + nsTableColGroupFrame* prevColGroup = + (nsTableColGroupFrame*)GetFrameAtOrBefore(this, aPrevFrame, nsLayoutAtoms::tableColGroupFrame); + if (prevColGroup) { + startColIndex = prevColGroup->GetStartColumnIndex() + prevColGroup->GetColCount(); + } + } + InsertColGroups(*aPresContext, startColIndex, aFrameList, lastFrame); } else if (IsRowGroup(display->mDisplay)) { - // Insert the frame + // get the starting row index of the new rows and insert them into the table + PRInt32 rowIndex = 0; + nsTableRowGroupFrame* prevRowGroup = (nsTableRowGroupFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsLayoutAtoms::tableRowGroupFrame); + if (prevRowGroup) { + PRInt32 numRows; + prevRowGroup->GetRowCount(numRows); + rowIndex = prevRowGroup->GetStartRowIndex() + numRows; + } + InsertRowGroups(*aPresContext, aFrameList, rowIndex); + + // Insert the frames in the sibling chain mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList); - - // We'll need to do a pass-1 layout of all cells in all the rows of the - // rowgroup - InvalidateFirstPassCache(); - - // We need to rebuild the cell map, because currently we can't insert - // new frames except at the end (append) - InvalidateCellMap(); - } else { // Just insert the frame and don't worry about reflowing it mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList); return NS_OK; } - // If we've added any columns, we need to rebuild the column cache. - InvalidateColumnCache(); + // Because the number of columns may have changed invalidate them + InvalidateColumnWidths(); - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - InvalidateColumnWidths(); + InvalidateFirstPassCache(); // XXX fix this // Mark the table as dirty and generate a reflow command targeted at the // outer table frame @@ -2094,6 +2325,8 @@ nsTableFrame::InsertFrames(nsIPresContext* aPresContext, NS_RELEASE(reflowCmd); } return rv; + + return NS_OK; } NS_IMETHODIMP @@ -2109,32 +2342,53 @@ nsTableFrame::RemoveFrame(nsIPresContext* aPresContext, if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) { nsIFrame* nextColGroupFrame; aOldFrame->GetNextSibling(&nextColGroupFrame); - - // Remove the col group frame + nsTableColGroupFrame* colGroup = (nsTableColGroupFrame*)aOldFrame; + PRInt32 firstColIndex = colGroup->GetStartColumnIndex(); + PRInt32 lastColIndex = firstColIndex + colGroup->GetColCount() - 1; + // remove the col frames, the colGroup frame and reset col indices + colGroup->RemoveChildrenAtEnd(*aPresContext, colGroup->GetColCount()); mColGroups.DestroyFrame(aPresContext, aOldFrame); + nsTableColGroupFrame::ResetColIndices(nextColGroupFrame, firstColIndex); + // remove the cols from the table + PRInt32 colX; + for (colX = lastColIndex; colX >= firstColIndex; colX--) { + nsTableColFrame* colFrame = (nsTableColFrame*)mColFrames.ElementAt(colX); + if (colFrame) { + RemoveCol(*aPresContext, colGroup, colX, PR_TRUE, PR_FALSE); + } + } + for (colX = lastColIndex; colX >= firstColIndex; colX--) { + nsTableColFrame* colFrame = (nsTableColFrame*)mColFrames.ElementAt(colX); + if (colFrame) { + RemoveCol(*aPresContext, colGroup, colX, PR_FALSE, PR_TRUE); + } + } - // Adjust the starting column index of the frames that follow - SetStartingColumnIndexFor((nsTableColGroupFrame*)nextColGroupFrame, - CalculateStartingColumnIndexFor((nsTableColGroupFrame*)nextColGroupFrame)); + PRInt32 numAnonymousColsToAdd = GetColCount() - mColFrames.Count(); + if (numAnonymousColsToAdd > 0) { + // this sets the child list, updates the col cache and cell map + CreateAnonymousColFrames(*aPresContext, numAnonymousColsToAdd, + eColAnonymousCell, PR_TRUE); + } + InvalidateColumnWidths(); } else if (IsRowGroup(display->mDisplay)) { + // remove the rows from the table + nsTableRowGroupFrame* rgFrame = (nsTableRowGroupFrame *) aOldFrame; + PRInt32 firstRowIndex = rgFrame->GetStartRowIndex(); + PRInt32 numRows; + rgFrame->GetRowCount(numRows); + RemoveRows(*aPresContext, firstRowIndex, numRows, PR_TRUE); + + // remove the row group frame from the sibling chain mFrames.DestroyFrame(aPresContext, aOldFrame); - // We need to rebuild the cell map, because currently we can't incrementally - // remove rows - InvalidateCellMap(); - + InvalidateColumnWidths(); } else { // Just remove the frame mFrames.DestroyFrame(aPresContext, aOldFrame); return NS_OK; } - - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - InvalidateColumnCache(); - // Because the number of columns may have changed invalidate the column // cache. Note that this has the side effect of recomputing the column // widths, so we don't need to call InvalidateColumnWidths() @@ -2200,6 +2454,29 @@ NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext* aPresContext, return rv; } +// this assumes the dirty children are contiguous +PRBool GetDirtyChildren(nsIFrame* aFrame, + nsIFrame** aFirstDirty, + PRInt32& aNumDirty) +{ + *aFirstDirty = nsnull; + aNumDirty = 0; + + nsIFrame* kidFrame; + aFrame->FirstChild(nsnull, &kidFrame); + while (kidFrame) { + nsFrameState frameState; + kidFrame->GetFrameState(&frameState); + if (frameState & NS_FRAME_IS_DIRTY) { + if (!*aFirstDirty) { + *aFirstDirty = kidFrame; + } + aNumDirty++; + } + } + return (aNumDirty > 0); +} + NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, InnerTableReflowState& aReflowState, @@ -2226,13 +2503,24 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext* aPresContext, break; case nsIReflowCommand::ReflowDirty: - // Problem is we don't know has changed, so assume the worst - InvalidateCellMap(); - InvalidateFirstPassCache(); - InvalidateColumnCache(); - InvalidateColumnWidths(); - rv = NS_OK; - break; + { + //nsIFrame* dirtyChild; + //PRInt32 numDirty; + //if (GetDirtyChildren(this, &dirtyChild, numDirty)) { + // for (PRInt32 dirtyX = 0; dirtyX < numDirty; dirtyX++) { + // ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus, + // dirtyChild, reason, PR_FALSE); + // dirtyChild->GetNextSibling(&dirtyChild); + // } + //} + //else { + // Problem is we don't know has changed, so assume the worst + InvalidateFirstPassCache(); + //} + InvalidateColumnWidths(); + rv = NS_OK; + break; + } default: NS_NOTYETIMPLEMENTED("unexpected reflow command type"); @@ -2893,13 +3181,13 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, mTableLayoutStrategy = new FixedTableLayoutStrategy(this); else mTableLayoutStrategy = new BasicTableLayoutStrategy(this, eCompatibility_NavQuirks == mode); - mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount(), aReflowState.mComputedWidth); + mTableLayoutStrategy->Initialize(aMaxElementSize, aReflowState.mComputedWidth); mBits.mColumnWidthsValid=PR_TRUE; } // fixed-layout tables need to reinitialize the layout strategy. When there are scroll bars // reflow gets called twice and the 2nd time has the correct space available. else if (!RequiresPass1Layout()) { - mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount(), aReflowState.mComputedWidth); + mTableLayoutStrategy->Initialize(aMaxElementSize, aReflowState.mComputedWidth); } mTableLayoutStrategy->BalanceColumnWidths(mStyleContext, aReflowState, maxWidth); @@ -2959,14 +3247,6 @@ void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext) nsRect tableSize = mRect; tableSize.width = tableWidth; - // account for scroll bars. XXX needs optimization/caching - if (mBits.mHasScrollableRowGroup) { - float sbWidth, sbHeight; - nsCOMPtr dc; - aPresContext->GetDeviceContext(getter_AddRefs(dc)); - dc->GetScrollBarDimensions(sbWidth, sbHeight); - tableSize.width += NSToCoordRound(sbWidth); - } SetRect(aPresContext, tableSize); } @@ -2984,7 +3264,7 @@ nscoord GetVerticalMarginBorderPadding(nsIFrame* aFrame, const nsIID& aIID) rv = iContent->QueryInterface(aIID, (void **)&htmlContent); if (htmlContent && NS_SUCCEEDED(rv)) { nsIStyleContext* styleContext; - aFrame->GetStyleContext(&styleContext); + aFrame->GetStyleContext(&styleContext); // XXX fix this leak const nsStyleSpacing* spacing = (const nsStyleSpacing*)styleContext->GetStyleData(eStyleStruct_Spacing); nsMargin margin(0,0,0,0); @@ -3287,8 +3567,9 @@ NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aCol nsCellMap *cellMap = GetCellMap(); if (nsnull!=cellMap) { // hooray, we get to do this the easy way because the info is cached - aColFrame = cellMap->GetColumnFrame(aColIndex); + aColFrame = (nsTableColFrame *)mColFrames.ElementAt(aColIndex); } + // XXX this should go away with the new synchronized col cache. else { // ah shucks, we have to go hunt for the column frame brute-force style nsIFrame *childFrame = mColGroups.FirstChild(); @@ -3302,7 +3583,7 @@ NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aCol PRInt32 colGroupStartingIndex = ((nsTableColGroupFrame *)childFrame)->GetStartColumnIndex(); if (aColIndex >= colGroupStartingIndex) { // the cell's col might be in this col group - PRInt32 colCount = ((nsTableColGroupFrame *)childFrame)->GetColumnCount(); + PRInt32 colCount = ((nsTableColGroupFrame *)childFrame)->GetColCount(); if (aColIndex < colGroupStartingIndex + colCount) { // yep, we've found it. GetColumnAt gives us the column at the offset colCount, not the absolute colIndex for the whole table aColFrame = ((nsTableColGroupFrame *)childFrame)->GetColumnAt(colCount); @@ -3322,45 +3603,6 @@ PRBool nsTableFrame::IsColumnWidthsSet() return (PRBool)firstInFlow->mBits.mColumnWidthsSet; } - -void nsTableFrame::CacheColFrames(nsIPresContext* aPresContext, - PRBool aReset) -{ - NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); - NS_ASSERTION(nsnull!=mCellMap, "never ever call me until the cell map is built!"); - - if (aReset) { - PRBool createdColFrames; - EnsureColumns(aPresContext, createdColFrames); - mCellMap->ClearColumnCache(); - } - - nsIFrame * childFrame = mColGroups.FirstChild(); - while (nsnull != childFrame) { // in this loop, we cache column info - nsTableColFrame* colFrame = nsnull; - childFrame->FirstChild(nsnull, (nsIFrame **)&colFrame); - while (nsnull != colFrame) { - const nsStyleDisplay* colDisplay; - colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) { - PRInt32 colIndex = colFrame->GetColumnIndex(); - PRInt32 repeat = colFrame->GetSpan(); - for (PRInt32 i=0; iGetColumnFrame(colIndex+i); - if (nsnull==cachedColFrame) { - mCellMap->AppendColumnFrame(colFrame); - } - colIndex++; - } - } - colFrame->GetNextSibling((nsIFrame **)&colFrame); - } - childFrame->GetNextSibling(&childFrame); - } - - mBits.mColumnCacheValid=PR_TRUE; -} - PRBool nsTableFrame::ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, const nsTableCellFrame& aCellFrame) const { @@ -3389,7 +3631,8 @@ PRBool nsTableFrame::ColumnsAreValidFor(const nsTableCellFrame& aCellFrame, } return PR_FALSE; } - + +// XXX This could be more incremental void nsTableFrame::InvalidateColumnWidths() { nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); @@ -3418,65 +3661,6 @@ void nsTableFrame::InvalidateFirstPassCache() firstInFlow->mBits.mFirstPassValid=PR_FALSE; } -PRBool nsTableFrame::IsColumnCacheValid() const -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - return (PRBool)firstInFlow->mBits.mColumnCacheValid; -} - -void nsTableFrame::InvalidateColumnCache() -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - firstInFlow->mBits.mColumnCacheValid=PR_FALSE; -} - -PRBool nsTableFrame::IsCellMapValid() const -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - return (PRBool)firstInFlow->mBits.mCellMapValid; -} - -static void InvalidateCellMapForRowGroup(nsIFrame* aRowGroupFrame) -{ - nsIFrame *rowFrame; - aRowGroupFrame->FirstChild(nsnull, &rowFrame); - for ( ; nsnull!=rowFrame; rowFrame->GetNextSibling(&rowFrame)) - { - const nsStyleDisplay *rowDisplay; - rowFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowDisplay); - if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) - { - ((nsTableRowFrame *)rowFrame)->ResetInitChildren(); - } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP==rowDisplay->mDisplay) - { - InvalidateCellMapForRowGroup(rowFrame); - } - } - -} - -void nsTableFrame::InvalidateCellMap() -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - firstInFlow->mBits.mCellMapValid=PR_FALSE; - // reset the state in each row - nsIFrame *rowGroupFrame=mFrames.FirstChild(); - for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(&rowGroupFrame)) - { - const nsStyleDisplay *rowGroupDisplay; - rowGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowGroupDisplay); - if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay)) - { - InvalidateCellMapForRowGroup(rowGroupFrame); - } - } -} - PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex) { nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); @@ -3937,35 +4121,18 @@ nsTableFrame::GetFrameName(nsString& aResult) const #endif // This assumes that aFrame is a scroll frame if -// XXX make this a macro if it becomes an issue -// XXX it has the side effect of setting mHasScrollableRowGroup nsTableRowGroupFrame* nsTableFrame::GetRowGroupFrameFor(nsIFrame* aFrame, const nsStyleDisplay* aDisplay) { nsIFrame* result = nsnull; -/* - if (IsRowGroup(aDisplay->mDisplay)) { - nsresult rv = aFrame->QueryInterface(kITableRowGroupFrameIID, (void **)&result); - if (NS_SUCCEEDED(rv) && (nsnull != result)) { - ; - } else { // it is a scroll frame that contains the row group frame - aFrame->FirstChild(nsnull, &result); - mBits.mHasScrollableRowGroup = PR_TRUE; - } - } -*/ - // ok this code looks to see if it is a scrollable frame. If it is it asks it for the scrolled // frame that should be the row group frame. -EDV nsIScrollableFrame* scrollable = nsnull; nsresult rv = aFrame->QueryInterface(kIScrollableFrameIID, (void **)&scrollable); if (NS_SUCCEEDED(rv) && (nsnull != scrollable)) { scrollable->GetScrolledFrame(nsnull, result); - - // this is scary? Why do we need this. - mBits.mHasScrollableRowGroup = PR_TRUE; } else { result = aFrame; } @@ -3980,15 +4147,109 @@ nsTableFrame::IsFinalPass(const nsHTMLReflowState& aState) (NS_UNCONSTRAINEDSIZE != aState.availableHeight); } -void nsTableFrame::Dump(PRBool aDumpCols, PRBool aDumpCellMap) +// Find the closet sibling before aPriorChildFrame (including aPriorChildFrame) that +// is of type aChildType +nsIFrame* +nsTableFrame::GetFrameAtOrBefore(nsIFrame* aParentFrame, + nsIFrame* aPriorChildFrame, + nsIAtom* aChildType) { - printf("***START TABLE DUMP***, \n colWidths="); - PRInt32 colX; + nsIFrame* result = nsnull; + if (!aPriorChildFrame) { + return result; + } + nsIAtom* frameType; + aPriorChildFrame->GetFrameType(&frameType); + if (aChildType == frameType) { + NS_RELEASE(frameType); + return (nsTableCellFrame*)aPriorChildFrame; + } + NS_IF_RELEASE(frameType); + + // aPriorChildFrame is not of type aChildType, so we need start from + // the beginnng and find the closest one + nsIFrame* childFrame; + nsIFrame* lastMatchingFrame = nsnull; + aParentFrame->FirstChild(nsnull, &childFrame); + while (childFrame != aPriorChildFrame) { + childFrame->GetFrameType(&frameType); + if (aChildType == frameType) { + lastMatchingFrame = childFrame; + } + NS_IF_RELEASE(frameType); + childFrame->GetNextSibling(&childFrame); + } + return (nsTableCellFrame*)lastMatchingFrame; +} + +void +nsTableFrame::DumpRowGroup(nsIFrame* aKidFrame) +{ + nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aKidFrame); + if (rgFrame) { + nsIFrame* rowFrame; + rgFrame->FirstChild(nsnull, &rowFrame); + while (rowFrame) { + nsIAtom* rowType; + rowFrame->GetFrameType(&rowType); + if (nsLayoutAtoms::tableRowFrame == rowType) { + printf("row(%d)=%p ", ((nsTableRowFrame*)rowFrame)->GetRowIndex(), rowFrame); + nsIFrame* cellFrame; + rowFrame->FirstChild(nsnull, &cellFrame); + while (cellFrame) { + nsIAtom* cellType; + cellFrame->GetFrameType(&cellType); + if (nsLayoutAtoms::tableCellFrame == cellType) { + PRInt32 colIndex; + ((nsTableCellFrame*)cellFrame)->GetColIndex(colIndex); + printf("cell(%d)=%p ", colIndex, cellFrame); + } + NS_IF_RELEASE(cellType); + cellFrame->GetNextSibling(&cellFrame); + } + printf("\n"); + } + else { + DumpRowGroup(rowFrame); + } + NS_IF_RELEASE(rowType); + rowFrame->GetNextSibling(&rowFrame); + } + } +} + +void nsTableFrame::Dump(PRBool aDumpRows, + PRBool aDumpCols, + PRBool aDumpCellMap) +{ + printf("***START TABLE DUMP*** \n"); + // dump the columns widths array + printf("mColWidths="); PRInt32 numCols = GetColCount(); + PRInt32 colX; for (colX = 0; colX < numCols; colX++) { printf("%d ", mColumnWidths[colX]); } + printf("\n"); + + if (aDumpRows) { + nsIFrame* kidFrame = mFrames.FirstChild(); + while (kidFrame) { + DumpRowGroup(kidFrame); + kidFrame->GetNextSibling(&kidFrame); + } + } + if (aDumpCols) { + // output col frame cache + printf("\n col frame cache ->"); + for (colX = 0; colX < numCols; colX++) { + nsTableColFrame* colFrame = (nsTableColFrame *)mColFrames.ElementAt(colX); + if (0 == (colX % 8)) { + printf("\n"); + } + printf ("%d=%p ", colX, colFrame); + } for (colX = 0; colX < numCols; colX++) { printf("\n"); nsTableColFrame* colFrame = GetColFrame(colX); @@ -3996,7 +4257,6 @@ void nsTableFrame::Dump(PRBool aDumpCols, PRBool aDumpCellMap) } } if (aDumpCellMap) { - printf("\n"); nsCellMap* cellMap = GetCellMap(); #ifdef NS_DEBUG cellMap->Dump(); @@ -4236,12 +4496,6 @@ NS_IMETHODIMP nsTableFrame::GetTableSize(PRInt32& aRowCount, PRInt32& aColCount) /*---------------- end of nsITableLayout implementation ------------------*/ -PRInt32 nsTableFrame::GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const -{ - nsCellMap* cellMap = GetCellMap(); - return cellMap->GetNumCellsOriginatingInRow(aRowIndex); -} - PRInt32 nsTableFrame::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const { nsCellMap* cellMap = GetCellMap(); @@ -4371,6 +4625,11 @@ nsTableFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const mCellMap->SizeOf(aHandler, &cellMapSize); aHandler->AddSize(nsLayoutAtoms::cellMap, cellMapSize); + // Add in size of col cache + PRUint32 voidArraySize; + mColFrames.SizeOf(aHandler, &voidArraySize); + sum += voidArraySize - sizeof(mColFrames); + // Add in size of table layout strategy PRUint32 strategySize; mTableLayoutStrategy->SizeOf(aHandler, &strategySize); diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h index fea1f1560e2..44d90099671 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.h +++ b/mozilla/layout/html/table/src/nsTableFrame.h @@ -43,6 +43,8 @@ class nsHTMLValue; struct InnerTableReflowState; struct nsStylePosition; struct nsStyleSpacing; +enum nsTableColType; +enum nsTableColGroupType; /** * Child list name indices @@ -124,8 +126,14 @@ public: /** helper method to find the table parent of any table frame object */ // TODO: today, this depends on display types. This should be changed to rely // on stronger criteria, like an inner table frame atom - static NS_METHOD GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aTableFrame); + static NS_METHOD GetTableFrame(nsIFrame* aSourceFrame, + nsTableFrame*& aTableFrame); + // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) + // of type aChildType. + static nsIFrame* nsTableFrame::GetFrameAtOrBefore(nsIFrame* aParentFrame, + nsIFrame* aPriorChildFrame, + nsIAtom* aChildType); /** * @param aReflowState the context within which we're to determine the table width info * @param aSpecifiedTableWidth [OUT] if the table is not auto-width, @@ -143,10 +151,6 @@ public: PRBool IsRowGroup(PRInt32 aDisplayType) const; /** Initialize the table frame with a set of children. - * Calls DidAppendRowGroup which calls nsTableRowFrame::InitChildren - * which finally calls back into this table frame to build the cell map. - * Also ensures we have the right number of column frames for the child list. - * * @see nsIFrame::SetInitialChildList */ NS_IMETHOD SetInitialChildList(nsIPresContext* aPresContext, @@ -162,16 +166,6 @@ public: NS_IMETHOD GetAdditionalChildListName(PRInt32 aIndex, nsIAtom** aListName) const; - /** complete the append of aRowGroupFrame to the table - * this builds the cell map by calling nsTableRowFrame::InitChildren - * which calls back into this table frame to build the cell map. - * @param aRowGroupFrame the row group that was appended. - * note that this method is optimized for content appended, and doesn't - * work for random insertion of row groups. Random insertion must go - * through incremental reflow notifications. - */ - NS_IMETHOD DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFrame); - /** @see nsIFrame::Paint */ NS_IMETHOD Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, @@ -221,6 +215,8 @@ public: */ NS_METHOD GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame); + nsFrameList& GetColGroups(); + /** return PR_TRUE if the column width information has been set */ PRBool IsColumnWidthsSet(); @@ -308,14 +304,84 @@ public: */ PRInt32 GetNextAvailRowIndex() const; - /** build as much of the CellMap as possible from the info we have so far - */ - virtual PRInt32 AddCellToTable (nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex); - virtual void RemoveCellFromTable (nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex); + /** return the column frame associated with aColIndex */ + nsTableColFrame* GetColFrame(PRInt32 aColIndex) const; - virtual void AddColumnFrame (nsTableColFrame *aColFrame); + void InsertCol(nsIPresContext& aPresContext, + nsTableColFrame& aColFrame, + PRInt32 aColIndex); + + nsTableColGroupFrame* CreateAnonymousColGroupFrame(nsIPresContext& aPresContext, + nsTableColGroupType aType); + + PRInt32 DestroyAnonymousColFrames(nsIPresContext& aPresContext, + PRInt32 aNumFrames); + + void CreateAnonymousColFrames(nsIPresContext& aPresContext, + PRInt32 aNumColsToAdd, + nsTableColType aColType, + PRBool aDoAppend, + nsIFrame* aPrevCol = nsnull); + + void CreateAnonymousColFrames(nsIPresContext& aPresContext, + nsTableColGroupFrame& aColGroupFrame, + PRInt32 aNumColsToAdd, + nsTableColType aColType, + PRBool aAddToColGroupAndTable, + nsIFrame* aPrevCol, + nsIFrame** aFirstNewFrame); + + /** empty the column frame cache */ + void ClearColCache(); + + virtual PRInt32 AppendCell(nsIPresContext& aPresContext, + nsTableCellFrame& aCellFrame, + PRInt32 aRowIndex); + + virtual void InsertCells(nsIPresContext& aPresContext, + nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndexBefore); + + virtual void RemoveCell(nsIPresContext& aPresContext, + nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex); + + void AppendRows(nsIPresContext& aPresContext, + nsVoidArray& aRowFrames); + + PRInt32 InsertRow(nsIPresContext& aPresContext, + nsIFrame& aFrame, + PRInt32 aRowIndex, + PRBool aConsiderSpans); + + PRInt32 InsertRows(nsIPresContext& aPresContext, + nsVoidArray& aFrames, + PRInt32 aRowIndex, + PRBool aConsiderSpans); + + virtual void RemoveRows(nsIPresContext& aPresContext, + PRInt32 aFirstRowFrame, + PRInt32 aNumRowsToRemove, + PRBool aConsiderSpans); + + void AppendRowGroups(nsIPresContext& aPresContext, + nsIFrame* aFirstRowGroupFrame); + + void InsertRowGroups(nsIPresContext& aPresContext, + nsIFrame* aFirstRowGroupFrame, + PRInt32 aRowIndex); + + void InsertColGroups(nsIPresContext& aPresContext, + PRInt32 aColIndex, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame = nsnull); + + virtual void RemoveCol(nsIPresContext& aPresContext, + nsTableColGroupFrame* aColGroupFrame, + PRInt32 aColIndex, + PRBool aRemoveFromCache, + PRBool aRemoveFromCellMap); static PRBool IsFinalPass(const nsHTMLReflowState& aReflowState); @@ -323,7 +389,7 @@ public: PRInt32 aColX, PRBool* aOriginates = nsnull, PRInt32* aColSpan = nsnull); - PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const; + PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const; NS_METHOD GetBorderPlusMarginPadding(nsMargin& aResult); @@ -554,9 +620,6 @@ protected: /** returns PR_TRUE if the cached pass 1 data is still valid */ virtual PRBool IsFirstPassValid() const; - /** returns PR_TRUE if the cached column info is still valid */ - virtual PRBool IsColumnCacheValid() const; - /** returns PR_TRUE if the cached column info is still valid */ virtual PRBool IsColumnWidthsValid() const; @@ -612,8 +675,6 @@ public: virtual void InvalidateFirstPassCache(); - virtual void InvalidateColumnCache(); - virtual void InvalidateColumnWidths(); protected: @@ -623,38 +684,18 @@ protected: void MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBorderWidth); PRBool ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult); - /** returns PR_TRUE if the cached pass 1 data is still valid */ - virtual PRBool IsCellMapValid() const; - public: /** Get the cell map for this table frame. It is not always mCellMap. * Only the firstInFlow has a legit cell map */ virtual nsCellMap *GetCellMap() const; - - /** ResetCellMap is called when the cell structure of the table is changed. - * Call with caution, only when changing the structure of the table such as - * inserting or removing rows, changing the rowspan or colspan attribute of a cell, etc. - */ - virtual void InvalidateCellMap(); - /** sum the columns represented by all nsTableColGroup objects. - * if the cell map says there are more columns than this, - * add extra implicit columns to the content tree. - * - * returns whether any implicit column frames were created - */ - virtual void EnsureColumns (nsIPresContext* aPresContext, - PRBool& aCreatedColFrames); - - // These methods are used to incrementally insert and remove rows - // from the cell map without having to invalidate the entire map. - NS_IMETHOD InsertRowIntoMap(nsTableRowFrame* aRow, PRInt32 aRowIndex); - NS_IMETHOD RemoveRowFromMap(nsTableRowFrame* aRow, PRInt32 aRowIndex); + void AdjustRowIndices(PRInt32 aRowIndex, + PRInt32 aAdjustment); NS_IMETHOD AdjustRowIndices(nsIFrame* aRowGroup, - PRInt32 aRowIndex, - PRInt32 anAdjustment); + PRInt32 aRowIndex, + PRInt32 anAdjustment); // Return PR_TRUE if rules=groups is set for the table content PRBool HasGroupRules() const; @@ -662,9 +703,9 @@ public: // Remove cell borders which aren't bordering row and/or col groups void ProcessGroupRules(nsIPresContext* aPresContext); + nsVoidArray& GetColCache(); + protected: - /** iterates all child frames and creates a new cell map */ - NS_IMETHOD ReBuildCellMap(); void SetColumnDimensions(nsIPresContext* aPresContext, nscoord aHeight); @@ -685,7 +726,14 @@ protected: /** * Return aFrame's child if aFrame is an nsScrollFrame, otherwise return aFrame */ - nsTableRowGroupFrame* GetRowGroupFrameFor(nsIFrame* aFrame, const nsStyleDisplay* aDisplay); + nsTableRowGroupFrame* GetRowGroupFrameFor(nsIFrame* aFrame, + const nsStyleDisplay* aDisplay); + + nsTableRowGroupFrame* GetRowGroupFrame(nsIFrame* aFrame, + nsIAtom* aFrameTypeIn = nsnull); + + void CollectRows(nsIFrame* aFrame, + nsVoidArray& aCollection); public: /* ----- Cell Map public methods ----- */ @@ -752,14 +800,16 @@ public: /* ----- Cell Map public methods ----- */ /*------------end of nsITableLayout methods -----------------------*/ - - virtual void CacheColFrames(nsIPresContext* aPresContext, - PRBool aReset = PR_FALSE); public: static nsIAtom* gColGroupAtom; - void Dump(PRBool aDumpCols, PRBool aDumpCellMap); + void Dump(PRBool aDumpRows, + PRBool aDumpCols, + PRBool aDumpCellMap); + + nsVoidArray mColFrames; // XXX temporarily public protected: + void DumpRowGroup(nsIFrame* aChildFrame); void DebugPrintCount() const; // Debugging routine // data members @@ -770,15 +820,11 @@ protected: unsigned mColumnWidthsSet:1; // PR_TRUE if column widths have been set at least once unsigned mColumnWidthsValid:1; // PR_TRUE if column width data is still legit, PR_FALSE if it needs to be recalculated unsigned mFirstPassValid:1; // PR_TRUE if first pass data is still legit, PR_FALSE if it needs to be recalculated - unsigned mColumnCacheValid:1; // PR_TRUE if column cache info is still legit, PR_FALSE if it needs to be recalculated - unsigned mCellMapValid:1; // PR_TRUE if cell map data is still legit, PR_FALSE if it needs to be recalculated unsigned mIsInvariantWidth:1; // PR_TRUE if table width cannot change - unsigned mHasScrollableRowGroup:1; // PR_TRUE if any section has overflow == "auto" or "scroll" unsigned mNonPercentSpansPercent:1; - int : 24; // unused + int : 26; // unused } mBits; - PRInt32 mColCount; // the number of columns in this table nsCellMap* mCellMap; // maintains the relationships between rows, cols, and cells nsITableLayoutStrategy * mTableLayoutStrategy; // the layout strategy for this frame nsFrameList mColGroups; // the list of colgroup frames @@ -811,6 +857,16 @@ inline void nsTableFrame::SetHasNonPercentSpanningPercent(PRBool aValue) mBits.mNonPercentSpansPercent = (unsigned)aValue; } +inline nsFrameList& nsTableFrame::GetColGroups() +{ + return mColGroups; +} + +inline nsVoidArray& nsTableFrame::GetColCache() +{ + return mColFrames; +} + enum nsTableIteration { eTableLTR = 0, eTableRTL = 1, diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index 3aedfc98fe5..26a593e6af2 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -56,6 +56,7 @@ nsTableRowFrame::nsTableRowFrame() mAllBits(0) { mBits.mMinRowSpan = 1; + mBits.mRowIndex = 0; } NS_IMETHODIMP @@ -129,23 +130,11 @@ nsTableRowFrame::AppendFrames(nsIPresContext* aPresContext, if (NS_STYLE_DISPLAY_TABLE_CELL == display->mDisplay) { // Add the cell to the cell map - PRInt32 colIndex = tableFrame->AddCellToTable((nsTableCellFrame*)childFrame, - GetRowIndex()); - - // Initialize the cell frame and give it its column index - ((nsTableCellFrame*)childFrame)->InitCellFrame(colIndex); + tableFrame->AppendCell(*aPresContext, (nsTableCellFrame&)*childFrame, GetRowIndex()); } } - // See if any implicit column frames need to be created as a result of - // adding the new rows - PRBool createdColFrames; - tableFrame->EnsureColumns(aPresContext, createdColFrames); - if (createdColFrames) { - // We need to rebuild the column cache - // XXX It would be nice if this could be done incrementally - tableFrame->InvalidateColumnCache(); - } + tableFrame->InvalidateColumnWidths(); // Reflow the new frames. They're already marked dirty, so generate a reflow // command that tells us to reflow our dirty child frames @@ -160,6 +149,7 @@ nsTableRowFrame::AppendFrames(nsIPresContext* aPresContext, return NS_OK; } + NS_IMETHODIMP nsTableRowFrame::InsertFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, @@ -171,26 +161,39 @@ nsTableRowFrame::InsertFrames(nsIPresContext* aPresContext, nsTableFrame* tableFrame = nsnull; nsTableFrame::GetTableFrame(this, tableFrame); - // Insert the frames + // gather the new frames (only those which are cells) into an array + nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsLayoutAtoms::tableCellFrame); + nsVoidArray cellChildren; + for (nsIFrame* childFrame = aFrameList; childFrame; childFrame->GetNextSibling(&childFrame)) { + nsIAtom* frameType; + childFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableCellFrame == frameType) { + cellChildren.AppendElement(childFrame); + } + NS_IF_RELEASE(frameType); + } + // insert the cells into the cell map + PRInt32 colIndex = -1; + if (prevCellFrame) { + prevCellFrame->GetColIndex(colIndex); + } + tableFrame->InsertCells(*aPresContext, cellChildren, GetRowIndex(), colIndex); + + // Insert the frames in the frame list mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); - // We need to rebuild the cell map, because currently we can't insert - // new frames except at the end (append) - tableFrame->InvalidateCellMap(); + // Because the number of columns may have changed invalidate the column widths + tableFrame->InvalidateColumnWidths(); - // We should try and avoid doing a pass1 reflow on all the cells and just - // do it for the newly added frames, but we need to add these frames to the - // cell map before we reflow them - tableFrame->InvalidateFirstPassCache(); + // Reflow the new frames. They're already marked dirty, so generate a reflow + // command that tells us to reflow our dirty child frames + nsIReflowCommand* reflowCmd; - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - tableFrame->InvalidateColumnCache(); - - // Generate a reflow command so we reflow the table itself. This will - // do a pass-1 reflow of all the rows including any rows we just added - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); + if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, + nsIReflowCommand::ReflowDirty))) { + aPresShell.AppendReflowCommand(reflowCmd); + NS_RELEASE(reflowCmd); + } return NS_OK; } @@ -203,91 +206,28 @@ nsTableRowFrame::RemoveFrame(nsIPresContext* aPresContext, // Get the table frame nsTableFrame* tableFrame=nsnull; nsTableFrame::GetTableFrame(this, tableFrame); + if (tableFrame) { + nsIAtom* frameType; + aOldFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableCellFrame == frameType) { + nsTableCellFrame* cellFrame = (nsTableCellFrame*)aOldFrame; + PRInt32 colIndex; + cellFrame->GetColIndex(colIndex); + tableFrame->RemoveCell(*aPresContext, cellFrame, GetRowIndex()); -#if 0 - // XXX Currently we can't incrementally remove cells from the cell map - PRInt32 colIndex; - aDeletedFrame->GetColIndex(colIndex); - tableFrame->RemoveCellFromTable(aOldFrame, GetRowIndex()); + // Remove the frame and destroy it + mFrames.DestroyFrame(aPresContext, aOldFrame); - // Remove the frame and destroy it - mFrames.DestroyFrame(aPresContext, (nsIFrame*)aOldFrame); + // cells have possibly shifted into different columns. + tableFrame->InvalidateColumnWidths(); - // XXX Reflow the row - -#else - // Remove the frame and destroy it - mFrames.DestroyFrame(aPresContext, aOldFrame); - - // We need to rebuild the cell map, because currently we can't incrementally - // remove rows - tableFrame->InvalidateCellMap(); - - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - tableFrame->InvalidateColumnCache(); - - // Because we haven't added any new frames we don't need to do a pass1 - // reflow. Just generate a reflow command so we reflow the table itself - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); -#endif - - return NS_OK; -} - -NS_IMETHODIMP -nsTableRowFrame::InitChildrenWithIndex(PRInt32 aRowIndex) -{ - nsTableFrame* table = nsnull; - nsresult result=NS_OK; - - // each child cell can only be added to the table one time. - // for now, we remember globally whether we've added all or none - if (0 == (mState & NS_TABLE_ROW_FRAME_INITIALIZED_CHILDREN)) - { - result = nsTableFrame::GetTableFrame(this, table); - if ((NS_OK==result) && (table != nsnull)) - { - mState |= NS_TABLE_ROW_FRAME_INITIALIZED_CHILDREN; - SetRowIndex(aRowIndex); - - for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) - { - const nsStyleDisplay *kidDisplay; - kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) - { - // add the cell frame to the table's cell map and get its col index - PRInt32 colIndex; - colIndex = table->AddCellToTable((nsTableCellFrame *)kidFrame, aRowIndex); - // what column does this cell belong to? - // this sets the frame's notion of its column index - ((nsTableCellFrame *)kidFrame)->InitCellFrame(colIndex); - } - } + // Because we haven't added any new frames we don't need to do a pass1 + // reflow. Just generate a reflow command so we reflow the table itself + AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); } + NS_IF_RELEASE(frameType); } - return NS_OK; -} -NS_IMETHODIMP -nsTableRowFrame::InitChildren() -{ - nsTableFrame* table = nsnull; - nsresult result=NS_OK; - - // each child cell can only be added to the table one time. - // for now, we remember globally whether we've added all or none - if (0 == (mState & NS_TABLE_ROW_FRAME_INITIALIZED_CHILDREN)) - { - result = nsTableFrame::GetTableFrame(this, table); - if ((NS_OK==result) && (table != nsnull)) - { - PRInt32 rowIndex = table->GetNextAvailRowIndex(); - InitChildrenWithIndex(rowIndex); - } - } return NS_OK; } diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.h b/mozilla/layout/html/table/src/nsTableRowFrame.h index 413af3ba959..bef9656dce0 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowFrame.h @@ -62,9 +62,6 @@ struct RowReflowState { /** * Additional frame-state bits */ -#define NS_TABLE_ROW_FRAME_INITIALIZED_CHILDREN 0x80000000 // set if child cells have been - // added to the table - #define NS_TABLE_MAX_ROW_INDEX (1<<19) /** @@ -100,12 +97,6 @@ public: nsIAtom* aListName, nsIFrame* aOldFrame); - /** Initialization of data */ - NS_IMETHOD InitChildren(); - NS_IMETHOD InitChildrenWithIndex(PRInt32 aRowIndex); - - void ResetInitChildren(); - /** instantiate a new instance of nsTableRowFrame. * @param aResult the new object is returned in this out-param * @param aContent the table object to map @@ -322,11 +313,6 @@ inline void nsTableRowFrame::SetRowIndex (int aRowIndex) mBits.mRowIndex = aRowIndex; } -inline void nsTableRowFrame::ResetInitChildren() -{ - mState &= ~NS_TABLE_ROW_FRAME_INITIALIZED_CHILDREN; -} - inline void nsTableRowFrame::GetMaxElementSize(nsSize& aMaxElementSize) const { aMaxElementSize.width = mMaxElementSize.width; diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 7c1992aa787..2d40d577ee0 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -565,6 +565,7 @@ NS_METHOD nsTableRowGroupFrame::PullUpAllRowFrames(nsIPresContext* aPresContext) void nsTableRowGroupFrame::GetNextRowSibling(nsIFrame** aRowFrame) { + if (!*aRowFrame) return; GetNextFrame(*aRowFrame, aRowFrame); while(*aRowFrame) { const nsStyleDisplay *display; @@ -596,7 +597,9 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, PRBool hasRowSpanningCell = PR_FALSE; PRInt32 numRows; GetRowCount(numRows, PR_FALSE); + if (numRows <= 0) return; nscoord *rowHeights = new nscoord[numRows]; + if (!rowHeights) return; nsCRT::memset (rowHeights, 0, numRows*sizeof(nscoord)); /* Step 1: get the height of the tallest cell in the row and save it for @@ -747,10 +750,11 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, // If this is pass 2 then resize the row to its final size and move the // row's position if the previous rows have caused a shift if (1 == counter) { - nsRect rowBounds; - rowFrame->GetRect(rowBounds); + PRBool movedFrame = (deltaY != 0); + nsRect rowBounds; // Move the row to the correct position + rowFrame->GetRect(rowBounds); // added rowBounds.y += deltaY; // Adjust our running delta @@ -759,6 +763,17 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, // Resize the row to its final size and position rowBounds.height = rowHeights[rowIndex]; rowFrame->SetRect(aPresContext, rowBounds); + + if (movedFrame) { + // Make sure any views are positioned properly + nsIView* view; + rowFrame->GetView(aPresContext, &view); + if (view) { + nsContainerFrame::PositionFrameView(aPresContext, rowFrame, view); + } else { + nsContainerFrame::PositionChildViews(aPresContext, rowFrame); + } + } } rowIndex++; @@ -1155,45 +1170,47 @@ nsTableRowGroupFrame::AddTableDirtyReflowCommand(nsIPresContext* aPresContext, return rv; } +#if 0 + // Reflow the new frames. They're already marked dirty, so generate a reflow + // command that tells us to reflow our dirty child frames + nsIReflowCommand* reflowCmd; + + if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, + nsIReflowCommand::ReflowDirty))) { + aPresShell.AppendReflowCommand(reflowCmd); + NS_RELEASE(reflowCmd); + } +#endif + +// this does not get called for trees NS_IMETHODIMP nsTableRowGroupFrame::AppendFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aFrameList) { - // Get the table frame - nsTableFrame* tableFrame; - nsTableFrame::GetTableFrame(this, tableFrame); + // collect the new row frames in an array + nsVoidArray rows; + for (nsIFrame* rowFrame = aFrameList; rowFrame; rowFrame->GetNextSibling(&rowFrame)) { + nsIAtom* frameType; + rowFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableRowFrame == frameType) { + rows.AppendElement(rowFrame); + } + NS_IF_RELEASE(frameType); + } - // Append the frames + // Append the frames to the sibling chain mFrames.AppendFrames(nsnull, aFrameList); - const nsStyleDisplay *display; - aFrameList->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - // See if the newly appended rows are the last rows in the table. - // XXX is this the correct code path for nested row groups, considering that whitespace frames may exist currently - if ((NS_STYLE_DISPLAY_TABLE_ROW_GROUP != display->mDisplay) && NoRowsFollow()) { - // The rows we appended are the last rows in the table so incrementally - // add them to the cell map - PRBool haveRows = PR_FALSE; - for (nsIFrame* rowFrame = aFrameList; rowFrame; rowFrame->GetNextSibling(&rowFrame)) { - rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - if (NS_STYLE_DISPLAY_TABLE_ROW == display->mDisplay) { - DidAppendRow((nsTableRowFrame*)rowFrame); - haveRows = PR_TRUE; - } - } + if (rows.Count() > 0) { + nsTableFrame* tableFrame = nsnull; + nsTableFrame::GetTableFrame(this, tableFrame); + if (tableFrame) { + tableFrame->AppendRows(*aPresContext, rows); - if (haveRows) { - // See if any implicit column frames need to be created as a result of - // adding the new rows - PRBool createdColFrames; - tableFrame->EnsureColumns(aPresContext, createdColFrames); - if (createdColFrames) { - // We need to rebuild the column cache - // XXX It would be nice if this could be done incrementally - tableFrame->InvalidateColumnCache(); - } + // Because the number of columns may have changed invalidate the column widths + tableFrame->InvalidateColumnWidths(); // Reflow the new frames. They're already marked dirty, so generate a reflow // command that tells us to reflow our dirty child frames @@ -1205,29 +1222,12 @@ nsTableRowGroupFrame::AppendFrames(nsIPresContext* aPresContext, NS_RELEASE(reflowCmd); } } - } else { - // We need to rebuild the cell map, because currently we can't insert - // new frames except at the end (append) - tableFrame->InvalidateCellMap(); - - // We should try and avoid doing a pass1 reflow on all the cells and just - // do it for the newly added frames, but we need to add these frames to the - // cell map before we reflow them - tableFrame->InvalidateFirstPassCache(); - - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - tableFrame->InvalidateColumnCache(); - - // Generate a reflow command so we reflow the table itself. This will - // do a pass-1 reflow of all the rows including any rows we just added - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); } return NS_OK; } +// this does not get called for trees NS_IMETHODIMP nsTableRowGroupFrame::InsertFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, @@ -1235,65 +1235,76 @@ nsTableRowGroupFrame::InsertFrames(nsIPresContext* aPresContext, nsIFrame* aPrevFrame, nsIFrame* aFrameList) { - // Get the table frame - nsTableFrame* tableFrame = nsnull; - nsTableFrame::GetTableFrame(this, tableFrame); + // collect the new row frames in an array + nsVoidArray rows; + for (nsIFrame* rowFrame = aFrameList; rowFrame; rowFrame->GetNextSibling(&rowFrame)) { + nsIAtom* frameType; + rowFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableRowFrame == frameType) { + rows.AppendElement(rowFrame); + } + NS_IF_RELEASE(frameType); + } - // Insert the frames + // Insert the frames in the sibling chain mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); - // We need to rebuild the cell map, because currently we can't insert - // new frames except at the end (append) - tableFrame->InvalidateCellMap(); + if (rows.Count() > 0) { + nsTableFrame* tableFrame = nsnull; + nsTableFrame::GetTableFrame(this, tableFrame); + if (tableFrame) { + nsTableRowFrame* prevRow = (nsTableRowFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsLayoutAtoms::tableRowFrame); + PRInt32 rowIndex = (prevRow) ? prevRow->GetRowIndex() : 0; + tableFrame->InsertRows(*aPresContext, rows, rowIndex, PR_TRUE); - // We should try and avoid doing a pass1 reflow on all the cells and just - // do it for the newly added frames, but we need to add these frames to the - // cell map before we reflow them - tableFrame->InvalidateFirstPassCache(); + // Reflow the new frames. They're already marked dirty, so generate a reflow + // command that tells us to reflow our dirty child frames + nsIReflowCommand* reflowCmd; - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - tableFrame->InvalidateColumnCache(); + if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, + nsIReflowCommand::ReflowDirty))) { + aPresShell.AppendReflowCommand(reflowCmd); + NS_RELEASE(reflowCmd); + } + + // Because the number of columns may have changed invalidate the column widths + tableFrame->InvalidateColumnWidths(); + + // Generate a reflow command so we reflow the table itself. This will + // do a pass-1 reflow of all the rows including any rows we just added + AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); + } + } - // Generate a reflow command so we reflow the table itself. This will - // do a pass-1 reflow of all the rows including any rows we just added - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); return NS_OK; } +// this does not get called for trees NS_IMETHODIMP nsTableRowGroupFrame::RemoveFrame(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aOldFrame) { - const nsStyleDisplay *display; - aOldFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - PRBool validChild = (NS_STYLE_DISPLAY_TABLE_ROW == display->mDisplay) || - (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == display->mDisplay); + nsTableFrame* tableFrame = nsnull; + nsTableFrame::GetTableFrame(this, tableFrame); + if (tableFrame) { + nsIAtom* frameType; + aOldFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableRowFrame == frameType) { + PRInt32 firstRowIndex = ((nsTableRowFrame *)aOldFrame)->GetRowIndex(); - // Remove the frame and destroy it - if (mFrames.DestroyFrame(aPresContext, aOldFrame)) { - if (validChild) { - // Get the table frame - nsTableFrame* tableFrame = nsnull; - nsTableFrame::GetTableFrame(this, tableFrame); - - // We need to rebuild the cell map, because currently we can't incrementally - // remove rows - tableFrame->InvalidateCellMap(); - - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - tableFrame->InvalidateColumnCache(); + tableFrame->RemoveRows(*aPresContext, firstRowIndex, 1, PR_TRUE); + // Because the number of columns may have changed invalidate the column widths + tableFrame->InvalidateColumnWidths(); // Because we haven't added any new frames we don't need to do a pass1 // reflow. Just generate a reflow command so we reflow the table itself AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); } + NS_IF_RELEASE(frameType); } + mFrames.DestroyFrame(aPresContext, aOldFrame); return NS_OK; } @@ -1350,54 +1361,6 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext* aPresContext, return rv; } -NS_METHOD nsTableRowGroupFrame::DidAppendRow(nsTableRowFrame *aRowFrame) -{ - nsresult rv=NS_OK; - /* need to make space in the cell map. Remeber that row spans can't cross row groups - once the space is made, tell the row to initizalize its children. - it will automatically find the row to initialize into. - but this is tough because a cell in aInsertedFrame could have a rowspan - which must be respected if a subsequent row is appended. - */ - rv = aRowFrame->InitChildren(); - return rv; -} - -// support method that tells us if there are any rows in the table after our rows -// returns PR_TRUE if there are no rows after ours -PRBool nsTableRowGroupFrame::NoRowsFollow() -{ - // XXX This method doesn't play well with the tree widget. - PRBool result = PR_TRUE; - nsIFrame *nextSib=nsnull; - GetNextSibling(&nextSib); - while (nsnull!=nextSib) - { - const nsStyleDisplay *sibDisplay; - nextSib->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)sibDisplay)); - if ((NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == sibDisplay->mDisplay) || - (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == sibDisplay->mDisplay) || - (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == sibDisplay->mDisplay)) - { - nsIFrame *childFrame=nsnull; - nextSib->FirstChild(nsnull, &childFrame); - while (nsnull!=childFrame) - { - const nsStyleDisplay *childDisplay; - childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { // found a row - result = PR_FALSE; - break; - } - childFrame->GetNextSibling(&childFrame); - } - } - nextSib->GetNextSibling(&nextSib); - } - return result; -} - NS_METHOD nsTableRowGroupFrame::GetHeightOfRows(nscoord& aResult) { // the rows in rowGroupFrame need to be expanded by rowHeightDelta[i] diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h index d1336651d59..da54198f00a 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h @@ -244,10 +244,6 @@ protected: RowGroupReflowState& aReflowState, nsReflowStatus& aStatus); - NS_IMETHOD DidAppendRow(nsTableRowFrame *aRowFrame); - - PRBool NoRowsFollow(); - nsresult AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, RowGroupReflowState& aReflowState, nsIFrame* aKidFrame, diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp index 31e8f436ad2..d65fd9d665c 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp @@ -59,17 +59,6 @@ PRBool CanAllocate(PRInt32 aTypeToAllocate, /* ---------- BasicTableLayoutStrategy ---------- */ -/* return true if the style indicates that the width is fixed - * for the purposes of column width determination - */ -inline -PRBool BasicTableLayoutStrategy::IsFixedWidth(const nsStylePosition* aStylePosition, - const nsStyleTable* aStyleTable) -{ - return PRBool ((eStyleUnit_Coord==aStylePosition->mWidth.GetUnit()) || - (eStyleUnit_Coord==aStyleTable->mSpanWidth.GetUnit())); -} - MOZ_DECL_CTOR_COUNTER(BasicTableLayoutStrategy); @@ -90,8 +79,7 @@ BasicTableLayoutStrategy::~BasicTableLayoutStrategy() MOZ_COUNT_DTOR(BasicTableLayoutStrategy); } -PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, - PRInt32 aNumCols, +PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, nscoord aMaxWidth) { ContinuingFrameCheck(); @@ -99,12 +87,10 @@ PRBool BasicTableLayoutStrategy::Initialize(nsSize* aMaxElementSize, PRBool result = PR_TRUE; // re-init instance variables - mNumCols = aNumCols; mMinTableContentWidth = 0; mMaxTableContentWidth = 0; mCellSpacingTotal = 0; mCols = mTableFrame->GetEffectiveCOLSAttribute(); - // assign the width of all fixed-width columns AssignPreliminaryColumnWidths(aMaxWidth); @@ -157,7 +143,7 @@ PRBool BCW_Wrapup(BasicTableLayoutStrategy* aStrategy, { if (aAllocTypes) delete [] aAllocTypes; - if (gsDebugBalance) {printf("BalanceColumnWidths ex \n"); aTableFrame->Dump(PR_TRUE, PR_FALSE);} + if (gsDebugBalance) {printf("BalanceColumnWidths ex \n"); aTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);} return PR_TRUE; } @@ -176,7 +162,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty const nsHTMLReflowState& aReflowState, nscoord aMaxWidthIn) { - if (gsDebugBalance) {printf("BalanceColumnWidths en max=%d\n", aMaxWidthIn); mTableFrame->Dump(PR_TRUE, PR_FALSE);} + if (gsDebugBalance) {printf("BalanceColumnWidths en max=%d\n", aMaxWidthIn); mTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);} ContinuingFrameCheck(); if (!aTableStyle) { @@ -184,6 +170,8 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty return PR_FALSE; } + PRInt32 numCols = mTableFrame->GetColCount(); + // determine if the table is auto/fixed and get the fixed width if available nscoord maxWidth = aMaxWidthIn; nscoord specifiedTableWidth = 0; @@ -204,7 +192,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty } // initialize the col percent and cell percent values to 0. PRInt32 colX; - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); colFrame->SetWidth(PCT, WIDTH_NOT_SET); colFrame->SetWidth(PCT_ADJ, WIDTH_NOT_SET); @@ -220,7 +208,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty PRBool recomputedAdjMin = RecomputeAdjMinIfNecessary(); // set the table's columns to the min width - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord colMinWidth = colFrame->GetMinWidth(); mTableFrame->SetColumnWidth(colX, colMinWidth); @@ -257,10 +245,10 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty nscoord totalAllocated = totalWidths[MIN_CON] + cellSpacingTotal; // allocate and initialize arrays indicating what col gets set - PRInt32* allocTypes = new PRInt32[mNumCols]; + PRInt32* allocTypes = new PRInt32[numCols]; if (!allocTypes) return PR_FALSE; - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { allocTypes[colX] = -1; } @@ -330,9 +318,9 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty PRBool skip0Proportional = totalCounts[DES_CON] > num0Proportional; if ( (tableIsAutoWidth && (perAdjTableWidth - totalAllocated > 0)) || (!tableIsAutoWidth && (totalAllocated < maxWidth)) ) { - if (totalCounts[PCT] != mNumCols) { + if (totalCounts[PCT] != numCols) { //PRBool onlyAuto = (totalCounts[DES_CON] > 0) && !mIsNavQuirksMode; - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (PCT == allocTypes[colX]) { allocTypes[colX] = -1; } @@ -350,7 +338,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aTableSty } // give the proportional cols the rest up to the max width in quirks mode else if (tableIsAutoWidth && mIsNavQuirksMode && (totalCounts[MIN_PRO] > 0)) { - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (DES_CON != allocTypes[colX]) { allocTypes[colX] = -1; } @@ -369,7 +357,8 @@ void BasicTableLayoutStrategy::AllocateFully(nscoord& aTotalAllocated, PRInt32 aWidthType, PRBool aMarkAllocated) { - for (PRInt32 colX = 0; colX < mNumCols; colX++) { + PRInt32 numCols = mTableFrame->GetColCount(); + for (PRInt32 colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord oldWidth = mTableFrame->GetColumnWidth(colX); nscoord newWidth = colFrame->GetWidth(aWidthType); @@ -408,13 +397,14 @@ void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount, PRInt32 numColsAllocated = 0; PRInt32 totalAllocated = 0; PRInt32 colX; - for (colX = 0; colX < mNumCols; colX++) { + PRInt32 numCols = mTableFrame->GetColCount(); + for (colX = 0; colX < numCols; colX++) { if (-1 != aAllocTypes[colX]) { divisor += mTableFrame->GetColumnWidth(colX); numColsAllocated++; } } - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (-1 != aAllocTypes[colX]) { if (aSkip0Proportional) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); @@ -703,9 +693,10 @@ BasicTableLayoutStrategy::ComputeColspanWidths(PRInt32 aWidthIndex, // and calculate min/max table width PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth) { - if (gsDebugAssign) {printf("AssignPrelimColWidths en max=%d\n", aMaxWidth); mTableFrame->Dump(PR_TRUE, PR_FALSE);} + if (gsDebugAssign) {printf("AssignPrelimColWidths en max=%d\n", aMaxWidth); mTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);} PRBool rv = PR_FALSE; PRInt32 numRows = mTableFrame->GetRowCount(); + PRInt32 numCols = mTableFrame->GetColCount(); nscoord spacingX = mTableFrame->GetCellSpacingX(); PRInt32 colX, rowX; mCellSpacingTotal = 0; @@ -713,12 +704,12 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth PRInt32 propTotal = 0; // total of numbers of the type 1*, 2*, etc PRInt32 numColsForColsAttr = 0; // Nav Quirks cols attribute for equal width cols if (NS_STYLE_TABLE_COLS_NONE != mCols) { - numColsForColsAttr = (NS_STYLE_TABLE_COLS_ALL == mCols) ? mNumCols : mCols; + numColsForColsAttr = (NS_STYLE_TABLE_COLS_ALL == mCols) ? numCols : mCols; } // For every column, determine it's min and desired width based on cell style // base on cells which do not span cols. Also, determine mCellSpacingTotal - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nscoord minWidth = 0; nscoord desWidth = 0; nscoord fixWidth = WIDTH_NOT_SET; @@ -794,6 +785,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth // proportional width on a col or Nav Quirks cols attr if (fixWidth <= 0) { nscoord proportion = WIDTH_NOT_SET; +#ifdef foobar const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); if (eStyleUnit_Proportional == colPosition->mWidth.GetUnit()) { @@ -806,6 +798,19 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth proportion = WIDTH_NOT_SET; } } +#else + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + if (eStyleUnit_Proportional == colStyleWidth.GetUnit()) { + proportion = colStyleWidth.GetIntValue(); + } + else if (colX < numColsForColsAttr) { + proportion = 1; + if ((eStyleUnit_Percent == colStyleWidth.GetUnit()) && + (colStyleWidth.GetPercentValue() > 0.0f)) { + proportion = WIDTH_NOT_SET; + } + } +#endif if (proportion >= 0) { colFrame->SetWidth(MIN_PRO, proportion); if (proportion > 0) { @@ -831,7 +836,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth nscoord minPropTotal = 0; nscoord desPropTotal = 0; // figure the totals of all proportional cols which support every min and desired width - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord colProp = colFrame->GetWidth(MIN_PRO); if (colProp > 0) { @@ -846,7 +851,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth mMinToDesProportionRatio = ((float)desPropTotal) / ((float)minPropTotal); } // figure the cols proportional min width based on the new totals - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord colProp = colFrame->GetWidth(MIN_PRO); if (colProp > 0) { @@ -861,7 +866,7 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth // Adjust the cols that each cell spans if necessary. Iterate backwards // so that nested and/or overlaping col spans handle the inner ones first, // ensuring more accurated calculations. - for (colX = mNumCols - 1; colX >= 0; colX--) { + for (colX = numCols - 1; colX >= 0; colX--) { for (rowX = 0; rowX < numRows; rowX++) { PRBool originates; PRInt32 colSpan; @@ -878,11 +883,12 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth // Set the col's fixed width if present // Set the table col width for each col to the content min. - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord fixColWidth = colFrame->GetWidth(FIX); // use the style width of a col only if the col hasn't gotten a fixed width from any cell if (fixColWidth <= 0) { +#ifdef foobar const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { @@ -891,13 +897,22 @@ PRBool BasicTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aMaxWidth colFrame->SetWidth(FIX, fixColWidth); } } +#else + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + if (eStyleUnit_Coord == colStyleWidth.GetUnit()) { + fixColWidth = colStyleWidth.GetCoordValue(); + if (fixColWidth > 0) { + colFrame->SetWidth(FIX, fixColWidth); + } + } +#endif } nscoord minWidth = colFrame->GetMinWidth(); mTableFrame->SetColumnWidth(colX, minWidth); } SetMinAndMaxTableContentWidths(); - if (gsDebugAssign) {printf("AssignPrelimColWidths ex\n"); mTableFrame->Dump(PR_TRUE, PR_FALSE);} + if (gsDebugAssign) {printf("AssignPrelimColWidths ex\n"); mTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);} return rv; } @@ -906,6 +921,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, PRBool aTableIsAutoWidth) { PRInt32 numRows = mTableFrame->GetRowCount(); + PRInt32 numCols = mTableFrame->GetColCount(); nscoord spacingX = mTableFrame->GetCellSpacingX(); PRInt32 colX, rowX; nscoord basis = aBasisIn; @@ -918,7 +934,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, PRInt32 numPerCols = 0; // number of colums that 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++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord colBasis = -1; // Scan the cells in the col @@ -950,6 +966,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, } if (-1 == colBasis) { // see if the col has a style percent width specified +#ifdef foobar const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); if (eStyleUnit_Percent == colPosition->mWidth.GetUnit()) { @@ -960,6 +977,17 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, colBasis = NSToCoordRound((float)desWidth / percent); } } +#else + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + if (eStyleUnit_Percent == colStyleWidth.GetUnit()) { + float percent = colStyleWidth.GetPercentValue(); + colBasis = 0; + if (percent > 0.0f) { + nscoord desWidth = colFrame->GetDesWidth(); + colBasis = NSToCoordRound((float)desWidth / percent); + } + } +#endif } basis = PR_MAX(basis, colBasis); nscoord fixWidth = colFrame->GetFixWidth(); @@ -976,7 +1004,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, return 0; } // If there is only one col and it is % based, it won't affect anything - if ((1 == mNumCols) && (mNumCols == numPerCols)) { + if ((1 == numCols) && (numCols == numPerCols)) { return 0; } // compute a basis considering total percentages and the desired width of everything else @@ -995,12 +1023,12 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, } nscoord colPctTotal = 0; - nscoord* colPcts = new nscoord[mNumCols]; + nscoord* colPcts = new nscoord[numCols]; if (!colPcts) return 0; // Determine the percentage contribution for cols and for cells with colspan = 1 // Iterate backwards, similarly to the reasoning in AssignPreliminaryColumnWidths - for (colX = mNumCols - 1; colX >= 0; colX--) { + for (colX = numCols - 1; colX >= 0; colX--) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord maxColPctWidth = WIDTH_NOT_SET; float maxColPct = 0.0f; @@ -1039,12 +1067,20 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, } if (WIDTH_NOT_SET == maxColPctWidth) { // see if the col has a style percent width specified +#ifdef foobar const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); if (eStyleUnit_Percent == colPosition->mWidth.GetUnit()) { maxColPct = colPosition->mWidth.GetPercentValue(); maxColPctWidth = NSToCoordRound( ((float)basis) * maxColPct ); } +#else + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + if (eStyleUnit_Percent == colStyleWidth.GetUnit()) { + maxColPct = colStyleWidth.GetPercentValue(); + maxColPctWidth = NSToCoordRound( ((float)basis) * maxColPct ); + } +#endif } // conflicting pct/fixed widths are recorded. Nav 4.x may be changing the // fixed width value if it exceeds the pct value and not recording the pct @@ -1066,7 +1102,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, // For each col, consider the cells originating in it with colspans > 1. // Adjust the cols that each cell spans if necessary. - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { for (rowX = 0; rowX < numRows; rowX++) { PRBool originates; PRInt32 colSpan; @@ -1162,7 +1198,7 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, // if the percent total went over 100%, adjustments need to be made to right most cols if (colPctTotal > 100) { - for (colX = mNumCols - 1; colX >= 0; colX--) { + for (colX = numCols - 1; colX >= 0; colX--) { if (colPcts[colX] > 0) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); nscoord newPct = colPcts[colX] - (colPctTotal - 100); @@ -1197,10 +1233,11 @@ nscoord BasicTableLayoutStrategy::AssignPercentageColumnWidths(nscoord aBasisIn, PRBool BasicTableLayoutStrategy::RecomputeAdjMinIfNecessary() { PRInt32 numRows = mTableFrame->GetRowCount(); + PRInt32 numCols = mTableFrame->GetColCount(); PRInt32 colX, rowX, spanX; PRBool spansPercent = PR_FALSE; - for (colX = mNumCols - 1; colX >= 0; colX--) { + for (colX = numCols - 1; colX >= 0; colX--) { for (rowX = 0; rowX < numRows; rowX++) { PRBool originates; PRInt32 colSpan; @@ -1233,7 +1270,7 @@ PRBool BasicTableLayoutStrategy::RecomputeAdjMinIfNecessary() nscoord spacingX = mTableFrame->GetCellSpacingX(); - for (colX = mNumCols - 1; colX >= 0; colX--) { + for (colX = numCols - 1; colX >= 0; colX--) { for (rowX = 0; rowX < numRows; rowX++) { PRBool originates; PRInt32 colSpan; @@ -1267,7 +1304,8 @@ void BasicTableLayoutStrategy::SetMinAndMaxTableContentWidths() mMaxTableContentWidth = 0; nscoord spacingX = mTableFrame->GetCellSpacingX(); - for (PRInt32 colX = 0; colX < mNumCols; colX++) { + PRInt32 numCols = mTableFrame->GetColCount(); + for (PRInt32 colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); mMinTableContentWidth += colFrame->GetMinWidth(); mMaxTableContentWidth += PR_MAX(colFrame->GetDesWidth(), colFrame->GetFixWidth()); @@ -1302,7 +1340,8 @@ void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, a0ProportionalCount = 0; nscoord spacingX = mTableFrame->GetCellSpacingX(); - for (PRInt32 colX = 0; colX < mNumCols; colX++) { + PRInt32 numCols = mTableFrame->GetColCount(); + for (PRInt32 colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (mTableFrame->GetNumCellsOriginatingInCol(colX) > 0) { aCellSpacing += spacingX; @@ -1387,7 +1426,7 @@ void BasicTableLayoutStrategy::CalculateTotals(PRInt32& aCellSpacing, aMinWidths[DES_CON] += minCol; } // if it is not a degenerate table, add the last spacing on the right - if (mNumCols > 0) { + if (numCols > 0) { aCellSpacing += spacingX; } } @@ -1508,11 +1547,12 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, return; } + PRInt32 numCols = mTableFrame->GetColCount(); PRInt32 numConstrainedCols = 0; nscoord sumMaxConstraints = 0; PRBool useAdj = PR_TRUE; PRInt32 colX; - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame, useAdj)) { if (-1 != aAllocTypes[colX]) { @@ -1539,7 +1579,7 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth, PRInt32 maxMinDiff = 0; PRInt32 constrColX = 0; // set the col info entries for each constrained col - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame, useAdj)) { if (-1 != aAllocTypes[colX]) { @@ -1810,11 +1850,16 @@ PRBool BasicTableLayoutStrategy::ColIsSpecifiedAsMinimumWidth(PRInt32 aColIndex) PRBool result = PR_FALSE; nsTableColFrame* colFrame; mTableFrame->GetColumnFrame(aColIndex, colFrame); +#ifdef foobar const nsStylePosition* colPosition; colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)colPosition); switch (colPosition->mWidth.GetUnit()) { +#else + nsStyleCoord colStyleWidth = colFrame->GetStyleWidth(); + switch (colStyleWidth.GetUnit()) { +#endif case eStyleUnit_Coord: - if (0 == colPosition->mWidth.GetCoordValue()) { + if (0 == colStyleWidth.GetCoordValue()) { result = PR_TRUE; } break; @@ -1823,14 +1868,14 @@ PRBool BasicTableLayoutStrategy::ColIsSpecifiedAsMinimumWidth(PRInt32 aColIndex) // total hack for now for 0% and 1% specifications // should compare percent to available parent width and see that it is below minimum // for this column - float percent = colPosition->mWidth.GetPercentValue(); + float percent = colStyleWidth.GetPercentValue(); if (0.0f == percent || 0.01f == percent) { result = PR_TRUE; } break; } case eStyleUnit_Proportional: - if (0 == colPosition->mWidth.GetIntValue()) { + if (0 == colStyleWidth.GetIntValue()) { result = PR_TRUE; } @@ -1849,8 +1894,8 @@ void BasicTableLayoutStrategy::Dump(PRInt32 aIndent) } indent[aIndent] = 0; - printf("%s**START BASIC STRATEGY DUMP** table=%p cols=%X numCols=%d", - indent, mTableFrame, mCols, mNumCols); + printf("%s**START BASIC STRATEGY DUMP** table=%p cols=%X", + indent, mTableFrame, mCols); printf("\n%s minConWidth=%d maxConWidth=%d cellSpacing=%d propRatio=%.2f navQuirks=%d", indent, mMinTableContentWidth, mMaxTableContentWidth, mCellSpacingTotal, mMinToDesProportionRatio, mIsNavQuirksMode); printf(" **END BASIC STRATEGY DUMP** \n"); diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.h b/mozilla/layout/tables/BasicTableLayoutStrategy.h index 2c96231aa82..34186cc4d7d 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.h +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.h @@ -57,11 +57,9 @@ public: /** call every time any table thing changes that might effect the width of any column * in the table (content, structure, or style) * @param aMaxElementSize [OUT] if not null, the max element size is computed and returned in this param - * @param aNumCols the total number of columns in the table */ - virtual PRBool Initialize(nsSize* aMaxElementSize, - PRInt32 aNumCols, - nscoord aMaxSize); + virtual PRBool Initialize(nsSize* aMaxElementSize, + nscoord aMaxSize); /** compute the max element size of the table. * assumes that Initialize has been called @@ -83,7 +81,6 @@ public: nscoord GetTableMinContentWidth() const; nscoord GetTableMaxContentWidth() const; nscoord GetCOLSAttribute() const; - nscoord GetNumCols() const; void Dump(PRInt32 aIndent); protected: @@ -159,13 +156,6 @@ protected: PRInt32* aAllocTypes, PRBool aSkip0Proportional); - /** return true if the style indicates that the width is a specific width - * for the purposes of column width determination. - * return false if the width changes based on content, parent size, etc. - */ - static PRBool IsFixedWidth(const nsStylePosition* aStylePosition, - const nsStyleTable* aStyleTable); - /** return true if the colIndex is in the list of colIndexes */ virtual PRBool IsColumnInList(const PRInt32 colIndex, PRInt32 *colIndexes, @@ -214,7 +204,6 @@ protected: protected: nsTableFrame * mTableFrame; PRInt32 mCols; - PRInt32 mNumCols; // cached data nscoord mMinTableContentWidth; // the smallest size for the table (excluding border and padding) nscoord mMaxTableContentWidth; // the "natural" size for the table, if unconstrained (excluding border and padding) @@ -233,9 +222,6 @@ inline nscoord BasicTableLayoutStrategy::GetTableMaxContentWidth() const inline nscoord BasicTableLayoutStrategy::GetCOLSAttribute() const { return mCols; }; -inline nscoord BasicTableLayoutStrategy::GetNumCols() const -{ return mNumCols; }; - #endif diff --git a/mozilla/layout/tables/FixedTableLayoutStrategy.cpp b/mozilla/layout/tables/FixedTableLayoutStrategy.cpp index fb2e1eb9af3..54a017944e2 100644 --- a/mozilla/layout/tables/FixedTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/FixedTableLayoutStrategy.cpp @@ -59,7 +59,6 @@ PRBool FixedTableLayoutStrategy::BalanceColumnWidths(nsIStyleContext* aT PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputedWidth) { // NS_ASSERTION(aComputedWidth != NS_UNCONSTRAINEDSIZE, "bad computed width"); - const nsStylePosition* tablePosition; mTableFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)tablePosition); PRBool tableIsFixedWidth = eStyleUnit_Coord == tablePosition->mWidth.GetUnit() || @@ -70,24 +69,25 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed nsMargin borderPadding; tableSpacing->CalcBorderPaddingFor(mTableFrame, borderPadding); + PRInt32 numCols = mTableFrame->GetColCount(); PRInt32 colX; // availWidth is used as the basis for percentage width columns. It is aComputedWidth // minus table border, padding, & cellspacing nscoord availWidth = aComputedWidth - borderPadding.left - borderPadding.right - - ((mNumCols + 1) * mTableFrame->GetCellSpacingX()); + ((numCols + 1) * mTableFrame->GetCellSpacingX()); PRInt32 specifiedCols = 0; // the number of columns whose width is given nscoord totalColWidth = 0; // the sum of the widths of the columns - nscoord* colWidths = new PRBool[mNumCols]; - nsCRT::memset(colWidths, WIDTH_NOT_SET, mNumCols*sizeof(nscoord)); + nscoord* colWidths = new PRBool[numCols]; + nsCRT::memset(colWidths, WIDTH_NOT_SET, numCols*sizeof(nscoord)); - nscoord* propInfo = new PRBool[mNumCols]; - nsCRT::memset(propInfo, 0, mNumCols*sizeof(nscoord)); + nscoord* propInfo = new PRBool[numCols]; + nsCRT::memset(propInfo, 0, numCols*sizeof(nscoord)); nscoord propTotal = 0; // for every column, determine its specified width - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { // Get column information nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) { @@ -115,6 +115,7 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed propTotal += propInfo[colX]; } else { // get width from the cell + nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(0, colX); if (nsnull != cellFrame) { // Get the cell's style @@ -148,7 +149,7 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed if (0 < remainingWidth) { if (propTotal > 0) { - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (propInfo[colX] > 0) { // We're proportional float percent = ((float)propInfo[colX])/((float)propTotal); @@ -159,10 +160,10 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed } } else if (tableIsFixedWidth) { - if (mNumCols > specifiedCols) { + if (numCols > specifiedCols) { // allocate the extra space to the columns which have no width specified - nscoord colAlloc = NSToCoordRound( ((float)remainingWidth) / (((float)mNumCols) - ((float)specifiedCols))); - for (colX = 0; colX < mNumCols; colX++) { + nscoord colAlloc = NSToCoordRound( ((float)remainingWidth) / (((float)numCols) - ((float)specifiedCols))); + for (colX = 0; colX < numCols; colX++) { if (-1 == colWidths[colX]) { colWidths[colX] = colAlloc; totalColWidth += colAlloc; @@ -172,7 +173,7 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed } else { // allocate the extra space to the columns which have width specified float divisor = (float)totalColWidth; - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (colWidths[colX] > 0) { nscoord colAlloc = NSToCoordRound(remainingWidth * colWidths[colX] / divisor); colWidths[colX] += colAlloc; @@ -187,7 +188,7 @@ PRBool FixedTableLayoutStrategy::AssignPreliminaryColumnWidths(nscoord aComputed nscoord overAllocation = (availWidth >= 0) ? totalColWidth - availWidth : 0; // set the column widths - for (colX = 0; colX < mNumCols; colX++) { + for (colX = 0; colX < numCols; colX++) { if (colWidths[colX] < 0) colWidths[colX] = 0; // if there was too much allocated due to rounding, remove it from the last col diff --git a/mozilla/layout/tables/nsCellMap.cpp b/mozilla/layout/tables/nsCellMap.cpp index ee21a1c4390..e6d444e54e4 100644 --- a/mozilla/layout/tables/nsCellMap.cpp +++ b/mozilla/layout/tables/nsCellMap.cpp @@ -20,6 +20,7 @@ * Contributor(s): */ +#include "nsLayoutAtoms.h" #include "nsVoidArray.h" #include "nsCellMap.h" #include "nsTableFrame.h" @@ -78,7 +79,7 @@ nsCellMap::~nsCellMap() MOZ_COUNT_DTOR(nsCellMap); PRInt32 mapRowCount = mRows.Count(); - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); PRInt32 colX; for (PRInt32 rowX = 0; rowX < mapRowCount; rowX++) { nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(rowX)); @@ -89,15 +90,11 @@ nsCellMap::~nsCellMap() } } delete row; - PRInt32* numOrig = (PRInt32 *)mNumCellsOrigInRow.ElementAt(rowX); - if (numOrig) { - delete numOrig; - } } for (colX = 0; colX < colCount; colX++) { - PRInt32* val = (PRInt32 *)mNumCellsOrigInCol.ElementAt(colX); - if (val) { - delete val; + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + if (colInfo) { + delete colInfo; } } @@ -115,7 +112,7 @@ nsCellMap::~nsCellMap() void nsCellMap::AddColsAtEnd(PRUint32 aNumCols) { - Grow(mRowCount, mNumCellsOrigInCol.Count() + aNumCols); + Grow(mRowCount, mCols.Count() + aNumCols); } PRInt32 nsCellMap::GetNextAvailRowIndex() @@ -127,7 +124,7 @@ void nsCellMap::Grow(PRInt32 aNumMapRows, PRInt32 aNumCols) { PRInt32 origNumMapRows = mRows.Count(); - PRInt32 origNumCols = mNumCellsOrigInCol.Count(); + PRInt32 origNumCols = mCols.Count(); // if the number of columns has increased, we need to add extra cols to mNumColsOriginating and // each row in mRows. @@ -142,9 +139,9 @@ void nsCellMap::Grow(PRInt32 aNumMapRows, } // update the col array for (colX = origNumCols; colX < aNumCols; colX++) { - PRInt32* val = new PRInt32(0); - if (val) { - mNumCellsOrigInCol.AppendElement(val); + nsColInfo* colInfo = new nsColInfo(); + if (colInfo) { + mCols.AppendElement(colInfo); } } } @@ -158,86 +155,91 @@ void nsCellMap::Grow(PRInt32 aNumMapRows, if (row) { mRows.AppendElement(row); } - PRInt32* val = new PRInt32(0); - if (val) { - mNumCellsOrigInRow.AppendElement(val); - } } } -void nsCellMap::InsertRowIntoMap(PRInt32 aRowIndex) +void +nsCellMap::InsertRows(nsVoidArray& aRows, + PRInt32 aFirstRowIndex, + PRBool aConsiderSpans) { - // XXX This function does not yet handle spans. - // XXX Does this function need to worry about adjusting the collapsed row/col arrays? - nsVoidArray* row; - PRInt32 origNumCols = mNumCellsOrigInCol.Count(); + PRInt32 numCols = mCols.Count(); - row = (0 == origNumCols) ? new nsVoidArray() : new nsVoidArray(origNumCols); - - if (row) { - mRows.InsertElementAt(row, aRowIndex); - if(mIsCollapsedRows) - InsertIntoCollapsedRows(aRowIndex); - } - - PRInt32* val = new PRInt32(0); - if (val) { - mNumCellsOrigInRow.InsertElementAt(val, aRowIndex); + if (aFirstRowIndex > mRowCount) { + NS_ASSERTION(PR_FALSE, "nsCellMap::InsertRows bad first row index"); + return; } - mRowCount++; - mNextAvailRowIndex++; + if (!aConsiderSpans) { + ExpandWithRows(aRows, aFirstRowIndex); + return; + } + + PRInt32 numMapRows = mRows.Count(); + + // if any cells span into or out of the row being inserted, then rebuild + PRBool spansCauseRebuild = CellsSpanInOrOut(aFirstRowIndex, aFirstRowIndex, + 0, numCols - 1); + + // if any of the new cells span out of the new rows being added, then rebuild + // XXX it would be better to only rebuild the portion of the map that follows the new rows + if (!spansCauseRebuild && (aFirstRowIndex < mRows.Count())) { + spansCauseRebuild = CellsSpanOut(aRows); + } + + if (spansCauseRebuild) { + RebuildConsideringRows(aFirstRowIndex, &aRows); + } + else { + ExpandWithRows(aRows, aFirstRowIndex); + } } -void nsCellMap::RemoveRowFromMap(PRInt32 aRowIndex) +void +nsCellMap::RemoveRows(PRInt32 aFirstRowIndex, + PRInt32 aNumRowsToRemove, + PRBool aConsiderSpans) { - // XXX This function does not yet handle spans. - // XXX Does this function need to worry about adjusting the collapsed row/col arrays? - - PRInt32 colCount = mNumCellsOrigInCol.Count(); - for (PRInt32 i = 0; i < colCount; i++) { - // Adjust the column counts. - PRInt32 span; - PRBool originates; - GetCellInfoAt(aRowIndex, i, &originates, &span); - if (originates) { - // Decrement the column count. - PRInt32* cols = (PRInt32*)(mNumCellsOrigInCol.ElementAt(i)); - *cols = *cols-1; - } + PRInt32 numRows = mRows.Count(); + PRInt32 numCols = mCols.Count(); + + if (aFirstRowIndex >= numRows) { + return; } + if (!aConsiderSpans) { + ShrinkWithoutRows(aFirstRowIndex, aNumRowsToRemove); + return; + } + PRInt32 endRowIndex = aFirstRowIndex + aNumRowsToRemove - 1; + if (endRowIndex >= numRows) { + NS_ASSERTION(PR_FALSE, "nsCellMap::RemoveRows tried to remove too many rows"); + endRowIndex = numRows - 1; + } + PRBool spansCauseRebuild = CellsSpanInOrOut(aFirstRowIndex, endRowIndex, + 0, numCols - 1); - // Delete the originating row info. - PRInt32* numOrig = (PRInt32 *)mNumCellsOrigInRow.ElementAt(aRowIndex); - mNumCellsOrigInRow.RemoveElementAt(aRowIndex); - if (numOrig) - delete numOrig; + if (spansCauseRebuild) { + RebuildConsideringRows(aFirstRowIndex, nsnull, aNumRowsToRemove); + } + else { + ShrinkWithoutRows(aFirstRowIndex, aNumRowsToRemove); + } +} - // Delete our row information. - nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(aRowIndex)); - for (PRInt32 colX = 0; colX < colCount; colX++) { - CellData* data = (CellData *)(row->ElementAt(colX)); - if (data) { - delete data; - } - } - mRows.RemoveElementAt(aRowIndex); - delete row; - if(mIsCollapsedRows) - RemoveFromCollapsedRows(aRowIndex); - - // Decrement our row and next available index counts. - mRowCount--; - mNextAvailRowIndex--; +void +nsCellMap::AppendCol() +{ + Grow(mRows.Count(), mCols.Count() + 1); } PRInt32 nsCellMap::AppendCell(nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex) + PRInt32 aRowIndex, + PRBool aRebuildIfNecessary) { NS_ASSERTION(aCellFrame, "bad cell frame"); PRInt32 origNumMapRows = mRows.Count(); - PRInt32 origNumCols = mNumCellsOrigInCol.Count(); + PRInt32 origNumCols = mCols.Count(); // get the first null CellData in the desired row. It may be 1 past the end if there are none PRInt32 startColIndex; @@ -253,10 +255,20 @@ PRInt32 nsCellMap::AppendCell(nsTableCellFrame* aCellFrame, startColIndex = 0; } - mRowCount = PR_MAX(mRowCount, aRowIndex + 1); - PRInt32 rowSpan = aCellFrame->GetRowSpan(); PRInt32 colSpan = aCellFrame->GetColSpan(); + + // if the new cell could potentially span into other rows and collide with + // originating cells there, we will play it safe and just rebuild the map + if (aRebuildIfNecessary && (aRowIndex < mRowCount - 1) && (rowSpan > 1)) { + nsVoidArray newCellArray; + newCellArray.AppendElement(aCellFrame); + RebuildConsideringCells(&newCellArray, aRowIndex, startColIndex, PR_TRUE); + return startColIndex; + } + + mRowCount = PR_MAX(mRowCount, aRowIndex + 1); + // Grow. we may need to add new rows/cols PRInt32 spanNumRows = aRowIndex + rowSpan; PRInt32 spanNumCols = startColIndex + colSpan; @@ -268,13 +280,8 @@ PRInt32 nsCellMap::AppendCell(nsTableCellFrame* aCellFrame, CellData* origData = new CellData(aCellFrame, nsnull, nsnull); SetMapCellAt(*origData, aRowIndex, startColIndex); - // reset the col index of the cell frame - PRInt32 oldColIndex; - aCellFrame->GetColIndex(oldColIndex); - if (startColIndex != oldColIndex) { - // only do this if they are different since it changes content - aCellFrame->SetColIndex(startColIndex); - } + // initialize the cell frame + aCellFrame->InitCellFrame(startColIndex); // Create CellData objects for the rows that this cell spans. Set // their mOrigCell to nsnull and their mSpanData to point to data. @@ -298,46 +305,662 @@ PRInt32 nsCellMap::AppendCell(nsTableCellFrame* aCellFrame, } else { cellData->mColSpanData = origData; + nsColInfo* colInfo = (nsColInfo *) mCols.ElementAt(colX); + colInfo->mNumCellsSpan++; } } } else { cellData = new CellData(nsnull, nsnull, nsnull); - if (rowX > aRowIndex) + if (rowX > aRowIndex) { cellData->mRowSpanData = origData; - if (colX > startColIndex) + } + if (colX > startColIndex) { cellData->mColSpanData = origData; + } SetMapCellAt(*cellData, rowX, colX); } } } } + //Dump(); return startColIndex; } -void nsCellMap::RemoveCell(nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex) +PRBool nsCellMap::CellsSpanOut(nsVoidArray& aRows) +{ + PRInt32 numNewRows = aRows.Count(); + for (PRInt32 rowX = 0; rowX < numNewRows; rowX++) { + nsIFrame* rowFrame = (nsIFrame *) aRows.ElementAt(rowX); + nsIFrame* cellFrame = nsnull; + rowFrame->FirstChild(nsnull, &cellFrame); + while (cellFrame) { + nsIAtom* frameType; + cellFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableCellFrame == frameType) { + PRInt32 rowSpan = ((nsTableCellFrame *)cellFrame)->GetRowSpan(); + if (rowX + rowSpan > numNewRows) { + NS_RELEASE(frameType); + return PR_TRUE; + } + } + NS_IF_RELEASE(frameType); + cellFrame->GetNextSibling(&cellFrame); + } + } + return PR_FALSE; +} + +// return PR_TRUE if any cells have rows spans into or out of the region +// defined by the row and col indices or any cells have colspans into the region +PRBool nsCellMap::CellsSpanInOrOut(PRInt32 aStartRowIndex, + PRInt32 aEndRowIndex, + PRInt32 aStartColIndex, + PRInt32 aEndColIndex) { - // XXX write me. For now the cell map is recalculate from scratch when a cell is deleted + for (PRInt32 colX = aStartColIndex; colX <= aEndColIndex; colX++) { + CellData* cellData; + if (aStartRowIndex > 0) { + cellData = GetMapCellAt(aStartRowIndex, colX); + if (cellData && (cellData->mRowSpanData)) { + return PR_TRUE; // a cell row spans into + } + } + if (aEndRowIndex < mRowCount - 1) { + cellData = GetMapCellAt(aEndRowIndex + 1, colX); + if ((cellData) && (cellData->mRowSpanData)) { + return PR_TRUE; // a cell row spans out + } + } + } + if (aStartColIndex > 0) { + for (PRInt32 rowX = aStartRowIndex; rowX <= aEndRowIndex; rowX++) { + CellData* cellData = GetMapCellAt(rowX, aStartColIndex); + if (cellData && (cellData->mColSpanData)) { + return PR_TRUE; + } + } + } + return PR_FALSE; } -PRInt32 nsCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const +void nsCellMap::InsertCells(nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndexBefore) { - PRInt32 rowCount = mNumCellsOrigInRow.Count(); - if ((aRowIndex >= 0) && (aRowIndex < rowCount)) { - return *((PRInt32 *)mNumCellsOrigInRow.ElementAt(aRowIndex)); + if (aCellFrames.Count() == 0) return; + PRInt32 numCols = mCols.Count(); + if (aColIndexBefore >= numCols) { + NS_ASSERTION(PR_FALSE, "bad arg in nsCellMap::InsertCellAt"); + return; + } + + // get the starting col index of the 1st new cells + PRInt32 startColIndex; + for (startColIndex = aColIndexBefore + 1; startColIndex < numCols; startColIndex++) { + CellData* data = GetMapCellAt(aRowIndex, startColIndex); + if (data && data->mOrigCell) { + break; // we found the col index + } + } + + // record whether inserted cells are going to cause complications due + // to existing row spans, col spans or table sizing. + PRBool spansCauseRebuild = PR_FALSE; + + // check that all cells have the same row span + PRInt32 numNewCells = aCellFrames.Count(); + PRInt32 rowSpan = 0; + for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) { + nsTableCellFrame* cell = (nsTableCellFrame*) aCellFrames.ElementAt(cellX); + PRInt32 rowSpan2 = cell->GetRowSpan(); + if (rowSpan == 0) { + rowSpan = rowSpan2; + } + else if (rowSpan != rowSpan2) { + spansCauseRebuild = PR_TRUE; + break; + } + } + + // check if the new cells will cause the table to add more rows + if (!spansCauseRebuild) { + if (mRows.Count() < aRowIndex + rowSpan) { + spansCauseRebuild = PR_TRUE; + } + } + + if (!spansCauseRebuild) { + spansCauseRebuild = CellsSpanInOrOut(aRowIndex, aRowIndex + rowSpan - 1, startColIndex, numCols - 1); + } + + if (spansCauseRebuild) { + RebuildConsideringCells(&aCellFrames, aRowIndex, startColIndex, PR_TRUE); } else { - NS_ASSERTION(PR_FALSE, "nsCellMap::GetNumCellsOriginatingInRow - bad row index"); - return 0; + ExpandWithCells(aCellFrames, aRowIndex, startColIndex, rowSpan); + } + +} + +PRBool +nsCellMap::CreateEmptyRow(PRInt32 aRowIndex, + PRInt32 aNumCols) +{ + nsVoidArray* row; + row = (0 == aNumCols) ? new nsVoidArray() : new nsVoidArray(aNumCols); + if (!row) { + return PR_FALSE; + } + mRows.InsertElementAt(row, aRowIndex); + + if(mIsCollapsedRows) { + InsertIntoCollapsedRows(aRowIndex); + } + return PR_TRUE; +} + + +void +nsCellMap::ExpandWithRows(nsVoidArray& aRowFrames, + PRInt32 aStartRowIndex) +{ + PRInt32 numNewRows = aRowFrames.Count();; + PRInt32 origNumCols = mCols.Count(); + PRInt32 endRowIndex = aStartRowIndex + numNewRows - 1; + PRInt32 numMapRows = mRows.Count(); + + // create the new rows first + PRInt32 newRowIndex = 0; + PRInt32 rowX; + for (rowX = aStartRowIndex; rowX <= endRowIndex; rowX++) { + if (!CreateEmptyRow(rowX, origNumCols)) { + return; + } + newRowIndex++; + } + mRowCount += numNewRows; + + newRowIndex = 0; + for (rowX = aStartRowIndex; rowX <= endRowIndex; rowX++) { + nsTableRowFrame* rFrame = (nsTableRowFrame *)aRowFrames.ElementAt(newRowIndex); + // append cells + nsIFrame* cFrame = nsnull; + rFrame->FirstChild(nsnull, &cFrame); + while (cFrame) { + nsIAtom* cFrameType; + cFrame->GetFrameType(&cFrameType); + if (nsLayoutAtoms::tableCellFrame == cFrameType) { + AppendCell((nsTableCellFrame *)cFrame, rowX, PR_FALSE); + } + NS_IF_RELEASE(cFrameType); + cFrame->GetNextSibling(&cFrame); + } + newRowIndex++; + } + mNextAvailRowIndex += numNewRows; +} + +void nsCellMap::ExpandWithCells(nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndex, + PRInt32 aRowSpan) +{ + PRInt32 endRowIndex = aRowIndex + aRowSpan - 1; + PRInt32 startColIndex = aColIndex; + PRInt32 endColIndex; + PRInt32 numCells = aCellFrames.Count(); + PRInt32 totalColSpan = 0; + + // add cellData entries for the space taken up by the new cells + for (PRInt32 cellX = 0; cellX < numCells; cellX++) { + nsTableCellFrame* cellFrame = (nsTableCellFrame*) aCellFrames.ElementAt(cellX); + CellData* origData = new CellData(cellFrame, nsnull, nsnull); // the originating cell + if (!origData) return; + + // set the starting and ending col index for the new cell + PRInt32 colSpan = cellFrame->GetColSpan(); + totalColSpan += colSpan; + if (cellX == 0) { + endColIndex = aColIndex + colSpan - 1; + } + else { + startColIndex = endColIndex + 1; + endColIndex = startColIndex + colSpan - 1; + } + + // add the originating cell data and any cell data corresponding to row/col spans + for (PRInt32 rowX = aRowIndex; rowX <= endRowIndex; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + for (PRInt32 colX = aColIndex; colX <= endColIndex; colX++) { + row->InsertElementAt(nsnull, colX); + CellData* data = origData; + if ((rowX != aRowIndex) || (colX != startColIndex)) { + data = new CellData(nsnull, nsnull, nsnull); + if (!data) return; + if (rowX > aRowIndex) { + data->mRowSpanData = origData; + } + if (colX > startColIndex) { + data->mColSpanData = origData; + } + } + SetMapCellAt(*data, rowX, colX); // this increments the mNumColsOrigInCol array + } + } + cellFrame->InitCellFrame(startColIndex); + } + + // if new columns were added to the rows occupied by the new cells, + // update the other rows to have the same number of cols + PRInt32 numNewCols = ((nsVoidArray*)mRows.ElementAt(aRowIndex))->Count() - mCols.Count(); + if (numNewCols > 0) { + Grow(mRows.Count(), mCols.Count() + numNewCols); + } + + // update the row and col info due to shifting + for (PRInt32 rowX = aRowIndex; rowX <= endRowIndex; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + PRInt32 numCols = row->Count(); + for (PRInt32 colX = aColIndex + totalColSpan; colX < numCols; colX++) { + CellData* data = (CellData*) row->ElementAt(colX); + if (data) { + if (data->mOrigCell) { + // a cell that gets moved needs adjustment as well as it new orignating col + data->mOrigCell->SetColIndex(colX); + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsOrig++; + } + else if (data->mColSpanData) { + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsSpan++; + } + } + data = (CellData*) row->ElementAt(colX - totalColSpan); + if (data) { + if (data->mOrigCell) { + // the old originating col of a moved cell needs adjustment + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX - totalColSpan); + colInfo->mNumCellsOrig--; + } + else if (data->mColSpanData) { + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsSpan--; + } + } + } + } +} + +void nsCellMap::ShrinkWithoutRows(PRInt32 aStartRowIndex, + PRInt32 aNumRowsToRemove) +{ + PRInt32 endRowIndex = aStartRowIndex + aNumRowsToRemove - 1; + PRInt32 colCount = mCols.Count(); + for (PRInt32 rowX = endRowIndex; rowX >= aStartRowIndex; rowX--) { + nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(rowX)); + PRInt32 colX; + for (colX = 0; colX < colCount; colX++) { + CellData* data = (CellData *) row->ElementAt(colX); + if (data) { + // Adjust the column counts. + if (data->mOrigCell) { + // Decrement the column count. + nsColInfo* colInfo = (nsColInfo *)(mCols.ElementAt(colX)); + colInfo->mNumCellsOrig--; + } + else if (data->mColSpanData) { + nsColInfo* colInfo = (nsColInfo *)(mCols.ElementAt(colX)); + colInfo->mNumCellsSpan--; + } + } + } + + // Delete our row information. + for (colX = 0; colX < colCount; colX++) { + CellData* data = (CellData *)(row->ElementAt(colX)); + if (data) { + delete data; + } + } + + mRows.RemoveElementAt(rowX); + delete row; + if(mIsCollapsedRows) { + RemoveFromCollapsedRows(rowX); + } + + // Decrement our row and next available index counts. + mRowCount--; + mNextAvailRowIndex--; + + // remove cols that may not be needed any more due to the removal of the rows + RemoveUnusedCols(colCount); + } +} + +void nsCellMap::ShrinkWithoutCell(nsTableCellFrame& aCellFrame, + PRInt32 aRowIndex, + PRInt32 aColIndex) +{ + PRInt32 rowSpan = aCellFrame.GetRowSpan(); + PRInt32 colSpan = aCellFrame.GetColSpan(); + PRInt32 endRowIndex = aRowIndex + rowSpan - 1; + PRInt32 endColIndex = aColIndex + colSpan - 1; + + PRInt32 colX; + // adjust the col counts due to the deleted cell before removing it + for (colX = aColIndex; colX <= endColIndex; colX++) { + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + if (colX == aColIndex) { + colInfo->mNumCellsOrig--; + } + else { + colInfo->mNumCellsSpan--; + } + } + + // remove the deleted cell and cellData entries for it + PRInt32 rowX; + for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + PRInt32 colX; + for (colX = aColIndex; colX <= endColIndex; colX++) { + row->RemoveElementAt(colX); + } + // put back null entries in the row to make it the right size + for (colX = 0; colX < colSpan; colX++) { + row->AppendElement(nsnull); + } + } + + PRInt32 numCols = mCols.Count(); + PRInt32 numRows = mRows.Count(); + + // update the row and col info due to shifting + for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + for (PRInt32 colX = aColIndex; colX < numCols - colSpan; colX++) { + CellData* data = (CellData*) row->ElementAt(colX); + if (data) { + if (data->mOrigCell) { + // a cell that gets moved to the left needs adjustment in its new location + data->mOrigCell->SetColIndex(colX); + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsOrig++; + // a cell that gets moved to the left needs adjustment in its old location + colInfo = (nsColInfo *)mCols.ElementAt(colX + colSpan); + if (colInfo) { + colInfo->mNumCellsOrig--; + } + } + else if (data->mColSpanData) { + // a cell that gets moved to the left needs adjustment in its new location + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsSpan++; + // a cell that gets moved to the left needs adjustment in its old location + colInfo = (nsColInfo *)mCols.ElementAt(colX + colSpan); + if (colInfo) { + colInfo->mNumCellsSpan--; + } + } + } + } + } + + // remove cols that may not be needed any more due to the removal of the cell + RemoveUnusedCols(mCols.Count()); +} + +PRInt32 +nsCellMap::RemoveUnusedCols(PRInt32 aMaxToRemove) +{ + PRInt32 numColsRemoved = 0; + for (PRInt32 colX = mCols.Count() - 1; colX >= 0; colX--) { + nsColInfo* colInfo = (nsColInfo *) mCols.ElementAt(colX); + if (!colInfo || (colInfo->mNumCellsOrig > 0) || (colInfo->mNumCellsSpan > 0)) { + return numColsRemoved; + } + else { + // remove the col from the cols array + nsColInfo* colInfo = (nsColInfo *) mCols.ElementAt(colX); + delete colInfo; + mCols.RemoveElementAt(colX); + + PRInt32 numMapRows = mRows.Count(); + // remove the col from each of the rows + for (PRInt32 rowX = 0; rowX < numMapRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + CellData* data = (CellData*) row->ElementAt(colX); + delete data; + row->RemoveElementAt(colX); + } + numColsRemoved++; + if (numColsRemoved >= aMaxToRemove) { + return numColsRemoved; + } + } + } + return numColsRemoved; +} + + +void +nsCellMap::RebuildConsideringRows(PRInt32 aStartRowIndex, + nsVoidArray* aRowsToInsert, + PRBool aNumRowsToRemove) +{ + PRInt32 numNewRows = 0; + // copy the old cell map into a new array + PRInt32 numOrigRows = mRows.Count(); + PRInt32 numOrigCols = mCols.Count(); + void** origRows = new void*[numOrigRows]; + if (!origRows) return; + PRInt32 rowX; + // copy the orig rows + for (rowX = 0; rowX < numOrigRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + origRows[rowX] = row; + } + for (PRInt32 colX = 0; colX < numOrigCols; colX++) { + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX); + colInfo->mNumCellsOrig = 0; + } + mRows.Clear(); + mRowCount = 0; + mNextAvailRowIndex = 0; + if (aRowsToInsert) { + Grow(numOrigRows, numOrigCols); + } + + // put back the rows before the affected ones just as before + for (rowX = 0; rowX < aStartRowIndex; rowX++) { + nsVoidArray* row = (nsVoidArray *)origRows[rowX]; + PRInt32 numCols = row->Count(); + for (PRInt32 colX = 0; colX < numCols; colX++) { + // put in the original cell from the cell map + CellData* data = (CellData*) row->ElementAt(colX); + if (data && data->mOrigCell) { + AppendCell(data->mOrigCell, rowX, PR_FALSE); + } + } + mNextAvailRowIndex++; + } + PRInt32 copyStartRowIndex; + if (aRowsToInsert) { + // add in the new cells and create rows if necessary + PRInt32 numNewRows = aRowsToInsert->Count(); + rowX = aStartRowIndex; + for (PRInt32 newRowX = 0; newRowX < numNewRows; newRowX++) { + nsTableRowFrame* rFrame = (nsTableRowFrame *)aRowsToInsert->ElementAt(newRowX); + nsIFrame* cFrame = nsnull; + rFrame->FirstChild(nsnull, &cFrame); + while (cFrame) { + nsIAtom* cFrameType; + cFrame->GetFrameType(&cFrameType); + if (nsLayoutAtoms::tableCellFrame == cFrameType) { + AppendCell((nsTableCellFrame *)cFrame, rowX, PR_FALSE); + } + NS_IF_RELEASE(cFrameType); + cFrame->GetNextSibling(&cFrame); + } + rowX++; + } + copyStartRowIndex = aStartRowIndex; + } + else { + rowX = aStartRowIndex; + copyStartRowIndex = aStartRowIndex + aNumRowsToRemove; + } + // put back the rows after the affected ones just as before + PRInt32 copyEndRowIndex = numOrigRows - 1; + for (PRInt32 copyRowX = copyStartRowIndex; copyRowX <= copyEndRowIndex; copyRowX++) { + nsVoidArray* row = (nsVoidArray *)origRows[copyRowX]; + PRInt32 numCols = row->Count(); + for (PRInt32 colX = 0; colX < numCols; colX++) { + // put in the original cell from the cell map + CellData* data = (CellData*) row->ElementAt(colX); + if (data && data->mOrigCell) { + AppendCell(data->mOrigCell, rowX, PR_FALSE); + } + } + rowX++; + } + + mNextAvailRowIndex = mRowCount; + + // delete the old cell map + for (rowX = 0; rowX < numOrigRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)origRows[rowX]; + PRInt32 len = row->Count(); + for (PRInt32 colX = 0; colX < len; colX++) { + CellData* data = (CellData*) row->ElementAt(colX); + delete data; + } + delete row; + } + delete [] origRows; +} + +void nsCellMap::RebuildConsideringCells(nsVoidArray* aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndex, + PRBool aInsert) +{ + // copy the old cell map into a new array + PRInt32 numOrigRows = mRows.Count(); + PRInt32 numOrigCols = mCols.Count(); + void** origRows = new void*[numOrigRows]; + if (!origRows) return; + PRInt32 rowX; + for (rowX = 0; rowX < numOrigRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX); + origRows[rowX] = row; + } + // reinitialize data members + mRows.Clear(); + mRowCount = 0; + mNextAvailRowIndex = numOrigRows; + Grow(numOrigRows, numOrigCols); + + PRInt32 numNewCells = (aCellFrames) ? aCellFrames->Count() : 0; + // build the new cell map + for (rowX = 0; rowX < numOrigRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)origRows[rowX]; + PRInt32 numCols = row->Count(); + for (PRInt32 colX = 0; colX < numCols; colX++) { + if ((rowX == aRowIndex) && (colX == aColIndex)) { + if (aInsert) { // put in the new cells + for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) { + nsTableCellFrame* cell = (nsTableCellFrame*)aCellFrames->ElementAt(cellX); + AppendCell(cell, rowX, PR_FALSE); + } + } + else { + continue; // do not put the deleted cell back + } + } + // put in the original cell from the cell map + CellData* data = (CellData*) row->ElementAt(colX); + if (data && data->mOrigCell) { + AppendCell(data->mOrigCell, rowX, PR_FALSE); + } + } + } + + // delete the old cell map + for (rowX = 0; rowX < numOrigRows; rowX++) { + nsVoidArray* row = (nsVoidArray *)origRows[rowX]; + PRInt32 len = row->Count(); + for (PRInt32 colX = 0; colX < len; colX++) { + CellData* data = (CellData*) row->ElementAt(colX); + delete data; + } + delete row; + } + delete [] origRows; +} + +void nsCellMap::RemoveCell(nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) +{ + PRInt32 numRows = mRows.Count(); + if ((aRowIndex < 0) || (aRowIndex >= numRows)) { + NS_ASSERTION(PR_FALSE, "bad arg in nsCellMap::RemoveCell"); + return; + } + PRInt32 numCols = mCols.Count(); + + // get the starting col index of the cell to remove + PRInt32 startColIndex; + for (startColIndex = 0; startColIndex < numCols; startColIndex++) { + CellData* data = GetMapCellAt(aRowIndex, startColIndex); + if (data && (aCellFrame == data->mOrigCell)) { + break; // we found the col index + } + } + + PRInt32 rowSpan = aCellFrame->GetRowSpan(); + PRInt32 endRowIndex = aRowIndex + rowSpan - 1; + PRInt32 endColIndex = startColIndex + aCellFrame->GetColSpan() - 1; + // record whether removing the cells is going to cause complications due + // to existing row spans, col spans or table sizing. + PRBool spansCauseRebuild = PR_FALSE; + + // check if removing the cell will cause the table to reduce the number of rows + if (endRowIndex == numRows) { + spansCauseRebuild = PR_TRUE; + for (PRInt32 rowX = aRowIndex; rowX <= endRowIndex; rowX++) { + for (PRInt32 colX = 0; colX < numCols; colX++) { + if ((colX < startColIndex) || (colX > endColIndex)) { + CellData* data = GetMapCellAt(rowX, colX); + if (data) { + // there is either an originating or spanned cell in a row of the cell + spansCauseRebuild = PR_FALSE; + break; + } + } + } + } + } + + if (!spansCauseRebuild) { + spansCauseRebuild = CellsSpanInOrOut(aRowIndex, aRowIndex + rowSpan - 1, startColIndex, numCols - 1); + } + + if (spansCauseRebuild) { + RebuildConsideringCells(nsnull, aRowIndex, startColIndex, PR_FALSE); + } + else { + ShrinkWithoutCell(*aCellFrame, aRowIndex, startColIndex); } } PRInt32 nsCellMap::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const { - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); if ((aColIndex >= 0) && (aColIndex < colCount)) { - return *((PRInt32 *)mNumCellsOrigInCol.ElementAt(aColIndex)); + return ((nsColInfo *)mCols.ElementAt(aColIndex))->mNumCellsOrig; } else { NS_ASSERTION(PR_FALSE, "nsCellMap::GetNumCellsOriginatingInCol - bad col index"); @@ -348,9 +971,9 @@ PRInt32 nsCellMap::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const #ifdef NS_DEBUG void nsCellMap::Dump() const { - printf("***** start CellMap Dump *****\n"); + printf("***** START CELL MAP DUMP *****\n"); PRInt32 mapRowCount = mRows.Count(); - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); PRInt32 colIndex; printf("mapRowCount=%d tableRowCount=%d, colCount=%d \n", mapRowCount, mRowCount, colCount); PRInt32 rowIndex; @@ -365,26 +988,32 @@ void nsCellMap::Dump() const printf("C%d,%d ", rowIndex, colIndex); } else { nsTableCellFrame* cell = nsnull; - int rr, cc; if (cd->mRowSpanData) { cell = cd->mRowSpanData->mOrigCell; - nsTableRowFrame* rowFrame; - cell->GetParent((nsIFrame**)&rowFrame); - rr = rowFrame->GetRowIndex(); - cell->GetColIndex(cc); - printf("r%d,%d ", rr, cc); + // check the validity of the cell map + nsVoidArray* rowAbove = (nsVoidArray *)mRows.ElementAt(rowIndex - 1); + CellData* cdAbove = (CellData *)rowAbove->ElementAt(colIndex); + if ((cdAbove->mOrigCell != cell) && (cdAbove->mRowSpanData->mOrigCell != cell)) { + NS_ASSERTION(PR_FALSE, "bad row span data"); + } + printf("R "); } - if (cd->mColSpanData){ + if (cd->mColSpanData) { cell = cd->mColSpanData->mOrigCell; - nsTableRowFrame* row2; - cell->GetParent((nsIFrame**)&row2); - rr = row2->GetRowIndex(); - cell->GetColIndex(cc); - printf("c%d,%d ", rr, cc); + // check the validity of the cell map + CellData* cdBefore = (CellData *)row->ElementAt(colIndex - 1); + if ((cdBefore->mOrigCell != cell) && (cdBefore->mColSpanData->mOrigCell != cell)) { + NS_ASSERTION(PR_FALSE, "bad col span data"); + } + printf("C "); + } + if (!(cd->mRowSpanData && cd->mColSpanData)) { + printf(" "); } + printf(" "); } } else { - printf("---- "); + printf("---- "); } } printf("\n"); @@ -409,28 +1038,12 @@ void nsCellMap::Dump() const printf("\n"); } - // output cells originating in rows - printf ("\ncells originating in rows array -> "); - for (rowIndex = 0; rowIndex < mapRowCount; rowIndex++) { - PRInt32* numCells = (PRInt32 *)mNumCellsOrigInRow.ElementAt(rowIndex); - printf ("%d=%d ", rowIndex, *numCells); - } - printf("\n"); - // output col frame info - printf("\n col frames ->"); - for (colIndex = 0; colIndex < mColFrames.Count(); colIndex++) { - nsTableColFrame* colFrame = (nsTableColFrame *)mColFrames.ElementAt(colIndex); - if (0 == (colIndex % 8)) - printf("\n"); - printf ("%d=%p ", colIndex, colFrame); - } - // output cells originating in cols - printf ("\ncells originating in cols array -> "); + // output col info + printf ("\ncols array orig/span-> "); for (colIndex = 0; colIndex < colCount; colIndex++) { - PRInt32* numCells = (PRInt32 *)mNumCellsOrigInCol.ElementAt(colIndex); - printf ("%d=%d ", colIndex, *numCells); + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colIndex); + printf ("%d=%d/%d ", colIndex, colInfo->mNumCellsOrig, colInfo->mNumCellsSpan); } - printf("\n"); printf("\n***** end CellMap Dump *****\n"); } #endif @@ -443,11 +1056,12 @@ void nsCellMap::SetMapCellAt(CellData& aNewCell, nsVoidArray* row = (nsVoidArray *)(mRows.ElementAt(aMapRowIndex)); row->ReplaceElementAt(&aNewCell, aColIndex); // update the originating cell counts if cell originates in this row, col + nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(aColIndex); if (aNewCell.mOrigCell) { - PRInt32* numCells = (PRInt32 *)mNumCellsOrigInCol.ElementAt(aColIndex); - (*numCells)++; - numCells = (PRInt32 *)mNumCellsOrigInRow.ElementAt(aMapRowIndex); - (*numCells)++; + colInfo->mNumCellsOrig++; + } + else if (aNewCell.mColSpanData) { + colInfo->mNumCellsSpan++; } } @@ -460,7 +1074,7 @@ PRInt32 nsCellMap::GetEffectiveColSpan(PRInt32 aColIndex, aCell->GetRowIndex(initialRowX); PRInt32 effColSpan = 0; - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); for (PRInt32 colX = aColIndex; colX < colCount; colX++) { PRBool found = PR_FALSE; CellData* cellData = GetCellAt(initialRowX, colX); @@ -482,6 +1096,10 @@ PRInt32 nsCellMap::GetEffectiveColSpan(PRInt32 aColIndex, break; } } + if (effColSpan == 0) { + printf("cell = %p \n", aCell); + Dump(); + } NS_ASSERTION(effColSpan > 0, "invalid col span or col index"); return effColSpan; } @@ -530,13 +1148,6 @@ nsTableCellFrame* nsCellMap::GetCellInfoAt(PRInt32 aRowX, return cellFrame; } - - -nsTableColFrame* nsCellMap::GetColumnFrame(PRInt32 aColIndex) const -{ - return (nsTableColFrame *)(mColFrames.ElementAt(aColIndex)); -} - PRInt32 nsCellMap::GetNumCollapsedRows() const { return mNumCollapsedRows; @@ -575,27 +1186,27 @@ void nsCellMap::SetRowCollapsedAt(PRInt32 aRow, PRBool aValue) void nsCellMap::InsertIntoCollapsedRows(PRInt32 aRow) { - if(mIsCollapsedRows) { - if((mRowCount + 1) > mIsCollapsedRowsSize){ + if (mIsCollapsedRows) { + if ((mRowCount + 1) > mIsCollapsedRowsSize){ PRInt32 newSize = mRowCount + kIsCollapsedRowsGrowSize; PRPackedBool * newIsCollapsedRows = new PRPackedBool[newSize]; - if(!newIsCollapsedRows) - return; + if(!newIsCollapsedRows) + return; if(aRow != 0) nsCRT::memcpy(newIsCollapsedRows, mIsCollapsedRows, aRow * sizeof (PRPackedBool)); if(aRow != mRowCount) nsCRT::memcpy(newIsCollapsedRows + aRow + 1, mIsCollapsedRows + aRow, - (mRowCount - aRow) * sizeof(PRPackedBool)); + (mRowCount - aRow) * sizeof(PRPackedBool)); delete[] mIsCollapsedRows; mIsCollapsedRows = newIsCollapsedRows; mIsCollapsedRowsSize = newSize; - } + } else { if(aRow != mRowCount) nsCRT::memmove(mIsCollapsedRows + aRow + 1, mIsCollapsedRows + aRow, - (mRowCount - aRow) * sizeof(PRPackedBool)); - } + (mRowCount - aRow) * sizeof(PRPackedBool)); + } mIsCollapsedRows[aRow] = PR_FALSE; } } @@ -620,7 +1231,7 @@ PRInt32 nsCellMap::GetNumCollapsedCols() const PRBool nsCellMap::IsColCollapsedAt(PRInt32 aCol) const { - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); if ((aCol >= 0) && (aCol < colCount)) { if (mIsCollapsedCols) { return mIsCollapsedCols[aCol]; @@ -631,7 +1242,7 @@ PRBool nsCellMap::IsColCollapsedAt(PRInt32 aCol) const void nsCellMap::SetColCollapsedAt(PRInt32 aCol, PRBool aValue) { - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); if ((aCol >= 0) && (aCol < colCount)) { if (nsnull == mIsCollapsedCols) { mIsCollapsedCols = new PRPackedBool[colCount]; @@ -655,7 +1266,7 @@ PRBool nsCellMap::RowIsSpannedInto(PRInt32 aRowIndex) const if ((0 > aRowIndex) || (aRowIndex >= mRowCount)) { return PR_FALSE; } - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++) { CellData* cd = GetCellAt(aRowIndex, colIndex); if (cd) { // there's really a cell at (aRowIndex, colIndex) @@ -673,7 +1284,7 @@ PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex) const if ((0 > aRowIndex) || (aRowIndex >= mRowCount)) { return PR_FALSE; } - PRInt32 colCount = mNumCellsOrigInCol.Count(); + PRInt32 colCount = mCols.Count(); if (aRowIndex != mRowCount - 1) { // aRowIndex is not the last row, so we check the next row after aRowIndex for spanners for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++) { @@ -692,7 +1303,7 @@ PRBool nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex) const PRBool nsCellMap::ColIsSpannedInto(PRInt32 aColIndex) const { - if ((0 > aColIndex) || (aColIndex >= mNumCellsOrigInCol.Count())) { + if ((0 > aColIndex) || (aColIndex >= mCols.Count())) { return PR_FALSE; } for (PRInt32 rowIndex = 0; rowIndex < mRowCount; rowIndex++) { @@ -709,8 +1320,8 @@ PRBool nsCellMap::ColIsSpannedInto(PRInt32 aColIndex) const PRBool nsCellMap::ColHasSpanningCells(PRInt32 aColIndex) const { - NS_PRECONDITION (aColIndex < mNumCellsOrigInCol.Count(), "bad col index arg"); - PRInt32 colCount = mNumCellsOrigInCol.Count(); + NS_PRECONDITION (aColIndex < mCols.Count(), "bad col index arg"); + PRInt32 colCount = mCols.Count(); if ((0 > aColIndex) || (aColIndex >= colCount - 1)) return PR_FALSE; @@ -740,12 +1351,8 @@ void nsCellMap::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const mRows.SizeOf(aHandler, &voidArraySize); sum += voidArraySize - sizeof(mRows); - mColFrames.SizeOf(aHandler, &voidArraySize); - sum += voidArraySize - sizeof(mColFrames); - mNumCellsOrigInRow.SizeOf(aHandler, &voidArraySize); - sum += voidArraySize - sizeof(mNumCellsOrigInRow); - mNumCellsOrigInCol.SizeOf(aHandler, &voidArraySize); - sum += voidArraySize - sizeof(mNumCellsOrigInCol); + mCols.SizeOf(aHandler, &voidArraySize); + sum += voidArraySize - sizeof(mCols); // Add in the size of the collapsed rows and collapsed column // packed bool arrays @@ -753,7 +1360,7 @@ void nsCellMap::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const sum += mRowCount * sizeof(PRPackedBool); } if (mIsCollapsedCols) { - sum += mNumCellsOrigInCol.Count() * sizeof(PRPackedBool); + sum += mCols.Count() * sizeof(PRPackedBool); } *aResult = sum; diff --git a/mozilla/layout/tables/nsCellMap.h b/mozilla/layout/tables/nsCellMap.h index 3e058cfff44..4d84149c90a 100644 --- a/mozilla/layout/tables/nsCellMap.h +++ b/mozilla/layout/tables/nsCellMap.h @@ -27,6 +27,22 @@ #include "nsVoidArray.h" class nsTableColFrame; class nsTableCellFrame; +class nsIPresContext; + +// XXX the collapsing row and col data structures need to be moved +// into nsTableFrame. Collapsing cols are broken due to the recent +// incremental cell map methods which don't attempt to update +// collapsing col info here. + +struct nsColInfo +{ + PRInt32 mNumCellsOrig; // number of cells originating in the col + PRInt32 mNumCellsSpan; // number of cells spanning into the col via colspans (not rowspans) + + nsColInfo(); + nsColInfo(PRInt32 aNumCellsOrig, + PRInt32 aNumCellsSpan); +}; /** nsCellMap is a support class for nsTablePart. * It maintains an Rows x Columns grid onto which the cells of the table are mapped. @@ -60,23 +76,29 @@ public: CellData* GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const; - /** insert a new row into the map - makes a blank row and adjusts spans - */ - void InsertRowIntoMap(PRInt32 aRowIndex); - - /** removes a row from the map and adjusts spans - */ - void RemoveRowFromMap(PRInt32 aRowIndex); + void AppendCol(); /** append the cellFrame at the end of the row at aRowIndex and return the col index */ PRInt32 AppendCell(nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex); + PRInt32 aRowIndex, + PRBool aRebuildIfNecessary); + + void InsertCells(nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndexBefore); void RemoveCell(nsTableCellFrame* aCellFrame, PRInt32 aRowIndex); + void InsertRows(nsVoidArray& aRows, + PRInt32 aFirstRowIndex, + PRBool aConsiderSpans); + + void RemoveRows(PRInt32 aFirstRowIndex, + PRInt32 aNumRowsToRemove, + PRBool aConsiderSpans); + PRInt32 GetNextAvailRowIndex(); PRInt32 GetEffectiveColSpan(nsTableCellFrame* aCell) const; @@ -102,17 +124,6 @@ public: /** return the actual number of rows in the table represented by this CellMap */ PRInt32 GetRowCount() const; - /** return the column frame associated with aColIndex */ - nsTableColFrame* GetColumnFrame(PRInt32 aColIndex) const; - - /** add a column frame to the list of column frames - * column frames must be added in order - */ - void AppendColumnFrame(nsTableColFrame *aColFrame); - - /** empty the column frame cache */ - void ClearColumnCache(); - // temporary until nsTableFrame::GetCellData uses GetCellFrameAt nsTableCellFrame* GetCellFrameOriginatingAt(PRInt32 aRowX, PRInt32 aColX) const; @@ -123,6 +134,7 @@ public: PRInt32* aColSpan = nsnull) const; void AddColsAtEnd(PRUint32 aNumCols); + PRInt32 RemoveUnusedCols(PRInt32 aMaxNumToRemove); PRBool RowIsSpannedInto(PRInt32 aRowIndex) const; PRBool RowHasSpanningCells(PRInt32 aRowIndex) const; @@ -156,23 +168,48 @@ protected: CellData* GetMapCellAt(PRInt32 aMapRowIndex, PRInt32 aColIndex) const; - PRInt32 GetNumCellsIn(PRInt32 aColIndex, - PRBool aOriginating) const; + PRInt32 GetNumCellsIn(PRInt32 aColIndex) const; + void ExpandWithRows(nsVoidArray& aRowFrames, + PRInt32 aStartRowIndex); + + void ExpandWithCells(nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndex, + PRInt32 aRowSpan); + + void ShrinkWithoutRows(PRInt32 aFirstRowIndex, + PRInt32 aNumRowsToRemove); + + void ShrinkWithoutCell(nsTableCellFrame& aCellFrame, + PRInt32 aRowIndex, + PRInt32 aColIndex); + + void RebuildConsideringRows(PRInt32 aStartRowIndex, + nsVoidArray* aRowsToInsert, + PRInt32 aNumRowsToRemove = 0); + + void RebuildConsideringCells(nsVoidArray* aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndex, + PRBool aInsert); + + PRBool CellsSpanOut(nsVoidArray& aNewRows); + + PRBool CellsSpanInOrOut(PRInt32 aStartRowIndex, + PRInt32 aEndRowIndex, + PRInt32 aStartColIndex, + PRInt32 aEndColIndex); + + PRBool CreateEmptyRow(PRInt32 aRowIndex, + PRInt32 aNumCols); /** an array containing col array. It can be larger than mRowCount due to * row spans extending beyond the table */ nsVoidArray mRows; - /** an array of col frames. It is as large as mRowCount */ - nsVoidArray mColFrames; - - /** an array of PRInt32 indexed by row and giving the number of cells originating - * in each row. */ - nsVoidArray mNumCellsOrigInRow; - - /** an array of PRInt32 indexed by col and giving the number of cells originating - * in each col. */ - nsVoidArray mNumCellsOrigInCol; + /** an array of nsColInfo indexed by col and giving the number of + * cells originating and spanning each col. */ + nsVoidArray mCols; // an array of booleans where the ith element indicates if the ith row is collapsed PRPackedBool* mIsCollapsedRows; @@ -196,7 +233,7 @@ inline CellData* nsCellMap::GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex) const { if ((0 > aRowIndex) || (aRowIndex >= mRowCount) || - (0 > aColIndex) || (aColIndex >= mNumCellsOrigInCol.Count())) { + (0 > aColIndex) || (aColIndex >= mCols.Count())) { //bug 9024 tickled this //printf("%s \n", "nsCellMap::GetCellAt called with invalid row or col index"); // XXX look at this when bug 10911 get fixed return nsnull; @@ -213,7 +250,7 @@ inline CellData* nsCellMap::GetMapCellAt(PRInt32 aMapRowIndex, PRInt32 aColIndex) const { if ((0 > aMapRowIndex) || (aMapRowIndex >= mRows.Count()) || - (0 > aColIndex) || (aColIndex >= mNumCellsOrigInCol.Count())) { + (0 > aColIndex) || (aColIndex >= mCols.Count())) { //see bug 9024 comments above //printf("%s \n", "nsCellMap::GetMapCellAt called with invalid row or col index"); // XXX look at this when bug 10911 get fixed return nsnull; @@ -228,7 +265,7 @@ inline CellData* nsCellMap::GetMapCellAt(PRInt32 aMapRowIndex, inline PRInt32 nsCellMap::GetColCount() const { - return mNumCellsOrigInCol.Count(); + return mCols.Count(); } inline PRInt32 nsCellMap::GetRowCount() const @@ -236,15 +273,16 @@ inline PRInt32 nsCellMap::GetRowCount() const return mRowCount; } -inline void nsCellMap::AppendColumnFrame(nsTableColFrame *aColFrame) -{ - mColFrames.AppendElement(aColFrame); -} +// nsColInfo -inline void nsCellMap::ClearColumnCache() -{ - mColFrames.Clear(); -} +inline nsColInfo::nsColInfo() + :mNumCellsOrig(0), mNumCellsSpan(0) +{} + +inline nsColInfo::nsColInfo(PRInt32 aNumCellsOrig, + PRInt32 aNumCellsSpan) + :mNumCellsOrig(aNumCellsOrig), mNumCellsSpan(aNumCellsSpan) +{} #endif diff --git a/mozilla/layout/tables/nsITableLayoutStrategy.h b/mozilla/layout/tables/nsITableLayoutStrategy.h index def6c668195..e0720d881f8 100644 --- a/mozilla/layout/tables/nsITableLayoutStrategy.h +++ b/mozilla/layout/tables/nsITableLayoutStrategy.h @@ -38,11 +38,9 @@ public: /** call once every time any table thing changes (content, structure, or style) * @param aMaxElementSize [OUT] if not null, the max element size is computed and returned in this param - * @param aNumCols the total number of columns in the table * @param aComputedWidth the computed size of the table */ virtual PRBool Initialize(nsSize* aMaxElementSize, - PRInt32 aNumCols, nscoord aComputedWidth)=0; /** compute the max-element-size for the table @@ -80,9 +78,6 @@ public: /** return the value of the COLS attribute, used for balancing column widths */ virtual nscoord GetCOLSAttribute() const = 0; - /** return the total number of columns in the table */ - virtual nscoord GetNumCols() const = 0; - // see nsTableFrame::ColumnsCanBeInvalidatedBy virtual PRBool ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, const nsTableCellFrame& aCellFrame) const = 0; diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp index 08940515386..cf9dd330f23 100644 --- a/mozilla/layout/tables/nsTableCellFrame.cpp +++ b/mozilla/layout/tables/nsTableCellFrame.cpp @@ -71,10 +71,9 @@ nsTableCellFrame::Init(nsIPresContext* aPresContext, if (aPrevInFlow) { // Set the column index nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow; - PRInt32 baseColIndex; - - cellFrame->GetColIndex(baseColIndex); - InitCellFrame(baseColIndex); + PRInt32 colIndex; + cellFrame->GetColIndex(colIndex); + InitCellFrame(colIndex); } return rv; @@ -139,29 +138,24 @@ nsTableCellFrame::RemoveFrame(nsIPresContext* aPresContext, void nsTableCellFrame::InitCellFrame(PRInt32 aColIndex) { - NS_PRECONDITION(0<=aColIndex, "bad col index arg"); - SetColIndex(aColIndex); // this also sets the contents col index nsTableFrame* tableFrame=nsnull; // I should be checking my own style context, but border-collapse isn't inheriting correctly nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) - { - if (NS_STYLE_BORDER_COLLAPSE == tableFrame->GetBorderCollapseStyle()) - { + if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) { + SetColIndex(aColIndex); + if (NS_STYLE_BORDER_COLLAPSE == tableFrame->GetBorderCollapseStyle()) { mBorderEdges = new nsBorderEdges; mBorderEdges->mOutsideEdge=PR_FALSE; PRInt32 rowspan = GetRowSpan(); PRInt32 i; - for (i=0; imEdges[NS_SIDE_LEFT].AppendElement(borderToAdd); borderToAdd = new nsBorderEdge(); mBorderEdges->mEdges[NS_SIDE_RIGHT].AppendElement(borderToAdd); } PRInt32 colspan = GetColSpan(); - for (i=0; imEdges[NS_SIDE_TOP].AppendElement(borderToAdd); borderToAdd = new nsBorderEdge(); diff --git a/mozilla/layout/tables/nsTableColFrame.cpp b/mozilla/layout/tables/nsTableColFrame.cpp index c7dcfdf0ef7..e4cceb6f942 100644 --- a/mozilla/layout/tables/nsTableColFrame.cpp +++ b/mozilla/layout/tables/nsTableColFrame.cpp @@ -19,6 +19,7 @@ * * Contributor(s): */ +#include "nsCOMPtr.h" #include "nsTableColFrame.h" #include "nsContainerFrame.h" #include "nsIReflowCommand.h" @@ -30,6 +31,11 @@ #include "nsCSSRendering.h" #include "nsLayoutAtoms.h" +#define COL_TYPE_CONTENT 0x0 +#define COL_TYPE_ANONYMOUS_COL 0x1 +#define COL_TYPE_ANONYMOUS_COLGROUP 0x2 +#define COL_TYPE_ANONYMOUS_CELL 0x3 + nsTableColFrame::nsTableColFrame() : nsFrame(), mProportion(WIDTH_NOT_SET), @@ -38,12 +44,55 @@ nsTableColFrame::nsTableColFrame() { // note that all fields are initialized to 0 by nsFrame::operator new ResetSizingInfo(); + SetType(eColContent); } nsTableColFrame::~nsTableColFrame() { } +nsTableColType nsTableColFrame::GetType() const { + switch(mBits.mType) { + case COL_TYPE_ANONYMOUS_COL: + return eColAnonymousCol; + case COL_TYPE_ANONYMOUS_COLGROUP: + return eColAnonymousColGroup; + case COL_TYPE_ANONYMOUS_CELL: + return eColAnonymousCell; + default: + return eColContent; + } +} + +void nsTableColFrame::SetType(nsTableColType aType) { + mBits.mType = aType - eColContent; +} + +// XXX what about other style besides width +nsStyleCoord nsTableColFrame::GetStyleWidth() const +{ + nsStylePosition* position = nsnull; + position = (nsStylePosition*)mStyleContext->GetStyleData(eStyleStruct_Position); + nsStyleCoord styleWidth = position->mWidth; + // the following should not be necessary since html.css defines table-col and + // :table-col to inherit. However, :table-col is not inheriting properly + if (eStyleUnit_Auto == styleWidth.GetUnit()) { + nsIFrame* parent; + GetParent(&parent); + nsCOMPtr styleContext; + parent->GetStyleContext(getter_AddRefs(styleContext)); + if (styleContext) { + position = (nsStylePosition*)styleContext->GetStyleData(eStyleStruct_Position); + styleWidth = position->mWidth; + } + } + + nsStyleCoord returnWidth; + returnWidth.mUnit = styleWidth.mUnit; + returnWidth.mValue = styleWidth.mValue; + return returnWidth; +} + void nsTableColFrame::ResetSizingInfo() { nsCRT::memset(mWidths, WIDTH_NOT_SET, NUM_WIDTHS * sizeof(PRInt32)); diff --git a/mozilla/layout/tables/nsTableColFrame.h b/mozilla/layout/tables/nsTableColFrame.h index 9a0207cfbc9..3a50b6e2859 100644 --- a/mozilla/layout/tables/nsTableColFrame.h +++ b/mozilla/layout/tables/nsTableColFrame.h @@ -55,6 +55,13 @@ enum nsColConstraint { e0ProportionConstraint = 4 // 0*, means to force to min width }; +enum nsTableColType { + eColContent = 0, // there is real col content associated + eColAnonymousCol = 1, // the result of a span on a col + eColAnonymousColGroup = 2, // the result of a span on a col group + eColAnonymousCell = 3, // the result of a cell alone +}; + class nsTableColFrame : public nsFrame { public: @@ -63,7 +70,8 @@ public: eWIDTH_SOURCE_CELL_WITH_SPAN=2 // a cell implicitly specified a width via colspan }; - void InitColFrame(PRInt32 aColIndex); + nsTableColType GetType() const; + void nsTableColFrame::SetType(nsTableColType aType); /** instantiate a new instance of nsTableColFrame. * @param aResult the new object is returned in this out-param @@ -75,6 +83,12 @@ public: friend nsresult NS_NewTableColFrame(nsIPresShell* aPresShell, nsIFrame** aResult); + nsStyleCoord GetStyleWidth() const; + + PRInt32 GetColIndex() const; + + void SetColIndex (PRInt32 aColIndex); + NS_IMETHOD Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -97,15 +111,9 @@ public: NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const; #endif - /** return the index of the column the col represents. always >= 0 */ - virtual PRInt32 GetColumnIndex (); - /** return the number of the columns the col represents. always >= 0 */ virtual PRInt32 GetSpan (); - /** set the index of the column this content object represents. must be >= 0 */ - virtual void SetColumnIndex (int aColIndex); - /** convenience method, calls into cellmap */ nsVoidArray * GetCells(); @@ -138,6 +146,11 @@ public: protected: + struct ColBits { + unsigned int mType:4; + unsigned int mUnused:28; + } mBits; + nsTableColFrame(); ~nsTableColFrame(); @@ -153,18 +166,11 @@ protected: PRPackedBool mNonPercentSpansPercent; }; - -inline void nsTableColFrame::InitColFrame(PRInt32 aColIndex) -{ - NS_ASSERTION(0<=aColIndex, "bad col index param"); - mColIndex = aColIndex; -} - -inline PRInt32 nsTableColFrame::GetColumnIndex() +inline PRInt32 nsTableColFrame::GetColIndex() const { return mColIndex; } -inline void nsTableColFrame::SetColumnIndex (int aColIndex) -{ mColIndex = aColIndex;} +inline void nsTableColFrame::SetColIndex (PRInt32 aColIndex) +{ mColIndex = aColIndex; } inline nsColConstraint nsTableColFrame::GetConstraint() const { return mConstraint; } diff --git a/mozilla/layout/tables/nsTableColGroupFrame.cpp b/mozilla/layout/tables/nsTableColGroupFrame.cpp index 0a1ecf5ef71..00ed27bcb09 100644 --- a/mozilla/layout/tables/nsTableColGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableColGroupFrame.cpp @@ -23,6 +23,7 @@ #include "nsTableColFrame.h" #include "nsTableFrame.h" #include "nsIHTMLTableColElement.h" +#include "nsIDOMHTMLTableColElement.h" #include "nsIReflowCommand.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" @@ -40,101 +41,230 @@ NS_DEF_PTR(nsIContent); static NS_DEFINE_IID(kIHTMLTableColElementIID, NS_IHTMLTABLECOLELEMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLTableColElementIID, NS_IDOMHTMLTABLECOLELEMENT_IID); + +#define COLGROUP_TYPE_CONTENT 0x0 +#define COLGROUP_TYPE_ANONYMOUS_COL 0x1 +#define COLGROUP_TYPE_ANONYMOUS_CELL 0x2 + +nsTableColGroupType nsTableColGroupFrame::GetType() const { + switch(mBits.mType) { + case COLGROUP_TYPE_ANONYMOUS_COL: + return eColGroupAnonymousCol; + case COLGROUP_TYPE_ANONYMOUS_CELL: + return eColGroupAnonymousCell; + default: + return eColGroupContent; + } +} + +void nsTableColGroupFrame::SetType(nsTableColGroupType aType) { + mBits.mType = aType - eColGroupContent; +} + +void nsTableColGroupFrame::ResetColIndices(nsIFrame* aFirstColGroup, + PRInt32 aFirstColIndex, + nsIFrame* aStartColFrame) +{ + nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame*)aFirstColGroup; + PRInt32 colIndex = aFirstColIndex; + while (colGroupFrame) { + nsIAtom* cgType; + colGroupFrame->GetFrameType(&cgType); + if (nsLayoutAtoms::tableColGroupFrame == cgType) { + colGroupFrame->SetStartColumnIndex(colIndex); + nsIFrame* colFrame = aStartColFrame; + if (!colFrame || (colIndex != aFirstColIndex)) { + colGroupFrame->FirstChild(nsnull, &colFrame); + } + while (colFrame) { + nsIAtom* colType; + colFrame->GetFrameType(&colType); + if (nsLayoutAtoms::tableColFrame == colType) { + ((nsTableColFrame*)colFrame)->SetColIndex(colIndex); + colIndex++; + } + NS_IF_RELEASE(colType); + colFrame->GetNextSibling(&colFrame); + } + } + NS_IF_RELEASE(cgType); + colGroupFrame->GetNextSibling((nsIFrame**)&colGroupFrame); + } +} + NS_IMETHODIMP -nsTableColGroupFrame::InitNewFrames(nsIPresContext* aPresContext, nsIFrame* aChildList) +nsTableColGroupFrame::AddColsToTable(nsIPresContext& aPresContext, + PRInt32 aFirstColIndex, + PRBool aResetSubsequentColIndices, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame) { - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - nsresult rv=NS_OK; - nsTableFrame* tableFrame=nsnull; + nsresult rv = NS_OK; + nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) { - // Process the newly added column frames - for (nsIFrame* kidFrame = aChildList; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { - const nsStyleDisplay* display; - kidFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == display->mDisplay) { - // Set the preliminary values for the column frame - PRInt32 colIndex = mStartColIndex + mColCount; - ((nsTableColFrame *)(kidFrame))->InitColFrame (colIndex); - PRInt32 repeat = ((nsTableColFrame *)(kidFrame))->GetSpan(); - mColCount += repeat; - for (PRInt32 i=0; iAddColumnFrame((nsTableColFrame *)kidFrame); - } - } - } - // colgroup's span attribute is how many columns the group represents - // in the absence of any COL children - // Note that this is the correct, though perhaps unexpected, behavior for the span attribute. - // The spec says that if there are any COL children, the colgroup's span is ignored. - if (0==mColCount) - { - nsIFrame *firstImplicitColFrame=nsnull; - nsIFrame *prevColFrame=nsnull; - nsAutoString colTag; - nsHTMLAtoms::col->ToString(colTag); - mColCount = GetSpan(); - for (PRInt32 colIndex=0; colIndexAppendChildTo((nsIContent*)col, PR_FALSE); - - // Create a new col frame - nsIFrame* colFrame; - NS_NewTableColFrame(shell, &colFrame); - - // Set its style context - nsCOMPtr colStyleContext; - aPresContext->ResolveStyleContextFor(col, mStyleContext, - PR_TRUE, - getter_AddRefs(colStyleContext)); - colFrame->Init(aPresContext, col, this, colStyleContext, nsnull); - colFrame->SetInitialChildList(aPresContext, nsnull, nsnull); - - // Set nsColFrame-specific information - PRInt32 absColIndex = mStartColIndex + colIndex; - ((nsTableColFrame *)(colFrame))->InitColFrame (absColIndex); - ((nsTableColFrame *)colFrame)->SetColumnIndex(absColIndex); - tableFrame->AddColumnFrame((nsTableColFrame *)colFrame); - - //hook into list of children - if (nsnull==firstImplicitColFrame) - firstImplicitColFrame = colFrame; - else - prevColFrame->SetNextSibling(colFrame); - prevColFrame = colFrame; - } - - // hook new columns into col group child list - mFrames.AppendFrames(nsnull, firstImplicitColFrame); - } - SetStyleContextForFirstPass(aPresContext); + if (!(NS_SUCCEEDED(rv) && tableFrame && aFirstFrame)) { + return rv; } + + // set the col indices of the col frames and and add col info to the table + PRInt32 colIndex = aFirstColIndex; + nsIFrame* kidFrame = aFirstFrame; + PRBool foundLastFrame = PR_FALSE; + while (kidFrame) { + nsIAtom* kidType; + kidFrame->GetFrameType(&kidType); + if (nsLayoutAtoms::tableColFrame == kidType) { + ((nsTableColFrame*)kidFrame)->SetColIndex(colIndex); + if (!foundLastFrame) { + tableFrame->InsertCol(aPresContext, (nsTableColFrame &)*kidFrame, colIndex); + mColCount++; + } + colIndex++; + } + NS_IF_RELEASE(kidType); + if (kidFrame == aLastFrame) { + foundLastFrame = PR_TRUE; + } + kidFrame->GetNextSibling(&kidFrame); + } + + if (aResetSubsequentColIndices) { + nsIFrame* nextSibling; + GetNextSibling(&nextSibling); + if (nextSibling) { + ResetColIndices(nextSibling, colIndex); + } + } + return rv; } -NS_IMETHODIMP -nsTableColGroupFrame::AppendNewFrames(nsIPresContext* aPresContext, nsIFrame* aChildList) +// this is called when a col frame doesn't have an explicit col group parent. +nsTableColGroupFrame* +nsTableColGroupFrame::FindParentForAppendedCol(nsTableFrame* aTableFrame, + nsTableColType aColType) { - if (nsnull!=aChildList) - mFrames.AppendFrames(nsnull, aChildList); - return NS_OK; + nsVoidArray& cols = aTableFrame->GetColCache(); + PRInt32 numCols = cols.Count(); + nsIFrame* lastColGroup; + nsIFrame* lastCol = (nsIFrame*)cols.ElementAt(numCols - 1); + if (!lastCol) return nsnull; // no columns so no colgroups + lastCol->GetParent(&lastColGroup); + if (!lastColGroup) return nsnull; // shouldn't happen + + nsTableColGroupFrame* relevantColGroup = (nsTableColGroupFrame *)lastColGroup; + nsTableColGroupType relevantColGroupType = relevantColGroup->GetType(); + if (eColGroupAnonymousCell == relevantColGroupType) { + if (eColAnonymousCell == aColType) { + return relevantColGroup; + } + else { + // find the next to last col group + for (PRInt32 colX = numCols - 2; colX >= 0; colX--) { + nsTableColFrame* colFrame = (nsTableColFrame*)cols.ElementAt(colX); + nsTableColGroupFrame* colGroupFrame; + colFrame->GetParent((nsIFrame**)&colGroupFrame); + nsTableColGroupType cgType = colGroupFrame->GetType(); + if (cgType != relevantColGroupType) { + relevantColGroup = colGroupFrame; + relevantColGroupType = cgType; + break; + } + else if (0 == colX) { + return nsnull; + } + } + } + } + + if (eColGroupAnonymousCol == relevantColGroupType) { + if ((eColContent == aColType) || (eColAnonymousCol == aColType)) { + return relevantColGroup; + } + } + + return nsnull; } +PRBool +nsTableColGroupFrame::GetLastRealColGroup(nsTableFrame* aTableFrame, + nsIFrame** aLastColGroup) +{ + *aLastColGroup = nsnull; + nsFrameList colGroups = aTableFrame->GetColGroups(); + + nsIFrame* nextToLastColGroup = nsnull; + nsIFrame* lastColGroup = colGroups.FirstChild(); + while(lastColGroup) { + nsIFrame* next; + lastColGroup->GetNextSibling(&next); + if (next) { + nextToLastColGroup = lastColGroup; + lastColGroup = next; + } + else { + break; + } + } + + if (!lastColGroup) return PR_TRUE; // there are no col group frames + + nsTableColGroupType lastColGroupType = ((nsTableColGroupFrame *)lastColGroup)->GetType(); + if (eColGroupAnonymousCell == lastColGroupType) { + *aLastColGroup = nextToLastColGroup; + return PR_FALSE; + } + else { + *aLastColGroup = lastColGroup; + return PR_TRUE; + } +} + +// don't set mColCount here, it is done in AddColsToTable NS_IMETHODIMP nsTableColGroupFrame::SetInitialChildList(nsIPresContext* aPresContext, nsIAtom* aListName, nsIFrame* aChildList) { - nsresult result = AppendNewFrames(aPresContext, aChildList); - if (NS_OK==result) - result = InitNewFrames(aPresContext, aChildList); - return result; + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + if (!aChildList) { + nsIFrame* firstChild; + tableFrame->CreateAnonymousColFrames(*aPresContext, *this, GetSpan(), eColAnonymousColGroup, + PR_FALSE, nsnull, &firstChild); + if (firstChild) { + SetInitialChildList(aPresContext, aListName, firstChild); + } + return NS_OK; + } + + nsIFrame* kidFrame = aChildList; + while (kidFrame) { + nsIAtom* kidType; + kidFrame->GetFrameType(&kidType); + if (nsLayoutAtoms::tableColFrame == kidType) { + // Set the preliminary values for the column frame + PRInt32 span = ((nsTableColFrame*)kidFrame)->GetSpan(); + if (span > 1) { + nsTableColFrame* firstSpannedCol; + tableFrame->CreateAnonymousColFrames(*aPresContext, *this, span - 1, eColAnonymousCol, + PR_FALSE, (nsTableColFrame*)kidFrame, (nsIFrame **)&firstSpannedCol); + nsIFrame* spanner = kidFrame; + kidFrame->GetNextSibling(&kidFrame); // need to do this before we insert the new frames + nsFrameList newChildren(aChildList); // used as a convience to hook up siblings + newChildren.InsertFrames(this, (nsTableColFrame*)spanner, (nsIFrame *)firstSpannedCol); + NS_RELEASE(kidType); + continue; + } + } + NS_IF_RELEASE(kidType); + kidFrame->GetNextSibling(&kidFrame); + } + + mFrames.AppendFrames(this, aChildList); + return NS_OK; } // Helper function. It marks the table frame as dirty and generates @@ -173,35 +303,8 @@ nsTableColGroupFrame::AppendFrames(nsIPresContext* aPresContext, nsIAtom* aListName, nsIFrame* aFrameList) { - // Append the new frames to our child list - mFrames.AppendFrames(nsnull, aFrameList); - - // Reset the starting column index of the col groups that follow - PRInt32 startingColIndex = mStartColIndex; - startingColIndex += GetColumnCount(); // has the side effect of resetting all column indexes - - nsIFrame *nextColGroupFrame=nsnull; - GetNextSibling(&nextColGroupFrame); - while (nextColGroupFrame) - { - const nsStyleDisplay *display; - nextColGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) - { - startingColIndex += ((nsTableColGroupFrame *)nextColGroupFrame)->SetStartColumnIndex(startingColIndex); - } - nextColGroupFrame->GetNextSibling(&nextColGroupFrame); - } - - // Today we need to rebuild the whole column cache. - // If the table frame is ever recoded to build the column cache incrementally, - // we could take advantage of that here - nsTableFrame* tableFrame; - nsTableFrame::GetTableFrame(this, tableFrame); - tableFrame->InvalidateColumnCache(); - - // Generate a reflow command so we reflow the table - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); + mFrames.AppendFrames(this, aFrameList); + InsertColsReflow(*aPresContext, aPresShell, mColCount, aFrameList); return NS_OK; } @@ -209,76 +312,121 @@ NS_IMETHODIMP nsTableColGroupFrame::InsertFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, - nsIFrame* aPrevFrame, + nsIFrame* aPrevFrameIn, nsIFrame* aFrameList) { - // Insert the new frames into our child list - mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); + nsFrameList frames(aFrameList); // convience for getting last frame + nsIFrame* lastFrame = frames.LastChild(); - // Reset the starting column index of the col groups that follow - PRInt32 startingColIndex=mStartColIndex; - startingColIndex += GetColumnCount(); // has the side effect of resetting all column indexes + mFrames.InsertFrames(this, aPrevFrameIn, aFrameList); + nsIFrame* prevFrame = nsTableFrame::GetFrameAtOrBefore(this, aPrevFrameIn, + nsLayoutAtoms::tableColFrame); - nsIFrame *nextColGroupFrame=nsnull; - GetNextSibling(&nextColGroupFrame); - while (nextColGroupFrame) - { - const nsStyleDisplay *display; - nextColGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) - { - startingColIndex += ((nsTableColGroupFrame *)nextColGroupFrame)->SetStartColumnIndex(startingColIndex); - } - nextColGroupFrame->GetNextSibling(&nextColGroupFrame); - } + PRInt32 colIndex = (prevFrame) ? ((nsTableColFrame*)prevFrame)->GetColIndex() + 1 : 0; + InsertColsReflow(*aPresContext, aPresShell, colIndex, aFrameList, lastFrame); - // Today we need to rebuild the whole column cache. - // If the table frame is ever recoded to build the column cache incrementally, - // we could take advantage of that here. - nsTableFrame* tableFrame; - nsTableFrame::GetTableFrame(this, tableFrame); - tableFrame->InvalidateColumnCache(); - - // Generate a reflow command so we reflow the table - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); return NS_OK; } +void +nsTableColGroupFrame::InsertColsReflow(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + PRInt32 aColIndex, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame) +{ + AddColsToTable(aPresContext, aColIndex, PR_TRUE, aFirstFrame, aLastFrame); + + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + tableFrame->InvalidateColumnWidths(); + + // Generate a reflow command so we reflow the table + AddTableDirtyReflowCommand(&aPresContext, aPresShell, tableFrame); +} + +void +nsTableColGroupFrame::RemoveChild(nsIPresContext& aPresContext, + nsTableColFrame& aChild, + PRBool aResetColIndices) +{ + PRInt32 colIndex = 0; + nsIFrame* nextChild = nsnull; + if (aResetColIndices) { + colIndex = aChild.GetColIndex(); + aChild.GetNextSibling(&nextChild); + } + if (mFrames.DestroyFrame(&aPresContext, (nsIFrame*)&aChild)) { + mColCount--; + if (aResetColIndices) { + ResetColIndices(this, colIndex, nextChild); + } + } +} + +// this removes children form the last col group (eColGroupAnonymousCell) in the +// table only,so there is no need to reset col indices for subsequent col groups. +void +nsTableColGroupFrame::RemoveChildrenAtEnd(nsIPresContext& aPresContext, + PRInt32 aNumChildrenToRemove) +{ + PRInt32 numToRemove = aNumChildrenToRemove; + if (numToRemove > mColCount) { + NS_ASSERTION(PR_FALSE, "invalid arg to RemoveChildrenAtEnd"); + numToRemove = mColCount; + } + PRInt32 offsetOfFirstRemoval = mColCount - numToRemove; + PRInt32 offsetX = 0; + nsIFrame* kidFrame = mFrames.FirstChild(); + while(kidFrame) { + nsIAtom* kidType; + kidFrame->GetFrameType(&kidType); + if (nsLayoutAtoms::tableColFrame == kidType) { + offsetX++; + if (offsetX > offsetOfFirstRemoval) { + nsIFrame* byebye = kidFrame; + kidFrame->GetNextSibling(&kidFrame); + mFrames.DestroyFrame(&aPresContext, byebye); + NS_RELEASE(kidType); + continue; + } + } + NS_IF_RELEASE(kidType); + kidFrame->GetNextSibling(&kidFrame); + } +} + + NS_IMETHODIMP nsTableColGroupFrame::RemoveFrame(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aOldFrame) { - // Remove the frame from our child list - mFrames.DestroyFrame(aPresContext, aOldFrame); + if (!aOldFrame) return NS_OK; - // Reset the starting column index of the col groups that follow - PRInt32 startingColIndex=mStartColIndex; - startingColIndex += GetColumnCount(); // has the side effect of resetting all column indexes - - nsIFrame *nextColGroupFrame=nsnull; - GetNextSibling(&nextColGroupFrame); - while (nextColGroupFrame) - { - const nsStyleDisplay *display; - nextColGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) - { - startingColIndex += ((nsTableColGroupFrame *)nextColGroupFrame)->SetStartColumnIndex(startingColIndex); + nsIAtom* frameType = nsnull; + aOldFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableColFrame == frameType) { + nsTableColFrame* colFrame = (nsTableColFrame*)aOldFrame; + PRInt32 colIndex = colFrame->GetColIndex(); + RemoveChild(*aPresContext, *colFrame, PR_TRUE); + + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + if (tableFrame) { + tableFrame->RemoveCol(*aPresContext, this, colIndex, PR_TRUE, PR_TRUE); } - nextColGroupFrame->GetNextSibling(&nextColGroupFrame); + + tableFrame->InvalidateColumnWidths(); + // Generate a reflow command so we reflow the table + AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); } + else { + mFrames.DestroyFrame(aPresContext, aOldFrame); + } + NS_IF_RELEASE(frameType); - // Today we need to rebuild the whole column cache. - // If the table frame is ever recoded to build the column cache incrementally, - // we could take advantage of that here - nsTableFrame* tableFrame; - nsTableFrame::GetTableFrame(this, tableFrame); - tableFrame->InvalidateColumnCache(); - - // Generate a reflow command so we reflow the table - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); return NS_OK; } @@ -429,11 +577,10 @@ NS_METHOD nsTableColGroupFrame::IR_StyleChanged(nsIPresContext* aPresCo nsresult rv = NS_OK; // we presume that all the easy optimizations were done in the nsHTMLStyleSheet before we were called here // XXX: we can optimize this when we know which style attribute changed - nsTableFrame* tableFrame=nsnull; + nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) - { - tableFrame->InvalidateColumnCache(); + if ((NS_SUCCEEDED(rv)) && tableFrame) { + tableFrame->InvalidateColumnWidths(); tableFrame->InvalidateFirstPassCache(); } return rv; @@ -448,7 +595,7 @@ NS_METHOD nsTableColGroupFrame::IR_TargetIsChild(nsIPresContext* aPresC nsresult rv; // Remember the old col count - const PRInt32 oldColCount = GetColumnCount(); + const PRInt32 oldColCount = GetColCount(); // Pass along the reflow command nsHTMLReflowMetrics desiredSize(nsnull); @@ -462,136 +609,16 @@ NS_METHOD nsTableColGroupFrame::IR_TargetIsChild(nsIPresContext* aPresC nsTableFrame *tableFrame=nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) - { + if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) { // compare the new col count to the old col count. // If they are the same, we just need to rebalance column widths // If they differ, we need to fix up other column groups and the column cache - const PRInt32 newColCount = GetColumnCount(); // this will set the new column indexes if necessary - if (oldColCount==newColCount) - tableFrame->InvalidateColumnWidths(); - else - tableFrame->InvalidateColumnCache(); + const PRInt32 newColCount = GetColCount(); + tableFrame->InvalidateColumnWidths(); } return rv; } -// Subclass hook for style post processing -NS_METHOD nsTableColGroupFrame::SetStyleContextForFirstPass(nsIPresContext* aPresContext) -{ - // get the table frame - nsTableFrame* tableFrame=nsnull; - nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); - if ((NS_SUCCEEDED(rv)) && (nsnull!=tableFrame)) - { - // get the style for the table frame - const nsStyleTable *tableStyle; - tableFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle); - - // if COLS is set, then map it into the COL frames - if (NS_STYLE_TABLE_COLS_NONE != tableStyle->mCols) - { - // set numCols to the number of columns effected by the COLS attribute - PRInt32 numCols=0; - if (NS_STYLE_TABLE_COLS_ALL == tableStyle->mCols) - numCols = mFrames.GetLength(); - else - numCols = tableStyle->mCols; - - // for every column effected, set its width style - PRInt32 colIndex=0; - nsIFrame *colFrame=mFrames.FirstChild(); - while (nsnull!=colFrame) - { - const nsStyleDisplay * colDisplay=nsnull; - colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) - { - nsCOMPtr colStyleContext; - nsStylePosition * colPosition=nsnull; - colFrame->GetStyleContext(getter_AddRefs(colStyleContext)); - colPosition = (nsStylePosition*)colStyleContext->GetMutableStyleData(eStyleStruct_Position); - if (colIndexmWidth = width; - } - else - { - colPosition->mWidth.SetCoordValue(0); - } - colStyleContext->RecalcAutomaticData(aPresContext); - colIndex++; - } - colFrame->GetNextSibling(&colFrame); - } - } - else - { - // propagate the colgroup width attribute down to the columns if they have no width of their own - nsStylePosition* position = (nsStylePosition*)mStyleContext->GetStyleData(eStyleStruct_Position); - if (eStyleUnit_Null!=position->mWidth.GetUnit()) - { - // now for every column that doesn't have it's own width, set the width style - nsIFrame *colFrame=mFrames.FirstChild(); - while (nsnull!=colFrame) - { - const nsStyleDisplay * colDisplay=nsnull; - colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) - { - nsCOMPtr colStyleContext; - const nsStylePosition * colPosition=nsnull; - colFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)colPosition); // get a read-only version of the style context - //XXX: how do I know this is auto because it's defaulted, vs. set explicitly to "auto"? - if (eStyleUnit_Auto==colPosition->mWidth.GetUnit()) - { - // notice how we defer getting a mutable style context until we're sure we really need one - colFrame->GetStyleContext(getter_AddRefs(colStyleContext)); - nsStylePosition * mutableColPosition = (nsStylePosition*)colStyleContext->GetMutableStyleData(eStyleStruct_Position); - mutableColPosition->mWidth = position->mWidth; - colStyleContext->RecalcAutomaticData(aPresContext); - } - } - colFrame->GetNextSibling(&colFrame); - } - } - } - //mStyleContext->RecalcAutomaticData(aPresContext); - } - return rv; -} - - -/** returns the number of columns represented by this group. - * if there are col children, count them (taking into account the span of each) - * else, check my own span attribute. - */ -int nsTableColGroupFrame::GetColumnCount () -{ - mColCount=0; - nsIFrame *childFrame = mFrames.FirstChild(); - while (nsnull!=childFrame) - { - const nsStyleDisplay *childDisplay; - childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == childDisplay->mDisplay) - { - nsTableColFrame *col = (nsTableColFrame *)childFrame; - col->SetColumnIndex (mStartColIndex + mColCount); - mColCount += col->GetSpan(); - } - childFrame->GetNextSibling(&childFrame); - } - if (0==mColCount) - { // there were no children of this colgroup that were columns. So use my span attribute - const nsStyleTable *tableStyle; - GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle); - mColCount = tableStyle->mSpan; - } - return mColCount; -} - nsTableColFrame * nsTableColGroupFrame::GetFirstColumn() { return GetNextColumn(nsnull); @@ -642,28 +669,26 @@ nsTableColFrame * nsTableColGroupFrame::GetColumnAt (PRInt32 aColIndex) PRInt32 nsTableColGroupFrame::GetSpan() { - PRInt32 span=1; - const nsStyleTable* tableStyle=nsnull; - GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle); - if (nsnull!=tableStyle) - { - span = tableStyle->mSpan; + PRInt32 span = 1; + nsCOMPtr iContent; + nsresult rv = GetContent(getter_AddRefs(iContent)); + if (NS_FAILED(rv) || !iContent) return rv; + + // col group element derives from col element + nsIDOMHTMLTableColElement* cgContent = nsnull; + rv = iContent->QueryInterface(kIDOMHTMLTableColElementIID, + (void **)&cgContent); + if (cgContent && NS_SUCCEEDED(rv)) { + cgContent->GetSpan(&span); + // XXX why does this work!! + if (span == -1) { + span = 1; + } + NS_RELEASE(cgContent); } return span; } -/* this may be needed when IsSynthetic is properly implemented -PRBool nsTableColGroupFrame::IsManufactured() -{ - PRBool result = PR_FALSE; - nsIFrame *firstCol = GetFirstColumn(); - if (nsTableFrame::IsSynthetic(this) && - ((nsnull==firstCol) || nsTableFrame::IsSynthetic(firstCol))) - result = PR_TRUE; - return result; -} -*/ - /** returns colcount because it is frequently used in the context of * shuffling relative colgroup order, and it's convenient to not have to * call GetColumnCount redundantly. @@ -671,15 +696,41 @@ PRBool nsTableColGroupFrame::IsManufactured() PRInt32 nsTableColGroupFrame::SetStartColumnIndex (int aIndex) { PRInt32 result = mColCount; - if (aIndex != mStartColIndex) - { + if (aIndex != mStartColIndex) { mStartColIndex = aIndex; - mColCount=0; - result = GetColumnCount(); // has the side effect of setting each column index based on new start index + result = GetColCount(); } return result; } + +// this could be optimized by using col group frame starting indicies, +// but typically there aren't enough very large col groups for the added complexity. +nsTableColGroupFrame* +nsTableColGroupFrame::GetColGroupFrameContaining(nsFrameList& aColGroupList, + nsTableColFrame& aColFrame) +{ + nsIFrame* childFrame = aColGroupList.FirstChild(); + while (childFrame) { + nsIAtom* frameType = nsnull; + childFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableColGroupFrame == frameType) { + nsTableColFrame* colFrame = nsnull; + childFrame->FirstChild(nsnull, (nsIFrame **)&colFrame); + while (colFrame) { + if (colFrame = &aColFrame) { + NS_RELEASE(frameType); + return (nsTableColGroupFrame *)childFrame; + } + colFrame->GetNextSibling((nsIFrame **)&colFrame); + } + } + NS_IF_RELEASE(frameType); + childFrame->GetNextSibling(&childFrame); + } + return nsnull; +} + void nsTableColGroupFrame::DeleteColFrame(nsIPresContext* aPresContext, nsTableColFrame* aColFrame) { mFrames.DestroyFrame(aPresContext, aColFrame); diff --git a/mozilla/layout/tables/nsTableColGroupFrame.h b/mozilla/layout/tables/nsTableColGroupFrame.h index 98759866de6..93125656a53 100644 --- a/mozilla/layout/tables/nsTableColGroupFrame.h +++ b/mozilla/layout/tables/nsTableColGroupFrame.h @@ -26,7 +26,14 @@ #include "nsHTMLContainerFrame.h" class nsTableColFrame; +class nsTableFrame; +enum nsTableColType; +enum nsTableColGroupType { + eColGroupContent = 0, // there is real col group content associated + eColGroupAnonymousCol = 1, // the result of a col + eColGroupAnonymousCell = 2, // the result of a cell alone +}; /** * nsTableColGroupFrame @@ -52,6 +59,16 @@ public: nsIAtom* aListName, nsIFrame* aChildList); + nsTableColGroupType GetType() const; + + void SetType(nsTableColGroupType aType); + + static PRBool GetLastRealColGroup(nsTableFrame* aTableFrame, + nsIFrame** aLastColGroup); + + static nsTableColGroupFrame* FindParentForAppendedCol(nsTableFrame* aTableFrame, + nsTableColType aColType); + NS_IMETHOD AppendFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, @@ -66,6 +83,13 @@ public: nsIAtom* aListName, nsIFrame* aOldFrame); + void RemoveChild(nsIPresContext& aPresContext, + nsTableColFrame& aLastChild, + PRBool aResetColIndices); + + void RemoveChildrenAtEnd(nsIPresContext& aPresContext, + PRInt32 aNumChildrenToRemove); + NS_IMETHOD Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -89,6 +113,12 @@ public: */ NS_IMETHOD GetFrameType(nsIAtom** aType) const; + NS_IMETHOD AddColsToTable(nsIPresContext& aPresContext, + PRInt32 aFirstColIndex, + PRBool aResetSubsequentColIndices, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame = nsnull); + #ifdef DEBUG NS_IMETHOD GetFrameName(nsString& aResult) const; NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const; @@ -98,7 +128,7 @@ public: * if there are col children, count them (taking into account the span of each) * else, check my own span attribute. */ - virtual PRInt32 GetColumnCount(); + virtual PRInt32 GetColCount() const; virtual nsTableColFrame * GetFirstColumn(); @@ -124,23 +154,25 @@ public: void DeleteColFrame(nsIPresContext* aPresContext, nsTableColFrame* aColFrame); -protected: + static nsTableColGroupFrame* GetColGroupFrameContaining(nsFrameList& aColGroupList, + nsTableColFrame& aColFrame); + nsFrameList& GetChildList(); + static void ResetColIndices(nsIFrame* aFirstColGroup, + PRInt32 aFirstColIndex, + nsIFrame* aStartColFrame = nsnull); +protected: nsTableColGroupFrame(); + void InsertColsReflow(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + PRInt32 aColIndex, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame = nsnull); + /** implement abstract method on nsHTMLContainerFrame */ virtual PRIntn GetSkipSides() const; - /** Hook for style post processing. - * Since we need to know the full column structure before the COLS attribute - * can be interpreted, we can't just use DidSetStyleContext - */ - NS_IMETHOD SetStyleContextForFirstPass(nsIPresContext* aPresContext); - - NS_IMETHOD InitNewFrames(nsIPresContext* aPresContext, nsIFrame* aChildList); - NS_IMETHOD AppendNewFrames(nsIPresContext* aPresContext, nsIFrame* aChildList); - - NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -174,13 +206,33 @@ protected: /** the starting column index this col group represents. Must be >= 0. */ PRInt32 mStartColIndex; + struct ColGroupBits { + unsigned int mType:4; + unsigned int mUnused:28; + } mBits; + }; inline nsTableColGroupFrame::nsTableColGroupFrame() : mColCount(0), mStartColIndex(0) -{} +{ + mBits.mType = 0; +} -inline int nsTableColGroupFrame::GetStartColumnIndex () -{ return mStartColIndex;} +inline PRInt32 nsTableColGroupFrame::GetStartColumnIndex() +{ + return mStartColIndex; +} + +inline PRInt32 nsTableColGroupFrame::GetColCount() const +{ + return mColCount; +} + +inline nsFrameList& nsTableColGroupFrame::GetChildList() +{ + return mFrames; +} #endif + diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index a7891ebbaba..199efa39f3b 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -20,6 +20,7 @@ * Contributor(s): */ #include "nsCOMPtr.h" +#include "nsVoidArray.h" #include "nsTableFrame.h" #include "nsTableBorderCollapser.h" #include "nsIRenderingContext.h" @@ -155,10 +156,7 @@ nsTableFrame::nsTableFrame() mBits.mColumnWidthsSet = PR_FALSE; mBits.mColumnWidthsValid = PR_FALSE; mBits.mFirstPassValid = PR_FALSE; - mBits.mColumnCacheValid = PR_FALSE; - mBits.mCellMapValid = PR_TRUE; mBits.mIsInvariantWidth = PR_FALSE; - mBits.mHasScrollableRowGroup = PR_FALSE; // XXX We really shouldn't do this, but if we don't then we'll have a // problem with the tree control... #if 0 @@ -248,6 +246,8 @@ nsTableFrame::Destroy(nsIPresContext* aPresContext) return nsHTMLContainerFrame::Destroy(aPresContext); } +// XXX this needs to be cleaned up so that the frame constructor breaks out col group +// frames into a separate child list. NS_IMETHODIMP nsTableFrame::SetInitialChildList(nsIPresContext* aPresContext, nsIAtom* aListName, @@ -263,17 +263,13 @@ nsTableFrame::SetInitialChildList(nsIPresContext* aPresContext, { const nsStyleDisplay *childDisplay; childFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)childDisplay); + // XXX this if should go away if (PR_TRUE==IsRowGroup(childDisplay->mDisplay)) { - if (mFrames.IsEmpty()) + if (mFrames.IsEmpty()) mFrames.SetFrames(childFrame); else prevMainChild->SetNextSibling(childFrame); - // If we have a prev-in-flow, then we're a table that has been split and - // so don't treat this like an append - if (!mPrevInFlow) { - rv = DidAppendRowGroup(GetRowGroupFrameFor(childFrame, childDisplay)); - } prevMainChild = childFrame; } else if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) @@ -301,9 +297,13 @@ nsTableFrame::SetInitialChildList(nsIPresContext* aPresContext, if (nsnull!=prevColGroupChild) prevColGroupChild->SetNextSibling(nsnull); - if (NS_SUCCEEDED(rv)) { - PRBool createdColFrames; - EnsureColumns(aPresContext, createdColFrames); + // If we have a prev-in-flow, then we're a table that has been split and + // so don't treat this like an append + if (!mPrevInFlow) { + // process col groups first so that real cols get constructed before + // anonymous ones due to cells in rows. + InsertColGroups(*aPresContext, 0, mColGroups.FirstChild()); + AppendRowGroups(*aPresContext, mFrames.FirstChild()); } if (HasGroupRules()) { @@ -313,32 +313,6 @@ nsTableFrame::SetInitialChildList(nsIPresContext* aPresContext, return rv; } -NS_IMETHODIMP nsTableFrame::DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFrame) -{ - nsresult rv=NS_OK; - nsIFrame *nextRow=nsnull; - aRowGroupFrame->FirstChild(nsnull, &nextRow); - for ( ; nsnull!=nextRow; nextRow->GetNextSibling(&nextRow)) - { - const nsStyleDisplay *rowDisplay; - nextRow->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowDisplay); - if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) { - rv = ((nsTableRowFrame *)nextRow)->InitChildren(); - if (NS_FAILED(rv)) { - return rv; - } - } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP==rowDisplay->mDisplay) { - rv = DidAppendRowGroup((nsTableRowGroupFrame*)nextRow); - if (NS_FAILED(rv)) { - return rv; - } - } - } - - return rv; -} - /* ****** CellMap methods ******* */ @@ -348,7 +322,7 @@ PRInt32 nsTableFrame::GetSpecifiedColumnCount () PRInt32 colCount = 0; nsIFrame * childFrame = mColGroups.FirstChild(); while (nsnull!=childFrame) { - colCount += ((nsTableColGroupFrame *)childFrame)->GetColumnCount(); + colCount += ((nsTableColGroupFrame *)childFrame)->GetColCount(); childFrame->GetNextSibling(&childFrame); } return colCount; @@ -376,15 +350,9 @@ PRInt32 nsTableFrame::GetColCount () } -nsTableColFrame * nsTableFrame::GetColFrame(PRInt32 aColIndex) +nsTableColFrame* nsTableFrame::GetColFrame(PRInt32 aColIndex) { - nsTableColFrame *result = nsnull; - nsCellMap *cellMap = GetCellMap(); - if (nsnull!=cellMap) - { - result = cellMap->GetColumnFrame(aColIndex); - } - return result; + return (nsTableColFrame *)mColFrames.ElementAt(aColIndex); } // can return nsnull @@ -545,6 +513,21 @@ void nsTableFrame::ProcessGroupRules(nsIPresContext* aPresContext) } +void nsTableFrame::AdjustRowIndices(PRInt32 aRowIndex, + PRInt32 aAdjustment) +{ + // Iterate over the row groups and adjust the row indices of all rows + // whose index is >= aRowIndex. + nsIFrame* rowGroupFrame = mFrames.FirstChild(); + for ( ; rowGroupFrame; rowGroupFrame->GetNextSibling(&rowGroupFrame)) { + const nsStyleDisplay *rowGroupDisplay; + rowGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowGroupDisplay); + if (IsRowGroup(rowGroupDisplay->mDisplay)) { + AdjustRowIndices(rowGroupFrame, aRowIndex, aAdjustment); + } + } +} + NS_IMETHODIMP nsTableFrame::AdjustRowIndices(nsIFrame* aRowGroup, PRInt32 aRowIndex, PRInt32 anAdjustment) @@ -570,179 +553,104 @@ NS_IMETHODIMP nsTableFrame::AdjustRowIndices(nsIFrame* aRowGroup, return rv; } -NS_IMETHODIMP nsTableFrame::RemoveRowFromMap(nsTableRowFrame* aRow, PRInt32 aRowIndex) + +void nsTableFrame::InsertColGroups(nsIPresContext& aPresContext, + PRInt32 aStartColIndex, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame) { - nsresult rv=NS_OK; - - // Create a new row in the cell map at the specified index. - mCellMap->RemoveRowFromMap(aRowIndex); - - // Iterate over our row groups and increment the row indices of all rows whose index - // is >= aRowIndex. - nsIFrame *rowGroupFrame=mFrames.FirstChild(); - for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(&rowGroupFrame)) - { - const nsStyleDisplay *rowGroupDisplay; - rowGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowGroupDisplay); - if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay)) - { - AdjustRowIndices(rowGroupFrame, aRowIndex, -1); + PRInt32 colIndex = aStartColIndex; + nsTableColGroupFrame* firstColGroupToReset = nsnull; + nsIFrame* kidFrame = aFirstFrame; + PRBool didLastFrame = PR_FALSE; + while (kidFrame) { + nsIAtom* kidType; + kidFrame->GetFrameType(&kidType); + if (nsLayoutAtoms::tableColGroupFrame == kidType) { + if (didLastFrame) { + firstColGroupToReset = (nsTableColGroupFrame*)kidFrame; + break; + } + else { + nsTableColGroupFrame* cgFrame = (nsTableColGroupFrame*)kidFrame; + cgFrame->SetStartColumnIndex(colIndex); + nsIFrame* firstCol; + kidFrame->FirstChild(nsnull, &firstCol); + cgFrame->AddColsToTable(aPresContext, colIndex, PR_FALSE, firstCol); + PRInt32 numCols = cgFrame->GetColCount(); + colIndex += numCols; + } } + NS_IF_RELEASE(kidType); + if (kidFrame == aLastFrame) { + didLastFrame = PR_TRUE; + } + kidFrame->GetNextSibling(&kidFrame); } - return rv; + if (firstColGroupToReset) { + nsTableColGroupFrame::ResetColIndices(firstColGroupToReset, aStartColIndex); + } } -NS_IMETHODIMP nsTableFrame::InsertRowIntoMap(nsTableRowFrame* aRow, PRInt32 aRowIndex) +void nsTableFrame::InsertCol(nsIPresContext& aPresContext, + nsTableColFrame& aColFrame, + PRInt32 aColIndex) { - nsresult rv=NS_OK; - - // Create a new row in the cell map at the specified index. - mCellMap->InsertRowIntoMap(aRowIndex); - - // Iterate over our row groups and increment the row indices of all rows whose index - // is >= aRowIndex. - nsIFrame *rowGroupFrame=mFrames.FirstChild(); - for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(&rowGroupFrame)) - { - const nsStyleDisplay *rowGroupDisplay; - rowGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowGroupDisplay); - if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay)) - { - AdjustRowIndices(rowGroupFrame, aRowIndex, 1); + mColFrames.InsertElementAt(&aColFrame, aColIndex); + nsTableColType insertedColType = aColFrame.GetType(); + PRInt32 numCacheCols = mColFrames.Count(); + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + PRInt32 numMapCols = cellMap->GetColCount(); + if (numCacheCols > numMapCols) { + PRBool removedFromCache = PR_FALSE; + if (eColAnonymousCell != insertedColType) { + nsTableColFrame* lastCol = (nsTableColFrame *)mColFrames.ElementAt(numCacheCols - 1); + if (lastCol) { + nsTableColType lastColType = lastCol->GetType(); + if (eColAnonymousCell == lastColType) { + // remove the col from the cache + mColFrames.RemoveElementAt(numCacheCols - 1); + // remove the col from the eColGroupAnonymousCell col group + nsTableColGroupFrame* lastColGroup = (nsTableColGroupFrame *)mColGroups.LastChild(); + if (lastColGroup) { + lastColGroup->RemoveChild(aPresContext, *lastCol, PR_FALSE); + } + // remove the col group if it is empty + if (lastColGroup->GetColCount() <= 0) { + mColGroups.DestroyFrame(&aPresContext, (nsIFrame*)lastColGroup); + } + removedFromCache = PR_TRUE; + } + } + } + if (!removedFromCache) { + cellMap->AppendCol(); + } } } - - // Init the row's index and add its cells to the cell map. - aRow->InitChildrenWithIndex(aRowIndex); - - return rv; } -/** sum the columns represented by all nsTableColGroup objects - * if the cell map says there are more columns than this, - * add extra implicit columns to the content tree. - */ -void nsTableFrame::EnsureColumns(nsIPresContext* aPresContext, - PRBool& aCreatedColFrames) +void nsTableFrame::RemoveCol(nsIPresContext& aPresContext, + nsTableColGroupFrame* aColGroupFrame, + PRInt32 aColIndex, + PRBool aRemoveFromCache, + PRBool aRemoveFromCellMap) { - NS_PRECONDITION(nsnull!=mCellMap, "bad state: null cellmap"); - - aCreatedColFrames = PR_FALSE; // initialize OUT parameter - if (nsnull == mCellMap) - return; // no info yet, so nothing useful to do - - // make sure we've accounted for the COLS attribute - AdjustColumnsForCOLSAttribute(); - - // count the number of column frames we already have - PRInt32 actualColumns = 0; - nsTableColGroupFrame *lastColGroupFrame = nsnull; - nsIFrame* childFrame = mColGroups.FirstChild(); - while (nsnull!=childFrame) { - ((nsTableColGroupFrame*)childFrame)->SetStartColumnIndex(actualColumns); - PRInt32 numCols = ((nsTableColGroupFrame*)childFrame)->GetColumnCount(); - actualColumns += numCols; - lastColGroupFrame = (nsTableColGroupFrame *)childFrame; - childFrame->GetNextSibling(&childFrame); + if (aRemoveFromCache) { + mColFrames.RemoveElementAt(aColIndex); } - - // if we have fewer column frames than we need, create some implicit column frames - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - - PRInt32 colCount = mCellMap->GetColCount(); - if (actualColumns < colCount) { - nsIContent *lastColGroupElement = nsnull; - if (nsnull==lastColGroupFrame) { // there are no col groups, so create an implicit colgroup frame - // Resolve style for the colgroup frame - // first, need to get the nearest containing content object - GetContent(&lastColGroupElement); // ADDREF a: lastColGroupElement++ (either here or in the loop below) - nsIFrame *parentFrame; - GetParent(&parentFrame); - while (nsnull==lastColGroupElement) { - parentFrame->GetContent(&lastColGroupElement); - if (nsnull==lastColGroupElement) - parentFrame->GetParent(&parentFrame); - } - // now we have a ref-counted "lastColGroupElement" content object - nsIStyleContext* colGroupStyleContext; - aPresContext->ResolvePseudoStyleContextFor (lastColGroupElement, - nsHTMLAtoms::tableColGroupPseudo, - mStyleContext, - PR_FALSE, - &colGroupStyleContext); // colGroupStyleContext: REFCNT++ - // Create a col group frame - nsIFrame* newFrame; - NS_NewTableColGroupFrame(shell, &newFrame); - newFrame->Init(aPresContext, lastColGroupElement, this, colGroupStyleContext, - nsnull); - lastColGroupFrame = (nsTableColGroupFrame*)newFrame; - NS_RELEASE(colGroupStyleContext); // kidStyleContenxt: REFCNT-- - - // hook lastColGroupFrame into child list - mColGroups.SetFrames(lastColGroupFrame); - } - else { - lastColGroupFrame->GetContent(&lastColGroupElement); // ADDREF b: lastColGroupElement++ - } - - // XXX It would be better to do this in the style code while constructing - // the table's frames. But we don't know how many columns we have at that point. - nsAutoString colTag; - nsHTMLAtoms::col->ToString(colTag); - PRInt32 excessColumns = colCount - actualColumns; - nsIFrame* firstNewColFrame = nsnull; - nsIFrame* lastNewColFrame = nsnull; - nsIStyleContextPtr lastColGroupStyle; - lastColGroupFrame->GetStyleContext(lastColGroupStyle.AssignPtr()); - for ( ; excessColumns > 0; excessColumns--) { - // Create a new col frame - nsIFrame* colFrame; - // note we pass in PR_TRUE here to force unique style contexts. - nsIStyleContext* colStyleContext; - aPresContext->ResolvePseudoStyleContextFor (lastColGroupElement, - nsHTMLAtoms::tableColPseudo, - lastColGroupStyle, - PR_TRUE, - &colStyleContext); // colStyleContext: REFCNT++ - aCreatedColFrames = PR_TRUE; // remember that we're creating implicit col frames - NS_NewTableColFrame(shell, &colFrame); - colFrame->Init(aPresContext, lastColGroupElement, lastColGroupFrame, - colStyleContext, nsnull); - NS_RELEASE(colStyleContext); - colFrame->SetInitialChildList(aPresContext, nsnull, nsnull); - ((nsTableColFrame *)colFrame)->SetIsAnonymous(PR_TRUE); - - // Add it to our list - if (nsnull == lastNewColFrame) { - firstNewColFrame = colFrame; - } else { - lastNewColFrame->SetNextSibling(colFrame); - } - lastNewColFrame = colFrame; - } - lastColGroupFrame->SetInitialChildList(aPresContext, nsnull, firstNewColFrame); - NS_RELEASE(lastColGroupElement); // ADDREF: lastColGroupElement-- - } - else if (actualColumns > colCount) { // the cell map needs to grow to accomodate extra cols + if (aRemoveFromCellMap) { nsCellMap* cellMap = GetCellMap(); if (cellMap) { - cellMap->AddColsAtEnd(actualColumns - colCount); + // check to see if the cell map can remove the col + if (cellMap->RemoveUnusedCols(1) < 1) { + // it couldn't be removed so we need a new anonymous col frame + CreateAnonymousColFrames(aPresContext, 1, eColAnonymousCell, PR_TRUE); + } } } - -} - - -void nsTableFrame::AddColumnFrame (nsTableColFrame *aColFrame) -{ - nsCellMap *cellMap = GetCellMap(); - NS_PRECONDITION (nsnull!=cellMap, "null cellMap."); - if (nsnull!=cellMap) - { - cellMap->AppendColumnFrame(aColFrame); - } } /** return the index of the next row that is not yet assigned */ @@ -770,72 +678,430 @@ nsCellMap * nsTableFrame::GetCellMap() const return mCellMap; } -PRInt32 nsTableFrame::AddCellToTable(nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex) +// XXX this needs to be moved to nsCSSFrameConstructor +nsTableColGroupFrame* +nsTableFrame::CreateAnonymousColGroupFrame(nsIPresContext& aPresContext, + nsTableColGroupType aColGroupType) { - NS_ASSERTION(nsnull != aCellFrame, "bad aCellFrame arg"); - NS_ASSERTION(nsnull != mCellMap, "bad cellMap"); + nsCOMPtr colGroupContent; + GetContent(getter_AddRefs(colGroupContent)); - // XXX: must be called only on first-in-flow! - return mCellMap->AppendCell(aCellFrame, aRowIndex); + nsCOMPtr colGroupStyle; + aPresContext.ResolvePseudoStyleContextFor(colGroupContent, + nsHTMLAtoms::tableColGroupPseudo, + mStyleContext, + PR_FALSE, + getter_AddRefs(colGroupStyle)); + // Create a col group frame + nsIFrame* newFrame; + nsCOMPtr presShell; + aPresContext.GetShell(getter_AddRefs(presShell)); + nsresult result = NS_NewTableColGroupFrame(presShell, &newFrame); + if (NS_SUCCEEDED(result) && newFrame) { + ((nsTableColGroupFrame *)newFrame)->SetType(aColGroupType); + newFrame->Init(&aPresContext, colGroupContent, this, colGroupStyle, nsnull); + } + return (nsTableColGroupFrame *)newFrame; } -void nsTableFrame::RemoveCellFromTable(nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex) +void +nsTableFrame::CreateAnonymousColFrames(nsIPresContext& aPresContext, + PRInt32 aNumColsToAdd, + nsTableColType aColType, + PRBool aDoAppend, + nsIFrame* aPrevColIn) +{ + // get the last col group frame + nsTableColGroupFrame* colGroupFrame = nsnull; + nsIFrame* childFrame = mColGroups.FirstChild(); + while (childFrame) { + nsIAtom* frameType = nsnull; + childFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableColGroupFrame == frameType) { + colGroupFrame = (nsTableColGroupFrame *)childFrame; + } + childFrame->GetNextSibling(&childFrame); + NS_IF_RELEASE(frameType); + } + + nsTableColGroupType lastColGroupType = eColGroupContent; + nsTableColGroupType newColGroupType = eColGroupContent; + if (colGroupFrame) { + lastColGroupType = colGroupFrame->GetType(); + } + if (eColAnonymousCell == aColType) { + if (eColGroupAnonymousCell != lastColGroupType) { + newColGroupType = eColGroupAnonymousCell; + } + } + else if (eColAnonymousCol == aColType) { + if (eColGroupAnonymousCol != lastColGroupType) { + newColGroupType = eColGroupAnonymousCol; + } + } + else { + NS_ASSERTION(PR_FALSE, "CreateAnonymousColFrames called incorrectly"); + return; + } + + if (eColGroupContent != newColGroupType) { + PRInt32 colIndex = (colGroupFrame) ? colGroupFrame->GetStartColumnIndex() + colGroupFrame->GetColCount() + : 0; + colGroupFrame = CreateAnonymousColGroupFrame(aPresContext, newColGroupType); + if (!colGroupFrame) { + return; + } + mColGroups.AppendFrame(this, colGroupFrame); // add the new frame to the child list + colGroupFrame->SetStartColumnIndex(colIndex); + } + + nsIFrame* prevCol = (aDoAppend) ? colGroupFrame->GetChildList().LastChild() : aPrevColIn; + + nsIFrame* firstNewFrame; + CreateAnonymousColFrames(aPresContext, *colGroupFrame, aNumColsToAdd, + aColType, PR_TRUE, prevCol, &firstNewFrame); +} + +// XXX this needs to be moved to nsCSSFrameConstructor +// Right now it only creates the col frames at the end +void +nsTableFrame::CreateAnonymousColFrames(nsIPresContext& aPresContext, + nsTableColGroupFrame& aColGroupFrame, + PRInt32 aNumColsToAdd, + nsTableColType aColType, + PRBool aAddToColGroupAndTable, + nsIFrame* aPrevFrameIn, + nsIFrame** aFirstNewFrame) +{ + *aFirstNewFrame = nsnull; + nsIFrame* lastColFrame = nsnull; + nsIFrame* childFrame; + + // Get the last col frame + aColGroupFrame.FirstChild(nsnull, &childFrame); + while (childFrame) { + nsIAtom* frameType = nsnull; + childFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableColFrame == frameType) { + lastColFrame = (nsTableColGroupFrame *)childFrame; + } + NS_IF_RELEASE(frameType); + childFrame->GetNextSibling(&childFrame); + } + + PRInt32 startIndex = mColFrames.Count(); + PRInt32 lastIndex = startIndex + aNumColsToAdd - 1; + + for (PRInt32 childX = startIndex; childX <= lastIndex; childX++) { + nsCOMPtr iContent; + nsCOMPtr styleContext; + + if ((aColType == eColAnonymousCol) && aPrevFrameIn) { + // a col due to a span in a previous col uses the style context of the col + aPrevFrameIn->GetStyleContext(getter_AddRefs(styleContext)); + } + else { + // all other anonymous cols use a pseudo style context of the col group + aColGroupFrame.GetContent(getter_AddRefs(iContent)); + aPresContext.ResolvePseudoStyleContextFor(iContent, nsHTMLAtoms::tableColPseudo, + styleContext, PR_FALSE, getter_AddRefs(styleContext)); + } + // create the new col frame + nsIFrame* colFrame; + nsCOMPtr presShell; + aPresContext.GetShell(getter_AddRefs(presShell)); + NS_NewTableColFrame(presShell, &colFrame); + ((nsTableColFrame *) colFrame)->SetType(aColType); + colFrame->Init(&aPresContext, iContent, &aColGroupFrame, + styleContext, nsnull); + colFrame->SetInitialChildList(&aPresContext, nsnull, nsnull); + ((nsTableColFrame *)colFrame)->SetType(aColType); + + // Add the col to the sibling chain + if (lastColFrame) { + lastColFrame->SetNextSibling(colFrame); + } + lastColFrame = colFrame; + if (childX == startIndex) { + *aFirstNewFrame = colFrame; + } + } + if (aAddToColGroupAndTable) { + nsFrameList& cols = aColGroupFrame.GetChildList(); + // the chain already exists, now add it to the col group child list + if (!aPrevFrameIn) { + cols.AppendFrames(&aColGroupFrame, *aFirstNewFrame); + } + // get the starting col index in the cache + PRInt32 startColIndex = aColGroupFrame.GetStartColumnIndex(); + if (aPrevFrameIn) { + nsTableColFrame* colFrame = + (nsTableColFrame*)nsTableFrame::GetFrameAtOrBefore((nsIFrame*)&aColGroupFrame, aPrevFrameIn, + nsLayoutAtoms::tableColFrame); + if (colFrame) { + startColIndex = colFrame->GetColIndex(); + } + } + aColGroupFrame.AddColsToTable(aPresContext, startColIndex, PR_TRUE, + *aFirstNewFrame, lastColFrame); + } +} + +PRInt32 nsTableFrame::AppendCell(nsIPresContext& aPresContext, + nsTableCellFrame& aCellFrame, + PRInt32 aRowIndex) +{ + PRInt32 colIndex = 0; + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + colIndex = cellMap->AppendCell(&aCellFrame, aRowIndex, PR_TRUE); + PRInt32 numColsInMap = GetColCount(); + PRInt32 numColsInCache = mColFrames.Count(); + PRInt32 numColsToAdd = numColsInMap - numColsInCache; + if (numColsToAdd > 0) { + // this sets the child list, updates the col cache and cell map + CreateAnonymousColFrames(aPresContext, numColsToAdd, eColAnonymousCell, PR_TRUE); + } + } + return colIndex; +} + +void nsTableFrame::InsertCells(nsIPresContext& aPresContext, + nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndexBefore) { nsCellMap* cellMap = GetCellMap(); - PRInt32 numCols = cellMap->GetColCount(); - cellMap->RemoveCell(aCellFrame, aRowIndex); - if (numCols != cellMap->GetColCount()) { - // XXX need to remove the anonymous col frames at the end - //nsTableColFrame* colFrame = nsnull; - //GetColumnFrame(colIndex, colFrame); - //if (colFrame && colFrame->IsAnonymous()) { - // nsTableColGroupFrame* colGroupFrame = nsnull; - //colFrame->GetParent((nsIFrame **)&colGroupFrame); - //if (colGroupFrame) { - // colGroupFrame->DeleteColFrame(aPresContext, colFrame); + if (cellMap) { + cellMap->InsertCells(aCellFrames, aRowIndex, aColIndexBefore); + PRInt32 numColsInMap = GetColCount(); + PRInt32 numColsInCache = mColFrames.Count(); + PRInt32 numColsToAdd = numColsInMap - numColsInCache; + if (numColsToAdd > 0) { + // this sets the child list, updates the col cache and cell map + CreateAnonymousColFrames(aPresContext, numColsToAdd, eColAnonymousCell, PR_TRUE); + } } } -static nsresult BuildCellMapForRowGroup(nsIFrame* rowGroupFrame) +// this removes the frames from the col group and table, but not the cell map +PRInt32 +nsTableFrame::DestroyAnonymousColFrames(nsIPresContext& aPresContext, + PRInt32 aNumFrames) { - nsresult rv = NS_OK; - nsIFrame *rowFrame; - rowGroupFrame->FirstChild(nsnull, &rowFrame); - for ( ; nsnull!=rowFrame; rowFrame->GetNextSibling(&rowFrame)) - { - const nsStyleDisplay *rowDisplay; - rowFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowDisplay); - if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) - { - rv = ((nsTableRowFrame *)rowFrame)->InitChildren(); - if (NS_FAILED(rv)) - return rv; + // only remove cols that are of type eTypeAnonymous cell (they are at the end) + PRInt32 endIndex = mColFrames.Count() - 1; + PRInt32 startIndex = (endIndex - aNumFrames) + 1; + PRInt32 numColsRemoved = 0; + for (PRInt32 colX = endIndex; colX >= startIndex; colX--) { + nsTableColFrame* colFrame = GetColFrame(colX); + if (colFrame && (eColAnonymousCell == colFrame->GetType())) { + nsTableColGroupFrame* cgFrame; + colFrame->GetParent((nsIFrame**)&cgFrame); + // remove the frame from the colgroup + cgFrame->RemoveChild(aPresContext, *colFrame, PR_FALSE); + // remove the frame from the cache, but not the cell map + RemoveCol(aPresContext, nsnull, colX, PR_TRUE, PR_FALSE); + numColsRemoved++; } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP==rowDisplay->mDisplay) - { - BuildCellMapForRowGroup(rowFrame); + else { + break; } } - return rv; + return (aNumFrames - numColsRemoved); } -NS_METHOD nsTableFrame::ReBuildCellMap() +void nsTableFrame::RemoveCell(nsIPresContext& aPresContext, + nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex) { - nsresult rv=NS_OK; - nsIFrame *rowGroupFrame=mFrames.FirstChild(); - for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(&rowGroupFrame)) - { - const nsStyleDisplay *rowGroupDisplay; - rowGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowGroupDisplay); - if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay)) - { - BuildCellMapForRowGroup(rowGroupFrame); + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + cellMap->RemoveCell(aCellFrame, aRowIndex); + PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols + PRInt32 numColsInCache = mColFrames.Count(); + PRInt32 numColsNotRemoved = DestroyAnonymousColFrames(aPresContext, numColsInCache - numColsInMap); + // if the cell map has fewer cols than the cache, correct it + if (numColsNotRemoved > 0) { + cellMap->AddColsAtEnd(numColsNotRemoved); } } - mBits.mCellMapValid=PR_TRUE; - return rv; +} + +// this cannot extend beyond a single row group +void nsTableFrame::AppendRows(nsIPresContext& aPresContext, + nsVoidArray& aRowFrames) +{ + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + PRInt32 rowIndex = cellMap->GetRowCount(); + InsertRows(aPresContext, aRowFrames, rowIndex, PR_TRUE); + } +} + +PRInt32 +nsTableFrame::InsertRow(nsIPresContext& aPresContext, + nsIFrame& aRowFrame, + PRInt32 aRowIndex, + PRBool aConsiderSpans) +{ + nsVoidArray rows; + rows.AppendElement(&aRowFrame); + return InsertRows(aPresContext, rows, aRowIndex, aConsiderSpans); +} + +// this cannot extend beyond a single row group +PRInt32 +nsTableFrame::InsertRows(nsIPresContext& aPresContext, + nsVoidArray& aRowFrames, + PRInt32 aRowIndex, + PRBool aConsiderSpans) +{ + //printf("insertRowsBefore firstRow=%d \n", aRowIndex); + //Dump(PR_TRUE, PR_FALSE, PR_TRUE); + + PRInt32 numColsToAdd = 0; + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + PRInt32 origNumRows = cellMap->GetRowCount(); + PRInt32 numNewRows = aRowFrames.Count(); + cellMap->InsertRows(aRowFrames, aRowIndex, aConsiderSpans); + PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols + PRInt32 numColsInCache = mColFrames.Count(); + numColsToAdd = numColsInMap - numColsInCache; + if (numColsToAdd > 0) { + // this sets the child list, updates the col cache and cell map + CreateAnonymousColFrames(aPresContext, numColsToAdd, eColAnonymousCell, + PR_TRUE); + } + if (aRowIndex < origNumRows) { + PRInt32 numNewRows = aRowFrames.Count(); + AdjustRowIndices(aRowIndex, numNewRows); + } + // assign the correct row indices to the new rows. If they were adjusted above + // it may not have been done correctly because each row is constructed with index 0 + for (PRInt32 rowX = 0; rowX < numNewRows; rowX++) { + nsTableRowFrame* rowFrame = (nsTableRowFrame *) aRowFrames.ElementAt(rowX); + rowFrame->SetRowIndex(aRowIndex + rowX); + } + } + + //printf("insertRowsAfter \n"); + //Dump(PR_TRUE, PR_FALSE, PR_TRUE); + + return numColsToAdd; +} + +// this cannot extend beyond a single row group +void nsTableFrame::RemoveRows(nsIPresContext& aPresContext, + PRInt32 aFirstRowIndex, + PRInt32 aNumRowsToRemove, + PRBool aConsiderSpans) +{ + //printf("removeRowsBefore firstRow=%d numRows=%d\n", aFirstRowIndex, aNumRowsToRemove); + //Dump(PR_TRUE, PR_FALSE, PR_TRUE); + + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + cellMap->RemoveRows(aFirstRowIndex, aNumRowsToRemove, aConsiderSpans); + // only remove cols that are of type eTypeAnonymous cell (they are at the end) + PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols + PRInt32 numColsInCache = mColFrames.Count(); + PRInt32 numColsNotRemoved = DestroyAnonymousColFrames(aPresContext, numColsInCache - numColsInMap); + // if the cell map has fewer cols than the cache, correct it + if (numColsNotRemoved > 0) { + cellMap->AddColsAtEnd(numColsNotRemoved); + } + } + AdjustRowIndices(aFirstRowIndex, -aNumRowsToRemove); + //printf("removeRowsAfter\n"); + //Dump(PR_TRUE, PR_FALSE, PR_TRUE); +} + +void nsTableFrame::AppendRowGroups(nsIPresContext& aPresContext, + nsIFrame* aFirstRowGroupFrame) +{ + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + PRInt32 rowIndex = cellMap->GetRowCount(); + InsertRowGroups(aPresContext, aFirstRowGroupFrame, rowIndex); + } +} + +nsTableRowGroupFrame* +nsTableFrame::GetRowGroupFrame(nsIFrame* aFrame, + nsIAtom* aFrameTypeIn) +{ + nsIFrame* rgFrame = nsnull; + nsIAtom* frameType = aFrameTypeIn; + if (!aFrameTypeIn) { + aFrame->GetFrameType(&frameType); + } + if (nsLayoutAtoms::tableRowGroupFrame == frameType) { + rgFrame = aFrame; + } + else if (nsLayoutAtoms::scrollFrame == frameType) { + nsIScrollableFrame* scrollable = nsnull; + nsresult rv = aFrame->QueryInterface(kIScrollableFrameIID, (void **)&scrollable); + if (NS_SUCCEEDED(rv) && (scrollable)) { + nsIFrame* scrolledFrame; + scrollable->GetScrolledFrame(nsnull, scrolledFrame); + if (scrolledFrame) { + nsIAtom* scrolledType; + scrolledFrame->GetFrameType(&scrolledType); + if (nsLayoutAtoms::tableRowGroupFrame == scrolledType) { + rgFrame = scrolledFrame; + } + NS_IF_RELEASE(scrolledType); + } + } + } + if (!aFrameTypeIn) { + NS_IF_RELEASE(frameType); + } + return (nsTableRowGroupFrame*)rgFrame; +} + +// collect the rows ancestors of aFrame +void +nsTableFrame::CollectRows(nsIFrame* aFrame, + nsVoidArray& aCollection) +{ + if (!aFrame) return; + nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aFrame); + if (rgFrame) { + nsIFrame* childFrame = nsnull; + rgFrame->FirstChild(nsnull, &childFrame); + while (childFrame) { + nsIAtom* childType; + childFrame->GetFrameType(&childType); + if (nsLayoutAtoms::tableRowFrame == childType) { + aCollection.AppendElement(childFrame); + } + else { + CollectRows(childFrame, aCollection); + } + NS_IF_RELEASE(childType); + childFrame->GetNextSibling(&childFrame); + } + } +} + +void +nsTableFrame::InsertRowGroups(nsIPresContext& aPresContext, + nsIFrame* aFirstRowGroupFrame, + PRInt32 aRowIndex) +{ + nsCellMap* cellMap = GetCellMap(); + if (cellMap) { + // collect the new row frames in an array + nsVoidArray rows; + for (nsIFrame* kidFrame = aFirstRowGroupFrame; kidFrame; kidFrame->GetNextSibling(&kidFrame)) { + CollectRows(kidFrame, rows); + } + + InsertRows(aPresContext, rows, aRowIndex, PR_TRUE); + } } /* ***** Column Layout Data methods ***** */ @@ -1037,14 +1303,12 @@ PRBool nsTableFrame::NeedsReflow(const nsHTMLReflowState& aReflowState) if (mBits.mIsInvariantWidth) { result = PR_FALSE; - } else if ((eReflowReason_Incremental == aReflowState.reason) && (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight)) { // If it's an incremental reflow and we're in galley mode, then only // do a full reflow if we need to. We need to if the cell map is invalid, // or the column info is invalid, or if we need to do a pass-1 reflow - result = !(IsCellMapValid() && IsFirstPassValid() && - IsColumnCacheValid() && IsColumnWidthsValid()); + result = !(IsFirstPassValid() && IsColumnWidthsValid()); } return result; } @@ -1213,12 +1477,6 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, { if (nsDebugTable::gRflTable) nsTableFrame::DebugReflow("T::Rfl en", this, &aReflowState, nsnull); - // this is a temporary fix to prevent a recent crash due to incremental content - // sink changes. this will go away when the col cache and cell map are synchronized - if (!IsColumnCacheValid()) { - CacheColFrames(aPresContext, PR_TRUE); - } - // Initialize out parameter if (nsnull != aDesiredSize.maxElementSize) { aDesiredSize.maxElementSize->width = 0; @@ -1238,22 +1496,12 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, } // NeedsReflow and IsFirstPassValid take into account reflow type = Initial_Reflow - if (PR_TRUE==NeedsReflow(aReflowState)) - { - PRBool needsRecalc=PR_FALSE; - if (eReflowReason_Initial!=aReflowState.reason && PR_FALSE==IsCellMapValid()) - { - if (nsnull!=mCellMap) - delete mCellMap; - mCellMap = new nsCellMap(0,0); - ReBuildCellMap(); - needsRecalc=PR_TRUE; - } + if (NeedsReflow(aReflowState)) { + PRBool needsRecalc = PR_FALSE; if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) || - (PR_FALSE==IsFirstPassValid())) - { + (PR_FALSE==IsFirstPassValid())) { nsReflowReason reason = aReflowState.reason; - if (eReflowReason_Initial!=reason) + if (eReflowReason_Initial != reason) reason = eReflowReason_Resize; if (mBorderCollapser) { mBorderCollapser->ComputeVerticalBorders(aPresContext, 0, -1); @@ -1261,33 +1509,15 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, rv = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus, nsnull, reason, PR_TRUE); if (NS_FAILED(rv)) return rv; - needsRecalc=PR_TRUE; + needsRecalc = PR_TRUE; } - if (PR_FALSE==IsColumnCacheValid()) - { - needsRecalc=PR_TRUE; - } - if (PR_TRUE==needsRecalc) - { - CacheColFrames(aPresContext, PR_TRUE); - // if we needed to rebuild the column cache, the data stored in the layout strategy is invalid - if (nsnull!=mTableLayoutStrategy) - { - mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount(), aReflowState.mComputedWidth); - mBits.mColumnWidthsValid=PR_TRUE; //so we don't do this a second time below - } - } - if (PR_FALSE==IsColumnWidthsValid()) - { - if (nsnull!=mTableLayoutStrategy) - { - mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, GetColCount(), aReflowState.mComputedWidth); - mBits.mColumnWidthsValid=PR_TRUE; - } + if (mTableLayoutStrategy && (needsRecalc || !IsColumnWidthsValid())) { + mTableLayoutStrategy->Initialize(aDesiredSize.maxElementSize, aReflowState.mComputedWidth); + mBits.mColumnWidthsValid = PR_TRUE; //so we don't do this a second time below } - if (nsnull==mPrevInFlow) - { // only do this for a first-in-flow table frame + if (!mPrevInFlow) { + // only do this for a first-in-flow table frame // assign column widths, and assign aMaxElementSize->width BalanceColumnWidths(aPresContext, aReflowState, nsSize(aReflowState.availableWidth, aReflowState.availableHeight), aDesiredSize.maxElementSize); @@ -1328,8 +1558,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, Invalidate(aPresContext, damageRect); } } - else - { + else { // set aDesiredSize and aMaxElementSize } @@ -1943,7 +2172,7 @@ nsTableFrame::CalculateStartingColumnIndexFor(nsTableColGroupFrame* aColGroupFra colGroupFrame && (colGroupFrame != aColGroupFrame); colGroupFrame->GetNextSibling((nsIFrame**)&colGroupFrame)) { - index += colGroupFrame->GetColumnCount(); + index += colGroupFrame->GetColCount(); } return index; @@ -1955,11 +2184,11 @@ nsTableFrame::AppendFrames(nsIPresContext* aPresContext, nsIAtom* aListName, nsIFrame* aFrameList) { - PRInt32 startingColIndex = -1; - + PRInt32 startColIndex = 0; // Because we actually have two child lists, one for col group frames and one // for everything else, we need to look at each frame individually nsIFrame* f = aFrameList; + nsIFrame* firstAppendedColGroup = nsnull; while (f) { nsIFrame* next; @@ -1974,21 +2203,20 @@ nsTableFrame::AppendFrames(nsIPresContext* aPresContext, if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) { // Append the new col group frame mColGroups.AppendFrame(nsnull, f); - - // Set its starting column index - if (-1 == startingColIndex) { - startingColIndex = CalculateStartingColumnIndexFor((nsTableColGroupFrame*)f); + if (!firstAppendedColGroup) { + firstAppendedColGroup = f; + nsIFrame* lastChild = mFrames.LastChild(); + nsTableColGroupFrame* lastColGroup = + (nsTableColGroupFrame*)GetFrameAtOrBefore(this, lastChild, nsLayoutAtoms::tableColGroupFrame); + startColIndex = (lastColGroup) + ? lastColGroup->GetStartColumnIndex() + lastColGroup->GetColCount() : 0; } - ((nsTableColGroupFrame*)f)->SetStartColumnIndex(startingColIndex); - startingColIndex += ((nsTableColGroupFrame *)f)->GetColumnCount(); - } else if (IsRowGroup(display->mDisplay)) { - // Append the new row group frame - mFrames.AppendFrame(nsnull, f); - - // Add the content of the row group to the cell map - DidAppendRowGroup((nsTableRowGroupFrame*)f); + // insert the rows into the table + InsertRowGroups(*aPresContext, aFrameList, GetRowCount()); + // Append the new row group frame to the sibling chain + mFrames.AppendFrame(nsnull, f); } else { // Nothing special to do, just add the frame to our child list mFrames.AppendFrame(nsnull, f); @@ -1998,18 +2226,17 @@ nsTableFrame::AppendFrames(nsIPresContext* aPresContext, f = next; } - // We'll need to do a pass-1 layout of all cells in all the rows of the - // rowgroup - InvalidateFirstPassCache(); - - // If we've added any columns, we need to rebuild the column cache. - InvalidateColumnCache(); - - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - InvalidateColumnWidths(); + if (firstAppendedColGroup) { + InsertColGroups(*aPresContext, startColIndex, firstAppendedColGroup); + } + // We'll need to do a pass-1 layout of all cells in all the rows of the + // rowgroup. XXX - fix this + InvalidateFirstPassCache(); + + // Because the number of columns may have changed invalidate them + InvalidateColumnWidths(); + // Mark the table as dirty and generate a reflow command targeted at the // outer table frame nsIReflowCommand* reflowCmd; @@ -2023,7 +2250,7 @@ nsTableFrame::AppendFrames(nsIPresContext* aPresContext, NS_RELEASE(reflowCmd); } - return rv; + return NS_OK; } NS_IMETHODIMP @@ -2048,38 +2275,42 @@ nsTableFrame::InsertFrames(nsIPresContext* aPresContext, if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) { // Insert the column group frame + nsFrameList frames(aFrameList); // convience for getting last frame + nsIFrame* lastFrame = frames.LastChild(); mColGroups.InsertFrame(nsnull, aPrevFrame, aFrameList); - - // Set its starting column index and adjust the index of the - // col group frames that follow - SetStartingColumnIndexFor((nsTableColGroupFrame*)aFrameList, - CalculateStartingColumnIndexFor((nsTableColGroupFrame*)aFrameList)); - + // find the starting col index for the first new col group + PRInt32 startColIndex = 0; + if (aPrevFrame) { + nsTableColGroupFrame* prevColGroup = + (nsTableColGroupFrame*)GetFrameAtOrBefore(this, aPrevFrame, nsLayoutAtoms::tableColGroupFrame); + if (prevColGroup) { + startColIndex = prevColGroup->GetStartColumnIndex() + prevColGroup->GetColCount(); + } + } + InsertColGroups(*aPresContext, startColIndex, aFrameList, lastFrame); } else if (IsRowGroup(display->mDisplay)) { - // Insert the frame + // get the starting row index of the new rows and insert them into the table + PRInt32 rowIndex = 0; + nsTableRowGroupFrame* prevRowGroup = (nsTableRowGroupFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsLayoutAtoms::tableRowGroupFrame); + if (prevRowGroup) { + PRInt32 numRows; + prevRowGroup->GetRowCount(numRows); + rowIndex = prevRowGroup->GetStartRowIndex() + numRows; + } + InsertRowGroups(*aPresContext, aFrameList, rowIndex); + + // Insert the frames in the sibling chain mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList); - - // We'll need to do a pass-1 layout of all cells in all the rows of the - // rowgroup - InvalidateFirstPassCache(); - - // We need to rebuild the cell map, because currently we can't insert - // new frames except at the end (append) - InvalidateCellMap(); - } else { // Just insert the frame and don't worry about reflowing it mFrames.InsertFrame(nsnull, aPrevFrame, aFrameList); return NS_OK; } - // If we've added any columns, we need to rebuild the column cache. - InvalidateColumnCache(); + // Because the number of columns may have changed invalidate them + InvalidateColumnWidths(); - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - InvalidateColumnWidths(); + InvalidateFirstPassCache(); // XXX fix this // Mark the table as dirty and generate a reflow command targeted at the // outer table frame @@ -2094,6 +2325,8 @@ nsTableFrame::InsertFrames(nsIPresContext* aPresContext, NS_RELEASE(reflowCmd); } return rv; + + return NS_OK; } NS_IMETHODIMP @@ -2109,32 +2342,53 @@ nsTableFrame::RemoveFrame(nsIPresContext* aPresContext, if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) { nsIFrame* nextColGroupFrame; aOldFrame->GetNextSibling(&nextColGroupFrame); - - // Remove the col group frame + nsTableColGroupFrame* colGroup = (nsTableColGroupFrame*)aOldFrame; + PRInt32 firstColIndex = colGroup->GetStartColumnIndex(); + PRInt32 lastColIndex = firstColIndex + colGroup->GetColCount() - 1; + // remove the col frames, the colGroup frame and reset col indices + colGroup->RemoveChildrenAtEnd(*aPresContext, colGroup->GetColCount()); mColGroups.DestroyFrame(aPresContext, aOldFrame); + nsTableColGroupFrame::ResetColIndices(nextColGroupFrame, firstColIndex); + // remove the cols from the table + PRInt32 colX; + for (colX = lastColIndex; colX >= firstColIndex; colX--) { + nsTableColFrame* colFrame = (nsTableColFrame*)mColFrames.ElementAt(colX); + if (colFrame) { + RemoveCol(*aPresContext, colGroup, colX, PR_TRUE, PR_FALSE); + } + } + for (colX = lastColIndex; colX >= firstColIndex; colX--) { + nsTableColFrame* colFrame = (nsTableColFrame*)mColFrames.ElementAt(colX); + if (colFrame) { + RemoveCol(*aPresContext, colGroup, colX, PR_FALSE, PR_TRUE); + } + } - // Adjust the starting column index of the frames that follow - SetStartingColumnIndexFor((nsTableColGroupFrame*)nextColGroupFrame, - CalculateStartingColumnIndexFor((nsTableColGroupFrame*)nextColGroupFrame)); + PRInt32 numAnonymousColsToAdd = GetColCount() - mColFrames.Count(); + if (numAnonymousColsToAdd > 0) { + // this sets the child list, updates the col cache and cell map + CreateAnonymousColFrames(*aPresContext, numAnonymousColsToAdd, + eColAnonymousCell, PR_TRUE); + } + InvalidateColumnWidths(); } else if (IsRowGroup(display->mDisplay)) { + // remove the rows from the table + nsTableRowGroupFrame* rgFrame = (nsTableRowGroupFrame *) aOldFrame; + PRInt32 firstRowIndex = rgFrame->GetStartRowIndex(); + PRInt32 numRows; + rgFrame->GetRowCount(numRows); + RemoveRows(*aPresContext, firstRowIndex, numRows, PR_TRUE); + + // remove the row group frame from the sibling chain mFrames.DestroyFrame(aPresContext, aOldFrame); - // We need to rebuild the cell map, because currently we can't incrementally - // remove rows - InvalidateCellMap(); - + InvalidateColumnWidths(); } else { // Just remove the frame mFrames.DestroyFrame(aPresContext, aOldFrame); return NS_OK; } - - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - InvalidateColumnCache(); - // Because the number of columns may have changed invalidate the column // cache. Note that this has the side effect of recomputing the column // widths, so we don't need to call InvalidateColumnWidths() @@ -2200,6 +2454,29 @@ NS_METHOD nsTableFrame::IncrementalReflow(nsIPresContext* aPresContext, return rv; } +// this assumes the dirty children are contiguous +PRBool GetDirtyChildren(nsIFrame* aFrame, + nsIFrame** aFirstDirty, + PRInt32& aNumDirty) +{ + *aFirstDirty = nsnull; + aNumDirty = 0; + + nsIFrame* kidFrame; + aFrame->FirstChild(nsnull, &kidFrame); + while (kidFrame) { + nsFrameState frameState; + kidFrame->GetFrameState(&frameState); + if (frameState & NS_FRAME_IS_DIRTY) { + if (!*aFirstDirty) { + *aFirstDirty = kidFrame; + } + aNumDirty++; + } + } + return (aNumDirty > 0); +} + NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, InnerTableReflowState& aReflowState, @@ -2226,13 +2503,24 @@ NS_METHOD nsTableFrame::IR_TargetIsMe(nsIPresContext* aPresContext, break; case nsIReflowCommand::ReflowDirty: - // Problem is we don't know has changed, so assume the worst - InvalidateCellMap(); - InvalidateFirstPassCache(); - InvalidateColumnCache(); - InvalidateColumnWidths(); - rv = NS_OK; - break; + { + //nsIFrame* dirtyChild; + //PRInt32 numDirty; + //if (GetDirtyChildren(this, &dirtyChild, numDirty)) { + // for (PRInt32 dirtyX = 0; dirtyX < numDirty; dirtyX++) { + // ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus, + // dirtyChild, reason, PR_FALSE); + // dirtyChild->GetNextSibling(&dirtyChild); + // } + //} + //else { + // Problem is we don't know has changed, so assume the worst + InvalidateFirstPassCache(); + //} + InvalidateColumnWidths(); + rv = NS_OK; + break; + } default: NS_NOTYETIMPLEMENTED("unexpected reflow command type"); @@ -2893,13 +3181,13 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, mTableLayoutStrategy = new FixedTableLayoutStrategy(this); else mTableLayoutStrategy = new BasicTableLayoutStrategy(this, eCompatibility_NavQuirks == mode); - mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount(), aReflowState.mComputedWidth); + mTableLayoutStrategy->Initialize(aMaxElementSize, aReflowState.mComputedWidth); mBits.mColumnWidthsValid=PR_TRUE; } // fixed-layout tables need to reinitialize the layout strategy. When there are scroll bars // reflow gets called twice and the 2nd time has the correct space available. else if (!RequiresPass1Layout()) { - mTableLayoutStrategy->Initialize(aMaxElementSize, GetColCount(), aReflowState.mComputedWidth); + mTableLayoutStrategy->Initialize(aMaxElementSize, aReflowState.mComputedWidth); } mTableLayoutStrategy->BalanceColumnWidths(mStyleContext, aReflowState, maxWidth); @@ -2959,14 +3247,6 @@ void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext) nsRect tableSize = mRect; tableSize.width = tableWidth; - // account for scroll bars. XXX needs optimization/caching - if (mBits.mHasScrollableRowGroup) { - float sbWidth, sbHeight; - nsCOMPtr dc; - aPresContext->GetDeviceContext(getter_AddRefs(dc)); - dc->GetScrollBarDimensions(sbWidth, sbHeight); - tableSize.width += NSToCoordRound(sbWidth); - } SetRect(aPresContext, tableSize); } @@ -2984,7 +3264,7 @@ nscoord GetVerticalMarginBorderPadding(nsIFrame* aFrame, const nsIID& aIID) rv = iContent->QueryInterface(aIID, (void **)&htmlContent); if (htmlContent && NS_SUCCEEDED(rv)) { nsIStyleContext* styleContext; - aFrame->GetStyleContext(&styleContext); + aFrame->GetStyleContext(&styleContext); // XXX fix this leak const nsStyleSpacing* spacing = (const nsStyleSpacing*)styleContext->GetStyleData(eStyleStruct_Spacing); nsMargin margin(0,0,0,0); @@ -3287,8 +3567,9 @@ NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aCol nsCellMap *cellMap = GetCellMap(); if (nsnull!=cellMap) { // hooray, we get to do this the easy way because the info is cached - aColFrame = cellMap->GetColumnFrame(aColIndex); + aColFrame = (nsTableColFrame *)mColFrames.ElementAt(aColIndex); } + // XXX this should go away with the new synchronized col cache. else { // ah shucks, we have to go hunt for the column frame brute-force style nsIFrame *childFrame = mColGroups.FirstChild(); @@ -3302,7 +3583,7 @@ NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aCol PRInt32 colGroupStartingIndex = ((nsTableColGroupFrame *)childFrame)->GetStartColumnIndex(); if (aColIndex >= colGroupStartingIndex) { // the cell's col might be in this col group - PRInt32 colCount = ((nsTableColGroupFrame *)childFrame)->GetColumnCount(); + PRInt32 colCount = ((nsTableColGroupFrame *)childFrame)->GetColCount(); if (aColIndex < colGroupStartingIndex + colCount) { // yep, we've found it. GetColumnAt gives us the column at the offset colCount, not the absolute colIndex for the whole table aColFrame = ((nsTableColGroupFrame *)childFrame)->GetColumnAt(colCount); @@ -3322,45 +3603,6 @@ PRBool nsTableFrame::IsColumnWidthsSet() return (PRBool)firstInFlow->mBits.mColumnWidthsSet; } - -void nsTableFrame::CacheColFrames(nsIPresContext* aPresContext, - PRBool aReset) -{ - NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); - NS_ASSERTION(nsnull!=mCellMap, "never ever call me until the cell map is built!"); - - if (aReset) { - PRBool createdColFrames; - EnsureColumns(aPresContext, createdColFrames); - mCellMap->ClearColumnCache(); - } - - nsIFrame * childFrame = mColGroups.FirstChild(); - while (nsnull != childFrame) { // in this loop, we cache column info - nsTableColFrame* colFrame = nsnull; - childFrame->FirstChild(nsnull, (nsIFrame **)&colFrame); - while (nsnull != colFrame) { - const nsStyleDisplay* colDisplay; - colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); - if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) { - PRInt32 colIndex = colFrame->GetColumnIndex(); - PRInt32 repeat = colFrame->GetSpan(); - for (PRInt32 i=0; iGetColumnFrame(colIndex+i); - if (nsnull==cachedColFrame) { - mCellMap->AppendColumnFrame(colFrame); - } - colIndex++; - } - } - colFrame->GetNextSibling((nsIFrame **)&colFrame); - } - childFrame->GetNextSibling(&childFrame); - } - - mBits.mColumnCacheValid=PR_TRUE; -} - PRBool nsTableFrame::ColumnsCanBeInvalidatedBy(nsStyleCoord* aPrevStyleWidth, const nsTableCellFrame& aCellFrame) const { @@ -3389,7 +3631,8 @@ PRBool nsTableFrame::ColumnsAreValidFor(const nsTableCellFrame& aCellFrame, } return PR_FALSE; } - + +// XXX This could be more incremental void nsTableFrame::InvalidateColumnWidths() { nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); @@ -3418,65 +3661,6 @@ void nsTableFrame::InvalidateFirstPassCache() firstInFlow->mBits.mFirstPassValid=PR_FALSE; } -PRBool nsTableFrame::IsColumnCacheValid() const -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - return (PRBool)firstInFlow->mBits.mColumnCacheValid; -} - -void nsTableFrame::InvalidateColumnCache() -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - firstInFlow->mBits.mColumnCacheValid=PR_FALSE; -} - -PRBool nsTableFrame::IsCellMapValid() const -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - return (PRBool)firstInFlow->mBits.mCellMapValid; -} - -static void InvalidateCellMapForRowGroup(nsIFrame* aRowGroupFrame) -{ - nsIFrame *rowFrame; - aRowGroupFrame->FirstChild(nsnull, &rowFrame); - for ( ; nsnull!=rowFrame; rowFrame->GetNextSibling(&rowFrame)) - { - const nsStyleDisplay *rowDisplay; - rowFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowDisplay); - if (NS_STYLE_DISPLAY_TABLE_ROW==rowDisplay->mDisplay) - { - ((nsTableRowFrame *)rowFrame)->ResetInitChildren(); - } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP==rowDisplay->mDisplay) - { - InvalidateCellMapForRowGroup(rowFrame); - } - } - -} - -void nsTableFrame::InvalidateCellMap() -{ - nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); - NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); - firstInFlow->mBits.mCellMapValid=PR_FALSE; - // reset the state in each row - nsIFrame *rowGroupFrame=mFrames.FirstChild(); - for ( ; nsnull!=rowGroupFrame; rowGroupFrame->GetNextSibling(&rowGroupFrame)) - { - const nsStyleDisplay *rowGroupDisplay; - rowGroupFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)rowGroupDisplay); - if (PR_TRUE==IsRowGroup(rowGroupDisplay->mDisplay)) - { - InvalidateCellMapForRowGroup(rowGroupFrame); - } - } -} - PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex) { nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); @@ -3937,35 +4121,18 @@ nsTableFrame::GetFrameName(nsString& aResult) const #endif // This assumes that aFrame is a scroll frame if -// XXX make this a macro if it becomes an issue -// XXX it has the side effect of setting mHasScrollableRowGroup nsTableRowGroupFrame* nsTableFrame::GetRowGroupFrameFor(nsIFrame* aFrame, const nsStyleDisplay* aDisplay) { nsIFrame* result = nsnull; -/* - if (IsRowGroup(aDisplay->mDisplay)) { - nsresult rv = aFrame->QueryInterface(kITableRowGroupFrameIID, (void **)&result); - if (NS_SUCCEEDED(rv) && (nsnull != result)) { - ; - } else { // it is a scroll frame that contains the row group frame - aFrame->FirstChild(nsnull, &result); - mBits.mHasScrollableRowGroup = PR_TRUE; - } - } -*/ - // ok this code looks to see if it is a scrollable frame. If it is it asks it for the scrolled // frame that should be the row group frame. -EDV nsIScrollableFrame* scrollable = nsnull; nsresult rv = aFrame->QueryInterface(kIScrollableFrameIID, (void **)&scrollable); if (NS_SUCCEEDED(rv) && (nsnull != scrollable)) { scrollable->GetScrolledFrame(nsnull, result); - - // this is scary? Why do we need this. - mBits.mHasScrollableRowGroup = PR_TRUE; } else { result = aFrame; } @@ -3980,15 +4147,109 @@ nsTableFrame::IsFinalPass(const nsHTMLReflowState& aState) (NS_UNCONSTRAINEDSIZE != aState.availableHeight); } -void nsTableFrame::Dump(PRBool aDumpCols, PRBool aDumpCellMap) +// Find the closet sibling before aPriorChildFrame (including aPriorChildFrame) that +// is of type aChildType +nsIFrame* +nsTableFrame::GetFrameAtOrBefore(nsIFrame* aParentFrame, + nsIFrame* aPriorChildFrame, + nsIAtom* aChildType) { - printf("***START TABLE DUMP***, \n colWidths="); - PRInt32 colX; + nsIFrame* result = nsnull; + if (!aPriorChildFrame) { + return result; + } + nsIAtom* frameType; + aPriorChildFrame->GetFrameType(&frameType); + if (aChildType == frameType) { + NS_RELEASE(frameType); + return (nsTableCellFrame*)aPriorChildFrame; + } + NS_IF_RELEASE(frameType); + + // aPriorChildFrame is not of type aChildType, so we need start from + // the beginnng and find the closest one + nsIFrame* childFrame; + nsIFrame* lastMatchingFrame = nsnull; + aParentFrame->FirstChild(nsnull, &childFrame); + while (childFrame != aPriorChildFrame) { + childFrame->GetFrameType(&frameType); + if (aChildType == frameType) { + lastMatchingFrame = childFrame; + } + NS_IF_RELEASE(frameType); + childFrame->GetNextSibling(&childFrame); + } + return (nsTableCellFrame*)lastMatchingFrame; +} + +void +nsTableFrame::DumpRowGroup(nsIFrame* aKidFrame) +{ + nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aKidFrame); + if (rgFrame) { + nsIFrame* rowFrame; + rgFrame->FirstChild(nsnull, &rowFrame); + while (rowFrame) { + nsIAtom* rowType; + rowFrame->GetFrameType(&rowType); + if (nsLayoutAtoms::tableRowFrame == rowType) { + printf("row(%d)=%p ", ((nsTableRowFrame*)rowFrame)->GetRowIndex(), rowFrame); + nsIFrame* cellFrame; + rowFrame->FirstChild(nsnull, &cellFrame); + while (cellFrame) { + nsIAtom* cellType; + cellFrame->GetFrameType(&cellType); + if (nsLayoutAtoms::tableCellFrame == cellType) { + PRInt32 colIndex; + ((nsTableCellFrame*)cellFrame)->GetColIndex(colIndex); + printf("cell(%d)=%p ", colIndex, cellFrame); + } + NS_IF_RELEASE(cellType); + cellFrame->GetNextSibling(&cellFrame); + } + printf("\n"); + } + else { + DumpRowGroup(rowFrame); + } + NS_IF_RELEASE(rowType); + rowFrame->GetNextSibling(&rowFrame); + } + } +} + +void nsTableFrame::Dump(PRBool aDumpRows, + PRBool aDumpCols, + PRBool aDumpCellMap) +{ + printf("***START TABLE DUMP*** \n"); + // dump the columns widths array + printf("mColWidths="); PRInt32 numCols = GetColCount(); + PRInt32 colX; for (colX = 0; colX < numCols; colX++) { printf("%d ", mColumnWidths[colX]); } + printf("\n"); + + if (aDumpRows) { + nsIFrame* kidFrame = mFrames.FirstChild(); + while (kidFrame) { + DumpRowGroup(kidFrame); + kidFrame->GetNextSibling(&kidFrame); + } + } + if (aDumpCols) { + // output col frame cache + printf("\n col frame cache ->"); + for (colX = 0; colX < numCols; colX++) { + nsTableColFrame* colFrame = (nsTableColFrame *)mColFrames.ElementAt(colX); + if (0 == (colX % 8)) { + printf("\n"); + } + printf ("%d=%p ", colX, colFrame); + } for (colX = 0; colX < numCols; colX++) { printf("\n"); nsTableColFrame* colFrame = GetColFrame(colX); @@ -3996,7 +4257,6 @@ void nsTableFrame::Dump(PRBool aDumpCols, PRBool aDumpCellMap) } } if (aDumpCellMap) { - printf("\n"); nsCellMap* cellMap = GetCellMap(); #ifdef NS_DEBUG cellMap->Dump(); @@ -4236,12 +4496,6 @@ NS_IMETHODIMP nsTableFrame::GetTableSize(PRInt32& aRowCount, PRInt32& aColCount) /*---------------- end of nsITableLayout implementation ------------------*/ -PRInt32 nsTableFrame::GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const -{ - nsCellMap* cellMap = GetCellMap(); - return cellMap->GetNumCellsOriginatingInRow(aRowIndex); -} - PRInt32 nsTableFrame::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const { nsCellMap* cellMap = GetCellMap(); @@ -4371,6 +4625,11 @@ nsTableFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const mCellMap->SizeOf(aHandler, &cellMapSize); aHandler->AddSize(nsLayoutAtoms::cellMap, cellMapSize); + // Add in size of col cache + PRUint32 voidArraySize; + mColFrames.SizeOf(aHandler, &voidArraySize); + sum += voidArraySize - sizeof(mColFrames); + // Add in size of table layout strategy PRUint32 strategySize; mTableLayoutStrategy->SizeOf(aHandler, &strategySize); diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h index fea1f1560e2..44d90099671 100644 --- a/mozilla/layout/tables/nsTableFrame.h +++ b/mozilla/layout/tables/nsTableFrame.h @@ -43,6 +43,8 @@ class nsHTMLValue; struct InnerTableReflowState; struct nsStylePosition; struct nsStyleSpacing; +enum nsTableColType; +enum nsTableColGroupType; /** * Child list name indices @@ -124,8 +126,14 @@ public: /** helper method to find the table parent of any table frame object */ // TODO: today, this depends on display types. This should be changed to rely // on stronger criteria, like an inner table frame atom - static NS_METHOD GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aTableFrame); + static NS_METHOD GetTableFrame(nsIFrame* aSourceFrame, + nsTableFrame*& aTableFrame); + // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) + // of type aChildType. + static nsIFrame* nsTableFrame::GetFrameAtOrBefore(nsIFrame* aParentFrame, + nsIFrame* aPriorChildFrame, + nsIAtom* aChildType); /** * @param aReflowState the context within which we're to determine the table width info * @param aSpecifiedTableWidth [OUT] if the table is not auto-width, @@ -143,10 +151,6 @@ public: PRBool IsRowGroup(PRInt32 aDisplayType) const; /** Initialize the table frame with a set of children. - * Calls DidAppendRowGroup which calls nsTableRowFrame::InitChildren - * which finally calls back into this table frame to build the cell map. - * Also ensures we have the right number of column frames for the child list. - * * @see nsIFrame::SetInitialChildList */ NS_IMETHOD SetInitialChildList(nsIPresContext* aPresContext, @@ -162,16 +166,6 @@ public: NS_IMETHOD GetAdditionalChildListName(PRInt32 aIndex, nsIAtom** aListName) const; - /** complete the append of aRowGroupFrame to the table - * this builds the cell map by calling nsTableRowFrame::InitChildren - * which calls back into this table frame to build the cell map. - * @param aRowGroupFrame the row group that was appended. - * note that this method is optimized for content appended, and doesn't - * work for random insertion of row groups. Random insertion must go - * through incremental reflow notifications. - */ - NS_IMETHOD DidAppendRowGroup(nsTableRowGroupFrame *aRowGroupFrame); - /** @see nsIFrame::Paint */ NS_IMETHOD Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, @@ -221,6 +215,8 @@ public: */ NS_METHOD GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame); + nsFrameList& GetColGroups(); + /** return PR_TRUE if the column width information has been set */ PRBool IsColumnWidthsSet(); @@ -308,14 +304,84 @@ public: */ PRInt32 GetNextAvailRowIndex() const; - /** build as much of the CellMap as possible from the info we have so far - */ - virtual PRInt32 AddCellToTable (nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex); - virtual void RemoveCellFromTable (nsTableCellFrame* aCellFrame, - PRInt32 aRowIndex); + /** return the column frame associated with aColIndex */ + nsTableColFrame* GetColFrame(PRInt32 aColIndex) const; - virtual void AddColumnFrame (nsTableColFrame *aColFrame); + void InsertCol(nsIPresContext& aPresContext, + nsTableColFrame& aColFrame, + PRInt32 aColIndex); + + nsTableColGroupFrame* CreateAnonymousColGroupFrame(nsIPresContext& aPresContext, + nsTableColGroupType aType); + + PRInt32 DestroyAnonymousColFrames(nsIPresContext& aPresContext, + PRInt32 aNumFrames); + + void CreateAnonymousColFrames(nsIPresContext& aPresContext, + PRInt32 aNumColsToAdd, + nsTableColType aColType, + PRBool aDoAppend, + nsIFrame* aPrevCol = nsnull); + + void CreateAnonymousColFrames(nsIPresContext& aPresContext, + nsTableColGroupFrame& aColGroupFrame, + PRInt32 aNumColsToAdd, + nsTableColType aColType, + PRBool aAddToColGroupAndTable, + nsIFrame* aPrevCol, + nsIFrame** aFirstNewFrame); + + /** empty the column frame cache */ + void ClearColCache(); + + virtual PRInt32 AppendCell(nsIPresContext& aPresContext, + nsTableCellFrame& aCellFrame, + PRInt32 aRowIndex); + + virtual void InsertCells(nsIPresContext& aPresContext, + nsVoidArray& aCellFrames, + PRInt32 aRowIndex, + PRInt32 aColIndexBefore); + + virtual void RemoveCell(nsIPresContext& aPresContext, + nsTableCellFrame* aCellFrame, + PRInt32 aRowIndex); + + void AppendRows(nsIPresContext& aPresContext, + nsVoidArray& aRowFrames); + + PRInt32 InsertRow(nsIPresContext& aPresContext, + nsIFrame& aFrame, + PRInt32 aRowIndex, + PRBool aConsiderSpans); + + PRInt32 InsertRows(nsIPresContext& aPresContext, + nsVoidArray& aFrames, + PRInt32 aRowIndex, + PRBool aConsiderSpans); + + virtual void RemoveRows(nsIPresContext& aPresContext, + PRInt32 aFirstRowFrame, + PRInt32 aNumRowsToRemove, + PRBool aConsiderSpans); + + void AppendRowGroups(nsIPresContext& aPresContext, + nsIFrame* aFirstRowGroupFrame); + + void InsertRowGroups(nsIPresContext& aPresContext, + nsIFrame* aFirstRowGroupFrame, + PRInt32 aRowIndex); + + void InsertColGroups(nsIPresContext& aPresContext, + PRInt32 aColIndex, + nsIFrame* aFirstFrame, + nsIFrame* aLastFrame = nsnull); + + virtual void RemoveCol(nsIPresContext& aPresContext, + nsTableColGroupFrame* aColGroupFrame, + PRInt32 aColIndex, + PRBool aRemoveFromCache, + PRBool aRemoveFromCellMap); static PRBool IsFinalPass(const nsHTMLReflowState& aReflowState); @@ -323,7 +389,7 @@ public: PRInt32 aColX, PRBool* aOriginates = nsnull, PRInt32* aColSpan = nsnull); - PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const; + PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const; NS_METHOD GetBorderPlusMarginPadding(nsMargin& aResult); @@ -554,9 +620,6 @@ protected: /** returns PR_TRUE if the cached pass 1 data is still valid */ virtual PRBool IsFirstPassValid() const; - /** returns PR_TRUE if the cached column info is still valid */ - virtual PRBool IsColumnCacheValid() const; - /** returns PR_TRUE if the cached column info is still valid */ virtual PRBool IsColumnWidthsValid() const; @@ -612,8 +675,6 @@ public: virtual void InvalidateFirstPassCache(); - virtual void InvalidateColumnCache(); - virtual void InvalidateColumnWidths(); protected: @@ -623,38 +684,18 @@ protected: void MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBorderWidth); PRBool ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult); - /** returns PR_TRUE if the cached pass 1 data is still valid */ - virtual PRBool IsCellMapValid() const; - public: /** Get the cell map for this table frame. It is not always mCellMap. * Only the firstInFlow has a legit cell map */ virtual nsCellMap *GetCellMap() const; - - /** ResetCellMap is called when the cell structure of the table is changed. - * Call with caution, only when changing the structure of the table such as - * inserting or removing rows, changing the rowspan or colspan attribute of a cell, etc. - */ - virtual void InvalidateCellMap(); - /** sum the columns represented by all nsTableColGroup objects. - * if the cell map says there are more columns than this, - * add extra implicit columns to the content tree. - * - * returns whether any implicit column frames were created - */ - virtual void EnsureColumns (nsIPresContext* aPresContext, - PRBool& aCreatedColFrames); - - // These methods are used to incrementally insert and remove rows - // from the cell map without having to invalidate the entire map. - NS_IMETHOD InsertRowIntoMap(nsTableRowFrame* aRow, PRInt32 aRowIndex); - NS_IMETHOD RemoveRowFromMap(nsTableRowFrame* aRow, PRInt32 aRowIndex); + void AdjustRowIndices(PRInt32 aRowIndex, + PRInt32 aAdjustment); NS_IMETHOD AdjustRowIndices(nsIFrame* aRowGroup, - PRInt32 aRowIndex, - PRInt32 anAdjustment); + PRInt32 aRowIndex, + PRInt32 anAdjustment); // Return PR_TRUE if rules=groups is set for the table content PRBool HasGroupRules() const; @@ -662,9 +703,9 @@ public: // Remove cell borders which aren't bordering row and/or col groups void ProcessGroupRules(nsIPresContext* aPresContext); + nsVoidArray& GetColCache(); + protected: - /** iterates all child frames and creates a new cell map */ - NS_IMETHOD ReBuildCellMap(); void SetColumnDimensions(nsIPresContext* aPresContext, nscoord aHeight); @@ -685,7 +726,14 @@ protected: /** * Return aFrame's child if aFrame is an nsScrollFrame, otherwise return aFrame */ - nsTableRowGroupFrame* GetRowGroupFrameFor(nsIFrame* aFrame, const nsStyleDisplay* aDisplay); + nsTableRowGroupFrame* GetRowGroupFrameFor(nsIFrame* aFrame, + const nsStyleDisplay* aDisplay); + + nsTableRowGroupFrame* GetRowGroupFrame(nsIFrame* aFrame, + nsIAtom* aFrameTypeIn = nsnull); + + void CollectRows(nsIFrame* aFrame, + nsVoidArray& aCollection); public: /* ----- Cell Map public methods ----- */ @@ -752,14 +800,16 @@ public: /* ----- Cell Map public methods ----- */ /*------------end of nsITableLayout methods -----------------------*/ - - virtual void CacheColFrames(nsIPresContext* aPresContext, - PRBool aReset = PR_FALSE); public: static nsIAtom* gColGroupAtom; - void Dump(PRBool aDumpCols, PRBool aDumpCellMap); + void Dump(PRBool aDumpRows, + PRBool aDumpCols, + PRBool aDumpCellMap); + + nsVoidArray mColFrames; // XXX temporarily public protected: + void DumpRowGroup(nsIFrame* aChildFrame); void DebugPrintCount() const; // Debugging routine // data members @@ -770,15 +820,11 @@ protected: unsigned mColumnWidthsSet:1; // PR_TRUE if column widths have been set at least once unsigned mColumnWidthsValid:1; // PR_TRUE if column width data is still legit, PR_FALSE if it needs to be recalculated unsigned mFirstPassValid:1; // PR_TRUE if first pass data is still legit, PR_FALSE if it needs to be recalculated - unsigned mColumnCacheValid:1; // PR_TRUE if column cache info is still legit, PR_FALSE if it needs to be recalculated - unsigned mCellMapValid:1; // PR_TRUE if cell map data is still legit, PR_FALSE if it needs to be recalculated unsigned mIsInvariantWidth:1; // PR_TRUE if table width cannot change - unsigned mHasScrollableRowGroup:1; // PR_TRUE if any section has overflow == "auto" or "scroll" unsigned mNonPercentSpansPercent:1; - int : 24; // unused + int : 26; // unused } mBits; - PRInt32 mColCount; // the number of columns in this table nsCellMap* mCellMap; // maintains the relationships between rows, cols, and cells nsITableLayoutStrategy * mTableLayoutStrategy; // the layout strategy for this frame nsFrameList mColGroups; // the list of colgroup frames @@ -811,6 +857,16 @@ inline void nsTableFrame::SetHasNonPercentSpanningPercent(PRBool aValue) mBits.mNonPercentSpansPercent = (unsigned)aValue; } +inline nsFrameList& nsTableFrame::GetColGroups() +{ + return mColGroups; +} + +inline nsVoidArray& nsTableFrame::GetColCache() +{ + return mColFrames; +} + enum nsTableIteration { eTableLTR = 0, eTableRTL = 1, diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index 3aedfc98fe5..26a593e6af2 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -56,6 +56,7 @@ nsTableRowFrame::nsTableRowFrame() mAllBits(0) { mBits.mMinRowSpan = 1; + mBits.mRowIndex = 0; } NS_IMETHODIMP @@ -129,23 +130,11 @@ nsTableRowFrame::AppendFrames(nsIPresContext* aPresContext, if (NS_STYLE_DISPLAY_TABLE_CELL == display->mDisplay) { // Add the cell to the cell map - PRInt32 colIndex = tableFrame->AddCellToTable((nsTableCellFrame*)childFrame, - GetRowIndex()); - - // Initialize the cell frame and give it its column index - ((nsTableCellFrame*)childFrame)->InitCellFrame(colIndex); + tableFrame->AppendCell(*aPresContext, (nsTableCellFrame&)*childFrame, GetRowIndex()); } } - // See if any implicit column frames need to be created as a result of - // adding the new rows - PRBool createdColFrames; - tableFrame->EnsureColumns(aPresContext, createdColFrames); - if (createdColFrames) { - // We need to rebuild the column cache - // XXX It would be nice if this could be done incrementally - tableFrame->InvalidateColumnCache(); - } + tableFrame->InvalidateColumnWidths(); // Reflow the new frames. They're already marked dirty, so generate a reflow // command that tells us to reflow our dirty child frames @@ -160,6 +149,7 @@ nsTableRowFrame::AppendFrames(nsIPresContext* aPresContext, return NS_OK; } + NS_IMETHODIMP nsTableRowFrame::InsertFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, @@ -171,26 +161,39 @@ nsTableRowFrame::InsertFrames(nsIPresContext* aPresContext, nsTableFrame* tableFrame = nsnull; nsTableFrame::GetTableFrame(this, tableFrame); - // Insert the frames + // gather the new frames (only those which are cells) into an array + nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsLayoutAtoms::tableCellFrame); + nsVoidArray cellChildren; + for (nsIFrame* childFrame = aFrameList; childFrame; childFrame->GetNextSibling(&childFrame)) { + nsIAtom* frameType; + childFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableCellFrame == frameType) { + cellChildren.AppendElement(childFrame); + } + NS_IF_RELEASE(frameType); + } + // insert the cells into the cell map + PRInt32 colIndex = -1; + if (prevCellFrame) { + prevCellFrame->GetColIndex(colIndex); + } + tableFrame->InsertCells(*aPresContext, cellChildren, GetRowIndex(), colIndex); + + // Insert the frames in the frame list mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); - // We need to rebuild the cell map, because currently we can't insert - // new frames except at the end (append) - tableFrame->InvalidateCellMap(); + // Because the number of columns may have changed invalidate the column widths + tableFrame->InvalidateColumnWidths(); - // We should try and avoid doing a pass1 reflow on all the cells and just - // do it for the newly added frames, but we need to add these frames to the - // cell map before we reflow them - tableFrame->InvalidateFirstPassCache(); + // Reflow the new frames. They're already marked dirty, so generate a reflow + // command that tells us to reflow our dirty child frames + nsIReflowCommand* reflowCmd; - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - tableFrame->InvalidateColumnCache(); - - // Generate a reflow command so we reflow the table itself. This will - // do a pass-1 reflow of all the rows including any rows we just added - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); + if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, + nsIReflowCommand::ReflowDirty))) { + aPresShell.AppendReflowCommand(reflowCmd); + NS_RELEASE(reflowCmd); + } return NS_OK; } @@ -203,91 +206,28 @@ nsTableRowFrame::RemoveFrame(nsIPresContext* aPresContext, // Get the table frame nsTableFrame* tableFrame=nsnull; nsTableFrame::GetTableFrame(this, tableFrame); + if (tableFrame) { + nsIAtom* frameType; + aOldFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableCellFrame == frameType) { + nsTableCellFrame* cellFrame = (nsTableCellFrame*)aOldFrame; + PRInt32 colIndex; + cellFrame->GetColIndex(colIndex); + tableFrame->RemoveCell(*aPresContext, cellFrame, GetRowIndex()); -#if 0 - // XXX Currently we can't incrementally remove cells from the cell map - PRInt32 colIndex; - aDeletedFrame->GetColIndex(colIndex); - tableFrame->RemoveCellFromTable(aOldFrame, GetRowIndex()); + // Remove the frame and destroy it + mFrames.DestroyFrame(aPresContext, aOldFrame); - // Remove the frame and destroy it - mFrames.DestroyFrame(aPresContext, (nsIFrame*)aOldFrame); + // cells have possibly shifted into different columns. + tableFrame->InvalidateColumnWidths(); - // XXX Reflow the row - -#else - // Remove the frame and destroy it - mFrames.DestroyFrame(aPresContext, aOldFrame); - - // We need to rebuild the cell map, because currently we can't incrementally - // remove rows - tableFrame->InvalidateCellMap(); - - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - tableFrame->InvalidateColumnCache(); - - // Because we haven't added any new frames we don't need to do a pass1 - // reflow. Just generate a reflow command so we reflow the table itself - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); -#endif - - return NS_OK; -} - -NS_IMETHODIMP -nsTableRowFrame::InitChildrenWithIndex(PRInt32 aRowIndex) -{ - nsTableFrame* table = nsnull; - nsresult result=NS_OK; - - // each child cell can only be added to the table one time. - // for now, we remember globally whether we've added all or none - if (0 == (mState & NS_TABLE_ROW_FRAME_INITIALIZED_CHILDREN)) - { - result = nsTableFrame::GetTableFrame(this, table); - if ((NS_OK==result) && (table != nsnull)) - { - mState |= NS_TABLE_ROW_FRAME_INITIALIZED_CHILDREN; - SetRowIndex(aRowIndex); - - for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) - { - const nsStyleDisplay *kidDisplay; - kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) - { - // add the cell frame to the table's cell map and get its col index - PRInt32 colIndex; - colIndex = table->AddCellToTable((nsTableCellFrame *)kidFrame, aRowIndex); - // what column does this cell belong to? - // this sets the frame's notion of its column index - ((nsTableCellFrame *)kidFrame)->InitCellFrame(colIndex); - } - } + // Because we haven't added any new frames we don't need to do a pass1 + // reflow. Just generate a reflow command so we reflow the table itself + AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); } + NS_IF_RELEASE(frameType); } - return NS_OK; -} -NS_IMETHODIMP -nsTableRowFrame::InitChildren() -{ - nsTableFrame* table = nsnull; - nsresult result=NS_OK; - - // each child cell can only be added to the table one time. - // for now, we remember globally whether we've added all or none - if (0 == (mState & NS_TABLE_ROW_FRAME_INITIALIZED_CHILDREN)) - { - result = nsTableFrame::GetTableFrame(this, table); - if ((NS_OK==result) && (table != nsnull)) - { - PRInt32 rowIndex = table->GetNextAvailRowIndex(); - InitChildrenWithIndex(rowIndex); - } - } return NS_OK; } diff --git a/mozilla/layout/tables/nsTableRowFrame.h b/mozilla/layout/tables/nsTableRowFrame.h index 413af3ba959..bef9656dce0 100644 --- a/mozilla/layout/tables/nsTableRowFrame.h +++ b/mozilla/layout/tables/nsTableRowFrame.h @@ -62,9 +62,6 @@ struct RowReflowState { /** * Additional frame-state bits */ -#define NS_TABLE_ROW_FRAME_INITIALIZED_CHILDREN 0x80000000 // set if child cells have been - // added to the table - #define NS_TABLE_MAX_ROW_INDEX (1<<19) /** @@ -100,12 +97,6 @@ public: nsIAtom* aListName, nsIFrame* aOldFrame); - /** Initialization of data */ - NS_IMETHOD InitChildren(); - NS_IMETHOD InitChildrenWithIndex(PRInt32 aRowIndex); - - void ResetInitChildren(); - /** instantiate a new instance of nsTableRowFrame. * @param aResult the new object is returned in this out-param * @param aContent the table object to map @@ -322,11 +313,6 @@ inline void nsTableRowFrame::SetRowIndex (int aRowIndex) mBits.mRowIndex = aRowIndex; } -inline void nsTableRowFrame::ResetInitChildren() -{ - mState &= ~NS_TABLE_ROW_FRAME_INITIALIZED_CHILDREN; -} - inline void nsTableRowFrame::GetMaxElementSize(nsSize& aMaxElementSize) const { aMaxElementSize.width = mMaxElementSize.width; diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index 7c1992aa787..2d40d577ee0 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -565,6 +565,7 @@ NS_METHOD nsTableRowGroupFrame::PullUpAllRowFrames(nsIPresContext* aPresContext) void nsTableRowGroupFrame::GetNextRowSibling(nsIFrame** aRowFrame) { + if (!*aRowFrame) return; GetNextFrame(*aRowFrame, aRowFrame); while(*aRowFrame) { const nsStyleDisplay *display; @@ -596,7 +597,9 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, PRBool hasRowSpanningCell = PR_FALSE; PRInt32 numRows; GetRowCount(numRows, PR_FALSE); + if (numRows <= 0) return; nscoord *rowHeights = new nscoord[numRows]; + if (!rowHeights) return; nsCRT::memset (rowHeights, 0, numRows*sizeof(nscoord)); /* Step 1: get the height of the tallest cell in the row and save it for @@ -747,10 +750,11 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, // If this is pass 2 then resize the row to its final size and move the // row's position if the previous rows have caused a shift if (1 == counter) { - nsRect rowBounds; - rowFrame->GetRect(rowBounds); + PRBool movedFrame = (deltaY != 0); + nsRect rowBounds; // Move the row to the correct position + rowFrame->GetRect(rowBounds); // added rowBounds.y += deltaY; // Adjust our running delta @@ -759,6 +763,17 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, // Resize the row to its final size and position rowBounds.height = rowHeights[rowIndex]; rowFrame->SetRect(aPresContext, rowBounds); + + if (movedFrame) { + // Make sure any views are positioned properly + nsIView* view; + rowFrame->GetView(aPresContext, &view); + if (view) { + nsContainerFrame::PositionFrameView(aPresContext, rowFrame, view); + } else { + nsContainerFrame::PositionChildViews(aPresContext, rowFrame); + } + } } rowIndex++; @@ -1155,45 +1170,47 @@ nsTableRowGroupFrame::AddTableDirtyReflowCommand(nsIPresContext* aPresContext, return rv; } +#if 0 + // Reflow the new frames. They're already marked dirty, so generate a reflow + // command that tells us to reflow our dirty child frames + nsIReflowCommand* reflowCmd; + + if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, + nsIReflowCommand::ReflowDirty))) { + aPresShell.AppendReflowCommand(reflowCmd); + NS_RELEASE(reflowCmd); + } +#endif + +// this does not get called for trees NS_IMETHODIMP nsTableRowGroupFrame::AppendFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aFrameList) { - // Get the table frame - nsTableFrame* tableFrame; - nsTableFrame::GetTableFrame(this, tableFrame); + // collect the new row frames in an array + nsVoidArray rows; + for (nsIFrame* rowFrame = aFrameList; rowFrame; rowFrame->GetNextSibling(&rowFrame)) { + nsIAtom* frameType; + rowFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableRowFrame == frameType) { + rows.AppendElement(rowFrame); + } + NS_IF_RELEASE(frameType); + } - // Append the frames + // Append the frames to the sibling chain mFrames.AppendFrames(nsnull, aFrameList); - const nsStyleDisplay *display; - aFrameList->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - // See if the newly appended rows are the last rows in the table. - // XXX is this the correct code path for nested row groups, considering that whitespace frames may exist currently - if ((NS_STYLE_DISPLAY_TABLE_ROW_GROUP != display->mDisplay) && NoRowsFollow()) { - // The rows we appended are the last rows in the table so incrementally - // add them to the cell map - PRBool haveRows = PR_FALSE; - for (nsIFrame* rowFrame = aFrameList; rowFrame; rowFrame->GetNextSibling(&rowFrame)) { - rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - if (NS_STYLE_DISPLAY_TABLE_ROW == display->mDisplay) { - DidAppendRow((nsTableRowFrame*)rowFrame); - haveRows = PR_TRUE; - } - } + if (rows.Count() > 0) { + nsTableFrame* tableFrame = nsnull; + nsTableFrame::GetTableFrame(this, tableFrame); + if (tableFrame) { + tableFrame->AppendRows(*aPresContext, rows); - if (haveRows) { - // See if any implicit column frames need to be created as a result of - // adding the new rows - PRBool createdColFrames; - tableFrame->EnsureColumns(aPresContext, createdColFrames); - if (createdColFrames) { - // We need to rebuild the column cache - // XXX It would be nice if this could be done incrementally - tableFrame->InvalidateColumnCache(); - } + // Because the number of columns may have changed invalidate the column widths + tableFrame->InvalidateColumnWidths(); // Reflow the new frames. They're already marked dirty, so generate a reflow // command that tells us to reflow our dirty child frames @@ -1205,29 +1222,12 @@ nsTableRowGroupFrame::AppendFrames(nsIPresContext* aPresContext, NS_RELEASE(reflowCmd); } } - } else { - // We need to rebuild the cell map, because currently we can't insert - // new frames except at the end (append) - tableFrame->InvalidateCellMap(); - - // We should try and avoid doing a pass1 reflow on all the cells and just - // do it for the newly added frames, but we need to add these frames to the - // cell map before we reflow them - tableFrame->InvalidateFirstPassCache(); - - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - tableFrame->InvalidateColumnCache(); - - // Generate a reflow command so we reflow the table itself. This will - // do a pass-1 reflow of all the rows including any rows we just added - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); } return NS_OK; } +// this does not get called for trees NS_IMETHODIMP nsTableRowGroupFrame::InsertFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, @@ -1235,65 +1235,76 @@ nsTableRowGroupFrame::InsertFrames(nsIPresContext* aPresContext, nsIFrame* aPrevFrame, nsIFrame* aFrameList) { - // Get the table frame - nsTableFrame* tableFrame = nsnull; - nsTableFrame::GetTableFrame(this, tableFrame); + // collect the new row frames in an array + nsVoidArray rows; + for (nsIFrame* rowFrame = aFrameList; rowFrame; rowFrame->GetNextSibling(&rowFrame)) { + nsIAtom* frameType; + rowFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableRowFrame == frameType) { + rows.AppendElement(rowFrame); + } + NS_IF_RELEASE(frameType); + } - // Insert the frames + // Insert the frames in the sibling chain mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); - // We need to rebuild the cell map, because currently we can't insert - // new frames except at the end (append) - tableFrame->InvalidateCellMap(); + if (rows.Count() > 0) { + nsTableFrame* tableFrame = nsnull; + nsTableFrame::GetTableFrame(this, tableFrame); + if (tableFrame) { + nsTableRowFrame* prevRow = (nsTableRowFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsLayoutAtoms::tableRowFrame); + PRInt32 rowIndex = (prevRow) ? prevRow->GetRowIndex() : 0; + tableFrame->InsertRows(*aPresContext, rows, rowIndex, PR_TRUE); - // We should try and avoid doing a pass1 reflow on all the cells and just - // do it for the newly added frames, but we need to add these frames to the - // cell map before we reflow them - tableFrame->InvalidateFirstPassCache(); + // Reflow the new frames. They're already marked dirty, so generate a reflow + // command that tells us to reflow our dirty child frames + nsIReflowCommand* reflowCmd; - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - tableFrame->InvalidateColumnCache(); + if (NS_SUCCEEDED(NS_NewHTMLReflowCommand(&reflowCmd, this, + nsIReflowCommand::ReflowDirty))) { + aPresShell.AppendReflowCommand(reflowCmd); + NS_RELEASE(reflowCmd); + } + + // Because the number of columns may have changed invalidate the column widths + tableFrame->InvalidateColumnWidths(); + + // Generate a reflow command so we reflow the table itself. This will + // do a pass-1 reflow of all the rows including any rows we just added + AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); + } + } - // Generate a reflow command so we reflow the table itself. This will - // do a pass-1 reflow of all the rows including any rows we just added - AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); return NS_OK; } +// this does not get called for trees NS_IMETHODIMP nsTableRowGroupFrame::RemoveFrame(nsIPresContext* aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aOldFrame) { - const nsStyleDisplay *display; - aOldFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); - PRBool validChild = (NS_STYLE_DISPLAY_TABLE_ROW == display->mDisplay) || - (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == display->mDisplay); + nsTableFrame* tableFrame = nsnull; + nsTableFrame::GetTableFrame(this, tableFrame); + if (tableFrame) { + nsIAtom* frameType; + aOldFrame->GetFrameType(&frameType); + if (nsLayoutAtoms::tableRowFrame == frameType) { + PRInt32 firstRowIndex = ((nsTableRowFrame *)aOldFrame)->GetRowIndex(); - // Remove the frame and destroy it - if (mFrames.DestroyFrame(aPresContext, aOldFrame)) { - if (validChild) { - // Get the table frame - nsTableFrame* tableFrame = nsnull; - nsTableFrame::GetTableFrame(this, tableFrame); - - // We need to rebuild the cell map, because currently we can't incrementally - // remove rows - tableFrame->InvalidateCellMap(); - - // Because the number of columns may have changed invalidate the column - // cache. Note that this has the side effect of recomputing the column - // widths, so we don't need to call InvalidateColumnWidths() - tableFrame->InvalidateColumnCache(); + tableFrame->RemoveRows(*aPresContext, firstRowIndex, 1, PR_TRUE); + // Because the number of columns may have changed invalidate the column widths + tableFrame->InvalidateColumnWidths(); // Because we haven't added any new frames we don't need to do a pass1 // reflow. Just generate a reflow command so we reflow the table itself AddTableDirtyReflowCommand(aPresContext, aPresShell, tableFrame); } + NS_IF_RELEASE(frameType); } + mFrames.DestroyFrame(aPresContext, aOldFrame); return NS_OK; } @@ -1350,54 +1361,6 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext* aPresContext, return rv; } -NS_METHOD nsTableRowGroupFrame::DidAppendRow(nsTableRowFrame *aRowFrame) -{ - nsresult rv=NS_OK; - /* need to make space in the cell map. Remeber that row spans can't cross row groups - once the space is made, tell the row to initizalize its children. - it will automatically find the row to initialize into. - but this is tough because a cell in aInsertedFrame could have a rowspan - which must be respected if a subsequent row is appended. - */ - rv = aRowFrame->InitChildren(); - return rv; -} - -// support method that tells us if there are any rows in the table after our rows -// returns PR_TRUE if there are no rows after ours -PRBool nsTableRowGroupFrame::NoRowsFollow() -{ - // XXX This method doesn't play well with the tree widget. - PRBool result = PR_TRUE; - nsIFrame *nextSib=nsnull; - GetNextSibling(&nextSib); - while (nsnull!=nextSib) - { - const nsStyleDisplay *sibDisplay; - nextSib->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)sibDisplay)); - if ((NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == sibDisplay->mDisplay) || - (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == sibDisplay->mDisplay) || - (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == sibDisplay->mDisplay)) - { - nsIFrame *childFrame=nsnull; - nextSib->FirstChild(nsnull, &childFrame); - while (nsnull!=childFrame) - { - const nsStyleDisplay *childDisplay; - childFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { // found a row - result = PR_FALSE; - break; - } - childFrame->GetNextSibling(&childFrame); - } - } - nextSib->GetNextSibling(&nextSib); - } - return result; -} - NS_METHOD nsTableRowGroupFrame::GetHeightOfRows(nscoord& aResult) { // the rows in rowGroupFrame need to be expanded by rowHeightDelta[i] diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.h b/mozilla/layout/tables/nsTableRowGroupFrame.h index d1336651d59..da54198f00a 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.h +++ b/mozilla/layout/tables/nsTableRowGroupFrame.h @@ -244,10 +244,6 @@ protected: RowGroupReflowState& aReflowState, nsReflowStatus& aStatus); - NS_IMETHOD DidAppendRow(nsTableRowFrame *aRowFrame); - - PRBool NoRowsFollow(); - nsresult AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, RowGroupReflowState& aReflowState, nsIFrame* aKidFrame, diff --git a/mozilla/layout/xul/base/src/nsTreeFrame.cpp b/mozilla/layout/xul/base/src/nsTreeFrame.cpp index 60177f937bc..380ff98b6d0 100644 --- a/mozilla/layout/xul/base/src/nsTreeFrame.cpp +++ b/mozilla/layout/xul/base/src/nsTreeFrame.cpp @@ -498,8 +498,6 @@ NS_IMETHODIMP nsTreeFrame::MarkForDirtyReflow(nsIPresContext* aPresContext) { mSuppressReflow = PR_FALSE; - InvalidateCellMap(); - InvalidateColumnCache(); InvalidateFirstPassCache(); nsCOMPtr shell; aPresContext->GetShell(getter_AddRefs(shell)); diff --git a/mozilla/layout/xul/base/src/nsTreeRowFrame.cpp b/mozilla/layout/xul/base/src/nsTreeRowFrame.cpp index 4e8df3e63b8..34c2f7e2126 100644 --- a/mozilla/layout/xul/base/src/nsTreeRowFrame.cpp +++ b/mozilla/layout/xul/base/src/nsTreeRowFrame.cpp @@ -91,7 +91,7 @@ NS_METHOD nsTreeRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, nsTableFrame* tableFrame = nsnull; nsTableFrame::GetTableFrame(this, tableFrame); - tableFrame->InvalidateCellMap(); + tableFrame->InvalidateColumnWidths(); } } return rv; diff --git a/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.cpp b/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.cpp index b8dafaf65d3..19bffaf47b1 100644 --- a/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.cpp +++ b/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.cpp @@ -45,6 +45,28 @@ #include "nsIDOMEventReceiver.h" #include "nsIDOMDragListener.h" #include "nsTreeItemDragCapturer.h" +#include "nsLayoutAtoms.h" + +// I added the following function to improve keeping the frame +// chains in synch with the table. repackage as appropriate - karnaze +void GetRowStartAndCount(nsIFrame* aFrame, + PRInt32& aStartRowIndex, + PRInt32& aNumRows) +{ + aStartRowIndex = -1; + aNumRows = 0; + nsIAtom* fType; + aFrame->GetFrameType(&fType); + if (nsLayoutAtoms::tableRowFrame == fType) { + aStartRowIndex = ((nsTableRowFrame*)aFrame)->GetRowIndex(); + aNumRows = 0; + } + else if (nsLayoutAtoms::tableRowGroupFrame == fType) { + aStartRowIndex = ((nsTableRowGroupFrame*)aFrame)->GetStartRowIndex(); + ((nsTableRowGroupFrame*)aFrame)->GetRowCount(aNumRows); + } + NS_IF_RELEASE(fType); +} static nsILayoutHistoryState* GetStateStorageObject(nsTreeRowGroupFrame* aTreeRowGroupFrame, @@ -179,6 +201,7 @@ void nsTreeRowGroupFrame::DestroyRows(nsTableFrame* aTableFrame, nsIPresContext* // reduced. A reflow will then pick up and create the new frames. nsIFrame* childFrame = GetFirstFrame(); while (childFrame && rowsToLose > 0) { + PRBool rowIndex = -1; if (IsTableRowGroupFrame(childFrame)) { PRInt32 rowGroupCount; @@ -196,16 +219,18 @@ void nsTreeRowGroupFrame::DestroyRows(nsTableFrame* aTableFrame, nsIPresContext* { // Lost a row. rowsToLose--; - - // Remove this row from our cell map. - nsTableRowFrame* rowFrame = (nsTableRowFrame*)childFrame; - aTableFrame->RemoveRowFromMap(rowFrame, rowFrame->GetRowIndex()); + rowIndex = ((nsTableRowFrame*)childFrame)->GetRowIndex(); } nsIFrame* nextFrame; GetNextFrame(childFrame, &nextFrame); mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, childFrame, GetStateStorageObject(this, aTableFrame)); mFrames.DestroyFrame(aPresContext, childFrame); + // remove the row from the table after it is removed from the sibling chain + if (rowIndex >= 0) { + aTableFrame->RemoveRows(*aPresContext, rowIndex, 1, PR_FALSE); + aTableFrame->InvalidateColumnWidths(); + } mTopFrame = childFrame = nextFrame; } } @@ -216,6 +241,7 @@ void nsTreeRowGroupFrame::ReverseDestroyRows(nsTableFrame* aTableFrame, nsIPresC // reduced. A reflow will then pick up and create the new frames. nsIFrame* childFrame = GetLastFrame(); while (childFrame && rowsToLose > 0) { + PRInt32 rowIndex = -1; if (IsTableRowGroupFrame(childFrame)) { PRInt32 rowGroupCount; @@ -233,15 +259,18 @@ void nsTreeRowGroupFrame::ReverseDestroyRows(nsTableFrame* aTableFrame, nsIPresC { // Lost a row. rowsToLose--; - // Remove this row from our cell map. - nsTableRowFrame* rowFrame = (nsTableRowFrame*)childFrame; - aTableFrame->RemoveRowFromMap(rowFrame, rowFrame->GetRowIndex()); + rowIndex = ((nsTableRowFrame*)childFrame)->GetRowIndex(); } nsIFrame* prevFrame; prevFrame = mFrames.GetPrevSiblingFor(childFrame); mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, childFrame, GetStateStorageObject(this, aTableFrame)); mFrames.DestroyFrame(aPresContext, childFrame); + // remove the row from the table after it is removed from the sibling chain + if (rowIndex >= 0) { + aTableFrame->RemoveRows(*aPresContext, rowIndex, 1, PR_FALSE); + aTableFrame->InvalidateColumnWidths(); + } mBottomFrame = childFrame = prevFrame; } } @@ -714,9 +743,19 @@ nsTreeRowGroupFrame::PositionChanged(nsIPresContext* aPresContext, PRInt32 aOldI // Just blow away all our frames, but keep a content chain // as a hint to figure out how to build the frames. // Remove the scrollbar first. + // get the starting row index and row count + PRInt32 startRowIndex, numRows; + GetRowStartAndCount(this, startRowIndex, numRows); + mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, this, GetStateStorageObject(this, tableFrame)); mFrames.DestroyFrames(aPresContext); - tableFrame->InvalidateCellMap(); + + // remove the rows from the table after removing from the sibling chain + if ((startRowIndex >= 0) && (numRows > 0)) { + tableFrame->RemoveRows(*aPresContext, startRowIndex, rowCount, PR_FALSE); + tableFrame->InvalidateColumnWidths(); + } + nsCOMPtr topRowContent; FindRowContentAtIndex(aNewIndex, mContent, getter_AddRefs(topRowContent)); @@ -1189,9 +1228,11 @@ nsTreeRowGroupFrame::GetFirstFrameForReflow(nsIPresContext* aPresContext) FindPreviousRowContent(delta, rowContent, nsnull, getter_AddRefs(topRowContent)); - AddRowToMap(tableFrame, aPresContext, topRowContent, mTopFrame); - - PostAppendRow(mTopFrame, aPresContext); + PRInt32 numColsAdded = AddRowToMap(tableFrame, *aPresContext, topRowContent, mTopFrame); + if (numColsAdded > 0) { + MarkTreeAsDirty(aPresContext, (nsTreeFrame*) tableFrame); + } + //PostAppendRow(mTopFrame, aPresContext, aTableFrame->GetColCount()); } else if (IsTableRowGroupFrame(mTopFrame) && mContentChain) { // We have just instantiated a row group, and we have a content chain. This @@ -1268,8 +1309,11 @@ nsTreeRowGroupFrame::GetNextFrameForReflow(nsIPresContext* aPresContext, nsIFram nsCOMPtr topRowContent; PRInt32 delta = 1; FindPreviousRowContent(delta, nextContent, nsnull, getter_AddRefs(topRowContent)); - AddRowToMap(tableFrame, aPresContext, topRowContent, (*aResult)); - PostAppendRow(*aResult, aPresContext); + PRInt32 numColsAdded = AddRowToMap(tableFrame, *aPresContext, topRowContent, (*aResult)); + if (numColsAdded > 0) { + MarkTreeAsDirty(aPresContext, (nsTreeFrame*) tableFrame); + } + //PostAppendRow(*aResult, aPresContext, tableFrame->GetColCount()); } } } @@ -1296,7 +1340,6 @@ nsTreeRowGroupFrame::TreeAppendFrames(nsIFrame* aFrameList) return NS_OK; } - PRBool nsTreeRowGroupFrame::ContinueReflow(nsIPresContext* aPresContext, nscoord y, nscoord height) { //printf("Y is: %d\n", y); @@ -1316,10 +1359,23 @@ PRBool nsTreeRowGroupFrame::ContinueReflow(nsIPresContext* aPresContext, nscoord nsIFrame* currFrame; startingPoint->GetNextSibling(&currFrame); while (currFrame) { + // get the starting row index and row count + PRInt32 startRowIndex, numRows; + GetRowStartAndCount(currFrame, startRowIndex, numRows); + nsIFrame* nextFrame; currFrame->GetNextSibling(&nextFrame); mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, currFrame, nsnull); mFrames.DestroyFrame(aPresContext, currFrame); + + // remove the rows from the table after removing from the sibling chain + if ((startRowIndex >= 0) && (numRows > 0)) { + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + tableFrame->RemoveRows(*aPresContext, startRowIndex, numRows, PR_FALSE); + tableFrame->InvalidateColumnWidths(); + } + currFrame = nextFrame; //printf("Nuked one off the end.\n"); } @@ -1368,9 +1424,21 @@ void nsTreeRowGroupFrame::OnContentInserted(nsIPresContext* aPresContext, nsIFra currFrame->GetNextSibling(&nextFrame); mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, currFrame, GetStateStorageObject(this, NULL)); + // get the starting row index and row count + PRInt32 startRowIndex, numRows; + GetRowStartAndCount(currFrame, startRowIndex, numRows); + mFrames.DestroyFrame(aPresContext, currFrame); currFrame = nextFrame; //printf("Nuked one off the end.\n"); + + // remove the rows from the table after removing from the sibling chain + if ((startRowIndex >= 0) && (numRows > 0)) { + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + tableFrame->RemoveRows(*aPresContext, startRowIndex, numRows, PR_FALSE); + tableFrame->InvalidateColumnWidths(); + } } OnContentAdded(aPresContext); @@ -1439,10 +1507,18 @@ void nsTreeRowGroupFrame::OnContentRemoved(nsIPresContext* aPresContext, // Go ahead and delete the frame. if (aChildFrame) { + // get the starting row index and row count + PRInt32 startRowIndex, numRows; + GetRowStartAndCount(aChildFrame, startRowIndex, numRows); + mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, aChildFrame, nsnull); mFrames.DestroyFrame(aPresContext, aChildFrame); - treeFrame->InvalidateCellMap(); - treeFrame->InvalidateColumnCache(); + + // remove the rows from the table after removing from the sibling chain + if ((startRowIndex >= 0) && (numRows > 0)) { + treeFrame->RemoveRows(*aPresContext, startRowIndex, numRows, PR_FALSE); + treeFrame->InvalidateColumnWidths(); + } } MarkTreeAsDirty(aPresContext, treeFrame); @@ -1647,28 +1723,6 @@ nsTreeRowGroupFrame::GetCellFrameAtIndex(PRInt32 aRowIndex, PRInt32 aColIndex, #endif } -void nsTreeRowGroupFrame::PostAppendRow(nsIFrame* aRowFrame, nsIPresContext* aPresContext) -{ - // shouldn't need this anymore - // DidAppendRow((nsTableRowFrame*)aRowFrame); - - // Get the table frame. - nsTableFrame* tableFrame; - nsTableFrame::GetTableFrame(this, tableFrame); - - // See if any implicit column frames need to be created as a result of - // adding the new rows - PRBool createdColFrames; - tableFrame->EnsureColumns(aPresContext, createdColFrames); - if (createdColFrames) { - // We need to rebuild the column cache - // XXX It would be nice if this could be done incrementally - tableFrame->InvalidateColumnCache(); - - MarkTreeAsDirty(aPresContext, (nsTreeFrame*) tableFrame); - } -} - void nsTreeRowGroupFrame::ScrollByLines(nsIPresContext* aPresContext, PRInt32 lines) { @@ -1726,18 +1780,23 @@ nsTreeRowGroupFrame::MarkTreeAsDirty(nsIPresContext* aPresContext, nsTreeFrame* // given a content node, insert a row into the cellmap -// for wherever it belows in the map -void -nsTreeRowGroupFrame::AddRowToMap(nsTableFrame *aTableFrame, - nsIPresContext* aPresContext, - nsIContent *aContent, - nsIFrame* aCurrentFrame) +// for wherever it belows in the map. Return the number of new colums that were added +PRInt32 +nsTreeRowGroupFrame::AddRowToMap(nsTableFrame* aTableFrame, + nsIPresContext& aPresContext, + nsIContent* aContent, + nsIFrame* aCurrentFrame) { PRInt32 insertionIndex = - GetInsertionIndexForContent(aTableFrame, aPresContext, aContent); - - aTableFrame->InsertRowIntoMap((nsTableRowFrame*)aCurrentFrame, - insertionIndex); + GetInsertionIndexForContent(aTableFrame, &aPresContext, aContent); + + PRInt32 numNewCols = 0; + if (aCurrentFrame) { + numNewCols = aTableFrame->InsertRow(aPresContext, *aCurrentFrame, + insertionIndex, PR_FALSE); + } + + return numNewCols; } diff --git a/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.h b/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.h index 24a97183a82..d88cd941f23 100644 --- a/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.h +++ b/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.h @@ -150,10 +150,6 @@ protected: void ComputeTotalRowCount(PRInt32& rowCount, nsIContent* aParent); - void PostAppendRow(nsIFrame* aRowFrame, nsIPresContext* aPresContext); - - void GetFirstRow(nsTableRowFrame **aRowFrame); - public: // Helpers that allow access to info. The tree is the primary consumer of this // info. @@ -190,9 +186,11 @@ public: nsIPresContext* aPresContext, nsIContent *aContent); - void AddRowToMap(nsTableFrame *aTableFrame, - nsIPresContext* aPresContext, - nsIContent *aContent, nsIFrame *aCurrentFrame); + // Also returns the number of new columns that were added + PRInt32 AddRowToMap(nsTableFrame* aTableFrame, + nsIPresContext& aPresContext, + nsIContent* aContent, + nsIFrame* aCurrentFrame); static PRBool IsTableRowGroupFrame(nsIFrame*); static PRBool IsTableRowFrame(nsIFrame*);