Bug 1156062 part 8 - Clean up nsHTMLEditRules::JoinBlocks; r=ehsan
authorAryeh Gregor <ayg@aryeh.name>
Tue, 19 Apr 2016 05:42:00 +0200
changeset 317663 f777b347e97f690ef2465ad86e6af2c358da7854
parent 317662 46b36ab490c16d2ef0c6329e4f470e1d6cd482ed
child 317664 7cdc241352d49d346e04729d64265368267071c7
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1156062
milestone48.0a1
Bug 1156062 part 8 - Clean up nsHTMLEditRules::JoinBlocks; r=ehsan
editor/libeditor/nsHTMLEditRules.cpp
editor/libeditor/nsHTMLEditRules.h
--- a/editor/libeditor/nsHTMLEditRules.cpp
+++ b/editor/libeditor/nsHTMLEditRules.cpp
@@ -2188,17 +2188,19 @@ nsHTMLEditRules::WillDeleteSelection(Sel
       // Else we are joining content to block
 
       nsCOMPtr<nsINode> selPointNode = startNode;
       int32_t selPointOffset = startOffset;
       {
         NS_ENSURE_STATE(mHTMLEditor);
         nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
                                     address_of(selPointNode), &selPointOffset);
-        res = JoinBlocks(GetAsDOMNode(leftNode), GetAsDOMNode(rightNode),
+        NS_ENSURE_STATE(leftNode && leftNode->IsContent() &&
+                        rightNode && rightNode->IsContent());
+        res = JoinBlocks(*leftNode->AsContent(), *rightNode->AsContent(),
                          aCancel);
         *aHandled = true;
         NS_ENSURE_SUCCESS(res, res);
       }
       aSelection->Collapse(selPointNode, selPointOffset);
       return NS_OK;
     }
 
@@ -2238,17 +2240,18 @@ nsHTMLEditRules::WillDeleteSelection(Sel
       }
 
       nsCOMPtr<nsINode> selPointNode = startNode;
       int32_t selPointOffset = startOffset;
       {
         NS_ENSURE_STATE(mHTMLEditor);
         nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
                                     address_of(selPointNode), &selPointOffset);
-        res = JoinBlocks(GetAsDOMNode(leftNode), GetAsDOMNode(rightNode),
+        NS_ENSURE_STATE(leftNode->IsContent() && rightNode->IsContent());
+        res = JoinBlocks(*leftNode->AsContent(), *rightNode->AsContent(),
                          aCancel);
         *aHandled = true;
         NS_ENSURE_SUCCESS(res, res);
       }
       aSelection->Collapse(selPointNode, selPointOffset);
       return NS_OK;
     }
   }
@@ -2424,18 +2427,17 @@ nsHTMLEditRules::WillDeleteSelection(Sel
           NS_ENSURE_STATE(mHTMLEditor);
           OwningNonNull<nsGenericDOMDataNode> dataNode =
             *static_cast<nsGenericDOMDataNode*>(endNode.get());
           res = mHTMLEditor->DeleteText(dataNode, 0, endOffset);
           NS_ENSURE_SUCCESS(res, res);
         }
 
         if (join) {
-          res = JoinBlocks(GetAsDOMNode(leftParent), GetAsDOMNode(rightParent),
-                           aCancel);
+          res = JoinBlocks(*leftParent, *rightParent, aCancel);
           NS_ENSURE_SUCCESS(res, res);
         }
       }
     }
   }
   // 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
@@ -2520,304 +2522,286 @@ nsHTMLEditRules::GetGoodSelPointForNode(
        mHTMLEditor->IsVisBreak(&aNode)) &&
       aAction == nsIEditor::ePrevious) {
     ret.offset++;
   }
   return ret;
 }
 
 
-/*****************************************************************************************************
-*    JoinBlocks: this method is used 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 throughout.
-*         nsCOMPtr<nsIDOMNode> *aLeftBlock         pointer to the left block
-*         nsCOMPtr<nsIDOMNode> *aRightBlock        pointer to the right block; will have contents moved to left block
-*         bool *aCanceled                        return TRUE if we had to cancel operation
-*/
+/**
+ * This method is used 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 throughout.
+ */
 nsresult
