Bug 1460509 - part 65: Make HTMLEditRules::WillHTMLIndent() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 17 May 2018 18:14:01 +0900
changeset 798783 5fd52aa507ec628eddc0e1cb53ee2d3e42dbedaf
parent 798782 fd141fa5b3cb8ef9c821b0daac382a3770278797
child 798784 2179a856265febf7b51b8cd6c56ba1731003ea33
push id110840
push usermasayuki@d-toybox.com
push dateWed, 23 May 2018 13:41:58 +0000
reviewersm_kato
bugs1460509
milestone62.0a1
Bug 1460509 - part 65: Make HTMLEditRules::WillHTMLIndent() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato MozReview-Commit-ID: 2jZh8GtC7BA
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -4801,30 +4801,49 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
   *aCancel = false;
   *aHandled = true;
 
   rv = NormalizeSelection();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  // IndentAroundSelectionWithHTML() creates AutoSelectionRestorer.
+  // Therefore, even if it returns NS_OK, editor might have been destroyed
+  // at restoring Selection.
+  rv = IndentAroundSelectionWithHTML();
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
+nsresult
+HTMLEditRules::IndentAroundSelectionWithHTML()
+{
+  MOZ_ASSERT(IsEditorDataAvailable());
+
   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 in the range
 
   nsTArray<RefPtr<nsRange>> arrayOfRanges;
   GetPromotedRanges(arrayOfRanges, EditAction::indent);
 
   // use these ranges to contruct a list of nodes to act on.
   nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
-  rv = GetNodesForOperation(arrayOfRanges, arrayOfNodes, EditAction::indent,
-                            TouchContent::yes);
+  nsresult rv =
+    GetNodesForOperation(arrayOfRanges, arrayOfNodes, EditAction::indent,
+                         TouchContent::yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // if nothing visible in list, make an empty block
   if (ListIsEmptyLine(arrayOfNodes)) {
     nsRange* firstRange = SelectionRef().GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
@@ -4841,37 +4860,45 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
       MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::blockquote,
                                                   atStartOfSelection);
     if (NS_WARN_IF(splitNodeResult.Failed())) {
       return splitNodeResult.Rv();
     }
     RefPtr<Element> theBlock =
       HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::blockquote,
                                                 splitNodeResult.SplitPoint());
+    if (NS_WARN_IF(!CanHandleEditAction())) {
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
     if (NS_WARN_IF(!theBlock)) {
       return NS_ERROR_FAILURE;
     }
     // remember our new block for postprocessing
     mNewBlock = theBlock;
     // delete anything that was in the list of nodes
     while (!arrayOfNodes.IsEmpty()) {
       OwningNonNull<nsINode> curNode = arrayOfNodes[0];
       rv = HTMLEditorRef().DeleteNodeWithTransaction(*curNode);
+      if (NS_WARN_IF(!CanHandleEditAction())) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       arrayOfNodes.RemoveElementAt(0);
     }
-    // put selection in new block
-    *aHandled = true;
     EditorRawDOMPoint atStartOfTheBlock(theBlock, 0);
+    // Don't restore the selection
+    selectionRestorer.Abort();
     ErrorResult error;
     SelectionRef().Collapse(atStartOfTheBlock, error);
-    // Don't restore the selection
-    selectionRestorer.Abort();
+    if (NS_WARN_IF(!CanHandleEditAction())) {
+      error.SuppressException();
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
     if (NS_WARN_IF(!error.Failed())) {
       return error.StealNSResult();
     }
     return NS_OK;
   }
 
   // Ok, now go through all the nodes and put them in a blockquote,
   // or whatever is appropriate.  Wohoo!
@@ -4898,16 +4925,19 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
       if (sibling && HTMLEditUtils::IsList(sibling) &&
           atCurNode.GetContainer()->NodeInfo()->NameAtom() ==
             sibling->NodeInfo()->NameAtom() &&
           atCurNode.GetContainer()->NodeInfo()->NamespaceID() ==
             sibling->NodeInfo()->NamespaceID()) {
         rv = HTMLEditorRef().MoveNodeWithTransaction(
                                *curNode->AsContent(),
                                EditorRawDOMPoint(sibling, 0));
+        if (NS_WARN_IF(!CanHandleEditAction())) {
+          return NS_ERROR_EDITOR_DESTROYED;
+        }
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
         continue;
       }
 
       // Check for whether we should join a list that preceeds curNode.
       // We do this if the previous element is a list, and the list is of
@@ -4915,16 +4945,19 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
       sibling = HTMLEditorRef().GetPriorHTMLSibling(curNode);
       if (sibling && HTMLEditUtils::IsList(sibling) &&
           atCurNode.GetContainer()->NodeInfo()->NameAtom() ==
             sibling->NodeInfo()->NameAtom() &&
           atCurNode.GetContainer()->NodeInfo()->NamespaceID() ==
             sibling->NodeInfo()->NamespaceID()) {
         rv = HTMLEditorRef().MoveNodeToEndWithTransaction(*curNode->AsContent(),
                                                           *sibling);
+        if (NS_WARN_IF(!CanHandleEditAction())) {
+          return NS_ERROR_EDITOR_DESTROYED;
+        }
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
         continue;
       }
 
       // check to see if curList is still appropriate.  Which it is if
       // curNode is still right after it in the same list.
@@ -4941,26 +4974,32 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
           MaybeSplitAncestorsForInsertWithTransaction(*containerName,
                                                       atCurNode);
         if (NS_WARN_IF(splitNodeResult.Failed())) {
           return splitNodeResult.Rv();
         }
         curList =
           HTMLEditorRef().CreateNodeWithTransaction(
                             *containerName, splitNodeResult.SplitPoint());
+        if (NS_WARN_IF(!CanHandleEditAction())) {
+          return NS_ERROR_EDITOR_DESTROYED;
+        }
         if (NS_WARN_IF(!curList)) {
           return NS_ERROR_FAILURE;
         }
         // curList is now the correct thing to put curNode in
         // remember our new block for postprocessing
         mNewBlock = curList;
       }
       // tuck the node into the end of the active list
       rv = HTMLEditorRef().MoveNodeToEndWithTransaction(*curNode->AsContent(),
                                                         *curList);
+      if (NS_WARN_IF(!CanHandleEditAction())) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       // forget curQuote, if any
       curQuote = nullptr;
 
       continue;
     }
@@ -4997,22 +5036,28 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
           MaybeSplitAncestorsForInsertWithTransaction(*containerName,
                                                       atListItem);
         if (NS_WARN_IF(splitNodeResult.Failed())) {
           return splitNodeResult.Rv();
         }
         curList =
           HTMLEditorRef().CreateNodeWithTransaction(
                             *containerName, splitNodeResult.SplitPoint());
+        if (NS_WARN_IF(!CanHandleEditAction())) {
+          return NS_ERROR_EDITOR_DESTROYED;
+        }
         if (NS_WARN_IF(!curList)) {
           return NS_ERROR_FAILURE;
         }
       }
 
       rv = HTMLEditorRef().MoveNodeToEndWithTransaction(*listItem, *curList);
+      if (NS_WARN_IF(!CanHandleEditAction())) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       // remember we indented this li
       indentedLI = listItem;
 
       continue;
@@ -5037,27 +5082,33 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
         MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::blockquote,
                                                     atCurNode);
       if (NS_WARN_IF(splitNodeResult.Failed())) {
         return splitNodeResult.Rv();
       }
       curQuote =
         HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::blockquote,
                                                   splitNodeResult.SplitPoint());
+      if (NS_WARN_IF(!CanHandleEditAction())) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
       if (NS_WARN_IF(!curQuote)) {
         return NS_ERROR_FAILURE;
       }
       // remember our new block for postprocessing
       mNewBlock = curQuote;
       // curQuote is now the correct thing to put curNode in
     }
 
     // tuck the node into the end of the active blockquote
     rv = HTMLEditorRef().MoveNodeToEndWithTransaction(*curNode->AsContent(),
                                                       *curQuote);
+    if (NS_WARN_IF(!CanHandleEditAction())) {
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     // forget curList, if any
     curList = nullptr;
   }
   return NS_OK;
 }
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -324,17 +324,25 @@ protected:
   nsresult WillMakeList(const nsAString* aListType,
                         bool aEntireList,
                         const nsAString* aBulletType,
                         bool* aCancel, bool* aHandled,
                         const nsAString* aItemType = nullptr);
   nsresult WillRemoveList(bool aOrdered, bool* aCancel, bool* aHandled);
   nsresult WillIndent(bool* aCancel, bool* aHandled);
   nsresult WillCSSIndent(bool* aCancel, bool* aHandled);
-  nsresult WillHTMLIndent(bool* aCancel, bool* aHandled);
+
+  /**
+   * Called before indenting around Selection and it's not in CSS mode.
+   * This method actually tries to indent the contents.
+   *
+   * @param aCancel             Returns true if the operation is canceled.
+   * @param aHandled            Returns true if the edit action is handled.
+   */
+  MOZ_MUST_USE nsresult WillHTMLIndent(bool* aCancel, bool* aHandled);
 
   /**
    * Called before outdenting around Selection.  This method actually tries
    * to indent the contents.
    *
    * @param aCancel             Returns true if the operation is canceled.
    * @param aHandled            Returns true if the edit action is handled.
    */
@@ -533,16 +541,24 @@ protected:
   /**
    * Called after handling edit action.  This may adjust Selection, remove
    * unnecessary empty nodes, create <br> elements if needed, etc.
    */
   MOZ_MUST_USE nsresult
   AfterEditInner(EditAction action, nsIEditor::EDirection aDirection);
 
   /**
+   * IndentAroundSelectionWithHTML() indents around Selection with HTML.
+   * This method creates AutoSelectionRestorer.  Therefore, each caller
+   * need to check if the editor is still available even if this returns
+   * NS_OK.
+   */
+  MOZ_MUST_USE nsresult IndentAroundSelectionWithHTML();
+
+  /**
    * OutdentAroundSelection() outdents contents around Selection.
    * This method creates AutoSelectionRestorer.  Therefore, each caller
    * need to check if the editor is still available even if this returns
    * NS_OK.
    *
    * @return                    The left content is left content of last
    *                            outdented element.
    *                            The right content is right content of last