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 |