Bug 1574852 - part 67-6: Split the last common part of `HTMLEditRules::HandleDeleteNonCollapsedSelection()` r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 06 Sep 2019 01:44:00 +0000
changeset 492002 349c2ae46aa1b1157cb573e056c5b2a181691d21
parent 492001 f68d89e1996c7521b1c5f9078115531186bff501
child 492003 e790ca6cf615d589cca5d0fac87c2cae53faa942
push id94658
push usermasayuki@d-toybox.com
push dateFri, 06 Sep 2019 12:09:38 +0000
treeherderautoland@e790ca6cf615 [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 67-6: Split the last common part of `HTMLEditRules::HandleDeleteNonCollapsedSelection()` r=m_kato Differential Revision: https://phabricator.services.mozilla.com/D44456
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -3129,17 +3129,16 @@ EditActionResult HTMLEditRules::HandleDe
     firstRangeStart.Set(startNode, startOffset);
     firstRangeEnd.Set(endNode, endOffset);
     if (NS_WARN_IF(!firstRangeStart.IsSet()) ||
         NS_WARN_IF(!firstRangeEnd.IsSet())) {
       return EditActionResult(NS_ERROR_FAILURE);
     }
   }
 
-  bool join = false;
   EditActionResult result(NS_OK);
   result.MarkAsHandled();
   {
     // Track location of where we are deleting
     // NOTE: Right now, firstRangeStart.mOffset and firstRangeEnd.mOffset
     //       are fixed so that we keep compatibility with older code which
     //       treated offset directly.
     AutoTrackDOMPoint startTracker(HTMLEditorRef().RangeUpdaterRef(),
@@ -3235,17 +3234,17 @@ EditActionResult HTMLEditRules::HandleDe
             return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
           }
           NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed");
           return result.SetResult(error.StealNSResult());
         }
 
         // Else blocks not same type, or not siblings.  Delete everything
         // except table elements.
