Bug 1460509 - part 41: Make HTMLEditRules::ReturnInHeader() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 15 May 2018 16:36:53 +0900
changeset 798759 188287c29177ed4e25ea5a5cd02348ff85941172
parent 798758 b9ab6125007ace745d804062c150d8a001567960
child 798760 da8dc60eeb184fe4d0abcefafddf748ac525b6b1
push id110840
push usermasayuki@d-toybox.com
push dateWed, 23 May 2018 13:41:58 +0000
reviewersm_kato
bugs1460509
milestone62.0a1
Bug 1460509 - part 41: Make HTMLEditRules::ReturnInHeader() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato MozReview-Commit-ID: r03QSPXsZ2
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1942,18 +1942,24 @@ HTMLEditRules::WillInsertBreak(bool* aCa
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
       "Failed to insert break into list item");
     *aHandled = true;
     return NS_OK;
   }
 
   if (HTMLEditUtils::IsHeader(*blockParent)) {
     // Headers: close (or split) header
-    ReturnInHeader(*blockParent, *atStartOfSelection.GetContainer(),
-                   atStartOfSelection.Offset());
+    nsresult rv =
+      ReturnInHeader(*blockParent, *atStartOfSelection.GetContainer(),
+                     atStartOfSelection.Offset());
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+      "Failed to handle insertParagraph in the heading element");
     *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
@@ -7365,48 +7371,50 @@ HTMLEditRules::IsInListItem(nsINode* aNo
 nsAtom&
 HTMLEditRules::DefaultParagraphSeparator()
 {
   MOZ_ASSERT(IsEditorDataAvailable());
   return ParagraphSeparatorElement(
            HTMLEditorRef().GetDefaultParagraphSeparator());
 }
 
-/**
- * ReturnInHeader: do the right thing for returns pressed in headers
- */
 nsresult
 HTMLEditRules::ReturnInHeader(Element& aHeader,
                               nsINode& aNode,
                               int32_t aOffset)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   // Remember where the header is
   nsCOMPtr<nsINode> headerParent = aHeader.GetParentNode();
   int32_t offset = headerParent ? headerParent->ComputeIndexOf(&aHeader) : -1;
 
   // Get ws code to adjust any ws
   nsCOMPtr<nsINode> node = &aNode;
   nsresult rv = WSRunObject::PrepareToSplitAcrossBlocks(&HTMLEditorRef(),
                                                         address_of(node),
                                                         &aOffset);
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   if (NS_WARN_IF(!node->IsContent())) {
     return NS_ERROR_FAILURE;
   }
 
   // Split the header
-  ErrorResult error;
   SplitNodeResult splitHeaderResult =
     HTMLEditorRef().SplitNodeDeepWithTransaction(
                       aHeader, EditorRawDOMPoint(node, aOffset),
                       SplitAtEdges::eAllowToCreateEmptyContainer);
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
   NS_WARNING_ASSERTION(splitHeaderResult.Succeeded(),
     "Failed to split aHeader");
 
   // If the previous heading of split point is empty, put a mozbr into it.
   nsCOMPtr<nsIContent> prevItem = HTMLEditorRef().GetPriorHTMLSibling(&aHeader);
   if (prevItem) {
     MOZ_DIAGNOSTIC_ASSERT(
       HTMLEditUtils::IsHeader(*prevItem));
@@ -7422,16 +7430,19 @@ HTMLEditRules::ReturnInHeader(Element& a
         return createMozBrResult.Rv();
       }
     }
   }
 
   // If the new (righthand) header node is empty, delete it
   if (IsEmptyBlockElement(aHeader, IgnoreSingleBR::eYes)) {
     rv = HTMLEditorRef().DeleteNodeWithTransaction(aHeader);
+    if (NS_WARN_IF(!CanHandleEditAction())) {
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     // Layout tells the caret to blink in a weird place if we don't place a
     // break after the header.
     nsCOMPtr<nsIContent> sibling;
     if (aHeader.GetNextSibling()) {
       sibling = HTMLEditorRef().GetNextHTMLSibling(aHeader.GetNextSibling());
@@ -7443,50 +7454,68 @@ HTMLEditRules::ReturnInHeader(Element& a
       // Create a paragraph
       nsAtom& paraAtom = DefaultParagraphSeparator();
       // We want a wrapper element even if we separate with <br>
       EditorRawDOMPoint nextToHeader(headerParent, offset + 1);
       RefPtr<Element> pNode =
         HTMLEditorRef().CreateNodeWithTransaction(&paraAtom == nsGkAtoms::br ?
                                                     *nsGkAtoms::p : paraAtom,
                                                   nextToHeader);
+      if (NS_WARN_IF(!CanHandleEditAction())) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
       if (NS_WARN_IF(!pNode)) {
         return NS_ERROR_FAILURE;
       }
 
       // Append a <br> to it
       RefPtr<Element> brElement =
         HTMLEditorRef().InsertBrElementWithTransaction(
                           SelectionRef(), EditorRawDOMPoint(pNode, 0));
+      if (NS_WARN_IF(!CanHandleEditAction())) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
       if (NS_WARN_IF(!brElement)) {
         return NS_ERROR_FAILURE;
       }
 
       // Set selection to before the break
       ErrorResult error;
       SelectionRef().Collapse(EditorRawDOMPoint(pNode, 0), error);
+      if (NS_WARN_IF(!CanHandleEditAction())) {
+        error.SuppressException();
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
       if (NS_WARN_IF(error.Failed())) {
         return error.StealNSResult();
       }
     } else {
       EditorRawDOMPoint afterSibling(sibling);
       if (NS_WARN_IF(!afterSibling.AdvanceOffset())) {
         return NS_ERROR_FAILURE;
       }
       // Put selection after break
       ErrorResult error;
       SelectionRef().Collapse(afterSibling, error);
+      if (NS_WARN_IF(!CanHandleEditAction())) {
+        error.SuppressException();
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
       if (NS_WARN_IF(error.Failed())) {
         return error.StealNSResult();
       }
     }
   } else {
     // Put selection at front of righthand heading
     ErrorResult error;
     SelectionRef().Collapse(RawRangeBoundary(&aHeader, 0), error);
+    if (NS_WARN_IF(!CanHandleEditAction())) {
+      error.SuppressException();
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
     if (NS_WARN_IF(error.Failed())) {
       return error.StealNSResult();
     }
   }
   return NS_OK;
 }
 
 EditActionResult
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -364,17 +364,32 @@ protected:
   enum class Lists { no, yes };
   enum class Tables { no, yes };
   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(Element& aHeader, nsINode& aNode, int32_t aOffset);
+
+  /**
+   * ReturnInHeader() handles insertParagraph command (i.e., handling Enter
+   * key press) in a heading element.  This splits aHeader element at
+   * aOffset in aNode.  Then, if right heading element is empty, it'll be
+   * removed and new paragraph is created (its type is decided with default
+   * paragraph separator).
+   *
+   * @param aHeader             The heading element to be split.
+   * @param aNode               Typically, Selection start container,
+   *                            where to be split.
+   * @param aOffset             Typically, Selection start offset in the
+   *                            start container, where to be split.
+   */
+  MOZ_MUST_USE nsresult
+  ReturnInHeader(Element& aHeader, nsINode& aNode, int32_t aOffset);
 
   /**
    * ReturnInParagraph() does the right thing for Enter key press or
    * 'insertParagraph' command in aParentDivOrP.  aParentDivOrP will be
    * split at start of first selection range.
    *
    * @param aParentDivOrP   The parent block.  This must be <p> or <div>
    *                        element.