| OLD | NEW | 
|    1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |    1 // Copyright (c) 2011 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/spellcheck_host_impl.h" |    5 #include "chrome/browser/spellchecker/spellcheck_host_impl.h" | 
|    6  |    6  | 
|    7 #include <set> |    7 #include <set> | 
|    8  |    8  | 
 |    9 #include "base/bind.h" | 
|    9 #include "base/file_util.h" |   10 #include "base/file_util.h" | 
|   10 #include "base/logging.h" |   11 #include "base/logging.h" | 
|   11 #include "base/path_service.h" |   12 #include "base/path_service.h" | 
|   12 #include "base/string_split.h" |   13 #include "base/string_split.h" | 
|   13 #include "base/threading/thread_restrictions.h" |   14 #include "base/threading/thread_restrictions.h" | 
|   14 #include "base/utf_string_conversions.h" |   15 #include "base/utf_string_conversions.h" | 
|   15 #include "chrome/browser/prefs/pref_service.h" |   16 #include "chrome/browser/prefs/pref_service.h" | 
|   16 #include "chrome/browser/profiles/profile.h" |   17 #include "chrome/browser/profiles/profile.h" | 
|   17 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h" |   18 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h" | 
|   18 #include "chrome/browser/spellchecker/spellcheck_profile_provider.h" |   19 #include "chrome/browser/spellchecker/spellcheck_profile_provider.h" | 
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   73 #endif |   74 #endif | 
|   74  |   75  | 
|   75 #if defined(OS_WIN) |   76 #if defined(OS_WIN) | 
|   76 FilePath GetFallbackFilePath(const FilePath& first_choice) { |   77 FilePath GetFallbackFilePath(const FilePath& first_choice) { | 
|   77   FilePath dict_dir; |   78   FilePath dict_dir; | 
|   78   PathService::Get(chrome::DIR_USER_DATA, &dict_dir); |   79   PathService::Get(chrome::DIR_USER_DATA, &dict_dir); | 
|   79   return dict_dir.Append(first_choice.BaseName()); |   80   return dict_dir.Append(first_choice.BaseName()); | 
|   80 } |   81 } | 
|   81 #endif |   82 #endif | 
|   82  |   83  | 
 |   84 void CloseDictionary(base::PlatformFile file) { | 
 |   85   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 
 |   86   base::ClosePlatformFile(file); | 
 |   87 } | 
 |   88  | 
|   83 }  // namespace |   89 }  // namespace | 
|   84  |   90  | 
|   85 // Constructed on UI thread. |   91 // Constructed on UI thread. | 
|   86 SpellCheckHostImpl::SpellCheckHostImpl( |   92 SpellCheckHostImpl::SpellCheckHostImpl( | 
|   87     SpellCheckProfileProvider* profile, |   93     SpellCheckProfileProvider* profile, | 
|   88     const std::string& language, |   94     const std::string& language, | 
|   89     net::URLRequestContextGetter* request_context_getter, |   95     net::URLRequestContextGetter* request_context_getter, | 
|   90     SpellCheckHostMetrics* metrics) |   96     SpellCheckHostMetrics* metrics) | 
|   91     : profile_(profile), |   97     : profile_(profile), | 
 |   98       dictionary_saved_(false), | 
