OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 <io.h> | |
6 | |
7 #include "chrome/browser/spellchecker.h" | 5 #include "chrome/browser/spellchecker.h" |
8 #include "base/basictypes.h" | 6 #include "base/basictypes.h" |
| 7 #include "base/compiler_specific.h" |
9 #include "base/file_util.h" | 8 #include "base/file_util.h" |
10 #include "base/histogram.h" | 9 #include "base/histogram.h" |
11 #include "base/logging.h" | 10 #include "base/logging.h" |
12 #include "base/path_service.h" | 11 #include "base/path_service.h" |
13 #include "base/string_util.h" | 12 #include "base/string_util.h" |
14 #include "base/thread.h" | 13 #include "base/thread.h" |
15 #include "base/win_util.h" | |
16 #include "chrome/app/locales/locale_settings.h" | 14 #include "chrome/app/locales/locale_settings.h" |
17 #include "chrome/browser/browser_process.h" | 15 #include "chrome/browser/browser_process.h" |
18 #include "chrome/browser/profile.h" | 16 #include "chrome/browser/profile.h" |
19 #include "chrome/browser/url_fetcher.h" | 17 #include "chrome/browser/url_fetcher.h" |
20 #include "chrome/common/chrome_constants.h" | 18 #include "chrome/common/chrome_constants.h" |
21 #include "chrome/common/chrome_counters.h" | 19 #include "chrome/common/chrome_counters.h" |
22 #include "chrome/common/chrome_paths.h" | 20 #include "chrome/common/chrome_paths.h" |
23 #include "chrome/common/l10n_util.h" | 21 #include "chrome/common/l10n_util.h" |
24 #include "chrome/common/pref_names.h" | 22 #include "chrome/common/pref_names.h" |
25 #include "chrome/common/pref_service.h" | 23 #include "chrome/common/pref_service.h" |
26 #include "chrome/common/render_messages.h" | |
27 #include "chrome/common/win_util.h" | |
28 #include "chrome/third_party/hunspell/src/hunspell/hunspell.hxx" | 24 #include "chrome/third_party/hunspell/src/hunspell/hunspell.hxx" |
29 #include "net/url_request/url_request.h" | 25 #include "net/url_request/url_request.h" |
30 | 26 |
31 #include "generated_resources.h" | 27 #include "generated_resources.h" |
32 | 28 |
33 using base::TimeTicks; | 29 using base::TimeTicks; |
34 | 30 |
35 static const int kMaxSuggestions = 5; // Max number of dictionary suggestions. | 31 static const int kMaxSuggestions = 5; // Max number of dictionary suggestions. |
36 | 32 |
37 namespace { | 33 namespace { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 } | 71 } |
76 | 72 |
77 void SpellChecker::SpellCheckLanguages(Languages* languages) { | 73 void SpellChecker::SpellCheckLanguages(Languages* languages) { |
78 for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages); ++i) | 74 for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages); ++i) |
79 languages->push_back(g_supported_spellchecker_languages[i]); | 75 languages->push_back(g_supported_spellchecker_languages[i]); |
80 } | 76 } |
81 | 77 |
82 SpellChecker::Language SpellChecker::GetCorrespondingSpellCheckLanguage( | 78 SpellChecker::Language SpellChecker::GetCorrespondingSpellCheckLanguage( |
83 const Language& language) { | 79 const Language& language) { |
84 // Look for exact match in the Spell Check language list. | 80 // Look for exact match in the Spell Check language list. |
85 for (int i = 0; i < arraysize(g_supported_spellchecker_languages); ++i) { | 81 for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages); ++i) { |
86 Language spellcheck_language(g_supported_spellchecker_languages[i]); | 82 Language spellcheck_language(g_supported_spellchecker_languages[i]); |
87 if (spellcheck_language == language) | 83 if (spellcheck_language == language) |
88 return language; | 84 return language; |
89 } | 85 } |
90 | 86 |
91 // Look for a match by comparing only language parts. All the 'en-RR' | 87 // Look for a match by comparing only language parts. All the 'en-RR' |
92 // except for 'en-GB' exactly matched in the above loop, will match | 88 // except for 'en-GB' exactly matched in the above loop, will match |
93 // 'en-US'. This is not ideal because 'en-AU', 'en-ZA', 'en-NZ' had | 89 // 'en-US'. This is not ideal because 'en-AU', 'en-ZA', 'en-NZ' had |
94 // better be matched with 'en-GB'. This does not handle cases like | 90 // better be matched with 'en-GB'. This does not handle cases like |
95 // 'az-Latn-AZ' vs 'az-Arab-AZ', either, but we don't use 3-part | 91 // 'az-Latn-AZ' vs 'az-Arab-AZ', either, but we don't use 3-part |
96 // locale ids with a script code in the middle, yet. | 92 // locale ids with a script code in the middle, yet. |
97 // TODO(jungshik): Add a better fallback. | 93 // TODO(jungshik): Add a better fallback. |
98 Language language_part(language, 0, language.find(L'-')); | 94 Language language_part(language, 0, language.find(L'-')); |
99 for (int i = 0; i < arraysize(g_supported_spellchecker_languages); ++i) { | 95 for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages); ++i) { |
100 Language spellcheck_language(g_supported_spellchecker_languages[i]); | 96 Language spellcheck_language(g_supported_spellchecker_languages[i]); |
101 if (spellcheck_language.substr(0, spellcheck_language.find(L'-')) == | 97 if (spellcheck_language.substr(0, spellcheck_language.find(L'-')) == |
102 language_part) | 98 language_part) |
103 return spellcheck_language; | 99 return spellcheck_language; |
104 } | 100 } |
105 | 101 |
106 // No match found - return blank. | 102 // No match found - return blank. |
107 return Language(); | 103 return Language(); |
108 } | 104 } |
109 | 105 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 // disk using file_util::WriteFile. | 201 // disk using file_util::WriteFile. |
206 class SpellChecker::DictionaryDownloadController | 202 class SpellChecker::DictionaryDownloadController |
207 : public URLFetcher::Delegate, | 203 : public URLFetcher::Delegate, |
208 public base::RefCountedThreadSafe<DictionaryDownloadController> { | 204 public base::RefCountedThreadSafe<DictionaryDownloadController> { |
209 public: | 205 public: |
210 DictionaryDownloadController( | 206 DictionaryDownloadController( |
211 Task* spellchecker_flag_set_task, | 207 Task* spellchecker_flag_set_task, |
212 const std::wstring& dic_file_path, | 208 const std::wstring& dic_file_path, |
213 URLRequestContext* url_request_context, | 209 URLRequestContext* url_request_context, |
214 MessageLoop* ui_loop) | 210 MessageLoop* ui_loop) |
215 : url_request_context_(url_request_context), | 211 : spellchecker_flag_set_task_(spellchecker_flag_set_task), |
| 212 url_request_context_(url_request_context), |
216 download_server_url_( | 213 download_server_url_( |
217 L"http://cache.pack.google.com/chrome/dict/"), | 214 L"http://cache.pack.google.com/chrome/dict/"), |
218 ui_loop_(ui_loop), | 215 ui_loop_(ui_loop) { |
219 spellchecker_flag_set_task_(spellchecker_flag_set_task) { | |
220 // Determine dictionary file path and name. | 216 // Determine dictionary file path and name. |
221 fetcher_.reset(NULL); | 217 fetcher_.reset(NULL); |
222 dic_zip_file_path_ = file_util::GetDirectoryFromPath(dic_file_path); | 218 dic_zip_file_path_ = file_util::GetDirectoryFromPath(dic_file_path); |
223 file_name_ = file_util::GetFilenameFromPath(dic_file_path); | 219 file_name_ = file_util::GetFilenameFromPath(dic_file_path); |
224 | 220 |
225 name_of_file_to_download_ = l10n_util::ToLower(file_name_); | 221 name_of_file_to_download_ = l10n_util::ToLower(file_name_); |
226 } | 222 } |
227 | 223 |
228 // Save the file in memory buffer to the designated dictionary file. | 224 // Save the file in memory buffer to the designated dictionary file. |
229 // returns the number of bytes it could save. | 225 // returns the number of bytes it could save. |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 } | 295 } |
300 | 296 |
301 // ################################################################ | 297 // ################################################################ |
302 // This part of the code is used for spell checking. | 298 // This part of the code is used for spell checking. |
303 // ################################################################ | 299 // ################################################################ |
304 | 300 |
305 std::wstring SpellChecker::GetVersionedFileName(const Language& language, | 301 std::wstring SpellChecker::GetVersionedFileName(const Language& language, |
306 const std::wstring& dict_dir) { | 302 const std::wstring& dict_dir) { |
307 // The default version string currently in use. | 303 // The default version string currently in use. |
308 static const wchar_t kDefaultVersionString[] = L"-1-1"; | 304 static const wchar_t kDefaultVersionString[] = L"-1-1"; |
309 | 305 |
310 // Use this struct to insert version strings for dictionary files which have | 306 // Use this struct to insert version strings for dictionary files which have |
311 // special version strings, other than the default version string. | 307 // special version strings, other than the default version string. |
312 // For de-DE, we are currently using de-DE-1-1-1 for versioning, because | 308 // For de-DE, we are currently using de-DE-1-1-1 for versioning, because |
313 // de-DE-1-1.bdic, in the download server, corresponds to a less used | 309 // de-DE-1-1.bdic, in the download server, corresponds to a less used |
314 // dictionary. This version, i.e., de-DE-1-1-1.bdic, is actually renamed | 310 // dictionary. This version, i.e., de-DE-1-1-1.bdic, is actually renamed |
315 // from de-DE-neu-1-1.bic. | 311 // from de-DE-neu-1-1.bic. |
316 static const struct { | 312 static const struct { |
317 // The language input. | 313 // The language input. |
318 const char* language; | 314 const char* language; |
319 | 315 |
320 // The corresponding version. | 316 // The corresponding version. |
321 const char* version; | 317 const char* version; |
322 } special_version_string[] = { | 318 } special_version_string[] = { |
323 "de-DE", "-1-1-1", | 319 {"de-DE", "-1-1-1"}, |
324 }; | 320 }; |
325 | 321 |
326 // Generate the bdict file name using default version string or special | 322 // Generate the bdict file name using default version string or special |
327 // version string, depending on the language. | 323 // version string, depending on the language. |
328 std::wstring versioned_bdict_file_name(language + kDefaultVersionString + | 324 std::wstring versioned_bdict_file_name(language + kDefaultVersionString + |
329 L".bdic"); | 325 L".bdic"); |
330 std::string language_string(WideToUTF8(language)); | 326 std::string language_string(WideToUTF8(language)); |
331 for (int i = 0; i < arraysize(special_version_string); ++i) { | 327 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(special_version_string); ++i) { |
332 if (language_string == special_version_string[i].language) { | 328 if (language_string == special_version_string[i].language) { |
333 versioned_bdict_file_name = | 329 versioned_bdict_file_name = |
334 language + UTF8ToWide(special_version_string[i].version) + L".bdic"; | 330 language + UTF8ToWide(special_version_string[i].version) + L".bdic"; |
335 break; | 331 break; |
336 } | 332 } |
337 } | 333 } |
338 | 334 |
339 std::wstring bdict_file_name(dict_dir); | 335 std::wstring bdict_file_name(dict_dir); |
340 file_util::AppendToPath(&bdict_file_name, versioned_bdict_file_name); | 336 file_util::AppendToPath(&bdict_file_name, versioned_bdict_file_name); |
341 return bdict_file_name; | 337 return bdict_file_name; |
342 } | 338 } |
343 | 339 |
344 SpellChecker::SpellChecker(const std::wstring& dict_dir, | 340 SpellChecker::SpellChecker(const std::wstring& dict_dir, |
345 const std::wstring& language, | 341 const std::wstring& language, |
346 URLRequestContext* request_context, | 342 URLRequestContext* request_context, |
347 const std::wstring& custom_dictionary_file_name) | 343 const std::wstring& custom_dictionary_file_name) |
348 : custom_dictionary_file_name_(custom_dictionary_file_name), | 344 : custom_dictionary_file_name_(custom_dictionary_file_name), |
349 tried_to_init_(false), | 345 tried_to_init_(false), |
350 #ifndef NDEBUG | 346 #ifndef NDEBUG |
351 worker_loop_(NULL), | 347 worker_loop_(NULL), |
352 #endif | 348 #endif |
353 tried_to_download_(false), | 349 tried_to_download_(false), |
| 350 file_loop_(NULL), |
354 url_request_context_(request_context), | 351 url_request_context_(request_context), |
355 file_loop_(NULL), | 352 dic_is_downloading_(false), |
356 #pragma warning(suppress: 4355) // Okay to pass "this" here. | 353 ALLOW_THIS_IN_INTIALIZER_LIST(dic_download_state_changer_factory_(this)) { |
357 dic_download_state_changer_factory_(this), | |
358 dic_is_downloading_(false) { | |
359 // Remember UI loop to later use this as a proxy to get IO loop. | 354 // Remember UI loop to later use this as a proxy to get IO loop. |
360 ui_loop_ = MessageLoop::current(); | 355 ui_loop_ = MessageLoop::current(); |
361 | 356 |
362 // Get File Loop - hunspell gets initialized here. | 357 // Get File Loop - hunspell gets initialized here. |
363 base::Thread* file_thread = g_browser_process->file_thread(); | 358 base::Thread* file_thread = g_browser_process->file_thread(); |
364 if (file_thread) | 359 if (file_thread) |
365 file_loop_ = file_thread->message_loop(); | 360 file_loop_ = file_thread->message_loop(); |
366 | 361 |
367 // Get the path to the spellcheck file. | 362 // Get the path to the spellcheck file. |
368 bdict_file_name_ = GetVersionedFileName(language, dict_dir); | 363 bdict_file_name_ = GetVersionedFileName(language, dict_dir); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 it != list_of_words.end(); ++it) { | 448 it != list_of_words.end(); ++it) { |
454 hunspell_->put_word(it->c_str()); | 449 hunspell_->put_word(it->c_str()); |
455 } | 450 } |
456 } | 451 } |
457 } | 452 } |
458 | 453 |
459 // Returns whether or not the given string is a valid contraction. | 454 // Returns whether or not the given string is a valid contraction. |
460 // This function is a fall-back when the SpellcheckWordIterator class | 455 // This function is a fall-back when the SpellcheckWordIterator class |
461 // returns a concatenated word which is not in the selected dictionary | 456 // returns a concatenated word which is not in the selected dictionary |
462 // (e.g. "in'n'out") but each word is valid. | 457 // (e.g. "in'n'out") but each word is valid. |
463 bool SpellChecker::IsValidContraction(const std::wstring& contraction) { | 458 bool SpellChecker::IsValidContraction(const string16& contraction) { |
464 SpellcheckWordIterator word_iterator; | 459 SpellcheckWordIterator word_iterator; |
465 word_iterator.Initialize(&character_attributes_, contraction.c_str(), | 460 word_iterator.Initialize(&character_attributes_, contraction.c_str(), |
466 contraction.length(), false); | 461 contraction.length(), false); |
467 | 462 |
468 std::wstring word; | 463 string16 word; |
469 int word_start; | 464 int word_start; |
470 int word_length; | 465 int word_length; |
471 while (word_iterator.GetNextWord(&word, &word_start, &word_length)) { | 466 while (word_iterator.GetNextWord(&word, &word_start, &word_length)) { |
472 if (!hunspell_->spell(WideToUTF8(word).c_str())) | 467 if (!hunspell_->spell(UTF16ToUTF8(word).c_str())) |
473 return false; | 468 return false; |
474 } | 469 } |
475 return true; | 470 return true; |
476 } | 471 } |
477 | 472 |
478 bool SpellChecker::SpellCheckWord( | 473 bool SpellChecker::SpellCheckWord( |
479 const wchar_t* in_word, | 474 const wchar_t* in_word, |
480 int in_word_len, | 475 int in_word_len, |
481 int* misspelling_start, | 476 int* misspelling_start, |
482 int* misspelling_len, | 477 int* misspelling_len, |
(...skipping 15 matching lines...) Expand all Loading... |
498 | 493 |
499 *misspelling_start = 0; | 494 *misspelling_start = 0; |
500 *misspelling_len = 0; | 495 *misspelling_len = 0; |
501 if (in_word_len == 0) | 496 if (in_word_len == 0) |
502 return true; // no input means always spelled correctly | 497 return true; // no input means always spelled correctly |
503 | 498 |
504 if (!hunspell_.get()) | 499 if (!hunspell_.get()) |
505 return true; // unable to spellcheck, return word is OK | 500 return true; // unable to spellcheck, return word is OK |
506 | 501 |
507 SpellcheckWordIterator word_iterator; | 502 SpellcheckWordIterator word_iterator; |
508 std::wstring word; | 503 string16 word; |
| 504 string16 in_word_utf16; |
| 505 WideToUTF16(in_word, in_word_len, &in_word_utf16); |
509 int word_start; | 506 int word_start; |
510 int word_length; | 507 int word_length; |
511 word_iterator.Initialize(&character_attributes_, in_word, in_word_len, true); | 508 word_iterator.Initialize(&character_attributes_, in_word_utf16.c_str(), |
| 509 in_word_len, true); |
512 while (word_iterator.GetNextWord(&word, &word_start, &word_length)) { | 510 while (word_iterator.GetNextWord(&word, &word_start, &word_length)) { |
513 // Found a word (or a contraction) that hunspell can check its spelling. | 511 // Found a word (or a contraction) that hunspell can check its spelling. |
514 std::string encoded_word = WideToUTF8(word); | 512 std::string encoded_word = UTF16ToUTF8(word); |
515 | 513 |
516 { | 514 { |
517 TimeTicks begin_time = TimeTicks::Now(); | 515 TimeTicks begin_time = TimeTicks::Now(); |
518 bool word_ok = !!hunspell_->spell(encoded_word.c_str()); | 516 bool word_ok = !!hunspell_->spell(encoded_word.c_str()); |
519 DHISTOGRAM_TIMES(L"Spellcheck.CheckTime", TimeTicks::Now() - begin_time); | 517 DHISTOGRAM_TIMES(L"Spellcheck.CheckTime", TimeTicks::Now() - begin_time); |
520 if (word_ok) | 518 if (word_ok) |
521 continue; | 519 continue; |
522 } | 520 } |
523 | 521 |
524 // If the given word is a concatenated word of two or more valid words | 522 // If the given word is a concatenated word of two or more valid words |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
589 hunspell_->put_word(word_to_add.c_str()); | 587 hunspell_->put_word(word_to_add.c_str()); |
590 | 588 |
591 // Now add the word to the custom dictionary file. | 589 // Now add the word to the custom dictionary file. |
592 Task* write_word_task = | 590 Task* write_word_task = |
593 new AddWordToCustomDictionaryTask(custom_dictionary_file_name_, word); | 591 new AddWordToCustomDictionaryTask(custom_dictionary_file_name_, word); |
594 if (file_loop_) | 592 if (file_loop_) |
595 file_loop_->PostTask(FROM_HERE, write_word_task); | 593 file_loop_->PostTask(FROM_HERE, write_word_task); |
596 else | 594 else |
597 write_word_task->Run(); | 595 write_word_task->Run(); |
598 } | 596 } |
OLD | NEW |