Bug 1451672 - part 5: Rename EditorBase::JoinNodes() and related methods with "WithTransaction" postfix r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 10 Apr 2018 03:46:44 +0900
changeset 468358 5f61649cdc967a95fccb1b13d8beaf6f97811ee5
parent 468357 1f538ba260f81864adfee97c14b81a03e032f275
child 468359 28422b0eee9a95a153980bcd741d5ac7b094cb0c
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1451672
milestone61.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 1451672 - part 5: Rename EditorBase::JoinNodes() and related methods with "WithTransaction" postfix r=m_kato This patch renames: EditorBase::JoinNodes() -> EditorBase::JoinNodesWithTransaction() EditorBase::JoinNodeDeep() -> EditorBase::JoinNodesDeepWithTransaction() HTMLEditRules::JoinNodesSmart() -> HTMLEditRules::JoinNearestEditableNodesWithTransaction() HTMLEditRules::TryToJoinBlocks() -> HTMLEditRules::TryToJoinBlocksWithTransaction() MozReview-Commit-ID: Ao16GhAcyIZ
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLStyleEditor.cpp
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -1538,22 +1538,22 @@ EditorBase::SplitNodeWithTransaction(
 NS_IMETHODIMP
 EditorBase::JoinNodes(nsIDOMNode* aLeftNode,
                       nsIDOMNode* aRightNode,
                       nsIDOMNode*)
 {
   nsCOMPtr<nsINode> leftNode = do_QueryInterface(aLeftNode);
   nsCOMPtr<nsINode> rightNode = do_QueryInterface(aRightNode);
   NS_ENSURE_STATE(leftNode && rightNode && leftNode->GetParentNode());
-  return JoinNodes(*leftNode, *rightNode);
+  return JoinNodesWithTransaction(*leftNode, *rightNode);
 }
 
 nsresult
-EditorBase::JoinNodes(nsINode& aLeftNode,
-                      nsINode& aRightNode)
+EditorBase::JoinNodesWithTransaction(nsINode& aLeftNode,
+                                     nsINode& aRightNode)
 {
   nsCOMPtr<nsINode> parent = aLeftNode.GetParentNode();
   MOZ_ASSERT(parent);
 
   AutoRules beginRulesSniffing(this, EditAction::joinNode,
                                nsIEditor::ePrevious);
 
   // Remember some values; later used for saved selection updating.
@@ -4141,39 +4141,35 @@ EditorBase::SplitNodeDeepWithTransaction
       // Try to split its parent before current node.
       atStartOfRightNode.Set(currentRightNode);
     }
   }
 
   return SplitNodeResult(NS_ERROR_FAILURE);
 }
 
-/**
- * This joins two like nodes "deeply", joining children as appropriate.
- * Returns the point of the join, or (nullptr, -1) in case of error.
- */
 EditorDOMPoint
-EditorBase::JoinNodeDeep(nsIContent& aLeftNode,
-                         nsIContent& aRightNode)
+EditorBase::JoinNodesDeepWithTransaction(nsIContent& aLeftNode,
+                                         nsIContent& aRightNode)
 {
   // While the rightmost children and their descendants of the left node match
   // the leftmost children and their descendants of the right node, join them
   // up.
 
   nsCOMPtr<nsIContent> leftNodeToJoin = &aLeftNode;
   nsCOMPtr<nsIContent> rightNodeToJoin = &aRightNode;
   nsCOMPtr<nsINode> parentNode = aRightNode.GetParentNode();
 
   EditorDOMPoint ret;
   while (leftNodeToJoin && rightNodeToJoin && parentNode &&
          AreNodesSameType(leftNodeToJoin, rightNodeToJoin)) {
     uint32_t length = leftNodeToJoin->Length();
 
     // Do the join
-    nsresult rv = JoinNodes(*leftNodeToJoin, *rightNodeToJoin);
+    nsresult rv = JoinNodesWithTransaction(*leftNodeToJoin, *rightNodeToJoin);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return EditorDOMPoint();
     }
 
     ret.Set(rightNodeToJoin, length);
 
     if (parentNode->GetAsText()) {
       // We've joined all the way down to text nodes, we're done!
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -384,17 +384,27 @@ public:
    * @param aError              If succeed, returns no error.  Otherwise, an
    *                            error.
    */
   template<typename PT, typename CT>
   already_AddRefed<nsIContent>
   SplitNodeWithTransaction(const EditorDOMPointBase<PT, CT>& aStartOfRightNode,
                            ErrorResult& aResult);
 
-  nsresult JoinNodes(nsINode& aLeftNode, nsINode& aRightNode);
+  /**
+   * JoinNodesWithTransaction() joins aLeftNode and aRightNode.  Content of
+   * aLeftNode will be merged into aRightNode.  Actual implemenation of this
+   * method is JoinNodesImpl().  So, see its explanation for the detail.
+   *
+   * @param aLeftNode   Will be removed from the DOM tree.
+   * @param aRightNode  The node which will be new container of the content of
+   *                    aLeftNode.
+   */
+  nsresult JoinNodesWithTransaction(nsINode& aLeftNode, nsINode& aRightNode);
+
   nsresult MoveNode(nsIContent* aNode, nsINode* aParent, int32_t aOffset);
 
   /**
    * MoveAllChildren() moves all children of aContainer to before
    * aPointToInsert.GetChild().
    * See explanation of MoveChildren() for the detail of the behavior.
    *
    * @param aContainer          The container node whose all children should
@@ -798,17 +808,21 @@ public:
    *                            node if necessary), returns no error.
    *                            Otherwise, an error.
    */
   void DoSplitNode(const EditorDOMPoint& aStartOfRightNode,
                    nsIContent& aNewLeftNode,
                    ErrorResult& aError);
 
   /**
-   * JoinNodes() takes 2 nodes and merge their content|children.
+   * JoinNodesImpl() merges contents in aNodeToJoin to aNodeToKeep and remove
+   * aNodeToJoin from the DOM tree.  aNodeToJoin and aNodeToKeep must have
+   * same parent, aParent.  Additionally, if one of aNodeToJoin or aNodeToKeep
+   * is a text node, the other must be a text node.
+   *
    * @param aNodeToKeep   The node that will remain after the join.
    * @param aNodeToJoin   The node that will be joined with aNodeToKeep.
    *                      There is no requirement that the two nodes be of the
    *                      same type.
    * @param aParent       The parent of aNodeToKeep
    */
   nsresult JoinNodesImpl(nsINode* aNodeToKeep,
                          nsINode* aNodeToJoin,
@@ -1270,18 +1284,30 @@ public:
    */
   template<typename PT, typename CT>
   SplitNodeResult
   SplitNodeDeepWithTransaction(
     nsIContent& aMostAncestorToSplit,
     const EditorDOMPointBase<PT, CT>& aDeepestStartOfRightNode,
     SplitAtEdges aSplitAtEdges);
 
-  EditorDOMPoint JoinNodeDeep(nsIContent& aLeftNode,
-                              nsIContent& aRightNode);
+  /**
+   * JoinNodesDeepWithTransaction() joins aLeftNode and aRightNode "deeply".
+   * First, they are joined simply, then, new right node is assumed as the
+   * child at length of the left node before joined and new left node is
+   * assumed as its previous sibling.  Then, they will be joined again.
+   * And then, these steps are repeated.
+   *
+   * @param aLeftNode   The node which will be removed form the tree.
+   * @param aRightNode  The node which will be inserted the contents of
+   *                    aLeftNode.
+   * @return            The point of the first child of the last right node.
+   */
+  EditorDOMPoint JoinNodesDeepWithTransaction(nsIContent& aLeftNode,
+                                              nsIContent& aRightNode);
 
   nsresult GetString(const nsAString& name, nsAString& value);
 
   void BeginUpdateViewBatch();
   virtual nsresult EndUpdateViewBatch();
 
   bool GetShouldTxnSetSelection();
 
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -2193,20 +2193,20 @@ HTMLEditRules::WillDeleteSelection(Selec
     rv = mHTMLEditor->DeleteTableCellContents();
     *aHandled = true;
     return rv;
   }
   cell = nullptr;
 
   // origCollapsed is used later to determine whether we should join blocks. We
   // don't really care about bCollapsed because it will be modified by
-  // ExtendSelectionForDelete later. TryToJoinBlocks() should happen if the
-  // original selection is collapsed and the cursor is at the end of a block
-  // element, in which case ExtendSelectionForDelete would always make the
-  // selection not collapsed.
+  // ExtendSelectionForDelete later. TryToJoinBlocksWithTransaction() should
+  // happen if the original selection is collapsed and the cursor is at the end
+  // of a block element, in which case ExtendSelectionForDelete would always
+  // make the selection not collapsed.
   bool bCollapsed = aSelection->Collapsed();
   bool join = false;
   bool origCollapsed = bCollapsed;
 
   nsCOMPtr<nsINode> selNode;
   int32_t selOffset;
 
   NS_ENSURE_STATE(aSelection->GetRangeAt(0));
@@ -2463,17 +2463,19 @@ HTMLEditRules::WillDeleteSelection(Selec
       nsCOMPtr<nsINode> stepbrother;
       if (sibling) {
         NS_ENSURE_STATE(mHTMLEditor);
         stepbrother = mHTMLEditor->GetNextHTMLSibling(sibling);
       }
       // Are they both text nodes?  If so, join them!
       if (startNode == stepbrother && startNode->GetAsText() &&
           sibling->GetAsText()) {
-        EditorDOMPoint pt = JoinNodesSmart(*sibling, *startNode->AsContent());
+        EditorDOMPoint pt =
+          JoinNearestEditableNodesWithTransaction(*sibling,
+                                                  *startNode->AsContent());
         if (NS_WARN_IF(!pt.IsSet())) {
           return NS_ERROR_FAILURE;
         }
         // Fix up selection
         ErrorResult error;
         aSelection->Collapse(pt, error);
         if (NS_WARN_IF(error.Failed())) {
           return error.StealNSResult();
@@ -2559,27 +2561,28 @@ HTMLEditRules::WillDeleteSelection(Selec
       int32_t selPointOffset = startOffset;
       {
         NS_ENSURE_STATE(mHTMLEditor);
         AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
                                   address_of(selPointNode), &selPointOffset);
         NS_ENSURE_STATE(leftNode && leftNode->IsContent() &&
                         rightNode && rightNode->IsContent());
         EditActionResult ret =
-          TryToJoinBlocks(*leftNode->AsContent(), *rightNode->AsContent());
+          TryToJoinBlocksWithTransaction(*leftNode->AsContent(),
+                                         *rightNode->AsContent());
         *aHandled |= ret.Handled();
         *aCancel |= ret.Canceled();
         if (NS_WARN_IF(ret.Failed())) {
           return ret.Rv();
         }
       }
 
-      // If TryToJoinBlocks() didn't handle it  and it's not canceled,
-      // user may want to modify the start leaf node or the last leaf node
-      // of the block.
+      // If TryToJoinBlocksWithTransaction() didn't handle it  and it's not
+      // canceled, user may want to modify the start leaf node or the last leaf
+      // node of the block.
       if (!*aHandled && !*aCancel && leafNode != startNode) {
         int32_t offset =
           aAction == nsIEditor::ePrevious ?
             static_cast<int32_t>(leafNode->Length()) : 0;
         aSelection->Collapse(leafNode, offset);
         return WillDeleteSelection(aSelection, aAction, aStripWrappers,
                                    aCancel, aHandled);
       }
@@ -2627,17 +2630,18 @@ HTMLEditRules::WillDeleteSelection(Selec
       nsCOMPtr<nsINode> selPointNode = startNode;
       int32_t selPointOffset = startOffset;
       {
         NS_ENSURE_STATE(mHTMLEditor);
         AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
                                   address_of(selPointNode), &selPointOffset);
         NS_ENSURE_STATE(leftNode->IsContent() && rightNode->IsContent());
         EditActionResult ret =
-          TryToJoinBlocks(*leftNode->AsContent(), *rightNode->AsContent());
+          TryToJoinBlocksWithTransaction(*leftNode->AsContent(),
+                                         *rightNode->AsContent());
         // This should claim that trying to join the block means that
         // this handles the action because the caller shouldn't do anything
         // anymore in this case.
         *aHandled = true;
         *aCancel |= ret.Canceled();
         if (NS_WARN_IF(ret.Failed())) {
           return ret.Rv();
         }
@@ -2730,17 +2734,18 @@ HTMLEditRules::WillDeleteSelection(Selec
              HTMLEditUtils::IsHeader(*leftParent))) {
           // First delete the selection
           NS_ENSURE_STATE(mHTMLEditor);
           rv = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers);
           NS_ENSURE_SUCCESS(rv, rv);
           // Join blocks
           NS_ENSURE_STATE(mHTMLEditor);
           EditorDOMPoint pt =
-            mHTMLEditor->JoinNodeDeep(*leftParent, *rightParent);
+            mHTMLEditor->JoinNodesDeepWithTransaction(*leftParent,
+                                                      *rightParent);
           if (NS_WARN_IF(!pt.IsSet())) {
             return NS_ERROR_FAILURE;
           }
           // Fix up selection
           ErrorResult error;
           aSelection->Collapse(pt, error);
           if (NS_WARN_IF(error.Failed())) {
             return error.StealNSResult();
@@ -2808,17 +2813,18 @@ HTMLEditRules::WillDeleteSelection(Selec
           NS_ENSURE_STATE(mHTMLEditor);
           OwningNonNull<CharacterData> dataNode =
             *static_cast<CharacterData*>(endNode.get());
           rv = mHTMLEditor->DeleteText(dataNode, 0, endOffset);
           NS_ENSURE_SUCCESS(rv, rv);
         }
 
         if (join) {
-          EditActionResult ret = TryToJoinBlocks(*leftParent, *rightParent);
+          EditActionResult ret =
+            TryToJoinBlocksWithTransaction(*leftParent, *rightParent);
           MOZ_ASSERT(*aHandled);
           *aCancel |= ret.Canceled();
           if (NS_WARN_IF(ret.Failed())) {
             return ret.Rv();
           }
         }
       }
     }
@@ -2975,18 +2981,18 @@ HTMLEditRules::GetGoodSelPointForNode(ns
   if ((!aNode.IsHTMLElement(nsGkAtoms::br) ||
        mHTMLEditor->IsVisibleBRElement(&aNode)) && isPreviousAction) {
     ret.AdvanceOffset();
   }
   return ret;
 }
 
 EditActionResult
-HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
-                               nsIContent& aRightNode)
+HTMLEditRules::TryToJoinBlocksWithTransaction(nsIContent& aLeftNode,
+                                              nsIContent& aRightNode)
 {
   if (NS_WARN_IF(!mHTMLEditor)) {
     return EditActionIgnored(NS_ERROR_UNEXPECTED);
   }
 
   RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
 
   nsCOMPtr<Element> leftBlock = htmlEditor->GetBlock(aLeftNode);
@@ -3277,17 +3283,18 @@ HTMLEditRules::TryToJoinBlocks(nsIConten
   }
   // 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 = JoinNodesSmart(*leftBlock, *rightBlock);
+    EditorDOMPoint pt =
+      JoinNearestEditableNodesWithTransaction(*leftBlock, *rightBlock);
     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);
@@ -7825,26 +7832,19 @@ HTMLEditRules::MaybeSplitAncestorsForIns
                   *pointToInsert.GetChild(),
                   aStartOfDeepestRightNode,
                   SplitAtEdges::eAllowToCreateEmptyContainer);
   NS_WARNING_ASSERTION(splitNodeResult.Succeeded(),
     "Failed to split the node for insert the element");
   return splitNodeResult;
 }
 
-/**
- * JoinNodesSmart: Join two nodes, doing whatever makes sense for their
- * children (which often means joining them, too).  aNodeLeft & aNodeRight must
- * be same type of node.
- *
- * Returns the point where they're merged, or (nullptr, -1) on failure.
- */
 EditorDOMPoint
-HTMLEditRules::JoinNodesSmart(nsIContent& aNodeLeft,
-                              nsIContent& aNodeRight)
+HTMLEditRules::JoinNearestEditableNodesWithTransaction(nsIContent& aNodeLeft,
+                                                       nsIContent& aNodeRight)
 {
   // 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);
   nsCOMPtr<nsINode> rightParent = aNodeRight.GetParentNode();
@@ -7861,17 +7861,17 @@ HTMLEditRules::JoinNodesSmart(nsIContent
     }
   }
 
   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 = mHTMLEditor->JoinNodes(aNodeLeft, aNodeRight);
+    nsresult rv = mHTMLEditor->JoinNodesWithTransaction(aNodeLeft, aNodeRight);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return EditorDOMPoint();
     }
     return ret;
   }
 
   // Remember the last left child, and first right child
   if (NS_WARN_IF(!mHTMLEditor)) {
@@ -7889,31 +7889,31 @@ HTMLEditRules::JoinNodesSmart(nsIContent
   if (NS_WARN_IF(!firstRight)) {
     return EditorDOMPoint();
   }
 
   // For list items, divs, etc., merge smart
   if (NS_WARN_IF(!mHTMLEditor)) {
     return EditorDOMPoint();
   }
-  nsresult rv = mHTMLEditor->JoinNodes(aNodeLeft, aNodeRight);
+  nsresult rv = mHTMLEditor->JoinNodesWithTransaction(aNodeLeft, aNodeRight);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return EditorDOMPoint();
   }
 
   if (lastLeft && firstRight && mHTMLEditor &&
       mHTMLEditor->AreNodesSameType(lastLeft, firstRight) &&
       (lastLeft->GetAsText() || !mHTMLEditor ||
        (lastLeft->IsElement() && firstRight->IsElement() &&
         CSSEditUtils::ElementsSameStyle(lastLeft->AsElement(),
                                         firstRight->AsElement())))) {
     if (NS_WARN_IF(!mHTMLEditor)) {
       return EditorDOMPoint();
     }
-    return JoinNodesSmart(*lastLeft, *firstRight);
+    return JoinNearestEditableNodesWithTransaction(*lastLeft, *firstRight);
   }
   return ret;
 }
 
 Element*
 HTMLEditRules::GetTopEnclosingMailCite(nsINode& aNode)
 {
   nsCOMPtr<Element> ret;
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -181,34 +181,35 @@ protected:
    *                        element, false.
    */
   nsresult InsertBRIfNeededInternal(nsINode& aNode, bool aInsertMozBR);
 
   EditorDOMPoint GetGoodSelPointForNode(nsINode& aNode,
                                         nsIEditor::EDirection aAction);
 
   /**
-   * TryToJoinBlocks() tries to join two block elements.  The right element is
-   * always joined to the left element.  If the elements are the same type and
-   * not nested within each other, JoinNodesSmart() is called (example, joining
-   * two list items together into one).  If the elements are not the same type,
-   * or one is a descendant of the other, we instead destroy the right block
-   * placing its children into leftblock.  DTD containment rules are followed
+   * TryToJoinBlocksWithTransaction() tries to join two block elements.  The
+   * right element is always joined to the left element.  If the elements are
+   * the same type and not nested within each other,
+   * JoinEditableNodesWithTransaction() is called (example, joining two list
+   * items together into one).  If the elements are not the same type, or one
+   * is a descendant of the other, we instead destroy the right block placing
+   * its children into leftblock.  DTD containment rules are followed
    * throughout.
    *
    * @return            Sets canceled to true if the operation should do
    *                    nothing anymore even if this doesn't join the blocks.
    *                    Sets handled to true if this actually handles the
    *                    request.  Note that this may set it to true even if this
    *                    does not join the block.  E.g., if the blocks shouldn't
    *                    be joined or it's impossible to join them but it's not
    *                    unexpected case, this returns true with this.
    */
-  EditActionResult TryToJoinBlocks(nsIContent& aLeftNode,
-                                   nsIContent& aRightNode);
+  EditActionResult TryToJoinBlocksWithTransaction(nsIContent& aLeftNode,
+                                                  nsIContent& aRightNode);
 
   /**
    * MoveBlock() moves the content from aRightBlock starting from aRightOffset
    * into aLeftBlock at aLeftOffset. Note that the "block" can be inline nodes
    * between <br>s, or between blocks, etc.  DTD containment rules are followed
    * throughout.
    *
    * @return            Sets handled to true if this actually joins the nodes.
@@ -454,18 +455,40 @@ protected:
    * @return                            When succeeded, SplitPoint() returns
    *                                    the point to insert the element.
    */
   template<typename PT, typename CT>
   SplitNodeResult MaybeSplitAncestorsForInsertWithTransaction(
                     nsAtom& aTag,
                     const EditorDOMPointBase<PT, CT>& aStartOfDeepestRightNode);
 
-  EditorDOMPoint JoinNodesSmart(nsIContent& aNodeLeft,
-                                nsIContent& aNodeRight);
+  /**
+   * JoinNearestEditableNodesWithTransaction() joins two editable nodes which
+   * are themselves or the nearest editable node of aLeftNode and aRightNode.
+   * XXX This method's behavior is odd.  For example, if user types Backspace
+   *     key at the second editable paragraph in this case:
+   *     <div contenteditable>
+   *       <p>first editable paragraph</p>
+   *       <p contenteditable="false">non-editable paragraph</p>
+   *       <p>second editable paragraph</p>
+   *     </div>
+   *     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.
+   */
+  EditorDOMPoint
+  JoinNearestEditableNodesWithTransaction(nsIContent& aLeftNode,
+                                          nsIContent& aRightNode);
+
   Element* GetTopEnclosingMailCite(nsINode& aNode);
   nsresult PopListItem(nsIContent& aListItem, bool* aOutOfList = nullptr);
   nsresult RemoveListStructure(Element& aList);
   nsresult CacheInlineStyles(nsINode* aNode);
   nsresult ReapplyCachedStyles();
   void ClearCachedStyles();
   void AdjustSpecialBreaks();
   nsresult AdjustWhitespace(Selection* aSelection);
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -3620,17 +3620,17 @@ HTMLEditor::GetEnclosingTable(nsIDOMNode
   return ret;
 }
 
 
 /**
  * This method scans the selection for adjacent text nodes
  * and collapses them into a single text node.
  * "adjacent" means literally adjacent siblings of the same parent.
- * Uses EditorBase::JoinNodes so action is undoable.
+ * Uses EditorBase::JoinNodesWithTransaction() so action is undoable.
  * Should be called within the context of a batch transaction.
  */
 nsresult
 HTMLEditor::CollapseAdjacentTextNodes(nsRange* aInRange)
 {
   NS_ENSURE_TRUE(aInRange, NS_ERROR_NULL_POINTER);
   AutoTransactionsConserveSelection dontChangeMySelection(this);
   nsTArray<nsCOMPtr<nsINode>> textNodes;
@@ -3663,18 +3663,20 @@ HTMLEditor::CollapseAdjacentTextNodes(ns
     // we assume a textNodes entry can't be nullptr
     nsINode* leftTextNode = textNodes[0];
     nsINode* rightTextNode = textNodes[1];
     NS_ASSERTION(leftTextNode && rightTextNode,"left or rightTextNode null in CollapseAdjacentTextNodes");
 
     // get the prev sibling of the right node, and see if its leftTextNode
     nsCOMPtr<nsINode> prevSibOfRightNode = rightTextNode->GetPreviousSibling();
     if (prevSibOfRightNode && prevSibOfRightNode == leftTextNode) {
-      rv = JoinNodes(*leftTextNode, *rightTextNode);
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = JoinNodesWithTransaction(*leftTextNode, *rightTextNode);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
     }
 
     textNodes.RemoveElementAt(0); // remove the leftmost text node from the list
   }
 
   return NS_OK;
 }
 
--- a/editor/libeditor/HTMLStyleEditor.cpp
+++ b/editor/libeditor/HTMLStyleEditor.cpp
@@ -361,18 +361,20 @@ HTMLEditor::SetInlinePropertyOnNodeImpl(
 
   // First check if there's an adjacent sibling we can put our node into.
   nsCOMPtr<nsIContent> previousSibling = GetPriorHTMLSibling(&aNode);
   nsCOMPtr<nsIContent> nextSibling = GetNextHTMLSibling(&aNode);
   if (IsSimpleModifiableNode(previousSibling, &aProperty, aAttribute, &aValue)) {
     nsresult rv = MoveNode(&aNode, previousSibling, -1);
     NS_ENSURE_SUCCESS(rv, rv);
     if (IsSimpleModifiableNode(nextSibling, &aProperty, aAttribute, &aValue)) {
-      rv = JoinNodes(*previousSibling, *nextSibling);
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = JoinNodesWithTransaction(*previousSibling, *nextSibling);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
     }
     return NS_OK;
   }
   if (IsSimpleModifiableNode(nextSibling, &aProperty, aAttribute, &aValue)) {
     nsresult rv = MoveNode(&aNode, nextSibling, 0);
     NS_ENSURE_SUCCESS(rv, rv);
     return NS_OK;
   }