michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #ifndef nsCellMap_h__ michael@0: #define nsCellMap_h__ michael@0: michael@0: #include "nscore.h" michael@0: #include "celldata.h" michael@0: #include "nsTArray.h" michael@0: #include "nsTArray.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsAlgorithm.h" michael@0: #include "nsAutoPtr.h" michael@0: #include michael@0: michael@0: #undef DEBUG_TABLE_CELLMAP michael@0: michael@0: class nsTableColFrame; michael@0: class nsTableCellFrame; michael@0: class nsTableRowFrame; michael@0: class nsTableRowGroupFrame; michael@0: class nsTableFrame; michael@0: class nsCellMap; michael@0: class nsPresContext; michael@0: class nsCellMapColumnIterator; michael@0: struct nsIntRect; michael@0: michael@0: struct nsColInfo michael@0: { michael@0: int32_t mNumCellsOrig; // number of cells originating in the col michael@0: int32_t mNumCellsSpan; // number of cells spanning into the col via colspans (not rowspans) michael@0: michael@0: nsColInfo(); michael@0: nsColInfo(int32_t aNumCellsOrig, michael@0: int32_t aNumCellsSpan); michael@0: }; michael@0: michael@0: enum Corner michael@0: { michael@0: eTopLeft = 0, michael@0: eTopRight = 1, michael@0: eBottomRight = 2, michael@0: eBottomLeft = 3 michael@0: }; michael@0: michael@0: struct BCInfo michael@0: { michael@0: nsTArray mRightBorders; michael@0: nsTArray mBottomBorders; michael@0: BCData mLowerRightCorner; michael@0: }; michael@0: michael@0: class nsTableCellMap michael@0: { michael@0: public: michael@0: nsTableCellMap(nsTableFrame& aTableFrame, michael@0: bool aBorderCollapse); michael@0: michael@0: /** destructor michael@0: * NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED michael@0: */ michael@0: ~nsTableCellMap(); michael@0: michael@0: void RemoveGroupCellMap(nsTableRowGroupFrame* aRowGroup); michael@0: michael@0: void InsertGroupCellMap(nsTableRowGroupFrame* aNewRowGroup, michael@0: nsTableRowGroupFrame*& aPrevRowGroup); michael@0: michael@0: /** michael@0: * Get the nsCellMap for the given row group. If aStartHint is non-null, michael@0: * will start looking with that cellmap and only fall back to starting at the michael@0: * beginning of the list if that doesn't find us the right nsCellMap. michael@0: * Otherwise, just start at the beginning. michael@0: * michael@0: * aRowGroup must not be null. michael@0: */ michael@0: nsCellMap* GetMapFor(const nsTableRowGroupFrame* aRowGroup, michael@0: nsCellMap* aStartHint) const; michael@0: michael@0: /** synchronize the cellmaps with the rowgroups again **/ michael@0: void Synchronize(nsTableFrame* aTableFrame); michael@0: michael@0: nsTableCellFrame* GetCellFrame(int32_t aRowIndex, michael@0: int32_t aColIndex, michael@0: CellData& aData, michael@0: bool aUseRowIfOverlap) const; michael@0: michael@0: /** return the CellData for the cell at (aRowIndex, aColIndex) */ michael@0: CellData* GetDataAt(int32_t aRowIndex, michael@0: int32_t aColIndex) const; michael@0: michael@0: // this function creates a col if needed michael@0: nsColInfo* GetColInfoAt(int32_t aColIndex); michael@0: michael@0: /** append the cellFrame at the end of the row at aRowIndex and return the col index michael@0: */ michael@0: CellData* AppendCell(nsTableCellFrame& aCellFrame, michael@0: int32_t aRowIndex, michael@0: bool aRebuildIfNecessary, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: void InsertCells(nsTArray& aCellFrames, michael@0: int32_t aRowIndex, michael@0: int32_t aColIndexBefore, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: void RemoveCell(nsTableCellFrame* aCellFrame, michael@0: int32_t aRowIndex, michael@0: nsIntRect& aDamageArea); michael@0: /** Remove the previously gathered column information */ michael@0: void ClearCols(); michael@0: void InsertRows(nsTableRowGroupFrame* aRowGroup, michael@0: nsTArray& aRows, michael@0: int32_t aFirstRowIndex, michael@0: bool aConsiderSpans, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: void RemoveRows(int32_t aFirstRowIndex, michael@0: int32_t aNumRowsToRemove, michael@0: bool aConsiderSpans, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: int32_t GetNumCellsOriginatingInRow(int32_t aRowIndex) const; michael@0: int32_t GetNumCellsOriginatingInCol(int32_t aColIndex) const; michael@0: michael@0: /** indicate whether the row has more than one cell that either originates michael@0: * or is spanned from the rows above michael@0: */ michael@0: bool HasMoreThanOneCell(int32_t aRowIndex) const; michael@0: michael@0: int32_t GetEffectiveRowSpan(int32_t aRowIndex, michael@0: int32_t aColIndex) const; michael@0: int32_t GetEffectiveColSpan(int32_t aRowIndex, michael@0: int32_t aColIndex) const; michael@0: michael@0: /** return the total number of columns in the table represented by this CellMap */ michael@0: int32_t GetColCount() const; michael@0: michael@0: /** return the actual number of rows in the table represented by this CellMap */ michael@0: int32_t GetRowCount() const; michael@0: michael@0: nsTableCellFrame* GetCellInfoAt(int32_t aRowX, michael@0: int32_t aColX, michael@0: bool* aOriginates = nullptr, michael@0: int32_t* aColSpan = nullptr) const; michael@0: michael@0: /** michael@0: * Returns the index at the given row and column coordinates. michael@0: * michael@0: * @see nsITableLayout::GetIndexByRowAndColumn() michael@0: * michael@0: * @param aRow [in] the row coordinate michael@0: * @param aColumn [in] the column coordinate michael@0: * @returns the index for the cell michael@0: */ michael@0: int32_t GetIndexByRowAndColumn(int32_t aRow, int32_t aColumn) const; michael@0: michael@0: /** michael@0: * Retrieves the row and column coordinates for the given index. michael@0: * michael@0: * @see nsITableLayout::GetRowAndColumnByIndex() michael@0: * michael@0: * @param aIndex [in] the index for which coordinates are to be retrieved michael@0: * @param aRow [out] the row coordinate to be returned michael@0: * @param aColumn [out] the column coordinate to be returned michael@0: */ michael@0: void GetRowAndColumnByIndex(int32_t aIndex, michael@0: int32_t *aRow, int32_t *aColumn) const; michael@0: michael@0: void AddColsAtEnd(uint32_t aNumCols); michael@0: void RemoveColsAtEnd(); michael@0: michael@0: bool RowIsSpannedInto(int32_t aRowIndex, int32_t aNumEffCols) const; michael@0: bool RowHasSpanningCells(int32_t aRowIndex, int32_t aNumEffCols) const; michael@0: void RebuildConsideringCells(nsCellMap* aCellMap, michael@0: nsTArray* aCellFrames, michael@0: int32_t aRowIndex, michael@0: int32_t aColIndex, michael@0: bool aInsert, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: protected: michael@0: /** michael@0: * Rebuild due to rows being inserted or deleted with cells spanning michael@0: * into or out of the rows. This function can only handle insertion michael@0: * or deletion but NOT both. So either aRowsToInsert must be null michael@0: * or aNumRowsToRemove must be 0. michael@0: * michael@0: * // XXXbz are both allowed to happen? That'd be a no-op... michael@0: */ michael@0: void RebuildConsideringRows(nsCellMap* aCellMap, michael@0: int32_t aStartRowIndex, michael@0: nsTArray* aRowsToInsert, michael@0: int32_t aNumRowsToRemove, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: public: michael@0: void ExpandZeroColSpans(); michael@0: michael@0: void ResetTopStart(uint8_t aSide, michael@0: nsCellMap& aCellMap, michael@0: uint32_t aYPos, michael@0: uint32_t aXPos, michael@0: bool aIsLowerRight = false); michael@0: michael@0: void SetBCBorderEdge(mozilla::css::Side aEdge, michael@0: nsCellMap& aCellMap, michael@0: uint32_t aCellMapStart, michael@0: uint32_t aYPos, michael@0: uint32_t aXPos, michael@0: uint32_t aLength, michael@0: BCBorderOwner aOwner, michael@0: nscoord aSize, michael@0: bool aChanged); michael@0: michael@0: void SetBCBorderCorner(::Corner aCorner, michael@0: nsCellMap& aCellMap, michael@0: uint32_t aCellMapStart, michael@0: uint32_t aYPos, michael@0: uint32_t aXPos, michael@0: mozilla::css::Side aOwner, michael@0: nscoord aSubSize, michael@0: bool aBevel, michael@0: bool aIsBottomRight = false); michael@0: michael@0: /** dump a representation of the cell map to stdout for debugging */ michael@0: #ifdef DEBUG michael@0: void Dump(char* aString = nullptr) const; michael@0: #endif michael@0: michael@0: protected: michael@0: BCData* GetRightMostBorder(int32_t aRowIndex); michael@0: BCData* GetBottomMostBorder(int32_t aColIndex); michael@0: michael@0: friend class nsCellMap; michael@0: friend class BCMapCellIterator; michael@0: friend class BCPaintBorderIterator; michael@0: friend class nsCellMapColumnIterator; michael@0: michael@0: /** Insert a row group cellmap after aPrevMap, if aPrefMap is null insert it michael@0: * at the beginning, the ordering of the cellmap corresponds to the ordering of michael@0: * rowgroups once OrderRowGroups has been called michael@0: */ michael@0: void InsertGroupCellMap(nsCellMap* aPrevMap, michael@0: nsCellMap& aNewMap); michael@0: void DeleteRightBottomBorders(); michael@0: michael@0: nsTableFrame& mTableFrame; michael@0: nsAutoTArray mCols; michael@0: nsCellMap* mFirstMap; michael@0: // border collapsing info michael@0: BCInfo* mBCInfo; michael@0: }; michael@0: michael@0: /** nsCellMap is a support class for nsTablePart. michael@0: * It maintains an Rows x Columns grid onto which the cells of the table are mapped. michael@0: * This makes processing of rowspan and colspan attributes much easier. michael@0: * Each cell is represented by a CellData object. michael@0: * michael@0: * @see CellData michael@0: * @see nsTableFrame::AddCellToMap michael@0: * @see nsTableFrame::GrowCellMap michael@0: * @see nsTableFrame::BuildCellIntoMap michael@0: * michael@0: * mRows is an array of rows. Each row is an array of cells. a cell michael@0: * can be null. michael@0: */ michael@0: class nsCellMap michael@0: { michael@0: public: michael@0: /** constructor michael@0: * @param aRowGroupFrame the row group frame this is a cellmap for michael@0: * @param aIsBC whether the table is doing border-collapse michael@0: */ michael@0: nsCellMap(nsTableRowGroupFrame* aRowGroupFrame, bool aIsBC); michael@0: michael@0: /** destructor michael@0: * NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED michael@0: */ michael@0: ~nsCellMap(); michael@0: michael@0: static void Init(); michael@0: static void Shutdown(); michael@0: michael@0: nsCellMap* GetNextSibling() const; michael@0: void SetNextSibling(nsCellMap* aSibling); michael@0: michael@0: nsTableRowGroupFrame* GetRowGroup() const; michael@0: michael@0: nsTableCellFrame* GetCellFrame(int32_t aRowIndex, michael@0: int32_t aColIndex, michael@0: CellData& aData, michael@0: bool aUseRowSpanIfOverlap) const; michael@0: michael@0: /** michael@0: * Returns highest cell index within the cell map. michael@0: * michael@0: * @param aColCount [in] the number of columns in the table michael@0: */ michael@0: int32_t GetHighestIndex(int32_t aColCount); michael@0: michael@0: /** michael@0: * Returns the index of the given row and column coordinates. michael@0: * michael@0: * @see nsITableLayout::GetIndexByRowAndColumn() michael@0: * michael@0: * @param aColCount [in] the number of columns in the table michael@0: * @param aRow [in] the row coordinate michael@0: * @param aColumn [in] the column coordinate michael@0: */ michael@0: int32_t GetIndexByRowAndColumn(int32_t aColCount, michael@0: int32_t aRow, int32_t aColumn) const; michael@0: michael@0: /** michael@0: * Get the row and column coordinates at the given index. michael@0: * michael@0: * @see nsITableLayout::GetRowAndColumnByIndex() michael@0: * michael@0: * @param aColCount [in] the number of columns in the table michael@0: * @param aIndex [in] the index for which coordinates are to be retrieved michael@0: * @param aRow [out] the row coordinate to be returned michael@0: * @param aColumn [out] the column coordinate to be returned michael@0: */ michael@0: void GetRowAndColumnByIndex(int32_t aColCount, int32_t aIndex, michael@0: int32_t *aRow, int32_t *aColumn) const; michael@0: michael@0: /** append the cellFrame at an empty or dead cell or finally at the end of michael@0: * the row at aRowIndex and return a pointer to the celldata entry in the michael@0: * cellmap michael@0: * michael@0: * @param aMap - reference to the table cell map michael@0: * @param aCellFrame - a pointer to the cellframe which will be appended michael@0: * to the row michael@0: * @param aRowIndex - to this row the celldata entry will be added michael@0: * @param aRebuildIfNecessay - if a cell spans into a row below it might be michael@0: * necesserary to rebuild the cellmap as this rowspan michael@0: * might overlap another cell. michael@0: * @param aDamageArea - area in cellmap coordinates which have been updated. michael@0: * @param aColToBeginSearch - if not null contains the column number where michael@0: * the search for a empty or dead cell in the michael@0: * row should start michael@0: * @return - a pointer to the celldata entry inserted into michael@0: * the cellmap michael@0: */ michael@0: CellData* AppendCell(nsTableCellMap& aMap, michael@0: nsTableCellFrame* aCellFrame, michael@0: int32_t aRowIndex, michael@0: bool aRebuildIfNecessary, michael@0: int32_t aRgFirstRowIndex, michael@0: nsIntRect& aDamageArea, michael@0: int32_t* aBeginSearchAtCol = nullptr); michael@0: michael@0: /** Function to be called when a cell is added at a location which is spanned michael@0: * to by a zero colspan. We handle this situation by collapsing the zero michael@0: * colspan, since there is really no good way to deal with it (trying to michael@0: * increase the number of columns to hold the new cell would just mean the michael@0: * zero colspan needs to expand). michael@0: michael@0: * @param aMap - reference to the table cell map michael@0: * @param aOrigData - zero colspanned cell that will be collapsed michael@0: * @param aRowIndex - row where the first collision appears michael@0: * @param aColIndex - column where the first collision appears michael@0: **/ michael@0: void CollapseZeroColSpan(nsTableCellMap& aMap, michael@0: CellData* aOrigData, michael@0: int32_t aRowIndex, michael@0: int32_t aColIndex); michael@0: michael@0: void InsertCells(nsTableCellMap& aMap, michael@0: nsTArray& aCellFrames, michael@0: int32_t aRowIndex, michael@0: int32_t aColIndexBefore, michael@0: int32_t aRgFirstRowIndex, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: void RemoveCell(nsTableCellMap& aMap, michael@0: nsTableCellFrame* aCellFrame, michael@0: int32_t aRowIndex, michael@0: int32_t aRgFirstRowIndex, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: void InsertRows(nsTableCellMap& aMap, michael@0: nsTArray& aRows, michael@0: int32_t aFirstRowIndex, michael@0: bool aConsiderSpans, michael@0: int32_t aRgFirstRowIndex, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: void RemoveRows(nsTableCellMap& aMap, michael@0: int32_t aFirstRowIndex, michael@0: int32_t aNumRowsToRemove, michael@0: bool aConsiderSpans, michael@0: int32_t aRgFirstRowIndex, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: int32_t GetNumCellsOriginatingInRow(int32_t aRowIndex) const; michael@0: int32_t GetNumCellsOriginatingInCol(int32_t aColIndex) const; michael@0: michael@0: /** return the number of rows in the table represented by this CellMap */ michael@0: int32_t GetRowCount(bool aConsiderDeadRowSpanRows = false) const; michael@0: michael@0: nsTableCellFrame* GetCellInfoAt(const nsTableCellMap& aMap, michael@0: int32_t aRowX, michael@0: int32_t aColX, michael@0: bool* aOriginates = nullptr, michael@0: int32_t* aColSpan = nullptr) const; michael@0: michael@0: bool RowIsSpannedInto(int32_t aRowIndex, michael@0: int32_t aNumEffCols) const; michael@0: michael@0: bool RowHasSpanningCells(int32_t aRowIndex, michael@0: int32_t aNumEffCols) const; michael@0: michael@0: void ExpandZeroColSpans(nsTableCellMap& aMap); michael@0: michael@0: /** indicate whether the row has more than one cell that either originates michael@0: * or is spanned from the rows above michael@0: */ michael@0: bool HasMoreThanOneCell(int32_t aRowIndex) const; michael@0: michael@0: /* Get the rowspan for a cell starting at aRowIndex and aColIndex. michael@0: * If aGetEffective is true the size will not exceed the last content based michael@0: * row. Cells can have a specified rowspan that extends below the last michael@0: * content based row. This is legitimate considering incr. reflow where the michael@0: * content rows will arive later. michael@0: */ michael@0: int32_t GetRowSpan(int32_t aRowIndex, michael@0: int32_t aColIndex, michael@0: bool aGetEffective) const; michael@0: michael@0: int32_t GetEffectiveColSpan(const nsTableCellMap& aMap, michael@0: int32_t aRowIndex, michael@0: int32_t aColIndex, michael@0: bool& aIsZeroColSpan) const; michael@0: michael@0: typedef nsTArray CellDataArray; michael@0: michael@0: /** dump a representation of the cell map to stdout for debugging */ michael@0: #ifdef DEBUG michael@0: void Dump(bool aIsBorderCollapse) const; michael@0: #endif michael@0: michael@0: protected: michael@0: friend class nsTableCellMap; michael@0: friend class BCMapCellIterator; michael@0: friend class BCPaintBorderIterator; michael@0: friend class nsTableFrame; michael@0: friend class nsCellMapColumnIterator; michael@0: michael@0: /** michael@0: * Increase the number of rows in this cellmap by aNumRows. Put the michael@0: * new rows at aRowIndex. If aRowIndex is -1, put them at the end. michael@0: */ michael@0: bool Grow(nsTableCellMap& aMap, michael@0: int32_t aNumRows, michael@0: int32_t aRowIndex = -1); michael@0: michael@0: void GrowRow(CellDataArray& aRow, michael@0: int32_t aNumCols); michael@0: michael@0: /** assign aCellData to the cell at (aRow,aColumn) */ michael@0: void SetDataAt(nsTableCellMap& aMap, michael@0: CellData& aCellData, michael@0: int32_t aMapRowIndex, michael@0: int32_t aColIndex); michael@0: michael@0: CellData* GetDataAt(int32_t aMapRowIndex, michael@0: int32_t aColIndex) const; michael@0: michael@0: int32_t GetNumCellsIn(int32_t aColIndex) const; michael@0: michael@0: void ExpandWithRows(nsTableCellMap& aMap, michael@0: nsTArray& aRowFrames, michael@0: int32_t aStartRowIndex, michael@0: int32_t aRgFirstRowIndex, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: void ExpandWithCells(nsTableCellMap& aMap, michael@0: nsTArray& aCellFrames, michael@0: int32_t aRowIndex, michael@0: int32_t aColIndex, michael@0: int32_t aRowSpan, michael@0: bool aRowSpanIsZero, michael@0: int32_t aRgFirstRowIndex, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: void ShrinkWithoutRows(nsTableCellMap& aMap, michael@0: int32_t aFirstRowIndex, michael@0: int32_t aNumRowsToRemove, michael@0: int32_t aRgFirstRowIndex, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: void ShrinkWithoutCell(nsTableCellMap& aMap, michael@0: nsTableCellFrame& aCellFrame, michael@0: int32_t aRowIndex, michael@0: int32_t aColIndex, michael@0: int32_t aRgFirstRowIndex, michael@0: nsIntRect& aDamageArea); michael@0: michael@0: /** michael@0: * Rebuild due to rows being inserted or deleted with cells spanning michael@0: * into or out of the rows. This function can only handle insertion michael@0: * or deletion but NOT both. So either aRowsToInsert must be null michael@0: * or aNumRowsToRemove must be 0. michael@0: * michael@0: * // XXXbz are both allowed to happen? That'd be a no-op... michael@0: */ michael@0: void RebuildConsideringRows(nsTableCellMap& aMap, michael@0: int32_t aStartRowIndex, michael@0: nsTArray* aRowsToInsert, michael@0: int32_t aNumRowsToRemove); michael@0: michael@0: void RebuildConsideringCells(nsTableCellMap& aMap, michael@0: int32_t aNumOrigCols, michael@0: nsTArray* aCellFrames, michael@0: int32_t aRowIndex, michael@0: int32_t aColIndex, michael@0: bool aInsert); michael@0: michael@0: bool CellsSpanOut(nsTArray& aNewRows) const; michael@0: michael@0: /** If a cell spans out of the area defined by aStartRowIndex, aEndRowIndex michael@0: * and aStartColIndex, aEndColIndex the cellmap changes are more severe so michael@0: * the corresponding routines needs to be called. This is also necessary if michael@0: * cells outside spans into this region. michael@0: * @aStartRowIndex - y start index michael@0: * @aEndRowIndex - y end index michael@0: * @param aStartColIndex - x start index michael@0: * @param aEndColIndex - x end index michael@0: * @return - true if a cell span crosses the border of the michael@0: region michael@0: */ michael@0: bool CellsSpanInOrOut(int32_t aStartRowIndex, michael@0: int32_t aEndRowIndex, michael@0: int32_t aStartColIndex, michael@0: int32_t aEndColIndex) const; michael@0: michael@0: void ExpandForZeroSpan(nsTableCellFrame* aCellFrame, michael@0: int32_t aNumColsInTable); michael@0: michael@0: bool CreateEmptyRow(int32_t aRowIndex, michael@0: int32_t aNumCols); michael@0: michael@0: int32_t GetRowSpanForNewCell(nsTableCellFrame* aCellFrameToAdd, michael@0: int32_t aRowIndex, michael@0: bool& aIsZeroRowSpan) const; michael@0: michael@0: int32_t GetColSpanForNewCell(nsTableCellFrame& aCellFrameToAdd, michael@0: bool& aIsZeroColSpan) const; michael@0: michael@0: // Destroy a CellData struct. This will handle the case of aData michael@0: // actually being a BCCellData properly. michael@0: void DestroyCellData(CellData* aData); michael@0: // Allocate a CellData struct. This will handle needing to create a michael@0: // BCCellData properly. michael@0: // @param aOrigCell the originating cell to pass to the celldata constructor michael@0: CellData* AllocCellData(nsTableCellFrame* aOrigCell); michael@0: michael@0: /** an array containing, for each row, the CellDatas for the cells michael@0: * in that row. It can be larger than mContentRowCount due to row spans michael@0: * extending beyond the table */ michael@0: // XXXbz once we have auto TArrays, we should probably use them here. michael@0: nsTArray mRows; michael@0: michael@0: /** the number of rows in the table (content) which is not indentical to the michael@0: * number of rows in the cell map due to row spans extending beyond the end michael@0: * of thetable (dead rows) or empty tr tags michael@0: */ michael@0: int32_t mContentRowCount; michael@0: michael@0: // the row group that corresponds to this map michael@0: nsTableRowGroupFrame* mRowGroupFrame; michael@0: michael@0: // the next row group cell map michael@0: nsCellMap* mNextSibling; michael@0: michael@0: // Whether this is a BC cellmap or not michael@0: bool mIsBC; michael@0: michael@0: // Prescontext to deallocate and allocate celldata michael@0: nsRefPtr mPresContext; michael@0: }; michael@0: michael@0: /** michael@0: * A class for iterating the cells in a given column. Must be given a michael@0: * non-null nsTableCellMap and a column number valid for that cellmap. michael@0: */ michael@0: class nsCellMapColumnIterator michael@0: { michael@0: public: michael@0: nsCellMapColumnIterator(const nsTableCellMap* aMap, int32_t aCol) : michael@0: mMap(aMap), mCurMap(aMap->mFirstMap), mCurMapStart(0), michael@0: mCurMapRow(0), mCol(aCol), mFoundCells(0) michael@0: { michael@0: NS_PRECONDITION(aMap, "Must have map"); michael@0: NS_PRECONDITION(mCol < aMap->GetColCount(), "Invalid column"); michael@0: mOrigCells = aMap->GetNumCellsOriginatingInCol(mCol); michael@0: if (mCurMap) { michael@0: mCurMapContentRowCount = mCurMap->GetRowCount(); michael@0: uint32_t rowArrayLength = mCurMap->mRows.Length(); michael@0: mCurMapRelevantRowCount = std::min(mCurMapContentRowCount, rowArrayLength); michael@0: if (mCurMapRelevantRowCount == 0 && mOrigCells > 0) { michael@0: // This row group is useless; advance! michael@0: AdvanceRowGroup(); michael@0: } michael@0: } michael@0: #ifdef DEBUG michael@0: else { michael@0: NS_ASSERTION(mOrigCells == 0, "Why no rowgroups?"); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: nsTableCellFrame* GetNextFrame(int32_t* aRow, int32_t* aColSpan); michael@0: michael@0: private: michael@0: void AdvanceRowGroup(); michael@0: michael@0: // Advance the row; aIncrement is considered to be a cell's rowspan, michael@0: // so if 0 is passed in we'll advance to the next rowgroup. michael@0: void IncrementRow(int32_t aIncrement); michael@0: michael@0: const nsTableCellMap* mMap; michael@0: const nsCellMap* mCurMap; michael@0: michael@0: // mCurMapStart is the row in the entire nsTableCellMap where michael@0: // mCurMap starts. This is used to compute row indices to pass to michael@0: // nsTableCellMap::GetDataAt, so must be a _content_ row index. michael@0: uint32_t mCurMapStart; michael@0: michael@0: // In steady-state mCurMapRow is the row in our current nsCellMap michael@0: // that we'll use the next time GetNextFrame() is called. Due to michael@0: // the way we skip over rowspans, the entry in mCurMapRow and mCol michael@0: // is either null, dead, originating, or a colspan. In particular, michael@0: // it cannot be a rowspan or overlap entry. michael@0: uint32_t mCurMapRow; michael@0: const int32_t mCol; michael@0: uint32_t mOrigCells; michael@0: uint32_t mFoundCells; michael@0: michael@0: // The number of content rows in mCurMap. This may be bigger than the number michael@0: // of "relevant" rows, or it might be smaller. michael@0: uint32_t mCurMapContentRowCount; michael@0: michael@0: // The number of "relevant" rows in mCurMap. That is, the number of rows michael@0: // which might have an originating cell in them. Once mCurMapRow reaches michael@0: // mCurMapRelevantRowCount, we should move to the next map. michael@0: uint32_t mCurMapRelevantRowCount; michael@0: }; michael@0: michael@0: michael@0: /* ----- inline methods ----- */ michael@0: inline int32_t nsTableCellMap::GetColCount() const michael@0: { michael@0: return mCols.Length(); michael@0: } michael@0: michael@0: inline nsCellMap* nsCellMap::GetNextSibling() const michael@0: { michael@0: return mNextSibling; michael@0: } michael@0: michael@0: inline void nsCellMap::SetNextSibling(nsCellMap* aSibling) michael@0: { michael@0: mNextSibling = aSibling; michael@0: } michael@0: michael@0: inline nsTableRowGroupFrame* nsCellMap::GetRowGroup() const michael@0: { michael@0: return mRowGroupFrame; michael@0: } michael@0: michael@0: inline int32_t nsCellMap::GetRowCount(bool aConsiderDeadRowSpanRows) const michael@0: { michael@0: int32_t rowCount = (aConsiderDeadRowSpanRows) ? mRows.Length() : mContentRowCount; michael@0: return rowCount; michael@0: } michael@0: michael@0: // nsColInfo michael@0: michael@0: inline nsColInfo::nsColInfo() michael@0: :mNumCellsOrig(0), mNumCellsSpan(0) michael@0: {} michael@0: michael@0: inline nsColInfo::nsColInfo(int32_t aNumCellsOrig, michael@0: int32_t aNumCellsSpan) michael@0: :mNumCellsOrig(aNumCellsOrig), mNumCellsSpan(aNumCellsSpan) michael@0: {} michael@0: michael@0: michael@0: #endif