Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(380)

Side by Side Diff: chrome/browser/spellcheck_host.cc

Issue 357003: Move the spellchecker to the renderer.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: rename Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:mergeinfo
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/spellcheck_host.h"
6
7 #include <fcntl.h>
8
9 #include "app/l10n_util.h"
10 #include "base/file_util.h"
11 #include "base/logging.h"
12 #include "base/path_service.h"
13 #include "base/string_util.h"
14 #include "chrome/common/chrome_constants.h"
15 #include "chrome/common/chrome_paths.h"
16 #include "chrome/common/notification_service.h"
17 #include "googleurl/src/gurl.h"
18
19 namespace {
20
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 } // namespace
125
126 // Constructed on UI thread.
127 SpellCheckHost::SpellCheckHost(Observer* observer,
128 const std::string& language,
129 URLRequestContextGetter* request_context_getter)
130 : observer_(observer),
131 language_(language),
132 tried_to_download_(false),
133 request_context_getter_(request_context_getter) {
134 DCHECK(observer_);
135 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
136
137 // TODO(estade): for Windows, we need to fall back to DIR_USER_DATA if
138 // DIR_APP_DICTIONARIES is not writeable.
139 FilePath dict_dir;
140 PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir);
141 bdict_file_ = GetVersionedFileName(language, dict_dir);
142
143 FilePath personal_file_directory;
144 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory);
145 custom_dictionary_file_ =
146 personal_file_directory.Append(chrome::kCustomDictionaryFileName);
147
148 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
149 NewRunnableMethod(this, &SpellCheckHost::Initialize));
150 }
151
152 SpellCheckHost::~SpellCheckHost() {
153 if (fd_.fd != -1)
154 close(fd_.fd);
155 }
156
157 void SpellCheckHost::UnsetObserver() {
158 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
159
160 observer_ = NULL;
161 }
162
163 void SpellCheckHost::AddWord(const std::string& word) {
164 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
165
166 custom_words_.push_back(word);
167 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
168 NewRunnableMethod(this,
169 &SpellCheckHost::WriteWordToCustomDictionary, word));
170 NotificationService::current()->Notify(
171 NotificationType::SPELLCHECK_WORD_ADDED,
172 Source<SpellCheckHost>(this), NotificationService::NoDetails());
173 }
174
175 void SpellCheckHost::Initialize() {
176 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
177
178 if (!observer_)
179 return;
180
181 // We set |auto_close| to false because we don't want IPC to close the fd.
182 // We will close it manually in the destructor.
183 fd_ = base::FileDescriptor(open(bdict_file_.value().c_str(), O_RDONLY),
184 false);
185
186 // File didn't exist. Download it.
187 if (fd_.fd == -1 && !tried_to_download_) {
188 DownloadDictionary();
189 return;
190 }
191
192 if (fd_.fd != -1) {
193 // Load custom dictionary.
194 std::string contents;
195 file_util::ReadFileToString(custom_dictionary_file_, &contents);
196 std::vector<std::string> list_of_words;
197 SplitString(contents, '\n', &list_of_words);
198 for (size_t i = 0; i < list_of_words.size(); ++i)
199 custom_words_.push_back(list_of_words[i]);
200 }
201
202 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
203 NewRunnableMethod(this,
204 &SpellCheckHost::InformObserverOfInitialization));
205 }
206
207 void SpellCheckHost::InformObserverOfInitialization() {
208 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
209
210 if (observer_)
211 observer_->SpellCheckHostInitialized();
212 }
213
214 void SpellCheckHost::DownloadDictionary() {
215 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
216
217 // Determine URL of file to download.
218 static const char kDownloadServerUrl[] =
219 "http://cache.pack.google.com/edgedl/chrome/dict/";
220 GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8(
221 l10n_util::ToLower(bdict_file_.BaseName().ToWStringHack())));
222 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this));
223 fetcher_->set_request_context(request_context_getter_);
224 tried_to_download_ = true;
225 fetcher_->Start();
226 }
227
228 void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) {
229 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
230
231 // Stored in UTF-8.
232 std::string word_to_add(word + "\n");
233 FILE* f = file_util::OpenFile(custom_dictionary_file_, "a+");
234 if (f != NULL)
235 fputs(word_to_add.c_str(), f);
236 file_util::CloseFile(f);
237 }
238
239 void SpellCheckHost::OnURLFetchComplete(const URLFetcher* source,
240 const GURL& url,
241 const URLRequestStatus& status,
242 int response_code,
243 const ResponseCookies& cookies,
244 const std::string& data) {
245 DCHECK(source);
246 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
247
248 if ((response_code / 100) != 2) {
249 // Initialize will not try to download the file a second time.
250 LOG(ERROR) << "Failure to download dictionary.";
251 Initialize();
252 return;
253 }
254
255 // Basic sanity check on the dictionary.
256 // There's the small chance that we might see a 200 status code for a body
257 // that represents some form of failure.
258 if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' ||
259 data[3] != 'c') {
260 LOG(ERROR) << "Failure to download dictionary.";
261 Initialize();
262 return;
263 }
264
265 size_t bytes_written =
266 file_util::WriteFile(bdict_file_, data.data(), data.length());
267 if (bytes_written != data.length()) {
268 LOG(ERROR) << "Failure to save dictionary.";
269 // To avoid trying to load a partially saved dictionary, shortcut the
270 // Initialize() call.
271 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
272 NewRunnableMethod(this,
273 &SpellCheckHost::InformObserverOfInitialization));
274 return;
275 }
276
277 Initialize();
278 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698