-        join = true;
+        bool join = true;
 
         AutoRangeArray arrayOfRanges(SelectionRefPtr());
         for (auto& range : arrayOfRanges.mRanges) {
           // Build a list of nodes in the range
           nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
           TrivialFunctor functor;
           DOMSubtreeIterator iter;
           nsresult rv = iter.Init(*range);
@@ -3321,109 +3320,134 @@ EditActionResult HTMLEditRules::HandleDe
 
         if (join) {
           result |=
               MOZ_KnownLive(HTMLEditorRef())
                   .TryToJoinBlocksWithTransaction(*leftBlock, *rightBlock);
           if (NS_WARN_IF(result.Failed())) {
             return result;
           }
-        }
-      }
-    }
-  }
+
+          // If we're joining blocks: if deleting forward the selection should
+          // be collapsed to the end of the selection, if deleting backward the
+          // selection should be collapsed to the beginning of the selection.
+          // But if we're not joining then the selection should collapse to the
+          // beginning of the selection if we'redeleting forward, because the
+          // end of the selection will still be in the next block. And same
+          // thing for deleting backwards (selection should collapse to the end,
+          // because the beginning will still be in the first block). See Bug
+          // 507936.
+          if (aDirectionAndAmount == nsIEditor::eNext) {
+            aDirectionAndAmount = nsIEditor::ePrevious;
+          } else {
+            aDirectionAndAmount = nsIEditor::eNext;
+          }
+        }
+      }
+    }
+  }
+
+  nsresult rv = DeleteUnnecessaryNodesAndCollapseSelection(
+      aDirectionAndAmount, firstRangeStart, firstRangeEnd);
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                       "DeleteUnnecessaryNodesAndCollapseSelection() failed");
+  return result.SetResult(rv);
+}
+
+nsresult HTMLEditRules::DeleteUnnecessaryNodesAndCollapseSelection(
+    nsIEditor::EDirection aDirectionAndAmount,
+    const EditorDOMPoint& aSelectionStartPoint,
+    const EditorDOMPoint& aSelectionEndPoint) {
+  MOZ_ASSERT(IsEditorDataAvailable());
+  MOZ_ASSERT(HTMLEditorRef().IsTopLevelEditSubActionDataAvailable());
+
+  EditorDOMPoint selectionStartPoint(aSelectionStartPoint);
+  EditorDOMPoint selectionEndPoint(aSelectionEndPoint);
 
   // If we're handling D&D, this is called to delete dragging item from the
   // tree.  In this case, we should move parent blocks if it becomes empty.
   if (HTMLEditorRef().GetEditAction() == EditAction::eDrop) {
-    MOZ_ASSERT(firstRangeStart.GetContainer() == firstRangeEnd.GetContainer());
-    MOZ_ASSERT(firstRangeStart.Offset() == firstRangeEnd.Offset());
+    MOZ_ASSERT(selectionStartPoint.GetContainer() ==
+               selectionEndPoint.GetContainer());
+    MOZ_ASSERT(selectionStartPoint.Offset() == selectionEndPoint.Offset());
     {
       AutoTrackDOMPoint startTracker(HTMLEditorRef().RangeUpdaterRef(),
-                                     &firstRangeStart);
+                                     &selectionStartPoint);
       AutoTrackDOMPoint endTracker(HTMLEditorRef().RangeUpdaterRef(),
-                                   &firstRangeEnd);
+                                   &selectionEndPoint);
 
       nsresult rv =
           MOZ_KnownLive(HTMLEditorRef())
-              .DeleteParentBlocksWithTransactionIfEmpty(firstRangeStart);
+              .DeleteParentBlocksWithTransactionIfEmpty(selectionStartPoint);
       if (NS_WARN_IF(NS_FAILED(rv))) {
-        return result.SetResult(rv);
+        return rv;
       }
       HTMLEditorRef()
           .TopLevelEditSubActionDataRef()
           .mDidDeleteEmptyParentBlocks = rv == NS_OK;
     }
     // If we removed parent blocks, Selection should be collapsed at where
     // the most ancestor empty block has been.
     if (HTMLEditorRef()
             .TopLevelEditSubActionDataRef()
             .mDidDeleteEmptyParentBlocks) {
       nsresult rv =
-          SelectionRefPtr()->Collapse(firstRangeStart.ToRawRangeBoundary());
+          SelectionRefPtr()->Collapse(selectionStartPoint.ToRawRangeBoundary());
       if (NS_WARN_IF(!CanHandleEditAction())) {
-        return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
+        return NS_ERROR_EDITOR_DESTROYED;
       }
       NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Selection::Collapse() failed");
-      return result.SetResult(rv);
+      return rv;
     }
   }
 
   // We might have left only collapsed whitespace in the start/end nodes
   {
     AutoTrackDOMPoint startTracker(HTMLEditorRef().RangeUpdaterRef(),
-                                   &firstRangeStart);
+                                   &selectionStartPoint);
     AutoTrackDOMPoint endTracker(HTMLEditorRef().RangeUpdaterRef(),
-                                 &firstRangeEnd);
+                                 &selectionEndPoint);
 
     nsresult rv = MOZ_KnownLive(HTMLEditorRef())
                       .DeleteNodeIfInvisibleAndEditableTextNode(
-                          MOZ_KnownLive(*firstRangeStart.GetContainer()));
+                          MOZ_KnownLive(*selectionStartPoint.GetContainer()));
     if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
-      return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
+      return NS_ERROR_EDITOR_DESTROYED;
     }
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "DeleteNodeIfInvisibleAndEditableTextNode() failed to "
                          "remove start node, but ignored");
     rv = MOZ_KnownLive(HTMLEditorRef())
              .DeleteNodeIfInvisibleAndEditableTextNode(
-                 MOZ_KnownLive(*firstRangeEnd.GetContainer()));
+                 MOZ_KnownLive(*selectionEndPoint.GetContainer()));
     if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
