Bug 1416099 - part 6: Make HTMLEditRules::WillInsertBreak() use EditorDOMPoint to store selection start r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 10 Nov 2017 16:10:06 +0900
changeset 696349 6833cc15b6ef1a09d4d714cc3c895c7e165a5b3f
parent 696348 2ebb0c26cf54f6f00942ba1b3f12b1a1e7f501ed
child 696350 077e6ce55ee26d1335493a119acea14911e0552c
push id88684
push usermasayuki@d-toybox.com
push dateFri, 10 Nov 2017 13:42:43 +0000
reviewersm_kato
bugs1416099
milestone58.0a1
Bug 1416099 - part 6: Make HTMLEditRules::WillInsertBreak() use EditorDOMPoint to store selection start r?m_kato The only caller of HTMLEditRules::ReturnInParagraph() is HTMLEditRules::WillInsertBreak(). It should use EditorDOMPoint for storing selection start. Then, this patch makes what is set to ReturnInParagraph() clear. So, the point ReturnInParagraph() is always start of selection. MozReview-Commit-ID: 6X0P5gpwXKr
editor/libeditor/EditorDOMPoint.h
editor/libeditor/HTMLEditRules.cpp
--- a/editor/libeditor/EditorDOMPoint.h
+++ b/editor/libeditor/EditorDOMPoint.h
@@ -92,16 +92,23 @@ public:
 
   template<typename A, typename B>
   EditorDOMPointBase& operator=(const EditorDOMPointBase<A, B>& aOther)
   {
     RangeBoundaryBase<ParentType, RefType>::operator=(aOther);
     return *this;
   }
 
+  template<typename A, typename B>
+  EditorDOMPointBase& operator=(const RangeBoundaryBase<A, B>& aOther)
+  {
+    RangeBoundaryBase<ParentType, RefType>::operator=(aOther);
+    return *this;
+  }
+
 private:
   static nsIContent* GetRef(nsINode* aContainerNode, nsIContent* aPointedNode)
   {
     // If referring one of a child of the container, the 'ref' should be the
     // previous sibling of the referring child.
     if (aPointedNode) {
       return aPointedNode->GetPreviousSibling();
     }
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1646,41 +1646,46 @@ HTMLEditRules::WillInsertBreak(Selection
     nsresult rv = SplitMailCites(&aSelection, aHandled);
     NS_ENSURE_SUCCESS(rv, rv);
     if (*aHandled) {
       return NS_OK;
     }
   }
 
   // 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();
+  nsRange* firstRange = aSelection.GetRangeAt(0);
+  if (NS_WARN_IF(!firstRange)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  EditorDOMPoint atStartOfSelection(firstRange->StartRef());
+  if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
+    return NS_ERROR_FAILURE;
+  }
+  MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
 
   // Do nothing if the node is read-only
-  if (!htmlEditor->IsModifiableNode(node)) {
+  if (!htmlEditor->IsModifiableNode(atStartOfSelection.Container())) {
     *aCancel = true;
     return NS_OK;
   }
 
   // If the active editing host is an inline element, or if the active editing
   // host is the block parent itself and we're configured to use <br> as a
   // paragraph separator, just append a <br>.
   nsCOMPtr<Element> host = htmlEditor->GetActiveEditingHost();
   if (NS_WARN_IF(!host)) {
     return NS_ERROR_FAILURE;
   }
 
   // Look for the nearest parent block.  However, don't return error even if
   // there is no block parent here because in such case, i.e., editing host
   // is an inline element, we should insert <br> simply.
-  RefPtr<Element> blockParent = HTMLEditor::GetBlock(node, host);
+  RefPtr<Element> blockParent =
+    HTMLEditor::GetBlock(*atStartOfSelection.Container(), host);
 
   ParagraphSeparator separator = htmlEditor->GetDefaultParagraphSeparator();
   bool insertBRElement;
   // If there is no block parent in the editing host, i.e., the editing host
   // itself is also a non-block element, we should insert a <br> element.
   if (!blockParent) {
     // XXX Chromium checks if the CSS box of the editing host is block.
     insertBRElement = true;
@@ -1707,49 +1712,53 @@ HTMLEditRules::WillInsertBreak(Selection
          blockAncestor = HTMLEditor::GetBlockNodeParent(blockAncestor, host)) {
       insertBRElement = !CanContainParagraph(*blockAncestor);
     }
   }
 
   // If we cannot insert a <p>/<div> element at the selection, we should insert
   // a <br> element instead.
   if (insertBRElement) {
-    nsresult rv = StandardBreakImpl(node, offset, aSelection);
+    nsresult rv = StandardBreakImpl(*atStartOfSelection.Container(),
+                                    atStartOfSelection.Offset(), aSelection);
     NS_ENSURE_SUCCESS(rv, rv);
     *aHandled = true;
     return NS_OK;
   }
 
   if (host == blockParent && separator != ParagraphSeparator::br) {
     // Insert a new block first
     MOZ_ASSERT(separator == ParagraphSeparator::div ||
                separator == ParagraphSeparator::p);
     nsresult rv = MakeBasicBlock(aSelection,
                                  ParagraphSeparatorElement(separator));
     // We warn on failure, but don't handle it, because it might be harmless.
     // Instead we just check that a new block was actually created.
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "HTMLEditRules::MakeBasicBlock() failed");
 
-    // Reinitialize node/offset in case they're not inside the new block
-    if (NS_WARN_IF(!aSelection.GetRangeAt(0) ||
-                   !aSelection.GetRangeAt(0)->GetStartContainer())) {
+    firstRange = aSelection.GetRangeAt(0);
+    if (NS_WARN_IF(!firstRange)) {
       return NS_ERROR_FAILURE;
     }
-    node = *aSelection.GetRangeAt(0)->GetStartContainer();
-    child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
-    offset = aSelection.GetRangeAt(0)->StartOffset();
-
-    blockParent = mHTMLEditor->GetBlock(node, host);
+
+    atStartOfSelection = firstRange->StartRef();
+    if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
+      return NS_ERROR_FAILURE;
+    }
+    MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
+
+    blockParent = mHTMLEditor->GetBlock(*atStartOfSelection.Container(), host);
     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>
-      rv = StandardBreakImpl(node, offset, aSelection);
+      rv = StandardBreakImpl(*atStartOfSelection.Container(),
+                             atStartOfSelection.Offset(), aSelection);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       *aHandled = true;
       return NS_OK;
     }
   }
 
