Bug 1574852 - part 101: Move `HTMLEditRules::DidDeleteSelection()` to `HTMLEditor` r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 12 Sep 2019 07:27:30 +0000
changeset 492800 b60769450e9db6e7ffcf7c80efa8d037d5004b66
parent 492799 1f68143604dd0672afdceac272b68074ddee9752
child 492801 123b06288aa05c1ba7435e65e005d131b46f092b
push id95157
push usermasayuki@d-toybox.com
push dateThu, 12 Sep 2019 11:11:33 +0000
treeherderautoland@61cc90ceac61 [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 101: Move `HTMLEditRules::DidDeleteSelection()` to `HTMLEditor` r=m_kato Differential Revision: https://phabricator.services.mozilla.com/D45295
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
editor/libeditor/HTMLEditor.h
editor/libeditor/TextEditRules.cpp
editor/libeditor/TextEditor.cpp
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -485,20 +485,23 @@ nsresult HTMLEditor::OnEndHandlingTopLev
       }
     }
 
     // if we did a ranged deletion or handling backspace key, make sure we have
     // a place to put caret.
     // Note we only want to do this if the overall operation was deletion,
     // not if deletion was done along the way for
     // EditSubAction::eInsertHTMLSource, EditSubAction::eInsertText, etc.
-    // That's why this is here rather than DidDeleteSelection().
+    // That's why this is here rather than DeleteSelectionAsSubAction().
     // However, we shouldn't insert <br> elements if we've already removed
     // empty block parents because users may want to disappear the line by
     // the deletion.
