Bug 1156062 - Back out for now, requested by Masayuki at bug 1191356 comment 23
authorAryeh Gregor <ayg@aryeh.name>
Wed, 20 Apr 2016 20:45:07 +0300
changeset 332017 9191bfcd54fbbdc3e540ecb33c573a267884070a
parent 332016 c91b0d2f2ed9a6386eb155319b47d3c0d06a5186
child 332018 227293880f3ed6db44a429e8ab36050da5312f35
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1156062, 1191356
milestone48.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 1156062 - Back out for now, requested by Masayuki at bug 1191356 comment 23
editor/libeditor/nsHTMLEditRules.cpp
editor/libeditor/nsHTMLEditRules.h
--- a/editor/libeditor/nsHTMLEditRules.cpp
+++ b/editor/libeditor/nsHTMLEditRules.cpp
@@ -2188,19 +2188,17 @@ 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);
-        NS_ENSURE_STATE(leftNode && leftNode->IsContent() &&
-                        rightNode && rightNode->IsContent());
-        res = JoinBlocks(*leftNode->AsContent(), *rightNode->AsContent(),
+        res = JoinBlocks(GetAsDOMNode(leftNode), GetAsDOMNode(rightNode),
                          aCancel);
         *aHandled = true;
         NS_ENSURE_SUCCESS(res, res);
       }
       aSelection->Collapse(selPointNode, selPointOffset);
       return NS_OK;
     }
 
@@ -2240,18 +2238,17 @@ nsHTMLEditRules::WillDeleteSelection(Sel
       }
 
       nsCOMPtr<nsINode> selPointNode = startNode;
       int32_t selPointOffset = startOffset;
       {
         NS_ENSURE_STATE(mHTMLEditor);
         nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
                                     address_of(selPointNode), &selPointOffset);
-        NS_ENSURE_STATE(leftNode->IsContent() && rightNode->IsContent());
-        res = JoinBlocks(*leftNode->AsContent(), *rightNode->AsContent(),
+        res = JoinBlocks(GetAsDOMNode(leftNode), GetAsDOMNode(rightNode),
                          aCancel);
         *aHandled = true;
         NS_ENSURE_SUCCESS(res, res);
       }
       aSelection->Collapse(selPointNode, selPointOffset);
       return NS_OK;
     }
   }
@@ -2427,17 +2424,18 @@ 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(*leftParent, *rightParent, aCancel);
+          res = JoinBlocks(GetAsDOMNode(leftParent), GetAsDOMNode(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
@@ -2522,286 +2520,304 @@ nsHTMLEditRules::GetGoodSelPointForNode(
        mHTMLEditor->IsVisBreak(&aNode)) &&
       aAction == nsIEditor::ePrevious) {
     ret.offset++;
   }
   return ret;
 }
 
 
-/**
- * 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.
- */
+/*****************************************************************************************************
+*    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
+*/
 nsresult
-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
+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
     *aCanceled = true;
     return NS_OK;
   }
 
-  // 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) {
+  // 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) {
     *aCanceled = true;
     return NS_OK;
   }
 
   // Joining a list item to its parent is a NOP.
-  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;
+  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;
   nsIAtom* existingList = nsGkAtoms::_empty;
-  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();
-    }
-  }
-
+  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);
   nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
 
   nsresult res = NS_OK;
-  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.
+  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.
     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(trackingRightBlock),
-                                  &rightOffset);
+                                  address_of(aRightBlock), &rightOffset);
+      nsCOMPtr<nsINode> rightBlock(do_QueryInterface(aRightBlock));
       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(GetAsDOMNode(leftBlock), kBlockEnd,
-                              address_of(brNode));
+    res = CheckForInvisibleBR(aLeftBlock, kBlockEnd, address_of(brNode));
     NS_ENSURE_SUCCESS(res, res);
-    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);
+    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);
         NS_ENSURE_SUCCESS(res, res);
-      }
-    } 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.
+
+        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));
     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(trackingLeftBlock), &leftOffset);
+                                  address_of(aLeftBlock), &leftOffset);
+      nsCOMPtr<nsINode> leftBlock(do_QueryInterface(aLeftBlock));
       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(GetAsDOMNode(leftBlock), kBeforeBlock,
-                              address_of(brNode), leftOffset);
+    res = CheckForInvisibleBR(aLeftBlock, kBeforeBlock, address_of(brNode),
+                              leftOffset);
     NS_ENSURE_SUCCESS(res, res);