|   92       language_(language), |   99       language_(language), | 
|   93       file_(base::kInvalidPlatformFileValue), |  100       file_(base::kInvalidPlatformFileValue), | 
|   94       tried_to_download_(false), |  101       tried_to_download_(false), | 
|   95       use_platform_spellchecker_(false), |  102       use_platform_spellchecker_(false), | 
|   96       request_context_getter_(request_context_getter), |  103       request_context_getter_(request_context_getter), | 
|   97       metrics_(metrics) { |  104       metrics_(metrics), | 
 |  105       weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 
|   98   DCHECK(profile_); |  106   DCHECK(profile_); | 
|   99   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |  107   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
|  100  |  108  | 
|  101   FilePath personal_file_directory; |  109   FilePath personal_file_directory; | 
|  102   PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); |  110   PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); | 
|  103   custom_dictionary_file_ = |  111   custom_dictionary_file_ = | 
|  104       personal_file_directory.Append(chrome::kCustomDictionaryFileName); |  112       personal_file_directory.Append(chrome::kCustomDictionaryFileName); | 
|  105  |  113  | 
|  106   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, |  114   registrar_.Add(weak_ptr_factory_.GetWeakPtr(), | 
 |  115                  content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 
|  107                  content::NotificationService::AllSources()); |  116                  content::NotificationService::AllSources()); | 
|  108 } |  117 } | 
|  109  |  118  | 
|  110 SpellCheckHostImpl::~SpellCheckHostImpl() { |  119 SpellCheckHostImpl::~SpellCheckHostImpl() { | 
|  111   if (file_ != base::kInvalidPlatformFileValue) |  120   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
|  112     base::ClosePlatformFile(file_); |  121  | 
 |  122   if (file_ != base::kInvalidPlatformFileValue) { | 
 |  123     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 
 |  124                             base::Bind(&CloseDictionary, file_)); | 
 |  125     file_ = base::kInvalidPlatformFileValue; | 
 |  126   } | 
|  113 } |  127 } | 
|  114  |  128  | 
|  115 void SpellCheckHostImpl::Initialize() { |  129 void SpellCheckHostImpl::Initialize() { | 
 |  130   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
 |  131  | 
|  116   if (SpellCheckerPlatform::SpellCheckerAvailable() && |  132   if (SpellCheckerPlatform::SpellCheckerAvailable() && | 
|  117       SpellCheckerPlatform::PlatformSupportsLanguage(language_)) { |  133       SpellCheckerPlatform::PlatformSupportsLanguage(language_)) { | 
|  118 #if defined(OS_MACOSX) |  134 #if defined(OS_MACOSX) | 
|  119     RecordSpellCheckStats(true, language_); |  135     RecordSpellCheckStats(true, language_); | 
|  120 #endif |  136 #endif | 
|  121     use_platform_spellchecker_ = true; |  137     use_platform_spellchecker_ = true; | 
|  122     SpellCheckerPlatform::SetLanguage(language_); |  138     SpellCheckerPlatform::SetLanguage(language_); | 
|  123     MessageLoop::current()->PostTask(FROM_HERE, |  139     MessageLoop::current()->PostTask(FROM_HERE, | 
|  124         NewRunnableMethod(this, |  140         base::Bind(&SpellCheckHostImpl::InformProfileOfInitialization, | 
|  125             &SpellCheckHostImpl::InformProfileOfInitialization)); |  141                    weak_ptr_factory_.GetWeakPtr())); | 
|  126     return; |  142     return; | 
|  127   } |  143   } | 
|  128  |  144  | 
|  129 #if defined(OS_MACOSX) |  145 #if defined(OS_MACOSX) | 
|  130   RecordSpellCheckStats(false, language_); |  146   RecordSpellCheckStats(false, language_); | 
|  131 #endif |  147 #endif | 
|  132  |  148  | 
|  133   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |  149   BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, | 
|  134       NewRunnableMethod(this, |  150       base::Bind(&SpellCheckHostImpl::InitializeDictionaryLocation, | 
|  135                         &SpellCheckHostImpl::InitializeDictionaryLocation)); |  151                  base::Unretained(this)), | 
 |  152       base::Bind(&SpellCheckHostImpl::InitializeDictionaryLocationComplete, | 
 |  153                  weak_ptr_factory_.GetWeakPtr())); | 
