diff --git a/mozilla/content/base/src/nsStyleContext.cpp b/mozilla/content/base/src/nsStyleContext.cpp index 350cc228cb8..87671f39ecb 100644 --- a/mozilla/content/base/src/nsStyleContext.cpp +++ b/mozilla/content/base/src/nsStyleContext.cpp @@ -530,6 +530,7 @@ void StyleTableImpl::ResetFrom(const nsStyleTable* aParent, nsIPresContext* aPre mRules = NS_STYLE_TABLE_RULES_NONE; mCellPadding.Reset(); mCellSpacing.Reset(); + mSpan=0; } diff --git a/mozilla/content/html/style/src/nsCSSParser.cpp b/mozilla/content/html/style/src/nsCSSParser.cpp index f6f6815f65c..6753d4a333b 100644 --- a/mozilla/content/html/style/src/nsCSSParser.cpp +++ b/mozilla/content/html/style/src/nsCSSParser.cpp @@ -1257,10 +1257,23 @@ static PRInt32 kDirectionKTable[] = { }; static PRInt32 kDisplayKTable[] = { - KEYWORD_NONE, NS_STYLE_DISPLAY_NONE, - KEYWORD_BLOCK, NS_STYLE_DISPLAY_BLOCK, - KEYWORD_INLINE, NS_STYLE_DISPLAY_INLINE, - KEYWORD_LIST_ITEM, NS_STYLE_DISPLAY_LIST_ITEM, + KEYWORD_NONE, NS_STYLE_DISPLAY_NONE, + KEYWORD_BLOCK, NS_STYLE_DISPLAY_BLOCK, + KEYWORD_INLINE, NS_STYLE_DISPLAY_INLINE, + KEYWORD_LIST_ITEM, NS_STYLE_DISPLAY_LIST_ITEM, + KEYWORD_MARKER, NS_STYLE_DISPLAY_MARKER, + KEYWORD_RUN_IN, NS_STYLE_DISPLAY_RUN_IN, + KEYWORD_COMPACT, NS_STYLE_DISPLAY_COMPACT, + KEYWORD_TABLE, NS_STYLE_DISPLAY_TABLE, + KEYWORD_INLINE_TABLE, NS_STYLE_DISPLAY_INLINE_TABLE, + KEYWORD_TABLE_ROW_GROUP, NS_STYLE_DISPLAY_TABLE_ROW_GROUP, + KEYWORD_TABLE_COLUMN, NS_STYLE_DISPLAY_TABLE_COLUMN, + KEYWORD_TABLE_COLUMN_GROUP, NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP, + KEYWORD_TABLE_HEADER_GROUP, NS_STYLE_DISPLAY_TABLE_HEADER_GROUP, + KEYWORD_TABLE_FOOTER_GROUP, NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP, + KEYWORD_TABLE_ROW, NS_STYLE_DISPLAY_TABLE_ROW, + KEYWORD_TABLE_CELL, NS_STYLE_DISPLAY_TABLE_CELL, + KEYWORD_TABLE_CAPTION, NS_STYLE_DISPLAY_TABLE_CAPTION, -1 }; diff --git a/mozilla/layout/base/public/nsIStyleContext.h b/mozilla/layout/base/public/nsIStyleContext.h index f1ffd561f92..46f09658b33 100644 --- a/mozilla/layout/base/public/nsIStyleContext.h +++ b/mozilla/layout/base/public/nsIStyleContext.h @@ -158,6 +158,7 @@ struct nsStyleTable: public nsStyleStruct { nsStyleCoord mCellPadding; // [reset] nsStyleCoord mCellSpacing; // [reset] PRInt32 mCols; // an integer if set, or see nsStyleConsts.h NS_STYLE_TABLE_COLS_* + PRInt32 mSpan; // the number of columns spanned by a colgroup protected: nsStyleTable(void); diff --git a/mozilla/layout/base/src/nsStyleConsts.h b/mozilla/layout/base/src/nsStyleConsts.h index f44ea220289..30fa853cc21 100644 --- a/mozilla/layout/base/src/nsStyleConsts.h +++ b/mozilla/layout/base/src/nsStyleConsts.h @@ -87,6 +87,19 @@ #define NS_STYLE_DISPLAY_BLOCK 1 #define NS_STYLE_DISPLAY_INLINE 2 #define NS_STYLE_DISPLAY_LIST_ITEM 3 +#define NS_STYLE_DISPLAY_MARKER 4 +#define NS_STYLE_DISPLAY_RUN_IN 5 +#define NS_STYLE_DISPLAY_COMPACT 6 +#define NS_STYLE_DISPLAY_TABLE 7 +#define NS_STYLE_DISPLAY_INLINE_TABLE 8 +#define NS_STYLE_DISPLAY_TABLE_ROW_GROUP 9 +#define NS_STYLE_DISPLAY_TABLE_COLUMN 10 +#define NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP 11 +#define NS_STYLE_DISPLAY_TABLE_HEADER_GROUP 12 +#define NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP 13 +#define NS_STYLE_DISPLAY_TABLE_ROW 14 +#define NS_STYLE_DISPLAY_TABLE_CELL 15 +#define NS_STYLE_DISPLAY_TABLE_CAPTION 16 // See nsStyleDisplay #define NS_STYLE_FLOAT_NONE 0 diff --git a/mozilla/layout/base/src/nsStyleContext.cpp b/mozilla/layout/base/src/nsStyleContext.cpp index 350cc228cb8..87671f39ecb 100644 --- a/mozilla/layout/base/src/nsStyleContext.cpp +++ b/mozilla/layout/base/src/nsStyleContext.cpp @@ -530,6 +530,7 @@ void StyleTableImpl::ResetFrom(const nsStyleTable* aParent, nsIPresContext* aPre mRules = NS_STYLE_TABLE_RULES_NONE; mCellPadding.Reset(); mCellSpacing.Reset(); + mSpan=0; } diff --git a/mozilla/layout/html/document/src/ua.css b/mozilla/layout/html/document/src/ua.css index 1c11630a359..39c3e06831e 100644 --- a/mozilla/layout/html/document/src/ua.css +++ b/mozilla/layout/html/document/src/ua.css @@ -209,7 +209,7 @@ PLAINTEXT, XMP, PRE { // Table tags TABLE { - display: block; + display: table; border-style: outset; border-color: #C0C0C0; cell-spacing: 4px; @@ -225,7 +225,7 @@ TD, TH { font-weight: normal; font-size: 11pt; line-height: 1.1; - display: block; + display: table-cell; cursor: arrow; } TH { @@ -234,8 +234,14 @@ TH { } CAPTION { text-align: center; - display: block; + display: table-caption; } +TBODY { display: table-row-group; } +THEAD { display: table-header-group; } +TFOOT { display: table-footer-group; } +COL { display: table-column; } +COLGROUP { display: table-column-group;} + MULTICOL { display: block; } diff --git a/mozilla/layout/html/style/src/nsCSSParser.cpp b/mozilla/layout/html/style/src/nsCSSParser.cpp index f6f6815f65c..6753d4a333b 100644 --- a/mozilla/layout/html/style/src/nsCSSParser.cpp +++ b/mozilla/layout/html/style/src/nsCSSParser.cpp @@ -1257,10 +1257,23 @@ static PRInt32 kDirectionKTable[] = { }; static PRInt32 kDisplayKTable[] = { - KEYWORD_NONE, NS_STYLE_DISPLAY_NONE, - KEYWORD_BLOCK, NS_STYLE_DISPLAY_BLOCK, - KEYWORD_INLINE, NS_STYLE_DISPLAY_INLINE, - KEYWORD_LIST_ITEM, NS_STYLE_DISPLAY_LIST_ITEM, + KEYWORD_NONE, NS_STYLE_DISPLAY_NONE, + KEYWORD_BLOCK, NS_STYLE_DISPLAY_BLOCK, + KEYWORD_INLINE, NS_STYLE_DISPLAY_INLINE, + KEYWORD_LIST_ITEM, NS_STYLE_DISPLAY_LIST_ITEM, + KEYWORD_MARKER, NS_STYLE_DISPLAY_MARKER, + KEYWORD_RUN_IN, NS_STYLE_DISPLAY_RUN_IN, + KEYWORD_COMPACT, NS_STYLE_DISPLAY_COMPACT, + KEYWORD_TABLE, NS_STYLE_DISPLAY_TABLE, + KEYWORD_INLINE_TABLE, NS_STYLE_DISPLAY_INLINE_TABLE, + KEYWORD_TABLE_ROW_GROUP, NS_STYLE_DISPLAY_TABLE_ROW_GROUP, + KEYWORD_TABLE_COLUMN, NS_STYLE_DISPLAY_TABLE_COLUMN, + KEYWORD_TABLE_COLUMN_GROUP, NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP, + KEYWORD_TABLE_HEADER_GROUP, NS_STYLE_DISPLAY_TABLE_HEADER_GROUP, + KEYWORD_TABLE_FOOTER_GROUP, NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP, + KEYWORD_TABLE_ROW, NS_STYLE_DISPLAY_TABLE_ROW, + KEYWORD_TABLE_CELL, NS_STYLE_DISPLAY_TABLE_CELL, + KEYWORD_TABLE_CAPTION, NS_STYLE_DISPLAY_TABLE_CAPTION, -1 }; diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp index d40919b3612..4274d31e4c1 100644 --- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -463,7 +463,10 @@ PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresConte for (PRInt32 cellIndex = 0; cellIndexElementAt(cellIndex)); - NS_ASSERTION(nsnull != data, "bad data"); + if (nsnull==data) + { // For cells that span rows there's only cell layout data for the first row + continue; + } nsSize * cellMinSize = data->GetMaxElementSize(); NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize"); nsReflowMetrics * cellDesiredSize = data->GetDesiredSize(); diff --git a/mozilla/layout/html/table/src/nsCellLayoutData.cpp b/mozilla/layout/html/table/src/nsCellLayoutData.cpp index 37b0b0442ed..882c5a9abff 100644 --- a/mozilla/layout/html/table/src/nsCellLayoutData.cpp +++ b/mozilla/layout/html/table/src/nsCellLayoutData.cpp @@ -15,8 +15,10 @@ * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ -#include "nsCRT.h" + #include "nsCellLayoutData.h" +#include "nsTableCellFrame.h" // should be removed, make only generic nsIFrame calls +#include "nsCRT.h" #include "nsSize.h" #include "nsVoidArray.h" #include "nsIFrame.h" diff --git a/mozilla/layout/html/table/src/nsCellLayoutData.h b/mozilla/layout/html/table/src/nsCellLayoutData.h index e7e9dd1d89d..8d7d9eda77c 100644 --- a/mozilla/layout/html/table/src/nsCellLayoutData.h +++ b/mozilla/layout/html/table/src/nsCellLayoutData.h @@ -21,11 +21,12 @@ #include "nscore.h" #include "nsSize.h" #include "nsIFrame.h" -#include "nsTableCellFrame.h" +class nsTableCellFrame; class nsColLayoutData; class nsTableFrame; class nsIStyleContext; +class nsVoidArray; struct nsStyleSpacing; diff --git a/mozilla/layout/html/table/src/nsCellMap.h b/mozilla/layout/html/table/src/nsCellMap.h index 57bc1498773..6d5d4d3fce2 100644 --- a/mozilla/layout/html/table/src/nsCellMap.h +++ b/mozilla/layout/html/table/src/nsCellMap.h @@ -28,12 +28,11 @@ class CellData; * Each cell is represented by a CellData object. * * @see CellData - * @see nsTablePart::BuildCellMap - * @see nsTablePart::GrowCellMap - * @see nsTablePart::BuildCellIntoMap + * @see nsTableFrame::BuildCellMap + * @see nsTableFrame::GrowCellMap + * @see nsTableFrame::BuildCellIntoMap * * acts like a 2-dimensional array, so all offsets are 0-indexed - TODO: inline methods */ class nsCellMap { diff --git a/mozilla/layout/html/table/src/nsColLayoutData.cpp b/mozilla/layout/html/table/src/nsColLayoutData.cpp index c4bfb1c6593..5a64d0944af 100644 --- a/mozilla/layout/html/table/src/nsColLayoutData.cpp +++ b/mozilla/layout/html/table/src/nsColLayoutData.cpp @@ -18,7 +18,7 @@ #include "nsColLayoutData.h" #include "nsVoidArray.h" #include "nsCellLayoutData.h" -#include "nsTableCell.h" +#include "nsTableCellFrame.h" nsColLayoutData::nsColLayoutData(nsTableColFrame* aColFrame, PRInt32 aNumRows) { diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp index 0663b08f1e7..2d82095503a 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp @@ -16,6 +16,7 @@ * Reserved. */ #include "nsTableCellFrame.h" +#include "nsCellLayoutData.h" #include "nsBodyFrame.h" #include "nsIReflowCommand.h" #include "nsIStyleContext.h" @@ -48,7 +49,8 @@ static const PRBool gsDebug = PR_FALSE; */ nsTableCellFrame::nsTableCellFrame(nsIContent* aContent, nsIFrame* aParentFrame) - : nsContainerFrame(aContent, aParentFrame) + : nsContainerFrame(aContent, aParentFrame), + mCellLayoutData(nsnull) { mRowSpan=1; mColSpan=1; @@ -57,6 +59,8 @@ nsTableCellFrame::nsTableCellFrame(nsIContent* aContent, nsTableCellFrame::~nsTableCellFrame() { + if (nsnull!=mCellLayoutData) + delete mCellLayoutData; } NS_METHOD nsTableCellFrame::Paint(nsIPresContext& aPresContext, diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.h b/mozilla/layout/html/table/src/nsTableCellFrame.h index b8242267548..b0077954d25 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.h +++ b/mozilla/layout/html/table/src/nsTableCellFrame.h @@ -22,6 +22,7 @@ #include "nsContainerFrame.h" #include "nsTableFrame.h" +class nsCellLayoutData; struct nsStyleSpacing; /** @@ -68,11 +69,16 @@ public: /** return the mapped cell's column index (starting at 0 for the first column) */ virtual PRInt32 GetColIndex(); + virtual void SetColIndex (int aColIndex); + virtual ~nsTableCellFrame(); // Get the TableFrame that contains this cell frame virtual nsTableFrame* GetTableFrame(); + nsCellLayoutData * GetCellLayoutData(); + void SetCellLayoutData(nsCellLayoutData *aData); + // For DEBUGGING Purposes Only NS_IMETHOD MoveTo(nscoord aX, nscoord aY); NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); @@ -106,6 +112,8 @@ protected: /** the starting column for this cell */ int mColIndex; + nsCellLayoutData *mCellLayoutData; + }; inline void nsTableCellFrame::Init(PRInt32 aRowSpan, PRInt32 aColSpan, PRInt32 aColIndex) @@ -127,5 +135,16 @@ inline PRInt32 nsTableCellFrame::GetColSpan() inline PRInt32 nsTableCellFrame::GetColIndex() { return mColIndex;} +inline void nsTableCellFrame::SetColIndex (int aColIndex) +{ + NS_ASSERTION(0<=aColIndex, "illegal negative column index."); + mColIndex = aColIndex; +} + +inline nsCellLayoutData * nsTableCellFrame::GetCellLayoutData() +{ return mCellLayoutData;} + +inline void nsTableCellFrame::SetCellLayoutData(nsCellLayoutData *aData) +{ mCellLayoutData = aData;} #endif diff --git a/mozilla/layout/html/table/src/nsTableColFrame.h b/mozilla/layout/html/table/src/nsTableColFrame.h index d6e299c7b39..e06d27b313f 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.h +++ b/mozilla/layout/html/table/src/nsTableColFrame.h @@ -21,7 +21,6 @@ #include "nscore.h" #include "nsContainerFrame.h" - class nsTableColFrame : public nsFrame { public: @@ -46,6 +45,9 @@ public: /** return the number of the columns the col represents. always >= 0 */ virtual int GetRepeat (); + /** set the index of the column this content object represents. must be >= 0 */ + virtual void SetColumnIndex (int aColIndex); + protected: nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame); @@ -75,6 +77,9 @@ inline nsTableColFrame::GetColumnIndex() inline nsTableColFrame::GetRepeat() { return mRepeat; } + +inline void nsTableColFrame::SetColumnIndex (int aColIndex) +{ mColIndex = aColIndex;} #endif diff --git a/mozilla/layout/html/table/src/nsTableColGroup.cpp b/mozilla/layout/html/table/src/nsTableColGroup.cpp index e82f665a150..abd06b21b3a 100644 --- a/mozilla/layout/html/table/src/nsTableColGroup.cpp +++ b/mozilla/layout/html/table/src/nsTableColGroup.cpp @@ -141,8 +141,6 @@ int nsTableColGroup::GetColumnCount () void nsTableColGroup::ResetColumns () { mColCount = 0; - if (nsnull != mTable) - mTable->ResetColumns (); } NS_IMETHODIMP diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp index 024d9bb3dc2..13b2dfa02f6 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp @@ -16,13 +16,13 @@ * Reserved. */ #include "nsTableColGroupFrame.h" +#include "nsTableColFrame.h" #include "nsIReflowCommand.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" #include "nsIPresContext.h" #include "nsIPtr.h" #include "nsIContentDelegate.h" -#include "nsTableContent.h" #include "nsHTMLAtoms.h" NS_DEF_PTR(nsIContent); @@ -35,6 +35,7 @@ nsTableColGroupFrame::nsTableColGroupFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsContainerFrame(aContent, aParentFrame) { + mColCount=0; } nsTableColGroupFrame::~nsTableColGroupFrame() @@ -66,7 +67,7 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext* aPresContext, LastChild(prevKidFrame); // XXX remember this... PRInt32 kidIndex = 0; - for (;;) + for (PRInt32 colIndex = 0; ;colIndex++) // colIndex is used to set the column frames' index field { nsIContentPtr kid = mContent->ChildAt(kidIndex); // kid: REFCNT++ if (kid.IsNull()) { @@ -75,7 +76,7 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext* aPresContext, // Resolve style nsIStyleContextPtr kidSC = - aPresContext->ResolveStyleContextFor(kid, this); + aPresContext->ResolveStyleContextFor(kid, this, PR_TRUE); const nsStyleSpacing* kidSpacing = (const nsStyleSpacing*) kidSC->GetStyleData(eStyleStruct_Spacing); @@ -95,6 +96,9 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext* aPresContext, // note that DidReflow is called as the result of some ancestor firing off a DidReflow above me kidFrame->SetRect(nsRect(0,0,0,0)); + // set nsColFrame-specific information + ((nsTableColFrame *)kidFrame)->SetColumnIndex(colIndex+mStartColIndex); + // Link child frame into the list of children if (nsnull != prevKidFrame) { prevKidFrame->SetNextSibling(kidFrame); @@ -178,6 +182,42 @@ NS_METHOD nsTableColGroupFrame::SetStyleContextForFirstPass(nsIPresContext* aPre return NS_OK; } + +/** 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 () +{ + if (0 == mColCount) + { + int count; + ChildCount (count); + if (0 < count) + { + nsIFrame * child = nsnull; + ChildAt(0, child); + NS_ASSERTION(nsnull!=child, "bad child"); + while (nsnull!=child) + { + nsTableColFrame *col = (nsTableColFrame *)child; + col->SetColumnIndex (mStartColIndex + mColCount); + mColCount += col->GetRepeat (); + child->GetNextSibling(child); + } + } + else + { + const nsStyleTable *tableStyle; + GetStyleData(eStyleStruct_Table, (nsStyleStruct *&)tableStyle); + mColCount = tableStyle->mSpan; + } + } + return mColCount; +} + +/* ----- static methods ----- */ + nsresult nsTableColGroupFrame::NewFrame(nsIFrame** aInstancePtrResult, nsIContent* aContent, nsIFrame* aParent) @@ -193,3 +233,5 @@ nsresult nsTableColGroupFrame::NewFrame(nsIFrame** aInstancePtrResult, *aInstancePtrResult = it; return NS_OK; } + + diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.h b/mozilla/layout/html/table/src/nsTableColGroupFrame.h index e95ff0dcd0b..6fbca4d4924 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.h +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.h @@ -50,6 +50,16 @@ public: const nsReflowState& aReflowState, nsReflowStatus& aStatus); + /** 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. + */ + virtual PRInt32 GetColumnCount (); + + virtual PRInt32 GetStartColumnIndex (); + + virtual void SetStartColumnIndex (PRInt32 aIndex); + protected: nsTableColGroupFrame(nsIContent* aContent, nsIFrame* aParentFrame); @@ -62,6 +72,22 @@ protected: */ NS_METHOD SetStyleContextForFirstPass(nsIPresContext* aPresContext); + + PRInt32 mColCount; + + /** the starting column index this col group represents. Must be >= 0. */ + PRInt32 mStartColIndex; + }; +inline int nsTableColGroupFrame::GetStartColumnIndex () +{ return mStartColIndex;} + +inline void nsTableColGroupFrame::SetStartColumnIndex (int aIndex) +{ + if (aIndex != mStartColIndex) + mColCount = 0; // our index is being changed, trigger reset of col indicies, don't propogate back to table + mStartColIndex = aIndex; +} + #endif diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index fba3efca02a..d60cb22365e 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -22,11 +22,11 @@ #include "nsIContent.h" #include "nsIContentDelegate.h" #include "nsCellMap.h" -#include "nsTableContent.h" -#include "nsTableCell.h" #include "nsTableCellFrame.h" -#include "nsTableCol.h" +#include "nsTableCol.h" // needed for building implicit columns +#include "nsTableColGroup.h" // needed for building implicit colgroups #include "nsTableColFrame.h" +#include "nsTableColGroupFrame.h" #include "nsTableRowFrame.h" #include "nsTableRowGroupFrame.h" #include "nsColLayoutData.h" @@ -65,9 +65,19 @@ static const PRBool gsDebugMBP = PR_FALSE; NS_DEF_PTR(nsIStyleContext); NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsTableContent); -NS_DEF_PTR(nsTableCol); -NS_DEF_PTR(nsTableCell); + +/* ----------- CellData ---------- */ + +/* CellData is the info stored in the cell map */ +CellData::CellData() +{ + mCell = nsnull; + mRealCell = nsnull; + mOverlap = nsnull; +} + +CellData::~CellData() +{} /* ----------- InnerTableReflowState ---------- */ @@ -250,11 +260,12 @@ void ColumnInfoCache::GetColumnsByType(const nsStyleUnit aType, -/* ----------- nsTableFrame ---------- */ +/* --------------------- nsTableFrame -------------------- */ nsTableFrame::nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsContainerFrame(aContent, aParentFrame), + mCellMap(nsnull), mColumnLayoutData(nsnull), mColCache(nsnull), mColumnWidths(nsnull), @@ -286,22 +297,483 @@ void nsTableFrame::DeleteColumnLayoutData() nsTableFrame::~nsTableFrame() { + if (nsnull!=mCellMap) + delete mCellMap; + DeleteColumnLayoutData(); + if (nsnull!=mColumnWidths) delete [] mColumnWidths; + if (nsnull!=mTableLayoutStrategy) delete mTableLayoutStrategy; + if (nsnull!=mColCache) delete mColCache; } +/* ****** CellMap methods ******* */ +/* return the index of the first row group after aStartIndex */ +PRInt32 nsTableFrame::NextRowGroup (PRInt32 aStartIndex) +{ + int index = aStartIndex; + int count; + ChildCount(count); + nsIFrame * child; + ChildAt (index+1, child); + + while (++index < count) + { + const nsStyleDisplay *childDisplay; + child->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) + return index; + child->GetNextSibling(child); + } + return count; +} + +/* counts columns in column groups */ +PRInt32 nsTableFrame::GetSpecifiedColumnCount () +{ + mColCount=0; + nsIFrame * colGroup; + ChildAt (0, (nsIFrame *&)colGroup); + while (nsnull!=colGroup) + { + const nsStyleDisplay *childDisplay; + colGroup->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) + { + mColCount += ((nsTableColGroupFrame *)colGroup)->GetColumnCount(); + } + else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) + { + break; + } + colGroup->GetNextSibling(colGroup); + } + return mColCount; +} + +PRInt32 nsTableFrame::GetRowCount () +{ + PRInt32 rowCount = 0; + + if (nsnull != mCellMap) + return mCellMap->GetRowCount(); + + nsIFrame *child=nsnull; + ChildAt(0, child); + while (nsnull!=child) + { + const nsStyleDisplay *childDisplay; + child->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) + rowCount += ((nsTableRowGroupFrame *)child)->GetRowCount (); + child->GetNextSibling(child); + } + return rowCount; +} +// return the rows spanned by aCell starting at aRowIndex +// note that this is different from just the rowspan of aCell +// (that would be GetEffectiveRowSpan (indexOfRowThatContains_aCell, aCell) +PRInt32 nsTableFrame::GetEffectiveRowSpan (PRInt32 aRowIndex, nsTableCellFrame *aCell) +{ + NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); + NS_PRECONDITION (0<=aRowIndex && aRowIndexGetRowSpan(); + int rowCount = GetRowCount(); + if (rowCount < (aRowIndex + rowSpan)) + return (rowCount - aRowIndex); + return rowSpan; +} + + +// returns the actual cell map, not a copy, so don't mess with it! +nsCellMap* nsTableFrame::GetCellMap() const +{ + return mCellMap; +} + +/* call when the cell structure has changed. mCellMap will be rebuilt on demand. */ +void nsTableFrame::ResetCellMap () +{ + if (nsnull!=mCellMap) + delete mCellMap; + mCellMap = nsnull; // for now, will rebuild when needed +} + +/* call when column structure has changed. */ +void nsTableFrame::ResetColumns () +{ + EnsureCellMap(); +} + +/** 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, + nsReflowMetrics& aDesiredSize, + const nsReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + EnsureCellMap(); + + PRInt32 actualColumns = 0; + nsTableColGroupFrame *lastColGroupFrame = nsnull; + nsIFrame * childFrame=nsnull; + nsIFrame * firstRowGroupFrame=nsnull; + nsIFrame * prevSibFrame=nsnull; + ChildAt (0, (nsIFrame *&)childFrame); + while (nsnull!=childFrame) + { + const nsStyleDisplay *childDisplay; + childFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) + { + PRInt32 numCols = ((nsTableColGroupFrame*)childFrame)->GetColumnCount(); + actualColumns += numCols; + lastColGroupFrame = (nsTableColGroupFrame *)childFrame; + } + else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) + { + firstRowGroupFrame = childFrame; + break; + } + prevSibFrame = childFrame; + childFrame->GetNextSibling(childFrame); + } + if (actualColumns < mCellMap->GetColCount()) + { + nsTableColGroup *lastColGroup=nsnull; + if (nsnull==lastColGroupFrame) + { + //QQQ + // need to find the generic way to stamp out this content, and ::AppendChild it + // this might be ok. no matter what my mcontent is, I know it needs a colgroup as a kid? + + // QQQ needs a ref count? + lastColGroup = new nsTableColGroup (PR_TRUE); + // XXX: how do I know whether AppendChild should notify or not? + mContent->AppendChild(lastColGroup, PR_FALSE); // was AppendColGroup + NS_ADDREF(lastColGroup); // ADDREF a: lastColGroup++ + // Resolve style for the child + nsIStyleContext* colGroupStyleContext = + aPresContext->ResolveStyleContextFor(lastColGroup, this, PR_TRUE); // kidStyleContext: REFCNT++ + nsIContentDelegate* kidDel = nsnull; + kidDel = lastColGroup->GetDelegate(aPresContext); // kidDel: REFCNT++ + nsresult rv = kidDel->CreateFrame(aPresContext, lastColGroup, this, + colGroupStyleContext, (nsIFrame *&)lastColGroupFrame); + NS_RELEASE(kidDel); // kidDel: REFCNT-- + NS_RELEASE(colGroupStyleContext); // kidStyleContenxt: REFCNT-- + + // hook lastColGroupFrame into child list + if (nsnull==firstRowGroupFrame) + { // make lastColGroupFrame the last frame + nsIFrame *lastChild=nsnull; + LastChild(lastChild); + lastChild->SetNextSibling(lastColGroupFrame); + } + else + { // insert lastColGroupFrame before the first row group frame + if (nsnull!=prevSibFrame) + { // lastColGroupFrame is inserted between prevSibFrame and lastColGroupFrame + prevSibFrame->SetNextSibling(lastColGroupFrame); + } + else + { // lastColGroupFrame is inserted as the first child of this table + mFirstChild = lastColGroupFrame; + } + lastColGroupFrame->SetNextSibling(firstRowGroupFrame); + } + mChildCount++; + } + else + { + lastColGroupFrame->GetContent((nsIContent *&)lastColGroup); // ADDREF b: lastColGroup++ + } + + PRInt32 excessColumns = mCellMap->GetColCount() - actualColumns; + for ( ; excessColumns > 0; excessColumns--) + {//QQQ + // need to find the generic way to stamp out this content, and ::AppendChild it + nsTableCol *col = new nsTableCol(PR_TRUE); + lastColGroup->AppendChild (col, PR_FALSE); + } + NS_RELEASE(lastColGroup); // ADDREF: lastColGroup-- + lastColGroupFrame->Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); + } +} + +void nsTableFrame::EnsureCellMap() +{ + if (mCellMap == nsnull) + BuildCellMap(); +} + +void nsTableFrame::BuildCellMap () +{ + if (gsDebug==PR_TRUE) printf("Build Cell Map...\n"); + + int rowCount = GetRowCount (); + NS_ASSERTION(0!=rowCount, "bad state"); + if (0 == rowCount) + { + // until we have some rows, there's nothing useful to do + return; + } + + // Make an educated guess as to how many columns we have. It's + // only a guess because we can't know exactly until we have + // processed the last row. + nsTableRowGroupFrame *rowGroup=nsnull; + PRInt32 childCount; + ChildCount (childCount); + PRInt32 groupIndex = NextRowGroup (-1); + if (0 == mColCount) + mColCount = GetSpecifiedColumnCount (); + if (0 == mColCount) // no column parts + { + ChildAt (groupIndex, (nsIFrame *&)rowGroup); + nsTableRowFrame *row; + rowGroup->ChildAt (0, (nsIFrame *&)row); + mColCount = row->GetMaxColumns (); + if (gsDebug==PR_TRUE) + printf("mColCount=0 at start. Guessing col count to be %d from a row.\n", mColCount); + } + if (nsnull==mCellMap) + mCellMap = new nsCellMap(rowCount, mColCount); + else + mCellMap->Reset(rowCount, mColCount); + if (gsDebug==PR_TRUE) printf("mCellMap set to (%d, %d)\n", rowCount, mColCount); + PRInt32 rowStart = 0; + if (gsDebug==PR_TRUE) printf("childCount is %d\n", childCount); + while (groupIndex < childCount) + { + if (gsDebug==PR_TRUE) printf(" groupIndex is %d\n", groupIndex); + if (gsDebug==PR_TRUE) printf(" rowStart is %d\n", rowStart); + ChildAt (groupIndex, (nsIFrame *&)rowGroup); + int groupRowCount; + rowGroup->ChildCount(groupRowCount); + if (gsDebug==PR_TRUE) printf(" groupRowCount is %d\n", groupRowCount); + nsTableRowFrame *row; + rowGroup->ChildAt (0, (nsIFrame *&)row); + for (PRInt32 rowIndex = 0; rowIndex < groupRowCount; rowIndex++) + { + PRInt32 cellCount; + row->ChildCount (cellCount); + PRInt32 cellIndex = 0; + PRInt32 colIndex = 0; + if (gsDebug==PR_TRUE) + DumpCellMap(); + if (gsDebug==PR_TRUE) printf(" rowIndex is %d, row->SetRowIndex(%d)\n", rowIndex, rowIndex + rowStart); + row->SetRowIndex (rowIndex + rowStart); + while (colIndex < mColCount) + { + if (gsDebug==PR_TRUE) printf(" colIndex = %d, with mColCount = %d\n", colIndex, mColCount); + CellData *data =mCellMap->GetCellAt(rowIndex + rowStart, colIndex); + if (nsnull == data) + { + if (gsDebug==PR_TRUE) printf(" null data from GetCellAt(%d,%d)\n", rowIndex+rowStart, colIndex); + if (gsDebug==PR_TRUE) printf(" cellIndex=%d, cellCount=%d)\n", cellIndex, cellCount); + if (cellIndex < cellCount) + { + nsTableCellFrame* cell; + row->ChildAt (cellIndex, (nsIFrame *&)cell); + if (gsDebug==PR_TRUE) printf(" calling BuildCellIntoMap(cell, %d, %d), and incrementing cellIndex\n", rowIndex + rowStart, colIndex); + BuildCellIntoMap (cell, rowIndex + rowStart, colIndex); + cellIndex++; + } + } + colIndex++; + } + + if (cellIndex < cellCount) + { + // We didn't use all the cells in this row up. Grow the cell + // data because we now know that we have more columns than we + // originally thought we had. + if (gsDebug==PR_TRUE) printf(" calling GrowCellMap because cellIndex < %d\n", cellIndex, cellCount); + GrowCellMap (cellCount); + while (cellIndex < cellCount) + { + if (gsDebug==PR_TRUE) printf(" calling GrowCellMap again because cellIndex < %d\n", cellIndex, cellCount); + GrowCellMap (colIndex + 1); // ensure enough cols in map, may be low due to colspans + CellData *data =mCellMap->GetCellAt(rowIndex + rowStart, colIndex); + if (data == nsnull) + { + nsTableCellFrame* cell; + row->ChildAt (cellIndex, (nsIFrame *&)cell); + BuildCellIntoMap (cell, rowIndex + rowStart, colIndex); + cellIndex++; + } + colIndex++; + } + } + row->GetNextSibling((nsIFrame *&)row); + } + rowStart += groupRowCount; + groupIndex = NextRowGroup (groupIndex); + } + if (gsDebug==PR_TRUE) + DumpCellMap (); + //QQQ EnsureColumns(); +} /** -* Lists the column layout data which turns -* around and lists the cell layout data. -* This is for debugging purposes only. -*/ + */ +void nsTableFrame::DumpCellMap () const +{ + printf("dumping CellMap:\n"); + if (nsnull != mCellMap) + { + PRInt32 rowCount = mCellMap->GetRowCount(); + PRInt32 cols = mCellMap->GetColCount(); + for (PRInt32 r = 0; r < rowCount; r++) + { + if (gsDebug==PR_TRUE) + { printf("row %d", r); + printf(": "); + } + for (PRInt32 c = 0; c < cols; c++) + { + CellData *cd =mCellMap->GetCellAt(r, c); + if (cd != nsnull) + { + if (cd->mCell != nsnull) + { + printf("C%d,%d ", r, c); + printf(" "); + } + else + { + nsTableCellFrame *cell = cd->mRealCell->mCell; + nsTableRowFrame *row; + cell->GetGeometricParent((nsIFrame *&)row); + int rr = row->GetRowIndex (); + int cc = cell->GetColIndex (); + printf("S%d,%d ", rr, cc); + if (cd->mOverlap != nsnull) + { + cell = cd->mOverlap->mCell; + nsTableRowFrame* row2; + cell->GetGeometricParent((nsIFrame *&)row); + rr = row2->GetRowIndex (); + cc = cell->GetColIndex (); + printf("O%d,%c ", rr, cc); + } + else + printf(" "); + } + } + else + printf("---- "); + } + printf("\n"); + } + } + else + printf ("[nsnull]"); +} + +void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex) +{ + NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); + NS_PRECONDITION (aColIndex < mColCount, "bad column index arg"); + NS_PRECONDITION (aRowIndex < GetRowCount(), "bad row index arg"); + + // Setup CellMap for this cell + int rowSpan = GetEffectiveRowSpan (aRowIndex, aCell); + int colSpan = aCell->GetColSpan (); + if (gsDebug==PR_TRUE) printf(" BuildCellIntoMap. rowSpan = %d, colSpan = %d\n", rowSpan, colSpan); + + // Grow the mCellMap array if we will end up addressing + // some new columns. + if (mColCount < (aColIndex + colSpan)) + { + if (gsDebug==PR_TRUE) printf(" mColCount=%dmCell = aCell; + data->mRealCell = data; + if (gsDebug==PR_TRUE) printf(" calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex); + mCellMap->SetCellAt(data, aRowIndex, aColIndex); + aCell->SetColIndex (aColIndex); + + // Create CellData objects for the rows that this cell spans. Set + // their mCell to nsnull and their mRealCell to point to data. If + // there were no column overlaps then we could use the same + // CellData object for each row that we span... + if ((1 < rowSpan) || (1 < colSpan)) + { + if (gsDebug==PR_TRUE) printf(" spans\n"); + for (int rowIndex = 0; rowIndex < rowSpan; rowIndex++) + { + if (gsDebug==PR_TRUE) printf(" rowIndex = %d\n", rowIndex); + int workRow = aRowIndex + rowIndex; + if (gsDebug==PR_TRUE) printf(" workRow = %d\n", workRow); + for (int colIndex = 0; colIndex < colSpan; colIndex++) + { + if (gsDebug==PR_TRUE) printf(" colIndex = %d\n", colIndex); + int workCol = aColIndex + colIndex; + if (gsDebug==PR_TRUE) printf(" workCol = %d\n", workCol); + CellData *testData = mCellMap->GetCellAt(workRow, workCol); + if (nsnull == testData) + { + CellData *spanData = new CellData (); + spanData->mRealCell = data; + if (gsDebug==PR_TRUE) printf(" null GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol); + mCellMap->SetCellAt(spanData, workRow, workCol); + } + else if ((0 < rowIndex) || (0 < colIndex)) + { // we overlap, replace existing data, it might be shared + if (gsDebug==PR_TRUE) printf(" overlapping Cell from GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol); + CellData *overlap = new CellData (); + overlap->mCell = testData->mCell; + overlap->mRealCell = testData->mRealCell; + overlap->mOverlap = data; + mCellMap->SetCellAt(overlap, workRow, workCol); + } + } + } + } +} + +void nsTableFrame::GrowCellMap (PRInt32 aColCount) +{ + if (nsnull!=mCellMap) + { + if (mColCount < aColCount) + { + mCellMap->GrowTo(aColCount); + } + mColCount = aColCount; + } +} + + +/* ***** Column Layout Data methods ***** */ + +/* + * Lists the column layout data which turns + * around and lists the cell layout data. + * This is for debugging purposes only. + */ void nsTableFrame::ListColumnLayoutData(FILE* out, PRInt32 aIndent) const { // if this is a continuing frame, there will be no output @@ -325,7 +797,7 @@ void nsTableFrame::ListColumnLayoutData(FILE* out, PRInt32 aIndent) const * For the TableCell in CellData, find the CellLayoutData assocated * and add it to the list **/ -void nsTableFrame::AppendLayoutData(nsVoidArray* aList, nsTableCell* aTableCell) +void nsTableFrame::AppendLayoutData(nsVoidArray* aList, nsTableCellFrame* aTableCell) { if (aTableCell != nsnull) @@ -338,18 +810,16 @@ void nsTableFrame::AppendLayoutData(nsVoidArray* aList, nsTableCell* aTableCell) void nsTableFrame::RecalcLayoutData() { + //QQQ should we ensureCellMap here? + PRInt32 colCount = mCellMap->GetColCount(); + PRInt32 rowCount = mCellMap->GetRowCount(); + PRInt32 row = 0; + PRInt32 col = 0; - nsTablePart* table = (nsTablePart*)mContent; - nsCellMap* cellMap = table->GetCellMap(); - PRInt32 colCount = cellMap->GetColCount(); - PRInt32 rowCount = cellMap->GetRowCount(); - PRInt32 row = 0; - PRInt32 col = 0; - - nsTableCell* above = nsnull; - nsTableCell* below = nsnull; - nsTableCell* left = nsnull; - nsTableCell* right = nsnull; + nsTableCellFrame* above = nsnull; + nsTableCellFrame* below = nsnull; + nsTableCellFrame* left = nsnull; + nsTableCellFrame* right = nsnull; PRInt32 edge = 0; @@ -365,51 +835,50 @@ void nsTableFrame::RecalcLayoutData() { for (col = 0; col < colCount; col++) { - nsTableCell* cell = nsnull; - CellData* cellData = cellMap->GetCellAt(row,col); + nsTableCellFrame* cell = nsnull; + CellData* cellData = mCellMap->GetCellAt(row,col); if (cellData) cell = cellData->mCell; - if (!cell) + if (nsnull==cell) continue; - PRInt32 colSpan = cell->GetColSpan(); - PRInt32 rowSpan = cell->GetRowSpan(); + PRInt32 colSpan = cell->GetColSpan(); + PRInt32 rowSpan = cell->GetRowSpan(); // clear the cells for all for edges for (edge = 0; edge < 4; edge++) boundaryCells[edge]->Clear(); - // Check to see if the cell data represents the top,left // corner of a a table cell // Check to see if cell the represents a top edge cell - if (row == 0) + if (0 == row) above = nsnull; else { - cellData = cellMap->GetCellAt(row-1,col); - if (cellData != nsnull) + cellData = mCellMap->GetCellAt(row-1,col); + if (nsnull != cellData) above = cellData->mRealCell->mCell; // Does the cell data point to the same cell? // If it is, then continue - if (above != nsnull && above == cell) + if ((nsnull != above) && (above == cell)) continue; } // Check to see if cell the represents a left edge cell - if (col == 0) + if (0 == col) left = nsnull; else { - cellData = cellMap->GetCellAt(row,col-1); + cellData = mCellMap->GetCellAt(row,col-1); if (cellData != nsnull) left = cellData->mRealCell->mCell; - if (left != nsnull && left == cell) + if ((nsnull != left) && (left == cell)) continue; } @@ -436,7 +905,7 @@ void nsTableFrame::RecalcLayoutData() // Add top edge cells if (c != col) { - cellData = cellMap->GetCellAt(r1,c); + cellData = mCellMap->GetCellAt(r1,c); if ((cellData != nsnull) && (cellData->mCell != above)) { above = cellData->mCell; @@ -453,7 +922,7 @@ void nsTableFrame::RecalcLayoutData() if (r2 < rowCount) { // Add bottom edge cells - cellData = cellMap->GetCellAt(r2,c); + cellData = mCellMap->GetCellAt(r2,c); if ((cellData != nsnull) && cellData->mCell != below) { below = cellData->mCell; @@ -478,7 +947,7 @@ void nsTableFrame::RecalcLayoutData() { if (r != row) { - cellData = cellMap->GetCellAt(r,c1); + cellData = mCellMap->GetCellAt(r,c1); if ((cellData != nsnull) && (cellData->mCell != left)) { left = cellData->mCell; @@ -495,7 +964,7 @@ void nsTableFrame::RecalcLayoutData() if (c2 < colCount) { // Add right edge cells - cellData = cellMap->GetCellAt(r,c2); + cellData = mCellMap->GetCellAt(r,c2); if ((cellData != nsnull) && (cellData->mCell != right)) { right = cellData->mCell; @@ -514,7 +983,6 @@ void nsTableFrame::RecalcLayoutData() } for (edge = 0; edge < 4; edge++) delete boundaryCells[edge]; - } @@ -611,7 +1079,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, if (PR_FALSE==IsFirstPassValid()) { // we treat the table as if we've never seen the layout data before mPass = kPASS_FIRST; - aStatus = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState); + aStatus = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus); // check result } mPass = kPASS_SECOND; @@ -656,13 +1124,15 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, */ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState) + const nsReflowState& aReflowState, + nsReflowStatus& aStatus) { NS_PRECONDITION(aReflowState.frame == this, "bad reflow state"); NS_PRECONDITION(aReflowState.parentReflowState->frame == mGeometricParent, "bad parent reflow state"); NS_ASSERTION(nsnull!=aPresContext, "bad pres context param"); NS_ASSERTION(nsnull==mPrevInFlow, "illegal call, cannot call pass 1 on a continuing frame."); + NS_ASSERTION(nsnull != mContent, "null content"); if (PR_TRUE==gsDebug) printf("nsTableFrame::ResizeReflow Pass1 for %p: maxSize=%d,%d\n", this, aReflowState.maxSize.width, aReflowState.maxSize.height); @@ -671,12 +1141,6 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, mChildCount = 0; mFirstContentOffset = mLastContentOffset = 0; - NS_ASSERTION(nsnull != mContent, "null content"); - nsTablePart* table = (nsTablePart*)mContent; - - // Ensure the cell map - table->EnsureCellMap(); - nsSize availSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); // availSize is the space available at any given time in the process nsSize maxSize(0, 0); // maxSize is the size of the largest child so far in the process nsSize kidMaxSize(0,0); @@ -685,7 +1149,7 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, nscoord maxAscent = 0; nscoord maxDescent = 0; PRInt32 kidIndex = 0; - PRInt32 lastIndex = table->ChildCount(); + PRInt32 lastIndex = mContent->ChildCount(); PRInt32 contentOffset=0; nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */ @@ -708,7 +1172,7 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, * TBody, in order */ for (;;) { - nsIContentPtr kid = table->ChildAt(kidIndex); // kid: REFCNT++ + nsIContentPtr kid = mContent->ChildAt(kidIndex); // kid: REFCNT++ if (kid.IsNull()) { result = NS_FRAME_COMPLETE; break; @@ -716,16 +1180,13 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, mLastContentIsComplete = PR_TRUE; - const PRInt32 contentType = ((nsTableContent *)(nsIContent*)kid)->GetType(); - if (contentType!=nsITableContent::kTableCaptionType) + // Resolve style + nsIStyleContextPtr kidStyleContext = + aPresContext->ResolveStyleContextFor(kid, this, PR_TRUE); + NS_ASSERTION(kidStyleContext.IsNotNull(), "null style context for kid"); + const nsStyleDisplay *childDisplay = (nsStyleDisplay*)kidStyleContext->GetStyleData(eStyleStruct_Display); + if (NS_STYLE_DISPLAY_TABLE_CAPTION != childDisplay->mDisplay) { - // Resolve style - nsIStyleContextPtr kidStyleContext = - aPresContext->ResolveStyleContextFor(kid, this); - NS_ASSERTION(kidStyleContext.IsNotNull(), "null style context for kid"); - - // SEC: TODO: when content is appended or deleted, be sure to clear out the frame hierarchy!!!! - // get next frame, creating one if needed nsIFrame* kidFrame=nsnull; if (nsnull!=prevKidFrame) @@ -800,6 +1261,9 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, } } + BuildColumnCache(aPresContext, aDesiredSize, aReflowState, aStatus); + EnsureCellMap();//QQQ have to determine where the right place for this is now that it's a frame-side operation + //QQQ cell map used to be forced before loop // Recalculate Layout Dependencies RecalcLayoutData(); @@ -984,10 +1448,9 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, } // If this is a footer row group, add it to the list of footer row groups - nsIAtom * tFootTag = NS_NewAtom(nsTablePart::kRowGroupFootTagString); // tFootTag: REFCNT++ - nsIAtom *kidType=nsnull; - ((nsTableRowGroupFrame *)aKidFrame)->GetRowGroupType(kidType); - if (tFootTag==kidType) + const nsStyleDisplay *childDisplay; + aKidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay) { if (nsnull==aState.footerList) aState.footerList = new nsVoidArray(); @@ -1004,8 +1467,8 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, aKidFrame->GetOrigin(origin); origin.y -= aState.footerHeight; aKidFrame->MoveTo(origin.x, origin.y); - nsIAtom * tBodyTag = NS_NewAtom(nsTablePart::kRowGroupBodyTagString); // tBodyTag: REFCNT++ - if (tBodyTag==kidType) + // XXX do we need to check for headers here also, or is that implicit? + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay) { PRInt32 numFooters = aState.footerList->Count(); for (PRInt32 footerIndex = 0; footerIndex < numFooters; footerIndex++) @@ -1020,10 +1483,8 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, } } } - NS_RELEASE(tBodyTag); } } - NS_RELEASE(tFootTag); // Update the maximum element size if (PR_TRUE==aState.firstRowGroup) @@ -1073,7 +1534,7 @@ PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext* aPresContext, PRInt32 childCount = 0; nsIFrame* prevKidFrame = nsnull; - + mLastContentOffset = 0; // Remember our original mLastContentIsComplete so that if we end up // having to push children, we have the correct value to hand to // PushChildren. @@ -1089,18 +1550,12 @@ PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext* aPresContext, desiredSize.width=desiredSize.height=desiredSize.ascent=desiredSize.descent=0; nsReflowStatus status; - // Get top margin for this kid - nsIContentPtr kid; - - kidFrame->GetContent(kid.AssignRef()); - const int contentType = ((nsTableContent *)(nsIContent*)kid)->GetType(); - if (contentType != nsITableContent::kTableCaptionType) + const nsStyleDisplay *childDisplay; + kidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_CAPTION != childDisplay->mDisplay) { // for all colgroups and rowgroups... - nsIStyleContextPtr kidSC; - - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - const nsStyleSpacing* kidSpacing = (const nsStyleSpacing*) - kidSC->GetStyleData(eStyleStruct_Spacing); + const nsStyleSpacing* kidSpacing; + kidFrame->GetStyleData(eStyleStruct_Spacing, ((nsStyleStruct *&)kidSpacing)); nsMargin kidMargin; kidSpacing->CalcMarginFor(kidFrame, kidMargin); @@ -1144,7 +1599,9 @@ PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext* aPresContext, nsRect kidRect (0, 0, desiredSize.width, desiredSize.height); kidRect.x += aState.leftInset + kidMargin.left; kidRect.y += aState.topInset + aState.y; - if (contentType == nsITableContent::kTableRowGroupType) + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) { PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize, kidMaxElementSize); @@ -1155,6 +1612,7 @@ PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext* aPresContext, } } childCount++; + kidFrame->GetContentIndex(mLastContentOffset); // Remember where we just were in case we end up pushing children prevKidFrame = kidFrame; @@ -1363,12 +1821,11 @@ PRBool nsTableFrame::PullUpChildren(nsIPresContext* aPresContext, nsRect kidRect (0, 0, kidSize.width, kidSize.height); //kidRect.x += kidMol->margin.left; kidRect.y += aState.y; - nsIContent* content=nsnull; - kidFrame->GetContent(content); - NS_ASSERTION(nsnull!=content, "bad kid"); - const int contentType = ((nsITableContent*)content)->GetType(); - NS_RELEASE(content); - if (contentType == nsITableContent::kTableRowGroupType) + const nsStyleDisplay *childDisplay; + kidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) { PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize, *pKidMaxElementSize); } @@ -1535,7 +1992,7 @@ nsTableFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, // Resolve style for the child nsIStyleContextPtr kidStyleContext = - aPresContext->ResolveStyleContextFor(kid, this); + aPresContext->ResolveStyleContextFor(kid, this, PR_TRUE); // Figure out how we should treat the child nsIFrame* kidFrame; @@ -1580,12 +2037,11 @@ nsTableFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, //aState.y += topMargin; nsRect kidRect (0, 0, kidSize.width, kidSize.height); kidRect.y += aState.y; - nsIContent* content=nsnull; - kidFrame->GetContent(content); - NS_ASSERTION(nsnull!=content, "bad kid"); - const int contentType = ((nsITableContent*)content)->GetType(); - NS_RELEASE(content); - if (contentType == nsITableContent::kTableRowGroupType) + const nsStyleDisplay *childDisplay; + kidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) { PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize, *pKidMaxElementSize); } @@ -1779,15 +2235,15 @@ void nsTableFrame::ShrinkWrapChildren(nsIPresContext* aPresContext, else kidFrame->GetNextSibling(kidFrame); NS_ASSERTION(nsnull != kidFrame, "bad kid frame"); - nsTableContentPtr kid; - - kidFrame->GetContent((nsIContent*&)(kid.AssignRef())); // kid: REFCNT++ - NS_ASSERTION(kid.IsNotNull(), "bad kid"); nscoord topInnerMargin = 0; nscoord bottomInnerMargin = 0; - if (kid->GetType() == nsITableContent::kTableRowGroupType) + const nsStyleDisplay *childDisplay; + kidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) { /* Step 1: set the row height to the height of the tallest cell, * and resize all cells in that row to that height (except cells with rowspan>1) @@ -2002,6 +2458,51 @@ void nsTableFrame::VerticallyAlignChildren(nsIPresContext* aPresContext, { } +NS_METHOD +nsTableFrame::SetColumnStyleFromCell(nsIPresContext * aPresContext, + nsTableCellFrame* aCellFrame, + nsTableRowFrame * aRowFrame) +{ + // if this cell is in the first row, then the width attribute + // also acts as the width attribute for the entire column + if ((nsnull!=aPresContext) && (nsnull!=aCellFrame) && (nsnull!=aRowFrame)) + { + if (0==aRowFrame->GetRowIndex()) + { + // get the cell style info + const nsStylePosition* cellPosition; + aCellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if ((eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) || + (eStyleUnit_Percent==cellPosition->mWidth.GetUnit())) { + // compute the width per column spanned + PRInt32 colSpan = aCellFrame->GetColSpan(); + for (PRInt32 i=0; iGetColIndex(), colFrame); + // get the column style and set the width attribute + nsIStyleContext* colSC; + colFrame->GetStyleContext(aPresContext, colSC); + nsStylePosition* colPosition = (nsStylePosition*) colSC->GetMutableStyleData(eStyleStruct_Position); + // set the column width attribute + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) + { + nscoord width = cellPosition->mWidth.GetCoordValue(); + colPosition->mWidth.SetCoordValue(width/colSpan); + } + else + { + float width = cellPosition->mWidth.GetPercentValue(); + colPosition->mWidth.SetPercentValue(width/colSpan); + } + } + } + } + } + return NS_OK; +} + /* there's an easy way and a hard way. The easy way is to look in our * cache and pull the frame from there. * If the cache isn't built yet, then we have to go hunting. @@ -2029,16 +2530,16 @@ NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aCol NS_ASSERTION (PR_FALSE, "scanned the frame hierarchy and no column frame could be found."); break; } - nsIContentPtr kid; - childFrame->GetContent(kid.AssignRef()); - const PRInt32 contentType = ((nsTableContent *)(nsIContent*)kid)->GetType(); - if (contentType==nsITableContent::kTableColGroupType) + const nsStyleDisplay *childDisplay; + childFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) { - nsTableColGroup *colGroup = (nsTableColGroup *)((nsIContent*)kid); - PRInt32 colGroupStartingIndex = colGroup->GetStartColumnIndex(); + PRInt32 colGroupStartingIndex = ((nsTableColGroupFrame *)childFrame)->GetStartColumnIndex(); if (aColIndex >= colGroupStartingIndex) { // the cell's col might be in this col group - if (aColIndex < colGroupStartingIndex + colGroup->ChildCount()) + PRInt32 childCount; + childFrame->ChildCount(childCount); + if (aColIndex < colGroupStartingIndex + childCount) { // yep, we've found it childFrame->ChildAt(aColIndex-colGroupStartingIndex, (nsIFrame *&)aColFrame); break; @@ -2051,6 +2552,64 @@ NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aCol return NS_OK; } +void nsTableFrame::BuildColumnCache( nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsReflowState& aReflowState, + nsReflowStatus& aStatus + ) +{ + EnsureColumns(aPresContext, aDesiredSize, aReflowState, aStatus); + if (nsnull==mColCache) + { + mColCache = new ColumnInfoCache(mColCount); + nsIFrame * childFrame = mFirstChild; + while (nsnull!=childFrame) + { // for every child, if it's a col group then get the columns + const nsStyleDisplay *childDisplay; + childFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) + { + nsTableColFrame *colFrame=nsnull; + childFrame->ChildAt(0, (nsIFrame *&)colFrame); + while (nsnull!=colFrame) + { // for every column, create an entry in the column cache + // assumes that the col style has been twiddled to account for first cell width attribute + const nsStylePosition* colPosition; + colFrame->GetStyleData(eStyleStruct_Position, ((nsStyleStruct *&)colPosition)); + mColCache->AddColumnInfo(colPosition->mWidth.GetUnit(), colFrame->GetColumnIndex()); + colFrame->GetNextSibling((nsIFrame *&)colFrame); + } + } + else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) + { // for every cell in every row, call SetCellLayoutData with the cached info + // QQQ we can probably just leave the info in the table cell frame, not cache it here + nsIFrame *rowFrame; + childFrame->ChildAt(0, rowFrame); + while (nsnull!=rowFrame) + { + nsIFrame *cellFrame; + rowFrame->ChildAt(0, cellFrame); + while (nsnull!=cellFrame) + { + nsCellLayoutData *cld = ((nsTableCellFrame*)cellFrame)->GetCellLayoutData(); + SetCellLayoutData(aPresContext, cld, (nsTableCellFrame*)cellFrame); + /* this is the first time we are guaranteed to have both the cell frames + * and the column frames, so it's a good time to + * set the column style from the cell's width attribute (if this is the first row) + */ + SetColumnStyleFromCell(aPresContext, (nsTableCellFrame *)cellFrame, (nsTableRowFrame *)rowFrame); + cellFrame->GetNextSibling(cellFrame); + } + rowFrame->GetNextSibling(rowFrame); + } + } + childFrame->GetNextSibling(childFrame); + } + } +} + nsVoidArray * nsTableFrame::GetColumnLayoutData() { nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); @@ -2064,10 +2623,11 @@ nsVoidArray * nsTableFrame::GetColumnLayoutData() * PR_FALSE if there was an error, such as aRow or aCol being invalid */ PRBool nsTableFrame::SetCellLayoutData(nsIPresContext* aPresContext, - nsCellLayoutData * aData, nsTableCell *aCell) + nsCellLayoutData * aData, nsTableCellFrame *aCell) { - NS_ASSERTION(nsnull != aData, "bad arg"); - NS_ASSERTION(nsnull != aCell, "bad arg"); + NS_ASSERTION(nsnull != aPresContext, "bad arg aPresContext"); + NS_ASSERTION(nsnull != aData, "bad arg aData"); + NS_ASSERTION(nsnull != aCell, "bad arg aCell"); PRBool result = PR_TRUE; @@ -2081,69 +2641,56 @@ PRBool nsTableFrame::SetCellLayoutData(nsIPresContext* aPresContext, { if (nsnull==mColumnLayoutData) { + PRInt32 rows = GetRowCount(); mColumnLayoutData = new nsVoidArray(); NS_ASSERTION(nsnull != mColumnLayoutData, "bad alloc"); - nsTablePart * tablePart = (nsTablePart *)mContent; - PRInt32 cols = tablePart->GetMaxColumns(); - PRInt32 rows = tablePart->GetRowCount(); - mColCache = new ColumnInfoCache(cols); - PRInt32 tableKidCount = tablePart->ChildCount(); + PRInt32 tableKidCount = mContent->ChildCount(); nsIFrame * colGroupFrame = mFirstChild; - for (PRInt32 i=0; iChildAt(i); - NS_ASSERTION(tableKid.IsNotNull(), "bad kid"); - const int contentType = tableKid->GetType(); - if (contentType == nsITableContent::kTableColGroupType) + const nsStyleDisplay *childDisplay; + colGroupFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) { - PRInt32 colsInGroup = tableKid->ChildCount(); - for (PRInt32 j=0; jChildAt(0, (nsIFrame *&)colFrame); + while (nsnull!=colFrame) { // TODO: unify these 2 kinds of column data // TODO: cache more column data, like the mWidth.GetUnit and what its value - - nsTableColFrame *colFrame=nsnull; - // XXX Why is this using ChildAt() instead of just walking the sibling list? - colGroupFrame->ChildAt(j, (nsIFrame *&)colFrame); nsColLayoutData *colData = new nsColLayoutData(colFrame, rows); mColumnLayoutData->AppendElement((void *)colData); - - // also add the column to the column cache - // assumes that the col style has been twiddled to account for first cell width attribute - nsIStyleContextPtr colSC; - colFrame->GetStyleContext(aPresContext, colSC.AssignRef()); - const nsStylePosition* colPosition = (const nsStylePosition*)colSC->GetStyleData(eStyleStruct_Position); - mColCache->AddColumnInfo(colPosition->mWidth.GetUnit(), colFrame->GetColumnIndex()); + colFrame->GetNextSibling((nsIFrame *&)colFrame); } } // can't have col groups after row groups, so stop if you find a row group - else if (contentType == nsITableContent::kTableRowGroupType) + else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) { break; } + i++; ChildAt(i, colGroupFrame); // can't use colGroupFrame->GetNextSibling because it hasn't been set yet } } - // create cell layout data objects for the passed in data, one per column spanned. - // For now, divide width equally between spanned columns - // XXX Add a GetRowIndex() member function to nsTableCell and we can save the - // reference counting overhead... - nsTableRow *row = aCell->GetRow(); // row: ADDREF++ - PRInt32 rowIndex = row->GetRowIndex(); - NS_RELEASE(row); // row: ADDREF-- - PRInt32 colSpan = aCell->GetColSpan(); PRInt32 firstColIndex = aCell->GetColIndex(); - - for (PRInt32 i = 0; i < colSpan; i++) { - if (i > 0) { - int j = 5; - } - nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex + i)); - nsVoidArray *col = colData->GetCells(); - if (gsDebugCLD) printf (" ~ SetCellLayoutData with row = %d, firstCol = %d, colSpan = %d, colData = %ld, col=%ld\n", - rowIndex, firstColIndex, colSpan, colData, col); - + nsTableRowFrame *row; + aCell->GetGeometricParent((nsIFrame*&)row); + PRInt32 rowIndex = row->GetRowIndex(); + PRInt32 colSpan = aCell->GetColSpan(); + nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex)); + nsVoidArray *col = colData->GetCells(); + if (gsDebugCLD) printf (" ~ SetCellLayoutData with row = %d, firstCol = %d, colSpan = %d, colData = %ld, col=%ld\n", + rowIndex, firstColIndex, colSpan, colData, col); + /* this logic looks wrong wrong wrong + it seems to add an entries in col (the array of cells for a column) for aCell + based on colspan. This is weird, because you would expect one entry in each + column spanned for aCell, not multiple entries in the same col. + */ + for (PRInt32 i=0; iGetMaxElementSize(); nsSize partialCellSize(*cellSize); partialCellSize.width = (cellSize->width)/colSpan; @@ -2171,7 +2718,7 @@ PRBool nsTableFrame::SetCellLayoutData(nsIPresContext* aPresContext, * @return nsnull if there was an error, such as aRow or aCol being invalid * otherwise, the data is returned. */ -nsCellLayoutData * nsTableFrame::GetCellLayoutData(nsTableCell *aCell) +nsCellLayoutData * nsTableFrame::GetCellLayoutData(nsTableCellFrame *aCell) { NS_ASSERTION(nsnull != aCell, "bad arg"); @@ -2186,20 +2733,24 @@ nsCellLayoutData * nsTableFrame::GetCellLayoutData(nsTableCell *aCell) { PRInt32 firstColIndex = aCell->GetColIndex(); nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex)); - nsTableRow *row = aCell->GetRow(); // row: ADDREF++ - PRInt32 rowIndex = row->GetRowIndex(); - NS_RELEASE(row); // row: ADDREF-- - + nsTableRowFrame *rowFrame; + aCell->GetGeometricParent((nsIFrame *&)rowFrame); + PRInt32 rowIndex = rowFrame->GetRowIndex(); result = colData->ElementAt(rowIndex); + #ifdef NS_DEBUG // Do some sanity checking if (nsnull != result) { - nsIContent* content; - result->GetCellFrame()->GetContent(content); - NS_ASSERTION(content == aCell, "unexpected cell"); - NS_IF_RELEASE(content); + nsIContent* inputContent; + nsIContent* resultContent; + result->GetCellFrame()->GetContent(resultContent); + aCell->GetContent(inputContent); + NS_ASSERTION(resultContent == inputContent, "unexpected cell"); + NS_IF_RELEASE(inputContent); + NS_IF_RELEASE(resultContent); } #endif + } } return result; @@ -2365,7 +2916,8 @@ void nsTableFrame::MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBo nsIStyleContext* styleContext = mStyleContext; - const nsStyleColor* colorData = (const nsStyleColor*)styleContext->GetStyleData(eStyleStruct_Color); + const nsStyleColor* colorData = (const nsStyleColor*) + styleContext->GetStyleData(eStyleStruct_Color); // Look until we find a style context with a NON-transparent background color while (styleContext) @@ -2477,21 +3029,15 @@ NS_METHOD nsTableFrame::DidSetStyleContext(nsIPresContext* aPresContext) return NS_OK; } -NS_METHOD nsTableFrame::GetCellMarginData(nsIFrame* aKidFrame, nsMargin& aMargin) +NS_METHOD nsTableFrame::GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& aMargin) { nsresult result = NS_ERROR_NOT_INITIALIZED; - nsIContent* content = nsnull; - aKidFrame->GetContent(content); - - if (nsnull != content) + if (nsnull != aKidFrame) { - nsTableCell* cell = (nsTableCell*)content; - - nsCellLayoutData* layoutData = GetCellLayoutData(cell); + nsCellLayoutData* layoutData = GetCellLayoutData(aKidFrame); if (layoutData) result = layoutData->GetMargin(aMargin); - NS_RELEASE(content); } return result; @@ -2597,11 +3143,10 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, until the style resolution stuff does the cool stuff about splitting style between outer and inner */ // begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! - nsIStyleContext* parentStyle = nsnull; nsIFrame * parent = nsnull; aTableFrame->GetGeometricParent(parent); - parent->GetStyleContext(nsnull, parentStyle); - const nsStylePosition* tablePosition = (const nsStylePosition*)parentStyle->GetStyleData(eStyleStruct_Position); + const nsStylePosition* tablePosition; + parent->GetStyleData(eStyleStruct_Position, ((nsStyleStruct *&)tablePosition)); // end REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! switch (tablePosition->mWidth.GetUnit()) { case eStyleUnit_Auto: // specified auto width diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h index e37723fc3ad..be1d16507d8 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.h +++ b/mozilla/layout/html/table/src/nsTableFrame.h @@ -22,11 +22,12 @@ #include "nsContainerFrame.h" #include "nsStyleCoord.h" +class nsCellMap; class nsCellLayoutData; -class nsTableCell; class nsVoidArray; class nsTableCellFrame; class nsTableColFrame; +class nsTableRowFrame; class CellData; class nsITableLayoutStrategy; class nsHTMLValue; @@ -120,6 +121,14 @@ public: nsReflowMetrics& aDesiredSize, nsSize* aMaxElementSize); + /** allow the cell and row attributes to effect the column frame + * currently, the only reason this exists is to support the HTML "rule" + * that a width attribute on a cell in the first column sets the column width. + */ + virtual NS_METHOD SetColumnStyleFromCell(nsIPresContext * aPresContext, + nsTableCellFrame* aCellFrame, + nsTableRowFrame * aRowFrame); + /** return the column frame corresponding to the given column index * there are two ways to do this, depending on whether we have cached * column information yet. @@ -140,15 +149,15 @@ public: * @return PR_TRUE if the data was successfully associated with a Cell * PR_FALSE if there was an error, such as aRow or aCol being invalid */ - virtual PRBool SetCellLayoutData(nsIPresContext* aPresContext, + virtual PRBool SetCellLayoutData(nsIPresContext * aPresContext, nsCellLayoutData * aData, - nsTableCell *aCell); + nsTableCellFrame * aCell); /** Get the layout data associated with the cell at (aRow,aCol) * @return PR_NULL if there was an error, such as aRow or aCol being invalid * otherwise, the data is returned. */ - virtual nsCellLayoutData * GetCellLayoutData(nsTableCell *aCell); + virtual nsCellLayoutData * GetCellLayoutData(nsTableCellFrame *aCell); /** * DEBUG METHOD @@ -167,16 +176,11 @@ public: * Calculate Layout Information * */ - void AppendLayoutData(nsVoidArray* aList, nsTableCell* aTableCell); + void AppendLayoutData(nsVoidArray* aList, nsTableCellFrame* aTableCell); void RecalcLayoutData(); - void ResetCellLayoutData( nsTableCell* aCell, - nsTableCell* aAbove, - nsTableCell* aBelow, - nsTableCell* aLeft, - nsTableCell* aRight); // Get cell margin information - NS_IMETHOD GetCellMarginData(nsIFrame* aKidFrame, nsMargin& aMargin); + NS_IMETHOD GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& aMargin); /** get cached column information for a subset of the columns * @@ -220,7 +224,8 @@ protected: */ virtual nsReflowStatus ResizeReflowPass1(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState); + const nsReflowState& aReflowState, + nsReflowStatus& aStatus); /** second pass of ResizeReflow. * lays out all table content with aMaxSize(computed_table_width, given_table_height) @@ -328,6 +333,85 @@ protected: void MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBorderWidth); PRBool ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult); + /** return the row span of a cell, taking into account row span magic at the bottom + * of a table. + * @param aRowIndex the first row that contains the cell + * @param aCell the content object representing the cell + * @return the row span, correcting for row spans that extend beyond the bottom + * of the table. + */ + virtual PRInt32 GetEffectiveRowSpan(PRInt32 aRowIndex, nsTableCellFrame *aCell); + + /** build as much of the CellMap as possible from the info we have so far + */ + virtual void BuildCellMap (); + + /** called whenever the number of columns changes, to increase the storage in mCellMap + */ + virtual void GrowCellMap(PRInt32 aColCount); + + /** 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 ResetCellMap (); + + /** ResetColumns is called when the column structure of the table is changed. + * Call with caution, only when adding or removing columns, changing + * column attributes, changing the rowspan or colspan attribute of a cell, etc. + */ + virtual void ResetColumns (); + + /** 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. + */ + virtual void EnsureColumns (nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsReflowState& aReflowState, + nsReflowStatus& aStatus); + + /** Ensure that the cell map has been built for the table + */ + virtual void EnsureCellMap(); + + virtual void BuildColumnCache(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsReflowState& aReflowState, + nsReflowStatus& aStatus); + + /** called every time we discover we have a new cell to add to the table. + * This could be because we got actual cell content, because of rowspan/colspan attributes, etc. + * This method changes mCellMap as necessary to account for the new cell. + * + * @param aCell the content object created for the cell + * @param aRowIndex the row into which the cell is to be inserted + * @param aColIndex the col into which the cell is to be inserted + */ + virtual void BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex); + + /** returns the index of the first child after aStartIndex that is a row group + */ + virtual PRInt32 NextRowGroup (PRInt32 aStartIndex); + + /** returns the number of rows in this table. + * if mCellMap has been created, it is asked for the number of rows.
+ * otherwise, the content is enumerated and the rows are counted. + */ + virtual PRInt32 GetRowCount(); + + + /** return the number of columns as specified by the input. + * has 2 side effects:
+ * calls SetStartColumnIndex on each nsTableColumn
+ * sets mSpecifiedColCount.
+ */ + virtual PRInt32 GetSpecifiedColumnCount (); + +public: + virtual void DumpCellMap() const; + virtual nsCellMap* GetCellMap() const; + private: void DebugPrintCount() const; // Debugging routine @@ -346,6 +430,8 @@ private: PRInt32 mPass; // which Reflow pass are we currently in? PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change nsITableLayoutStrategy * mTableLayoutStrategy; // the layout strategy for this frame + PRInt32 mColCount; // the number of columns in this table + nsCellMap* mCellMap; // maintains the relationships between rows, cols, and cells }; #endif diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp index bd20a7e8d5a..8b7ec26ec9f 100644 --- a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp @@ -232,7 +232,7 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, mInnerTableFrame->SetReflowPass(nsTableFrame::kPASS_FIRST); nsReflowState innerTableReflowState(mInnerTableFrame, aReflowState, aReflowState.maxSize); aStatus = mInnerTableFrame->ResizeReflowPass1(aPresContext, aDesiredSize, - innerTableReflowState); + innerTableReflowState, aStatus); } mInnerTableFrame->SetReflowPass(nsTableFrame::kPASS_SECOND); // assign table width info only if the inner table frame is a first-in-flow @@ -468,11 +468,8 @@ PRBool nsTableOuterFrame::ReflowMappedChildren( nsIPresContext* aPresContex kidFrame, aState.processingCaption?"caption":"inner"); // Get top margin for this kid - nsIStyleContextPtr kidSC; - - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - const nsStyleSpacing* kidSpacing = - (const nsStyleSpacing*)kidSC->GetStyleData(eStyleStruct_Spacing); + const nsStyleSpacing* kidSpacing; + kidFrame->GetStyleData(eStyleStruct_Spacing, (nsStyleStruct *&)kidSpacing); nsMargin kidMargin; kidSpacing->CalcMarginFor(kidFrame, kidMargin); nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMargin); @@ -904,12 +901,8 @@ nsTableOuterFrame::ReflowChild( nsIFrame* aKidFrame, if (PR_TRUE==aState.processingCaption) { // it's a caption, find out if it's top or bottom // Resolve style - nsIStyleContextPtr captionStyleContext; - - aKidFrame->GetStyleContext(aPresContext, captionStyleContext.AssignRef()); - NS_ASSERTION(captionStyleContext.IsNotNull(), "null style context for caption"); - const nsStyleText* captionStyle = - (const nsStyleText*)captionStyleContext->GetStyleData(eStyleStruct_Text); + const nsStyleText* captionStyle; + aKidFrame->GetStyleData(eStyleStruct_Text, ( nsStyleStruct *&)captionStyle); NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption"); if ((eStyleUnit_Enumerated == captionStyle->mVerticalAlign.GetUnit()) && (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->mVerticalAlign.GetIntValue())) @@ -975,31 +968,32 @@ void nsTableOuterFrame::CreateChildFrames(nsIPresContext* aPresContext) mCaptionFrames = new nsVoidArray(); // create caption frames as needed nsIFrame *lastTopCaption = nsnull; - for (PRInt32 kidIndex=0; /* nada */ ;kidIndex++) { - nsIContentPtr caption = mContent->ChildAt(kidIndex); // caption: REFCNT++ - if (caption.IsNull()) { + for (PRInt32 kidIndex=0; /* nada */ ;kidIndex++) + { + nsIContentPtr caption = mContent->ChildAt(kidIndex); + if (PR_TRUE==caption.IsNull()) { break; } - const PRInt32 contentType = ((nsTableContent *)(nsIContent*)caption)->GetType(); - if (contentType==nsITableContent::kTableCaptionType) + // Resolve style + nsIStyleContextPtr captionSC = + aPresContext->ResolveStyleContextFor(caption, this); + NS_ASSERTION(captionSC.IsNotNull(), "bad style context for caption."); + nsStyleDisplay *childDisplay = (nsStyleDisplay*)captionSC->GetStyleData(eStyleStruct_Display); + if (NS_STYLE_DISPLAY_TABLE_CAPTION == childDisplay->mDisplay) { - // Resolve style - nsIStyleContextPtr captionStyleContext = - aPresContext->ResolveStyleContextFor(caption, this); - NS_ASSERTION(captionStyleContext.IsNotNull(), "bad style context for caption."); - const nsStyleText* captionStyle = - (const nsStyleText*)captionStyleContext->GetStyleData(eStyleStruct_Text); + const nsStyleText* captionTextStyle = + (const nsStyleText*)captionSC->GetStyleData(eStyleStruct_Text); // create the frame nsIFrame *captionFrame=nsnull; frameCreated = ((nsIHTMLContent*)(nsIContent*)caption)->CreateFrame(aPresContext, - this, captionStyleContext, captionFrame); + this, captionSC, captionFrame); if (NS_OK!=frameCreated) return; // SEC: an error!!!! mChildCount++; // Link child frame into the list of children - if ((eStyleUnit_Enumerated == captionStyle->mVerticalAlign.GetUnit()) && - (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->mVerticalAlign.GetIntValue())) + if ((eStyleUnit_Enumerated == captionTextStyle->mVerticalAlign.GetUnit()) && + (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionTextStyle->mVerticalAlign.GetIntValue())) { // bottom captions get added to the end of the outer frame child list prevKidFrame->SetNextSibling(captionFrame); prevKidFrame = captionFrame; @@ -1027,7 +1021,8 @@ void nsTableOuterFrame::CreateChildFrames(nsIPresContext* aPresContext) mCaptionFrames->AppendElement(captionFrame); } else - { + { // otherwise I know there are no more captions + // I'm assuming the frames were created in the correct order break; } } @@ -1085,16 +1080,12 @@ nsTableOuterFrame::ResizeReflowTopCaptionsPass2(nsIPresContext* aPresCont nsTableCaptionFrame *captionFrame = (nsTableCaptionFrame *)mCaptionFrames->ElementAt(captionIndex); // Resolve style - nsIStyleContextPtr captionStyleContext; - - captionFrame->GetStyleContext(aPresContext, captionStyleContext.AssignRef()); - NS_ASSERTION(captionStyleContext.IsNotNull(), "null style context for caption"); - const nsStyleText* captionStyle = - (const nsStyleText*)captionStyleContext->GetStyleData(eStyleStruct_Text); - NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption"); + const nsStyleText* captionTextStyle; + captionFrame->GetStyleData(eStyleStruct_Text, (nsStyleStruct *&)captionTextStyle); + NS_ASSERTION(nsnull != captionTextStyle, "null style molecule for caption"); - if ((eStyleUnit_Enumerated == captionStyle->mVerticalAlign.GetUnit()) && - (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->mVerticalAlign.GetIntValue())) + if ((eStyleUnit_Enumerated == captionTextStyle->mVerticalAlign.GetUnit()) && + (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionTextStyle->mVerticalAlign.GetIntValue())) { } else @@ -1158,10 +1149,10 @@ nsTableOuterFrame::ResizeReflowBottomCaptionsPass2(nsIPresContext* aPresContext // Resolve style /* - nsIStyleContextPtr captionStyleContext = captionFrame->GetStyleContext(aPresContext); - NS_ASSERTION(nsnull != captionStyleContext, "null style context for caption"); + nsIStyleContextPtr captionSC = captionFrame->GetStyleContext(aPresContext); + NS_ASSERTION(nsnull != captionSC, "null style context for caption"); nsStyleMolecule* captionStyle = - (nsStyleMolecule*)captionStyleContext->GetData(eStyleStruct_Molecule); + (nsStyleMolecule*)captionSC->GetData(eStyleStruct_Molecule); NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption"); */ // reflow the caption diff --git a/mozilla/layout/html/table/src/nsTablePart.cpp b/mozilla/layout/html/table/src/nsTablePart.cpp index 9d5b4d35c63..812ed54d46c 100644 --- a/mozilla/layout/html/table/src/nsTablePart.cpp +++ b/mozilla/layout/html/table/src/nsTablePart.cpp @@ -24,7 +24,6 @@ #include "nsTableCaption.h" #include "nsTableRow.h" #include "nsTableCell.h" -#include "nsCellMap.h" #include "nsHTMLParts.h" #include "nsIPresContext.h" #include "nsContainerFrame.h" @@ -57,17 +56,6 @@ const char *nsTablePart::kColTagString="COL"; const char *nsTablePart::kDataCellTagString="TD"; const char *nsTablePart::kHeaderCellTagString="TH"; -CellData::CellData() -{ - mCell = nsnull; - mRealCell = nsnull; - mOverlap = nsnull; -} - -CellData::~CellData() -{} - - /*---------- nsTablePart implementation -----------*/ /** @@ -118,14 +106,15 @@ CellData::~CellData() * */ +//QQQ can remove mColCount? + /** constructor * I do not check or addref aTag because my superclass does that for me */ nsTablePart::nsTablePart(nsIAtom* aTag) : nsHTMLContainer(aTag), mColCount(0), - mSpecifiedColCount(0), - mCellMap(0) + mSpecifiedColCount(0) { } @@ -135,8 +124,7 @@ nsTablePart::nsTablePart(nsIAtom* aTag) nsTablePart::nsTablePart (nsIAtom* aTag, PRInt32 aColumnCount) : nsHTMLContainer(aTag), mColCount(aColumnCount), - mSpecifiedColCount(0), - mCellMap(0) + mSpecifiedColCount(0) { } @@ -144,10 +132,6 @@ nsTablePart::nsTablePart (nsIAtom* aTag, PRInt32 aColumnCount) */ nsTablePart::~nsTablePart() { - if (nsnull!=mCellMap) - { - delete mCellMap; - } } /** @@ -177,153 +161,13 @@ nsrefcnt nsTablePart::Release(void) return mRefCnt; } +/** assumes that mColCount has been set */ +///QQQQQ can be removed? PRInt32 nsTablePart::GetMaxColumns () { - if (nsnull == mCellMap) - { - BuildCellMap (); - } return mColCount; } - // XXX what do rows with no cells turn into? -PRInt32 nsTablePart::GetRowCount () -{ - // if we've already built the cellMap, ask it for the row count - if (nsnull != mCellMap) - return mCellMap->GetRowCount(); - - // otherwise, we need to compute it by walking our children - int rowCount = 0; - int index = ChildCount (); - while (0 < index) - { - nsIContent *child = ChildAt (--index); // child: REFCNT++ - nsTableContent *tableContent = (nsTableContent *)child; - const int contentType = tableContent->GetType(); - if (contentType == nsITableContent::kTableRowGroupType) - rowCount += ((nsTableRowGroup *)tableContent)->GetRowCount (); - NS_RELEASE(child); // child: REFCNT-- - } - return rowCount; -} - -/* counts columns in column groups */ -PRInt32 nsTablePart::GetSpecifiedColumnCount () -{ - if (mSpecifiedColCount < 0) - { - mSpecifiedColCount = 0; - int count = ChildCount (); - for (int index = 0; index < count; index++) - { - nsIContent *child = ChildAt (index); // child: REFCNT++ - nsTableContent *tableContent = (nsTableContent *)child; - const int contentType = tableContent->GetType(); - if (contentType == nsITableContent::kTableColGroupType) - { - ((nsTableColGroup *)tableContent)->SetStartColumnIndex (mSpecifiedColCount); - mSpecifiedColCount += ((nsTableColGroup *)tableContent)->GetColumnCount (); - } - NS_RELEASE(child); // child: REFCNT-- - } - } - return mSpecifiedColCount; -} - -// returns the actual cell map, not a copy, so don't mess with it! -nsCellMap* nsTablePart::GetCellMap() const -{ - return mCellMap; -} - - -/* call when the cell structure has changed. mCellMap will be rebuilt on demand. */ -void nsTablePart::ResetCellMap () -{ - if (nsnull==mCellMap) - delete mCellMap; - mCellMap = nsnull; // for now, will rebuild when needed -} - -/* call when column structure has changed. */ -void nsTablePart::ResetColumns () -{ - mSpecifiedColCount = -1; - if (nsnull != mCellMap) - { - int colCount = GetSpecifiedColumnCount (); - GrowCellMap (colCount); // make sure we're at least as big as specified columns - } - else - mColCount = 0; // we'll compute later (as part of building cell map) -} - -/** 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 nsTablePart::EnsureColumns() -{ - if (nsnull!=mCellMap) - { - PRInt32 actualColumns = 0; - PRInt32 numColGroups = ChildCount(); - nsTableColGroup *lastColGroup = nsnull; - for (PRInt32 colGroupIndex = 0; colGroupIndex < numColGroups; colGroupIndex++) - { - nsTableContent *colGroup = (nsTableContent*)ChildAt(colGroupIndex); // colGroup: REFCNT++ - const int contentType = colGroup->GetType(); - if (contentType==nsTableContent::kTableColGroupType) - { - PRInt32 numCols = ((nsTableColGroup *)colGroup)->GetColumnCount(); - actualColumns += numCols; - lastColGroup = (nsTableColGroup *)colGroup; - NS_RELEASE(colGroup); - } - else if (contentType==nsTableContent::kTableRowGroupType) - { - NS_RELEASE(colGroup); - break; - } - } - if (actualColumns < mCellMap->GetColCount()) - { - if (nsnull==lastColGroup) - { - lastColGroup = new nsTableColGroup (PR_TRUE); - AppendColGroup(lastColGroup); - } - PRInt32 excessColumns = mCellMap->GetColCount() - actualColumns; - for ( ; excessColumns > 0; excessColumns--) - { - nsTableCol *col = new nsTableCol(PR_TRUE); - lastColGroup->AppendChild (col, PR_FALSE); - } - } - } -} - -void nsTablePart::EnsureCellMap() -{ - if (mCellMap == nsnull) - BuildCellMap(); -} - - -/** - */ -void nsTablePart::ReorderChildren() -{ - NS_ASSERTION(PR_FALSE, "not yet implemented."); -} - -void nsTablePart::NotifyContentComplete() -{ - // set the children in order - ReorderChildren(); -} - /** add a child to the table content. * tables are special because they require the content to be normalized, in order. * so this function doesn't really "append" the content, but adds it in the proper place, @@ -336,13 +180,11 @@ void nsTablePart::NotifyContentComplete() * TFOOTs (optional) * TBODY (at least 1, possibly implicit) * - * should be broken out into separate functions! */ NS_IMETHODIMP nsTablePart::AppendChild (nsIContent * aContent, PRBool aNotify) { NS_PRECONDITION(nsnull!=aContent, "bad arg"); - PRBool newCells = PR_FALSE; PRBool contentHandled = PR_FALSE; // wait, stop! need to check to see if this is really tableContent or not! @@ -400,7 +242,6 @@ nsTablePart::AppendChild (nsIContent * aContent, PRBool aNotify) } // group is guaranteed to be allocated at this point rv = group->AppendChild(aContent, PR_FALSE); - newCells = (PRBool)(NS_OK==rv); contentHandled = PR_TRUE; NS_RELEASE(group); // group: REFCNT-- } @@ -408,7 +249,6 @@ nsTablePart::AppendChild (nsIContent * aContent, PRBool aNotify) { // TODO: switch Append* to COM interfaces result = AppendColumn((nsTableCol *)aContent); - newCells = result; contentHandled = PR_TRUE; } else if (contentType == nsITableContent::kTableCaptionType) @@ -419,22 +259,14 @@ nsTablePart::AppendChild (nsIContent * aContent, PRBool aNotify) else if (contentType == nsITableContent::kTableRowGroupType) { result = AppendRowGroup((nsTableRowGroup *)aContent); - if (PR_TRUE==result) - { - newCells = PR_TRUE; - } - else + if (PR_FALSE==result) rv=NS_ERROR_FAILURE; contentHandled = PR_TRUE; // whether we succeeded or not, we've "handled" this request } else if (contentType == nsITableContent::kTableColGroupType) { result = AppendColGroup((nsTableColGroup *)aContent); - if (PR_TRUE==result) - { - newCells = PR_TRUE; - } - else + if (PR_FALSE==result) rv = NS_ERROR_FAILURE; contentHandled = PR_TRUE; // whether we succeeded or not, we've "handled" this request } @@ -462,11 +294,6 @@ nsTablePart::AppendChild (nsIContent * aContent, PRBool aNotify) } result = caption->AppendChild (aContent, PR_FALSE); } - /* if we added new cells, we need to fix up the cell map */ - if (newCells) - { - ResetCellMap (); - } } NS_RELEASE(tableContentInterface); // tableContentInterface: REFCNT-- @@ -492,7 +319,6 @@ nsTablePart::InsertChildAt(nsIContent * aContent, PRInt32 aIndex, if (NS_OK == rv) { tableContent->SetTable (this); - ResetCellMap (); } } @@ -522,7 +348,6 @@ nsTablePart::ReplaceChildAt (nsIContent *aContent, PRInt32 aIndex, if (nsnull != lastChild) tableContent->SetTable (nsnull); tableContent->SetTable (this); - ResetCellMap (); } NS_IF_RELEASE(lastChild); // lastChild: REFCNT-- } @@ -552,7 +377,6 @@ nsTablePart::RemoveChildAt (PRInt32 aIndex, PRBool aNotify) if (nsnull != lastChild) ((nsTableRow *)tableContent)->SetRowGroup (nsnull); tableContent->SetTable(nsnull); - ResetCellMap (); } } NS_IF_RELEASE(lastChild); @@ -752,287 +576,6 @@ PRBool nsTablePart::AppendCaption(nsTableCaption *aContent) return (PRBool)(NS_OK==rv); } -/* return the index of the first row group after aStartIndex */ -PRInt32 nsTablePart::NextRowGroup (PRInt32 aStartIndex) -{ - int index = aStartIndex; - int count = ChildCount (); - - while (++index < count) - { - nsIContent * child = ChildAt (index); // child: REFCNT++ - nsTableContent *tableContent = (nsTableColGroup *)child; - const int contentType = tableContent->GetType(); - NS_RELEASE(child); // child: REFCNT-- - if (contentType == nsITableContent::kTableRowGroupType) - return index; - } - return count; -} - -// XXX This should be computed incrementally and updated -// automatically when rows are added/deleted. To do this, however, -// we need to change the way the ContentSink works and somehow -// notify this table when a row is modified. We can give the rows -// parent pointers, but that would bite. - -// XXX nuke this; instead pretend the content sink is working -// incrementally like we want it to and build up the data a row at a -// time. - -void nsTablePart::BuildCellMap () -{ - if (gsDebug==PR_TRUE) printf("Build Cell Map...\n"); - int rowCount = GetRowCount (); - if (0 == rowCount) - { - if (gsDebug==PR_TRUE) printf("0 row count. Returning.\n"); - mColCount = GetSpecifiedColumnCount (); // at least set known column count - EnsureColumns(); - return; - } - - // Make an educated guess as to how many columns we have. It's - // only a guess because we can't know exactly until we have - // processed the last row. - - int childCount = ChildCount (); - int groupIndex = NextRowGroup (-1); - if (0 == mColCount) - mColCount = GetSpecifiedColumnCount (); - if (0 == mColCount) // no column parts - { - nsTableRowGroup *rowGroup = (nsTableRowGroup*)(ChildAt (groupIndex)); // rowGroup: REFCNT++ - nsTableRow *row = (nsTableRow *)(rowGroup->ChildAt (0)); // row: REFCNT++ - mColCount = row->GetMaxColumns (); - if (gsDebug==PR_TRUE) printf("mColCount=0 at start. Guessing col count to be %d from a row.\n", mColCount); - NS_RELEASE(rowGroup); // rowGroup: REFCNT-- - NS_RELEASE(row); // row: REFCNT-- - } - if (nsnull==mCellMap) - mCellMap = new nsCellMap(rowCount, mColCount); - else - mCellMap->Reset(rowCount, mColCount); - if (gsDebug==PR_TRUE) printf("mCellMap set to (%d, %d)\n", rowCount, mColCount); - int rowStart = 0; - if (gsDebug==PR_TRUE) printf("childCount is %d\n", childCount); - while (groupIndex < childCount) - { - if (gsDebug==PR_TRUE) printf(" groupIndex is %d\n", groupIndex); - if (gsDebug==PR_TRUE) printf(" rowStart is %d\n", rowStart); - nsTableRowGroup *rowGroup = (nsTableRowGroup *)ChildAt (groupIndex); // rowGroup: REFCNT++ - int groupRowCount = rowGroup->ChildCount (); - if (gsDebug==PR_TRUE) printf(" groupRowCount is %d\n", groupRowCount); - for (int rowIndex = 0; rowIndex < groupRowCount; rowIndex++) - { - nsTableRow *row = (nsTableRow *)(rowGroup->ChildAt (rowIndex)); // row: REFCNT++ - int cellCount = row->ChildCount (); - int cellIndex = 0; - int colIndex = 0; - if (gsDebug==PR_TRUE) - DumpCellMap(); - if (gsDebug==PR_TRUE) printf(" rowIndex is %d, row->SetRowIndex(%d)\n", rowIndex, rowIndex + rowStart); - row->SetRowIndex (rowIndex + rowStart); - while (colIndex < mColCount) - { - if (gsDebug==PR_TRUE) printf(" colIndex = %d, with mColCount = %d\n", colIndex, mColCount); - CellData *data =mCellMap->GetCellAt(rowIndex + rowStart, colIndex); - if (nsnull == data) - { - if (gsDebug==PR_TRUE) printf(" null data from GetCellAt(%d,%d)\n", rowIndex+rowStart, colIndex); - if (gsDebug==PR_TRUE) printf(" cellIndex=%d, cellCount=%d)\n", cellIndex, cellCount); - if (cellIndex < cellCount) - { - nsTableCell* cell = (nsTableCell *) row->ChildAt (cellIndex); // cell: REFCNT++ - if (gsDebug==PR_TRUE) printf(" calling BuildCellIntoMap(cell, %d, %d), and incrementing cellIndex\n", rowIndex + rowStart, colIndex); - BuildCellIntoMap (cell, rowIndex + rowStart, colIndex); - NS_RELEASE(cell); // cell: REFCNT-- - cellIndex++; - } - } - colIndex++; - } - - if (cellIndex < cellCount) - { - // We didn't use all the cells in this row up. Grow the cell - // data because we now know that we have more columns than we - // originally thought we had. - if (gsDebug==PR_TRUE) printf(" calling GrowCellMap because cellIndex < %d\n", cellIndex, cellCount); - GrowCellMap (cellCount); - while (cellIndex < cellCount) - { - if (gsDebug==PR_TRUE) printf(" calling GrowCellMap again because cellIndex < %d\n", cellIndex, cellCount); - GrowCellMap (colIndex + 1); // ensure enough cols in map, may be low due to colspans - CellData *data =mCellMap->GetCellAt(rowIndex + rowStart, colIndex); - if (data == nsnull) - { - nsTableCell* cell = (nsTableCell *) row->ChildAt (cellIndex); // cell: REFCNT++ - BuildCellIntoMap (cell, rowIndex + rowStart, colIndex); - cellIndex++; - NS_RELEASE(cell); // cell: REFCNT-- - } - colIndex++; - } - } - NS_RELEASE(row); // row: REFCNT-- - } - NS_RELEASE(rowGroup); // rowGroup: REFCNT-- - rowStart += groupRowCount; - groupIndex = NextRowGroup (groupIndex); - } - if (gsDebug==PR_TRUE) - DumpCellMap (); - EnsureColumns(); -} - -/** - */ -void nsTablePart::DumpCellMap () const -{ - printf("dumping CellMap:\n"); - if (nsnull != mCellMap) - { - int rowCount = mCellMap->GetRowCount(); - int cols = mCellMap->GetColCount(); - for (int r = 0; r < rowCount; r++) - { - if (gsDebug==PR_TRUE) - { printf("row %d", r); - printf(": "); - } - for (int c = 0; c < cols; c++) - { - CellData *cd =mCellMap->GetCellAt(r, c); - if (cd != nsnull) - { - if (cd->mCell != nsnull) - { - printf("C%d,%d ", r, c); - printf(" "); - } - else - { - nsTableCell *cell = cd->mRealCell->mCell; - nsTableRow *row = cell->GetRow(); - int rr = row->GetRowIndex (); - int cc = cell->GetColIndex (); - printf("S%d,%d ", rr, cc); - if (cd->mOverlap != nsnull) - { - cell = cd->mOverlap->mCell; - nsTableRow* row2 = cell->GetRow(); - rr = row2->GetRowIndex (); - cc = cell->GetColIndex (); - printf("O%d,%c ", rr, cc); - NS_RELEASE(row2); - } - else - printf(" "); - NS_RELEASE(row); - } - } - else - printf("---- "); - } - printf("\n"); - } - } - else - printf ("[nsnull]"); -} - -void nsTablePart::BuildCellIntoMap (nsTableCell *aCell, PRInt32 aRowIndex, PRInt32 aColIndex) -{ - NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); - NS_PRECONDITION (aColIndex < mColCount, "bad column index arg"); - NS_PRECONDITION (aRowIndex < GetRowCount(), "bad row index arg"); - - // Setup CellMap for this cell - int rowSpan = GetEffectiveRowSpan (aRowIndex, aCell); - int colSpan = aCell->GetColSpan (); - if (gsDebug==PR_TRUE) printf(" BuildCellIntoMap. rowSpan = %d, colSpan = %d\n", rowSpan, colSpan); - - // Grow the mCellMap array if we will end up addressing - // some new columns. - if (mColCount < (aColIndex + colSpan)) - { - if (gsDebug==PR_TRUE) printf(" mColCount=%dmCell = aCell; - data->mRealCell = data; - if (gsDebug==PR_TRUE) printf(" calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex); - mCellMap->SetCellAt(data, aRowIndex, aColIndex); - aCell->SetColIndex (aColIndex); - - // Create CellData objects for the rows that this cell spans. Set - // their mCell to nsnull and their mRealCell to point to data. If - // there were no column overlaps then we could use the same - // CellData object for each row that we span... - if ((1 < rowSpan) || (1 < colSpan)) - { - if (gsDebug==PR_TRUE) printf(" spans\n"); - for (int rowIndex = 0; rowIndex < rowSpan; rowIndex++) - { - if (gsDebug==PR_TRUE) printf(" rowIndex = %d\n", rowIndex); - int workRow = aRowIndex + rowIndex; - if (gsDebug==PR_TRUE) printf(" workRow = %d\n", workRow); - for (int colIndex = 0; colIndex < colSpan; colIndex++) - { - if (gsDebug==PR_TRUE) printf(" colIndex = %d\n", colIndex); - int workCol = aColIndex + colIndex; - if (gsDebug==PR_TRUE) printf(" workCol = %d\n", workCol); - CellData *testData = mCellMap->GetCellAt(workRow, workCol); - if (nsnull == testData) - { - CellData *spanData = new CellData (); - spanData->mRealCell = data; - if (gsDebug==PR_TRUE) printf(" null GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol); - mCellMap->SetCellAt(spanData, workRow, workCol); - } - else if ((0 < rowIndex) || (0 < colIndex)) - { // we overlap, replace existing data, it might be shared - if (gsDebug==PR_TRUE) printf(" overlapping Cell from GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol); - CellData *overlap = new CellData (); - overlap->mCell = testData->mCell; - overlap->mRealCell = testData->mRealCell; - overlap->mOverlap = data; - mCellMap->SetCellAt(overlap, workRow, workCol); - } - } - } - } -} - -void nsTablePart::GrowCellMap (PRInt32 aColCount) -{ - if (nsnull!=mCellMap) - { - if (mColCount < aColCount) - { - mCellMap->GrowTo(aColCount); - } - mColCount = aColCount; - } -} - -PRInt32 nsTablePart::GetEffectiveRowSpan (PRInt32 aRowIndex, nsTableCell *aCell) -{ - NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); - NS_PRECONDITION (0<=aRowIndex && aRowIndexGetRowSpan (); - int rowCount = GetRowCount (); - if (rowCount < (aRowIndex + rowSpan)) - return (rowCount - aRowIndex); - return rowSpan; -} - - /** * Create a frame object that will layout this table. */ diff --git a/mozilla/layout/html/table/src/nsTablePart.h b/mozilla/layout/html/table/src/nsTablePart.h index 28ab6a71692..65ee68905ff 100644 --- a/mozilla/layout/html/table/src/nsTablePart.h +++ b/mozilla/layout/html/table/src/nsTablePart.h @@ -23,7 +23,7 @@ #include "nsHTMLContainer.h" // forward declarations -class nsTableCell; +class nsTableCellFrame; class nsCellMap; class nsTableRowGroup; class nsTableColGroup; @@ -35,15 +35,15 @@ class nsTableCaption; * in addition, if fOverlap is non-null then it will point to the * other cell that overlaps this position * @see nsCellMap - * @see nsTablePart::BuildCellMap - * @see nsTablePart::GrowCellMap - * @see nsTablePart::BuildCellIntoMap + * @see nsTableFrame::BuildCellMap + * @see nsTableFrame::GrowCellMap + * @see nsTableFrame::BuildCellIntoMap * */ class CellData { public: - nsTableCell *mCell; + nsTableCellFrame *mCell; CellData *mRealCell; CellData *mOverlap; @@ -100,41 +100,6 @@ public: /* public Table methods */ - /** 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 ResetCellMap (); - - /** ResetColumns is called when the column structure of the table is changed. - * Call with caution, only when adding or removing columns, changing - * column attributes, changing the rowspan or colspan attribute of a cell, etc. - */ - virtual void ResetColumns (); - - /** 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. - */ - virtual void EnsureColumns (); - - /** Ensure that the cell map has been built for the table - */ - virtual void EnsureCellMap(); - - /** return the number of columns as specified by the input. - * has 2 side effects:
- * calls SetStartColumnIndex on each nsTableColumn
- * sets mSpecifiedColCount.
- */ - virtual PRInt32 GetSpecifiedColumnCount (); - - /** returns the number of rows in this table. - * if mCellMap has been created, it is asked for the number of rows.
- * otherwise, the content is enumerated and the rows are counted. - */ - virtual PRInt32 GetRowCount(); - /** returns the actual number of columns in this table.
* as a side effect, will call BuildCellMap to constuct mCellMap if needed. */ @@ -153,10 +118,6 @@ public: nsIStyleContext* aStyleContext, nsIFrame*& aResult); - /** called when the input stream knows that the input has been completely consumed. - * this is a hook for future optimizations. - */ - virtual void NotifyContentComplete(); static void GetTableBorder(nsIHTMLContent* aContent, nsIStyleContext* aContext, @@ -169,40 +130,6 @@ protected: */ virtual ~nsTablePart(); - /** return the row span of a cell, taking into account row span magic at the bottom - * of a table. - * @param aRowIndex the first row that contains the cell - * @param aCell the content object representing the cell - * @return the row span, correcting for row spans that extend beyond the bottom - * of the table. - */ - virtual PRInt32 GetEffectiveRowSpan(PRInt32 aRowIndex, nsTableCell *aCell); - - /** build as much of the CellMap as possible from the info we have so far - */ - virtual void BuildCellMap (); - - /** called whenever the number of columns changes, to increase the storage in mCellMap - */ - virtual void GrowCellMap(PRInt32 aColCount); - - /** called every time we discover we have a new cell to add to the table. - * This could be because we got actual cell content, because of rowspan/colspan attributes, etc. - * This method changes mCellMap as necessary to account for the new cell. - * - * @param aCell the content object created for the cell - * @param aRowIndex the row into which the cell is to be inserted - * @param aColIndex the col into which the cell is to be inserted - */ - virtual void BuildCellIntoMap (nsTableCell *aCell, PRInt32 aRowIndex, PRInt32 aColIndex); - - /** returns the index of the first child after aStartIndex that is a row group - */ - virtual PRInt32 NextRowGroup (PRInt32 aStartIndex); - - /** obsolete! */ - virtual void ReorderChildren(); - /** append aContent to my child list * @return PR_TRUE on success, PR_FALSE if aContent could not be appended */ @@ -223,16 +150,10 @@ protected: */ virtual PRBool AppendCaption(nsTableCaption *aContent); - -public: - virtual void DumpCellMap() const; - virtual nsCellMap* GetCellMap() const; - private: PRInt32 mColCount; PRInt32 mSpecifiedColCount; - nsCellMap* mCellMap; static nsIAtom *kDefaultTag; }; diff --git a/mozilla/layout/html/table/src/nsTableRow.cpp b/mozilla/layout/html/table/src/nsTableRow.cpp index f67e65812f5..3938669a32a 100644 --- a/mozilla/layout/html/table/src/nsTableRow.cpp +++ b/mozilla/layout/html/table/src/nsTableRow.cpp @@ -110,6 +110,7 @@ nsrefcnt nsTableRow::Release(void) return mRefCnt; } +//QQQ could be removed PRInt32 nsTableRow::GetMaxColumns() { int sum = 0; diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index 0543f3670e5..47ca194ffbd 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -25,7 +25,6 @@ #include "nsTableFrame.h" #include "nsTableColFrame.h" #include "nsTableCellFrame.h" -#include "nsTableCell.h" #include "nsCellLayoutData.h" #include "nsColLayoutData.h" #include "nsIView.h" @@ -186,6 +185,10 @@ void nsTableRowFrame::PaintChildren(nsIPresContext& aPresContext, } } +void nsTableRowFrame::SetRowIndex (int aRowIndex) +{ + mRowIndex = aRowIndex; +} /** returns the height of the tallest child in this row (ignoring any cell with rowspans) */ nscoord nsTableRowFrame::GetTallestChild() const @@ -203,6 +206,18 @@ nscoord nsTableRowFrame::GetChildMaxBottomMargin() const return mCellMaxBottomMargin; } +PRInt32 nsTableRowFrame::GetMaxColumns() const +{ + int sum = 0; + nsTableCellFrame *cell=nsnull; + ChildAt(0, (nsIFrame *&)cell); + while (nsnull!=cell) { + sum += cell->GetColSpan(); + cell->GetNextSibling((nsIFrame *&)cell); + } + return sum; +} + // Collapse child's top margin with previous bottom margin nscoord nsTableRowFrame::GetTopMarginFor( nsIPresContext* aCX, @@ -264,7 +279,7 @@ void nsTableRowFrame::PlaceChild(nsIPresContext* aPresContext, { nsMargin margin(0,0,0,0); - if (aState.tableFrame->GetCellMarginData(aKidFrame, margin) == NS_OK) + if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)aKidFrame, margin) == NS_OK) { nscoord height = aKidRect.height + margin.top + margin.bottom; @@ -324,11 +339,6 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, nscoord maxCellBottomMargin = 0; for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { - - nsIContent* content = nsnull; - kidFrame->GetContent(content); // cell: REFCNT++ - nsTableCell* cell = (nsTableCell*)content; - nsSize kidAvailSize(aState.availSize); if (0>=kidAvailSize.height) kidAvailSize.height = 1; // XXX: HaCk - we don't handle negative heights yet @@ -338,13 +348,11 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, nsReflowStatus status; nsMargin kidMargin(0,0,0,0); - aState.tableFrame->GetCellMarginData(kidFrame,kidMargin); + aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame,kidMargin); if (kidMargin.top > maxCellTopMargin) maxCellTopMargin = kidMargin.top; if (kidMargin.bottom > maxCellBottomMargin) maxCellBottomMargin = kidMargin.bottom; - - // Figure out the amount of available size for the child (subtract // off the top margin we are going to apply to it) @@ -365,14 +373,14 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, kidFrame->WillReflow(*aPresContext); status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState); - nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); - aState.tableFrame->SetCellLayoutData(aPresContext, &kidLayoutData, cell); + nsCellLayoutData *kidLayoutData = new nsCellLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); + ((nsTableCellFrame *)kidFrame)->SetCellLayoutData(kidLayoutData); } else { // we're in a constrained situation, so get the avail width from the known column widths - nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData(cell); - PRInt32 cellStartingCol = cell->GetColIndex(); - PRInt32 cellColSpan = cell->GetColSpan(); + nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCellFrame *)kidFrame); + PRInt32 cellStartingCol = ((nsTableCellFrame *)kidFrame)->GetColIndex(); + PRInt32 cellColSpan = ((nsTableCellFrame *)kidFrame)->GetColSpan(); nscoord availWidth = 0; for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan); @@ -395,8 +403,6 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, NS_FRAME_IS_COMPLETE(status)?"complete":"NOT complete", desiredSize.width, desiredSize.height); } - NS_RELEASE(content); // cell: REFCNT-- - cell = nsnull; // Did the child fit? if ((kidFrame != mFirstChild) && @@ -656,14 +662,10 @@ PRBool nsTableRowFrame::PullUpChildren(nsIPresContext* aPresContext, break; } - nsIContent *content = nsnull; - kidFrame->GetContent(content); // cell: REFNCT++ - nsTableCell* cell = (nsTableCell*)content; - // we're in a constrained situation, so get the avail width from the known column widths - nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData(cell); - PRInt32 cellStartingCol = cell->GetColIndex(); - PRInt32 cellColSpan = cell->GetColSpan(); + nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCellFrame *)kidFrame); + PRInt32 cellStartingCol = ((nsTableCellFrame *)kidFrame)->GetColIndex(); + PRInt32 cellColSpan = ((nsTableCellFrame *)kidFrame)->GetColSpan(); nscoord availWidth = 0; for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan); @@ -688,8 +690,6 @@ PRBool nsTableRowFrame::PullUpChildren(nsIPresContext* aPresContext, desiredSize.width, desiredSize.height); } } - NS_RELEASE(content); // cell: REFCNT-- - cell = nsnull; // Did the child fit? if ((desiredSize.height > aState.availSize.height) && (nsnull != mFirstChild)) { @@ -900,7 +900,7 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, nsIFrame* kidFrame; // Create a child frame -- always an nsTableCell frame - nsIStyleContext* kidStyleContext = aPresContext->ResolveStyleContextFor(cell, this); + nsIStyleContext* kidStyleContext = aPresContext->ResolveStyleContextFor(cell, this, PR_TRUE); if (nsnull == kidPrevInFlow) { nsIContentDelegate* kidDel = nsnull; kidDel = cell->GetDelegate(aPresContext); @@ -911,11 +911,6 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, kidPrevInFlow->CreateContinuingFrame(aPresContext, this, kidStyleContext, kidFrame); } - /* since I'm creating the cell frame, this is the first time through reflow - * it's a good time to set the column style from the cell's width attribute - * if this is the first row - */ - SetColumnStyleFromCell(aPresContext, (nsTableCellFrame *)kidFrame, kidStyleContext); NS_RELEASE(kidStyleContext); @@ -923,7 +918,7 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, nscoord topMargin = 0; nscoord bottomMargin = 0; - if (aState.tableFrame->GetCellMarginData(kidFrame, margin) == NS_OK) + if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, margin) == NS_OK) { topMargin = margin.top; bottomMargin = margin.bottom; @@ -944,14 +939,14 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, // Reflow the child into the available space kidFrame->WillReflow(*aPresContext); status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState); - nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); - aState.tableFrame->SetCellLayoutData(aPresContext, &kidLayoutData, (nsTableCell *)cell); + nsCellLayoutData *kidLayoutData = new nsCellLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); + ((nsTableCellFrame *)kidFrame)->SetCellLayoutData(kidLayoutData); } else { // we're in a constrained situation, so get the avail width from the known column widths - nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCell *)cell); - PRInt32 cellStartingCol = ((nsTableCell *)cell)->GetColIndex(); - PRInt32 cellColSpan = ((nsTableCell *)cell)->GetColSpan(); + nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCellFrame *)kidFrame); + PRInt32 cellStartingCol = ((nsTableCellFrame *)kidFrame)->GetColIndex(); + PRInt32 cellColSpan = ((nsTableCellFrame *)kidFrame)->GetColSpan(); nscoord availWidth = 0; for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan); @@ -1154,53 +1149,6 @@ nsTableRowFrame::CreateContinuingFrame(nsIPresContext* aPresContext, return NS_OK; } -NS_METHOD -nsTableRowFrame::SetColumnStyleFromCell(nsIPresContext* aPresContext, - nsTableCellFrame* aCellFrame, - nsIStyleContext* aCellSC) -{ - // if this cell is in the first row, then the width attribute - // also acts as the width attribute for the entire column - if ((nsnull!=aCellSC) && (nsnull!=aCellFrame)) - { - if (0==mRowIndex) - { - // get the cell style info - const nsStylePosition* cellPosition = (const nsStylePosition*) aCellSC->GetStyleData(eStyleStruct_Position); - if ((eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) || - (eStyleUnit_Percent==cellPosition->mWidth.GetUnit())) { - - // compute the width per column spanned - PRInt32 colSpan = aCellFrame->GetColSpan(); - nsTableFrame *tableFrame; - mGeometricParent->GetGeometricParent((nsIFrame *&)tableFrame); - for (PRInt32 i=0; iGetColumnFrame(i+aCellFrame->GetColIndex(), colFrame); - // get the column style and set the width attribute - nsIStyleContextPtr colSC; - colFrame->GetStyleContext(aPresContext, colSC.AssignRef()); - nsStylePosition* colPosition = (nsStylePosition*) colSC->GetMutableStyleData(eStyleStruct_Position); - // set the column width attribute - if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) - { - nscoord width = cellPosition->mWidth.GetCoordValue(); - colPosition->mWidth.SetCoordValue(width/colSpan); - } - else - { - float width = cellPosition->mWidth.GetPercentValue(); - colPosition->mWidth.SetPercentValue(width/colSpan); - } - } - } - } - } - return NS_OK; -} - nsresult nsTableRowFrame::NewFrame( nsIFrame** aInstancePtrResult, nsIContent* aContent, nsIFrame* aParent) diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.h b/mozilla/layout/html/table/src/nsTableRowFrame.h index 87774963d04..f3aa68d79e1 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowFrame.h @@ -102,6 +102,14 @@ public: nscoord GetChildMaxTopMargin() const; nscoord GetChildMaxBottomMargin() const; + PRInt32 GetMaxColumns() const; + + /** returns the ordinal position of this row in its table */ + virtual PRInt32 GetRowIndex() const; + + /** set this row's starting row index */ + virtual void SetRowIndex (int aRowIndex); + // For DEBUGGING Purposes Only NS_IMETHOD MoveTo(nscoord aX, nscoord aY); NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); @@ -163,10 +171,6 @@ protected: RowReflowState& aState, nsSize* aMaxElementSize); - NS_METHOD SetColumnStyleFromCell(nsIPresContext * aPresContext, - nsTableCellFrame* aCellFrame, - nsIStyleContext * aCellSC); - private: PRInt32 mRowIndex; nscoord mTallestCell; // not my height, but the height of my tallest child @@ -182,4 +186,10 @@ inline void nsTableRowFrame::Init(PRInt32 aRowIndex) mRowIndex = aRowIndex; } +inline PRInt32 nsTableRowFrame::GetRowIndex() const +{ + NS_ASSERTION(0<=mRowIndex, "bad state: row index"); + return (mRowIndex); +} + #endif diff --git a/mozilla/layout/html/table/src/nsTableRowGroup.cpp b/mozilla/layout/html/table/src/nsTableRowGroup.cpp index f6a6efea2d7..55087fb724c 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroup.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroup.cpp @@ -89,6 +89,7 @@ nsTableRowGroup::~nsTableRowGroup() } /** return the number of columns in the widest row in this group */ +///QQQ could be removed PRInt32 nsTableRowGroup::GetMaxColumns() { // computed every time for now, could be cached PRInt32 result = 0; @@ -187,10 +188,7 @@ nsTableRowGroup::CreateFrame(nsIPresContext* aPresContext, void nsTableRowGroup::ResetCellMap () { - // GREG: enable this assertion when the content notification code is checked in - // NS_ASSERTION(nsnull!=mTable, "illegal table content state"); - if (nsnull != mTable) - mTable->ResetCellMap (); + } NS_IMETHODIMP @@ -211,10 +209,7 @@ nsTableRowGroup::AppendChild (nsIContent *aContent, PRBool aNotify) if (NS_OK==result) { ((nsTableRow *)aContent)->SetRowGroup (this); - // after each row insertion, make sure we have corresponding column content objects - if (nsnull!=mTable) - mTable->EnsureColumns(); - // also make sure the table cell map gets rebuilt + // make sure the table cell map gets rebuilt ResetCellMap (); } } diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 578c6a375b4..6fef74a1d99 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -743,7 +743,7 @@ nsTableRowGroupFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, // Resolve style nsIStyleContextPtr kidSC = - aPresContext->ResolveStyleContextFor(kid, this); + aPresContext->ResolveStyleContextFor(kid, this, PR_TRUE); const nsStyleSpacing* kidSpacing = (const nsStyleSpacing*) kidSC->GetStyleData(eStyleStruct_Spacing); nsMargin kidMargin; diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h index 15df8b1a379..a0d440b25b0 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h @@ -91,6 +91,9 @@ public: */ NS_IMETHOD GetRowGroupType(nsIAtom *& aType); + /** return the number of contained rows */ + PRInt32 GetRowCount (); + // For DEBUGGING Purposes Only NS_IMETHOD MoveTo(nscoord aX, nscoord aY); NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); @@ -157,5 +160,13 @@ private: }; +//XXX: change this if row groups can contain non-row types +// in this case, iterate through kids and add 1 if the kid's display type is "row" +inline PRInt32 nsTableRowGroupFrame::GetRowCount () +{ + PRInt32 result = 0; + ChildCount(result); + return result; +} #endif diff --git a/mozilla/layout/style/nsCSSParser.cpp b/mozilla/layout/style/nsCSSParser.cpp index f6f6815f65c..6753d4a333b 100644 --- a/mozilla/layout/style/nsCSSParser.cpp +++ b/mozilla/layout/style/nsCSSParser.cpp @@ -1257,10 +1257,23 @@ static PRInt32 kDirectionKTable[] = { }; static PRInt32 kDisplayKTable[] = { - KEYWORD_NONE, NS_STYLE_DISPLAY_NONE, - KEYWORD_BLOCK, NS_STYLE_DISPLAY_BLOCK, - KEYWORD_INLINE, NS_STYLE_DISPLAY_INLINE, - KEYWORD_LIST_ITEM, NS_STYLE_DISPLAY_LIST_ITEM, + KEYWORD_NONE, NS_STYLE_DISPLAY_NONE, + KEYWORD_BLOCK, NS_STYLE_DISPLAY_BLOCK, + KEYWORD_INLINE, NS_STYLE_DISPLAY_INLINE, + KEYWORD_LIST_ITEM, NS_STYLE_DISPLAY_LIST_ITEM, + KEYWORD_MARKER, NS_STYLE_DISPLAY_MARKER, + KEYWORD_RUN_IN, NS_STYLE_DISPLAY_RUN_IN, + KEYWORD_COMPACT, NS_STYLE_DISPLAY_COMPACT, + KEYWORD_TABLE, NS_STYLE_DISPLAY_TABLE, + KEYWORD_INLINE_TABLE, NS_STYLE_DISPLAY_INLINE_TABLE, + KEYWORD_TABLE_ROW_GROUP, NS_STYLE_DISPLAY_TABLE_ROW_GROUP, + KEYWORD_TABLE_COLUMN, NS_STYLE_DISPLAY_TABLE_COLUMN, + KEYWORD_TABLE_COLUMN_GROUP, NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP, + KEYWORD_TABLE_HEADER_GROUP, NS_STYLE_DISPLAY_TABLE_HEADER_GROUP, + KEYWORD_TABLE_FOOTER_GROUP, NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP, + KEYWORD_TABLE_ROW, NS_STYLE_DISPLAY_TABLE_ROW, + KEYWORD_TABLE_CELL, NS_STYLE_DISPLAY_TABLE_CELL, + KEYWORD_TABLE_CAPTION, NS_STYLE_DISPLAY_TABLE_CAPTION, -1 }; diff --git a/mozilla/layout/style/nsStyleContext.cpp b/mozilla/layout/style/nsStyleContext.cpp index 350cc228cb8..87671f39ecb 100644 --- a/mozilla/layout/style/nsStyleContext.cpp +++ b/mozilla/layout/style/nsStyleContext.cpp @@ -530,6 +530,7 @@ void StyleTableImpl::ResetFrom(const nsStyleTable* aParent, nsIPresContext* aPre mRules = NS_STYLE_TABLE_RULES_NONE; mCellPadding.Reset(); mCellSpacing.Reset(); + mSpan=0; } diff --git a/mozilla/layout/style/ua.css b/mozilla/layout/style/ua.css index 1c11630a359..39c3e06831e 100644 --- a/mozilla/layout/style/ua.css +++ b/mozilla/layout/style/ua.css @@ -209,7 +209,7 @@ PLAINTEXT, XMP, PRE { // Table tags TABLE { - display: block; + display: table; border-style: outset; border-color: #C0C0C0; cell-spacing: 4px; @@ -225,7 +225,7 @@ TD, TH { font-weight: normal; font-size: 11pt; line-height: 1.1; - display: block; + display: table-cell; cursor: arrow; } TH { @@ -234,8 +234,14 @@ TH { } CAPTION { text-align: center; - display: block; + display: table-caption; } +TBODY { display: table-row-group; } +THEAD { display: table-header-group; } +TFOOT { display: table-footer-group; } +COL { display: table-column; } +COLGROUP { display: table-column-group;} + MULTICOL { display: block; } diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp index d40919b3612..4274d31e4c1 100644 --- a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp +++ b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp @@ -463,7 +463,10 @@ PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresConte for (PRInt32 cellIndex = 0; cellIndexElementAt(cellIndex)); - NS_ASSERTION(nsnull != data, "bad data"); + if (nsnull==data) + { // For cells that span rows there's only cell layout data for the first row + continue; + } nsSize * cellMinSize = data->GetMaxElementSize(); NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize"); nsReflowMetrics * cellDesiredSize = data->GetDesiredSize(); diff --git a/mozilla/layout/tables/nsCellMap.h b/mozilla/layout/tables/nsCellMap.h index 57bc1498773..6d5d4d3fce2 100644 --- a/mozilla/layout/tables/nsCellMap.h +++ b/mozilla/layout/tables/nsCellMap.h @@ -28,12 +28,11 @@ class CellData; * Each cell is represented by a CellData object. * * @see CellData - * @see nsTablePart::BuildCellMap - * @see nsTablePart::GrowCellMap - * @see nsTablePart::BuildCellIntoMap + * @see nsTableFrame::BuildCellMap + * @see nsTableFrame::GrowCellMap + * @see nsTableFrame::BuildCellIntoMap * * acts like a 2-dimensional array, so all offsets are 0-indexed - TODO: inline methods */ class nsCellMap { diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp index 0663b08f1e7..2d82095503a 100644 --- a/mozilla/layout/tables/nsTableCellFrame.cpp +++ b/mozilla/layout/tables/nsTableCellFrame.cpp @@ -16,6 +16,7 @@ * Reserved. */ #include "nsTableCellFrame.h" +#include "nsCellLayoutData.h" #include "nsBodyFrame.h" #include "nsIReflowCommand.h" #include "nsIStyleContext.h" @@ -48,7 +49,8 @@ static const PRBool gsDebug = PR_FALSE; */ nsTableCellFrame::nsTableCellFrame(nsIContent* aContent, nsIFrame* aParentFrame) - : nsContainerFrame(aContent, aParentFrame) + : nsContainerFrame(aContent, aParentFrame), + mCellLayoutData(nsnull) { mRowSpan=1; mColSpan=1; @@ -57,6 +59,8 @@ nsTableCellFrame::nsTableCellFrame(nsIContent* aContent, nsTableCellFrame::~nsTableCellFrame() { + if (nsnull!=mCellLayoutData) + delete mCellLayoutData; } NS_METHOD nsTableCellFrame::Paint(nsIPresContext& aPresContext, diff --git a/mozilla/layout/tables/nsTableCellFrame.h b/mozilla/layout/tables/nsTableCellFrame.h index b8242267548..b0077954d25 100644 --- a/mozilla/layout/tables/nsTableCellFrame.h +++ b/mozilla/layout/tables/nsTableCellFrame.h @@ -22,6 +22,7 @@ #include "nsContainerFrame.h" #include "nsTableFrame.h" +class nsCellLayoutData; struct nsStyleSpacing; /** @@ -68,11 +69,16 @@ public: /** return the mapped cell's column index (starting at 0 for the first column) */ virtual PRInt32 GetColIndex(); + virtual void SetColIndex (int aColIndex); + virtual ~nsTableCellFrame(); // Get the TableFrame that contains this cell frame virtual nsTableFrame* GetTableFrame(); + nsCellLayoutData * GetCellLayoutData(); + void SetCellLayoutData(nsCellLayoutData *aData); + // For DEBUGGING Purposes Only NS_IMETHOD MoveTo(nscoord aX, nscoord aY); NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); @@ -106,6 +112,8 @@ protected: /** the starting column for this cell */ int mColIndex; + nsCellLayoutData *mCellLayoutData; + }; inline void nsTableCellFrame::Init(PRInt32 aRowSpan, PRInt32 aColSpan, PRInt32 aColIndex) @@ -127,5 +135,16 @@ inline PRInt32 nsTableCellFrame::GetColSpan() inline PRInt32 nsTableCellFrame::GetColIndex() { return mColIndex;} +inline void nsTableCellFrame::SetColIndex (int aColIndex) +{ + NS_ASSERTION(0<=aColIndex, "illegal negative column index."); + mColIndex = aColIndex; +} + +inline nsCellLayoutData * nsTableCellFrame::GetCellLayoutData() +{ return mCellLayoutData;} + +inline void nsTableCellFrame::SetCellLayoutData(nsCellLayoutData *aData) +{ mCellLayoutData = aData;} #endif diff --git a/mozilla/layout/tables/nsTableColFrame.h b/mozilla/layout/tables/nsTableColFrame.h index d6e299c7b39..e06d27b313f 100644 --- a/mozilla/layout/tables/nsTableColFrame.h +++ b/mozilla/layout/tables/nsTableColFrame.h @@ -21,7 +21,6 @@ #include "nscore.h" #include "nsContainerFrame.h" - class nsTableColFrame : public nsFrame { public: @@ -46,6 +45,9 @@ public: /** return the number of the columns the col represents. always >= 0 */ virtual int GetRepeat (); + /** set the index of the column this content object represents. must be >= 0 */ + virtual void SetColumnIndex (int aColIndex); + protected: nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame); @@ -75,6 +77,9 @@ inline nsTableColFrame::GetColumnIndex() inline nsTableColFrame::GetRepeat() { return mRepeat; } + +inline void nsTableColFrame::SetColumnIndex (int aColIndex) +{ mColIndex = aColIndex;} #endif diff --git a/mozilla/layout/tables/nsTableColGroupFrame.cpp b/mozilla/layout/tables/nsTableColGroupFrame.cpp index 024d9bb3dc2..13b2dfa02f6 100644 --- a/mozilla/layout/tables/nsTableColGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableColGroupFrame.cpp @@ -16,13 +16,13 @@ * Reserved. */ #include "nsTableColGroupFrame.h" +#include "nsTableColFrame.h" #include "nsIReflowCommand.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" #include "nsIPresContext.h" #include "nsIPtr.h" #include "nsIContentDelegate.h" -#include "nsTableContent.h" #include "nsHTMLAtoms.h" NS_DEF_PTR(nsIContent); @@ -35,6 +35,7 @@ nsTableColGroupFrame::nsTableColGroupFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsContainerFrame(aContent, aParentFrame) { + mColCount=0; } nsTableColGroupFrame::~nsTableColGroupFrame() @@ -66,7 +67,7 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext* aPresContext, LastChild(prevKidFrame); // XXX remember this... PRInt32 kidIndex = 0; - for (;;) + for (PRInt32 colIndex = 0; ;colIndex++) // colIndex is used to set the column frames' index field { nsIContentPtr kid = mContent->ChildAt(kidIndex); // kid: REFCNT++ if (kid.IsNull()) { @@ -75,7 +76,7 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext* aPresContext, // Resolve style nsIStyleContextPtr kidSC = - aPresContext->ResolveStyleContextFor(kid, this); + aPresContext->ResolveStyleContextFor(kid, this, PR_TRUE); const nsStyleSpacing* kidSpacing = (const nsStyleSpacing*) kidSC->GetStyleData(eStyleStruct_Spacing); @@ -95,6 +96,9 @@ NS_METHOD nsTableColGroupFrame::Reflow(nsIPresContext* aPresContext, // note that DidReflow is called as the result of some ancestor firing off a DidReflow above me kidFrame->SetRect(nsRect(0,0,0,0)); + // set nsColFrame-specific information + ((nsTableColFrame *)kidFrame)->SetColumnIndex(colIndex+mStartColIndex); + // Link child frame into the list of children if (nsnull != prevKidFrame) { prevKidFrame->SetNextSibling(kidFrame); @@ -178,6 +182,42 @@ NS_METHOD nsTableColGroupFrame::SetStyleContextForFirstPass(nsIPresContext* aPre return NS_OK; } + +/** 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 () +{ + if (0 == mColCount) + { + int count; + ChildCount (count); + if (0 < count) + { + nsIFrame * child = nsnull; + ChildAt(0, child); + NS_ASSERTION(nsnull!=child, "bad child"); + while (nsnull!=child) + { + nsTableColFrame *col = (nsTableColFrame *)child; + col->SetColumnIndex (mStartColIndex + mColCount); + mColCount += col->GetRepeat (); + child->GetNextSibling(child); + } + } + else + { + const nsStyleTable *tableStyle; + GetStyleData(eStyleStruct_Table, (nsStyleStruct *&)tableStyle); + mColCount = tableStyle->mSpan; + } + } + return mColCount; +} + +/* ----- static methods ----- */ + nsresult nsTableColGroupFrame::NewFrame(nsIFrame** aInstancePtrResult, nsIContent* aContent, nsIFrame* aParent) @@ -193,3 +233,5 @@ nsresult nsTableColGroupFrame::NewFrame(nsIFrame** aInstancePtrResult, *aInstancePtrResult = it; return NS_OK; } + + diff --git a/mozilla/layout/tables/nsTableColGroupFrame.h b/mozilla/layout/tables/nsTableColGroupFrame.h index e95ff0dcd0b..6fbca4d4924 100644 --- a/mozilla/layout/tables/nsTableColGroupFrame.h +++ b/mozilla/layout/tables/nsTableColGroupFrame.h @@ -50,6 +50,16 @@ public: const nsReflowState& aReflowState, nsReflowStatus& aStatus); + /** 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. + */ + virtual PRInt32 GetColumnCount (); + + virtual PRInt32 GetStartColumnIndex (); + + virtual void SetStartColumnIndex (PRInt32 aIndex); + protected: nsTableColGroupFrame(nsIContent* aContent, nsIFrame* aParentFrame); @@ -62,6 +72,22 @@ protected: */ NS_METHOD SetStyleContextForFirstPass(nsIPresContext* aPresContext); + + PRInt32 mColCount; + + /** the starting column index this col group represents. Must be >= 0. */ + PRInt32 mStartColIndex; + }; +inline int nsTableColGroupFrame::GetStartColumnIndex () +{ return mStartColIndex;} + +inline void nsTableColGroupFrame::SetStartColumnIndex (int aIndex) +{ + if (aIndex != mStartColIndex) + mColCount = 0; // our index is being changed, trigger reset of col indicies, don't propogate back to table + mStartColIndex = aIndex; +} + #endif diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index fba3efca02a..d60cb22365e 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -22,11 +22,11 @@ #include "nsIContent.h" #include "nsIContentDelegate.h" #include "nsCellMap.h" -#include "nsTableContent.h" -#include "nsTableCell.h" #include "nsTableCellFrame.h" -#include "nsTableCol.h" +#include "nsTableCol.h" // needed for building implicit columns +#include "nsTableColGroup.h" // needed for building implicit colgroups #include "nsTableColFrame.h" +#include "nsTableColGroupFrame.h" #include "nsTableRowFrame.h" #include "nsTableRowGroupFrame.h" #include "nsColLayoutData.h" @@ -65,9 +65,19 @@ static const PRBool gsDebugMBP = PR_FALSE; NS_DEF_PTR(nsIStyleContext); NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsTableContent); -NS_DEF_PTR(nsTableCol); -NS_DEF_PTR(nsTableCell); + +/* ----------- CellData ---------- */ + +/* CellData is the info stored in the cell map */ +CellData::CellData() +{ + mCell = nsnull; + mRealCell = nsnull; + mOverlap = nsnull; +} + +CellData::~CellData() +{} /* ----------- InnerTableReflowState ---------- */ @@ -250,11 +260,12 @@ void ColumnInfoCache::GetColumnsByType(const nsStyleUnit aType, -/* ----------- nsTableFrame ---------- */ +/* --------------------- nsTableFrame -------------------- */ nsTableFrame::nsTableFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsContainerFrame(aContent, aParentFrame), + mCellMap(nsnull), mColumnLayoutData(nsnull), mColCache(nsnull), mColumnWidths(nsnull), @@ -286,22 +297,483 @@ void nsTableFrame::DeleteColumnLayoutData() nsTableFrame::~nsTableFrame() { + if (nsnull!=mCellMap) + delete mCellMap; + DeleteColumnLayoutData(); + if (nsnull!=mColumnWidths) delete [] mColumnWidths; + if (nsnull!=mTableLayoutStrategy) delete mTableLayoutStrategy; + if (nsnull!=mColCache) delete mColCache; } +/* ****** CellMap methods ******* */ +/* return the index of the first row group after aStartIndex */ +PRInt32 nsTableFrame::NextRowGroup (PRInt32 aStartIndex) +{ + int index = aStartIndex; + int count; + ChildCount(count); + nsIFrame * child; + ChildAt (index+1, child); + + while (++index < count) + { + const nsStyleDisplay *childDisplay; + child->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) + return index; + child->GetNextSibling(child); + } + return count; +} + +/* counts columns in column groups */ +PRInt32 nsTableFrame::GetSpecifiedColumnCount () +{ + mColCount=0; + nsIFrame * colGroup; + ChildAt (0, (nsIFrame *&)colGroup); + while (nsnull!=colGroup) + { + const nsStyleDisplay *childDisplay; + colGroup->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) + { + mColCount += ((nsTableColGroupFrame *)colGroup)->GetColumnCount(); + } + else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) + { + break; + } + colGroup->GetNextSibling(colGroup); + } + return mColCount; +} + +PRInt32 nsTableFrame::GetRowCount () +{ + PRInt32 rowCount = 0; + + if (nsnull != mCellMap) + return mCellMap->GetRowCount(); + + nsIFrame *child=nsnull; + ChildAt(0, child); + while (nsnull!=child) + { + const nsStyleDisplay *childDisplay; + child->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) + rowCount += ((nsTableRowGroupFrame *)child)->GetRowCount (); + child->GetNextSibling(child); + } + return rowCount; +} +// return the rows spanned by aCell starting at aRowIndex +// note that this is different from just the rowspan of aCell +// (that would be GetEffectiveRowSpan (indexOfRowThatContains_aCell, aCell) +PRInt32 nsTableFrame::GetEffectiveRowSpan (PRInt32 aRowIndex, nsTableCellFrame *aCell) +{ + NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); + NS_PRECONDITION (0<=aRowIndex && aRowIndexGetRowSpan(); + int rowCount = GetRowCount(); + if (rowCount < (aRowIndex + rowSpan)) + return (rowCount - aRowIndex); + return rowSpan; +} + + +// returns the actual cell map, not a copy, so don't mess with it! +nsCellMap* nsTableFrame::GetCellMap() const +{ + return mCellMap; +} + +/* call when the cell structure has changed. mCellMap will be rebuilt on demand. */ +void nsTableFrame::ResetCellMap () +{ + if (nsnull!=mCellMap) + delete mCellMap; + mCellMap = nsnull; // for now, will rebuild when needed +} + +/* call when column structure has changed. */ +void nsTableFrame::ResetColumns () +{ + EnsureCellMap(); +} + +/** 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, + nsReflowMetrics& aDesiredSize, + const nsReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + EnsureCellMap(); + + PRInt32 actualColumns = 0; + nsTableColGroupFrame *lastColGroupFrame = nsnull; + nsIFrame * childFrame=nsnull; + nsIFrame * firstRowGroupFrame=nsnull; + nsIFrame * prevSibFrame=nsnull; + ChildAt (0, (nsIFrame *&)childFrame); + while (nsnull!=childFrame) + { + const nsStyleDisplay *childDisplay; + childFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) + { + PRInt32 numCols = ((nsTableColGroupFrame*)childFrame)->GetColumnCount(); + actualColumns += numCols; + lastColGroupFrame = (nsTableColGroupFrame *)childFrame; + } + else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) + { + firstRowGroupFrame = childFrame; + break; + } + prevSibFrame = childFrame; + childFrame->GetNextSibling(childFrame); + } + if (actualColumns < mCellMap->GetColCount()) + { + nsTableColGroup *lastColGroup=nsnull; + if (nsnull==lastColGroupFrame) + { + //QQQ + // need to find the generic way to stamp out this content, and ::AppendChild it + // this might be ok. no matter what my mcontent is, I know it needs a colgroup as a kid? + + // QQQ needs a ref count? + lastColGroup = new nsTableColGroup (PR_TRUE); + // XXX: how do I know whether AppendChild should notify or not? + mContent->AppendChild(lastColGroup, PR_FALSE); // was AppendColGroup + NS_ADDREF(lastColGroup); // ADDREF a: lastColGroup++ + // Resolve style for the child + nsIStyleContext* colGroupStyleContext = + aPresContext->ResolveStyleContextFor(lastColGroup, this, PR_TRUE); // kidStyleContext: REFCNT++ + nsIContentDelegate* kidDel = nsnull; + kidDel = lastColGroup->GetDelegate(aPresContext); // kidDel: REFCNT++ + nsresult rv = kidDel->CreateFrame(aPresContext, lastColGroup, this, + colGroupStyleContext, (nsIFrame *&)lastColGroupFrame); + NS_RELEASE(kidDel); // kidDel: REFCNT-- + NS_RELEASE(colGroupStyleContext); // kidStyleContenxt: REFCNT-- + + // hook lastColGroupFrame into child list + if (nsnull==firstRowGroupFrame) + { // make lastColGroupFrame the last frame + nsIFrame *lastChild=nsnull; + LastChild(lastChild); + lastChild->SetNextSibling(lastColGroupFrame); + } + else + { // insert lastColGroupFrame before the first row group frame + if (nsnull!=prevSibFrame) + { // lastColGroupFrame is inserted between prevSibFrame and lastColGroupFrame + prevSibFrame->SetNextSibling(lastColGroupFrame); + } + else + { // lastColGroupFrame is inserted as the first child of this table + mFirstChild = lastColGroupFrame; + } + lastColGroupFrame->SetNextSibling(firstRowGroupFrame); + } + mChildCount++; + } + else + { + lastColGroupFrame->GetContent((nsIContent *&)lastColGroup); // ADDREF b: lastColGroup++ + } + + PRInt32 excessColumns = mCellMap->GetColCount() - actualColumns; + for ( ; excessColumns > 0; excessColumns--) + {//QQQ + // need to find the generic way to stamp out this content, and ::AppendChild it + nsTableCol *col = new nsTableCol(PR_TRUE); + lastColGroup->AppendChild (col, PR_FALSE); + } + NS_RELEASE(lastColGroup); // ADDREF: lastColGroup-- + lastColGroupFrame->Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); + } +} + +void nsTableFrame::EnsureCellMap() +{ + if (mCellMap == nsnull) + BuildCellMap(); +} + +void nsTableFrame::BuildCellMap () +{ + if (gsDebug==PR_TRUE) printf("Build Cell Map...\n"); + + int rowCount = GetRowCount (); + NS_ASSERTION(0!=rowCount, "bad state"); + if (0 == rowCount) + { + // until we have some rows, there's nothing useful to do + return; + } + + // Make an educated guess as to how many columns we have. It's + // only a guess because we can't know exactly until we have + // processed the last row. + nsTableRowGroupFrame *rowGroup=nsnull; + PRInt32 childCount; + ChildCount (childCount); + PRInt32 groupIndex = NextRowGroup (-1); + if (0 == mColCount) + mColCount = GetSpecifiedColumnCount (); + if (0 == mColCount) // no column parts + { + ChildAt (groupIndex, (nsIFrame *&)rowGroup); + nsTableRowFrame *row; + rowGroup->ChildAt (0, (nsIFrame *&)row); + mColCount = row->GetMaxColumns (); + if (gsDebug==PR_TRUE) + printf("mColCount=0 at start. Guessing col count to be %d from a row.\n", mColCount); + } + if (nsnull==mCellMap) + mCellMap = new nsCellMap(rowCount, mColCount); + else + mCellMap->Reset(rowCount, mColCount); + if (gsDebug==PR_TRUE) printf("mCellMap set to (%d, %d)\n", rowCount, mColCount); + PRInt32 rowStart = 0; + if (gsDebug==PR_TRUE) printf("childCount is %d\n", childCount); + while (groupIndex < childCount) + { + if (gsDebug==PR_TRUE) printf(" groupIndex is %d\n", groupIndex); + if (gsDebug==PR_TRUE) printf(" rowStart is %d\n", rowStart); + ChildAt (groupIndex, (nsIFrame *&)rowGroup); + int groupRowCount; + rowGroup->ChildCount(groupRowCount); + if (gsDebug==PR_TRUE) printf(" groupRowCount is %d\n", groupRowCount); + nsTableRowFrame *row; + rowGroup->ChildAt (0, (nsIFrame *&)row); + for (PRInt32 rowIndex = 0; rowIndex < groupRowCount; rowIndex++) + { + PRInt32 cellCount; + row->ChildCount (cellCount); + PRInt32 cellIndex = 0; + PRInt32 colIndex = 0; + if (gsDebug==PR_TRUE) + DumpCellMap(); + if (gsDebug==PR_TRUE) printf(" rowIndex is %d, row->SetRowIndex(%d)\n", rowIndex, rowIndex + rowStart); + row->SetRowIndex (rowIndex + rowStart); + while (colIndex < mColCount) + { + if (gsDebug==PR_TRUE) printf(" colIndex = %d, with mColCount = %d\n", colIndex, mColCount); + CellData *data =mCellMap->GetCellAt(rowIndex + rowStart, colIndex); + if (nsnull == data) + { + if (gsDebug==PR_TRUE) printf(" null data from GetCellAt(%d,%d)\n", rowIndex+rowStart, colIndex); + if (gsDebug==PR_TRUE) printf(" cellIndex=%d, cellCount=%d)\n", cellIndex, cellCount); + if (cellIndex < cellCount) + { + nsTableCellFrame* cell; + row->ChildAt (cellIndex, (nsIFrame *&)cell); + if (gsDebug==PR_TRUE) printf(" calling BuildCellIntoMap(cell, %d, %d), and incrementing cellIndex\n", rowIndex + rowStart, colIndex); + BuildCellIntoMap (cell, rowIndex + rowStart, colIndex); + cellIndex++; + } + } + colIndex++; + } + + if (cellIndex < cellCount) + { + // We didn't use all the cells in this row up. Grow the cell + // data because we now know that we have more columns than we + // originally thought we had. + if (gsDebug==PR_TRUE) printf(" calling GrowCellMap because cellIndex < %d\n", cellIndex, cellCount); + GrowCellMap (cellCount); + while (cellIndex < cellCount) + { + if (gsDebug==PR_TRUE) printf(" calling GrowCellMap again because cellIndex < %d\n", cellIndex, cellCount); + GrowCellMap (colIndex + 1); // ensure enough cols in map, may be low due to colspans + CellData *data =mCellMap->GetCellAt(rowIndex + rowStart, colIndex); + if (data == nsnull) + { + nsTableCellFrame* cell; + row->ChildAt (cellIndex, (nsIFrame *&)cell); + BuildCellIntoMap (cell, rowIndex + rowStart, colIndex); + cellIndex++; + } + colIndex++; + } + } + row->GetNextSibling((nsIFrame *&)row); + } + rowStart += groupRowCount; + groupIndex = NextRowGroup (groupIndex); + } + if (gsDebug==PR_TRUE) + DumpCellMap (); + //QQQ EnsureColumns(); +} /** -* Lists the column layout data which turns -* around and lists the cell layout data. -* This is for debugging purposes only. -*/ + */ +void nsTableFrame::DumpCellMap () const +{ + printf("dumping CellMap:\n"); + if (nsnull != mCellMap) + { + PRInt32 rowCount = mCellMap->GetRowCount(); + PRInt32 cols = mCellMap->GetColCount(); + for (PRInt32 r = 0; r < rowCount; r++) + { + if (gsDebug==PR_TRUE) + { printf("row %d", r); + printf(": "); + } + for (PRInt32 c = 0; c < cols; c++) + { + CellData *cd =mCellMap->GetCellAt(r, c); + if (cd != nsnull) + { + if (cd->mCell != nsnull) + { + printf("C%d,%d ", r, c); + printf(" "); + } + else + { + nsTableCellFrame *cell = cd->mRealCell->mCell; + nsTableRowFrame *row; + cell->GetGeometricParent((nsIFrame *&)row); + int rr = row->GetRowIndex (); + int cc = cell->GetColIndex (); + printf("S%d,%d ", rr, cc); + if (cd->mOverlap != nsnull) + { + cell = cd->mOverlap->mCell; + nsTableRowFrame* row2; + cell->GetGeometricParent((nsIFrame *&)row); + rr = row2->GetRowIndex (); + cc = cell->GetColIndex (); + printf("O%d,%c ", rr, cc); + } + else + printf(" "); + } + } + else + printf("---- "); + } + printf("\n"); + } + } + else + printf ("[nsnull]"); +} + +void nsTableFrame::BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex) +{ + NS_PRECONDITION (nsnull!=aCell, "bad cell arg"); + NS_PRECONDITION (aColIndex < mColCount, "bad column index arg"); + NS_PRECONDITION (aRowIndex < GetRowCount(), "bad row index arg"); + + // Setup CellMap for this cell + int rowSpan = GetEffectiveRowSpan (aRowIndex, aCell); + int colSpan = aCell->GetColSpan (); + if (gsDebug==PR_TRUE) printf(" BuildCellIntoMap. rowSpan = %d, colSpan = %d\n", rowSpan, colSpan); + + // Grow the mCellMap array if we will end up addressing + // some new columns. + if (mColCount < (aColIndex + colSpan)) + { + if (gsDebug==PR_TRUE) printf(" mColCount=%dmCell = aCell; + data->mRealCell = data; + if (gsDebug==PR_TRUE) printf(" calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex); + mCellMap->SetCellAt(data, aRowIndex, aColIndex); + aCell->SetColIndex (aColIndex); + + // Create CellData objects for the rows that this cell spans. Set + // their mCell to nsnull and their mRealCell to point to data. If + // there were no column overlaps then we could use the same + // CellData object for each row that we span... + if ((1 < rowSpan) || (1 < colSpan)) + { + if (gsDebug==PR_TRUE) printf(" spans\n"); + for (int rowIndex = 0; rowIndex < rowSpan; rowIndex++) + { + if (gsDebug==PR_TRUE) printf(" rowIndex = %d\n", rowIndex); + int workRow = aRowIndex + rowIndex; + if (gsDebug==PR_TRUE) printf(" workRow = %d\n", workRow); + for (int colIndex = 0; colIndex < colSpan; colIndex++) + { + if (gsDebug==PR_TRUE) printf(" colIndex = %d\n", colIndex); + int workCol = aColIndex + colIndex; + if (gsDebug==PR_TRUE) printf(" workCol = %d\n", workCol); + CellData *testData = mCellMap->GetCellAt(workRow, workCol); + if (nsnull == testData) + { + CellData *spanData = new CellData (); + spanData->mRealCell = data; + if (gsDebug==PR_TRUE) printf(" null GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol); + mCellMap->SetCellAt(spanData, workRow, workCol); + } + else if ((0 < rowIndex) || (0 < colIndex)) + { // we overlap, replace existing data, it might be shared + if (gsDebug==PR_TRUE) printf(" overlapping Cell from GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol); + CellData *overlap = new CellData (); + overlap->mCell = testData->mCell; + overlap->mRealCell = testData->mRealCell; + overlap->mOverlap = data; + mCellMap->SetCellAt(overlap, workRow, workCol); + } + } + } + } +} + +void nsTableFrame::GrowCellMap (PRInt32 aColCount) +{ + if (nsnull!=mCellMap) + { + if (mColCount < aColCount) + { + mCellMap->GrowTo(aColCount); + } + mColCount = aColCount; + } +} + + +/* ***** Column Layout Data methods ***** */ + +/* + * Lists the column layout data which turns + * around and lists the cell layout data. + * This is for debugging purposes only. + */ void nsTableFrame::ListColumnLayoutData(FILE* out, PRInt32 aIndent) const { // if this is a continuing frame, there will be no output @@ -325,7 +797,7 @@ void nsTableFrame::ListColumnLayoutData(FILE* out, PRInt32 aIndent) const * For the TableCell in CellData, find the CellLayoutData assocated * and add it to the list **/ -void nsTableFrame::AppendLayoutData(nsVoidArray* aList, nsTableCell* aTableCell) +void nsTableFrame::AppendLayoutData(nsVoidArray* aList, nsTableCellFrame* aTableCell) { if (aTableCell != nsnull) @@ -338,18 +810,16 @@ void nsTableFrame::AppendLayoutData(nsVoidArray* aList, nsTableCell* aTableCell) void nsTableFrame::RecalcLayoutData() { + //QQQ should we ensureCellMap here? + PRInt32 colCount = mCellMap->GetColCount(); + PRInt32 rowCount = mCellMap->GetRowCount(); + PRInt32 row = 0; + PRInt32 col = 0; - nsTablePart* table = (nsTablePart*)mContent; - nsCellMap* cellMap = table->GetCellMap(); - PRInt32 colCount = cellMap->GetColCount(); - PRInt32 rowCount = cellMap->GetRowCount(); - PRInt32 row = 0; - PRInt32 col = 0; - - nsTableCell* above = nsnull; - nsTableCell* below = nsnull; - nsTableCell* left = nsnull; - nsTableCell* right = nsnull; + nsTableCellFrame* above = nsnull; + nsTableCellFrame* below = nsnull; + nsTableCellFrame* left = nsnull; + nsTableCellFrame* right = nsnull; PRInt32 edge = 0; @@ -365,51 +835,50 @@ void nsTableFrame::RecalcLayoutData() { for (col = 0; col < colCount; col++) { - nsTableCell* cell = nsnull; - CellData* cellData = cellMap->GetCellAt(row,col); + nsTableCellFrame* cell = nsnull; + CellData* cellData = mCellMap->GetCellAt(row,col); if (cellData) cell = cellData->mCell; - if (!cell) + if (nsnull==cell) continue; - PRInt32 colSpan = cell->GetColSpan(); - PRInt32 rowSpan = cell->GetRowSpan(); + PRInt32 colSpan = cell->GetColSpan(); + PRInt32 rowSpan = cell->GetRowSpan(); // clear the cells for all for edges for (edge = 0; edge < 4; edge++) boundaryCells[edge]->Clear(); - // Check to see if the cell data represents the top,left // corner of a a table cell // Check to see if cell the represents a top edge cell - if (row == 0) + if (0 == row) above = nsnull; else { - cellData = cellMap->GetCellAt(row-1,col); - if (cellData != nsnull) + cellData = mCellMap->GetCellAt(row-1,col); + if (nsnull != cellData) above = cellData->mRealCell->mCell; // Does the cell data point to the same cell? // If it is, then continue - if (above != nsnull && above == cell) + if ((nsnull != above) && (above == cell)) continue; } // Check to see if cell the represents a left edge cell - if (col == 0) + if (0 == col) left = nsnull; else { - cellData = cellMap->GetCellAt(row,col-1); + cellData = mCellMap->GetCellAt(row,col-1); if (cellData != nsnull) left = cellData->mRealCell->mCell; - if (left != nsnull && left == cell) + if ((nsnull != left) && (left == cell)) continue; } @@ -436,7 +905,7 @@ void nsTableFrame::RecalcLayoutData() // Add top edge cells if (c != col) { - cellData = cellMap->GetCellAt(r1,c); + cellData = mCellMap->GetCellAt(r1,c); if ((cellData != nsnull) && (cellData->mCell != above)) { above = cellData->mCell; @@ -453,7 +922,7 @@ void nsTableFrame::RecalcLayoutData() if (r2 < rowCount) { // Add bottom edge cells - cellData = cellMap->GetCellAt(r2,c); + cellData = mCellMap->GetCellAt(r2,c); if ((cellData != nsnull) && cellData->mCell != below) { below = cellData->mCell; @@ -478,7 +947,7 @@ void nsTableFrame::RecalcLayoutData() { if (r != row) { - cellData = cellMap->GetCellAt(r,c1); + cellData = mCellMap->GetCellAt(r,c1); if ((cellData != nsnull) && (cellData->mCell != left)) { left = cellData->mCell; @@ -495,7 +964,7 @@ void nsTableFrame::RecalcLayoutData() if (c2 < colCount) { // Add right edge cells - cellData = cellMap->GetCellAt(r,c2); + cellData = mCellMap->GetCellAt(r,c2); if ((cellData != nsnull) && (cellData->mCell != right)) { right = cellData->mCell; @@ -514,7 +983,6 @@ void nsTableFrame::RecalcLayoutData() } for (edge = 0; edge < 4; edge++) delete boundaryCells[edge]; - } @@ -611,7 +1079,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, if (PR_FALSE==IsFirstPassValid()) { // we treat the table as if we've never seen the layout data before mPass = kPASS_FIRST; - aStatus = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState); + aStatus = ResizeReflowPass1(aPresContext, aDesiredSize, aReflowState, aStatus); // check result } mPass = kPASS_SECOND; @@ -656,13 +1124,15 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, */ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState) + const nsReflowState& aReflowState, + nsReflowStatus& aStatus) { NS_PRECONDITION(aReflowState.frame == this, "bad reflow state"); NS_PRECONDITION(aReflowState.parentReflowState->frame == mGeometricParent, "bad parent reflow state"); NS_ASSERTION(nsnull!=aPresContext, "bad pres context param"); NS_ASSERTION(nsnull==mPrevInFlow, "illegal call, cannot call pass 1 on a continuing frame."); + NS_ASSERTION(nsnull != mContent, "null content"); if (PR_TRUE==gsDebug) printf("nsTableFrame::ResizeReflow Pass1 for %p: maxSize=%d,%d\n", this, aReflowState.maxSize.width, aReflowState.maxSize.height); @@ -671,12 +1141,6 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, mChildCount = 0; mFirstContentOffset = mLastContentOffset = 0; - NS_ASSERTION(nsnull != mContent, "null content"); - nsTablePart* table = (nsTablePart*)mContent; - - // Ensure the cell map - table->EnsureCellMap(); - nsSize availSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); // availSize is the space available at any given time in the process nsSize maxSize(0, 0); // maxSize is the size of the largest child so far in the process nsSize kidMaxSize(0,0); @@ -685,7 +1149,7 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, nscoord maxAscent = 0; nscoord maxDescent = 0; PRInt32 kidIndex = 0; - PRInt32 lastIndex = table->ChildCount(); + PRInt32 lastIndex = mContent->ChildCount(); PRInt32 contentOffset=0; nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */ @@ -708,7 +1172,7 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, * TBody, in order */ for (;;) { - nsIContentPtr kid = table->ChildAt(kidIndex); // kid: REFCNT++ + nsIContentPtr kid = mContent->ChildAt(kidIndex); // kid: REFCNT++ if (kid.IsNull()) { result = NS_FRAME_COMPLETE; break; @@ -716,16 +1180,13 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, mLastContentIsComplete = PR_TRUE; - const PRInt32 contentType = ((nsTableContent *)(nsIContent*)kid)->GetType(); - if (contentType!=nsITableContent::kTableCaptionType) + // Resolve style + nsIStyleContextPtr kidStyleContext = + aPresContext->ResolveStyleContextFor(kid, this, PR_TRUE); + NS_ASSERTION(kidStyleContext.IsNotNull(), "null style context for kid"); + const nsStyleDisplay *childDisplay = (nsStyleDisplay*)kidStyleContext->GetStyleData(eStyleStruct_Display); + if (NS_STYLE_DISPLAY_TABLE_CAPTION != childDisplay->mDisplay) { - // Resolve style - nsIStyleContextPtr kidStyleContext = - aPresContext->ResolveStyleContextFor(kid, this); - NS_ASSERTION(kidStyleContext.IsNotNull(), "null style context for kid"); - - // SEC: TODO: when content is appended or deleted, be sure to clear out the frame hierarchy!!!! - // get next frame, creating one if needed nsIFrame* kidFrame=nsnull; if (nsnull!=prevKidFrame) @@ -800,6 +1261,9 @@ nsReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, } } + BuildColumnCache(aPresContext, aDesiredSize, aReflowState, aStatus); + EnsureCellMap();//QQQ have to determine where the right place for this is now that it's a frame-side operation + //QQQ cell map used to be forced before loop // Recalculate Layout Dependencies RecalcLayoutData(); @@ -984,10 +1448,9 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, } // If this is a footer row group, add it to the list of footer row groups - nsIAtom * tFootTag = NS_NewAtom(nsTablePart::kRowGroupFootTagString); // tFootTag: REFCNT++ - nsIAtom *kidType=nsnull; - ((nsTableRowGroupFrame *)aKidFrame)->GetRowGroupType(kidType); - if (tFootTag==kidType) + const nsStyleDisplay *childDisplay; + aKidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay) { if (nsnull==aState.footerList) aState.footerList = new nsVoidArray(); @@ -1004,8 +1467,8 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, aKidFrame->GetOrigin(origin); origin.y -= aState.footerHeight; aKidFrame->MoveTo(origin.x, origin.y); - nsIAtom * tBodyTag = NS_NewAtom(nsTablePart::kRowGroupBodyTagString); // tBodyTag: REFCNT++ - if (tBodyTag==kidType) + // XXX do we need to check for headers here also, or is that implicit? + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay) { PRInt32 numFooters = aState.footerList->Count(); for (PRInt32 footerIndex = 0; footerIndex < numFooters; footerIndex++) @@ -1020,10 +1483,8 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, } } } - NS_RELEASE(tBodyTag); } } - NS_RELEASE(tFootTag); // Update the maximum element size if (PR_TRUE==aState.firstRowGroup) @@ -1073,7 +1534,7 @@ PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext* aPresContext, PRInt32 childCount = 0; nsIFrame* prevKidFrame = nsnull; - + mLastContentOffset = 0; // Remember our original mLastContentIsComplete so that if we end up // having to push children, we have the correct value to hand to // PushChildren. @@ -1089,18 +1550,12 @@ PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext* aPresContext, desiredSize.width=desiredSize.height=desiredSize.ascent=desiredSize.descent=0; nsReflowStatus status; - // Get top margin for this kid - nsIContentPtr kid; - - kidFrame->GetContent(kid.AssignRef()); - const int contentType = ((nsTableContent *)(nsIContent*)kid)->GetType(); - if (contentType != nsITableContent::kTableCaptionType) + const nsStyleDisplay *childDisplay; + kidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_CAPTION != childDisplay->mDisplay) { // for all colgroups and rowgroups... - nsIStyleContextPtr kidSC; - - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - const nsStyleSpacing* kidSpacing = (const nsStyleSpacing*) - kidSC->GetStyleData(eStyleStruct_Spacing); + const nsStyleSpacing* kidSpacing; + kidFrame->GetStyleData(eStyleStruct_Spacing, ((nsStyleStruct *&)kidSpacing)); nsMargin kidMargin; kidSpacing->CalcMarginFor(kidFrame, kidMargin); @@ -1144,7 +1599,9 @@ PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext* aPresContext, nsRect kidRect (0, 0, desiredSize.width, desiredSize.height); kidRect.x += aState.leftInset + kidMargin.left; kidRect.y += aState.topInset + aState.y; - if (contentType == nsITableContent::kTableRowGroupType) + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) { PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize, kidMaxElementSize); @@ -1155,6 +1612,7 @@ PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext* aPresContext, } } childCount++; + kidFrame->GetContentIndex(mLastContentOffset); // Remember where we just were in case we end up pushing children prevKidFrame = kidFrame; @@ -1363,12 +1821,11 @@ PRBool nsTableFrame::PullUpChildren(nsIPresContext* aPresContext, nsRect kidRect (0, 0, kidSize.width, kidSize.height); //kidRect.x += kidMol->margin.left; kidRect.y += aState.y; - nsIContent* content=nsnull; - kidFrame->GetContent(content); - NS_ASSERTION(nsnull!=content, "bad kid"); - const int contentType = ((nsITableContent*)content)->GetType(); - NS_RELEASE(content); - if (contentType == nsITableContent::kTableRowGroupType) + const nsStyleDisplay *childDisplay; + kidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) { PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize, *pKidMaxElementSize); } @@ -1535,7 +1992,7 @@ nsTableFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, // Resolve style for the child nsIStyleContextPtr kidStyleContext = - aPresContext->ResolveStyleContextFor(kid, this); + aPresContext->ResolveStyleContextFor(kid, this, PR_TRUE); // Figure out how we should treat the child nsIFrame* kidFrame; @@ -1580,12 +2037,11 @@ nsTableFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, //aState.y += topMargin; nsRect kidRect (0, 0, kidSize.width, kidSize.height); kidRect.y += aState.y; - nsIContent* content=nsnull; - kidFrame->GetContent(content); - NS_ASSERTION(nsnull!=content, "bad kid"); - const int contentType = ((nsITableContent*)content)->GetType(); - NS_RELEASE(content); - if (contentType == nsITableContent::kTableRowGroupType) + const nsStyleDisplay *childDisplay; + kidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) { PlaceChild(aPresContext, aState, kidFrame, kidRect, aMaxElementSize, *pKidMaxElementSize); } @@ -1779,15 +2235,15 @@ void nsTableFrame::ShrinkWrapChildren(nsIPresContext* aPresContext, else kidFrame->GetNextSibling(kidFrame); NS_ASSERTION(nsnull != kidFrame, "bad kid frame"); - nsTableContentPtr kid; - - kidFrame->GetContent((nsIContent*&)(kid.AssignRef())); // kid: REFCNT++ - NS_ASSERTION(kid.IsNotNull(), "bad kid"); nscoord topInnerMargin = 0; nscoord bottomInnerMargin = 0; - if (kid->GetType() == nsITableContent::kTableRowGroupType) + const nsStyleDisplay *childDisplay; + kidFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) { /* Step 1: set the row height to the height of the tallest cell, * and resize all cells in that row to that height (except cells with rowspan>1) @@ -2002,6 +2458,51 @@ void nsTableFrame::VerticallyAlignChildren(nsIPresContext* aPresContext, { } +NS_METHOD +nsTableFrame::SetColumnStyleFromCell(nsIPresContext * aPresContext, + nsTableCellFrame* aCellFrame, + nsTableRowFrame * aRowFrame) +{ + // if this cell is in the first row, then the width attribute + // also acts as the width attribute for the entire column + if ((nsnull!=aPresContext) && (nsnull!=aCellFrame) && (nsnull!=aRowFrame)) + { + if (0==aRowFrame->GetRowIndex()) + { + // get the cell style info + const nsStylePosition* cellPosition; + aCellFrame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)cellPosition); + if ((eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) || + (eStyleUnit_Percent==cellPosition->mWidth.GetUnit())) { + // compute the width per column spanned + PRInt32 colSpan = aCellFrame->GetColSpan(); + for (PRInt32 i=0; iGetColIndex(), colFrame); + // get the column style and set the width attribute + nsIStyleContext* colSC; + colFrame->GetStyleContext(aPresContext, colSC); + nsStylePosition* colPosition = (nsStylePosition*) colSC->GetMutableStyleData(eStyleStruct_Position); + // set the column width attribute + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) + { + nscoord width = cellPosition->mWidth.GetCoordValue(); + colPosition->mWidth.SetCoordValue(width/colSpan); + } + else + { + float width = cellPosition->mWidth.GetPercentValue(); + colPosition->mWidth.SetPercentValue(width/colSpan); + } + } + } + } + } + return NS_OK; +} + /* there's an easy way and a hard way. The easy way is to look in our * cache and pull the frame from there. * If the cache isn't built yet, then we have to go hunting. @@ -2029,16 +2530,16 @@ NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aCol NS_ASSERTION (PR_FALSE, "scanned the frame hierarchy and no column frame could be found."); break; } - nsIContentPtr kid; - childFrame->GetContent(kid.AssignRef()); - const PRInt32 contentType = ((nsTableContent *)(nsIContent*)kid)->GetType(); - if (contentType==nsITableContent::kTableColGroupType) + const nsStyleDisplay *childDisplay; + childFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) { - nsTableColGroup *colGroup = (nsTableColGroup *)((nsIContent*)kid); - PRInt32 colGroupStartingIndex = colGroup->GetStartColumnIndex(); + PRInt32 colGroupStartingIndex = ((nsTableColGroupFrame *)childFrame)->GetStartColumnIndex(); if (aColIndex >= colGroupStartingIndex) { // the cell's col might be in this col group - if (aColIndex < colGroupStartingIndex + colGroup->ChildCount()) + PRInt32 childCount; + childFrame->ChildCount(childCount); + if (aColIndex < colGroupStartingIndex + childCount) { // yep, we've found it childFrame->ChildAt(aColIndex-colGroupStartingIndex, (nsIFrame *&)aColFrame); break; @@ -2051,6 +2552,64 @@ NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aCol return NS_OK; } +void nsTableFrame::BuildColumnCache( nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsReflowState& aReflowState, + nsReflowStatus& aStatus + ) +{ + EnsureColumns(aPresContext, aDesiredSize, aReflowState, aStatus); + if (nsnull==mColCache) + { + mColCache = new ColumnInfoCache(mColCount); + nsIFrame * childFrame = mFirstChild; + while (nsnull!=childFrame) + { // for every child, if it's a col group then get the columns + const nsStyleDisplay *childDisplay; + childFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) + { + nsTableColFrame *colFrame=nsnull; + childFrame->ChildAt(0, (nsIFrame *&)colFrame); + while (nsnull!=colFrame) + { // for every column, create an entry in the column cache + // assumes that the col style has been twiddled to account for first cell width attribute + const nsStylePosition* colPosition; + colFrame->GetStyleData(eStyleStruct_Position, ((nsStyleStruct *&)colPosition)); + mColCache->AddColumnInfo(colPosition->mWidth.GetUnit(), colFrame->GetColumnIndex()); + colFrame->GetNextSibling((nsIFrame *&)colFrame); + } + } + else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) + { // for every cell in every row, call SetCellLayoutData with the cached info + // QQQ we can probably just leave the info in the table cell frame, not cache it here + nsIFrame *rowFrame; + childFrame->ChildAt(0, rowFrame); + while (nsnull!=rowFrame) + { + nsIFrame *cellFrame; + rowFrame->ChildAt(0, cellFrame); + while (nsnull!=cellFrame) + { + nsCellLayoutData *cld = ((nsTableCellFrame*)cellFrame)->GetCellLayoutData(); + SetCellLayoutData(aPresContext, cld, (nsTableCellFrame*)cellFrame); + /* this is the first time we are guaranteed to have both the cell frames + * and the column frames, so it's a good time to + * set the column style from the cell's width attribute (if this is the first row) + */ + SetColumnStyleFromCell(aPresContext, (nsTableCellFrame *)cellFrame, (nsTableRowFrame *)rowFrame); + cellFrame->GetNextSibling(cellFrame); + } + rowFrame->GetNextSibling(rowFrame); + } + } + childFrame->GetNextSibling(childFrame); + } + } +} + nsVoidArray * nsTableFrame::GetColumnLayoutData() { nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); @@ -2064,10 +2623,11 @@ nsVoidArray * nsTableFrame::GetColumnLayoutData() * PR_FALSE if there was an error, such as aRow or aCol being invalid */ PRBool nsTableFrame::SetCellLayoutData(nsIPresContext* aPresContext, - nsCellLayoutData * aData, nsTableCell *aCell) + nsCellLayoutData * aData, nsTableCellFrame *aCell) { - NS_ASSERTION(nsnull != aData, "bad arg"); - NS_ASSERTION(nsnull != aCell, "bad arg"); + NS_ASSERTION(nsnull != aPresContext, "bad arg aPresContext"); + NS_ASSERTION(nsnull != aData, "bad arg aData"); + NS_ASSERTION(nsnull != aCell, "bad arg aCell"); PRBool result = PR_TRUE; @@ -2081,69 +2641,56 @@ PRBool nsTableFrame::SetCellLayoutData(nsIPresContext* aPresContext, { if (nsnull==mColumnLayoutData) { + PRInt32 rows = GetRowCount(); mColumnLayoutData = new nsVoidArray(); NS_ASSERTION(nsnull != mColumnLayoutData, "bad alloc"); - nsTablePart * tablePart = (nsTablePart *)mContent; - PRInt32 cols = tablePart->GetMaxColumns(); - PRInt32 rows = tablePart->GetRowCount(); - mColCache = new ColumnInfoCache(cols); - PRInt32 tableKidCount = tablePart->ChildCount(); + PRInt32 tableKidCount = mContent->ChildCount(); nsIFrame * colGroupFrame = mFirstChild; - for (PRInt32 i=0; iChildAt(i); - NS_ASSERTION(tableKid.IsNotNull(), "bad kid"); - const int contentType = tableKid->GetType(); - if (contentType == nsITableContent::kTableColGroupType) + const nsStyleDisplay *childDisplay; + colGroupFrame->GetStyleData(eStyleStruct_Display, ((nsStyleStruct *&)childDisplay)); + if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) { - PRInt32 colsInGroup = tableKid->ChildCount(); - for (PRInt32 j=0; jChildAt(0, (nsIFrame *&)colFrame); + while (nsnull!=colFrame) { // TODO: unify these 2 kinds of column data // TODO: cache more column data, like the mWidth.GetUnit and what its value - - nsTableColFrame *colFrame=nsnull; - // XXX Why is this using ChildAt() instead of just walking the sibling list? - colGroupFrame->ChildAt(j, (nsIFrame *&)colFrame); nsColLayoutData *colData = new nsColLayoutData(colFrame, rows); mColumnLayoutData->AppendElement((void *)colData); - - // also add the column to the column cache - // assumes that the col style has been twiddled to account for first cell width attribute - nsIStyleContextPtr colSC; - colFrame->GetStyleContext(aPresContext, colSC.AssignRef()); - const nsStylePosition* colPosition = (const nsStylePosition*)colSC->GetStyleData(eStyleStruct_Position); - mColCache->AddColumnInfo(colPosition->mWidth.GetUnit(), colFrame->GetColumnIndex()); + colFrame->GetNextSibling((nsIFrame *&)colFrame); } } // can't have col groups after row groups, so stop if you find a row group - else if (contentType == nsITableContent::kTableRowGroupType) + else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay || + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay ) { break; } + i++; ChildAt(i, colGroupFrame); // can't use colGroupFrame->GetNextSibling because it hasn't been set yet } } - // create cell layout data objects for the passed in data, one per column spanned. - // For now, divide width equally between spanned columns - // XXX Add a GetRowIndex() member function to nsTableCell and we can save the - // reference counting overhead... - nsTableRow *row = aCell->GetRow(); // row: ADDREF++ - PRInt32 rowIndex = row->GetRowIndex(); - NS_RELEASE(row); // row: ADDREF-- - PRInt32 colSpan = aCell->GetColSpan(); PRInt32 firstColIndex = aCell->GetColIndex(); - - for (PRInt32 i = 0; i < colSpan; i++) { - if (i > 0) { - int j = 5; - } - nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex + i)); - nsVoidArray *col = colData->GetCells(); - if (gsDebugCLD) printf (" ~ SetCellLayoutData with row = %d, firstCol = %d, colSpan = %d, colData = %ld, col=%ld\n", - rowIndex, firstColIndex, colSpan, colData, col); - + nsTableRowFrame *row; + aCell->GetGeometricParent((nsIFrame*&)row); + PRInt32 rowIndex = row->GetRowIndex(); + PRInt32 colSpan = aCell->GetColSpan(); + nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex)); + nsVoidArray *col = colData->GetCells(); + if (gsDebugCLD) printf (" ~ SetCellLayoutData with row = %d, firstCol = %d, colSpan = %d, colData = %ld, col=%ld\n", + rowIndex, firstColIndex, colSpan, colData, col); + /* this logic looks wrong wrong wrong + it seems to add an entries in col (the array of cells for a column) for aCell + based on colspan. This is weird, because you would expect one entry in each + column spanned for aCell, not multiple entries in the same col. + */ + for (PRInt32 i=0; iGetMaxElementSize(); nsSize partialCellSize(*cellSize); partialCellSize.width = (cellSize->width)/colSpan; @@ -2171,7 +2718,7 @@ PRBool nsTableFrame::SetCellLayoutData(nsIPresContext* aPresContext, * @return nsnull if there was an error, such as aRow or aCol being invalid * otherwise, the data is returned. */ -nsCellLayoutData * nsTableFrame::GetCellLayoutData(nsTableCell *aCell) +nsCellLayoutData * nsTableFrame::GetCellLayoutData(nsTableCellFrame *aCell) { NS_ASSERTION(nsnull != aCell, "bad arg"); @@ -2186,20 +2733,24 @@ nsCellLayoutData * nsTableFrame::GetCellLayoutData(nsTableCell *aCell) { PRInt32 firstColIndex = aCell->GetColIndex(); nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex)); - nsTableRow *row = aCell->GetRow(); // row: ADDREF++ - PRInt32 rowIndex = row->GetRowIndex(); - NS_RELEASE(row); // row: ADDREF-- - + nsTableRowFrame *rowFrame; + aCell->GetGeometricParent((nsIFrame *&)rowFrame); + PRInt32 rowIndex = rowFrame->GetRowIndex(); result = colData->ElementAt(rowIndex); + #ifdef NS_DEBUG // Do some sanity checking if (nsnull != result) { - nsIContent* content; - result->GetCellFrame()->GetContent(content); - NS_ASSERTION(content == aCell, "unexpected cell"); - NS_IF_RELEASE(content); + nsIContent* inputContent; + nsIContent* resultContent; + result->GetCellFrame()->GetContent(resultContent); + aCell->GetContent(inputContent); + NS_ASSERTION(resultContent == inputContent, "unexpected cell"); + NS_IF_RELEASE(inputContent); + NS_IF_RELEASE(resultContent); } #endif + } } return result; @@ -2365,7 +2916,8 @@ void nsTableFrame::MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBo nsIStyleContext* styleContext = mStyleContext; - const nsStyleColor* colorData = (const nsStyleColor*)styleContext->GetStyleData(eStyleStruct_Color); + const nsStyleColor* colorData = (const nsStyleColor*) + styleContext->GetStyleData(eStyleStruct_Color); // Look until we find a style context with a NON-transparent background color while (styleContext) @@ -2477,21 +3029,15 @@ NS_METHOD nsTableFrame::DidSetStyleContext(nsIPresContext* aPresContext) return NS_OK; } -NS_METHOD nsTableFrame::GetCellMarginData(nsIFrame* aKidFrame, nsMargin& aMargin) +NS_METHOD nsTableFrame::GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& aMargin) { nsresult result = NS_ERROR_NOT_INITIALIZED; - nsIContent* content = nsnull; - aKidFrame->GetContent(content); - - if (nsnull != content) + if (nsnull != aKidFrame) { - nsTableCell* cell = (nsTableCell*)content; - - nsCellLayoutData* layoutData = GetCellLayoutData(cell); + nsCellLayoutData* layoutData = GetCellLayoutData(aKidFrame); if (layoutData) result = layoutData->GetMargin(aMargin); - NS_RELEASE(content); } return result; @@ -2597,11 +3143,10 @@ PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, until the style resolution stuff does the cool stuff about splitting style between outer and inner */ // begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! - nsIStyleContext* parentStyle = nsnull; nsIFrame * parent = nsnull; aTableFrame->GetGeometricParent(parent); - parent->GetStyleContext(nsnull, parentStyle); - const nsStylePosition* tablePosition = (const nsStylePosition*)parentStyle->GetStyleData(eStyleStruct_Position); + const nsStylePosition* tablePosition; + parent->GetStyleData(eStyleStruct_Position, ((nsStyleStruct *&)tablePosition)); // end REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! switch (tablePosition->mWidth.GetUnit()) { case eStyleUnit_Auto: // specified auto width diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h index e37723fc3ad..be1d16507d8 100644 --- a/mozilla/layout/tables/nsTableFrame.h +++ b/mozilla/layout/tables/nsTableFrame.h @@ -22,11 +22,12 @@ #include "nsContainerFrame.h" #include "nsStyleCoord.h" +class nsCellMap; class nsCellLayoutData; -class nsTableCell; class nsVoidArray; class nsTableCellFrame; class nsTableColFrame; +class nsTableRowFrame; class CellData; class nsITableLayoutStrategy; class nsHTMLValue; @@ -120,6 +121,14 @@ public: nsReflowMetrics& aDesiredSize, nsSize* aMaxElementSize); + /** allow the cell and row attributes to effect the column frame + * currently, the only reason this exists is to support the HTML "rule" + * that a width attribute on a cell in the first column sets the column width. + */ + virtual NS_METHOD SetColumnStyleFromCell(nsIPresContext * aPresContext, + nsTableCellFrame* aCellFrame, + nsTableRowFrame * aRowFrame); + /** return the column frame corresponding to the given column index * there are two ways to do this, depending on whether we have cached * column information yet. @@ -140,15 +149,15 @@ public: * @return PR_TRUE if the data was successfully associated with a Cell * PR_FALSE if there was an error, such as aRow or aCol being invalid */ - virtual PRBool SetCellLayoutData(nsIPresContext* aPresContext, + virtual PRBool SetCellLayoutData(nsIPresContext * aPresContext, nsCellLayoutData * aData, - nsTableCell *aCell); + nsTableCellFrame * aCell); /** Get the layout data associated with the cell at (aRow,aCol) * @return PR_NULL if there was an error, such as aRow or aCol being invalid * otherwise, the data is returned. */ - virtual nsCellLayoutData * GetCellLayoutData(nsTableCell *aCell); + virtual nsCellLayoutData * GetCellLayoutData(nsTableCellFrame *aCell); /** * DEBUG METHOD @@ -167,16 +176,11 @@ public: * Calculate Layout Information * */ - void AppendLayoutData(nsVoidArray* aList, nsTableCell* aTableCell); + void AppendLayoutData(nsVoidArray* aList, nsTableCellFrame* aTableCell); void RecalcLayoutData(); - void ResetCellLayoutData( nsTableCell* aCell, - nsTableCell* aAbove, - nsTableCell* aBelow, - nsTableCell* aLeft, - nsTableCell* aRight); // Get cell margin information - NS_IMETHOD GetCellMarginData(nsIFrame* aKidFrame, nsMargin& aMargin); + NS_IMETHOD GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& aMargin); /** get cached column information for a subset of the columns * @@ -220,7 +224,8 @@ protected: */ virtual nsReflowStatus ResizeReflowPass1(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState); + const nsReflowState& aReflowState, + nsReflowStatus& aStatus); /** second pass of ResizeReflow. * lays out all table content with aMaxSize(computed_table_width, given_table_height) @@ -328,6 +333,85 @@ protected: void MapHTMLBorderStyle(nsStyleSpacing& aSpacingStyle, nscoord aBorderWidth); PRBool ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult); + /** return the row span of a cell, taking into account row span magic at the bottom + * of a table. + * @param aRowIndex the first row that contains the cell + * @param aCell the content object representing the cell + * @return the row span, correcting for row spans that extend beyond the bottom + * of the table. + */ + virtual PRInt32 GetEffectiveRowSpan(PRInt32 aRowIndex, nsTableCellFrame *aCell); + + /** build as much of the CellMap as possible from the info we have so far + */ + virtual void BuildCellMap (); + + /** called whenever the number of columns changes, to increase the storage in mCellMap + */ + virtual void GrowCellMap(PRInt32 aColCount); + + /** 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 ResetCellMap (); + + /** ResetColumns is called when the column structure of the table is changed. + * Call with caution, only when adding or removing columns, changing + * column attributes, changing the rowspan or colspan attribute of a cell, etc. + */ + virtual void ResetColumns (); + + /** 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. + */ + virtual void EnsureColumns (nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsReflowState& aReflowState, + nsReflowStatus& aStatus); + + /** Ensure that the cell map has been built for the table + */ + virtual void EnsureCellMap(); + + virtual void BuildColumnCache(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsReflowState& aReflowState, + nsReflowStatus& aStatus); + + /** called every time we discover we have a new cell to add to the table. + * This could be because we got actual cell content, because of rowspan/colspan attributes, etc. + * This method changes mCellMap as necessary to account for the new cell. + * + * @param aCell the content object created for the cell + * @param aRowIndex the row into which the cell is to be inserted + * @param aColIndex the col into which the cell is to be inserted + */ + virtual void BuildCellIntoMap (nsTableCellFrame *aCell, PRInt32 aRowIndex, PRInt32 aColIndex); + + /** returns the index of the first child after aStartIndex that is a row group + */ + virtual PRInt32 NextRowGroup (PRInt32 aStartIndex); + + /** returns the number of rows in this table. + * if mCellMap has been created, it is asked for the number of rows.
+ * otherwise, the content is enumerated and the rows are counted. + */ + virtual PRInt32 GetRowCount(); + + + /** return the number of columns as specified by the input. + * has 2 side effects:
+ * calls SetStartColumnIndex on each nsTableColumn
+ * sets mSpecifiedColCount.
+ */ + virtual PRInt32 GetSpecifiedColumnCount (); + +public: + virtual void DumpCellMap() const; + virtual nsCellMap* GetCellMap() const; + private: void DebugPrintCount() const; // Debugging routine @@ -346,6 +430,8 @@ private: PRInt32 mPass; // which Reflow pass are we currently in? PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change nsITableLayoutStrategy * mTableLayoutStrategy; // the layout strategy for this frame + PRInt32 mColCount; // the number of columns in this table + nsCellMap* mCellMap; // maintains the relationships between rows, cols, and cells }; #endif diff --git a/mozilla/layout/tables/nsTableOuterFrame.cpp b/mozilla/layout/tables/nsTableOuterFrame.cpp index bd20a7e8d5a..8b7ec26ec9f 100644 --- a/mozilla/layout/tables/nsTableOuterFrame.cpp +++ b/mozilla/layout/tables/nsTableOuterFrame.cpp @@ -232,7 +232,7 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, mInnerTableFrame->SetReflowPass(nsTableFrame::kPASS_FIRST); nsReflowState innerTableReflowState(mInnerTableFrame, aReflowState, aReflowState.maxSize); aStatus = mInnerTableFrame->ResizeReflowPass1(aPresContext, aDesiredSize, - innerTableReflowState); + innerTableReflowState, aStatus); } mInnerTableFrame->SetReflowPass(nsTableFrame::kPASS_SECOND); // assign table width info only if the inner table frame is a first-in-flow @@ -468,11 +468,8 @@ PRBool nsTableOuterFrame::ReflowMappedChildren( nsIPresContext* aPresContex kidFrame, aState.processingCaption?"caption":"inner"); // Get top margin for this kid - nsIStyleContextPtr kidSC; - - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - const nsStyleSpacing* kidSpacing = - (const nsStyleSpacing*)kidSC->GetStyleData(eStyleStruct_Spacing); + const nsStyleSpacing* kidSpacing; + kidFrame->GetStyleData(eStyleStruct_Spacing, (nsStyleStruct *&)kidSpacing); nsMargin kidMargin; kidSpacing->CalcMarginFor(kidFrame, kidMargin); nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMargin); @@ -904,12 +901,8 @@ nsTableOuterFrame::ReflowChild( nsIFrame* aKidFrame, if (PR_TRUE==aState.processingCaption) { // it's a caption, find out if it's top or bottom // Resolve style - nsIStyleContextPtr captionStyleContext; - - aKidFrame->GetStyleContext(aPresContext, captionStyleContext.AssignRef()); - NS_ASSERTION(captionStyleContext.IsNotNull(), "null style context for caption"); - const nsStyleText* captionStyle = - (const nsStyleText*)captionStyleContext->GetStyleData(eStyleStruct_Text); + const nsStyleText* captionStyle; + aKidFrame->GetStyleData(eStyleStruct_Text, ( nsStyleStruct *&)captionStyle); NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption"); if ((eStyleUnit_Enumerated == captionStyle->mVerticalAlign.GetUnit()) && (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->mVerticalAlign.GetIntValue())) @@ -975,31 +968,32 @@ void nsTableOuterFrame::CreateChildFrames(nsIPresContext* aPresContext) mCaptionFrames = new nsVoidArray(); // create caption frames as needed nsIFrame *lastTopCaption = nsnull; - for (PRInt32 kidIndex=0; /* nada */ ;kidIndex++) { - nsIContentPtr caption = mContent->ChildAt(kidIndex); // caption: REFCNT++ - if (caption.IsNull()) { + for (PRInt32 kidIndex=0; /* nada */ ;kidIndex++) + { + nsIContentPtr caption = mContent->ChildAt(kidIndex); + if (PR_TRUE==caption.IsNull()) { break; } - const PRInt32 contentType = ((nsTableContent *)(nsIContent*)caption)->GetType(); - if (contentType==nsITableContent::kTableCaptionType) + // Resolve style + nsIStyleContextPtr captionSC = + aPresContext->ResolveStyleContextFor(caption, this); + NS_ASSERTION(captionSC.IsNotNull(), "bad style context for caption."); + nsStyleDisplay *childDisplay = (nsStyleDisplay*)captionSC->GetStyleData(eStyleStruct_Display); + if (NS_STYLE_DISPLAY_TABLE_CAPTION == childDisplay->mDisplay) { - // Resolve style - nsIStyleContextPtr captionStyleContext = - aPresContext->ResolveStyleContextFor(caption, this); - NS_ASSERTION(captionStyleContext.IsNotNull(), "bad style context for caption."); - const nsStyleText* captionStyle = - (const nsStyleText*)captionStyleContext->GetStyleData(eStyleStruct_Text); + const nsStyleText* captionTextStyle = + (const nsStyleText*)captionSC->GetStyleData(eStyleStruct_Text); // create the frame nsIFrame *captionFrame=nsnull; frameCreated = ((nsIHTMLContent*)(nsIContent*)caption)->CreateFrame(aPresContext, - this, captionStyleContext, captionFrame); + this, captionSC, captionFrame); if (NS_OK!=frameCreated) return; // SEC: an error!!!! mChildCount++; // Link child frame into the list of children - if ((eStyleUnit_Enumerated == captionStyle->mVerticalAlign.GetUnit()) && - (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->mVerticalAlign.GetIntValue())) + if ((eStyleUnit_Enumerated == captionTextStyle->mVerticalAlign.GetUnit()) && + (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionTextStyle->mVerticalAlign.GetIntValue())) { // bottom captions get added to the end of the outer frame child list prevKidFrame->SetNextSibling(captionFrame); prevKidFrame = captionFrame; @@ -1027,7 +1021,8 @@ void nsTableOuterFrame::CreateChildFrames(nsIPresContext* aPresContext) mCaptionFrames->AppendElement(captionFrame); } else - { + { // otherwise I know there are no more captions + // I'm assuming the frames were created in the correct order break; } } @@ -1085,16 +1080,12 @@ nsTableOuterFrame::ResizeReflowTopCaptionsPass2(nsIPresContext* aPresCont nsTableCaptionFrame *captionFrame = (nsTableCaptionFrame *)mCaptionFrames->ElementAt(captionIndex); // Resolve style - nsIStyleContextPtr captionStyleContext; - - captionFrame->GetStyleContext(aPresContext, captionStyleContext.AssignRef()); - NS_ASSERTION(captionStyleContext.IsNotNull(), "null style context for caption"); - const nsStyleText* captionStyle = - (const nsStyleText*)captionStyleContext->GetStyleData(eStyleStruct_Text); - NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption"); + const nsStyleText* captionTextStyle; + captionFrame->GetStyleData(eStyleStruct_Text, (nsStyleStruct *&)captionTextStyle); + NS_ASSERTION(nsnull != captionTextStyle, "null style molecule for caption"); - if ((eStyleUnit_Enumerated == captionStyle->mVerticalAlign.GetUnit()) && - (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->mVerticalAlign.GetIntValue())) + if ((eStyleUnit_Enumerated == captionTextStyle->mVerticalAlign.GetUnit()) && + (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionTextStyle->mVerticalAlign.GetIntValue())) { } else @@ -1158,10 +1149,10 @@ nsTableOuterFrame::ResizeReflowBottomCaptionsPass2(nsIPresContext* aPresContext // Resolve style /* - nsIStyleContextPtr captionStyleContext = captionFrame->GetStyleContext(aPresContext); - NS_ASSERTION(nsnull != captionStyleContext, "null style context for caption"); + nsIStyleContextPtr captionSC = captionFrame->GetStyleContext(aPresContext); + NS_ASSERTION(nsnull != captionSC, "null style context for caption"); nsStyleMolecule* captionStyle = - (nsStyleMolecule*)captionStyleContext->GetData(eStyleStruct_Molecule); + (nsStyleMolecule*)captionSC->GetData(eStyleStruct_Molecule); NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption"); */ // reflow the caption diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index 0543f3670e5..47ca194ffbd 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -25,7 +25,6 @@ #include "nsTableFrame.h" #include "nsTableColFrame.h" #include "nsTableCellFrame.h" -#include "nsTableCell.h" #include "nsCellLayoutData.h" #include "nsColLayoutData.h" #include "nsIView.h" @@ -186,6 +185,10 @@ void nsTableRowFrame::PaintChildren(nsIPresContext& aPresContext, } } +void nsTableRowFrame::SetRowIndex (int aRowIndex) +{ + mRowIndex = aRowIndex; +} /** returns the height of the tallest child in this row (ignoring any cell with rowspans) */ nscoord nsTableRowFrame::GetTallestChild() const @@ -203,6 +206,18 @@ nscoord nsTableRowFrame::GetChildMaxBottomMargin() const return mCellMaxBottomMargin; } +PRInt32 nsTableRowFrame::GetMaxColumns() const +{ + int sum = 0; + nsTableCellFrame *cell=nsnull; + ChildAt(0, (nsIFrame *&)cell); + while (nsnull!=cell) { + sum += cell->GetColSpan(); + cell->GetNextSibling((nsIFrame *&)cell); + } + return sum; +} + // Collapse child's top margin with previous bottom margin nscoord nsTableRowFrame::GetTopMarginFor( nsIPresContext* aCX, @@ -264,7 +279,7 @@ void nsTableRowFrame::PlaceChild(nsIPresContext* aPresContext, { nsMargin margin(0,0,0,0); - if (aState.tableFrame->GetCellMarginData(aKidFrame, margin) == NS_OK) + if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)aKidFrame, margin) == NS_OK) { nscoord height = aKidRect.height + margin.top + margin.bottom; @@ -324,11 +339,6 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, nscoord maxCellBottomMargin = 0; for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { - - nsIContent* content = nsnull; - kidFrame->GetContent(content); // cell: REFCNT++ - nsTableCell* cell = (nsTableCell*)content; - nsSize kidAvailSize(aState.availSize); if (0>=kidAvailSize.height) kidAvailSize.height = 1; // XXX: HaCk - we don't handle negative heights yet @@ -338,13 +348,11 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, nsReflowStatus status; nsMargin kidMargin(0,0,0,0); - aState.tableFrame->GetCellMarginData(kidFrame,kidMargin); + aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame,kidMargin); if (kidMargin.top > maxCellTopMargin) maxCellTopMargin = kidMargin.top; if (kidMargin.bottom > maxCellBottomMargin) maxCellBottomMargin = kidMargin.bottom; - - // Figure out the amount of available size for the child (subtract // off the top margin we are going to apply to it) @@ -365,14 +373,14 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, kidFrame->WillReflow(*aPresContext); status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState); - nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); - aState.tableFrame->SetCellLayoutData(aPresContext, &kidLayoutData, cell); + nsCellLayoutData *kidLayoutData = new nsCellLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); + ((nsTableCellFrame *)kidFrame)->SetCellLayoutData(kidLayoutData); } else { // we're in a constrained situation, so get the avail width from the known column widths - nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData(cell); - PRInt32 cellStartingCol = cell->GetColIndex(); - PRInt32 cellColSpan = cell->GetColSpan(); + nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCellFrame *)kidFrame); + PRInt32 cellStartingCol = ((nsTableCellFrame *)kidFrame)->GetColIndex(); + PRInt32 cellColSpan = ((nsTableCellFrame *)kidFrame)->GetColSpan(); nscoord availWidth = 0; for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan); @@ -395,8 +403,6 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, NS_FRAME_IS_COMPLETE(status)?"complete":"NOT complete", desiredSize.width, desiredSize.height); } - NS_RELEASE(content); // cell: REFCNT-- - cell = nsnull; // Did the child fit? if ((kidFrame != mFirstChild) && @@ -656,14 +662,10 @@ PRBool nsTableRowFrame::PullUpChildren(nsIPresContext* aPresContext, break; } - nsIContent *content = nsnull; - kidFrame->GetContent(content); // cell: REFNCT++ - nsTableCell* cell = (nsTableCell*)content; - // we're in a constrained situation, so get the avail width from the known column widths - nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData(cell); - PRInt32 cellStartingCol = cell->GetColIndex(); - PRInt32 cellColSpan = cell->GetColSpan(); + nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCellFrame *)kidFrame); + PRInt32 cellStartingCol = ((nsTableCellFrame *)kidFrame)->GetColIndex(); + PRInt32 cellColSpan = ((nsTableCellFrame *)kidFrame)->GetColSpan(); nscoord availWidth = 0; for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan); @@ -688,8 +690,6 @@ PRBool nsTableRowFrame::PullUpChildren(nsIPresContext* aPresContext, desiredSize.width, desiredSize.height); } } - NS_RELEASE(content); // cell: REFCNT-- - cell = nsnull; // Did the child fit? if ((desiredSize.height > aState.availSize.height) && (nsnull != mFirstChild)) { @@ -900,7 +900,7 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, nsIFrame* kidFrame; // Create a child frame -- always an nsTableCell frame - nsIStyleContext* kidStyleContext = aPresContext->ResolveStyleContextFor(cell, this); + nsIStyleContext* kidStyleContext = aPresContext->ResolveStyleContextFor(cell, this, PR_TRUE); if (nsnull == kidPrevInFlow) { nsIContentDelegate* kidDel = nsnull; kidDel = cell->GetDelegate(aPresContext); @@ -911,11 +911,6 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, kidPrevInFlow->CreateContinuingFrame(aPresContext, this, kidStyleContext, kidFrame); } - /* since I'm creating the cell frame, this is the first time through reflow - * it's a good time to set the column style from the cell's width attribute - * if this is the first row - */ - SetColumnStyleFromCell(aPresContext, (nsTableCellFrame *)kidFrame, kidStyleContext); NS_RELEASE(kidStyleContext); @@ -923,7 +918,7 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, nscoord topMargin = 0; nscoord bottomMargin = 0; - if (aState.tableFrame->GetCellMarginData(kidFrame, margin) == NS_OK) + if (aState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, margin) == NS_OK) { topMargin = margin.top; bottomMargin = margin.bottom; @@ -944,14 +939,14 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, // Reflow the child into the available space kidFrame->WillReflow(*aPresContext); status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState); - nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); - aState.tableFrame->SetCellLayoutData(aPresContext, &kidLayoutData, (nsTableCell *)cell); + nsCellLayoutData *kidLayoutData = new nsCellLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); + ((nsTableCellFrame *)kidFrame)->SetCellLayoutData(kidLayoutData); } else { // we're in a constrained situation, so get the avail width from the known column widths - nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCell *)cell); - PRInt32 cellStartingCol = ((nsTableCell *)cell)->GetColIndex(); - PRInt32 cellColSpan = ((nsTableCell *)cell)->GetColSpan(); + nsCellLayoutData *cellData = aState.tableFrame->GetCellLayoutData((nsTableCellFrame *)kidFrame); + PRInt32 cellStartingCol = ((nsTableCellFrame *)kidFrame)->GetColIndex(); + PRInt32 cellColSpan = ((nsTableCellFrame *)kidFrame)->GetColSpan(); nscoord availWidth = 0; for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan); @@ -1154,53 +1149,6 @@ nsTableRowFrame::CreateContinuingFrame(nsIPresContext* aPresContext, return NS_OK; } -NS_METHOD -nsTableRowFrame::SetColumnStyleFromCell(nsIPresContext* aPresContext, - nsTableCellFrame* aCellFrame, - nsIStyleContext* aCellSC) -{ - // if this cell is in the first row, then the width attribute - // also acts as the width attribute for the entire column - if ((nsnull!=aCellSC) && (nsnull!=aCellFrame)) - { - if (0==mRowIndex) - { - // get the cell style info - const nsStylePosition* cellPosition = (const nsStylePosition*) aCellSC->GetStyleData(eStyleStruct_Position); - if ((eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) || - (eStyleUnit_Percent==cellPosition->mWidth.GetUnit())) { - - // compute the width per column spanned - PRInt32 colSpan = aCellFrame->GetColSpan(); - nsTableFrame *tableFrame; - mGeometricParent->GetGeometricParent((nsIFrame *&)tableFrame); - for (PRInt32 i=0; iGetColumnFrame(i+aCellFrame->GetColIndex(), colFrame); - // get the column style and set the width attribute - nsIStyleContextPtr colSC; - colFrame->GetStyleContext(aPresContext, colSC.AssignRef()); - nsStylePosition* colPosition = (nsStylePosition*) colSC->GetMutableStyleData(eStyleStruct_Position); - // set the column width attribute - if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) - { - nscoord width = cellPosition->mWidth.GetCoordValue(); - colPosition->mWidth.SetCoordValue(width/colSpan); - } - else - { - float width = cellPosition->mWidth.GetPercentValue(); - colPosition->mWidth.SetPercentValue(width/colSpan); - } - } - } - } - } - return NS_OK; -} - nsresult nsTableRowFrame::NewFrame( nsIFrame** aInstancePtrResult, nsIContent* aContent, nsIFrame* aParent) diff --git a/mozilla/layout/tables/nsTableRowFrame.h b/mozilla/layout/tables/nsTableRowFrame.h index 87774963d04..f3aa68d79e1 100644 --- a/mozilla/layout/tables/nsTableRowFrame.h +++ b/mozilla/layout/tables/nsTableRowFrame.h @@ -102,6 +102,14 @@ public: nscoord GetChildMaxTopMargin() const; nscoord GetChildMaxBottomMargin() const; + PRInt32 GetMaxColumns() const; + + /** returns the ordinal position of this row in its table */ + virtual PRInt32 GetRowIndex() const; + + /** set this row's starting row index */ + virtual void SetRowIndex (int aRowIndex); + // For DEBUGGING Purposes Only NS_IMETHOD MoveTo(nscoord aX, nscoord aY); NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); @@ -163,10 +171,6 @@ protected: RowReflowState& aState, nsSize* aMaxElementSize); - NS_METHOD SetColumnStyleFromCell(nsIPresContext * aPresContext, - nsTableCellFrame* aCellFrame, - nsIStyleContext * aCellSC); - private: PRInt32 mRowIndex; nscoord mTallestCell; // not my height, but the height of my tallest child @@ -182,4 +186,10 @@ inline void nsTableRowFrame::Init(PRInt32 aRowIndex) mRowIndex = aRowIndex; } +inline PRInt32 nsTableRowFrame::GetRowIndex() const +{ + NS_ASSERTION(0<=mRowIndex, "bad state: row index"); + return (mRowIndex); +} + #endif diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index 578c6a375b4..6fef74a1d99 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -743,7 +743,7 @@ nsTableRowGroupFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, // Resolve style nsIStyleContextPtr kidSC = - aPresContext->ResolveStyleContextFor(kid, this); + aPresContext->ResolveStyleContextFor(kid, this, PR_TRUE); const nsStyleSpacing* kidSpacing = (const nsStyleSpacing*) kidSC->GetStyleData(eStyleStruct_Spacing); nsMargin kidMargin; diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.h b/mozilla/layout/tables/nsTableRowGroupFrame.h index 15df8b1a379..a0d440b25b0 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.h +++ b/mozilla/layout/tables/nsTableRowGroupFrame.h @@ -91,6 +91,9 @@ public: */ NS_IMETHOD GetRowGroupType(nsIAtom *& aType); + /** return the number of contained rows */ + PRInt32 GetRowCount (); + // For DEBUGGING Purposes Only NS_IMETHOD MoveTo(nscoord aX, nscoord aY); NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); @@ -157,5 +160,13 @@ private: }; +//XXX: change this if row groups can contain non-row types +// in this case, iterate through kids and add 1 if the kid's display type is "row" +inline PRInt32 nsTableRowGroupFrame::GetRowCount () +{ + PRInt32 result = 0; + ChildCount(result); + return result; +} #endif