Bug 437980 - 9 tests fail in table_indexes.html chrome test file, r=marcoz, davidb, bernd
authorAlexander Surkov <surkov.alexander@gmail.com>
Mon, 29 Jun 2009 18:54:26 +0800
changeset 29821 643cdff78555aa50e234c63131e99e3a70c65e85
parent 29820 ad6203ab39b80011f270a4f04f0d045c235fb424
child 29822 c1a07fb50446601930bb65bad942cea10fb497bb
push id7782
push usersurkov.alexander@gmail.com
push dateMon, 29 Jun 2009 09:59:17 +0000
treeherdermozilla-central@643cdff78555 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarcoz, davidb, bernd
bugs437980
milestone1.9.2a1pre
Bug 437980 - 9 tests fail in table_indexes.html chrome test file, r=marcoz, davidb, bernd
accessible/src/html/nsHTMLTableAccessible.cpp
accessible/tests/mochitest/Makefile.in
accessible/tests/mochitest/table.js
accessible/tests/mochitest/test_table_indexes.html
accessible/tests/mochitest/test_table_indexes_ariagrid.html
layout/tables/nsCellMap.cpp
layout/tables/nsCellMap.h
layout/tables/nsTableFrame.cpp
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -844,17 +844,21 @@ nsHTMLTableAccessible::GetIndexAt(PRInt3
   NS_ENSURE_ARG_POINTER(aIndex);
 
   NS_ENSURE_TRUE(IsValidRow(aRow) && IsValidColumn(aColumn), NS_ERROR_INVALID_ARG);
 
   nsITableLayout *tableLayout = nsnull;
   nsresult rv = GetTableLayout(&tableLayout);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return tableLayout->GetIndexByRowAndColumn(aRow, aColumn, aIndex);
+  rv = tableLayout->GetIndexByRowAndColumn(aRow, aColumn, aIndex);
+  if (rv == NS_TABLELAYOUT_CELL_NOT_FOUND)
+    return NS_ERROR_INVALID_ARG;
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLTableAccessible::GetColumnAtIndex(PRInt32 aIndex, PRInt32 *aColumn)
 {
   NS_ENSURE_ARG_POINTER(aColumn);
 
   nsITableLayout *tableLayout = nsnull;
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -121,17 +121,17 @@ include $(topsrcdir)/config/rules.mk
 		test_states_editablebody.html \
 		test_states_doc.html \
 		test_states_docarticle.html \
 		test_states_frames.html \
 		test_table_1.html \
 		test_table_2.html \
 		test_table_3.html \
 		test_table_4.html \
-  $(warning test_table_indexes.html temporarily disabled) \
+		test_table_indexes.html \
 		test_table_indexes_ariagrid.html \
 		test_table_sels_ariagrid.html \
 		test_textattrs.html \
 		test_textboxes.html \
 		test_textboxes.xul \
 		test_value.xul \
 		testTextboxes.js \
 		treeview.js \
--- a/accessible/tests/mochitest/table.js
+++ b/accessible/tests/mochitest/table.js
@@ -1,76 +1,97 @@
 /**
  * Test table indexes.
  *
  * @param  aIdentifier  [in] table accessible identifier
- * @param  aLen         [in] cells count
- * @param  aRowIdxes    [in] array of row indexes for each cell index
- * @param  aColIdxes    [in] array of column indexes for each cell index
+ * @param  aIdxes       [in] two dimensional array of cell indexes
  */
-function testTableIndexes(aIdentifier, aLen, aRowIdxes, aColIdxes)
+function testTableIndexes(aIdentifier, aIdxes)
 {
   var tableAcc = getAccessible(aIdentifier, [nsIAccessibleTable]);
   if (!tableAcc)
     return;
 
-  var row, column, index;
+  var obtainedRowIdx, obtainedColIdx, obtainedIdx;
   var cellAcc;
 
   var id = prettyName(aIdentifier);
 
-  for (var i = 0; i < aLen; i++) {
-    try {
-      row = tableAcc.getRowAtIndex(i);
-    } catch (e) {
-      ok(false, id + ": can't get row index for cell index " + i + "," + e);
-    }
+  var rowCount = aIdxes.length;
+  for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
+    var colCount = aIdxes[rowIdx].length;
+    for (var colIdx = 0; colIdx < colCount; colIdx++) {
+      var idx = aIdxes[rowIdx][colIdx];
+      if (idx != - 1) {
+        // getRowAtIndex
+        var origRowIdx = rowIdx;
+        while (origRowIdx > 0 &&
+               aIdxes[rowIdx][colIdx] == aIdxes[origRowIdx - 1][colIdx])
+          origRowIdx--;
 
-    try {
-      column = tableAcc.getColumnAtIndex(i);
-    } catch (e) {
-      ok(false, id + ": can't get column index for cell index " + i + "," + e);
-    }
+        try {
+          obtainedRowIdx = tableAcc.getRowAtIndex(idx);
+        } catch (e) {
+          ok(false, id + ": can't get row index for cell index " + idx + "," + e);
+        }
 
-    try {
-      index = tableAcc.getIndexAt(aRowIdxes[i], aColIdxes[i]);
-    } catch (e) {
-      ok(false,
-         id + ": can't get cell index by row index " + aRowIdxes[i] +
-           " and column index: " + aColIdxes[i]  + ", " + e);
-    }
+        is(obtainedRowIdx, origRowIdx,
+           id + ": row  for index " + idx +" is not correct");
+
+        // getColumnAtIndex
+        var origColIdx = colIdx;
+        while (origColIdx > 0 &&
+               aIdxes[rowIdx][colIdx] == aIdxes[rowIdx][origColIdx - 1])
+          origColIdx--;
 
-    is(row, aRowIdxes[i], id + ": row  for index " + i +" is nor correct");
-    is(column, aColIdxes[i],
-       id + ": column  for index " + i +" is not correct");
-    is(index, i,
-       id + ": row " + row + " /column " + column + " and index " + index + " aren't inconsistent.");
+        try {
+          obtainedColIdx = tableAcc.getColumnAtIndex(idx);
+        } catch (e) {
+          ok(false, id + ": can't get column index for cell index " + idx + "," + e);
+        }
 
-    try {
-      cellAcc = null;
-      cellAcc = tableAcc.cellRefAt(row, column);
-    } catch (e) { }
+        is(obtainedColIdx, origColIdx,
+           id + ": column  for index " + idx +" is not correct");
+
+        // cellRefAt
+        try {
+          cellAcc = null;
+          cellAcc = tableAcc.cellRefAt(rowIdx, colIdx);
+        } catch (e) { }
 
-    ok(cellAcc,
-       id + ": Can't get cell accessible at row = " + row + ", column = " + column);
+        ok(cellAcc,
+           id + ": Can't get cell accessible at row = " + rowIdx + ", column = " + colIdx);
 
-    if (cellAcc) {
-      var attrs = cellAcc.attributes;
-      var strIdx = "";
-      try {
-        strIdx = attrs.getStringProperty("table-cell-index");
-      } catch (e) {
-        ok(false,
-           id + ": no cell index from object attributes on the cell accessible at index " + index + ".");
+        // 'table-cell-index' attribute
+        if (cellAcc) {
+          var attrs = cellAcc.attributes;
+          var strIdx = "";
+          try {
+            strIdx = attrs.getStringProperty("table-cell-index");
+          } catch (e) {
+            ok(false,
+               id + ": no cell index from object attributes on the cell accessible at index " + idx + ".");
+          }
+
+          if (strIdx) {
+            is (parseInt(strIdx), idx,
+                id + ": cell index from object attributes of cell accessible isn't corrent.");
+          }
+        }
       }
 
-      if (strIdx) {
-        is (parseInt(strIdx), index,
-            id + ": cell index from object attributes of cell accessible isn't corrent.");
+      // getIndexAt
+      try {
+        obtainedIdx = tableAcc.getIndexAt(rowIdx, colIdx);
+      } catch (e) {
+        obtainedIdx = -1;
       }
+
+      is(obtainedIdx, idx,
+         id + ": row " + rowIdx + " /column " + colIdx + " and index " + obtainedIdx + " aren't inconsistent.");
     }
   }
 }
 
 /**
  * Test table getters selection methods.
  *
  * @param  aIdentifier  [in] table accessible identifier
--- a/accessible/tests/mochitest/test_table_indexes.html
+++ b/accessible/tests/mochitest/test_table_indexes.html
@@ -18,48 +18,100 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript"
           src="chrome://mochikit/content/a11y/accessible/table.js"></script>
 
   <script type="application/javascript">
     function doTest()
     {
       //////////////////////////////////////////////////////////////////////////
       // table
-      var tRow = new Array(0,0,0,1,1,1,2,2,3,3);
-      var tCol = new Array(0,1,2,0,1,2,0,1,1,2);
-
-      testTableIndexes("table", 10, tRow, tCol);
-
-      //////////////////////////////////////////////////////////////////////////
-      // tableinsane1
-      tRow = [0,0,0,1,1,1,2,2,3,3];
-      tCol = [0,1,2,0,1,2,0,1,1,2];
-
-      testTableIndexes("tableinsane1", 10, tRow, tCol);
+      var idxes = [
+        [0, 1, 2],
+        [3, 4, 5],
+        [6, 7, 7],
+        [6, 8, 9]
+      ];
 
-      //////////////////////////////////////////////////////////////////////////
-      // tableinsane2
-      tRow = [0,0,0,1,1,1,2,2,3,3,4,4,4];
-      tCol = [0,1,2,0,1,2,0,1,1,2,1,3,4];
-
-      testTableIndexes("tableinsane2", 13, tRow, tCol);
-
-      //////////////////////////////////////////////////////////////////////////
-      // tableinsane4
-      tRow = [0,0,0,1,1,1,2,2,3,4];
-      tCol = [0,1,2,0,1,2,0,2,0,0];
-
-      testTableIndexes("tableinsane4", 10, tRow, tCol);
+      testTableIndexes("table", idxes);
 
       //////////////////////////////////////////////////////////////////////////
       // tableborder
-      tRow = [0,0,0,1,1,1,2,2,3,3];
-      tCol = [0,1,2,0,1,2,0,1,1,2];
+      idxes = [
+        [0, 1, 2],
+        [3, 4, 5],
+        [6, 7, 7],
+        [6, 8, 9]
+      ];
+
+      testTableIndexes("tableborder", idxes);
+
+      //////////////////////////////////////////////////////////////////////////
+      // table
+      var idxes = [
+        [ 0,  1,  2,  2,  3,  4,  5,  6],
+        [ 7,  8,  9, 10, 11, 12, 13,  6],
+        [14, 15, 15, 16, 17, 18, 19,  6],
+        [20, 15, 15, 21, 22, 18, 23,  6]
+      ];
+
+      testTableIndexes("table2", idxes);
+
+      //////////////////////////////////////////////////////////////////////////
+      // tableinsane1 (empty row groups)
+      idxes = [
+        [0, 1, 2],
+        [3, 4, 5],
+        [6, 7, 7],
+        [6, 8, 9]
+      ];
+
+      testTableIndexes("tableinsane1", idxes);
 
-      testTableIndexes("tableborder", 10, tRow, tCol);
+      //////////////////////////////////////////////////////////////////////////
+      // tableinsane2 (empry rows)
+      idxes = [
+        [-1, -1, -1],
+        [-1, -1, -1],
+        [ 0,  1,  2]
+      ];
+
+      testTableIndexes("tableinsane2", idxes);
+
+      //////////////////////////////////////////////////////////////////////////
+      // tableinsane3 (cell holes)
+      idxes = [
+        [0, 1, -1],
+        [2, 3,  4]
+      ];
+
+      testTableIndexes("tableinsane3", idxes);
+
+      //////////////////////////////////////////////////////////////////////////
+      // tableinsane4 (empty row groups/rows and cell holes)
+      idxes = [
+        [ 0,  1,  2],
+        [-1, -1, -1],
+        [ 3,  4,  5],
+        [ 6,  6,  7],
+        [ 8, -1,  7],
+        [ 9,  9,  9]
+      ];
+      testTableIndexes("tableinsane4", idxes);
+
+      //////////////////////////////////////////////////////////////////////////
+      // tableinsane4 (just a crazy table)
+      idxes = [
+        [ 0,  1,  2, -1, -1],
+        [-1, -1, -1, -1, -1],
+        [ 3,  4,  5, -1, -1],
+        [ 6,  7,  7,  7,  7],
+        [ 6,  8,  9, -1, -1],
+        [ 6, 10,  9, 11, 12]
+      ];
+      testTableIndexes("tableinsane5", idxes);
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(doTest);
   </script>
 </head>
@@ -122,16 +174,54 @@ https://bugzilla.mozilla.org/show_bug.cg
       </tr>
       <tr>
         <td>6</td>
         <td>7</td>
       </tr>
     </tbody>
   </table>
 
+  <table cellpadding="2" cellspacing="2" border="1" width="50%" id="table2">
+    <caption>column and row spans</caption>
+    <tbody>
+      <tr>
+        <td>0</td>
+        <td>1</td>
+        <td rowspan="1" colspan="2">2</td>
+        <td>3</td>
+        <td>4</td>
+        <td>5</td>
+        <td rowspan="4" colspan="1">6</td>
+      </tr>
+      <tr>
+        <td>7</td>
+        <td>8</td>
+        <td>8</td>
+        <td>10</td>
+        <td>11</td>
+        <td>12</td>
+        <td>13</td>
+      </tr>
+      <tr>
+        <td>14</td>
+        <td rowspan="2" colspan="2">15</td>
+        <td>16</td>
+        <td>17</td>
+        <td rowspan="2" colspan="1">18</td>
+        <td>19</td>
+      </tr>
+      <tr>
+        <td>20</td>
+        <td>21</td>
+        <td>22</td>
+        <td>23</td>
+      </tr>
+    </tbody>
+  </table>
+
   <table border="1" id="tableinsane1">
     <caption>test empty row groups</caption>
     <thead>
       <tr>
         <th>col1</th>
         <th>col2</th>
         <th>col3</th>
       </tr>
@@ -151,18 +241,80 @@ https://bugzilla.mozilla.org/show_bug.cg
       </tr>
       <tr>
         <td>6</td>
         <td>7</td>
       </tr>
     </tbody>
   </table>
 
-  <table border="1" id="tableinsane2" >
-    <caption>empty rowgroup + empty rows</caption>
+  <table border="1" id="tableinsane2">
+    <caption>empty rows</caption>
+    <tbody><tr></tr><tr></tr></tbody>
+    <tbody></tbody>
+    <tbody>
+      <tr>
+        <td>0</td>
+        <td>1</td>
+        <td>2</td>
+      </tr>
+    </tbody>
+  </table>
+
+  <table border="1" id="tableinsane3">
+    <caption>missed cell</caption>
+    <tbody>
+      <tr>
+        <td>0</td>
+        <td>1</td>
+      </tr>
+    </tbody>
+    <tbody>
+      <tr>
+        <td>2</td>
+        <td>3</td>
+        <td>4</td>
+      </tr>
+    </tbody>
+  </table>
+
+  <table border="1" id="tableinsane4">
+    <caption>test empty rows + cellmap holes</caption>
+    <thead>
+      <tr>
+        <th>col1</th>
+        <th>col2</th>
+        <th>col3</th>
+      </tr>
+    </thead>
+    <tbody><tr></tr></tbody>
+    <tbody></tbody>
+    <tbody></tbody>
+    <tbody>
+      <tr>
+        <td>1</td>
+        <td>2</td>
+        <td>3</td>
+      </tr>
+      <tr>
+         <td colspan="2">4</td>
+        <td rowspan="2">5</td>
+        </tr>
+      <tr>
+        <td>6</td>
+      </tr>
+      <tr>
+        <td colspan="3">7</td>       
+      </tr>
+
+    </tbody>
+  </table>
+
+  <table border="1" id="tableinsane5">
+    <caption>just a crazy table</caption>
     <thead>
       <tr>
         <th>col1</th>
         <th>col2</th>
         <th>col3</th>
       </tr>
     </thead>
     <tbody><tr></tr></tbody>
@@ -185,42 +337,10 @@ https://bugzilla.mozilla.org/show_bug.cg
       <tr>
         <td>8</td>
         <td>9</td>
         <td>10</td>
       </tr>
 
     </tbody>
 
-  <table border="1" id="tableinsane4" >
-    <caption>test cellmap holes</caption>
-    <thead>
-      <tr>
-        <th>col1</th>
-        <th>col2</th>
-        <th>col3</th>
-      </tr>
-    </thead>
-    <tbody><tr></tr></tbody>
-    <tbody></tbody>
-    <tbody></tbody>
-    <tbody>
-      <tr>
-        <td>1</td>
-        <td>2</td>
-        <td>3</td>
-      </tr>
-      <tr>
-         <td colspan="2">4</td>
-        <td rowspan="2">5</td>
-        </tr>
-      <tr>
-        <td>6</td>
-      </tr>
-      <tr>
-        <td colspan="3">7</td>       
-      </tr>
-
-    </tbody>
-  </table>
-
 </body>
 </html>
--- a/accessible/tests/mochitest/test_table_indexes_ariagrid.html
+++ b/accessible/tests/mochitest/test_table_indexes_ariagrid.html
@@ -17,20 +17,23 @@
   <script type="application/javascript"
           src="chrome://mochikit/content/a11y/accessible/table.js"></script>
 
   <script type="application/javascript">
     function doTest()
     {
       //////////////////////////////////////////////////////////////////////////
       // ARIA grid
-      var tRow = new Array(0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3);
-      var tCol = new Array(0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2);
-
-      testTableIndexes("grid", 12, tRow, tCol);
+      var idxes = [
+        [0, 1, 2],
+        [3, 4, 5],
+        [6, 7, 8],
+        [9, 10, 11]
+      ];
+      testTableIndexes("grid", idxes);
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
--- a/layout/tables/nsCellMap.cpp
+++ b/layout/tables/nsCellMap.cpp
@@ -811,32 +811,32 @@ nsTableCellMap::GetIndexByRowAndColumn(P
 
   nsCellMap* cellMap = mFirstMap;
   while (cellMap) {
     PRInt32 rowCount = cellMap->GetRowCount();
     if (rowIndex >= rowCount) {
       // 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  + 1;
-        rowIndex -= rowCount;
-      }
+      rowIndex -= rowCount;
+
+      PRInt32 cellMapIdx = cellMap->GetHighestIndex(colCount);
+      if (cellMapIdx != -1)
+        index += cellMapIdx + 1;
+
     } 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
-      }
+      if (cellMapIdx == -1)
+        return -1; // no cell at the given row and column.
+
+      index += cellMapIdx;
+      return index;  // no need to look through further maps here
     }
 
     cellMap = cellMap->GetNextSibling();
   }
 
   return -1;
 }
 
@@ -852,20 +852,22 @@ nsTableCellMap::GetRowAndColumnByIndex(P
   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) {
+    PRInt32 cellMapIdx = cellMap->GetHighestIndex(colCount);
+    if (cellMapIdx == -1) {
+      // The index is not within this map, increase the total row index
+      // accordingly.
+      previousRows += rowCount;
+    } else {
       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 + 1;
         previousRows += rowCount;
       } else {
         cellMap->GetRowAndColumnByIndex(colCount, index, aRow, aColumn);
         // If there were previous indexes, take them into account.
@@ -1234,36 +1236,72 @@ nsCellMap::GetCellFrame(PRInt32   aRowIn
     mRows.SafeElementAt(rowIndex, *sEmptyRow).SafeElementAt(colIndex);
   if (data) {
     return data->GetCellFrame();
   }
   return nsnull;
 }
 
 PRInt32
+nsCellMap::GetHighestIndex(PRInt32 aColCount)
+{
+  PRInt32 index = -1;
+  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);
+      // No data means row doesn't have more cells.
+      if (!data)
+        break;
+
+      if (data->IsOrig())
+        index++;
+    }
+  }
+
+  return index;
+}
+
+PRInt32
 nsCellMap::GetIndexByRowAndColumn(PRInt32 aColCount,
                                   PRInt32 aRow, PRInt32 aColumn) const
 {
-  PRInt32 index = -1;
+  if (PRUint32(aRow) >= mRows.Length())
+    return -1;
 
-  if (PRUint32(aRow) >= mRows.Length())
-    return index;
+  PRInt32 index = -1;
+  PRInt32 lastColsIdx = aColCount - 1;
 
-  PRInt32 lastColsIdx = aColCount - 1;
-  for (PRInt32 rowIdx = 0; rowIdx <= aRow; rowIdx++) {
+  // Find row index of the cell where row span is started.
+  const CellDataArray& row = mRows[aRow];
+  CellData* data = row.SafeElementAt(aColumn);
+  PRInt32 origRow = data ? aRow - data->GetRowSpanOffset() : aRow;
+
+  // Calculate cell index.
+  for (PRInt32 rowIdx = 0; rowIdx <= origRow; rowIdx++) {
     const CellDataArray& row = mRows[rowIdx];
-    PRInt32 colCount = (rowIdx == aRow) ? aColumn : lastColsIdx;
+    PRInt32 colCount = (rowIdx == origRow) ? aColumn : lastColsIdx;
 
     for (PRInt32 colIdx = 0; colIdx <= colCount; colIdx++) {
-      CellData* data = row.SafeElementAt(colIdx);
-      if (data && data->IsOrig())
+      data = row.SafeElementAt(colIdx);
+      // No data means row doesn't have more cells.
+      if (!data)
+        break;
+
+      if (data->IsOrig())
         index++;
     }
   }
 
+  // Given row and column don't point to the cell.
+  if (!data)
+    return -1;
+
   return index;
 }
 
 void
 nsCellMap::GetRowAndColumnByIndex(PRInt32 aColCount, PRInt32 aIndex,
                                   PRInt32 *aRow, PRInt32 *aColumn) const
 {
   *aRow = -1;
@@ -1272,17 +1310,22 @@ nsCellMap::GetRowAndColumnByIndex(PRInt3
   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())
+
+      // The row doesn't have more cells.
+      if (!data)
+        break;
+
+      if (data->IsOrig())
         index--;
 
       if (index < 0) {
         *aRow = rowIdx;
         *aColumn = colIdx;
         return;
       }
     }
--- a/layout/tables/nsCellMap.h
+++ b/layout/tables/nsCellMap.h
@@ -321,33 +321,40 @@ public:
   nsTableRowGroupFrame* GetRowGroup() const;
 
   nsTableCellFrame* GetCellFrame(PRInt32   aRowIndex,
                                  PRInt32   aColIndex,
                                  CellData& aData,
                                  PRBool    aUseRowSpanIfOverlap) const;
 
   /**
+   * Returns highest cell index within the cell map.
+   *
+   * @param  aColCount  [in] the number of columns in the table
+   */
+  PRInt32 GetHighestIndex(PRInt32 aColCount);
+
+  /**
    * 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
+   * @param aColCount    [in] the number of columns in the table
+   * @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 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(PRInt32 aColCount, PRInt32 aIndex,
                               PRInt32 *aRow, PRInt32 *aColumn) const;
 
   /** append the cellFrame at an empty or dead cell or finally at the end of 
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -4033,17 +4033,17 @@ nsTableFrame::GetIndexByRowAndColumn(PRI
   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;
+  return (*aIndex == -1) ? NS_TABLELAYOUT_CELL_NOT_FOUND : NS_OK;
 }
 
 NS_IMETHODIMP
 nsTableFrame::GetRowAndColumnByIndex(PRInt32 aIndex,
                                     PRInt32 *aRow, PRInt32 *aColumn)
 {
   NS_ENSURE_ARG_POINTER(aRow);
   *aRow = -1;