| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_hunspell_dictionary.h" | 5 #include "chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h" |
| 6 | 6 |
| 7 #include "base/files/file_util.h" | 7 #include "base/files/file_util.h" |
| 8 #include "base/files/memory_mapped_file.h" | 8 #include "base/files/memory_mapped_file.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 #include "net/url_request/url_request_context_getter.h" | 21 #include "net/url_request/url_request_context_getter.h" |
| 22 #include "third_party/hunspell/google/bdict.h" | 22 #include "third_party/hunspell/google/bdict.h" |
| 23 #include "url/gurl.h" | 23 #include "url/gurl.h" |
| 24 | 24 |
| 25 using content::BrowserThread; | 25 using content::BrowserThread; |
| 26 | 26 |
| 27 namespace { | 27 namespace { |
| 28 | 28 |
| 29 // Close the file. | 29 // Close the file. |
| 30 void CloseDictionary(base::File file) { | 30 void CloseDictionary(base::File file) { |
| 31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 31 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 32 file.Close(); | 32 file.Close(); |
| 33 } | 33 } |
| 34 | 34 |
| 35 // Saves |data| to file at |path|. Returns true on successful save, otherwise | 35 // Saves |data| to file at |path|. Returns true on successful save, otherwise |
| 36 // returns false. | 36 // returns false. |
| 37 bool SaveDictionaryData(scoped_ptr<std::string> data, | 37 bool SaveDictionaryData(scoped_ptr<std::string> data, |
| 38 const base::FilePath& path) { | 38 const base::FilePath& path) { |
| 39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 39 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 40 | 40 |
| 41 size_t bytes_written = | 41 size_t bytes_written = |
| 42 base::WriteFile(path, data->data(), data->length()); | 42 base::WriteFile(path, data->data(), data->length()); |
| 43 if (bytes_written != data->length()) { | 43 if (bytes_written != data->length()) { |
| 44 bool success = false; | 44 bool success = false; |
| 45 #if defined(OS_WIN) | 45 #if defined(OS_WIN) |
| 46 base::FilePath dict_dir; | 46 base::FilePath dict_dir; |
| 47 PathService::Get(chrome::DIR_USER_DATA, &dict_dir); | 47 PathService::Get(chrome::DIR_USER_DATA, &dict_dir); |
| 48 base::FilePath fallback_file_path = | 48 base::FilePath fallback_file_path = |
| 49 dict_dir.Append(path.BaseName()); | 49 dict_dir.Append(path.BaseName()); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 request_context_getter_(request_context_getter), | 99 request_context_getter_(request_context_getter), |
| 100 spellcheck_service_(spellcheck_service), | 100 spellcheck_service_(spellcheck_service), |
| 101 download_status_(DOWNLOAD_NONE), | 101 download_status_(DOWNLOAD_NONE), |
| 102 weak_ptr_factory_(this) { | 102 weak_ptr_factory_(this) { |
| 103 } | 103 } |
| 104 | 104 |
| 105 SpellcheckHunspellDictionary::~SpellcheckHunspellDictionary() { | 105 SpellcheckHunspellDictionary::~SpellcheckHunspellDictionary() { |
| 106 } | 106 } |
| 107 | 107 |
| 108 void SpellcheckHunspellDictionary::Load() { | 108 void SpellcheckHunspellDictionary::Load() { |
| 109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 109 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 110 | 110 |
| 111 #if defined(OS_MACOSX) | 111 #if defined(OS_MACOSX) |
| 112 if (spellcheck_mac::SpellCheckerAvailable() && | 112 if (spellcheck_mac::SpellCheckerAvailable() && |
| 113 spellcheck_mac::PlatformSupportsLanguage(language_)) { | 113 spellcheck_mac::PlatformSupportsLanguage(language_)) { |
| 114 use_platform_spellchecker_ = true; | 114 use_platform_spellchecker_ = true; |
| 115 spellcheck_mac::SetLanguage(language_); | 115 spellcheck_mac::SetLanguage(language_); |
| 116 base::MessageLoop::current()->PostTask(FROM_HERE, | 116 base::MessageLoop::current()->PostTask(FROM_HERE, |
| 117 base::Bind( | 117 base::Bind( |
| 118 &SpellcheckHunspellDictionary::InformListenersOfInitialization, | 118 &SpellcheckHunspellDictionary::InformListenersOfInitialization, |
| 119 weak_ptr_factory_.GetWeakPtr())); | 119 weak_ptr_factory_.GetWeakPtr())); |
| 120 return; | 120 return; |
| 121 } | 121 } |
| 122 #endif // OS_MACOSX | 122 #endif // OS_MACOSX |
| 123 | 123 |
| 124 BrowserThread::PostTaskAndReplyWithResult( | 124 BrowserThread::PostTaskAndReplyWithResult( |
| 125 BrowserThread::FILE, | 125 BrowserThread::FILE, |
| 126 FROM_HERE, | 126 FROM_HERE, |
| 127 base::Bind(&InitializeDictionaryLocation, language_), | 127 base::Bind(&InitializeDictionaryLocation, language_), |
| 128 base::Bind( | 128 base::Bind( |
| 129 &SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete, | 129 &SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete, |
| 130 weak_ptr_factory_.GetWeakPtr())); | 130 weak_ptr_factory_.GetWeakPtr())); |
| 131 } | 131 } |
| 132 | 132 |
| 133 void SpellcheckHunspellDictionary::RetryDownloadDictionary( | 133 void SpellcheckHunspellDictionary::RetryDownloadDictionary( |
| 134 net::URLRequestContextGetter* request_context_getter) { | 134 net::URLRequestContextGetter* request_context_getter) { |
| 135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 135 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 136 request_context_getter_ = request_context_getter; | 136 request_context_getter_ = request_context_getter; |
| 137 DownloadDictionary(GetDictionaryURL()); | 137 DownloadDictionary(GetDictionaryURL()); |
| 138 } | 138 } |
| 139 | 139 |
| 140 bool SpellcheckHunspellDictionary::IsReady() const { | 140 bool SpellcheckHunspellDictionary::IsReady() const { |
| 141 return GetDictionaryFile().IsValid() || IsUsingPlatformChecker(); | 141 return GetDictionaryFile().IsValid() || IsUsingPlatformChecker(); |
| 142 } | 142 } |
| 143 | 143 |
| 144 const base::File& SpellcheckHunspellDictionary::GetDictionaryFile() const { | 144 const base::File& SpellcheckHunspellDictionary::GetDictionaryFile() const { |
| 145 return dictionary_file_.file; | 145 return dictionary_file_.file; |
| 146 } | 146 } |
| 147 | 147 |
| 148 const std::string& SpellcheckHunspellDictionary::GetLanguage() const { | 148 const std::string& SpellcheckHunspellDictionary::GetLanguage() const { |
| 149 return language_; | 149 return language_; |
| 150 } | 150 } |
| 151 | 151 |
| 152 bool SpellcheckHunspellDictionary::IsUsingPlatformChecker() const { | 152 bool SpellcheckHunspellDictionary::IsUsingPlatformChecker() const { |
| 153 return use_platform_spellchecker_; | 153 return use_platform_spellchecker_; |
| 154 } | 154 } |
| 155 | 155 |
| 156 void SpellcheckHunspellDictionary::AddObserver(Observer* observer) { | 156 void SpellcheckHunspellDictionary::AddObserver(Observer* observer) { |
| 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 157 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 158 observers_.AddObserver(observer); | 158 observers_.AddObserver(observer); |
| 159 } | 159 } |
| 160 | 160 |
| 161 void SpellcheckHunspellDictionary::RemoveObserver(Observer* observer) { | 161 void SpellcheckHunspellDictionary::RemoveObserver(Observer* observer) { |
| 162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 162 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 163 observers_.RemoveObserver(observer); | 163 observers_.RemoveObserver(observer); |
| 164 } | 164 } |
| 165 | 165 |
| 166 bool SpellcheckHunspellDictionary::IsDownloadInProgress() { | 166 bool SpellcheckHunspellDictionary::IsDownloadInProgress() { |
| 167 return download_status_ == DOWNLOAD_IN_PROGRESS; | 167 return download_status_ == DOWNLOAD_IN_PROGRESS; |
| 168 } | 168 } |
| 169 | 169 |
| 170 bool SpellcheckHunspellDictionary::IsDownloadFailure() { | 170 bool SpellcheckHunspellDictionary::IsDownloadFailure() { |
| 171 return download_status_ == DOWNLOAD_FAILED; | 171 return download_status_ == DOWNLOAD_FAILED; |
| 172 } | 172 } |
| 173 | 173 |
| 174 void SpellcheckHunspellDictionary::OnURLFetchComplete( | 174 void SpellcheckHunspellDictionary::OnURLFetchComplete( |
| 175 const net::URLFetcher* source) { | 175 const net::URLFetcher* source) { |
| 176 DCHECK(source); | 176 DCHECK(source); |
| 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 177 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 178 scoped_ptr<net::URLFetcher> fetcher_destructor(fetcher_.release()); | 178 scoped_ptr<net::URLFetcher> fetcher_destructor(fetcher_.release()); |
| 179 | 179 |
| 180 if ((source->GetResponseCode() / 100) != 2) { | 180 if ((source->GetResponseCode() / 100) != 2) { |
| 181 // Initialize will not try to download the file a second time. | 181 // Initialize will not try to download the file a second time. |
| 182 InformListenersOfDownloadFailure(); | 182 InformListenersOfDownloadFailure(); |
| 183 return; | 183 return; |
| 184 } | 184 } |
| 185 | 185 |
| 186 // Basic sanity check on the dictionary. There's a small chance of 200 status | 186 // Basic sanity check on the dictionary. There's a small chance of 200 status |
| 187 // code for a body that represents some form of failure. | 187 // code for a body that represents some form of failure. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 217 "http://cache.pack.google.com/edgedl/chrome/dict/"; | 217 "http://cache.pack.google.com/edgedl/chrome/dict/"; |
| 218 std::string bdict_file = dictionary_file_.path.BaseName().MaybeAsASCII(); | 218 std::string bdict_file = dictionary_file_.path.BaseName().MaybeAsASCII(); |
| 219 | 219 |
| 220 DCHECK(!bdict_file.empty()); | 220 DCHECK(!bdict_file.empty()); |
| 221 | 221 |
| 222 return GURL(std::string(kDownloadServerUrl) + | 222 return GURL(std::string(kDownloadServerUrl) + |
| 223 base::StringToLowerASCII(bdict_file)); | 223 base::StringToLowerASCII(bdict_file)); |
| 224 } | 224 } |
| 225 | 225 |
| 226 void SpellcheckHunspellDictionary::DownloadDictionary(GURL url) { | 226 void SpellcheckHunspellDictionary::DownloadDictionary(GURL url) { |
| 227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 227 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 228 DCHECK(request_context_getter_); | 228 DCHECK(request_context_getter_); |
| 229 | 229 |
| 230 download_status_ = DOWNLOAD_IN_PROGRESS; | 230 download_status_ = DOWNLOAD_IN_PROGRESS; |
| 231 FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryDownloadBegin()); | 231 FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryDownloadBegin()); |
| 232 | 232 |
| 233 fetcher_.reset(net::URLFetcher::Create(url, net::URLFetcher::GET, this)); | 233 fetcher_.reset(net::URLFetcher::Create(url, net::URLFetcher::GET, this)); |
| 234 fetcher_->SetRequestContext(request_context_getter_); | 234 fetcher_->SetRequestContext(request_context_getter_); |
| 235 fetcher_->SetLoadFlags( | 235 fetcher_->SetLoadFlags( |
| 236 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); | 236 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); |
| 237 fetcher_->Start(); | 237 fetcher_->Start(); |
| 238 // Attempt downloading the dictionary only once. | 238 // Attempt downloading the dictionary only once. |
| 239 request_context_getter_ = NULL; | 239 request_context_getter_ = NULL; |
| 240 } | 240 } |
| 241 | 241 |
| 242 // The default_dictionary_file can either come from the standard list of | 242 // The default_dictionary_file can either come from the standard list of |
| 243 // hunspell dictionaries (determined in InitializeDictionaryLocation), or it | 243 // hunspell dictionaries (determined in InitializeDictionaryLocation), or it |
| 244 // can be passed in via an extension. In either case, the file is checked for | 244 // can be passed in via an extension. In either case, the file is checked for |
| 245 // existence so that it's not re-downloaded. | 245 // existence so that it's not re-downloaded. |
| 246 // For systemwide installations on Windows, the default directory may not | 246 // For systemwide installations on Windows, the default directory may not |
| 247 // have permissions for download. In that case, the alternate directory for | 247 // have permissions for download. In that case, the alternate directory for |
| 248 // download is chrome::DIR_USER_DATA. | 248 // download is chrome::DIR_USER_DATA. |
| 249 SpellcheckHunspellDictionary::DictionaryFile | 249 SpellcheckHunspellDictionary::DictionaryFile |
| 250 SpellcheckHunspellDictionary::OpenDictionaryFile(const base::FilePath& path) { | 250 SpellcheckHunspellDictionary::OpenDictionaryFile(const base::FilePath& path) { |
| 251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 251 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 252 DictionaryFile dictionary; | 252 DictionaryFile dictionary; |
| 253 | 253 |
| 254 #if defined(OS_WIN) | 254 #if defined(OS_WIN) |
| 255 // Check if the dictionary exists in the fallback location. If so, use it | 255 // Check if the dictionary exists in the fallback location. If so, use it |
| 256 // rather than downloading anew. | 256 // rather than downloading anew. |
| 257 base::FilePath user_dir; | 257 base::FilePath user_dir; |
| 258 PathService::Get(chrome::DIR_USER_DATA, &user_dir); | 258 PathService::Get(chrome::DIR_USER_DATA, &user_dir); |
| 259 base::FilePath fallback = user_dir.Append(path.BaseName()); | 259 base::FilePath fallback = user_dir.Append(path.BaseName()); |
| 260 if (!base::PathExists(path) && base::PathExists(fallback)) | 260 if (!base::PathExists(path) && base::PathExists(fallback)) |
| 261 dictionary.path = fallback; | 261 dictionary.path = fallback; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 284 } | 284 } |
| 285 | 285 |
| 286 return dictionary.Pass(); | 286 return dictionary.Pass(); |
| 287 } | 287 } |
| 288 | 288 |
| 289 // The default place where the spellcheck dictionary resides is | 289 // The default place where the spellcheck dictionary resides is |
| 290 // chrome::DIR_APP_DICTIONARIES. | 290 // chrome::DIR_APP_DICTIONARIES. |
| 291 SpellcheckHunspellDictionary::DictionaryFile | 291 SpellcheckHunspellDictionary::DictionaryFile |
| 292 SpellcheckHunspellDictionary::InitializeDictionaryLocation( | 292 SpellcheckHunspellDictionary::InitializeDictionaryLocation( |
| 293 const std::string& language) { | 293 const std::string& language) { |
| 294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 294 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 295 | 295 |
| 296 // Initialize the BDICT path. Initialization should be in the FILE thread | 296 // Initialize the BDICT path. Initialization should be in the FILE thread |
| 297 // because it checks if there is a "Dictionaries" directory and create it. | 297 // because it checks if there is a "Dictionaries" directory and create it. |
| 298 base::FilePath dict_dir; | 298 base::FilePath dict_dir; |
| 299 PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); | 299 PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); |
| 300 base::FilePath dict_path = | 300 base::FilePath dict_path = |
| 301 chrome::spellcheck_common::GetVersionedFileName(language, dict_dir); | 301 chrome::spellcheck_common::GetVersionedFileName(language, dict_dir); |
| 302 | 302 |
| 303 return OpenDictionaryFile(dict_path); | 303 return OpenDictionaryFile(dict_path); |
| 304 } | 304 } |
| 305 | 305 |
| 306 void SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete( | 306 void SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete( |
| 307 DictionaryFile file) { | 307 DictionaryFile file) { |
| 308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 308 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 309 dictionary_file_ = file.Pass(); | 309 dictionary_file_ = file.Pass(); |
| 310 | 310 |
| 311 if (!dictionary_file_.file.IsValid()) { | 311 if (!dictionary_file_.file.IsValid()) { |
| 312 | 312 |
| 313 // Notify browser tests that this dictionary is corrupted. Skip downloading | 313 // Notify browser tests that this dictionary is corrupted. Skip downloading |
| 314 // the dictionary in browser tests. | 314 // the dictionary in browser tests. |
| 315 // TODO(rouslan): Remove this test-only case. | 315 // TODO(rouslan): Remove this test-only case. |
| 316 if (spellcheck_service_->SignalStatusEvent( | 316 if (spellcheck_service_->SignalStatusEvent( |
| 317 SpellcheckService::BDICT_CORRUPTED)) { | 317 SpellcheckService::BDICT_CORRUPTED)) { |
| 318 request_context_getter_ = NULL; | 318 request_context_getter_ = NULL; |
| 319 } | 319 } |
| 320 | 320 |
| 321 if (request_context_getter_) { | 321 if (request_context_getter_) { |
| 322 // Download from the UI thread to check that |request_context_getter_| is | 322 // Download from the UI thread to check that |request_context_getter_| is |
| 323 // still valid. | 323 // still valid. |
| 324 DownloadDictionary(GetDictionaryURL()); | 324 DownloadDictionary(GetDictionaryURL()); |
| 325 return; | 325 return; |
| 326 } | 326 } |
| 327 } | 327 } |
| 328 | 328 |
| 329 InformListenersOfInitialization(); | 329 InformListenersOfInitialization(); |
| 330 } | 330 } |
| 331 | 331 |
| 332 void SpellcheckHunspellDictionary::SaveDictionaryDataComplete( | 332 void SpellcheckHunspellDictionary::SaveDictionaryDataComplete( |
| 333 bool dictionary_saved) { | 333 bool dictionary_saved) { |
| 334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 334 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 335 | 335 |
| 336 if (dictionary_saved) { | 336 if (dictionary_saved) { |
| 337 download_status_ = DOWNLOAD_NONE; | 337 download_status_ = DOWNLOAD_NONE; |
| 338 FOR_EACH_OBSERVER(Observer, | 338 FOR_EACH_OBSERVER(Observer, |
| 339 observers_, | 339 observers_, |
| 340 OnHunspellDictionaryDownloadSuccess()); | 340 OnHunspellDictionaryDownloadSuccess()); |
| 341 Load(); | 341 Load(); |
| 342 } else { | 342 } else { |
| 343 InformListenersOfDownloadFailure(); | 343 InformListenersOfDownloadFailure(); |
| 344 InformListenersOfInitialization(); | 344 InformListenersOfInitialization(); |
| 345 } | 345 } |
| 346 } | 346 } |
| 347 | 347 |
| 348 void SpellcheckHunspellDictionary::InformListenersOfInitialization() { | 348 void SpellcheckHunspellDictionary::InformListenersOfInitialization() { |
| 349 FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryInitialized()); | 349 FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryInitialized()); |
| 350 } | 350 } |
| 351 | 351 |
| 352 void SpellcheckHunspellDictionary::InformListenersOfDownloadFailure() { | 352 void SpellcheckHunspellDictionary::InformListenersOfDownloadFailure() { |
| 353 download_status_ = DOWNLOAD_FAILED; | 353 download_status_ = DOWNLOAD_FAILED; |
| 354 FOR_EACH_OBSERVER(Observer, | 354 FOR_EACH_OBSERVER(Observer, |
| 355 observers_, | 355 observers_, |
| 356 OnHunspellDictionaryDownloadFailure()); | 356 OnHunspellDictionaryDownloadFailure()); |
| 357 } | 357 } |
| OLD | NEW |