| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/spellcheck_host.h" | 5 #include "chrome/browser/spellcheck_host.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 | 8 |
| 9 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/path_service.h" | 12 #include "base/path_service.h" |
| 13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
| 14 #include "chrome/browser/profile.h" |
| 15 #include "chrome/browser/spellchecker_platform_engine.h" |
| 14 #include "chrome/common/chrome_constants.h" | 16 #include "chrome/common/chrome_constants.h" |
| 15 #include "chrome/common/chrome_paths.h" | 17 #include "chrome/common/chrome_paths.h" |
| 16 #include "chrome/common/notification_service.h" | 18 #include "chrome/common/notification_service.h" |
| 19 #include "chrome/common/pref_member.h" |
| 20 #include "chrome/common/pref_names.h" |
| 21 #include "chrome/common/spellcheck_common.h" |
| 17 #include "googleurl/src/gurl.h" | 22 #include "googleurl/src/gurl.h" |
| 18 | 23 |
| 19 namespace { | 24 namespace { |
| 20 | 25 |
| 21 static const struct { | |
| 22 // The language. | |
| 23 const char* language; | |
| 24 | |
| 25 // The corresponding language and region, used by the dictionaries. | |
| 26 const char* language_region; | |
| 27 } g_supported_spellchecker_languages[] = { | |
| 28 // Several languages are not to be included in the spellchecker list: | |
| 29 // th-TH, hu-HU, bg-BG, uk-UA | |
| 30 {"ca", "ca-ES"}, | |
| 31 {"cs", "cs-CZ"}, | |
| 32 {"da", "da-DK"}, | |
| 33 {"de", "de-DE"}, | |
| 34 {"el", "el-GR"}, | |
| 35 {"en-AU", "en-AU"}, | |
| 36 {"en-GB", "en-GB"}, | |
| 37 {"en-US", "en-US"}, | |
| 38 {"es", "es-ES"}, | |
| 39 {"et", "et-EE"}, | |
| 40 {"fr", "fr-FR"}, | |
| 41 {"he", "he-IL"}, | |
| 42 {"hi", "hi-IN"}, | |
| 43 {"hr", "hr-HR"}, | |
| 44 {"id", "id-ID"}, | |
| 45 {"it", "it-IT"}, | |
| 46 {"lt", "lt-LT"}, | |
| 47 {"lv", "lv-LV"}, | |
| 48 {"nb", "nb-NO"}, | |
| 49 {"nl", "nl-NL"}, | |
| 50 {"pl", "pl-PL"}, | |
| 51 {"pt-BR", "pt-BR"}, | |
| 52 {"pt-PT", "pt-PT"}, | |
| 53 {"ro", "ro-RO"}, | |
| 54 {"ru", "ru-RU"}, | |
| 55 {"sk", "sk-SK"}, | |
| 56 {"sl", "sl-SI"}, | |
| 57 {"sv", "sv-SE"}, | |
| 58 {"tr", "tr-TR"}, | |
| 59 {"vi", "vi-VN"}, | |
| 60 }; | |
| 61 | |
| 62 // This function returns the language-region version of language name. | |
| 63 // e.g. returns hi-IN for hi. | |
| 64 std::string GetSpellCheckLanguageRegion(const std::string& input_language) { | |
| 65 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); | |
| 66 ++i) { | |
| 67 if (g_supported_spellchecker_languages[i].language == input_language) { | |
| 68 return std::string( | |
| 69 g_supported_spellchecker_languages[i].language_region); | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 return input_language; | |
| 74 } | |
| 75 | |
| 76 FilePath GetVersionedFileName(const std::string& input_language, | |
| 77 const FilePath& dict_dir) { | |
| 78 // The default dictionary version is 1-2. These versions have been augmented | |
| 79 // with additional words found by the translation team. | |
| 80 static const char kDefaultVersionString[] = "-1-2"; | |
| 81 | |
| 82 // The following dictionaries have either not been augmented with additional | |
| 83 // words (version 1-1) or have new words, as well as an upgraded dictionary | |
| 84 // as of Feb 2009 (version 1-3). | |
| 85 static const struct { | |
| 86 // The language input. | |
| 87 const char* language; | |
| 88 | |
| 89 // The corresponding version. | |
| 90 const char* version; | |
| 91 } special_version_string[] = { | |
| 92 {"en-AU", "-1-1"}, | |
| 93 {"en-GB", "-1-1"}, | |
| 94 {"es-ES", "-1-1"}, | |
| 95 {"nl-NL", "-1-1"}, | |
| 96 {"ru-RU", "-1-1"}, | |
| 97 {"sv-SE", "-1-1"}, | |
| 98 {"he-IL", "-1-1"}, | |
| 99 {"el-GR", "-1-1"}, | |
| 100 {"hi-IN", "-1-1"}, | |
| 101 {"tr-TR", "-1-1"}, | |
| 102 {"et-EE", "-1-1"}, | |
| 103 {"fr-FR", "-1-4"}, // To fix a crash, fr dictionary was updated to 1.4. | |
| 104 {"lt-LT", "-1-3"}, | |
| 105 {"pl-PL", "-1-3"} | |
| 106 }; | |
| 107 | |
| 108 // Generate the bdict file name using default version string or special | |
| 109 // version string, depending on the language. | |
| 110 std::string language = GetSpellCheckLanguageRegion(input_language); | |
| 111 std::string versioned_bdict_file_name(language + kDefaultVersionString + | |
| 112 ".bdic"); | |
| 113 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(special_version_string); ++i) { | |
| 114 if (language == special_version_string[i].language) { | |
| 115 versioned_bdict_file_name = | |
| 116 language + special_version_string[i].version + ".bdic"; | |
| 117 break; | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 return dict_dir.AppendASCII(versioned_bdict_file_name); | |
| 122 } | |
| 123 | |
| 124 FilePath GetFirstChoiceFilePath(const std::string& language) { | 26 FilePath GetFirstChoiceFilePath(const std::string& language) { |
| 125 FilePath dict_dir; | 27 FilePath dict_dir; |
| 126 PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); | 28 PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); |
| 127 return GetVersionedFileName(language, dict_dir); | 29 return SpellCheckCommon::GetVersionedFileName(language, dict_dir); |
| 128 } | 30 } |
| 129 | 31 |
| 130 FilePath GetFallbackFilePath(const FilePath& first_choice) { | 32 FilePath GetFallbackFilePath(const FilePath& first_choice) { |
| 131 FilePath dict_dir; | 33 FilePath dict_dir; |
| 132 PathService::Get(chrome::DIR_USER_DATA, &dict_dir); | 34 PathService::Get(chrome::DIR_USER_DATA, &dict_dir); |
| 133 return dict_dir.Append(first_choice.BaseName()); | 35 return dict_dir.Append(first_choice.BaseName()); |
| 134 } | 36 } |
| 135 | 37 |
| 136 } // namespace | 38 } // namespace |
| 137 | 39 |
| 138 // Constructed on UI thread. | 40 // Constructed on UI thread. |
| 139 SpellCheckHost::SpellCheckHost(Observer* observer, | 41 SpellCheckHost::SpellCheckHost(Observer* observer, |
| 140 const std::string& language, | 42 const std::string& language, |
| 141 URLRequestContextGetter* request_context_getter) | 43 URLRequestContextGetter* request_context_getter) |
| 142 : observer_(observer), | 44 : observer_(observer), |
| 143 language_(language), | 45 language_(language), |
| 144 file_(base::kInvalidPlatformFileValue), | 46 file_(base::kInvalidPlatformFileValue), |
| 145 tried_to_download_(false), | 47 tried_to_download_(false), |
| 48 use_platform_spellchecker_(false), |
| 146 request_context_getter_(request_context_getter) { | 49 request_context_getter_(request_context_getter) { |
| 147 DCHECK(observer_); | 50 DCHECK(observer_); |
| 148 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 51 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 149 | 52 |
| 150 FilePath personal_file_directory; | 53 FilePath personal_file_directory; |
| 151 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); | 54 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); |
| 152 custom_dictionary_file_ = | 55 custom_dictionary_file_ = |
| 153 personal_file_directory.Append(chrome::kCustomDictionaryFileName); | 56 personal_file_directory.Append(chrome::kCustomDictionaryFileName); |
| 154 | 57 |
| 155 bdict_file_path_ = GetFirstChoiceFilePath(language); | 58 bdict_file_path_ = GetFirstChoiceFilePath(language); |
| 156 } | 59 } |
| 157 | 60 |
| 158 SpellCheckHost::~SpellCheckHost() { | 61 SpellCheckHost::~SpellCheckHost() { |
| 159 if (file_ != base::kInvalidPlatformFileValue) | 62 if (file_ != base::kInvalidPlatformFileValue) |
| 160 base::ClosePlatformFile(file_); | 63 base::ClosePlatformFile(file_); |
| 161 } | 64 } |
| 162 | 65 |
| 163 void SpellCheckHost::Initialize() { | 66 void SpellCheckHost::Initialize() { |
| 67 if (SpellCheckerPlatform::SpellCheckerAvailable() && |
| 68 SpellCheckerPlatform::PlatformSupportsLanguage(language_)) { |
| 69 use_platform_spellchecker_ = true; |
| 70 SpellCheckerPlatform::SetLanguage(language_); |
| 71 MessageLoop::current()->PostTask(FROM_HERE, |
| 72 NewRunnableMethod(this, |
| 73 &SpellCheckHost::InformObserverOfInitialization)); |
| 74 return; |
| 75 } |
| 76 |
| 164 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 77 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 165 NewRunnableMethod(this, &SpellCheckHost::InitializeDictionaryLocation)); | 78 NewRunnableMethod(this, &SpellCheckHost::InitializeDictionaryLocation)); |
| 166 } | 79 } |
| 167 | 80 |
| 168 void SpellCheckHost::UnsetObserver() { | 81 void SpellCheckHost::UnsetObserver() { |
| 169 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 82 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 170 | 83 |
| 171 observer_ = NULL; | 84 observer_ = NULL; |
| 172 request_context_getter_ = NULL; | 85 request_context_getter_ = NULL; |
| 173 fetcher_.reset(); | 86 fetcher_.reset(); |
| 174 } | 87 } |
| 175 | 88 |
| 176 void SpellCheckHost::AddWord(const std::string& word) { | 89 void SpellCheckHost::AddWord(const std::string& word) { |
| 177 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 90 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 178 | 91 |
| 179 custom_words_.push_back(word); | 92 custom_words_.push_back(word); |
| 180 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 93 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 181 NewRunnableMethod(this, | 94 NewRunnableMethod(this, |
| 182 &SpellCheckHost::WriteWordToCustomDictionary, word)); | 95 &SpellCheckHost::WriteWordToCustomDictionary, word)); |
| 183 NotificationService::current()->Notify( | 96 NotificationService::current()->Notify( |
| 184 NotificationType::SPELLCHECK_WORD_ADDED, | 97 NotificationType::SPELLCHECK_WORD_ADDED, |
| 185 Source<SpellCheckHost>(this), NotificationService::NoDetails()); | 98 Source<SpellCheckHost>(this), NotificationService::NoDetails()); |
| 186 } | 99 } |
| 187 | 100 |
| 101 // static |
| 102 int SpellCheckHost::GetSpellCheckLanguages( |
| 103 Profile* profile, |
| 104 std::vector<std::string>* languages) { |
| 105 StringPrefMember accept_languages_pref; |
| 106 StringPrefMember dictionary_language_pref; |
| 107 accept_languages_pref.Init(prefs::kAcceptLanguages, profile->GetPrefs(), |
| 108 NULL); |
| 109 dictionary_language_pref.Init(prefs::kSpellCheckDictionary, |
| 110 profile->GetPrefs(), NULL); |
| 111 std::string dictionary_language = |
| 112 WideToASCII(dictionary_language_pref.GetValue()); |
| 113 |
| 114 // The current dictionary language should be there. |
| 115 languages->push_back(dictionary_language); |
| 116 |
| 117 // Now scan through the list of accept languages, and find possible mappings |
| 118 // from this list to the existing list of spell check languages. |
| 119 std::vector<std::string> accept_languages; |
| 120 |
| 121 if (SpellCheckerPlatform::SpellCheckerAvailable()) { |
| 122 SpellCheckerPlatform::GetAvailableLanguages(&accept_languages); |
| 123 } else { |
| 124 SplitString(WideToASCII(accept_languages_pref.GetValue()), ',', |
| 125 &accept_languages); |
| 126 } |
| 127 for (std::vector<std::string>::const_iterator i = accept_languages.begin(); |
| 128 i != accept_languages.end(); ++i) { |
| 129 std::string language = |
| 130 SpellCheckCommon::GetCorrespondingSpellCheckLanguage(*i); |
| 131 if (!language.empty() && |
| 132 std::find(languages->begin(), languages->end(), language) == |
| 133 languages->end()) { |
| 134 languages->push_back(language); |
| 135 } |
| 136 } |
| 137 |
| 138 for (size_t i = 0; i < languages->size(); ++i) { |
| 139 if ((*languages)[i] == dictionary_language) |
| 140 return i; |
| 141 } |
| 142 return -1; |
| 143 } |
| 144 |
| 188 void SpellCheckHost::InitializeDictionaryLocation() { | 145 void SpellCheckHost::InitializeDictionaryLocation() { |
| 189 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 146 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 190 | 147 |
| 191 #if defined(OS_WIN) | 148 #if defined(OS_WIN) |
| 192 // Check if the dictionary exists in the fallback location. If so, use it | 149 // Check if the dictionary exists in the fallback location. If so, use it |
| 193 // rather than downloading anew. | 150 // rather than downloading anew. |
| 194 FilePath fallback = GetFallbackFilePath(bdict_file_path_); | 151 FilePath fallback = GetFallbackFilePath(bdict_file_path_); |
| 195 if (!file_util::PathExists(bdict_file_path_) && | 152 if (!file_util::PathExists(bdict_file_path_) && |
| 196 file_util::PathExists(fallback)) { | 153 file_util::PathExists(fallback)) { |
| 197 bdict_file_path_ = fallback; | 154 bdict_file_path_ = fallback; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, | 297 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 341 NewRunnableMethod(this, | 298 NewRunnableMethod(this, |
| 342 &SpellCheckHost::InformObserverOfInitialization)); | 299 &SpellCheckHost::InformObserverOfInitialization)); |
| 343 return; | 300 return; |
| 344 } | 301 } |
| 345 } | 302 } |
| 346 | 303 |
| 347 data_.clear(); | 304 data_.clear(); |
| 348 Initialize(); | 305 Initialize(); |
| 349 } | 306 } |
| OLD | NEW |