@@ -1762,51 +1771,60 @@ HTMLEditRules::WillInsertBreak(Selection
   if (isEmpty) {
     nsCOMPtr<Element> br = htmlEditor->CreateBR(blockParent,
                                                 blockParent->Length());
     NS_ENSURE_STATE(br);
   }
 
   nsCOMPtr<Element> listItem = IsInListItem(blockParent);
   if (listItem && listItem != host) {
-    ReturnInListItem(aSelection, *listItem, node, offset);
+    ReturnInListItem(aSelection, *listItem, *atStartOfSelection.Container(),
+                     atStartOfSelection.Offset());
     *aHandled = true;
     return NS_OK;
-  } else if (HTMLEditUtils::IsHeader(*blockParent)) {
+  }
+
+  if (HTMLEditUtils::IsHeader(*blockParent)) {
     // Headers: close (or split) header
-    ReturnInHeader(aSelection, *blockParent, node, offset);
+    ReturnInHeader(aSelection, *blockParent, *atStartOfSelection.Container(),
+                   atStartOfSelection.Offset());
     *aHandled = true;
     return NS_OK;
   }
+
   // XXX Ideally, we should take same behavior with both <p> container and
   //     <div> container.  However, we are still using <br> as default
   //     paragraph separator (non-standard) and we've split only <p> container
   //     long time.  Therefore, some web apps may depend on this behavior like
   //     Gmail.  So, let's use traditional odd behavior only when the default
   //     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))) {
+  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
     EditActionResult result =
-      ReturnInParagraph(aSelection, *blockParent, node, offset, child);
+      ReturnInParagraph(aSelection, *blockParent,
+                        atStartOfSelection.Container(),
+                        atStartOfSelection.Offset(),
+                        atStartOfSelection.GetChildAtOffset());
     if (NS_WARN_IF(result.Failed())) {
       return result.Rv();
     }
     *aHandled = result.Handled();
     *aCancel = result.Canceled();
     // 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);
+    return StandardBreakImpl(*atStartOfSelection.Container(),
+                             atStartOfSelection.Offset(), aSelection);
   }
   return NS_OK;
 }
 
 nsresult
 HTMLEditRules::StandardBreakImpl(nsINode& aNode,
                                  int32_t aOffset,
                                  Selection& aSelection)