Bug 697981 - Prevent reloading of spelling dictionary on unfocused editors; r=roc
authorJorg K <mozilla@jorgk.com>
Tue, 15 Sep 2015 11:35:10 +0530
changeset 296838 59b6a838f0f266f8089f68092d10dcf3348a9a07
parent 296837 62dbe8652b14bcda337b6fb897b2d55f8f0f6ef0
child 296839 c12f114be9665d11096bef392c6a3ea0b73584c1
push id962
push userjlund@mozilla.com
push dateFri, 04 Dec 2015 23:28:54 +0000
treeherdermozilla-release@23a2d286e80f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs697981
milestone43.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 697981 - Prevent reloading of spelling dictionary on unfocused editors; r=roc
editor/libeditor/nsEditor.cpp
editor/libeditor/nsEditor.h
editor/libeditor/nsEditorEventListener.cpp
extensions/spellcheck/hunspell/src/mozHunspell.cpp
extensions/spellcheck/idl/mozISpellCheckingEngine.idl
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -143,16 +143,17 @@ nsEditor::nsEditor()
 ,  mDocDirtyState(-1)
 ,  mSpellcheckCheckboxState(eTriUnset)
 ,  mShouldTxnSetSelection(true)
 ,  mDidPreDestroy(false)
 ,  mDidPostCreate(false)
 ,  mDispatchInputEvent(true)
 ,  mIsInEditAction(false)
 ,  mHidingCaret(false)
+,  mObservingDictionaryUpdates(false)
 {
 }
 
 nsEditor::~nsEditor()
 {
   NS_ASSERTION(!mDocWeak || mDidPreDestroy, "Why PreDestroy hasn't been called?");
 
   if (mComposition) {
@@ -302,17 +303,17 @@ nsEditor::PostCreate()
 
     // update the UI with our state
     NotifyDocumentListeners(eDocumentCreated);
     NotifyDocumentListeners(eDocumentStateChanged);
 
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->AddObserver(this,
-                       SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
+                       SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION,
                        false);
     }
   }
 
   // update nsTextStateManager and caret if we have focus
   nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
   if (focusedContent) {
     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(focusedContent);
@@ -446,16 +447,18 @@ nsEditor::PreDestroy(bool aDestroyingFra
     return NS_OK;
 
   IMEStateManager::OnEditorDestroying(this);
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->RemoveObserver(this,
                         SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION);
+    obs->RemoveObserver(this,
+                        SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION);
   }
 
   // Let spellchecker clean up its observers etc. It is important not to
   // actually free the spellchecker here, since the spellchecker could have
   // caused flush notifications, which could have gotten here if a textbox
   // is being removed. Setting the spellchecker to nullptr could free the
   // object that is still in use! It will be freed when the editor is
   // destroyed.
@@ -1310,17 +1313,19 @@ NS_IMETHODIMP nsEditor::GetInlineSpellCh
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic,
                                 const char16_t *aData)
 {
   NS_ASSERTION(!strcmp(aTopic,
-                       SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION),
+                       SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION) ||
+               !strcmp(aTopic,
+                       SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION),
                "Unexpected observer topic");
 
   // When mozInlineSpellChecker::CanEnableInlineSpellChecking changes
   SyncRealTimeSpell();
 
   // When nsIEditorSpellCheck::GetCurrentDictionary changes
   if (mInlineSpellChecker) {
     // if the current dictionary is no longer available, find another one
@@ -5197,16 +5202,39 @@ void
 nsEditor::OnFocus(nsIDOMEventTarget* aFocusEventTarget)
 {
   InitializeSelection(aFocusEventTarget);
   if (mInlineSpellChecker) {
     mInlineSpellChecker->UpdateCurrentDictionary();
   }
 }
 
+void
+nsEditor::StartWatchingDictionaryChanges()
+{
+  if (!mObservingDictionaryUpdates) {
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+      obs->AddObserver(this, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, false);
+    }
+    mObservingDictionaryUpdates = true;
+  }
+}
+
+void
+nsEditor::StopWatchingDictionaryChanges()
+{
+  // Removing an observer that wasn't added doesn't cause any harm.
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->RemoveObserver(this, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION);
+  }
+  mObservingDictionaryUpdates = false;
+}
+
 NS_IMETHODIMP
 nsEditor::GetSuppressDispatchingInputEvent(bool *aSuppressed)
 {
   NS_ENSURE_ARG_POINTER(aSuppressed);
   *aSuppressed = !mDispatchInputEvent;
   return NS_OK;
 }
 
--- a/editor/libeditor/nsEditor.h
+++ b/editor/libeditor/nsEditor.h
@@ -244,16 +244,19 @@ public:
 
   // IME event handlers
   virtual nsresult BeginIMEComposition(mozilla::WidgetCompositionEvent* aEvent);
   virtual nsresult UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) = 0;
   void EndIMEComposition();
 
   void SwitchTextDirectionTo(uint32_t aDirection);
 
+  void StartWatchingDictionaryChanges();
+  void StopWatchingDictionaryChanges();
+
 protected:
   nsresult DetermineCurrentDirection();
   void FireInputEvent();
 
   /** Create a transaction for setting aAttribute to aValue on aElement.  Never
     * returns null.
     */
   already_AddRefed<mozilla::dom::ChangeAttributeTxn>
@@ -886,16 +889,17 @@ protected:
   uint8_t           mSpellcheckCheckboxState; // a Tristate value
 
   bool mShouldTxnSetSelection;  // turn off for conservative selection adjustment by txns
   bool mDidPreDestroy;    // whether PreDestroy has been called
   bool mDidPostCreate;    // whether PostCreate has been called
   bool mDispatchInputEvent;
   bool mIsInEditAction;   // true while the instance is handling an edit action
   bool mHidingCaret;      // whether caret is hidden forcibly.
+  bool mObservingDictionaryUpdates;  // whether the editor is observing dictionary changes.
 
   friend bool NSCanUnload(nsISupports* serviceMgr);
   friend class nsAutoTxnsConserveSelection;
   friend class nsAutoSelectionReset;
   friend class nsAutoRules;
   friend class nsRangeUpdater;
 };
 
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -1109,32 +1109,36 @@ nsEditorEventListener::Focus(nsIDOMEvent
       nsCOMPtr<nsIDOMElement> element;
       fm->GetFocusedElement(getter_AddRefs(element));
       if (!SameCOMIdentity(element, target)) {
         return NS_OK;
       }
     }
   }
 
+  mEditor->StartWatchingDictionaryChanges();
+
   mEditor->OnFocus(target);
 
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   NS_ENSURE_TRUE(ps, NS_OK);
   nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContentForIME();
   IMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent,
                                    mEditor);
 
   return NS_OK;
 }
 
 nsresult
 nsEditorEventListener::Blur(nsIDOMEvent* aEvent)
 {
   NS_ENSURE_TRUE(aEvent, NS_OK);
 
+  mEditor->StopWatchingDictionaryChanges();
+
   // check if something else is focused. If another element is focused, then
   // we should not change the selection.
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, NS_OK);
 
   nsCOMPtr<nsIDOMElement> element;
   fm->GetFocusedElement(getter_AddRefs(element));
   if (!element) {
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.cpp
@@ -599,10 +599,16 @@ NS_IMETHODIMP mozHunspell::AddDirectory(
   LoadDictionaryList(true);
   return NS_OK;
 }
 
 NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir)
 {
   mDynamicDirectories.RemoveObject(aDir);
   LoadDictionaryList(true);
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->NotifyObservers(nullptr,
+                         SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION,
+                         nullptr);
+  }
   return NS_OK;
 }
--- a/extensions/spellcheck/idl/mozISpellCheckingEngine.idl
+++ b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl
@@ -99,9 +99,11 @@ interface mozISpellCheckingEngine : nsIS
 };
 
 %{C++
 #define DICTIONARY_SEARCH_DIRECTORY "DictD"
 #define DICTIONARY_SEARCH_DIRECTORY_LIST "DictDL"
 
 #define SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION \
   "spellcheck-dictionary-update"
+#define SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION \
+  "spellcheck-dictionary-remove"
 %}