Bug 1460509 - part 66: Make HTMLEditRules::WillCSSIndent() 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:27:35 +0900
changeset 798784 2179a856265febf7b51b8cd6c56ba1731003ea33
parent 798783 5fd52aa507ec628eddc0e1cb53ee2d3e42dbedaf
child 798785 e3cac1b7ff6fee7af79e288a9e5cfa82f2eeb0b8
push id110840
push usermasayuki@d-toybox.com
push dateWed, 23 May 2018 13:41:58 +0000
reviewersm_kato
bugs1460509
milestone62.0a1
Bug 1460509 - part 66: Make HTMLEditRules::WillCSSIndent() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato MozReview-Commit-ID: nnnC5VDpk8
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -4547,16 +4547,35 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
 
   *aCancel = false;
   *aHandled = true;
 
   rv = NormalizeSelection();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
+
+  // IndentAroundSelectionWithCSS() creates AutoSelectionRestorer.
+  // Therefore, even if it returns NS_OK, editor might have been destroyed
+  // at restoring Selection.
+  rv = IndentAroundSelectionWithCSS();
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
+nsresult
+HTMLEditRules::IndentAroundSelectionWithCSS()
+{
+  MOZ_ASSERT(IsEditorDataAvailable());
+
   AutoSelectionRestorer selectionRestorer(&SelectionRef(), &HTMLEditorRef());
   nsTArray<OwningNonNull<nsRange>> arrayOfRanges;
   nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
 
   // short circuit: detect case of collapsed selection inside an <li>.
   // just sublist that <li>.  This prevents bug 97797.
 
   nsCOMPtr<Element> liNode;
@@ -4575,18 +4594,19 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
 
   if (liNode) {
     arrayOfNodes.AppendElement(*liNode);
   } else {
     // 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
-    rv = GetNodesFromSelection(EditAction::indent, arrayOfNodes,
-                               TouchContent::yes);
+    nsresult rv =
+      GetNodesFromSelection(EditAction::indent, arrayOfNodes,
+                            TouchContent::yes);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // if nothing visible in list, make an empty block
   if (ListIsEmptyLine(arrayOfNodes)) {
     // get selection location
@@ -4605,42 +4625,51 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
       MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
                                                   atStartOfSelection);
     if (NS_WARN_IF(splitNodeResult.Failed())) {
       return splitNodeResult.Rv();
     }
     RefPtr<Element> theBlock =
       HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::div,
                                                 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;
     nsresult rv = IncreaseMarginToIndent(*theBlock);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return NS_ERROR_EDITOR_DESTROYED;
     }
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to increase indentation");
     // 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!
@@ -4664,36 +4693,44 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
       // We do this if the next element is a list, and the list is of the
       // same type (li/ol) as curNode was a part it.
       sibling = HTMLEditorRef().GetNextHTMLSibling(curNode);
       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));
+        nsresult 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
       // the same type (li/ol) as curNode was a part of.
       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);
+        nsresult 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.
@@ -4710,26 +4747,33 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
           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);
+      nsresult 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;
       }
       continue;
     }
 
     // Not a list item.
 
@@ -4753,32 +4797,39 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
       SplitNodeResult splitNodeResult =
         MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div, atCurNode);
       if (NS_WARN_IF(splitNodeResult.Failed())) {
         return splitNodeResult.Rv();
       }
       curQuote =
         HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::div,
                                                   splitNodeResult.SplitPoint());
+      if (NS_WARN_IF(!CanHandleEditAction())) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
       if (NS_WARN_IF(!curQuote)) {
         return NS_ERROR_FAILURE;
       }
       nsresult rv = IncreaseMarginToIndent(*curQuote);
       if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to increase indentation");
       // 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);
+    nsresult 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;
     }
   }
   return NS_OK;
 }
 
 nsresult
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -323,17 +323,25 @@ protected:
   nsresult DeleteNonTableElements(nsINode* aNode);
   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);
+
+  /**
+   * Called before indenting around Selection and it's 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 WillCSSIndent(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.
    */
@@ -541,16 +549,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);
 
   /**
+   * IndentAroundSelectionWithCSS() indents around Selection with CSS.
+   * 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 IndentAroundSelectionWithCSS();
+
+  /**
    * 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();
 
   /**