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