Bug 1415800 - part 4: Redesign HTMLEditor::GetNextHTMLNode() same as similar to EditorBase::GetNext*() r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 10 Nov 2017 00:12:22 +0900
changeset 696008 4f10b9a1d41a89f6d82edde16faa951e2432b838
parent 696007 5d078405c46b553ed876cb6d78d2e0e65c882f4d
child 696009 dcf51aa102e9e596604c5ea1ad5d44a959ed8729
push id88610
push usermasayuki@d-toybox.com
push dateFri, 10 Nov 2017 04:02:33 +0000
reviewersm_kato
bugs1415800
milestone58.0a1
Bug 1415800 - part 4: Redesign HTMLEditor::GetNextHTMLNode() same as similar to EditorBase::GetNext*() r?m_kato HTMLEditor::GetNextHTMLNode() should be redesigned as HTMLEditor::GetNextEditableHTMLNode(nsINode&), HTMLEditor::GetNextEditableHTMLNodeInBlock(nsINode&), HTMLEditor::GetNextEditableHTMLNode(const EditorRawDOMPoint&) and HTMLEditor::GetNextEditableHTMLNodeInBlock(const EditorRawDOMPoint&). Same as GetPreviousEditableHTMLNode*(), we don't need the methods to find non-editable nodes too. MozReview-Commit-ID: JjZauCMblp4
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLEditor.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -2483,17 +2483,17 @@ HTMLEditRules::WillDeleteSelection(Selec
       // First find the relevant nodes
       nsCOMPtr<nsINode> leftNode, rightNode;
       if (aAction == nsIEditor::ePrevious) {
         NS_ENSURE_STATE(mHTMLEditor);
         leftNode = mHTMLEditor->GetPreviousEditableHTMLNode(*visNode);
         rightNode = startNode;
       } else {
         NS_ENSURE_STATE(mHTMLEditor);
-        rightNode = mHTMLEditor->GetNextHTMLNode(visNode);
+        rightNode = mHTMLEditor->GetNextEditableHTMLNode(*visNode);
         leftNode = startNode;
       }
 
       // Nothing to join
       if (!leftNode || !rightNode) {
         *aCancel = true;
         return NS_OK;
       }
@@ -3796,17 +3796,18 @@ HTMLEditRules::MakeBasicBlock(Selection&
       // We are removing blocks (going to "body text")
       NS_ENSURE_TRUE(htmlEditor->GetBlock(container), NS_ERROR_NULL_POINTER);
       OwningNonNull<Element> curBlock = *htmlEditor->GetBlock(container);
       if (HTMLEditUtils::IsFormatNode(curBlock)) {
         // If the first editable node after selection is a br, consume it.
         // Otherwise it gets pushed into a following block after the split,
         // which is visually bad.
         nsCOMPtr<nsIContent> brNode =
-          htmlEditor->GetNextHTMLNode(container, offset, child);
+          htmlEditor->GetNextEditableHTMLNode(
+                        EditorRawDOMPoint(container, child, offset));
         if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
           rv = htmlEditor->DeleteNode(brNode);
           NS_ENSURE_SUCCESS(rv, rv);
         }
         // Do the splits!
         offset = htmlEditor->SplitNodeDeep(curBlock, *container->AsContent(),
                                             offset,
                                             HTMLEditor::EmptyContainers::no);
@@ -3819,17 +3820,18 @@ HTMLEditRules::MakeBasicBlock(Selection&
         // Don't restore the selection
         selectionRestorer.Abort();
         NS_ENSURE_SUCCESS(rv, rv);
       }
       // Else nothing to do!
     } else {
       // We are making a block.  Consume a br, if needed.
       nsCOMPtr<nsIContent> brNode =
-        htmlEditor->GetNextHTMLNode(container, offset, child, true);
+        htmlEditor->GetNextEditableHTMLNodeInBlock(
+                      EditorRawDOMPoint(container, child, offset));
       if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
         rv = htmlEditor->DeleteNode(brNode);
         NS_ENSURE_SUCCESS(rv, rv);
         // We don't need to act on this node any more
         arrayOfNodes.RemoveElement(brNode);
         // XXX We need to recompute child here because SplitAsNeeded() and
         //     EditorBase::SplitNodeDeep() don't compute child in some cases.
         child = container->GetChildAt(offset);
@@ -4960,32 +4962,32 @@ HTMLEditRules::WillAlign(Selection& aSel
     nsCOMPtr<nsIContent> child =
       aSelection.GetRangeAt(0)->GetChildAtStartOffset();
 
     rv = SplitAsNeeded(*nsGkAtoms::div, parent, offset,
                        address_of(child));
     NS_ENSURE_SUCCESS(rv, rv);
     // Consume a trailing br, if any.  This is to keep an alignment from
     // creating extra lines, if possible.
+    EditorRawDOMPoint atChild(parent, child, offset);
     nsCOMPtr<nsIContent> brContent =
-      htmlEditor->GetNextHTMLNode(parent, offset, child);
+      htmlEditor->GetNextEditableHTMLNodeInBlock(atChild);
     if (brContent && TextEditUtils::IsBreak(brContent)) {
       // Making use of html structure... if next node after where we are
       // putting our div is not a block, then the br we found is in same block
       // we are, so it's safe to consume it.
       nsCOMPtr<nsIContent> sibling;
       if (child) {
         sibling = htmlEditor->GetNextHTMLSibling(child);
       }
       if (sibling && !IsBlockNode(*sibling)) {
         rv = htmlEditor->DeleteNode(brContent);
         NS_ENSURE_SUCCESS(rv, rv);
       }
     }
-    EditorRawDOMPoint atChild(parent, child, offset);
     RefPtr<Element> div = htmlEditor->CreateNode(nsGkAtoms::div, atChild);
     NS_ENSURE_STATE(div);
     // Remember our new block for postprocessing
     mNewBlock = div;
     // Set up the alignment on the div, using HTML or CSS
     rv = AlignBlock(*div, aAlignType, ContentsOnly::yes);
     NS_ENSURE_SUCCESS(rv, rv);
     *aHandled = true;
@@ -5627,19 +5629,18 @@ HTMLEditRules::NormalizeSelection(Select
         int32_t offset = -1;
         newStartNode = EditorBase::GetNodeLocation(child, &offset);
         newStartOffset = static_cast<uint32_t>(offset);
       }
       // else block is empty - we can leave selection alone here, i think.
     } else if (wsStartObj.mEndReason == WSType::thisBlock) {
       // startpoint is just before end of this block
       nsINode* child =
-        htmlEditor->GetNextHTMLNode(startNode,
-                                    static_cast<int32_t>(startOffset),
-                                    startChild);
+        htmlEditor->GetNextEditableHTMLNode(
+                      EditorRawDOMPoint(startNode, startChild, startOffset));
       if (child) {
         int32_t offset = -1;
         newStartNode = EditorBase::GetNodeLocation(child, &offset);
         newStartOffset = static_cast<uint32_t>(offset);
       }
       // else block is empty - we can leave selection alone here, i think.
     } else if (wsStartObj.mEndReason == WSType::br) {
       // startpoint is just before a break.  lets adjust it to after it.
@@ -5805,18 +5806,17 @@ HTMLEditRules::GetPromotedPoint(RulesEnd
     DebugOnly<bool> advanced = point.AdvanceOffset();
     NS_WARNING_ASSERTION(advanced,
       "Failed to advance offset to after the text node");
   }
 
   // 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(point.Container(), point.Offset(),
-                                point.GetChildAtOffset(), true);
+    htmlEditor->GetNextEditableHTMLNodeInBlock(point.AsRaw());
 
   while (nextNode && !IsBlockNode(*nextNode) && nextNode->GetParentNode()) {
     point.Set(nextNode);
     if (NS_WARN_IF(!point.AdvanceOffset())) {
       break;
     }
     if (htmlEditor->IsVisibleBRElement(nextNode)) {
       break;
@@ -5834,44 +5834,41 @@ HTMLEditRules::GetPromotedPoint(RulesEnd
           if (static_cast<uint32_t>(newlinePos) + 1 == tempString.Length()) {
             // No need for special processing if the newline is at the end.
             break;
           }
           return EditorDOMPoint(nextNode, newlinePos + 1);
         }
       }
     }
-    nextNode = htmlEditor->GetNextHTMLNode(point.Container(), point.Offset(),
-                                           point.GetChildAtOffset(), true);
+    nextNode = htmlEditor->GetNextEditableHTMLNodeInBlock(point.AsRaw());
   }
 
   // finding the real end for this point.  look up the tree for as long as we
   // are the last node in the container, and as long as we haven't hit the body
   // node.
   nsCOMPtr<nsIContent> nearNode =
-    htmlEditor->GetNextHTMLNode(point.Container(), point.Offset(),
-                                point.GetChildAtOffset(), true);
+    htmlEditor->GetNextEditableHTMLNodeInBlock(point.AsRaw());
   while (!nearNode &&
          !point.Container()->IsHTMLElement(nsGkAtoms::body) &&
          point.Container()->GetParentNode()) {
     // 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(point.Container()) &&
         !htmlEditor->IsDescendantOfEditorRoot(
                        point.Container()->GetParentNode())) {
       break;
     }
 
     point.Set(point.Container());
     if (NS_WARN_IF(!point.AdvanceOffset())) {
       break;
     }
-    nearNode = htmlEditor->GetNextHTMLNode(point.Container(), point.Offset(),
-                                           point.GetChildAtOffset(), true);
+    nearNode = htmlEditor->GetNextEditableHTMLNodeInBlock(point.AsRaw());
   }
   return point;
 }
 
 /**
  * GetPromotedRanges() runs all the selection range endpoint through
  * GetPromotedPoint().
  */
