summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2017-08-01 16:06:43 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-02-02 19:23:51 +0100
commit6d3a0633543c2f6dfa3cb82aab519ac5fbd33e35 (patch)
treed081843307b735d415ef822f97f6d2ead87b6da6
parentcd3c3c6018409a6405697927791a069db9ab1a01 (diff)
downloadUXP-6d3a0633543c2f6dfa3cb82aab519ac5fbd33e35.tar
UXP-6d3a0633543c2f6dfa3cb82aab519ac5fbd33e35.tar.gz
UXP-6d3a0633543c2f6dfa3cb82aab519ac5fbd33e35.tar.lz
UXP-6d3a0633543c2f6dfa3cb82aab519ac5fbd33e35.tar.xz
UXP-6d3a0633543c2f6dfa3cb82aab519ac5fbd33e35.zip
Fix spellchecker dictionary logic.
This fixes #6.
-rw-r--r--editor/composer/nsEditorSpellCheck.cpp300
-rw-r--r--modules/libpref/init/all.js3
2 files changed, 118 insertions, 185 deletions
diff --git a/editor/composer/nsEditorSpellCheck.cpp b/editor/composer/nsEditorSpellCheck.cpp
index 7cae48c1f..790480034 100644
--- a/editor/composer/nsEditorSpellCheck.cpp
+++ b/editor/composer/nsEditorSpellCheck.cpp
@@ -594,45 +594,24 @@ nsEditorSpellCheck::SetCurrentDictionary(const nsAString& aDictionary)
// Ignore pending dictionary fetchers by increasing this number.
mDictionaryFetcherGroup++;
- uint32_t flags = 0;
- mEditor->GetFlags(&flags);
- if (!(flags & nsIPlaintextEditor::eEditorMailMask)) {
- if (!aDictionary.IsEmpty() && (mPreferredLang.IsEmpty() ||
- !mPreferredLang.Equals(aDictionary,
- nsCaseInsensitiveStringComparator()))) {
- // When user sets dictionary manually, we store this value associated
- // with editor url, if it doesn't match the document language exactly.
- // For example on "en" sites, we need to store "en-GB", otherwise
- // the language might jump back to en-US although the user explicitly
- // chose otherwise.
- StoreCurrentDictionary(mEditor, aDictionary);
-#ifdef DEBUG_DICT
- printf("***** Writing content preferences for |%s|\n",
- NS_ConvertUTF16toUTF8(aDictionary).get());
-#endif
- } else {
- // If user sets a dictionary matching the language defined by
- // document, we consider content pref has been canceled, and we clear it.
- ClearCurrentDictionary(mEditor);
-#ifdef DEBUG_DICT
- printf("***** Clearing content preferences for |%s|\n",
- NS_ConvertUTF16toUTF8(aDictionary).get());
-#endif
- }
-
- // Also store it in as a preference, so we can use it as a fallback.
- // We don't want this for mail composer because it uses
- // "spellchecker.dictionary" as a preference.
- Preferences::SetString("spellchecker.dictionary", aDictionary);
-#ifdef DEBUG_DICT
- printf("***** Storing spellchecker.dictionary |%s|\n",
- NS_ConvertUTF16toUTF8(aDictionary).get());
-#endif
+ if (mPreferredLang.IsEmpty() ||
+ !mPreferredLang.Equals(aDictionary, nsCaseInsensitiveStringComparator())) {
+ // When user sets dictionary manually, we store this value associated
+ // with editor url, if it doesn't match the document language exactly.
+ // For example on "en" sites, we need to store "en-GB", otherwise
+ // the language might jump back to en-US although the user explicitly
+ // chose otherwise.
+ StoreCurrentDictionary(mEditor, aDictionary);
+ } else {
+ // If user sets a dictionary matching the language defined by
+ // document, we consider content pref has been canceled, and we clear it.
+ ClearCurrentDictionary(mEditor);
}
}
return mSpellChecker->SetCurrentDictionary(aDictionary);
}
+
NS_IMETHODIMP
nsEditorSpellCheck::UninitSpellChecker()
{
@@ -771,23 +750,16 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
/*
* We try to derive the dictionary to use based on the following priorities:
- * 1) Content preference, so the language the user set for the site before.
- * (Introduced in bug 678842 and corrected in bug 717433.)
- * 2) Language set by the website, or any other dictionary that partly
- * matches that. (Introduced in bug 338427.)
- * Eg. if the website is "en-GB", a user who only has "en-US" will get
- * that. If the website is generic "en", the user will get one of the
- * "en-*" installed, (almost) at random.
- * However, we prefer what is stored in "spellchecker.dictionary",
- * so if the user chose "en-AU" before, they will get "en-AU" on a plain
- * "en" site. (Introduced in bug 682564.)
- * 3) The value of "spellchecker.dictionary" which reflects a previous
- * language choice of the user (on another site).
- * (This was the original behaviour before the aforementioned bugs
- * landed).
- * 4) The user's locale.
- * 5) Use the current dictionary that is currently set.
- * 6) The content of the "LANG" environment variable (if set).
+ * 1) Content preference: the language the user set for the site before.
+ * 2) The value of "spellchecker.dictionary.override" which reflects a
+ * global choice of language explicitly set by the user.
+ * 3) Language set by the website, or any other dictionary that partly matches that.
+ * Eg. if the website is "en-GB", a user who only has "en-US" will get that.
+ * If the website is generic "en", the user will get one of the "en-*" installed,
+ * pretty much at random.
+ * 4) The user's locale
+ * 5) Leave the current dictionary set.
+ * 6) The content of the "LANG" environment variable (if set)
* 7) The first spell check dictionary installed.
*/
@@ -795,131 +767,100 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
// https://html.spec.whatwg.org/#attr-lang
// This is used in SetCurrentDictionary.
mPreferredLang.Assign(aFetcher->mRootContentLang);
-#ifdef DEBUG_DICT
- printf("***** mPreferredLang (element) |%s|\n",
- NS_ConvertUTF16toUTF8(mPreferredLang).get());
-#endif
// If no luck, try the "Content-Language" header.
if (mPreferredLang.IsEmpty()) {
mPreferredLang.Assign(aFetcher->mRootDocContentLang);
-#ifdef DEBUG_DICT
- printf("***** mPreferredLang (content-language) |%s|\n",
- NS_ConvertUTF16toUTF8(mPreferredLang).get());
-#endif
}
-
- // Auxiliary status.
- nsresult rv2;
-
- // We obtain a list of available dictionaries.
- nsTArray<nsString> dictList;
- rv2 = mSpellChecker->GetDictionaryList(&dictList);
- NS_ENSURE_SUCCESS(rv2, rv2);
-
+
// Priority 1:
+ // Get language from content prefs, if set.
// If we successfully fetched a dictionary from content prefs, do not go
// further. Use this exact dictionary.
- // Don't use content preferences for editor with eEditorMailMask flag.
nsAutoString dictName;
- uint32_t flags;
- mEditor->GetFlags(&flags);
- if (!(flags & nsIPlaintextEditor::eEditorMailMask)) {
- dictName.Assign(aFetcher->mDictionary);
- if (!dictName.IsEmpty()) {
- if (NS_SUCCEEDED(TryDictionary(dictName, dictList, DICT_NORMAL_COMPARE))) {
-#ifdef DEBUG_DICT
- printf("***** Assigned from content preferences |%s|\n",
- NS_ConvertUTF16toUTF8(dictName).get());
-#endif
-
- // We take an early exit here, so let's not forget to clear the word
- // list.
- DeleteSuggestedWordList();
- return NS_OK;
- }
- // May be dictionary was uninstalled ?
- // Clear the content preference and continue.
- ClearCurrentDictionary(mEditor);
+ dictName.Assign(aFetcher->mDictionary);
+ if (!dictName.IsEmpty()) {
+ if (NS_SUCCEEDED(SetCurrentDictionary(dictName))) {
+ // We take an early exit here, so clear the suggested word list.
+ DeleteSuggestedWordList();
+ return NS_OK;
}
+ // Maybe the dictionary was uninstalled ?
+ // Clear the content preference and continue.
+ ClearCurrentDictionary(mEditor);
}
-
+
// Priority 2:
- // After checking the content preferences, we use the language of the element
- // or document.
- dictName.Assign(mPreferredLang);
-#ifdef DEBUG_DICT
- printf("***** Assigned from element/doc |%s|\n",
- NS_ConvertUTF16toUTF8(dictName).get());
-#endif
-
- // Get the preference value.
+ // Get global preferred language from preferences, if set.
nsAutoString preferredDict;
- preferredDict = Preferences::GetLocalizedString("spellchecker.dictionary");
+ preferredDict = Preferences::GetLocalizedString("spellchecker.dictionary.override");
+ if (!preferredDict.IsEmpty()) {
+ dictName.Assign(preferredDict);
+ }
- // The following will be driven by this status. Once we were able to set a
+ // Priority 3:
+ // Get language from element/doc, if set.
+ if (dictName.IsEmpty() && !mPreferredLang.IsEmpty()) {
+ dictName.Assign(mPreferredLang);
+ }
+
+ // Auxiliary status value
+ nsresult rv2;
+
+ // Obtain a list of available dictionaries to check against.
+ nsTArray<nsString> dictList;
+ rv2 = mSpellChecker->GetDictionaryList(&dictList);
+ NS_ENSURE_SUCCESS(rv2, rv2);
+ int32_t i, dictCount = dictList.Length();
+
+ // The following will be driven by this status. Once we are able to set a
// dictionary successfully, we're done. So we start with a "failed" status.
- nsresult rv = NS_ERROR_NOT_AVAILABLE;
-
+ nsresult rv = NS_ERROR_FAILURE;
+
if (!dictName.IsEmpty()) {
- // RFC 5646 explicitly states that matches should be case-insensitive.
- rv = TryDictionary (dictName, dictList, DICT_COMPARE_CASE_INSENSITIVE);
-
- if (NS_FAILED(rv)) {
-#ifdef DEBUG_DICT
- printf("***** Setting of |%s| failed (or it wasn't available)\n",
- NS_ConvertUTF16toUTF8(dictName).get());
-#endif
+ for (i = 0; i < dictCount; i++) {
+ nsAutoString dictStr(dictList.ElementAt(i));
+ if (dictName.Equals(dictStr, nsCaseInsensitiveStringComparator())) {
+ // First let's correct any problems due to non-matching case.
+ // This applies to both a user-set override and document language.
+ // RFC 5646 explicitly states that matches should be case-insensitive.
+ dictName.Assign(dictStr);
+ // Try to set it. Doing this inside this loop avoids trying to set a
+ // dictionary that isn't available.
+ rv = SetCurrentDictionary(dictName);
+ break;
+ }
+ }
+ if (NS_FAILED(rv)) {
// Required dictionary was not available. Try to get a dictionary
- // matching at least language part of dictName.
+ // matching at least the language part of dictName:
nsAutoString langCode;
int32_t dashIdx = dictName.FindChar('-');
- if (dashIdx != -1) {
+ if (dashIdx != -1) {
langCode.Assign(Substring(dictName, 0, dashIdx));
} else {
langCode.Assign(dictName);
}
- // Try dictionary.spellchecker preference, if it starts with langCode,
- // so we don't just get any random dictionary matching the language.
- if (!preferredDict.IsEmpty() &&
- nsStyleUtil::DashMatchCompare(preferredDict, langCode, nsDefaultStringComparator())) {
-#ifdef DEBUG_DICT
- printf("***** Trying preference value |%s| since it matches language code\n",
- NS_ConvertUTF16toUTF8(preferredDict).get());
-#endif
- rv = TryDictionary (preferredDict, dictList,
- DICT_COMPARE_CASE_INSENSITIVE);
- }
+ nsDefaultStringComparator comparator;
- if (NS_FAILED(rv)) {
- // Use any dictionary with the required language.
-#ifdef DEBUG_DICT
- printf("***** Trying to find match for language code |%s|\n",
- NS_ConvertUTF16toUTF8(langCode).get());
-#endif
- rv = TryDictionary (langCode, dictList, DICT_COMPARE_DASHMATCH);
+ // Loop over available dictionaries; if we find one with the required
+ // language, use it.
+ for (i = 0; i < dictCount; i++) {
+ nsAutoString dictStr(dictList.ElementAt(i));
+ if (nsStyleUtil::DashMatchCompare(dictStr, langCode, comparator) &&
+ NS_SUCCEEDED(rv = SetCurrentDictionary(dictStr))) {
+ break;
+ }
}
}
}
-
- // Priority 3:
- // If the document didn't supply a dictionary or the setting failed,
- // try the user preference next.
- if (NS_FAILED(rv)) {
- if (!preferredDict.IsEmpty()) {
-#ifdef DEBUG_DICT
- printf("***** Trying preference value |%s|\n",
- NS_ConvertUTF16toUTF8(preferredDict).get());
-#endif
- rv = TryDictionary (preferredDict, dictList, DICT_NORMAL_COMPARE);
- }
- }
-
+
// Priority 4:
- // As next fallback, try the current locale.
- if (NS_FAILED(rv)) {
+ // Content prefs, override and document didn't give us a valid dictionary
+ // name, so we just get the current locale and try to use that.
+ if (NS_FAILED (rv)) {
nsCOMPtr<nsIXULChromeRegistry> packageRegistry =
mozilla::services::GetXULChromeRegistryService();
@@ -929,69 +870,57 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
false, utf8DictName);
dictName.Assign(EmptyString());
AppendUTF8toUTF16(utf8DictName, dictName);
-#ifdef DEBUG_DICT
- printf("***** Trying locale |%s|\n",
- NS_ConvertUTF16toUTF8(dictName).get());
-#endif
- rv = TryDictionary (dictName, dictList, DICT_COMPARE_CASE_INSENSITIVE);
+ // Try to set it, if it's in the list.
+ for (i = 0; i < dictCount; i++) {
+ nsAutoString dictStr(dictList.ElementAt(i));
+ if (dictStr.Equals(dictName)) {
+ rv = SetCurrentDictionary(dictName);
+ break;
+ }
+ }
}
}
-
+
if (NS_FAILED(rv)) {
- // Still no success.
+ // Still no success. Further fallback attempts required.
- // Priority 5:
- // If we have a current dictionary, don't try anything else.
+ // Priority 5:
+ // If we have a current dictionary, don't try anything else.
nsAutoString currentDictionary;
rv2 = GetCurrentDictionary(currentDictionary);
-#ifdef DEBUG_DICT
- if (NS_SUCCEEDED(rv2)) {
- printf("***** Retrieved current dict |%s|\n",
- NS_ConvertUTF16toUTF8(currentDictionary).get());
- }
-#endif
-
+
if (NS_FAILED(rv2) || currentDictionary.IsEmpty()) {
+ // We don't have a current dictionary.
// Priority 6:
// Try to get current dictionary from environment variable LANG.
- // LANG = language[_territory][.charset]
+ // LANG = language[_territory][.codeset]
char* env_lang = getenv("LANG");
- if (env_lang) {
+ if (env_lang != nullptr) {
nsString lang = NS_ConvertUTF8toUTF16(env_lang);
+
// Strip trailing charset, if there is any.
int32_t dot_pos = lang.FindChar('.');
if (dot_pos != -1) {
lang = Substring(lang, 0, dot_pos);
}
-
+
+ // Convert underscore to dash.
int32_t underScore = lang.FindChar('_');
if (underScore != -1) {
lang.Replace(underScore, 1, '-');
-#ifdef DEBUG_DICT
- printf("***** Trying LANG from environment |%s|\n",
- NS_ConvertUTF16toUTF8(lang).get());
-#endif
- nsAutoString lang2;
- lang2.Assign(lang);
- rv = TryDictionary(lang2, dictList, DICT_COMPARE_CASE_INSENSITIVE);
+ // Only attempt to set if a _territory is present.
+ rv = SetCurrentDictionary(lang);
}
}
-
+
// Priority 7:
- // If it does not work, pick the first one.
- if (NS_FAILED(rv) && !dictList.IsEmpty()) {
- nsAutoString firstInList;
- firstInList.Assign(dictList[0]);
- rv = TryDictionary(firstInList, dictList, DICT_NORMAL_COMPARE);
-#ifdef DEBUG_DICT
- printf("***** Trying first of list |%s|\n",
- NS_ConvertUTF16toUTF8(dictList[0]).get());
- if (NS_SUCCEEDED(rv)) {
- printf ("***** Setting worked.\n");
+ // If LANG does not work either, pick the first one.
+ if (NS_FAILED(rv)) {
+ if (dictList.Length() > 0) {
+ rv = SetCurrentDictionary(dictList[0]);
}
-#endif
}
- }
+ }
}
// If an error was thrown while setting the dictionary, just
@@ -999,6 +928,7 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
// up. The user can manually reset the language to their choice on
// the dialog if it is wrong.
+ // Dictionary has changed, so delete the suggested word list.
DeleteSuggestedWordList();
return NS_OK;
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 67c632e71..62aedead2 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1117,6 +1117,9 @@ pref("print.print_via_parent", false);
// in a document.
pref("extensions.spellcheck.inline.max-misspellings", 500);
+// Predefined convenience pref for overriding the dictionary
+pref("spellchecker.dictionary.override", "");
+
// Prefs used by libeditor. Prefs specific to seamonkey composer
// belong in comm-central/editor/ui/composer.js