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