| 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 |