OLD | NEW |
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-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/spellchecker.h" | 5 #include "chrome/browser/spellchecker.h" |
6 | 6 |
7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
8 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
11 #include "base/histogram.h" | 11 #include "base/histogram.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/path_service.h" | 13 #include "base/path_service.h" |
14 #include "base/stats_counters.h" | 14 #include "base/stats_counters.h" |
15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
16 #include "base/thread.h" | |
17 #include "chrome/browser/browser_process.h" | |
18 #include "chrome/browser/chrome_thread.h" | 16 #include "chrome/browser/chrome_thread.h" |
19 #include "chrome/browser/net/url_fetcher.h" | 17 #include "chrome/browser/net/url_fetcher.h" |
20 #include "chrome/browser/profile.h" | 18 #include "chrome/browser/profile.h" |
21 #include "chrome/browser/spellchecker_common.h" | 19 #include "chrome/browser/spellchecker_common.h" |
22 #include "chrome/browser/spellchecker_platform_engine.h" | 20 #include "chrome/browser/spellchecker_platform_engine.h" |
23 #include "chrome/common/chrome_constants.h" | 21 #include "chrome/common/chrome_constants.h" |
24 #include "chrome/common/chrome_counters.h" | 22 #include "chrome/common/chrome_counters.h" |
25 #include "chrome/common/chrome_paths.h" | 23 #include "chrome/common/chrome_paths.h" |
26 #include "chrome/common/pref_names.h" | 24 #include "chrome/common/pref_names.h" |
27 #include "chrome/common/pref_service.h" | 25 #include "chrome/common/pref_service.h" |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 | 86 |
89 bool SaveBufferToFile(const std::string& data, | 87 bool SaveBufferToFile(const std::string& data, |
90 FilePath file_to_write) { | 88 FilePath file_to_write) { |
91 int num_bytes = data.length(); | 89 int num_bytes = data.length(); |
92 return file_util::WriteFile(file_to_write, data.data(), num_bytes) == | 90 return file_util::WriteFile(file_to_write, data.data(), num_bytes) == |
93 num_bytes; | 91 num_bytes; |
94 } | 92 } |
95 | 93 |
96 } // namespace | 94 } // namespace |
97 | 95 |
98 // This is a helper class which acts as a proxy for invoking a task from the | |
99 // file loop back to the IO loop. Invoking a task from file loop to the IO | |
100 // loop directly is not safe as during browser shutdown, the IO loop tears | |
101 // down before the file loop. To avoid a crash, this object is invoked in the | |
102 // UI loop from the file loop, from where it gets the IO thread directly from | |
103 // g_browser_process and invokes the given task in the IO loop if it is not | |
104 // NULL. This object also takes ownership of the given task. | |
105 class UIProxyForIOTask : public Task { | |
106 public: | |
107 explicit UIProxyForIOTask(Task* callback_task, SpellChecker* spellchecker) | |
108 : callback_task_(callback_task), | |
109 spellchecker_(spellchecker) { | |
110 } | |
111 | |
112 private: | |
113 void Run(); | |
114 | |
115 Task* callback_task_; | |
116 // The SpellChecker that invoked the file loop task. May be NULL. If not | |
117 // NULL, then we will Release() on it if we don't run |callback_task_|. This | |
118 // balances any refs the spellchecker might have had outstanding which it | |
119 // would have Released() when |callback_task_| was run. | |
120 SpellChecker* spellchecker_; | |
121 DISALLOW_COPY_AND_ASSIGN(UIProxyForIOTask); | |
122 }; | |
123 | |
124 void UIProxyForIOTask::Run() { | |
125 // This has been invoked in the UI thread. | |
126 base::Thread* io_thread = g_browser_process->io_thread(); | |
127 if (io_thread) { // io_thread has not been torn down yet. | |
128 MessageLoop* io_loop = io_thread->message_loop(); | |
129 io_loop->PostTask(FROM_HERE, callback_task_); | |
130 } else { | |
131 if (spellchecker_) | |
132 spellchecker_->Release(); | |
133 delete callback_task_; | |
134 } | |
135 | |
136 callback_task_ = NULL; | |
137 } | |
138 | |
139 // Design: The spellchecker initializes hunspell_ in the Initialize() method. | 96 // Design: The spellchecker initializes hunspell_ in the Initialize() method. |
140 // This is done using the dictionary file on disk, e.g. "en-US_1_1.bdic". | 97 // This is done using the dictionary file on disk, e.g. "en-US_1_1.bdic". |
141 // Initialization of hunspell_ is held off during this process. If the | 98 // Initialization of hunspell_ is held off during this process. If the |
142 // dictionary is not available, we first attempt to download and save it. After | 99 // dictionary is not available, we first attempt to download and save it. After |
143 // the dictionary is downloaded and saved to disk (or the attempt to do so | 100 // the dictionary is downloaded and saved to disk (or the attempt to do so |
144 // fails)), corresponding flags are set | 101 // fails)), corresponding flags are set in spellchecker - in the IO thread. |
145 // in spellchecker - in the IO thread. Since IO thread goes first during closing | 102 // After the flags are cleared, a (final) attempt is made to initialize |
146 // of browser, a proxy task |UIProxyForIOTask| is created in the UI thread, | 103 // hunspell_. If it fails even then (dictionary could not download), no more |
147 // which obtains the IO thread independently and invokes the task in the IO | 104 // attempts are made to initialize it. |
148 // thread if it's not NULL. After the flags are cleared, a (final) attempt is | |
149 // made to initialize hunspell_. If it fails even then (dictionary could not | |
150 // download), no more attempts are made to initialize it. | |
151 class SaveDictionaryTask : public Task { | 105 class SaveDictionaryTask : public Task { |
152 public: | 106 public: |
153 SaveDictionaryTask(Task* on_dictionary_save_complete_callback_task, | 107 SaveDictionaryTask(Task* on_dictionary_save_complete_callback_task, |
154 const FilePath& first_attempt_file_name, | 108 const FilePath& first_attempt_file_name, |
155 const FilePath& fallback_file_name, | 109 const FilePath& fallback_file_name, |
156 const std::string& data) | 110 const std::string& data) |
157 : on_dictionary_save_complete_callback_task_( | 111 : on_dictionary_save_complete_callback_task_( |
158 on_dictionary_save_complete_callback_task), | 112 on_dictionary_save_complete_callback_task), |
159 first_attempt_file_name_(first_attempt_file_name), | 113 first_attempt_file_name_(first_attempt_file_name), |
160 fallback_file_name_(fallback_file_name), | 114 fallback_file_name_(fallback_file_name), |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 // write permission. If even this fails, there is nothing to be done. | 148 // write permission. If even this fails, there is nothing to be done. |
195 FilePath fallback_dir = fallback_file_name_.DirName(); | 149 FilePath fallback_dir = fallback_file_name_.DirName(); |
196 // Create the directory if it does not exist. | 150 // Create the directory if it does not exist. |
197 if (!file_util::PathExists(fallback_dir)) | 151 if (!file_util::PathExists(fallback_dir)) |
198 file_util::CreateDirectory(fallback_dir); | 152 file_util::CreateDirectory(fallback_dir); |
199 SaveBufferToFile(data_, fallback_file_name_); | 153 SaveBufferToFile(data_, fallback_file_name_); |
200 } // Unsuccessful save is taken care of in SpellChecker::Initialize(). | 154 } // Unsuccessful save is taken care of in SpellChecker::Initialize(). |
201 | 155 |
202 // Set Flag that dictionary is not downloading anymore. | 156 // Set Flag that dictionary is not downloading anymore. |
203 ChromeThread::PostTask( | 157 ChromeThread::PostTask( |
204 ChromeThread::UI, FROM_HERE, | 158 ChromeThread::IO, FROM_HERE, on_dictionary_save_complete_callback_task_); |
205 new UIProxyForIOTask(on_dictionary_save_complete_callback_task_, NULL)); | |
206 } | 159 } |
207 | 160 |
208 // Design: this task tries to read the dictionary from disk and load it into | 161 // Design: this task tries to read the dictionary from disk and load it into |
209 // memory. It is executed on the file thread, and posts the results back to | 162 // memory. It is executed on the file thread, and posts the results back to |
210 // the IO thread (via the UI thread---see UIProxyForIOTask). | 163 // the IO thread. |
211 // The task first checks for the existence of the dictionary in one of the two | 164 // The task first checks for the existence of the dictionary in one of the two |
212 // given locations. If it does not exist, the task informs the SpellChecker, | 165 // given locations. If it does not exist, the task informs the SpellChecker, |
213 // which will try to download the directory and run a new ReadDictionaryTask. | 166 // which will try to download the directory and run a new ReadDictionaryTask. |
214 class ReadDictionaryTask : public Task { | 167 class ReadDictionaryTask : public Task { |
215 public: | 168 public: |
216 ReadDictionaryTask(SpellChecker* spellchecker, | 169 ReadDictionaryTask(SpellChecker* spellchecker, |
217 const FilePath& dict_file_name_app, | 170 const FilePath& dict_file_name_app, |
218 const FilePath& dict_file_name_usr) | 171 const FilePath& dict_file_name_usr) |
219 : spellchecker_(spellchecker), | 172 : spellchecker_(spellchecker), |
220 hunspell_(NULL), | 173 hunspell_(NULL), |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 } else { | 211 } else { |
259 delete bdict_file_; | 212 delete bdict_file_; |
260 bdict_file_ = NULL; | 213 bdict_file_ = NULL; |
261 } | 214 } |
262 | 215 |
263 Finish(true); | 216 Finish(true); |
264 } | 217 } |
265 | 218 |
266 private: | 219 private: |
267 void Finish(bool file_existed) { | 220 void Finish(bool file_existed) { |
268 Task* task = NewRunnableMethod(spellchecker_, &SpellChecker::HunspellInited, | 221 ChromeThread::PostTask( |
269 hunspell_, bdict_file_, file_existed); | 222 ChromeThread::IO, FROM_HERE, |
270 if (spellchecker_->file_loop_) { | 223 NewRunnableMethod( |
271 // We were called on the file loop. Post back to the IO loop. | 224 spellchecker_, &SpellChecker::HunspellInited, hunspell_, |
272 // If this never gets posted to the IO loop, then we will leak |hunspell_| | 225 bdict_file_, file_existed)); |
273 // and |bdict_file_|. But that can only happen during shutdown, so it's | |
274 // not worth caring about. | |
275 ChromeThread::PostTask( | |
276 ChromeThread::UI, FROM_HERE, | |
277 new UIProxyForIOTask(task, spellchecker_)); | |
278 } else { | |
279 // We were called directly (e.g., during testing). Run the task directly. | |
280 task->Run(); | |
281 delete task; | |
282 } | |
283 } | 226 } |
284 | 227 |
285 // The SpellChecker we are working for. We are guaranteed to be outlived | 228 // The SpellChecker we are working for. We are guaranteed to be outlived |
286 // by this object because it AddRefs() itself before calling us. | 229 // by this object because it AddRefs() itself before calling us. |
287 // Accessing it is not necessarily thread safe, but are careful to only access | 230 // Accessing it is not necessarily thread safe, but are careful to only access |
288 // it in ways that are. | 231 // it in ways that are. |
289 SpellChecker* spellchecker_; | 232 SpellChecker* spellchecker_; |
290 Hunspell* hunspell_; | 233 Hunspell* hunspell_; |
291 file_util::MemoryMappedFile* bdict_file_; | 234 file_util::MemoryMappedFile* bdict_file_; |
292 | 235 |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 } | 406 } |
464 | 407 |
465 SpellChecker::SpellChecker(const FilePath& dict_dir, | 408 SpellChecker::SpellChecker(const FilePath& dict_dir, |
466 const std::string& language, | 409 const std::string& language, |
467 URLRequestContextGetter* request_context_getter, | 410 URLRequestContextGetter* request_context_getter, |
468 const FilePath& custom_dictionary_file_name) | 411 const FilePath& custom_dictionary_file_name) |
469 : given_dictionary_directory_(dict_dir), | 412 : given_dictionary_directory_(dict_dir), |
470 custom_dictionary_file_name_(custom_dictionary_file_name), | 413 custom_dictionary_file_name_(custom_dictionary_file_name), |
471 tried_to_init_(false), | 414 tried_to_init_(false), |
472 language_(language), | 415 language_(language), |
473 worker_loop_(NULL), | |
474 tried_to_download_dictionary_file_(false), | 416 tried_to_download_dictionary_file_(false), |
475 file_loop_(NULL), | |
476 request_context_getter_(request_context_getter), | 417 request_context_getter_(request_context_getter), |
477 obtaining_dictionary_(false), | 418 obtaining_dictionary_(false), |
478 auto_spell_correct_turned_on_(false), | 419 auto_spell_correct_turned_on_(false), |
479 is_using_platform_spelling_engine_(false), | 420 is_using_platform_spelling_engine_(false), |
480 fetcher_(NULL), | 421 fetcher_(NULL), |
481 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | 422 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
482 if (SpellCheckerPlatform::SpellCheckerAvailable()) { | 423 if (SpellCheckerPlatform::SpellCheckerAvailable()) { |
483 SpellCheckerPlatform::Init(); | 424 SpellCheckerPlatform::Init(); |
484 if (SpellCheckerPlatform::PlatformSupportsLanguage(language)) { | 425 if (SpellCheckerPlatform::PlatformSupportsLanguage(language)) { |
485 // If we have reached here, then we know that the current platform | 426 // If we have reached here, then we know that the current platform |
486 // supports the given language and we will use it instead of hunspell. | 427 // supports the given language and we will use it instead of hunspell. |
487 SpellCheckerPlatform::SetLanguage(language); | 428 SpellCheckerPlatform::SetLanguage(language); |
488 is_using_platform_spelling_engine_ = true; | 429 is_using_platform_spelling_engine_ = true; |
489 } | 430 } |
490 } | 431 } |
491 | 432 |
492 // Get the corresponding BDIC file name. | 433 // Get the corresponding BDIC file name. |
493 bdic_file_name_ = GetVersionedFileName(language, dict_dir).BaseName(); | 434 bdic_file_name_ = GetVersionedFileName(language, dict_dir).BaseName(); |
494 | 435 |
495 // Get File Loop - hunspell gets initialized here. | |
496 base::Thread* file_thread = g_browser_process->file_thread(); | |
497 if (file_thread) | |
498 file_loop_ = file_thread->message_loop(); | |
499 | |
500 // Get the path to the custom dictionary file. | 436 // Get the path to the custom dictionary file. |
501 if (custom_dictionary_file_name_.empty()) { | 437 if (custom_dictionary_file_name_.empty()) { |
502 FilePath personal_file_directory; | 438 FilePath personal_file_directory; |
503 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); | 439 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); |
504 custom_dictionary_file_name_ = | 440 custom_dictionary_file_name_ = |
505 personal_file_directory.Append(chrome::kCustomDictionaryFileName); | 441 personal_file_directory.Append(chrome::kCustomDictionaryFileName); |
506 } | 442 } |
507 | 443 |
508 // Use this dictionary language as the default one of the | 444 // Use this dictionary language as the default one of the |
509 // SpellcheckCharAttribute object. | 445 // SpellcheckCharAttribute object. |
510 character_attributes_.SetDefaultLanguage(language); | 446 character_attributes_.SetDefaultLanguage(language); |
511 } | 447 } |
512 | 448 |
513 SpellChecker::~SpellChecker() { | 449 SpellChecker::~SpellChecker() { |
514 // This must be deleted on the I/O thread (see the header). This is the same | 450 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
515 // thread that SpellCheckWord is called on, so we verify that they were all | |
516 // the same thread. | |
517 if (worker_loop_) | |
518 DCHECK(MessageLoop::current() == worker_loop_); | |
519 } | 451 } |
520 | 452 |
521 void SpellChecker::StartDictionaryDownload(const FilePath& file_name) { | 453 void SpellChecker::StartDictionaryDownload(const FilePath& file_name) { |
522 // Determine URL of file to download. | 454 // Determine URL of file to download. |
523 static const char kDownloadServerUrl[] = | 455 static const char kDownloadServerUrl[] = |
524 "http://cache.pack.google.com/edgedl/chrome/dict/"; | 456 "http://cache.pack.google.com/edgedl/chrome/dict/"; |
525 GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8( | 457 GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8( |
526 l10n_util::ToLower(bdic_file_name_.ToWStringHack()))); | 458 l10n_util::ToLower(bdic_file_name_.ToWStringHack()))); |
527 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); | 459 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); |
528 fetcher_->set_request_context(request_context_getter_); | 460 fetcher_->set_request_context(request_context_getter_); |
(...skipping 22 matching lines...) Expand all Loading... |
551 return; | 483 return; |
552 } | 484 } |
553 | 485 |
554 // Save the file in the file thread, and not here, the IO thread. | 486 // Save the file in the file thread, and not here, the IO thread. |
555 FilePath first_attempt_file_name = given_dictionary_directory_.Append( | 487 FilePath first_attempt_file_name = given_dictionary_directory_.Append( |
556 bdic_file_name_); | 488 bdic_file_name_); |
557 FilePath user_data_dir = GetFallbackDictionaryDownloadDirectory(); | 489 FilePath user_data_dir = GetFallbackDictionaryDownloadDirectory(); |
558 FilePath fallback_file_name = user_data_dir.Append(bdic_file_name_); | 490 FilePath fallback_file_name = user_data_dir.Append(bdic_file_name_); |
559 Task* dic_task = method_factory_. | 491 Task* dic_task = method_factory_. |
560 NewRunnableMethod(&SpellChecker::OnDictionarySaveComplete); | 492 NewRunnableMethod(&SpellChecker::OnDictionarySaveComplete); |
561 file_loop_->PostTask(FROM_HERE, new SaveDictionaryTask(dic_task, | 493 ChromeThread::PostTask( |
562 first_attempt_file_name, fallback_file_name, data)); | 494 ChromeThread::FILE, FROM_HERE, |
| 495 new SaveDictionaryTask( |
| 496 dic_task, first_attempt_file_name, fallback_file_name, data)); |
563 } | 497 } |
564 | 498 |
565 void SpellChecker::OnDictionarySaveComplete() { | 499 void SpellChecker::OnDictionarySaveComplete() { |
566 obtaining_dictionary_ = false; | 500 obtaining_dictionary_ = false; |
567 // Now that the dictionary is downloaded, continue trying to download. | 501 // Now that the dictionary is downloaded, continue trying to download. |
568 Initialize(); | 502 Initialize(); |
569 } | 503 } |
570 | 504 |
571 // Initialize SpellChecker. In this method, if the dictionary is not present | 505 // Initialize SpellChecker. In this method, if the dictionary is not present |
572 // in the local disk, it is fetched asynchronously. | 506 // in the local disk, it is fetched asynchronously. |
573 bool SpellChecker::Initialize() { | 507 bool SpellChecker::Initialize() { |
574 if (!worker_loop_) | 508 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
575 worker_loop_ = MessageLoop::current(); | |
576 else | |
577 DCHECK(worker_loop_ == MessageLoop::current()); | |
578 | 509 |
579 // Return false if the dictionary files are downloading. | 510 // Return false if the dictionary files are downloading. |
580 if (obtaining_dictionary_) | 511 if (obtaining_dictionary_) |
581 return false; | 512 return false; |
582 | 513 |
583 // Return false if tried to init and failed - don't try multiple times in | 514 // Return false if tried to init and failed - don't try multiple times in |
584 // this session. | 515 // this session. |
585 if (tried_to_init_) | 516 if (tried_to_init_) |
586 return hunspell_.get() != NULL; | 517 return hunspell_.get() != NULL; |
587 | 518 |
(...skipping 11 matching lines...) Expand all Loading... |
599 // File name for downloading in DIR_APP_DICTIONARIES. | 530 // File name for downloading in DIR_APP_DICTIONARIES. |
600 FilePath dictionary_file_name_app = GetVersionedFileName(language_, | 531 FilePath dictionary_file_name_app = GetVersionedFileName(language_, |
601 given_dictionary_directory_); | 532 given_dictionary_directory_); |
602 | 533 |
603 // Filename for downloading in the fallback dictionary download directory, | 534 // Filename for downloading in the fallback dictionary download directory, |
604 // DIR_USER_DATA. | 535 // DIR_USER_DATA. |
605 FilePath dict_dir_userdata = GetFallbackDictionaryDownloadDirectory(); | 536 FilePath dict_dir_userdata = GetFallbackDictionaryDownloadDirectory(); |
606 FilePath dictionary_file_name_usr = GetVersionedFileName(language_, | 537 FilePath dictionary_file_name_usr = GetVersionedFileName(language_, |
607 dict_dir_userdata); | 538 dict_dir_userdata); |
608 | 539 |
609 // Balances Release() in HunspellInited(), or in UIProxyForIOTask if the IO | 540 // Balances Release() in HunspellInited(). |
610 // thread is torn down before the ReadDictionaryTask calls us back. | |
611 AddRef(); | 541 AddRef(); |
612 Task* task = new ReadDictionaryTask(this, | 542 ChromeThread::PostTask( |
613 dictionary_file_name_app, dictionary_file_name_usr); | 543 ChromeThread::FILE, FROM_HERE, |
614 if (file_loop_) { | 544 new ReadDictionaryTask( |
615 file_loop_->PostTask(FROM_HERE, task); | 545 this, dictionary_file_name_app, dictionary_file_name_usr)); |
616 } else { | |
617 task->Run(); | |
618 delete task; | |
619 } | |
620 | 546 |
621 return hunspell_.get() != NULL; | 547 return hunspell_.get() != NULL; |
622 } | 548 } |
623 | 549 |
624 void SpellChecker::HunspellInited(Hunspell* hunspell, | 550 void SpellChecker::HunspellInited(Hunspell* hunspell, |
625 file_util::MemoryMappedFile* bdict_file, | 551 file_util::MemoryMappedFile* bdict_file, |
626 bool file_existed) { | 552 bool file_existed) { |
627 DCHECK(worker_loop_ == MessageLoop::current()); | 553 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
628 | 554 |
629 if (file_existed) | 555 if (file_existed) |
630 tried_to_init_ = true; | 556 tried_to_init_ = true; |
631 | 557 |
632 if (!hunspell) { | 558 if (!hunspell) { |
633 if (!file_existed) { | 559 if (!file_existed) { |
634 // File didn't exist. We need to download a dictionary. | 560 // File didn't exist. We need to download a dictionary. |
635 DoDictionaryDownload(); | 561 DoDictionaryDownload(); |
636 } | 562 } |
637 | 563 |
(...skipping 10 matching lines...) Expand all Loading... |
648 hunspell_->add(custom_words_.front().c_str()); | 574 hunspell_->add(custom_words_.front().c_str()); |
649 custom_words_.pop(); | 575 custom_words_.pop(); |
650 } | 576 } |
651 | 577 |
652 // Balances AddRef() in Initialize(). | 578 // Balances AddRef() in Initialize(). |
653 Release(); | 579 Release(); |
654 } | 580 } |
655 | 581 |
656 void SpellChecker::DoDictionaryDownload() { | 582 void SpellChecker::DoDictionaryDownload() { |
657 // Download the dictionary file. | 583 // Download the dictionary file. |
658 if (file_loop_ && request_context_getter_) { | 584 if (request_context_getter_) { |
659 if (!tried_to_download_dictionary_file_) { | 585 if (!tried_to_download_dictionary_file_) { |
660 FilePath dictionary_file_name_app = GetVersionedFileName(language_, | 586 FilePath dictionary_file_name_app = GetVersionedFileName(language_, |
661 given_dictionary_directory_); | 587 given_dictionary_directory_); |
662 StartDictionaryDownload(dictionary_file_name_app); | 588 StartDictionaryDownload(dictionary_file_name_app); |
663 tried_to_download_dictionary_file_ = true; | 589 tried_to_download_dictionary_file_ = true; |
664 } else { | 590 } else { |
665 // Don't try to download a dictionary more than once. | 591 // Don't try to download a dictionary more than once. |
666 tried_to_init_ = true; | 592 tried_to_init_ = true; |
667 } | 593 } |
668 } else { | 594 } else { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
743 const char16* in_word, | 669 const char16* in_word, |
744 int in_word_len, | 670 int in_word_len, |
745 int tag, | 671 int tag, |
746 int* misspelling_start, | 672 int* misspelling_start, |
747 int* misspelling_len, | 673 int* misspelling_len, |
748 std::vector<string16>* optional_suggestions) { | 674 std::vector<string16>* optional_suggestions) { |
749 DCHECK(in_word_len >= 0); | 675 DCHECK(in_word_len >= 0); |
750 DCHECK(misspelling_start && misspelling_len) << "Out vars must be given."; | 676 DCHECK(misspelling_start && misspelling_len) << "Out vars must be given."; |
751 | 677 |
752 // This must always be called on the same thread (normally the I/O thread). | 678 // This must always be called on the same thread (normally the I/O thread). |
753 if (worker_loop_) | 679 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
754 DCHECK(MessageLoop::current() == worker_loop_); | |
755 | 680 |
756 // Check if the platform spellchecker is being used. | 681 // Check if the platform spellchecker is being used. |
757 if (!is_using_platform_spelling_engine_) { | 682 if (!is_using_platform_spelling_engine_) { |
758 // If it isn't, try and init hunspell. | 683 // If it isn't, try and init hunspell. |
759 Initialize(); | 684 Initialize(); |
760 | 685 |
761 // Check to see if hunspell was successfuly initialized. | 686 // Check to see if hunspell was successfuly initialized. |
762 if (!hunspell_.get()) | 687 if (!hunspell_.get()) |
763 return true; // Unable to spellcheck, return word is OK. | 688 return true; // Unable to spellcheck, return word is OK. |
764 } | 689 } |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
843 if (!word_to_add.empty() && word_to_add.length() < MAXWORDUTF8LEN) { | 768 if (!word_to_add.empty() && word_to_add.length() < MAXWORDUTF8LEN) { |
844 // Either add the word to |hunspell_|, or, if |hunspell_| is still loading, | 769 // Either add the word to |hunspell_|, or, if |hunspell_| is still loading, |
845 // defer it till after the load completes. | 770 // defer it till after the load completes. |
846 if (hunspell_.get()) | 771 if (hunspell_.get()) |
847 hunspell_->add(word_to_add.c_str()); | 772 hunspell_->add(word_to_add.c_str()); |
848 else | 773 else |
849 custom_words_.push(word_to_add); | 774 custom_words_.push(word_to_add); |
850 } | 775 } |
851 | 776 |
852 // Now add the word to the custom dictionary file. | 777 // Now add the word to the custom dictionary file. |
853 Task* write_word_task = | 778 ChromeThread::PostTask( |
854 new AddWordToCustomDictionaryTask(custom_dictionary_file_name_, word); | 779 ChromeThread::FILE, FROM_HERE, |
855 if (file_loop_) { | 780 new AddWordToCustomDictionaryTask(custom_dictionary_file_name_, word)); |
856 file_loop_->PostTask(FROM_HERE, write_word_task); | |
857 } else { | |
858 write_word_task->Run(); | |
859 delete write_word_task; | |
860 } | |
861 } | 781 } |
862 | 782 |
863 bool SpellChecker::CheckSpelling(const string16& word_to_check, int tag) { | 783 bool SpellChecker::CheckSpelling(const string16& word_to_check, int tag) { |
864 bool word_correct = false; | 784 bool word_correct = false; |
865 | 785 |
866 TimeTicks begin_time = TimeTicks::Now(); | 786 TimeTicks begin_time = TimeTicks::Now(); |
867 if (is_using_platform_spelling_engine_) { | 787 if (is_using_platform_spelling_engine_) { |
868 word_correct = SpellCheckerPlatform::CheckSpelling(word_to_check, tag); | 788 word_correct = SpellCheckerPlatform::CheckSpelling(word_to_check, tag); |
869 } else { | 789 } else { |
870 std::string word_to_check_utf8(UTF16ToUTF8(word_to_check)); | 790 std::string word_to_check_utf8(UTF16ToUTF8(word_to_check)); |
(...skipping 25 matching lines...) Expand all Loading... |
896 | 816 |
897 // Populate the vector of WideStrings. | 817 // Populate the vector of WideStrings. |
898 for (int i = 0; i < number_of_suggestions; i++) { | 818 for (int i = 0; i < number_of_suggestions; i++) { |
899 if (i < kMaxSuggestions) | 819 if (i < kMaxSuggestions) |
900 optional_suggestions->push_back(UTF8ToUTF16(suggestions[i])); | 820 optional_suggestions->push_back(UTF8ToUTF16(suggestions[i])); |
901 free(suggestions[i]); | 821 free(suggestions[i]); |
902 } | 822 } |
903 if (suggestions != NULL) | 823 if (suggestions != NULL) |
904 free(suggestions); | 824 free(suggestions); |
905 } | 825 } |
OLD | NEW |