diff options
author | sidchat@google.com <sidchat@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-17 20:49:11 +0000 |
---|---|---|
committer | sidchat@google.com <sidchat@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-17 20:49:11 +0000 |
commit | f714394a299cc645b5d7777722b66b398a2fea8e (patch) | |
tree | 89b589f8476cf0c63fcf85f8d2cda17034fb2eb1 /chrome | |
parent | b1a544ba592980b698790b99e9faa3f1399d0b86 (diff) | |
download | chromium_src-f714394a299cc645b5d7777722b66b398a2fea8e.zip chromium_src-f714394a299cc645b5d7777722b66b398a2fea8e.tar.gz chromium_src-f714394a299cc645b5d7777722b66b398a2fea8e.tar.bz2 |
For system-level installs, if the spellcheck dictionary fails to get downloaded in the profile Application directory, download it in the User Data directory instead.
BUG=http://www.crbug.com/9650
TEST=Launch Chrome, and navigate to translate.google.com. Before typing anything in the text box, change name of folder Chrome/Application/Dictionaries to something else. Then, start typing something. The spellcheck dictionary, unable to get the folder Dictionaries, will fail to download, which will trigger its download in Chrome/User Data/Dictionaries. After it has downloaded, spellchecker will start working automatically.
Review URL: http://codereview.chromium.org/155394
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20995 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/spellchecker.cc | 107 | ||||
-rw-r--r-- | chrome/browser/spellchecker.h | 19 |
2 files changed, 95 insertions, 31 deletions
diff --git a/chrome/browser/spellchecker.cc b/chrome/browser/spellchecker.cc index cbc0f7a..f3bb9d3 100644 --- a/chrome/browser/spellchecker.cc +++ b/chrome/browser/spellchecker.cc @@ -77,6 +77,15 @@ static const struct { {"tr", "tr-TR"}, }; +// Get the fallback folder (currently chrome::DIR_USER_DATA) where the +// dictionary is downloaded in case of system-wide installations. +FilePath GetFallbackDictionaryDownloadDirectory() { + FilePath dict_dir_userdata; + PathService::Get(chrome::DIR_USER_DATA, &dict_dir_userdata); + dict_dir_userdata = dict_dir_userdata.AppendASCII("Dictionaries"); + return dict_dir_userdata; +} + } void SpellChecker::SpellCheckLanguages(std::vector<std::string>* languages) { @@ -248,6 +257,7 @@ class UIProxyForIOTask : public Task { // This object downloads the dictionary files asynchronously by first // fetching it to memory using URL fetcher and then writing it to // disk using file_util::WriteFile. + class SpellChecker::DictionaryDownloadController : public URLFetcher::Delegate, public base::RefCountedThreadSafe<DictionaryDownloadController> { @@ -281,8 +291,8 @@ class SpellChecker::DictionaryDownloadController private: // The file has been downloaded in memory - need to write it down to file. - bool SaveBufferToFile(const std::string& data) { - FilePath file_to_write = dic_zip_file_path_.Append(file_name_); + bool SaveBufferToFile(const std::string& data, + FilePath file_to_write) { int num_bytes = data.length(); return file_util::WriteFile(file_to_write, data.data(), num_bytes) == num_bytes; @@ -296,11 +306,22 @@ class SpellChecker::DictionaryDownloadController const ResponseCookies& cookies, const std::string& data) { DCHECK(source); - bool save_success = false; if ((response_code / 100) == 2 || response_code == 401 || response_code == 407) { - save_success = SaveBufferToFile(data); + FilePath file_to_write = dic_zip_file_path_.Append(file_name_); + if (!SaveBufferToFile(data, file_to_write)) { + // Try saving it to user data/Dictionaries, which almost surely has + // write permission. If even this fails, there is nothing to be done. + FilePath user_data_dir = GetFallbackDictionaryDownloadDirectory(); + + // Create the directory if it does not exist. + if (!file_util::PathExists(user_data_dir)) + file_util::CreateDirectory(user_data_dir); + + file_to_write = user_data_dir.Append(file_name_); + SaveBufferToFile(data, file_to_write); + } } // Unsuccessful save is taken care of in SpellChecker::Initialize(). // Set Flag that dictionary is not downloading anymore. @@ -391,12 +412,14 @@ SpellChecker::SpellChecker(const FilePath& dict_dir, const std::string& language, URLRequestContext* request_context, const FilePath& custom_dictionary_file_name) - : custom_dictionary_file_name_(custom_dictionary_file_name), + : given_dictionary_directory_(dict_dir), + custom_dictionary_file_name_(custom_dictionary_file_name), tried_to_init_(false), + language_(language), #ifndef NDEBUG worker_loop_(NULL), #endif - tried_to_download_(false), + tried_to_download_dictionary_file_(false), file_loop_(NULL), url_request_context_(request_context), dic_is_downloading_(false), @@ -422,9 +445,6 @@ SpellChecker::SpellChecker(const FilePath& dict_dir, if (file_thread) file_loop_ = file_thread->message_loop(); - // Get the path to the spellcheck file. - bdict_file_name_ = GetVersionedFileName(language, dict_dir); - // Get the path to the custom dictionary file. if (custom_dictionary_file_name_.empty()) { FilePath personal_file_directory; @@ -448,6 +468,17 @@ SpellChecker::~SpellChecker() { #endif } +void SpellChecker::StartDictionaryDownloadInFileThread( + const FilePath& file_name) { + Task* dic_task = dic_download_state_changer_factory_.NewRunnableMethod( + &SpellChecker::set_file_is_downloading, false); + ddc_dic_ = new DictionaryDownloadController(dic_task, file_name, + url_request_context_, ui_loop_); + set_file_is_downloading(true); + file_loop_->PostTask(FROM_HERE, NewRunnableMethod(ddc_dic_.get(), + &DictionaryDownloadController::StartDownload)); +} + // Initialize SpellChecker. In this method, if the dicitonary is not present // in the local disk, it is fetched asynchronously. // TODO(sidchat): After dictionary is downloaded, initialize hunspell in @@ -465,28 +496,52 @@ bool SpellChecker::Initialize() { StatsScope<StatsCounterTimer> timer(chrome::Counters::spellcheck_init()); - bool dic_exists = file_util::PathExists(bdict_file_name_); - if (!dic_exists) { - if (file_loop_ && !tried_to_download_ && url_request_context_) { - Task* dic_task = dic_download_state_changer_factory_.NewRunnableMethod( - &SpellChecker::set_file_is_downloading, false); - ddc_dic_ = new DictionaryDownloadController(dic_task, bdict_file_name_, - url_request_context_, ui_loop_); - set_file_is_downloading(true); - file_loop_->PostTask(FROM_HERE, NewRunnableMethod(ddc_dic_.get(), - &DictionaryDownloadController::StartDownload)); + // The default place whether the spellcheck dictionary can reside is + // chrome::DIR_APP_DICTIONARIES. However, for systemwide installations, + // this directory may not have permissions for download. In that case, the + // alternate directory for download is chrome::DIR_USER_DATA. We have to check + // for the spellcheck dictionaries in both the directories. If not found in + // either one, it has to be downloaded in either of the two. + // TODO(sidchat): Some sort of UI to warn users that spellchecker is not + // working at all (due to failed dictionary download)? + + // File name for downloading in DIR_APP_DICTIONARIES. + FilePath dictionary_file_name_app = GetVersionedFileName(language_, + given_dictionary_directory_); + + // Filename for downloading in the fallback dictionary download directory, + // DIR_USER_DATA. + FilePath dict_dir_userdata = GetFallbackDictionaryDownloadDirectory(); + FilePath dictionary_file_name_usr = GetVersionedFileName(language_, + dict_dir_userdata); + + // Check in both the directories to see whether the spellcheck dictionary + // already resides in one of these. + FilePath bdic_file_name; + if (file_util::PathExists(dictionary_file_name_app)) { + bdic_file_name = dictionary_file_name_app; + } else if (file_util::PathExists(dictionary_file_name_usr)) { + bdic_file_name = dictionary_file_name_usr; + } else { + // Download the dictionary file. + if (file_loop_ && url_request_context_) { + if (!tried_to_download_dictionary_file_) { + StartDictionaryDownloadInFileThread(dictionary_file_name_app); + tried_to_download_dictionary_file_ = true; + return false; + } else { // There is no dictionary even after trying to download it. + // Stop trying to download the dictionary in this session. + tried_to_init_ = true; + return false; + } } } - if (!dic_exists && !tried_to_download_) { - tried_to_download_ = true; - return false; - } - - // Control has come so far - both files probably exist. + // Control has come so far - the BDIC dictionary file probably exists. Now try + // to initialize hunspell using the available bdic dictionary file. TimeTicks begin_time = TimeTicks::Now(); bdict_file_.reset(new file_util::MemoryMappedFile()); - if (bdict_file_->Initialize(bdict_file_name_)) { + if (bdict_file_->Initialize(bdic_file_name)) { hunspell_.reset(new Hunspell(bdict_file_->data(), bdict_file_->length())); AddCustomWordsToHunspell(); } diff --git a/chrome/browser/spellchecker.h b/chrome/browser/spellchecker.h index cfb7979..fd1e182 100644 --- a/chrome/browser/spellchecker.h +++ b/chrome/browser/spellchecker.h @@ -147,8 +147,15 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker> { static std::string GetCorrespondingSpellCheckLanguage( const std::string& language); - // Path to the spellchecker file. - FilePath bdict_file_name_; + // Start the dictionary download process in the file thread. On completion, + // this function calls on set_file_is_downloading() in the IO thread to notify + // that download has completed. This function has to be called in the IO + // thread. + void StartDictionaryDownloadInFileThread(const FilePath& file_name); + + // The given path to the directory whether SpellChecker first tries to + // download the spellcheck bdic dictionary file. + FilePath given_dictionary_directory_; // Path to the custom dictionary file. FilePath custom_dictionary_file_name_; @@ -167,6 +174,9 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker> { // attempted initialiation, we won't retry to avoid failure loops. bool tried_to_init_; + // The language that this spellchecker works in. + std::string language_; + #ifndef NDEBUG // This object must only be used on the same thread. However, it is normally // created on the UI thread. This checks calls to SpellCheckWord and the @@ -177,9 +187,8 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker> { MessageLoop* worker_loop_; #endif - // Flag indicating whether we've tried to download dictionary files. If we've - // already attempted download, we won't retry to avoid failure loops. - bool tried_to_download_; + // Flag indicating whether we tried to download the dictionary file. + bool tried_to_download_dictionary_file_; // File Thread Message Loop. MessageLoop* file_loop_; |