| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/spellcheck_host.h" | 5 #include "chrome/browser/spellcheck_host.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 | 8 |
| 9 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 if (language == special_version_string[i].language) { | 114 if (language == special_version_string[i].language) { |
| 115 versioned_bdict_file_name = | 115 versioned_bdict_file_name = |
| 116 language + special_version_string[i].version + ".bdic"; | 116 language + special_version_string[i].version + ".bdic"; |
| 117 break; | 117 break; |
| 118 } | 118 } |
| 119 } | 119 } |
| 120 | 120 |
| 121 return dict_dir.AppendASCII(versioned_bdict_file_name); | 121 return dict_dir.AppendASCII(versioned_bdict_file_name); |
| 122 } | 122 } |
| 123 | 123 |
| 124 FilePath GetFirstChoiceFilePath(const std::string& language) { |
| 125 FilePath dict_dir; |
| 126 PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); |
| 127 return GetVersionedFileName(language, dict_dir); |
| 128 } |
| 129 |
| 130 FilePath GetFallbackFilePath(const FilePath& first_choice) { |
| 131 FilePath dict_dir; |
| 132 PathService::Get(chrome::DIR_USER_DATA, &dict_dir); |
| 133 return dict_dir.Append(first_choice.BaseName()); |
| 134 } |
| 135 |
| 124 } // namespace | 136 } // namespace |
| 125 | 137 |
| 126 // Constructed on UI thread. | 138 // Constructed on UI thread. |
| 127 SpellCheckHost::SpellCheckHost(Observer* observer, | 139 SpellCheckHost::SpellCheckHost(Observer* observer, |
| 128 const std::string& language, | 140 const std::string& language, |
| 129 URLRequestContextGetter* request_context_getter) | 141 URLRequestContextGetter* request_context_getter) |
| 130 : observer_(observer), | 142 : observer_(observer), |
| 131 language_(language), | 143 language_(language), |
| 144 file_(base::kInvalidPlatformFileValue), |
| 132 tried_to_download_(false), | 145 tried_to_download_(false), |
| 133 request_context_getter_(request_context_getter) { | 146 request_context_getter_(request_context_getter) { |
| 134 DCHECK(observer_); | 147 DCHECK(observer_); |
| 135 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 148 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 136 | 149 |
| 137 // TODO(estade): for Windows, we need to fall back to DIR_USER_DATA if | |
| 138 // DIR_APP_DICTIONARIES is not writeable. | |
| 139 FilePath dict_dir; | |
| 140 PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); | |
| 141 bdict_file_ = GetVersionedFileName(language, dict_dir); | |
| 142 | |
| 143 FilePath personal_file_directory; | 150 FilePath personal_file_directory; |
| 144 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); | 151 PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); |
| 145 custom_dictionary_file_ = | 152 custom_dictionary_file_ = |
| 146 personal_file_directory.Append(chrome::kCustomDictionaryFileName); | 153 personal_file_directory.Append(chrome::kCustomDictionaryFileName); |
| 147 | 154 |
| 155 bdict_file_path_ = GetFirstChoiceFilePath(language); |
| 156 |
| 148 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 157 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 149 NewRunnableMethod(this, &SpellCheckHost::Initialize)); | 158 NewRunnableMethod(this, &SpellCheckHost::InitializeDictionaryLocation)); |
| 150 } | 159 } |
| 151 | 160 |
| 152 SpellCheckHost::~SpellCheckHost() { | 161 SpellCheckHost::~SpellCheckHost() { |
| 153 if (fd_.fd != -1) | 162 if (file_ != base::kInvalidPlatformFileValue) |
| 154 close(fd_.fd); | 163 base::ClosePlatformFile(file_); |
| 155 } | 164 } |
| 156 | 165 |
| 157 void SpellCheckHost::UnsetObserver() { | 166 void SpellCheckHost::UnsetObserver() { |
| 158 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 167 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 159 | 168 |
| 160 observer_ = NULL; | 169 observer_ = NULL; |
| 161 } | 170 } |
| 162 | 171 |
| 163 void SpellCheckHost::AddWord(const std::string& word) { | 172 void SpellCheckHost::AddWord(const std::string& word) { |
| 164 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 173 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 165 | 174 |
| 166 custom_words_.push_back(word); | 175 custom_words_.push_back(word); |
| 167 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 176 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 168 NewRunnableMethod(this, | 177 NewRunnableMethod(this, |
| 169 &SpellCheckHost::WriteWordToCustomDictionary, word)); | 178 &SpellCheckHost::WriteWordToCustomDictionary, word)); |
| 170 NotificationService::current()->Notify( | 179 NotificationService::current()->Notify( |
| 171 NotificationType::SPELLCHECK_WORD_ADDED, | 180 NotificationType::SPELLCHECK_WORD_ADDED, |
| 172 Source<SpellCheckHost>(this), NotificationService::NoDetails()); | 181 Source<SpellCheckHost>(this), NotificationService::NoDetails()); |
| 173 } | 182 } |
| 174 | 183 |
| 184 void SpellCheckHost::InitializeDictionaryLocation() { |
| 185 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 186 |
| 187 #if defined(OS_WIN) |
| 188 // Check if the dictionary exists in the fallback location. If so, use it |
| 189 // rather than downloading anew. |
| 190 FilePath fallback = GetFallbackFilePath(bdict_file_path_); |
| 191 if (!file_util::PathExists(bdict_file_path_) && |
| 192 file_util::PathExists(fallback)) { |
| 193 bdict_file_path_ = fallback; |
| 194 } |
| 195 #endif |
| 196 |
| 197 Initialize(); |
| 198 } |
| 199 |
| 175 void SpellCheckHost::Initialize() { | 200 void SpellCheckHost::Initialize() { |
| 176 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 201 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 177 | 202 |
| 178 if (!observer_) | 203 if (!observer_) |
| 179 return; | 204 return; |
| 180 | 205 |
| 181 // We set |auto_close| to false because we don't want IPC to close the fd. | 206 file_ = base::CreatePlatformFile(bdict_file_path_, |
| 182 // We will close it manually in the destructor. | 207 base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, |
| 183 fd_ = base::FileDescriptor(open(bdict_file_.value().c_str(), O_RDONLY), | 208 NULL); |
| 184 false); | |
| 185 | 209 |
| 186 // File didn't exist. Download it. | 210 // File didn't exist. Download it. |
| 187 if (fd_.fd == -1 && !tried_to_download_) { | 211 if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_) { |
| 188 DownloadDictionary(); | 212 DownloadDictionary(); |
| 189 return; | 213 return; |
| 190 } | 214 } |
| 191 | 215 |
| 192 if (fd_.fd != -1) { | 216 if (file_ != base::kInvalidPlatformFileValue) { |
| 193 // Load custom dictionary. | 217 // Load custom dictionary. |
| 194 std::string contents; | 218 std::string contents; |
| 195 file_util::ReadFileToString(custom_dictionary_file_, &contents); | 219 file_util::ReadFileToString(custom_dictionary_file_, &contents); |
| 196 std::vector<std::string> list_of_words; | 220 std::vector<std::string> list_of_words; |
| 197 SplitString(contents, '\n', &list_of_words); | 221 SplitString(contents, '\n', &list_of_words); |
| 198 for (size_t i = 0; i < list_of_words.size(); ++i) | 222 for (size_t i = 0; i < list_of_words.size(); ++i) |
| 199 custom_words_.push_back(list_of_words[i]); | 223 custom_words_.push_back(list_of_words[i]); |
| 200 } | 224 } |
| 201 | 225 |
| 202 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, | 226 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 203 NewRunnableMethod(this, | 227 NewRunnableMethod(this, |
| 204 &SpellCheckHost::InformObserverOfInitialization)); | 228 &SpellCheckHost::InformObserverOfInitialization)); |
| 205 } | 229 } |
| 206 | 230 |
| 207 void SpellCheckHost::InformObserverOfInitialization() { | 231 void SpellCheckHost::InformObserverOfInitialization() { |
| 208 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 232 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 209 | 233 |
| 210 if (observer_) | 234 if (observer_) |
| 211 observer_->SpellCheckHostInitialized(); | 235 observer_->SpellCheckHostInitialized(); |
| 212 } | 236 } |
| 213 | 237 |
| 214 void SpellCheckHost::DownloadDictionary() { | 238 void SpellCheckHost::DownloadDictionary() { |
| 215 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 239 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 216 | 240 |
| 217 // Determine URL of file to download. | 241 // Determine URL of file to download. |
| 218 static const char kDownloadServerUrl[] = | 242 static const char kDownloadServerUrl[] = |
| 219 "http://cache.pack.google.com/edgedl/chrome/dict/"; | 243 "http://cache.pack.google.com/edgedl/chrome/dict/"; |
| 220 GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8( | 244 GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8( |
| 221 l10n_util::ToLower(bdict_file_.BaseName().ToWStringHack()))); | 245 l10n_util::ToLower(bdict_file_path_.BaseName().ToWStringHack()))); |
| 222 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); | 246 fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); |
| 223 fetcher_->set_request_context(request_context_getter_.get()); | 247 fetcher_->set_request_context(request_context_getter_.get()); |
| 224 tried_to_download_ = true; | 248 tried_to_download_ = true; |
| 225 fetcher_->Start(); | 249 fetcher_->Start(); |
| 226 } | 250 } |
| 227 | 251 |
| 228 void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) { | 252 void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) { |
| 229 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 253 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 230 | 254 |
| 231 // Stored in UTF-8. | 255 // Stored in UTF-8. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 256 // There's the small chance that we might see a 200 status code for a body | 280 // There's the small chance that we might see a 200 status code for a body |
| 257 // that represents some form of failure. | 281 // that represents some form of failure. |
| 258 if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || | 282 if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || |
| 259 data[3] != 'c') { | 283 data[3] != 'c') { |
| 260 LOG(ERROR) << "Failure to download dictionary."; | 284 LOG(ERROR) << "Failure to download dictionary."; |
| 261 Initialize(); | 285 Initialize(); |
| 262 return; | 286 return; |
| 263 } | 287 } |
| 264 | 288 |
| 265 size_t bytes_written = | 289 size_t bytes_written = |
| 266 file_util::WriteFile(bdict_file_, data.data(), data.length()); | 290 file_util::WriteFile(bdict_file_path_, data.data(), data.length()); |
| 267 if (bytes_written != data.length()) { | 291 if (bytes_written != data.length()) { |
| 268 LOG(ERROR) << "Failure to save dictionary."; | 292 bool success = false; |
| 269 // To avoid trying to load a partially saved dictionary, shortcut the | 293 #if defined(OS_WIN) |
| 270 // Initialize() call. | 294 bdict_file_path_ = GetFallbackFilePath(bdict_file_path_); |
| 271 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, | 295 bytes_written = |
| 272 NewRunnableMethod(this, | 296 file_util::WriteFile(GetFallbackFilePath(bdict_file_path_), |
| 273 &SpellCheckHost::InformObserverOfInitialization)); | 297 data.data(), data.length()); |
| 274 return; | 298 if (bytes_written == data.length()) |
| 299 success = true; |
| 300 #endif |
| 301 |
| 302 if (!success) { |
| 303 LOG(ERROR) << "Failure to save dictionary."; |
| 304 // To avoid trying to load a partially saved dictionary, shortcut the |
| 305 // Initialize() call. |
| 306 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 307 NewRunnableMethod(this, |
| 308 &SpellCheckHost::InformObserverOfInitialization)); |
| 309 return; |
| 310 } |
| 275 } | 311 } |
| 276 | 312 |
| 277 Initialize(); | 313 Initialize(); |
| 278 } | 314 } |
| OLD | NEW |