-nsHTMLEditRules::JoinBlocks(nsIDOMNode *aLeftNode,
-                            nsIDOMNode *aRightNode,
-                            bool *aCanceled)
-{
-  NS_ENSURE_ARG_POINTER(aLeftNode && aRightNode);
-
-  nsCOMPtr<nsIDOMNode> aLeftBlock, aRightBlock;
-
-  if (IsBlockNode(aLeftNode)) {
-    aLeftBlock = aLeftNode;
-  } else if (aLeftNode) {
-    NS_ENSURE_STATE(mHTMLEditor);
-    aLeftBlock = mHTMLEditor->GetBlockNodeParent(aLeftNode);
-  }
-
-  if (IsBlockNode(aRightNode)) {
-    aRightBlock = aRightNode;
-  } else if (aRightNode) {
-    NS_ENSURE_STATE(mHTMLEditor);
-    aRightBlock = mHTMLEditor->GetBlockNodeParent(aRightNode);
-  }
-
-  // sanity checks
-  NS_ENSURE_TRUE(aLeftBlock && aRightBlock, NS_ERROR_NULL_POINTER);
-  NS_ENSURE_STATE(aLeftBlock != aRightBlock);
-
-  if (nsHTMLEditUtils::IsTableElement(aLeftBlock) ||
-      nsHTMLEditUtils::IsTableElement(aRightBlock)) {
-    // do not try to merge table elements
+nsHTMLEditRules::JoinBlocks(nsIContent& aLeftNode, nsIContent& aRightNode,
+                            bool* aCanceled)
+{
+  MOZ_ASSERT(aCanceled);
+
+  NS_ENSURE_STATE(mHTMLEditor);
+  nsCOMPtr<nsIEditor> kungFuDeathGrip(mHTMLEditor);
+
+  nsCOMPtr<Element> leftBlock = mHTMLEditor->GetBlock(aLeftNode);
+  nsCOMPtr<Element> rightBlock = mHTMLEditor->GetBlock(aRightNode);
+
+  // Sanity checks
+  NS_ENSURE_TRUE(leftBlock && rightBlock, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_STATE(leftBlock != rightBlock);
+
+  if (nsHTMLEditUtils::IsTableElement(leftBlock) ||
+      nsHTMLEditUtils::IsTableElement(rightBlock)) {
+    // Do not try to merge table elements
     *aCanceled = true;
     return NS_OK;
   }
 
-  // make sure we don't try to move thing's into HR's, which look like blocks but aren't containers
-  if (nsHTMLEditUtils::IsHR(aLeftBlock)) {
-    NS_ENSURE_STATE(mHTMLEditor);
-    nsCOMPtr<nsIDOMNode> realLeft = mHTMLEditor->GetBlockNodeParent(aLeftBlock);
-    aLeftBlock = realLeft;
-  }
-  if (nsHTMLEditUtils::IsHR(aRightBlock)) {
-    NS_ENSURE_STATE(mHTMLEditor);
-    nsCOMPtr<nsIDOMNode> realRight = mHTMLEditor->GetBlockNodeParent(aRightBlock);
-    aRightBlock = realRight;
-  }
-  NS_ENSURE_STATE(aLeftBlock && aRightBlock);
-
-  // bail if both blocks the same
-  if (aLeftBlock == aRightBlock) {
+  // Make sure we don't try to move things into HR's, which look like blocks
+  // but aren't containers
+  if (leftBlock->IsHTMLElement(nsGkAtoms::hr)) {
+    leftBlock = mHTMLEditor->GetBlockNodeParent(leftBlock);
+  }
+  if (rightBlock->IsHTMLElement(nsGkAtoms::hr)) {
+    rightBlock = mHTMLEditor->GetBlockNodeParent(rightBlock);
+  }
+  NS_ENSURE_STATE(leftBlock && rightBlock);
+
+  // Bail if both blocks the same
+  if (leftBlock == rightBlock) {
     *aCanceled = true;
     return NS_OK;
   }
 
   // Joining a list item to its parent is a NOP.
-  if (nsHTMLEditUtils::IsList(aLeftBlock) &&
-      nsHTMLEditUtils::IsListItem(aRightBlock)) {
-    nsCOMPtr<nsIDOMNode> rightParent;
-    aRightBlock->GetParentNode(getter_AddRefs(rightParent));
-    if (rightParent == aLeftBlock) {
-      return NS_OK;
-    }
-  }
-
-  // special rule here: if we are trying to join list items, and they are in different lists,
-  // join the lists instead.
-  bool bMergeLists = false;
+  if (nsHTMLEditUtils::IsList(leftBlock) &&
+      nsHTMLEditUtils::IsListItem(rightBlock) &&
+      rightBlock->GetParentNode() == leftBlock) {
+    return NS_OK;
+  }
+
+  // Special rule here: if we are trying to join list items, and they are in
+  // different lists, join the lists instead.
+  bool mergeLists = false;
   nsIAtom* existingList = nsGkAtoms::_empty;
-  int32_t theOffset;
-  nsCOMPtr<nsIDOMNode> leftList, rightList;
-  if (nsHTMLEditUtils::IsListItem(aLeftBlock) &&
-      nsHTMLEditUtils::IsListItem(aRightBlock)) {
-    aLeftBlock->GetParentNode(getter_AddRefs(leftList));
-    aRightBlock->GetParentNode(getter_AddRefs(rightList));
-    if (leftList && rightList && (leftList!=rightList))
-    {
-      // there are some special complications if the lists are descendants of
-      // the other lists' items.  Note that it is ok for them to be descendants
-      // of the other lists themselves, which is the usual case for sublists
-      // in our impllementation.
-      if (!nsEditorUtils::IsDescendantOf(leftList, aRightBlock, &theOffset) &&
-          !nsEditorUtils::IsDescendantOf(rightList, aLeftBlock, &theOffset))
-      {
-        aLeftBlock = leftList;
-        aRightBlock = rightList;
-        bMergeLists = true;
-        NS_ENSURE_STATE(mHTMLEditor);
-        existingList = mHTMLEditor->GetTag(leftList);
-      }
-    }
-  }
-
-  NS_ENSURE_STATE(mHTMLEditor);
+  int32_t offset;
+  nsCOMPtr<Element> leftList, rightList;
+  if (nsHTMLEditUtils::IsListItem(leftBlock) &&
+      nsHTMLEditUtils::IsListItem(rightBlock)) {
+    leftList = leftBlock->GetParentElement();
+    rightList = rightBlock->GetParentElement();
+    if (leftList && rightList && leftList != rightList &&
+        !nsEditorUtils::IsDescendantOf(leftList, rightBlock, &offset) &&
+        !nsEditorUtils::IsDescendantOf(rightList, leftBlock, &offset)) {
+      // There are some special complications if the lists are descendants of
+      // the other lists' items.  Note that it is okay for them to be
+      // descendants of the other lists themselves, which is the usual case for
+      // sublists in our implementation.
+      leftBlock = leftList;
+      rightBlock = rightList;
+      mergeLists = true;
+      existingList = leftList->NodeInfo()->NameAtom();
+    }
+  }
+
   nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
 
   nsresult res = NS_OK;
-  int32_t  rightOffset = 0;
-  int32_t  leftOffset  = -1;
-
-  // theOffset below is where you find yourself in aRightBlock when you traverse upwards
-  // from aLeftBlock
-  if (nsEditorUtils::IsDescendantOf(aLeftBlock, aRightBlock, &rightOffset)) {
-    // tricky case.  left block is inside right block.
-    // Do ws adjustment.  This just destroys non-visible ws at boundaries we will be joining.
+  int32_t rightOffset = 0;
+  int32_t leftOffset = -1;
+
+  // offset below is where you find yourself in rightBlock when you traverse
+  // upwards from leftBlock
+  if (nsEditorUtils::IsDescendantOf(leftBlock, rightBlock, &rightOffset)) {
+    // Tricky case.  Left block is inside right block.  Do ws adjustment.  This
+    // just destroys non-visible ws at boundaries we will be joining.
     rightOffset++;
-    NS_ENSURE_STATE(mHTMLEditor);
-    nsCOMPtr<nsINode> leftBlock(do_QueryInterface(aLeftBlock));
     res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
                                             nsWSRunObject::kBlockEnd,
                                             leftBlock);
     NS_ENSURE_SUCCESS(res, res);
 
     {
+      // We can't just track rightBlock because it's an Element.
+      nsCOMPtr<nsINode> trackingRightBlock(rightBlock);
       nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
-                                  address_of(aRightBlock), &rightOffset);
-      nsCOMPtr<nsINode> rightBlock(do_QueryInterface(aRightBlock));
+                                  address_of(trackingRightBlock),
+                                  &rightOffset);
       res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
                                               nsWSRunObject::kAfterBlock,
                                               rightBlock, rightOffset);
       NS_ENSURE_SUCCESS(res, res);
+      if (trackingRightBlock->IsElement()) {
+        rightBlock = trackingRightBlock->AsElement();
+      } else {
+        NS_ENSURE_STATE(trackingRightBlock->GetParentElement());
+        rightBlock = trackingRightBlock->GetParentElement();
+      }
     }
     // Do br adjustment.
     nsCOMPtr<nsIDOMNode> brNode;
-    res = CheckForInvisibleBR(aLeftBlock, kBlockEnd, address_of(brNode));
+    res = CheckForInvisibleBR(GetAsDOMNode(leftBlock), kBlockEnd,
+                              address_of(brNode));
     NS_ENSURE_SUCCESS(res, res);
-    if (bMergeLists)
-    {
-      // idea here is to take all children in  rightList that are past
-      // theOffset, and pull them into leftlist.
-      nsCOMPtr<nsIContent> parent(do_QueryInterface(rightList));
-      NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
-
-      nsIContent *child = parent->GetChildAt(theOffset);
-      nsCOMPtr<nsINode> leftList_ = do_QueryInterface(leftList);
-      NS_ENSURE_STATE(leftList_);
-      while (child)
-      {
-        NS_ENSURE_STATE(mHTMLEditor);
-        res = mHTMLEditor->MoveNode(child, leftList_, -1);
+    if (mergeLists) {
+      // The idea here is to take all children in rightList that are past
+      // offset, and pull them into leftlist.
+      for (nsCOMPtr<nsIContent> child = rightList->GetChildAt(offset);
+           child; child = rightList->GetChildAt(rightOffset)) {
+        res = mHTMLEditor->MoveNode(child, leftList, -1);
         NS_ENSURE_SUCCESS(res, res);
-
-        child = parent->GetChildAt(rightOffset);
-      }
-    }
-    else
-    {
-      res = MoveBlock(aLeftBlock, aRightBlock, leftOffset, rightOffset);
-    }
-    NS_ENSURE_STATE(mHTMLEditor);
-    if (brNode) mHTMLEditor->DeleteNode(brNode);
-  // theOffset below is where you find yourself in aLeftBlock when you traverse upwards
-  // from aRightBlock
-  } else if (nsEditorUtils::IsDescendantOf(aRightBlock, aLeftBlock, &leftOffset)) {
-    // tricky case.  right block is inside left block.
-    // Do ws adjustment.  This just destroys non-visible ws at boundaries we will be joining.
-    NS_ENSURE_STATE(mHTMLEditor);
-    nsCOMPtr<nsINode> rightBlock(do_QueryInterface(aRightBlock));
+      }
+    } else {
+      res = MoveBlock(GetAsDOMNode(leftBlock), GetAsDOMNode(rightBlock),
+                      leftOffset, rightOffset);
+    }
+    if (brNode) {
+      mHTMLEditor->DeleteNode(brNode);
+    }
+  // Offset below is where you find yourself in leftBlock when you traverse
+  // upwards from rightBlock
+  } else if (nsEditorUtils::IsDescendantOf(rightBlock, leftBlock,
+                                           &leftOffset)) {
+    // Tricky case.  Right block is inside left block.  Do ws adjustment.  This
+    // just destroys non-visible ws at boundaries we will be joining.
     res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
                                             nsWSRunObject::kBlockStart,
                                             rightBlock);
     NS_ENSURE_SUCCESS(res, res);
-    NS_ENSURE_STATE(mHTMLEditor);
     {
+      // We can't just track leftBlock because it's an Element, so track
+      // something else.
+      nsCOMPtr<nsINode> trackingLeftBlock(leftBlock);
       nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
-                                  address_of(aLeftBlock), &leftOffset);
-      nsCOMPtr<nsINode> leftBlock(do_QueryInterface(aLeftBlock));
+                                  address_of(trackingLeftBlock), &leftOffset);
       res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
                                               nsWSRunObject::kBeforeBlock,
                                               leftBlock, leftOffset);
       NS_ENSURE_SUCCESS(res, res);
