+
+
diff --git a/editor/txtsvc/public/nsISpellChecker.h b/editor/txtsvc/public/nsISpellChecker.h
index d1644df77fe..b3545d5dad4 100644
--- a/editor/txtsvc/public/nsISpellChecker.h
+++ b/editor/txtsvc/public/nsISpellChecker.h
@@ -44,9 +44,9 @@
#define NS_SPELLCHECKER_CONTRACTID "@mozilla.org/spellchecker;1"
#define NS_ISPELLCHECKER_IID \
-{ /* E75AC48C-E948-452E-8DB3-30FEE29FE3D2 */ \
-0xe75ac48c, 0xe948, 0x452e, \
- { 0x8d, 0xb3, 0x30, 0xfe, 0xe2, 0x9f, 0xe3, 0xd2 } }
+{ /* 27bff957-b486-40ae-9f5d-af0cdd211868 */ \
+0x27bff957, 0xb486, 0x40ae, \
+ { 0x9f, 0x5d, 0xaf, 0x0c, 0xdd, 0x21, 0x18, 0x68 } }
class nsITextServicesDocument;
class nsString;
@@ -146,6 +146,12 @@ public:
* empty string, spellchecker will be disabled.
*/
NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) = 0;
+
+ /**
+ * Call this on any change in installed dictionaries to ensure that the spell
+ * checker is not using a current dictionary which is no longer available.
+ */
+ NS_IMETHOD CheckCurrentDictionary() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsISpellChecker, NS_ISPELLCHECKER_IID)
diff --git a/extensions/spellcheck/Makefile.in b/extensions/spellcheck/Makefile.in
index e7895eacba6..b270c3e9006 100644
--- a/extensions/spellcheck/Makefile.in
+++ b/extensions/spellcheck/Makefile.in
@@ -44,4 +44,8 @@ include $(DEPTH)/config/autoconf.mk
MODULE = spellchecker
DIRS = idl locales hunspell src
+ifdef ENABLE_TESTS
+DIRS += tests
+endif
+
include $(topsrcdir)/config/rules.mk
diff --git a/extensions/spellcheck/hunspell/src/Makefile.in b/extensions/spellcheck/hunspell/src/Makefile.in
index 7ca1316e308..c53c279bc10 100644
--- a/extensions/spellcheck/hunspell/src/Makefile.in
+++ b/extensions/spellcheck/hunspell/src/Makefile.in
@@ -71,6 +71,8 @@ endif
include $(topsrcdir)/config/rules.mk
+INCLUDES += -I$(topsrcdir)/extensions/spellcheck/src
+
ifdef MOZ_NATIVE_HUNSPELL
CXXFLAGS += $(MOZ_HUNSPELL_CFLAGS)
endif
diff --git a/extensions/spellcheck/hunspell/src/mozHunspell.cpp b/extensions/spellcheck/hunspell/src/mozHunspell.cpp
index 89826d2dab6..8e0eb6a75ee 100644
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.cpp
@@ -41,6 +41,7 @@
* Harri Pitkanen
* Andras Timar
* Tor Lillqvist
+ * Jesper Kristensen (mail@jesperkristensen.dk)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -70,6 +71,8 @@
#include "nsUnicharUtilCIID.h"
#include "nsUnicharUtils.h"
#include "nsCRT.h"
+#include "mozInlineSpellChecker.h"
+#include "mozilla/Services.h"
#include
#include "nsIMemoryReporter.h"
@@ -122,8 +125,7 @@ mozHunspell::Init()
LoadDictionaryList();
- nsCOMPtr obs =
- do_GetService("@mozilla.org/observer-service;1");
+ nsCOMPtr obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(this, "profile-do-change", PR_TRUE);
}
@@ -147,9 +149,6 @@ NS_IMETHODIMP mozHunspell::GetDictionary(PRUnichar **aDictionary)
{
NS_ENSURE_ARG_POINTER(aDictionary);
- if (mDictionary.IsEmpty())
- return NS_ERROR_NOT_INITIALIZED;
-
*aDictionary = ToNewUnicode(mDictionary);
return *aDictionary ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
@@ -161,8 +160,23 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const PRUnichar *aDictionary)
{
NS_ENSURE_ARG_POINTER(aDictionary);
- if (mDictionary.Equals(aDictionary))
+ if (nsDependentString(aDictionary).IsEmpty()) {
+ delete mHunspell;
+ mHunspell = nsnull;
+ mDictionary.AssignLiteral("");
+ mAffixFileName.AssignLiteral("");
+ mLanguage.AssignLiteral("");
+ mDecoder = nsnull;
+ mEncoder = nsnull;
+
+ nsCOMPtr obs = mozilla::services::GetObserverService();
+ if (obs) {
+ obs->NotifyObservers(nsnull,
+ SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
+ nsnull);
+ }
return NS_OK;
+ }
nsIFile* affFile = mDictionaries.GetWeak(nsDependentString(aDictionary));
if (!affFile)
@@ -178,6 +192,9 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const PRUnichar *aDictionary)
nsresult rv = affFile->GetNativePath(affFileName);
NS_ENSURE_SUCCESS(rv, rv);
+ if (mAffixFileName.Equals(affFileName.get()))
+ return NS_OK;
+
dictFileName = affFileName;
PRInt32 dotPos = dictFileName.RFindChar('.');
if (dotPos == -1)
@@ -191,6 +208,7 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const PRUnichar *aDictionary)
delete mHunspell;
mDictionary = aDictionary;
+ mAffixFileName = affFileName;
mHunspell = new Hunspell(affFileName.get(),
dictFileName.get());
@@ -222,6 +240,13 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const PRUnichar *aDictionary)
else
mLanguage = Substring(mDictionary, 0, pos);
+ nsCOMPtr obs = mozilla::services::GetObserverService();
+ if (obs) {
+ obs->NotifyObservers(nsnull,
+ SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
+ nsnull);
+ }
+
return NS_OK;
}
@@ -333,6 +358,14 @@ NS_IMETHODIMP mozHunspell::GetDictionaryList(PRUnichar ***aDictionaries,
return NS_OK;
}
+static PLDHashOperator
+FindFirstString(const nsAString& aString, nsIFile* aFile, void* aClosure)
+{
+ nsAString *dic = (nsAString*) aClosure;
+ dic->Assign(aString);
+ return PL_DHASH_STOP;
+}
+
void
mozHunspell::LoadDictionaryList()
{
@@ -345,6 +378,7 @@ mozHunspell::LoadDictionaryList()
if (!dirSvc)
return;
+ // find built in dictionaries
nsCOMPtr dictDir;
rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY,
NS_GET_IID(nsIFile), getter_AddRefs(dictDir));
@@ -372,6 +406,7 @@ mozHunspell::LoadDictionaryList()
}
}
+ // find dictionaries from extensions requiring restart
nsCOMPtr dictDirs;
rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY_LIST,
NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dictDirs));
@@ -387,6 +422,29 @@ mozHunspell::LoadDictionaryList()
if (dictDir)
LoadDictionariesFromDir(dictDir);
}
+
+ // find dictionaries from restartless extensions
+ for (PRUint32 i = 0; i < mDynamicDirectories.Count(); i++) {
+ LoadDictionariesFromDir(mDynamicDirectories[i]);
+ }
+
+ // Now we have finished updating the list of dictionaries, update the current
+ // dictionary and any editors which may use it.
+ mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking();
+
+ // Check if the current dictionary is still available.
+ // If not, try to replace it with another dictionary of the same language.
+ if (!mDictionary.IsEmpty()) {
+ rv = SetDictionary(mDictionary.get());
+ if (NS_SUCCEEDED(rv))
+ return;
+ }
+
+ // If the current dictionary has gone, and we don't have a good replacement,
+ // set no current dictionary.
+ if (!mDictionary.IsEmpty()) {
+ SetDictionary(EmptyString().get());
+ }
}
NS_IMETHODIMP
@@ -542,3 +600,19 @@ mozHunspell::Observe(nsISupports* aSubj, const char *aTopic,
return NS_OK;
}
+
+/* void addDirectory(in nsIFile dir); */
+NS_IMETHODIMP mozHunspell::AddDirectory(nsIFile *aDir)
+{
+ mDynamicDirectories.AppendObject(aDir);
+ LoadDictionaryList();
+ return NS_OK;
+}
+
+/* void removeDirectory(in nsIFile dir); */
+NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir)
+{
+ mDynamicDirectories.RemoveObject(aDir);
+ LoadDictionaryList();
+ return NS_OK;
+}
diff --git a/extensions/spellcheck/hunspell/src/mozHunspell.h b/extensions/spellcheck/hunspell/src/mozHunspell.h
index 5b76d0c3601..4b81b06cddc 100644
--- a/extensions/spellcheck/hunspell/src/mozHunspell.h
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.h
@@ -41,6 +41,7 @@
* Harri Pitkanen
* Andras Timar
* Tor Lillqvist
+ * Jesper Kristensen (mail@jesperkristensen.dk)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -64,6 +65,7 @@
#include "mozIPersonalDictionary.h"
#include "nsString.h"
#include "nsCOMPtr.h"
+#include "nsCOMArray.h"
#include "nsIObserver.h"
#include "nsIUnicodeEncoder.h"
#include "nsIUnicodeDecoder.h"
@@ -109,6 +111,10 @@ protected:
nsInterfaceHashtable mDictionaries;
nsString mDictionary;
nsString mLanguage;
+ nsCString mAffixFileName;
+
+ // dynamic dirs used to search for dictionaries
+ nsCOMArray mDynamicDirectories;
Hunspell *mHunspell;
diff --git a/extensions/spellcheck/idl/mozISpellCheckingEngine.idl b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl
index e880d87353e..db505f9907d 100644
--- a/extensions/spellcheck/idl/mozISpellCheckingEngine.idl
+++ b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl
@@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
+ * Jesper Kristensen
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -40,7 +41,7 @@
interface nsIFile;
interface mozIPersonalDictionary;
-[scriptable, uuid(6eb307d6-3567-481a-971a-feb666b8ae72)]
+[scriptable, uuid(8ba643a4-7ddc-4662-b976-7ec123843f10)]
/**
* This interface represents a SpellChecker.
@@ -48,12 +49,23 @@ interface mozIPersonalDictionary;
interface mozISpellCheckingEngine : nsISupports {
/**
- * The name of the current dictionary
+ * The name of the current dictionary. Is either a value from
+ * getDictionaryList or the empty string if no dictionary is selected.
+ * Setting this attribute to a value not in getDictionaryList will throw
+ * NS_ERROR_FILE_NOT_FOUND.
+ *
+ * The spellcheck engine will send a notification with
+ * "spellcheck-dictionary-update" as topic when this changes.
+ * If the dictionary is changed to no dictionary (the empty string), an
+ * observer is allowed to set another dictionary before it returns.
*/
attribute wstring dictionary;
/**
* The language this spellchecker is using when checking
+ *
+ * The spellcheck engine will send a notification with
+ * "spellcheck-dictionary-update" as topic when this changes.
*/
readonly attribute wstring language;
@@ -89,11 +101,17 @@ interface mozISpellCheckingEngine : nsISupports {
/**
* check a word
+ *
+ * The spellcheck engine will send a notification with
+ * "spellcheck-dictionary-update" as topic when this changes.
*/
boolean check(in wstring word);
/**
* get a list of suggestions for a misspelled word
+ *
+ * The spellcheck engine will send a notification with
+ * "spellcheck-dictionary-update" as topic when this changes.
*/
void suggest(in wstring word,[array, size_is(count)] out wstring suggestions, out PRUint32 count);
@@ -101,9 +119,22 @@ interface mozISpellCheckingEngine : nsISupports {
* Load dictionaries from the specified dir
*/
void loadDictionariesFromDir(in nsIFile dir);
+
+ /**
+ * Add dictionaries from a directory to the spell checker
+ */
+ void addDirectory(in nsIFile dir);
+
+ /**
+ * Remove dictionaries from a directory from the spell checker
+ */
+ void removeDirectory(in nsIFile dir);
};
%{C++
#define DICTIONARY_SEARCH_DIRECTORY "DictD"
#define DICTIONARY_SEARCH_DIRECTORY_LIST "DictDL"
+
+#define SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION \
+ "spellcheck-dictionary-update"
%}
diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.cpp b/extensions/spellcheck/src/mozInlineSpellChecker.cpp
index e159d38e567..12d9b9bc3d4 100644
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp
@@ -600,9 +600,9 @@ nsresult mozInlineSpellChecker::Cleanup(PRBool aDestroyingFrames)
// do that and caches the result so we don't have to keep allocating those
// objects if there are no dictionaries or spellchecking.
//
-// This caching will prevent adding dictionaries at runtime if we start out
-// with no dictionaries! Installing dictionaries as extensions will require
-// a restart anyway, so it shouldn't be a problem.
+// Whenever dictionaries are added or removed at runtime, this value must be
+// updated before an observer notification is sent out about the change, to
+// avoid editors getting a wrong cached result.
PRBool // static
mozInlineSpellChecker::CanEnableInlineSpellChecking()
@@ -625,6 +625,12 @@ mozInlineSpellChecker::CanEnableInlineSpellChecking()
return (gCanEnableSpellChecking == SpellCheck_Available);
}
+void // static
+mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking()
+{
+ gCanEnableSpellChecking = SpellCheck_Uninitialized;
+}
+
// mozInlineSpellChecker::RegisterEventListeners
//
// The inline spell checker listens to mouse events and keyboard navigation+ // events.
diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.h b/extensions/spellcheck/src/mozInlineSpellChecker.h
index 183422fd02f..f371ed72f8e 100644
--- a/extensions/spellcheck/src/mozInlineSpellChecker.h
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.h
@@ -229,8 +229,10 @@ public:
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozInlineSpellChecker, nsIDOMEventListener)
- // returns true if it looks likely that we can enable real-time spell checking
+ // returns true if there are any spell checking dictionaries available
static PRBool CanEnableInlineSpellChecking();
+ // update the cached value whenever the list of available dictionaries changes
+ static void UpdateCanEnableInlineSpellChecking();
nsresult Blur(nsIDOMEvent* aEvent);
nsresult MouseClick(nsIDOMEvent* aMouseEvent);
diff --git a/extensions/spellcheck/src/mozSpellChecker.cpp b/extensions/spellcheck/src/mozSpellChecker.cpp
index 96832848549..0ea96376c38 100644
--- a/extensions/spellcheck/src/mozSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozSpellChecker.cpp
@@ -18,6 +18,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): David Einstein Deinst@world.std.com
+ * Jesper Kristensen
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -77,9 +78,6 @@ mozSpellChecker::Init()
mPersonalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
mSpellCheckingEngine = nsnull;
- mCurrentEngineContractId = nsnull;
- mDictionariesMap.Init();
- InitSpellCheckDictionaryMap();
return NS_OK;
}
@@ -307,35 +305,45 @@ mozSpellChecker::GetPersonalDictionary(nsTArray *aWordList)
return NS_OK;
}
-struct AppendNewStruct
-{
- nsTArray *dictionaryList;
- PRBool failed;
-};
-
-static PLDHashOperator
-AppendNewString(const nsAString& aString, nsCString*, void* aClosure)
-{
- AppendNewStruct *ans = (AppendNewStruct*) aClosure;
-
- if (!ans->dictionaryList->AppendElement(aString))
- {
- ans->failed = PR_TRUE;
- return PL_DHASH_STOP;
- }
-
- return PL_DHASH_NEXT;
-}
-
NS_IMETHODIMP
mozSpellChecker::GetDictionaryList(nsTArray *aDictionaryList)
{
- AppendNewStruct ans = {aDictionaryList, PR_FALSE};
+ nsresult rv;
- mDictionariesMap.EnumerateRead(AppendNewString, &ans);
+ // For catching duplicates
+ nsClassHashtable dictionaries;
+ dictionaries.Init();
- if (ans.failed)
- return NS_ERROR_OUT_OF_MEMORY;
+ nsCOMArray spellCheckingEngines;
+ rv = GetEngineList(&spellCheckingEngines);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ for (PRUint32 i = 0; i < spellCheckingEngines.Count(); i++) {
+ nsCOMPtr engine = spellCheckingEngines[i];
+
+ PRUint32 count = 0;
+ PRUnichar **words = NULL;
+ engine->GetDictionaryList(&words, &count);
+ for (PRUint32 k = 0; k < count; k++) {
+ nsAutoString dictName;
+
+ dictName.Assign(words[k]);
+
+ // Skip duplicate dictionaries. Only take the first one
+ // for each name.
+ if (dictionaries.Get(dictName, NULL))
+ continue;
+
+ dictionaries.Put(dictName, NULL);
+
+ if (!aDictionaryList->AppendElement(dictName)) {
+ NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ }
+
+ NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words);
+ }
return NS_OK;
}
@@ -343,11 +351,12 @@ mozSpellChecker::GetDictionaryList(nsTArray *aDictionaryList)
NS_IMETHODIMP
mozSpellChecker::GetCurrentDictionary(nsAString &aDictionary)
{
+ if (!mSpellCheckingEngine) {
+ aDictionary.AssignLiteral("");
+ return NS_OK;
+ }
+
nsXPIDLString dictname;
-
- if (!mSpellCheckingEngine)
- return NS_ERROR_NOT_INITIALIZED;
-
mSpellCheckingEngine->GetDictionary(getter_Copies(dictname));
aDictionary = dictname;
return NS_OK;
@@ -356,44 +365,62 @@ mozSpellChecker::GetCurrentDictionary(nsAString &aDictionary)
NS_IMETHODIMP
mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary)
{
- nsresult rv;
- nsCString *contractId;
+ mSpellCheckingEngine = nsnull;
if (aDictionary.IsEmpty()) {
- mCurrentEngineContractId = nsnull;
- mSpellCheckingEngine = nsnull;
return NS_OK;
}
- if (!mDictionariesMap.Get(aDictionary, &contractId)){
- NS_WARNING("Dictionary not found");
- return NS_ERROR_NOT_AVAILABLE;
+ nsresult rv;
+ nsCOMArray spellCheckingEngines;
+ rv = GetEngineList(&spellCheckingEngines);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ for (PRUint32 i = 0; i < spellCheckingEngines.Count(); i++) {
+ // We must set mSpellCheckingEngine before we call SetDictionary, since
+ // SetDictionary calls back to this spell checker to check if the
+ // dictionary was set
+ mSpellCheckingEngine = spellCheckingEngines[i];
+
+ rv = mSpellCheckingEngine->SetDictionary(PromiseFlatString(aDictionary).get());
+
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr personalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
+ mSpellCheckingEngine->SetPersonalDictionary(personalDictionary.get());
+
+ return NS_OK;
+ }
}
- if (!mCurrentEngineContractId || !mCurrentEngineContractId->Equals(*contractId)){
- mSpellCheckingEngine = do_GetService(contractId->get(), &rv);
- if (NS_FAILED(rv))
- return rv;
-
- mCurrentEngineContractId = contractId;
- }
-
- nsresult res;
- res = mSpellCheckingEngine->SetDictionary(PromiseFlatString(aDictionary).get());
- if(NS_FAILED(res)){
- NS_WARNING("Dictionary load failed");
- return res;
- }
-
- mSpellCheckingEngine->SetPersonalDictionary(mPersonalDictionary);
-
- nsXPIDLString language;
+ mSpellCheckingEngine = NULL;
- nsCOMPtr serv(do_GetService("@mozilla.org/spellchecker/i18nmanager;1", &res));
- if(serv && NS_SUCCEEDED(res)){
- res = serv->GetUtil(language.get(),getter_AddRefs(mConverter));
+ // We could not find any engine with the requested dictionary
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+mozSpellChecker::CheckCurrentDictionary()
+{
+ // If the current dictionary has been uninstalled, we need to stop using it.
+ // This happens when there is a current engine, but that engine has no
+ // current dictionary.
+
+ if (!mSpellCheckingEngine) {
+ // We didn't have a current dictionary
+ return NS_OK;
}
- return res;
+
+ nsXPIDLString dictname;
+ mSpellCheckingEngine->GetDictionary(getter_Copies(dictname));
+
+ if (!dictname.IsEmpty()) {
+ // We still have a current dictionary
+ return NS_OK;
+ }
+
+ // We had a current dictionary, but it has gone, so we cannot use it anymore.
+ mSpellCheckingEngine = nsnull;
+ return NS_OK;
}
nsresult
@@ -477,11 +504,10 @@ mozSpellChecker::GetCurrentBlockIndex(nsITextServicesDocument *aDoc, PRInt32 *ou
}
nsresult
-mozSpellChecker::InitSpellCheckDictionaryMap()
+mozSpellChecker::GetEngineList(nsCOMArray* aSpellCheckingEngines)
{
nsresult rv;
PRBool hasMoreEngines;
- nsTArray contractIds;
nsCOMPtr catMgr = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
if (!catMgr)
@@ -508,52 +534,24 @@ mozSpellChecker::InitSpellCheckDictionaryMap()
if (NS_FAILED(rv))
return rv;
- contractIds.AppendElement(contractId);
- }
-
- contractIds.AppendElement(NS_LITERAL_CSTRING(DEFAULT_SPELL_CHECKER));
-
- // Retrieve dictionaries from all available spellcheckers and
- // fill mDictionariesMap hash (only the first dictionary with the
- // each name is used).
- for (PRUint32 i=0;i < contractIds.Length();i++){
- PRUint32 count,k;
- PRUnichar **words;
-
- const nsCString& contractId = contractIds[i];
-
// Try to load spellchecker engine. Ignore errors silently
// except for the last one (HunSpell).
nsCOMPtr engine =
do_GetService(contractId.get(), &rv);
- if (NS_FAILED(rv)){
- // Fail if not succeeded to load HunSpell. Ignore errors
- // for external spellcheck engines.
- if (i==contractIds.Length()-1){
- return rv;
- }
-
- continue;
+ if (NS_SUCCEEDED(rv)) {
+ aSpellCheckingEngines->AppendObject(engine);
}
-
- engine->GetDictionaryList(&words,&count);
- for(k=0;k engine =
+ do_GetService(DEFAULT_SPELL_CHECKER, &rv);
+ if (NS_FAILED(rv)) {
+ // Fail if not succeeded to load HunSpell. Ignore errors
+ // for external spellcheck engines.
+ return rv;
+ }
+ aSpellCheckingEngines->AppendObject(engine);
+
return NS_OK;
}
diff --git a/extensions/spellcheck/src/mozSpellChecker.h b/extensions/spellcheck/src/mozSpellChecker.h
index 142c0ee15f4..10f52f21a9a 100644
--- a/extensions/spellcheck/src/mozSpellChecker.h
+++ b/extensions/spellcheck/src/mozSpellChecker.h
@@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): David Einstein Deinst@world.std.com
+ * Jesper Kristensen
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -39,6 +40,7 @@
#define mozSpellChecker_h__
#include "nsCOMPtr.h"
+#include "nsCOMArray.h"
#include "nsISpellChecker.h"
#include "nsString.h"
#include "nsITextServicesDocument.h"
@@ -75,17 +77,13 @@ public:
NS_IMETHOD GetDictionaryList(nsTArray *aDictionaryList);
NS_IMETHOD GetCurrentDictionary(nsAString &aDictionary);
NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary);
+ NS_IMETHOD CheckCurrentDictionary();
protected:
nsCOMPtr mConverter;
nsCOMPtr mTsDoc;
nsCOMPtr mPersonalDictionary;
- // Hastable maps directory name to the spellchecker contract ID
- nsClassHashtable mDictionariesMap;
-
- nsString mDictionaryName;
- nsCString *mCurrentEngineContractId;
nsCOMPtr mSpellCheckingEngine;
PRBool mFromStart;
@@ -93,6 +91,6 @@ protected:
nsresult GetCurrentBlockIndex(nsITextServicesDocument *aDoc, PRInt32 *outBlockIndex);
- nsresult InitSpellCheckDictionaryMap();
+ nsresult GetEngineList(nsCOMArray *aDictionaryList);
};
#endif // mozSpellChecker_h__
diff --git a/extensions/spellcheck/src/mozSpellCheckerFactory.cpp b/extensions/spellcheck/src/mozSpellCheckerFactory.cpp
index 8ab97debbca..e4f917a8307 100644
--- a/extensions/spellcheck/src/mozSpellCheckerFactory.cpp
+++ b/extensions/spellcheck/src/mozSpellCheckerFactory.cpp
@@ -59,39 +59,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(mozHunspellDirProvider)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozSpellChecker, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozPersonalDictionary, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(mozSpellI18NManager)
-
-// This special constructor for the inline spell checker asks the inline
-// spell checker if we can create spell checking objects at all (ie, if there
-// are any dictionaries loaded) before trying to create one. The static
-// CanEnableInlineSpellChecking caches the value so this will be faster (we
-// have to run this code for every edit box we create, as well as for every
-// right click in those edit boxes).
-static nsresult
-mozInlineSpellCheckerConstructor(nsISupports *aOuter, REFNSIID aIID,
- void **aResult)
-{
- if (! mozInlineSpellChecker::CanEnableInlineSpellChecking())
- return NS_ERROR_FAILURE;
-
- nsresult rv;
-
- *aResult = NULL;
- if (NULL != aOuter) {
- rv = NS_ERROR_NO_AGGREGATION;
- return rv;
- }
-
- mozInlineSpellChecker* inst = new mozInlineSpellChecker();
- if (NULL == inst) {
- rv = NS_ERROR_OUT_OF_MEMORY;
- return rv;
- }
- NS_ADDREF(inst);
- rv = inst->QueryInterface(aIID, aResult);
- NS_RELEASE(inst);
-
- return rv;
-}
+NS_GENERIC_FACTORY_CONSTRUCTOR(mozInlineSpellChecker)
NS_DEFINE_NAMED_CID(MOZ_HUNSPELL_CID);
NS_DEFINE_NAMED_CID(HUNSPELLDIRPROVIDER_CID);
diff --git a/extensions/spellcheck/tests/Makefile.in b/extensions/spellcheck/tests/Makefile.in
new file mode 100644
index 00000000000..686fe393fd4
--- /dev/null
+++ b/extensions/spellcheck/tests/Makefile.in
@@ -0,0 +1,48 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = extensions/spellcheck/tests
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = chrome
+
+include $(topsrcdir)/config/rules.mk
diff --git a/extensions/spellcheck/tests/chrome/Makefile.in b/extensions/spellcheck/tests/chrome/Makefile.in
new file mode 100644
index 00000000000..da60413beb7
--- /dev/null
+++ b/extensions/spellcheck/tests/chrome/Makefile.in
@@ -0,0 +1,54 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = extensions/spellcheck/tests/chrome
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = base map
+
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = test_add_remove_dictionaries.xul \
+ $(NULL)
+
+libs:: $(_TEST_FILES)
+ $(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
diff --git a/extensions/spellcheck/tests/chrome/base/Makefile.in b/extensions/spellcheck/tests/chrome/base/Makefile.in
new file mode 100644
index 00000000000..04159b2ca7a
--- /dev/null
+++ b/extensions/spellcheck/tests/chrome/base/Makefile.in
@@ -0,0 +1,52 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = extensions/spellcheck/tests/chrome/base
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = base_utf.dic \
+ base_utf.aff \
+ $(NULL)
+
+libs:: $(_TEST_FILES)
+ $(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
diff --git a/extensions/spellcheck/tests/chrome/base/base_utf.aff b/extensions/spellcheck/tests/chrome/base/base_utf.aff
new file mode 100644
index 00000000000..493157b3018
--- /dev/null
+++ b/extensions/spellcheck/tests/chrome/base/base_utf.aff
@@ -0,0 +1,198 @@
+# OpenOffice.org’s en_US.aff file
+# with Unicode apostrophe: ’
+
+SET UTF-8
+TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ'
+
+MAXNGRAMSUGS 1
+WORDCHARS .'’
+
+PFX A Y 1
+PFX A 0 re .
+
+PFX I Y 1
+PFX I 0 in .
+
+PFX U Y 1
+PFX U 0 un .
+
+PFX C Y 1
+PFX C 0 de .
+
+PFX E Y 1
+PFX E 0 dis .
+
+PFX F Y 1
+PFX F 0 con .
+
+PFX K Y 1
+PFX K 0 pro .
+
+SFX V N 2
+SFX V e ive e
+SFX V 0 ive [^e]
+
+SFX N Y 3
+SFX N e ion e
+SFX N y ication y
+SFX N 0 en [^ey]
+
+SFX X Y 3
+SFX X e ions e
+SFX X y ications y
+SFX X 0 ens [^ey]
+
+SFX H N 2
+SFX H y ieth y
+SFX H 0 th [^y]
+
+SFX Y Y 1
+SFX Y 0 ly .
+
+SFX G Y 2
+SFX G e ing e
+SFX G 0 ing [^e]
+
+SFX J Y 2
+SFX J e ings e
+SFX J 0 ings [^e]
+
+SFX D Y 4
+SFX D 0 d e
+SFX D y ied [^aeiou]y
+SFX D 0 ed [^ey]
+SFX D 0 ed [aeiou]y
+
+SFX T N 4
+SFX T 0 st e
+SFX T y iest [^aeiou]y
+SFX T 0 est [aeiou]y
+SFX T 0 est [^ey]
+
+SFX R Y 4
+SFX R 0 r e
+SFX R y ier [^aeiou]y
+SFX R 0 er [aeiou]y
+SFX R 0 er [^ey]
+
+SFX Z Y 4
+SFX Z 0 rs e
+SFX Z y iers [^aeiou]y
+SFX Z 0 ers [aeiou]y
+SFX Z 0 ers [^ey]
+
+SFX S Y 4
+SFX S y ies [^aeiou]y
+SFX S 0 s [aeiou]y
+SFX S 0 es [sxzh]
+SFX S 0 s [^sxzhy]
+
+SFX P Y 3
+SFX P y iness [^aeiou]y
+SFX P 0 ness [aeiou]y
+SFX P 0 ness [^y]
+
+SFX M Y 1
+SFX M 0 's .
+
+SFX B Y 3
+SFX B 0 able [^aeiou]
+SFX B 0 able ee
+SFX B e able [^aeiou]e
+
+SFX L Y 1
+SFX L 0 ment .
+
+REP 88
+REP a ei
+REP ei a
+REP a ey
+REP ey a
+REP ai ie
+REP ie ai
+REP are air
+REP are ear
+REP are eir
+REP air are
+REP air ere
+REP ere air
+REP ere ear
+REP ere eir
+REP ear are
+REP ear air
+REP ear ere
+REP eir are
+REP eir ere
+REP ch te
+REP te ch
+REP ch ti
+REP ti ch
+REP ch tu
+REP tu ch
+REP ch s
+REP s ch
+REP ch k
+REP k ch
+REP f ph
+REP ph f
+REP gh f
+REP f gh
+REP i igh
+REP igh i
+REP i uy
+REP uy i
+REP i ee
+REP ee i
+REP j di
+REP di j
+REP j gg
+REP gg j
+REP j ge
+REP ge j
+REP s ti
+REP ti s
+REP s ci
+REP ci s
+REP k cc
+REP cc k
+REP k qu
+REP qu k
+REP kw qu
+REP o eau
+REP eau o
+REP o ew
+REP ew o
+REP oo ew
+REP ew oo
+REP ew ui
+REP ui ew
+REP oo ui
+REP ui oo
+REP ew u
+REP u ew
+REP oo u
+REP u oo
+REP u oe
+REP oe u
+REP u ieu
+REP ieu u
+REP ue ew
+REP ew ue
+REP uff ough
+REP oo ieu
+REP ieu oo
+REP ier ear
+REP ear ier
+REP ear air
+REP air ear
+REP w qu
+REP qu w
+REP z ss
+REP ss z
+REP shun tion
+REP shun sion
+REP shun cion
+McDonalds’sá/w
+McDonald’sszá/g3) st:McDonald’s po:noun_prs is:TRANS
+McDonald’sszal/g4) st:McDonald’s po:noun_prs is:INSTR
+McDonald’ssal/w
diff --git a/extensions/spellcheck/tests/chrome/base/base_utf.dic b/extensions/spellcheck/tests/chrome/base/base_utf.dic
new file mode 100644
index 00000000000..b2b536d2854
--- /dev/null
+++ b/extensions/spellcheck/tests/chrome/base/base_utf.dic
@@ -0,0 +1,29 @@
+28
+created/U
+create/XKVNGADS
+imply/GNSDX
+natural/PUY
+like/USPBY
+convey/BDGS
+look/GZRDS
+text
+hello
+said
+sawyer
+NASA
+rotten
+day
+tomorrow
+seven
+FAQ/SM
+can’t
+doesn’t
+etc
+won’t
+lip
+text
+horrifying
+speech
+suggest
+uncreate/V
+Hunspell
diff --git a/extensions/spellcheck/tests/chrome/map/Makefile.in b/extensions/spellcheck/tests/chrome/map/Makefile.in
new file mode 100644
index 00000000000..f9da7553bee
--- /dev/null
+++ b/extensions/spellcheck/tests/chrome/map/Makefile.in
@@ -0,0 +1,52 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = extensions/spellcheck/tests/chrome/map
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = maputf.dic \
+ maputf.aff \
+ $(NULL)
+
+libs:: $(_TEST_FILES)
+ $(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
diff --git a/extensions/spellcheck/tests/chrome/map/maputf.aff b/extensions/spellcheck/tests/chrome/map/maputf.aff
new file mode 100644
index 00000000000..30edb2a7850
--- /dev/null
+++ b/extensions/spellcheck/tests/chrome/map/maputf.aff
@@ -0,0 +1,11 @@
+# With MAP suggestion, Hunspell can add missing accents to a word.
+
+SET UTF-8
+
+# switch off ngram suggestion for testing
+MAXNGRAMSUGS 0
+
+MAP 3
+MAP uúü
+MAP öóo
+MAP ß(ss)
diff --git a/extensions/spellcheck/tests/chrome/map/maputf.dic b/extensions/spellcheck/tests/chrome/map/maputf.dic
new file mode 100644
index 00000000000..1c6fa8d0589
--- /dev/null
+++ b/extensions/spellcheck/tests/chrome/map/maputf.dic
@@ -0,0 +1,4 @@
+3
+Frühstück
+tükörfúró
+groß
diff --git a/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul b/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul
new file mode 100644
index 00000000000..8299c2a9313
--- /dev/null
+++ b/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul
@@ -0,0 +1,110 @@
+
+
+
+
+ Add and remove dictionaries test
+
+
+
+
+
+
diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp
index 3d8a391ec05..688795ffd0d 100644
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -2522,6 +2522,7 @@ BasicShadowableImageLayer::Paint(gfxContext* aContext)
nsRefPtr backSurface =
BasicManager()->OpenDescriptor(mBackBuffer);
nsRefPtr tmpCtx = new gfxContext(backSurface);
+ tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
PaintContext(pat,
nsIntRegion(nsIntRect(0, 0, mSize.width, mSize.height)),
nsnull, 1.0, tmpCtx);
diff --git a/gfx/tests/crashtests/686190-1.html b/gfx/tests/crashtests/686190-1.html
new file mode 100644
index 00000000000..26cda094fa8
--- /dev/null
+++ b/gfx/tests/crashtests/686190-1.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+xyzzy
+
+