|  136 } |  154 } | 
|  137  |  155  | 
|  138 void SpellCheckHostImpl::UnsetProfile() { |  156 void SpellCheckHostImpl::UnsetProfile() { | 
|  139   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |  157   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
|  140  |  158  | 
|  141   profile_ = NULL; |  159   profile_ = NULL; | 
|  142   request_context_getter_ = NULL; |  160   request_context_getter_ = NULL; | 
|  143   fetcher_.reset(); |  161   fetcher_.reset(); | 
|  144   registrar_.RemoveAll(); |  162   registrar_.RemoveAll(); | 
|  145 } |  163 } | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
|  170       profile_ ? profile_->GetCustomWords() : CustomWordList(), |  188       profile_ ? profile_->GetCustomWords() : CustomWordList(), | 
|  171       GetLanguage(), |  189       GetLanguage(), | 
|  172       prefs->GetBoolean(prefs::kEnableAutoSpellCorrect))); |  190       prefs->GetBoolean(prefs::kEnableAutoSpellCorrect))); | 
|  173 } |  191 } | 
|  174  |  192  | 
|  175 void SpellCheckHostImpl::AddWord(const std::string& word) { |  193 void SpellCheckHostImpl::AddWord(const std::string& word) { | 
|  176   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |  194   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
|  177  |  195  | 
|  178   if (profile_) |  196   if (profile_) | 
|  179     profile_->CustomWordAddedLocally(word); |  197     profile_->CustomWordAddedLocally(word); | 
|  180   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |  198  | 
|  181       NewRunnableMethod(this, |  199   BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, | 
|  182           &SpellCheckHostImpl::WriteWordToCustomDictionary, word)); |  200       base::Bind(&SpellCheckHostImpl::WriteWordToCustomDictionary, | 
|  183   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); |  201                  base::Unretained(this), word), | 
|  184        !i.IsAtEnd(); i.Advance()) { |  202       base::Bind(&SpellCheckHostImpl::AddWordComplete, | 
|  185     i.GetCurrentValue()->Send(new SpellCheckMsg_WordAdded(word)); |  203                  weak_ptr_factory_.GetWeakPtr(), word)); | 
|  186   } |  | 
|  187 } |  204 } | 
|  188  |  205  | 
|  189 void SpellCheckHostImpl::InitializeDictionaryLocation() { |  206 void SpellCheckHostImpl::InitializeDictionaryLocation() { | 
|  190   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |  207   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 
|  191  |  208  | 
|  192   // Initialize the BDICT path. This initialization should be in the FILE thread |  209   // Initialize the BDICT path. This initialization should be in the FILE thread | 
|  193   // because it checks if there is a "Dictionaries" directory and create it. |  210   // because it checks if there is a "Dictionaries" directory and create it. | 
|  194   if (bdict_file_path_.empty()) |  211   if (bdict_file_path_.empty()) | 
|  195     bdict_file_path_ = GetFirstChoiceFilePath(language_); |  212     bdict_file_path_ = GetFirstChoiceFilePath(language_); | 
|  196  |  213  | 
|  197 #if defined(OS_WIN) |  214 #if defined(OS_WIN) | 
|  198   // Check if the dictionary exists in the fallback location. If so, use it |  215   // Check if the dictionary exists in the fallback location. If so, use it | 
|  199   // rather than downloading anew. |  216   // rather than downloading anew. | 
|  200   FilePath fallback = GetFallbackFilePath(bdict_file_path_); |  217   FilePath fallback = GetFallbackFilePath(bdict_file_path_); | 
|  201   if (!file_util::PathExists(bdict_file_path_) && |  218   if (!file_util::PathExists(bdict_file_path_) && | 
|  202       file_util::PathExists(fallback)) { |  219       file_util::PathExists(fallback)) { | 
|  203     bdict_file_path_ = fallback; |  220     bdict_file_path_ = fallback; | 
|  204   } |  221   } | 
|  205 #endif |  222 #endif | 
|  206  |  223  | 
|  207   InitializeInternal(); |  | 
|  208 } |  | 
|  209  |  | 
|  210 void SpellCheckHostImpl::InitializeInternal() { |  | 
|  211   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |  | 
|  212  |  | 
|  213   if (!profile_) |  224   if (!profile_) | 
|  214     return; |  225     return; | 
|  215  |  226  | 
|  216   if (!VerifyBDict(bdict_file_path_)) { |  227   if (!VerifyBDict(bdict_file_path_)) { | 
|  217     DCHECK_EQ(file_, base::kInvalidPlatformFileValue); |  228     DCHECK_EQ(file_, base::kInvalidPlatformFileValue); | 
|  218     file_util::Delete(bdict_file_path_, false); |  229     file_util::Delete(bdict_file_path_, false); | 
|  219  |  230  | 
|  220     // Notify browser tests that this dictionary is corrupted. We also skip |  231     // Notify browser tests that this dictionary is corrupted. We also skip | 
|  221     // downloading the dictionary when we run this function on browser tests. |  232     // downloading the dictionary when we run this function on browser tests. | 
|  222     if (SignalStatusEvent(BDICT_CORRUPTED)) |  233     if (SignalStatusEvent(BDICT_CORRUPTED)) | 
|  223       tried_to_download_ = true; |  234       tried_to_download_ = true; | 
|  224   } else { |  235   } else { | 
|  225     file_ = base::CreatePlatformFile( |  236     file_ = base::CreatePlatformFile( | 
|  226         bdict_file_path_, |  237         bdict_file_path_, | 
|  227         base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, |  238         base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, | 
|  228         NULL, NULL); |  239         NULL, NULL); | 
|  229   } |  240   } | 
|  230  |  241  | 
|  231   // File didn't exist. Download it. |  242   // File didn't exist. Download it. | 
|  232   if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_ && |  243   if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_ && | 
|  233       request_context_getter_) { |  244       request_context_getter_) { | 
 |  245     // Return this function so InitializeDictionaryLocationComplete() can start | 
 |  246     // downloading the dictionary. | 
 |  247     return; | 
 |  248   } | 
 |  249  | 
 |  250   request_context_getter_ = NULL; | 
 |  251  | 
 |  252   custom_words_.reset(new CustomWordList()); | 
 |  253   if (file_ != base::kInvalidPlatformFileValue) | 
 |  254     LoadCustomDictionary(custom_words_.get()); | 
 |  255 } | 
 |  256  | 
 |  257 void SpellCheckHostImpl::InitializeDictionaryLocationComplete() { | 
 |  258   if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_ && | 
 |  259       request_context_getter_) { | 
|  234     // We download from the ui thread because we need to know that |  260     // We download from the ui thread because we need to know that | 
|  235     // |request_context_getter_| is still valid before initiating the download. |  261     // |request_context_getter_| is still valid before initiating the download. | 
|  236     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |  262     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 
|  237         NewRunnableMethod(this, &SpellCheckHostImpl::DownloadDictionary)); |  263         base::Bind(&SpellCheckHostImpl::DownloadDictionary, | 
|  238     return; |  264                    weak_ptr_factory_.GetWeakPtr())); | 
 |  265   } else { | 
 |  266     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 
 |  267         base::Bind( | 
 |  268             &SpellCheckHostImpl::InformProfileOfInitializationWithCustomWords, | 
 |  269             weak_ptr_factory_.GetWeakPtr(), | 
 |  270             custom_words_.release())); | 
