summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorsidchat@google.com <sidchat@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-15 19:30:41 +0000
committersidchat@google.com <sidchat@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-15 19:30:41 +0000
commit209308572c06cc9d0a7c38e37928d6765ef9f4c7 (patch)
tree294a02a68af2475e624e7a8490525c7198ac521f /chrome
parentece541a4d861b2fd0d83ea32dec75d233e217d5c (diff)
downloadchromium_src-209308572c06cc9d0a7c38e37928d6765ef9f4c7.zip
chromium_src-209308572c06cc9d0a7c38e37928d6765ef9f4c7.tar.gz
chromium_src-209308572c06cc9d0a7c38e37928d6765ef9f4c7.tar.bz2
Change SpellChecker language without restarting the browser.
Review URL: http://codereview.chromium.org/7056 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3407 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/profile.cc89
-rw-r--r--chrome/browser/profile.h18
-rw-r--r--chrome/browser/resource_message_filter.cc22
-rw-r--r--chrome/browser/resource_message_filter.h14
-rw-r--r--chrome/browser/views/options/languages_page_view.cc21
-rw-r--r--chrome/browser/views/options/languages_page_view.h4
-rw-r--r--chrome/common/notification_types.h5
-rw-r--r--chrome/test/testing_profile.h2
8 files changed, 150 insertions, 25 deletions
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index ad2ddb1..bf40016 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -479,6 +479,10 @@ class OffTheRecordProfileImpl : public Profile,
return NULL;
}
+ virtual void InitializeSpellChecker() {
+ profile_->InitializeSpellChecker();
+ }
+
virtual void ResetTabRestoreService() {
}
@@ -837,24 +841,79 @@ void ProfileImpl::ResetTabRestoreService() {
tab_restore_service_.reset(NULL);
}
+// To be run in the IO thread to notify all resource message filters that the
+// spellchecker has changed.
+class NotifySpellcheckerChangeTask : public Task {
+ public:
+ NotifySpellcheckerChangeTask(
+ Profile* profile, const SpellcheckerReinitializedDetails& spellchecker)
+ : profile_(profile),
+ spellchecker_(spellchecker) {
+ }
+
+ private:
+ void Run(void) {
+ NotificationService::current()->Notify(
+ NOTIFY_SPELLCHECKER_REINITIALIZED,
+ Source<Profile>(profile_),
+ Details<SpellcheckerReinitializedDetails>(&spellchecker_));
+ }
+
+ Profile* profile_;
+ SpellcheckerReinitializedDetails spellchecker_;
+};
+
+void ProfileImpl::InitializeSpellChecker() {
+ bool need_to_broadcast = false;
+
+ // The I/O thread may be NULL during testing.
+ base::Thread* io_thread = g_browser_process->io_thread();
+ if (spellchecker_) {
+ // The spellchecker must be deleted on the I/O thread.
+ // A dummy variable to aid in logical clarity.
+ SpellChecker* last_spellchecker = spellchecker_;
+
+ if (io_thread)
+ io_thread->message_loop()->ReleaseSoon(FROM_HERE, last_spellchecker);
+ else // during testing, we don't have an I/O thread
+ last_spellchecker->Release();
+
+ need_to_broadcast = true;
+ }
+
+ std::wstring dict_dir;
+ PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir);
+
+ // Retrieve the (perhaps updated recently) dictionary name from preferences.
+ PrefService* prefs = GetPrefs();
+ std::wstring language = prefs->GetString(prefs::kSpellCheckDictionary);
+
+ // Note that, as the object pointed to by previously by spellchecker_
+ // is being deleted in the io thread, the spellchecker_ can be made to point
+ // to a new object (RE-initialized) in parallel in this UI thread.
+ spellchecker_ = new SpellChecker(dict_dir, language, GetRequestContext(),
+ L"");
+ spellchecker_->AddRef(); // Manual refcounting.
+
+ if (need_to_broadcast && io_thread) { // Notify resource message filters.
+ SpellcheckerReinitializedDetails scoped_spellchecker;
+ scoped_spellchecker.spellchecker = spellchecker_;
+ io_thread->message_loop()->PostTask(
+ FROM_HERE,
+ new NotifySpellcheckerChangeTask(this, scoped_spellchecker));
+ }
+}
+
SpellChecker* ProfileImpl::GetSpellChecker() {
if (!spellchecker_) {
- // Don't check for an error here. In the extremely unlikely case that this
- // fails, the spellchecker just won't find the file. This prevents callers
- // from having to check for NULL return values from this function.
- std::wstring dict_dir;
- PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir);
-
- // Retrieve the dictionary name from preferences or the language DLL.
- // When we retrieve it from the language DLL.
- PrefService* prefs = GetPrefs();
- std::wstring dictionary_name = prefs->GetString(
- prefs::kSpellCheckDictionary);
-
- spellchecker_ = new SpellChecker(dict_dir, dictionary_name,
- GetRequestContext(), L"");
- spellchecker_->AddRef(); // Manual refcounting.
+ // This is where spellchecker gets initialized. Note that this is being
+ // initialized in the ui_thread. However, this is not a problem as long as
+ // it is *used* in the io thread.
+ // TODO (sidchat) One day, change everything so that spellchecker gets
+ // initialized in the IO thread itself.
+ InitializeSpellChecker();
}
+
return spellchecker_;
}
diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h
index 09b0baf..2edc40c 100644
--- a/chrome/browser/profile.h
+++ b/chrome/browser/profile.h
@@ -194,6 +194,13 @@ class Profile {
virtual void ResetTabRestoreService() = 0;
+ // Initializes the spellchecker. If the spellchecker already exsts, then
+ // it is released, and initialized again. This model makes sure that
+ // spellchecker language can be changed without restarting the browser.
+ // NOTE: This is being currently called in the UI thread, which is OK as long
+ // as the spellchecker object is USED in the IO thread.
+ virtual void InitializeSpellChecker() = 0;
+
// Returns the spell checker object for this profile. THIS OBJECT MUST ONLY
// BE USED ON THE I/O THREAD! This pointer is retrieved from the profile and
// sent to the I/O thread where it is actually used.
@@ -203,8 +210,7 @@ class Profile {
//
// NOTE: this is invoked internally on a normal shutdown, but is public so
// that it can be invoked when the user logs out/powers down (WM_ENDSESSION).
- virtual void MarkAsCleanShutdown() = 0;
-
+ virtual void MarkAsCleanShutdown() = 0;
#ifdef UNIT_TEST
// Use with caution. GetDefaultRequestContext may be called on any thread!
static void set_default_request_context(URLRequestContext* c) {
@@ -250,6 +256,7 @@ class ProfileImpl : public Profile {
virtual Time GetStartTime() const;
virtual TabRestoreService* GetTabRestoreService();
virtual void ResetTabRestoreService();
+ virtual void InitializeSpellChecker();
virtual SpellChecker* GetSpellChecker();
virtual void MarkAsCleanShutdown();
#ifdef CHROME_PERSONALIZATION
@@ -316,5 +323,12 @@ class ProfileImpl : public Profile {
DISALLOW_EVIL_CONSTRUCTORS(ProfileImpl);
};
+// This struct is used to pass the spellchecker object through the notification
+// NOTIFY_SPELLCHECKER_REINITIALIZED. This is used as the details for the
+// notification service.
+struct SpellcheckerReinitializedDetails {
+ scoped_refptr<SpellChecker> spellchecker;
+};
+
#endif // CHROME_BROWSER_PROFILE_H__
diff --git a/chrome/browser/resource_message_filter.cc b/chrome/browser/resource_message_filter.cc
index 4821cfd..5afe628 100644
--- a/chrome/browser/resource_message_filter.cc
+++ b/chrome/browser/resource_message_filter.cc
@@ -91,6 +91,7 @@ ResourceMessageFilter::ResourceMessageFilter(
render_process_host_id_(render_process_host_id),
render_handle_(NULL),
request_context_(profile->GetRequestContext()),
+ profile_(profile),
render_widget_helper_(render_widget_helper),
spellchecker_(spellchecker) {
@@ -101,11 +102,23 @@ ResourceMessageFilter::ResourceMessageFilter(
ResourceMessageFilter::~ResourceMessageFilter() {
if (render_handle_)
CloseHandle(render_handle_);
+
+ // This function should be called on the IO thread.
+ DCHECK(MessageLoop::current() ==
+ ChromeThread::GetMessageLoop(ChromeThread::IO));
+ NotificationService::current()->RemoveObserver(
+ this, NOTIFY_SPELLCHECKER_REINITIALIZED,
+ Source<Profile>(profile_));
}
// Called on the IPC thread:
void ResourceMessageFilter::OnFilterAdded(IPC::Channel* channel) {
channel_ = channel;
+
+ // Add the observers to intercept
+ NotificationService::current()->AddObserver(
+ this, NOTIFY_SPELLCHECKER_REINITIALIZED,
+ Source<Profile>(profile_));
}
// Called on the IPC thread:
@@ -738,6 +751,15 @@ void ResourceMessageFilter::OnSpellCheck(const std::wstring& word,
}
}
+void ResourceMessageFilter::Observe(NotificationType type,
+ const NotificationSource &source,
+ const NotificationDetails &details) {
+ if (type == NOTIFY_SPELLCHECKER_REINITIALIZED) {
+ spellchecker_ = Details<SpellcheckerReinitializedDetails>
+ (details).ptr()->spellchecker;
+ }
+}
+
void ResourceMessageFilter::OnDnsPrefetch(
const std::vector<std::string>& hostnames) {
chrome_browser_net::DnsPrefetchList(hostnames);
diff --git a/chrome/browser/resource_message_filter.h b/chrome/browser/resource_message_filter.h
index a83a0e9..aee07c1 100644
--- a/chrome/browser/resource_message_filter.h
+++ b/chrome/browser/resource_message_filter.h
@@ -9,6 +9,7 @@
#include "base/ref_counted.h"
#include "chrome/browser/resource_dispatcher_host.h"
#include "chrome/common/ipc_channel_proxy.h"
+#include "chrome/common/notification_service.h"
#include "webkit/glue/cache_manager.h"
class ClipboardService;
@@ -29,12 +30,13 @@ class PrintJobManager;
// will not interfere with browser UI.
class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
- public ResourceDispatcherHost::Receiver {
+ public ResourceDispatcherHost::Receiver,
+ public NotificationObserver {
public:
// Create the filter.
// Note: because the lifecycle of the ResourceMessageFilter is not
// tied to the lifecycle of the object which created it, the
- // ResourceMessageFilter is 'given' ownership of the spellcker
+ // ResourceMessageFilter is 'given' ownership of the spellchecker
// object and must clean it up on exit.
ResourceMessageFilter(ResourceDispatcherHost* resource_dispatcher_host,
PluginService* plugin_service,
@@ -60,6 +62,11 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
int render_process_host_id() const { return render_process_host_id_;}
HANDLE renderer_handle() const { return render_handle_;}
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
private:
void OnMsgCreateView(int opener_id, bool user_gesture, int* route_id,
@@ -176,6 +183,9 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
// Contextual information to be used for requests created here.
scoped_refptr<URLRequestContext> request_context_;
+ // Save the profile pointer so that notification observer can be added.
+ Profile* profile_;
+
scoped_refptr<RenderWidgetHelper> render_widget_helper_;
};
diff --git a/chrome/browser/views/options/languages_page_view.cc b/chrome/browser/views/options/languages_page_view.cc
index 465a2fa..9a22c74 100644
--- a/chrome/browser/views/options/languages_page_view.cc
+++ b/chrome/browser/views/options/languages_page_view.cc
@@ -681,6 +681,7 @@ void LanguagesPageView::NotifyPrefChanged(const std::wstring* pref_name) {
int index = dictionary_language_model_->GetSelectedLanguageIndex(
prefs::kSpellCheckDictionary);
change_dictionary_language_combobox_->SetSelectedItem(index);
+ spellcheck_language_index_selected_ = -1;
}
}
@@ -693,11 +694,8 @@ void LanguagesPageView::ItemChanged(ChromeViews::ComboBox* sender,
app_locale_.SetValue(ui_language_model_->GetLocaleFromIndex(new_index));
RestartMessageBox::ShowMessageBox(GetRootWindow());
} else if (sender == change_dictionary_language_combobox_) {
- UserMetricsRecordAction(L"Options_DictionaryLanguage",
- profile()->GetPrefs());
- dictionary_language_.SetValue(dictionary_language_model_->
- GetLocaleFromIndex(new_index));
- RestartMessageBox::ShowMessageBox(GetRootWindow());
+ if (new_index != prev_index)
+ spellcheck_language_index_selected_ = new_index;
}
}
@@ -750,5 +748,16 @@ void LanguagesPageView::OnMoveUpLanguage() {
void LanguagesPageView::SaveChanges() {
if (language_order_table_model_.get() && language_table_edited_)
accept_languages_.SetValue(language_order_table_model_->GetLanguageList());
-}
+ if (spellcheck_language_index_selected_ != -1) {
+ UserMetricsRecordAction(L"Options_DictionaryLanguage",
+ profile()->GetPrefs());
+ dictionary_language_.SetValue(dictionary_language_model_->
+ GetLocaleFromIndex(spellcheck_language_index_selected_));
+
+ // Initialize spellchecker. Keeping with the tradition, spellchecker is
+ // being initialized in this UI thread. However, it must be USED in the IO
+ // thread.
+ profile()->InitializeSpellChecker();
+ }
+}
diff --git a/chrome/browser/views/options/languages_page_view.h b/chrome/browser/views/options/languages_page_view.h
index 41c362f..fc7d0b0 100644
--- a/chrome/browser/views/options/languages_page_view.h
+++ b/chrome/browser/views/options/languages_page_view.h
@@ -89,6 +89,10 @@ class LanguagesPageView : public OptionsPageView,
// The contents of the "dictionary language" combobox.
scoped_ptr<LanguageComboboxModel> dictionary_language_model_;
StringPrefMember dictionary_language_;
+
+ // This is assigned the new index of spellcheck language if the language
+ // is changed. Otherwise, it remains -1, and pref members are not updated.
+ int spellcheck_language_index_selected_;
bool language_table_edited_;
diff --git a/chrome/common/notification_types.h b/chrome/common/notification_types.h
index 4340c9b..29ba6e1 100644
--- a/chrome/common/notification_types.h
+++ b/chrome/common/notification_types.h
@@ -397,6 +397,11 @@ enum NotificationType {
// Profile, and the details aren't used.
NOTIFY_BOOKMARK_MODEL_LOADED,
+ // Sent when the spellchecker object changes. Note that this is not sent the
+ // first time the spellchecker gets initialized. The source is the profile,
+ // the details is SpellcheckerReinitializedDetails defined in profile.
+ NOTIFY_SPELLCHECKER_REINITIALIZED,
+
// Sent when the bookmark bubble is shown for a particular URL. The source
// is the profile, the details the URL.
NOTIFY_BOOKMARK_BUBBLE_SHOWN,
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index c68e9fcb..892d357 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -140,6 +140,8 @@ class TestingProfile : public Profile {
}
virtual void ResetTabRestoreService() {
}
+ virtual void InitializeSpellChecker() {
+ }
virtual SpellChecker* GetSpellChecker() {
return NULL;
}