+    // XXX We should make HandleDeleteSelection() store expected container
+    //     for handling this here since we cannot trust current selection is
+    //     collapsed at deleted point.
     if (GetTopLevelEditSubAction() == EditSubAction::eDeleteSelectedContent &&
         TopLevelEditSubActionDataRef().mDidDeleteNonCollapsedRange &&
         !TopLevelEditSubActionDataRef().mDidDeleteEmptyParentBlocks) {
       nsresult rv = InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
           EditorBase::GetStartPoint(*SelectionRefPtr()));
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
@@ -828,25 +831,24 @@ nsresult HTMLEditRules::DidDoAction(Edit
 
   AutoSafeEditorData setData(*this, *mHTMLEditor);
 
   switch (aInfo.mEditSubAction) {
     case EditSubAction::eInsertText:
     case EditSubAction::eInsertLineBreak:
     case EditSubAction::eInsertTextComingFromIME:
       return NS_OK;
-    case EditSubAction::eDeleteSelectedContent:
-      return DidDeleteSelection();
     case EditSubAction::eInsertElement:
     case EditSubAction::eInsertQuotedText:
       return NS_OK;
     case EditSubAction::eCreateOrChangeDefinitionListItem:
     case EditSubAction::eCreateOrChangeList:
     case EditSubAction::eCreateOrRemoveBlock:
     case EditSubAction::eDecreaseZIndex:
+    case EditSubAction::eDeleteSelectedContent:
     case EditSubAction::eIncreaseZIndex:
     case EditSubAction::eIndent:
     case EditSubAction::eInsertHTMLSource:
     case EditSubAction::eInsertParagraphSeparator:
     case EditSubAction::eOutdent:
     case EditSubAction::eUndo:
     case EditSubAction::eRedo:
     case EditSubAction::eRemoveList:
@@ -4053,67 +4055,58 @@ nsresult HTMLEditor::DeleteElementsExcep
     nsresult rv = DeleteElementsExceptTableRelatedElements(child);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
   return NS_OK;
 }
 
-nsresult HTMLEditRules::DidDeleteSelection() {
-  MOZ_ASSERT(IsEditorDataAvailable());
-
-  // find where we are
-  EditorDOMPoint atStartOfSelection(
-      EditorBase::GetStartPoint(*SelectionRefPtr()));
-  if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
+nsresult HTMLEditor::DeleteMostAncestorMailCiteElementIfEmpty(
+    nsIContent& aContent) {
+  MOZ_ASSERT(IsEditActionDataAvailable());
+
+  // The element must be `<blockquote type="cite">` or
+  // `<span _moz_quote="true">`.
+  RefPtr<Element> mailCiteElement = GetMostAncestorMailCiteElement(aContent);
+  if (!mailCiteElement) {
+    return NS_OK;
+  }
+  bool isEmpty = true, seenBR = false;
+  IsEmptyNodeImpl(mailCiteElement, &isEmpty, true, true, false, &seenBR);
+  EditorDOMPoint atEmptyMailCiteElement(mailCiteElement);
+  {
+    AutoEditorDOMPointChildInvalidator lockOffset(atEmptyMailCiteElement);
+    nsresult rv = DeleteNodeWithTransaction(*mailCiteElement);
+    if (NS_WARN_IF(Destroyed())) {
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  if (NS_WARN_IF(!atEmptyMailCiteElement.IsSet()) || !seenBR) {
+    return NS_OK;
+  }
+
+  RefPtr<Element> brElement =
+      InsertBRElementWithTransaction(atEmptyMailCiteElement);
+  if (NS_WARN_IF(Destroyed())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  if (NS_WARN_IF(!brElement)) {
     return NS_ERROR_FAILURE;
   }
-
-  // find any enclosing mailcite
-  RefPtr<Element> citeNode = HTMLEditorRef().GetMostAncestorMailCiteElement(
-      *atStartOfSelection.GetContainer());
-  if (citeNode) {
-    bool isEmpty = true, seenBR = false;
-    HTMLEditorRef().IsEmptyNodeImpl(citeNode, &isEmpty, true, true, false,
-                                    &seenBR);
-    if (isEmpty) {
-      EditorDOMPoint atCiteNode(citeNode);
-      {
-        AutoEditorDOMPointChildInvalidator lockOffset(atCiteNode);
-        nsresult rv =
-            MOZ_KnownLive(HTMLEditorRef()).DeleteNodeWithTransaction(*citeNode);
-        if (NS_WARN_IF(!CanHandleEditAction())) {
-          return NS_ERROR_EDITOR_DESTROYED;
-        }
-        if (NS_WARN_IF(NS_FAILED(rv))) {
-          return rv;
-        }
-      }
-      if (atCiteNode.IsSet() && seenBR) {
-        RefPtr<Element> brElement =
-            MOZ_KnownLive(HTMLEditorRef())
-                .InsertBRElementWithTransaction(atCiteNode);
-        if (NS_WARN_IF(!CanHandleEditAction())) {
-          return NS_ERROR_EDITOR_DESTROYED;
-        }
-        if (NS_WARN_IF(!brElement)) {
-          return NS_ERROR_FAILURE;
-        }
-        IgnoredErrorResult error;
-        SelectionRefPtr()->Collapse(EditorRawDOMPoint(brElement), error);
-        if (NS_WARN_IF(!CanHandleEditAction())) {
-          return NS_ERROR_EDITOR_DESTROYED;
-        }
-        NS_WARNING_ASSERTION(
-            !error.Failed(),
-            "Failed to collapse selection at the new <br> element");
-      }
-    }
-  }
+  IgnoredErrorResult ignoredError;
+  SelectionRefPtr()->Collapse(EditorRawDOMPoint(brElement), ignoredError);
+  if (NS_WARN_IF(Destroyed())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(!ignoredError.Failed(), "Selection::Collapse() failed");
   return NS_OK;
 }
 
 EditActionResult HTMLEditor::MakeOrChangeListAndListItemAsSubAction(
     nsAtom& aListElementOrListItemElementTagName, const nsAString& aBulletType,
     SelectAllOfCurrentList aSelectAllOfCurrentList) {
   MOZ_ASSERT(IsEditActionDataAvailable());
   MOZ_ASSERT(&aListElementOrListItemElementTagName == nsGkAtoms::ul ||
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -101,23 +101,16 @@ class HTMLEditRules : public TextEditRul
  protected:
   virtual ~HTMLEditRules() = default;
 
   HTMLEditor& HTMLEditorRef() const {
     MOZ_ASSERT(mData);
     return mData->HTMLEditorRef();
   }
 
-  /**
-   * Called after deleting selected content.
-   * This method removes unnecessary empty nodes and/or inserts <br> if
-   * necessary.
-   */
-  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult DidDeleteSelection();
-
   nsresult AppendInnerFormatNodes(nsTArray<OwningNonNull<nsINode>>& aArray,
                                   nsINode* aNode);
   nsresult GetFormatString(nsINode* aNode, nsAString& outFormat);
 
   MOZ_CAN_RUN_SCRIPT
   nsresult GetParagraphFormatNodes(
       nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes);
 
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -2270,16 +2270,26 @@ class HTMLEditor final : public TextEdit
    * @param aDirectionAndAmount Direction of the deletion.
    * @param aStripWrappers      Must be eStrip or eNoStrip.
    */
   MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult
   HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount,
                         nsIEditor::EStripWrappers aStripWrappers);
 
   /**
+   * DeleteMostAncestorMailCiteElementIfEmpty() deletes most ancestor
+   * mail cite element (`<blockquote type="cite">` or
+   * `<span _moz_quote="true">`, the former can be created with middle click
+   * paste with `Control` or `Command` even in the web) of aContent if it
+   * becomes empty.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
+  DeleteMostAncestorMailCiteElementIfEmpty(nsIContent& aContent);
+
+  /**
    * LiftUpListItemElement() moves aListItemElement outside its parent.
    * If it's in a middle of a list element, the parent list element is split
    * before aListItemElement.  Then, moves aListItemElement to before its
    * parent list element.  I.e., moves aListItemElement between the 2 list
    * elements if original parent was split.  Then, if new parent becomes not a
    * list element, the list item element is removed and its contents are moved
    * to where the list item element was.  If aListItemElement becomse not a
    * child of list element, its contents are unwrapped from aListItemElement.
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -256,18 +256,16 @@ nsresult TextEditRules::WillDoAction(Edi
 nsresult TextEditRules::DidDoAction(EditSubActionInfo& aInfo,
                                     nsresult aResult) {
   if (NS_WARN_IF(!CanHandleEditAction())) {
     return NS_ERROR_EDITOR_DESTROYED;
   }
 
   switch (aInfo.mEditSubAction) {
     case EditSubAction::eDeleteSelectedContent:
-      MOZ_ASSERT(!mIsHTMLEditRules);
-      return NS_OK;
     case EditSubAction::eInsertElement:
     case EditSubAction::eUndo:
     case EditSubAction::eRedo:
       MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
       return NS_ERROR_UNEXPECTED;
     default:
       // Don't fail on transactions we don't handle here!
       return NS_OK;
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -662,20 +662,32 @@ nsresult TextEditor::DeleteSelectionAsSu
   bool cancel, handled;
   nsresult rv = rules->WillDoAction(subActionInfo, &cancel, &handled);
   if (NS_WARN_IF(NS_FAILED(rv)) || cancel) {
     return rv;
   }
   if (!handled) {
     rv = DeleteSelectionWithTransaction(aDirection, aStripWrappers);
   }
-  // post-process
-  rv = rules->DidDoAction(subActionInfo, rv);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+
+  if (AsHTMLEditor()) {
+    EditorDOMPoint atNewStartOfSelection(
+        EditorBase::GetStartPoint(*SelectionRefPtr()));
+    if (NS_WARN_IF(!atNewStartOfSelection.IsSet())) {
+      return NS_ERROR_FAILURE;
+    }
+    if (atNewStartOfSelection.GetContainerAsContent()) {
+      nsresult rv =
+          MOZ_KnownLive(AsHTMLEditor())
+              ->DeleteMostAncestorMailCiteElementIfEmpty(MOZ_KnownLive(
+                  *atNewStartOfSelection.GetContainerAsContent()));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
   }
 
   // XXX This is odd.  We just tries to remove empty text node here but we
   //     refer `Selection`.  It may be modified by mutation event listeners
   //     so that we should remove the empty text node when we make it empty.
   EditorDOMPoint atNewStartOfSelection(
       EditorBase::GetStartPoint(*SelectionRefPtr()));
   if (NS_WARN_IF(!atNewStartOfSelection.IsSet())) {