@@ -6798,17 +6795,19 @@ HTMLEditRules::ReturnInParagraph(Selecti
     nearNode =
       mHTMLEditor->GetPreviousEditableHTMLNode(
                      EditorRawDOMPoint(node, aChildAtOffset, aOffset));
     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, aChildAtOffset);
+      nearNode =
+        mHTMLEditor->GetNextEditableHTMLNode(
+                       EditorRawDOMPoint(node, aChildAtOffset, aOffset));
       NS_ENSURE_STATE(mHTMLEditor);
       if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
           TextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) {
         newBRneeded = true;
         parent = node;
         offset = aOffset;
         newSelNode = true;
       }
@@ -7953,17 +7952,17 @@ HTMLEditRules::AdjustSelection(Selection
           ErrorResult error;
           aSelection->Collapse(point.AsRaw(), error);
           if (NS_WARN_IF(error.Failed())) {
             return error.StealNSResult();
           }
         } else {
           NS_ENSURE_STATE(mHTMLEditor);
           nsCOMPtr<nsIContent> nextNode =
-            mHTMLEditor->GetNextHTMLNode(nearNode, true);
+            mHTMLEditor->GetNextEditableHTMLNodeInBlock(*nearNode);
           if (nextNode && TextEditUtils::IsMozBR(nextNode)) {
             // selection between br and mozbr.  make it stick to mozbr
             // so that it will be on blank line.
             aSelection->SetInterlinePosition(true);
           }
         }
       }
     }
@@ -7975,18 +7974,17 @@ HTMLEditRules::AdjustSelection(Selection
   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);
-  nearNode = mHTMLEditor->GetNextHTMLNode(point.Container(), point.Offset(),
-                                          point.GetChildAtOffset(), true);
+  nearNode = mHTMLEditor->GetNextEditableHTMLNodeInBlock(point.AsRaw());
   if (nearNode && (TextEditUtils::IsBreak(nearNode) ||
                    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.
@@ -8027,18 +8025,17 @@ HTMLEditRules::FindNearSelectableNode(ns
   if (aDirection == nsIEditor::ePrevious) {
     NS_ENSURE_STATE(mHTMLEditor);
     nearNode = mHTMLEditor->GetPreviousEditableHTMLNode(point);
     if (NS_WARN_IF(!nearNode)) {
       return NS_ERROR_FAILURE;
     }
   } else {
     NS_ENSURE_STATE(mHTMLEditor);
-    nearNode = mHTMLEditor->GetNextHTMLNode(point.Container(), point.Offset(),
-                                            point.GetChildAtOffset());
+    nearNode = mHTMLEditor->GetNextEditableHTMLNode(point);
     if (NS_WARN_IF(!nearNode)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   // Try the other direction then.
   if (!nearNode) {
     if (aDirection == nsIEditor::ePrevious) {
@@ -8071,17 +8068,17 @@ HTMLEditRules::FindNearSelectableNode(ns
     if (aDirection == nsIEditor::ePrevious) {
       NS_ENSURE_STATE(mHTMLEditor);
       nearNode = mHTMLEditor->GetPreviousEditableHTMLNode(*curNode);
       if (NS_WARN_IF(!nearNode)) {
         return NS_ERROR_FAILURE;
       }
     } else {
       NS_ENSURE_STATE(mHTMLEditor);
-      nearNode = mHTMLEditor->GetNextHTMLNode(curNode);
+      nearNode = mHTMLEditor->GetNextEditableHTMLNode(*curNode);
       if (NS_WARN_IF(!nearNode)) {
         return NS_ERROR_FAILURE;
       }
     }
     NS_ENSURE_STATE(mHTMLEditor);
   }
 
   if (nearNode) {
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -871,17 +871,17 @@ HTMLEditor::IsPrevCharInNodeWhitespace(n
 bool
 HTMLEditor::IsVisibleBRElement(nsINode* aNode)
 {
   MOZ_ASSERT(aNode);
   if (!TextEditUtils::IsBreak(aNode)) {
     return false;
   }
   // Check if there is a later node in block after br
-  nsCOMPtr<nsINode> nextNode = GetNextHTMLNode(aNode, true);
+  nsCOMPtr<nsINode> nextNode = GetNextEditableHTMLNodeInBlock(*aNode);
   if (nextNode && TextEditUtils::IsBreak(nextNode)) {
     return true;
   }
 
   // A single line break before a block boundary is not displayed, so e.g.
   // foo<p>bar<br></p> and foo<br><p>bar</p> display the same as foo<p>bar</p>.
   // But if there are multiple <br>s in a row, all but the last are visible.
   if (!nextNode) {
@@ -3884,55 +3884,36 @@ HTMLEditor::GetPreviousEditableHTMLNodeI
 {
   if (!GetActiveEditingHost()) {
     return nullptr;
   }
   return aNoBlockCrossing ? GetPreviousEditableNodeInBlock(aPoint) :
                             GetPreviousEditableNode(aPoint);
 }
 
-/**
- * GetNextHTMLNode() returns the next editable leaf node, if there is
- * one within the <body>.
- */
 nsIContent*
-HTMLEditor::GetNextHTMLNode(nsINode* aNode,
-                            bool aNoBlockCrossing)
+HTMLEditor::GetNextEditableHTMLNodeInternal(nsINode& aNode,
+                                            bool aNoBlockCrossing)
 {
-  MOZ_ASSERT(aNode);
-
-  nsIContent* result =
-    aNoBlockCrossing ? GetNextEditableNodeInBlock(*aNode) :
-                       GetNextEditableNode(*aNode);
-  if (result && !IsDescendantOfEditorRoot(result)) {
+  if (!GetActiveEditingHost()) {
     return nullptr;
   }
-  return result;
+  return aNoBlockCrossing ? GetNextEditableNodeInBlock(aNode) :
+                            GetNextEditableNode(aNode);
 }
 
-/**
- * GetNextHTMLNode() is same as above but takes {parent,offset} instead of node.
- */
 nsIContent*
-HTMLEditor::GetNextHTMLNode(nsINode* aParent,
-                            int32_t aOffset,
-                            nsINode* aChildAtOffset,
-                            bool aNoBlockCrossing)
+HTMLEditor::GetNextEditableHTMLNodeInternal(const EditorRawDOMPoint& aPoint,
+                                            bool aNoBlockCrossing)
 {
-  EditorRawDOMPoint point(aParent,
-                          aChildAtOffset && aChildAtOffset->IsContent() ?
-                            aChildAtOffset->AsContent() : nullptr,
-                          aOffset);
-  nsIContent* content =
-    aNoBlockCrossing ? GetNextEditableNodeInBlock(point) :
-                       GetNextEditableNode(point);
-  if (content && !IsDescendantOfEditorRoot(content)) {
+  if (!GetActiveEditingHost()) {
     return nullptr;
   }
-  return content;
+  return aNoBlockCrossing ? GetNextEditableNodeInBlock(aPoint) :
+                            GetNextEditableNode(aPoint);
 }
 
 bool
 HTMLEditor::IsFirstEditableChild(nsINode* aNode)
 {
   MOZ_ASSERT(aNode);
   // find first editable child and compare it to aNode
   nsCOMPtr<nsINode> parent = aNode->GetParentNode();
@@ -3978,17 +3959,17 @@ HTMLEditor::GetLastEditableChild(nsINode
   return child;
 }
 
 nsIContent*
 HTMLEditor::GetFirstEditableLeaf(nsINode& aNode)
 {
   nsCOMPtr<nsIContent> child = GetLeftmostChild(&aNode);
   while (child && (!IsEditable(child) || child->HasChildren())) {
-    child = GetNextHTMLNode(child);
+    child = GetNextEditableHTMLNode(*child);
 
     // Only accept nodes that are descendants of aNode
     if (!aNode.Contains(child)) {
       return nullptr;
     }
   }
 
   return child;
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -805,20 +805,53 @@ protected:
    * of above methods.  Please don't use this method directly.
    */
   nsIContent* GetPreviousEditableHTMLNodeInternal(nsINode& aNode,
                                                   bool aNoBlockCrossing);
   nsIContent* GetPreviousEditableHTMLNodeInternal(
                 const EditorRawDOMPoint& aPoint,
                 bool aNoBlockCrossing);
 
-  nsIContent* GetNextHTMLNode(nsINode* aNode, bool aNoBlockCrossing = false);
-  nsIContent* GetNextHTMLNode(nsINode* aParent, int32_t aOffset,
-                              nsINode* aChildAtOffset,
-                              bool aNoBlockCrossing = false);
+  /**
+   * GetNextEditableHTMLNode*() methods are similar to
+   * EditorBase::GetNextEditableNode() but this won't return nodes outside
+   * active editing host.
+   *
+   * Note that same as EditorBaseGetTextEditableNode(), methods which take
+   * |const EditorRawDOMPoint&| start to search from the node pointed by it.
+   * On the other hand, methods which take |nsINode&| start to search from
+   * next node of aNode.
+   */
+  nsIContent* GetNextEditableHTMLNode(nsINode& aNode)
+  {
+    return GetNextEditableHTMLNodeInternal(aNode, false);
+  }
+  nsIContent* GetNextEditableHTMLNodeInBlock(nsINode& aNode)
+  {
+    return GetNextEditableHTMLNodeInternal(aNode, true);
+  }
+  nsIContent* GetNextEditableHTMLNode(const EditorRawDOMPoint& aPoint)
+  {
+    return GetNextEditableHTMLNodeInternal(aPoint, false);
+  }
+  nsIContent* GetNextEditableHTMLNodeInBlock(
+                const EditorRawDOMPoint& aPoint)
+  {
+    return GetNextEditableHTMLNodeInternal(aPoint, true);
+  }
+
+  /**
+   * GetNextEditableHTMLNodeInternal() methods are common implementation
+   * of above methods.  Please don't use this method directly.
+   */
+  nsIContent* GetNextEditableHTMLNodeInternal(nsINode& aNode,
+                                                  bool aNoBlockCrossing);
+  nsIContent* GetNextEditableHTMLNodeInternal(
+                const EditorRawDOMPoint& aPoint,
+                bool aNoBlockCrossing);
 
   bool IsFirstEditableChild(nsINode* aNode);
   bool IsLastEditableChild(nsINode* aNode);
   nsIContent* GetFirstEditableChild(nsINode& aNode);
   nsIContent* GetLastEditableChild(nsINode& aNode);
 
   nsIContent* GetFirstEditableLeaf(nsINode& aNode);
   nsIContent* GetLastEditableLeaf(nsINode& aNode);