|  239   } |  271   } | 
|  240  |  | 
|  241   request_context_getter_ = NULL; |  | 
|  242  |  | 
|  243   scoped_ptr<CustomWordList> custom_words(new CustomWordList()); |  | 
|  244   if (file_ != base::kInvalidPlatformFileValue) |  | 
|  245     LoadCustomDictionary(custom_words.get()); |  | 
|  246  |  | 
|  247   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |  | 
|  248       NewRunnableMethod( |  | 
|  249           this, |  | 
|  250           &SpellCheckHostImpl::InformProfileOfInitializationWithCustomWords, |  | 
|  251           custom_words.release())); |  | 
|  252 } |  | 
|  253  |  | 
|  254 void SpellCheckHostImpl::InitializeOnFileThread() { |  | 
|  255   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE)); |  | 
|  256  |  | 
|  257   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |  | 
|  258       NewRunnableMethod(this, &SpellCheckHostImpl::Initialize)); |  | 
|  259 } |  272 } | 
|  260  |  273  | 
|  261 void SpellCheckHostImpl::InformProfileOfInitialization() { |  274 void SpellCheckHostImpl::InformProfileOfInitialization() { | 
|  262   InformProfileOfInitializationWithCustomWords(NULL); |  275   InformProfileOfInitializationWithCustomWords(NULL); | 
|  263 } |  276 } | 
|  264  |  277  | 
|  265 void SpellCheckHostImpl::InformProfileOfInitializationWithCustomWords( |  278 void SpellCheckHostImpl::InformProfileOfInitializationWithCustomWords( | 
|  266     CustomWordList* custom_words) { |  279     CustomWordList* custom_words) { | 
|  267   // Non-null |custom_words| should be given only if the profile is available |  280   // Non-null |custom_words| should be given only if the profile is available | 
|  268   // for simplifying the life-cycle management of the word list. |  281   // for simplifying the life-cycle management of the word list. | 
|  269   DCHECK(profile_ || !custom_words); |  282   DCHECK(profile_ || !custom_words); | 
|  270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |  283   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
|  271  |  284  | 
|  272   if (profile_) |  285   if (profile_) | 
|  273     profile_->SpellCheckHostInitialized(custom_words); |  286     profile_->SpellCheckHostInitialized(custom_words); | 
|  274  |  287  | 
|  275   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); |  288   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); | 
|  276        !i.IsAtEnd(); i.Advance()) { |  289        !i.IsAtEnd(); i.Advance()) { | 
|  277     RenderProcessHost* process = i.GetCurrentValue(); |  290     RenderProcessHost* process = i.GetCurrentValue(); | 
|  278     if (process) |  291     if (process) | 
|  279       InitForRenderer(process); |  292       InitForRenderer(process); | 
|  280   } |  293   } | 
|  281 } |  294 } | 
|  282  |  295  | 
|  283 void SpellCheckHostImpl::DownloadDictionary() { |  296 void SpellCheckHostImpl::DownloadDictionary() { | 
|  284   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |  297   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
|  285  |  298   DCHECK(request_context_getter_); | 
|  286   if (!request_context_getter_) { |  | 
|  287     InitializeOnFileThread(); |  | 
|  288     return; |  | 
|  289   } |  | 
|  290  |  299  | 
|  291   // Determine URL of file to download. |  300   // Determine URL of file to download. | 
|  292   static const char kDownloadServerUrl[] = |  301   static const char kDownloadServerUrl[] = | 
|  293       "http://cache.pack.google.com/edgedl/chrome/dict/"; |  302       "http://cache.pack.google.com/edgedl/chrome/dict/"; | 
|  294   std::string bdict_file = bdict_file_path_.BaseName().MaybeAsASCII(); |  303   std::string bdict_file = bdict_file_path_.BaseName().MaybeAsASCII(); | 
|  295   if (bdict_file.empty()) { |  304   if (bdict_file.empty()) { | 
|  296     NOTREACHED(); |  305     NOTREACHED(); | 
|  297     return; |  306     return; | 
|  298   } |  307   } | 
|  299   GURL url = GURL(std::string(kDownloadServerUrl) + |  308   GURL url = GURL(std::string(kDownloadServerUrl) + | 
|  300                   StringToLowerASCII(bdict_file)); |  309                   StringToLowerASCII(bdict_file)); | 
|  301   fetcher_.reset(content::URLFetcher::Create( |  310   fetcher_.reset(content::URLFetcher::Create(url, content::URLFetcher::GET, | 
|  302       url, content::URLFetcher::GET, this)); |  311                                 weak_ptr_factory_.GetWeakPtr())); | 
|  303   fetcher_->SetRequestContext(request_context_getter_); |  312   fetcher_->SetRequestContext(request_context_getter_); | 
|  304   tried_to_download_ = true; |  313   tried_to_download_ = true; | 
|  305   fetcher_->Start(); |  314   fetcher_->Start(); | 
|  306   request_context_getter_ = NULL; |  315   request_context_getter_ = NULL; | 
|  307 } |  316 } | 
|  308  |  317  | 
|  309 void SpellCheckHostImpl::LoadCustomDictionary(CustomWordList* custom_words) { |  318 void SpellCheckHostImpl::LoadCustomDictionary(CustomWordList* custom_words) { | 
|  310   if (!custom_words) |  319   if (!custom_words) | 
|  311     return; |  320     return; | 
|  312  |  321  | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
|  336 } |  345 } | 
|  337  |  346  | 
|  338 void SpellCheckHostImpl::OnURLFetchComplete(const content::URLFetcher* source) { |  347 void SpellCheckHostImpl::OnURLFetchComplete(const content::URLFetcher* source) { | 
|  339   DCHECK(source); |  348   DCHECK(source); | 
|  340   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |  349   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
|  341   scoped_ptr<content::URLFetcher> fetcher_destructor(fetcher_.release()); |  350   scoped_ptr<content::URLFetcher> fetcher_destructor(fetcher_.release()); | 
|  342  |  351  | 
|  343   if ((source->GetResponseCode() / 100) != 2) { |  352   if ((source->GetResponseCode() / 100) != 2) { | 
|  344     // Initialize will not try to download the file a second time. |  353     // Initialize will not try to download the file a second time. | 
|  345     LOG(ERROR) << "Failure to download dictionary."; |  354     LOG(ERROR) << "Failure to download dictionary."; | 
|  346     InitializeOnFileThread(); |  | 
|  347     return; |  355     return; | 
|  348   } |  356   } | 
|  349  |  357  | 
|  350   // Basic sanity check on the dictionary. |  358   // Basic sanity check on the dictionary. | 
|  351   // There's the small chance that we might see a 200 status code for a body |  359   // There's the small chance that we might see a 200 status code for a body | 
|  352   // that represents some form of failure. |  360   // that represents some form of failure. | 
|  353   std::string data; |  361   std::string data; | 
|  354   source->GetResponseAsString(&data); |  362   source->GetResponseAsString(&data); | 
|  355   if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || |  363   if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || | 
|  356       data[3] != 'c') { |  364       data[3] != 'c') { | 
|  357     LOG(ERROR) << "Failure to download dictionary."; |  365     LOG(ERROR) << "Failure to download dictionary."; | 
|  358     InitializeOnFileThread(); |  | 
|  359     return; |  366     return; | 
|  360   } |  367   } | 
|  361  |  368  | 
|  362   data_ = data; |  369   data_ = data; | 
|  363   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |  370   dictionary_saved_ = false; | 
|  364       NewRunnableMethod(this, &SpellCheckHostImpl::SaveDictionaryData)); |  371   BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, | 
 |  372       base::Bind(&SpellCheckHostImpl::SaveDictionaryData, | 
 |  373                  base::Unretained(this)), | 
 |  374       base::Bind(&SpellCheckHostImpl::SaveDictionaryDataComplete, | 
 |  375                  weak_ptr_factory_.GetWeakPtr())); | 
