Bug 1483434 - Allow nullptr parameter for PriorVisibleNode and NextVisibleNode. r=masayuki
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Tue, 14 Aug 2018 18:26:46 +0900
changeset 431840 7de9496d9640c757f486c8fe80e0679ed78d3cf2
parent 431839 280d5dade1c6296b232fcf876a1ece7a8cf79784
child 431841 f578ca2a361ec09d98582dc9428345d9c57096ec
push id106565
push userm_kato@ga2.so-net.ne.jp
push dateThu, 16 Aug 2018 02:21:06 +0000
treeherdermozilla-inbound@7de9496d9640 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1483434
milestone63.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 1483434 - Allow nullptr parameter for PriorVisibleNode and NextVisibleNode. r=masayuki Summary: Sometimes the caller of PriorVisibleNode or NextVisibleNode doesn't use outVisNode and/or outvisOffset. But both methods require all parameters and it don't allow nullptr. It is complex whether parameter is used or unused. So I would like to allow nullptr. Also, this methods can change to const method, so I will change some methods to const method too for this change. Reviewers: masayuki Tags: #secure-revision Bug #: 1483434 Differential Revision: https://phabricator.services.mozilla.com/D3387
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLEditorDataTransfer.cpp
editor/libeditor/WSRunObject.cpp
editor/libeditor/WSRunObject.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1983,26 +1983,22 @@ HTMLEditRules::InsertBRElement(const Edi
       return NS_ERROR_EDITOR_DESTROYED;
     }
     if (NS_WARN_IF(!brElement)) {
       return NS_ERROR_FAILURE;
     }
   } else {
     EditorDOMPoint pointToBreak(aPointToBreak);
     WSRunObject wsObj(&HTMLEditorRef(), pointToBreak);
-    int32_t visOffset = 0;
     WSType wsType;
-    nsCOMPtr<nsINode> visNode;
-    wsObj.PriorVisibleNode(pointToBreak,
-                           address_of(visNode), &visOffset, &wsType);
+    wsObj.PriorVisibleNode(pointToBreak, &wsType);
     if (wsType & WSType::block) {
       brElementIsAfterBlock = true;
     }
-    wsObj.NextVisibleNode(pointToBreak,
-                          address_of(visNode), &visOffset, &wsType);
+    wsObj.NextVisibleNode(pointToBreak, &wsType);
     if (wsType & WSType::block) {
       brElementIsBeforeBlock = true;
     }
     // If the container of the break is a link, we need to split it and
     // insert new <br> between the split links.
     nsCOMPtr<nsINode> linkDOMNode;
     if (HTMLEditorRef().IsInLink(pointToBreak.GetContainer(),
                                  address_of(linkDOMNode))) {
@@ -2062,20 +2058,19 @@ HTMLEditRules::InsertBRElement(const Edi
   }
 
   EditorDOMPoint afterBRElement(brElement);
   DebugOnly<bool> advanced = afterBRElement.AdvanceOffset();
   NS_WARNING_ASSERTION(advanced,
     "Failed to advance offset after the new <br> element");
   WSRunObject wsObj(&HTMLEditorRef(), afterBRElement);
   nsCOMPtr<nsINode> maybeSecondBRNode;
-  int32_t visOffset = 0;
   WSType wsType;
   wsObj.NextVisibleNode(afterBRElement,
-                        address_of(maybeSecondBRNode), &visOffset, &wsType);
+                        address_of(maybeSecondBRNode), nullptr, &wsType);
   if (wsType == WSType::br) {
     // The next thing after the break we inserted is another break.  Move the
     // second break to be the first break's sibling.  This will prevent them
     // from being in different inline nodes, which would break
     // SetInterlinePosition().  It will also assure that if the user clicks
     // away and then clicks back on their new blank line, they will still get
     // the style from the line above.
     EditorDOMPoint atSecondBRElement(maybeSecondBRNode);
@@ -2144,19 +2139,18 @@ HTMLEditRules::SplitMailCites(bool* aHan
   // 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(&HTMLEditorRef(), pointToSplit);
   nsCOMPtr<nsINode> visNode;
-  int32_t visOffset=0;
   WSType wsType;
-  wsObj.NextVisibleNode(pointToSplit, address_of(visNode), &visOffset, &wsType);
+  wsObj.NextVisibleNode(pointToSplit, address_of(visNode), nullptr, &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");
@@ -2250,30 +2244,27 @@ HTMLEditRules::SplitMailCites(bool* aHan
   // 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(&HTMLEditorRef(), pointToCreateNewBrNode);
-    nsCOMPtr<nsINode> visNode;
-    int32_t visOffset=0;
     WSType wsType;
-    wsObj.PriorVisibleNode(pointToCreateNewBrNode,
-                           address_of(visNode), &visOffset, &wsType);
+    wsObj.PriorVisibleNode(pointToCreateNewBrNode, nullptr, nullptr,
+                           &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(&HTMLEditorRef(), pointAfterNewBrNode);
-      wsObjAfterBR.NextVisibleNode(pointAfterNewBrNode,
-                                   address_of(visNode), &visOffset, &wsType);
+      wsObjAfterBR.NextVisibleNode(pointAfterNewBrNode, &wsType);
       if (wsType == WSType::normalWS || wsType == WSType::text ||
           wsType == WSType::special ||
           // In case we're at the very end.
           wsType == WSType::thisBlock) {
         brElement =
           HTMLEditorRef().InsertBrElementWithTransaction(
                             SelectionRef(), pointToCreateNewBrNode);
         if (NS_WARN_IF(!CanHandleEditAction())) {
@@ -2652,21 +2643,20 @@ HTMLEditRules::WillDeleteSelection(nsIEd
           mDidExplicitlySetInterline = true;
           *aHandled = true;
 
           // There is one exception to the move only case.  If the <hr> is
           // followed by a <br> we want to delete the <br>.
 
           WSType otherWSType;
           nsCOMPtr<nsINode> otherNode;
-          int32_t otherOffset;
 
           wsObj.NextVisibleNode(EditorRawDOMPoint(startNode, startOffset),
-                                address_of(otherNode),
-                                &otherOffset, &otherWSType);
+                                address_of(otherNode), nullptr,
+                                &otherWSType);
 
           if (otherWSType == WSType::br) {
             // Delete the <br>
             if (NS_WARN_IF(!otherNode->IsContent())) {
               return NS_ERROR_FAILURE;
             }
             nsIContent* otherContent = otherNode->AsContent();
             rv = WSRunObject::PrepareToDeleteNode(&HTMLEditorRef(),
@@ -2761,27 +2751,26 @@ HTMLEditRules::WillDeleteSelection(nsIEd
       }
 
       // Next to a block.  See if we are between a block and a br.  If so, we
       // really want to delete the br.  Else join content at selection to the
       // block.
       bool bDeletedBR = false;
       WSType otherWSType;
       nsCOMPtr<nsINode> otherNode;
-      int32_t otherOffset;
 
       // Find node in other direction
       if (aAction == nsIEditor::eNext) {
         wsObj.PriorVisibleNode(EditorRawDOMPoint(startNode, startOffset),
-                               address_of(otherNode),
-                               &otherOffset, &otherWSType);
+                               address_of(otherNode), nullptr,
+                               &otherWSType);
       } else {
         wsObj.NextVisibleNode(EditorRawDOMPoint(startNode, startOffset),
-                              address_of(otherNode),
-                              &otherOffset, &otherWSType);
+                              address_of(otherNode), nullptr,
+                              &otherWSType);
       }
 
       // First find the adjacent node in the block
       nsCOMPtr<nsIContent> leafNode;
       nsCOMPtr<nsINode> leftNode, rightNode;
       if (aAction == nsIEditor::ePrevious) {
         leafNode = HTMLEditorRef().GetLastEditableLeaf(*visNode);
         leftNode = leafNode;
@@ -6730,30 +6719,29 @@ HTMLEditRules::ExpandSelectionForDeletio
   RefPtr<Element> selCommon =
     HTMLEditor::GetBlock(*firstRange->GetCommonAncestor());
   if (NS_WARN_IF(!selCommon)) {
     return NS_ERROR_FAILURE;
   }
 
   // Set up for loops and cache our root element
   nsCOMPtr<nsINode> firstBRParent;
-  nsCOMPtr<nsINode> unused;
-  int32_t visOffset = 0, firstBROffset = 0;
+  int32_t firstBROffset = 0;
   WSType wsType;
   RefPtr<Element> root = HTMLEditorRef().GetActiveEditingHost();
   if (NS_WARN_IF(!root)) {
     return NS_ERROR_FAILURE;
   }
 
   // Find previous visible things before start of selection
   if (selStartNode != selCommon && selStartNode != root) {
     while (true) {
       WSRunObject wsObj(&HTMLEditorRef(), selStartNode, selStartOffset);
       wsObj.PriorVisibleNode(EditorRawDOMPoint(selStartNode, selStartOffset),
-                             address_of(unused), &visOffset, &wsType);
+                             &wsType);
       if (wsType != WSType::thisBlock) {
         break;
       }
       // We want to keep looking up.  But stop if we are crossing table
       // element boundaries, or if we hit the root.
       if (HTMLEditUtils::IsTableElement(wsObj.mStartReasonNode) ||
           selCommon == wsObj.mStartReasonNode ||
           root == wsObj.mStartReasonNode) {
@@ -6765,17 +6753,17 @@ HTMLEditRules::ExpandSelectionForDeletio
     }
   }
 
   // Find next visible things after end of selection
   if (selEndNode != selCommon && selEndNode != root) {
     for (;;) {
       WSRunObject wsObj(&HTMLEditorRef(), selEndNode, selEndOffset);
       wsObj.NextVisibleNode(EditorRawDOMPoint(selEndNode, selEndOffset),
-                            address_of(unused), &visOffset, &wsType);
+                            &wsType);
       if (wsType == WSType::br) {
         if (HTMLEditorRef().IsVisibleBRElement(wsObj.mEndReasonNode)) {
           break;
         }
         if (!firstBRParent) {
           firstBRParent = selEndNode;
           firstBROffset = selEndOffset;
         }
@@ -6896,27 +6884,24 @@ HTMLEditRules::NormalizeSelection()
 
   // adjusted values default to original values
   nsCOMPtr<nsINode> newStartNode = startNode;
   uint32_t newStartOffset = startOffset;
   nsCOMPtr<nsINode> newEndNode = endNode;
   uint32_t newEndOffset = endOffset;
 
   // some locals we need for whitespace code
-  nsCOMPtr<nsINode> unused;
-  int32_t offset = -1;
   WSType wsType;
 
   // let the whitespace code do the heavy lifting
   WSRunObject wsEndObj(&HTMLEditorRef(), endNode,
                        static_cast<int32_t>(endOffset));
   // Is there any intervening visible whitespace?  If so we can't push
   // selection past that, it would visibly change meaning of users selection.
-  wsEndObj.PriorVisibleNode(EditorRawDOMPoint(endNode, endOffset),
-                            address_of(unused), &offset, &wsType);
+  wsEndObj.PriorVisibleNode(EditorRawDOMPoint(endNode, endOffset), &wsType);
   if (wsType != WSType::text && wsType != WSType::normalWS) {
     // eThisBlock and eOtherBlock conveniently distinguish cases
     // of going "down" into a block and "up" out of a block.
     if (wsEndObj.mStartReason == WSType::otherBlock) {
       // endpoint is just after the close of a block.
       nsINode* child =
         HTMLEditorRef().GetRightmostChild(wsEndObj.mStartReasonNode, true);
       if (child) {
@@ -6948,17 +6933,17 @@ HTMLEditRules::NormalizeSelection()
 
 
   // similar dealio for start of range
   WSRunObject wsStartObj(&HTMLEditorRef(), startNode,
                          static_cast<int32_t>(startOffset));
   // Is there any intervening visible whitespace?  If so we can't push
   // selection past that, it would visibly change meaning of users selection.
   wsStartObj.NextVisibleNode(EditorRawDOMPoint(startNode, startOffset),
-                             address_of(unused), &offset, &wsType);
+                             &wsType);
   if (wsType != WSType::text && wsType != WSType::normalWS) {
     // eThisBlock and eOtherBlock conveniently distinguish cases
     // of going "down" into a block and "up" out of a block.
     if (wsStartObj.mEndReason == WSType::otherBlock) {
       // startpoint is just before the start of a block.
       nsINode* child =
         HTMLEditorRef().GetLeftmostChild(wsStartObj.mEndReasonNode, true);
       if (child) {
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -1028,21 +1028,18 @@ HTMLEditor::IsVisibleBRElement(nsINode* 
 
   // Sigh.  We have to use expensive whitespace calculation code to
   // determine what is going on
   int32_t selOffset;
   nsCOMPtr<nsINode> selNode = GetNodeLocation(aNode, &selOffset);
   // Let's look after the break
   selOffset++;
   WSRunObject wsObj(this, selNode, selOffset);
-  nsCOMPtr<nsINode> unused;
-  int32_t visOffset = 0;
   WSType visType;
-  wsObj.NextVisibleNode(EditorRawDOMPoint(selNode, selOffset),
-                        address_of(unused), &visOffset, &visType);
+  wsObj.NextVisibleNode(EditorRawDOMPoint(selNode, selOffset), &visType);
   if (visType & WSType::block) {
     return false;
   }
 
   return true;
 }
 
 NS_IMETHODIMP
@@ -1517,36 +1514,34 @@ HTMLEditor::GetBetterInsertionPointFor(n
 
   WSRunObject wsObj(this, pointToInsert.GetContainer(),
                     pointToInsert.Offset());
 
   // If the insertion position is after the last visible item in a line,
   // i.e., the insertion position is just before a visible line break <br>,
   // we want to skip to the position just after the line break (see bug 68767).
   nsCOMPtr<nsINode> nextVisibleNode;
-  int32_t nextVisibleOffset = 0;
   WSType nextVisibleType;
   wsObj.NextVisibleNode(pointToInsert, address_of(nextVisibleNode),
-                        &nextVisibleOffset, &nextVisibleType);
+                        nullptr, &nextVisibleType);
   // So, if the next visible node isn't a <br> element, we can insert the block
   // level element to the point.
   if (!nextVisibleNode ||
       !(nextVisibleType & WSType::br)) {
     return pointToInsert;
   }
 
   // However, we must not skip next <br> element when the caret appears to be
   // positioned at the beginning of a block, in that case skipping the <br>
   // would not insert the <br> at the caret position, but after the current
   // empty line.
   nsCOMPtr<nsINode> previousVisibleNode;
-  int32_t previousVisibleOffset = 0;
   WSType previousVisibleType;
   wsObj.PriorVisibleNode(pointToInsert, address_of(previousVisibleNode),
-                         &previousVisibleOffset, &previousVisibleType);
+                         nullptr, &previousVisibleType);
   // So, if there is no previous visible node,
   // or, if both nodes of the insertion point is <br> elements,
   // or, if the previous visible node is different block,
   // we need to skip the following <br>.  So, otherwise, we can insert the
   // block at the insertion point.
   if (!previousVisibleNode ||
       (previousVisibleType & WSType::br) ||
       (previousVisibleType & WSType::thisBlock)) {
@@ -4108,21 +4103,20 @@ HTMLEditor::IsVisibleTextNode(Text& aTex
   }
 
   if (!aText.TextIsOnlyWhitespace()) {
     return true;
   }
 
   WSRunObject wsRunObj(this, &aText, 0);
   nsCOMPtr<nsINode> nextVisibleNode;
-  int32_t unused = 0;
   WSType visibleNodeType;
   wsRunObj.NextVisibleNode(EditorRawDOMPoint(&aText, 0),
                            address_of(nextVisibleNode),
-                           &unused, &visibleNodeType);
+                           nullptr, &visibleNodeType);
   return (visibleNodeType == WSType::normalWS ||
           visibleNodeType == WSType::text) &&
          &aText == nextVisibleNode;
 }
 
 /**
  * IsEmptyNode() figures out if aNode is an empty node.  A block can have
  * children and still be considered empty, if the children are empty or
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -615,34 +615,34 @@ HTMLEditor::DoInsertHTMLWithContext(cons
         // the stuff we just inserted from the DOM.
         selNode = pointAtContainer.GetContainer();
         // Want to be *after* last leaf node in paste.
         selOffset = pointAtContainer.Offset() + 1;
       }
 
       // make sure we don't end up with selection collapsed after an invisible break node
       WSRunObject wsRunObj(this, selNode, selOffset);
-      nsCOMPtr<nsINode> visNode;
-      int32_t outVisOffset=0;
       WSType visType;
       wsRunObj.PriorVisibleNode(EditorRawDOMPoint(selNode, selOffset),
-                                address_of(visNode), &outVisOffset, &visType);
+                                &visType);
       if (visType == WSType::br) {
         // we are after a break.  Is it visible?  Despite the name,
         // PriorVisibleNode does not make that determination for breaks.
         // It also may not return the break in visNode.  We have to pull it
         // out of the WSRunObject's state.
         if (!IsVisibleBRElement(wsRunObj.mStartReasonNode)) {
           // don't leave selection past an invisible break;
           // reset {selNode,selOffset} to point before break
           EditorRawDOMPoint atStartReasonNode(wsRunObj.mStartReasonNode);
           selNode = atStartReasonNode.GetContainer();
           selOffset = atStartReasonNode.Offset();
           // we want to be inside any inline style prior to break
           WSRunObject wsRunObj(this, selNode, selOffset);
+          nsCOMPtr<nsINode> visNode;
+          int32_t outVisOffset;
           wsRunObj.PriorVisibleNode(EditorRawDOMPoint(selNode, selOffset),
                                     address_of(visNode),
                                     &outVisOffset, &visType);
           if (visType == WSType::text || visType == WSType::normalWS) {
             selNode = visNode;
             selOffset = outVisOffset;  // PriorVisibleNode already set offset to _after_ the text or ws
           } else if (visType == WSType::special) {
             // prior visible thing is an image or some other non-text thingy.
--- a/editor/libeditor/WSRunObject.cpp
+++ b/editor/libeditor/WSRunObject.cpp
@@ -36,29 +36,29 @@ const char16_t kNBSP = 160;
 
 template WSRunObject::WSRunObject(HTMLEditor* aHTMLEditor,
                                   const EditorDOMPoint& aPoint);
 template WSRunObject::WSRunObject(HTMLEditor* aHTMLEditor,
                                   const EditorRawDOMPoint& aPoint);
 template void WSRunObject::PriorVisibleNode(const EditorDOMPoint& aPoint,
                                             nsCOMPtr<nsINode>* outVisNode,
                                             int32_t* outVisOffset,
-                                            WSType* outType);
+                                            WSType* outType) const;
 template void WSRunObject::PriorVisibleNode(const EditorRawDOMPoint& aPoint,
                                             nsCOMPtr<nsINode>* outVisNode,
                                             int32_t* outVisOffset,
-                                            WSType* outType);
+                                            WSType* outType) const;
 template void WSRunObject::NextVisibleNode(const EditorDOMPoint& aPoint,
                                            nsCOMPtr<nsINode>* outVisNode,
                                            int32_t* outVisOffset,
-                                           WSType* outType);
+                                           WSType* outType) const;
 template void WSRunObject::NextVisibleNode(const EditorRawDOMPoint& aPoint,
                                            nsCOMPtr<nsINode>* outVisNode,
                                            int32_t* outVisOffset,
-                                           WSType* outType);
+                                           WSType* outType) const;
 template already_AddRefed<Element>
 WSRunObject::InsertBreak(Selection& aSelection,
                          const EditorDOMPoint& aPointToInsert,
                          nsIEditor::EDirection aSelect);
 template already_AddRefed<Element>
 WSRunObject::InsertBreak(Selection& aSelection,
                          const EditorRawDOMPoint& aPointToInsert,
                          nsIEditor::EDirection aSelect);
@@ -553,88 +553,104 @@ WSRunObject::DeleteWSForward()
   return NS_OK;
 }
 
 template<typename PT, typename CT>
 void
 WSRunObject::PriorVisibleNode(const EditorDOMPointBase<PT, CT>& aPoint,
                               nsCOMPtr<nsINode>* outVisNode,
                               int32_t* outVisOffset,
-                              WSType* outType)
+                              WSType* outType) const
 {
   // Find first visible thing before the point.  Position
   // outVisNode/outVisOffset just _after_ that thing.  If we don't find
   // anything return start of ws.
-  MOZ_ASSERT(aPoint.IsSet() && outVisNode && outVisOffset && outType);
+  MOZ_ASSERT(aPoint.IsSet() && outType);
 
   WSFragment* run = FindNearestRun(aPoint, false);
 
   // Is there a visible run there or earlier?
   for (; run; run = run->mLeft) {
     if (run->mType == WSType::normalWS) {
       WSPoint point = GetPreviousCharPoint(aPoint);
       // When it's a non-empty text node, return it.
       if (point.mTextNode && point.mTextNode->Length()) {
-        *outVisNode = point.mTextNode;
-        *outVisOffset = point.mOffset + 1;
+        if (outVisNode) {
+          *outVisNode = point.mTextNode;
+        }
+        if (outVisOffset) {
+          *outVisOffset = point.mOffset + 1;
+        }
         if (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == kNBSP) {
           *outType = WSType::normalWS;
         } else {
           *outType = WSType::text;
         }
         return;
       }
       // If no text node, keep looking.  We should eventually fall out of loop
     }
   }
 
-  // If we get here, then nothing in ws data to find.  Return start reason.
-  *outVisNode = mStartReasonNode;
-  // This really isn't meaningful if mStartReasonNode != mStartNode
-  *outVisOffset = mStartOffset;
+  if (outVisNode) {
+    // If we get here, then nothing in ws data to find.  Return start reason.
+    *outVisNode = mStartReasonNode;
+  }
+  if (outVisOffset) {
+    // This really isn't meaningful if mStartReasonNode != mStartNode
+    *outVisOffset = mStartOffset;
+  }
   *outType = mStartReason;
 }
 
 template<typename PT, typename CT>
 void
 WSRunObject::NextVisibleNode(const EditorDOMPointBase<PT, CT>& aPoint,
                              nsCOMPtr<nsINode>* outVisNode,
                              int32_t* outVisOffset,
-                             WSType* outType)
+                             WSType* outType) const
 {
   // Find first visible thing after the point.  Position
   // outVisNode/outVisOffset just _before_ that thing.  If we don't find
   // anything return end of ws.
-  MOZ_ASSERT(aPoint.IsSet() && outVisNode && outVisOffset && outType);
+  MOZ_ASSERT(aPoint.IsSet() && outType);
 
   WSFragment* run = FindNearestRun(aPoint, true);
 
   // Is there a visible run there or later?
   for (; run; run = run->mRight) {
     if (run->mType == WSType::normalWS) {
       WSPoint point = GetNextCharPoint(aPoint);
       // When it's a non-empty text node, return it.
       if (point.mTextNode && point.mTextNode->Length()) {
-        *outVisNode = point.mTextNode;
-        *outVisOffset = point.mOffset;
+        if (outVisNode) {
+          *outVisNode = point.mTextNode;
+        }
+        if (outVisOffset) {
+          *outVisOffset = point.mOffset;
+        }
         if (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == kNBSP) {
           *outType = WSType::normalWS;
         } else {
           *outType = WSType::text;
         }
         return;
       }
       // If no text node, keep looking.  We should eventually fall out of loop
     }
   }
 
-  // If we get here, then nothing in ws data to find.  Return end reason
-  *outVisNode = mEndReasonNode;
-  // This really isn't meaningful if mEndReasonNode != mEndNode
-  *outVisOffset = mEndOffset;
+  if (outVisNode) {
+    // If we get here, then nothing in ws data to find.  Return end reason
+    *outVisNode = mEndReasonNode;
+  }
+  if (outVisOffset) {
+    // This really isn't meaningful if mEndReasonNode != mEndNode
+    *outVisOffset = mEndOffset;
+  }
   *outType = mEndReason;
 }
 
 nsresult
 WSRunObject::AdjustWhitespace()
 {
   // this routine examines a run of ws and tries to get rid of some unneeded nbsp's,
   // replacing them with regualr ascii space if possible.  Keeping things simple
@@ -1437,46 +1453,47 @@ WSRunObject::DeleteRange(const EditorDOM
       }
     }
   }
   return NS_OK;
 }
 
 template<typename PT, typename CT>
 WSRunObject::WSPoint
-WSRunObject::GetNextCharPoint(const EditorDOMPointBase<PT, CT>& aPoint)
+WSRunObject::GetNextCharPoint(const EditorDOMPointBase<PT, CT>& aPoint) const
 {
   MOZ_ASSERT(aPoint.IsSetAndValid());
 
   int32_t idx = mNodeArray.IndexOf(aPoint.GetContainer());
   if (idx == -1) {
     // Use range comparisons to get next text node which is in mNodeArray.
     return GetNextCharPointInternal(aPoint);
   }
   // Use WSPoint version of GetNextCharPoint()
   return GetNextCharPoint(WSPoint(mNodeArray[idx], aPoint.Offset(), 0));
 }
 
 template<typename PT, typename CT>
 WSRunObject::WSPoint
-WSRunObject::GetPreviousCharPoint(const EditorDOMPointBase<PT, CT>& aPoint)
+WSRunObject::GetPreviousCharPoint(
+               const EditorDOMPointBase<PT, CT>& aPoint) const
 {
   MOZ_ASSERT(aPoint.IsSetAndValid());
 
   int32_t idx = mNodeArray.IndexOf(aPoint.GetContainer());
   if (idx == -1) {
     // Use range comparisons to get previous text node which is in mNodeArray.
     return GetPreviousCharPointInternal(aPoint);
   }
   // Use WSPoint version of GetPreviousCharPoint()
   return GetPreviousCharPoint(WSPoint(mNodeArray[idx], aPoint.Offset(), 0));
 }
 
 WSRunObject::WSPoint
-WSRunObject::GetNextCharPoint(const WSPoint &aPoint)
+WSRunObject::GetNextCharPoint(const WSPoint &aPoint) const
 {
   MOZ_ASSERT(aPoint.mTextNode);
 
   WSPoint outPoint;
   outPoint.mTextNode = nullptr;
   outPoint.mOffset = 0;
   outPoint.mChar = 0;
 
@@ -1499,17 +1516,17 @@ WSRunObject::GetNextCharPoint(const WSPo
     outPoint.mOffset = 0;
     outPoint.mChar = GetCharAt(outPoint.mTextNode, 0);
   }
 
   return outPoint;
 }
 
 WSRunObject::WSPoint
-WSRunObject::GetPreviousCharPoint(const WSPoint &aPoint)
+WSRunObject::GetPreviousCharPoint(const WSPoint &aPoint) const
 {
   MOZ_ASSERT(aPoint.mTextNode);
 
   WSPoint outPoint;
   outPoint.mTextNode = nullptr;
   outPoint.mOffset = 0;
   outPoint.mChar = 0;
 
@@ -1650,17 +1667,17 @@ WSRunObject::GetASCIIWhitespacesBounds(i
   *outStartOffset = startOffset;
   endNode.forget(outEndNode);
   *outEndOffset = endOffset;
 }
 
 template<typename PT, typename CT>
 WSRunObject::WSFragment*
 WSRunObject::FindNearestRun(const EditorDOMPointBase<PT, CT>& aPoint,
-                            bool aForward)
+                            bool aForward) const
 {
   MOZ_ASSERT(aPoint.IsSetAndValid());
 
   for (WSFragment* run = mStartRun; run; run = run->mRight) {
     int32_t comp = run->mStartNode ?
       nsContentUtils::ComparePoints(aPoint, run->StartPoint()) : -1;
     if (comp <= 0) {
       // aPoint equals or before start of the run.  Return the run if we're
@@ -1689,48 +1706,49 @@ WSRunObject::FindNearestRun(const Editor
     }
   }
 
   return nullptr;
 }
 
 char16_t
 WSRunObject::GetCharAt(Text* aTextNode,
-                       int32_t aOffset)
+                       int32_t aOffset) const
 {
   // return 0 if we can't get a char, for whatever reason
   NS_ENSURE_TRUE(aTextNode, 0);
 
   int32_t len = int32_t(aTextNode->TextLength());
   if (aOffset < 0 || aOffset >= len) {
     return 0;
   }
   return aTextNode->GetText()->CharAt(aOffset);
 }
 
 template<typename PT, typename CT>
 WSRunObject::WSPoint
-WSRunObject::GetNextCharPointInternal(const EditorDOMPointBase<PT, CT>& aPoint)
+WSRunObject::GetNextCharPointInternal(
+               const EditorDOMPointBase<PT, CT>& aPoint) const
 {
   // Note: only to be called if aPoint.GetContainer() is not a ws node.
 
   // Binary search on wsnodes
   uint32_t numNodes = mNodeArray.Length();
 
   if (!numNodes) {
     // Do nothing if there are no nodes to search
     WSPoint outPoint;
     return outPoint;
   }
 
   // Begin binary search.  We do this because we need to minimize calls to
   // ComparePoints(), which is expensive.
   uint32_t firstNum = 0, curNum = numNodes / 2, lastNum = numNodes;
   while (curNum != lastNum) {
-    RefPtr<Text> curNode = mNodeArray[curNum];
+    Text* curNode = mNodeArray[curNum];
     int16_t cmp =
       nsContentUtils::ComparePoints(aPoint, EditorRawDOMPoint(curNode, 0));
     if (cmp < 0) {
       lastNum = curNum;
     } else {
       firstNum = curNum + 1;
     }
     curNum = (lastNum - firstNum) / 2 + firstNum;
@@ -1739,51 +1757,50 @@ WSRunObject::GetNextCharPointInternal(co
 
   // When the binary search is complete, we always know that the current node
   // is the same as the end node, which is always past our range.  Therefore,
   // we've found the node immediately after the point of interest.
   if (curNum == mNodeArray.Length()) {
     // hey asked for past our range (it's after the last node).
     // GetNextCharPoint() will do the work for us when we pass it the last
     // index of the last node.
-    RefPtr<Text> textNode(mNodeArray[curNum - 1]);
+    Text* textNode = mNodeArray[curNum - 1];
     WSPoint point(textNode, textNode->TextLength(), 0);
     return GetNextCharPoint(point);
   }
 
   // The char after the point is the first character of our range.
-  RefPtr<Text> textNode(mNodeArray[curNum]);
+  Text* textNode = mNodeArray[curNum];
   WSPoint point(textNode, 0, 0);
   return GetNextCharPoint(point);
 }
 
 template<typename PT, typename CT>
 WSRunObject::WSPoint
 WSRunObject::GetPreviousCharPointInternal(
-               const EditorDOMPointBase<PT, CT>& aPoint)
+               const EditorDOMPointBase<PT, CT>& aPoint) const
 {
   // Note: only to be called if aNode is not a ws node.
 
   // Binary search on wsnodes
   uint32_t numNodes = mNodeArray.Length();
 
   if (!numNodes) {
     // Do nothing if there are no nodes to search
     WSPoint outPoint;
     return outPoint;
   }
 
   uint32_t firstNum = 0, curNum = numNodes/2, lastNum = numNodes;
   int16_t cmp = 0;
-  RefPtr<Text>  curNode;
 
   // Begin binary search.  We do this because we need to minimize calls to
   // ComparePoints(), which is expensive.
   while (curNum != lastNum) {
-    curNode = mNodeArray[curNum];
+    Text* curNode = mNodeArray[curNum];
     cmp = nsContentUtils::ComparePoints(aPoint, EditorRawDOMPoint(curNode, 0));
     if (cmp < 0) {
       lastNum = curNum;
     } else {
       firstNum = curNum + 1;
     }
     curNum = (lastNum - firstNum)/2 + firstNum;
     MOZ_ASSERT(firstNum <= curNum && curNum <= lastNum, "Bad binary search");
@@ -1791,25 +1808,25 @@ WSRunObject::GetPreviousCharPointInterna
 
   // When the binary search is complete, we always know that the current node
   // is the same as the end node, which is always past our range. Therefore,
   // we've found the node immediately after the point of interest.
   if (curNum == mNodeArray.Length()) {
     // Get the point before the end of the last node, we can pass the length of
     // the node into GetPreviousCharPoint(), and it will return the last
     // character.
-    RefPtr<Text> textNode(mNodeArray[curNum - 1]);
+    Text* textNode = mNodeArray[curNum - 1];
     WSPoint point(textNode, textNode->TextLength(), 0);
     return GetPreviousCharPoint(point);
   }
 
   // We can just ask the current node for the point immediately before it,
   // it will handle moving to the previous node (if any) and returning the
   // appropriate character
-  RefPtr<Text> textNode(mNodeArray[curNum]);
+  Text* textNode = mNodeArray[curNum];
   WSPoint point(textNode, 0, 0);
   return GetPreviousCharPoint(point);
 }
 
 nsresult
 WSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
 {
   // Try to change an nbsp to a space, if possible, just to prevent nbsp
--- a/editor/libeditor/WSRunObject.h
+++ b/editor/libeditor/WSRunObject.h
@@ -271,33 +271,52 @@ public:
 
   // DeleteWSForward deletes a single visible piece of ws after the ws point
   // (the point to create the wsRunObject, passed to its constructor).  It
   // makes any needed conversion to adjacent ws to retain its significance.
   nsresult DeleteWSForward();
 
   // PriorVisibleNode() returns the first piece of visible thing before aPoint.
   // If there is no visible ws qualifying it returns what is before the ws run.
+  // If outVisNode and/or outvisOffset is unused, callers can use nullptr.
   // Note that {outVisNode,outVisOffset} is set to just AFTER the visible
-  // object.
+  // object. Also outVisOffset might be invalid offset unless outVisNode is
+  // start reason node.
   template<typename PT, typename CT>
   void PriorVisibleNode(const EditorDOMPointBase<PT, CT>& aPoint,
                         nsCOMPtr<nsINode>* outVisNode,
                         int32_t* outVisOffset,
-                        WSType* outType);
+                        WSType* outType) const;
+
+  template<typename PT, typename CT>
+  void PriorVisibleNode(const EditorDOMPointBase<PT, CT>& aPoint,
+                        WSType* outType) const
+  {
+    PriorVisibleNode(aPoint, nullptr, nullptr, outType);
+  }
+
 
   // NextVisibleNode() returns the first piece of visible thing after aPoint.
   // If there is no visible ws qualifying it returns what is after the ws run.
+  // If outVisNode and/or outvisOffset is unused, callers can use nullptr.
   // Note that {outVisNode,outVisOffset} is set to just BEFORE the visible
-  // object.
+  // object. Also outVisOffset might be invalid offset unless outVisNode is
+  // end reason node.
   template<typename PT, typename CT>
   void NextVisibleNode(const EditorDOMPointBase<PT, CT>& aPoint,
                        nsCOMPtr<nsINode>* outVisNode,
                        int32_t* outVisOffset,
-                       WSType* outType);
+                       WSType* outType) const;
+
+  template<typename PT, typename CT>
+  void NextVisibleNode(const EditorDOMPointBase<PT, CT>& aPoint,
+                       WSType* outType) const
+  {
+    NextVisibleNode(aPoint, nullptr, nullptr, outType);
+  }
 
   // AdjustWhitespace examines the ws object for nbsp's that can
   // be safely converted to regular ascii space and converts them.
   nsresult AdjustWhitespace();
 
 protected:
   // WSFragment represents a single run of ws (all leadingws, or all normalws,
   // or all trailingws, or all leading+trailingws).  Note that this single run
@@ -387,41 +406,42 @@ protected:
   nsresult DeleteRange(const EditorDOMPointBase<PT1, CT1>& aStartPoint,
                        const EditorDOMPointBase<PT2, CT2>& aEndPoint);
 
   /**
    * GetNextCharPoint() returns next character's point of aPoint.  If there is
    * no character after aPoint, mTextNode is set to nullptr.
    */
   template<typename PT, typename CT>
-  WSPoint GetNextCharPoint(const EditorDOMPointBase<PT, CT>& aPoint);
-  WSPoint GetNextCharPoint(const WSPoint& aPoint);
+  WSPoint GetNextCharPoint(const EditorDOMPointBase<PT, CT>& aPoint) const;
+  WSPoint GetNextCharPoint(const WSPoint& aPoint) const;
 
   /**
    * GetPreviousCharPoint() returns previous character's point of of aPoint.
    * If there is no character before aPoint, mTextNode is set to nullptr.
    */
   template<typename PT, typename CT>
-  WSPoint GetPreviousCharPoint(const EditorDOMPointBase<PT, CT>& aPoint);
-  WSPoint GetPreviousCharPoint(const WSPoint& aPoint);
+  WSPoint GetPreviousCharPoint(const EditorDOMPointBase<PT, CT>& aPoint) const;
+  WSPoint GetPreviousCharPoint(const WSPoint& aPoint) const;
 
   /**
    * GetNextCharPointInternal() and GetPreviousCharPointInternal() are
    * helper methods of GetNextCharPoint(const EditorRawDOMPoint&) and
    * GetPreviousCharPoint(const EditorRawDOMPoint&).  When the container
    * isn't in mNodeArray, they call one of these methods.  Then, these
    * methods look for nearest text node in mNodeArray from aPoint.
    * Then, will call GetNextCharPoint(const WSPoint&) or
    * GetPreviousCharPoint(const WSPoint&) and returns its result.
    */
   template<typename PT, typename CT>
-  WSPoint GetNextCharPointInternal(const EditorDOMPointBase<PT, CT>& aPoint);
+  WSPoint
+  GetNextCharPointInternal(const EditorDOMPointBase<PT, CT>& aPoint) const;
   template<typename PT, typename CT>
   WSPoint
-  GetPreviousCharPointInternal(const EditorDOMPointBase<PT, CT>& aPoint);
+  GetPreviousCharPointInternal(const EditorDOMPointBase<PT, CT>& aPoint) const;
 
   /**
    * InsertNBSPAndRemoveFollowingASCIIWhitespaces() inserts an NBSP first.
    * Then, if following characters are ASCII whitespaces, will remove them.
    */
   nsresult InsertNBSPAndRemoveFollowingASCIIWhitespaces(WSPoint aPoint);
 
   /**
@@ -471,19 +491,19 @@ protected:
    *                    If aForward is false and:
    *                      if aPoint is end of a run, returns the run.
    *                      if aPoint is start of a run, returns its next run.
    *                      if aPoint is before the first run, returns nullptr.
    *                      if aPoint is after the last run, returns the last run.
    */
   template<typename PT, typename CT>
   WSFragment* FindNearestRun(const EditorDOMPointBase<PT, CT>& aPoint,
-                             bool aForward);
+                             bool aForward) const;
 
-  char16_t GetCharAt(dom::Text* aTextNode, int32_t aOffset);
+  char16_t GetCharAt(dom::Text* aTextNode, int32_t aOffset) const;
   nsresult CheckTrailingNBSPOfRun(WSFragment *aRun);
 
   /**
    * ReplacePreviousNBSPIfUnncessary() replaces previous character of aPoint
    * if it's a NBSP and it's unnecessary.
    *
    * @param aRun        Current text run.  aPoint must be in this run.
    * @param aPoint      Current insertion point.  Its previous character is