Bug 1407305 - Part 1: Add a aChildAtOffset argument to HTMLEditor::GetPriorHTMLNode(); r=masayuki
authorEhsan Akhgari <ehsan@mozilla.com>
Sat, 07 Oct 2017 17:30:38 -0400
changeset 385574 aa6c322a98b09b94faf4184274b10d62b7393075
parent 385573 a2bc0214fbcaf6104fe2ae8d2f4843997ea283de
child 385575 dc1c6227e652a56ac396d9f4717c0bc49ff5247f
push id32662
push userryanvm@gmail.com
push dateWed, 11 Oct 2017 21:53:47 +0000
treeherdermozilla-central@3d918ff5d634 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1407305
milestone58.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 1407305 - Part 1: Add a aChildAtOffset argument to HTMLEditor::GetPriorHTMLNode(); r=masayuki
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLEditor.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1214,21 +1214,23 @@ HTMLEditRules::WillInsert(Selection& aSe
   }
 
   // If we are after a mozBR in the same block, then move selection to be
   // before it
   NS_ENSURE_TRUE_VOID(aSelection.GetRangeAt(0) &&
                       aSelection.GetRangeAt(0)->GetStartContainer());
   OwningNonNull<nsINode> selNode =
     *aSelection.GetRangeAt(0)->GetStartContainer();
