Bug 1460509 - part 1: Declare NS_ERROR_EDITOR_DESTROYED error code and add a check method to TextEditRules whether it can keep handling edit action at a moment r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 24 Apr 2018 15:23:01 +0900
changeset 798719 f035a55c225ed4ecc730daf466d7ee2392314b49
parent 798691 d36cd8bdbc5c0df1d1d7a167f5fedb95c3a3648e
child 798720 6aec242133f1f4385c0832b5bcb486b221145588
push id110840
push usermasayuki@d-toybox.com
push dateWed, 23 May 2018 13:41:58 +0000
reviewersm_kato
bugs1460509
milestone62.0a1
Bug 1460509 - part 1: Declare NS_ERROR_EDITOR_DESTROYED error code and add a check method to TextEditRules whether it can keep handling edit action at a moment r?m_kato This patch defines NS_ERROR_EDITOR_DESTROYED error code as an editor module specific error code. And creates TextEditRules::CanHandleEditAction() to check if the instance can keep handling edit action. MozReview-Commit-ID: 4qECwNBO0yz
editor/libeditor/EditorUtils.h
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/TextEditRules.cpp
editor/libeditor/TextEditRules.h
xpcom/base/ErrorList.py
--- a/editor/libeditor/EditorUtils.h
+++ b/editor/libeditor/EditorUtils.h
@@ -38,16 +38,17 @@ template <class T> class OwningNonNull;
 class MOZ_STACK_CLASS EditActionResult final
 {
 public:
   bool Succeeded() const { return NS_SUCCEEDED(mRv); }
   bool Failed() const { return NS_FAILED(mRv); }
   nsresult Rv() const { return mRv; }
   bool Canceled() const { return mCanceled; }
   bool Handled() const { return mHandled; }
+  bool EditorDestroyed() const { return mRv == NS_ERROR_EDITOR_DESTROYED; }
 
   EditActionResult SetResult(nsresult aRv)
   {
     mRv = aRv;
     return *this;
   }
   EditActionResult MarkAsCanceled()
   {
@@ -70,18 +71,23 @@ public:
   EditActionResult& operator|=(const EditActionResult& aOther)
   {
     mCanceled |= aOther.mCanceled;
     mHandled |= aOther.mHandled;
     // When both result are same, keep the result.
     if (mRv == aOther.mRv) {
       return *this;
     }
+    // If one of the result is NS_ERROR_EDITOR_DESTROYED, use it since it's
+    // the most important error code for editor.
+    if (EditorDestroyed() || aOther.EditorDestroyed()) {
+      mRv = NS_ERROR_EDITOR_DESTROYED;
+    }
     // If one of the results is error, use NS_ERROR_FAILURE.
-    if (Failed() || aOther.Failed()) {
+    else if (Failed() || aOther.Failed()) {
       mRv = NS_ERROR_FAILURE;
     } else {
       // Otherwise, use generic success code, NS_OK.
       mRv = NS_OK;
     }
     return *this;
   }
 
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -321,24 +321,24 @@ HTMLEditRules::DetachEditor()
   mHTMLEditor = nullptr;
   return TextEditRules::DetachEditor();
 }
 
 nsresult
 HTMLEditRules::BeforeEdit(EditAction aAction,
                           nsIEditor::EDirection aDirection)
 {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+
   if (mLockRulesSniffing) {
     return NS_OK;
   }
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
   AutoLockRulesSniffing lockIt(this);
   mDidExplicitlySetInterline = false;
 
   if (!mActionNesting) {
     mActionNesting++;
 
     // Clear our flag about if just deleted a range
     mDidRangedDelete = false;
@@ -407,23 +407,24 @@ HTMLEditRules::BeforeEdit(EditAction aAc
   return NS_OK;
 }
 
 
 nsresult
 HTMLEditRules::AfterEdit(EditAction aAction,
                          nsIEditor::EDirection aDirection)
 {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+
   if (mLockRulesSniffing) {
     return NS_OK;
   }
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
   AutoLockRulesSniffing lockIt(this);
 
   MOZ_ASSERT(mActionNesting > 0);
   nsresult rv = NS_OK;
   mActionNesting--;
   if (!mActionNesting) {
     Selection* selection = mHTMLEditor->GetSelection();
     if (NS_WARN_IF(!selection)) {
@@ -612,18 +613,18 @@ nsresult
 HTMLEditRules::WillDoAction(Selection* aSelection,
                             RulesInfo* aInfo,
                             bool* aCancel,
                             bool* aHandled)
 {
   if (NS_WARN_IF(!aSelection) || NS_WARN_IF(!aInfo)) {
     return NS_ERROR_INVALID_ARG;
   }
-  if (NS_WARN_IF(!mHTMLEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
   }
 
   MOZ_ASSERT(aCancel);
   MOZ_ASSERT(aHandled);
 
   *aCancel = false;
   *aHandled = false;
 
@@ -716,18 +717,18 @@ HTMLEditRules::WillDoAction(Selection* a
 nsresult
 HTMLEditRules::DidDoAction(Selection* aSelection,
                            RulesInfo* aInfo,
                            nsresult aResult)
 {
   if (NS_WARN_IF(!aSelection) || NS_WARN_IF(!aInfo)) {
     return NS_ERROR_INVALID_ARG;
   }
-  if (NS_WARN_IF(!mHTMLEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, *aSelection);
 
   switch (aInfo->action) {
     case EditAction::insertText:
     case EditAction::insertBreak:
     case EditAction::insertIMEText:
@@ -765,19 +766,20 @@ HTMLEditRules::GetListState(bool* aMixed
 {
   NS_ENSURE_TRUE(aMixed && aOL && aUL && aDL, NS_ERROR_NULL_POINTER);
   *aMixed = false;
   *aOL = false;
   *aUL = false;
   *aDL = false;
   bool bNonList = false;
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+
   Selection* selection = mHTMLEditor->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, *selection);
 
   nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
@@ -828,19 +830,20 @@ HTMLEditRules::GetListItemState(bool* aM
 {
   NS_ENSURE_TRUE(aMixed && aLI && aDT && aDD, NS_ERROR_NULL_POINTER);
   *aMixed = false;
   *aLI = false;
   *aDT = false;
   *aDD = false;
   bool bNonList = false;
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+
   Selection* selection = mHTMLEditor->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, *selection);
 
   nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
@@ -882,19 +885,20 @@ HTMLEditRules::GetListItemState(bool* aM
 }
 
 nsresult
 HTMLEditRules::GetAlignment(bool* aMixed,
                             nsIHTMLEditor::EAlignment* aAlign)
 {
   MOZ_ASSERT(aMixed && aAlign);
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+
   Selection* selection = mHTMLEditor->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, *selection);
 
   // For now, just return first alignment.  We'll lie about if it's mixed.
@@ -1070,25 +1074,26 @@ MarginPropertyAtomForIndent(nsINode& aNo
 nsresult
 HTMLEditRules::GetIndentState(bool* aCanIndent,
                               bool* aCanOutdent)
 {
   if (NS_WARN_IF(!aCanIndent) || NS_WARN_IF(!aCanOutdent)) {
     return NS_ERROR_INVALID_ARG;
   }
 
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+
   // XXX Looks like that this is implementation of
   //     nsIHTMLEditor::getIndentState() however nobody calls this method
   //     even with the interface method.
   *aCanIndent = true;
   *aCanOutdent = false;
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
   Selection* selection = mHTMLEditor->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, *selection);
 
   // contruct a list of nodes to act on.
@@ -1173,24 +1178,25 @@ HTMLEditRules::GetIndentState(bool* aCan
 nsresult
 HTMLEditRules::GetParagraphState(bool* aMixed,
                                  nsAString& outFormat)
 {
   if (NS_WARN_IF(!aMixed)) {
     return NS_ERROR_INVALID_ARG;
   }
 
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+
   // This routine is *heavily* tied to our ui choices in the paragraph
   // style popup.  I can't see a way around that.
   *aMixed = true;
   outFormat.Truncate(0);
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
   Selection* selection = mHTMLEditor->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, *selection);
 
   bool bMixed = false;
@@ -9455,17 +9461,17 @@ HTMLEditRules::InsertBRIfNeededInternal(
 void
 HTMLEditRules::DidCreateNode(Selection& aSelection,
                              Element& aNewElement)
 {
   if (!mListenerEnabled) {
     return;
   }
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
     return;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, aSelection);
 
   // assumption that Join keeps the righthand node
   IgnoredErrorResult ignoredError;
   mUtilRange->SelectNode(aNewElement, ignoredError);
@@ -9478,17 +9484,17 @@ HTMLEditRules::DidCreateNode(Selection& 
 void
 HTMLEditRules::DidInsertNode(Selection& aSelection,
                              nsIContent& aContent)
 {
   if (!mListenerEnabled) {
     return;
   }
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
     return;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, aSelection);
 
   IgnoredErrorResult ignoredError;
   mUtilRange->SelectNode(aContent, ignoredError);
   if (NS_WARN_IF(ignoredError.Failed())) {
@@ -9500,17 +9506,17 @@ HTMLEditRules::DidInsertNode(Selection& 
 void
 HTMLEditRules::WillDeleteNode(Selection& aSelection,
                               nsINode& aChild)
 {
   if (!mListenerEnabled) {
     return;
   }
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
     return;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, aSelection);
 
   IgnoredErrorResult ignoredError;
   mUtilRange->SelectNode(aChild, ignoredError);
   if (NS_WARN_IF(ignoredError.Failed())) {
@@ -9523,17 +9529,17 @@ void
 HTMLEditRules::DidSplitNode(Selection& aSelection,
                             nsINode& aExistingRightNode,
                             nsINode& aNewLeftNode)
 {
   if (!mListenerEnabled) {
     return;
   }
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
     return;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, aSelection);
 
   nsresult rv = mUtilRange->SetStartAndEnd(&aNewLeftNode, 0,
                                            &aExistingRightNode, 0);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -9544,30 +9550,35 @@ HTMLEditRules::DidSplitNode(Selection& a
 
 void
 HTMLEditRules::WillJoinNodes(nsINode& aLeftNode,
                              nsINode& aRightNode)
 {
   if (!mListenerEnabled) {
     return;
   }
+
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return;
+  }
+
   // remember split point
   mJoinOffset = aLeftNode.Length();
 }
 
 void
 HTMLEditRules::DidJoinNodes(Selection& aSelection,
                             nsINode& aLeftNode,
                             nsINode& aRightNode)
 {
   if (!mListenerEnabled) {
     return;
   }
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
     return;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, aSelection);
 
   // assumption that Join keeps the righthand node
   nsresult rv = mUtilRange->CollapseTo(&aRightNode, mJoinOffset);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -9581,17 +9592,17 @@ HTMLEditRules::DidInsertText(Selection& 
                              nsINode& aTextNode,
                              int32_t aOffset,
                              const nsAString& aString)
 {
   if (!mListenerEnabled) {
     return;
   }
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
     return;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, aSelection);
 
   int32_t length = aString.Length();
   nsresult rv = mUtilRange->SetStartAndEnd(&aTextNode, aOffset,
                                            &aTextNode, aOffset + length);
@@ -9606,17 +9617,17 @@ HTMLEditRules::DidDeleteText(Selection& 
                              nsINode& aTextNode,
                              int32_t aOffset,
                              int32_t aLength)
 {
   if (!mListenerEnabled) {
     return;
   }
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
     return;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, aSelection);
 
   nsresult rv = mUtilRange->CollapseTo(&aTextNode, aOffset);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
@@ -9626,17 +9637,17 @@ HTMLEditRules::DidDeleteText(Selection& 
 
 void
 HTMLEditRules::WillDeleteSelection(Selection& aSelection)
 {
   if (!mListenerEnabled) {
     return;
   }
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
     return;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, aSelection);
 
   EditorRawDOMPoint startPoint = EditorBase::GetStartPoint(&SelectionRef());
   if (NS_WARN_IF(!startPoint.IsSet())) {
     return;
@@ -9795,18 +9806,18 @@ HTMLEditRules::MakeSureElemStartsOrEndsO
   return NS_OK;
 }
 
 nsresult
 HTMLEditRules::MakeSureElemStartsAndEndsOnCR(nsINode& aNode)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
-  if (NS_WARN_IF(!mHTMLEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
   }
 
   Selection* selection = mHTMLEditor->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor, *selection);
@@ -10264,17 +10275,17 @@ HTMLEditRules::DocumentModified()
                       this,
                       &HTMLEditRules::DocumentModifiedWorker));
   return NS_OK;
 }
 
 void
 HTMLEditRules::DocumentModifiedWorker()
 {
-  if (!mHTMLEditor) {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
     return;
   }
 
   Selection* selection = mHTMLEditor->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return;
   }
 
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -192,33 +192,32 @@ TextEditRules::DetachEditor()
   mTextEditor = nullptr;
   return NS_OK;
 }
 
 nsresult
 TextEditRules::BeforeEdit(EditAction aAction,
                           nsIEditor::EDirection aDirection)
 {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+
   if (mLockRulesSniffing) {
     return NS_OK;
   }
 
   AutoLockRulesSniffing lockIt(this);
   mDidExplicitlySetInterline = false;
   if (!mActionNesting) {
     // let rules remember the top level action
     mTheAction = aAction;
   }
   mActionNesting++;
 
-  // get the selection and cache the position before editing
-  if (NS_WARN_IF(!mTextEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
   if (aAction == EditAction::setText) {
     // setText replaces all text, so mCachedSelectionNode might be invalid on
     // AfterEdit.
     // Since this will be used as start position of spellchecker, we should
     // use root instead.
     mCachedSelectionNode = mTextEditor->GetRoot();
     mCachedSelectionOffset = 0;
   } else {
@@ -232,27 +231,28 @@ TextEditRules::BeforeEdit(EditAction aAc
 
   return NS_OK;
 }
 
 nsresult
 TextEditRules::AfterEdit(EditAction aAction,
                          nsIEditor::EDirection aDirection)
 {
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+
   if (mLockRulesSniffing) {
     return NS_OK;
   }
 
   AutoLockRulesSniffing lockIt(this);
 
   MOZ_ASSERT(mActionNesting>0, "bad action nesting!");
   if (!--mActionNesting) {
-    if (NS_WARN_IF(!mTextEditor)) {
-      return NS_ERROR_NOT_AVAILABLE;
-    }
     Selection* selection = mTextEditor->GetSelection();
     if (NS_WARN_IF(!selection)) {
       return NS_ERROR_FAILURE;
     }
 
     AutoSafeEditorData setData(*this, *mTextEditor, *selection);
 
     nsresult rv =
@@ -295,18 +295,18 @@ nsresult
 TextEditRules::WillDoAction(Selection* aSelection,
                             RulesInfo* aInfo,
                             bool* aCancel,
                             bool* aHandled)
 {
   if (NS_WARN_IF(!aSelection) || NS_WARN_IF(!aInfo)) {
     return NS_ERROR_INVALID_ARG;
   }
-  if (NS_WARN_IF(!mTextEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
   }
 
   MOZ_ASSERT(aCancel);
   MOZ_ASSERT(aHandled);
 
   *aCancel = false;
   *aHandled = false;
 
@@ -353,18 +353,18 @@ TextEditRules::WillDoAction(Selection* a
 nsresult
 TextEditRules::DidDoAction(Selection* aSelection,
                            RulesInfo* aInfo,
                            nsresult aResult)
 {
   if (NS_WARN_IF(!aSelection) || NS_WARN_IF(!aInfo)) {
     return NS_ERROR_INVALID_ARG;
   }
-  if (NS_WARN_IF(!mTextEditor)) {
-    return NS_ERROR_NOT_AVAILABLE;
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
   }
 
   AutoSafeEditorData setData(*this, *mTextEditor, *aSelection);
 
   // don't let any txns in here move the selection around behind our back.
   // Note that this won't prevent explicit selection setting from working.
   AutoTransactionsConserveSelection dontChangeMySelection(&TextEditorRef());
 
--- a/editor/libeditor/TextEditRules.h
+++ b/editor/libeditor/TextEditRules.h
@@ -329,16 +329,27 @@ protected:
     MOZ_ASSERT(mData);
     return mData->TextEditorRef();
   }
   Selection& SelectionRef() const
   {
     MOZ_ASSERT(mData);
     return mData->SelectionRef();
   }
+  bool CanHandleEditAction() const
+  {
+    if (!mTextEditor) {
+      return false;
+    }
+    if (mTextEditor->Destroyed()) {
+      return false;
+    }
+    MOZ_ASSERT(mTextEditor->IsInitialized());
+    return true;
+  }
 
 #ifdef DEBUG
   bool IsEditorDataAvailable() const { return !!mData; }
 #endif // #ifdef DEBUG
 
   // A buffer we use to store the real value of password editors.
   nsString mPasswordText;
   // A buffer we use to track the IME composition string.
--- a/xpcom/base/ErrorList.py
+++ b/xpcom/base/ErrorList.py
@@ -697,16 +697,18 @@ with modules["IMGLIB"]:
     errors["NS_IMAGELIB_ERROR_NO_ENCODER"] = FAILURE(9)
 
 
 
 # =======================================================================
 # 17: NS_ERROR_MODULE_EDITOR
 # =======================================================================
 with modules["EDITOR"]:
+    errors["NS_ERROR_EDITOR_DESTROYED"] = FAILURE(1)
+
     errors["NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND"] = SUCCESS(1)
     errors["NS_SUCCESS_EDITOR_FOUND_TARGET"] = SUCCESS(2)
 
 
 
 # =======================================================================
 # 18: NS_ERROR_MODULE_XPCONNECT
 # =======================================================================