Bug 1388269 - part1: mozInlineSpellChecker should store editor as strong pointer instead of weak pointer r?smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 14 Aug 2017 13:04:37 +0900
changeset 646319 ed9e14879c16bd88798112749b9c9b54b56be24a
parent 646317 3c2f1fa98367f95e951916a935890b5f2723ae0f
child 646320 1a3d91eb4ef27d9dfdc16297f2a2292e52f47add
push id74070
push usermasayuki@d-toybox.com
push dateTue, 15 Aug 2017 04:00:57 +0000
reviewerssmaug
bugs1388269
milestone57.0a1
Bug 1388269 - part1: mozInlineSpellChecker should store editor as strong pointer instead of weak pointer r?smaug mozInlineSpellChecker is a cycle collectable class. Therefore, with including mEditor to the cycle, we can make it nsCOMPtr<nsIEditor> instead of nsWeakPtr. MozReview-Commit-ID: DAK02zbksvy
extensions/spellcheck/src/mozInlineSpellChecker.cpp
extensions/spellcheck/src/mozInlineSpellChecker.h
extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
extensions/spellcheck/src/mozInlineSpellWordUtil.h
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp
@@ -30,16 +30,17 @@
  * exit if something has changed. If we navigate inside the word, we don't want
  * to do anything. As a result, this flag is cleared in FinishNavigationEvent
  * when we know that we are checking as a result of navigation.
  */
 
 #include "mozilla/EditorBase.h"
 #include "mozilla/EditorUtils.h"
 #include "mozilla/Services.h"
+#include "mozilla/TextEditor.h"
 #include "mozilla/dom/Selection.h"
 #include "mozInlineSpellChecker.h"
 #include "mozInlineSpellWordUtil.h"
 #include "mozISpellI18NManager.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMDocument.h"
@@ -212,27 +213,28 @@ mozInlineSpellStatus::InitForEditorChang
 
 nsresult
 mozInlineSpellStatus::InitForNavigation(
     bool aForceCheck, int32_t aNewPositionOffset,
     nsIDOMNode* aOldAnchorNode, int32_t aOldAnchorOffset,
     nsIDOMNode* aNewAnchorNode, int32_t aNewAnchorOffset,
     bool* aContinue)
 {
-  nsresult rv;
   mOp = eOpNavigation;
 
   mForceNavigationWordCheck = aForceCheck;
   mNewNavigationPositionOffset = aNewPositionOffset;
 
   // get the root node for checking
-  nsCOMPtr<nsIEditor> editor = do_QueryReferent(mSpellChecker->mEditor, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIEditor> editor = mSpellChecker->mEditor;
+  if (NS_WARN_IF(!editor)) {
+    return NS_ERROR_FAILURE;
+  }
   nsCOMPtr<nsIDOMElement> rootElt;
-  rv = editor->GetRootElement(getter_AddRefs(rootElt));
+  nsresult rv = editor->GetRootElement(getter_AddRefs(rootElt));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // the anchor node might not be in the DOM anymore, check
   nsCOMPtr<nsINode> root = do_QueryInterface(rootElt, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsINode> currentAnchor = do_QueryInterface(aOldAnchorNode, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
   if (root && currentAnchor && ! ContentIsDescendantOf(currentAnchor, root)) {
@@ -341,17 +343,17 @@ mozInlineSpellStatus::FinishInitOnEvent(
 //    Notice that we don't set mNoCheckRange. We check here whether the cursor
 //    is in the word that needs checking, so it isn't necessary. Plus, the
 //    spellchecker isn't guaranteed to only check the given word, and it could
 //    remove the underline from the new word under the cursor.
 
 nsresult
 mozInlineSpellStatus::FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil)
 {
-  nsCOMPtr<nsIEditor> editor = do_QueryReferent(mSpellChecker->mEditor);
+  nsCOMPtr<nsIEditor> editor = mSpellChecker->mEditor;
   if (! editor)
     return NS_ERROR_FAILURE; // editor is gone
 
   NS_ASSERTION(mAnchorRange, "No anchor for navigation!");
   nsCOMPtr<nsIDOMNode> newAnchorNode, oldAnchorNode;
 
   // get the DOM position of the old caret, the range should be collapsed
   nsresult rv = mOldNavigationAnchorRange->GetStartContainer(
@@ -363,19 +365,19 @@ mozInlineSpellStatus::FinishNavigationEv
   // to check
   RefPtr<nsRange> oldWord;
   rv = aWordUtil.GetRangeForWord(oldAnchorNode,
                                  static_cast<int32_t>(oldAnchorOffset),
                                  getter_AddRefs(oldWord));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // aWordUtil.GetRangeForWord flushes pending notifications, check editor again.
-  editor = do_QueryReferent(mSpellChecker->mEditor);
-  if (! editor)
+  if (!mSpellChecker->mEditor) {
     return NS_ERROR_FAILURE; // editor is gone
+  }
 
   // get the DOM position of the new caret, the range should be collapsed
   rv = mAnchorRange->GetStartContainer(getter_AddRefs(newAnchorNode));
   NS_ENSURE_SUCCESS(rv, rv);
   uint32_t newAnchorOffset = mAnchorRange->StartOffset();
 
   // see if the new cursor position is in the word of the old cursor position
   bool isInRange = false;
@@ -426,26 +428,27 @@ mozInlineSpellStatus::FillNoCheckRangeFr
 // mozInlineSpellStatus::GetDocument
 //
 //    Returns the nsIDOMDocument object for the document for the
 //    current spellchecker.
 
 nsresult
 mozInlineSpellStatus::GetDocument(nsIDOMDocument** aDocument)
 {
-  nsresult rv;
   *aDocument = nullptr;
   if (! mSpellChecker->mEditor)
     return NS_ERROR_UNEXPECTED;
 
-  nsCOMPtr<nsIEditor> editor = do_QueryReferent(mSpellChecker->mEditor, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIEditor> editor = mSpellChecker->mEditor;
+  if (NS_WARN_IF(!editor)) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsCOMPtr<nsIDOMDocument> domDoc;
-  rv = editor->GetDocument(getter_AddRefs(domDoc));
+  nsresult rv = editor->GetDocument(getter_AddRefs(domDoc));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(domDoc, NS_ERROR_NULL_POINTER);
   domDoc.forget(aDocument);
   return NS_OK;
 }
 
 // mozInlineSpellStatus::PositionToCollapsedRange
 //
@@ -541,16 +544,17 @@ NS_INTERFACE_MAP_BEGIN(mozInlineSpellChe
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozInlineSpellChecker)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozInlineSpellChecker)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozInlineSpellChecker)
 
 NS_IMPL_CYCLE_COLLECTION(mozInlineSpellChecker,
+                         mEditor,
                          mSpellCheck,
                          mTreeWalker,
                          mCurrentSelectionAnchorNode)
 
 mozInlineSpellChecker::SpellCheckingState
   mozInlineSpellChecker::gCanEnableSpellChecking =
   mozInlineSpellChecker::SpellCheck_Uninitialized;
 
@@ -579,17 +583,17 @@ mozInlineSpellChecker::GetSpellChecker(n
   *aSpellCheck = mSpellCheck;
   NS_IF_ADDREF(*aSpellCheck);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 mozInlineSpellChecker::Init(nsIEditor *aEditor)
 {
-  mEditor = do_GetWeakReference(aEditor);
+  mEditor = aEditor;
   return NS_OK;
 }
 
 // mozInlineSpellChecker::Cleanup
 //
 //    Called by the editor when the editor is going away. This is important
 //    because we remove listeners. We do NOT clean up anything else in this
 //    function, because it can get called while DoSpellCheck is running!
@@ -617,17 +621,17 @@ nsresult mozInlineSpellChecker::Cleanup(
   // Notify ENDED observers now.  If we wait to notify as we normally do when
   // these async operations finish, then in the meantime the editor may create
   // another inline spell checker and cause more STARTED and ENDED
   // notifications to be broadcast.  Interleaved notifications for the same
   // editor but different inline spell checkers could easily confuse
   // observers.  They may receive two consecutive STARTED notifications for
   // example, which we guarantee will not happen.
 
-  nsCOMPtr<nsIEditor> editor = do_QueryReferent(mEditor);
+  nsCOMPtr<nsIEditor> editor = mEditor.forget();
   if (mPendingSpellCheck) {
     // Cancel the pending editor spell checker initialization.
     mPendingSpellCheck = nullptr;
     mPendingInitEditorSpellCheckCallback->Cancel();
     mPendingInitEditorSpellCheckCallback = nullptr;
     ChangeNumPendingSpellChecks(-1, editor);
   }
 
@@ -641,17 +645,16 @@ nsresult mozInlineSpellChecker::Cleanup(
     mNumPendingUpdateCurrentDictionary = 0;
   }
   if (mNumPendingSpellChecks > 0) {
     // If mNumPendingSpellChecks is still > 0 at this point, the remainder is
     // pending scheduled spell checks.
     ChangeNumPendingSpellChecks(-mNumPendingSpellChecks, editor);
   }
 
-  mEditor = nullptr;
   mFullSpellCheckScheduled = false;
 
   return rv;
 }
 
 // mozInlineSpellChecker::CanEnableInlineSpellChecking
 //
 //    This function can be called to see if it seems likely that we can enable
@@ -696,23 +699,24 @@ mozInlineSpellChecker::UpdateCanEnableIn
 // mozInlineSpellChecker::RegisterEventListeners
 //
 //    The inline spell checker listens to mouse events and keyboard navigation
 //    events.
 
 nsresult
 mozInlineSpellChecker::RegisterEventListeners()
 {
-  nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
-  NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER);
+  if (NS_WARN_IF(!mEditor)) {
+    return NS_ERROR_FAILURE;
+  }
 
-  editor->AddEditActionListener(this);
+  mEditor->AddEditActionListener(this);
 
   nsCOMPtr<nsIDOMDocument> doc;
-  nsresult rv = editor->GetDocument(getter_AddRefs(doc));
+  nsresult rv = mEditor->GetDocument(getter_AddRefs(doc));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<EventTarget> piTarget = do_QueryInterface(doc, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   piTarget->AddEventListener(NS_LITERAL_STRING("blur"), this,
                              true, false);
   piTarget->AddEventListener(NS_LITERAL_STRING("click"), this,
@@ -722,23 +726,24 @@ mozInlineSpellChecker::RegisterEventList
   return NS_OK;
 }
 
 // mozInlineSpellChecker::UnregisterEventListeners
 
 nsresult
 mozInlineSpellChecker::UnregisterEventListeners()
 {
-  nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
-  NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER);
+  if (NS_WARN_IF(!mEditor)) {
+    return NS_ERROR_FAILURE;
+  }
 
-  editor->RemoveEditActionListener(this);
+  mEditor->RemoveEditActionListener(this);
 
   nsCOMPtr<nsIDOMDocument> doc;
-  editor->GetDocument(getter_AddRefs(doc));
+  mEditor->GetDocument(getter_AddRefs(doc));
   NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<EventTarget> piTarget = do_QueryInterface(doc);
   NS_ENSURE_TRUE(piTarget, NS_ERROR_NULL_POINTER);
 
   piTarget->RemoveEventListener(NS_LITERAL_STRING("blur"), this, true);
   piTarget->RemoveEventListener(NS_LITERAL_STRING("click"), this, false);
   piTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, false);
@@ -791,19 +796,18 @@ mozInlineSpellChecker::SetEnableRealTime
   mPendingSpellCheck->SetFilter(filter);
 
   mPendingInitEditorSpellCheckCallback = new InitEditorSpellCheckCallback(this);
   if (!mPendingInitEditorSpellCheckCallback) {
     mPendingSpellCheck = nullptr;
     NS_ENSURE_STATE(mPendingInitEditorSpellCheckCallback);
   }
 
-  nsCOMPtr<nsIEditor> editor = do_QueryReferent(mEditor);
   nsresult rv = mPendingSpellCheck->InitSpellChecker(
-                  editor, false, mPendingInitEditorSpellCheckCallback);
+                  mEditor, false, mPendingInitEditorSpellCheckCallback);
   if (NS_FAILED(rv)) {
     mPendingSpellCheck = nullptr;
     mPendingInitEditorSpellCheckCallback = nullptr;
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   ChangeNumPendingSpellChecks(1);
 
@@ -852,20 +856,19 @@ mozInlineSpellChecker::ChangeNumPendingS
 // Broadcasts the given topic to observers.  aEditor is passed to observers if
 // nonnull; otherwise mEditor is passed.
 void
 mozInlineSpellChecker::NotifyObservers(const char* aTopic, nsIEditor* aEditor)
 {
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (!os)
     return;
-  nsCOMPtr<nsIEditor> editor = aEditor;
-  if (!editor) {
-    editor = do_QueryReferent(mEditor);
-  }
+  // XXX Do we need to grab the editor here?  If it's necessary, each observer
+  //     should do it instead.
+  nsCOMPtr<nsIEditor> editor = aEditor ? aEditor : mEditor.get();
   os->NotifyObservers(editor, aTopic, nullptr);
 }
 
 // mozInlineSpellChecker::SpellCheckAfterEditorChange
 //
 //    Called by the editor when nearly anything happens to change the content.
 //
 //    The start and end positions specify a range for the thing that happened,
@@ -950,44 +953,45 @@ mozInlineSpellChecker::GetMisspelledWord
 }
 
 // mozInlineSpellChecker::ReplaceWord
 
 NS_IMETHODIMP
 mozInlineSpellChecker::ReplaceWord(nsIDOMNode *aNode, int32_t aOffset,
                                    const nsAString &newword)
 {
-  nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
-  NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER);
-  NS_ENSURE_TRUE(newword.Length() != 0, NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!mEditor) || NS_WARN_IF(newword.IsEmpty())) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsCOMPtr<nsIDOMRange> range;
   nsresult res = GetMisspelledWord(aNode, aOffset, getter_AddRefs(range));
   NS_ENSURE_SUCCESS(res, res);
 
   if (range)
   {
     // This range was retrieved from the spellchecker selection. As
     // ranges cannot be shared between selections, we must clone it
     // before adding it to the editor's selection.
     nsCOMPtr<nsIDOMRange> editorRange;
     res = range->CloneRange(getter_AddRefs(editorRange));
     NS_ENSURE_SUCCESS(res, res);
 
-    AutoPlaceHolderBatch phb(editor, nullptr);
+    AutoPlaceHolderBatch phb(mEditor, nullptr);
 
     nsCOMPtr<nsISelection> selection;
-    res = editor->GetSelection(getter_AddRefs(selection));
+    res = mEditor->GetSelection(getter_AddRefs(selection));
     NS_ENSURE_SUCCESS(res, res);
     selection->RemoveAllRanges();
     selection->AddRange(editorRange);
 
-    nsCOMPtr<nsIPlaintextEditor> textEditor(do_QueryReferent(mEditor));
-    if (textEditor)
-      textEditor->InsertText(newword);
+    MOZ_ASSERT(mEditor);
+    RefPtr<TextEditor> textEditor = mEditor->AsTextEditor();
+    MOZ_ASSERT(textEditor);
+    textEditor->InsertText(newword);
   }
 
   return NS_OK;
 }
 
 // mozInlineSpellChecker::AddWordToDictionary
 
 NS_IMETHODIMP
@@ -1160,31 +1164,32 @@ nsresult
 mozInlineSpellChecker::MakeSpellCheckRange(
     nsIDOMNode* aStartNode, int32_t aStartOffset,
     nsIDOMNode* aEndNode, int32_t aEndOffset,
     nsRange** aRange)
 {
   nsresult rv;
   *aRange = nullptr;
 
-  nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
-  NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER);
+  if (NS_WARN_IF(!mEditor)) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsCOMPtr<nsIDOMDocument> doc;
-  rv = editor->GetDocument(getter_AddRefs(doc));
+  rv = mEditor->GetDocument(getter_AddRefs(doc));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsINode> documentNode = do_QueryInterface(doc);
   RefPtr<nsRange> range = new nsRange(documentNode);
 
   // possibly use full range of the editor
   nsCOMPtr<nsIDOMElement> rootElem;
   if (! aStartNode || ! aEndNode) {
-    rv = editor->GetRootElement(getter_AddRefs(rootElem));
+    rv = mEditor->GetRootElement(getter_AddRefs(rootElem));
     NS_ENSURE_SUCCESS(rv, rv);
 
     aStartNode = rootElem;
     aStartOffset = 0;
 
     aEndNode = rootElem;
     aEndOffset = -1;
   }
@@ -1459,17 +1464,17 @@ nsresult mozInlineSpellChecker::DoSpellC
                                              bool* aDoneChecking)
 {
   *aDoneChecking = true;
 
   NS_ENSURE_TRUE(mSpellCheck, NS_ERROR_NOT_INITIALIZED);
 
   // get the editor for ShouldSpellCheckNode, this may fail in reasonable
   // circumstances since the editor could have gone away
-  nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
+  nsCOMPtr<nsIEditor> editor = mEditor;
   if (! editor)
     return NS_ERROR_FAILURE;
 
   if (aStatus->mRange->Collapsed())
     return NS_OK;
 
   // see if the selection has any ranges, if not, then we can optimize checking
   // range inclusion later (we have no ranges when we are initially checking or
@@ -1494,20 +1499,19 @@ nsresult mozInlineSpellChecker::DoSpellC
       return NS_OK;
     }
 
     aWordUtil.SetEnd(endNode, endOffset);
     aWordUtil.SetPosition(beginNode, beginOffset);
   }
 
   // aWordUtil.SetPosition flushes pending notifications, check editor again.
-  // XXX Uhhh, *we're* holding a strong ref to the editor.
-  editor = do_QueryReferent(mEditor);
-  if (! editor)
+  if (!mEditor) {
     return NS_ERROR_FAILURE;
+  }
 
   int32_t wordsChecked = 0;
   PRTime beginTime = PR_Now();
 
   nsAutoString wordText;
   RefPtr<nsRange> wordRange;
   bool dontCheckWord;
   while (NS_SUCCEEDED(aWordUtil.GetNextWord(wordText,
@@ -1652,19 +1656,19 @@ mozInlineSpellChecker::ResumeCheck(Uniqu
                  "How could this be false?  The full spell check is "
                  "calling us!!");
     mFullSpellCheckScheduled = false;
   }
 
   if (! mSpellCheck)
     return NS_OK; // spell checking has been turned off
 
-  nsCOMPtr<nsIEditor> editor = do_QueryReferent(mEditor);
-  if (! editor)
-    return NS_OK; // editor is gone
+  if (!mEditor) {
+    return NS_OK;
+  }
 
   mozInlineSpellWordUtil wordUtil;
   nsresult rv = wordUtil.Init(mEditor);
   if (NS_FAILED(rv))
     return NS_OK; // editor doesn't like us, don't assert
 
   nsCOMPtr<nsISelection> spellCheckSelectionRef;
   rv = GetSpellCheckSelection(getter_AddRefs(spellCheckSelectionRef));
@@ -1810,36 +1814,40 @@ mozInlineSpellChecker::AddRange(nsISelec
     rv = aSpellCheckSelection->AddRange(aRange);
     if (NS_SUCCEEDED(rv))
       mNumWordsInSpellSelection++;
   }
 
   return rv;
 }
 
-nsresult mozInlineSpellChecker::GetSpellCheckSelection(nsISelection ** aSpellCheckSelection)
+nsresult
+mozInlineSpellChecker::GetSpellCheckSelection(
+                         nsISelection** aSpellCheckSelection)
 {
-  nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
-  NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER);
-
+  if (NS_WARN_IF(!mEditor)) {
+    return NS_ERROR_FAILURE;
+  }
   nsCOMPtr<nsISelectionController> selcon;
-  nsresult rv = editor->GetSelectionController(getter_AddRefs(selcon));
+  nsresult rv = mEditor->GetSelectionController(getter_AddRefs(selcon));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return selcon->GetSelection(nsISelectionController::SELECTION_SPELLCHECK, aSpellCheckSelection);
 }
 
-nsresult mozInlineSpellChecker::SaveCurrentSelectionPosition()
+nsresult
+mozInlineSpellChecker::SaveCurrentSelectionPosition()
 {
-  nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
-  NS_ENSURE_TRUE(editor, NS_OK);
+  if (NS_WARN_IF(!mEditor)) {
+    return NS_OK; // XXX Why NS_OK?
+  }
 
   // figure out the old caret position based on the current selection
   nsCOMPtr<nsISelection> selection;
-  nsresult rv = editor->GetSelection(getter_AddRefs(selection));
+  nsresult rv = mEditor->GetSelection(getter_AddRefs(selection));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = selection->GetFocusNode(getter_AddRefs(mCurrentSelectionAnchorNode));
   NS_ENSURE_SUCCESS(rv, rv);
 
   selection->GetFocusOffset(&mCurrentSelectionOffset);
 
   return NS_OK;
--- a/extensions/spellcheck/src/mozInlineSpellChecker.h
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.h
@@ -2,26 +2,27 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __mozinlinespellchecker_h__
 #define __mozinlinespellchecker_h__
 
 #include "mozilla/EditorBase.h"
-#include "nsRange.h"
-#include "nsIEditorSpellCheck.h"
-#include "nsIEditActionListener.h"
-#include "nsIInlineSpellChecker.h"
+
+#include "mozISpellI18NUtil.h"
+
+#include "nsCycleCollectionParticipant.h"
+#include "nsIDOMEventListener.h"
 #include "nsIDOMTreeWalker.h"
-#include "nsWeakReference.h"
-#include "nsIDOMEventListener.h"
+#include "nsIEditActionListener.h"
+#include "nsIEditorSpellCheck.h"
+#include "nsIInlineSpellChecker.h"
+#include "nsRange.h"
 #include "nsWeakReference.h"
-#include "mozISpellI18NUtil.h"
-#include "nsCycleCollectionParticipant.h"
 
 // X.h defines KeyPress
 #ifdef KeyPress
 #undef KeyPress
 #endif
 
 class mozInlineSpellWordUtil;
 class mozInlineSpellChecker;
@@ -127,17 +128,17 @@ private:
   friend class mozInlineSpellResume;
 
   // Access with CanEnableInlineSpellChecking
   enum SpellCheckingState { SpellCheck_Uninitialized = -1,
                             SpellCheck_NotAvailable = 0,
                             SpellCheck_Available = 1};
   static SpellCheckingState gCanEnableSpellChecking;
 
-  nsWeakPtr mEditor;
+  nsCOMPtr<nsIEditor> mEditor;
   nsCOMPtr<nsIEditorSpellCheck> mSpellCheck;
   nsCOMPtr<nsIEditorSpellCheck> mPendingSpellCheck;
   nsCOMPtr<nsIDOMTreeWalker> mTreeWalker;
   nsCOMPtr<mozISpellI18NUtil> mConverter;
 
   int32_t mNumWordsInSpellSelection;
   int32_t mMaxNumWordsInSpellSelection;
 
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
@@ -45,38 +45,34 @@ inline bool IsConditionalPunctuation(cha
   return (ch == '\'' ||
           ch == 0x2019 || // RIGHT SINGLE QUOTATION MARK
           ch == 0x00B7); // MIDDLE DOT
 }
 
 // mozInlineSpellWordUtil::Init
 
 nsresult
-mozInlineSpellWordUtil::Init(const nsWeakPtr& aWeakEditor)
+mozInlineSpellWordUtil::Init(nsIEditor* aEditor)
 {
-  nsresult rv;
-
-  // getting the editor can fail commonly because the editor was detached, so
-  // don't assert
-  nsCOMPtr<nsIEditor> editor = do_QueryReferent(aWeakEditor, &rv);
-  if (NS_FAILED(rv))
-    return rv;
+  if (NS_WARN_IF(!aEditor)) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsCOMPtr<nsIDOMDocument> domDoc;
-  rv = editor->GetDocument(getter_AddRefs(domDoc));
+  nsresult rv = aEditor->GetDocument(getter_AddRefs(domDoc));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(domDoc, NS_ERROR_NULL_POINTER);
 
   mDOMDocument = domDoc;
   mDocument = do_QueryInterface(domDoc);
 
   // Find the root node for the editor. For contenteditable we'll need something
   // cleverer here.
   nsCOMPtr<nsIDOMElement> rootElt;
-  rv = editor->GetRootElement(getter_AddRefs(rootElt));
+  rv = aEditor->GetRootElement(getter_AddRefs(rootElt));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsINode> rootNode = do_QueryInterface(rootElt);
   mRootNode = rootNode;
   NS_ASSERTION(mRootNode, "GetRootElement returned null *and* claimed to suceed!");
   return NS_OK;
 }
 
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.h
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.h
@@ -10,16 +10,17 @@
 #include "nsIDOMDocument.h"
 #include "nsIDocument.h"
 #include "nsString.h"
 #include "nsTArray.h"
 
 //#define DEBUG_SPELLCHECK
 
 class nsRange;
+class nsIEditor;
 class nsINode;
 
 /**
  *    This class extracts text from the DOM and builds it into a single string.
  *    The string includes whitespace breaks whereever non-inline elements begin
  *    and end. This string is broken into "real words", following somewhat
  *    complex rules; for example substrings that look like URLs or
  *    email addresses are treated as single words, but otherwise many kinds of
@@ -56,17 +57,17 @@ public:
     }
   };
 
   mozInlineSpellWordUtil()
     : mRootNode(nullptr),
       mSoftBegin(nullptr, 0), mSoftEnd(nullptr, 0),
       mNextWordIndex(-1), mSoftTextValid(false) {}
 
-  nsresult Init(const nsWeakPtr& aWeakEditor);
+  nsresult Init(nsIEditor* aEditor);
 
   nsresult SetEnd(nsINode* aEndNode, int32_t aEndOffset);
 
   // sets the current position, this should be inside the range. If we are in
   // the middle of a word, we'll move to its start.
   nsresult SetPosition(nsINode* aNode, int32_t aOffset);
 
   // Given a point inside or immediately following a word, this returns the