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" |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 if (language == special_version_string[i].language) { | 114 if (language == special_version_string[i].language) { |
115 versioned_bdict_file_name = | 115 versioned_bdict_file_name = |
116 language + special_version_string[i].version + ".bdic"; | 116 language + special_version_string[i].version + ".bdic"; |
117 break; | 117 break; |
118 } | 118 } |
119 } | 119 } |
120 | 120 |
121 return dict_dir.AppendASCII(versioned_bdict_file_name); | 121 return dict_dir.AppendASCII(versioned_bdict_file_name); |
122 } | 122 } |
123 | 123 |
124 FilePath GetFirstChoiceFilePath(const std::string& language) { | |
125 FilePath dict_dir; | |
126 PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); | |
127 return GetVersionedFileName(language, dict_dir); | |
128 } | |
129 | |
130 FilePath GetFallbackFilePath(const FilePath& first_choice) { | |
131 FilePath dict_dir; | |
132 PathService::Get(chrome::DIR_USER_DATA, &dict_dir); | |
133 return dict_dir.Append(first_choice.BaseName()); | |
134 } | |
135 | |
136 } // namespace | 124 } // namespace |
137 | 125 |
138 // Constructed on UI thread. | 126 // Constructed on UI thread. |
139 SpellCheckHost::SpellCheckHost(Observer* observer, | 127 SpellCheckHost::SpellCheckHost(Observer* observer, |
140 const std::string& language, | 128 const std::string& language, |
141 URLRequestContextGetter* request_context_getter) | 129 URLRequestContextGetter* request_context_getter) |
142 : observer_(observer), | 130 : observer_(observer), |
143 language_(language), | 131 language_(language), |
144 file_(base::kInvalidPlatformFileValue), | |
145 tried_to_download_(false), | 132 tried_to_download_(false), |
146 request_context_getter_(request_context_getter) { | 133 request_context_getter_(request_context_getter) { |
147 DCHECK(observer_); | 134 DCHECK(observer_); |
148 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 135 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
149 | 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 |
150 FilePath personal_file_directory; | 143 FilePath personal_file_directory; |
151 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); | 144 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); |
152 custom_dictionary_file_ = | 145 custom_dictionary_file_ = |
153 personal_file_directory.Append(chrome::kCustomDictionaryFileName); | 146 personal_file_directory.Append(chrome::kCustomDictionaryFileName); |
154 | 147 |
155 bdict_file_path_ = GetFirstChoiceFilePath(language); | |
156 | |
157 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 148 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
158 NewRunnableMethod(this, &SpellCheckHost::InitializeDictionaryLocation)); | 149 NewRunnableMethod(this, &SpellCheckHost::Initialize)); |
159 } | 150 } |
160 | 151 |
161 SpellCheckHost::~SpellCheckHost() { | 152 SpellCheckHost::~SpellCheckHost() { |
162 if (file_ != base::kInvalidPlatformFileValue) | 153 if (fd_.fd != -1) |
163 base::ClosePlatformFile(file_); | 154 close(fd_.fd); |
164 } | 155 } |
165 | 156 |
166 void SpellCheckHost::UnsetObserver() { | 157 void SpellCheckHost::UnsetObserver() { |
167 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 158 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
168 | 159 |
169 observer_ = NULL; | 160 observer_ = NULL; |
170 } | 161 } |
171 | 162 |
172 void SpellCheckHost::AddWord(const std::string& word) { | 163 void SpellCheckHost::AddWord(const std::string& word) { |
173 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 164 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
174 | 165 |
175 custom_words_.push_back(word); | 166 custom_words_.push_back(word); |
176 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 167 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
177 NewRunnableMethod(this, | 168 NewRunnableMethod(this, |
178 &SpellCheckHost::WriteWordToCustomDictionary, word)); | 169 &SpellCheckHost::WriteWordToCustomDictionary, word)); |
179 NotificationService::current()->Notify( | 170 NotificationService::current()->Notify( |
180 NotificationType::SPELLCHECK_WORD_ADDED, | 171 NotificationType::SPELLCHECK_WORD_ADDED, |
181 Source<SpellCheckHost>(this), NotificationService::NoDetails()); | 172 Source<SpellCheckHost>(this), NotificationService::NoDetails()); |
182 } | 173 } |
183 | 174 |
184 void SpellCheckHost::InitializeDictionaryLocation() { | |
185 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | |
186 | |
187 #if defined(OS_WIN) | |
188 // Check if the dictionary exists in the fallback location. If so, use it | |
189 // rather than downloading anew. | |
190 FilePath fallback = GetFallbackFilePath(bdict_file_path_); | |
191 if (!file_util::PathExists(bdict_file_path_) && | |
192 file_util::PathExists(fallback)) { | |
193 bdict_file_path_ = fallback; | |
194 } | |
195 #endif | |
196 | |
197 Initialize(); | |
198 } | |
199 | |
200 void SpellCheckHost::Initialize() { | 175 void SpellCheckHost::Initialize() { |
201 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 176 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
202 | 177 |
203 if (!observer_) | 178 if (!observer_) |
204 return; | 179 return; |
205 | 180 |
206 file_ = base::CreatePlatformFile(bdict_file_path_, | 181 // We set |auto_close| to false because we don't want IPC to close the fd. |
207 base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, | 182 // We will close it manually in the destructor. |
208 NULL); | 183 fd_ = base::FileDescriptor(open(bdict_file_.value().c_str(), O_RDONLY), |
| 184 false); |
209 | 185 |
210 // File didn't exist. Download it. | 186 // File didn't exist. Download it. |
211 if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_) { | 187 if (fd_.fd == -1 && !tried_to_download_) { |
212 DownloadDictionary(); | 188 DownloadDictionary(); |
213 return; | 189 return; |
214 } | 190 } |
215 | 191 |
216 if (file_ != base::kInvalidPlatformFileValue) { | 192 if (fd_.fd != -1) { |
217 // Load custom dictionary. | 193 // Load custom dictionary. |
218 std::string contents; | 194 std::string contents; |
219 file_util::ReadFileToString(custom_dictionary_file_, &contents); | 195 file_util::ReadFileToString(custom_dictionary_file_, &contents); |
220 std::vector<std::string> list_of_words; | 196 std::vector<std::string> list_of_words; |
221 SplitString(contents, '\n', &list_of_words); | 197 SplitString(contents, '\n', &list_of_words); |
222 for (size_t i = 0; i < list_of_words.size(); ++i) | 198 for (size_t i = 0; i < list_of_words.size(); ++i) |
223 custom_words_.push_back(list_of_words[i]); | 199 custom_words_.push_back(list_of_words[i]); |
224 } | 200 } |
225 | 201 |
226 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, | 202 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
227 NewRunnableMethod(this, | 203 NewRunnableMethod(this, |
228 &SpellCheckHost::InformObserverOfInitialization)); | 204 &SpellCheckHost::InformObserverOfInitialization)); |
229 } | 205 } |
230 | 206 |
231 void SpellCheckHost::InformObserverOfInitialization() { | 207 void SpellCheckHost::InformObserverOfInitialization() { |
232 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 208 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
233 | 209 |
234 if (observer_) | 210 if (observer_) |
235 observer_->SpellCheckHostInitialized(); | 211 observer_->SpellCheckHostInitialized(); |
236 } | 212 } |
237 | 213 |
238 void SpellCheckHost::DownloadDictionary() { | 214 void SpellCheckHost::DownloadDictionary() { |
239 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 215 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
240 | 216 |
241 // Determine URL of file to download. | 217 // Determine URL of file to download. |
242 static const char kDownloadServerUrl[] = | 218 static const char kDownloadServerUrl[] = |
243 "http://cache.pack.google.com/edgedl/chrome/dict/"; | 219 "http://cache.pack.google.com/edgedl/chrome/dict/"; |
244 GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8( | 220 GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8( |
245 l10n_util::ToLower(bdict_file_path_.BaseName().ToWStringHack()))); | 221 l10n_util::ToLower(bdict_file_.BaseName().ToWStringHack()))); |
246 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); | 222 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); |
247 fetcher_->set_request_context(request_context_getter_.get()); | 223 fetcher_->set_request_context(request_context_getter_.get()); |
248 tried_to_download_ = true; | 224 tried_to_download_ = true; |
249 fetcher_->Start(); | 225 fetcher_->Start(); |
250 } | 226 } |
251 | 227 |
252 void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) { | 228 void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) { |
253 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 229 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
254 | 230 |
255 // Stored in UTF-8. | 231 // Stored in UTF-8. |
(...skipping 24 matching lines...) Expand all Loading... |
280 // There's the small chance that we might see a 200 status code for a body | 256 // There's the small chance that we might see a 200 status code for a body |
281 // that represents some form of failure. | 257 // that represents some form of failure. |
282 if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || | 258 if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || |
283 data[3] != 'c') { | 259 data[3] != 'c') { |
284 LOG(ERROR) << "Failure to download dictionary."; | 260 LOG(ERROR) << "Failure to download dictionary."; |
285 Initialize(); | 261 Initialize(); |
286 return; | 262 return; |
287 } | 263 } |
288 | 264 |
289 size_t bytes_written = | 265 size_t bytes_written = |
290 file_util::WriteFile(bdict_file_path_, data.data(), data.length()); | 266 file_util::WriteFile(bdict_file_, data.data(), data.length()); |
291 if (bytes_written != data.length()) { | 267 if (bytes_written != data.length()) { |
292 bool success = false; | 268 LOG(ERROR) << "Failure to save dictionary."; |
293 #if defined(OS_WIN) | 269 // To avoid trying to load a partially saved dictionary, shortcut the |
294 bdict_file_path_ = GetFallbackFilePath(bdict_file_path_); | 270 // Initialize() call. |
295 bytes_written = | 271 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
296 file_util::WriteFile(GetFallbackFilePath(bdict_file_path_), | 272 NewRunnableMethod(this, |
297 data.data(), data.length()); | 273 &SpellCheckHost::InformObserverOfInitialization)); |
298 if (bytes_written == data.length()) | 274 return; |
299 success = true; | |
300 #endif | |
301 | |
302 if (!success) { | |
303 LOG(ERROR) << "Failure to save dictionary."; | |
304 // To avoid trying to load a partially saved dictionary, shortcut the | |
305 // Initialize() call. | |
306 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, | |
307 NewRunnableMethod(this, | |
308 &SpellCheckHost::InformObserverOfInitialization)); | |
309 return; | |
310 } | |
311 } | 275 } |
312 | 276 |
313 Initialize(); | 277 Initialize(); |
314 } | 278 } |
OLD | NEW |