Bug 1445569 - part 4: Get rid of EditorBase::GetStartNodeAndOffset() and EditorBase::GetEndNodeAndOffset() r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 15 Mar 2018 21:25:41 +0900
changeset 768343 8575488ffaa3fc6d292c8975c013a5173ff267db
parent 768342 1fd7ffcc3f5a1e926278ff3e91bef91d6512ad06
push id102858
push usermasayuki@d-toybox.com
push dateFri, 16 Mar 2018 03:57:40 +0000
reviewersm_kato
bugs1445569
milestone61.0a1
Bug 1445569 - part 4: Get rid of EditorBase::GetStartNodeAndOffset() and EditorBase::GetEndNodeAndOffset() r?m_kato EditorBase::GetStartNodeAndOffset() and EditorBase::GetEndNodeAndOffset() are just wrappers of EditorBase::GetStartPoint() and EditorBase::GetEndPoint(). They may *compute* offset in the container node even if some callers don't need the offset. Therefore, we should get rid of them and make all callers use EditorBase::GetStartPoint() or EditorBase::GetEndPoint() directly. Note that EditorBase::GetStartNodeAndOffset() and EditorBase::GetEndNodeAndOffset() returns NS_ERROR_FAILURE if EditorBase::GetStartPoint() or EditorBase::GetEndPoint() returns not set point. Therefore, checking the result is set equals checking the old nsresult as an error. MozReview-Commit-ID: JLwqRMFLjHC
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditorDataTransfer.cpp
editor/libeditor/TextEditRules.cpp
editor/libeditor/TypeInState.cpp
editor/libeditor/TypeInState.h
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -4033,42 +4033,16 @@ EditorBase::GetNodeAtRangeOffsetPoint(co
     return nullptr;
   }
   if (aPoint.Container()->GetAsText()) {
     return aPoint.Container()->AsContent();
   }
   return aPoint.GetChildAtOffset();
 }
 