-    if (mergeLists) {
-      res = MoveContents(GetAsDOMNode(rightList), GetAsDOMNode(leftList),
-                         &leftOffset);
-    } else {
+    if (bMergeLists)
+    {
+      res = MoveContents(rightList, 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<nsINode> previousContentParent;
-
-      if (&aLeftNode == leftBlock) {
+      nsCOMPtr<nsIDOMNode> previousContentParent;
+
+      if (aLeftNode == aLeftBlock) {
         // We are working with valid HTML, aLeftNode is a block node, and is
-        // therefore allowed to contain rightBlock.  This is the simple case,
-        // we will simply move the content in rightBlock out of its block.
-        previousContentParent = leftBlock;
+        // therefore allowed to contain aRightBlock.  This is the simple case,
+        // we will simply move the content in aRightBlock out of its block.
+        previousContentParent = aLeftBlock;
         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 = aLeftNode.GetParentNode();
-        previousContentOffset = previousContentParent ?
-          previousContentParent->IndexOf(&aLeftNode) : -1;
+        previousContentParent =
+          nsEditor::GetNodeLocation(aLeftNode, &previousContentOffset);
 
         // 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.
 
-      nsCOMPtr<Element> editorRoot = mHTMLEditor->GetEditorRoot();
-      if (!editorRoot || &aLeftNode != editorRoot) {
-        nsCOMPtr<nsIDOMNode> previousContentParentDOM =
-          GetAsDOMNode(previousContentParent);
-        nsCOMPtr<nsIDOMNode> splittedPreviousContentDOM;
-        res = mHTMLEditor->SplitStyleAbovePoint(address_of(previousContentParentDOM),
+      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),
                                                 &previousContentOffset,
                                                 nullptr, nullptr, nullptr,
-                                                address_of(splittedPreviousContentDOM));
+                                                address_of(splittedPreviousContent));
         NS_ENSURE_SUCCESS(res, res);
-        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;
+
+        if (splittedPreviousContent) {
+          previousContentParent =
+            nsEditor::GetNodeLocation(splittedPreviousContent,
+                                      &previousContentOffset);
         }
       }
 
-      res = MoveBlock(GetAsDOMNode(previousContentParent),
-                      GetAsDOMNode(rightBlock),
+      res = MoveBlock(previousContentParent, aRightBlock,
                       previousContentOffset, rightOffset);
-      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
+    }
+    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));
     res = nsWSRunObject::PrepareToJoinBlocks(mHTMLEditor, leftBlock, rightBlock);
     NS_ENSURE_SUCCESS(res, res);
     // Do br adjustment.
     nsCOMPtr<nsIDOMNode> brNode;
-    res = CheckForInvisibleBR(GetAsDOMNode(leftBlock), kBlockEnd,
-                              address_of(brNode));
+    res = CheckForInvisibleBR(aLeftBlock, kBlockEnd, address_of(brNode));
     NS_ENSURE_SUCCESS(res, res);
-    if (mergeLists || leftBlock->NodeInfo()->NameAtom() ==
-                      rightBlock->NodeInfo()->NameAtom()) {
-      // Nodes are same type.  Merge them.
+    NS_ENSURE_STATE(mHTMLEditor);
+    if (bMergeLists || mHTMLEditor->NodesSameType(aLeftBlock, aRightBlock)) {
+      // nodes are same type.  merge them.
       ::DOMPoint pt = JoinNodesSmart(*leftBlock, *rightBlock);
-      if (pt.node && mergeLists) {
-        nsCOMPtr<Element> newBlock;
-        res = ConvertListType(rightBlock, getter_AddRefs(newBlock),
+      if (pt.node && bMergeLists) {
+        nsCOMPtr<nsIDOMNode> newBlock;
+        res = ConvertListType(aRightBlock, address_of(newBlock),
                               existingList, nsGkAtoms::li);
       }
-    } else {
-      // Nodes are dissimilar types.
-      res = MoveBlock(GetAsDOMNode(leftBlock), GetAsDOMNode(rightBlock),
-                      leftOffset, rightOffset);
-      NS_ENSURE_SUCCESS(res, res);
-    }
-    if (brNode) {
+    }
+    else
+    {
+      // nodes are disimilar types.
+      res = MoveBlock(aLeftBlock, aRightBlock, leftOffset, rightOffset);
+    }
+    if (NS_SUCCEEDED(res) && brNode)
+    {
+      NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->DeleteNode(brNode);
-      NS_ENSURE_SUCCESS(res, res);
-    }
-  }
-  return NS_OK;
+    }
+  }
+  return res;
 }
 
 
 /*****************************************************************************************************
 *    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,18 +146,17 @@ 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(nsIContent& aLeftNode, nsIContent& aRightNode,
-                      bool* aCanceled);
+  nsresult JoinBlocks(nsIDOMNode *aLeftNode, nsIDOMNode *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,