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

Unified Diff: chrome/browser/spellcheck_host.cc

Issue 357003: Move the spellchecker to the renderer.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: rename Created 11 years, 1 month 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
Index: chrome/browser/spellcheck_host.cc
===================================================================
--- chrome/browser/spellcheck_host.cc (revision 0)
+++ chrome/browser/spellcheck_host.cc (revision 0)
@@ -0,0 +1,278 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/spellcheck_host.h"
+
+#include <fcntl.h>
+
+#include "app/l10n_util.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/notification_service.h"
+#include "googleurl/src/gurl.h"
+
+namespace {
+
+static const struct {
+ // The language.
+ const char* language;
+
+ // The corresponding language and region, used by the dictionaries.
+ const char* language_region;
+} g_supported_spellchecker_languages[] = {
+ // Several languages are not to be included in the spellchecker list:
+ // th-TH, hu-HU, bg-BG, uk-UA
+ {"ca", "ca-ES"},
+ {"cs", "cs-CZ"},
+ {"da", "da-DK"},
+ {"de", "de-DE"},
+ {"el", "el-GR"},
+ {"en-AU", "en-AU"},
+ {"en-GB", "en-GB"},
+ {"en-US", "en-US"},
+ {"es", "es-ES"},
+ {"et", "et-EE"},
+ {"fr", "fr-FR"},
+ {"he", "he-IL"},
+ {"hi", "hi-IN"},
+ {"hr", "hr-HR"},
+ {"id", "id-ID"},
+ {"it", "it-IT"},
+ {"lt", "lt-LT"},
+ {"lv", "lv-LV"},
+ {"nb", "nb-NO"},
+ {"nl", "nl-NL"},
+ {"pl", "pl-PL"},
+ {"pt-BR", "pt-BR"},
+ {"pt-PT", "pt-PT"},
+ {"ro", "ro-RO"},
+ {"ru", "ru-RU"},
+ {"sk", "sk-SK"},
+ {"sl", "sl-SI"},
+ {"sv", "sv-SE"},
+ {"tr", "tr-TR"},
+ {"vi", "vi-VN"},
+};
+
+// This function returns the language-region version of language name.
+// e.g. returns hi-IN for hi.
+std::string GetSpellCheckLanguageRegion(const std::string& input_language) {
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages);
+ ++i) {
+ if (g_supported_spellchecker_languages[i].language == input_language) {
+ return std::string(
+ g_supported_spellchecker_languages[i].language_region);
+ }
+ }
+
+ return input_language;
+}
+
+FilePath GetVersionedFileName(const std::string& input_language,
+ const FilePath& dict_dir) {
+ // The default dictionary version is 1-2. These versions have been augmented
+ // with additional words found by the translation team.
+ static const char kDefaultVersionString[] = "-1-2";
+
+ // The following dictionaries have either not been augmented with additional
+ // words (version 1-1) or have new words, as well as an upgraded dictionary
+ // as of Feb 2009 (version 1-3).
+ static const struct {
+ // The language input.
+ const char* language;
+
+ // The corresponding version.
+ const char* version;
+ } special_version_string[] = {
+ {"en-AU", "-1-1"},
+ {"en-GB", "-1-1"},
+ {"es-ES", "-1-1"},
+ {"nl-NL", "-1-1"},
+ {"ru-RU", "-1-1"},
+ {"sv-SE", "-1-1"},
+ {"he-IL", "-1-1"},
+ {"el-GR", "-1-1"},
+ {"hi-IN", "-1-1"},
+ {"tr-TR", "-1-1"},
+ {"et-EE", "-1-1"},
+ {"fr-FR", "-1-4"}, // To fix a crash, fr dictionary was updated to 1.4.
+ {"lt-LT", "-1-3"},
+ {"pl-PL", "-1-3"}
+ };
+
+ // Generate the bdict file name using default version string or special
+ // version string, depending on the language.
+ std::string language = GetSpellCheckLanguageRegion(input_language);
+ std::string versioned_bdict_file_name(language + kDefaultVersionString +
+ ".bdic");
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(special_version_string); ++i) {
+ if (language == special_version_string[i].language) {
+ versioned_bdict_file_name =
+ language + special_version_string[i].version + ".bdic";
+ break;
+ }
+ }
+
+ return dict_dir.AppendASCII(versioned_bdict_file_name);
+}
+
+} // namespace
+
+// Constructed on UI thread.
+SpellCheckHost::SpellCheckHost(Observer* observer,
+ const std::string& language,
+ URLRequestContextGetter* request_context_getter)
+ : observer_(observer),
+ language_(language),
+ tried_to_download_(false),
+ request_context_getter_(request_context_getter) {
+ DCHECK(observer_);
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ // TODO(estade): for Windows, we need to fall back to DIR_USER_DATA if
+ // DIR_APP_DICTIONARIES is not writeable.
+ FilePath dict_dir;
+ PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir);
+ bdict_file_ = GetVersionedFileName(language, dict_dir);
+
+ FilePath personal_file_directory;
+ PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory);
+ custom_dictionary_file_ =
+ personal_file_directory.Append(chrome::kCustomDictionaryFileName);
+
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &SpellCheckHost::Initialize));
+}
+
+SpellCheckHost::~SpellCheckHost() {
+ if (fd_.fd != -1)
+ close(fd_.fd);
+}
+
+void SpellCheckHost::UnsetObserver() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ observer_ = NULL;
+}
+
+void SpellCheckHost::AddWord(const std::string& word) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ custom_words_.push_back(word);
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(this,
+ &SpellCheckHost::WriteWordToCustomDictionary, word));
+ NotificationService::current()->Notify(
+ NotificationType::SPELLCHECK_WORD_ADDED,
+ Source<SpellCheckHost>(this), NotificationService::NoDetails());
+}
+
+void SpellCheckHost::Initialize() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
+ if (!observer_)
+ return;
+
+ // We set |auto_close| to false because we don't want IPC to close the fd.
+ // We will close it manually in the destructor.
+ fd_ = base::FileDescriptor(open(bdict_file_.value().c_str(), O_RDONLY),
+ false);
+
+ // File didn't exist. Download it.
+ if (fd_.fd == -1 && !tried_to_download_) {
+ DownloadDictionary();
+ return;
+ }
+
+ if (fd_.fd != -1) {
+ // Load custom dictionary.
+ std::string contents;
+ file_util::ReadFileToString(custom_dictionary_file_, &contents);
+ std::vector<std::string> list_of_words;
+ SplitString(contents, '\n', &list_of_words);
+ for (size_t i = 0; i < list_of_words.size(); ++i)
+ custom_words_.push_back(list_of_words[i]);
+ }
+
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &SpellCheckHost::InformObserverOfInitialization));
+}
+
+void SpellCheckHost::InformObserverOfInitialization() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ if (observer_)
+ observer_->SpellCheckHostInitialized();
+}
+
+void SpellCheckHost::DownloadDictionary() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
+ // 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(bdict_file_.BaseName().ToWStringHack())));
+ fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this));
+ fetcher_->set_request_context(request_context_getter_);
+ tried_to_download_ = true;
+ fetcher_->Start();
+}
+
+void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
+ // Stored in UTF-8.
+ std::string word_to_add(word + "\n");
+ FILE* f = file_util::OpenFile(custom_dictionary_file_, "a+");
+ if (f != NULL)
+ fputs(word_to_add.c_str(), f);
+ file_util::CloseFile(f);
+}
+
+void SpellCheckHost::OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ DCHECK(source);
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
+ if ((response_code / 100) != 2) {
+ // Initialize will not try to download the file a second time.
+ LOG(ERROR) << "Failure to download dictionary.";
+ Initialize();
+ return;
+ }
+
+ // Basic sanity check on the dictionary.
+ // There's the small chance that we might see a 200 status code for a body
+ // that represents some form of failure.
+ if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' ||
+ data[3] != 'c') {
+ LOG(ERROR) << "Failure to download dictionary.";
+ Initialize();
+ return;
+ }
+
+ size_t bytes_written =
+ file_util::WriteFile(bdict_file_, data.data(), data.length());
+ if (bytes_written != data.length()) {
+ LOG(ERROR) << "Failure to save dictionary.";
+ // To avoid trying to load a partially saved dictionary, shortcut the
+ // Initialize() call.
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &SpellCheckHost::InformObserverOfInitialization));
+ return;
+ }
+
+ Initialize();
+}
Property changes on: chrome/browser/spellcheck_host.cc
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698