Bug 1574852 - part 51: Move `HTMLEditRules::IsInListItem()` to `HTMLEditor` r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 02 Sep 2019 23:59:49 +0000
changeset 491634 fc87b392688b3a516d0ef57c7141d568d8b57d84
parent 491633 d00ed80a7115be7c82a4f49f6512fc31d288aa99
child 491635 16d4fc4754b67bb255ed28f158c00f5818447295
push id94419
push usermasayuki@d-toybox.com
push dateWed, 04 Sep 2019 04:53:54 +0000
treeherderautoland@fc87b392688b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1574852
milestone71.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 1574852 - part 51: Move `HTMLEditRules::IsInListItem()` to `HTMLEditor` r=m_kato Differential Revision: https://phabricator.services.mozilla.com/D44189
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
editor/libeditor/HTMLEditor.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1923,17 +1923,18 @@ EditActionResult HTMLEditRules::WillInse
     if (NS_WARN_IF(!CanHandleEditAction())) {
       return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
     }
     if (NS_WARN_IF(!brElement)) {
       return EditActionIgnored(NS_ERROR_FAILURE);
     }
   }
 
-  nsCOMPtr<Element> listItem = IsInListItem(blockParent);
+  RefPtr<Element> listItem =
+      HTMLEditorRef().GetNearestAncestorListItemElement(*blockParent);
   if (listItem && listItem != host) {
     nsresult rv =
         MOZ_KnownLive(HTMLEditorRef())
             .HandleInsertParagraphInListItemElement(
                 *listItem, MOZ_KnownLive(*atStartOfSelection.GetContainer()),
                 atStartOfSelection.Offset());
     if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
       return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
@@ -5308,17 +5309,21 @@ nsresult HTMLEditRules::IndentAroundSele
     // Not a list item, use blockquote?
 
     // if we are inside a list item, we don't want to blockquote, we want
     // to sublist the list item.  We may have several nodes listed in the
     // array of nodes to act on, that are in the same list item.  Since
     // we only want to indent that li once, we must keep track of the most
     // recent indented list item, and not indent it if we find another node
     // to act on that is still inside the same li.
-    RefPtr<Element> listItem = IsInListItem(curNode);
+    RefPtr<Element> listItem =
+        curNode->IsContent()
+            ? HTMLEditorRef().GetNearestAncestorListItemElement(
+                  *curNode->AsContent())
+            : nullptr;
     if (listItem) {
       if (indentedLI == listItem) {
         // already indented this list item
         continue;
       }
       // check to see if curList is still appropriate.  Which it is if
       // curNode is still right after it in the same list.
       if (curList) {
@@ -7935,31 +7940,33 @@ void HTMLEditRules::MakeTransitionList(
     } else {
       // Same parents: these nodes grew up together
       aTransitionArray[i] = false;
     }
     prevParent = aNodeArray[i]->GetParentNode();
   }
 }
 
-Element* HTMLEditRules::IsInListItem(nsINode* aNode) {
-  MOZ_ASSERT(IsEditorDataAvailable());
-
-  NS_ENSURE_TRUE(aNode, nullptr);
-  if (HTMLEditUtils::IsListItem(aNode)) {
-    return aNode->AsElement();
-  }
-
-  Element* parent = aNode->GetParentElement();
-  while (parent && HTMLEditorRef().IsDescendantOfEditorRoot(parent) &&
-         !HTMLEditUtils::IsTableElement(parent)) {
-    if (HTMLEditUtils::IsListItem(parent)) {
-      return parent;
-    }
-    parent = parent->GetParentElement();
+Element* HTMLEditor::GetNearestAncestorListItemElement(
+    nsIContent& aContent) const {
+  // XXX Why don't we test whether aContent is in an editing host?
+  if (HTMLEditUtils::IsListItem(&aContent)) {
+    return aContent.AsElement();
+  }
+
+  // XXX This loop is too expensive since calling IsDescendantOfEditorRoot()
+  //     a lot.  Rewrite this with caching active editing host and check
+  //     whether we reach it or not.
+  for (Element* parentElement = aContent.GetParentElement();
+       parentElement && IsDescendantOfEditorRoot(parentElement) &&
+       !HTMLEditUtils::IsTableElement(parentElement);
+       parentElement = parentElement->GetParentElement()) {
+    if (HTMLEditUtils::IsListItem(parentElement)) {
+      return parentElement;
+    }
   }
   return nullptr;
 }
 
 nsresult HTMLEditor::HandleInsertParagraphInHeadingElement(Element& aHeader,
                                                            nsINode& aNode,
                                                            int32_t aOffset) {
   MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable());
@@ -10950,17 +10957,21 @@ nsresult HTMLEditRules::PrepareToMakeEle
     }
 
     // Not a list item, use blockquote?  If we are inside a list item, we
     // don't want to blockquote, we want to sublist the list item.  We may
     // have several nodes listed in the array of nodes to act on, that are in
     // the same list item.  Since we only want to indent that li once, we
     // must keep track of the most recent indented list item, and not indent
     // it if we find another node to act on that is still inside the same li.
-    RefPtr<Element> listItem = IsInListItem(curNode);
+    RefPtr<Element> listItem =
+        curNode->IsContent()
+            ? HTMLEditorRef().GetNearestAncestorListItemElement(
+                  *curNode->AsContent())
+            : nullptr;
     if (listItem) {
       if (indentedLI == listItem) {
         // Already indented this list item
         continue;
       }
       // Check to see if curList is still appropriate.  Which it is if
       // curNode is still right after it in the same list.
       if (curList) {
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -445,23 +445,16 @@ class HTMLEditRules : public TextEditRul
   MOZ_CAN_RUN_SCRIPT
   MOZ_MUST_USE nsresult AlignContentsAtSelection(const nsAString& aAlignType);
 
   nsresult AppendInnerFormatNodes(nsTArray<OwningNonNull<nsINode>>& aArray,
                                   nsINode* aNode);
   nsresult GetFormatString(nsINode* aNode, nsAString& outFormat);
 
   /**
-   * If aNode is the descendant of a listitem, return that li.  But table
-   * element boundaries are stoppers on the search.  Also stops on the active
-   * editor host (contenteditable).  Also test if aNode is an li itself.
-   */
-  Element* IsInListItem(nsINode* aNode);
-
-  /**
    * Called after handling edit action.  This may adjust Selection, remove
    * unnecessary empty nodes, create <br> elements if needed, etc.
    */
   MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult AfterEditInner();
 
   /**
    * IndentAroundSelectionWithCSS() indents around Selection with CSS.
    * This method creates AutoSelectionRestorer.  Therefore, each caller
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -1838,16 +1838,23 @@ class HTMLEditor final : public TextEdit
    *                            insert a break.
    * @param aOffset             Typically, Selection start offset in the
    *                            start container, where to insert a break.
    */
   MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
   HandleInsertParagraphInListItemElement(Element& aListItem, nsINode& aNode,
                                          int32_t aOffset);
 
+  /**
+   * GetNearestAncestorListItemElement() returns a list item element if
+   * aContent or its ancestor in editing host is one.  However, this won't
+   * cross table related element.
+   */
+  Element* GetNearestAncestorListItemElement(nsIContent& aContent) const;
+
  protected:  // Called by helper classes.
   virtual void OnStartToHandleTopLevelEditSubAction(
       EditSubAction aEditSubAction, nsIEditor::EDirection aDirection) override;
   MOZ_CAN_RUN_SCRIPT
   virtual void OnEndHandlingTopLevelEditSubAction() override;
 
  protected:  // Shouldn't be used by friend classes
   virtual ~HTMLEditor();