|  365 } |  376 } | 
|  366  |  377  | 
|  367 void SpellCheckHostImpl::Observe(int type, |  378 void SpellCheckHostImpl::Observe(int type, | 
|  368                                  const content::NotificationSource& source, |  379                                  const content::NotificationSource& source, | 
|  369                                  const content::NotificationDetails& details) { |  380                                  const content::NotificationDetails& details) { | 
|  370   DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CREATED); |  381   DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CREATED); | 
|  371   RenderProcessHost* process = content::Source<RenderProcessHost>(source).ptr(); |  382   RenderProcessHost* process = content::Source<RenderProcessHost>(source).ptr(); | 
|  372   InitForRenderer(process); |  383   InitForRenderer(process); | 
|  373 } |  384 } | 
|  374  |  385  | 
|  375 void SpellCheckHostImpl::SaveDictionaryData() { |  386 void SpellCheckHostImpl::SaveDictionaryData() { | 
|  376   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |  387   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 
|  377  |  388  | 
|  378   // To prevent corrupted dictionary data from causing a renderer crash, scan |  389   // To prevent corrupted dictionary data from causing a renderer crash, scan | 
|  379   // the dictionary data and verify it is sane before save it to a file. |  390   // the dictionary data and verify it is sane before save it to a file. | 
|  380   bool verified = hunspell::BDict::Verify(data_.data(), data_.size()); |  391   bool verified = hunspell::BDict::Verify(data_.data(), data_.size()); | 
|  381   if (metrics_) |  392   if (metrics_) | 
|  382     metrics_->RecordDictionaryCorruptionStats(!verified); |  393     metrics_->RecordDictionaryCorruptionStats(!verified); | 
|  383   if (!verified) { |  394   if (!verified) { | 
|  384     LOG(ERROR) << "Failure to verify the downloaded dictionary."; |  395     LOG(ERROR) << "Failure to verify the downloaded dictionary."; | 
|  385     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |  396     // Let PostTaskAndReply caller send to InformProfileOfInitialization | 
|  386         NewRunnableMethod(this, |  | 
|  387                           &SpellCheckHostImpl::InformProfileOfInitialization)); |  | 
|  388     return; |  397     return; | 
|  389   } |  398   } | 
|  390  |  399  | 
|  391   size_t bytes_written = |  400   size_t bytes_written = | 
|  392       file_util::WriteFile(bdict_file_path_, data_.data(), data_.length()); |  401       file_util::WriteFile(bdict_file_path_, data_.data(), data_.length()); | 
|  393   if (bytes_written != data_.length()) { |  402   if (bytes_written != data_.length()) { | 
|  394     bool success = false; |  403     bool success = false; | 
|  395 #if defined(OS_WIN) |  404 #if defined(OS_WIN) | 
|  396     bdict_file_path_ = GetFallbackFilePath(bdict_file_path_); |  405     bdict_file_path_ = GetFallbackFilePath(bdict_file_path_); | 
|  397     bytes_written = |  406     bytes_written = | 
|  398         file_util::WriteFile(GetFallbackFilePath(bdict_file_path_), |  407         file_util::WriteFile(GetFallbackFilePath(bdict_file_path_), | 
|  399                                                  data_.data(), data_.length()); |  408                                                  data_.data(), data_.length()); | 
|  400     if (bytes_written == data_.length()) |  409     if (bytes_written == data_.length()) | 
|  401       success = true; |  410       success = true; | 
|  402 #endif |  411 #endif | 
|  403     data_.clear(); |  412     data_.clear(); | 
|  404  |  413  | 
|  405     if (!success) { |  414     if (!success) { | 
|  406       LOG(ERROR) << "Failure to save dictionary."; |  415       LOG(ERROR) << "Failure to save dictionary."; | 
|  407       file_util::Delete(bdict_file_path_, false); |  416       file_util::Delete(bdict_file_path_, false); | 
|  408       // To avoid trying to load a partially saved dictionary, shortcut the |  417       // To avoid trying to load a partially saved dictionary, shortcut the | 
|  409       // Initialize() call. |  418       // Initialize() call. Let PostTaskAndReply caller send to | 
|  410       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |  419       // InformProfileOfInitialization through SaveDictionaryDataComplete() | 
|  411           NewRunnableMethod(this, |  | 
|  412               &SpellCheckHostImpl::InformProfileOfInitialization)); |  | 
|  413       return; |  420       return; | 
|  414     } |  421     } | 
|  415   } |  422   } | 
|  416  |  423  | 
|  417   data_.clear(); |  424   data_.clear(); | 
|  418   Initialize(); |  425   dictionary_saved_ = true; | 
 |  426 } | 
 |  427  | 
 |  428 void SpellCheckHostImpl::SaveDictionaryDataComplete() { | 
 |  429   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
 |  430  | 
 |  431   if (dictionary_saved_) { | 
 |  432     Initialize(); | 
 |  433   } else { | 
 |  434     InformProfileOfInitialization(); | 
 |  435   } | 
|  419 } |  436 } | 
|  420  |  437  | 
|  421 bool SpellCheckHostImpl::VerifyBDict(const FilePath& path) const { |  438 bool SpellCheckHostImpl::VerifyBDict(const FilePath& path) const { | 
|  422   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |  439   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 
|  423  |  440  | 
|  424   // Read the dictionary file and scan its data. We need to close this file |  441   // Read the dictionary file and scan its data. We need to close this file | 
|  425   // after scanning its data so we can delete it and download a new dictionary |  442   // after scanning its data so we can delete it and download a new dictionary | 
|  426   // from our dictionary-download server if it is corrupted. |  443   // from our dictionary-download server if it is corrupted. | 
|  427   file_util::MemoryMappedFile map; |  444   file_util::MemoryMappedFile map; | 
|  428   if (!map.Initialize(path)) |  445   if (!map.Initialize(path)) | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
|  445   return file_; |  462   return file_; | 
|  446 } |  463 } | 
|  447  |  464  | 
|  448 const std::string& SpellCheckHostImpl::GetLanguage() const { |  465 const std::string& SpellCheckHostImpl::GetLanguage() const { | 
|  449   return language_; |  466   return language_; | 
|  450 } |  467 } | 
|  451  |  468  | 
|  452 bool SpellCheckHostImpl::IsUsingPlatformChecker() const { |  469 bool SpellCheckHostImpl::IsUsingPlatformChecker() const { | 
|  453   return use_platform_spellchecker_; |  470   return use_platform_spellchecker_; | 
|  454 } |  471 } | 
 |  472  | 
 |  473 void SpellCheckHostImpl::AddWordComplete(const std::string& word) { | 
 |  474   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
 |  475  | 
 |  476   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); | 
 |  477        !i.IsAtEnd(); i.Advance()) { | 
 |  478     i.GetCurrentValue()->Send(new SpellCheckMsg_WordAdded(word)); | 
 |  479   } | 
 |  480 } | 
| OLD | NEW |