| 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 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 | 162 |
| 163 void SpellCheckHost::Initialize() { | 163 void SpellCheckHost::Initialize() { |
| 164 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 164 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 165 NewRunnableMethod(this, &SpellCheckHost::InitializeDictionaryLocation)); | 165 NewRunnableMethod(this, &SpellCheckHost::InitializeDictionaryLocation)); |
| 166 } | 166 } |
| 167 | 167 |
| 168 void SpellCheckHost::UnsetObserver() { | 168 void SpellCheckHost::UnsetObserver() { |
| 169 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 169 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 170 | 170 |
| 171 observer_ = NULL; | 171 observer_ = NULL; |
| 172 request_context_getter_ = NULL; |
| 173 fetcher_.reset(); |
| 172 } | 174 } |
| 173 | 175 |
| 174 void SpellCheckHost::AddWord(const std::string& word) { | 176 void SpellCheckHost::AddWord(const std::string& word) { |
| 175 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 177 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 176 | 178 |
| 177 custom_words_.push_back(word); | 179 custom_words_.push_back(word); |
| 178 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 180 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 179 NewRunnableMethod(this, | 181 NewRunnableMethod(this, |
| 180 &SpellCheckHost::WriteWordToCustomDictionary, word)); | 182 &SpellCheckHost::WriteWordToCustomDictionary, word)); |
| 181 NotificationService::current()->Notify( | 183 NotificationService::current()->Notify( |
| (...skipping 21 matching lines...) Expand all Loading... |
| 203 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 205 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 204 | 206 |
| 205 if (!observer_) | 207 if (!observer_) |
| 206 return; | 208 return; |
| 207 | 209 |
| 208 file_ = base::CreatePlatformFile(bdict_file_path_, | 210 file_ = base::CreatePlatformFile(bdict_file_path_, |
| 209 base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, | 211 base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, |
| 210 NULL); | 212 NULL); |
| 211 | 213 |
| 212 // File didn't exist. Download it. | 214 // File didn't exist. Download it. |
| 213 if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_) { | 215 if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_ && |
| 214 DownloadDictionary(); | 216 request_context_getter_) { |
| 217 // We download from the ui thread because we need to know that |
| 218 // |request_context_getter_| is still valid before initiating the download. |
| 219 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 220 NewRunnableMethod(this, &SpellCheckHost::DownloadDictionary)); |
| 215 return; | 221 return; |
| 216 } | 222 } |
| 217 | 223 |
| 224 request_context_getter_ = NULL; |
| 225 |
| 218 if (file_ != base::kInvalidPlatformFileValue) { | 226 if (file_ != base::kInvalidPlatformFileValue) { |
| 219 // Load custom dictionary. | 227 // Load custom dictionary. |
| 220 std::string contents; | 228 std::string contents; |
| 221 file_util::ReadFileToString(custom_dictionary_file_, &contents); | 229 file_util::ReadFileToString(custom_dictionary_file_, &contents); |
| 222 std::vector<std::string> list_of_words; | 230 std::vector<std::string> list_of_words; |
| 223 SplitString(contents, '\n', &list_of_words); | 231 SplitString(contents, '\n', &list_of_words); |
| 224 for (size_t i = 0; i < list_of_words.size(); ++i) | 232 for (size_t i = 0; i < list_of_words.size(); ++i) |
| 225 custom_words_.push_back(list_of_words[i]); | 233 custom_words_.push_back(list_of_words[i]); |
| 226 } | 234 } |
| 227 | 235 |
| 228 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, | 236 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 229 NewRunnableMethod(this, | 237 NewRunnableMethod(this, |
| 230 &SpellCheckHost::InformObserverOfInitialization)); | 238 &SpellCheckHost::InformObserverOfInitialization)); |
| 231 } | 239 } |
| 232 | 240 |
| 241 void SpellCheckHost::InitializeOnFileThread() { |
| 242 DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 243 |
| 244 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 245 NewRunnableMethod(this, &SpellCheckHost::Initialize)); |
| 246 } |
| 247 |
| 233 void SpellCheckHost::InformObserverOfInitialization() { | 248 void SpellCheckHost::InformObserverOfInitialization() { |
| 234 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 249 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 235 | 250 |
| 236 if (observer_) | 251 if (observer_) |
| 237 observer_->SpellCheckHostInitialized(); | 252 observer_->SpellCheckHostInitialized(); |
| 238 } | 253 } |
| 239 | 254 |
| 240 void SpellCheckHost::DownloadDictionary() { | 255 void SpellCheckHost::DownloadDictionary() { |
| 241 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 256 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 257 |
| 258 if (!request_context_getter_) { |
| 259 InitializeOnFileThread(); |
| 260 return; |
| 261 } |
| 242 | 262 |
| 243 // Determine URL of file to download. | 263 // Determine URL of file to download. |
| 244 static const char kDownloadServerUrl[] = | 264 static const char kDownloadServerUrl[] = |
| 245 "http://cache.pack.google.com/edgedl/chrome/dict/"; | 265 "http://cache.pack.google.com/edgedl/chrome/dict/"; |
| 246 GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8( | 266 GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8( |
| 247 l10n_util::ToLower(bdict_file_path_.BaseName().ToWStringHack()))); | 267 l10n_util::ToLower(bdict_file_path_.BaseName().ToWStringHack()))); |
| 248 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); | 268 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); |
| 249 fetcher_->set_request_context(request_context_getter_.get()); | 269 fetcher_->set_request_context(request_context_getter_); |
| 250 tried_to_download_ = true; | 270 tried_to_download_ = true; |
| 251 fetcher_->Start(); | 271 fetcher_->Start(); |
| 272 request_context_getter_ = NULL; |
| 252 } | 273 } |
| 253 | 274 |
| 254 void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) { | 275 void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) { |
| 255 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 276 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 256 | 277 |
| 257 // Stored in UTF-8. | 278 // Stored in UTF-8. |
| 258 std::string word_to_add(word + "\n"); | 279 std::string word_to_add(word + "\n"); |
| 259 FILE* f = file_util::OpenFile(custom_dictionary_file_, "a+"); | 280 FILE* f = file_util::OpenFile(custom_dictionary_file_, "a+"); |
| 260 if (f != NULL) | 281 if (f != NULL) |
| 261 fputs(word_to_add.c_str(), f); | 282 fputs(word_to_add.c_str(), f); |
| 262 file_util::CloseFile(f); | 283 file_util::CloseFile(f); |
| 263 } | 284 } |
| 264 | 285 |
| 265 void SpellCheckHost::OnURLFetchComplete(const URLFetcher* source, | 286 void SpellCheckHost::OnURLFetchComplete(const URLFetcher* source, |
| 266 const GURL& url, | 287 const GURL& url, |
| 267 const URLRequestStatus& status, | 288 const URLRequestStatus& status, |
| 268 int response_code, | 289 int response_code, |
| 269 const ResponseCookies& cookies, | 290 const ResponseCookies& cookies, |
| 270 const std::string& data) { | 291 const std::string& data) { |
| 271 DCHECK(source); | 292 DCHECK(source); |
| 272 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 293 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 294 fetcher_.reset(); |
| 273 | 295 |
| 274 if ((response_code / 100) != 2) { | 296 if ((response_code / 100) != 2) { |
| 275 // Initialize will not try to download the file a second time. | 297 // Initialize will not try to download the file a second time. |
| 276 LOG(ERROR) << "Failure to download dictionary."; | 298 LOG(ERROR) << "Failure to download dictionary."; |
| 277 Initialize(); | 299 InitializeOnFileThread(); |
| 278 return; | 300 return; |
| 279 } | 301 } |
| 280 | 302 |
| 281 // Basic sanity check on the dictionary. | 303 // Basic sanity check on the dictionary. |
| 282 // There's the small chance that we might see a 200 status code for a body | 304 // There's the small chance that we might see a 200 status code for a body |
| 283 // that represents some form of failure. | 305 // that represents some form of failure. |
| 284 if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || | 306 if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || |
| 285 data[3] != 'c') { | 307 data[3] != 'c') { |
| 286 LOG(ERROR) << "Failure to download dictionary."; | 308 LOG(ERROR) << "Failure to download dictionary."; |
| 287 Initialize(); | 309 InitializeOnFileThread(); |
| 288 return; | 310 return; |
| 289 } | 311 } |
| 290 | 312 |
| 313 data_ = data; |
| 314 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 315 NewRunnableMethod(this, &SpellCheckHost::SaveDictionaryData)); |
| 316 } |
| 317 |
| 318 void SpellCheckHost::SaveDictionaryData() { |
| 319 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 320 |
| 291 size_t bytes_written = | 321 size_t bytes_written = |
| 292 file_util::WriteFile(bdict_file_path_, data.data(), data.length()); | 322 file_util::WriteFile(bdict_file_path_, data_.data(), data_.length()); |
| 293 if (bytes_written != data.length()) { | 323 if (bytes_written != data_.length()) { |
| 294 bool success = false; | 324 bool success = false; |
| 295 #if defined(OS_WIN) | 325 #if defined(OS_WIN) |
| 296 bdict_file_path_ = GetFallbackFilePath(bdict_file_path_); | 326 bdict_file_path_ = GetFallbackFilePath(bdict_file_path_); |
| 297 bytes_written = | 327 bytes_written = |
| 298 file_util::WriteFile(GetFallbackFilePath(bdict_file_path_), | 328 file_util::WriteFile(GetFallbackFilePath(bdict_file_path_), |
| 299 data.data(), data.length()); | 329 data_.data(), data_.length()); |
| 300 if (bytes_written == data.length()) | 330 if (bytes_written == data_.length()) |
| 301 success = true; | 331 success = true; |
| 302 #endif | 332 #endif |
| 333 data_.clear(); |
| 303 | 334 |
| 304 if (!success) { | 335 if (!success) { |
| 305 LOG(ERROR) << "Failure to save dictionary."; | 336 LOG(ERROR) << "Failure to save dictionary."; |
| 337 file_util::Delete(bdict_file_path_, false); |
| 306 // To avoid trying to load a partially saved dictionary, shortcut the | 338 // To avoid trying to load a partially saved dictionary, shortcut the |
| 307 // Initialize() call. | 339 // Initialize() call. |
| 308 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, | 340 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 309 NewRunnableMethod(this, | 341 NewRunnableMethod(this, |
| 310 &SpellCheckHost::InformObserverOfInitialization)); | 342 &SpellCheckHost::InformObserverOfInitialization)); |
| 311 return; | 343 return; |
| 312 } | 344 } |
| 313 } | 345 } |
| 314 | 346 |
| 347 data_.clear(); |
| 315 Initialize(); | 348 Initialize(); |
| 316 } | 349 } |
| OLD | NEW |