Bug 1460509 - part 33: Make HTMLEditRules::JoinNearestEditableNodesWithTransaction() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 14 May 2018 23:51:23 +0900
changeset 798751 ab036ff607ee93a005f7d9e0ca8421a7a76c1dc3
parent 798750 4e5baa212eb0faf7e14d1e5bbd7bdb556065cebb
child 798752 cf57752d514063481155c116e01d856a4cd1b63f
push id110840
push usermasayuki@d-toybox.com
push dateWed, 23 May 2018 13:41:58 +0000
reviewersm_kato
bugs1460509
milestone62.0a1
Bug 1460509 - part 33: Make HTMLEditRules::JoinNearestEditableNodesWithTransaction() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato Unfortunately, we need to make it take out argument for returning new first child point of right node. If we can create JoinNodesResult which have nsresult and EditorDOMPoint, we can avoid that, but EditorBase::JoinNodes() does not want it. So, even if we create such class, only 2 callers of the methods are its users... MozReview-Commit-ID: 1zwVZ0FriwN
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -2667,19 +2667,23 @@ HTMLEditRules::WillDeleteSelection(nsIEd
       // Is there a prior node and are they siblings?
       nsCOMPtr<nsINode> stepbrother;
       if (sibling) {
         stepbrother = HTMLEditorRef().GetNextHTMLSibling(sibling);
       }
       // Are they both text nodes?  If so, join them!
       if (startNode == stepbrother && startNode->GetAsText() &&
           sibling->GetAsText()) {
-        EditorDOMPoint pt =
+        EditorDOMPoint pt;
+        nsresult rv =
           JoinNearestEditableNodesWithTransaction(*sibling,
-                                                  *startNode->AsContent());
+                                                  *startNode->AsContent(), &pt);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
         if (NS_WARN_IF(!pt.IsSet())) {
           return NS_ERROR_FAILURE;
         }
         // Fix up selection
         ErrorResult error;
         SelectionRef().Collapse(pt, error);
         if (NS_WARN_IF(error.Failed())) {
           return error.StealNSResult();
@@ -3511,18 +3515,22 @@ HTMLEditRules::TryToJoinBlocksWithTransa
   }
   // Do br adjustment.
   nsCOMPtr<Element> brNode =
     CheckForInvisibleBR(*leftBlock, BRLocation::blockEnd);
   EditActionResult ret(NS_OK);
   if (mergeLists || leftBlock->NodeInfo()->NameAtom() ==
                     rightBlock->NodeInfo()->NameAtom()) {
     // Nodes are same type.  merge them.
-    EditorDOMPoint pt =
-      JoinNearestEditableNodesWithTransaction(*leftBlock, *rightBlock);
+    EditorDOMPoint pt;
+    nsresult rv =
+      JoinNearestEditableNodesWithTransaction(*leftBlock, *rightBlock, &pt);
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
+    }
     if (pt.IsSet() && mergeLists) {
       RefPtr<Element> newBlock =
         ConvertListType(rightBlock, existingList, nsGkAtoms::li);
     }
     ret.MarkAsHandled();
   } else {
     // Nodes are dissimilar types.
     ret |= MoveBlock(*leftBlock, *rightBlock, -1, 0);
@@ -8377,82 +8385,102 @@ HTMLEditRules::MaybeSplitAncestorsForIns
                       *pointToInsert.GetChild(),
                       aStartOfDeepestRightNode,
                       SplitAtEdges::eAllowToCreateEmptyContainer);
   NS_WARNING_ASSERTION(splitNodeResult.Succeeded(),
     "Failed to split the node for insert the element");
   return splitNodeResult;
 }
 
-EditorDOMPoint
-HTMLEditRules::JoinNearestEditableNodesWithTransaction(nsIContent& aNodeLeft,
-                                                       nsIContent& aNodeRight)
+nsresult
+HTMLEditRules::JoinNearestEditableNodesWithTransaction(
+                 nsIContent& aNodeLeft,
+                 nsIContent& aNodeRight,
+                 EditorDOMPoint* aNewFirstChildOfRightNode)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
+  MOZ_ASSERT(aNewFirstChildOfRightNode);
 
   // Caller responsible for left and right node being the same type
   nsCOMPtr<nsINode> parent = aNodeLeft.GetParentNode();
   if (NS_WARN_IF(!parent)) {
-    return EditorDOMPoint();
-  }
-  int32_t parOffset = parent->ComputeIndexOf(&aNodeLeft);
+    return NS_ERROR_FAILURE;
+  }
   nsCOMPtr<nsINode> rightParent = aNodeRight.GetParentNode();
 
   // If they don't have the same parent, first move the right node to after the
   // left one
   if (parent != rightParent) {
+    int32_t parOffset = parent->ComputeIndexOf(&aNodeLeft);
     nsresult rv =
       HTMLEditorRef().MoveNodeWithTransaction(
                         aNodeRight, EditorRawDOMPoint(parent, parOffset));
+    if (NS_WARN_IF(!CanHandleEditAction())) {
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      return EditorDOMPoint();
+      return rv;
     }
   }
 
   EditorDOMPoint ret(&aNodeRight, aNodeLeft.Length());
 
   // Separate join rules for differing blocks
   if (HTMLEditUtils::IsList(&aNodeLeft) || aNodeLeft.GetAsText()) {
     // For lists, merge shallow (wouldn't want to combine list items)
     nsresult rv =
       HTMLEditorRef().JoinNodesWithTransaction(aNodeLeft, aNodeRight);
+    if (NS_WARN_IF(!CanHandleEditAction())) {
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      return EditorDOMPoint();
-    }
-    return ret;
+      return rv;
+    }
+    *aNewFirstChildOfRightNode = Move(ret);
+    return NS_OK;
   }
 
   // Remember the last left child, and first right child
   nsCOMPtr<nsIContent> lastLeft =
     HTMLEditorRef().GetLastEditableChild(aNodeLeft);
   if (NS_WARN_IF(!lastLeft)) {
-    return EditorDOMPoint();
+    return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIContent> firstRight =
     HTMLEditorRef().GetFirstEditableChild(aNodeRight);
   if (NS_WARN_IF(!firstRight)) {
-    return EditorDOMPoint();
+    return NS_ERROR_FAILURE;
   }
 
   // For list items, divs, etc., merge smart
   nsresult rv = HTMLEditorRef().JoinNodesWithTransaction(aNodeLeft, aNodeRight);
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    return EditorDOMPoint();
+    return rv;
   }
 
   if (lastLeft && firstRight &&
       HTMLEditorRef().AreNodesSameType(lastLeft, firstRight) &&
       (lastLeft->GetAsText() ||
        (lastLeft->IsElement() && firstRight->IsElement() &&
         CSSEditUtils::ElementsSameStyle(lastLeft->AsElement(),
                                         firstRight->AsElement())))) {
-    return JoinNearestEditableNodesWithTransaction(*lastLeft, *firstRight);
-  }
-  return ret;
+    nsresult rv =
+      JoinNearestEditableNodesWithTransaction(*lastLeft, *firstRight,
+                                              aNewFirstChildOfRightNode);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    return NS_OK;
+  }
+  *aNewFirstChildOfRightNode = Move(ret);
+  return NS_OK;
 }
 
 Element*
 HTMLEditRules::GetTopEnclosingMailCite(nsINode& aNode)
 {
   nsCOMPtr<Element> ret;
 
   for (nsCOMPtr<nsINode> node = &aNode; node; node = node->GetParentNode()) {
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -545,21 +545,23 @@ protected:
    *     The first editable paragraph's content will be moved into the second
    *     editable paragraph and the non-editable paragraph becomes the first
    *     paragraph of the editor.  I don't think that it's expected behavior of
    *     any users...
    *
    * @param aLeftNode   The node which will be removed.
    * @param aRightNode  The node which will be inserted the content of
    *                    aLeftNode.
-   * @return            The point at the first child of aRightNode.
+   * @param aNewFirstChildOfRightNode
+   *                    The point at the first child of aRightNode.
    */
-  EditorDOMPoint
-  JoinNearestEditableNodesWithTransaction(nsIContent& aLeftNode,
-                                          nsIContent& aRightNode);
+  MOZ_MUST_USE nsresult
+  JoinNearestEditableNodesWithTransaction(
+    nsIContent& aLeftNode, nsIContent& aRightNode,
+    EditorDOMPoint* aNewFirstChildOfRightNode);
 
   Element* GetTopEnclosingMailCite(nsINode& aNode);
 
   /**
    * PopListItem() tries to move aListItem outside its parent.  If it's
    * in a middle of a list element, the parent list element is split before
    * aListItem.  Then, moves aListItem to before its parent list element.
    * I.e., moves aListItem between the 2 list elements if original parent