+      if (trackingLeftBlock->IsElement()) {
+        leftBlock = trackingLeftBlock->AsElement();
+      } else {
+        NS_ENSURE_STATE(trackingLeftBlock->GetParentElement());
+        leftBlock = trackingLeftBlock->GetParentElement();
+      }
     }
     // Do br adjustment.
     nsCOMPtr<nsIDOMNode> brNode;
-    res = CheckForInvisibleBR(aLeftBlock, kBeforeBlock, address_of(brNode),
-                              leftOffset);
+    res = CheckForInvisibleBR(GetAsDOMNode(leftBlock), kBeforeBlock,
+                              address_of(brNode), leftOffset);
     NS_ENSURE_SUCCESS(res, res);
-    if (bMergeLists)
-    {
-      res = MoveContents(rightList, leftList, &leftOffset);
-    }
-    else
-    {
+    if (mergeLists) {
+      res = MoveContents(GetAsDOMNode(rightList), GetAsDOMNode(leftList),
+                         &leftOffset);
+    } else {
       // Left block is a parent of right block, and the parent of the previous
       // visible content.  Right block is a child and contains the contents we
       // want to move.
 
       int32_t previousContentOffset;
-      nsCOMPtr<nsIDOMNode> previousContentParent;
-
-      if (aLeftNode == aLeftBlock) {
+      nsCOMPtr<nsINode> previousContentParent;
+
+      if (&aLeftNode == leftBlock) {
         // We are working with valid HTML, aLeftNode is a block node, and is
-        // therefore allowed to contain aRightBlock.  This is the simple case,
-        // we will simply move the content in aRightBlock out of its block.
-        previousContentParent = aLeftBlock;
+        // therefore allowed to contain rightBlock.  This is the simple case,
+        // we will simply move the content in rightBlock out of its block.
+        previousContentParent = leftBlock;
         previousContentOffset = leftOffset;
       } else {
         // We try to work as well as possible with HTML that's already invalid.
         // Although "right block" is a block, and a block must not be contained
         // in inline elements, reality is that broken documents do exist.  The
         // DIRECT parent of "left NODE" might be an inline element.  Previous
         // versions of this code skipped inline parents until the first block
         // parent was found (and used "left block" as the destination).
         // However, in some situations this strategy moves the content to an
         // unexpected position.  (see bug 200416) The new idea is to make the
         // moving content a sibling, next to the previous visible content.
 
-        previousContentParent =
-          nsEditor::GetNodeLocation(aLeftNode, &previousContentOffset);
+        previousContentParent = aLeftNode.GetParentNode();
+        previousContentOffset = previousContentParent ?
+          previousContentParent->IndexOf(&aLeftNode) : -1;
 
         // We want to move our content just after the previous visible node.
         previousContentOffset++;
       }
 
       // Because we don't want the moving content to receive the style of the
       // previous content, we split the previous content's style.
 
-      NS_ENSURE_STATE(mHTMLEditor);
-      nsCOMPtr<nsINode> editorRoot = mHTMLEditor->GetEditorRoot();
-      if (!editorRoot || aLeftNode != editorRoot->AsDOMNode()) {
-        nsCOMPtr<nsIDOMNode> splittedPreviousContent;
-        NS_ENSURE_STATE(mHTMLEditor);
-        res = mHTMLEditor->SplitStyleAbovePoint(address_of(previousContentParent),
+      nsCOMPtr<Element> editorRoot = mHTMLEditor->GetEditorRoot();
+      if (!editorRoot || &aLeftNode != editorRoot) {
+        nsCOMPtr<nsIDOMNode> previousContentParentDOM =
+          GetAsDOMNode(previousContentParent);
+        nsCOMPtr<nsIDOMNode> splittedPreviousContentDOM;
+        res = mHTMLEditor->SplitStyleAbovePoint(address_of(previousContentParentDOM),
                                                 &previousContentOffset,
                                                 nullptr, nullptr, nullptr,
-                                                address_of(splittedPreviousContent));
+                                                address_of(splittedPreviousContentDOM));
         NS_ENSURE_SUCCESS(res, res);
-
-        if (splittedPreviousContent) {
-          previousContentParent =
-            nsEditor::GetNodeLocation(splittedPreviousContent,
-                                      &previousContentOffset);
+        previousContentParent = do_QueryInterface(previousContentParentDOM);
+        NS_ENSURE_STATE(previousContentParent || !previousContentParentDOM);
+
+        if (splittedPreviousContentDOM) {
+          nsCOMPtr<nsINode> splittedPreviousContent =
+            do_QueryInterface(splittedPreviousContentDOM);
+          NS_ENSURE_STATE(splittedPreviousContent ||
+                          !splittedPreviousContentDOM);
+          previousContentParent = splittedPreviousContent->GetParentNode();
+          previousContentOffset = previousContentParent ?
+            previousContentParent->IndexOf(splittedPreviousContent) : -1;
         }
       }
 
-      res = MoveBlock(previousContentParent, aRightBlock,
+      res = MoveBlock(GetAsDOMNode(previousContentParent),
+                      GetAsDOMNode(rightBlock),
                       previousContentOffset, rightOffset);
-    }
-    NS_ENSURE_STATE(mHTMLEditor);
-    if (brNode) mHTMLEditor->DeleteNode(brNode);
-  }
-  else
-  {
-    // normal case.  blocks are siblings, or at least close enough to siblings.  An example
-    // of the latter is a <p>paragraph</p><ul><li>one<li>two<li>three</ul>.  The first
-    // li and the p are not true siblings, but we still want to join them if you backspace
-    // from li into p.
-
-    // adjust whitespace at block boundaries
-    NS_ENSURE_STATE(mHTMLEditor);
-    nsCOMPtr<Element> leftBlock(do_QueryInterface(aLeftBlock));
-    nsCOMPtr<Element> rightBlock(do_QueryInterface(aRightBlock));
+      NS_ENSURE_SUCCESS(res, res);
+    }
+    if (brNode) {
+      mHTMLEditor->DeleteNode(brNode);
+    }
+  } else {
+    // Normal case.  Blocks are siblings, or at least close enough.  An example
+    // of the latter is <p>paragraph</p><ul><li>one<li>two<li>three</ul>.  The
+    // first li and the p are not true siblings, but we still want to join them
+    // if you backspace from li into p.
+
+    // Adjust whitespace at block boundaries
     res = nsWSRunObject::PrepareToJoinBlocks(mHTMLEditor, leftBlock, rightBlock);
     NS_ENSURE_SUCCESS(res, res);
     // Do br adjustment.
     nsCOMPtr<nsIDOMNode> brNode;
-    res = CheckForInvisibleBR(aLeftBlock, kBlockEnd, address_of(brNode));
+    res = CheckForInvisibleBR(GetAsDOMNode(leftBlock), kBlockEnd,
+                              address_of(brNode));
     NS_ENSURE_SUCCESS(res, res);
-    NS_ENSURE_STATE(mHTMLEditor);
-    if (bMergeLists || mHTMLEditor->NodesSameType(aLeftBlock, aRightBlock)) {
-      // nodes are same type.  merge them.
+    if (mergeLists || leftBlock->NodeInfo()->NameAtom() ==
+                      rightBlock->NodeInfo()->NameAtom()) {
+      // Nodes are same type.  Merge them.
       ::DOMPoint pt = JoinNodesSmart(*leftBlock, *rightBlock);
-      if (pt.node && bMergeLists) {
-        nsCOMPtr<nsIDOMNode> newBlock;
-        res = ConvertListType(aRightBlock, address_of(newBlock),
+      if (pt.node && mergeLists) {
+        nsCOMPtr<Element> newBlock;
+        res = ConvertListType(rightBlock, getter_AddRefs(newBlock),
                               existingList, nsGkAtoms::li);
       }
-    }
-    else
-    {
-      // nodes are disimilar types.
-      res = MoveBlock(aLeftBlock, aRightBlock, leftOffset, rightOffset);
-    }
-    if (NS_SUCCEEDED(res) && brNode)
-    {
-      NS_ENSURE_STATE(mHTMLEditor);
+    } else {
+      // Nodes are dissimilar types.
+      res = MoveBlock(GetAsDOMNode(leftBlock), GetAsDOMNode(rightBlock),
+                      leftOffset, rightOffset);
+      NS_ENSURE_SUCCESS(res, res);
+    }
+    if (brNode) {
       res = mHTMLEditor->DeleteNode(brNode);
-    }
-  }
-  return res;
+      NS_ENSURE_SUCCESS(res, res);
+    }
+  }
+  return NS_OK;
 }
 
 
 /*****************************************************************************************************
 *    MoveBlock: this method is used to move the content from rightBlock into leftBlock
 *    Note that the "block" might merely be inline nodes between <br>s, or between blocks, etc.
 *    DTD containment rules are followed throughout.
 *         nsIDOMNode *aLeftBlock         parent to receive moved content
--- a/editor/libeditor/nsHTMLEditRules.h
+++ b/editor/libeditor/nsHTMLEditRules.h
@@ -146,17 +146,18 @@ protected:
                                nsIEditor::EStripWrappers aStripWrappers,
                                bool* aCancel, bool* aHandled);
   nsresult DidDeleteSelection(mozilla::dom::Selection* aSelection,
                               nsIEditor::EDirection aDir,
                               nsresult aResult);
   nsresult InsertBRIfNeeded(mozilla::dom::Selection* aSelection);
   ::DOMPoint GetGoodSelPointForNode(nsINode& aNode,
                                     nsIEditor::EDirection aAction);
-  nsresult JoinBlocks(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, bool *aCanceled);
+  nsresult JoinBlocks(nsIContent& aLeftNode, nsIContent& aRightNode,
+                      bool* aCanceled);
   nsresult MoveBlock(nsIDOMNode *aLeft, nsIDOMNode *aRight, int32_t aLeftOffset, int32_t aRightOffset);
   nsresult MoveNodeSmart(nsIDOMNode *aSource, nsIDOMNode *aDest, int32_t *aOffset);
   nsresult MoveContents(nsIDOMNode *aSource, nsIDOMNode *aDest, int32_t *aOffset);
   nsresult DeleteNonTableElements(nsINode* aNode);
   nsresult WillMakeList(mozilla::dom::Selection* aSelection,
                         const nsAString* aListType,
                         bool aEntireList,
                         const nsAString* aBulletType,