+  nsIContent* selChild = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
   int32_t selOffset = aSelection.GetRangeAt(0)->StartOffset();
 
   // Get prior node
   nsCOMPtr<nsIContent> priorNode = htmlEditor->GetPriorHTMLNode(selNode,
-                                                                selOffset);
+                                                                selOffset,
+                                                                selChild);
   if (priorNode && TextEditUtils::IsMozBR(priorNode)) {
     nsCOMPtr<Element> block1 = htmlEditor->GetBlock(selNode);
     nsCOMPtr<Element> block2 = htmlEditor->GetBlockNodeParent(priorNode);
 
     if (block1 && block1 == block2) {
       // If we are here then the selection is right after a mozBR that is in
       // the same block as the selection.  We need to move the selection start
       // to be before the mozBR.
@@ -1528,16 +1530,17 @@ HTMLEditRules::WillInsertBreak(Selection
     }
   }
 
   // Smart splitting rules
   NS_ENSURE_TRUE(aSelection.GetRangeAt(0) &&
                  aSelection.GetRangeAt(0)->GetStartContainer(),
                  NS_ERROR_FAILURE);
   OwningNonNull<nsINode> node = *aSelection.GetRangeAt(0)->GetStartContainer();
+  nsIContent* child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
   int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
 
   // Do nothing if the node is read-only
   if (!htmlEditor->IsModifiableNode(node)) {
     *aCancel = true;
     return NS_OK;
   }
 
@@ -1580,16 +1583,17 @@ HTMLEditRules::WillInsertBreak(Selection
     Unused << NS_WARN_IF(NS_FAILED(rv));
 
     // Reinitialize node/offset in case they're not inside the new block
     if (NS_WARN_IF(!aSelection.GetRangeAt(0) ||
                    !aSelection.GetRangeAt(0)->GetStartContainer())) {
       return NS_ERROR_FAILURE;
     }
     node = *aSelection.GetRangeAt(0)->GetStartContainer();
+    child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
     offset = aSelection.GetRangeAt(0)->StartOffset();
 
     blockParent = mHTMLEditor->GetBlock(node);
     if (NS_WARN_IF(!blockParent)) {
       return NS_ERROR_UNEXPECTED;
     }
     if (NS_WARN_IF(blockParent == host)) {
       // Didn't create a new block for some reason, fall back to <br>
@@ -1633,18 +1637,18 @@ HTMLEditRules::WillInsertBreak(Selection
   //     paragraph separator is <br>.  Otherwise, take consistent behavior
   //     between <p> container and <div> container.
   else if ((separator == ParagraphSeparator::br &&
             blockParent->IsHTMLElement(nsGkAtoms::p)) ||
            (separator != ParagraphSeparator::br &&
             blockParent->IsAnyOfHTMLElements(nsGkAtoms::p, nsGkAtoms::div))) {
     // Paragraphs: special rules to look for <br>s
     nsresult rv =
-      ReturnInParagraph(&aSelection, GetAsDOMNode(blockParent),
-                        GetAsDOMNode(node), offset, aCancel, aHandled);
+      ReturnInParagraph(&aSelection, blockParent, node,
+                        offset, child, aCancel, aHandled);
     NS_ENSURE_SUCCESS(rv, rv);
     // Fall through, we may not have handled it in ReturnInParagraph()
   }
 
   // If not already handled then do the standard thing
   if (!(*aHandled)) {
     *aHandled = true;
     return StandardBreakImpl(node, offset, aSelection);
@@ -5313,16 +5317,17 @@ HTMLEditRules::NormalizeSelection(Select
   nsCOMPtr<nsINode> startNode = range->GetStartContainer();
   if (NS_WARN_IF(!startNode)) {
     return NS_ERROR_FAILURE;
   }
   nsCOMPtr<nsINode> endNode = range->GetEndContainer();
   if (NS_WARN_IF(!endNode)) {
     return NS_ERROR_FAILURE;
   }
+  nsIContent* endChild = range->GetChildAtEndOffset();
   uint32_t startOffset = range->StartOffset();
   uint32_t endOffset = range->EndOffset();
 
   // adjusted values default to original values
   nsCOMPtr<nsINode> newStartNode = startNode;
   uint32_t newStartOffset = startOffset;
   nsCOMPtr<nsINode> newEndNode = endNode;
   uint32_t newEndOffset = endOffset;
@@ -5350,17 +5355,18 @@ HTMLEditRules::NormalizeSelection(Select
         newEndNode = EditorBase::GetNodeLocation(child, &offset);
         // offset *after* child
         newEndOffset = static_cast<uint32_t>(offset + 1);
       }
       // else block is empty - we can leave selection alone here, i think.
     } else if (wsEndObj.mStartReason == WSType::thisBlock) {
       // endpoint is just after start of this block
       nsINode* child =
-        htmlEditor->GetPriorHTMLNode(endNode, static_cast<int32_t>(endOffset));
+        htmlEditor->GetPriorHTMLNode(endNode, static_cast<int32_t>(endOffset),
+                                     endChild);
       if (child) {
         int32_t offset = -1;
         newEndNode = EditorBase::GetNodeLocation(child, &offset);
         // offset *after* child
         newEndOffset = static_cast<uint32_t>(offset + 1);
       }
       // else block is empty - we can leave selection alone here, i think.
     } else if (wsEndObj.mStartReason == WSType::br) {
@@ -5488,49 +5494,52 @@ HTMLEditRules::GetPromotedPoint(RulesEnd
         break;
       }
     }
 
     return EditorDOMPoint(content, newOffset);
   }
 
   nsCOMPtr<nsINode> node = &aNode;
+  nsINode* child = node->GetChildAt(aOffset);
   int32_t offset = aOffset;
 
   // else not a text section.  In this case we want to see if we should grab
   // any adjacent inline nodes and/or parents and other ancestors
   if (aWhere == kStart) {
     // some special casing for text nodes
     if (node->IsNodeOfType(nsINode::eTEXT)) {
       if (!node->GetParentNode()) {
         // Okay, can't promote any further
         return EditorDOMPoint(node, offset);
       }
       offset = node->GetParentNode()->IndexOf(node);
+      child = node;
       node = node->GetParentNode();
     }
 
     // look back through any further inline nodes that aren't across a <br>
     // from us, and that are enclosed in the same block.
     nsCOMPtr<nsINode> priorNode =
-      htmlEditor->GetPriorHTMLNode(node, offset, true);
+      htmlEditor->GetPriorHTMLNode(node, offset, child, true);
 
     while (priorNode && priorNode->GetParentNode() &&
            !htmlEditor->IsVisibleBRElement(priorNode) &&
            !IsBlockNode(*priorNode)) {
       offset = priorNode->GetParentNode()->IndexOf(priorNode);
+      child = node;
       node = priorNode->GetParentNode();
-      priorNode = htmlEditor->GetPriorHTMLNode(node, offset, true);
+      priorNode = htmlEditor->GetPriorHTMLNode(node, offset, child, true);
     }
 
     // finding the real start for this point.  look up the tree for as long as
     // we are the first node in the container, and as long as we haven't hit
     // the body node.
     nsCOMPtr<nsIContent> nearNode =
-      htmlEditor->GetPriorHTMLNode(node, offset, true);
+      htmlEditor->GetPriorHTMLNode(node, offset, child, true);
     while (!nearNode && !node->IsHTMLElement(nsGkAtoms::body) &&
            node->GetParentNode()) {
       // some cutoffs are here: we don't need to also include them in the
       // aWhere == kEnd case.  as long as they are in one or the other it will
       // work.  special case for outdent: don't keep looking up if we have
       // found a blockquote element to act on
       if (actionID == EditAction::outdent &&
           node->IsHTMLElement(nsGkAtoms::blockquote)) {
@@ -5549,42 +5558,45 @@ HTMLEditRules::GetPromotedPoint(RulesEnd
                               actionID == EditAction::align ||
                               actionID == EditAction::makeBasicBlock;
       if (!htmlEditor->IsDescendantOfEditorRoot(parent) &&
           (blockLevelAction ||
            !htmlEditor->IsDescendantOfEditorRoot(node))) {
         break;
       }
 
+      child = node;
       node = parent;
       offset = parentOffset;
-      nearNode = htmlEditor->GetPriorHTMLNode(node, offset, true);
+      nearNode = htmlEditor->GetPriorHTMLNode(node, offset, child, true);
     }
     return EditorDOMPoint(node, offset);
   }
 
   // aWhere == kEnd
   // some special casing for text nodes
   if (node->IsNodeOfType(nsINode::eTEXT)) {
     if (!node->GetParentNode()) {
       // Okay, can't promote any further
       return EditorDOMPoint(node, offset);
     }
     // want to be after the text node
     offset = 1 + node->GetParentNode()->IndexOf(node);
+    child = node;
     node = node->GetParentNode();
   }
 
   // look ahead through any further inline nodes that aren't across a <br> from
   // us, and that are enclosed in the same block.
   nsCOMPtr<nsIContent> nextNode =
     htmlEditor->GetNextHTMLNode(node, offset, true);
 
   while (nextNode && !IsBlockNode(*nextNode) && nextNode->GetParentNode()) {
     offset = 1 + nextNode->GetParentNode()->IndexOf(nextNode);
+    child = nextNode->GetNextSibling();
     node = nextNode->GetParentNode();
     if (htmlEditor->IsVisibleBRElement(nextNode)) {
       break;
     }
 
     // Check for newlines in pre-formatted text nodes.
     bool isPRE;
     htmlEditor->IsPreformatted(nextNode->AsDOMNode(), &isPRE);
@@ -5618,16 +5630,17 @@ HTMLEditRules::GetPromotedPoint(RulesEnd
     // Don't walk past the editable section. Note that we need to check before
     // walking up to a parent because we need to return the parent object, so
     // the parent itself might not be in the editable area, but it's OK.
     if (!htmlEditor->IsDescendantOfEditorRoot(node) &&
         !htmlEditor->IsDescendantOfEditorRoot(parent)) {
       break;
     }
 
+    child = node->GetNextSibling();
     node = parent;
     // we want to be AFTER nearNode
     offset = parentOffset + 1;
     nearNode = htmlEditor->GetNextHTMLNode(node, offset, true);
   }
   return EditorDOMPoint(node, offset);
 }
 
@@ -6435,19 +6448,20 @@ HTMLEditRules::ReturnInHeader(Selection&
 /**
  * ReturnInParagraph() does the right thing for returns pressed in paragraphs.
  * For our purposes, this means either <p> or <div>, which is not in keeping
  * with the semantics of <div>, but is necessary for compatibility with other
  * browsers.
  */
 nsresult
 HTMLEditRules::ReturnInParagraph(Selection* aSelection,
-                                 nsIDOMNode* aPara,
-                                 nsIDOMNode* aNode,
+                                 nsINode* aPara,
+                                 nsINode* aNode,
                                  int32_t aOffset,
+                                 nsIContent* aChildAtOffset,
                                  bool* aCancel,
                                  bool* aHandled)
 {
   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
   if (!aSelection || !aPara || !node || !aCancel || !aHandled) {
     return NS_ERROR_NULL_POINTER;
   }
   *aCancel = false;
@@ -6457,17 +6471,17 @@ HTMLEditRules::ReturnInParagraph(Selecti
   nsCOMPtr<nsINode> parent = EditorBase::GetNodeLocation(node, &offset);
 
   NS_ENSURE_STATE(mHTMLEditor);
   bool doesCRCreateNewP = mHTMLEditor->GetReturnInParagraphCreatesNewParagraph();
 
   bool newBRneeded = false;
   bool newSelNode = false;
   nsCOMPtr<nsIContent> sibling;
-  nsCOMPtr<nsIDOMNode> selNode = aNode;
+  nsCOMPtr<nsIDOMNode> selNode = GetAsDOMNode(aNode);
   int32_t selOffset = aOffset;
 
   NS_ENSURE_STATE(mHTMLEditor);
   if (aNode == aPara && doesCRCreateNewP) {
     // we are at the edges of the block, newBRneeded not needed!
     sibling = node->AsContent();
   } else if (EditorBase::IsTextNode(aNode)) {
     // at beginning of text node?
@@ -6495,30 +6509,30 @@ HTMLEditRules::ReturnInParagraph(Selecti
       }
     } else {
       if (doesCRCreateNewP) {
         nsCOMPtr<nsIDOMNode> tmp;
         if (NS_WARN_IF(!mHTMLEditor)) {
           return NS_ERROR_UNEXPECTED;
         }
         nsresult rv =
-          mHTMLEditor->SplitNode(aNode, aOffset, getter_AddRefs(tmp));
+          mHTMLEditor->SplitNode(selNode, aOffset, getter_AddRefs(tmp));
         NS_ENSURE_SUCCESS(rv, rv);
         selNode = tmp;
       }
 
       newBRneeded = true;
       offset++;
     }
   } else {
     // not in a text node.
     // is there a BR prior to it?
     nsCOMPtr<nsIContent> nearNode;
     NS_ENSURE_STATE(mHTMLEditor);
-    nearNode = mHTMLEditor->GetPriorHTMLNode(node, aOffset);
+    nearNode = mHTMLEditor->GetPriorHTMLNode(node, aOffset, aChildAtOffset);
     NS_ENSURE_STATE(mHTMLEditor);
     if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
         TextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) {
       // is there a BR after it?
       NS_ENSURE_STATE(mHTMLEditor);
       nearNode = mHTMLEditor->GetNextHTMLNode(node, aOffset);
       NS_ENSURE_STATE(mHTMLEditor);
       if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
@@ -6541,17 +6555,18 @@ HTMLEditRules::ReturnInParagraph(Selecti
     sibling = mHTMLEditor->CreateBR(parent, offset);
     if (newSelNode) {
       // We split the parent after the br we've just inserted.
       selNode = GetAsDOMNode(parent);
       selOffset = offset + 1;
     }
   }
   *aHandled = true;
-  return SplitParagraph(aPara, sibling, aSelection, address_of(selNode), &selOffset);
+  return SplitParagraph(GetAsDOMNode(aPara), sibling, aSelection,
+                        address_of(selNode), &selOffset);
 }
 
 /**
  * SplitParagraph() splits a paragraph at selection point, possibly deleting a
  * br.
  */
 nsresult
 HTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
@@ -7484,17 +7499,17 @@ HTMLEditRules::CheckInterlinePosition(Se
     *aSelection.GetRangeAt(0)->GetStartContainer();
   int32_t selOffset = aSelection.GetRangeAt(0)->StartOffset();
   nsIContent* child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
 
   // First, let's check to see if we are after a <br>.  We take care of this
   // special-case first so that we don't accidentally fall through into one of
   // the other conditionals.
   nsCOMPtr<nsIContent> node =
-    htmlEditor->GetPriorHTMLNode(selNode, selOffset, true);
+    htmlEditor->GetPriorHTMLNode(selNode, selOffset, child, true);
   if (node && node->IsHTMLElement(nsGkAtoms::br)) {
     aSelection.SetInterlinePosition(true);
     return;
   }
 
   // Are we after a block?  If so try set caret to following content
   if (child) {
     node = htmlEditor->GetPriorHTMLSibling(child);
@@ -7532,16 +7547,17 @@ HTMLEditRules::AdjustSelection(Selection
 
   // get the (collapsed) selection location
   nsCOMPtr<nsINode> selNode, temp;
   int32_t selOffset;
   nsresult rv =
     EditorBase::GetStartNodeAndOffset(aSelection,
                                       getter_AddRefs(selNode), &selOffset);
   NS_ENSURE_SUCCESS(rv, rv);
+  nsIContent* child = aSelection->GetRangeAt(0)->GetChildAtStartOffset();
   temp = selNode;
 
   // are we in an editable node?
   NS_ENSURE_STATE(mHTMLEditor);
   while (!mHTMLEditor->IsEditable(selNode)) {
     // scan up the tree until we find an editable place to be
     selNode = EditorBase::GetNodeLocation(temp, &selOffset);
     NS_ENSURE_TRUE(selNode, NS_ERROR_FAILURE);
@@ -7584,17 +7600,17 @@ HTMLEditRules::AdjustSelection(Selection
 
   // do we need to insert a special mozBR?  We do if we are:
   // 1) prior node is in same block where selection is AND
   // 2) prior node is a br AND
   // 3) that br is not visible
 
   NS_ENSURE_STATE(mHTMLEditor);
   nsCOMPtr<nsIContent> nearNode =
-    mHTMLEditor->GetPriorHTMLNode(selNode, selOffset);
+    mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, child);
   if (nearNode) {
     // is nearNode also a descendant of same block?
     NS_ENSURE_STATE(mHTMLEditor);
     nsCOMPtr<Element> block = mHTMLEditor->GetBlock(*selNode);
     nsCOMPtr<Element> nearBlock = mHTMLEditor->GetBlockNodeParent(nearNode);
     if (block && block == nearBlock) {
       if (nearNode && TextEditUtils::IsBreak(nearNode)) {
         NS_ENSURE_STATE(mHTMLEditor);
@@ -7623,17 +7639,17 @@ HTMLEditRules::AdjustSelection(Selection
           }
         }
       }
     }
   }
 
   // we aren't in a textnode: are we adjacent to text or a break or an image?
   NS_ENSURE_STATE(mHTMLEditor);
-  nearNode = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, true);
+  nearNode = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, child, true);
   if (nearNode && (TextEditUtils::IsBreak(nearNode) ||
                    EditorBase::IsTextNode(nearNode) ||
                    HTMLEditUtils::IsImage(nearNode) ||
                    nearNode->IsHTMLElement(nsGkAtoms::hr))) {
     // this is a good place for the caret to be
     return NS_OK;
   }
   NS_ENSURE_STATE(mHTMLEditor);
@@ -7642,17 +7658,17 @@ HTMLEditRules::AdjustSelection(Selection
                    EditorBase::IsTextNode(nearNode) ||
                    nearNode->IsAnyOfHTMLElements(nsGkAtoms::img,
                                                  nsGkAtoms::hr))) {
     return NS_OK; // this is a good place for the caret to be
   }
 
   // look for a nearby text node.
   // prefer the correct direction.
-  rv = FindNearSelectableNode(selNode, selOffset, aAction,
+  rv = FindNearSelectableNode(selNode, selOffset, child, aAction,
                               address_of(nearNode));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!nearNode) {
     return NS_OK;
   }
   EditorDOMPoint pt = GetGoodSelPointForNode(*nearNode, aAction);
   rv = aSelection->Collapse(pt.node, pt.offset);
@@ -7661,26 +7677,28 @@ HTMLEditRules::AdjustSelection(Selection
   }
   return NS_OK;
 }
 
 
 nsresult
 HTMLEditRules::FindNearSelectableNode(nsINode* aSelNode,
                                       int32_t aSelOffset,
+                                      nsIContent* aChildAtOffset,
                                       nsIEditor::EDirection& aDirection,
                                       nsCOMPtr<nsIContent>* outSelectableNode)
 {
   NS_ENSURE_TRUE(aSelNode && outSelectableNode, NS_ERROR_NULL_POINTER);
   *outSelectableNode = nullptr;
 
   nsCOMPtr<nsIContent> nearNode, curNode;
   if (aDirection == nsIEditor::ePrevious) {
     NS_ENSURE_STATE(mHTMLEditor);
-    nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset);
+    nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset,
+                                             aChildAtOffset);
     if (NS_WARN_IF(!nearNode)) {
       return NS_ERROR_FAILURE;
     }
   } else {
     NS_ENSURE_STATE(mHTMLEditor);
     nearNode = mHTMLEditor->GetNextHTMLNode(aSelNode, aSelOffset);
     if (NS_WARN_IF(!nearNode)) {
       return NS_ERROR_FAILURE;
@@ -7692,23 +7710,25 @@ HTMLEditRules::FindNearSelectableNode(ns
     if (aDirection == nsIEditor::ePrevious) {
       aDirection = nsIEditor::eNext;
     } else {
       aDirection = nsIEditor::ePrevious;
     }
 
     if (aDirection == nsIEditor::ePrevious) {
       NS_ENSURE_STATE(mHTMLEditor);
-      nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset);
+      nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset,
+                                               aChildAtOffset);
       if (NS_WARN_IF(!nearNode)) {
         return NS_ERROR_FAILURE;
       }
     } else {
       NS_ENSURE_STATE(mHTMLEditor);
-      nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset);
+      nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset,
+                                               aChildAtOffset);
       if (NS_WARN_IF(!nearNode)) {
         return NS_ERROR_FAILURE;
       }
     }
   }
 
   // scan in the right direction until we find an eligible text node,
   // but don't cross any breaks, images, or table elements.
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -284,19 +284,20 @@ protected:
   void GetInnerContent(nsINode& aNode,
                        nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
                        int32_t* aIndex, Lists aLists = Lists::yes,
                        Tables aTables = Tables::yes);
   Element* IsInListItem(nsINode* aNode);
   nsAtom& DefaultParagraphSeparator();
   nsresult ReturnInHeader(Selection& aSelection, Element& aHeader,
                           nsINode& aNode, int32_t aOffset);
-  nsresult ReturnInParagraph(Selection* aSelection, nsIDOMNode* aHeader,
-                             nsIDOMNode* aTextNode, int32_t aOffset,
-                             bool* aCancel, bool* aHandled);
+  nsresult ReturnInParagraph(Selection* aSelection, nsINode* aHeader,
+                             nsINode* aTextNode, int32_t aOffset,
+                             nsIContent* aChildAtOffset, bool* aCancel,
+                             bool* aHandled);
   nsresult SplitParagraph(nsIDOMNode* aPara,
                           nsIContent* aBRNode,
                           Selection* aSelection,
                           nsCOMPtr<nsIDOMNode>* aSelNode,
                           int32_t* aOffset);
   nsresult ReturnInListItem(Selection& aSelection, Element& aHeader,
                             nsINode& aNode, int32_t aOffset);
   nsresult AfterEditInner(EditAction action,
@@ -394,16 +395,17 @@ protected:
   void AdjustSpecialBreaks();
   nsresult AdjustWhitespace(Selection* aSelection);
   nsresult PinSelectionToNewBlock(Selection* aSelection);
   void CheckInterlinePosition(Selection& aSelection);
   nsresult AdjustSelection(Selection* aSelection,
                            nsIEditor::EDirection aAction);
   nsresult FindNearSelectableNode(nsINode* aSelNode,
                                   int32_t aSelOffset,
+                                  nsIContent* aChildAtOffset,
                                   nsIEditor::EDirection& aDirection,
                                   nsCOMPtr<nsIContent>* outSelectableNode);
   /**
    * Returns true if aNode1 or aNode2 or both is the descendant of some type of
    * table element, but their nearest table element ancestors differ.  "Table
    * element" here includes not just <table> but also <td>, <tbody>, <tr>, etc.
    * The nodes count as being their own descendants for this purpose, so a
    * table element is its own nearest table element ancestor.
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -3887,16 +3887,17 @@ HTMLEditor::GetPriorHTMLNode(nsIDOMNode*
 
 /**
  * GetPriorHTMLNode() is same as above but takes {parent,offset} instead of
  * node.
  */
 nsIContent*
 HTMLEditor::GetPriorHTMLNode(nsINode* aParent,
                              int32_t aOffset,
+                             nsINode* aChildAtOffset,
                              bool aNoBlockCrossing)
 {
   MOZ_ASSERT(aParent);
 
   if (!GetActiveEditingHost()) {
     return nullptr;
   }
 
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -774,16 +774,17 @@ protected:
   nsIContent* GetNextHTMLSibling(nsINode* aNode);
   nsresult GetNextHTMLSibling(nsIDOMNode* inNode,
                               nsCOMPtr<nsIDOMNode>* outNode);
 
   nsIContent* GetPriorHTMLNode(nsINode* aNode, bool aNoBlockCrossing = false);
   nsresult GetPriorHTMLNode(nsIDOMNode* inNode, nsCOMPtr<nsIDOMNode>* outNode,
                             bool bNoBlockCrossing = false);
   nsIContent* GetPriorHTMLNode(nsINode* aParent, int32_t aOffset,
+                               nsINode* aChildAtOffset,
                                bool aNoBlockCrossing = false);
 
   nsIContent* GetNextHTMLNode(nsINode* aNode, bool aNoBlockCrossing = false);
   nsresult GetNextHTMLNode(nsIDOMNode* inNode, nsCOMPtr<nsIDOMNode>* outNode,
                            bool bNoBlockCrossing = false);
   nsIContent* GetNextHTMLNode(nsINode* aParent, int32_t aOffset,
                               bool aNoBlockCrossing = false);