Bug 1430785 - Make mozInlineSpellChecker not derived from nsIEditActionListener r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 17 Jan 2018 14:05:06 +0900
changeset 722565 cba108cfe14fae055dcb982a80f6ec5a3d0bef17
parent 722564 0d2fb26930cc562f243fce41ce477c1ad45b4249
child 746633 1aaaeb21998432d811deda071b6d408081e96f25
push id96170
push usermasayuki@d-toybox.com
push dateFri, 19 Jan 2018 07:47:18 +0000
reviewersm_kato
bugs1430785
milestone59.0a1
Bug 1430785 - Make mozInlineSpellChecker not derived from nsIEditActionListener r?m_kato mozInlineSpellChecker listens to only DidSplitNode() and DidJoinNodes(). So, EditorBase should call them directly rather than treating it as an nsIEditActionListener since its runtime cost becomes really cheaper. Different from EditorSpellCheck, nobody creates instance of nsIInlineSpellChecker. So, we can now stop supporting createInstance() for it in chrome JS and should do this since EditorBase cannot support multiple mozInlineSpellChecker instances without nsIEditActionListener interface. Therefore, this patch removes the entry from factory. MozReview-Commit-ID: W1CLdsJaaB
editor/libeditor/EditorBase.cpp
editor/txtsvc/nsIInlineSpellChecker.idl
extensions/spellcheck/src/mozInlineSpellChecker.cpp
extensions/spellcheck/src/mozInlineSpellChecker.h
extensions/spellcheck/src/mozSpellCheckerFactory.cpp
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -1572,16 +1572,21 @@ EditorBase::SplitNode(const EditorRawDOM
   mRangeUpdater.SelAdjSplitNode(*aStartOfRightNode.GetContainerAsContent(),
                                 newNode);
 
   if (mRules && mRules->AsHTMLEditRules()) {
     RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
     htmlEditRules->DidSplitNode(aStartOfRightNode.GetContainer(), newNode);
   }
 
+  if (mInlineSpellChecker) {
+    RefPtr<mozInlineSpellChecker> spellChecker = mInlineSpellChecker;
+    spellChecker->DidSplitNode(aStartOfRightNode.GetContainer(), newNode);
+  }
+
   if (!mActionListeners.IsEmpty()) {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
       listener->DidSplitNode(aStartOfRightNode.GetContainerAsDOMNode(),
                              GetAsDOMNode(newNode));
     }
   }
 
@@ -1636,16 +1641,21 @@ EditorBase::JoinNodes(nsINode& aLeftNode
   mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, *parent, offset,
                                 (int32_t)oldLeftNodeLen);
 
   if (mRules && mRules->AsHTMLEditRules()) {
     RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
     htmlEditRules->DidJoinNodes(aLeftNode, aRightNode);
   }
 
+  if (mInlineSpellChecker) {
+    RefPtr<mozInlineSpellChecker> spellChecker = mInlineSpellChecker;
+    spellChecker->DidJoinNodes(aLeftNode, aRightNode);
+  }
+
   if (mTextServicesDocument && NS_SUCCEEDED(rv)) {
     RefPtr<TextServicesDocument> textServicesDocument = mTextServicesDocument;
     textServicesDocument->DidJoinNodes(aLeftNode, aRightNode);
   }
 
   if (!mActionListeners.IsEmpty()) {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
@@ -2210,31 +2220,35 @@ EditorBase::AddEditActionListener(nsIEdi
         }
       }
     }
   }
 
   // Make sure the listener isn't already on the list
   if (!mActionListeners.Contains(aListener)) {
     mActionListeners.AppendElement(*aListener);
+    NS_WARNING_ASSERTION(mActionListeners.Length() != 1,
+      "nsIEditActionListener installed, this editor becomes slower");
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 EditorBase::RemoveEditActionListener(nsIEditActionListener* aListener)
 {
   NS_ENSURE_TRUE(aListener, NS_ERROR_FAILURE);
 
   if (static_cast<nsIEditActionListener*>(mTextServicesDocument) == aListener) {
     mTextServicesDocument = nullptr;
     return NS_OK;
   }
 
+  NS_WARNING_ASSERTION(mActionListeners.Length() != 1,
+    "All nsIEditActionListeners have been removed, this editor becomes faster");
   mActionListeners.RemoveElement(aListener);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 EditorBase::AddDocumentStateListener(nsIDocumentStateListener* aListener)
 {
--- a/editor/txtsvc/nsIInlineSpellChecker.idl
+++ b/editor/txtsvc/nsIInlineSpellChecker.idl
@@ -43,14 +43,8 @@ interface nsIInlineSpellChecker : nsISup
   void removeWordFromDictionary(in AString aWord);
 
   void ignoreWord(in AString aWord);
   void ignoreWords([array, size_is(aCount)] in wstring aWordsToIgnore, in unsigned long aCount);
   void updateCurrentDictionary();
 
   readonly attribute boolean spellCheckPending;
 };
-
-%{C++
-
-#define MOZ_INLINESPELLCHECKER_CONTRACTID "@mozilla.org/spellchecker-inline;1"
-
-%}
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp
@@ -522,17 +522,16 @@ public:
 private:
   RefPtr<mozInlineSpellChecker> mSpellChecker;
 };
 NS_IMPL_ISUPPORTS(InitEditorSpellCheckCallback, nsIEditorSpellCheckCallback)
 
 
 NS_INTERFACE_MAP_BEGIN(mozInlineSpellChecker)
   NS_INTERFACE_MAP_ENTRY(nsIInlineSpellChecker)
-  NS_INTERFACE_MAP_ENTRY(nsIEditActionListener)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
   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)
@@ -700,17 +699,17 @@ mozInlineSpellChecker::UpdateCanEnableIn
 
 nsresult
 mozInlineSpellChecker::RegisterEventListeners()
 {
   if (NS_WARN_IF(!mTextEditor)) {
     return NS_ERROR_FAILURE;
   }
 
-  mTextEditor->AddEditActionListener(this);
+  StartToListenToEditActions();
 
   nsCOMPtr<nsIDocument> doc = mTextEditor->GetDocument();
   if (NS_WARN_IF(!doc)) {
     return NS_ERROR_FAILURE;
   }
   doc->AddEventListener(NS_LITERAL_STRING("blur"), this, true, false);
   doc->AddEventListener(NS_LITERAL_STRING("click"), this, false, false);
   doc->AddEventListener(NS_LITERAL_STRING("keypress"), this, false, false);
@@ -721,17 +720,17 @@ mozInlineSpellChecker::RegisterEventList
 
 nsresult
 mozInlineSpellChecker::UnregisterEventListeners()
 {
   if (NS_WARN_IF(!mTextEditor)) {
     return NS_ERROR_FAILURE;
   }
 
-  mTextEditor->RemoveEditActionListener(this);
+  EndListeningToEditActions();
 
   nsCOMPtr<nsIDocument> doc = mTextEditor->GetDocument();
   if (NS_WARN_IF(!doc)) {
     return NS_ERROR_FAILURE;
   }
   doc->RemoveEventListener(NS_LITERAL_STRING("blur"), this, true);
   doc->RemoveEventListener(NS_LITERAL_STRING("click"), this, false);
   doc->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, false);
@@ -1033,90 +1032,36 @@ mozInlineSpellChecker::IgnoreWords(const
                    nsDependentString(aWordsToIgnore[index]));
 
   auto status = MakeUnique<mozInlineSpellStatus>(this);
   nsresult rv = status->InitForSelection();
   NS_ENSURE_SUCCESS(rv, rv);
   return ScheduleSpellCheck(Move(status));
 }
 
-NS_IMETHODIMP
-mozInlineSpellChecker::DidCreateNode(const nsAString& aTag,
-                                     nsIDOMNode* aNewNode,
-                                     nsresult aResult)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-mozInlineSpellChecker::DidInsertNode(nsIDOMNode* aNode,
-                                     nsresult aResult)
+void
+mozInlineSpellChecker::DidSplitNode(nsINode* aExistingRightNode,
+                                    nsINode* aNewLeftNode)
 {
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-mozInlineSpellChecker::DidDeleteNode(nsIDOMNode* aChild,
-                                     nsresult aResult)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-mozInlineSpellChecker::DidSplitNode(nsIDOMNode* aExistingRightNode,
-                                    nsIDOMNode* aNewLeftNode)
-{
-  return SpellCheckBetweenNodes(aNewLeftNode, 0, aNewLeftNode, 0);
+  if (!mIsListeningToEditActions) {
+    return;
+  }
+  nsIDOMNode* newLeftDOMNode =
+    aNewLeftNode ? aNewLeftNode->AsDOMNode() : nullptr;
+  SpellCheckBetweenNodes(newLeftDOMNode, 0, newLeftDOMNode, 0);
 }
 
-NS_IMETHODIMP
-mozInlineSpellChecker::DidJoinNodes(nsIDOMNode* aLeftNode,
-                                    nsIDOMNode* aRightNode,
-                                    nsIDOMNode* aParent,
-                                    nsresult aResult)
-{
-  return SpellCheckBetweenNodes(aRightNode, 0, aRightNode, 0);
-}
-
-NS_IMETHODIMP
-mozInlineSpellChecker::DidInsertText(nsIDOMCharacterData* aTextNode,
-                                     int32_t aOffset,
-                                     const nsAString& aString,
-                                     nsresult aResult)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-mozInlineSpellChecker::WillDeleteText(nsIDOMCharacterData* aTextNode,
-                                      int32_t aOffset,
-                                      int32_t aLength)
+void
+mozInlineSpellChecker::DidJoinNodes(nsINode& aLeftNode,
+                                    nsINode& aRightNode)
 {
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-mozInlineSpellChecker::DidDeleteText(nsIDOMCharacterData* aTextNode,
-                                     int32_t aOffset,
-                                     int32_t aLength,
-                                     nsresult aResult)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-mozInlineSpellChecker::WillDeleteSelection(nsISelection* aSelection)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-mozInlineSpellChecker::DidDeleteSelection(nsISelection* aSelection)
-{
-  return NS_OK;
+  if (!mIsListeningToEditActions) {
+    return;
+  }
+  SpellCheckBetweenNodes(aRightNode.AsDOMNode(), 0, aRightNode.AsDOMNode(), 0);
 }
 
 // mozInlineSpellChecker::MakeSpellCheckRange
 //
 //    Given begin and end positions, this function constructs a range as
 //    required for ScheduleSpellCheck. If the start and end nodes are nullptr,
 //    then the entire range will be selected, and you can supply -1 as the
 //    offset to the end range to select all of that node.
--- a/extensions/spellcheck/src/mozInlineSpellChecker.h
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.h
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_mozInlineSpellChecker_h
 #define mozilla_mozInlineSpellChecker_h
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMTreeWalker.h"
-#include "nsIEditActionListener.h"
 #include "nsIEditorSpellCheck.h"
 #include "nsIInlineSpellChecker.h"
 #include "nsRange.h"
 #include "nsWeakReference.h"
 
 class InitEditorSpellCheckCallback;
 class mozInlineSpellWordUtil;
 class mozInlineSpellChecker;
@@ -107,17 +106,16 @@ protected:
   nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil);
 
   already_AddRefed<nsIDocument> GetDocument();
   already_AddRefed<nsRange> PositionToCollapsedRange(nsINode* aNode,
                                                      uint32_t aOffset);
 };
 
 class mozInlineSpellChecker final : public nsIInlineSpellChecker,
-                                    public nsIEditActionListener,
                                     public nsIDOMEventListener,
                                     public nsSupportsWeakReference
 {
 private:
   friend class mozInlineSpellStatus;
   friend class InitEditorSpellCheckCallback;
   friend class UpdateCurrentDictionaryCallback;
   friend class AutoChangeNumPendingSpellChecks;
@@ -171,20 +169,23 @@ private:
   // Set when we have spellchecked after the last edit operation. See the
   // commment at the top of the .cpp file for more info.
   bool mNeedsCheckAfterNavigation;
 
   // Set when we have a pending mozInlineSpellResume which will check
   // the whole document.
   bool mFullSpellCheckScheduled;
 
+  // Set to true when this instance needs to listen to edit actions of
+  // the editor.
+  bool mIsListeningToEditActions;
+
 public:
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_NSIEDITACTIONLISTENER
   NS_DECL_NSIINLINESPELLCHECKER
   NS_DECL_NSIDOMEVENTLISTENER
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozInlineSpellChecker, nsIDOMEventListener)
 
   mozilla::EditorSpellCheck* GetEditorSpellCheck();
 
   // returns true if there are any spell checking dictionaries available
   static bool CanEnableInlineSpellChecking();
@@ -245,23 +246,31 @@ public:
   nsresult UnregisterEventListeners();
   nsresult HandleNavigationEvent(bool aForceWordSpellCheck, int32_t aNewPositionOffset = 0);
 
   already_AddRefed<mozilla::dom::Selection> GetSpellCheckSelection();
   nsresult SaveCurrentSelectionPosition();
 
   nsresult ResumeCheck(mozilla::UniquePtr<mozInlineSpellStatus>&& aStatus);
 
+  // Those methods are called when mTextEditor splits a node or joins the
+  // given nodes.
+  void DidSplitNode(nsINode* aExistingRightNode, nsINode* aNewLeftNode);
+  void DidJoinNodes(nsINode& aRightNode, nsINode& aLeftNode);
+
 protected:
   virtual ~mozInlineSpellChecker();
 
   // called when async nsIEditorSpellCheck methods complete
   nsresult EditorSpellCheckInited();
   nsresult CurrentDictionaryUpdated();
 
   // track the number of pending spell checks and async operations that may lead
   // to spell checks, notifying observers accordingly
   void ChangeNumPendingSpellChecks(int32_t aDelta,
                                    mozilla::TextEditor* aTextEditor = nullptr);
   void NotifyObservers(const char* aTopic, mozilla::TextEditor* aTextEditor);
+
+  void StartToListenToEditActions() { mIsListeningToEditActions = true; }
+  void EndListeningToEditActions() { mIsListeningToEditActions = false; }
 };
 
 #endif // #ifndef mozilla_mozInlineSpellChecker_h
--- a/extensions/spellcheck/src/mozSpellCheckerFactory.cpp
+++ b/extensions/spellcheck/src/mozSpellCheckerFactory.cpp
@@ -3,62 +3,52 @@
  * 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/. */
 
 
 #include "mozilla/ModuleUtils.h"
 #include "mozHunspell.h"
 #include "mozHunspellDirProvider.h"
 #include "mozSpellChecker.h"
-#include "mozInlineSpellChecker.h"
 #include "mozPersonalDictionary.h"
 #include "mozSpellI18NManager.h"
 #include "nsIFile.h"
 
 #define NS_SPELLCHECKER_CID         \
 { /* 8227f019-afc7-461e-b030-9f185d7a0e29 */    \
 0x8227F019, 0xAFC7, 0x461e,                     \
 { 0xB0, 0x30, 0x9F, 0x18, 0x5D, 0x7A, 0x0E, 0x29} }
 
-#define MOZ_INLINESPELLCHECKER_CID         \
-{ /* 9FE5D975-09BD-44aa-A01A-66402EA28657 */    \
-0x9fe5d975, 0x9bd, 0x44aa,                      \
-{ 0xa0, 0x1a, 0x66, 0x40, 0x2e, 0xa2, 0x86, 0x57} }
-
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozHunspell, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(mozHunspellDirProvider)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozSpellChecker, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozPersonalDictionary, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(mozSpellI18NManager)
-NS_GENERIC_FACTORY_CONSTRUCTOR(mozInlineSpellChecker)
 
 NS_DEFINE_NAMED_CID(MOZ_HUNSPELL_CID);
 NS_DEFINE_NAMED_CID(HUNSPELLDIRPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_SPELLCHECKER_CID);
 NS_DEFINE_NAMED_CID(MOZ_PERSONALDICTIONARY_CID);
 NS_DEFINE_NAMED_CID(MOZ_SPELLI18NMANAGER_CID);
-NS_DEFINE_NAMED_CID(MOZ_INLINESPELLCHECKER_CID);
 
 static const mozilla::Module::CIDEntry kSpellcheckCIDs[] = {
     { &kMOZ_HUNSPELL_CID, false, nullptr, mozHunspellConstructor },
     { &kHUNSPELLDIRPROVIDER_CID, false, nullptr, mozHunspellDirProviderConstructor },
     { &kNS_SPELLCHECKER_CID, false, nullptr, mozSpellCheckerConstructor },
     { &kMOZ_PERSONALDICTIONARY_CID, false, nullptr, mozPersonalDictionaryConstructor },
     { &kMOZ_SPELLI18NMANAGER_CID, false, nullptr, mozSpellI18NManagerConstructor },
-    { &kMOZ_INLINESPELLCHECKER_CID, false, nullptr, mozInlineSpellCheckerConstructor },
     { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kSpellcheckContracts[] = {
     { MOZ_HUNSPELL_CONTRACTID, &kMOZ_HUNSPELL_CID },
     { mozHunspellDirProvider::kContractID, &kHUNSPELLDIRPROVIDER_CID },
     { NS_SPELLCHECKER_CONTRACTID, &kNS_SPELLCHECKER_CID },
     { MOZ_PERSONALDICTIONARY_CONTRACTID, &kMOZ_PERSONALDICTIONARY_CID },
     { MOZ_SPELLI18NMANAGER_CONTRACTID, &kMOZ_SPELLI18NMANAGER_CID },
-    { MOZ_INLINESPELLCHECKER_CONTRACTID, &kMOZ_INLINESPELLCHECKER_CID },
     { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kSpellcheckCategories[] = {
     { XPCOM_DIRECTORY_PROVIDER_CATEGORY, "spellcheck-directory-provider", mozHunspellDirProvider::kContractID },
     { nullptr }
 };