Bug 1546888 - Make editor public methods which may be canceled by clipboard event listener return NS_SUCCESS_DOM_NO_OPERATION when it's canceled r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 02 May 2019 08:39:53 +0000
changeset 531244 4e509c724417f6ed43df0f3a5a4f9dcefef5fd52
parent 531243 21a63a10a2a91311ea3817ff72c2c93e242afeeb
child 531245 f57c98fd52a63fa9b084763801bb7d34bfef3e2f
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1546888
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1546888 - Make editor public methods which may be canceled by clipboard event listener return NS_SUCCESS_DOM_NO_OPERATION when it's canceled r=m_kato This patch makes editors return new error code internally when clipboard event is dispatched and canceled by script. This is for making each caller stop handling the edit action. However, it's not actual failure. Therefore, making public methods return `NS_SUCCESS_DOM_NO_OPERATION` instead via `EditorBase::ToGenericNSResult()`. Differential Revision: https://phabricator.services.mozilla.com/D28935
editor/libeditor/EditorBase.h
editor/libeditor/HTMLEditorDataTransfer.cpp
editor/libeditor/TextEditor.cpp
editor/libeditor/TextEditorDataTransfer.cpp
xpcom/base/ErrorList.py
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -1815,16 +1815,23 @@ class EditorBase : public nsIEditor,
       case NS_ERROR_EDITOR_DESTROYED:
         return NS_OK;
       // If editor meets unexpected DOM tree due to modified by mutation event
       // listener, editor needs to stop handling it.  However, editor shouldn't
       // return error for the users because Chrome does not throw exception in
       // this case.
       case NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE:
         return NS_OK;
+      // If the editing action is canceled by event listeners, editor needs
+      // to stop handling it.  However, editor shouldn't return error for
+      // the callers but they should be able to distinguish whether it's
+      // canceled or not.  Although it's DOM specific code, let's return
+      // DOM_SUCCESS_DOM_NO_OPERATION here.
+      case NS_ERROR_EDITOR_ACTION_CANCELED:
+        return NS_SUCCESS_DOM_NO_OPERATION;
       default:
         return aRv;
     }
   }
 
   /**
    * GetDocumentCharsetInternal() returns charset of the document.
    */
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -1449,17 +1449,17 @@ bool HTMLEditor::HavePrivateHTMLFlavor(n
   return false;
 }
 
 nsresult HTMLEditor::PasteInternal(int32_t aClipboardType,
                                    bool aDispatchPasteEvent) {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   if (aDispatchPasteEvent && !FireClipboardEvent(ePaste, aClipboardType)) {
-    return NS_OK;
+    return NS_ERROR_EDITOR_ACTION_CANCELED;
   }
 
   // Get Clipboard Service
   nsresult rv;
   nsCOMPtr<nsIClipboard> clipboard =
       do_GetService("@mozilla.org/widget/clipboard;1", &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -1541,17 +1541,17 @@ nsresult HTMLEditor::PasteTransferable(n
     return NS_ERROR_NOT_INITIALIZED;
   }
   editActionData.InitializeDataTransfer(aTransferable);
 
   // Use an invalid value for the clipboard type as data comes from
   // aTransferable and we don't currently implement a way to put that in the
   // data transfer yet.
   if (!FireClipboardEvent(ePaste, nsIClipboard::kGlobalClipboard)) {
-    return NS_OK;
+    return EditorBase::ToGenericNSResult(NS_ERROR_EDITOR_ACTION_CANCELED);
   }
 
   nsAutoString contextStr, infoStr;
   nsresult rv = InsertFromTransferable(aTransferable, nullptr, contextStr,
                                        infoStr, false, true);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return EditorBase::ToGenericNSResult(rv);
   }
@@ -1566,17 +1566,17 @@ HTMLEditor::PasteNoFormatting(int32_t aS
   AutoEditActionDataSetter editActionData(*this, EditAction::ePaste);
   if (NS_WARN_IF(!editActionData.CanHandle())) {
     return NS_ERROR_NOT_INITIALIZED;
   }
   editActionData.InitializeDataTransferWithClipboard(
       SettingDataTransfer::eWithoutFormat, aSelectionType);
 
   if (!FireClipboardEvent(ePasteNoFormatting, aSelectionType)) {
-    return NS_OK;
+    return EditorBase::ToGenericNSResult(NS_ERROR_EDITOR_ACTION_CANCELED);
   }
 
   CommitComposition();
 
   // Get Clipboard Service
   nsresult rv;
   nsCOMPtr<nsIClipboard> clipboard(
       do_GetService("@mozilla.org/widget/clipboard;1", &rv));
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -1783,17 +1783,18 @@ TextEditor::Cut() {
   bool actionTaken = false;
   if (FireClipboardEvent(eCut, nsIClipboard::kGlobalClipboard, &actionTaken)) {
     // XXX This transaction name is referred by PlaceholderTransaction::Merge()
     //     so that we need to keep using it here.
     AutoPlaceholderBatch treatAsOneTransaction(*this,
                                                *nsGkAtoms::DeleteTxnName);
     DeleteSelectionAsSubAction(eNone, eStrip);
   }
-  return actionTaken ? NS_OK : NS_ERROR_FAILURE;
+  return EditorBase::ToGenericNSResult(
+      actionTaken ? NS_OK : NS_ERROR_EDITOR_ACTION_CANCELED);
 }
 
 bool TextEditor::CanCut() const {
   AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
   if (NS_WARN_IF(!editActionData.CanHandle())) {
     return false;
   }
 
@@ -1811,17 +1812,18 @@ TextEditor::Copy() {
   AutoEditActionDataSetter editActionData(*this, EditAction::eCopy);
   if (NS_WARN_IF(!editActionData.CanHandle())) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   bool actionTaken = false;
   FireClipboardEvent(eCopy, nsIClipboard::kGlobalClipboard, &actionTaken);
 
-  return actionTaken ? NS_OK : NS_ERROR_FAILURE;
+  return EditorBase::ToGenericNSResult(
+      actionTaken ? NS_OK : NS_ERROR_EDITOR_ACTION_CANCELED);
 }
 
 bool TextEditor::CanCopy() const {
   AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
   if (NS_WARN_IF(!editActionData.CanHandle())) {
     return false;
   }
 
--- a/editor/libeditor/TextEditorDataTransfer.cpp
+++ b/editor/libeditor/TextEditorDataTransfer.cpp
@@ -373,17 +373,17 @@ nsresult TextEditor::PasteAsAction(int32
                       ->PasteInternal(aClipboardType, aDispatchPasteEvent);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return EditorBase::ToGenericNSResult(rv);
     }
     return NS_OK;
   }
 
   if (aDispatchPasteEvent && !FireClipboardEvent(ePaste, aClipboardType)) {
-    return NS_OK;
+    return EditorBase::ToGenericNSResult(NS_ERROR_EDITOR_ACTION_CANCELED);
   }
 
   // Get Clipboard Service
   nsresult rv;
   nsCOMPtr<nsIClipboard> clipboard =
       do_GetService("@mozilla.org/widget/clipboard;1", &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -420,17 +420,17 @@ TextEditor::PasteTransferable(nsITransfe
   if (NS_WARN_IF(!editActionData.CanHandle())) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   // Use an invalid value for the clipboard type as data comes from
   // aTransferable and we don't currently implement a way to put that in the
   // data transfer yet.
   if (!FireClipboardEvent(ePaste, -1)) {
-    return NS_OK;
+    return EditorBase::ToGenericNSResult(NS_ERROR_EDITOR_ACTION_CANCELED);
   }
 
   if (!IsModifiable()) {
     return NS_OK;
   }
 
   nsresult rv = InsertTextFromTransferable(aTransferable);
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/xpcom/base/ErrorList.py
+++ b/xpcom/base/ErrorList.py
@@ -674,22 +674,28 @@ with modules["IMGLIB"]:
 
 
 # =======================================================================
 # 17: NS_ERROR_MODULE_EDITOR
 # =======================================================================
 with modules["EDITOR"]:
     errors["NS_ERROR_EDITOR_DESTROYED"] = FAILURE(1)
 
-    # A error code that indicates that the DOM tree has been modified by
+    # An error code that indicates that the DOM tree has been modified by
     # web app or add-on while the editor modifying the tree.  However,
     # this shouldn't be exposed to the web because the result should've
     # been expected by the web app.
     errors["NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE"] = FAILURE(2)
 
+    # An error code that indicates that the edit action canceled by
+    # clipboard event listener or beforeinput event listener.  Note that
+    # don't make this as a success code since it's not check with NS_FAILED()
+    # and may keep handling the operation unexpectedly.
+    errors["NS_ERROR_EDITOR_ACTION_CANCELED"] = FAILURE(3)
+
     errors["NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND"] = SUCCESS(1)
     errors["NS_SUCCESS_EDITOR_FOUND_TARGET"] = SUCCESS(2)
 
 
 # =======================================================================
 # 18: NS_ERROR_MODULE_XPCONNECT
 # =======================================================================
 with modules["XPCONNECT"]: