Bug 1484092 - part 1: Make HTMLEditor::GetElementOrParentByTagName() use nsAtom for the tag name r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 17 Aug 2018 14:06:18 +0000
changeset 432113 717fb8632016211ce9cf8a7267be60e52f7e77c8
parent 432112 4656d3bf8e9c09101329b6a6a016764e2e93b32d
child 432114 25d58e97db2d7f1bd8fcf5bc2676d7bd77bb6e8d
push id34460
push userdvarga@mozilla.com
push dateFri, 17 Aug 2018 21:51:39 +0000
treeherdermozilla-central@2f1bbddc826b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1484092
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1484092 - part 1: Make HTMLEditor::GetElementOrParentByTagName() use nsAtom for the tag name r=m_kato HTMLElementOrParentByTagName() is the last user of IsLinkTag(const nsAString&) and IsNamedAnchorTag(const nsAString&). For making their maintenance easier, let's make GetElementOrParentByTagName() take const nsAtom& for tag name. GetElementOrParentByTagName() has two functions, one is looking for an element starting from a node. The other is, if the start node is nullptr, it retrieves anchor node of Selection as start node. Therefore, this patch splits the first part to GetElementOrParentByTagNameInternal(). Then, creates its wrapper which retrieves anchor of Selection automatically, GetElementOrParentByTagNameAtSelection(). Additionally, this patch makes all internal callers of HTMLEditor use GetElementOrParentByTagNameInternal() or GetElementOrParentByTagNameAtSelection() directly. Then, public method, GetElementOrParentByTagName() is called only by outer classes. Note that some callers use both GetElementOrParentByTagNameInternal() and GetElementOrParentByTagNameAtSelection() since they don't check whether setting node is nullptr. They may be bug of them. We should investigate the API callers later. Differential Revision: https://phabricator.services.mozilla.com/D3584
editor/libeditor/HTMLAnonymousNodeEditor.cpp
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLEditor.h
editor/libeditor/HTMLEditorEventListener.cpp
editor/libeditor/HTMLTableEditor.cpp
editor/nsIHTMLEditor.idl
--- a/editor/libeditor/HTMLAnonymousNodeEditor.cpp
+++ b/editor/libeditor/HTMLAnonymousNodeEditor.cpp
@@ -284,17 +284,19 @@ HTMLEditor::DeleteRefToAnonymousNode(Man
 
 // The following method is mostly called by a selection listener. When a
 // selection change is notified, the method is called to check if resizing
 // handles, a grabber and/or inline table editing UI need to be displayed
 // or refreshed
 NS_IMETHODIMP
 HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
 {
-  NS_ENSURE_ARG_POINTER(aSelection);
+  if (NS_WARN_IF(!aSelection)) {
+    return NS_ERROR_INVALID_ARG;
+  }
 
   // early way out if all contextual UI extensions are disabled
   NS_ENSURE_TRUE(mIsObjectResizingEnabled ||
       mIsAbsolutelyPositioningEnabled ||
       mIsInlineTableEditingEnabled, NS_OK);
 
   // Don't change selection state if we're moving.
   if (mIsMoving) {
@@ -321,17 +323,18 @@ HTMLEditor::CheckSelectionStateForAnonym
     // in an absolutely positioned element ?
     absPosElement = GetAbsolutelyPositionedSelectionContainer();
   }
 
   RefPtr<Element> cellElement;
   if (mIsObjectResizingEnabled || mIsInlineTableEditingEnabled) {
     // Resizing or Inline Table Editing is enabled, we need to check if the
     // selection is contained in a table cell
-    cellElement = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
+    cellElement =
+      GetElementOrParentByTagNameAtSelection(*aSelection, *nsGkAtoms::td);
   }
 
   if (mIsObjectResizingEnabled && cellElement) {
     // we are here because Resizing is enabled AND selection is contained in
     // a cell
 
     // get the enclosing table
     if (nsGkAtoms::img != focusTagAtom) {
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -84,34 +84,22 @@ GetLowerCaseNameAtom(const nsAString& aT
   }
   nsAutoString lowerTagName;
   nsContentUtils::ASCIIToLower(aTagName, lowerTagName);
   return NS_Atomize(lowerTagName);
 }
 
 // Some utilities to handle overloading of "A" tag for link and named anchor.
 static bool
-IsLinkTag(const nsString& s)
-{
-  return s.EqualsIgnoreCase("href");
-}
-
-static bool
 IsLinkTag(const nsAtom& aTagName)
 {
   return aTagName.Equals(NS_LITERAL_STRING("href"));
 }
 
 static bool
-IsNamedAnchorTag(const nsString& s)
-{
-  return s.EqualsIgnoreCase("anchor") || s.EqualsIgnoreCase("namedanchor");
-}
-
-static bool
 IsNamedAnchorTag(const nsAtom& aTagName)
 {
   return aTagName.Equals(NS_LITERAL_STRING("anchor")) ||
          aTagName.Equals(NS_LITERAL_STRING("namedanchor"));
 }
 
 template EditorDOMPoint
 HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(
@@ -1101,34 +1089,48 @@ HTMLEditor::OnInputLineBreak()
 
 nsresult
 HTMLEditor::TabInTable(bool inIsShift,
                        bool* outHandled)
 {
   NS_ENSURE_TRUE(outHandled, NS_ERROR_NULL_POINTER);
   *outHandled = false;
 
+  RefPtr<Selection> selection = GetSelection();
+  if (NS_WARN_IF(!selection)) {
+    // Do nothing if we didn't find a table cell.
+    return NS_OK;
+  }
+
   // Find enclosing table cell from selection (cell may be selected element)
-  nsCOMPtr<Element> cellElement =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
-  // Do nothing -- we didn't find a table cell
-  NS_ENSURE_TRUE(cellElement, NS_OK);
+  Element* cellElement =
+    GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
+  if (NS_WARN_IF(!cellElement)) {
+    // Do nothing if we didn't find a table cell.
+    return NS_OK;
+  }
 
   // find enclosing table
-  nsCOMPtr<Element> table = GetEnclosingTable(cellElement);
-  NS_ENSURE_TRUE(table, NS_OK);
+  RefPtr<Element> table = GetEnclosingTable(cellElement);
+  if (NS_WARN_IF(!table)) {
+    return NS_OK;
+  }
 
   // advance to next cell
   // first create an iterator over the table
   nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
   nsresult rv = iter->Init(table);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   // position iter at block
   rv = iter->PositionAt(cellElement);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   nsCOMPtr<nsINode> node;
   do {
     if (inIsShift) {
       iter->Prev();
     } else {
       iter->Next();
     }
@@ -2522,115 +2524,129 @@ HTMLEditor::Align(const nsAString& aAlig
    rules->WillDoAction(selection, subActionInfo, &cancel, &handled);
   if (cancel || NS_FAILED(rv)) {
     return rv;
   }
 
   return rules->DidDoAction(selection, subActionInfo, rv);
 }
 
-already_AddRefed<Element>
-HTMLEditor::GetElementOrParentByTagName(const nsAString& aTagName,
+Element*
+HTMLEditor::GetElementOrParentByTagName(const nsAtom& aTagName,
                                         nsINode* aNode)
 {
-  MOZ_ASSERT(!aTagName.IsEmpty());
-
-  nsCOMPtr<nsINode> node = aNode;
+  MOZ_ASSERT(&aTagName != nsGkAtoms::_empty);
+
+  if (aNode) {
+    return GetElementOrParentByTagNameInternal(aTagName, *aNode);
+  }
+  RefPtr<Selection> selection = GetSelection();
+  if (NS_WARN_IF(!selection)) {
+    return nullptr;
+  }
+  return GetElementOrParentByTagNameAtSelection(*selection, aTagName);
+}
+
+Element*
+HTMLEditor::GetElementOrParentByTagNameAtSelection(Selection& aSelection,
+                                                   const nsAtom& aTagName)
+{
+  MOZ_ASSERT(&aTagName != nsGkAtoms::_empty);
+
+  // If no node supplied, get it from anchor node of current selection
+  const EditorRawDOMPoint atAnchor(aSelection.AnchorRef());
+  if (NS_WARN_IF(!atAnchor.IsSet())) {
+    return nullptr;
+  }
+
+  // Try to get the actual selected node
+  nsCOMPtr<nsINode> node;
+  if (atAnchor.GetContainer()->HasChildNodes() &&
+      atAnchor.GetContainerAsContent()) {
+    node = atAnchor.GetChild();
+  }
+  // Anchor node is probably a text node - just use that
   if (!node) {
-    // If no node supplied, get it from anchor node of current selection
-    RefPtr<Selection> selection = GetSelection();
-    if (NS_WARN_IF(!selection)) {
-      return nullptr;
-    }
-
-    const EditorDOMPoint atAnchor(selection->AnchorRef());
-    if (NS_WARN_IF(!atAnchor.IsSet())) {
+    node = atAnchor.GetContainer();
+    if (NS_WARN_IF(!node)) {
       return nullptr;
     }
-
-    // Try to get the actual selected node
-    if (atAnchor.GetContainer()->HasChildNodes() &&
-        atAnchor.GetContainerAsContent()) {
-      node = atAnchor.GetChild();
-    }
-    // Anchor node is probably a text node - just use that
-    if (!node) {
-      node = atAnchor.GetContainer();
-    }
-  }
-
-  nsCOMPtr<Element> current;
-  if (node->IsElement()) {
-    current = node->AsElement();
-  } else if (node->GetParentElement()) {
-    current = node->GetParentElement();
-  } else {
+  }
+  return GetElementOrParentByTagNameInternal(aTagName, *node);
+}
+
+Element*
+HTMLEditor::GetElementOrParentByTagNameInternal(const nsAtom& aTagName,
+                                                nsINode& aNode)
+{
+  MOZ_ASSERT(&aTagName != nsGkAtoms::_empty);
+
+  Element* currentElement =
+    aNode.IsElement() ? aNode.AsElement() : aNode.GetParentElement();
+  if (NS_WARN_IF(!currentElement)) {
     // Neither aNode nor its parent is an element, so no ancestor is
-    MOZ_ASSERT(!node->GetParentNode() ||
-               !node->GetParentNode()->GetParentNode());
+    MOZ_ASSERT(!aNode.GetParentNode() ||
+               !aNode.GetParentNode()->GetParentNode());
     return nullptr;
   }
 
-  nsAutoString tagName(aTagName);
-  ToLowerCase(tagName);
-  bool getLink = IsLinkTag(tagName);
-  bool getNamedAnchor = IsNamedAnchorTag(tagName);
-  if (getLink || getNamedAnchor) {
-    tagName.Assign('a');
-  }
-  bool findTableCell = tagName.EqualsLiteral("td");
-  bool findList = tagName.EqualsLiteral("list");
-
-  for (; current; current = current->GetParentElement()) {
+  bool getLink = IsLinkTag(aTagName);
+  bool getNamedAnchor = IsNamedAnchorTag(aTagName);
+  const nsAtom& tagName = getLink || getNamedAnchor ? *nsGkAtoms::a : aTagName;
+  for (; currentElement; currentElement = currentElement->GetParentElement()) {
     // Test if we have a link (an anchor with href set)
-    if ((getLink && HTMLEditUtils::IsLink(current)) ||
-        (getNamedAnchor && HTMLEditUtils::IsNamedAnchor(current))) {
-      return current.forget();
+    if ((getLink && HTMLEditUtils::IsLink(currentElement)) ||
+        (getNamedAnchor && HTMLEditUtils::IsNamedAnchor(currentElement))) {
+      return currentElement;
     }
-    if (findList) {
+    if (&tagName == nsGkAtoms::list_) {
       // Match "ol", "ul", or "dl" for lists
-      if (HTMLEditUtils::IsList(current)) {
-        return current.forget();
+      if (HTMLEditUtils::IsList(currentElement)) {
+        return currentElement;
       }
-    } else if (findTableCell) {
+    } else if (&tagName == nsGkAtoms::td) {
       // Table cells are another special case: match either "td" or "th"
-      if (HTMLEditUtils::IsTableCell(current)) {
-        return current.forget();
+      if (HTMLEditUtils::IsTableCell(currentElement)) {
+        return currentElement;
       }
-    } else if (current->NodeName().Equals(tagName,
-                   nsCaseInsensitiveStringComparator())) {
-      return current.forget();
+    } else if (&tagName == currentElement->NodeInfo()->NameAtom()) {
+      return currentElement;
     }
 
     // Stop searching if parent is a body tag.  Note: Originally used IsRoot to
     // stop at table cells, but that's too messy when you are trying to find
     // the parent table
-    if (current->GetParentElement() &&
-        current->GetParentElement()->IsHTMLElement(nsGkAtoms::body)) {
+    if (currentElement->GetParentElement() &&
+        currentElement->GetParentElement()->IsHTMLElement(nsGkAtoms::body)) {
       break;
     }
   }
 
   return nullptr;
 }
 
 NS_IMETHODIMP
 HTMLEditor::GetElementOrParentByTagName(const nsAString& aTagName,
                                         nsINode* aNode,
                                         Element** aReturn)
 {
-  NS_ENSURE_TRUE(!aTagName.IsEmpty(), NS_ERROR_NULL_POINTER);
-  NS_ENSURE_TRUE(aReturn, NS_ERROR_NULL_POINTER);
-
-  RefPtr<Element> parent = GetElementOrParentByTagName(aTagName, aNode);
-
+  if (NS_WARN_IF(aTagName.IsEmpty()) ||
+      NS_WARN_IF(!aReturn)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  RefPtr<nsAtom> tagName = GetLowerCaseNameAtom(aTagName);
+  if (NS_WARN_IF(!tagName) || NS_WARN_IF(tagName == nsGkAtoms::_empty)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  RefPtr<Element> parent = GetElementOrParentByTagName(*tagName, aNode);
   if (!parent) {
     return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
   }
-
   parent.forget(aReturn);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLEditor::GetSelectedElement(const nsAString& aTagName,
                                nsISupports** aReturn)
 {
@@ -2702,32 +2718,32 @@ HTMLEditor::GetSelectedElement(Selection
   if (isLinkTag) {
     // Link tag is a special case - we return the anchor node
     //  found for any selection that is totally within a link,
     //  included a collapsed selection (just a caret in a link)
     const RangeBoundary& anchor = aSelection.AnchorRef();
     const RangeBoundary& focus = aSelection.FocusRef();
     // Link node must be the same for both ends of selection
     if (anchor.IsSet()) {
-      RefPtr<Element> parentLinkOfAnchor =
-        GetElementOrParentByTagName(NS_LITERAL_STRING("href"),
-                                    anchor.Container());
+      Element* parentLinkOfAnchor =
+        GetElementOrParentByTagNameInternal(*nsGkAtoms::href,
+                                            *anchor.Container());
       // XXX: ERROR_HANDLING  can parentLinkOfAnchor be null?
       if (parentLinkOfAnchor) {
         if (aSelection.IsCollapsed()) {
           // We have just a caret in the link.
-          return parentLinkOfAnchor.forget();
+          return do_AddRef(parentLinkOfAnchor);
         }
         if (focus.IsSet()) {
           // Link node must be the same for both ends of selection.
-          RefPtr<Element> parentLinkOfFocus =
-            GetElementOrParentByTagName(NS_LITERAL_STRING("href"),
-                                        focus.Container());
+          Element* parentLinkOfFocus =
+            GetElementOrParentByTagNameInternal(*nsGkAtoms::href,
+                                                *focus.Container());
           if (parentLinkOfFocus == parentLinkOfAnchor) {
-            return parentLinkOfAnchor.forget();
+            return do_AddRef(parentLinkOfAnchor);
           }
         }
       } else if (anchor.GetChildAtOffset() && focus.GetChildAtOffset()) {
         // Check if link node is the only thing selected
         if (HTMLEditUtils::IsLink(anchor.GetChildAtOffset()) &&
             anchor.Container() == focus.Container() &&
             focus.GetChildAtOffset() ==
               anchor.GetChildAtOffset()->GetNextSibling()) {
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -317,18 +317,38 @@ public:
 
   /**
    * Modifies the table containing the selection according to the
    * activation of an inline table editing UI element
    * @param aUIAnonymousElement [IN] the inline table editing UI element
    */
   nsresult DoInlineTableEditingAction(const Element& aUIAnonymousElement);
 
-  already_AddRefed<Element>
-  GetElementOrParentByTagName(const nsAString& aTagName, nsINode* aNode);
+  /**
+   * GetElementOrParentByTagName() looks for an element node whose name matches
+   * aTagName from aNode or anchor node of Selection to <body> element.
+   *
+   * @param aTagName        The tag name which you want to look for.
+   *                        Must not be nsGkAtoms::_empty.
+   *                        If nsGkAtoms::list, the result may be <ul>, <ol> or
+   *                        <dl> element.
+   *                        If nsGkAtoms::td, the result may be <td> or <th>.
+   *                        If nsGkAtoms::href, the result may be <a> element
+   *                        which has "href" attribute with non-empty value.
+   *                        If nsGkAtoms::anchor or atom of "namedanchor", the
+   *                        result may be <a> which has "name" attribute with
+   *                        non-empty value.
+   * @param aNode           If non-nullptr, this starts to look for the result
+   *                        from it.  Otherwise, i.e., nullptr, starts from
+   *                        anchor node of Selection.
+   * @return                If an element which matches aTagName, returns
+   *                        an Element.  Otherwise, nullptr.
+   */
+  Element*
+  GetElementOrParentByTagName(const nsAtom& aTagName, nsINode* aNode);
 
   /**
     * Get an active editor's editing host in DOM window.  If this editor isn't
     * active in the DOM window, this returns NULL.
     */
   Element* GetActiveEditingHost() const;
 
 protected: // May be called by friends.
@@ -810,16 +830,60 @@ protected: // Shouldn't be used by frien
   /**
    * CollapseSelectionAfter() collapses Selection after aElement.
    * If aElement is an orphan node or not in editing host, returns error.
    */
   nsresult CollapseSelectionAfter(Selection& aSelection,
                                   Element& aElement);
 
   /**
+   * GetElementOrParentByTagNameAtSelection() looks for an element node whose
+   * name matches aTagName from anchor node of Selection to <body> element.
+   *
+   * @param aSelection      The Selection for this editor.
+   * @param aTagName        The tag name which you want to look for.
+   *                        Must not be nsGkAtoms::_empty.
+   *                        If nsGkAtoms::list, the result may be <ul>, <ol> or
+   *                        <dl> element.
+   *                        If nsGkAtoms::td, the result may be <td> or <th>.
+   *                        If nsGkAtoms::href, the result may be <a> element
+   *                        which has "href" attribute with non-empty value.
+   *                        If nsGkAtoms::anchor or atom of "namedanchor", the
+   *                        result may be <a> which has "name" attribute with
+   *                        non-empty value.
+   * @return                If an element which matches aTagName, returns
+   *                        an Element.  Otherwise, nullptr.
+   */
+  Element*
+  GetElementOrParentByTagNameAtSelection(Selection& aSelection,
+                                         const nsAtom& aTagName);
+
+  /**
+   * GetElementOrParentByTagNameInternal() looks for an element node whose
+   * name matches aTagName from aNode to <body> element.
+   *
+   * @param aTagName        The tag name which you want to look for.
+   *                        Must not be nsGkAtoms::_empty.
+   *                        If nsGkAtoms::list, the result may be <ul>, <ol> or
+   *                        <dl> element.
+   *                        If nsGkAtoms::td, the result may be <td> or <th>.
+   *                        If nsGkAtoms::href, the result may be <a> element
+   *                        which has "href" attribute with non-empty value.
+   *                        If nsGkAtoms::anchor or atom of "namedanchor", the
+   *                        result may be <a> which has "name" attribute with
+   *                        non-empty value.
+   * @param aNode           Start node to look for the element.
+   * @return                If an element which matches aTagName, returns
+   *                        an Element.  Otherwise, nullptr.
+   */
+  Element*
+  GetElementOrParentByTagNameInternal(const nsAtom& aTagName,
+                                      nsINode& aNode);
+
+  /**
    * GetSelectedElement() returns an element node which is in first range of
    * aSelection.  The rule is a little bit complicated and the rules do not
    * make sense except in a few cases.  If you want to use this newly,
    * you should create new method instead.  This needs to be here for
    * comm-central.
    * The rules are:
    *   1. If Selection selects an element node, i.e., both containers are
    *      same node and start offset and end offset is start offset + 1.
--- a/editor/libeditor/HTMLEditorEventListener.cpp
+++ b/editor/libeditor/HTMLEditorEventListener.cpp
@@ -137,19 +137,18 @@ HTMLEditorEventListener::MouseDown(Mouse
     nsCOMPtr<nsINode> node = do_QueryInterface(target);
     if (node && !nodeIsInSelection) {
       if (!element) {
         if (isContextClick) {
           // Set the selection to the point under the mouse cursor:
           selection->Collapse(parent, offset);
         } else {
           // Get enclosing link if in text so we can select the link
-          RefPtr<Element> linkElement =
-            htmlEditor->GetElementOrParentByTagName(NS_LITERAL_STRING("href"),
-                                                    node);
+          Element* linkElement =
+            htmlEditor->GetElementOrParentByTagName(*nsGkAtoms::href, node);
           if (linkElement) {
             element = linkElement;
           }
         }
       }
       // Select entire element clicked on if NOT within an existing selection
       //   and not the entire body, or table-related elements
       if (element) {
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -219,26 +219,27 @@ HTMLEditor::InsertTableCell(int32_t aNum
   //     InsertNodeWithTransaction() or CreateElementWithDefaults().
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLEditor::GetFirstRow(Element* aTableElement,
                         nsINode** aRowNode)
 {
-  NS_ENSURE_TRUE(aRowNode, NS_ERROR_NULL_POINTER);
+  if (NS_WARN_IF(!aTableElement) || NS_WARN_IF(!aRowNode)) {
+    return NS_ERROR_INVALID_ARG;
+  }
 
   *aRowNode = nullptr;
 
-  nsCOMPtr<nsINode> tableElement = aTableElement;
-  NS_ENSURE_TRUE(tableElement, NS_ERROR_NULL_POINTER);
-
-  tableElement = GetElementOrParentByTagName(NS_LITERAL_STRING("table"),
-                                             tableElement);
-  NS_ENSURE_TRUE(tableElement, NS_ERROR_NULL_POINTER);
+  Element* tableElement =
+    GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aTableElement);
+  if (NS_WARN_IF(!tableElement)) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsCOMPtr<nsIContent> tableChild = tableElement->GetFirstChild();
   while (tableChild) {
     if (tableChild->IsHTMLElement(nsGkAtoms::tr)) {
       // Found a row directly under <table>
       tableChild.forget(aRowNode);
       return NS_OK;
     }
@@ -597,29 +598,30 @@ HTMLEditor::InsertTableRow(int32_t aNumb
       // Save cell from the last row that we will use below
       if (!cellForRowParent && curStartRowIndex == lastRow) {
         cellForRowParent = curCell;
       }
     }
   }
 
   if (cellsInRow > 0) {
-
-    NS_NAMED_LITERAL_STRING(trStr, "tr");
-    if (!cellForRowParent) {
+    if (NS_WARN_IF(!cellForRowParent)) {
       return NS_ERROR_FAILURE;
     }
-
-    nsCOMPtr<Element> parentRow =
-      GetElementOrParentByTagName(trStr, cellForRowParent);
-    NS_ENSURE_TRUE(parentRow, NS_ERROR_NULL_POINTER);
+    Element* parentRow =
+      GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cellForRowParent);
+    if (NS_WARN_IF(!parentRow)) {
+      return NS_ERROR_FAILURE;
+    }
 
     // The row parent and offset where we will insert new row
     nsCOMPtr<nsINode> parentOfRow = parentRow->GetParentNode();
-    NS_ENSURE_TRUE(parentOfRow, NS_ERROR_NULL_POINTER);
+    if (NS_WARN_IF(!parentOfRow)) {
+      return NS_ERROR_FAILURE;
+    }
     int32_t newRowOffset = parentOfRow->ComputeIndexOf(parentRow);
 
     // Adjust for when adding past the end
     if (aAfter && startRowIndex >= rowCount) {
       newRowOffset++;
     }
 
     for (int32_t row = 0; row < aNumber; row++) {
@@ -846,22 +848,26 @@ HTMLEditor::DeleteTableCell(int32_t aNum
     for (int32_t i = 0; i < aNumber; i++) {
       rv = GetCellContext(getter_AddRefs(selection),
                           getter_AddRefs(table),
                           getter_AddRefs(cell),
                           nullptr, nullptr,
                           &startRowIndex, &startColIndex);
       NS_ENSURE_SUCCESS(rv, rv);
       // Don't fail if no cell found
-      NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
+      if (NS_WARN_IF(!cell)) {
+        return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
+      }
 
       if (GetNumberOfCellsInRow(table, startRowIndex) == 1) {
-        RefPtr<Element> parentRow =
-          GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cell);
-        NS_ENSURE_TRUE(parentRow, NS_ERROR_NULL_POINTER);
+        Element* parentRow =
+          GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cell);
+        if (NS_WARN_IF(!parentRow)) {
+          return NS_ERROR_FAILURE;
+        }
 
         // We should delete the row instead,
         //  but first check if its the only row left
         //  so we can delete the entire table
         int32_t rowCount, colCount;
         rv = GetTableSize(table, &rowCount, &colCount);
         NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1082,20 +1088,20 @@ HTMLEditor::DeleteColumn(Element* aTable
           DeleteCellContents(cell);
         }
         // To next cell in column
         rowIndex += actualRowSpan;
       } else {
         // Delete the cell
         if (GetNumberOfCellsInRow(aTable, rowIndex) == 1) {
           // Only 1 cell in row - delete the row
-          RefPtr<Element> parentRow =
-            GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cell);
-          if (!parentRow) {
-            return NS_ERROR_NULL_POINTER;
+          Element* parentRow =
+            GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cell);
+          if (NS_WARN_IF(!parentRow)) {
+            return NS_ERROR_FAILURE;
           }
 
           //  But first check if its the only row left
           //  so we can delete the entire table
           //  (This should never happen but it's the safe thing to do)
           int32_t rowCount, colCount;
           rv = GetTableSize(aTable, &rowCount, &colCount);
           NS_ENSURE_SUCCESS(rv, rv);
@@ -1299,22 +1305,23 @@ HTMLEditor::DeleteRow(Element* aTable,
         }
       }
       // Skip over other columns spanned by this cell
       colIndex += actualColSpan;
     }
   } while (cell);
 
   // Things are messed up if we didn't find a cell in the row!
-  NS_ENSURE_TRUE(cellInDeleteRow, NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!cellInDeleteRow)) {
+    return NS_ERROR_FAILURE;
+  }
 
   // Delete the entire row
   RefPtr<Element> parentRow =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cellInDeleteRow);
-
+    GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cellInDeleteRow);
   if (parentRow) {
     rv = DeleteNodeWithTransaction(*parentRow);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // Now we can set new rowspans for cells stored above
@@ -1327,57 +1334,77 @@ HTMLEditor::DeleteRow(Element* aTable,
   }
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 HTMLEditor::SelectTable()
 {
+  RefPtr<Selection> selection = GetSelection();
+  if (NS_WARN_IF(!selection)) {
+    return NS_OK; // Don't fail if we didn't find a table.
+  }
   RefPtr<Element> table =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr);
-  // Don't fail if we didn't find a table
-  NS_ENSURE_TRUE(table, NS_OK);
+    GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
+  if (NS_WARN_IF(!table)) {
+    return NS_OK; // Don't fail if we didn't find a table.
+  }
 
   nsresult rv = ClearSelection();
   if (NS_FAILED(rv)) {
     return rv;
   }
   return AppendNodeToSelectionAsRange(table);
 }
 
 NS_IMETHODIMP
 HTMLEditor::SelectTableCell()
 {
+  RefPtr<Selection> selection = GetSelection();
+  if (NS_WARN_IF(!selection)) {
+    return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
+  }
   RefPtr<Element> cell =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
-  NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
+    GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
+  if (NS_WARN_IF(!cell)) {
+    return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
+  }
 
   nsresult rv = ClearSelection();
   if (NS_FAILED(rv)) {
     return rv;
   }
   return AppendNodeToSelectionAsRange(cell);
 }
 
 NS_IMETHODIMP
 HTMLEditor::SelectBlockOfCells(Element* aStartCell,
                                Element* aEndCell)
 {
-  NS_ENSURE_TRUE(aStartCell && aEndCell, NS_ERROR_NULL_POINTER);
+  if (NS_WARN_IF(!aStartCell) || NS_WARN_IF(!aEndCell)) {
+    return NS_ERROR_INVALID_ARG;
+  }
 
   RefPtr<Selection> selection = GetSelection();
-  NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
-
-  NS_NAMED_LITERAL_STRING(tableStr, "table");
-  RefPtr<Element> table = GetElementOrParentByTagName(tableStr, aStartCell);
-  NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
-
-  RefPtr<Element> endTable = GetElementOrParentByTagName(tableStr, aEndCell);
-  NS_ENSURE_TRUE(endTable, NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!selection)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  RefPtr<Element> table =
+    GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aStartCell);
+  if (NS_WARN_IF(!table)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  RefPtr<Element> endTable =
+    GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aEndCell);
+  if (NS_WARN_IF(!endTable)) {
+    return NS_ERROR_FAILURE;
+  }
 
   // We can only select a block if within the same table,
   //  so do nothing if not within one table
   if (table != endTable) {
     return NS_OK;
   }
 
   int32_t startRowIndex, startColIndex, endRowIndex, endColIndex;
@@ -1452,38 +1479,40 @@ HTMLEditor::SelectBlockOfCells(Element* 
   // NS_OK, otherwise, the last failure of GetCellDataAt() or
   // AppendNodeToSelectionAsRange().
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLEditor::SelectAllTableCells()
 {
+  RefPtr<Selection> selection = GetSelection();
+  if (NS_WARN_IF(!selection)) {
+    return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
+  }
   RefPtr<Element> cell =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
-
-  // Don't fail if we didn't find a cell
-  NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
+    GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
+  if (NS_WARN_IF(!cell)) {
+    // Don't fail if we didn't find a cell.
+    return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
+  }
 
   RefPtr<Element> startCell = cell;
 
   // Get parent table
   RefPtr<Element> table =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("table"), cell);
-  if (!table) {
-    return NS_ERROR_NULL_POINTER;
+    GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *cell);
+  if (NS_WARN_IF(!table)) {
+    return NS_ERROR_FAILURE;
   }
 
   int32_t rowCount, colCount;
   nsresult rv = GetTableSize(table, &rowCount, &colCount);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  RefPtr<Selection> selection = GetSelection();
-  NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
-
   // Suppress nsISelectionListener notification
   //  until all selection changes are finished
   SelectionBatcher selectionBatcher(selection);
 
   // It is now safe to clear the selection
   // BE SURE TO RESET IT BEFORE LEAVING!
   rv = ClearSelection();
 
@@ -1517,29 +1546,35 @@ HTMLEditor::SelectAllTableCells()
   // NS_OK, otherwise, the error of ClearSelection() when there is no column or
   // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLEditor::SelectTableRow()
 {
+  RefPtr<Selection> selection = GetSelection();
+  if (NS_WARN_IF(!selection)) {
+    // Don't fail if we didn't find a cell.
+    return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
+  }
   RefPtr<Element> cell =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
-
-  // Don't fail if we didn't find a cell
-  NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
+    GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
+  if (NS_WARN_IF(!cell)) {
+    // Don't fail if we didn't find a cell.
+    return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
+  }
+
   RefPtr<Element> startCell = cell;
 
   // Get table and location of cell:
-  RefPtr<Selection> selection;
   RefPtr<Element> table;
   int32_t startRowIndex, startColIndex;
 
-  nsresult rv = GetCellContext(getter_AddRefs(selection),
+  nsresult rv = GetCellContext(nullptr,
                                getter_AddRefs(table),
                                getter_AddRefs(cell),
                                nullptr, nullptr,
                                &startRowIndex, &startColIndex);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
 
   int32_t rowCount, colCount;
@@ -1585,30 +1620,35 @@ HTMLEditor::SelectTableRow()
   // NS_OK, otherwise, the error of ClearSelection() when there is no column or
   // the last failure of GetCellDataAt() or AppendNodeToSelectionAsRange().
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLEditor::SelectTableColumn()
 {
+  RefPtr<Selection> selection = GetSelection();
+  if (NS_WARN_IF(!selection)) {
+    // Don't fail if we didn't find a cell.
+    return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
+  }
   RefPtr<Element> cell =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
-
-  // Don't fail if we didn't find a cell
-  NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
+    GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
+  if (NS_WARN_IF(!cell)) {
+    // Don't fail if we didn't find a cell.
+    return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
+  }
 
   RefPtr<Element> startCell = cell;
 
   // Get location of cell:
-  RefPtr<Selection> selection;
   RefPtr<Element> table;
   int32_t startRowIndex, startColIndex;
 
-  nsresult rv = GetCellContext(getter_AddRefs(selection),
+  nsresult rv = GetCellContext(nullptr,
                                getter_AddRefs(table),
                                getter_AddRefs(cell),
                                nullptr, nullptr,
                                &startRowIndex, &startColIndex);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
 
   int32_t rowCount, colCount;
@@ -2464,23 +2504,28 @@ HTMLEditor::FixBadColSpan(Element* aTabl
   }
   return GetTableSize(aTable, &rowCount, &aNewColCount);
 }
 
 NS_IMETHODIMP
 HTMLEditor::NormalizeTable(Element* aTable)
 {
   RefPtr<Selection> selection = GetSelection();
-  NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!selection)) {
+    return NS_ERROR_FAILURE;
+  }
 
   RefPtr<Element> table =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("table"),
-                                aTable);
-  // Don't fail if we didn't find a table
-  NS_ENSURE_TRUE(table, NS_OK);
+    aTable ?
+      GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aTable) :
+      GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
+  if (NS_WARN_IF(!table)) {
+    // Don't fail if we didn't find a table.
+    return NS_OK;
+  }
 
   int32_t rowCount, colCount, rowIndex, colIndex;
   nsresult rv = GetTableSize(table, &rowCount, &colCount);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Save current selection
   AutoSelectionRestorer selectionRestorer(selection, this);
 
@@ -2556,21 +2601,29 @@ NS_IMETHODIMP
 HTMLEditor::GetCellIndexes(Element* aCell,
                            int32_t* aRowIndex,
                            int32_t* aColIndex)
 {
   NS_ENSURE_ARG_POINTER(aRowIndex);
   *aColIndex=0; // initialize out params
   NS_ENSURE_ARG_POINTER(aColIndex);
   *aRowIndex=0;
-  RefPtr<Element> cell; // Needs to stay alive while we're using
-                        // aCell, since it may be keeping it alive.
+  // Needs to stay alive while we're using aCell, since it may be keeping it
+  // alive.
+  // XXX Looks like it's safe to use raw pointer here.  However, layout code
+  //     change won't be handled by editor developers so that it must be safe
+  //     to keep using RefPtr here.
+  RefPtr<Element> cell;
   if (!aCell) {
+    RefPtr<Selection> selection = GetSelection();
+    if (NS_WARN_IF(!selection)) {
+      return NS_ERROR_FAILURE;
+    }
     // Get the selected cell or the cell enclosing the selection anchor
-    cell = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
+    cell = GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
     if (!cell) {
       return NS_ERROR_FAILURE;
     }
     aCell = cell;
   }
 
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
@@ -2627,22 +2680,41 @@ HTMLEditor::GetTableSize(Element* aTable
                          int32_t* aRowCount,
                          int32_t* aColCount)
 {
   NS_ENSURE_ARG_POINTER(aRowCount);
   NS_ENSURE_ARG_POINTER(aColCount);
   *aRowCount = 0;
   *aColCount = 0;
   // Get the selected talbe or the table enclosing the selection anchor
-  RefPtr<Element> table =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("table"), aTable);
-  NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
+  // XXX Looks like it's safe to use raw pointer here.  However, layout code
+  //     change won't be handled by editor developers so that it must be safe
+  //     to keep using RefPtr here.
+  RefPtr<Element> table;
+  if (aTable) {
+    table = GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aTable);
+    if (NS_WARN_IF(!table)) {
+      return NS_ERROR_FAILURE;
+    }
+  } else {
+    RefPtr<Selection> selection = GetSelection();
+    if (NS_WARN_IF(!selection)) {
+      return NS_ERROR_FAILURE;
+    }
+    table =
+      GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
+    if (NS_WARN_IF(!table)) {
+      return NS_ERROR_FAILURE;
+    }
+  }
 
   nsTableWrapperFrame* tableFrame = do_QueryFrame(table->GetPrimaryFrame());
-  NS_ENSURE_TRUE(tableFrame, NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!tableFrame)) {
+    return NS_ERROR_FAILURE;
+  }
 
   *aRowCount = tableFrame->GetRowCount();
   *aColCount = tableFrame->GetColCount();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -2672,20 +2744,29 @@ HTMLEditor::GetCellDataAt(Element* aTabl
   *aRowSpan = 0;
   *aColSpan = 0;
   *aActualRowSpan = 0;
   *aActualColSpan = 0;
   *aIsSelected = false;
 
   *aCell = nullptr;
 
-  RefPtr<Element> table; // needs to live while we use aTable
+  // needs to live while we use aTable
+  // XXX Really? Looks like it's safe to use raw pointer here.
+  //     However, layout code change won't be handled by editor developers
+  //     so that it must be safe to keep using RefPtr here.
+  RefPtr<Element> table;
   if (!aTable) {
-    // Get the selected table or the table enclosing the selection anchor
-    table = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr);
+    RefPtr<Selection> selection = GetSelection();
+    if (NS_WARN_IF(!selection)) {
+      return NS_ERROR_FAILURE;
+    }
+    // Get the selected table or the table enclosing the selection anchor.
+    table =
+      GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
     if (!table) {
       return NS_ERROR_FAILURE;
     }
     aTable = table;
   }
 
   nsTableWrapperFrame* tableFrame = GetTableFrame(aTable);
   NS_ENSURE_TRUE(tableFrame, NS_ERROR_FAILURE);
@@ -2714,21 +2795,32 @@ NS_IMETHODIMP
 HTMLEditor::GetCellAt(Element* aTable,
                       int32_t aRowIndex,
                       int32_t aColIndex,
                       Element** aCell)
 {
   NS_ENSURE_ARG_POINTER(aCell);
   *aCell = nullptr;
 
-  RefPtr<Element> table; // Needs to live as long as we use aTable
+  // Needs to live as long as we use aTable
+  // XXX Really? Looks like it's safe to use raw pointer here.
+  //     However, layout code change won't be handled by editor developers
+  //     so that it must be safe to keep using RefPtr here.
+  RefPtr<Element> table;
   if (!aTable) {
-    // Get the selected table or the table enclosing the selection anchor
-    table = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr);
-    NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
+    RefPtr<Selection> selection = GetSelection();
+    if (NS_WARN_IF(!selection)) {
+      return NS_ERROR_FAILURE;
+    }
+    // Get the selected table or the table enclosing the selection anchor.
+    table =
+      GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
+    if (NS_WARN_IF(!table)) {
+      return NS_ERROR_FAILURE;
+    }
     aTable = table;
   }
 
   nsTableWrapperFrame* tableFrame = GetTableFrame(aTable);
   if (!tableFrame) {
     *aCell = nullptr;
     return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
   }
@@ -2786,17 +2878,19 @@ HTMLEditor::GetCellContext(Selection** a
   if (aRowIndex) {
     *aRowIndex = 0;
   }
   if (aColIndex) {
     *aColIndex = 0;
   }
 
   RefPtr<Selection> selection = GetSelection();
-  NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!selection)) {
+    return NS_ERROR_FAILURE;
+  }
 
   if (aSelection) {
     *aSelection = selection.get();
     NS_ADDREF(*aSelection);
   }
   RefPtr<Element> table;
   RefPtr<Element> cell;
 
@@ -2824,27 +2918,30 @@ HTMLEditor::GetCellContext(Selection** a
       }
       return NS_OK;
     }
     if (!tagName.EqualsLiteral("td")) {
       return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
     }
 
     // We found a cell
+    MOZ_ASSERT(cellOrTableElement);
     cell = cellOrTableElement;
   }
   if (aCell) {
     // we don't want to cell.forget() here, because we use it below.
     *aCell = do_AddRef(cell).take();
   }
 
   // Get containing table
-  table = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), cell);
-  // Cell must be in a table, so fail if not found
-  NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
+  table = GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *cell);
+  if (NS_WARN_IF(!table)) {
+    // Cell must be in a table, so fail if not found
+    return NS_ERROR_FAILURE;
+  }
   if (aTable) {
     table.forget(aTable);
   }
 
   // Get the rest of the related data only if requested
   if (aRowIndex || aColIndex) {
     int32_t rowIndex, colIndex;
     // Get current cell location so we can put caret back there when done
@@ -3152,55 +3249,54 @@ HTMLEditor::GetSelectedOrParentTableElem
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
 
   // Try to get the first selected cell
   RefPtr<Element> tableOrCellElement;
   nsresult rv = GetFirstSelectedCell(nullptr,
                                      getter_AddRefs(tableOrCellElement));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  NS_NAMED_LITERAL_STRING(tdName, "td");
-
   if (tableOrCellElement) {
       // Each cell is in its own selection range,
       //  so count signals multiple-cell selection
       *aSelectedCount = selection->RangeCount();
-      aTagName = tdName;
+      aTagName = NS_LITERAL_STRING("td");
   } else {
     nsCOMPtr<nsINode> anchorNode = selection->GetAnchorNode();
     if (NS_WARN_IF(!anchorNode)) {
       return NS_ERROR_FAILURE;
     }
 
     // Get child of anchor node, if exists
     if (anchorNode->HasChildNodes()) {
       nsINode* selectedNode = selection->GetChildAtAnchorOffset();
       if (selectedNode) {
         if (selectedNode->IsHTMLElement(nsGkAtoms::td)) {
           tableOrCellElement = selectedNode->AsElement();
-          aTagName = tdName;
+          aTagName = NS_LITERAL_STRING("td");
           // Each cell is in its own selection range,
           //  so count signals multiple-cell selection
           *aSelectedCount = selection->RangeCount();
         } else if (selectedNode->IsHTMLElement(nsGkAtoms::table)) {
           tableOrCellElement = selectedNode->AsElement();
           aTagName.AssignLiteral("table");
           *aSelectedCount = 1;
         } else if (selectedNode->IsHTMLElement(nsGkAtoms::tr)) {
           tableOrCellElement = selectedNode->AsElement();
           aTagName.AssignLiteral("tr");
           *aSelectedCount = 1;
         }
       }
     }
     if (!tableOrCellElement) {
       // Didn't find a table element -- find a cell parent
-      tableOrCellElement = GetElementOrParentByTagName(tdName, anchorNode);
+      tableOrCellElement =
+        GetElementOrParentByTagNameInternal(*nsGkAtoms::td, *anchorNode);
       if (tableOrCellElement) {
-        aTagName = tdName;
+        aTagName = NS_LITERAL_STRING("td");
       }
     }
   }
   if (tableOrCellElement) {
     tableOrCellElement.forget(aTableElement);
   }
   return NS_OK;
 }
@@ -3209,18 +3305,30 @@ NS_IMETHODIMP
 HTMLEditor::GetSelectedCellsType(Element* aElement,
                                  uint32_t* aSelectionType)
 {
   NS_ENSURE_ARG_POINTER(aSelectionType);
   *aSelectionType = 0;
 
   // Be sure we have a table element
   //  (if aElement is null, this uses selection's anchor node)
-  RefPtr<Element> table =
-    GetElementOrParentByTagName(NS_LITERAL_STRING("table"), aElement);
+  RefPtr<Element> table;
+  if (aElement) {
+    table = GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aElement);
+  } else {
+    RefPtr<Selection> selection = GetSelection();
+    if (NS_WARN_IF(!selection)) {
+      // If there is no Selection, the following GetTableSize() will return
+      // nullptr if we set first argument to nullptr.  So, let's return error
+      // in this case.
+      return NS_ERROR_FAILURE;
+    }
+    table =
+      GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
+  }
 
   // table might be null at this point, but if so GetTableSize will fail.
   int32_t rowCount, colCount;
   nsresult rv = GetTableSize(table, &rowCount, &colCount);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Traverse all selected cells
   RefPtr<Element> selectedCell;
--- a/editor/nsIHTMLEditor.idl
+++ b/editor/nsIHTMLEditor.idl
@@ -297,34 +297,33 @@ interface nsIHTMLEditor : nsISupports
 
   /**
    * Document me!
    *
    */
   void  align(in AString aAlign);
 
   /**
-   * Return the input node or a parent matching the given aTagName,
-   *   starting the search at the supplied node.
-   * An example of use is for testing if a node is in a table cell
-   *   given a selection anchor node.
+   * GetElementOrParentByTagName() looks for an element node whose name matches
+   * aTagName from aNode or anchor node of Selection to <body> element.
    *
-   * @param aTagName  The HTML tagname
-   *  Special input values:
-   *    Use "href" to get a link node
-   *      (an "A" tag with the "href" attribute set)
-   *    Use "anchor" or "namedanchor" to get a named anchor node
-   *      (an "A" tag with the "name" attribute set)
-   *    Use "list" to get an OL, UL, or DL list node
-   *    Use "td" to get either a TD or TH cell node
-   *
-   * @param aNode    The node in the document to start the search.
-   *     If it is null, the anchor node of the current selection is used.
-   * @return         NS_EDITOR_ELEMENT_NOT_FOUND if an element is not found
-   *                 (passes NS_SUCCEEDED macro)
+   * @param aTagName        The tag name which you want to look for.
+   *                        Must not be empty string.
+   *                        If "list", the result may be <ul>, <ol> or <dl>
+   *                        element.
+   *                        If "td", the result may be <td> or <th>.
+   *                        If "href", the result may be <a> element
+   *                        which has "href" attribute with non-empty value.
+   *                        If "anchor" or "namedanchor", the result may be <a>
+   *                        which has "name" attribute with non-empty value.
+   * @param aNode           If non-null, this starts to look for the result
+   *                        from it.  Otherwise, i.e., null, starts from
+   *                        anchor node of Selection.
+   * @return                If an element which matches aTagName, returns
+   *                        an Element.  Otherwise, nullptr.
    */
   Element getElementOrParentByTagName(in AString aTagName,
                                       in Node aNode);
 
   /**
    * Return an Element only if it is the only node selected,
    *    such as an image, horizontal rule, etc.  The return type is
    *    nsISupports for implementation convenience; the returned object,