| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/spellchecker/spellcheck_host_impl.h" | 5 #include "chrome/browser/spellchecker/spellcheck_host_impl.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/bind.h" |
| 9 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 10 #include "base/logging.h" | 11 #include "base/logging.h" |
| 11 #include "base/path_service.h" | 12 #include "base/path_service.h" |
| 12 #include "base/string_split.h" | 13 #include "base/string_split.h" |
| 13 #include "base/threading/thread_restrictions.h" | 14 #include "base/threading/thread_restrictions.h" |
| 14 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
| 15 #include "chrome/browser/prefs/pref_service.h" | 16 #include "chrome/browser/prefs/pref_service.h" |
| 16 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
| 17 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h" | 18 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h" |
| 18 #include "chrome/browser/spellchecker/spellcheck_profile_provider.h" | 19 #include "chrome/browser/spellchecker/spellcheck_profile_provider.h" |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 SpellCheckProfileProvider* profile, | 85 SpellCheckProfileProvider* profile, |
| 85 const std::string& language, | 86 const std::string& language, |
| 86 net::URLRequestContextGetter* request_context_getter, | 87 net::URLRequestContextGetter* request_context_getter, |
| 87 SpellCheckHostMetrics* metrics) | 88 SpellCheckHostMetrics* metrics) |
| 88 : profile_(profile), | 89 : profile_(profile), |
| 89 language_(language), | 90 language_(language), |
| 90 file_(base::kInvalidPlatformFileValue), | 91 file_(base::kInvalidPlatformFileValue), |
| 91 tried_to_download_(false), | 92 tried_to_download_(false), |
| 92 use_platform_spellchecker_(false), | 93 use_platform_spellchecker_(false), |
| 93 request_context_getter_(request_context_getter), | 94 request_context_getter_(request_context_getter), |
| 94 metrics_(metrics) { | 95 metrics_(metrics), |
| 96 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| 95 DCHECK(profile_); | 97 DCHECK(profile_); |
| 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 97 | 99 |
| 98 FilePath personal_file_directory; | 100 FilePath personal_file_directory; |
| 99 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); | 101 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); |
| 100 custom_dictionary_file_ = | 102 custom_dictionary_file_ = |
| 101 personal_file_directory.Append(chrome::kCustomDictionaryFileName); | 103 personal_file_directory.Append(chrome::kCustomDictionaryFileName); |
| 102 | 104 |
| 103 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 105 registrar_.Add(weak_ptr_factory_.GetWeakPtr(), |
| 106 content::NOTIFICATION_RENDERER_PROCESS_CREATED, |
| 104 content::NotificationService::AllSources()); | 107 content::NotificationService::AllSources()); |
| 105 } | 108 } |
| 106 | 109 |
| 107 SpellCheckHostImpl::~SpellCheckHostImpl() { | 110 SpellCheckHostImpl::~SpellCheckHostImpl() { |
| 108 if (file_ != base::kInvalidPlatformFileValue) | 111 if (file_ != base::kInvalidPlatformFileValue) |
| 109 base::ClosePlatformFile(file_); | 112 base::ClosePlatformFile(file_); |
| 110 } | 113 } |
| 111 | 114 |
| 112 void SpellCheckHostImpl::Initialize() { | 115 void SpellCheckHostImpl::Initialize() { |
| 113 if (SpellCheckerPlatform::SpellCheckerAvailable() && | 116 if (SpellCheckerPlatform::SpellCheckerAvailable() && |
| 114 SpellCheckerPlatform::PlatformSupportsLanguage(language_)) { | 117 SpellCheckerPlatform::PlatformSupportsLanguage(language_)) { |
| 115 #if defined(OS_MACOSX) | 118 #if defined(OS_MACOSX) |
| 116 RecordSpellCheckStats(true, language_); | 119 RecordSpellCheckStats(true, language_); |
| 117 #endif | 120 #endif |
| 118 use_platform_spellchecker_ = true; | 121 use_platform_spellchecker_ = true; |
| 119 SpellCheckerPlatform::SetLanguage(language_); | 122 SpellCheckerPlatform::SetLanguage(language_); |
| 120 MessageLoop::current()->PostTask(FROM_HERE, | 123 MessageLoop::current()->PostTask(FROM_HERE, |
| 121 NewRunnableMethod(this, | 124 base::Bind(&SpellCheckHostImpl::InformProfileOfInitialization, |
| 122 &SpellCheckHostImpl::InformProfileOfInitialization)); | 125 weak_ptr_factory_.GetWeakPtr())); |
| 123 return; | 126 return; |
| 124 } | 127 } |
| 125 | 128 |
| 126 #if defined(OS_MACOSX) | 129 #if defined(OS_MACOSX) |
| 127 RecordSpellCheckStats(false, language_); | 130 RecordSpellCheckStats(false, language_); |
| 128 #endif | 131 #endif |
| 129 | 132 |
| 130 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 133 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 131 NewRunnableMethod(this, | 134 base::Bind(&SpellCheckHostImpl::InitializeDictionaryLocation, |
| 132 &SpellCheckHostImpl::InitializeDictionaryLocation)); | 135 weak_ptr_factory_.GetWeakPtr())); |
| 133 } | 136 } |
| 134 | 137 |
| 135 void SpellCheckHostImpl::UnsetProfile() { | 138 void SpellCheckHostImpl::UnsetProfile() { |
| 136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 137 | 140 |
| 138 profile_ = NULL; | 141 profile_ = NULL; |
| 139 request_context_getter_ = NULL; | 142 request_context_getter_ = NULL; |
| 140 fetcher_.reset(); | 143 fetcher_.reset(); |
| 141 registrar_.RemoveAll(); | 144 registrar_.RemoveAll(); |
| 142 } | 145 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 168 GetLanguage(), | 171 GetLanguage(), |
| 169 prefs->GetBoolean(prefs::kEnableAutoSpellCorrect))); | 172 prefs->GetBoolean(prefs::kEnableAutoSpellCorrect))); |
| 170 } | 173 } |
| 171 | 174 |
| 172 void SpellCheckHostImpl::AddWord(const std::string& word) { | 175 void SpellCheckHostImpl::AddWord(const std::string& word) { |
| 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 174 | 177 |
| 175 if (profile_) | 178 if (profile_) |
| 176 profile_->CustomWordAddedLocally(word); | 179 profile_->CustomWordAddedLocally(word); |
| 177 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 180 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 178 NewRunnableMethod(this, | 181 base::Bind(&SpellCheckHostImpl::WriteWordToCustomDictionary, |
| 179 &SpellCheckHostImpl::WriteWordToCustomDictionary, word)); | 182 weak_ptr_factory_.GetWeakPtr(), word)); |
| 180 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); | 183 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); |
| 181 !i.IsAtEnd(); i.Advance()) { | 184 !i.IsAtEnd(); i.Advance()) { |
| 182 i.GetCurrentValue()->Send(new SpellCheckMsg_WordAdded(word)); | 185 i.GetCurrentValue()->Send(new SpellCheckMsg_WordAdded(word)); |
| 183 } | 186 } |
| 184 } | 187 } |
| 185 | 188 |
| 186 void SpellCheckHostImpl::InitializeDictionaryLocation() { | 189 void SpellCheckHostImpl::InitializeDictionaryLocation() { |
| 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 188 | 191 |
| 189 // Initialize the BDICT path. This initialization should be in the FILE thread | 192 // Initialize the BDICT path. This initialization should be in the FILE thread |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, | 227 base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, |
| 225 NULL, NULL); | 228 NULL, NULL); |
| 226 } | 229 } |
| 227 | 230 |
| 228 // File didn't exist. Download it. | 231 // File didn't exist. Download it. |
| 229 if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_ && | 232 if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_ && |
| 230 request_context_getter_) { | 233 request_context_getter_) { |
| 231 // We download from the ui thread because we need to know that | 234 // We download from the ui thread because we need to know that |
| 232 // |request_context_getter_| is still valid before initiating the download. | 235 // |request_context_getter_| is still valid before initiating the download. |
| 233 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 236 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 234 NewRunnableMethod(this, &SpellCheckHostImpl::DownloadDictionary)); | 237 base::Bind(&SpellCheckHostImpl::DownloadDictionary, |
| 238 weak_ptr_factory_.GetWeakPtr())); |
| 235 return; | 239 return; |
| 236 } | 240 } |
| 237 | 241 |
| 238 request_context_getter_ = NULL; | 242 request_context_getter_ = NULL; |
| 239 | 243 |
| 240 scoped_ptr<CustomWordList> custom_words(new CustomWordList()); | 244 scoped_ptr<CustomWordList> custom_words(new CustomWordList()); |
| 241 if (file_ != base::kInvalidPlatformFileValue) { | 245 if (file_ != base::kInvalidPlatformFileValue) { |
| 242 // Load custom dictionary. | 246 // Load custom dictionary. |
| 243 std::string contents; | 247 std::string contents; |
| 244 file_util::ReadFileToString(custom_dictionary_file_, &contents); | 248 file_util::ReadFileToString(custom_dictionary_file_, &contents); |
| 245 CustomWordList list_of_words; | 249 CustomWordList list_of_words; |
| 246 base::SplitString(contents, '\n', &list_of_words); | 250 base::SplitString(contents, '\n', &list_of_words); |
| 247 for (size_t i = 0; i < list_of_words.size(); ++i) | 251 for (size_t i = 0; i < list_of_words.size(); ++i) |
| 248 custom_words->push_back(list_of_words[i]); | 252 custom_words->push_back(list_of_words[i]); |
| 249 } | 253 } |
| 250 | 254 |
| 251 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 255 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 252 NewRunnableMethod( | 256 base::Bind( |
| 253 this, | |
| 254 &SpellCheckHostImpl::InformProfileOfInitializationWithCustomWords, | 257 &SpellCheckHostImpl::InformProfileOfInitializationWithCustomWords, |
| 258 weak_ptr_factory_.GetWeakPtr(), |
| 255 custom_words.release())); | 259 custom_words.release())); |
| 256 } | 260 } |
| 257 | 261 |
| 258 void SpellCheckHostImpl::InitializeOnFileThread() { | 262 void SpellCheckHostImpl::InitializeOnFileThread() { |
| 259 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 263 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 260 | 264 |
| 261 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 265 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 262 NewRunnableMethod(this, &SpellCheckHostImpl::Initialize)); | 266 base::Bind(&SpellCheckHostImpl::Initialize, |
| 267 weak_ptr_factory_.GetWeakPtr())); |
| 263 } | 268 } |
| 264 | 269 |
| 265 void SpellCheckHostImpl::InformProfileOfInitialization() { | 270 void SpellCheckHostImpl::InformProfileOfInitialization() { |
| 266 InformProfileOfInitializationWithCustomWords(NULL); | 271 InformProfileOfInitializationWithCustomWords(NULL); |
| 267 } | 272 } |
| 268 | 273 |
| 269 void SpellCheckHostImpl::InformProfileOfInitializationWithCustomWords( | 274 void SpellCheckHostImpl::InformProfileOfInitializationWithCustomWords( |
| 270 CustomWordList* custom_words) { | 275 CustomWordList* custom_words) { |
| 271 // Non-null |custom_words| should be given only if the profile is available | 276 // Non-null |custom_words| should be given only if the profile is available |
| 272 // for simplifying the life-cycle management of the word list. | 277 // for simplifying the life-cycle management of the word list. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 295 // Determine URL of file to download. | 300 // Determine URL of file to download. |
| 296 static const char kDownloadServerUrl[] = | 301 static const char kDownloadServerUrl[] = |
| 297 "http://cache.pack.google.com/edgedl/chrome/dict/"; | 302 "http://cache.pack.google.com/edgedl/chrome/dict/"; |
| 298 std::string bdict_file = bdict_file_path_.BaseName().MaybeAsASCII(); | 303 std::string bdict_file = bdict_file_path_.BaseName().MaybeAsASCII(); |
| 299 if (bdict_file.empty()) { | 304 if (bdict_file.empty()) { |
| 300 NOTREACHED(); | 305 NOTREACHED(); |
| 301 return; | 306 return; |
| 302 } | 307 } |
| 303 GURL url = GURL(std::string(kDownloadServerUrl) + | 308 GURL url = GURL(std::string(kDownloadServerUrl) + |
| 304 StringToLowerASCII(bdict_file)); | 309 StringToLowerASCII(bdict_file)); |
| 305 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); | 310 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, |
| 311 weak_ptr_factory_.GetWeakPtr())); |
| 306 fetcher_->set_request_context(request_context_getter_); | 312 fetcher_->set_request_context(request_context_getter_); |
| 307 tried_to_download_ = true; | 313 tried_to_download_ = true; |
| 308 fetcher_->Start(); | 314 fetcher_->Start(); |
| 309 request_context_getter_ = NULL; | 315 request_context_getter_ = NULL; |
| 310 } | 316 } |
| 311 | 317 |
| 312 void SpellCheckHostImpl::WriteWordToCustomDictionary(const std::string& word) { | 318 void SpellCheckHostImpl::WriteWordToCustomDictionary(const std::string& word) { |
| 313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 314 | 320 |
| 315 // Stored in UTF-8. | 321 // Stored in UTF-8. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 342 // that represents some form of failure. | 348 // that represents some form of failure. |
| 343 if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || | 349 if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || |
| 344 data[3] != 'c') { | 350 data[3] != 'c') { |
| 345 LOG(ERROR) << "Failure to download dictionary."; | 351 LOG(ERROR) << "Failure to download dictionary."; |
| 346 InitializeOnFileThread(); | 352 InitializeOnFileThread(); |
| 347 return; | 353 return; |
| 348 } | 354 } |
| 349 | 355 |
| 350 data_ = data; | 356 data_ = data; |
| 351 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 357 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 352 NewRunnableMethod(this, &SpellCheckHostImpl::SaveDictionaryData)); | 358 base::Bind(&SpellCheckHostImpl::SaveDictionaryData, |
| 359 weak_ptr_factory_.GetWeakPtr())); |
| 353 } | 360 } |
| 354 | 361 |
| 355 void SpellCheckHostImpl::Observe(int type, | 362 void SpellCheckHostImpl::Observe(int type, |
| 356 const content::NotificationSource& source, | 363 const content::NotificationSource& source, |
| 357 const content::NotificationDetails& details) { | 364 const content::NotificationDetails& details) { |
| 358 DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CREATED); | 365 DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CREATED); |
| 359 RenderProcessHost* process = content::Source<RenderProcessHost>(source).ptr(); | 366 RenderProcessHost* process = content::Source<RenderProcessHost>(source).ptr(); |
| 360 InitForRenderer(process); | 367 InitForRenderer(process); |
| 361 } | 368 } |
| 362 | 369 |
| 363 void SpellCheckHostImpl::SaveDictionaryData() { | 370 void SpellCheckHostImpl::SaveDictionaryData() { |
| 364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 365 | 372 |
| 366 // To prevent corrupted dictionary data from causing a renderer crash, scan | 373 // To prevent corrupted dictionary data from causing a renderer crash, scan |
| 367 // the dictionary data and verify it is sane before save it to a file. | 374 // the dictionary data and verify it is sane before save it to a file. |
| 368 bool verified = hunspell::BDict::Verify(data_.data(), data_.size()); | 375 bool verified = hunspell::BDict::Verify(data_.data(), data_.size()); |
| 369 if (metrics_) | 376 if (metrics_) |
| 370 metrics_->RecordDictionaryCorruptionStats(!verified); | 377 metrics_->RecordDictionaryCorruptionStats(!verified); |
| 371 if (!verified) { | 378 if (!verified) { |
| 372 LOG(ERROR) << "Failure to verify the downloaded dictionary."; | 379 LOG(ERROR) << "Failure to verify the downloaded dictionary."; |
| 373 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 380 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 374 NewRunnableMethod(this, | 381 base::Bind(&SpellCheckHostImpl::InformProfileOfInitialization, |
| 375 &SpellCheckHostImpl::InformProfileOfInitialization)); | 382 weak_ptr_factory_.GetWeakPtr())); |
| 376 return; | 383 return; |
| 377 } | 384 } |
| 378 | 385 |
| 379 size_t bytes_written = | 386 size_t bytes_written = |
| 380 file_util::WriteFile(bdict_file_path_, data_.data(), data_.length()); | 387 file_util::WriteFile(bdict_file_path_, data_.data(), data_.length()); |
| 381 if (bytes_written != data_.length()) { | 388 if (bytes_written != data_.length()) { |
| 382 bool success = false; | 389 bool success = false; |
| 383 #if defined(OS_WIN) | 390 #if defined(OS_WIN) |
| 384 bdict_file_path_ = GetFallbackFilePath(bdict_file_path_); | 391 bdict_file_path_ = GetFallbackFilePath(bdict_file_path_); |
| 385 bytes_written = | 392 bytes_written = |
| 386 file_util::WriteFile(GetFallbackFilePath(bdict_file_path_), | 393 file_util::WriteFile(GetFallbackFilePath(bdict_file_path_), |
| 387 data_.data(), data_.length()); | 394 data_.data(), data_.length()); |
| 388 if (bytes_written == data_.length()) | 395 if (bytes_written == data_.length()) |
| 389 success = true; | 396 success = true; |
| 390 #endif | 397 #endif |
| 391 data_.clear(); | 398 data_.clear(); |
| 392 | 399 |
| 393 if (!success) { | 400 if (!success) { |
| 394 LOG(ERROR) << "Failure to save dictionary."; | 401 LOG(ERROR) << "Failure to save dictionary."; |
| 395 file_util::Delete(bdict_file_path_, false); | 402 file_util::Delete(bdict_file_path_, false); |
| 396 // To avoid trying to load a partially saved dictionary, shortcut the | 403 // To avoid trying to load a partially saved dictionary, shortcut the |
| 397 // Initialize() call. | 404 // Initialize() call. |
| 398 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 405 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 399 NewRunnableMethod(this, | 406 base::Bind( |
| 400 &SpellCheckHostImpl::InformProfileOfInitialization)); | 407 &SpellCheckHostImpl::InformProfileOfInitialization, |
| 408 weak_ptr_factory_.GetWeakPtr())); |
| 401 return; | 409 return; |
| 402 } | 410 } |
| 403 } | 411 } |
| 404 | 412 |
| 405 data_.clear(); | 413 data_.clear(); |
| 406 Initialize(); | 414 Initialize(); |
| 407 } | 415 } |
| 408 | 416 |
| 409 bool SpellCheckHostImpl::VerifyBDict(const FilePath& path) const { | 417 bool SpellCheckHostImpl::VerifyBDict(const FilePath& path) const { |
| 410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 433 return file_; | 441 return file_; |
| 434 } | 442 } |
| 435 | 443 |
| 436 const std::string& SpellCheckHostImpl::GetLanguage() const { | 444 const std::string& SpellCheckHostImpl::GetLanguage() const { |
| 437 return language_; | 445 return language_; |
| 438 } | 446 } |
| 439 | 447 |
| 440 bool SpellCheckHostImpl::IsUsingPlatformChecker() const { | 448 bool SpellCheckHostImpl::IsUsingPlatformChecker() const { |
| 441 return use_platform_spellchecker_; | 449 return use_platform_spellchecker_; |
| 442 } | 450 } |
| OLD | NEW |