Bug 1460509 - part 54: Make HTMLEditRules::WillInsert() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 16 May 2018 14:21:21 +0900
changeset 798772 1e792c98bfdbc481c6b360a85bcdda6a6bcd6b5a
parent 798771 9c4903ab97c67f78c72047867a80401357646840
child 798773 a12b9cff5631dee020fa967a21ccbb1325c4790a
push id110840
push usermasayuki@d-toybox.com
push dateWed, 23 May 2018 13:41:58 +0000
reviewersm_kato
bugs1460509
milestone62.0a1
Bug 1460509 - part 54: Make HTMLEditRules::WillInsert() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato MozReview-Commit-ID: Mhim8mp1aw
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -714,19 +714,24 @@ HTMLEditRules::WillDoAction(Selection* a
       return WillAlign(*aInfo->alignType, aCancel, aHandled);
     case EditAction::makeBasicBlock:
       return WillMakeBasicBlock(*aInfo->blockType, aCancel, aHandled);
     case EditAction::removeList:
       return WillRemoveList(aInfo->bOrdered, aCancel, aHandled);
     case EditAction::makeDefListItem:
       return WillMakeDefListItem(aInfo->blockType,
                                  aInfo->entireList, aCancel, aHandled);
-    case EditAction::insertElement:
-      WillInsert(aCancel);
+    case EditAction::insertElement: {
+      nsresult rv = WillInsert(aCancel);
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
       return NS_OK;
+    }
     case EditAction::decreaseZIndex:
       return WillRelativeChangeZIndex(-1, aCancel, aHandled);
     case EditAction::increaseZIndex:
       return WillRelativeChangeZIndex(1, aCancel, aHandled);
     default:
       return TextEditRules::WillDoAction(&SelectionRef(), aInfo,
                                          aCancel, aHandled);
   }
@@ -1342,83 +1347,87 @@ HTMLEditRules::GetFormatString(nsINode* 
   if (HTMLEditUtils::IsFormatNode(aNode)) {
     aNode->NodeInfo()->NameAtom()->ToString(outFormat);
   } else {
     outFormat.Truncate();
   }
   return NS_OK;
 }
 
-void
+nsresult
 HTMLEditRules::WillInsert(bool* aCancel)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
-  MOZ_ASSERT(aCancel);
 
   nsresult rv = TextEditRules::WillInsert(aCancel);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
+    return rv;
   }
 
   // Adjust selection to prevent insertion after a moz-BR.  This next only
   // works for collapsed selections right now, because selection is a pain to
   // work with when not collapsed.  (no good way to extend start or end of
   // selection), so we ignore those types of selections.
   if (!SelectionRef().IsCollapsed()) {
-    return;
+    return NS_OK;
   }
 
   // If we are after a mozBR in the same block, then move selection to be
   // before it
   nsRange* firstRange = SelectionRef().GetRangeAt(0);
   if (NS_WARN_IF(!firstRange)) {
-    return;
+    return NS_ERROR_FAILURE;
   }
 
   EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
   if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
-    return;
+    return NS_ERROR_FAILURE;
   }
   MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
 
   // Get prior node
   nsCOMPtr<nsIContent> priorNode =
     HTMLEditorRef().GetPreviousEditableHTMLNode(atStartOfSelection);
   if (priorNode && TextEditUtils::IsMozBR(priorNode)) {
     RefPtr<Element> block1 =
       HTMLEditorRef().GetBlock(*atStartOfSelection.GetContainer());
     RefPtr<Element> block2 = HTMLEditorRef().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.
       EditorRawDOMPoint point(priorNode);
-      IgnoredErrorResult error;
+      ErrorResult error;
       SelectionRef().Collapse(point, error);
+      if (NS_WARN_IF(!CanHandleEditAction())) {
+        error.SuppressException();
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
       if (NS_WARN_IF(error.Failed())) {
-        return;
+        return error.StealNSResult();
       }
     }
   }
 
   if (mDidDeleteSelection &&
       (mTheAction == EditAction::insertText ||
        mTheAction == EditAction::insertIMEText ||
        mTheAction == EditAction::deleteSelection)) {
     nsresult rv = ReapplyCachedStyles();
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      return;
+      return rv;
     }
   }
   // For most actions we want to clear the cached styles, but there are
   // exceptions
   if (!IsStyleCachePreservingAction(mTheAction)) {
     ClearCachedStyles();
   }
+  return NS_OK;
 }
 
 nsresult
 HTMLEditRules::WillInsertText(EditAction aAction,
                               bool* aCancel,
                               bool* aHandled,
                               const nsAString* inString,
                               nsAString* outString,
@@ -1443,29 +1452,31 @@ HTMLEditRules::WillInsertText(EditAction
     if (NS_WARN_IF(!CanHandleEditAction())) {
       return NS_ERROR_EDITOR_DESTROYED;
     }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  WillInsert(aCancel);
-  // initialize out param
-  // we want to ignore result of WillInsert()
-  *aCancel = false;
+  // FYI: Ignore cancel result of WillInsert().
+  nsresult rv = WillInsert();
+  if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
 
   // we need to get the doc
   nsCOMPtr<nsIDocument> doc = HTMLEditorRef().GetDocument();
   if (NS_WARN_IF(!doc)) {
     return NS_ERROR_FAILURE;
   }
 
   // for every property that is set, insert a new inline style node
-  nsresult rv = CreateStyleForInsertText(*doc);
+  rv = CreateStyleForInsertText(*doc);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // get the (collapsed) selection location
   nsRange* firstRange = SelectionRef().GetRangeAt(0);
   if (NS_WARN_IF(!firstRange)) {
     return NS_ERROR_FAILURE;
@@ -1798,20 +1809,22 @@ HTMLEditRules::WillInsertBreak(bool* aCa
     if (NS_WARN_IF(!CanHandleEditAction())) {
       return NS_ERROR_EDITOR_DESTROYED;
     }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  WillInsert(aCancel);
-
-  // Initialize out param.  We want to ignore result of WillInsert().
-  *aCancel = false;
+  // FYI: Ignore cancel result of WillInsert().
+  nsresult rv = WillInsert();
+  if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
 
   // Split any mailcites in the way.  Should we abort this if we encounter
   // table cell boundaries?
   if (IsMailEditor()) {
     nsresult rv = SplitMailCites(aHandled);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
@@ -2016,17 +2029,17 @@ HTMLEditRules::WillInsertBreak(bool* aCa
     // Fall through, if ReturnInParagraph() didn't handle it.
     MOZ_ASSERT(!*aCancel, "ReturnInParagraph canceled this edit action, "
                           "WillInsertBreak() needs to handle such case");
   }
 
   // If nobody handles this edit action, let's insert new <br> at the selection.
   MOZ_ASSERT(!*aHandled, "Reached last resort of WillInsertBreak() "
                          "after the edit action is handled");
-  nsresult rv = InsertBRElement(atStartOfSelection);
+  rv = InsertBRElement(atStartOfSelection);
   *aHandled = true;
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
 nsresult
@@ -3832,25 +3845,28 @@ HTMLEditRules::WillMakeList(const nsAStr
                             const nsAString* aItemType)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   if (NS_WARN_IF(!aListType) || NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  OwningNonNull<nsAtom> listType = NS_Atomize(*aListType);
-
-  WillInsert(aCancel);
-
-  // initialize out param
-  // we want to ignore result of WillInsert()
   *aCancel = false;
   *aHandled = false;
 
+  OwningNonNull<nsAtom> listType = NS_Atomize(*aListType);
+
+  // FYI: Ignore cancel result of WillInsert().
+  nsresult rv = WillInsert();
+  if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+
   // deduce what tag to use for list items
   RefPtr<nsAtom> itemType;
   if (aItemType) {
     itemType = NS_Atomize(*aItemType);
   } else if (listType == nsGkAtoms::dl) {
     itemType = nsGkAtoms::dd;
   } else {
     itemType = nsGkAtoms::li;
@@ -3858,17 +3874,17 @@ HTMLEditRules::WillMakeList(const nsAStr
 
   // convert the selection ranges into "promoted" selection ranges:
   // this basically just expands the range to include the immediate
   // block parent, and then further expands to include any ancestors
   // whose children are all in the range
 
   *aHandled = true;
 
-  nsresult rv = NormalizeSelection();
+  rv = NormalizeSelection();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   AutoSelectionRestorer selectionRestorer(&SelectionRef(), &HTMLEditorRef());
 
   nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
   rv = GetListActionNodes(arrayOfNodes,
@@ -4282,22 +4298,27 @@ HTMLEditRules::WillMakeBasicBlock(const 
                                   bool* aCancel,
                                   bool* aHandled)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
   MOZ_ASSERT(aCancel && aHandled);
 
   OwningNonNull<nsAtom> blockType = NS_Atomize(aBlockType);
 
-  WillInsert(aCancel);
-  // We want to ignore result of WillInsert()
+  // FYI: Ignore cancel result of WillInsert().
+  nsresult rv = WillInsert();
+  if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+
   *aCancel = false;
   *aHandled = true;
 
-  nsresult rv = MakeBasicBlock(blockType);
+  rv = MakeBasicBlock(blockType);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
 nsresult
 HTMLEditRules::MakeBasicBlock(nsAtom& blockType)
@@ -4498,24 +4519,27 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
                              bool* aHandled)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   if (NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  WillInsert(aCancel);
-
-  // initialize out param
-  // we want to ignore result of WillInsert()
+  // FYI: Ignore cancel result of WillInsert().
+  nsresult rv = WillInsert();
+  if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+
   *aCancel = false;
   *aHandled = true;
 
-  nsresult rv = NormalizeSelection();
+  rv = NormalizeSelection();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   AutoSelectionRestorer selectionRestorer(&SelectionRef(), &HTMLEditorRef());
   nsTArray<OwningNonNull<nsRange>> arrayOfRanges;
   nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
 
   // short circuit: detect case of collapsed selection inside an <li>.
@@ -4748,24 +4772,27 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
                               bool* aHandled)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   if (NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  WillInsert(aCancel);
-
-  // initialize out param
-  // we want to ignore result of WillInsert()
+  // FYI: Ignore cancel result of WillInsert().
+  nsresult rv = WillInsert();
+  if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+
   *aCancel = false;
   *aHandled = true;
 
-  nsresult rv = NormalizeSelection();
+  rv = NormalizeSelection();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   AutoSelectionRestorer selectionRestorer(&SelectionRef(), &HTMLEditorRef());
 
   // convert the selection ranges into "promoted" selection ranges:
   // this basically just expands the range to include the immediate
@@ -5619,23 +5646,27 @@ HTMLEditRules::IsEmptyBlockElement(Eleme
 nsresult
 HTMLEditRules::WillAlign(const nsAString& aAlignType,
                          bool* aCancel,
                          bool* aHandled)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
   MOZ_ASSERT(aCancel && aHandled);
 
-  WillInsert(aCancel);
-
-  // Initialize out param.  We want to ignore result of WillInsert().
   *aCancel = false;
   *aHandled = false;
 
-  nsresult rv = NormalizeSelection();
+  // FYI: Ignore cancel result of WillInsert().
+  nsresult rv = WillInsert();
+  if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+
+  rv = NormalizeSelection();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   AutoSelectionRestorer selectionRestorer(&SelectionRef(), &HTMLEditorRef());
 
   // Convert the selection ranges into "promoted" selection ranges: This
   // basically just expands the range to include the immediate block parent,
   // and then further expands to include any ancestors whose children are all
@@ -10463,29 +10494,33 @@ HTMLEditRules::ChangeMarginStart(Element
 
 nsresult
 HTMLEditRules::WillAbsolutePosition(bool* aCancel,
                                     bool* aHandled)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
   MOZ_ASSERT(aCancel && aHandled);
 
-  WillInsert(aCancel);
-
-  // We want to ignore result of WillInsert()
+  // FYI: Ignore cancel result of WillInsert().
+  nsresult rv = WillInsert();
+  if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+
   *aCancel = false;
   *aHandled = true;
 
   RefPtr<Element> focusElement = HTMLEditorRef().GetSelectionContainer();
   if (focusElement && HTMLEditUtils::IsImage(focusElement)) {
     mNewBlock = focusElement;
     return NS_OK;
   }
 
-  nsresult rv = NormalizeSelection();
+  rv = NormalizeSelection();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = PrepareToMakeElementAbsolutePosition(aHandled, address_of(mNewBlock));
   // PrepareToMakeElementAbsolutePosition() may restore selection with
   // AutoSelectionRestorer.  Therefore, the editor might have already been
   // destroyed now.
@@ -10791,20 +10826,23 @@ HTMLEditRules::WillRemoveAbsolutePositio
                                           bool* aHandled)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   if (NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  WillInsert(aCancel);
-
-  // initialize out param
-  // we want to ignore aCancel from WillInsert()
+  // FYI: Ignore cancel result of WillInsert().
+  nsresult rv = WillInsert();
+  if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+
   *aCancel = false;
   *aHandled = true;
 
   RefPtr<Element> element =
     HTMLEditorRef().GetAbsolutelyPositionedSelectionContainer();
   if (NS_WARN_IF(!element)) {
     return NS_ERROR_FAILURE;
   }
@@ -10834,20 +10872,23 @@ HTMLEditRules::WillRelativeChangeZIndex(
                                         bool* aHandled)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   if (NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  WillInsert(aCancel);
-
-  // initialize out param
-  // we want to ignore aCancel from WillInsert()
+  // FYI: Ignore cancel result of WillInsert().
+  nsresult rv = WillInsert();
+  if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+
   *aCancel = false;
   *aHandled = true;
 
   RefPtr<Element> element =
     HTMLEditorRef().GetAbsolutelyPositionedSelectionContainer();
   if (NS_WARN_IF(!element)) {
     return NS_ERROR_FAILURE;
   }
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -145,17 +145,25 @@ protected:
   enum RulesEndpoint
   {
     kStart,
     kEnd
   };
 
   void InitFields();
 
-  void WillInsert(bool* aCancel);
+  /**
+   * Called before inserting something into the editor.
+   * This method may removes mBougsNode if there is.  Therefore, this method
+   * might cause destroying the editor.
+   *
+   * @param aCancel             Returns true if the operation is canceled.
+   *                            This can be nullptr.
+   */
+  MOZ_MUST_USE nsresult WillInsert(bool* aCancel = nullptr);
 
   /**
    * Called before inserting text.
    * This method may actually inserts text into the editor.  Therefore, this
    * might cause destroying the editor.
    *
    * @param aAction             Must be EditAction::insertIMEText or
    *                            EditAction::insertText.