Bug 1460509 - part 8: Make TextEditRules::WillDeleteSelection() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 11 May 2018 17:15:53 +0900
changeset 798726 9271e9273e1af33f91eb4b0d731d022883927f21
parent 798725 848da409dcf41cd4c3e4299565b6a4a07f44a5ed
child 798727 36e927743abd7e646870751ac4126c5edc1d7bc6
push id110840
push usermasayuki@d-toybox.com
push dateWed, 23 May 2018 13:41:58 +0000
reviewersm_kato
bugs1460509
milestone62.0a1
Bug 1460509 - part 8: Make TextEditRules::WillDeleteSelection() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato This patch creates internal method for it as DeleteSelectionWithTransaction() because it needs to create SelectionBatcher and destruction of it may cause destroying the editor. Therefore, unfortunately, all callers of DeleteSelectionWithTransaction() needs to check CanHandleEditAction() manually. If we could use try-catch, we could make it safer, though. MozReview-Commit-ID: 13enOQjEzNn
editor/libeditor/TextEditRules.cpp
editor/libeditor/TextEditRules.h
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -982,16 +982,38 @@ TextEditRules::WillDeleteSelection(nsIEd
   *aCancel = false;
   *aHandled = false;
 
   // if there is only bogus content, cancel the operation
   if (mBogusNode) {
     *aCancel = true;
     return NS_OK;
   }
+  nsresult rv =
+    DeleteSelectionWithTransaction(aCollapsedAction, aCancel, aHandled);
+  // DeleteSelectionWithTransaction() creates SelectionBatcher.  Therefore,
+  // quitting from it might cause having destroyed the editor.
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
+nsresult
+TextEditRules::DeleteSelectionWithTransaction(
+                 nsIEditor::EDirection aCollapsedAction,
+                 bool* aCancel,
+                 bool* aHandled)
+{
+  MOZ_ASSERT(IsEditorDataAvailable());
+  MOZ_ASSERT(aCancel);
+  MOZ_ASSERT(aHandled);
 
   // If the current selection is empty (e.g the user presses backspace with
   // a collapsed selection), then we want to avoid sending the selectstart
   // event to the user, so we hide selection changes. However, we still
   // want to send a single selectionchange event to the document, so we
   // batch the selectionchange events, such that a single event fires after
   // the AutoHideSelectionChanges destructor has been run.
   SelectionBatcher selectionBatcher(&SelectionRef());
@@ -1066,16 +1088,19 @@ TextEditRules::WillDeleteSelection(nsIEd
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   nsresult rv =
     TextEditorRef().DeleteSelectionWithTransaction(aCollapsedAction,
                                                    nsIEditor::eStrip);
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   *aHandled = true;
   ASSERT_PASSWORD_LENGTHS_EQUAL()
   return NS_OK;
 }
--- a/editor/libeditor/TextEditRules.h
+++ b/editor/libeditor/TextEditRules.h
@@ -141,19 +141,45 @@ protected:
 
   nsresult WillSetText(bool* aCancel,
                        bool* aHandled,
                        const nsAString* inString,
                        int32_t aMaxLength);
 
   void WillInsert(bool* aCancel);
 
-  nsresult WillDeleteSelection(nsIEditor::EDirection aCollapsedAction,
-                               bool* aCancel,
-                               bool* aHandled);
+  /**
+   * Called before deleting selected content.
+   * This method may actually remove the selected content with
+   * DeleteSelectionWithTransaction().  So, this might cause destroying the
+   * editor.
+   *
+   * @param aCaollapsedAction   Direction to extend the selection.
+   * @param aCancel             Returns true if the operation is canceled.
+   * @param aHandled            Returns true if the edit action is handled.
+   */
+  MOZ_MUST_USE nsresult
+  WillDeleteSelection(nsIEditor::EDirection aCollapsedAction,
+                      bool* aCancel, bool* aHandled);
+
+  /**
+   * DeleteSelectionWithTransaction() is internal method of
+   * WillDeleteSelection() since it needs to create SelectionBatcher in
+   * big scope and destroying it might causes destroying the editor.
+   * So, after calling this method, callers need to check CanHandleEditAction()
+   * manually.
+   *
+   * @param aCaollapsedAction   Direction to extend the selection.
+   * @param aCancel             Returns true if the operation is canceled.
+   * @param aHandled            Returns true if the edit action is handled.
+   */
+  MOZ_MUST_USE nsresult
+  DeleteSelectionWithTransaction(nsIEditor::EDirection aCollapsedAction,
+                                 bool* aCancel, bool* aHandled);
+
   /**
    * Called after deleted selected content.
    * This method may remove empty text node and makes guarantee that caret
    * is never at left of <br> element.
    */
   MOZ_MUST_USE nsresult DidDeleteSelection();
 
   nsresult WillSetTextProperty(bool* aCancel, bool* aHandled);