From a3e189584ed6a1585a3cd33530f922d61fdfd350 Mon Sep 17 00:00:00 2001 From: "surkov.alexander@gmail.com" Date: Wed, 6 Feb 2008 23:03:26 -0800 Subject: [PATCH] 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 --- accessible/src/html/nsHTMLTableAccessible.cpp | 47 ++----- layout/tables/nsCellMap.cpp | 129 +++++++++++++++++- layout/tables/nsCellMap.h | 48 +++++++ layout/tables/nsITableLayout.h | 27 +++- layout/tables/nsTableFrame.cpp | 33 +++++ layout/tables/nsTableFrame.h | 2 + layout/tables/nsTableOuterFrame.cpp | 48 ++++--- layout/tables/nsTableOuterFrame.h | 3 + 8 files changed, 287 insertions(+), 50 deletions(-) diff --git a/accessible/src/html/nsHTMLTableAccessible.cpp b/accessible/src/html/nsHTMLTableAccessible.cpp index e16fded2501..1fc1b5a3b07 100644 --- a/accessible/src/html/nsHTMLTableAccessible.cpp +++ b/accessible/src/html/nsHTMLTableAccessible.cpp @@ -531,20 +531,11 @@ nsHTMLTableAccessible::GetIndexAt(PRInt32 aRow, PRInt32 aColumn, NS_ENSURE_TRUE(IsValidRow(aRow) && IsValidColumn(aColumn), NS_ERROR_INVALID_ARG); - nsresult rv = NS_OK; - nsCOMPtr domElement; - rv = GetCellAt(aRow, aColumn, *getter_AddRefs(domElement)); + nsITableLayout *tableLayout = nsnull; + nsresult rv = GetTableLayout(&tableLayout); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr 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 @@ -552,16 +543,12 @@ nsHTMLTableAccessible::GetColumnAtIndex(PRInt32 aIndex, PRInt32 *aColumn) { NS_ENSURE_ARG_POINTER(aColumn); - nsCOMPtr child; - GetChildAt(aIndex, getter_AddRefs(child)); - NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); - nsCOMPtr childNode(do_QueryInterface(child)); - NS_ASSERTION(childNode, "childNode not valid in GetColumnAtIndex!"); - nsIFrame* frame = childNode->GetFrame(); - NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); - nsCOMPtr 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 @@ -569,16 +556,12 @@ nsHTMLTableAccessible::GetRowAtIndex(PRInt32 aIndex, PRInt32 *aRow) { NS_ENSURE_ARG_POINTER(aRow); - nsCOMPtr child; - GetChildAt(aIndex, getter_AddRefs(child)); - NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); - nsCOMPtr childNode(do_QueryInterface(child)); - NS_ASSERTION(childNode, "childNode not valid in GetRowAtIndex!"); - nsIFrame* frame = childNode->GetFrame(); - NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); - nsCOMPtr 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 diff --git a/layout/tables/nsCellMap.cpp b/layout/tables/nsCellMap.cpp index a7cdb20d834..160fce3d6b1 100644 --- a/layout/tables/nsCellMap.cpp +++ b/layout/tables/nsCellMap.cpp @@ -891,7 +891,83 @@ nsTableCellMap::GetCellInfoAt(PRInt32 aRowIndex, } 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 @@ -1250,6 +1326,57 @@ nsCellMap::GetCellFrame(PRInt32 aRowIndexIn, 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) diff --git a/layout/tables/nsCellMap.h b/layout/tables/nsCellMap.h index 15bd08697d4..6435289b32d 100644 --- a/layout/tables/nsCellMap.h +++ b/layout/tables/nsCellMap.h @@ -173,6 +173,29 @@ public: 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(); @@ -301,6 +324,31 @@ public: 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 diff --git a/layout/tables/nsITableLayout.h b/layout/tables/nsITableLayout.h index c369a2f0719..72e304702c1 100644 --- a/layout/tables/nsITableLayout.h +++ b/layout/tables/nsITableLayout.h @@ -43,7 +43,7 @@ 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 @@ -87,6 +87,31 @@ public: * 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) diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 3121e741318..4bce9f2abc8 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -3880,6 +3880,39 @@ NS_IMETHODIMP nsTableFrame::GetTableSize(PRInt32& aRowCount, PRInt32& aColCount) 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 diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index bb3e3ffbcfe..54846ef28d9 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -469,6 +469,8 @@ public: 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; diff --git a/layout/tables/nsTableOuterFrame.cpp b/layout/tables/nsTableOuterFrame.cpp index 0f05eb3e9d2..bfe6c1ccd19 100644 --- a/layout/tables/nsTableOuterFrame.cpp +++ b/layout/tables/nsTableOuterFrame.cpp @@ -1342,25 +1342,41 @@ nsTableOuterFrame::GetCellDataAt(PRInt32 aRowIndex, PRInt32 aColIndex, 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_IMETHODIMP +nsTableOuterFrame::GetTableSize(PRInt32& aRowCount, PRInt32& aColCount) { - 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_ASSERTION(mInnerTableFrame, "no inner table frame yet?"); + + mInnerTableFrame->GetTableSize(aRowCount, aColCount); +} + +NS_IMETHODIMP +nsTableOuterFrame::GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 aColumn, + PRInt32 *aIndex) +{ + 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 ------------------*/ diff --git a/layout/tables/nsTableOuterFrame.h b/layout/tables/nsTableOuterFrame.h index a4781a100f5..cc6150ac65f 100644 --- a/layout/tables/nsTableOuterFrame.h +++ b/layout/tables/nsTableOuterFrame.h @@ -192,6 +192,9 @@ public: /** @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: