LCOV - code coverage report
Current view: top level - editor/libeditor - HTMLTableEditor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1688 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 54 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include <stdio.h>
       7             : 
       8             : #include "mozilla/HTMLEditor.h"
       9             : 
      10             : #include "HTMLEditUtils.h"
      11             : #include "mozilla/Assertions.h"
      12             : #include "mozilla/EditorUtils.h"
      13             : #include "mozilla/dom/Selection.h"
      14             : #include "mozilla/dom/Element.h"
      15             : #include "nsAString.h"
      16             : #include "nsAlgorithm.h"
      17             : #include "nsCOMPtr.h"
      18             : #include "nsDebug.h"
      19             : #include "nsError.h"
      20             : #include "nsGkAtoms.h"
      21             : #include "nsIAtom.h"
      22             : #include "nsIContent.h"
      23             : #include "nsIDOMElement.h"
      24             : #include "nsIDOMNode.h"
      25             : #include "nsIFrame.h"
      26             : #include "nsINode.h"
      27             : #include "nsIPresShell.h"
      28             : #include "nsISupportsUtils.h"
      29             : #include "nsITableCellLayout.h" // For efficient access to table cell
      30             : #include "nsITableEditor.h"
      31             : #include "nsLiteralString.h"
      32             : #include "nsQueryFrame.h"
      33             : #include "nsRange.h"
      34             : #include "nsString.h"
      35             : #include "nsTArray.h"
      36             : #include "nsTableCellFrame.h"
      37             : #include "nsTableWrapperFrame.h"
      38             : #include "nscore.h"
      39             : #include <algorithm>
      40             : 
      41             : namespace mozilla {
      42             : 
      43             : using namespace dom;
      44             : 
      45             : /**
      46             :  * Stack based helper class for restoring selection after table edit.
      47             :  */
      48             : class MOZ_STACK_CLASS AutoSelectionSetterAfterTableEdit final
      49             : {
      50             : private:
      51             :   nsCOMPtr<nsITableEditor> mTableEditor;
      52             :   nsCOMPtr<nsIDOMElement> mTable;
      53             :   int32_t mCol, mRow, mDirection, mSelected;
      54             : 
      55             : public:
      56           0 :   AutoSelectionSetterAfterTableEdit(nsITableEditor* aTableEditor,
      57             :                                     nsIDOMElement* aTable,
      58             :                                     int32_t aRow,
      59             :                                     int32_t aCol,
      60             :                                     int32_t aDirection,
      61             :                                     bool aSelected)
      62           0 :     : mTableEditor(aTableEditor)
      63             :     , mTable(aTable)
      64             :     , mCol(aCol)
      65             :     , mRow(aRow)
      66             :     , mDirection(aDirection)
      67           0 :     , mSelected(aSelected)
      68             :   {
      69           0 :   }
      70             : 
      71           0 :   ~AutoSelectionSetterAfterTableEdit()
      72           0 :   {
      73           0 :     if (mTableEditor) {
      74           0 :       mTableEditor->SetSelectionAfterTableEdit(mTable, mRow, mCol, mDirection,
      75           0 :                                                mSelected);
      76             :     }
      77           0 :   }
      78             : 
      79             :   // This is needed to abort the caret reset in the destructor
      80             :   //  when one method yields control to another
      81             :   void CancelSetCaret()
      82             :   {
      83             :     mTableEditor = nullptr;
      84             :     mTable = nullptr;
      85             :   }
      86             : };
      87             : 
      88             : NS_IMETHODIMP
      89           0 : HTMLEditor::InsertCell(nsIDOMElement* aCell,
      90             :                        int32_t aRowSpan,
      91             :                        int32_t aColSpan,
      92             :                        bool aAfter,
      93             :                        bool aIsHeader,
      94             :                        nsIDOMElement** aNewCell)
      95             : {
      96           0 :   NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
      97           0 :   if (aNewCell) {
      98           0 :     *aNewCell = nullptr;
      99             :   }
     100             : 
     101             :   // And the parent and offsets needed to do an insert
     102           0 :   nsCOMPtr<nsIDOMNode> cellParent;
     103           0 :   nsresult rv = aCell->GetParentNode(getter_AddRefs(cellParent));
     104           0 :   NS_ENSURE_SUCCESS(rv, rv);
     105           0 :   NS_ENSURE_TRUE(cellParent, NS_ERROR_NULL_POINTER);
     106             : 
     107           0 :   int32_t cellOffset = GetChildOffset(aCell, cellParent);
     108             : 
     109           0 :   nsCOMPtr<nsIDOMElement> newCell;
     110           0 :   rv = CreateElementWithDefaults(aIsHeader ? NS_LITERAL_STRING("th") :
     111           0 :                                              NS_LITERAL_STRING("tb"),
     112           0 :                                  getter_AddRefs(newCell));
     113           0 :   if (NS_FAILED(rv)) {
     114           0 :     return rv;
     115             :   }
     116           0 :   if (!newCell) {
     117           0 :     return NS_ERROR_FAILURE;
     118             :   }
     119             : 
     120             :   //Optional: return new cell created
     121           0 :   if (aNewCell) {
     122           0 :     *aNewCell = newCell.get();
     123           0 :     NS_ADDREF(*aNewCell);
     124             :   }
     125             : 
     126           0 :   if (aRowSpan > 1) {
     127             :     // Note: Do NOT use editor transaction for this
     128           0 :     nsAutoString newRowSpan;
     129           0 :     newRowSpan.AppendInt(aRowSpan, 10);
     130           0 :     newCell->SetAttribute(NS_LITERAL_STRING("rowspan"), newRowSpan);
     131             :   }
     132           0 :   if (aColSpan > 1) {
     133             :     // Note: Do NOT use editor transaction for this
     134           0 :     nsAutoString newColSpan;
     135           0 :     newColSpan.AppendInt(aColSpan, 10);
     136           0 :     newCell->SetAttribute(NS_LITERAL_STRING("colspan"), newColSpan);
     137             :   }
     138           0 :   if (aAfter) {
     139           0 :     cellOffset++;
     140             :   }
     141             : 
     142             :   //Don't let Rules System change the selection
     143           0 :   AutoTransactionsConserveSelection dontChangeSelection(this);
     144           0 :   return InsertNode(newCell, cellParent, cellOffset);
     145             : }
     146             : 
     147             : NS_IMETHODIMP
     148           0 : HTMLEditor::SetColSpan(nsIDOMElement* aCell,
     149             :                        int32_t aColSpan)
     150             : {
     151           0 :   NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
     152           0 :   nsAutoString newSpan;
     153           0 :   newSpan.AppendInt(aColSpan, 10);
     154           0 :   return SetAttribute(aCell, NS_LITERAL_STRING("colspan"), newSpan);
     155             : }
     156             : 
     157             : NS_IMETHODIMP
     158           0 : HTMLEditor::SetRowSpan(nsIDOMElement* aCell,
     159             :                        int32_t aRowSpan)
     160             : {
     161           0 :   NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
     162           0 :   nsAutoString newSpan;
     163           0 :   newSpan.AppendInt(aRowSpan, 10);
     164           0 :   return SetAttribute(aCell, NS_LITERAL_STRING("rowspan"), newSpan);
     165             : }
     166             : 
     167             : NS_IMETHODIMP
     168           0 : HTMLEditor::InsertTableCell(int32_t aNumber,
     169             :                             bool aAfter)
     170             : {
     171           0 :   nsCOMPtr<nsIDOMElement> table;
     172           0 :   nsCOMPtr<nsIDOMElement> curCell;
     173           0 :   nsCOMPtr<nsIDOMNode> cellParent;
     174             :   int32_t cellOffset, startRowIndex, startColIndex;
     175           0 :   nsresult rv = GetCellContext(nullptr,
     176           0 :                                getter_AddRefs(table),
     177           0 :                                getter_AddRefs(curCell),
     178           0 :                                getter_AddRefs(cellParent), &cellOffset,
     179           0 :                                &startRowIndex, &startColIndex);
     180           0 :   NS_ENSURE_SUCCESS(rv, rv);
     181             :   // Don't fail if no cell found
     182           0 :   NS_ENSURE_TRUE(curCell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
     183             : 
     184             :   // Get more data for current cell in row we are inserting at (we need COLSPAN)
     185             :   int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
     186             :   bool    isSelected;
     187           0 :   rv = GetCellDataAt(table, startRowIndex, startColIndex,
     188           0 :                      getter_AddRefs(curCell),
     189             :                      &curStartRowIndex, &curStartColIndex, &rowSpan, &colSpan,
     190           0 :                      &actualRowSpan, &actualColSpan, &isSelected);
     191           0 :   NS_ENSURE_SUCCESS(rv, rv);
     192           0 :   NS_ENSURE_TRUE(curCell, NS_ERROR_FAILURE);
     193           0 :   int32_t newCellIndex = aAfter ? (startColIndex+colSpan) : startColIndex;
     194             :   //We control selection resetting after the insert...
     195             :   AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
     196             :                                              newCellIndex, ePreviousColumn,
     197           0 :                                              false);
     198             :   //...so suppress Rules System selection munging
     199           0 :   AutoTransactionsConserveSelection dontChangeSelection(this);
     200             : 
     201           0 :   for (int32_t i = 0; i < aNumber; i++) {
     202           0 :     nsCOMPtr<nsIDOMElement> newCell;
     203           0 :     rv = CreateElementWithDefaults(NS_LITERAL_STRING("td"),
     204           0 :                                    getter_AddRefs(newCell));
     205           0 :     if (NS_SUCCEEDED(rv) && newCell) {
     206           0 :       if (aAfter) {
     207           0 :         cellOffset++;
     208             :       }
     209           0 :       rv = InsertNode(newCell, cellParent, cellOffset);
     210           0 :       if (NS_FAILED(rv)) {
     211           0 :         break;
     212             :       }
     213             :     }
     214             :   }
     215             :   // XXX This is perhaps the result of the last call of InsertNode() or
     216             :   //     CreateElementWithDefaults().
     217           0 :   return rv;
     218             : }
     219             : 
     220             : NS_IMETHODIMP
     221           0 : HTMLEditor::GetFirstRow(nsIDOMElement* aTableElement,
     222             :                         nsIDOMNode** aRowNode)
     223             : {
     224           0 :   NS_ENSURE_TRUE(aRowNode, NS_ERROR_NULL_POINTER);
     225             : 
     226           0 :   *aRowNode = nullptr;
     227             : 
     228           0 :   NS_ENSURE_TRUE(aTableElement, NS_ERROR_NULL_POINTER);
     229             : 
     230           0 :   nsCOMPtr<nsIDOMElement> tableElement;
     231           0 :   nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"),
     232             :                                             aTableElement,
     233           0 :                                             getter_AddRefs(tableElement));
     234           0 :   NS_ENSURE_SUCCESS(rv, rv);
     235           0 :   NS_ENSURE_TRUE(tableElement, NS_ERROR_NULL_POINTER);
     236             : 
     237           0 :   nsCOMPtr<nsIDOMNode> tableChild;
     238           0 :   rv = tableElement->GetFirstChild(getter_AddRefs(tableChild));
     239           0 :   NS_ENSURE_SUCCESS(rv, rv);
     240             : 
     241           0 :   while (tableChild) {
     242           0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(tableChild);
     243           0 :     if (content) {
     244           0 :       if (content->IsHTMLElement(nsGkAtoms::tr)) {
     245             :         // Found a row directly under <table>
     246           0 :         *aRowNode = tableChild;
     247           0 :         NS_ADDREF(*aRowNode);
     248           0 :         return NS_OK;
     249             :       }
     250             :       // Look for row in one of the row container elements
     251           0 :       if (content->IsAnyOfHTMLElements(nsGkAtoms::tbody,
     252             :                                        nsGkAtoms::thead,
     253             :                                        nsGkAtoms::tfoot)) {
     254           0 :         nsCOMPtr<nsIDOMNode> rowNode;
     255           0 :         rv = tableChild->GetFirstChild(getter_AddRefs(rowNode));
     256           0 :         NS_ENSURE_SUCCESS(rv, rv);
     257             : 
     258             :         // We can encounter textnodes here -- must find a row
     259           0 :         while (rowNode && !HTMLEditUtils::IsTableRow(rowNode)) {
     260           0 :           nsCOMPtr<nsIDOMNode> nextNode;
     261           0 :           rv = rowNode->GetNextSibling(getter_AddRefs(nextNode));
     262           0 :           NS_ENSURE_SUCCESS(rv, rv);
     263             : 
     264           0 :           rowNode = nextNode;
     265             :         }
     266           0 :         if (rowNode) {
     267           0 :           *aRowNode = rowNode.get();
     268           0 :           NS_ADDREF(*aRowNode);
     269           0 :           return NS_OK;
     270             :         }
     271             :       }
     272             :     }
     273             :     // Here if table child was a CAPTION or COLGROUP
     274             :     //  or child of a row parent wasn't a row (bad HTML?),
     275             :     //  or first child was a textnode
     276             :     // Look in next table child
     277           0 :     nsCOMPtr<nsIDOMNode> nextChild;
     278           0 :     rv = tableChild->GetNextSibling(getter_AddRefs(nextChild));
     279           0 :     NS_ENSURE_SUCCESS(rv, rv);
     280             : 
     281           0 :     tableChild = nextChild;
     282             :   }
     283             :   // If here, row was not found
     284           0 :   return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
     285             : }
     286             : 
     287             : NS_IMETHODIMP
     288           0 : HTMLEditor::GetNextRow(nsIDOMNode* aCurrentRowNode,
     289             :                        nsIDOMNode** aRowNode)
     290             : {
     291           0 :   NS_ENSURE_TRUE(aRowNode, NS_ERROR_NULL_POINTER);
     292             : 
     293           0 :   *aRowNode = nullptr;
     294             : 
     295           0 :   NS_ENSURE_TRUE(aCurrentRowNode, NS_ERROR_NULL_POINTER);
     296             : 
     297           0 :   if (!HTMLEditUtils::IsTableRow(aCurrentRowNode)) {
     298           0 :     return NS_ERROR_FAILURE;
     299             :   }
     300             : 
     301           0 :   nsCOMPtr<nsIDOMNode> nextRow;
     302           0 :   nsresult rv = aCurrentRowNode->GetNextSibling(getter_AddRefs(nextRow));
     303           0 :   NS_ENSURE_SUCCESS(rv, rv);
     304             : 
     305           0 :   nsCOMPtr<nsIDOMNode> nextNode;
     306             : 
     307             :   // Skip over any textnodes here
     308           0 :   while (nextRow && !HTMLEditUtils::IsTableRow(nextRow)) {
     309           0 :     rv = nextRow->GetNextSibling(getter_AddRefs(nextNode));
     310           0 :     NS_ENSURE_SUCCESS(rv, rv);
     311             : 
     312           0 :     nextRow = nextNode;
     313             :   }
     314           0 :   if (nextRow) {
     315           0 :     *aRowNode = nextRow.get();
     316           0 :     NS_ADDREF(*aRowNode);
     317           0 :     return NS_OK;
     318             :   }
     319             : 
     320             :   // No row found, search for rows in other table sections
     321           0 :   nsCOMPtr<nsIDOMNode> rowParent;
     322           0 :   rv = aCurrentRowNode->GetParentNode(getter_AddRefs(rowParent));
     323           0 :   NS_ENSURE_SUCCESS(rv, rv);
     324           0 :   NS_ENSURE_TRUE(rowParent, NS_ERROR_NULL_POINTER);
     325             : 
     326           0 :   nsCOMPtr<nsIDOMNode> parentSibling;
     327           0 :   rv = rowParent->GetNextSibling(getter_AddRefs(parentSibling));
     328           0 :   NS_ENSURE_SUCCESS(rv, rv);
     329             : 
     330           0 :   while (parentSibling) {
     331           0 :     rv = parentSibling->GetFirstChild(getter_AddRefs(nextRow));
     332           0 :     NS_ENSURE_SUCCESS(rv, rv);
     333             : 
     334             :     // We can encounter textnodes here -- must find a row
     335           0 :     while (nextRow && !HTMLEditUtils::IsTableRow(nextRow)) {
     336           0 :       rv = nextRow->GetNextSibling(getter_AddRefs(nextNode));
     337           0 :       NS_ENSURE_SUCCESS(rv, rv);
     338             : 
     339           0 :       nextRow = nextNode;
     340             :     }
     341           0 :     if (nextRow) {
     342           0 :       *aRowNode = nextRow.get();
     343           0 :       NS_ADDREF(*aRowNode);
     344           0 :       return NS_OK;
     345             :     }
     346             : 
     347             :     // We arrive here only if a table section has no children
     348             :     //  or first child of section is not a row (bad HTML or more "_moz_text" nodes!)
     349             :     // So look for another section sibling
     350           0 :     rv = parentSibling->GetNextSibling(getter_AddRefs(nextNode));
     351           0 :     NS_ENSURE_SUCCESS(rv, rv);
     352             : 
     353           0 :     parentSibling = nextNode;
     354             :   }
     355             :   // If here, row was not found
     356           0 :   return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
     357             : }
     358             : 
     359             : nsresult
     360           0 : HTMLEditor::GetLastCellInRow(nsIDOMNode* aRowNode,
     361             :                              nsIDOMNode** aCellNode)
     362             : {
     363           0 :   NS_ENSURE_TRUE(aCellNode, NS_ERROR_NULL_POINTER);
     364             : 
     365           0 :   *aCellNode = nullptr;
     366             : 
     367           0 :   NS_ENSURE_TRUE(aRowNode, NS_ERROR_NULL_POINTER);
     368             : 
     369           0 :   nsCOMPtr<nsIDOMNode> rowChild;
     370           0 :   nsresult rv = aRowNode->GetLastChild(getter_AddRefs(rowChild));
     371           0 :   NS_ENSURE_SUCCESS(rv, rv);
     372             : 
     373           0 :   while (rowChild && !HTMLEditUtils::IsTableCell(rowChild)) {
     374             :     // Skip over textnodes
     375           0 :     nsCOMPtr<nsIDOMNode> previousChild;
     376           0 :     rv = rowChild->GetPreviousSibling(getter_AddRefs(previousChild));
     377           0 :     NS_ENSURE_SUCCESS(rv, rv);
     378             : 
     379           0 :     rowChild = previousChild;
     380             :   }
     381           0 :   if (rowChild) {
     382           0 :     *aCellNode = rowChild.get();
     383           0 :     NS_ADDREF(*aCellNode);
     384           0 :     return NS_OK;
     385             :   }
     386             :   // If here, cell was not found
     387           0 :   return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
     388             : }
     389             : 
     390             : NS_IMETHODIMP
     391           0 : HTMLEditor::InsertTableColumn(int32_t aNumber,
     392             :                               bool aAfter)
     393             : {
     394           0 :   RefPtr<Selection> selection;
     395           0 :   nsCOMPtr<nsIDOMElement> table;
     396           0 :   nsCOMPtr<nsIDOMElement> curCell;
     397             :   int32_t startRowIndex, startColIndex;
     398           0 :   nsresult rv = GetCellContext(getter_AddRefs(selection),
     399           0 :                                getter_AddRefs(table),
     400           0 :                                getter_AddRefs(curCell),
     401             :                                nullptr, nullptr,
     402           0 :                                &startRowIndex, &startColIndex);
     403           0 :   NS_ENSURE_SUCCESS(rv, rv);
     404             :   // Don't fail if no cell found
     405           0 :   NS_ENSURE_TRUE(curCell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
     406             : 
     407             :   // Get more data for current cell (we need ROWSPAN)
     408             :   int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
     409             :   bool    isSelected;
     410           0 :   rv = GetCellDataAt(table, startRowIndex, startColIndex,
     411           0 :                      getter_AddRefs(curCell),
     412             :                      &curStartRowIndex, &curStartColIndex,
     413             :                      &rowSpan, &colSpan,
     414           0 :                      &actualRowSpan, &actualColSpan, &isSelected);
     415           0 :   NS_ENSURE_SUCCESS(rv, rv);
     416           0 :   NS_ENSURE_TRUE(curCell, NS_ERROR_FAILURE);
     417             : 
     418           0 :   AutoEditBatch beginBatching(this);
     419             :   // Prevent auto insertion of BR in new cell until we're done
     420           0 :   AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
     421             : 
     422             :   // Use column after current cell if requested
     423           0 :   if (aAfter) {
     424           0 :     startColIndex += actualColSpan;
     425             :     //Detect when user is adding after a COLSPAN=0 case
     426             :     // Assume they want to stop the "0" behavior and
     427             :     // really add a new column. Thus we set the
     428             :     // colspan to its true value
     429           0 :     if (!colSpan) {
     430           0 :       SetColSpan(curCell, actualColSpan);
     431             :     }
     432             :   }
     433             : 
     434             :   int32_t rowCount, colCount, rowIndex;
     435           0 :   rv = GetTableSize(table, &rowCount, &colCount);
     436           0 :   NS_ENSURE_SUCCESS(rv, rv);
     437             : 
     438             :   //We reset caret in destructor...
     439             :   AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
     440             :                                              startColIndex, ePreviousRow,
     441           0 :                                              false);
     442             :   //.. so suppress Rules System selection munging
     443           0 :   AutoTransactionsConserveSelection dontChangeSelection(this);
     444             : 
     445             :   // If we are inserting after all existing columns
     446             :   // Make sure table is "well formed"
     447             :   //  before appending new column
     448           0 :   if (startColIndex >= colCount) {
     449           0 :     NormalizeTable(table);
     450             :   }
     451             : 
     452           0 :   nsCOMPtr<nsIDOMNode> rowNode;
     453           0 :   for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
     454           0 :     if (startColIndex < colCount) {
     455             :       // We are inserting before an existing column
     456           0 :       rv = GetCellDataAt(table, rowIndex, startColIndex,
     457           0 :                          getter_AddRefs(curCell),
     458             :                          &curStartRowIndex, &curStartColIndex,
     459             :                          &rowSpan, &colSpan,
     460           0 :                          &actualRowSpan, &actualColSpan, &isSelected);
     461           0 :       NS_ENSURE_SUCCESS(rv, rv);
     462             : 
     463             :       // Don't fail entire process if we fail to find a cell
     464             :       //  (may fail just in particular rows with < adequate cells per row)
     465           0 :       if (curCell) {
     466           0 :         if (curStartColIndex < startColIndex) {
     467             :           // We have a cell spanning this location
     468             :           // Simply increase its colspan to keep table rectangular
     469             :           // Note: we do nothing if colsSpan=0,
     470             :           //  since it should automatically span the new column
     471           0 :           if (colSpan > 0) {
     472           0 :             SetColSpan(curCell, colSpan+aNumber);
     473             :           }
     474             :         } else {
     475             :           // Simply set selection to the current cell
     476             :           //  so we can let InsertTableCell() do the work
     477             :           // Insert a new cell before current one
     478           0 :           selection->Collapse(curCell, 0);
     479           0 :           rv = InsertTableCell(aNumber, false);
     480             :         }
     481             :       }
     482             :     } else {
     483             :       // Get current row and append new cells after last cell in row
     484           0 :       if (!rowIndex) {
     485           0 :         rv = GetFirstRow(table.get(), getter_AddRefs(rowNode));
     486           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
     487           0 :           return rv;
     488             :         }
     489             :       } else {
     490           0 :         nsCOMPtr<nsIDOMNode> nextRow;
     491           0 :         rv = GetNextRow(rowNode.get(), getter_AddRefs(nextRow));
     492           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
     493           0 :           return rv;
     494             :         }
     495           0 :         rowNode = nextRow;
     496             :       }
     497             : 
     498           0 :       if (rowNode) {
     499           0 :         nsCOMPtr<nsIDOMNode> lastCell;
     500           0 :         rv = GetLastCellInRow(rowNode, getter_AddRefs(lastCell));
     501           0 :         NS_ENSURE_SUCCESS(rv, rv);
     502           0 :         NS_ENSURE_TRUE(lastCell, NS_ERROR_FAILURE);
     503             : 
     504           0 :         curCell = do_QueryInterface(lastCell);
     505           0 :         if (curCell) {
     506             :           // Simply add same number of cells to each row
     507             :           // Although tempted to check cell indexes for curCell,
     508             :           //  the effects of COLSPAN>1 in some cells makes this futile!
     509             :           // We must use NormalizeTable first to assure
     510             :           //  that there are cells in each cellmap location
     511           0 :           selection->Collapse(curCell, 0);
     512           0 :           rv = InsertTableCell(aNumber, true);
     513             :         }
     514             :       }
     515             :     }
     516             :   }
     517             :   // XXX This is perhaps the result of the last call of InsertTableCell().
     518           0 :   return rv;
     519             : }
     520             : 
     521             : NS_IMETHODIMP
     522           0 : HTMLEditor::InsertTableRow(int32_t aNumber,
     523             :                            bool aAfter)
     524             : {
     525           0 :   nsCOMPtr<nsIDOMElement> table;
     526           0 :   nsCOMPtr<nsIDOMElement> curCell;
     527             : 
     528             :   int32_t startRowIndex, startColIndex;
     529           0 :   nsresult rv = GetCellContext(nullptr,
     530           0 :                                getter_AddRefs(table),
     531           0 :                                getter_AddRefs(curCell),
     532             :                                nullptr, nullptr,
     533           0 :                                &startRowIndex, &startColIndex);
     534           0 :   NS_ENSURE_SUCCESS(rv, rv);
     535             :   // Don't fail if no cell found
     536           0 :   NS_ENSURE_TRUE(curCell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
     537             : 
     538             :   // Get more data for current cell in row we are inserting at (we need COLSPAN)
     539             :   int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
     540             :   bool    isSelected;
     541           0 :   rv = GetCellDataAt(table, startRowIndex, startColIndex,
     542           0 :                      getter_AddRefs(curCell),
     543             :                      &curStartRowIndex, &curStartColIndex,
     544             :                      &rowSpan, &colSpan,
     545           0 :                      &actualRowSpan, &actualColSpan, &isSelected);
     546           0 :   NS_ENSURE_SUCCESS(rv, rv);
     547           0 :   NS_ENSURE_TRUE(curCell, NS_ERROR_FAILURE);
     548             : 
     549             :   int32_t rowCount, colCount;
     550           0 :   rv = GetTableSize(table, &rowCount, &colCount);
     551           0 :   NS_ENSURE_SUCCESS(rv, rv);
     552             : 
     553           0 :   AutoEditBatch beginBatching(this);
     554             :   // Prevent auto insertion of BR in new cell until we're done
     555           0 :   AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
     556             : 
     557           0 :   if (aAfter) {
     558             :     // Use row after current cell
     559           0 :     startRowIndex += actualRowSpan;
     560             : 
     561             :     //Detect when user is adding after a ROWSPAN=0 case
     562             :     // Assume they want to stop the "0" behavior and
     563             :     // really add a new row. Thus we set the
     564             :     // rowspan to its true value
     565           0 :     if (!rowSpan) {
     566           0 :       SetRowSpan(curCell, actualRowSpan);
     567             :     }
     568             :   }
     569             : 
     570             :   //We control selection resetting after the insert...
     571             :   AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
     572             :                                              startColIndex, ePreviousColumn,
     573           0 :                                              false);
     574             :   //...so suppress Rules System selection munging
     575           0 :   AutoTransactionsConserveSelection dontChangeSelection(this);
     576             : 
     577           0 :   nsCOMPtr<nsIDOMElement> cellForRowParent;
     578           0 :   int32_t cellsInRow = 0;
     579           0 :   if (startRowIndex < rowCount) {
     580             :     // We are inserting above an existing row
     581             :     // Get each cell in the insert row to adjust for COLSPAN effects while we
     582             :     //   count how many cells are needed
     583           0 :     int32_t colIndex = 0;
     584           0 :     while (NS_SUCCEEDED(GetCellDataAt(table, startRowIndex, colIndex,
     585             :                                       getter_AddRefs(curCell),
     586             :                                       &curStartRowIndex, &curStartColIndex,
     587             :                                       &rowSpan, &colSpan,
     588             :                                       &actualRowSpan, &actualColSpan,
     589             :                                       &isSelected))) {
     590           0 :       if (curCell) {
     591           0 :         if (curStartRowIndex < startRowIndex) {
     592             :           // We have a cell spanning this location
     593             :           // Simply increase its rowspan
     594             :           //Note that if rowSpan == 0, we do nothing,
     595             :           //  since that cell should automatically extend into the new row
     596           0 :           if (rowSpan > 0) {
     597           0 :             SetRowSpan(curCell, rowSpan+aNumber);
     598             :           }
     599             :         } else {
     600             :           // We have a cell in the insert row
     601             : 
     602             :           // Count the number of cells we need to add to the new row
     603           0 :           cellsInRow += actualColSpan;
     604             : 
     605             :           // Save cell we will use below
     606           0 :           if (!cellForRowParent) {
     607           0 :             cellForRowParent = curCell;
     608             :           }
     609             :         }
     610             :         // Next cell in row
     611           0 :         colIndex += actualColSpan;
     612             :       } else {
     613           0 :         colIndex++;
     614             :       }
     615             :     }
     616             :   } else {
     617             :     // We are adding a new row after all others
     618             :     // If it weren't for colspan=0 effect,
     619             :     // we could simply use colCount for number of new cells...
     620             :     // XXX colspan=0 support has now been removed in table layout so maybe this can be cleaned up now? (bug 1243183)
     621           0 :     cellsInRow = colCount;
     622             : 
     623             :     // ...but we must compensate for all cells with rowSpan = 0 in the last row
     624           0 :     int32_t lastRow = rowCount-1;
     625           0 :     int32_t tempColIndex = 0;
     626           0 :     while (NS_SUCCEEDED(GetCellDataAt(table, lastRow, tempColIndex,
     627             :                                       getter_AddRefs(curCell),
     628             :                                       &curStartRowIndex, &curStartColIndex,
     629             :                                       &rowSpan, &colSpan,
     630             :                                       &actualRowSpan, &actualColSpan,
     631             :                                       &isSelected))) {
     632           0 :       if (!rowSpan) {
     633           0 :         cellsInRow -= actualColSpan;
     634             :       }
     635             : 
     636           0 :       tempColIndex += actualColSpan;
     637             : 
     638             :       // Save cell from the last row that we will use below
     639           0 :       if (!cellForRowParent && curStartRowIndex == lastRow) {
     640           0 :         cellForRowParent = curCell;
     641             :       }
     642             :     }
     643             :   }
     644             : 
     645           0 :   nsCOMPtr<nsINode> cellNodeForRowParent = do_QueryInterface(cellForRowParent);
     646             : 
     647           0 :   if (cellsInRow > 0) {
     648             : 
     649           0 :     NS_NAMED_LITERAL_STRING(trStr, "tr");
     650           0 :     if (!cellNodeForRowParent) {
     651           0 :       return NS_ERROR_FAILURE;
     652             :     }
     653             : 
     654             :     nsCOMPtr<Element> parentRow =
     655           0 :       GetElementOrParentByTagName(trStr, cellNodeForRowParent);
     656           0 :     NS_ENSURE_TRUE(parentRow, NS_ERROR_NULL_POINTER);
     657             : 
     658             :     // The row parent and offset where we will insert new row
     659           0 :     nsCOMPtr<nsINode> parentOfRow = parentRow->GetParentNode();
     660           0 :     NS_ENSURE_TRUE(parentOfRow, NS_ERROR_NULL_POINTER);
     661           0 :     int32_t newRowOffset = parentOfRow->IndexOf(parentRow);
     662             : 
     663             :     // Adjust for when adding past the end
     664           0 :     if (aAfter && startRowIndex >= rowCount) {
     665           0 :       newRowOffset++;
     666             :     }
     667             : 
     668           0 :     for (int32_t row = 0; row < aNumber; row++) {
     669             :       // Create a new row
     670           0 :       nsCOMPtr<Element> newRow = CreateElementWithDefaults(trStr);
     671           0 :       NS_ENSURE_TRUE(newRow, NS_ERROR_FAILURE);
     672             : 
     673           0 :       for (int32_t i = 0; i < cellsInRow; i++) {
     674             :         nsCOMPtr<Element> newCell =
     675           0 :           CreateElementWithDefaults(NS_LITERAL_STRING("td"));
     676           0 :         NS_ENSURE_TRUE(newCell, NS_ERROR_FAILURE);
     677             : 
     678             :         // Don't use transaction system yet! (not until entire row is
     679             :         // inserted)
     680           0 :         ErrorResult result;
     681           0 :         newRow->AppendChild(*newCell, result);
     682           0 :         if (NS_WARN_IF(result.Failed())) {
     683           0 :           return result.StealNSResult();
     684             :         }
     685             :       }
     686             : 
     687             :       // Use transaction system to insert the entire row+cells
     688             :       // (Note that rows are inserted at same childoffset each time)
     689           0 :       rv = InsertNode(*newRow, *parentOfRow, newRowOffset);
     690           0 :       NS_ENSURE_SUCCESS(rv, rv);
     691             :     }
     692             :   }
     693             :   // XXX This might be the result of the last call of
     694             :   //     CreateElementWithDefaults(), otherwise, NS_OK.
     695           0 :   return rv;
     696             : }
     697             : 
     698             : // Editor helper only
     699             : // XXX Code changed for bug 217717 and now we don't need aSelection param
     700             : //     TODO: Remove aSelection param
     701             : nsresult
     702           0 : HTMLEditor::DeleteTable2(nsIDOMElement* aTable,
     703             :                          Selection* aSelection)
     704             : {
     705           0 :   NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
     706             : 
     707             :   // Select the table
     708           0 :   nsresult rv = ClearSelection();
     709           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     710           0 :     return rv;
     711             :   }
     712           0 :   rv = AppendNodeToSelectionAsRange(aTable);
     713           0 :   NS_ENSURE_SUCCESS(rv, rv);
     714             : 
     715           0 :   return DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
     716             : }
     717             : 
     718             : NS_IMETHODIMP
     719           0 : HTMLEditor::DeleteTable()
     720             : {
     721           0 :   RefPtr<Selection> selection;
     722           0 :   nsCOMPtr<nsIDOMElement> table;
     723           0 :   nsresult rv = GetCellContext(getter_AddRefs(selection),
     724           0 :                                getter_AddRefs(table),
     725           0 :                                nullptr, nullptr, nullptr, nullptr, nullptr);
     726           0 :   NS_ENSURE_SUCCESS(rv, rv);
     727             : 
     728           0 :   AutoEditBatch beginBatching(this);
     729           0 :   return DeleteTable2(table, selection);
     730             : }
     731             : 
     732             : NS_IMETHODIMP
     733           0 : HTMLEditor::DeleteTableCell(int32_t aNumber)
     734             : {
     735           0 :   RefPtr<Selection> selection;
     736           0 :   nsCOMPtr<nsIDOMElement> table;
     737           0 :   nsCOMPtr<nsIDOMElement> cell;
     738             :   int32_t startRowIndex, startColIndex;
     739             : 
     740             : 
     741           0 :   nsresult rv = GetCellContext(getter_AddRefs(selection),
     742           0 :                                getter_AddRefs(table),
     743           0 :                                getter_AddRefs(cell),
     744             :                                nullptr, nullptr,
     745           0 :                                &startRowIndex, &startColIndex);
     746             : 
     747           0 :   NS_ENSURE_SUCCESS(rv, rv);
     748             :   // Don't fail if we didn't find a table or cell
     749           0 :   NS_ENSURE_TRUE(table && cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
     750             : 
     751           0 :   AutoEditBatch beginBatching(this);
     752             :   // Prevent rules testing until we're done
     753           0 :   AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
     754             : 
     755           0 :   nsCOMPtr<nsIDOMElement> firstCell;
     756           0 :   nsCOMPtr<nsIDOMRange> range;
     757           0 :   rv = GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(firstCell));
     758           0 :   NS_ENSURE_SUCCESS(rv, rv);
     759             : 
     760             :   int32_t rangeCount;
     761           0 :   rv = selection->GetRangeCount(&rangeCount);
     762           0 :   NS_ENSURE_SUCCESS(rv, rv);
     763             : 
     764           0 :   if (firstCell && rangeCount > 1) {
     765             :     // When > 1 selected cell,
     766             :     //  ignore aNumber and use selected cells
     767           0 :     cell = firstCell;
     768             : 
     769             :     int32_t rowCount, colCount;
     770           0 :     rv = GetTableSize(table, &rowCount, &colCount);
     771           0 :     NS_ENSURE_SUCCESS(rv, rv);
     772             : 
     773             :     // Get indexes -- may be different than original cell
     774           0 :     rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
     775           0 :     NS_ENSURE_SUCCESS(rv, rv);
     776             : 
     777             :     // The setCaret object will call AutoSelectionSetterAfterTableEdit in its
     778             :     // destructor
     779             :     AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
     780             :                                                startColIndex, ePreviousColumn,
     781           0 :                                                false);
     782           0 :     AutoTransactionsConserveSelection dontChangeSelection(this);
     783             : 
     784           0 :     bool    checkToDeleteRow = true;
     785           0 :     bool    checkToDeleteColumn = true;
     786           0 :     while (cell) {
     787           0 :       bool deleteRow = false;
     788           0 :       bool deleteCol = false;
     789             : 
     790           0 :       if (checkToDeleteRow) {
     791             :         // Optimize to delete an entire row
     792             :         // Clear so we don't repeat AllCellsInRowSelected within the same row
     793           0 :         checkToDeleteRow = false;
     794             : 
     795           0 :         deleteRow = AllCellsInRowSelected(table, startRowIndex, colCount);
     796           0 :         if (deleteRow) {
     797             :           // First, find the next cell in a different row
     798             :           //   to continue after we delete this row
     799           0 :           int32_t nextRow = startRowIndex;
     800           0 :           while (nextRow == startRowIndex) {
     801           0 :             rv = GetNextSelectedCell(nullptr, getter_AddRefs(cell));
     802           0 :             NS_ENSURE_SUCCESS(rv, rv);
     803           0 :             if (!cell) {
     804           0 :               break;
     805             :             }
     806           0 :             rv = GetCellIndexes(cell, &nextRow, &startColIndex);
     807           0 :             NS_ENSURE_SUCCESS(rv, rv);
     808             :           }
     809             :           // Delete entire row
     810           0 :           rv = DeleteRow(table, startRowIndex);
     811           0 :           NS_ENSURE_SUCCESS(rv, rv);
     812             : 
     813           0 :           if (cell) {
     814             :             // For the next cell: Subtract 1 for row we deleted
     815           0 :             startRowIndex = nextRow - 1;
     816             :             // Set true since we know we will look at a new row next
     817           0 :             checkToDeleteRow = true;
     818             :           }
     819             :         }
     820             :       }
     821           0 :       if (!deleteRow) {
     822           0 :         if (checkToDeleteColumn) {
     823             :           // Optimize to delete an entire column
     824             :           // Clear this so we don't repeat AllCellsInColSelected within the same Col
     825           0 :           checkToDeleteColumn = false;
     826             : 
     827           0 :           deleteCol = AllCellsInColumnSelected(table, startColIndex, colCount);
     828           0 :           if (deleteCol) {
     829             :             // First, find the next cell in a different column
     830             :             //   to continue after we delete this column
     831           0 :             int32_t nextCol = startColIndex;
     832           0 :             while (nextCol == startColIndex) {
     833           0 :               rv = GetNextSelectedCell(nullptr, getter_AddRefs(cell));
     834           0 :               NS_ENSURE_SUCCESS(rv, rv);
     835           0 :               if (!cell) {
     836           0 :                 break;
     837             :               }
     838           0 :               rv = GetCellIndexes(cell, &startRowIndex, &nextCol);
     839           0 :               NS_ENSURE_SUCCESS(rv, rv);
     840             :             }
     841             :             // Delete entire Col
     842           0 :             rv = DeleteColumn(table, startColIndex);
     843           0 :             NS_ENSURE_SUCCESS(rv, rv);
     844           0 :             if (cell) {
     845             :               // For the next cell, subtract 1 for col. deleted
     846           0 :               startColIndex = nextCol - 1;
     847             :               // Set true since we know we will look at a new column next
     848           0 :               checkToDeleteColumn = true;
     849             :             }
     850             :           }
     851             :         }
     852           0 :         if (!deleteCol) {
     853             :           // First get the next cell to delete
     854           0 :           nsCOMPtr<nsIDOMElement> nextCell;
     855           0 :           rv = GetNextSelectedCell(getter_AddRefs(range),
     856           0 :                                    getter_AddRefs(nextCell));
     857           0 :           NS_ENSURE_SUCCESS(rv, rv);
     858             : 
     859             :           // Then delete the cell
     860           0 :           rv = DeleteNode(cell);
     861           0 :           NS_ENSURE_SUCCESS(rv, rv);
     862             : 
     863             :           // The next cell to delete
     864           0 :           cell = nextCell;
     865           0 :           if (cell) {
     866           0 :             rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
     867           0 :             NS_ENSURE_SUCCESS(rv, rv);
     868             :           }
     869             :         }
     870             :       }
     871             :     }
     872             :   } else {
     873           0 :     for (int32_t i = 0; i < aNumber; i++) {
     874           0 :       rv = GetCellContext(getter_AddRefs(selection),
     875           0 :                           getter_AddRefs(table),
     876           0 :                           getter_AddRefs(cell),
     877             :                           nullptr, nullptr,
     878           0 :                           &startRowIndex, &startColIndex);
     879           0 :       NS_ENSURE_SUCCESS(rv, rv);
     880             :       // Don't fail if no cell found
     881           0 :       NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
     882             : 
     883           0 :       if (GetNumberOfCellsInRow(table, startRowIndex) == 1) {
     884           0 :         nsCOMPtr<nsIDOMElement> parentRow;
     885           0 :         rv = GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cell,
     886           0 :                                          getter_AddRefs(parentRow));
     887           0 :         NS_ENSURE_SUCCESS(rv, rv);
     888           0 :         NS_ENSURE_TRUE(parentRow, NS_ERROR_NULL_POINTER);
     889             : 
     890             :         // We should delete the row instead,
     891             :         //  but first check if its the only row left
     892             :         //  so we can delete the entire table
     893             :         int32_t rowCount, colCount;
     894           0 :         rv = GetTableSize(table, &rowCount, &colCount);
     895           0 :         NS_ENSURE_SUCCESS(rv, rv);
     896             : 
     897           0 :         if (rowCount == 1) {
     898           0 :           return DeleteTable2(table, selection);
     899             :         }
     900             : 
     901             :         // We need to call DeleteTableRow to handle cells with rowspan
     902           0 :         rv = DeleteTableRow(1);
     903           0 :         NS_ENSURE_SUCCESS(rv, rv);
     904             :       } else {
     905             :         // More than 1 cell in the row
     906             : 
     907             :         // The setCaret object will call AutoSelectionSetterAfterTableEdit in its
     908             :         // destructor
     909             :         AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
     910             :                                                    startColIndex, ePreviousColumn,
     911           0 :                                                    false);
     912           0 :         AutoTransactionsConserveSelection dontChangeSelection(this);
     913             : 
     914           0 :         rv = DeleteNode(cell);
     915             :         // If we fail, don't try to delete any more cells???
     916           0 :         NS_ENSURE_SUCCESS(rv, rv);
     917             :       }
     918             :     }
     919             :   }
     920           0 :   return NS_OK;
     921             : }
     922             : 
     923             : NS_IMETHODIMP
     924           0 : HTMLEditor::DeleteTableCellContents()
     925             : {
     926           0 :   RefPtr<Selection> selection;
     927           0 :   nsCOMPtr<nsIDOMElement> table;
     928           0 :   nsCOMPtr<nsIDOMElement> cell;
     929             :   int32_t startRowIndex, startColIndex;
     930           0 :   nsresult rv = GetCellContext(getter_AddRefs(selection),
     931           0 :                                getter_AddRefs(table),
     932           0 :                                getter_AddRefs(cell),
     933             :                                nullptr, nullptr,
     934           0 :                                &startRowIndex, &startColIndex);
     935           0 :   NS_ENSURE_SUCCESS(rv, rv);
     936             :   // Don't fail if no cell found
     937           0 :   NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
     938             : 
     939             : 
     940           0 :   AutoEditBatch beginBatching(this);
     941             :   // Prevent rules testing until we're done
     942           0 :   AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
     943             :   //Don't let Rules System change the selection
     944           0 :   AutoTransactionsConserveSelection dontChangeSelection(this);
     945             : 
     946             : 
     947           0 :   nsCOMPtr<nsIDOMElement> firstCell;
     948           0 :   nsCOMPtr<nsIDOMRange> range;
     949           0 :   rv = GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(firstCell));
     950           0 :   NS_ENSURE_SUCCESS(rv, rv);
     951             : 
     952             : 
     953           0 :   if (firstCell) {
     954           0 :     cell = firstCell;
     955           0 :     rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
     956           0 :     NS_ENSURE_SUCCESS(rv, rv);
     957             :   }
     958             : 
     959             :   AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
     960             :                                              startColIndex, ePreviousColumn,
     961           0 :                                              false);
     962             : 
     963           0 :   while (cell) {
     964           0 :     DeleteCellContents(cell);
     965           0 :     if (firstCell) {
     966             :       // We doing a selected cells, so do all of them
     967           0 :       rv = GetNextSelectedCell(nullptr, getter_AddRefs(cell));
     968           0 :       NS_ENSURE_SUCCESS(rv, rv);
     969             :     } else {
     970           0 :       cell = nullptr;
     971             :     }
     972             :   }
     973           0 :   return NS_OK;
     974             : }
     975             : 
     976             : NS_IMETHODIMP
     977           0 : HTMLEditor::DeleteCellContents(nsIDOMElement* aCell)
     978             : {
     979           0 :   NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
     980             : 
     981             :   // Prevent rules testing until we're done
     982           0 :   AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
     983             : 
     984           0 :   nsCOMPtr<nsIDOMNode> child;
     985             :   bool hasChild;
     986           0 :   aCell->HasChildNodes(&hasChild);
     987             : 
     988           0 :   while (hasChild) {
     989           0 :     aCell->GetLastChild(getter_AddRefs(child));
     990           0 :     nsresult rv = DeleteNode(child);
     991           0 :     NS_ENSURE_SUCCESS(rv, rv);
     992           0 :     aCell->HasChildNodes(&hasChild);
     993             :   }
     994           0 :   return NS_OK;
     995             : }
     996             : 
     997             : NS_IMETHODIMP
     998           0 : HTMLEditor::DeleteTableColumn(int32_t aNumber)
     999             : {
    1000           0 :   RefPtr<Selection> selection;
    1001           0 :   nsCOMPtr<nsIDOMElement> table;
    1002           0 :   nsCOMPtr<nsIDOMElement> cell;
    1003             :   int32_t startRowIndex, startColIndex, rowCount, colCount;
    1004           0 :   nsresult rv = GetCellContext(getter_AddRefs(selection),
    1005           0 :                                getter_AddRefs(table),
    1006           0 :                                getter_AddRefs(cell),
    1007             :                                nullptr, nullptr,
    1008           0 :                                &startRowIndex, &startColIndex);
    1009           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1010             :   // Don't fail if no cell found
    1011           0 :   NS_ENSURE_TRUE(table && cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
    1012             : 
    1013           0 :   rv = GetTableSize(table, &rowCount, &colCount);
    1014           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1015             : 
    1016             :   // Shortcut the case of deleting all columns in table
    1017           0 :   if (!startColIndex && aNumber >= colCount) {
    1018           0 :     return DeleteTable2(table, selection);
    1019             :   }
    1020             : 
    1021             :   // Check for counts too high
    1022           0 :   aNumber = std::min(aNumber,(colCount-startColIndex));
    1023             : 
    1024           0 :   AutoEditBatch beginBatching(this);
    1025             :   // Prevent rules testing until we're done
    1026           0 :   AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
    1027             : 
    1028             :   // Test if deletion is controlled by selected cells
    1029           0 :   nsCOMPtr<nsIDOMElement> firstCell;
    1030           0 :   nsCOMPtr<nsIDOMRange> range;
    1031           0 :   rv = GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(firstCell));
    1032           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1033             : 
    1034             :   int32_t rangeCount;
    1035           0 :   rv = selection->GetRangeCount(&rangeCount);
    1036           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1037             : 
    1038           0 :   if (firstCell && rangeCount > 1) {
    1039             :     // Fetch indexes again - may be different for selected cells
    1040           0 :     rv = GetCellIndexes(firstCell, &startRowIndex, &startColIndex);
    1041           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1042             :   }
    1043             :   //We control selection resetting after the insert...
    1044             :   AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
    1045             :                                              startColIndex, ePreviousRow,
    1046           0 :                                              false);
    1047             : 
    1048           0 :   if (firstCell && rangeCount > 1) {
    1049             :     // Use selected cells to determine what rows to delete
    1050           0 :     cell = firstCell;
    1051             : 
    1052           0 :     while (cell) {
    1053           0 :       if (cell != firstCell) {
    1054           0 :         rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
    1055           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1056             :       }
    1057             :       // Find the next cell in a different column
    1058             :       // to continue after we delete this column
    1059           0 :       int32_t nextCol = startColIndex;
    1060           0 :       while (nextCol == startColIndex) {
    1061           0 :         rv = GetNextSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
    1062           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1063           0 :         if (!cell) {
    1064           0 :           break;
    1065             :         }
    1066           0 :         rv = GetCellIndexes(cell, &startRowIndex, &nextCol);
    1067           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1068             :       }
    1069           0 :       rv = DeleteColumn(table, startColIndex);
    1070           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1071             :     }
    1072             :   } else {
    1073           0 :     for (int32_t i = 0; i < aNumber; i++) {
    1074           0 :       rv = DeleteColumn(table, startColIndex);
    1075           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1076             :     }
    1077             :   }
    1078           0 :   return NS_OK;
    1079             : }
    1080             : 
    1081             : NS_IMETHODIMP
    1082           0 : HTMLEditor::DeleteColumn(nsIDOMElement* aTable,
    1083             :                          int32_t aColIndex)
    1084             : {
    1085           0 :   NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
    1086             : 
    1087           0 :   nsCOMPtr<nsIDOMElement> cell;
    1088             :   int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    1089             :   bool    isSelected;
    1090           0 :   int32_t rowIndex = 0;
    1091             : 
    1092           0 :   do {
    1093             :     nsresult rv =
    1094           0 :       GetCellDataAt(aTable, rowIndex, aColIndex, getter_AddRefs(cell),
    1095             :                     &startRowIndex, &startColIndex, &rowSpan, &colSpan,
    1096           0 :                     &actualRowSpan, &actualColSpan, &isSelected);
    1097           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1098             : 
    1099           0 :     if (cell) {
    1100             :       // Find cells that don't start in column we are deleting
    1101           0 :       if (startColIndex < aColIndex || colSpan > 1 || !colSpan) {
    1102             :         // We have a cell spanning this location
    1103             :         // Decrease its colspan to keep table rectangular,
    1104             :         // but if colSpan=0, it will adjust automatically
    1105           0 :         if (colSpan > 0) {
    1106           0 :           NS_ASSERTION((colSpan > 1),"Bad COLSPAN in DeleteTableColumn");
    1107           0 :           SetColSpan(cell, colSpan-1);
    1108             :         }
    1109           0 :         if (startColIndex == aColIndex) {
    1110             :           // Cell is in column to be deleted, but must have colspan > 1,
    1111             :           // so delete contents of cell instead of cell itself
    1112             :           // (We must have reset colspan above)
    1113           0 :           DeleteCellContents(cell);
    1114             :         }
    1115             :         // To next cell in column
    1116           0 :         rowIndex += actualRowSpan;
    1117             :       } else {
    1118             :         // Delete the cell
    1119           0 :         if (GetNumberOfCellsInRow(aTable, rowIndex) == 1) {
    1120             :           // Only 1 cell in row - delete the row
    1121           0 :           nsCOMPtr<nsIDOMElement> parentRow;
    1122           0 :           rv = GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cell,
    1123           0 :                                            getter_AddRefs(parentRow));
    1124           0 :           NS_ENSURE_SUCCESS(rv, rv);
    1125           0 :           if (!parentRow) {
    1126           0 :             return NS_ERROR_NULL_POINTER;
    1127             :           }
    1128             : 
    1129             :           //  But first check if its the only row left
    1130             :           //  so we can delete the entire table
    1131             :           //  (This should never happen but it's the safe thing to do)
    1132             :           int32_t rowCount, colCount;
    1133           0 :           rv = GetTableSize(aTable, &rowCount, &colCount);
    1134           0 :           NS_ENSURE_SUCCESS(rv, rv);
    1135             : 
    1136           0 :           if (rowCount == 1) {
    1137           0 :             RefPtr<Selection> selection = GetSelection();
    1138           0 :             NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    1139           0 :             return DeleteTable2(aTable, selection);
    1140             :           }
    1141             : 
    1142             :           // Delete the row by placing caret in cell we were to delete
    1143             :           // We need to call DeleteTableRow to handle cells with rowspan
    1144           0 :           rv = DeleteRow(aTable, startRowIndex);
    1145           0 :           NS_ENSURE_SUCCESS(rv, rv);
    1146             : 
    1147             :           // Note that we don't incremenet rowIndex
    1148             :           // since a row was deleted and "next"
    1149             :           // row now has current rowIndex
    1150             :         } else {
    1151             :           // A more "normal" deletion
    1152           0 :           rv = DeleteNode(cell);
    1153           0 :           NS_ENSURE_SUCCESS(rv, rv);
    1154             : 
    1155             :           //Skip over any rows spanned by this cell
    1156           0 :           rowIndex += actualRowSpan;
    1157             :         }
    1158             :       }
    1159             :     }
    1160             :   } while (cell);
    1161             : 
    1162           0 :   return NS_OK;
    1163             : }
    1164             : 
    1165             : NS_IMETHODIMP
    1166           0 : HTMLEditor::DeleteTableRow(int32_t aNumber)
    1167             : {
    1168           0 :   RefPtr<Selection> selection;
    1169           0 :   nsCOMPtr<nsIDOMElement> table;
    1170           0 :   nsCOMPtr<nsIDOMElement> cell;
    1171             :   int32_t startRowIndex, startColIndex;
    1172             :   int32_t rowCount, colCount;
    1173           0 :   nsresult rv =  GetCellContext(getter_AddRefs(selection),
    1174           0 :                                 getter_AddRefs(table),
    1175           0 :                                 getter_AddRefs(cell),
    1176             :                                 nullptr, nullptr,
    1177           0 :                                 &startRowIndex, &startColIndex);
    1178           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1179             :   // Don't fail if no cell found
    1180           0 :   NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
    1181             : 
    1182           0 :   rv = GetTableSize(table, &rowCount, &colCount);
    1183           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1184             : 
    1185             :   // Shortcut the case of deleting all rows in table
    1186           0 :   if (!startRowIndex && aNumber >= rowCount) {
    1187           0 :     return DeleteTable2(table, selection);
    1188             :   }
    1189             : 
    1190           0 :   AutoEditBatch beginBatching(this);
    1191             :   // Prevent rules testing until we're done
    1192           0 :   AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
    1193             : 
    1194           0 :   nsCOMPtr<nsIDOMElement> firstCell;
    1195           0 :   nsCOMPtr<nsIDOMRange> range;
    1196           0 :   rv = GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(firstCell));
    1197           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1198             : 
    1199             :   int32_t rangeCount;
    1200           0 :   rv = selection->GetRangeCount(&rangeCount);
    1201           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1202             : 
    1203           0 :   if (firstCell && rangeCount > 1) {
    1204             :     // Fetch indexes again - may be different for selected cells
    1205           0 :     rv = GetCellIndexes(firstCell, &startRowIndex, &startColIndex);
    1206           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1207             :   }
    1208             : 
    1209             :   //We control selection resetting after the insert...
    1210             :   AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
    1211             :                                              startColIndex, ePreviousRow,
    1212           0 :                                              false);
    1213             :   // Don't change selection during deletions
    1214           0 :   AutoTransactionsConserveSelection dontChangeSelection(this);
    1215             : 
    1216           0 :   if (firstCell && rangeCount > 1) {
    1217             :     // Use selected cells to determine what rows to delete
    1218           0 :     cell = firstCell;
    1219             : 
    1220           0 :     while (cell) {
    1221           0 :       if (cell != firstCell) {
    1222           0 :         rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
    1223           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1224             :       }
    1225             :       // Find the next cell in a different row
    1226             :       // to continue after we delete this row
    1227           0 :       int32_t nextRow = startRowIndex;
    1228           0 :       while (nextRow == startRowIndex) {
    1229           0 :         rv = GetNextSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
    1230           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1231           0 :         if (!cell) break;
    1232           0 :         rv = GetCellIndexes(cell, &nextRow, &startColIndex);
    1233           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1234             :       }
    1235             :       // Delete entire row
    1236           0 :       rv = DeleteRow(table, startRowIndex);
    1237           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1238             :     }
    1239             :   } else {
    1240             :     // Check for counts too high
    1241           0 :     aNumber = std::min(aNumber,(rowCount-startRowIndex));
    1242           0 :     for (int32_t i = 0; i < aNumber; i++) {
    1243           0 :       rv = DeleteRow(table, startRowIndex);
    1244             :       // If failed in current row, try the next
    1245           0 :       if (NS_FAILED(rv)) {
    1246           0 :         startRowIndex++;
    1247             :       }
    1248             : 
    1249             :       // Check if there's a cell in the "next" row
    1250           0 :       rv = GetCellAt(table, startRowIndex, startColIndex, getter_AddRefs(cell));
    1251           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1252           0 :       if (!cell) {
    1253           0 :         break;
    1254             :       }
    1255             :     }
    1256             :   }
    1257           0 :   return NS_OK;
    1258             : }
    1259             : 
    1260             : // Helper that doesn't batch or change the selection
    1261             : NS_IMETHODIMP
    1262           0 : HTMLEditor::DeleteRow(nsIDOMElement* aTable,
    1263             :                       int32_t aRowIndex)
    1264             : {
    1265           0 :   NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
    1266             : 
    1267           0 :   nsCOMPtr<nsIDOMElement> cell;
    1268           0 :   nsCOMPtr<nsIDOMElement> cellInDeleteRow;
    1269             :   int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    1270             :   bool    isSelected;
    1271           0 :   int32_t colIndex = 0;
    1272             : 
    1273             :   // Prevent rules testing until we're done
    1274           0 :   AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
    1275             : 
    1276             :   // The list of cells we will change rowspan in
    1277             :   //  and the new rowspan values for each
    1278           0 :   nsTArray<nsCOMPtr<nsIDOMElement> > spanCellList;
    1279           0 :   nsTArray<int32_t> newSpanList;
    1280             : 
    1281             :   int32_t rowCount, colCount;
    1282           0 :   nsresult rv = GetTableSize(aTable, &rowCount, &colCount);
    1283           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1284             : 
    1285             :   // Scan through cells in row to do rowspan adjustments
    1286             :   // Note that after we delete row, startRowIndex will point to the
    1287             :   //   cells in the next row to be deleted
    1288           0 :   do {
    1289           0 :     if (aRowIndex >= rowCount || colIndex >= colCount) {
    1290             :       break;
    1291             :     }
    1292             : 
    1293           0 :     rv = GetCellDataAt(aTable, aRowIndex, colIndex, getter_AddRefs(cell),
    1294             :                        &startRowIndex, &startColIndex, &rowSpan, &colSpan,
    1295           0 :                        &actualRowSpan, &actualColSpan, &isSelected);
    1296             :     // We don't fail if we don't find a cell, so this must be real bad
    1297           0 :     if (NS_FAILED(rv)) {
    1298           0 :       return rv;
    1299             :     }
    1300             : 
    1301             :     // Compensate for cells that don't start or extend below the row we are deleting
    1302           0 :     if (cell) {
    1303           0 :       if (startRowIndex < aRowIndex) {
    1304             :         // Cell starts in row above us
    1305             :         // Decrease its rowspan to keep table rectangular
    1306             :         //  but we don't need to do this if rowspan=0,
    1307             :         //  since it will automatically adjust
    1308           0 :         if (rowSpan > 0) {
    1309             :           // Build list of cells to change rowspan
    1310             :           // We can't do it now since it upsets cell map,
    1311             :           //  so we will do it after deleting the row
    1312           0 :           spanCellList.AppendElement(cell);
    1313           0 :           newSpanList.AppendElement(std::max((aRowIndex - startRowIndex), actualRowSpan-1));
    1314             :         }
    1315             :       } else {
    1316           0 :         if (rowSpan > 1) {
    1317             :           // Cell spans below row to delete, so we must insert new cells to
    1318             :           // keep rows below.  Note that we test "rowSpan" so we don't do this
    1319             :           // if rowSpan = 0 (automatic readjustment).
    1320           0 :           int32_t aboveRowToInsertNewCellInto = aRowIndex - startRowIndex + 1;
    1321           0 :           int32_t numOfRawSpanRemainingBelow = actualRowSpan - 1;
    1322           0 :           rv = SplitCellIntoRows(aTable, startRowIndex, startColIndex,
    1323             :                                  aboveRowToInsertNewCellInto,
    1324           0 :                                  numOfRawSpanRemainingBelow, nullptr);
    1325           0 :           NS_ENSURE_SUCCESS(rv, rv);
    1326             :         }
    1327           0 :         if (!cellInDeleteRow) {
    1328           0 :           cellInDeleteRow = cell; // Reference cell to find row to delete
    1329             :         }
    1330             :       }
    1331             :       // Skip over other columns spanned by this cell
    1332           0 :       colIndex += actualColSpan;
    1333             :     }
    1334             :   } while (cell);
    1335             : 
    1336             :   // Things are messed up if we didn't find a cell in the row!
    1337           0 :   NS_ENSURE_TRUE(cellInDeleteRow, NS_ERROR_FAILURE);
    1338             : 
    1339             :   // Delete the entire row
    1340           0 :   nsCOMPtr<nsIDOMElement> parentRow;
    1341           0 :   rv = GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cellInDeleteRow,
    1342           0 :                                    getter_AddRefs(parentRow));
    1343           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1344             : 
    1345           0 :   if (parentRow) {
    1346           0 :     rv = DeleteNode(parentRow);
    1347           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1348             :   }
    1349             : 
    1350             :   // Now we can set new rowspans for cells stored above
    1351           0 :   for (uint32_t i = 0, n = spanCellList.Length(); i < n; i++) {
    1352           0 :     nsIDOMElement *cellPtr = spanCellList[i];
    1353           0 :     if (cellPtr) {
    1354           0 :       rv = SetRowSpan(cellPtr, newSpanList[i]);
    1355           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1356             :     }
    1357             :   }
    1358           0 :   return NS_OK;
    1359             : }
    1360             : 
    1361             : 
    1362             : NS_IMETHODIMP
    1363           0 : HTMLEditor::SelectTable()
    1364             : {
    1365           0 :   nsCOMPtr<nsIDOMElement> table;
    1366           0 :   nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr,
    1367           0 :                                             getter_AddRefs(table));
    1368           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1369             :   // Don't fail if we didn't find a table
    1370           0 :   NS_ENSURE_TRUE(table, NS_OK);
    1371             : 
    1372           0 :   rv = ClearSelection();
    1373           0 :   if (NS_FAILED(rv)) {
    1374           0 :     return rv;
    1375             :   }
    1376           0 :   return AppendNodeToSelectionAsRange(table);
    1377             : }
    1378             : 
    1379             : NS_IMETHODIMP
    1380           0 : HTMLEditor::SelectTableCell()
    1381             : {
    1382           0 :   nsCOMPtr<nsIDOMElement> cell;
    1383           0 :   nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
    1384           0 :                                             getter_AddRefs(cell));
    1385           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1386           0 :   NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
    1387             : 
    1388           0 :   rv = ClearSelection();
    1389           0 :   if (NS_FAILED(rv)) {
    1390           0 :     return rv;
    1391             :   }
    1392           0 :   return AppendNodeToSelectionAsRange(cell);
    1393             : }
    1394             : 
    1395             : NS_IMETHODIMP
    1396           0 : HTMLEditor::SelectBlockOfCells(nsIDOMElement* aStartCell,
    1397             :                                nsIDOMElement* aEndCell)
    1398             : {
    1399           0 :   NS_ENSURE_TRUE(aStartCell && aEndCell, NS_ERROR_NULL_POINTER);
    1400             : 
    1401           0 :   RefPtr<Selection> selection = GetSelection();
    1402           0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    1403             : 
    1404           0 :   NS_NAMED_LITERAL_STRING(tableStr, "table");
    1405           0 :   nsCOMPtr<nsIDOMElement> table;
    1406           0 :   nsresult rv = GetElementOrParentByTagName(tableStr, aStartCell,
    1407           0 :                                             getter_AddRefs(table));
    1408           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1409           0 :   NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
    1410             : 
    1411           0 :   nsCOMPtr<nsIDOMElement> endTable;
    1412           0 :   rv = GetElementOrParentByTagName(tableStr, aEndCell,
    1413           0 :                                    getter_AddRefs(endTable));
    1414           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1415           0 :   NS_ENSURE_TRUE(endTable, NS_ERROR_FAILURE);
    1416             : 
    1417             :   // We can only select a block if within the same table,
    1418             :   //  so do nothing if not within one table
    1419           0 :   if (table != endTable) {
    1420           0 :     return NS_OK;
    1421             :   }
    1422             : 
    1423             :   int32_t startRowIndex, startColIndex, endRowIndex, endColIndex;
    1424             : 
    1425             :   // Get starting and ending cells' location in the cellmap
    1426           0 :   rv = GetCellIndexes(aStartCell, &startRowIndex, &startColIndex);
    1427           0 :   if (NS_FAILED(rv)) {
    1428           0 :     return rv;
    1429             :   }
    1430             : 
    1431           0 :   rv = GetCellIndexes(aEndCell, &endRowIndex, &endColIndex);
    1432           0 :   if (NS_FAILED(rv)) {
    1433           0 :     return rv;
    1434             :   }
    1435             : 
    1436             :   // Suppress nsISelectionListener notification
    1437             :   //  until all selection changes are finished
    1438           0 :   SelectionBatcher selectionBatcher(selection);
    1439             : 
    1440             :   // Examine all cell nodes in current selection and
    1441             :   //  remove those outside the new block cell region
    1442           0 :   int32_t minColumn = std::min(startColIndex, endColIndex);
    1443           0 :   int32_t minRow    = std::min(startRowIndex, endRowIndex);
    1444           0 :   int32_t maxColumn   = std::max(startColIndex, endColIndex);
    1445           0 :   int32_t maxRow      = std::max(startRowIndex, endRowIndex);
    1446             : 
    1447           0 :   nsCOMPtr<nsIDOMElement> cell;
    1448             :   int32_t currentRowIndex, currentColIndex;
    1449           0 :   nsCOMPtr<nsIDOMRange> range;
    1450           0 :   rv = GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
    1451           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1452           0 :   if (rv == NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND) {
    1453           0 :     return NS_OK;
    1454             :   }
    1455             : 
    1456           0 :   while (cell) {
    1457           0 :     rv = GetCellIndexes(cell, &currentRowIndex, &currentColIndex);
    1458           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1459             : 
    1460           0 :     if (currentRowIndex < maxRow || currentRowIndex > maxRow ||
    1461           0 :         currentColIndex < maxColumn || currentColIndex > maxColumn) {
    1462           0 :       selection->RemoveRange(range);
    1463             :       // Since we've removed the range, decrement pointer to next range
    1464           0 :       mSelectedCellIndex--;
    1465             :     }
    1466           0 :     rv = GetNextSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
    1467           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1468             :   }
    1469             : 
    1470             :   int32_t rowSpan, colSpan, actualRowSpan, actualColSpan;
    1471             :   bool    isSelected;
    1472           0 :   for (int32_t row = minRow; row <= maxRow; row++) {
    1473           0 :     for (int32_t col = minColumn; col <= maxColumn;
    1474           0 :         col += std::max(actualColSpan, 1)) {
    1475           0 :       rv = GetCellDataAt(table, row, col, getter_AddRefs(cell),
    1476             :                          &currentRowIndex, &currentColIndex,
    1477             :                          &rowSpan, &colSpan,
    1478           0 :                          &actualRowSpan, &actualColSpan, &isSelected);
    1479           0 :       if (NS_FAILED(rv)) {
    1480           0 :         break;
    1481             :       }
    1482             :       // Skip cells that already selected or are spanned from previous locations
    1483           0 :       if (!isSelected && cell &&
    1484           0 :           row == currentRowIndex && col == currentColIndex) {
    1485           0 :         rv = AppendNodeToSelectionAsRange(cell);
    1486           0 :         if (NS_FAILED(rv)) {
    1487           0 :           break;
    1488             :         }
    1489             :       }
    1490             :     }
    1491             :   }
    1492             :   // NS_OK, otherwise, the last failure of GetCellDataAt() or
    1493             :   // AppendNodeToSelectionAsRange().
    1494           0 :   return rv;
    1495             : }
    1496             : 
    1497             : NS_IMETHODIMP
    1498           0 : HTMLEditor::SelectAllTableCells()
    1499             : {
    1500           0 :   nsCOMPtr<nsIDOMElement> cell;
    1501           0 :   nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
    1502           0 :                                             getter_AddRefs(cell));
    1503           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1504             : 
    1505             :   // Don't fail if we didn't find a cell
    1506           0 :   NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
    1507             : 
    1508           0 :   nsCOMPtr<nsIDOMElement> startCell = cell;
    1509             : 
    1510             :   // Get parent table
    1511           0 :   nsCOMPtr<nsIDOMElement> table;
    1512           0 :   rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), cell,
    1513           0 :                                    getter_AddRefs(table));
    1514           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1515           0 :   if (!table) {
    1516           0 :     return NS_ERROR_NULL_POINTER;
    1517             :   }
    1518             : 
    1519             :   int32_t rowCount, colCount;
    1520           0 :   rv = GetTableSize(table, &rowCount, &colCount);
    1521           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1522             : 
    1523           0 :   RefPtr<Selection> selection = GetSelection();
    1524           0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    1525             : 
    1526             :   // Suppress nsISelectionListener notification
    1527             :   //  until all selection changes are finished
    1528           0 :   SelectionBatcher selectionBatcher(selection);
    1529             : 
    1530             :   // It is now safe to clear the selection
    1531             :   // BE SURE TO RESET IT BEFORE LEAVING!
    1532           0 :   rv = ClearSelection();
    1533             : 
    1534             :   // Select all cells in the same column as current cell
    1535           0 :   bool cellSelected = false;
    1536             :   int32_t rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
    1537             :   bool    isSelected;
    1538           0 :   for (int32_t row = 0; row < rowCount; row++) {
    1539           0 :     for (int32_t col = 0; col < colCount; col += std::max(actualColSpan, 1)) {
    1540           0 :       rv = GetCellDataAt(table, row, col, getter_AddRefs(cell),
    1541             :                          &currentRowIndex, &currentColIndex,
    1542             :                          &rowSpan, &colSpan,
    1543           0 :                          &actualRowSpan, &actualColSpan, &isSelected);
    1544           0 :       if (NS_FAILED(rv)) {
    1545           0 :         break;
    1546             :       }
    1547             :       // Skip cells that are spanned from previous rows or columns
    1548           0 :       if (cell && row == currentRowIndex && col == currentColIndex) {
    1549           0 :         rv =  AppendNodeToSelectionAsRange(cell);
    1550           0 :         if (NS_FAILED(rv)) {
    1551           0 :           break;
    1552             :         }
    1553           0 :         cellSelected = true;
    1554             :       }
    1555             :     }
    1556             :   }
    1557             :   // Safety code to select starting cell if nothing else was selected
    1558           0 :   if (!cellSelected) {
    1559           0 :     return AppendNodeToSelectionAsRange(startCell);
    1560             :   }
    1561             :   // NS_OK, otherwise, the error of ClearSelection() when there is no column or
    1562             :   // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
    1563           0 :   return rv;
    1564             : }
    1565             : 
    1566             : NS_IMETHODIMP
    1567           0 : HTMLEditor::SelectTableRow()
    1568             : {
    1569           0 :   nsCOMPtr<nsIDOMElement> cell;
    1570           0 :   nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
    1571           0 :                                             getter_AddRefs(cell));
    1572           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1573             : 
    1574             :   // Don't fail if we didn't find a cell
    1575           0 :   NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
    1576           0 :   nsCOMPtr<nsIDOMElement> startCell = cell;
    1577             : 
    1578             :   // Get table and location of cell:
    1579           0 :   RefPtr<Selection> selection;
    1580           0 :   nsCOMPtr<nsIDOMElement> table;
    1581             :   int32_t startRowIndex, startColIndex;
    1582             : 
    1583           0 :   rv = GetCellContext(getter_AddRefs(selection),
    1584           0 :                       getter_AddRefs(table),
    1585           0 :                       getter_AddRefs(cell),
    1586             :                       nullptr, nullptr,
    1587           0 :                       &startRowIndex, &startColIndex);
    1588           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1589           0 :   NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
    1590             : 
    1591             :   int32_t rowCount, colCount;
    1592           0 :   rv = GetTableSize(table, &rowCount, &colCount);
    1593           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1594             : 
    1595             :   //Note: At this point, we could get first and last cells in row,
    1596             :   //  then call SelectBlockOfCells, but that would take just
    1597             :   //  a little less code, so the following is more efficient
    1598             : 
    1599             :   // Suppress nsISelectionListener notification
    1600             :   //  until all selection changes are finished
    1601           0 :   SelectionBatcher selectionBatcher(selection);
    1602             : 
    1603             :   // It is now safe to clear the selection
    1604             :   // BE SURE TO RESET IT BEFORE LEAVING!
    1605           0 :   rv = ClearSelection();
    1606             : 
    1607             :   // Select all cells in the same row as current cell
    1608           0 :   bool cellSelected = false;
    1609             :   int32_t rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
    1610             :   bool    isSelected;
    1611           0 :   for (int32_t col = 0; col < colCount; col += std::max(actualColSpan, 1)) {
    1612           0 :     rv = GetCellDataAt(table, startRowIndex, col, getter_AddRefs(cell),
    1613             :                        &currentRowIndex, &currentColIndex, &rowSpan, &colSpan,
    1614           0 :                        &actualRowSpan, &actualColSpan, &isSelected);
    1615           0 :     if (NS_FAILED(rv)) {
    1616           0 :       break;
    1617             :     }
    1618             :     // Skip cells that are spanned from previous rows or columns
    1619           0 :     if (cell && currentRowIndex == startRowIndex && currentColIndex == col) {
    1620           0 :       rv = AppendNodeToSelectionAsRange(cell);
    1621           0 :       if (NS_FAILED(rv)) {
    1622           0 :         break;
    1623             :       }
    1624           0 :       cellSelected = true;
    1625             :     }
    1626             :   }
    1627             :   // Safety code to select starting cell if nothing else was selected
    1628           0 :   if (!cellSelected) {
    1629           0 :     return AppendNodeToSelectionAsRange(startCell);
    1630             :   }
    1631             :   // NS_OK, otherwise, the error of ClearSelection() when there is no column or
    1632             :   // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
    1633           0 :   return rv;
    1634             : }
    1635             : 
    1636             : NS_IMETHODIMP
    1637           0 : HTMLEditor::SelectTableColumn()
    1638             : {
    1639           0 :   nsCOMPtr<nsIDOMElement> cell;
    1640           0 :   nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
    1641           0 :                                             getter_AddRefs(cell));
    1642           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1643             : 
    1644             :   // Don't fail if we didn't find a cell
    1645           0 :   NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
    1646             : 
    1647           0 :   nsCOMPtr<nsIDOMElement> startCell = cell;
    1648             : 
    1649             :   // Get location of cell:
    1650           0 :   RefPtr<Selection> selection;
    1651           0 :   nsCOMPtr<nsIDOMElement> table;
    1652             :   int32_t startRowIndex, startColIndex;
    1653             : 
    1654           0 :   rv = GetCellContext(getter_AddRefs(selection),
    1655           0 :                       getter_AddRefs(table),
    1656           0 :                       getter_AddRefs(cell),
    1657             :                       nullptr, nullptr,
    1658           0 :                       &startRowIndex, &startColIndex);
    1659           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1660           0 :   NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
    1661             : 
    1662             :   int32_t rowCount, colCount;
    1663           0 :   rv = GetTableSize(table, &rowCount, &colCount);
    1664           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1665             : 
    1666             :   // Suppress nsISelectionListener notification
    1667             :   //  until all selection changes are finished
    1668           0 :   SelectionBatcher selectionBatcher(selection);
    1669             : 
    1670             :   // It is now safe to clear the selection
    1671             :   // BE SURE TO RESET IT BEFORE LEAVING!
    1672           0 :   rv = ClearSelection();
    1673             : 
    1674             :   // Select all cells in the same column as current cell
    1675           0 :   bool cellSelected = false;
    1676             :   int32_t rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
    1677             :   bool    isSelected;
    1678           0 :   for (int32_t row = 0; row < rowCount; row += std::max(actualRowSpan, 1)) {
    1679           0 :     rv = GetCellDataAt(table, row, startColIndex, getter_AddRefs(cell),
    1680             :                        &currentRowIndex, &currentColIndex, &rowSpan, &colSpan,
    1681           0 :                        &actualRowSpan, &actualColSpan, &isSelected);
    1682           0 :     if (NS_FAILED(rv)) {
    1683           0 :       break;
    1684             :     }
    1685             :     // Skip cells that are spanned from previous rows or columns
    1686           0 :     if (cell && currentRowIndex == row && currentColIndex == startColIndex) {
    1687           0 :       rv = AppendNodeToSelectionAsRange(cell);
    1688           0 :       if (NS_FAILED(rv)) {
    1689           0 :         break;
    1690             :       }
    1691           0 :       cellSelected = true;
    1692             :     }
    1693             :   }
    1694             :   // Safety code to select starting cell if nothing else was selected
    1695           0 :   if (!cellSelected) {
    1696           0 :     return AppendNodeToSelectionAsRange(startCell);
    1697             :   }
    1698             :   // NS_OK, otherwise, the error of ClearSelection() when there is no row or
    1699             :   // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
    1700           0 :   return rv;
    1701             : }
    1702             : 
    1703             : NS_IMETHODIMP
    1704           0 : HTMLEditor::SplitTableCell()
    1705             : {
    1706           0 :   nsCOMPtr<nsIDOMElement> table;
    1707           0 :   nsCOMPtr<nsIDOMElement> cell;
    1708             :   int32_t startRowIndex, startColIndex, actualRowSpan, actualColSpan;
    1709             :   // Get cell, table, etc. at selection anchor node
    1710           0 :   nsresult rv = GetCellContext(nullptr,
    1711           0 :                                getter_AddRefs(table),
    1712           0 :                                getter_AddRefs(cell),
    1713             :                                nullptr, nullptr,
    1714           0 :                                &startRowIndex, &startColIndex);
    1715           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1716           0 :   if (!table || !cell) {
    1717           0 :     return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
    1718             :   }
    1719             : 
    1720             :   // We need rowspan and colspan data
    1721           0 :   rv = GetCellSpansAt(table, startRowIndex, startColIndex,
    1722           0 :                       actualRowSpan, actualColSpan);
    1723           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1724             : 
    1725             :   // Must have some span to split
    1726           0 :   if (actualRowSpan <= 1 && actualColSpan <= 1) {
    1727           0 :     return NS_OK;
    1728             :   }
    1729             : 
    1730           0 :   AutoEditBatch beginBatching(this);
    1731             :   // Prevent auto insertion of BR in new cell until we're done
    1732           0 :   AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
    1733             : 
    1734             :   // We reset selection
    1735             :   AutoSelectionSetterAfterTableEdit setCaret(this, table, startRowIndex,
    1736             :                                              startColIndex, ePreviousColumn,
    1737           0 :                                              false);
    1738             :   //...so suppress Rules System selection munging
    1739           0 :   AutoTransactionsConserveSelection dontChangeSelection(this);
    1740             : 
    1741           0 :   nsCOMPtr<nsIDOMElement> newCell;
    1742           0 :   int32_t rowIndex = startRowIndex;
    1743             :   int32_t rowSpanBelow, colSpanAfter;
    1744             : 
    1745             :   // Split up cell row-wise first into rowspan=1 above, and the rest below,
    1746             :   //  whittling away at the cell below until no more extra span
    1747           0 :   for (rowSpanBelow = actualRowSpan-1; rowSpanBelow >= 0; rowSpanBelow--) {
    1748             :     // We really split row-wise only if we had rowspan > 1
    1749           0 :     if (rowSpanBelow > 0) {
    1750           0 :       rv = SplitCellIntoRows(table, rowIndex, startColIndex, 1, rowSpanBelow,
    1751           0 :                              getter_AddRefs(newCell));
    1752           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1753           0 :       CopyCellBackgroundColor(newCell, cell);
    1754             :     }
    1755           0 :     int32_t colIndex = startColIndex;
    1756             :     // Now split the cell with rowspan = 1 into cells if it has colSpan > 1
    1757           0 :     for (colSpanAfter = actualColSpan-1; colSpanAfter > 0; colSpanAfter--) {
    1758           0 :       rv = SplitCellIntoColumns(table, rowIndex, colIndex, 1, colSpanAfter,
    1759           0 :                                 getter_AddRefs(newCell));
    1760           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1761           0 :       CopyCellBackgroundColor(newCell, cell);
    1762           0 :       colIndex++;
    1763             :     }
    1764             :     // Point to the new cell and repeat
    1765           0 :     rowIndex++;
    1766             :   }
    1767           0 :   return NS_OK;
    1768             : }
    1769             : 
    1770             : nsresult
    1771           0 : HTMLEditor::CopyCellBackgroundColor(nsIDOMElement* destCell,
    1772             :                                     nsIDOMElement* sourceCell)
    1773             : {
    1774           0 :   NS_ENSURE_TRUE(destCell && sourceCell, NS_ERROR_NULL_POINTER);
    1775             : 
    1776             :   // Copy backgournd color to new cell
    1777           0 :   NS_NAMED_LITERAL_STRING(bgcolor, "bgcolor");
    1778           0 :   nsAutoString color;
    1779             :   bool isSet;
    1780           0 :   nsresult rv = GetAttributeValue(sourceCell, bgcolor, color, &isSet);
    1781           0 :   if (NS_FAILED(rv)) {
    1782           0 :     return rv;
    1783             :   }
    1784           0 :   if (!isSet) {
    1785           0 :     return NS_OK;
    1786             :   }
    1787           0 :   return SetAttribute(destCell, bgcolor, color);
    1788             : }
    1789             : 
    1790             : NS_IMETHODIMP
    1791           0 : HTMLEditor::SplitCellIntoColumns(nsIDOMElement* aTable,
    1792             :                                  int32_t aRowIndex,
    1793             :                                  int32_t aColIndex,
    1794             :                                  int32_t aColSpanLeft,
    1795             :                                  int32_t aColSpanRight,
    1796             :                                  nsIDOMElement** aNewCell)
    1797             : {
    1798           0 :   NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
    1799           0 :   if (aNewCell) {
    1800           0 :     *aNewCell = nullptr;
    1801             :   }
    1802             : 
    1803           0 :   nsCOMPtr<nsIDOMElement> cell;
    1804             :   int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    1805             :   bool    isSelected;
    1806             :   nsresult rv =
    1807           0 :     GetCellDataAt(aTable, aRowIndex, aColIndex, getter_AddRefs(cell),
    1808             :                   &startRowIndex, &startColIndex,
    1809             :                   &rowSpan, &colSpan,
    1810           0 :                   &actualRowSpan, &actualColSpan, &isSelected);
    1811           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1812           0 :   NS_ENSURE_TRUE(cell, NS_ERROR_NULL_POINTER);
    1813             : 
    1814             :   // We can't split!
    1815           0 :   if (actualColSpan <= 1 || (aColSpanLeft + aColSpanRight) > actualColSpan) {
    1816           0 :     return NS_OK;
    1817             :   }
    1818             : 
    1819             :   // Reduce colspan of cell to split
    1820           0 :   rv = SetColSpan(cell, aColSpanLeft);
    1821           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1822             : 
    1823             :   // Insert new cell after using the remaining span
    1824             :   //  and always get the new cell so we can copy the background color;
    1825           0 :   nsCOMPtr<nsIDOMElement> newCell;
    1826           0 :   rv = InsertCell(cell, actualRowSpan, aColSpanRight, true, false,
    1827           0 :                   getter_AddRefs(newCell));
    1828           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1829           0 :   if (!newCell) {
    1830           0 :     return NS_OK;
    1831             :   }
    1832           0 :   if (aNewCell) {
    1833           0 :     NS_ADDREF(*aNewCell = newCell.get());
    1834             :   }
    1835           0 :   return CopyCellBackgroundColor(newCell, cell);
    1836             : }
    1837             : 
    1838             : NS_IMETHODIMP
    1839           0 : HTMLEditor::SplitCellIntoRows(nsIDOMElement* aTable,
    1840             :                               int32_t aRowIndex,
    1841             :                               int32_t aColIndex,
    1842             :                               int32_t aRowSpanAbove,
    1843             :                               int32_t aRowSpanBelow,
    1844             :                               nsIDOMElement** aNewCell)
    1845             : {
    1846           0 :   NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
    1847           0 :   if (aNewCell) *aNewCell = nullptr;
    1848             : 
    1849           0 :   nsCOMPtr<nsIDOMElement> cell;
    1850             :   int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    1851             :   bool    isSelected;
    1852             :   nsresult rv =
    1853           0 :     GetCellDataAt(aTable, aRowIndex, aColIndex, getter_AddRefs(cell),
    1854             :                   &startRowIndex, &startColIndex,
    1855             :                   &rowSpan, &colSpan,
    1856           0 :                   &actualRowSpan, &actualColSpan, &isSelected);
    1857           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1858           0 :   NS_ENSURE_TRUE(cell, NS_ERROR_NULL_POINTER);
    1859             : 
    1860             :   // We can't split!
    1861           0 :   if (actualRowSpan <= 1 || (aRowSpanAbove + aRowSpanBelow) > actualRowSpan) {
    1862           0 :     return NS_OK;
    1863             :   }
    1864             : 
    1865             :   int32_t rowCount, colCount;
    1866           0 :   rv = GetTableSize(aTable, &rowCount, &colCount);
    1867           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1868             : 
    1869           0 :   nsCOMPtr<nsIDOMElement> cell2;
    1870           0 :   nsCOMPtr<nsIDOMElement> lastCellFound;
    1871             :   int32_t startRowIndex2, startColIndex2, rowSpan2, colSpan2, actualRowSpan2, actualColSpan2;
    1872             :   bool    isSelected2;
    1873           0 :   int32_t colIndex = 0;
    1874           0 :   bool insertAfter = (startColIndex > 0);
    1875             :   // This is the row we will insert new cell into
    1876           0 :   int32_t rowBelowIndex = startRowIndex+aRowSpanAbove;
    1877             : 
    1878             :   // Find a cell to insert before or after
    1879             :   for (;;) {
    1880             :     // Search for a cell to insert before
    1881           0 :     rv = GetCellDataAt(aTable, rowBelowIndex,
    1882           0 :                        colIndex, getter_AddRefs(cell2),
    1883             :                        &startRowIndex2, &startColIndex2, &rowSpan2, &colSpan2,
    1884           0 :                        &actualRowSpan2, &actualColSpan2, &isSelected2);
    1885             :     // If we fail here, it could be because row has bad rowspan values,
    1886             :     //   such as all cells having rowspan > 1 (Call FixRowSpan first!)
    1887           0 :     if (NS_FAILED(rv) || !cell) {
    1888           0 :       return NS_ERROR_FAILURE;
    1889             :     }
    1890             : 
    1891             :     // Skip over cells spanned from above (like the one we are splitting!)
    1892           0 :     if (cell2 && startRowIndex2 == rowBelowIndex) {
    1893           0 :       if (!insertAfter) {
    1894             :         // Inserting before, so stop at first cell in row we want to insert
    1895             :         // into.
    1896           0 :         break;
    1897             :       }
    1898             :       // New cell isn't first in row,
    1899             :       // so stop after we find the cell just before new cell's column
    1900           0 :       if (startColIndex2 + actualColSpan2 == startColIndex) {
    1901           0 :         break;
    1902             :       }
    1903             :       // If cell found is AFTER desired new cell colum,
    1904             :       //  we have multiple cells with rowspan > 1 that
    1905             :       //  prevented us from finding a cell to insert after...
    1906           0 :       if (startColIndex2 > startColIndex) {
    1907             :         // ... so instead insert before the cell we found
    1908           0 :         insertAfter = false;
    1909           0 :         break;
    1910             :       }
    1911           0 :       lastCellFound = cell2;
    1912             :     }
    1913             :     // Skip to next available cellmap location
    1914           0 :     colIndex += std::max(actualColSpan2, 1);
    1915             : 
    1916             :     // Done when past end of total number of columns
    1917           0 :     if (colIndex > colCount) {
    1918           0 :       break;
    1919             :     }
    1920             :   }
    1921             : 
    1922           0 :   if (!cell2 && lastCellFound) {
    1923             :     // Edge case where we didn't find a cell to insert after
    1924             :     //  or before because column(s) before desired column
    1925             :     //  and all columns after it are spanned from above.
    1926             :     //  We can insert after the last cell we found
    1927           0 :     cell2 = lastCellFound;
    1928           0 :     insertAfter = true; // Should always be true, but let's be sure
    1929             :   }
    1930             : 
    1931             :   // Reduce rowspan of cell to split
    1932           0 :   rv = SetRowSpan(cell, aRowSpanAbove);
    1933           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1934             : 
    1935             : 
    1936             :   // Insert new cell after using the remaining span
    1937             :   //  and always get the new cell so we can copy the background color;
    1938           0 :   nsCOMPtr<nsIDOMElement> newCell;
    1939           0 :   rv = InsertCell(cell2, aRowSpanBelow, actualColSpan, insertAfter, false,
    1940           0 :                   getter_AddRefs(newCell));
    1941           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1942           0 :   if (!newCell) {
    1943           0 :     return NS_OK;
    1944             :   }
    1945           0 :   if (aNewCell) {
    1946           0 :     NS_ADDREF(*aNewCell = newCell.get());
    1947             :   }
    1948           0 :   return CopyCellBackgroundColor(newCell, cell2);
    1949             : }
    1950             : 
    1951             : NS_IMETHODIMP
    1952           0 : HTMLEditor::SwitchTableCellHeaderType(nsIDOMElement* aSourceCell,
    1953             :                                       nsIDOMElement** aNewCell)
    1954             : {
    1955           0 :   nsCOMPtr<Element> sourceCell = do_QueryInterface(aSourceCell);
    1956           0 :   NS_ENSURE_TRUE(sourceCell, NS_ERROR_NULL_POINTER);
    1957             : 
    1958           0 :   AutoEditBatch beginBatching(this);
    1959             :   // Prevent auto insertion of BR in new cell created by ReplaceContainer
    1960           0 :   AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
    1961             : 
    1962             :   // Save current selection to restore when done
    1963             :   // This is needed so ReplaceContainer can monitor selection
    1964             :   //  when replacing nodes
    1965           0 :   RefPtr<Selection> selection = GetSelection();
    1966           0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    1967           0 :   AutoSelectionRestorer selectionRestorer(selection, this);
    1968             : 
    1969             :   // Set to the opposite of current type
    1970           0 :   nsCOMPtr<nsIAtom> atom = EditorBase::GetTag(aSourceCell);
    1971           0 :   nsIAtom* newCellType = atom == nsGkAtoms::td ? nsGkAtoms::th : nsGkAtoms::td;
    1972             : 
    1973             :   // This creates new node, moves children, copies attributes (true)
    1974             :   //   and manages the selection!
    1975           0 :   nsCOMPtr<Element> newNode = ReplaceContainer(sourceCell, newCellType,
    1976           0 :       nullptr, nullptr, EditorBase::eCloneAttributes);
    1977           0 :   NS_ENSURE_TRUE(newNode, NS_ERROR_FAILURE);
    1978             : 
    1979             :   // Return the new cell
    1980           0 :   if (aNewCell) {
    1981           0 :     nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newNode);
    1982           0 :     *aNewCell = newElement.get();
    1983           0 :     NS_ADDREF(*aNewCell);
    1984             :   }
    1985             : 
    1986           0 :   return NS_OK;
    1987             : }
    1988             : 
    1989             : NS_IMETHODIMP
    1990           0 : HTMLEditor::JoinTableCells(bool aMergeNonContiguousContents)
    1991             : {
    1992           0 :   nsCOMPtr<nsIDOMElement> table;
    1993           0 :   nsCOMPtr<nsIDOMElement> targetCell;
    1994             :   int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    1995             :   bool    isSelected;
    1996           0 :   nsCOMPtr<nsIDOMElement> cell2;
    1997             :   int32_t startRowIndex2, startColIndex2, rowSpan2, colSpan2, actualRowSpan2, actualColSpan2;
    1998             :   bool    isSelected2;
    1999             : 
    2000             :   // Get cell, table, etc. at selection anchor node
    2001           0 :   nsresult rv = GetCellContext(nullptr,
    2002           0 :                                getter_AddRefs(table),
    2003           0 :                                getter_AddRefs(targetCell),
    2004             :                                nullptr, nullptr,
    2005           0 :                                &startRowIndex, &startColIndex);
    2006           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2007           0 :   if (!table || !targetCell) {
    2008           0 :     return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
    2009             :   }
    2010             : 
    2011           0 :   AutoEditBatch beginBatching(this);
    2012             :   //Don't let Rules System change the selection
    2013           0 :   AutoTransactionsConserveSelection dontChangeSelection(this);
    2014             : 
    2015             :   // Note: We dont' use AutoSelectionSetterAfterTableEdit here so the selection
    2016             :   //  is retained after joining. This leaves the target cell selected
    2017             :   //  as well as the "non-contiguous" cells, so user can see what happened.
    2018             : 
    2019           0 :   nsCOMPtr<nsIDOMElement> firstCell;
    2020             :   int32_t firstRowIndex, firstColIndex;
    2021           0 :   rv = GetFirstSelectedCellInTable(&firstRowIndex, &firstColIndex,
    2022           0 :                                    getter_AddRefs(firstCell));
    2023           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2024             : 
    2025           0 :   bool joinSelectedCells = false;
    2026           0 :   if (firstCell) {
    2027           0 :     nsCOMPtr<nsIDOMElement> secondCell;
    2028           0 :     rv = GetNextSelectedCell(nullptr, getter_AddRefs(secondCell));
    2029           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2030             : 
    2031             :     // If only one cell is selected, join with cell to the right
    2032           0 :     joinSelectedCells = (secondCell != nullptr);
    2033             :   }
    2034             : 
    2035           0 :   if (joinSelectedCells) {
    2036             :     // We have selected cells: Join just contiguous cells
    2037             :     //  and just merge contents if not contiguous
    2038             : 
    2039             :     int32_t rowCount, colCount;
    2040           0 :     rv = GetTableSize(table, &rowCount, &colCount);
    2041           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2042             : 
    2043             :     // Get spans for cell we will merge into
    2044             :     int32_t firstRowSpan, firstColSpan;
    2045           0 :     rv = GetCellSpansAt(table, firstRowIndex, firstColIndex,
    2046           0 :                         firstRowSpan, firstColSpan);
    2047           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2048             : 
    2049             :     // This defines the last indexes along the "edges"
    2050             :     //  of the contiguous block of cells, telling us
    2051             :     //  that we can join adjacent cells to the block
    2052             :     // Start with same as the first values,
    2053             :     //  then expand as we find adjacent selected cells
    2054           0 :     int32_t lastRowIndex = firstRowIndex;
    2055           0 :     int32_t lastColIndex = firstColIndex;
    2056             :     int32_t rowIndex, colIndex;
    2057             : 
    2058             :     // First pass: Determine boundaries of contiguous rectangular block
    2059             :     //  that we will join into one cell,
    2060             :     //  favoring adjacent cells in the same row
    2061           0 :     for (rowIndex = firstRowIndex; rowIndex <= lastRowIndex; rowIndex++) {
    2062           0 :       int32_t currentRowCount = rowCount;
    2063             :       // Be sure each row doesn't have rowspan errors
    2064           0 :       rv = FixBadRowSpan(table, rowIndex, rowCount);
    2065           0 :       NS_ENSURE_SUCCESS(rv, rv);
    2066             :       // Adjust rowcount by number of rows we removed
    2067           0 :       lastRowIndex -= (currentRowCount-rowCount);
    2068             : 
    2069           0 :       bool cellFoundInRow = false;
    2070           0 :       bool lastRowIsSet = false;
    2071           0 :       int32_t lastColInRow = 0;
    2072           0 :       int32_t firstColInRow = firstColIndex;
    2073           0 :       for (colIndex = firstColIndex; colIndex < colCount;
    2074           0 :            colIndex += std::max(actualColSpan2, 1)) {
    2075           0 :         rv = GetCellDataAt(table, rowIndex, colIndex, getter_AddRefs(cell2),
    2076             :                            &startRowIndex2, &startColIndex2,
    2077             :                            &rowSpan2, &colSpan2,
    2078           0 :                            &actualRowSpan2, &actualColSpan2, &isSelected2);
    2079           0 :         NS_ENSURE_SUCCESS(rv, rv);
    2080             : 
    2081           0 :         if (isSelected2) {
    2082           0 :           if (!cellFoundInRow) {
    2083             :             // We've just found the first selected cell in this row
    2084           0 :             firstColInRow = colIndex;
    2085             :           }
    2086           0 :           if (rowIndex > firstRowIndex && firstColInRow != firstColIndex) {
    2087             :             // We're in at least the second row,
    2088             :             // but left boundary is "ragged" (not the same as 1st row's start)
    2089             :             //Let's just end block on previous row
    2090             :             // and keep previous lastColIndex
    2091             :             //TODO: We could try to find the Maximum firstColInRow
    2092             :             //      so our block can still extend down more rows?
    2093           0 :             lastRowIndex = std::max(0,rowIndex - 1);
    2094           0 :             lastRowIsSet = true;
    2095           0 :             break;
    2096             :           }
    2097             :           // Save max selected column in this row, including extra colspan
    2098           0 :           lastColInRow = colIndex + (actualColSpan2-1);
    2099           0 :           cellFoundInRow = true;
    2100           0 :         } else if (cellFoundInRow) {
    2101             :           // No cell or not selected, but at least one cell in row was found
    2102           0 :           if (rowIndex > (firstRowIndex + 1) && colIndex <= lastColIndex) {
    2103             :             // Cell is in a column less than current right border in
    2104             :             //  the third or higher selected row, so stop block at the previous row
    2105           0 :             lastRowIndex = std::max(0,rowIndex - 1);
    2106           0 :             lastRowIsSet = true;
    2107             :           }
    2108             :           // We're done with this row
    2109           0 :           break;
    2110             :         }
    2111             :       } // End of column loop
    2112             : 
    2113             :       // Done with this row
    2114           0 :       if (cellFoundInRow) {
    2115           0 :         if (rowIndex == firstRowIndex) {
    2116             :           // First row always initializes the right boundary
    2117           0 :           lastColIndex = lastColInRow;
    2118             :         }
    2119             : 
    2120             :         // If we didn't determine last row above...
    2121           0 :         if (!lastRowIsSet) {
    2122           0 :           if (colIndex < lastColIndex) {
    2123             :             // (don't think we ever get here?)
    2124             :             // Cell is in a column less than current right boundary,
    2125             :             //  so stop block at the previous row
    2126           0 :             lastRowIndex = std::max(0,rowIndex - 1);
    2127             :           } else {
    2128             :             // Go on to examine next row
    2129           0 :             lastRowIndex = rowIndex+1;
    2130             :           }
    2131             :         }
    2132             :         // Use the minimum col we found so far for right boundary
    2133           0 :         lastColIndex = std::min(lastColIndex, lastColInRow);
    2134             :       } else {
    2135             :         // No selected cells in this row -- stop at row above
    2136             :         //  and leave last column at its previous value
    2137           0 :         lastRowIndex = std::max(0,rowIndex - 1);
    2138             :       }
    2139             :     }
    2140             : 
    2141             :     // The list of cells we will delete after joining
    2142           0 :     nsTArray<nsCOMPtr<nsIDOMElement> > deleteList;
    2143             : 
    2144             :     // 2nd pass: Do the joining and merging
    2145           0 :     for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
    2146           0 :       for (colIndex = 0; colIndex < colCount;
    2147           0 :            colIndex += std::max(actualColSpan2, 1)) {
    2148           0 :         rv = GetCellDataAt(table, rowIndex, colIndex, getter_AddRefs(cell2),
    2149             :                            &startRowIndex2, &startColIndex2,
    2150             :                            &rowSpan2, &colSpan2,
    2151           0 :                            &actualRowSpan2, &actualColSpan2, &isSelected2);
    2152           0 :         NS_ENSURE_SUCCESS(rv, rv);
    2153             : 
    2154             :         // If this is 0, we are past last cell in row, so exit the loop
    2155           0 :         if (!actualColSpan2) {
    2156           0 :           break;
    2157             :         }
    2158             : 
    2159             :         // Merge only selected cells (skip cell we're merging into, of course)
    2160           0 :         if (isSelected2 && cell2 != firstCell) {
    2161           0 :           if (rowIndex >= firstRowIndex && rowIndex <= lastRowIndex &&
    2162           0 :               colIndex >= firstColIndex && colIndex <= lastColIndex) {
    2163             :             // We are within the join region
    2164             :             // Problem: It is very tricky to delete cells as we merge,
    2165             :             //  since that will upset the cellmap
    2166             :             //  Instead, build a list of cells to delete and do it later
    2167           0 :             NS_ASSERTION(startRowIndex2 == rowIndex, "JoinTableCells: StartRowIndex is in row above");
    2168             : 
    2169           0 :             if (actualColSpan2 > 1) {
    2170             :               //Check if cell "hangs" off the boundary because of colspan > 1
    2171             :               //  Use split methods to chop off excess
    2172           0 :               int32_t extraColSpan = (startColIndex2 + actualColSpan2) - (lastColIndex+1);
    2173           0 :               if ( extraColSpan > 0) {
    2174           0 :                 rv = SplitCellIntoColumns(table, startRowIndex2, startColIndex2,
    2175             :                                           actualColSpan2 - extraColSpan,
    2176           0 :                                           extraColSpan, nullptr);
    2177           0 :                 NS_ENSURE_SUCCESS(rv, rv);
    2178             :               }
    2179             :             }
    2180             : 
    2181           0 :             rv = MergeCells(firstCell, cell2, false);
    2182           0 :             NS_ENSURE_SUCCESS(rv, rv);
    2183             : 
    2184             :             // Add cell to list to delete
    2185           0 :             deleteList.AppendElement(cell2.get());
    2186           0 :           } else if (aMergeNonContiguousContents) {
    2187             :             // Cell is outside join region -- just merge the contents
    2188           0 :             rv = MergeCells(firstCell, cell2, false);
    2189           0 :             NS_ENSURE_SUCCESS(rv, rv);
    2190             :           }
    2191             :         }
    2192             :       }
    2193             :     }
    2194             : 
    2195             :     // All cell contents are merged. Delete the empty cells we accumulated
    2196             :     // Prevent rules testing until we're done
    2197             :     AutoRules beginRulesSniffing(this, EditAction::deleteNode,
    2198           0 :                                  nsIEditor::eNext);
    2199             : 
    2200           0 :     for (uint32_t i = 0, n = deleteList.Length(); i < n; i++) {
    2201           0 :       nsIDOMElement *elementPtr = deleteList[i];
    2202           0 :       if (elementPtr) {
    2203           0 :         nsCOMPtr<nsIDOMNode> node = do_QueryInterface(elementPtr);
    2204           0 :         rv = DeleteNode(node);
    2205           0 :         NS_ENSURE_SUCCESS(rv, rv);
    2206             :       }
    2207             :     }
    2208             :     // Cleanup selection: remove ranges where cells were deleted
    2209           0 :     RefPtr<Selection> selection = GetSelection();
    2210           0 :     NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    2211             : 
    2212             :     int32_t rangeCount;
    2213           0 :     rv = selection->GetRangeCount(&rangeCount);
    2214           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2215             : 
    2216           0 :     RefPtr<nsRange> range;
    2217           0 :     for (int32_t i = 0; i < rangeCount; i++) {
    2218           0 :       range = selection->GetRangeAt(i);
    2219           0 :       NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
    2220             : 
    2221           0 :       nsCOMPtr<nsIDOMElement> deletedCell;
    2222           0 :       GetCellFromRange(range, getter_AddRefs(deletedCell));
    2223           0 :       if (!deletedCell) {
    2224           0 :         selection->RemoveRange(range);
    2225           0 :         rangeCount--;
    2226           0 :         i--;
    2227             :       }
    2228             :     }
    2229             : 
    2230             :     // Set spans for the cell everthing merged into
    2231           0 :     rv = SetRowSpan(firstCell, lastRowIndex-firstRowIndex+1);
    2232           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2233           0 :     rv = SetColSpan(firstCell, lastColIndex-firstColIndex+1);
    2234           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2235             : 
    2236             : 
    2237             :     // Fixup disturbances in table layout
    2238           0 :     NormalizeTable(table);
    2239             :   } else {
    2240             :     // Joining with cell to the right -- get rowspan and colspan data of target cell
    2241           0 :     rv = GetCellDataAt(table, startRowIndex, startColIndex,
    2242           0 :                        getter_AddRefs(targetCell),
    2243             :                        &startRowIndex, &startColIndex, &rowSpan, &colSpan,
    2244           0 :                        &actualRowSpan, &actualColSpan, &isSelected);
    2245           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2246           0 :     NS_ENSURE_TRUE(targetCell, NS_ERROR_NULL_POINTER);
    2247             : 
    2248             :     // Get data for cell to the right
    2249           0 :     rv = GetCellDataAt(table, startRowIndex, startColIndex + actualColSpan,
    2250           0 :                        getter_AddRefs(cell2),
    2251             :                        &startRowIndex2, &startColIndex2, &rowSpan2, &colSpan2,
    2252           0 :                        &actualRowSpan2, &actualColSpan2, &isSelected2);
    2253           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2254           0 :     if (!cell2) {
    2255           0 :       return NS_OK; // Don't fail if there's no cell
    2256             :     }
    2257             : 
    2258             :     // sanity check
    2259           0 :     NS_ASSERTION((startRowIndex >= startRowIndex2),"JoinCells: startRowIndex < startRowIndex2");
    2260             : 
    2261             :     // Figure out span of merged cell starting from target's starting row
    2262             :     // to handle case of merged cell starting in a row above
    2263           0 :     int32_t spanAboveMergedCell = startRowIndex - startRowIndex2;
    2264           0 :     int32_t effectiveRowSpan2 = actualRowSpan2 - spanAboveMergedCell;
    2265             : 
    2266           0 :     if (effectiveRowSpan2 > actualRowSpan) {
    2267             :       // Cell to the right spans into row below target
    2268             :       // Split off portion below target cell's bottom-most row
    2269           0 :       rv = SplitCellIntoRows(table, startRowIndex2, startColIndex2,
    2270             :                              spanAboveMergedCell+actualRowSpan,
    2271           0 :                              effectiveRowSpan2-actualRowSpan, nullptr);
    2272           0 :       NS_ENSURE_SUCCESS(rv, rv);
    2273             :     }
    2274             : 
    2275             :     // Move contents from cell to the right
    2276             :     // Delete the cell now only if it starts in the same row
    2277             :     //   and has enough row "height"
    2278           0 :     rv = MergeCells(targetCell, cell2,
    2279           0 :                     (startRowIndex2 == startRowIndex) &&
    2280           0 :                     (effectiveRowSpan2 >= actualRowSpan));
    2281           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2282             : 
    2283           0 :     if (effectiveRowSpan2 < actualRowSpan) {
    2284             :       // Merged cell is "shorter"
    2285             :       // (there are cells(s) below it that are row-spanned by target cell)
    2286             :       // We could try splitting those cells, but that's REAL messy,
    2287             :       //  so the safest thing to do is NOT really join the cells
    2288           0 :       return NS_OK;
    2289             :     }
    2290             : 
    2291           0 :     if (spanAboveMergedCell > 0) {
    2292             :       // Cell we merged started in a row above the target cell
    2293             :       // Reduce rowspan to give room where target cell will extend its colspan
    2294           0 :       rv = SetRowSpan(cell2, spanAboveMergedCell);
    2295           0 :       NS_ENSURE_SUCCESS(rv, rv);
    2296             :     }
    2297             : 
    2298             :     // Reset target cell's colspan to encompass cell to the right
    2299           0 :     rv = SetColSpan(targetCell, actualColSpan+actualColSpan2);
    2300           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2301             :   }
    2302           0 :   return NS_OK;
    2303             : }
    2304             : 
    2305             : NS_IMETHODIMP
    2306           0 : HTMLEditor::MergeCells(nsCOMPtr<nsIDOMElement> aTargetCell,
    2307             :                        nsCOMPtr<nsIDOMElement> aCellToMerge,
    2308             :                        bool aDeleteCellToMerge)
    2309             : {
    2310           0 :   nsCOMPtr<dom::Element> targetCell = do_QueryInterface(aTargetCell);
    2311           0 :   nsCOMPtr<dom::Element> cellToMerge = do_QueryInterface(aCellToMerge);
    2312           0 :   NS_ENSURE_TRUE(targetCell && cellToMerge, NS_ERROR_NULL_POINTER);
    2313             : 
    2314             :   // Prevent rules testing until we're done
    2315           0 :   AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
    2316             : 
    2317             :   // Don't need to merge if cell is empty
    2318           0 :   if (!IsEmptyCell(cellToMerge)) {
    2319             :     // Get index of last child in target cell
    2320             :     // If we fail or don't have children,
    2321             :     //  we insert at index 0
    2322           0 :     int32_t insertIndex = 0;
    2323             : 
    2324             :     // Start inserting just after last child
    2325           0 :     uint32_t len = targetCell->GetChildCount();
    2326           0 :     if (len == 1 && IsEmptyCell(targetCell)) {
    2327             :       // Delete the empty node
    2328           0 :       nsIContent* cellChild = targetCell->GetFirstChild();
    2329           0 :       nsresult rv = DeleteNode(cellChild->AsDOMNode());
    2330           0 :       NS_ENSURE_SUCCESS(rv, rv);
    2331           0 :       insertIndex = 0;
    2332             :     } else {
    2333           0 :       insertIndex = (int32_t)len;
    2334             :     }
    2335             : 
    2336             :     // Move the contents
    2337           0 :     while (cellToMerge->HasChildren()) {
    2338           0 :       nsCOMPtr<nsIDOMNode> cellChild = cellToMerge->GetLastChild()->AsDOMNode();
    2339           0 :       nsresult rv = DeleteNode(cellChild);
    2340           0 :       NS_ENSURE_SUCCESS(rv, rv);
    2341             : 
    2342           0 :       rv = InsertNode(cellChild, aTargetCell, insertIndex);
    2343           0 :       NS_ENSURE_SUCCESS(rv, rv);
    2344             :     }
    2345             :   }
    2346             : 
    2347             :   // Delete cells whose contents were moved
    2348           0 :   if (aDeleteCellToMerge) {
    2349           0 :     return DeleteNode(aCellToMerge);
    2350             :   }
    2351             : 
    2352           0 :   return NS_OK;
    2353             : }
    2354             : 
    2355             : 
    2356             : NS_IMETHODIMP
    2357           0 : HTMLEditor::FixBadRowSpan(nsIDOMElement* aTable,
    2358             :                           int32_t aRowIndex,
    2359             :                           int32_t& aNewRowCount)
    2360             : {
    2361           0 :   NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
    2362             : 
    2363             :   int32_t rowCount, colCount;
    2364           0 :   nsresult rv = GetTableSize(aTable, &rowCount, &colCount);
    2365           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2366             : 
    2367           0 :   nsCOMPtr<nsIDOMElement>cell;
    2368             :   int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    2369             :   bool    isSelected;
    2370             : 
    2371           0 :   int32_t minRowSpan = -1;
    2372             :   int32_t colIndex;
    2373             : 
    2374           0 :   for (colIndex = 0; colIndex < colCount;
    2375           0 :        colIndex += std::max(actualColSpan, 1)) {
    2376           0 :     rv = GetCellDataAt(aTable, aRowIndex, colIndex, getter_AddRefs(cell),
    2377             :                        &startRowIndex, &startColIndex, &rowSpan, &colSpan,
    2378           0 :                        &actualRowSpan, &actualColSpan, &isSelected);
    2379             :     // NOTE: This is a *real* failure.
    2380             :     // GetCellDataAt passes if cell is missing from cellmap
    2381           0 :     if (NS_FAILED(rv)) {
    2382           0 :       return rv;
    2383             :     }
    2384           0 :     if (!cell) {
    2385           0 :       break;
    2386             :     }
    2387           0 :     if (rowSpan > 0 &&
    2388           0 :         startRowIndex == aRowIndex &&
    2389           0 :         (rowSpan < minRowSpan || minRowSpan == -1)) {
    2390           0 :       minRowSpan = rowSpan;
    2391             :     }
    2392           0 :     NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in FixBadRowSpan");
    2393             :   }
    2394           0 :   if (minRowSpan > 1) {
    2395             :     // The amount to reduce everyone's rowspan
    2396             :     // so at least one cell has rowspan = 1
    2397           0 :     int32_t rowsReduced = minRowSpan - 1;
    2398           0 :     for (colIndex = 0; colIndex < colCount;
    2399           0 :          colIndex += std::max(actualColSpan, 1)) {
    2400           0 :       rv = GetCellDataAt(aTable, aRowIndex, colIndex, getter_AddRefs(cell),
    2401             :                          &startRowIndex, &startColIndex, &rowSpan, &colSpan,
    2402           0 :                          &actualRowSpan, &actualColSpan, &isSelected);
    2403           0 :       if (NS_FAILED(rv)) {
    2404           0 :         return rv;
    2405             :       }
    2406             :       // Fixup rowspans only for cells starting in current row
    2407           0 :       if (cell && rowSpan > 0 &&
    2408           0 :           startRowIndex == aRowIndex &&
    2409           0 :           startColIndex ==  colIndex ) {
    2410           0 :         rv = SetRowSpan(cell, rowSpan-rowsReduced);
    2411           0 :         if (NS_FAILED(rv)) {
    2412           0 :           return rv;
    2413             :         }
    2414             :       }
    2415           0 :       NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in FixBadRowSpan");
    2416             :     }
    2417             :   }
    2418           0 :   return GetTableSize(aTable, &aNewRowCount, &colCount);
    2419             : }
    2420             : 
    2421             : NS_IMETHODIMP
    2422           0 : HTMLEditor::FixBadColSpan(nsIDOMElement* aTable,
    2423             :                           int32_t aColIndex,
    2424             :                           int32_t& aNewColCount)
    2425             : {
    2426           0 :   NS_ENSURE_TRUE(aTable, NS_ERROR_NULL_POINTER);
    2427             : 
    2428             :   int32_t rowCount, colCount;
    2429           0 :   nsresult rv = GetTableSize(aTable, &rowCount, &colCount);
    2430           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2431             : 
    2432           0 :   nsCOMPtr<nsIDOMElement> cell;
    2433             :   int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    2434             :   bool    isSelected;
    2435             : 
    2436           0 :   int32_t minColSpan = -1;
    2437             :   int32_t rowIndex;
    2438             : 
    2439           0 :   for (rowIndex = 0; rowIndex < rowCount;
    2440           0 :        rowIndex += std::max(actualRowSpan, 1)) {
    2441           0 :     rv = GetCellDataAt(aTable, rowIndex, aColIndex, getter_AddRefs(cell),
    2442             :                        &startRowIndex, &startColIndex, &rowSpan, &colSpan,
    2443           0 :                        &actualRowSpan, &actualColSpan, &isSelected);
    2444             :     // NOTE: This is a *real* failure.
    2445             :     // GetCellDataAt passes if cell is missing from cellmap
    2446           0 :     if (NS_FAILED(rv)) {
    2447           0 :       return rv;
    2448             :     }
    2449           0 :     if (!cell) {
    2450           0 :       break;
    2451             :     }
    2452           0 :     if (colSpan > 0 &&
    2453           0 :         startColIndex == aColIndex &&
    2454           0 :         (colSpan < minColSpan || minColSpan == -1)) {
    2455           0 :       minColSpan = colSpan;
    2456             :     }
    2457           0 :     NS_ASSERTION((actualRowSpan > 0),"ActualRowSpan = 0 in FixBadColSpan");
    2458             :   }
    2459           0 :   if (minColSpan > 1) {
    2460             :     // The amount to reduce everyone's colspan
    2461             :     // so at least one cell has colspan = 1
    2462           0 :     int32_t colsReduced = minColSpan - 1;
    2463           0 :     for (rowIndex = 0; rowIndex < rowCount;
    2464           0 :          rowIndex += std::max(actualRowSpan, 1)) {
    2465           0 :       rv = GetCellDataAt(aTable, rowIndex, aColIndex, getter_AddRefs(cell),
    2466             :                          &startRowIndex, &startColIndex, &rowSpan, &colSpan,
    2467           0 :                          &actualRowSpan, &actualColSpan, &isSelected);
    2468           0 :       if (NS_FAILED(rv)) {
    2469           0 :         return rv;
    2470             :       }
    2471             :       // Fixup colspans only for cells starting in current column
    2472           0 :       if (cell && colSpan > 0 &&
    2473           0 :           startColIndex == aColIndex &&
    2474           0 :           startRowIndex ==  rowIndex) {
    2475           0 :         rv = SetColSpan(cell, colSpan-colsReduced);
    2476           0 :         if (NS_FAILED(rv)) {
    2477           0 :           return rv;
    2478             :         }
    2479             :       }
    2480           0 :       NS_ASSERTION((actualRowSpan > 0),"ActualRowSpan = 0 in FixBadColSpan");
    2481             :     }
    2482             :   }
    2483           0 :   return GetTableSize(aTable, &rowCount, &aNewColCount);
    2484             : }
    2485             : 
    2486             : NS_IMETHODIMP
    2487           0 : HTMLEditor::NormalizeTable(nsIDOMElement* aTable)
    2488             : {
    2489           0 :   RefPtr<Selection> selection = GetSelection();
    2490           0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    2491             : 
    2492           0 :   nsCOMPtr<nsIDOMElement> table;
    2493           0 :   nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"),
    2494           0 :                                             aTable, getter_AddRefs(table));
    2495           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2496             :   // Don't fail if we didn't find a table
    2497           0 :   NS_ENSURE_TRUE(table, NS_OK);
    2498             : 
    2499             :   int32_t rowCount, colCount, rowIndex, colIndex;
    2500           0 :   rv = GetTableSize(table, &rowCount, &colCount);
    2501           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2502             : 
    2503             :   // Save current selection
    2504           0 :   AutoSelectionRestorer selectionRestorer(selection, this);
    2505             : 
    2506           0 :   AutoEditBatch beginBatching(this);
    2507             :   // Prevent auto insertion of BR in new cell until we're done
    2508           0 :   AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
    2509             : 
    2510           0 :   nsCOMPtr<nsIDOMElement> cell;
    2511             :   int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    2512             :   bool    isSelected;
    2513             : 
    2514             :   // Scan all cells in each row to detect bad rowspan values
    2515           0 :   for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
    2516           0 :     rv = FixBadRowSpan(table, rowIndex, rowCount);
    2517           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2518             :   }
    2519             :   // and same for colspans
    2520           0 :   for (colIndex = 0; colIndex < colCount; colIndex++) {
    2521           0 :     rv = FixBadColSpan(table, colIndex, colCount);
    2522           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2523             :   }
    2524             : 
    2525             :   // Fill in missing cellmap locations with empty cells
    2526           0 :   for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
    2527           0 :     nsCOMPtr<nsIDOMElement> previousCellInRow;
    2528           0 :     for (colIndex = 0; colIndex < colCount; colIndex++) {
    2529           0 :       rv = GetCellDataAt(table, rowIndex, colIndex, getter_AddRefs(cell),
    2530             :                          &startRowIndex, &startColIndex, &rowSpan, &colSpan,
    2531           0 :                          &actualRowSpan, &actualColSpan, &isSelected);
    2532             :       // NOTE: This is a *real* failure.
    2533             :       // GetCellDataAt passes if cell is missing from cellmap
    2534           0 :       if (NS_FAILED(rv)) {
    2535           0 :         return rv;
    2536             :       }
    2537           0 :       if (!cell) {
    2538             :         //We are missing a cell at a cellmap location
    2539             : #ifdef DEBUG
    2540             :         printf("NormalizeTable found missing cell at row=%d, col=%d\n",
    2541           0 :                rowIndex, colIndex);
    2542             : #endif
    2543             :         // Add a cell after the previous Cell in the current row
    2544           0 :         if (!previousCellInRow) {
    2545             :           // We don't have any cells in this row -- We are really messed up!
    2546             : #ifdef DEBUG
    2547             :           printf("NormalizeTable found no cells in row=%d, col=%d\n",
    2548           0 :                  rowIndex, colIndex);
    2549             : #endif
    2550           0 :           return NS_ERROR_FAILURE;
    2551             :         }
    2552             : 
    2553             :         // Insert a new cell after (true), and return the new cell to us
    2554           0 :         rv = InsertCell(previousCellInRow, 1, 1, true, false,
    2555           0 :                         getter_AddRefs(cell));
    2556           0 :         NS_ENSURE_SUCCESS(rv, rv);
    2557             : 
    2558             :         // Set this so we use returned new "cell" to set previousCellInRow below
    2559           0 :         if (cell) {
    2560           0 :           startRowIndex = rowIndex;
    2561             :         }
    2562             :       }
    2563             :       // Save the last cell found in the same row we are scanning
    2564           0 :       if (startRowIndex == rowIndex) {
    2565           0 :         previousCellInRow = cell;
    2566             :       }
    2567             :     }
    2568             :   }
    2569           0 :   return NS_OK;
    2570             : }
    2571             : 
    2572             : NS_IMETHODIMP
    2573           0 : HTMLEditor::GetCellIndexes(nsIDOMElement* aCell,
    2574             :                            int32_t* aRowIndex,
    2575             :                            int32_t* aColIndex)
    2576             : {
    2577           0 :   NS_ENSURE_ARG_POINTER(aRowIndex);
    2578           0 :   *aColIndex=0; // initialize out params
    2579           0 :   NS_ENSURE_ARG_POINTER(aColIndex);
    2580           0 :   *aRowIndex=0;
    2581           0 :   if (!aCell) {
    2582             :     // Get the selected cell or the cell enclosing the selection anchor
    2583           0 :     nsCOMPtr<nsIDOMElement> cell;
    2584           0 :     nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
    2585           0 :                                               getter_AddRefs(cell));
    2586           0 :     if (NS_FAILED(rv) || !cell) {
    2587           0 :       return NS_ERROR_FAILURE;
    2588             :     }
    2589           0 :     aCell = cell;
    2590             :   }
    2591             : 
    2592           0 :   nsCOMPtr<nsIPresShell> ps = GetPresShell();
    2593           0 :   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
    2594             : 
    2595           0 :   nsCOMPtr<nsIContent> nodeAsContent( do_QueryInterface(aCell) );
    2596           0 :   NS_ENSURE_TRUE(nodeAsContent, NS_ERROR_FAILURE);
    2597             :   // frames are not ref counted, so don't use an nsCOMPtr
    2598           0 :   nsIFrame *layoutObject = nodeAsContent->GetPrimaryFrame();
    2599           0 :   NS_ENSURE_TRUE(layoutObject, NS_ERROR_FAILURE);
    2600             : 
    2601           0 :   nsITableCellLayout *cellLayoutObject = do_QueryFrame(layoutObject);
    2602           0 :   NS_ENSURE_TRUE(cellLayoutObject, NS_ERROR_FAILURE);
    2603           0 :   return cellLayoutObject->GetCellIndexes(*aRowIndex, *aColIndex);
    2604             : }
    2605             : 
    2606             : nsTableWrapperFrame*
    2607           0 : HTMLEditor::GetTableFrame(nsIDOMElement* aTable)
    2608             : {
    2609           0 :   NS_ENSURE_TRUE(aTable, nullptr);
    2610             : 
    2611           0 :   nsCOMPtr<nsIContent> nodeAsContent( do_QueryInterface(aTable) );
    2612           0 :   NS_ENSURE_TRUE(nodeAsContent, nullptr);
    2613           0 :   return do_QueryFrame(nodeAsContent->GetPrimaryFrame());
    2614             : }
    2615             : 
    2616             : //Return actual number of cells (a cell with colspan > 1 counts as just 1)
    2617             : int32_t
    2618           0 : HTMLEditor::GetNumberOfCellsInRow(nsIDOMElement* aTable,
    2619             :                                   int32_t rowIndex)
    2620             : {
    2621           0 :   int32_t cellCount = 0;
    2622           0 :   nsCOMPtr<nsIDOMElement> cell;
    2623           0 :   int32_t colIndex = 0;
    2624           0 :   do {
    2625             :     int32_t startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    2626             :     bool    isSelected;
    2627             :     nsresult rv =
    2628           0 :       GetCellDataAt(aTable, rowIndex, colIndex, getter_AddRefs(cell),
    2629             :                     &startRowIndex, &startColIndex, &rowSpan, &colSpan,
    2630           0 :                     &actualRowSpan, &actualColSpan, &isSelected);
    2631           0 :     NS_ENSURE_SUCCESS(rv, 0);
    2632           0 :     if (cell) {
    2633             :       // Only count cells that start in row we are working with
    2634           0 :       if (startRowIndex == rowIndex) {
    2635           0 :         cellCount++;
    2636             :       }
    2637             :       //Next possible location for a cell
    2638           0 :       colIndex += actualColSpan;
    2639             :     } else {
    2640           0 :       colIndex++;
    2641             :     }
    2642             :   } while (cell);
    2643             : 
    2644           0 :   return cellCount;
    2645             : }
    2646             : 
    2647             : NS_IMETHODIMP
    2648           0 : HTMLEditor::GetTableSize(nsIDOMElement* aTable,
    2649             :                          int32_t* aRowCount,
    2650             :                          int32_t* aColCount)
    2651             : {
    2652           0 :   NS_ENSURE_ARG_POINTER(aRowCount);
    2653           0 :   NS_ENSURE_ARG_POINTER(aColCount);
    2654           0 :   *aRowCount = 0;
    2655           0 :   *aColCount = 0;
    2656           0 :   nsCOMPtr<nsIDOMElement> table;
    2657             :   // Get the selected talbe or the table enclosing the selection anchor
    2658           0 :   nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), aTable,
    2659           0 :                                             getter_AddRefs(table));
    2660           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2661           0 :   NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
    2662             : 
    2663           0 :   nsTableWrapperFrame* tableFrame = GetTableFrame(table.get());
    2664           0 :   NS_ENSURE_TRUE(tableFrame, NS_ERROR_FAILURE);
    2665             : 
    2666           0 :   *aRowCount = tableFrame->GetRowCount();
    2667           0 :   *aColCount = tableFrame->GetColCount();
    2668             : 
    2669           0 :   return NS_OK;
    2670             : }
    2671             : 
    2672             : NS_IMETHODIMP
    2673           0 : HTMLEditor::GetCellDataAt(nsIDOMElement* aTable,
    2674             :                           int32_t aRowIndex,
    2675             :                           int32_t aColIndex,
    2676             :                           nsIDOMElement** aCell,
    2677             :                           int32_t* aStartRowIndex,
    2678             :                           int32_t* aStartColIndex,
    2679             :                           int32_t* aRowSpan,
    2680             :                           int32_t* aColSpan,
    2681             :                           int32_t* aActualRowSpan,
    2682             :                           int32_t* aActualColSpan,
    2683             :                           bool* aIsSelected)
    2684             : {
    2685           0 :   NS_ENSURE_ARG_POINTER(aStartRowIndex);
    2686           0 :   NS_ENSURE_ARG_POINTER(aStartColIndex);
    2687           0 :   NS_ENSURE_ARG_POINTER(aRowSpan);
    2688           0 :   NS_ENSURE_ARG_POINTER(aColSpan);
    2689           0 :   NS_ENSURE_ARG_POINTER(aActualRowSpan);
    2690           0 :   NS_ENSURE_ARG_POINTER(aActualColSpan);
    2691           0 :   NS_ENSURE_ARG_POINTER(aIsSelected);
    2692           0 :   NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
    2693             : 
    2694           0 :   *aStartRowIndex = 0;
    2695           0 :   *aStartColIndex = 0;
    2696           0 :   *aRowSpan = 0;
    2697           0 :   *aColSpan = 0;
    2698           0 :   *aActualRowSpan = 0;
    2699           0 :   *aActualColSpan = 0;
    2700           0 :   *aIsSelected = false;
    2701             : 
    2702           0 :   *aCell = nullptr;
    2703             : 
    2704           0 :   if (!aTable) {
    2705             :     // Get the selected table or the table enclosing the selection anchor
    2706           0 :     nsCOMPtr<nsIDOMElement> table;
    2707             :     nsresult rv =
    2708           0 :       GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr,
    2709           0 :                                   getter_AddRefs(table));
    2710           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2711           0 :     if (!table) {
    2712           0 :       return NS_ERROR_FAILURE;
    2713             :     }
    2714           0 :     aTable = table;
    2715             :   }
    2716             : 
    2717           0 :   nsTableWrapperFrame* tableFrame = GetTableFrame(aTable);
    2718           0 :   NS_ENSURE_TRUE(tableFrame, NS_ERROR_FAILURE);
    2719             : 
    2720             :   nsTableCellFrame* cellFrame =
    2721           0 :     tableFrame->GetCellFrameAt(aRowIndex, aColIndex);
    2722           0 :   if (!cellFrame) {
    2723           0 :     return NS_ERROR_FAILURE;
    2724             :   }
    2725             : 
    2726           0 :   *aIsSelected = cellFrame->IsSelected();
    2727           0 :   cellFrame->GetRowIndex(*aStartRowIndex);
    2728           0 :   cellFrame->GetColIndex(*aStartColIndex);
    2729           0 :   *aRowSpan = cellFrame->GetRowSpan();
    2730           0 :   *aColSpan = cellFrame->GetColSpan();
    2731           0 :   *aActualRowSpan = tableFrame->GetEffectiveRowSpanAt(aRowIndex, aColIndex);
    2732           0 :   *aActualColSpan = tableFrame->GetEffectiveColSpanAt(aRowIndex, aColIndex);
    2733           0 :   nsCOMPtr<nsIDOMElement> domCell = do_QueryInterface(cellFrame->GetContent());
    2734           0 :   domCell.forget(aCell);
    2735             : 
    2736           0 :   return NS_OK;
    2737             : }
    2738             : 
    2739             : // When all you want is the cell
    2740             : NS_IMETHODIMP
    2741           0 : HTMLEditor::GetCellAt(nsIDOMElement* aTable,
    2742             :                       int32_t aRowIndex,
    2743             :                       int32_t aColIndex,
    2744             :                       nsIDOMElement** aCell)
    2745             : {
    2746           0 :   NS_ENSURE_ARG_POINTER(aCell);
    2747           0 :   *aCell = nullptr;
    2748             : 
    2749           0 :   if (!aTable) {
    2750             :     // Get the selected table or the table enclosing the selection anchor
    2751           0 :     nsCOMPtr<nsIDOMElement> table;
    2752             :     nsresult rv =
    2753           0 :       GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr,
    2754           0 :                                   getter_AddRefs(table));
    2755           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2756           0 :     NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
    2757           0 :     aTable = table;
    2758             :   }
    2759             : 
    2760           0 :   nsTableWrapperFrame* tableFrame = GetTableFrame(aTable);
    2761           0 :   if (!tableFrame) {
    2762           0 :     *aCell = nullptr;
    2763           0 :     return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
    2764             :   }
    2765             : 
    2766             :   nsCOMPtr<nsIDOMElement> domCell =
    2767           0 :     do_QueryInterface(tableFrame->GetCellAt(aRowIndex, aColIndex));
    2768           0 :   domCell.forget(aCell);
    2769             : 
    2770           0 :   return NS_OK;
    2771             : }
    2772             : 
    2773             : // When all you want are the rowspan and colspan (not exposed in nsITableEditor)
    2774             : NS_IMETHODIMP
    2775           0 : HTMLEditor::GetCellSpansAt(nsIDOMElement* aTable,
    2776             :                            int32_t aRowIndex,
    2777             :                            int32_t aColIndex,
    2778             :                            int32_t& aActualRowSpan,
    2779             :                            int32_t& aActualColSpan)
    2780             : {
    2781           0 :   nsTableWrapperFrame* tableFrame = GetTableFrame(aTable);
    2782           0 :   if (!tableFrame) {
    2783           0 :     return NS_ERROR_FAILURE;
    2784             :   }
    2785           0 :   aActualRowSpan = tableFrame->GetEffectiveRowSpanAt(aRowIndex, aColIndex);
    2786           0 :   aActualColSpan = tableFrame->GetEffectiveColSpanAt(aRowIndex, aColIndex);
    2787             : 
    2788           0 :   return NS_OK;
    2789             : }
    2790             : 
    2791             : nsresult
    2792           0 : HTMLEditor::GetCellContext(Selection** aSelection,
    2793             :                            nsIDOMElement** aTable,
    2794             :                            nsIDOMElement** aCell,
    2795             :                            nsIDOMNode** aCellParent,
    2796             :                            int32_t* aCellOffset,
    2797             :                            int32_t* aRowIndex,
    2798             :                            int32_t* aColIndex)
    2799             : {
    2800             :   // Initialize return pointers
    2801           0 :   if (aSelection) {
    2802           0 :     *aSelection = nullptr;
    2803             :   }
    2804           0 :   if (aTable) {
    2805           0 :     *aTable = nullptr;
    2806             :   }
    2807           0 :   if (aCell) {
    2808           0 :     *aCell = nullptr;
    2809             :   }
    2810           0 :   if (aCellParent) {
    2811           0 :     *aCellParent = nullptr;
    2812             :   }
    2813           0 :   if (aCellOffset) {
    2814           0 :     *aCellOffset = 0;
    2815             :   }
    2816           0 :   if (aRowIndex) {
    2817           0 :     *aRowIndex = 0;
    2818             :   }
    2819           0 :   if (aColIndex) {
    2820           0 :     *aColIndex = 0;
    2821             :   }
    2822             : 
    2823           0 :   RefPtr<Selection> selection = GetSelection();
    2824           0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    2825             : 
    2826           0 :   if (aSelection) {
    2827           0 :     *aSelection = selection.get();
    2828           0 :     NS_ADDREF(*aSelection);
    2829             :   }
    2830           0 :   nsCOMPtr <nsIDOMElement> table;
    2831           0 :   nsCOMPtr <nsIDOMElement> cell;
    2832             : 
    2833             :   // Caller may supply the cell...
    2834           0 :   if (aCell && *aCell) {
    2835           0 :     cell = *aCell;
    2836             :   }
    2837             : 
    2838             :   // ...but if not supplied,
    2839             :   //    get cell if it's the child of selection anchor node,
    2840             :   //    or get the enclosing by a cell
    2841           0 :   if (!cell) {
    2842             :     // Find a selected or enclosing table element
    2843           0 :     nsCOMPtr<nsIDOMElement> cellOrTableElement;
    2844             :     int32_t selectedCount;
    2845           0 :     nsAutoString tagName;
    2846             :     nsresult rv =
    2847           0 :       GetSelectedOrParentTableElement(tagName, &selectedCount,
    2848           0 :                                       getter_AddRefs(cellOrTableElement));
    2849           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2850           0 :     if (tagName.EqualsLiteral("table")) {
    2851             :       // We have a selected table, not a cell
    2852           0 :       if (aTable) {
    2853           0 :         *aTable = cellOrTableElement.get();
    2854           0 :         NS_ADDREF(*aTable);
    2855             :       }
    2856           0 :       return NS_OK;
    2857             :     }
    2858           0 :     if (!tagName.EqualsLiteral("td")) {
    2859           0 :       return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
    2860             :     }
    2861             : 
    2862             :     // We found a cell
    2863           0 :     cell = cellOrTableElement;
    2864             :   }
    2865           0 :   if (aCell) {
    2866           0 :     *aCell = cell.get();
    2867           0 :     NS_ADDREF(*aCell);
    2868             :   }
    2869             : 
    2870             :   // Get containing table
    2871           0 :   nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), cell,
    2872           0 :                                             getter_AddRefs(table));
    2873           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2874             :   // Cell must be in a table, so fail if not found
    2875           0 :   NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
    2876           0 :   if (aTable) {
    2877           0 :     *aTable = table.get();
    2878           0 :     NS_ADDREF(*aTable);
    2879             :   }
    2880             : 
    2881             :   // Get the rest of the related data only if requested
    2882           0 :   if (aRowIndex || aColIndex) {
    2883             :     int32_t rowIndex, colIndex;
    2884             :     // Get current cell location so we can put caret back there when done
    2885           0 :     rv = GetCellIndexes(cell, &rowIndex, &colIndex);
    2886           0 :     if (NS_FAILED(rv)) {
    2887           0 :       return rv;
    2888             :     }
    2889           0 :     if (aRowIndex) {
    2890           0 :       *aRowIndex = rowIndex;
    2891             :     }
    2892           0 :     if (aColIndex) {
    2893           0 :       *aColIndex = colIndex;
    2894             :     }
    2895             :   }
    2896           0 :   if (aCellParent) {
    2897           0 :     nsCOMPtr <nsIDOMNode> cellParent;
    2898             :     // Get the immediate parent of the cell
    2899           0 :     rv = cell->GetParentNode(getter_AddRefs(cellParent));
    2900           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2901             :     // Cell has to have a parent, so fail if not found
    2902           0 :     NS_ENSURE_TRUE(cellParent, NS_ERROR_FAILURE);
    2903             : 
    2904           0 :     *aCellParent = cellParent.get();
    2905           0 :     NS_ADDREF(*aCellParent);
    2906             : 
    2907           0 :     if (aCellOffset) {
    2908           0 :       *aCellOffset = GetChildOffset(cell, cellParent);
    2909             :     }
    2910             :   }
    2911             : 
    2912           0 :   return NS_OK;
    2913             : }
    2914             : 
    2915             : nsresult
    2916           0 : HTMLEditor::GetCellFromRange(nsRange* aRange,
    2917             :                              nsIDOMElement** aCell)
    2918             : {
    2919             :   // Note: this might return a node that is outside of the range.
    2920             :   // Use carefully.
    2921           0 :   NS_ENSURE_TRUE(aRange && aCell, NS_ERROR_NULL_POINTER);
    2922             : 
    2923           0 :   *aCell = nullptr;
    2924             : 
    2925           0 :   nsCOMPtr<nsIDOMNode> startContainer;
    2926           0 :   nsresult rv = aRange->GetStartContainer(getter_AddRefs(startContainer));
    2927           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2928           0 :   NS_ENSURE_TRUE(startContainer, NS_ERROR_FAILURE);
    2929             : 
    2930             :   int32_t startOffset;
    2931           0 :   rv = aRange->GetStartOffset(&startOffset);
    2932           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2933             : 
    2934           0 :   nsCOMPtr<nsIDOMNode> childNode = GetChildAt(startContainer, startOffset);
    2935             :   // This means selection is probably at a text node (or end of doc?)
    2936           0 :   if (!childNode) {
    2937           0 :     return NS_ERROR_FAILURE;
    2938             :   }
    2939             : 
    2940           0 :   nsCOMPtr<nsIDOMNode> endContainer;
    2941           0 :   rv = aRange->GetEndContainer(getter_AddRefs(endContainer));
    2942           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2943           0 :   NS_ENSURE_TRUE(startContainer, NS_ERROR_FAILURE);
    2944             : 
    2945             :   int32_t endOffset;
    2946           0 :   rv = aRange->GetEndOffset(&endOffset);
    2947           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2948             : 
    2949             :   // If a cell is deleted, the range is collapse
    2950             :   //   (startOffset == endOffset)
    2951             :   //   so tell caller the cell wasn't found
    2952           0 :   if (startContainer == endContainer &&
    2953           0 :       endOffset == startOffset+1 &&
    2954           0 :       HTMLEditUtils::IsTableCell(childNode)) {
    2955             :     // Should we also test if frame is selected? (Use GetCellDataAt())
    2956             :     // (Let's not for now -- more efficient)
    2957           0 :     nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(childNode);
    2958           0 :     *aCell = cellElement.get();
    2959           0 :     NS_ADDREF(*aCell);
    2960           0 :     return NS_OK;
    2961             :   }
    2962           0 :   return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
    2963             : }
    2964             : 
    2965             : NS_IMETHODIMP
    2966           0 : HTMLEditor::GetFirstSelectedCell(nsIDOMRange** aRange,
    2967             :                                  nsIDOMElement** aCell)
    2968             : {
    2969           0 :   NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
    2970           0 :   *aCell = nullptr;
    2971           0 :   if (aRange) {
    2972           0 :     *aRange = nullptr;
    2973             :   }
    2974             : 
    2975           0 :   RefPtr<Selection> selection = GetSelection();
    2976           0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    2977             : 
    2978           0 :   RefPtr<nsRange> range = selection->GetRangeAt(0);
    2979           0 :   NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
    2980             : 
    2981           0 :   mSelectedCellIndex = 0;
    2982             : 
    2983           0 :   nsresult rv = GetCellFromRange(range, aCell);
    2984             :   // Failure here probably means selection is in a text node,
    2985             :   //  so there's no selected cell
    2986           0 :   if (NS_FAILED(rv)) {
    2987           0 :     return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
    2988             :   }
    2989             :   // No cell means range was collapsed (cell was deleted)
    2990           0 :   if (!*aCell) {
    2991           0 :     return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
    2992             :   }
    2993             : 
    2994           0 :   if (aRange) {
    2995           0 :     *aRange = range.get();
    2996           0 :     NS_ADDREF(*aRange);
    2997             :   }
    2998             : 
    2999             :   // Setup for next cell
    3000           0 :   mSelectedCellIndex = 1;
    3001             : 
    3002           0 :   return NS_OK;
    3003             : }
    3004             : 
    3005             : NS_IMETHODIMP
    3006           0 : HTMLEditor::GetNextSelectedCell(nsIDOMRange** aRange,
    3007             :                                 nsIDOMElement** aCell)
    3008             : {
    3009           0 :   NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
    3010           0 :   *aCell = nullptr;
    3011           0 :   if (aRange) {
    3012           0 :     *aRange = nullptr;
    3013             :   }
    3014             : 
    3015           0 :   RefPtr<Selection> selection = GetSelection();
    3016           0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    3017             : 
    3018           0 :   int32_t rangeCount = selection->RangeCount();
    3019             : 
    3020             :   // Don't even try if index exceeds range count
    3021           0 :   if (mSelectedCellIndex >= rangeCount) {
    3022           0 :     return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
    3023             :   }
    3024             : 
    3025             :   // Scan through ranges to find next valid selected cell
    3026           0 :   RefPtr<nsRange> range;
    3027           0 :   for (; mSelectedCellIndex < rangeCount; mSelectedCellIndex++) {
    3028           0 :     range = selection->GetRangeAt(mSelectedCellIndex);
    3029           0 :     NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
    3030             : 
    3031           0 :     nsresult rv = GetCellFromRange(range, aCell);
    3032             :     // Failure here means the range doesn't contain a cell
    3033           0 :     NS_ENSURE_SUCCESS(rv, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
    3034             : 
    3035             :     // We found a selected cell
    3036           0 :     if (*aCell) {
    3037           0 :       break;
    3038             :     }
    3039             : 
    3040             :     // If we didn't find a cell, continue to next range in selection
    3041             :   }
    3042             :   // No cell means all remaining ranges were collapsed (cells were deleted)
    3043           0 :   NS_ENSURE_TRUE(*aCell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
    3044             : 
    3045           0 :   if (aRange) {
    3046           0 :     *aRange = range.get();
    3047           0 :     NS_ADDREF(*aRange);
    3048             :   }
    3049             : 
    3050             :   // Setup for next cell
    3051           0 :   mSelectedCellIndex++;
    3052             : 
    3053           0 :   return NS_OK;
    3054             : }
    3055             : 
    3056             : NS_IMETHODIMP
    3057           0 : HTMLEditor::GetFirstSelectedCellInTable(int32_t* aRowIndex,
    3058             :                                         int32_t* aColIndex,
    3059             :                                         nsIDOMElement** aCell)
    3060             : {
    3061           0 :   NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
    3062           0 :   *aCell = nullptr;
    3063           0 :   if (aRowIndex) {
    3064           0 :     *aRowIndex = 0;
    3065             :   }
    3066           0 :   if (aColIndex) {
    3067           0 :     *aColIndex = 0;
    3068             :   }
    3069             : 
    3070           0 :   nsCOMPtr<nsIDOMElement> cell;
    3071           0 :   nsresult rv = GetFirstSelectedCell(nullptr, getter_AddRefs(cell));
    3072           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3073           0 :   NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
    3074             : 
    3075           0 :   *aCell = cell.get();
    3076           0 :   NS_ADDREF(*aCell);
    3077             : 
    3078             :   // Also return the row and/or column if requested
    3079           0 :   if (aRowIndex || aColIndex) {
    3080             :     int32_t startRowIndex, startColIndex;
    3081           0 :     rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
    3082           0 :     if (NS_FAILED(rv)) {
    3083           0 :       return rv;
    3084             :     }
    3085             : 
    3086           0 :     if (aRowIndex) {
    3087           0 :       *aRowIndex = startRowIndex;
    3088             :     }
    3089           0 :     if (aColIndex) {
    3090           0 :       *aColIndex = startColIndex;
    3091             :     }
    3092             :   }
    3093             : 
    3094           0 :   return NS_OK;
    3095             : }
    3096             : 
    3097             : NS_IMETHODIMP
    3098           0 : HTMLEditor::SetSelectionAfterTableEdit(nsIDOMElement* aTable,
    3099             :                                        int32_t aRow,
    3100             :                                        int32_t aCol,
    3101             :                                        int32_t aDirection,
    3102             :                                        bool aSelected)
    3103             : {
    3104           0 :   NS_ENSURE_TRUE(aTable, NS_ERROR_NOT_INITIALIZED);
    3105             : 
    3106           0 :   RefPtr<Selection> selection = GetSelection();
    3107             : 
    3108           0 :   if (!selection) {
    3109           0 :     return NS_ERROR_FAILURE;
    3110             :   }
    3111             : 
    3112           0 :   nsCOMPtr<nsIDOMElement> cell;
    3113           0 :   bool done = false;
    3114           0 :   do {
    3115           0 :     nsresult rv = GetCellAt(aTable, aRow, aCol, getter_AddRefs(cell));
    3116           0 :     if (NS_FAILED(rv)) {
    3117           0 :       break;
    3118             :     }
    3119             : 
    3120           0 :     if (cell) {
    3121           0 :       if (aSelected) {
    3122             :         // Reselect the cell
    3123           0 :         return SelectElement(cell);
    3124             :       } else {
    3125             :         // Set the caret to deepest first child
    3126             :         //   but don't go into nested tables
    3127             :         // TODO: Should we really be placing the caret at the END
    3128             :         //  of the cell content?
    3129           0 :         nsCOMPtr<nsINode> cellNode = do_QueryInterface(cell);
    3130           0 :         if (cellNode) {
    3131           0 :           CollapseSelectionToDeepestNonTableFirstChild(selection, cellNode);
    3132             :         }
    3133           0 :         return NS_OK;
    3134             :       }
    3135             :     } else {
    3136             :       // Setup index to find another cell in the
    3137             :       //   direction requested, but move in
    3138             :       //   other direction if already at beginning of row or column
    3139           0 :       switch (aDirection) {
    3140             :         case ePreviousColumn:
    3141           0 :           if (!aCol) {
    3142           0 :             if (aRow > 0) {
    3143           0 :               aRow--;
    3144             :             } else {
    3145           0 :               done = true;
    3146             :             }
    3147             :           } else {
    3148           0 :             aCol--;
    3149             :           }
    3150           0 :           break;
    3151             :         case ePreviousRow:
    3152           0 :           if (!aRow) {
    3153           0 :             if (aCol > 0) {
    3154           0 :               aCol--;
    3155             :             } else {
    3156           0 :               done = true;
    3157             :             }
    3158             :           } else {
    3159           0 :             aRow--;
    3160             :           }
    3161           0 :           break;
    3162             :         default:
    3163           0 :           done = true;
    3164             :       }
    3165             :     }
    3166           0 :   } while (!done);
    3167             : 
    3168             :   // We didn't find a cell
    3169             :   // Set selection to just before the table
    3170           0 :   nsCOMPtr<nsIDOMNode> tableParent;
    3171           0 :   nsresult rv = aTable->GetParentNode(getter_AddRefs(tableParent));
    3172           0 :   if (NS_SUCCEEDED(rv) && tableParent) {
    3173           0 :     int32_t tableOffset = GetChildOffset(aTable, tableParent);
    3174           0 :     return selection->Collapse(tableParent, tableOffset);
    3175             :   }
    3176             :   // Last resort: Set selection to start of doc
    3177             :   // (it's very bad to not have a valid selection!)
    3178           0 :   return SetSelectionAtDocumentStart(selection);
    3179             : }
    3180             : 
    3181             : NS_IMETHODIMP
    3182           0 : HTMLEditor::GetSelectedOrParentTableElement(nsAString& aTagName,
    3183             :                                             int32_t* aSelectedCount,
    3184             :                                             nsIDOMElement** aTableElement)
    3185             : {
    3186           0 :   NS_ENSURE_ARG_POINTER(aTableElement);
    3187           0 :   NS_ENSURE_ARG_POINTER(aSelectedCount);
    3188           0 :   *aTableElement = nullptr;
    3189           0 :   aTagName.Truncate();
    3190           0 :   *aSelectedCount = 0;
    3191             : 
    3192           0 :   RefPtr<Selection> selection = GetSelection();
    3193           0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    3194             : 
    3195             :   // Try to get the first selected cell
    3196           0 :   nsCOMPtr<nsIDOMElement> tableOrCellElement;
    3197           0 :   nsresult rv = GetFirstSelectedCell(nullptr,
    3198           0 :                                      getter_AddRefs(tableOrCellElement));
    3199           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3200             : 
    3201           0 :   NS_NAMED_LITERAL_STRING(tdName, "td");
    3202             : 
    3203           0 :   if (tableOrCellElement) {
    3204             :       // Each cell is in its own selection range,
    3205             :       //  so count signals multiple-cell selection
    3206           0 :       rv = selection->GetRangeCount(aSelectedCount);
    3207           0 :       NS_ENSURE_SUCCESS(rv, rv);
    3208           0 :       aTagName = tdName;
    3209             :   } else {
    3210           0 :     nsCOMPtr<nsIDOMNode> anchorNode;
    3211           0 :     rv = selection->GetAnchorNode(getter_AddRefs(anchorNode));
    3212           0 :     if (NS_FAILED(rv)) {
    3213           0 :       return rv;
    3214             :     }
    3215           0 :     NS_ENSURE_TRUE(anchorNode, NS_ERROR_FAILURE);
    3216             : 
    3217           0 :     nsCOMPtr<nsIDOMNode> selectedNode;
    3218             : 
    3219             :     // Get child of anchor node, if exists
    3220             :     bool hasChildren;
    3221           0 :     anchorNode->HasChildNodes(&hasChildren);
    3222             : 
    3223           0 :     if (hasChildren) {
    3224             :       int32_t anchorOffset;
    3225           0 :       rv = selection->GetAnchorOffset(&anchorOffset);
    3226           0 :       NS_ENSURE_SUCCESS(rv, rv);
    3227           0 :       selectedNode = GetChildAt(anchorNode, anchorOffset);
    3228           0 :       if (!selectedNode) {
    3229           0 :         selectedNode = anchorNode;
    3230             :         // If anchor doesn't have a child, we can't be selecting a table element,
    3231             :         //  so don't do the following:
    3232             :       } else {
    3233           0 :         nsCOMPtr<nsIAtom> atom = EditorBase::GetTag(selectedNode);
    3234             : 
    3235           0 :         if (atom == nsGkAtoms::td) {
    3236           0 :           tableOrCellElement = do_QueryInterface(selectedNode);
    3237           0 :           aTagName = tdName;
    3238             :           // Each cell is in its own selection range,
    3239             :           //  so count signals multiple-cell selection
    3240           0 :           rv = selection->GetRangeCount(aSelectedCount);
    3241           0 :           NS_ENSURE_SUCCESS(rv, rv);
    3242           0 :         } else if (atom == nsGkAtoms::table) {
    3243           0 :           tableOrCellElement = do_QueryInterface(selectedNode);
    3244           0 :           aTagName.AssignLiteral("table");
    3245           0 :           *aSelectedCount = 1;
    3246           0 :         } else if (atom == nsGkAtoms::tr) {
    3247           0 :           tableOrCellElement = do_QueryInterface(selectedNode);
    3248           0 :           aTagName.AssignLiteral("tr");
    3249           0 :           *aSelectedCount = 1;
    3250             :         }
    3251             :       }
    3252             :     }
    3253           0 :     if (!tableOrCellElement) {
    3254             :       // Didn't find a table element -- find a cell parent
    3255           0 :       rv = GetElementOrParentByTagName(tdName, anchorNode,
    3256           0 :                                        getter_AddRefs(tableOrCellElement));
    3257           0 :       if (NS_FAILED(rv)) {
    3258           0 :         return rv;
    3259             :       }
    3260           0 :       if (tableOrCellElement) {
    3261           0 :         aTagName = tdName;
    3262             :       }
    3263             :     }
    3264             :   }
    3265           0 :   if (tableOrCellElement) {
    3266           0 :     *aTableElement = tableOrCellElement.get();
    3267           0 :     NS_ADDREF(*aTableElement);
    3268             :   }
    3269           0 :   return NS_OK;
    3270             : }
    3271             : 
    3272             : NS_IMETHODIMP
    3273           0 : HTMLEditor::GetSelectedCellsType(nsIDOMElement* aElement,
    3274             :                                  uint32_t* aSelectionType)
    3275             : {
    3276           0 :   NS_ENSURE_ARG_POINTER(aSelectionType);
    3277           0 :   *aSelectionType = 0;
    3278             : 
    3279             :   // Be sure we have a table element
    3280             :   //  (if aElement is null, this uses selection's anchor node)
    3281           0 :   nsCOMPtr<nsIDOMElement> table;
    3282             : 
    3283             :   nsresult rv =
    3284           0 :     GetElementOrParentByTagName(NS_LITERAL_STRING("table"), aElement,
    3285           0 :                                 getter_AddRefs(table));
    3286           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3287             : 
    3288             :   int32_t rowCount, colCount;
    3289           0 :   rv = GetTableSize(table, &rowCount, &colCount);
    3290           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3291             : 
    3292             :   // Traverse all selected cells
    3293           0 :   nsCOMPtr<nsIDOMElement> selectedCell;
    3294           0 :   rv = GetFirstSelectedCell(nullptr, getter_AddRefs(selectedCell));
    3295           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3296           0 :   if (rv == NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND) {
    3297           0 :     return NS_OK;
    3298             :   }
    3299             : 
    3300             :   // We have at least one selected cell, so set return value
    3301           0 :   *aSelectionType = nsISelectionPrivate::TABLESELECTION_CELL;
    3302             : 
    3303             :   // Store indexes of each row/col to avoid duplication of searches
    3304           0 :   nsTArray<int32_t> indexArray;
    3305             : 
    3306           0 :   bool allCellsInRowAreSelected = false;
    3307           0 :   bool allCellsInColAreSelected = false;
    3308           0 :   while (NS_SUCCEEDED(rv) && selectedCell) {
    3309             :     // Get the cell's location in the cellmap
    3310             :     int32_t startRowIndex, startColIndex;
    3311           0 :     rv = GetCellIndexes(selectedCell, &startRowIndex, &startColIndex);
    3312           0 :     if (NS_FAILED(rv)) {
    3313           0 :       return rv;
    3314             :     }
    3315             : 
    3316           0 :     if (!indexArray.Contains(startColIndex)) {
    3317           0 :       indexArray.AppendElement(startColIndex);
    3318           0 :       allCellsInRowAreSelected = AllCellsInRowSelected(table, startRowIndex, colCount);
    3319             :       // We're done as soon as we fail for any row
    3320           0 :       if (!allCellsInRowAreSelected) {
    3321           0 :         break;
    3322             :       }
    3323             :     }
    3324           0 :     rv = GetNextSelectedCell(nullptr, getter_AddRefs(selectedCell));
    3325             :   }
    3326             : 
    3327           0 :   if (allCellsInRowAreSelected) {
    3328           0 :     *aSelectionType = nsISelectionPrivate::TABLESELECTION_ROW;
    3329           0 :     return NS_OK;
    3330             :   }
    3331             :   // Test for columns
    3332             : 
    3333             :   // Empty the indexArray
    3334           0 :   indexArray.Clear();
    3335             : 
    3336             :   // Start at first cell again
    3337           0 :   rv = GetFirstSelectedCell(nullptr, getter_AddRefs(selectedCell));
    3338           0 :   while (NS_SUCCEEDED(rv) && selectedCell) {
    3339             :     // Get the cell's location in the cellmap
    3340             :     int32_t startRowIndex, startColIndex;
    3341           0 :     rv = GetCellIndexes(selectedCell, &startRowIndex, &startColIndex);
    3342           0 :     if (NS_FAILED(rv)) {
    3343           0 :       return rv;
    3344             :     }
    3345             : 
    3346           0 :     if (!indexArray.Contains(startRowIndex)) {
    3347           0 :       indexArray.AppendElement(startColIndex);
    3348           0 :       allCellsInColAreSelected = AllCellsInColumnSelected(table, startColIndex, rowCount);
    3349             :       // We're done as soon as we fail for any column
    3350           0 :       if (!allCellsInRowAreSelected) {
    3351           0 :         break;
    3352             :       }
    3353             :     }
    3354           0 :     rv = GetNextSelectedCell(nullptr, getter_AddRefs(selectedCell));
    3355             :   }
    3356           0 :   if (allCellsInColAreSelected) {
    3357           0 :     *aSelectionType = nsISelectionPrivate::TABLESELECTION_COLUMN;
    3358             :   }
    3359             : 
    3360           0 :   return NS_OK;
    3361             : }
    3362             : 
    3363             : bool
    3364           0 : HTMLEditor::AllCellsInRowSelected(nsIDOMElement* aTable,
    3365             :                                   int32_t aRowIndex,
    3366             :                                   int32_t aNumberOfColumns)
    3367             : {
    3368           0 :   NS_ENSURE_TRUE(aTable, false);
    3369             : 
    3370             :   int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    3371             :   bool    isSelected;
    3372             : 
    3373           0 :   for (int32_t col = 0; col < aNumberOfColumns;
    3374           0 :        col += std::max(actualColSpan, 1)) {
    3375           0 :     nsCOMPtr<nsIDOMElement> cell;
    3376           0 :     nsresult rv = GetCellDataAt(aTable, aRowIndex, col, getter_AddRefs(cell),
    3377             :                                 &curStartRowIndex, &curStartColIndex,
    3378             :                                 &rowSpan, &colSpan,
    3379           0 :                                 &actualRowSpan, &actualColSpan, &isSelected);
    3380             : 
    3381           0 :     NS_ENSURE_SUCCESS(rv, false);
    3382             :     // If no cell, we may have a "ragged" right edge,
    3383             :     //   so return TRUE only if we already found a cell in the row
    3384           0 :     NS_ENSURE_TRUE(cell, (col > 0) ? true : false);
    3385             : 
    3386             :     // Return as soon as a non-selected cell is found
    3387           0 :     NS_ENSURE_TRUE(isSelected, false);
    3388             : 
    3389           0 :     NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in AllCellsInRowSelected");
    3390             :   }
    3391           0 :   return true;
    3392             : }
    3393             : 
    3394             : bool
    3395           0 : HTMLEditor::AllCellsInColumnSelected(nsIDOMElement* aTable,
    3396             :                                      int32_t aColIndex,
    3397             :                                      int32_t aNumberOfRows)
    3398             : {
    3399           0 :   NS_ENSURE_TRUE(aTable, false);
    3400             : 
    3401             :   int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
    3402             :   bool    isSelected;
    3403             : 
    3404           0 :   for (int32_t row = 0; row < aNumberOfRows;
    3405           0 :        row += std::max(actualRowSpan, 1)) {
    3406           0 :     nsCOMPtr<nsIDOMElement> cell;
    3407           0 :     nsresult rv = GetCellDataAt(aTable, row, aColIndex, getter_AddRefs(cell),
    3408             :                                 &curStartRowIndex, &curStartColIndex,
    3409             :                                 &rowSpan, &colSpan,
    3410           0 :                                 &actualRowSpan, &actualColSpan, &isSelected);
    3411             : 
    3412           0 :     NS_ENSURE_SUCCESS(rv, false);
    3413             :     // If no cell, we must have a "ragged" right edge on the last column
    3414             :     //   so return TRUE only if we already found a cell in the row
    3415           0 :     NS_ENSURE_TRUE(cell, (row > 0) ? true : false);
    3416             : 
    3417             :     // Return as soon as a non-selected cell is found
    3418           0 :     NS_ENSURE_TRUE(isSelected, false);
    3419             :   }
    3420           0 :   return true;
    3421             : }
    3422             : 
    3423             : bool
    3424           0 : HTMLEditor::IsEmptyCell(dom::Element* aCell)
    3425             : {
    3426           0 :   MOZ_ASSERT(aCell);
    3427             : 
    3428             :   // Check if target only contains empty text node or <br>
    3429           0 :   nsCOMPtr<nsINode> cellChild = aCell->GetFirstChild();
    3430           0 :   if (!cellChild) {
    3431           0 :     return false;
    3432             :   }
    3433             : 
    3434           0 :   nsCOMPtr<nsINode> nextChild = cellChild->GetNextSibling();
    3435           0 :   if (nextChild) {
    3436           0 :     return false;
    3437             :   }
    3438             : 
    3439             :   // We insert a single break into a cell by default
    3440             :   //   to have some place to locate a cursor -- it is dispensable
    3441           0 :   if (cellChild->IsHTMLElement(nsGkAtoms::br)) {
    3442           0 :     return true;
    3443             :   }
    3444             : 
    3445             :   bool isEmpty;
    3446             :   // Or check if no real content
    3447           0 :   nsresult rv = IsEmptyNode(cellChild, &isEmpty, false, false);
    3448           0 :   NS_ENSURE_SUCCESS(rv, false);
    3449           0 :   return isEmpty;
    3450             : }
    3451             : 
    3452             : } // namespace mozilla

Generated by: LCOV version 1.13