-      return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
+      return NS_ERROR_EDITOR_DESTROYED;
     }
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "DeleteNodeIfInvisibleAndEditableTextNode() failed to "
                          "remove end node, but ignored");
   }
 
-  // If we're joining blocks: if deleting forward the selection should be
-  // collapsed to the end of the selection, if deleting backward the selection
-  // should be collapsed to the beginning of the selection. But if we're not
-  // joining then the selection should collapse to the beginning of the
-  // selection if we'redeleting forward, because the end of the selection will
-  // still be in the next block. And same thing for deleting backwards
-  // (selection should collapse to the end, because the beginning will still be
-  // in the first block). See Bug 507936
-  if (aDirectionAndAmount == (join ? nsIEditor::eNext : nsIEditor::ePrevious)) {
+  if (aDirectionAndAmount == nsIEditor::ePrevious) {
     nsresult rv =
-        SelectionRefPtr()->Collapse(firstRangeEnd.ToRawRangeBoundary());
+        SelectionRefPtr()->Collapse(selectionEndPoint.ToRawRangeBoundary());
     if (NS_WARN_IF(!CanHandleEditAction())) {
-      return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
+      return NS_ERROR_EDITOR_DESTROYED;
     }
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Selection::Collapse() failed");
-    return result.SetResult(rv);
+    return rv;
   }
 
   nsresult rv =
-      SelectionRefPtr()->Collapse(firstRangeStart.ToRawRangeBoundary());
+      SelectionRefPtr()->Collapse(selectionStartPoint.ToRawRangeBoundary());
   if (NS_WARN_IF(!CanHandleEditAction())) {
-    return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
+    return NS_ERROR_EDITOR_DESTROYED;
   }
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Selection::Collapse() failed");
-  return result.SetResult(rv);
+  return rv;
 }
 
 nsresult HTMLEditor::DeleteNodeIfInvisibleAndEditableTextNode(nsINode& aNode) {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   Text* text = aNode.GetAsText();
   if (!text) {
     return NS_OK;
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -209,16 +209,38 @@ class HTMLEditRules : public TextEditRul
    *                                    or end).
    */
   MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult
   HandleDeleteCollapsedSelectionAtCurrentBlockBoundary(
       nsIEditor::EDirection aDirectionAndAmount, Element& aCurrentBlockElement,
       const EditorDOMPoint& aCaretPoint);
 
   /**
+   * DeleteUnnecessaryNodesAndCollapseSelection() removes unnecessary nodes
+   * around aSelectionStartPoint and aSelectionEndPoint.  Then, collapse
+   * selection at aSelectionStartPoint or aSelectionEndPoint (depending on
+   * aDirectionAndAmount).
+   *
+   * @param aDirectionAndAmount         Direction of the deletion.
+   *                                    If nsIEditor::ePrevious, selection will
+   *                                    be collapsed to aSelectionEndPoint.
+   *                                    Otherwise, selection will be collapsed
+   *                                    to aSelectionStartPoint.
+   * @param aSelectionStartPoint        First selection range start after
+   *                                    computing the deleting range.
+   * @param aSelectionEndPoint          First selection range end after
+   *                                    computing the deleting range.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
+  DeleteUnnecessaryNodesAndCollapseSelection(
+      nsIEditor::EDirection aDirectionAndAmount,
+      const EditorDOMPoint& aSelectionStartPoint,
+      const EditorDOMPoint& aSelectionEndPoint);
+
+  /**
    * HandleDeleteAroundCollapsedSelection() handles deletion with collapsed
    * `Selection`.  Callers must guarantee that this is called only when
    * `Selection` is collapsed.
    *
    * @param aDirectionAndAmount Direction of the deletion.
    * @param aStripWrappers      Must be eStrip or eNoStrip.
    */
   MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult