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
--- 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);