-/**
- * GetStartNodeAndOffset() returns whatever the start parent & offset is of
- * the first range in the selection.
- */
-nsresult
-EditorBase::GetStartNodeAndOffset(Selection* aSelection,
-                                  nsINode** aStartContainer,
-                                  int32_t* aStartOffset)
-{
-  MOZ_ASSERT(aSelection);
-  MOZ_ASSERT(aStartContainer);
-  MOZ_ASSERT(aStartOffset);
-
-  *aStartContainer = nullptr;
-  *aStartOffset = 0;
-
-  EditorRawDOMPoint point = EditorBase::GetStartPoint(aSelection);
-  if (!point.IsSet()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  NS_ADDREF(*aStartContainer = point.GetContainer());
-  *aStartOffset = point.Offset();
-  return NS_OK;
-}
-
 // static
 EditorRawDOMPoint
 EditorBase::GetStartPoint(Selection* aSelection)
 {
   MOZ_ASSERT(aSelection);
 
   if (NS_WARN_IF(!aSelection->RangeCount())) {
     return EditorRawDOMPoint();
@@ -4078,42 +4052,16 @@ EditorBase::GetStartPoint(Selection* aSe
   if (NS_WARN_IF(!range) ||
       NS_WARN_IF(!range->IsPositioned())) {
     return EditorRawDOMPoint();
   }
 
   return EditorRawDOMPoint(range->StartRef());
 }
 
-/**
- * GetEndNodeAndOffset() returns whatever the end parent & offset is of
- * the first range in the selection.
- */
-nsresult
-EditorBase::GetEndNodeAndOffset(Selection* aSelection,
-                                nsINode** aEndContainer,
-                                int32_t* aEndOffset)
-{
-  MOZ_ASSERT(aSelection);
-  MOZ_ASSERT(aEndContainer);
-  MOZ_ASSERT(aEndOffset);
-
-  *aEndContainer = nullptr;
-  *aEndOffset = 0;
-
-  EditorRawDOMPoint point = EditorBase::GetEndPoint(aSelection);
-  if (!point.IsSet()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  NS_ADDREF(*aEndContainer = point.GetContainer());
-  *aEndOffset = point.Offset();
-  return NS_OK;
-}
-
 // static
 EditorRawDOMPoint
 EditorBase::GetEndPoint(Selection* aSelection)
 {
   MOZ_ASSERT(aSelection);
 
   if (NS_WARN_IF(!aSelection->RangeCount())) {
     return EditorRawDOMPoint();
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -1116,23 +1116,17 @@ public:
    */
   static nsIContent* GetNodeAtRangeOffsetPoint(nsINode* aContainer,
                                                int32_t aOffset)
   {
     return GetNodeAtRangeOffsetPoint(RawRangeBoundary(aContainer, aOffset));
   }
   static nsIContent* GetNodeAtRangeOffsetPoint(const RawRangeBoundary& aPoint);
 
-  static nsresult GetStartNodeAndOffset(Selection* aSelection,
-                                        nsINode** aStartContainer,
-                                        int32_t* aStartOffset);
   static EditorRawDOMPoint GetStartPoint(Selection* aSelection);
-  static nsresult GetEndNodeAndOffset(Selection* aSelection,
-                                      nsINode** aEndContainer,
-                                      int32_t* aEndOffset);
   static EditorRawDOMPoint GetEndPoint(Selection* aSelection);
 
   static nsresult GetEndChildNode(Selection* aSelection,
                                   nsIContent** aEndNode);
 
   Selection* GetSelection(SelectionType aSelectionType =
                                           SelectionType::eNormal)
   {
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1020,52 +1020,58 @@ HTMLEditRules::GetIndentState(bool* aCan
       // if the number part is strictly positive, outdent is possible
       if (0 < f) {
         *aCanOutdent = true;
         break;
       }
     }
   }
 
-  if (!*aCanOutdent) {
-    // if we haven't found something to outdent yet, also check the parents
-    // of selection endpoints.  We might have a blockquote or list item
-    // in the parent hierarchy.
-
-    // gather up info we need for test
-    NS_ENSURE_STATE(mHTMLEditor);
-    nsCOMPtr<nsINode> parent, root = mHTMLEditor->GetRoot();
-    NS_ENSURE_TRUE(root, NS_ERROR_NULL_POINTER);
-    int32_t selOffset;
-    NS_ENSURE_STATE(mHTMLEditor);
-    RefPtr<Selection> selection = mHTMLEditor->GetSelection();
-    NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
-
-    // test start parent hierarchy
-    rv = EditorBase::GetStartNodeAndOffset(selection, getter_AddRefs(parent),
-                                           &selOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    while (parent && parent != root) {
-      if (HTMLEditUtils::IsNodeThatCanOutdent(parent)) {
-        *aCanOutdent = true;
-        break;
-      }
-      parent = parent->GetParentNode();
-    }
-
-    // test end parent hierarchy
-    rv = EditorBase::GetEndNodeAndOffset(selection, getter_AddRefs(parent),
-                                         &selOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    while (parent && parent != root) {
-      if (HTMLEditUtils::IsNodeThatCanOutdent(parent)) {
-        *aCanOutdent = true;
-        break;
-      }
-      parent = parent->GetParentNode();
+  if (*aCanOutdent) {
+    return NS_OK;
+  }
+
+  // if we haven't found something to outdent yet, also check the parents
+  // of selection endpoints.  We might have a blockquote or list item
+  // in the parent hierarchy.
+
+  if (NS_WARN_IF(!mHTMLEditor)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  Element* rootElement = mHTMLEditor->GetRoot();
+  if (NS_WARN_IF(!rootElement)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Test selection start container hierarchy.
+  EditorRawDOMPoint selectionStartPoint(EditorBase::GetStartPoint(selection));
+  if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
+    return NS_ERROR_FAILURE;
+  }
+  for (nsINode* node = selectionStartPoint.GetContainer();
+       node && node != rootElement;
+       node = node->GetParentNode()) {
+    if (HTMLEditUtils::IsNodeThatCanOutdent(node)) {
+      *aCanOutdent = true;
+      return NS_OK;
+    }
+  }
+
+  // Test selection end container hierarchy.
+  EditorRawDOMPoint selectionEndPoint(EditorBase::GetEndPoint(selection));
+  if (NS_WARN_IF(!selectionEndPoint.IsSet())) {
+    return NS_ERROR_FAILURE;
+  }
+  for (nsINode* node = selectionEndPoint.GetContainer();
+       node && node != rootElement;
+       node = node->GetParentNode()) {
+    if (HTMLEditUtils::IsNodeThatCanOutdent(node)) {
+      *aCanOutdent = true;
+      return NS_OK;
     }
   }
   return NS_OK;
 }
 
 
 nsresult
 HTMLEditRules::GetParagraphState(bool* aMixed,
@@ -1097,26 +1103,28 @@ HTMLEditRules::GetParagraphState(bool* a
       rv = AppendInnerFormatNodes(arrayOfNodes, curNode);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   // we might have an empty node list.  if so, find selection parent
   // and put that on the list
   if (arrayOfNodes.IsEmpty()) {
-    nsCOMPtr<nsINode> selNode;
-    int32_t selOffset;
-    NS_ENSURE_STATE(mHTMLEditor);
-    RefPtr<Selection> selection = mHTMLEditor->GetSelection();
-    NS_ENSURE_STATE(selection);
-    rv = EditorBase::GetStartNodeAndOffset(selection, getter_AddRefs(selNode),
-                                           &selOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(selNode, NS_ERROR_NULL_POINTER);
-    arrayOfNodes.AppendElement(*selNode);
+    if (NS_WARN_IF(!mHTMLEditor)) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+    Selection* selection = mHTMLEditor->GetSelection();
+    if (NS_WARN_IF(!selection)) {
+      return NS_ERROR_FAILURE;
+    }
+    EditorRawDOMPoint selectionStartPoint(EditorBase::GetStartPoint(selection));
+    if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
+      return NS_ERROR_FAILURE;
+    }
+    arrayOfNodes.AppendElement(*selectionStartPoint.GetContainer());
   }
 
   // remember root node
   NS_ENSURE_STATE(mHTMLEditor);
   nsCOMPtr<Element> rootElem = mHTMLEditor->GetRoot();
   NS_ENSURE_TRUE(rootElem, NS_ERROR_NULL_POINTER);
 
   // loop through the nodes in selection and examine their paragraph format
@@ -1978,162 +1986,180 @@ HTMLEditRules::SplitMailCites(Selection*
     return NS_ERROR_INVALID_ARG;
   }
 
   if (NS_WARN_IF(!mHTMLEditor)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
 
-  nsCOMPtr<nsINode> selNode;
-  nsCOMPtr<Element> citeNode;
-  int32_t selOffset;
-  nsresult rv =
-    EditorBase::GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode),
-                                      &selOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  citeNode = GetTopEnclosingMailCite(*selNode);
-  if (citeNode) {
-    // If our selection is just before a break, nudge it to be
-    // just after it.  This does two things for us.  It saves us the trouble of having to add
-    // a break here ourselves to preserve the "blockness" of the inline span mailquote
-    // (in the inline case), and :
-    // it means the break won't end up making an empty line that happens to be inside a
-    // mailquote (in either inline or block case).
-    // The latter can confuse a user if they click there and start typing,
-    // because being in the mailquote may affect wrapping behavior, or font color, etc.
-    WSRunObject wsObj(htmlEditor, selNode, selOffset);
+  EditorRawDOMPoint pointToSplit(EditorBase::GetStartPoint(aSelection));
+  if (NS_WARN_IF(!pointToSplit.IsSet())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  RefPtr<Element> citeNode =
+    GetTopEnclosingMailCite(*pointToSplit.GetContainer());
+  if (!citeNode) {
+    return NS_OK;
+  }
+
+  // If our selection is just before a break, nudge it to be just after it.
+  // This does two things for us.  It saves us the trouble of having to add
+  // a break here ourselves to preserve the "blockness" of the inline span
+  // mailquote (in the inline case), and :
+  // it means the break won't end up making an empty line that happens to be
+  // inside a mailquote (in either inline or block case).
+  // The latter can confuse a user if they click there and start typing,
+  // because being in the mailquote may affect wrapping behavior, or font
+  // color, etc.
+  WSRunObject wsObj(htmlEditor, pointToSplit);
+  nsCOMPtr<nsINode> visNode;
+  int32_t visOffset=0;
+  WSType wsType;
+  wsObj.NextVisibleNode(pointToSplit, address_of(visNode), &visOffset, &wsType);
+  // If selection start point is before a break and it's inside the mailquote,
+  // let's split it after the visible node.
+  if (wsType == WSType::br &&
+      visNode != citeNode && citeNode->Contains(visNode)) {
+    pointToSplit.Set(visNode);
+    DebugOnly<bool> advanced = pointToSplit.AdvanceOffset();
+    NS_WARNING_ASSERTION(advanced,
+      "Failed to advance offset to after the visible node");
+  }
+
+  if (NS_WARN_IF(!pointToSplit.GetContainerAsContent())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  SplitNodeResult splitCiteNodeResult =
+    htmlEditor->SplitNodeDeep(*citeNode, pointToSplit,
+                              SplitAtEdges::eDoNotCreateEmptyContainer);
+  if (NS_WARN_IF(splitCiteNodeResult.Failed())) {
+    return splitCiteNodeResult.Rv();
+  }
+  pointToSplit.Clear();
+
+  // Add an invisible <br> to the end of current cite node (If new left cite
+  // has not been created, we're at the end of it.  Otherwise, we're still at
+  // the right node) if it was a <span> of style="display: block". This is
+  // important, since when serializing the cite to plain text, the span which
+  // caused the visual break is discarded.  So the added <br> will guarantee
+  // that the serializer will insert a break where the user saw one.
+  // FYI: splitCiteNodeResult grabs the previous node with nsCOMPtr.  So, it's
+  //      safe to access previousNodeOfSplitPoint even after changing the DOM
+  //      tree and/or selection even though it's raw pointer.
+  nsIContent* previousNodeOfSplitPoint =
+    splitCiteNodeResult.GetPreviousNode();
+  if (previousNodeOfSplitPoint &&
+      previousNodeOfSplitPoint->IsHTMLElement(nsGkAtoms::span) &&
+      previousNodeOfSplitPoint->GetPrimaryFrame()->
+                                  IsFrameOfType(nsIFrame::eBlockFrame)) {
+    nsCOMPtr<nsINode> lastChild =
+      previousNodeOfSplitPoint->GetLastChild();
+    if (lastChild && !lastChild->IsHTMLElement(nsGkAtoms::br)) {
+      // We ignore the result here.
+      EditorRawDOMPoint endOfPreviousNodeOfSplitPoint;
+      endOfPreviousNodeOfSplitPoint.SetToEndOf(previousNodeOfSplitPoint);
+      RefPtr<Element> invisBR =
+        htmlEditor->CreateBR(endOfPreviousNodeOfSplitPoint);
+    }
+  }
+
+  // In most cases, <br> should be inserted after current cite.  However, if
+  // left cite hasn't been created because the split point was start of the
+  // cite node, <br> should be inserted before the current cite.
+  EditorRawDOMPoint pointToInsertBrNode(splitCiteNodeResult.SplitPoint());
+  RefPtr<Element> brNode = htmlEditor->CreateBR(pointToInsertBrNode);
+  if (NS_WARN_IF(!brNode)) {
+    return NS_ERROR_FAILURE;
+  }
+  // Now, offset of pointToInsertBrNode is invalid.  Let's clear it.
+  pointToInsertBrNode.Clear();
+
+  // Want selection before the break, and on same line.
+  EditorDOMPoint atBrNode(brNode);
+  Unused << atBrNode.Offset(); // Needs offset after collapsing the selection.
+  aSelection->SetInterlinePosition(true);
+  ErrorResult error;
+  aSelection->Collapse(atBrNode, error);
+  if (NS_WARN_IF(error.Failed())) {
+    return error.StealNSResult();
+  }
+
+  // if citeNode wasn't a block, we might also want another break before it.
+  // We need to examine the content both before the br we just added and also
+  // just after it.  If we don't have another br or block boundary adjacent,
+  // then we will need a 2nd br added to achieve blank line that user expects.
+  if (IsInlineNode(*citeNode)) {
+    // Use DOM point which we tried to collapse to.
+    EditorRawDOMPoint pointToCreateNewBrNode(atBrNode.GetContainer(),
+                                             atBrNode.Offset());
+
+    WSRunObject wsObj(htmlEditor, pointToCreateNewBrNode);
     nsCOMPtr<nsINode> visNode;
     int32_t visOffset=0;
     WSType wsType;
-    wsObj.NextVisibleNode(EditorRawDOMPoint(selNode, selOffset),
-                          address_of(visNode), &visOffset, &wsType);
-    if (wsType == WSType::br) {
-      // ok, we are just before a break.  is it inside the mailquote?
-      if (visNode != citeNode && citeNode->Contains(visNode)) {
-        // it is.  so lets reset our selection to be just after it.
-        selNode = EditorBase::GetNodeLocation(visNode, &selOffset);
-        ++selOffset;
-      }
-    }
-
-    NS_ENSURE_STATE(selNode->IsContent());
-    SplitNodeResult splitCiteNodeResult =
-      htmlEditor->SplitNodeDeep(*citeNode,
-                                EditorRawDOMPoint(selNode, selOffset),
-                                SplitAtEdges::eDoNotCreateEmptyContainer);
-    if (NS_WARN_IF(splitCiteNodeResult.Failed())) {
-      return splitCiteNodeResult.Rv();
-    }
-
-    // Add an invisible <br> to the end of current cite node (If new left cite
-    // has not been created, we're at the end of it.  Otherwise, we're still at
-    // the right node) if it was a <span> of style="display: block". This is
-    // important, since when serializing the cite to plain text, the span which
-    // caused the visual break is discarded.  So the added <br> will guarantee
-    // that the serializer will insert a break where the user saw one.
-    // FYI: splitCiteNodeResult grabs the previous node with nsCOMPtr.
-    //      So, it's safe to access previousNodeOfSplitPoint even after
-    //      changing the DOM tree and/or selection even though it's raw pointer.
-    nsIContent* previousNodeOfSplitPoint =
-      splitCiteNodeResult.GetPreviousNode();
-    if (previousNodeOfSplitPoint &&
-        previousNodeOfSplitPoint->IsHTMLElement(nsGkAtoms::span) &&
-        previousNodeOfSplitPoint->GetPrimaryFrame()->
-                                    IsFrameOfType(nsIFrame::eBlockFrame)) {
-      nsCOMPtr<nsINode> lastChild =
-        previousNodeOfSplitPoint->GetLastChild();
-      if (lastChild && !lastChild->IsHTMLElement(nsGkAtoms::br)) {
-        // We ignore the result here.
-        EditorRawDOMPoint endOfPreviousNodeOfSplitPoint;
-        endOfPreviousNodeOfSplitPoint.SetToEndOf(previousNodeOfSplitPoint);
-        RefPtr<Element> invisBR =
-          htmlEditor->CreateBR(endOfPreviousNodeOfSplitPoint);
-      }
-    }
-
-    // In most cases, <br> should be inserted after current cite.  However, if
-    // left cite hasn't been created because the split point was start of the
-    // cite node, <br> should be inserted before the current cite.
-    EditorRawDOMPoint pointToInsertBrNode(splitCiteNodeResult.SplitPoint());
-    RefPtr<Element> brNode = htmlEditor->CreateBR(pointToInsertBrNode);
-    if (NS_WARN_IF(!brNode)) {
-      return NS_ERROR_FAILURE;
-    }
-    // Now, offset of pointToInsertBrNode is invalid.  Let's clear it.
-    pointToInsertBrNode.Clear();
-
-    // Want selection before the break, and on same line.
-    EditorRawDOMPoint atBrNode(brNode);
-    aSelection->SetInterlinePosition(true);
-    ErrorResult error;
-    aSelection->Collapse(atBrNode, error);
-    if (NS_WARN_IF(error.Failed())) {
-      return error.StealNSResult();
-    }
-
-    selNode = atBrNode.GetContainer();
-    selOffset = atBrNode.Offset();
-
-    // if citeNode wasn't a block, we might also want another break before it.
-    // We need to examine the content both before the br we just added and also
-    // just after it.  If we don't have another br or block boundary adjacent,
-    // then we will need a 2nd br added to achieve blank line that user expects.
-    if (IsInlineNode(*citeNode)) {
-      WSRunObject wsObj(htmlEditor, selNode, selOffset);
-      nsCOMPtr<nsINode> visNode;
-      int32_t visOffset=0;
-      WSType wsType;
-      wsObj.PriorVisibleNode(EditorRawDOMPoint(selNode, selOffset),
-                             address_of(visNode), &visOffset, &wsType);
+    wsObj.PriorVisibleNode(pointToCreateNewBrNode,
+                           address_of(visNode), &visOffset, &wsType);
+    if (wsType == WSType::normalWS || wsType == WSType::text ||
+        wsType == WSType::special) {
+      EditorRawDOMPoint pointAfterNewBrNode(pointToCreateNewBrNode);
+      DebugOnly<bool> advanced = pointAfterNewBrNode.AdvanceOffset();
+      NS_WARNING_ASSERTION(advanced,
+        "Failed to advance offset after the <br> node");
+      WSRunObject wsObjAfterBR(htmlEditor, pointAfterNewBrNode);
+      wsObjAfterBR.NextVisibleNode(pointAfterNewBrNode,
+                                   address_of(visNode), &visOffset, &wsType);
       if (wsType == WSType::normalWS || wsType == WSType::text ||
-          wsType == WSType::special) {
-        WSRunObject wsObjAfterBR(htmlEditor, selNode, selOffset + 1);
-        wsObjAfterBR.NextVisibleNode(EditorRawDOMPoint(selNode, selOffset + 1),
-                                     address_of(visNode), &visOffset, &wsType);
-        if (wsType == WSType::normalWS || wsType == WSType::text ||
-            wsType == WSType::special ||
-            // In case we're at the very end.
-            wsType == WSType::thisBlock) {
-          brNode = htmlEditor->CreateBR(EditorRawDOMPoint(selNode, selOffset));
-          NS_ENSURE_STATE(brNode);
+          wsType == WSType::special ||
+          // In case we're at the very end.
+          wsType == WSType::thisBlock) {
+        brNode = htmlEditor->CreateBR(pointToCreateNewBrNode);
+        if (NS_WARN_IF(!brNode)) {
+          return NS_ERROR_FAILURE;
         }
-      }
-    }
-
-    // delete any empty cites
-    bool bEmptyCite = false;
-    if (previousNodeOfSplitPoint) {
-      rv = htmlEditor->IsEmptyNode(previousNodeOfSplitPoint, &bEmptyCite,
-                                   true, false);
+        // Now, those points may be invalid.
+        pointToCreateNewBrNode.Clear();
+        pointAfterNewBrNode.Clear();
+      }
+    }
+  }
+
+  // delete any empty cites
+  bool bEmptyCite = false;
+  if (previousNodeOfSplitPoint) {
+    nsresult rv =
+      htmlEditor->IsEmptyNode(previousNodeOfSplitPoint, &bEmptyCite,
+                              true, false);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    if (bEmptyCite) {
+      rv = htmlEditor->DeleteNode(previousNodeOfSplitPoint);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
-      if (bEmptyCite) {
-        rv = htmlEditor->DeleteNode(previousNodeOfSplitPoint);
-        if (NS_WARN_IF(NS_FAILED(rv))) {
-          return rv;
-        }
-      }
-    }
-
-    if (citeNode) {
-      rv = htmlEditor->IsEmptyNode(citeNode, &bEmptyCite, true, false);
+    }
+  }
+
+  if (citeNode) {
+    nsresult rv = htmlEditor->IsEmptyNode(citeNode, &bEmptyCite, true, false);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    if (bEmptyCite) {
+      rv = htmlEditor->DeleteNode(citeNode);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
-      if (bEmptyCite) {
-        rv = htmlEditor->DeleteNode(citeNode);
-        if (NS_WARN_IF(NS_FAILED(rv))) {
-          return rv;
-        }
-      }
-    }
-    *aHandled = true;
-  }
+    }
+  }
+
+  *aHandled = true;
   return NS_OK;
 }
 
 
 nsresult
 HTMLEditRules::WillDeleteSelection(Selection* aSelection,
                                    nsIEditor::EDirection aAction,
                                    nsIEditor::EStripWrappers aStripWrappers,
@@ -4063,23 +4089,23 @@ HTMLEditRules::WillCSSIndent(Selection* 
   nsTArray<OwningNonNull<nsRange>> arrayOfRanges;
   nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
 
   // short circuit: detect case of collapsed selection inside an <li>.
   // just sublist that <li>.  This prevents bug 97797.
 
   nsCOMPtr<Element> liNode;
   if (aSelection->Collapsed()) {
-    nsCOMPtr<nsINode> node;
-    int32_t offset;
-    nsresult rv =
-      EditorBase::GetStartNodeAndOffset(aSelection,
-                                        getter_AddRefs(node), &offset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    RefPtr<Element> block = htmlEditor->GetBlock(*node);
+    EditorRawDOMPoint selectionStartPoint(
+                        EditorBase::GetStartPoint(aSelection));
+    if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
+      return NS_ERROR_FAILURE;
+    }
+    Element* block =
+      htmlEditor->GetBlock(*selectionStartPoint.GetContainer());
     if (block && HTMLEditUtils::IsListItem(block)) {
       liNode = block;
     }
   }
 
   if (liNode) {
     arrayOfNodes.AppendElement(*liNode);
   } else {
@@ -7991,60 +8017,55 @@ HTMLEditRules::AdjustSpecialBreaks()
       return;
     }
   }
 }
 
 nsresult
 HTMLEditRules::AdjustWhitespace(Selection* aSelection)
 {
-  // get selection point
-  nsCOMPtr<nsINode> selNode;
-  int32_t selOffset;
-  nsresult rv =
-    EditorBase::GetStartNodeAndOffset(aSelection,
-                                      getter_AddRefs(selNode), &selOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // ask whitespace object to tweak nbsp's
-  NS_ENSURE_STATE(mHTMLEditor);
-  return WSRunObject(mHTMLEditor, selNode, selOffset).AdjustWhitespace();
+  EditorRawDOMPoint selectionStartPoint(EditorBase::GetStartPoint(aSelection));
+  if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Ask whitespace object to tweak nbsp's
+  if (NS_WARN_IF(!mHTMLEditor)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+  return WSRunObject(mHTMLEditor, selectionStartPoint).AdjustWhitespace();
 }
 
 nsresult
 HTMLEditRules::PinSelectionToNewBlock(Selection* aSelection)
 {
   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
   if (!aSelection->Collapsed()) {
     return NS_OK;
   }
 
   if (NS_WARN_IF(!mNewBlock)) {
     return NS_ERROR_NULL_POINTER;
   }
 
-  // get the (collapsed) selection location
-  nsCOMPtr<nsINode> selNode;
-  int32_t selOffset;
-  nsresult rv =
-    EditorBase::GetStartNodeAndOffset(aSelection,
-                                      getter_AddRefs(selNode), &selOffset);
+  EditorRawDOMPoint selectionStartPoint(EditorBase::GetStartPoint(aSelection));
+  if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Use ranges and nsRange::CompareNodeToRange() to compare selection start
+  // to new block.
+  // XXX It's too expensive to use nsRange and set it only for comparing a
+  //     DOM point with a node.
+  RefPtr<nsRange> range = new nsRange(selectionStartPoint.GetContainer());
+  nsresult rv = range->CollapseTo(selectionStartPoint);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
-  if (NS_WARN_IF(!selNode)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  // use ranges and sRangeHelper to compare sel point to new block
-  RefPtr<nsRange> range = new nsRange(selNode);
-  rv = range->CollapseTo(selNode, selOffset);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
+
   bool nodeBefore, nodeAfter;
   rv = nsRange::CompareNodeToRange(mNewBlock, range, &nodeBefore, &nodeAfter);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (nodeBefore && nodeAfter) {
     return NS_OK;  // selection is inside block
   }
 
@@ -8712,75 +8733,67 @@ HTMLEditRules::RemoveListStructure(Eleme
 
   // Delete the now-empty list
   nsresult rv = htmlEditor->RemoveBlockContainer(aList);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
+// XXX This method is not necessary because even if selection is outside the
+//     <body> element, the element can be editable.
 nsresult
 HTMLEditRules::ConfirmSelectionInBody()
 {
-  // get the body
-  NS_ENSURE_STATE(mHTMLEditor);
-  RefPtr<Element> rootElement = mHTMLEditor->GetRoot();
+  if (NS_WARN_IF(!mHTMLEditor)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  Element* rootElement = mHTMLEditor->GetRoot();
   if (NS_WARN_IF(!rootElement)) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  // get the selection
-  NS_ENSURE_STATE(mHTMLEditor);
-  RefPtr<Selection> selection = mHTMLEditor->GetSelection();
+  Selection* selection = mHTMLEditor->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  // get the selection start location
-  nsCOMPtr<nsINode> selNode;
-  int32_t selOffset;
-  nsresult rv =
-    EditorBase::GetStartNodeAndOffset(selection,
-                                      getter_AddRefs(selNode), &selOffset);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsINode* temp = selNode;
+  EditorRawDOMPoint selectionStartPoint(EditorBase::GetStartPoint(selection));
+  if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Check that selection start container is inside the <body> element.
+  //XXXsmaug this code is insane.
+  nsINode* temp = selectionStartPoint.GetContainer();
+  while (temp && !temp->IsHTMLElement(nsGkAtoms::body)) {
+    temp = temp->GetParentOrHostNode();
+  }
+
+  // If we aren't in the <body> element, force the issue.
+  if (!temp) {
+    selection->Collapse(rootElement, 0);
+    return NS_OK;
+  }
+
+  EditorRawDOMPoint selectionEndPoint(EditorBase::GetEndPoint(selection));
+  if (NS_WARN_IF(!selectionEndPoint.IsSet())) {
+    return NS_ERROR_FAILURE;
+  }
 
   // check that selNode is inside body
   //XXXsmaug this code is insane.
+  temp = selectionEndPoint.GetContainer();
   while (temp && !temp->IsHTMLElement(nsGkAtoms::body)) {
     temp = temp->GetParentOrHostNode();
   }
 
-  // if we aren't in the body, force the issue
+  // If we aren't in the <body> element, force the issue.
   if (!temp) {
-//    uncomment this to see when we get bad selections
-//    NS_NOTREACHED("selection not in body");
-    selection->Collapse(rootElement, 0);
-    return NS_OK;
-  }
-
-  // get the selection end location
-  rv = EditorBase::GetEndNodeAndOffset(selection,
-                                       getter_AddRefs(selNode), &selOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  temp = selNode;
-
-  // check that selNode is inside body
-  //XXXsmaug this code is insane.
-  while (temp && !temp->IsHTMLElement(nsGkAtoms::body)) {
-    temp = temp->GetParentOrHostNode();
-  }
-
-  // if we aren't in the body, force the issue
-  if (!temp) {
-//    uncomment this to see when we get bad selections
-//    NS_NOTREACHED("selection not in body");
     selection->Collapse(rootElement, 0);
   }
 
   return NS_OK;
 }
 
 nsresult
 HTMLEditRules::UpdateDocChangeRange(nsRange* aRange)
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -189,17 +189,17 @@ HTMLEditor::InsertHTMLWithContext(const 
 }
 
 nsresult
 HTMLEditor::DoInsertHTMLWithContext(const nsAString& aInputString,
                                     const nsAString& aContextStr,
                                     const nsAString& aInfoStr,
                                     const nsAString& aFlavor,
                                     nsIDOMDocument* aSourceDoc,
-                                    nsIDOMNode* aDestNode,
+                                    nsIDOMNode* aDestDOMNode,
                                     int32_t aDestOffset,
                                     bool aDeleteSelection,
                                     bool aTrustedInput,
                                     bool aClearStyle)
 {
   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
 
   // Prevent the edit rules object from dying
@@ -222,49 +222,50 @@ HTMLEditor::DoInsertHTMLWithContext(cons
                                            address_of(fragmentAsNode),
                                            address_of(streamStartParent),
                                            address_of(streamEndParent),
                                            &streamStartOffset,
                                            &streamEndOffset,
                                            aTrustedInput);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsINode> targetNode;
-  int32_t targetOffset=0;
-
-  if (!aDestNode) {
+  EditorDOMPoint targetPoint;
+  if (!aDestDOMNode) {
     // if caller didn't provide the destination/target node,
     // fetch the paste insertion point from our selection
-    rv = GetStartNodeAndOffset(selection, getter_AddRefs(targetNode), &targetOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (!targetNode || !IsEditable(targetNode)) {
+    targetPoint = EditorBase::GetStartPoint(selection);
+    if (NS_WARN_IF(!targetPoint.IsSet()) ||
+        !IsEditable(targetPoint.GetContainer())) {
       return NS_ERROR_FAILURE;
     }
   } else {
-    targetNode = do_QueryInterface(aDestNode);
-    targetOffset = aDestOffset;
+    nsCOMPtr<nsINode> destNode = do_QueryInterface(aDestDOMNode);
+    targetPoint.Set(destNode, aDestOffset);
   }
 
   // if we have a destination / target node, we want to insert there
   // rather than in place of the selection
-  // ignore aDeleteSelection here if no aDestNode since deletion will
+  // ignore aDeleteSelection here if no aDestDOMNode since deletion will
   // also occur later; this block is intended to cover the various
   // scenarios where we are dropping in an editor (and may want to delete
   // the selection before collapsing the selection in the new destination)
-  if (aDestNode) {
+  if (aDestDOMNode) {
     if (aDeleteSelection) {
       // Use an auto tracker so that our drop point is correctly
       // positioned after the delete.
-      AutoTrackDOMPoint tracker(mRangeUpdater, &targetNode, &targetOffset);
+      AutoTrackDOMPoint tracker(mRangeUpdater, &targetPoint);
       rv = DeleteSelection(eNone, eStrip);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    rv = selection->Collapse(targetNode, targetOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
+    ErrorResult error;
+    selection->Collapse(targetPoint, error);
+    if (NS_WARN_IF(error.Failed())) {
+      return error.StealNSResult();
+    }
   }
 
   // we need to recalculate various things based on potentially new offsets
   // this is work to be completed at a later date (probably by jfrancis)
 
   // make a list of what nodes in docFrag we need to move
   nsTArray<OwningNonNull<nsINode>> nodeList;
   CreateListOfNodesToPaste(*static_cast<DocumentFragment*>(fragmentAsNode.get()),
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -458,91 +458,95 @@ TextEditRules::CollapseSelectionToTraili
 {
   // we only need to execute the stuff below if we are a plaintext editor.
   // html editors have a different mechanism for putting in mozBR's
   // (because there are a bunch more places you have to worry about it in html)
   if (!IsPlaintextEditor()) {
     return NS_OK;
   }
 
-  NS_ENSURE_STATE(mTextEditor);
+  if (NS_WARN_IF(!mTextEditor)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+  RefPtr<TextEditor> textEditor(mTextEditor);
 
   // If there is no selection ranges, we should set to the end of the editor.
   // This is usually performed in TextEditRules::Init(), however, if the
   // editor is reframed, this may be called by AfterEdit().
   if (!aSelection->RangeCount()) {
-    mTextEditor->CollapseSelectionToEnd(aSelection);
+    textEditor->CollapseSelectionToEnd(aSelection);
+    if (!mTextEditor) {
+      // The editor has been destroyed.
+      return NS_ERROR_FAILURE;
+    }
   }
 
-  // if we are at the end of the textarea, we need to set the
-  // selection to stick to the mozBR at the end of the textarea.
-  int32_t selOffset;
-  nsCOMPtr<nsINode> selNode;
-  nsresult rv =
-    EditorBase::GetStartNodeAndOffset(aSelection,
-                                      getter_AddRefs(selNode), &selOffset);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+  // If we are at the end of the <textarea> element, we need to set the
+  // selection to stick to the moz-<br> at the end of the <textarea>.
+  EditorRawDOMPoint selectionStartPoint(EditorBase::GetStartPoint(aSelection));
+  if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
+    return NS_ERROR_FAILURE;
   }
 
-  if (!EditorBase::IsTextNode(selNode)) {
-    return NS_OK; // Nothing to do if we're not at a text node.
-  }
-
-  // nothing to do if we're not at the end of the text node
-  if (selOffset != static_cast<int32_t>(selNode->Length())) {
+  // Nothing to do if we're not at the end of the text node.
+  if (!selectionStartPoint.IsInTextNode() ||
+      !selectionStartPoint.IsEndOfContainer()) {
     return NS_OK;
   }
 
-  NS_ENSURE_STATE(mTextEditor);
-  nsINode* root = mTextEditor->GetRoot();
-  if (NS_WARN_IF(!root)) {
+  Element* rootElement = textEditor->GetRoot();
+  if (NS_WARN_IF(!rootElement)) {
     return NS_ERROR_NULL_POINTER;
   }
-  nsINode* parentNode = selNode->GetParentNode();
-  if (parentNode != root) {
+  nsINode* parentNode = selectionStartPoint.GetContainer()->GetParentNode();
+  if (parentNode != rootElement) {
     return NS_OK;
   }
 
-  nsINode* nextNode = selNode->GetNextSibling();
-  if (nextNode && TextEditUtils::IsMozBR(nextNode)) {
-    EditorRawDOMPoint afterSelNode(selNode);
-    if (NS_WARN_IF(!afterSelNode.AdvanceOffset())) {
-      return NS_ERROR_FAILURE;
-    }
-    rv = aSelection->Collapse(afterSelNode);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
+  nsINode* nextNode = selectionStartPoint.GetContainer()->GetNextSibling();
+  if (!nextNode || !TextEditUtils::IsMozBR(nextNode)) {
+    return NS_OK;
+  }
+
+  EditorRawDOMPoint afterStartContainer(selectionStartPoint.GetContainer());
+  if (NS_WARN_IF(!afterStartContainer.AdvanceOffset())) {
+    return NS_ERROR_FAILURE;
+  }
+  ErrorResult error;
+  aSelection->Collapse(afterStartContainer, error);
+  if (NS_WARN_IF(error.Failed())) {
+    return error.StealNSResult();
   }
   return NS_OK;
 }
 
 static inline already_AddRefed<nsINode>
-GetTextNode(Selection* selection)
+GetTextNode(Selection* aSelection)
 {
-  int32_t selOffset;
-  nsCOMPtr<nsINode> selNode;
-  nsresult rv =
-    EditorBase::GetStartNodeAndOffset(selection,
-                                      getter_AddRefs(selNode), &selOffset);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-  if (!EditorBase::IsTextNode(selNode)) {
-    // This should be the root node, walk the tree looking for text nodes
-    RefPtr<NodeIterator> iter =
-      new NodeIterator(selNode, NodeFilterBinding::SHOW_TEXT, nullptr);
-    while (!EditorBase::IsTextNode(selNode)) {
-      selNode = iter->NextNode(IgnoreErrors());
-      if (!selNode) {
-        return nullptr;
-      }
+  EditorRawDOMPoint selectionStartPoint(EditorBase::GetStartPoint(aSelection));
+  if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
+    return nullptr;
+  }
+  if (selectionStartPoint.IsInTextNode()) {
+    nsCOMPtr<nsINode> node = selectionStartPoint.GetContainer();
+    return node.forget();
+  }
+  // This should be the root node, walk the tree looking for text nodes.
+  nsCOMPtr<nsINode> node = selectionStartPoint.GetContainer();
+  RefPtr<NodeIterator> iter =
+    new NodeIterator(node, NodeFilterBinding::SHOW_TEXT, nullptr);
+  while (!EditorBase::IsTextNode(node)) {
+    node = iter->NextNode(IgnoreErrors());
+    if (!node) {
+      return nullptr;
     }
   }
-  return selNode.forget();
+  return node.forget();
 }
+
 #ifdef DEBUG
 #define ASSERT_PASSWORD_LENGTHS_EQUAL()                                \
   if (IsPasswordEditor() && mTextEditor->GetRoot()) {                  \
     int32_t txtLen;                                                    \
     mTextEditor->GetTextLength(&txtLen);                               \
     NS_ASSERTION(mPasswordText.Length() == uint32_t(txtLen),           \
                  "password length not equal to number of asterisks");  \
   }
@@ -1027,32 +1031,29 @@ TextEditRules::WillDeleteSelection(Selec
       }
       // Otherwise nothing to do for this collapsed selection.
     }
     // Extended selection.
     else {
       mPasswordText.Cut(start, end-start);
     }
   } else {
-    nsCOMPtr<nsINode> startNode;
-    int32_t startOffset;
-    nsresult rv =
-      EditorBase::GetStartNodeAndOffset(aSelection, getter_AddRefs(startNode),
-                                        &startOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
+    EditorRawDOMPoint selectionStartPoint(
+                        EditorBase::GetStartPoint(aSelection));
+    if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
+      return NS_ERROR_FAILURE;
+    }
 
     if (!aSelection->IsCollapsed()) {
       return NS_OK;
     }
 
     // Test for distance between caret and text that will be deleted
-    rv = CheckBidiLevelForDeletion(aSelection,
-                                   EditorRawDOMPoint(startNode, startOffset),
-                                   aCollapsedAction, aCancel);
+    nsresult rv = CheckBidiLevelForDeletion(aSelection, selectionStartPoint,
+                                            aCollapsedAction, aCancel);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     if (*aCancel) {
       return NS_OK;
     }
 
     NS_ENSURE_STATE(mTextEditor);
@@ -1070,39 +1071,35 @@ TextEditRules::WillDeleteSelection(Selec
   return NS_OK;
 }
 
 nsresult
 TextEditRules::DidDeleteSelection(Selection* aSelection,
                                   nsIEditor::EDirection aCollapsedAction,
                                   nsresult aResult)
 {
-  nsCOMPtr<nsINode> startNode;
-  int32_t startOffset;
-  nsresult rv =
-    EditorBase::GetStartNodeAndOffset(aSelection,
-                                      getter_AddRefs(startNode), &startOffset);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-  if (NS_WARN_IF(!startNode)) {
+  EditorRawDOMPoint selectionStartPoint(EditorBase::GetStartPoint(aSelection));
+  if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
     return NS_ERROR_FAILURE;
   }
 
-  // delete empty text nodes at selection
-  if (EditorBase::IsTextNode(startNode)) {
-    // are we in an empty text node?
-    if (!startNode->Length()) {
-      NS_ENSURE_STATE(mTextEditor);
-      rv = mTextEditor->DeleteNode(startNode);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-      }
+  // Delete empty text nodes at selection.
+  if (selectionStartPoint.IsInTextNode() &&
+      !selectionStartPoint.GetContainer()->Length()) {
+    if (NS_WARN_IF(!mTextEditor)) {
+      return NS_ERROR_NOT_AVAILABLE;
     }
+    RefPtr<TextEditor> textEditor(mTextEditor);
+    nsresult rv = textEditor->DeleteNode(selectionStartPoint.GetContainer());
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    // Be aware, mTextEditor may be nullptr here.
   }
+
   if (mDidExplicitlySetInterline) {
     return NS_OK;
   }
   // We prevent the caret from sticking on the left of prior BR
   // (i.e. the end of previous line) after this deletion.  Bug 92124
   return aSelection->SetInterlinePosition(true);
 }
 
--- a/editor/libeditor/TypeInState.cpp
+++ b/editor/libeditor/TypeInState.cpp
@@ -34,91 +34,92 @@ using namespace dom;
 
 /********************************************************************
  * mozilla::TypeInState
  *******************************************************************/
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(TypeInState)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TypeInState)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLastSelectionContainer)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLastSelectionPoint)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TypeInState)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLastSelectionContainer)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLastSelectionPoint)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(TypeInState, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(TypeInState, Release)
 
 TypeInState::TypeInState()
   : mRelativeFontSize(0)
-  , mLastSelectionOffset(0)
 {
   Reset();
 }
 
 TypeInState::~TypeInState()
 {
   // Call Reset() to release any data that may be in
   // mClearedArray and mSetArray.
 
   Reset();
 }
 
 nsresult
 TypeInState::UpdateSelState(Selection* aSelection)
 {
-  NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
+  if (NS_WARN_IF(!aSelection)) {
+    return NS_ERROR_INVALID_ARG;
+  }
 
   if (!aSelection->Collapsed()) {
     return NS_OK;
   }
 
-  return EditorBase::GetStartNodeAndOffset(
-                       aSelection, getter_AddRefs(mLastSelectionContainer),
-                       &mLastSelectionOffset);
+  mLastSelectionPoint = EditorBase::GetStartPoint(aSelection);
+  if (!mLastSelectionPoint.IsSet()) {
+    return NS_ERROR_FAILURE;
+  }
+  // We need to store only offset because referring child may be removed by
+  // we'll check the point later.
+  AutoEditorDOMPointChildInvalidator saveOnlyOffset(mLastSelectionPoint);
+  return NS_OK;
 }
 
 void
 TypeInState::OnSelectionChange(Selection& aSelection)
 {
   // XXX: Selection currently generates bogus selection changed notifications
   // XXX: (bug 140303). It can notify us when the selection hasn't actually
   // XXX: changed, and it notifies us more than once for the same change.
   // XXX:
   // XXX: The following code attempts to work around the bogus notifications,
   // XXX: and should probably be removed once bug 140303 is fixed.
   // XXX:
   // XXX: This code temporarily fixes the problem where clicking the mouse in
   // XXX: the same location clears the type-in-state.
 
   if (aSelection.IsCollapsed() && aSelection.RangeCount()) {
-    nsCOMPtr<nsINode> selNode;
-    int32_t selOffset = 0;
-
-    nsresult rv =
-      EditorBase::GetStartNodeAndOffset(&aSelection, getter_AddRefs(selNode),
-                                        &selOffset);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
+    EditorRawDOMPoint selectionStartPoint(
+                        EditorBase::GetStartPoint(&aSelection));
+    if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
       return;
     }
 
-    if (selNode &&
-        selNode == mLastSelectionContainer &&
-        selOffset == mLastSelectionOffset) {
+    if (mLastSelectionPoint == selectionStartPoint) {
       // We got a bogus selection changed notification!
       return;
     }
 
-    mLastSelectionContainer = selNode;
-    mLastSelectionOffset = selOffset;
+    mLastSelectionPoint = selectionStartPoint;
+    // We need to store only offset because referring child may be removed by
+    // we'll check the point later.
+    AutoEditorDOMPointChildInvalidator saveOnlyOffset(mLastSelectionPoint);
   } else {
-    mLastSelectionContainer = nullptr;
-    mLastSelectionOffset = 0;
+    mLastSelectionPoint.Clear();
   }
 
   Reset();
 }
 
 void
 TypeInState::Reset()
 {
--- a/editor/libeditor/TypeInState.h
+++ b/editor/libeditor/TypeInState.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TypeInState_h
 #define TypeInState_h
 
+#include "mozilla/EditorDOMPoint.h"
 #include "mozilla/UniquePtr.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsISupportsImpl.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nscore.h"
 
@@ -91,19 +92,18 @@ protected:
   bool IsPropSet(nsAtom* aProp, nsAtom* aAttr, nsAString* outValue);
   bool IsPropSet(nsAtom* aProp, nsAtom* aAttr, nsAString* outValue,
                  int32_t& outIndex);
   bool IsPropCleared(nsAtom* aProp, nsAtom* aAttr);
   bool IsPropCleared(nsAtom* aProp, nsAtom* aAttr, int32_t& outIndex);
 
   nsTArray<PropItem*> mSetArray;
   nsTArray<PropItem*> mClearedArray;
+  EditorDOMPoint mLastSelectionPoint;
   int32_t mRelativeFontSize;
-  nsCOMPtr<nsINode> mLastSelectionContainer;
-  int32_t mLastSelectionOffset;
 
   friend class HTMLEditRules;
 };
 
 } // namespace mozilla
 
 #endif  // #ifndef TypeInState_h