Bug 1484126 - part 2: Make all nsITableEditor::GetCellDataAt() use CellData r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 15 Oct 2018 01:43:11 +0000
changeset 489725 d3609fcd3c88b1b424ccd09cff8c8279853cba2b
parent 489724 bf74fc63e8163598d8978e014ee28bdab9bb4455
child 489726 24e31e2070fa5386008cbf4e75589e10086d3e83
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersm_kato
bugs1484126
milestone64.0a1
Bug 1484126 - part 2: Make all nsITableEditor::GetCellDataAt() use CellData r=m_kato This patch makes all nsITableEditor::GetCellDataAt() use CellData, and if each caller checks the result of GetCellDataAt() with NS_FAILED(), this replaces it with CellData::FailedOrNotFound() since GetCellDataAt() returns error even when it does not find a cell element. Finally, copies each CellData member to the variable which received corresponding value from GetCellDataAt() for making this change safe. Note that for easier to review, the copying blocks have odd indent. Those variables will be removed or corrected the indent by the following patches. Differential Revision: https://phabricator.services.mozilla.com/D8339
editor/libeditor/HTMLTableEditor.cpp
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -191,37 +191,38 @@ HTMLEditor::InsertTableCellsWithTransact
   nsresult rv = GetCellContext(nullptr,
                                getter_AddRefs(table),
                                getter_AddRefs(curCell),
                                getter_AddRefs(cellParent), &cellOffset,
                                &startRowIndex, &startColIndex);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
