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
--- 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 }
};