Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1281)

Unified Diff: chrome/browser/spellchecker.cc

Issue 164511: Merge 23048 - Fix a spell check dictionary download bug, where killing the sp... (Closed) Base URL: svn://chrome-svn/chrome/branches/195/src/
Patch Set: Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/spellchecker.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/spellchecker.cc
===================================================================
--- chrome/browser/spellchecker.cc (revision 23354)
+++ chrome/browser/spellchecker.cc (working copy)
@@ -86,8 +86,15 @@
return dict_dir_userdata;
}
+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;
}
+}
+
void SpellChecker::SpellCheckLanguages(std::vector<std::string>* languages) {
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages);
++i)
@@ -204,162 +211,6 @@
return -1;
}
-// This is a helper class which acts as a proxy for invoking a task from the
-// file loop back to the IO loop. Invoking a task from file loop to the IO
-// loop directly is not safe as during browser shutdown, the IO loop tears
-// down before the file loop. To avoid a crash, this object is invoked in the
-// UI loop from the file loop, from where it gets the IO thread directly from
-// g_browser_process and invokes the given task in the IO loop if it is not
-// NULL. This object also takes ownership of the given task.
-class UIProxyForIOTask : public Task {
- public:
- explicit UIProxyForIOTask(Task* spellchecker_flag_set_task)
- : spellchecker_flag_set_task_(spellchecker_flag_set_task) {
- }
-
- private:
- void Run() {
- // This has been invoked in the UI thread.
- base::Thread* io_thread = g_browser_process->io_thread();
- if (io_thread) { // io_thread has not been torn down yet.
- MessageLoop* io_loop = io_thread->message_loop();
- if (io_loop) {
- io_loop->PostTask(FROM_HERE, spellchecker_flag_set_task_);
- spellchecker_flag_set_task_ = NULL;
- }
- }
- }
-
- Task* spellchecker_flag_set_task_;
- DISALLOW_COPY_AND_ASSIGN(UIProxyForIOTask);
-};
-
-// ############################################################################
-// This part of the spellchecker code is used for downloading spellchecking
-// dictionary if required. This code is included in this file since dictionary
-// is an integral part of spellchecker.
-
-// Design: The spellchecker initializes hunspell_ in the Initialize() method.
-// This is done using the dictionary file on disk, for example, "en-US.bdic".
-// If this file is missing, a |DictionaryDownloadController| object is used to
-// download the missing files asynchronously (using URLFetcher) in the file
-// thread. Initialization of hunspell_ is held off during this process. After
-// the dictionary downloads (or fails to download), corresponding flags are set
-// in spellchecker - in the IO thread. Since IO thread goes first during closing
-// of browser, a proxy task |UIProxyForIOTask| is created in the UI thread,
-// which obtains the IO thread independently and invokes the task in the IO
-// thread if it's not NULL. After the flags are cleared, a (final) attempt is
-// made to initialize hunspell_. If it fails even then (dictionary could not
-// download), no more attempts are made to initialize it.
-
-// ############################################################################
-
-// 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> {
- public:
- DictionaryDownloadController(
- Task* spellchecker_flag_set_task,
- const FilePath& dic_file_path,
- URLRequestContext* url_request_context,
- MessageLoop* ui_loop)
- : spellchecker_flag_set_task_(spellchecker_flag_set_task),
- url_request_context_(url_request_context),
- ui_loop_(ui_loop) {
- // Determine dictionary file path and name.
- dic_zip_file_path_ = dic_file_path.DirName();
- file_name_ = dic_file_path.BaseName();
- }
-
- // Save the file in memory buffer to the designated dictionary file.
- // returns the number of bytes it could save.
- // Invoke this on the file thread.
- void StartDownload() {
- static const char kDownloadServerUrl[] =
- "http://cache.pack.google.com/edgedl/chrome/dict/";
-
- GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8(
- l10n_util::ToLower(file_name_.ToWStringHack())));
- fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this));
- fetcher_->set_request_context(url_request_context_);
- fetcher_->Start();
- }
-
- 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) {
- int num_bytes = data.length();
- return file_util::WriteFile(file_to_write, data.data(), num_bytes) ==
- num_bytes;
- }
-
- // URLFetcher::Delegate interface.
- virtual void OnURLFetchComplete(const URLFetcher* source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data) {
- DCHECK(source);
- if ((response_code / 100) == 2 ||
- response_code == 401 ||
- response_code == 407) {
- 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.
- ui_loop_->PostTask(FROM_HERE,
- new UIProxyForIOTask(spellchecker_flag_set_task_));
- fetcher_.reset(NULL);
- }
-
- // factory object to invokelater back to spellchecker in io thread on
- // download completion to change appropriate flags.
- Task* spellchecker_flag_set_task_;
-
- // URLRequestContext to be used by URLFetcher. This is obtained from profile.
- // The ownership remains with the profile.
- URLRequestContext* url_request_context_;
-
- // URLFetcher to fetch the file in memory.
- scoped_ptr<URLFetcher> fetcher_;
-
- // The file path where both the dic files have to be written locally.
- FilePath dic_zip_file_path_;
-
- // The name of the file which has to be stored locally.
- FilePath file_name_;
-
- // this invokes back to io loop when downloading is over.
- MessageLoop* ui_loop_;
- DISALLOW_COPY_AND_ASSIGN(DictionaryDownloadController);
-};
-
-void SpellChecker::set_file_is_downloading(bool value) {
- dic_is_downloading_ = value;
-}
-
-// ################################################################
-// This part of the code is used for spell checking.
-// ################################################################
-
FilePath SpellChecker::GetVersionedFileName(const std::string& input_language,
const FilePath& dict_dir) {
// The default dictionary version is 1-2. These versions have been augmented
@@ -425,8 +276,7 @@
dic_is_downloading_(false),
auto_spell_correct_turned_on_(false),
is_using_platform_spelling_engine_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- dic_download_state_changer_factory_(this)) {
+ fetcher_(NULL) {
if (SpellCheckerPlatform::SpellCheckerAvailable()) {
SpellCheckerPlatform::Init();
if (SpellCheckerPlatform::PlatformSupportsLanguage(language)) {
@@ -437,8 +287,8 @@
}
}
- // Remember UI loop to later use this as a proxy to get IO loop.
- ui_loop_ = MessageLoop::current();
+ // Get the corresponding BDIC file name.
+ bdic_file_name_ = GetVersionedFileName(language, dict_dir).BaseName();
// Get File Loop - hunspell gets initialized here.
base::Thread* file_thread = g_browser_process->file_thread();
@@ -468,18 +318,48 @@
#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));
+void SpellChecker::StartDictionaryDownload(const FilePath& file_name) {
+ // Determine URL of file to download.
+ static const char kDownloadServerUrl[] =
+ "http://cache.pack.google.com/edgedl/chrome/dict/";
+ GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8(
+ l10n_util::ToLower(bdic_file_name_.ToWStringHack())));
+ fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this));
+ fetcher_->set_request_context(url_request_context_);
+ dic_is_downloading_ = true;
+ fetcher_->Start();
}
-// Initialize SpellChecker. In this method, if the dicitonary is not present
+void SpellChecker::OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ DCHECK(source);
+ if ((response_code / 100) == 2 ||
+ response_code == 401 ||
+ response_code == 407) {
+ FilePath file_to_write = given_dictionary_directory_.Append(
+ bdic_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(bdic_file_name_);
+ SaveBufferToFile(data, file_to_write);
+ }
+ } // Unsuccessful save is taken care of in SpellChecker::Initialize().
+
+ dic_is_downloading_ = false;
+}
+
+// Initialize SpellChecker. In this method, if the dictionary is not present
// in the local disk, it is fetched asynchronously.
// TODO(sidchat): After dictionary is downloaded, initialize hunspell in
// file loop - this is currently being done in the io loop.
@@ -526,7 +406,7 @@
// Download the dictionary file.
if (file_loop_ && url_request_context_) {
if (!tried_to_download_dictionary_file_) {
- StartDictionaryDownloadInFileThread(dictionary_file_name_app);
+ StartDictionaryDownload(dictionary_file_name_app);
tried_to_download_dictionary_file_ = true;
return false;
} else { // There is no dictionary even after trying to download it.
Property changes on: chrome\browser\spellchecker.cc
___________________________________________________________________
Added: svn:mergeinfo
Merged /trunk/src/chrome/browser/spellchecker.cc:r23048
Merged /branches/chrome_webkit_merge_branch/chrome/browser/spellchecker.cc:r69-2775
« no previous file with comments | « chrome/browser/spellchecker.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698