-  if (NS_WARN_IF(!curCell)) {
+  if (NS_WARN_IF(!table) || NS_WARN_IF(!curCell)) {
     // Don't fail if no cell found.
     return NS_OK;
   }
 
   // Get more data for current cell in row we are inserting at since we need
   // colspan value.
-  int32_t curStartRowIndex = 0, curStartColIndex = 0;
-  int32_t rowSpan = 0, colSpan = 0;
-  int32_t actualRowSpan = 0, actualColSpan = 0;
-  bool isSelected = false;
-  rv = GetCellDataAt(table, startRowIndex, startColIndex,
-                     getter_AddRefs(curCell),
-                     &curStartRowIndex, &curStartColIndex, &rowSpan, &colSpan,
-                     &actualRowSpan, &actualColSpan, &isSelected);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-  if (NS_WARN_IF(!curCell)) {
+  IgnoredErrorResult ignoredError;
+  CellData cellDataAtSelection(*this, *table, startRowIndex, startColIndex,
+                               ignoredError);
+  if (NS_WARN_IF(cellDataAtSelection.FailedOrNotFound())) {
     return NS_ERROR_FAILURE;
   }
+  MOZ_ASSERT(curCell == cellDataAtSelection.mElement);
+
+  // int32_t curStartRowIndex = cellDataAtSelection.mFirst.mRow;
+  // int32_t curStartColIndex = cellDataAtSelection.mFirst.mColumn;
+  // int32_t rowSpan =          cellDataAtSelection.mRowSpan;
+  int32_t    colSpan =          cellDataAtSelection.mColSpan;
+  // int32_t actualRowSpan =    cellDataAtSelection.mEffectiveRowSpan;
+  // int32_t actualColSpan =    cellDataAtSelection.mEffectiveColSpan;
+  // bool    isSelected =       cellDataAtSelection.mIsSelected;
 
   int32_t newCellIndex;
   switch (aInsertPosition) {
     case InsertPosition::eBeforeSelectedCell:
       newCellIndex = startColIndex;
       break;
     case InsertPosition::eAfterSelectedCell:
       newCellIndex = startColIndex + colSpan;
@@ -429,37 +430,37 @@ HTMLEditor::InsertTableColumnsWithTransa
   nsresult rv = GetCellContext(getter_AddRefs(selection),
                                getter_AddRefs(table),
                                getter_AddRefs(curCell),
                                nullptr, nullptr,
                                &startRowIndex, &startColIndex);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
-  if (NS_WARN_IF(!curCell)) {
+  if (NS_WARN_IF(!table) || NS_WARN_IF(!curCell)) {
     // Don't fail if no cell found.
     return NS_OK;
   }
 
   // Get more data for current cell, we need rowspan value.
-  int32_t curStartRowIndex = 0, curStartColIndex = 0;
-  int32_t rowSpan = 0, colSpan = 0;
-  int32_t actualRowSpan = 0, actualColSpan = 0;
-  bool isSelected = false;
-  rv = GetCellDataAt(table, startRowIndex, startColIndex,
-                     getter_AddRefs(curCell),
-                     &curStartRowIndex, &curStartColIndex,
-                     &rowSpan, &colSpan,
-                     &actualRowSpan, &actualColSpan, &isSelected);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-  if (NS_WARN_IF(!curCell)) {
+  IgnoredErrorResult ignoredError;
+  CellData cellDataAtSelection(*this, *table, startRowIndex, startColIndex,
+                               ignoredError);
+  if (NS_WARN_IF(cellDataAtSelection.FailedOrNotFound())) {
     return NS_ERROR_FAILURE;
   }
+  MOZ_ASSERT(curCell == cellDataAtSelection.mElement);
+
+  // int32_t curStartRowIndex = cellDataAtSelection.mFirst.mRow;
+  // int32_t curStartColIndex = cellDataAtSelection.mFirst.mColumn;
+  // int32_t rowSpan =          cellDataAtSelection.mRowSpan;
+  int32_t    colSpan =          cellDataAtSelection.mColSpan;
+  // int32_t actualRowSpan =    cellDataAtSelection.mEffectiveRowSpan;
+  int32_t    actualColSpan =    cellDataAtSelection.mEffectiveColSpan;
+  // bool    isSelected =       cellDataAtSelection.mIsSelected;
 
   ErrorResult error;
   TableSize tableSize(*this, *table, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
   // Should not be empty since we've already found a cell.
   MOZ_ASSERT(!tableSize.IsEmpty());
@@ -493,45 +494,48 @@ HTMLEditor::InsertTableColumnsWithTransa
                                              startColIndex, ePreviousRow,
                                              false);
   // Suppress Rules System selection munging.
   AutoTransactionsConserveSelection dontChangeSelection(*this);
 
   // If we are inserting after all existing columns, make sure table is
   // "well formed" before appending new column.
   // XXX As far as I've tested, NormalizeTable() always fails to normalize
-  //     non-rectangular table.  So, the following GetCellDataAt() will
-  //     fail if the table is not rectangle.
+  //     non-rectangular table.  So, the following CellData will fail if
+  //     the table is not rectangle.
   if (startColIndex >= tableSize.mColumnCount) {
     if (NS_WARN_IF(!selection)) {
       return NS_ERROR_FAILURE;
     }
     DebugOnly<nsresult> rv = NormalizeTable(*selection, *table);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to normalize the table");
   }
 
   RefPtr<Element> rowElement;
   for (int32_t rowIndex = 0; rowIndex < tableSize.mRowCount; rowIndex++) {
     if (startColIndex < tableSize.mColumnCount) {
       // We are inserting before an existing column.
-      int32_t curStartRowIndex = 0, curStartColIndex = 0;
-      int32_t rowSpan = 0, colSpan = 0;
-      int32_t actualRowSpan = 0, actualColSpan = 0;
-      bool isSelected = false;
-      rv = GetCellDataAt(table, rowIndex, startColIndex,
-                         getter_AddRefs(curCell),
-                         &curStartRowIndex, &curStartColIndex,
-                         &rowSpan, &colSpan,
-                         &actualRowSpan, &actualColSpan, &isSelected);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
+      CellData cellData(*this, *table, rowIndex, startColIndex, ignoredError);
+      if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+        return NS_ERROR_FAILURE;
       }
 
+      RefPtr<Element> curCell = std::move(cellData.mElement);
+      // int32_t curStartRowIndex =       cellData.mFirst.mRow;
+      int32_t    curStartColIndex =       cellData.mFirst.mColumn;
+      // int32_t rowSpan =                cellData.mRowSpan;
+      int32_t    colSpan =                cellData.mColSpan;
+      // int32_t actualRowSpan =          cellData.mEffectiveRowSpan;
+      // int32_t actualColSpan =          cellData.mEffectiveColSpan;
+      // bool    isSelected =             cellData.mIsSelected;
+
       // Don't fail entire process if we fail to find a cell (may fail just in
       // particular rows with < adequate cells per row).
+      // XXX So, here wants to know whether the CellData actually failed above.
+      //     Fix this later.
       if (!curCell) {
         continue;
       }
 
       if (curStartColIndex < startColIndex) {
         // If we have a cell spanning this location, simply increase its
         // colspan to keep table rectangular.
         // Note: we do nothing if colsspan=0, since it should automatically
@@ -540,17 +544,16 @@ HTMLEditor::InsertTableColumnsWithTransa
           SetColSpan(curCell, colSpan + aNumberOfColumnsToInsert);
         }
         continue;
       }
 
       // Simply set selection to the current cell. So, we can let
       // InsertTableCellsWithTransaction() do the work.  Insert a new cell
       // before current one.
-      IgnoredErrorResult ignoredError;
       selection->Collapse(RawRangeBoundary(curCell, 0), ignoredError);
       NS_WARNING_ASSERTION(!ignoredError.Failed(),
         "Failed to collapse Selection into the cell");
       rv = InsertTableCellsWithTransaction(aNumberOfColumnsToInsert,
                                            InsertPosition::eBeforeSelectedCell);
       NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert a cell element");
       continue;
     }
@@ -588,17 +591,16 @@ HTMLEditor::InsertTableColumnsWithTransa
       return NS_ERROR_FAILURE;
     }
 
     curCell = lastCell->AsElement();
     // Simply add same number of cells to each row.  Although tempted to check
     // cell indexes for curCell, the effects of colspan > 1 in some cells makes
     // this futile.  We must use NormalizeTable first to assure that there are
     // cells in each cellmap location.
-    IgnoredErrorResult ignoredError;
     selection->Collapse(RawRangeBoundary(curCell, 0), ignoredError);
     NS_WARNING_ASSERTION(!ignoredError.Failed(),
       "Failed to collapse Selection into the cell");
     rv = InsertTableCellsWithTransaction(aNumberOfColumnsToInsert,
                                          InsertPosition::eAfterSelectedCell);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert a cell element");
   }
   // XXX This is perhaps the result of the last call of
@@ -631,38 +633,38 @@ HTMLEditor::InsertTableRowsWithTransacti
   nsresult rv = GetCellContext(nullptr,
                                getter_AddRefs(table),
                                getter_AddRefs(curCell),
                                nullptr, nullptr,
                                &startRowIndex, &startColIndex);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
-  if (NS_WARN_IF(!curCell)) {
+  if (NS_WARN_IF(!table) || NS_WARN_IF(!curCell)) {
     // Don't fail if no cell found.
     return NS_OK;
   }
 
   // Get more data for current cell in row we are inserting at because we need
   // colspan.
-  int32_t curStartRowIndex = 0, curStartColIndex = 0;
-  int32_t rowSpan = 0, colSpan = 0;
-  int32_t actualRowSpan = 0, actualColSpan = 0;
-  bool isSelected = false;
-  rv = GetCellDataAt(table, startRowIndex, startColIndex,
-                     getter_AddRefs(curCell),
-                     &curStartRowIndex, &curStartColIndex,
-                     &rowSpan, &colSpan,
-                     &actualRowSpan, &actualColSpan, &isSelected);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-  if (NS_WARN_IF(!curCell)) {
+  IgnoredErrorResult ignoredError;
+  CellData cellDataAtSelection(*this, *table, startRowIndex, startColIndex,
+                               ignoredError);
+  if (NS_WARN_IF(cellDataAtSelection.FailedOrNotFound())) {
     return NS_ERROR_FAILURE;
   }
+  MOZ_ASSERT(curCell == cellDataAtSelection.mElement);
+
+  // int32_t curStartRowIndex = cellDataAtSelection.mFirst.mRow;
+  // int32_t curStartColIndex = cellDataAtSelection.mFirst.mColumn;
+  int32_t    rowSpan =          cellDataAtSelection.mRowSpan;
+  // int32_t colSpan =          cellDataAtSelection.mColSpan;
+  int32_t    actualRowSpan =    cellDataAtSelection.mEffectiveRowSpan;
+  // int32_t actualColSpan =    cellDataAtSelection.mEffectiveColSpan;
+  // bool isSelected =          cellDataAtSelection.mIsSelected;
 
   ErrorResult error;
   TableSize tableSize(*this, *table, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
   // Should not be empty since we've already found a cell.
   MOZ_ASSERT(!tableSize.IsEmpty());
@@ -700,32 +702,32 @@ HTMLEditor::InsertTableRowsWithTransacti
 
   RefPtr<Element> cellForRowParent;
   int32_t cellsInRow = 0;
   if (startRowIndex < tableSize.mRowCount) {
     // We are inserting above an existing row.  Get each cell in the insert
     // row to adjust for colspan effects while we count how many cells are
     // needed.
     for (int32_t colIndex = 0, actualColSpan = 0;; colIndex += actualColSpan) {
-      RefPtr<Element> cellElement;
-      int32_t curStartRowIndex = 0, curStartColIndex = 0;
-      int32_t rowSpan = 0, colSpan = 0;
-      int32_t actualRowSpan = 0;
-      nsresult rv = GetCellDataAt(table, startRowIndex, colIndex,
-                                  getter_AddRefs(cellElement),
-                                  &curStartRowIndex, &curStartColIndex,
-                                  &rowSpan, &colSpan,
-                                  &actualRowSpan, &actualColSpan,
-                                  &isSelected);
-      if (NS_FAILED(rv)) {
+      CellData cellData(*this, *table, startRowIndex, colIndex, ignoredError);
+      if (cellData.FailedOrNotFound()) {
         break; // Perhaps, we reach end of the row.
       }
 
+      RefPtr<Element> cellElement = std::move(cellData.mElement);
+      int32_t    curStartRowIndex =           cellData.mFirst.mRow;
+      // int32_t curStartColIndex =           cellData.mFirst.mColumn;
+      int32_t    rowSpan =                    cellData.mRowSpan;
+      // int32_t colSpan =                    cellData.mColSpan;
+      // int32_t actualRowSpan =              cellData.mEffectiveRowSpan;
+                 actualColSpan =              cellData.mEffectiveColSpan;
+      // bool    isSelected =                 cellData.mIsSelected;
+
+      // XXX So, this is impossible case. Will be removed.
       if (NS_WARN_IF(!cellElement)) {
-        // XXX What's this case?
         actualColSpan = 1;
         continue;
       }
 
       if (curStartRowIndex < startRowIndex) {
         // We have a cell spanning this location.  Increase its rowspan.
         // Note that if rowspan is 0, we do nothing since that cell should
         // automatically extend into the new row.
@@ -746,30 +748,30 @@ HTMLEditor::InsertTableRowsWithTransacti
     // cells...
     // XXX colspan=0 support has now been removed in table layout so maybe this
     //     can be cleaned up now? (bug 1243183)
     cellsInRow = tableSize.mColumnCount;
 
     // but we must compensate for all cells with rowspan = 0 in the last row.
     const int32_t kLastRowIndex = tableSize.mRowCount - 1;
     for (int32_t colIndex = 0, actualColSpan = 0;; colIndex += actualColSpan) {
-      RefPtr<Element> cellElement;
-      int32_t curStartRowIndex = 0, curStartColIndex = 0;
-      int32_t rowSpan = 0, colSpan = 0;
-      int32_t actualRowSpan = 0;
-      nsresult rv = GetCellDataAt(table, kLastRowIndex, colIndex,
-                                  getter_AddRefs(cellElement),
-                                  &curStartRowIndex, &curStartColIndex,
-                                  &rowSpan, &colSpan,
-                                  &actualRowSpan, &actualColSpan,
-                                  &isSelected);
-      if (NS_FAILED(rv)) {
+      CellData cellData(*this, *table, kLastRowIndex, colIndex, ignoredError);
+      if (cellData.FailedOrNotFound()) {
         break; // Perhaps, we reach end of the row.
       }
 
+      RefPtr<Element> cellElement = std::move(cellData.mElement);
+      int32_t    curStartRowIndex =           cellData.mFirst.mRow;
+      // int32_t curStartColIndex =           cellData.mFirst.mColumn;
+      int32_t    rowSpan =                    cellData.mRowSpan;
+      // int32_t colSpan =                    cellData.mColSpan;
+      // int32_t actualRowSpan =              cellData.mEffectiveRowSpan;
+                 actualColSpan =              cellData.mEffectiveColSpan;
+      // bool    isSelected =                 cellData.mIsSelected;
+
       if (!rowSpan) {
         MOZ_ASSERT(cellsInRow >= actualColSpan);
         cellsInRow -= actualColSpan;
       }
 
       // Save cell from the last row that we will use below
       if (!cellForRowParent && curStartRowIndex == kLastRowIndex) {
         cellForRowParent = std::move(cellElement);
@@ -1394,37 +1396,37 @@ HTMLEditor::DeleteSelectedTableColumnsWi
 }
 
 nsresult
 HTMLEditor::DeleteTableColumnWithTransaction(Element& aTableElement,
                                              int32_t aColumnIndex)
 {
   // XXX Why don't this method remove proper <col> (and <colgroup>)?
   ErrorResult error;
+  IgnoredErrorResult ignoredError;
   for (int32_t rowIndex = 0;; rowIndex++) {
-    RefPtr<Element> cell;
-    int32_t startRowIndex = 0, startColIndex = 0;
-    int32_t rowSpan = 0, colSpan = 0;
-    int32_t actualRowSpan = 0, actualColSpan = 0;
-    bool isSelected = false;
-    nsresult rv =
-      GetCellDataAt(&aTableElement, rowIndex, aColumnIndex,
-                    getter_AddRefs(cell),
-                    &startRowIndex, &startColIndex, &rowSpan, &colSpan,
-                    &actualRowSpan, &actualColSpan, &isSelected);
+    CellData cellData(*this, aTableElement, rowIndex, aColumnIndex,
+                      ignoredError);
     // Failure means that there is no more row in the table.  In this case,
     // we shouldn't return error since we just reach the end of the table.
-    // XXX Ideally, GetCellDataAt() should return
-    //     NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND in such case instead of
-    //     error.  However, it's used by a lot of methods, so, it's really
-    //     risky to change it.
-    if (NS_FAILED(rv) || !cell) {
+    // XXX Should distinguish whether CellData returns error or just not found
+    //     later.
+    if (cellData.FailedOrNotFound()) {
       return NS_OK;
     }
 
+    RefPtr<Element> cell = std::move(cellData.mElement);
+    int32_t    startRowIndex =       cellData.mFirst.mRow;
+    int32_t    startColIndex =       cellData.mFirst.mColumn;
+    // int32_t rowSpan =             cellData.mRowSpan;
+    int32_t    colSpan =             cellData.mColSpan;
+    int32_t    actualRowSpan =       cellData.mEffectiveRowSpan;
+    // int32_t actualColSpan =       cellData.mEffectiveColSpan;
+    // bool    isSelected =          cellData.mIsSelected;
+
     // Find cells that don't start in column we are deleting.
     MOZ_ASSERT(colSpan >= 0);
     if (startColIndex < aColumnIndex || colSpan != 1) {
       // If we have a cell spanning this location, decrease its colspan to
       // keep table rectangular, but if colspan is 0, it'll be adjusted
       // automatically.
       if (colSpan > 0) {
         NS_WARNING_ASSERTION(colSpan > 1, "colspan should be 2 or larger");
@@ -1446,17 +1448,17 @@ HTMLEditor::DeleteTableColumnWithTransac
     // Delete the cell
     int32_t numberOfCellsInRow =
       GetNumberOfCellsInRow(aTableElement, rowIndex);
     NS_WARNING_ASSERTION(numberOfCellsInRow > 0,
       "Failed to count existing cells in the row");
     if (numberOfCellsInRow != 1) {
       // If removing cell is not the last cell of the row, we can just remove
       // it.
-      rv = DeleteNodeWithTransaction(*cell);
+      nsresult rv = DeleteNodeWithTransaction(*cell);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       // Skip rows which the removed cell spanned.
       rowIndex += actualRowSpan - 1;
       continue;
     }
 
@@ -1475,27 +1477,27 @@ HTMLEditor::DeleteTableColumnWithTransac
     }
 
     if (tableSize.mRowCount == 1) {
       // We're deleting the last row.  So, let's remove the <table> now.
       RefPtr<Selection> selection = GetSelection();
       if (NS_WARN_IF(!selection)) {
         return NS_ERROR_FAILURE;
       }
-      rv = DeleteTableElementAndChildrenWithTransaction(*selection,
-                                                        aTableElement);
+      nsresult rv =
+        DeleteTableElementAndChildrenWithTransaction(*selection, aTableElement);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       return NS_OK;
     }
 
     // Delete the row by placing caret in cell we were to delete.  We need
     // to call DeleteTableRowWithTransaction() to handle cells with rowspan.
-    rv = DeleteTableRowWithTransaction(aTableElement, startRowIndex);
+    nsresult rv = DeleteTableRowWithTransaction(aTableElement, startRowIndex);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     // Note that we decrement rowIndex since a row was deleted.
     rowIndex--;
   }
 }
@@ -1672,36 +1674,40 @@ HTMLEditor::DeleteTableRowWithTransactio
       : mElement(aSpanCellElement)
       , mNewRowSpanValue(aNewRowSpanValue)
     {
     }
   };
   AutoTArray<SpanCell, 10> spanCellArray;
   RefPtr<Element> cellInDeleteRow;
   int32_t columnIndex = 0;
+  IgnoredErrorResult ignoredError;
   while (aRowIndex < tableSize.mRowCount &&
          columnIndex < tableSize.mColumnCount) {
-    RefPtr<Element> cell;
-    int32_t startRowIndex = 0, startColIndex = 0;
-    int32_t rowSpan = 0, colSpan = 0;
-    int32_t actualRowSpan = 0, actualColSpan = 0;
-    bool isSelected = false;
-    nsresult rv =
-      GetCellDataAt(&aTableElement, aRowIndex, columnIndex,
-                    getter_AddRefs(cell),
-                    &startRowIndex, &startColIndex, &rowSpan, &colSpan,
-                    &actualRowSpan, &actualColSpan, &isSelected);
-    // We don't fail if we don't find a cell, so this must be real bad
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    CellData cellData(*this, aTableElement, aRowIndex, columnIndex,
+                      ignoredError);
+    if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+      return NS_ERROR_FAILURE;
     }
 
+    RefPtr<Element> cell = std::move(cellData.mElement);
+    int32_t    startRowIndex =       cellData.mFirst.mRow;
+    int32_t    startColIndex =       cellData.mFirst.mColumn;
+    int32_t    rowSpan =             cellData.mRowSpan;
+    // int32_t colSpan =             cellData.mColSpan;
+    int32_t    actualRowSpan =       cellData.mEffectiveRowSpan;
+    int32_t    actualColSpan =       cellData.mEffectiveColSpan;
+    // bool    isSelected =          cellData.mIsSelected;
+
+    // XXX So, we should distinguish if CellDate returns error or just not
+    //     found later.
     if (!cell) {
       break;
     }
+
     // Compensate for cells that don't start or extend below the row we are
     // deleting.
     if (startRowIndex < aRowIndex) {
       // If a cell starts in row above us, decrease its rowspan to keep table
       // rectangular but we don't need to do this if rowspan=0, since it will
       // be automatically adjusted.
       if (rowSpan > 0) {
         // Build list of cells to change rowspan.  We can't do it now since
@@ -1712,19 +1718,20 @@ HTMLEditor::DeleteTableRowWithTransactio
       }
     } else {
       if (rowSpan > 1) {
         // Cell spans below row to delete, so we must insert new cells to
         // keep rows below.  Note that we test "rowSpan" so we don't do this
         // if rowSpan = 0 (automatic readjustment).
         int32_t aboveRowToInsertNewCellInto = aRowIndex - startRowIndex + 1;
         int32_t numOfRawSpanRemainingBelow = actualRowSpan - 1;
-        rv = SplitCellIntoRows(&aTableElement, startRowIndex, startColIndex,
-                               aboveRowToInsertNewCellInto,
-                               numOfRawSpanRemainingBelow, nullptr);
+        nsresult rv =
+          SplitCellIntoRows(&aTableElement, startRowIndex, startColIndex,
+                            aboveRowToInsertNewCellInto,
+                            numOfRawSpanRemainingBelow, nullptr);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
       if (!cellInDeleteRow) {
         cellInDeleteRow = cell; // Reference cell to find row to delete
       }
     }
@@ -1853,17 +1860,16 @@ HTMLEditor::SelectBlockOfCells(Element* 
   int32_t minRow =
     std::min(startCellIndexes.mRow, endCellIndexes.mRow);
   int32_t maxColumn =
     std::max(startCellIndexes.mColumn, endCellIndexes.mColumn);
   int32_t maxRow =
     std::max(startCellIndexes.mRow, endCellIndexes.mRow);
 
   RefPtr<Element> cell;
-  int32_t currentRowIndex, currentColIndex;
   cell = GetFirstSelectedTableCellElement(*selection, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
   if (!cell) {
     return NS_OK;
   }
   RefPtr<nsRange> range = selection->GetRangeAt(0);
@@ -1887,41 +1893,49 @@ HTMLEditor::SelectBlockOfCells(Element* 
       return error.StealNSResult();
     }
     if (cell) {
       MOZ_ASSERT(mSelectedCellIndex > 0);
       range = selection->GetRangeAt(mSelectedCellIndex - 1);
     }
   }
 
-  int32_t rowSpan, colSpan, actualRowSpan, actualColSpan;
-  bool    isSelected;
   nsresult rv = NS_OK;
+  IgnoredErrorResult ignoredError;
   for (int32_t row = minRow; row <= maxRow; row++) {
-    for (int32_t col = minColumn; col <= maxColumn;
-        col += std::max(actualColSpan, 1)) {
-      rv = GetCellDataAt(table, row, col, getter_AddRefs(cell),
-                         &currentRowIndex, &currentColIndex,
-                         &rowSpan, &colSpan,
-                         &actualRowSpan, &actualColSpan, &isSelected);
-      if (NS_FAILED(rv)) {
-        break;
+    for (int32_t col = minColumn, actualColSpan = 0;
+         col <= maxColumn;
+         col += std::max(actualColSpan, 1)) {
+      CellData cellData(*this, *table, row, col, ignoredError);
+      if (cellData.FailedOrNotFound()) {
+        return NS_ERROR_FAILURE;
       }
+
+      RefPtr<Element> cell = std::move(cellData.mElement);
+      int32_t    currentRowIndex =     cellData.mFirst.mRow;
+      int32_t    currentColIndex =     cellData.mFirst.mColumn;
+      // int32_t rowSpan =             cellData.mRowSpan;
+      // int32_t colSpan =             cellData.mColSpan;
+      // int32_t actualRowSpan =       cellData.mEffectiveRowSpan;
+                 actualColSpan =       cellData.mEffectiveColSpan;
+      bool       isSelected =          cellData.mIsSelected;
+
       // Skip cells that already selected or are spanned from previous locations
+      // XXX So, we should distinguish whether CellData returns error or just
+      //     not found later.
       if (!isSelected && cell &&
           row == currentRowIndex && col == currentColIndex) {
         rv = AppendNodeToSelectionAsRange(cell);
         if (NS_FAILED(rv)) {
           break;
         }
       }
     }
   }
-  // NS_OK, otherwise, the last failure of GetCellDataAt() or
-  // AppendNodeToSelectionAsRange().
+  // NS_OK, otherwise, the last failure of AppendNodeToSelectionAsRange().
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLEditor::SelectAllTableCells()
 {
   RefPtr<Selection> selection = GetSelection();
   if (NS_WARN_IF(!selection)) {
@@ -1954,45 +1968,54 @@ HTMLEditor::SelectAllTableCells()
   SelectionBatcher selectionBatcher(selection);
 
   // It is now safe to clear the selection
   // BE SURE TO RESET IT BEFORE LEAVING!
   nsresult rv = ClearSelection();
 
   // Select all cells in the same column as current cell
   bool cellSelected = false;
-  int32_t rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
-  bool    isSelected;
+  IgnoredErrorResult ignoredError;
   for (int32_t row = 0; row < tableSize.mRowCount; row++) {
-    for (int32_t col = 0;
+    for (int32_t col = 0, actualColSpan = 0;
          col < tableSize.mColumnCount;
          col += std::max(actualColSpan, 1)) {
-      rv = GetCellDataAt(table, row, col, getter_AddRefs(cell),
-                         &currentRowIndex, &currentColIndex,
-                         &rowSpan, &colSpan,
-                         &actualRowSpan, &actualColSpan, &isSelected);
-      if (NS_FAILED(rv)) {
+      CellData cellData(*this, *table, row, col, ignoredError);
+      if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+        rv = NS_ERROR_FAILURE;
         break;
       }
+
+      RefPtr<Element> cell = std::move(cellData.mElement);
+      int32_t    currentRowIndex =     cellData.mFirst.mRow;
+      int32_t    currentColIndex =     cellData.mFirst.mColumn;
+      // int32_t rowSpan =             cellData.mRowSpan;
+      // int32_t colSpan =             cellData.mColSpan;
+      // int32_t actualRowSpan =       cellData.mEffectiveRowSpan;
+                 actualColSpan =       cellData.mEffectiveColSpan;
+      // bool    isSelected =          cellData.mIsSelected;
+
       // Skip cells that are spanned from previous rows or columns
+      // XXX So, we should distinguish whether CellData returns error or just
+      //     not found later.
       if (cell && row == currentRowIndex && col == currentColIndex) {
         rv =  AppendNodeToSelectionAsRange(cell);
         if (NS_FAILED(rv)) {
           break;
         }
         cellSelected = true;
       }
     }
   }
   // Safety code to select starting cell if nothing else was selected
   if (!cellSelected) {
     return AppendNodeToSelectionAsRange(startCell);
   }
   // NS_OK, otherwise, the error of ClearSelection() when there is no column or
-  // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
+  // the last failure of CellData or AppendNodeToSelectionAsRange().
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLEditor::SelectTableRow()
 {
   RefPtr<Selection> selection = GetSelection();
   if (NS_WARN_IF(!selection)) {
@@ -2039,42 +2062,52 @@ HTMLEditor::SelectTableRow()
   SelectionBatcher selectionBatcher(selection);
 
   // It is now safe to clear the selection
   // BE SURE TO RESET IT BEFORE LEAVING!
   rv = ClearSelection();
 
   // Select all cells in the same row as current cell
   bool cellSelected = false;
-  int32_t rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
-  bool    isSelected;
-  for (int32_t col = 0;
+  IgnoredErrorResult ignoredError;
+  for (int32_t col = 0, actualColSpan = 0;
        col < tableSize.mColumnCount;
        col += std::max(actualColSpan, 1)) {
-    rv = GetCellDataAt(table, startRowIndex, col, getter_AddRefs(cell),
-                       &currentRowIndex, &currentColIndex, &rowSpan, &colSpan,
-                       &actualRowSpan, &actualColSpan, &isSelected);
-    if (NS_FAILED(rv)) {
+    CellData cellData(*this, *table, startRowIndex, col, ignoredError);
+    if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+      rv = NS_ERROR_FAILURE;
       break;
     }
+
+    RefPtr<Element> cell = std::move(cellData.mElement);
+    int32_t    currentRowIndex =     cellData.mFirst.mRow;
+    int32_t    currentColIndex =     cellData.mFirst.mColumn;
+    // int32_t rowSpan =             cellData.mRowSpan;
+    // int32_t colSpan =             cellData.mColSpan;
+    // int32_t actualRowSpan =       cellData.mEffectiveRowSpan;
+               actualColSpan =       cellData.mEffectiveColSpan;
+    // bool    isSelected =          cellData.mIsSelected;
+
     // Skip cells that are spanned from previous rows or columns
+    // XXX So, we should distinguish whether CellData returns error or just
+    //     not found later.
     if (cell && currentRowIndex == startRowIndex && currentColIndex == col) {
       rv = AppendNodeToSelectionAsRange(cell);
       if (NS_FAILED(rv)) {
         break;
       }
       cellSelected = true;
     }
   }
   // Safety code to select starting cell if nothing else was selected
   if (!cellSelected) {
     return AppendNodeToSelectionAsRange(startCell);
   }
   // NS_OK, otherwise, the error of ClearSelection() when there is no column or
-  // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
+  // the last failure of CellData or AppendNodeToSelectionAsRange().
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLEditor::SelectTableColumn()
 {
   RefPtr<Selection> selection = GetSelection();
   if (NS_WARN_IF(!selection)) {
@@ -2117,42 +2150,52 @@ HTMLEditor::SelectTableColumn()
   SelectionBatcher selectionBatcher(selection);
 
   // It is now safe to clear the selection
   // BE SURE TO RESET IT BEFORE LEAVING!
   rv = ClearSelection();
 
   // Select all cells in the same column as current cell
   bool cellSelected = false;
-  int32_t rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
-  bool    isSelected;
-  for (int32_t row = 0;
+  IgnoredErrorResult ignoredError;
+  for (int32_t row = 0, actualRowSpan = 0;
        row < tableSize.mRowCount;
        row += std::max(actualRowSpan, 1)) {
-    rv = GetCellDataAt(table, row, startColIndex, getter_AddRefs(cell),
-                       &currentRowIndex, &currentColIndex, &rowSpan, &colSpan,
-                       &actualRowSpan, &actualColSpan, &isSelected);
-    if (NS_FAILED(rv)) {
+    CellData cellData(*this, *table, row, startColIndex, ignoredError);
+    if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+      rv = NS_ERROR_FAILURE;
       break;
     }
+
+    RefPtr<Element> cell = std::move(cellData.mElement);
+    int32_t    currentRowIndex =     cellData.mFirst.mRow;
+    int32_t    currentColIndex =     cellData.mFirst.mColumn;
+    // int32_t rowSpan =             cellData.mRowSpan;
+    // int32_t colSpan =             cellData.mColSpan;
+               actualRowSpan =       cellData.mEffectiveRowSpan;
+    // int32_t actualColSpan =       cellData.mEffectiveColSpan;
+    // bool    isSelected =          cellData.mIsSelected;
+
     // Skip cells that are spanned from previous rows or columns
+    // XXX So, we should distinguish whether CellData returns error or just
+    //     not found later.
     if (cell && currentRowIndex == row && currentColIndex == startColIndex) {
       rv = AppendNodeToSelectionAsRange(cell);
       if (NS_FAILED(rv)) {
         break;
       }
       cellSelected = true;
     }
   }
   // Safety code to select starting cell if nothing else was selected
   if (!cellSelected) {
     return AppendNodeToSelectionAsRange(startCell);
   }
   // NS_OK, otherwise, the error of ClearSelection() when there is no row or
-  // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
+  // the last failure of CellData or AppendNodeToSelectionAsRange().
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLEditor::SplitTableCell()
 {
   RefPtr<Element> table;
   RefPtr<Element> cell;
@@ -2246,47 +2289,57 @@ HTMLEditor::CopyCellBackgroundColor(Elem
 nsresult
 HTMLEditor::SplitCellIntoColumns(Element* aTable,
                                  int32_t aRowIndex,
                                  int32_t aColIndex,
                                  int32_t aColSpanLeft,
                                  int32_t aColSpanRight,
                                  Element** aNewCell)
 {
-  NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
+  if (NS_WARN_IF(!aTable)) {
+    return NS_ERROR_INVALID_ARG;
+  }
   if (aNewCell) {
     *aNewCell = nullptr;
   }
 
-  RefPtr<Element> cell;
-  int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
-  bool    isSelected;
-  nsresult rv =
-    GetCellDataAt(aTable, aRowIndex, aColIndex, getter_AddRefs(cell),
-                  &startRowIndex, &startColIndex,
-                  &rowSpan, &colSpan,
-                  &actualRowSpan, &actualColSpan, &isSelected);
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(cell, NS_ERROR_NULL_POINTER);
+  IgnoredErrorResult ignoredError;
+  CellData cellData(*this, *aTable, aRowIndex, aColIndex, ignoredError);
+  if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  RefPtr<Element> cell = std::move(cellData.mElement);
+  // int32_t startRowIndex =       cellData.mFirst.mRow;
+  // int32_t startColIndex =       cellData.mFirst.mColumn;
+  // int32_t rowSpan =             cellData.mRowSpan;
+  // int32_t colSpan =             cellData.mColSpan;
+  int32_t    actualRowSpan =       cellData.mEffectiveRowSpan;
+  int32_t    actualColSpan =       cellData.mEffectiveColSpan;
+  // bool    isSelected =          cellData.mIsSelected;
 
   // We can't split!
   if (actualColSpan <= 1 || (aColSpanLeft + aColSpanRight) > actualColSpan) {
     return NS_OK;
   }
 
   // Reduce colspan of cell to split
-  rv = SetColSpan(cell, aColSpanLeft);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsresult rv = SetColSpan(cell, aColSpanLeft);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   // Insert new cell after using the remaining span
   //  and always get the new cell so we can copy the background color;
   RefPtr<Element> newCell;
   rv = InsertCell(cell, actualRowSpan, aColSpanRight, true, false,
                   getter_AddRefs(newCell));
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   if (!newCell) {
     return NS_OK;
   }
   if (aNewCell) {
     NS_ADDREF(*aNewCell = newCell.get());
   }
   return CopyCellBackgroundColor(newCell, cell);
 }
@@ -2302,64 +2355,71 @@ HTMLEditor::SplitCellIntoRows(Element* a
   if (NS_WARN_IF(!aTable)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (aNewCell) {
     *aNewCell = nullptr;
   }
 
-  RefPtr<Element> cell;
-  int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
-  bool    isSelected;
-  nsresult rv =
-    GetCellDataAt(aTable, aRowIndex, aColIndex, getter_AddRefs(cell),
-                  &startRowIndex, &startColIndex,
-                  &rowSpan, &colSpan,
-                  &actualRowSpan, &actualColSpan, &isSelected);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-  if (NS_WARN_IF(!cell)) {
+  IgnoredErrorResult ignoredError;
+  CellData cellData(*this, *aTable, aRowIndex, aColIndex, ignoredError);
+  if (NS_WARN_IF(cellData.FailedOrNotFound())) {
     return NS_ERROR_FAILURE;
   }
 
+  RefPtr<Element> cell = std::move(cellData.mElement);
+  int32_t    startRowIndex =       cellData.mFirst.mRow;
+  int32_t    startColIndex =       cellData.mFirst.mColumn;
+  // int32_t rowSpan =             cellData.mRowSpan;
+  // int32_t colSpan =             cellData.mColSpan;
+  int32_t    actualRowSpan =       cellData.mEffectiveRowSpan;
+  int32_t    actualColSpan =       cellData.mEffectiveColSpan;
+  // bool    isSelected =          cellData.mIsSelected;
+
   // We can't split!
   if (actualRowSpan <= 1 || (aRowSpanAbove + aRowSpanBelow) > actualRowSpan) {
     return NS_OK;
   }
 
   ErrorResult error;
   TableSize tableSize(*this, *aTable, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
+  // Find a cell to insert before or after
   RefPtr<Element> cell2;
   RefPtr<Element> lastCellFound;
-  int32_t startRowIndex2, startColIndex2, rowSpan2, colSpan2, actualRowSpan2, actualColSpan2;
-  bool    isSelected2;
-  int32_t colIndex = 0;
   bool insertAfter = (startColIndex > 0);
-  // This is the row we will insert new cell into
-  int32_t rowBelowIndex = startRowIndex+aRowSpanAbove;
-
-  // Find a cell to insert before or after
-  for (;;) {
-    // Search for a cell to insert before
-    rv = GetCellDataAt(aTable, rowBelowIndex,
-                       colIndex, getter_AddRefs(cell2),
-                       &startRowIndex2, &startColIndex2, &rowSpan2, &colSpan2,
-                       &actualRowSpan2, &actualColSpan2, &isSelected2);
+  for (int32_t colIndex = 0, actualColSpan2 = 0,
+               rowBelowIndex = startRowIndex + aRowSpanAbove;
+       colIndex <= tableSize.mColumnCount;
+       colIndex += std::max(actualColSpan2, 1)) {
+    CellData cellDataAtInsertionPoint(*this, *aTable, rowBelowIndex, colIndex,
+                                      ignoredError);
     // If we fail here, it could be because row has bad rowspan values,
-    //   such as all cells having rowspan > 1 (Call FixRowSpan first!)
-    if (NS_FAILED(rv) || !cell) {
+    // such as all cells having rowspan > 1 (Call FixRowSpan first!).
+    // XXX According to the comment, this does not assume that
+    //     FixRowSpan() doesn't work well and user can create non-rectangular
+    //     table.  So, we should not return error when CellData cannot find
+    //     a cell.
+    if (NS_WARN_IF(cellDataAtInsertionPoint.FailedOrNotFound())) {
       return NS_ERROR_FAILURE;
     }
 
+    cell2 =           std::move(cellDataAtInsertionPoint.mElement);
+    int32_t    startRowIndex2 = cellDataAtInsertionPoint.mFirst.mRow;
+    int32_t    startColIndex2 = cellDataAtInsertionPoint.mFirst.mColumn;
+    // int32_t rowSpan2 =       cellDataAtInsertionPoint.mRowSpan;
+    // int32_t colSpan2 =       cellDataAtInsertionPoint.mColSpan;
+    // int32_t actualRowSpan2 = cellDataAtInsertionPoint.mEffectiveRowSpan;
+               actualColSpan2 = cellDataAtInsertionPoint.mEffectiveColSpan;
+    // bool    isSelected2 =    cellDataAtInsertionPoint.mIsSelected;
+
     // Skip over cells spanned from above (like the one we are splitting!)
     if (cell2 && startRowIndex2 == rowBelowIndex) {
       if (!insertAfter) {
         // Inserting before, so stop at first cell in row we want to insert
         // into.
         break;
       }
       // New cell isn't first in row,
@@ -2372,45 +2432,41 @@ HTMLEditor::SplitCellIntoRows(Element* a
       //  prevented us from finding a cell to insert after...
       if (startColIndex2 > startColIndex) {
         // ... so instead insert before the cell we found
         insertAfter = false;
         break;
       }
       lastCellFound = cell2;
     }
-    // Skip to next available cellmap location
-    colIndex += std::max(actualColSpan2, 1);
-
-    // Done when past end of total number of columns
-    if (colIndex > tableSize.mColumnCount) {
-      break;
-    }
   }
 
   if (!cell2 && lastCellFound) {
     // Edge case where we didn't find a cell to insert after
     //  or before because column(s) before desired column
     //  and all columns after it are spanned from above.
     //  We can insert after the last cell we found
     cell2 = lastCellFound;
     insertAfter = true; // Should always be true, but let's be sure
   }
 
   // Reduce rowspan of cell to split
-  rv = SetRowSpan(cell, aRowSpanAbove);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  nsresult rv = SetRowSpan(cell, aRowSpanAbove);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   // Insert new cell after using the remaining span
   //  and always get the new cell so we can copy the background color;
   RefPtr<Element> newCell;
   rv = InsertCell(cell2, aRowSpanBelow, actualColSpan, insertAfter, false,
                   getter_AddRefs(newCell));
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   if (!newCell) {
     return NS_OK;
   }
   if (aNewCell) {
     NS_ADDREF(*aNewCell = newCell.get());
   }
   return CopyCellBackgroundColor(newCell, cell2);
 }
@@ -2461,31 +2517,29 @@ HTMLEditor::SwitchTableCellHeaderType(El
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLEditor::JoinTableCells(bool aMergeNonContiguousContents)
 {
   RefPtr<Element> table;
   RefPtr<Element> targetCell;
-  int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
-  bool    isSelected;
-  RefPtr<Element> cell2;
-  int32_t startRowIndex2, startColIndex2, rowSpan2, colSpan2, actualRowSpan2, actualColSpan2;
-  bool    isSelected2;
+  int32_t startRowIndex, startColIndex;
 
   // Get cell, table, etc. at selection anchor node
   nsresult rv = GetCellContext(nullptr,
                                getter_AddRefs(table),
                                getter_AddRefs(targetCell),
                                nullptr, nullptr,
                                &startRowIndex, &startColIndex);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   if (!table || !targetCell) {
-    return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
+    return NS_OK;
   }
 
   AutoPlaceholderBatch beginBatching(this);
   //Don't let Rules System change the selection
   AutoTransactionsConserveSelection dontChangeSelection(*this);
 
   // Note: We dont' use AutoSelectionSetterAfterTableEdit here so the selection
   //  is retained after joining. This leaves the target cell selected
@@ -2534,71 +2588,81 @@ HTMLEditor::JoinTableCells(bool aMergeNo
 
     // This defines the last indexes along the "edges"
     //  of the contiguous block of cells, telling us
     //  that we can join adjacent cells to the block
     // Start with same as the first values,
     //  then expand as we find adjacent selected cells
     int32_t lastRowIndex = firstSelectedCell.mIndexes.mRow;
     int32_t lastColIndex = firstSelectedCell.mIndexes.mColumn;
-    int32_t rowIndex, colIndex;
-
-    // First pass: Determine boundaries of contiguous rectangular block
-    //  that we will join into one cell,
-    //  favoring adjacent cells in the same row
-    for (rowIndex = firstSelectedCell.mIndexes.mRow;
+
+    // First pass: Determine boundaries of contiguous rectangular block that
+    // we will join into one cell, favoring adjacent cells in the same row.
+    IgnoredErrorResult ignoredError;
+    for (int32_t rowIndex = firstSelectedCell.mIndexes.mRow;
          rowIndex <= lastRowIndex;
          rowIndex++) {
       int32_t currentRowCount = tableSize.mRowCount;
       // Be sure each row doesn't have rowspan errors
       rv = FixBadRowSpan(table, rowIndex, tableSize.mRowCount);
-      NS_ENSURE_SUCCESS(rv, rv);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       // Adjust rowcount by number of rows we removed
       lastRowIndex -= currentRowCount - tableSize.mRowCount;
 
       bool cellFoundInRow = false;
       bool lastRowIsSet = false;
       int32_t lastColInRow = 0;
       int32_t firstColInRow = firstSelectedCell.mIndexes.mColumn;
-      for (colIndex = firstSelectedCell.mIndexes.mColumn;
+      int32_t colIndex = firstSelectedCell.mIndexes.mColumn;
+      for (int32_t actualColSpan2 = 0;
            colIndex < tableSize.mColumnCount;
            colIndex += std::max(actualColSpan2, 1)) {
-        rv = GetCellDataAt(table, rowIndex, colIndex, getter_AddRefs(cell2),
-                           &startRowIndex2, &startColIndex2,
-                           &rowSpan2, &colSpan2,
-                           &actualRowSpan2, &actualColSpan2, &isSelected2);
-        NS_ENSURE_SUCCESS(rv, rv);
+        CellData cellData(*this, *table, rowIndex, colIndex, ignoredError);
+        if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+          return NS_ERROR_FAILURE;
+        }
+
+        // RefPtr<Element> cell2 = std::move(cellData.mElement);
+        // int32_t startRowIndex2 =          cellData.mFirst.mRow;
+        // int32_t startColIndex2 =          cellData.mFirst.mColumn;
+        // int32_t rowSpan2 =                cellData.mRowSpan;
+        // int32_t colSpan2 =                cellData.mColSpan;
+        // int32_t actualRowSpan2 =          cellData.mEffectiveRowSpan;
+                   actualColSpan2 =          cellData.mEffectiveColSpan;
+        bool       isSelected2 =             cellData.mIsSelected;
 
         if (isSelected2) {
           if (!cellFoundInRow) {
             // We've just found the first selected cell in this row
             firstColInRow = colIndex;
           }
           if (rowIndex > firstSelectedCell.mIndexes.mRow &&
               firstColInRow != firstSelectedCell.mIndexes.mColumn) {
             // We're in at least the second row,
             // but left boundary is "ragged" (not the same as 1st row's start)
             //Let's just end block on previous row
             // and keep previous lastColIndex
             //TODO: We could try to find the Maximum firstColInRow
             //      so our block can still extend down more rows?
-            lastRowIndex = std::max(0,rowIndex - 1);
+            lastRowIndex = std::max(0, rowIndex - 1);
             lastRowIsSet = true;
             break;
           }
           // Save max selected column in this row, including extra colspan
           lastColInRow = colIndex + (actualColSpan2-1);
           cellFoundInRow = true;
         } else if (cellFoundInRow) {
           // No cell or not selected, but at least one cell in row was found
           if (rowIndex > firstSelectedCell.mIndexes.mRow + 1 &&
               colIndex <= lastColIndex) {
             // Cell is in a column less than current right border in
             //  the third or higher selected row, so stop block at the previous row
-            lastRowIndex = std::max(0,rowIndex - 1);
+            lastRowIndex = std::max(0, rowIndex - 1);
             lastRowIsSet = true;
           }
           // We're done with this row
           break;
         }
       } // End of column loop
 
       // Done with this row
@@ -2609,44 +2673,52 @@ HTMLEditor::JoinTableCells(bool aMergeNo
         }
 
         // If we didn't determine last row above...
         if (!lastRowIsSet) {
           if (colIndex < lastColIndex) {
             // (don't think we ever get here?)
             // Cell is in a column less than current right boundary,
             //  so stop block at the previous row
-            lastRowIndex = std::max(0,rowIndex - 1);
+            lastRowIndex = std::max(0, rowIndex - 1);
           } else {
             // Go on to examine next row
-            lastRowIndex = rowIndex+1;
+            lastRowIndex = rowIndex + 1;
           }
         }
         // Use the minimum col we found so far for right boundary
         lastColIndex = std::min(lastColIndex, lastColInRow);
       } else {
         // No selected cells in this row -- stop at row above
         //  and leave last column at its previous value
-        lastRowIndex = std::max(0,rowIndex - 1);
+        lastRowIndex = std::max(0, rowIndex - 1);
       }
     }
 
     // The list of cells we will delete after joining
     nsTArray<RefPtr<Element>> deleteList;
 
     // 2nd pass: Do the joining and merging
-    for (rowIndex = 0; rowIndex < tableSize.mRowCount; rowIndex++) {
-      for (colIndex = 0;
+    for (int32_t rowIndex = 0; rowIndex < tableSize.mRowCount; rowIndex++) {
+      for (int32_t colIndex = 0, actualColSpan2 = 0;
            colIndex < tableSize.mColumnCount;
            colIndex += std::max(actualColSpan2, 1)) {
-        rv = GetCellDataAt(table, rowIndex, colIndex, getter_AddRefs(cell2),
-                           &startRowIndex2, &startColIndex2,
-                           &rowSpan2, &colSpan2,
-                           &actualRowSpan2, &actualColSpan2, &isSelected2);
-        NS_ENSURE_SUCCESS(rv, rv);
+        CellData cellData(*this, *table, rowIndex, colIndex, ignoredError);
+        if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+          return NS_ERROR_FAILURE;
+        }
+
+        RefPtr<Element> cell2 = std::move(cellData.mElement);
+        int32_t    startRowIndex2 =       cellData.mFirst.mRow;
+        int32_t    startColIndex2 =       cellData.mFirst.mColumn;
+        // int32_t rowSpan2 =             cellData.mRowSpan;
+        // int32_t colSpan2 =             cellData.mColSpan;
+        // int32_t actualRowSpan2 =       cellData.mEffectiveRowSpan;
+                   actualColSpan2 =       cellData.mEffectiveColSpan;
+        bool       isSelected2 =          cellData.mIsSelected;
 
         // If this is 0, we are past last cell in row, so exit the loop
         if (!actualColSpan2) {
           break;
         }
 
         // Merge only selected cells (skip cell we're merging into, of course)
         if (isSelected2 && cell2 != firstSelectedCell.mElement) {
@@ -2736,30 +2808,53 @@ HTMLEditor::JoinTableCells(bool aMergeNo
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     // Fixup disturbances in table layout
     DebugOnly<nsresult> rv = NormalizeTable(*selection, *table);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to normalize the table");
   } else {
-    // Joining with cell to the right -- get rowspan and colspan data of target cell
-    rv = GetCellDataAt(table, startRowIndex, startColIndex,
-                       getter_AddRefs(targetCell),
-                       &startRowIndex, &startColIndex, &rowSpan, &colSpan,
-                       &actualRowSpan, &actualColSpan, &isSelected);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(targetCell, NS_ERROR_NULL_POINTER);
-
-    // Get data for cell to the right
-    rv = GetCellDataAt(table, startRowIndex, startColIndex + actualColSpan,
-                       getter_AddRefs(cell2),
-                       &startRowIndex2, &startColIndex2, &rowSpan2, &colSpan2,
-                       &actualRowSpan2, &actualColSpan2, &isSelected2);
-    NS_ENSURE_SUCCESS(rv, rv);
+    // Joining with cell to the right -- get rowspan and colspan data of target
+    // cell.
+    IgnoredErrorResult ignoredError;
+    CellData leftCellData(*this, *table, startRowIndex, startColIndex,
+                          ignoredError);
+    if (NS_WARN_IF(leftCellData.FailedOrNotFound())) {
+      return NS_ERROR_FAILURE;
+    }
+
+    RefPtr<Element> targetCell = std::move(leftCellData.mElement);
+               startRowIndex =             leftCellData.mFirst.mRow;
+               startColIndex =             leftCellData.mFirst.mColumn;
+    // int32_t rowSpan =                   leftCellData.mRowSpan;
+    // int32_t colSpan =                   leftCellData.mColSpan;
+    int32_t    actualRowSpan =             leftCellData.mEffectiveRowSpan;
+    int32_t    actualColSpan =             leftCellData.mEffectiveColSpan;
+    // bool    isSelected =                leftCellData.mIsSelected;
+
+    // Get data for cell to the right.
+    CellData rightCellData(*this, *table,
+                           startRowIndex, startColIndex + actualColSpan,
+                           ignoredError);
+    if (NS_WARN_IF(rightCellData.FailedOrNotFound())) {
+      return NS_ERROR_FAILURE;
+    }
+
+    RefPtr<Element> cell2 = std::move(rightCellData.mElement);
+    int32_t    startRowIndex2 =       rightCellData.mFirst.mRow;
+    int32_t    startColIndex2 =       rightCellData.mFirst.mColumn;
+    // int32_t rowSpan2 =             rightCellData.mRowSpan;
+    // int32_t colSpan2 =             rightCellData.mColSpan;
+    int32_t    actualRowSpan2 =       rightCellData.mEffectiveRowSpan;
+    int32_t    actualColSpan2 =       rightCellData.mEffectiveColSpan;
+    // bool    isSelected2 =          rightCellData.mIsSelected;
+
+    // XXX So, this does not assume that CellData returns error when just not
+    //     found.  We need to fix this later.
     if (!cell2) {
       return NS_OK; // Don't fail if there's no cell
     }
 
     // sanity check
     NS_ASSERTION((startRowIndex >= startRowIndex2),"JoinCells: startRowIndex < startRowIndex2");
 
     // Figure out span of merged cell starting from target's starting row
@@ -2884,67 +2979,81 @@ HTMLEditor::FixBadRowSpan(Element* aTabl
   }
 
   ErrorResult error;
   TableSize tableSize(*this, *aTable, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
-  RefPtr<Element> cell;
-  int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
-  bool    isSelected;
-
   int32_t minRowSpan = -1;
-  int32_t colIndex;
-
-  for (colIndex = 0;
+  IgnoredErrorResult ignoredError;
+  for (int32_t colIndex = 0, actualColSpan = 0;
        colIndex < tableSize.mColumnCount;
        colIndex += std::max(actualColSpan, 1)) {
-    nsresult rv =
-      GetCellDataAt(aTable, aRowIndex, colIndex, getter_AddRefs(cell),
-                    &startRowIndex, &startColIndex, &rowSpan, &colSpan,
-                    &actualRowSpan, &actualColSpan, &isSelected);
+    CellData cellData(*this, *aTable, aRowIndex, colIndex, ignoredError);
     // NOTE: This is a *real* failure.
-    // GetCellDataAt passes if cell is missing from cellmap
+    // CellData passes if cell is missing from cellmap
     // XXX If <table> has large rowspan value or colspan value than actual
     //     cells, we may hit error.  So, this method is always failed to
     //     "fix" the rowspan...
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+      return NS_ERROR_FAILURE;
     }
+
+    RefPtr<Element> cell = std::move(cellData.mElement);
+    int32_t    startRowIndex =       cellData.mFirst.mRow;
+    // int32_t startColIndex =       cellData.mFirst.mColumn;
+    int32_t    rowSpan =             cellData.mRowSpan;
+    // int32_t colSpan =             cellData.mColSpan;
+    // int32_t actualRowSpan =       cellData.mEffectiveRowSpan;
+               actualColSpan =       cellData.mEffectiveColSpan;
+    // bool    isSelected =          cellData.mIsSelected;
+
+    // XXX So, this does not assume that CellData returns error when just not
+    //     found.  We need to fix this later.
     if (!cell) {
       break;
     }
+
     if (rowSpan > 0 &&
         startRowIndex == aRowIndex &&
         (rowSpan < minRowSpan || minRowSpan == -1)) {
       minRowSpan = rowSpan;
     }
     NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in FixBadRowSpan");
   }
   if (minRowSpan > 1) {
     // The amount to reduce everyone's rowspan
     // so at least one cell has rowspan = 1
     int32_t rowsReduced = minRowSpan - 1;
-    for (colIndex = 0;
+    for (int32_t colIndex = 0, actualColSpan = 0;
          colIndex < tableSize.mColumnCount;
          colIndex += std::max(actualColSpan, 1)) {
-      nsresult rv =
-        GetCellDataAt(aTable, aRowIndex, colIndex, getter_AddRefs(cell),
-                      &startRowIndex, &startColIndex, &rowSpan, &colSpan,
-                      &actualRowSpan, &actualColSpan, &isSelected);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
+      CellData cellData(*this, *aTable, aRowIndex, colIndex, ignoredError);
+      if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+        return NS_ERROR_FAILURE;
       }
+
+      RefPtr<Element> cell = std::move(cellData.mElement);
+      int32_t    startRowIndex =       cellData.mFirst.mRow;
+      int32_t    startColIndex =       cellData.mFirst.mColumn;
+      int32_t    rowSpan =             cellData.mRowSpan;
+      // int32_t colSpan =             cellData.mColSpan;
+      // int32_t actualRowSpan =       cellData.mEffectiveRowSpan;
+                 actualColSpan =       cellData.mEffectiveColSpan;
+      // bool    isSelected =          cellData.mIsSelected;
+
       // Fixup rowspans only for cells starting in current row
+      // XXX So, this does not assume that CellData returns error when just
+      //     not found a cell.  Fix this later.
       if (cell && rowSpan > 0 &&
           startRowIndex == aRowIndex &&
           startColIndex ==  colIndex ) {
-        rv = SetRowSpan(cell, rowSpan-rowsReduced);
+        nsresult rv = SetRowSpan(cell, rowSpan-rowsReduced);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
       NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in FixBadRowSpan");
     }
   }
   tableSize.Update(*this, *aTable, error);
@@ -2965,67 +3074,80 @@ HTMLEditor::FixBadColSpan(Element* aTabl
   }
 
   ErrorResult error;
   TableSize tableSize(*this, *aTable, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
-  RefPtr<Element> cell;
-  int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
-  bool    isSelected;
-
   int32_t minColSpan = -1;
-  int32_t rowIndex;
-
-  for (rowIndex = 0;
+  IgnoredErrorResult ignoredError;
+  for (int32_t rowIndex = 0, actualRowSpan = 0;
        rowIndex < tableSize.mRowCount;
        rowIndex += std::max(actualRowSpan, 1)) {
-    nsresult rv =
-      GetCellDataAt(aTable, rowIndex, aColIndex, getter_AddRefs(cell),
-                    &startRowIndex, &startColIndex, &rowSpan, &colSpan,
-                    &actualRowSpan, &actualColSpan, &isSelected);
+    CellData cellData(*this, *aTable, rowIndex, aColIndex, ignoredError);
     // NOTE: This is a *real* failure.
-    // GetCellDataAt passes if cell is missing from cellmap
+    // CellData passes if cell is missing from cellmap
     // XXX If <table> has large rowspan value or colspan value than actual
     //     cells, we may hit error.  So, this method is always failed to
     //     "fix" the colspan...
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+      return NS_ERROR_FAILURE;
     }
+
+    RefPtr<Element> cell = std::move(cellData.mElement);
+    // int32_t startRowIndex =       cellData.mFirst.mRow;
+    int32_t    startColIndex =       cellData.mFirst.mColumn;
+    // int32_t rowSpan =             cellData.mRowSpan;
+    int32_t    colSpan =             cellData.mColSpan;
+               actualRowSpan =       cellData.mEffectiveRowSpan;
+    // int32_t actualColSpan =       cellData.mEffectiveColSpan;
+    // bool    isSelected =          cellData.mIsSelected;
+
+    // XXX So, this does not assume that CellData returns error when just
+    //     not found a cell.  Fix this later.
     if (!cell) {
       break;
     }
     if (colSpan > 0 &&
         startColIndex == aColIndex &&
         (colSpan < minColSpan || minColSpan == -1)) {
       minColSpan = colSpan;
     }
     NS_ASSERTION((actualRowSpan > 0),"ActualRowSpan = 0 in FixBadColSpan");
   }
   if (minColSpan > 1) {
     // The amount to reduce everyone's colspan
     // so at least one cell has colspan = 1
     int32_t colsReduced = minColSpan - 1;
-    for (rowIndex = 0;
+    for (int32_t rowIndex = 0, actualRowSpan = 0;
          rowIndex < tableSize.mRowCount;
          rowIndex += std::max(actualRowSpan, 1)) {
-      nsresult rv =
-        GetCellDataAt(aTable, rowIndex, aColIndex, getter_AddRefs(cell),
-                      &startRowIndex, &startColIndex, &rowSpan, &colSpan,
-                      &actualRowSpan, &actualColSpan, &isSelected);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
+      CellData cellData(*this, *aTable, rowIndex, aColIndex, ignoredError);
+      if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+        return NS_ERROR_FAILURE;
       }
+
+      RefPtr<Element> cell = std::move(cellData.mElement);
+      int32_t    startRowIndex =       cellData.mFirst.mRow;
+      int32_t    startColIndex =       cellData.mFirst.mColumn;
+      // int32_t rowSpan =             cellData.mRowSpan;
+      int32_t    colSpan =             cellData.mColSpan;
+                 actualRowSpan =       cellData.mEffectiveRowSpan;
+      // int32_t actualColSpan =       cellData.mEffectiveColSpan;
+      // bool    isSelected =          cellData.mIsSelected;
+
       // Fixup colspans only for cells starting in current column
+      // XXX So, this does not assume that CellData returns error when just
+      //     not found a cell.  Fix this later.
       if (cell && colSpan > 0 &&
           startColIndex == aColIndex &&
           startRowIndex ==  rowIndex) {
-        rv = SetColSpan(cell, colSpan-colsReduced);
+        nsresult rv = SetColSpan(cell, colSpan-colsReduced);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
       NS_ASSERTION((actualRowSpan > 0),"ActualRowSpan = 0 in FixBadColSpan");
     }
   }
   tableSize.Update(*this, *aTable, error);
@@ -3103,45 +3225,50 @@ HTMLEditor::NormalizeTable(Selection& aS
   for (int32_t colIndex = 0; colIndex < tableSize.mColumnCount; colIndex++) {
     nsresult rv = FixBadColSpan(tableElement, colIndex, tableSize.mColumnCount);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // Fill in missing cellmap locations with empty cells
+  IgnoredErrorResult ignoredError;
   for (int32_t rowIndex = 0; rowIndex < tableSize.mRowCount; rowIndex++) {
     RefPtr<Element> previousCellElementInRow;
     for (int32_t colIndex = 0; colIndex < tableSize.mColumnCount; colIndex++) {
-      int32_t startRowIndex = 0, startColIndex = 0;
-      int32_t rowSpan = 0, colSpan = 0;
-      int32_t actualRowSpan = 0, actualColSpan = 0;
-      bool isSelected;
-      RefPtr<Element> cellElement;
-      nsresult rv =
-        GetCellDataAt(tableElement, rowIndex, colIndex,
-                      getter_AddRefs(cellElement),
-                      &startRowIndex, &startColIndex, &rowSpan, &colSpan,
-                      &actualRowSpan, &actualColSpan, &isSelected);
+      CellData cellData(*this, *tableElement, rowIndex, colIndex, ignoredError);
       // NOTE: This is a *real* failure.
-      // GetCellDataAt passes if cell is missing from cellmap
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
+      // CellData passes if cell is missing from cellmap
+      // XXX So, this method assumes that CellData won't return error when
+      //     just not found.  Fix this later.
+      if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+        return NS_ERROR_FAILURE;
       }
+
+      RefPtr<Element> cellElement = std::move(cellData.mElement);
+      int32_t    startRowIndex =              cellData.mFirst.mRow;
+      // int32_t startColIndex =              cellData.mFirst.mColumn;
+      // int32_t rowSpan =                    cellData.mRowSpan;
+      // int32_t colSpan =                    cellData.mColSpan;
+      // int32_t actualRowSpan =              cellData.mEffectiveRowSpan;
+      // int32_t actualColSpan =              cellData.mEffectiveColSpan;
+      // bool    isSelected =                 cellData.mIsSelected;
+
       if (!cellElement) {
         // We are missing a cell at a cellmap location.
         // Add a cell after the previous cell element in the current row.
         if (NS_WARN_IF(!previousCellElementInRow)) {
           // We don't have any cells in this row -- We are really messed up!
           return NS_ERROR_FAILURE;
         }
 
         // Insert a new cell after (true), and return the new cell to us
-        rv = InsertCell(previousCellElementInRow, 1, 1, true, false,
-                        getter_AddRefs(cellElement));
+        nsresult rv =
+          InsertCell(previousCellElementInRow, 1, 1, true, false,
+                     getter_AddRefs(cellElement));
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
 
         // Set this so we use returned new "cell" to set
         // previousCellElementInRow below.
         if (cellElement) {
           startRowIndex = rowIndex;
@@ -3256,35 +3383,35 @@ HTMLEditor::GetNumberOfCellsInRow(Elemen
   IgnoredErrorResult ignoredError;
   TableSize tableSize(*this, aTableElement, ignoredError);
   if (NS_WARN_IF(ignoredError.Failed())) {
     return -1;
   }
 
   int32_t numberOfCells = 0;
   for (int32_t columnIndex = 0; columnIndex < tableSize.mColumnCount;) {
-    RefPtr<Element> cellElement;
-    int32_t startRowIndex = 0, startColIndex = 0;
-    int32_t rowSpan = 0, colSpan = 0;
-    int32_t actualRowSpan = 0, actualColSpan = 0;
-    bool isSelected = false;
-    nsresult rv =
-      GetCellDataAt(&aTableElement, aRowIndex, columnIndex,
-                    getter_AddRefs(cellElement),
-                    &startRowIndex, &startColIndex, &rowSpan, &colSpan,
-                    &actualRowSpan, &actualColSpan, &isSelected);
+    CellData cellData(*this, aTableElement, aRowIndex, columnIndex,
+                      ignoredError);
     // Failure means that there is no more cell in the row.  In this case,
     // we shouldn't return error since we just reach the end of the row.
-    // XXX Ideally, GetCellDataAt() should return
-    //     NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND in such case instead of
-    //     error.  However, it's used by a lot of methods, so, it's really
-    //     risky to change it.
-    if (NS_FAILED(rv)) {
+    // XXX So, this method assumes that CellData won't return error when
+    //     just not found.  Fix this later.
+    if (cellData.FailedOrNotFound()) {
       break;
     }
+
+    RefPtr<Element> cellElement = std::move(cellData.mElement);
+    int32_t    startRowIndex =              cellData.mFirst.mRow;
+    // int32_t startColIndex =              cellData.mFirst.mColumn;
+    // int32_t rowSpan =                    cellData.mRowSpan;
+    // int32_t colSpan =                    cellData.mColSpan;
+    // int32_t actualRowSpan =              cellData.mEffectiveRowSpan;
+    int32_t    actualColSpan =              cellData.mEffectiveColSpan;
+    // bool    isSelected =                 cellData.mIsSelected;
+
     if (cellElement) {
       // Only count cells that start in row we are working with
       if (startRowIndex == aRowIndex) {
         numberOfCells++;
       }
       // Next possible location for a cell
       columnIndex += actualColSpan;
     } else {
@@ -3689,17 +3816,17 @@ HTMLEditor::GetCellFromRange(nsRange* aR
   }
 
   // If a cell is deleted, the range is collapse
   //   (startOffset == aRange->EndOffset())
   //   so tell caller the cell wasn't found
   if (startContainer == endContainer &&
       aRange->EndOffset() == startOffset+1 &&
       HTMLEditUtils::IsTableCell(childNode)) {
-    // Should we also test if frame is selected? (Use GetCellDataAt())
+    // Should we also test if frame is selected? (Use CellData)
     // (Let's not for now -- more efficient)
     RefPtr<Element> cellElement = childNode->AsElement();
     cellElement.forget(aCell);
     return NS_OK;
   }
   return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
 }
 
@@ -4241,67 +4368,99 @@ HTMLEditor::GetSelectedCellsType(Element
   return NS_OK;
 }
 
 bool
 HTMLEditor::AllCellsInRowSelected(Element* aTable,
                                   int32_t aRowIndex,
                                   int32_t aNumberOfColumns)
 {
-  NS_ENSURE_TRUE(aTable, false);
-
-  int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
-  bool    isSelected;
-
-  for (int32_t col = 0; col < aNumberOfColumns;
+  if (NS_WARN_IF(!aTable)) {
+    return false;
+  }
+
+  IgnoredErrorResult ignoredError;
+  for (int32_t col = 0, actualColSpan = 0;
+       col < aNumberOfColumns;
        col += std::max(actualColSpan, 1)) {
-    RefPtr<Element> cell;
-    nsresult rv = GetCellDataAt(aTable, aRowIndex, col, getter_AddRefs(cell),
-                                &curStartRowIndex, &curStartColIndex,
-                                &rowSpan, &colSpan,
-                                &actualRowSpan, &actualColSpan, &isSelected);
-
-    NS_ENSURE_SUCCESS(rv, false);
-    // If no cell, we may have a "ragged" right edge,
-    //   so return TRUE only if we already found a cell in the row
-    NS_ENSURE_TRUE(cell, (col > 0) ? true : false);
-
-    // Return as soon as a non-selected cell is found
-    NS_ENSURE_TRUE(isSelected, false);
-
-    NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in AllCellsInRowSelected");
+    CellData cellData(*this, *aTable, aRowIndex, col, ignoredError);
+    if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+      return false;
+    }
+
+    RefPtr<Element> cell = std::move(cellData.mElement);
+    // int32_t curStartRowIndex =    cellData.mFirst.mRow;
+    // int32_t curStartColIndex =    cellData.mFirst.mColumn;
+    // int32_t rowSpan =             cellData.mRowSpan;
+    // int32_t colSpan =             cellData.mColSpan;
+    // int32_t actualRowSpan =       cellData.mEffectiveRowSpan;
+               actualColSpan =       cellData.mEffectiveColSpan;
+    bool       isSelected =          cellData.mIsSelected;
+
+    // If no cell, we may have a "ragged" right edge, so return TRUE only if
+    // we already found a cell in the row.
+    // XXX So, this does not assume that CellData returns error when just
+    //     not found a cell.  Fix this later.
+    if (NS_WARN_IF(!cell)) {
+      return col > 0;
+    }
+
+    // Return as soon as a non-selected cell is found.
+    // XXX Odd, this is testing if each cell element is selected.  Why do
+    //     we need to warn if it's false??
+    if (NS_WARN_IF(!isSelected)) {
+      return false;
+    }
+
+    MOZ_ASSERT(actualColSpan > 0);
   }
   return true;
 }
 
 bool
 HTMLEditor::AllCellsInColumnSelected(Element* aTable,
                                      int32_t aColIndex,
                                      int32_t aNumberOfRows)
 {
-  NS_ENSURE_TRUE(aTable, false);
-
-  int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
-  bool    isSelected;
-
-  for (int32_t row = 0; row < aNumberOfRows;
+  if (NS_WARN_IF(!aTable)) {
+    return false;
+  }
+
+  IgnoredErrorResult ignoredError;
+  for (int32_t row = 0, actualRowSpan = 0;
+       row < aNumberOfRows;
        row += std::max(actualRowSpan, 1)) {
-    RefPtr<Element> cell;
-    nsresult rv = GetCellDataAt(aTable, row, aColIndex, getter_AddRefs(cell),
-                                &curStartRowIndex, &curStartColIndex,
-                                &rowSpan, &colSpan,
-                                &actualRowSpan, &actualColSpan, &isSelected);
-
-    NS_ENSURE_SUCCESS(rv, false);
-    // If no cell, we must have a "ragged" right edge on the last column
-    //   so return TRUE only if we already found a cell in the row
-    NS_ENSURE_TRUE(cell, (row > 0) ? true : false);
-
-    // Return as soon as a non-selected cell is found
-    NS_ENSURE_TRUE(isSelected, false);
+    CellData cellData(*this, *aTable, row, aColIndex, ignoredError);
+    if (NS_WARN_IF(cellData.FailedOrNotFound())) {
+      return false;
+    }
+
+    RefPtr<Element> cell = std::move(cellData.mElement);
+    // int32_t curStartRowIndex =    cellData.mFirst.mRow;
+    // int32_t curStartColIndex =    cellData.mFirst.mColumn;
+    // int32_t rowSpan =             cellData.mRowSpan;
+    // int32_t colSpan =             cellData.mColSpan;
+               actualRowSpan =       cellData.mEffectiveRowSpan;
+    // int32_t actualColSpan =       cellData.mEffectiveColSpan;
+    bool       isSelected =          cellData.mIsSelected;
+
+    // If no cell, we must have a "ragged" right edge on the last column so
+    // return TRUE only if we already found a cell in the row.
+    // XXX So, this does not assume that CellData returns error when just
+    //     not found a cell.  Fix this later.
+    if (NS_WARN_IF(!cell)) {
+      return row > 0;
+    }
+
+    // Return as soon as a non-selected cell is found.
+    // XXX Odd, this is testing if each cell element is selected.  Why do
+    //     we need to warn if it's false??
+    if (NS_WARN_IF(!isSelected)) {
+      return false;
+    }
   }
   return true;
 }
 
 bool
 HTMLEditor::IsEmptyCell(dom::Element* aCell)
 {
   MOZ_ASSERT(aCell);