Bug 410052 - Fix our nsHTMLAccessibleTable class so GetIndexAt and GetRowAtIndex and GetColumnAtIndex behave consistently, patch=me, marcoz, r=marcoz, me, bernd, sr=roc, blocking1.9+=dsicore
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -526,64 +526,47 @@ nsHTMLTableAccessible::CellRefAt(PRInt32
NS_IMETHODIMP
nsHTMLTableAccessible::GetIndexAt(PRInt32 aRow, PRInt32 aColumn,
PRInt32 *aIndex)
{
NS_ENSURE_ARG_POINTER(aIndex);
NS_ENSURE_TRUE(IsValidRow(aRow) && IsValidColumn(aColumn), NS_ERROR_INVALID_ARG);
- nsresult rv = NS_OK;
- nsCOMPtr<nsIDOMElement> domElement;
- rv = GetCellAt(aRow, aColumn, *getter_AddRefs(domElement));
+ nsITableLayout *tableLayout = nsnull;
+ nsresult rv = GetTableLayout(&tableLayout);
NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIAccessible> accessible;
- GetAccService()->GetCachedAccessible(domElement, mWeakShell, getter_AddRefs(accessible));
- if (accessible) {
- rv = accessible->GetIndexInParent(aIndex);
- } else {
- // not found the corresponding cell
- *aIndex = -1;
- }
- return rv;
+ return tableLayout->GetIndexByRowAndColumn(aRow, aColumn, aIndex);
}
NS_IMETHODIMP
nsHTMLTableAccessible::GetColumnAtIndex(PRInt32 aIndex, PRInt32 *aColumn)
{
NS_ENSURE_ARG_POINTER(aColumn);
- nsCOMPtr<nsIAccessible> child;
- GetChildAt(aIndex, getter_AddRefs(child));
- NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
- nsCOMPtr<nsPIAccessNode> childNode(do_QueryInterface(child));
- NS_ASSERTION(childNode, "childNode not valid in GetColumnAtIndex!");
- nsIFrame* frame = childNode->GetFrame();
- NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
- nsCOMPtr<nsITableCellLayout> cellLayout(do_QueryInterface(frame));
- NS_ENSURE_TRUE(cellLayout, NS_ERROR_FAILURE);
- return cellLayout->GetColIndex(*aColumn);
+ nsITableLayout *tableLayout = nsnull;
+ nsresult rv = GetTableLayout(&tableLayout);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRInt32 row;
+ return tableLayout->GetRowAndColumnByIndex(aIndex, &row, aColumn);
}
NS_IMETHODIMP
nsHTMLTableAccessible::GetRowAtIndex(PRInt32 aIndex, PRInt32 *aRow)
{
NS_ENSURE_ARG_POINTER(aRow);
- nsCOMPtr<nsIAccessible> child;
- GetChildAt(aIndex, getter_AddRefs(child));
- NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
- nsCOMPtr<nsPIAccessNode> childNode(do_QueryInterface(child));
- NS_ASSERTION(childNode, "childNode not valid in GetRowAtIndex!");
- nsIFrame* frame = childNode->GetFrame();
- NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
- nsCOMPtr<nsITableCellLayout> cellLayout(do_QueryInterface(frame));
- NS_ENSURE_TRUE(cellLayout, NS_ERROR_FAILURE);
- return cellLayout->GetRowIndex(*aRow);
+ nsITableLayout *tableLayout = nsnull;
+ nsresult rv = GetTableLayout(&tableLayout);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRInt32 column;
+ return tableLayout->GetRowAndColumnByIndex(aIndex, aRow, &column);
}
NS_IMETHODIMP
nsHTMLTableAccessible::GetColumnExtentAt(PRInt32 aRow, PRInt32 aColumn,
PRInt32 *_retval)
{
NS_ENSURE_TRUE(IsValidRow(aRow) && IsValidColumn(aColumn), NS_ERROR_INVALID_ARG);
--- a/layout/tables/nsCellMap.cpp
+++ b/layout/tables/nsCellMap.cpp
@@ -886,17 +886,93 @@ nsTableCellMap::GetCellInfoAt(PRInt32 a
if (cellMap->GetRowCount() > rowIndex) {
return cellMap->GetCellInfoAt(*this, rowIndex, aColIndex, aOriginates, aColSpan);
}
rowIndex -= cellMap->GetRowCount();
cellMap = cellMap->GetNextSibling();
}
return nsnull;
}
-
+
+PRInt32
+nsTableCellMap::GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 aColumn) const
+{
+ PRInt32 index = 0;
+
+ PRInt32 colCount = mCols.Count();
+ PRInt32 rowIndex = aRow;
+
+ nsCellMap* cellMap = mFirstMap;
+ while (cellMap) {
+ PRInt32 rowCount = cellMap->GetRowCount();
+ if (rowCount < rowIndex) {
+ // If the rowCount is less than the rowIndex, this means that the index is
+ // not within the current map. If so, get the index of the last cell in
+ // the last row.
+ PRInt32 cellMapIdx = cellMap->GetIndexByRowAndColumn(colCount,
+ rowCount - 1,
+ colCount - 1);
+ if (cellMapIdx != -1) {
+ index += cellMapIdx;
+ rowIndex -= rowCount;
+ }
+ } else {
+ // Index is in valid range for this cellmap, so get the index of rowIndex
+ // and aColumn.
+ PRInt32 cellMapIdx = cellMap->GetIndexByRowAndColumn(colCount, rowIndex,
+ aColumn);
+ if (cellMapIdx != -1) {
+ index += cellMapIdx;
+ return index; // no need to look through further maps here
+ }
+ }
+
+ cellMap = cellMap->GetNextSibling();
+ }
+
+ return -1;
+}
+
+void
+nsTableCellMap::GetRowAndColumnByIndex(PRInt32 aIndex,
+ PRInt32 *aRow, PRInt32 *aColumn) const
+{
+ *aRow = -1;
+ *aColumn = -1;
+
+ PRInt32 colCount = mCols.Count();
+
+ PRInt32 previousRows = 0;
+ PRInt32 index = aIndex;
+
+ nsCellMap* cellMap = mFirstMap;
+ while (cellMap) {
+ PRInt32 rowCount = cellMap->GetRowCount();
+ // Determine the highest possible index in this map to see
+ // if wanted index is in here.
+ PRInt32 cellMapIdx = cellMap->GetIndexByRowAndColumn(colCount,
+ rowCount - 1,
+ colCount - 1);
+ if (cellMapIdx != -1) {
+ if (index > cellMapIdx) {
+ // The index is not within this map, so decrease it by the cellMapIdx
+ // determined index and increase the total row index accordingly.
+ index -= cellMapIdx;
+ previousRows += rowCount;
+ } else {
+ cellMap->GetRowAndColumnByIndex(colCount, index, aRow, aColumn);
+ // If there were previous indexes, take them into account.
+ *aRow += previousRows;
+ return; // no need to look any further.
+ }
+ }
+
+ cellMap = cellMap->GetNextSibling();
+ }
+}
PRBool nsTableCellMap::RowIsSpannedInto(PRInt32 aRowIndex,
PRInt32 aNumEffCols) const
{
PRInt32 rowIndex = aRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
if (cellMap->GetRowCount() > rowIndex) {
@@ -1245,16 +1321,67 @@ nsCellMap::GetCellFrame(PRInt32 aRowIn
CellData* data =
mRows.SafeElementAt(rowIndex, *sEmptyRow).SafeElementAt(colIndex);
if (data) {
return data->GetCellFrame();
}
return nsnull;
}
+PRInt32
+nsCellMap::GetIndexByRowAndColumn(PRInt32 aColCount,
+ PRInt32 aRow, PRInt32 aColumn) const
+{
+ PRInt32 index = -1;
+
+ if (aRow >= mRows.Length())
+ return index;
+
+ PRInt32 lastColsIdx = aColCount - 1;
+ for (PRInt32 rowIdx = 0; rowIdx <= aRow; rowIdx++) {
+ const CellDataArray& row = mRows[rowIdx];
+ PRInt32 colCount = (rowIdx == aRow) ? aColumn : lastColsIdx;
+
+ for (PRInt32 colIdx = 0; colIdx <= colCount; colIdx++) {
+ CellData* data = row.SafeElementAt(colIdx);
+ if (data && data->IsOrig())
+ index++;
+ }
+ }
+
+ return index;
+}
+
+void
+nsCellMap::GetRowAndColumnByIndex(PRInt32 aColCount, PRInt32 aIndex,
+ PRInt32 *aRow, PRInt32 *aColumn) const
+{
+ *aRow = -1;
+ *aColumn = -1;
+
+ PRInt32 index = aIndex;
+ PRInt32 rowCount = mRows.Length();
+
+ for (PRInt32 rowIdx = 0; rowIdx < rowCount; rowIdx++) {
+ const CellDataArray& row = mRows[rowIdx];
+
+ for (PRInt32 colIdx = 0; colIdx < aColCount; colIdx++) {
+ CellData* data = row.SafeElementAt(colIdx);
+ if (data && data->IsOrig())
+ index--;
+
+ if (index < 0) {
+ *aRow = rowIdx;
+ *aColumn = colIdx;
+ return;
+ }
+ }
+ }
+}
+
PRBool nsCellMap::Grow(nsTableCellMap& aMap,
PRInt32 aNumRows,
PRInt32 aRowIndex)
{
NS_ASSERTION(aNumRows >= 1, "Why are we calling this?");
// Get the number of cols we want to use for preallocating the row arrays.
PRInt32 numCols = aMap.GetColCount();
--- a/layout/tables/nsCellMap.h
+++ b/layout/tables/nsCellMap.h
@@ -168,16 +168,39 @@ public:
/** return the actual number of rows in the table represented by this CellMap */
PRInt32 GetRowCount() const;
nsTableCellFrame* GetCellInfoAt(PRInt32 aRowX,
PRInt32 aColX,
PRBool* aOriginates = nsnull,
PRInt32* aColSpan = nsnull) 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
+ */
+ PRInt32 GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 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(PRInt32 aIndex,
+ PRInt32 *aRow, PRInt32 *aColumn) const;
+
void AddColsAtEnd(PRUint32 aNumCols);
void RemoveColsAtEnd();
PRBool RowIsSpannedInto(PRInt32 aRowIndex, PRInt32 aNumEffCols) const;
PRBool RowHasSpanningCells(PRInt32 aRowIndex, PRInt32 aNumEffCols) const;
void RebuildConsideringCells(nsCellMap* aCellMap,
nsVoidArray* aCellFrames,
PRInt32 aRowIndex,
@@ -296,16 +319,41 @@ public:
nsTableRowGroupFrame* GetRowGroup() const;
nsTableCellFrame* GetCellFrame(PRInt32 aRowIndex,
PRInt32 aColIndex,
CellData& aData,
PRBool aUseRowSpanIfOverlap) const;
+ /**
+ * Returns the index of the given row and column coordinates.
+ *
+ * @see nsITableLayout::GetIndexByRowAndColumn()
+ *
+ * @param aColCount [in] the number of columns in a row
+ * @param aRow [in] the row coordinate
+ * @param aColumn [in] the column coordinate
+ */
+ PRInt32 GetIndexByRowAndColumn(PRInt32 aColCount,
+ PRInt32 aRow, PRInt32 aColumn) const;
+
+ /**
+ * Get the row and column coordinates at the given index.
+ *
+ * @see nsITableLayout::GetRowAndColumnByIndex()
+ *
+ * @param aColCount [in] the number of columns in a row
+ * @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(PRInt32 aColCount, PRInt32 aIndex,
+ PRInt32 *aRow, PRInt32 *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
--- a/layout/tables/nsITableLayout.h
+++ b/layout/tables/nsITableLayout.h
@@ -38,17 +38,17 @@
#define nsITableLayout_h__
#include "nsISupports.h"
class nsIDOMElement;
// IID for the nsITableLayout interface
// A9222E6B-437E-11d3-B227-004095E27A10
#define NS_ITABLELAYOUT_IID \
- { 0xa9222e6b, 0x437e, 0x11d3, { 0xb2, 0x27, 0x0, 0x40, 0x95, 0xe2, 0x7a, 0x10 }}
+ { 0xf8363dea, 0x11ad, 0x483a, { 0xba, 0xea, 0xf6, 0xf2, 0xc3, 0x58, 0x8d, 0xde }}
/**
* nsITableLayout
* interface for layout objects that act like tables.
* initially, we use this to get cell info
*
* @author sclark
*/
@@ -82,13 +82,38 @@ public:
PRInt32& aActualRowSpan, PRInt32& aActualColSpan,
PRBool& aIsSelected)=0;
/** Get the number of rows and column for a table from the frame's cellmap
* Some rows may not have enough cells (the number returned is the maximum possible),
* which displays as a ragged-right edge table
*/
NS_IMETHOD GetTableSize(PRInt32& aRowCount, PRInt32& aColCount)=0;
+
+ /**
+ * Retrieves the index of the cell at the given coordinates.
+ *
+ * @note The index is the order number of the cell calculated from top left
+ * cell to the right bottom cell of the table.
+ *
+ * @param aRow [in] the row the cell is in
+ * @param aColumn [in] the column the cell is in
+ * @param aIndex [out] the index to be returned
+ */
+ NS_IMETHOD GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 aColumn,
+ PRInt32 *aIndex) = 0;
+
+ /**
+ * Retrieves the coordinates of the cell at the given index.
+ *
+ * @see nsITableLayout::GetIndexByRowAndColumn()
+ *
+ * @param aIndex [in] the index for which the coordinates are to be retrieved
+ * @param aRow [out] the resulting row coordinate
+ * @param aColumn [out] the resulting column coordinate
+ */
+ NS_IMETHOD GetRowAndColumnByIndex(PRInt32 aIndex,
+ PRInt32 *aRow, PRInt32 *aColumn) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsITableLayout, NS_ITABLELAYOUT_IID)
#endif
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -3875,16 +3875,49 @@ NS_IMETHODIMP nsTableFrame::GetTableSize
aColCount = 0;
if (!cellMap) { return NS_ERROR_NOT_INITIALIZED;}
aRowCount = cellMap->GetRowCount();
aColCount = cellMap->GetColCount();
return NS_OK;
}
+NS_IMETHODIMP
+nsTableFrame::GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 aColumn,
+ PRInt32 *aIndex)
+{
+ NS_ENSURE_ARG_POINTER(aIndex);
+ *aIndex = -1;
+
+ nsTableCellMap* cellMap = GetCellMap();
+ if (!cellMap)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ *aIndex = cellMap->GetIndexByRowAndColumn(aRow, aColumn);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsTableFrame::GetRowAndColumnByIndex(PRInt32 aIndex,
+ PRInt32 *aRow, PRInt32 *aColumn)
+{
+ NS_ENSURE_ARG_POINTER(aRow);
+ *aRow = -1;
+
+ NS_ENSURE_ARG_POINTER(aColumn);
+ *aColumn = -1;
+
+ nsTableCellMap* cellMap = GetCellMap();
+ if (!cellMap)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ cellMap->GetRowAndColumnByIndex(aIndex, aRow, aColumn);
+ return NS_OK;
+}
+
/*---------------- end of nsITableLayout implementation ------------------*/
PRInt32 nsTableFrame::GetNumCellsOriginatingInCol(PRInt32 aColIndex) const
{
nsTableCellMap* cellMap = GetCellMap();
if (cellMap)
return cellMap->GetNumCellsOriginatingInCol(aColIndex);
else
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -464,16 +464,18 @@ public:
nsIFrame* aFirstFrame,
nsIFrame* aLastFrame = nsnull);
virtual void RemoveCol(nsTableColGroupFrame* aColGroupFrame,
PRInt32 aColIndex,
PRBool aRemoveFromCache,
PRBool aRemoveFromCellMap);
+ NS_IMETHOD GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 aColumn, PRInt32 *aIndex);
+ NS_IMETHOD GetRowAndColumnByIndex(PRInt32 aIndex, PRInt32 *aRow, PRInt32 *aColumn);
PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const;
PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const;
PRBool HasPctCol() const;
void SetHasPctCol(PRBool aValue);
PRBool HasCellSpanningPctCol() const;
void SetHasCellSpanningPctCol(PRBool aValue);
--- a/layout/tables/nsTableOuterFrame.cpp
+++ b/layout/tables/nsTableOuterFrame.cpp
@@ -1337,35 +1337,51 @@ nsTableOuterFrame::GetType() const
NS_IMETHODIMP
nsTableOuterFrame::GetCellDataAt(PRInt32 aRowIndex, PRInt32 aColIndex,
nsIDOMElement* &aCell, //out params
PRInt32& aStartRowIndex, PRInt32& aStartColIndex,
PRInt32& aRowSpan, PRInt32& aColSpan,
PRInt32& aActualRowSpan, PRInt32& aActualColSpan,
PRBool& aIsSelected)
{
- if (!mInnerTableFrame) { return NS_ERROR_NOT_INITIALIZED; }
- nsITableLayout *inner;
- if (NS_SUCCEEDED(CallQueryInterface(mInnerTableFrame, &inner))) {
- return (inner->GetCellDataAt(aRowIndex, aColIndex, aCell,
- aStartRowIndex, aStartColIndex,
- aRowSpan, aColSpan, aActualRowSpan, aActualColSpan,
- aIsSelected));
- }
- return NS_ERROR_NULL_POINTER;
+ NS_ASSERTION(mInnerTableFrame, "no inner table frame yet?");
+
+ mInnerTableFrame->GetCellDataAt(aRowIndex, aColIndex, aCell,
+ aStartRowIndex, aStartColIndex,
+ aRowSpan, aColSpan, aActualRowSpan,
+ aActualColSpan, aIsSelected);
+}
+
+NS_IMETHODIMP
+nsTableOuterFrame::GetTableSize(PRInt32& aRowCount, PRInt32& aColCount)
+{
+ NS_ASSERTION(mInnerTableFrame, "no inner table frame yet?");
+
+ mInnerTableFrame->GetTableSize(aRowCount, aColCount);
}
-NS_IMETHODIMP nsTableOuterFrame::GetTableSize(PRInt32& aRowCount, PRInt32& aColCount)
+NS_IMETHODIMP
+nsTableOuterFrame::GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 aColumn,
+ PRInt32 *aIndex)
{
- if (!mInnerTableFrame) { return NS_ERROR_NOT_INITIALIZED; }
- nsITableLayout *inner;
- if (NS_SUCCEEDED(CallQueryInterface(mInnerTableFrame, &inner))) {
- return (inner->GetTableSize(aRowCount, aColCount));
- }
- return NS_ERROR_NULL_POINTER;
+ NS_ENSURE_ARG_POINTER(aIndex);
+
+ NS_ASSERTION(mInnerTableFrame, "no inner table frame yet?");
+ return mInnerTableFrame->GetIndexByRowAndColumn(aRow, aColumn, aIndex);
+}
+
+NS_IMETHODIMP
+nsTableOuterFrame::GetRowAndColumnByIndex(PRInt32 aIndex,
+ PRInt32 *aRow, PRInt32 *aColumn)
+{
+ NS_ENSURE_ARG_POINTER(aRow);
+ NS_ENSURE_ARG_POINTER(aColumn);
+
+ NS_ASSERTION(mInnerTableFrame, "no inner table frame yet?");
+ return mInnerTableFrame->GetRowAndColumnByIndex(aIndex, aRow, aColumn);
}
/*---------------- end of nsITableLayout implementation ------------------*/
nsIFrame*
NS_NewTableOuterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
--- a/layout/tables/nsTableOuterFrame.h
+++ b/layout/tables/nsTableOuterFrame.h
@@ -187,16 +187,19 @@ public:
PRInt32& aStartRowIndex, PRInt32& aStartColIndex,
PRInt32& aRowSpan, PRInt32& aColSpan,
PRInt32& aActualRowSpan, PRInt32& aActualColSpan,
PRBool& aIsSelected);
/** @see nsITableFrame::GetTableSize */
NS_IMETHOD GetTableSize(PRInt32& aRowCount, PRInt32& aColCount);
+ NS_IMETHOD GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 aColumn, PRInt32 *aIndex);
+ NS_IMETHOD GetRowAndColumnByIndex(PRInt32 aIndex, PRInt32 *aRow, PRInt32 *aColumn);
+
PRBool IsNested(const nsHTMLReflowState& aReflowState) const;
protected:
nsTableOuterFrame(nsStyleContext* aContext);
virtual ~nsTableOuterFrame();