diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-19 22:44:29 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-19 22:44:29 +0000 |
commit | c27324bdb7b9ee448a0c73d5c005c709282c8cbc (patch) | |
tree | d7ec31ab43e6493ef3f00eb81faeca0c79a793c3 /chrome | |
parent | 5ef3748a651d073bf12928e880a042bf450e1aa8 (diff) | |
download | chromium_src-c27324bdb7b9ee448a0c73d5c005c709282c8cbc.zip chromium_src-c27324bdb7b9ee448a0c73d5c005c709282c8cbc.tar.gz chromium_src-c27324bdb7b9ee448a0c73d5c005c709282c8cbc.tar.bz2 |
Move Mac to using renderer spellchecker.
BUG=25677
Review URL: http://codereview.chromium.org/395007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@32561 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
37 files changed, 845 insertions, 2633 deletions
diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc index b166f1c..4399923 100644 --- a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc +++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc @@ -196,6 +196,8 @@ class BrowserActionButton : public NotificationObserver, GdkPixbuf* default_icon_; NotificationRegistrar registrar_; + + friend class BrowserActionsToolbarGtk; }; BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser) diff --git a/chrome/browser/gtk/options/languages_page_gtk.cc b/chrome/browser/gtk/options/languages_page_gtk.cc index 0cd30d0..3af1834 100644 --- a/chrome/browser/gtk/options/languages_page_gtk.cc +++ b/chrome/browser/gtk/options/languages_page_gtk.cc @@ -13,10 +13,10 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/language_combobox_model.h" #include "chrome/browser/language_order_table_model.h" -#include "chrome/browser/spellchecker.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/gtk_util.h" #include "chrome/common/pref_names.h" +#include "chrome/common/spellcheck_common.h" #include "grit/generated_resources.h" namespace { @@ -246,7 +246,7 @@ void LanguagesPageGtk::Init() { } std::vector<std::string> spell_check_languages; - SpellChecker::SpellCheckLanguages(&spell_check_languages); + SpellCheckCommon::SpellCheckLanguages(&spell_check_languages); dictionary_language_model_.reset(new LanguageComboboxModel(profile(), spell_check_languages)); dictionary_language_combobox_ = NewComboboxFromModel( @@ -330,7 +330,7 @@ void LanguagesPageGtk::NotifyPrefChanged(const std::wstring* pref_name) { const std::string& lang_region = WideToASCII( dictionary_language_.GetValue()); dictionary_language_.SetValue(ASCIIToWide( - SpellChecker::GetLanguageFromLanguageRegion(lang_region))); + SpellCheckCommon::GetLanguageFromLanguageRegion(lang_region))); index = dictionary_language_model_->GetSelectedLanguageIndex( prefs::kSpellCheckDictionary); } diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index eb998ba..fea876b 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -39,7 +39,6 @@ #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/sessions/session_service.h" #include "chrome/browser/sessions/tab_restore_service.h" -#include "chrome/browser/spellchecker.h" #include "chrome/browser/ssl/ssl_host_state.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/thumbnail_store.h" @@ -472,19 +471,6 @@ class OffTheRecordProfileImpl : public Profile, virtual void ResetTabRestoreService() { } - virtual void ReinitializeSpellChecker() { - profile_->ReinitializeSpellChecker(); - } - - virtual SpellChecker* GetSpellChecker() { - return profile_->GetSpellChecker(); - } - - virtual void DeleteSpellChecker() { - profile_->DeleteSpellChecker(); - } - -#if defined(SPELLCHECKER_IN_RENDERER) virtual SpellCheckHost* GetSpellCheckHost() { return profile_->GetSpellCheckHost(); } @@ -492,14 +478,13 @@ class OffTheRecordProfileImpl : public Profile, virtual void ReinitializeSpellCheckHost(bool force) { profile_->ReinitializeSpellCheckHost(force); } -#endif virtual WebKitContext* GetWebKitContext() { - if (!webkit_context_.get()) - webkit_context_ = new WebKitContext(GetPath(), true); - DCHECK(webkit_context_.get()); - return webkit_context_.get(); -} + if (!webkit_context_.get()) + webkit_context_ = new WebKitContext(GetPath(), true); + DCHECK(webkit_context_.get()); + return webkit_context_.get(); + } virtual ThumbnailStore* GetThumbnailStore() { return NULL; @@ -593,7 +578,6 @@ ProfileImpl::ProfileImpl(const FilePath& path) created_download_manager_(false), created_theme_provider_(false), start_time_(Time::Now()), - spellchecker_(NULL), #if defined(OS_LINUX) spellcheck_host_(NULL), spellcheck_host_ready_(false), @@ -778,11 +762,8 @@ ProfileImpl::~ProfileImpl() { if (history_service_.get()) history_service_->Cleanup(); -#if defined(SPELLCHECKER_IN_RENDERER) if (spellcheck_host_.get()) spellcheck_host_->UnsetObserver(); -#endif - DeleteSpellCheckerImpl(false); if (default_request_context_ == request_context_) default_request_context_ = NULL; @@ -1258,57 +1239,6 @@ void ProfileImpl::ResetTabRestoreService() { tab_restore_service_ = 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( - NotificationType::SPELLCHECKER_REINITIALIZED, - Source<Profile>(profile_), - Details<SpellcheckerReinitializedDetails>(&spellchecker_)); - } - - Profile* profile_; - SpellcheckerReinitializedDetails spellchecker_; -}; - -void ProfileImpl::ReinitializeSpellChecker() { - PrefService* prefs = GetPrefs(); - if (prefs->GetBoolean(prefs::kEnableSpellCheck)) { - DeleteSpellCheckerImpl(false); - - // Retrieve the (perhaps updated recently) dictionary name from preferences. - FilePath dict_dir; - PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); - // 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, - WideToASCII(prefs->GetString(prefs::kSpellCheckDictionary)), - GetRequestContext(), - FilePath()); - spellchecker_->AddRef(); // Manual refcounting. - - // Set auto spell correct status for spellchecker. - spellchecker_->EnableAutoSpellCorrect( - prefs->GetBoolean(prefs::kEnableAutoSpellCorrect)); - - NotifySpellCheckerChanged(); - } else { - DeleteSpellCheckerImpl(true); - } -} - -#if defined(SPELLCHECKER_IN_RENDERER) SpellCheckHost* ProfileImpl::GetSpellCheckHost() { return spellcheck_host_ready_ ? spellcheck_host_.get() : NULL; } @@ -1343,45 +1273,12 @@ void ProfileImpl::ReinitializeSpellCheckHost(bool force) { void ProfileImpl::SpellCheckHostInitialized() { spellcheck_host_ready_ = spellcheck_host_ && - spellcheck_host_->bdict_file() != base::kInvalidPlatformFileValue; + (spellcheck_host_->bdict_file() != base::kInvalidPlatformFileValue || + spellcheck_host_->use_platform_spellchecker()); NotificationService::current()->Notify( NotificationType::SPELLCHECK_HOST_REINITIALIZED, Source<Profile>(this), NotificationService::NoDetails()); } -#endif - -void ProfileImpl::NotifySpellCheckerChanged() { - SpellcheckerReinitializedDetails scoped_spellchecker; - scoped_spellchecker.spellchecker = spellchecker_; - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - new NotifySpellcheckerChangeTask(this, scoped_spellchecker)); -} - -void ProfileImpl::DeleteSpellCheckerImpl(bool notify) { - if (!spellchecker_) - return; - - // The spellchecker must be deleted on the I/O thread. - ChromeThread::ReleaseSoon(ChromeThread::IO, FROM_HERE, spellchecker_); - spellchecker_ = NULL; - - if (notify) - NotifySpellCheckerChanged(); -} - -SpellChecker* ProfileImpl::GetSpellChecker() { - if (!spellchecker_) { - // 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. - ReinitializeSpellChecker(); - } - - return spellchecker_; -} WebKitContext* ProfileImpl::GetWebKitContext() { if (!webkit_context_.get()) @@ -1418,14 +1315,12 @@ void ProfileImpl::Observe(NotificationType type, PrefService* prefs = Source<PrefService>(source).ptr(); DCHECK(pref_name_in && prefs); if (*pref_name_in == prefs::kSpellCheckDictionary || -#if !defined(SPELLCHECKER_IN_RENDERER) - *pref_name_in == prefs::kEnableAutoSpellCorrect || -#endif *pref_name_in == prefs::kEnableSpellCheck) { - ReinitializeSpellChecker(); -#if defined(SPELLCHECKER_IN_RENDERER) ReinitializeSpellCheckHost(true); -#endif + } else if (*pref_name_in == prefs::kEnableAutoSpellCorrect) { + NotificationService::current()->Notify( + NotificationType::SPELLCHECK_AUTOSPELL_TOGGLED, + Source<Profile>(this), NotificationService::NoDetails()); } } else if (NotificationType::THEME_INSTALLED == type) { Extension* extension = Details<Extension>(details).ptr(); diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index b8cec92..c931f31 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -14,9 +14,7 @@ #include "base/file_path.h" #include "base/scoped_ptr.h" #include "base/timer.h" -#if defined(SPELLCHECKER_IN_RENDERER) #include "chrome/browser/spellcheck_host.h" -#endif #include "chrome/browser/web_resource/web_resource_service.h" #include "chrome/common/notification_registrar.h" @@ -54,7 +52,6 @@ class PrefService; class ProfileSyncService; class SearchVersusNavigateClassifier; class SessionService; -class SpellChecker; class SSLConfigServiceManager; class SSLHostState; class StrictTransportSecurityPersister; @@ -342,21 +339,6 @@ class Profile { virtual void ResetTabRestoreService() = 0; - // This reinitializes the spellchecker according to the current dictionary - // language, and enable spell check option, in the prefs. Then a - // SPELLCHECKER_REINITIALIZED notification is sent on the IO thread. - virtual void ReinitializeSpellChecker() = 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. - virtual SpellChecker* GetSpellChecker() = 0; - - // Deletes the spellchecker. This is only really useful when we need to purge - // memory. - virtual void DeleteSpellChecker() = 0; - -#if defined(SPELLCHECKER_IN_RENDERER) // May return NULL. virtual SpellCheckHost* GetSpellCheckHost() = 0; @@ -364,7 +346,6 @@ class Profile { // the process of initializing), then do nothing. Otherwise clobber the // current spellchecker and replace it with a new one. virtual void ReinitializeSpellCheckHost(bool force) = 0; -#endif // Returns the WebKitContext assigned to this profile. virtual WebKitContext* GetWebKitContext() = 0; @@ -412,9 +393,7 @@ class OffTheRecordProfileImpl; // The default profile implementation. class ProfileImpl : public Profile, -#if defined(SPELLCHECKER_IN_RENDERER) public SpellCheckHost::Observer, -#endif public NotificationObserver { public: virtual ~ProfileImpl(); @@ -473,13 +452,8 @@ class ProfileImpl : public Profile, virtual base::Time GetStartTime() const; virtual TabRestoreService* GetTabRestoreService(); virtual void ResetTabRestoreService(); - virtual void ReinitializeSpellChecker(); - virtual SpellChecker* GetSpellChecker(); - virtual void DeleteSpellChecker() { DeleteSpellCheckerImpl(true); } -#if defined(SPELLCHECKER_IN_RENDERER) virtual SpellCheckHost* GetSpellCheckHost(); virtual void ReinitializeSpellCheckHost(bool force); -#endif virtual WebKitContext* GetWebKitContext(); virtual DesktopNotificationService* GetDesktopNotificationService(); virtual void MarkAsCleanShutdown(); @@ -494,10 +468,8 @@ class ProfileImpl : public Profile, const NotificationSource& source, const NotificationDetails& details); -#if defined(SPELLCHECKER_IN_RENDERER) // SpellCheckHost::Observer implementation. virtual void SpellCheckHostInitialized(); -#endif private: friend class Profile; @@ -519,9 +491,6 @@ class ProfileImpl : public Profile, GetSessionService(); } - void NotifySpellCheckerChanged(); - void DeleteSpellCheckerImpl(bool notify); - NotificationRegistrar registrar_; FilePath path_; @@ -587,17 +556,11 @@ class ProfileImpl : public Profile, scoped_refptr<TabRestoreService> tab_restore_service_; - // This can not be a scoped_refptr because we must release it on the I/O - // thread. - SpellChecker* spellchecker_; - -#if defined(SPELLCHECKER_IN_RENDERER) scoped_refptr<SpellCheckHost> spellcheck_host_; // Indicates whether |spellcheck_host_| has told us initialization is // finished. bool spellcheck_host_ready_; -#endif // Set to true when ShutdownSessionService is invoked. If true // GetSessionService won't recreate the SessionService. @@ -614,11 +577,4 @@ class ProfileImpl : public Profile, DISALLOW_COPY_AND_ASSIGN(ProfileImpl); }; -// This struct is used to pass the spellchecker object through the notification -// 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/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index 1f630af..e9bfedb 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -40,16 +40,15 @@ #include "chrome/browser/renderer_host/render_widget_host.h" #include "chrome/browser/renderer_host/resource_message_filter.h" #include "chrome/browser/renderer_host/web_cache_manager.h" -#if defined(SPELLCHECKER_IN_RENDERER) #include "chrome/browser/spellcheck_host.h" -#endif -#include "chrome/browser/spellchecker.h" #include "chrome/browser/visitedlink_master.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/child_process_info.h" #include "chrome/common/child_process_host.h" #include "chrome/common/logging_chrome.h" #include "chrome/common/notification_service.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/process_watcher.h" #include "chrome/common/render_messages.h" #include "chrome/common/result_codes.h" #include "chrome/renderer/render_process.h" @@ -199,15 +198,12 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile) registrar_.Add(this, NotificationType::USER_SCRIPTS_UPDATED, NotificationService::AllSources()); -#if defined(SPELLCHECKER_IN_RENDERER) registrar_.Add(this, NotificationType::SPELLCHECK_HOST_REINITIALIZED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::SPELLCHECK_WORD_ADDED, NotificationService::AllSources()); - - PrefService* prefs = profile->GetPrefs(); - prefs->AddPrefObserver(prefs::kEnableAutoSpellCorrect, this); -#endif + registrar_.Add(this, NotificationType::SPELLCHECK_AUTOSPELL_TOGGLED, + NotificationService::AllSources()); visited_link_updater_.reset(new VisitedLinkUpdater()); @@ -221,11 +217,6 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile) } BrowserRenderProcessHost::~BrowserRenderProcessHost() { -#if defined(SPELLCHECKER_IN_RENDERER) - PrefService* prefs = profile()->GetPrefs(); - prefs->RemovePrefObserver(prefs::kEnableAutoSpellCorrect, this); -#endif - WebCacheManager::GetInstance()->Remove(id()); ChildProcessSecurityPolicy::GetInstance()->Remove(id()); @@ -277,7 +268,6 @@ bool BrowserRenderProcessHost::Init(bool is_extensions_process, g_browser_process->print_job_manager(), profile(), widget_helper_, - profile()->GetSpellChecker(), request_context); // Find the renderer before creating the channel so if this fails early we @@ -394,15 +384,6 @@ void BrowserRenderProcessHost::WidgetHidden() { } } -void BrowserRenderProcessHost::AddWord(const string16& word) { - SpellChecker* spellchecker = profile()->GetSpellChecker(); - if (spellchecker) { - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod(spellchecker, &SpellChecker::AddWord, word)); - } -} - void BrowserRenderProcessHost::SendVisitedLinkTable( base::SharedMemory* table_memory) { // Check if the process is still starting and we don't have a handle for it @@ -762,10 +743,8 @@ void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) { OnExtensionRemoveListener) IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionCloseChannel, OnExtensionCloseChannel) -#if defined(SPELLCHECKER_IN_RENDERER) IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_RequestDictionary, OnSpellCheckerRequestDictionary) -#endif IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP_EX() @@ -900,7 +879,6 @@ void BrowserRenderProcessHost::Observe(NotificationType type, } break; } -#if defined(SPELLCHECKER_IN_RENDERER) case NotificationType::SPELLCHECK_HOST_REINITIALIZED: { InitSpellChecker(); break; @@ -911,18 +889,12 @@ void BrowserRenderProcessHost::Observe(NotificationType type, ptr()->last_added_word()); break; } - case NotificationType::PREF_CHANGED: { - std::wstring* pref_name_in = Details<std::wstring>(details).ptr(); - PrefService* prefs = Source<PrefService>(source).ptr(); - DCHECK(pref_name_in && prefs); - if (*pref_name_in == prefs::kEnableAutoSpellCorrect) { - EnableAutoSpellCorrect( - prefs->GetBoolean(prefs::kEnableAutoSpellCorrect)); - break; - } - // Fall through. + case NotificationType::SPELLCHECK_AUTOSPELL_TOGGLED: { + PrefService* prefs = profile()->GetPrefs(); + EnableAutoSpellCorrect( + prefs->GetBoolean(prefs::kEnableAutoSpellCorrect)); + break; } -#endif default: { NOTREACHED(); break; @@ -937,14 +909,12 @@ void BrowserRenderProcessHost::OnProcessLaunched() { InitVisitedLinks(); InitUserScripts(); InitExtensions(); -#if defined(SPELLCHECKER_IN_RENDERER) // We don't want to initialize the spellchecker unless SpellCheckHost has been // created. In InitSpellChecker(), we know if GetSpellCheckHost() is NULL // then the spellchecker has been turned off, but here, we don't know if // it's been turned off or just not loaded yet. if (profile()->GetSpellCheckHost()) InitSpellChecker(); -#endif if (max_page_id_ != -1) Send(new ViewMsg_SetNextPageID(max_page_id_ + 1)); @@ -981,7 +951,6 @@ void BrowserRenderProcessHost::OnExtensionCloseChannel(int port_id) { } } -#if defined(SPELLCHECKER_IN_RENDERER) void BrowserRenderProcessHost::OnSpellCheckerRequestDictionary() { // We may have gotten multiple requests from different renderers. We don't // want to initialize multiple times in this case, so we set |force| to false. @@ -997,12 +966,16 @@ void BrowserRenderProcessHost::InitSpellChecker() { if (spellcheck_host) { PrefService* prefs = profile()->GetPrefs(); IPC::PlatformFileForTransit file; + + if (spellcheck_host->bdict_file() != base::kInvalidPlatformFileValue) { #if defined(OS_POSIX) - file = base::FileDescriptor(spellcheck_host->bdict_file(), false); + file = base::FileDescriptor(spellcheck_host->bdict_file(), false); #elif defined(OS_WIN) - ::DuplicateHandle(::GetCurrentProcess(), spellcheck_host->bdict_file(), - GetHandle(), &file, 0, false, DUPLICATE_SAME_ACCESS); + ::DuplicateHandle(::GetCurrentProcess(), spellcheck_host->bdict_file(), + GetHandle(), &file, 0, false, DUPLICATE_SAME_ACCESS); #endif + } + Send(new ViewMsg_SpellChecker_Init( file, spellcheck_host->custom_words(), @@ -1020,4 +993,3 @@ void BrowserRenderProcessHost::InitSpellChecker() { void BrowserRenderProcessHost::EnableAutoSpellCorrect(bool enable) { Send(new ViewMsg_SpellChecker_EnableAutoSpellCorrect(enable)); } -#endif diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h index 4ab6c73..fae3145 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.h +++ b/chrome/browser/renderer_host/browser_render_process_host.h @@ -70,7 +70,6 @@ class BrowserRenderProcessHost : public RenderProcessHost, virtual void WidgetRestored(); virtual void WidgetHidden(); virtual void ViewCreated(); - virtual void AddWord(const string16& word); virtual void SendVisitedLinkTable(base::SharedMemory* table_memory); virtual void AddVisitedLinks(const VisitedLinkCommon::Fingerprints& links); virtual void ResetVisitedLinks(); @@ -142,7 +141,6 @@ class BrowserRenderProcessHost : public RenderProcessHost, // Returns true if the priority is backgrounded; false otherwise. void SetBackgrounded(bool boost); -#if defined(SPELLCHECKER_IN_RENDERER) // The renderer has requested that we initialize its spellchecker. This should // generally only be called once per session, as after the first call, all // future renderers will be passed the initialization information on startup @@ -159,7 +157,6 @@ class BrowserRenderProcessHost : public RenderProcessHost, // Tell the renderer that auto spell correction has been enabled/disabled. void EnableAutoSpellCorrect(bool enable); -#endif NotificationRegistrar registrar_; diff --git a/chrome/browser/renderer_host/render_process_host.h b/chrome/browser/renderer_host/render_process_host.h index 0914a52..0edf46c 100644 --- a/chrome/browser/renderer_host/render_process_host.h +++ b/chrome/browser/renderer_host/render_process_host.h @@ -173,9 +173,6 @@ class RenderProcessHost : public IPC::Channel::Sender, // Called when RenderView is created by a listener. virtual void ViewCreated() = 0; - // Add a word in the spellchecker. - virtual void AddWord(const string16& word) = 0; - // Informs the renderer about a new visited link table. virtual void SendVisitedLinkTable(base::SharedMemory* table_memory) = 0; diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 6b3307c..b414aea 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -542,10 +542,6 @@ void RenderViewHost::ToggleSpellCheck() { Send(new ViewMsg_ToggleSpellCheck(routing_id())); } -void RenderViewHost::AddToDictionary(const string16& word) { - process()->AddWord(word); -} - void RenderViewHost::Delete() { Send(new ViewMsg_Delete(routing_id())); } diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index 4b03af0..4aae99b 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -277,7 +277,6 @@ class RenderViewHost : public RenderWidgetHost, void CopyToFindPboard(); void Paste(); void ToggleSpellCheck(); - void AddToDictionary(const string16& word); void Delete(); void SelectAll(); void ToggleSpellPanel(bool is_currently_visible); diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 93ee409..b03118d 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -31,7 +31,6 @@ #include "chrome/browser/renderer_host/database_dispatcher_host.h" #include "chrome/browser/renderer_host/render_widget_helper.h" #include "chrome/browser/renderer_host/socket_stream_dispatcher_host.h" -#include "chrome/browser/spellchecker.h" #include "chrome/browser/spellchecker_platform_engine.h" #include "chrome/browser/task_manager.h" #include "chrome/browser/worker_host/message_port_dispatcher.h" @@ -150,14 +149,12 @@ ResourceMessageFilter::ResourceMessageFilter( printing::PrintJobManager* print_job_manager, Profile* profile, RenderWidgetHelper* render_widget_helper, - SpellChecker* spellchecker, URLRequestContextGetter* request_context) : Receiver(RENDER_PROCESS, child_id), channel_(NULL), resource_dispatcher_host_(resource_dispatcher_host), plugin_service_(plugin_service), print_job_manager_(print_job_manager), - spellchecker_(spellchecker), ALLOW_THIS_IN_INITIALIZER_LIST(resolve_proxy_msg_helper_(this, NULL)), request_context_(request_context), media_request_context_(profile->GetRequestContextForMedia()), @@ -214,8 +211,6 @@ void ResourceMessageFilter::OnFilterAdded(IPC::Channel* channel) { channel_ = channel; // Add the observers to intercept. - registrar_.Add(this, NotificationType::SPELLCHECKER_REINITIALIZED, - Source<Profile>(static_cast<Profile*>(profile_))); registrar_.Add(this, NotificationType::BLACKLIST_BLOCKED_RESOURCE, NotificationService::AllSources()); } @@ -317,13 +312,14 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) { OnCancelCreateDedicatedWorker) IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker, OnForwardToWorker) - IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SpellCheck, OnSpellCheck) + IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_PlatformCheckSpelling, + OnPlatformCheckSpelling) + IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_PlatformFillSuggestionList, + OnPlatformFillSuggestionList) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetDocumentTag, OnGetDocumentTag) IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentWithTagClosed, OnDocumentWithTagClosed) - IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetAutoCorrectWord, - OnGetAutoCorrectWord) IPC_MESSAGE_HANDLER(ViewHostMsg_ShowSpellingPanel, OnShowSpellingPanel) IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateSpellingPanelWithMisspelledWord, OnUpdateSpellingPanelWithMisspelledWord) @@ -420,21 +416,6 @@ void ResourceMessageFilter::OnReceiveContextMenuMsg(const IPC::Message& msg) { if (!IPC::ParamTraits<ContextMenuParams>::Read(&msg, &iter, ¶ms)) return; - // Fill in the dictionary suggestions if required. - if (!params.misspelled_word.empty() && - spellchecker_ != NULL && params.spellcheck_enabled) { - int misspell_location, misspell_length; - bool is_misspelled = !spellchecker_->SpellCheckWord( - params.misspelled_word.c_str(), - static_cast<int>(params.misspelled_word.length()), 0, - &misspell_location, &misspell_length, - ¶ms.dictionary_suggestions); - - // If not misspelled, make the misspelled_word param empty. - if (!is_misspelled) - params.misspelled_word.clear(); - } - // Create a new ViewHostMsg_ContextMenu message. const ViewHostMsg_ContextMenu context_menu_message(msg.routing_id(), params); ChromeThread::PostTask( @@ -1010,33 +991,16 @@ ResourceMessageFilter::GetRequestContextForURL( context_getter->GetURLRequestContext()); } -// Notes about SpellCheck. -// -// Spellchecking generally uses a fair amount of RAM. For this reason, we load -// the spellcheck dictionaries into the browser process, and all renderers ask -// the browsers to do SpellChecking. -// -// This filter should not try to initialize the spellchecker. It is up to the -// profile to initialize it when required, and send it here. If |spellchecker_| -// is made NULL, it corresponds to spellchecker turned off - i.e., all -// spellings are correct. -// -// Note: This is called in the IO thread. -void ResourceMessageFilter::OnSpellCheck(const string16& word, int tag, - IPC::Message* reply_msg) { - int misspell_location = 0; - int misspell_length = 0; - - if (spellchecker_ != NULL) { - spellchecker_->SpellCheckWord(word.c_str(), - static_cast<int>(word.length()), tag, - &misspell_location, &misspell_length, NULL); - } +void ResourceMessageFilter::OnPlatformCheckSpelling(const string16& word, + int tag, + bool* correct) { + *correct = SpellCheckerPlatform::CheckSpelling(word, tag); +} - ViewHostMsg_SpellCheck::WriteReplyParams(reply_msg, misspell_location, - misspell_length); - Send(reply_msg); - return; +void ResourceMessageFilter::OnPlatformFillSuggestionList( + const string16& word, + std::vector<string16>* suggestions) { + SpellCheckerPlatform::FillSuggestionList(word, suggestions); } void ResourceMessageFilter::OnGetDocumentTag(IPC::Message* reply_msg) { @@ -1050,19 +1014,6 @@ void ResourceMessageFilter::OnDocumentWithTagClosed(int tag) { SpellCheckerPlatform::CloseDocumentWithTag(tag); } -void ResourceMessageFilter::OnGetAutoCorrectWord(const string16& word, - int tag, - IPC::Message* reply_msg) { - string16 autocorrect_word; - if (spellchecker_ != NULL) - autocorrect_word = spellchecker_->GetAutoCorrectionWord(word, tag); - - ViewHostMsg_GetAutoCorrectWord::WriteReplyParams(reply_msg, - autocorrect_word); - Send(reply_msg); - return; -} - void ResourceMessageFilter::OnShowSpellingPanel(bool show) { SpellCheckerPlatform::ShowSpellingPanel(show); } @@ -1075,10 +1026,7 @@ void ResourceMessageFilter::OnUpdateSpellingPanelWithMisspelledWord( void ResourceMessageFilter::Observe(NotificationType type, const NotificationSource &source, const NotificationDetails &details) { - if (type == NotificationType::SPELLCHECKER_REINITIALIZED) { - spellchecker_ = Details<SpellcheckerReinitializedDetails> - (details).ptr()->spellchecker; - } else if (type == NotificationType::BLACKLIST_BLOCKED_RESOURCE) { + if (type == NotificationType::BLACKLIST_BLOCKED_RESOURCE) { BlacklistObserver::ContentBlocked(Details<const URLRequest>(details).ptr()); } } diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 50507db..f2cb2df 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -87,7 +87,6 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, printing::PrintJobManager* print_job_manager, Profile* profile, RenderWidgetHelper* render_widget_helper, - SpellChecker* spellchecker, URLRequestContextGetter* request_context); // IPC::ChannelProxy::MessageFilter methods: @@ -104,7 +103,6 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, uint32 request_id, const ViewHostMsg_Resource_Request& request_data); - SpellChecker* spellchecker() { return spellchecker_.get(); } ResourceDispatcherHost* resource_dispatcher_host() { return resource_dispatcher_host_; } @@ -185,11 +183,11 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnDownloadUrl(const IPC::Message& message, const GURL& url, const GURL& referrer); - void OnSpellCheck(const string16& word, int tag, IPC::Message* reply_msg); + void OnPlatformCheckSpelling(const string16& word, int tag, bool* correct); + void OnPlatformFillSuggestionList(const string16& word, + std::vector<string16>* suggestions); void OnGetDocumentTag(IPC::Message* reply_msg); void OnDocumentWithTagClosed(int tag); - void OnGetAutoCorrectWord(const string16& word, int tag, - IPC::Message* reply_msg); void OnShowSpellingPanel(bool show); void OnUpdateSpellingPanelWithMisspelledWord(const string16& word); void OnDnsPrefetch(const std::vector<std::string>& hostnames); @@ -349,9 +347,6 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, // before this object, we only hold an ID for lookup. int child_id_; - // Our spellchecker object. - scoped_refptr<SpellChecker> spellchecker_; - // Helper class for handling PluginProcessHost_ResolveProxy messages (manages // the requests to the proxy service). ResolveProxyMsgHelper resolve_proxy_msg_helper_; diff --git a/chrome/browser/spellcheck_host.cc b/chrome/browser/spellcheck_host.cc index 446d19d..f716e7a 100644 --- a/chrome/browser/spellcheck_host.cc +++ b/chrome/browser/spellcheck_host.cc @@ -11,120 +11,22 @@ #include "base/logging.h" #include "base/path_service.h" #include "base/string_util.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/spellchecker_platform_engine.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/notification_service.h" +#include "chrome/common/pref_member.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/spellcheck_common.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); -} - FilePath GetFirstChoiceFilePath(const std::string& language) { FilePath dict_dir; PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); - return GetVersionedFileName(language, dict_dir); + return SpellCheckCommon::GetVersionedFileName(language, dict_dir); } FilePath GetFallbackFilePath(const FilePath& first_choice) { @@ -143,6 +45,7 @@ SpellCheckHost::SpellCheckHost(Observer* observer, language_(language), file_(base::kInvalidPlatformFileValue), tried_to_download_(false), + use_platform_spellchecker_(false), request_context_getter_(request_context_getter) { DCHECK(observer_); DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); @@ -161,6 +64,16 @@ SpellCheckHost::~SpellCheckHost() { } void SpellCheckHost::Initialize() { + if (SpellCheckerPlatform::SpellCheckerAvailable() && + SpellCheckerPlatform::PlatformSupportsLanguage(language_)) { + use_platform_spellchecker_ = true; + SpellCheckerPlatform::SetLanguage(language_); + MessageLoop::current()->PostTask(FROM_HERE, + NewRunnableMethod(this, + &SpellCheckHost::InformObserverOfInitialization)); + return; + } + ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, NewRunnableMethod(this, &SpellCheckHost::InitializeDictionaryLocation)); } @@ -185,6 +98,50 @@ void SpellCheckHost::AddWord(const std::string& word) { Source<SpellCheckHost>(this), NotificationService::NoDetails()); } +// static +int SpellCheckHost::GetSpellCheckLanguages( + Profile* profile, + std::vector<std::string>* languages) { + StringPrefMember accept_languages_pref; + StringPrefMember dictionary_language_pref; + accept_languages_pref.Init(prefs::kAcceptLanguages, profile->GetPrefs(), + NULL); + dictionary_language_pref.Init(prefs::kSpellCheckDictionary, + profile->GetPrefs(), NULL); + std::string dictionary_language = + WideToASCII(dictionary_language_pref.GetValue()); + + // The current dictionary language should be there. + languages->push_back(dictionary_language); + + // Now scan through the list of accept languages, and find possible mappings + // from this list to the existing list of spell check languages. + std::vector<std::string> accept_languages; + + if (SpellCheckerPlatform::SpellCheckerAvailable()) { + SpellCheckerPlatform::GetAvailableLanguages(&accept_languages); + } else { + SplitString(WideToASCII(accept_languages_pref.GetValue()), ',', + &accept_languages); + } + for (std::vector<std::string>::const_iterator i = accept_languages.begin(); + i != accept_languages.end(); ++i) { + std::string language = + SpellCheckCommon::GetCorrespondingSpellCheckLanguage(*i); + if (!language.empty() && + std::find(languages->begin(), languages->end(), language) == + languages->end()) { + languages->push_back(language); + } + } + + for (size_t i = 0; i < languages->size(); ++i) { + if ((*languages)[i] == dictionary_language) + return i; + } + return -1; +} + void SpellCheckHost::InitializeDictionaryLocation() { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); diff --git a/chrome/browser/spellcheck_host.h b/chrome/browser/spellcheck_host.h index 6b25cd0..325921a 100644 --- a/chrome/browser/spellcheck_host.h +++ b/chrome/browser/spellcheck_host.h @@ -15,6 +15,8 @@ #include "chrome/browser/net/url_fetcher.h" #include "chrome/browser/net/url_request_context_getter.h" +class Profile; + class SpellCheckHost : public base::RefCountedThreadSafe<SpellCheckHost, ChromeThread::DeleteOnFileThread>, public URLFetcher::Delegate { @@ -37,6 +39,14 @@ class SpellCheckHost : public base::RefCountedThreadSafe<SpellCheckHost, // update. void AddWord(const std::string& word); + // This function computes a vector of strings which are to be displayed in + // the context menu over a text area for changing spell check languages. It + // returns the index of the current spell check language in the vector. + // TODO(port): this should take a vector of string16, but the implementation + // has some dependencies in l10n util that need porting first. + static int GetSpellCheckLanguages(Profile* profile, + std::vector<std::string>* languages); + const base::PlatformFile& bdict_file() const { return file_; } const std::vector<std::string>& custom_words() const { return custom_words_; } @@ -45,6 +55,8 @@ class SpellCheckHost : public base::RefCountedThreadSafe<SpellCheckHost, const std::string& language() const { return language_; } + bool use_platform_spellchecker() const { return use_platform_spellchecker_; } + private: // These two classes can destruct us. friend class ChromeThread; @@ -109,6 +121,9 @@ class SpellCheckHost : public base::RefCountedThreadSafe<SpellCheckHost, // once. bool tried_to_download_; + // Whether we should use the platform spellchecker instead of Hunspell. + bool use_platform_spellchecker_; + // Data received from the dictionary download. std::string data_; diff --git a/chrome/browser/spellcheck_worditerator.cc b/chrome/browser/spellcheck_worditerator.cc deleted file mode 100644 index 34f2330..0000000 --- a/chrome/browser/spellcheck_worditerator.cc +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright (c) 2006-2008 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_worditerator.h" - -#include <map> -#include <string> - -#include "base/basictypes.h" -#include "base/string_util.h" -#include "chrome/browser/spellchecker.h" - -#include "third_party/icu/public/common/unicode/normlzr.h" -#include "third_party/icu/public/common/unicode/schriter.h" -#include "third_party/icu/public/common/unicode/uchar.h" -#include "third_party/icu/public/common/unicode/uscript.h" -#include "third_party/icu/public/common/unicode/uset.h" -#include "third_party/icu/public/i18n/unicode/ulocdata.h" - -SpellcheckCharAttribute::SpellcheckCharAttribute() { - InitializeScriptTable(); - - // Even though many dictionaries treats numbers and contractions as words and - // treats USCRIPT_COMMON characters as word characters, the - // SpellcheckWordIterator class treats USCRIPT_COMMON characters as non-word - // characters to strictly-distinguish contraction characters from word - // characters. - SetWordScript(USCRIPT_COMMON, false); - - // Initialize the table of characters used for contractions. - // This array consists of the 'Midletter' and 'MidNumLet' characters of the - // word-break property list provided by Unicode, Inc.: - // http://www.unicode.org/Public/UNIDATA/auxiliary/WordBreakProperty.txt - static const UChar32 kMidLetters[] = { - L'\x003A', // MidLetter # COLON - L'\x00B7', // MidLetter # MIDDLE DOT - L'\x0387', // MidLetter # GREEK ANO TELEIA - L'\x05F4', // MidLetter # HEBREW PUNCTUATION GERSHAYIM - L'\x2027', // MidLetter # HYPHENATION POINT - L'\xFE13', // MidLetter # PRESENTATION FORM FOR VERTICAL COLON - L'\xFE55', // MidLetter # SMALL COLON - L'\xFF1A', // MidLetter # FULLWIDTH COLON - L'\x0027', // MidNumLet # APOSTROPHE - L'\x002E', // MidNumLet # FULL STOP - L'\x2018', // MidNumLet # LEFT SINGLE QUOTATION MARK - L'\x2019', // MidNumLet # RIGHT SINGLE QUOTATION MARK - L'\x2024', // MidNumLet # ONE DOT LEADER - L'\xFE52', // MidNumLet # SMALL FULL STOP - L'\xFF07', // MidNumLet # FULLWIDTH APOSTROPHE - L'\xFF0E', // MidNumLet # FULLWIDTH FULL STOP - }; - for (size_t i = 0; i < arraysize(kMidLetters); ++i) - middle_letters_[kMidLetters[i]] = true; -} - -SpellcheckCharAttribute::~SpellcheckCharAttribute() { -} - -// Sets the default language for this object. -// This function retrieves the exemplar set to set up the default character -// attributes. -void SpellcheckCharAttribute::SetDefaultLanguage(const std::string& language) { - UErrorCode status = U_ZERO_ERROR; - ULocaleData* locale_data = ulocdata_open(language.c_str(), &status); - if (U_FAILURE(status)) - return; - - // Retrieves the exemplar set of the given language and update the - // character-attribute table to treat its characters as word characters. - USet* exemplar_set = uset_open(1, 0); - ulocdata_getExemplarSet(locale_data, exemplar_set, 0, ULOCDATA_ES_STANDARD, - &status); - ulocdata_close(locale_data); - if (U_SUCCESS(status)) { - int length = uset_size(exemplar_set); - for (int i = 0; i < length; ++i) { - UChar32 character = uset_charAt(exemplar_set, i); - SetWordScript(GetScriptCode(character), true); - } - - // Many languages use combining characters to input their characters from - // keyboards. On the other hand, this exemplar set does not always include - // combining characters for such languages. - // To treat such combining characters as word characters, we decompose - // this exemplar set and treat the decomposed characters as word characters. - icu::UnicodeString composed; - for (int i = 0; i < length; ++i) - composed.append(uset_charAt(exemplar_set, i)); - - icu::UnicodeString decomposed; - icu::Normalizer::decompose(composed, FALSE, 0, decomposed, status); - if (U_SUCCESS(status)) { - icu::StringCharacterIterator iterator(decomposed); - UChar32 character = iterator.first32(); - while (character != icu::CharacterIterator::DONE) { - SetWordScript(GetScriptCode(character), true); - character = iterator.next32(); - } - } - } - uset_close(exemplar_set); -} - -// Returns whether or not the given character is a character used by the -// selected dictionary. -bool SpellcheckCharAttribute::IsWordChar(UChar32 character) const { - return IsWordScript(GetScriptCode(character)) && !u_isdigit(character); -} - -// Returns whether or not the given character is a character used by -// contractions. -bool SpellcheckCharAttribute::IsContractionChar(UChar32 character) const { - std::map<UChar32, bool>::const_iterator iterator; - iterator = middle_letters_.find(character); - if (iterator == middle_letters_.end()) - return false; - return iterator->second; -} - -// Initializes the mapping table. -void SpellcheckCharAttribute::InitializeScriptTable() { - for (size_t i = 0; i < arraysize(script_attributes_); ++i) - script_attributes_[i] = false; -} - -// Retrieves the ICU script code. -UScriptCode SpellcheckCharAttribute::GetScriptCode(UChar32 character) const { - UErrorCode status = U_ZERO_ERROR; - UScriptCode script_code = uscript_getScript(character, &status); - return U_SUCCESS(status) ? script_code : USCRIPT_INVALID_CODE; -} - -// Updates the mapping table from an ICU script code to its attribute, i.e. -// whether not a script is used by the selected dictionary. -void SpellcheckCharAttribute::SetWordScript(const int script_code, - bool in_use) { - if (script_code < 0 || - static_cast<size_t>(script_code) >= arraysize(script_attributes_)) - return; - script_attributes_[script_code] = in_use; -} - -// Returns whether or not the given script is used by the selected -// dictionary. -bool SpellcheckCharAttribute::IsWordScript( - const UScriptCode script_code) const { - if (script_code < 0 || - static_cast<size_t>(script_code) >= arraysize(script_attributes_)) - return false; - return script_attributes_[script_code]; -} - -SpellcheckWordIterator::SpellcheckWordIterator() - : word_(NULL), - length_(0), - position_(0), - allow_contraction_(false), - attribute_(NULL) { -} - -SpellcheckWordIterator::~SpellcheckWordIterator() { -} - -// Initialize a word-iterator object. -void SpellcheckWordIterator::Initialize( - const SpellcheckCharAttribute* attribute, - const char16* word, - size_t length, - bool allow_contraction) { - word_ = word; - position_ = 0; - length_ = static_cast<int>(length); - allow_contraction_ = allow_contraction; - attribute_ = attribute; -} - -// Retrieves a word (or a contraction). -// When a contraction is enclosed with contraction characters (e.g. 'isn't', -// 'rock'n'roll'), we should discard the beginning and the end of the -// contraction but we should never split the contraction. -// To handle this case easily, we should firstly extract a segment consisting -// of word characters and contraction characters, and discard contraction -// characters at the beginning and the end of the extracted segment. -bool SpellcheckWordIterator::GetNextWord(string16* word_string, - int* word_start, - int* word_length) { - word_string->clear(); - *word_start = 0; - *word_length = 0; - while (position_ < length_) { - int segment_start = 0; - int segment_end = 0; - GetSegment(&segment_start, &segment_end); - TrimSegment(segment_start, segment_end, word_start, word_length); - if (*word_length > 0) - return Normalize(*word_start, *word_length, word_string); - } - - return false; -} - -// Retrieves a segment consisting of word characters (and contraction -// characters if the |allow_contraction_| value is true). -// When the current position refers to a non-word character, this function -// returns a non-empty segment consisting of the character itself. In this -// case, the TrimSegment() function discards the character and returns an -// empty word (i.e. |word_length| == 0). -void SpellcheckWordIterator::GetSegment(int* segment_start, - int* segment_end) { - int position = position_; - while (position < length_) { - UChar32 character; - U16_NEXT(word_, position, length_, character); - if (!attribute_->IsWordChar(character)) { - if (!allow_contraction_ || !attribute_->IsContractionChar(character)) - break; - } - } - *segment_start = position_; - *segment_end = position; - position_ = position; -} - -// Discards non-word characters at the beginning and the end of the given -// segment. -void SpellcheckWordIterator::TrimSegment(int segment_start, - int segment_end, - int* word_start, - int* word_length) const { - while (segment_start < segment_end) { - UChar32 character; - int segment_next = segment_start; - U16_NEXT(word_, segment_next, segment_end, character); - if (attribute_->IsWordChar(character)) { - *word_start = segment_start; - break; - } - segment_start = segment_next; - } - while (segment_end >= segment_start) { - UChar32 character; - int segment_prev = segment_end; - U16_PREV(word_, segment_start, segment_prev, character); - if (attribute_->IsWordChar(character)) { - *word_length = segment_end - segment_start; - break; - } - segment_end = segment_prev; - } -} - -// Normalizes a non-terminated string into its canonical form so that -// a spellchecker object can check spellings of words which contain ligatures, -// full-width letters, etc. -// USCRIPT_LATIN does not only consists of US-ASCII and ISO/IEC 8859-1, but -// also consists of ISO/IEC 8859-{2,3,4,9,10}, ligatures, fullwidth latin, -// etc. For its details, please read the script table in -// "http://www.unicode.org/Public/UNIDATA/Scripts.txt". -bool SpellcheckWordIterator::Normalize(int input_start, - int input_length, - string16* output_string) const { - // Unicode Standard Annex #15 "http://www.unicode.org/unicode/reports/tr15/" - // does not only write NFKD and NFKC can compose ligatures into their ASCII - // alternatives, but also write NFKC keeps accents of characters. - // Therefore, NFKC seems to be the best option for hunspell. - icu::UnicodeString input(FALSE, &word_[input_start], input_length); - UErrorCode status = U_ZERO_ERROR; - icu::UnicodeString output; - icu::Normalizer::normalize(input, UNORM_NFKC, 0, output, status); - if (U_SUCCESS(status)) - output_string->assign(output.getTerminatedBuffer()); - return status == U_ZERO_ERROR || status == U_STRING_NOT_TERMINATED_WARNING; -} diff --git a/chrome/browser/spellcheck_worditerator.h b/chrome/browser/spellcheck_worditerator.h deleted file mode 100644 index c0fb8e1..0000000 --- a/chrome/browser/spellcheck_worditerator.h +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) 2006-2008 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. - -#ifndef CHROME_BROWSER_SPELLCHECK_WORDITERATOR_H_ -#define CHROME_BROWSER_SPELLCHECK_WORDITERATOR_H_ - -#include <map> -#include <string> - -#include "base/basictypes.h" -#include "base/string16.h" - -#include "unicode/uscript.h" - -// A class which handles character attributes dependent on a spellchecker and -// its dictionary. -// This class is used by the SpellcheckWordIterator class to determine whether -// or not a character is one used by the spellchecker and its dictinary. -class SpellcheckCharAttribute { - public: - SpellcheckCharAttribute(); - - ~SpellcheckCharAttribute(); - - // Sets the default language of the spell checker. This controls which - // characters are considered parts of words of the given language. - void SetDefaultLanguage(const std::string& language); - - // Returns whether or not the given character is a character used by the - // selected dictionary. - // Parameters - // * character [in] (UChar32) - // Represents a Unicode character to be checked. - // Return values - // * true - // The given character is a word character. - // * false - // The given character is not a word character. - bool IsWordChar(UChar32 character) const; - - // Returns whether or not the given character is a character used by - // contractions. - // Parameters - // * character [in] (UChar32) - // Represents a Unicode character to be checked. - // Return values - // * true - // The given character is a character used by contractions. - // * false - // The given character is not a character used by contractions. - bool IsContractionChar(UChar32 character) const; - - private: - // Initializes the mapping table. - void InitializeScriptTable(); - - // Retrieves the ICU script code. - UScriptCode GetScriptCode(UChar32 character) const; - - // Updates an entry in the mapping table. - void SetWordScript(const int script_code, bool in_use); - - // Returns whether or not the given script is used by the selected - // dictionary. - bool IsWordScript(const UScriptCode script_code) const; - - private: - // Represents a mapping table from a script code to a boolean value - // representing whether or not the script is used by the selected dictionary. - bool script_attributes_[USCRIPT_CODE_LIMIT]; - - // Represents a table of characters used by contractions. - std::map<UChar32, bool> middle_letters_; - - DISALLOW_COPY_AND_ASSIGN(SpellcheckCharAttribute); -}; - -// A class which implements methods for finding the location of word boundaries -// used by the Spellchecker class. -// This class is implemented on the following assumptions: -// * An input string is encoded in UTF-16 (i.e. it may contain surrogate -// pairs), and; -// * The length of a string is the number of UTF-16 characters in the string -// (i.e. the length of a non-BMP character becomes two). -class SpellcheckWordIterator { - public: - SpellcheckWordIterator(); - - ~SpellcheckWordIterator(); - - // Initializes a word-iterator object. - // Parameters - // * attribute [in] (const SpellcheckCharAttribute*) - // Represents a set of character attributes used for filtering out - // non-word characters. - // * word [in] (const char16*) - // Represents a string from which this object extracts words. - // (This string does not have to be NUL-terminated.) - // * length [in] (size_t) - // Represents the length of the given string, in UTF-16 characters. - // This value should not include terminating NUL characters. - // * allow_contraction [in] (bool) - // Represents a flag to control whether or not this object should split a - // possible contraction (e.g. "isn't", "in'n'out", etc.) - // Return values - // * true - // This word-iterator object is initialized successfully. - // * false - // An error occured while initializing this object. - void Initialize(const SpellcheckCharAttribute* attribute, - const char16* word, - size_t length, - bool allow_contraction); - - // Retrieves a word (or a contraction). - // Parameters - // * word_string [out] (string16*) - // Represents a word (or a contraction) to be checked its spelling. - // This |word_string| has been already normalized to its canonical form - // (i.e. decomposed ligatures, replaced full-width latin characters to - // its ASCII alternatives, etc.) so that a SpellChecker object can check - // its spelling without any additional operations. - // On the other hand, a substring of the input string - // string16 str(&word[word_start], word_length); - // represents the non-normalized version of this extracted word. - // * word_start [out] (int*) - // Represents the offset of this word from the beginning of the input - // string, in UTF-16 characters. - // * word_length [out] (int*) - // Represents the length of an extracted word before normalization, in - // UTF-16 characters. - // When the input string contains ligatures, this value may not be equal - // to the length of the |word_string|. - // Return values - // * true - // Found a word (or a contraction) to be checked its spelling. - // * false - // Not found any more words or contractions to be checked their spellings. - bool GetNextWord(string16* word_string, - int* word_start, - int* word_length); - - private: - // Retrieves a segment consisting of word characters (and contraction - // characters if the |allow_contraction| value is true). - void GetSegment(int* segment_start, - int* segment_end); - - // Discards non-word characters at the beginning and the end of the given - // segment. - void TrimSegment(int segment_start, - int segment_end, - int* word_start, - int* word_length) const; - - // Normalizes the given segment of the |word_| variable and write its - // canonical form to the |output_string|. - bool Normalize(int input_start, - int input_length, - string16* output_string) const; - - private: - // The pointer to the input string from which we are extracting words. - const char16* word_; - - // The length of the original string. - int length_; - - // The current position in the original string. - int position_; - - // The flag to control whether or not this object should extract possible - // contractions. - bool allow_contraction_; - - // The character attributes used for filtering out non-word characters. - const SpellcheckCharAttribute* attribute_; - - DISALLOW_COPY_AND_ASSIGN(SpellcheckWordIterator); -}; - -#endif // CHROME_BROWSER_SPELLCHECK_WORDITERATOR_H_ diff --git a/chrome/browser/spellchecker.cc b/chrome/browser/spellchecker.cc deleted file mode 100644 index 903cdb9..0000000 --- a/chrome/browser/spellchecker.cc +++ /dev/null @@ -1,814 +0,0 @@ -// Copyright (c) 2006-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/spellchecker.h" - -#include "app/l10n_util.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/file_util.h" -#include "base/histogram.h" -#include "base/logging.h" -#include "base/path_service.h" -#include "base/stats_counters.h" -#include "base/string_util.h" -#include "chrome/browser/net/url_fetcher.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/spellchecker_common.h" -#include "chrome/browser/spellchecker_platform_engine.h" -#include "chrome/common/chrome_constants.h" -#include "chrome/common/chrome_counters.h" -#include "chrome/common/chrome_paths.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/pref_service.h" -#include "grit/generated_resources.h" -#include "grit/locale_settings.h" -#include "net/url_request/url_request.h" -#include "third_party/hunspell/src/hunspell/hunspell.hxx" - -using base::TimeTicks; - -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[] = { - {"en-US", "en-US"}, - {"en-GB", "en-GB"}, - {"en-AU", "en-AU"}, - {"fr", "fr-FR"}, - {"it", "it-IT"}, - {"de", "de-DE"}, - {"es", "es-ES"}, - {"nl", "nl-NL"}, - {"pt-BR", "pt-BR"}, - {"ru", "ru-RU"}, - {"pl", "pl-PL"}, - // {"th", "th-TH"}, // Not to be included in Spellchecker as per B=1277824 - {"sv", "sv-SE"}, - {"da", "da-DK"}, - {"pt-PT", "pt-PT"}, - {"ro", "ro-RO"}, - // {"hu", "hu-HU"}, // Not to be included in Spellchecker as per B=1277824 - {"he", "he-IL"}, - {"id", "id-ID"}, - {"cs", "cs-CZ"}, - {"el", "el-GR"}, - {"nb", "nb-NO"}, - {"vi", "vi-VN"}, - // {"bg", "bg-BG"}, // Not to be included in Spellchecker as per B=1277824 - {"hr", "hr-HR"}, - {"lt", "lt-LT"}, - {"sk", "sk-SK"}, - {"sl", "sl-SI"}, - {"ca", "ca-ES"}, - {"lv", "lv-LV"}, - // {"uk", "uk-UA"}, // Not to be included in Spellchecker as per B=1277824 - {"hi", "hi-IN"}, - {"et", "et-EE"}, - {"tr", "tr-TR"}, -}; - -// Get the fallback folder (currently chrome::DIR_USER_DATA) where the -// dictionary is downloaded in case of system-wide installations. -FilePath GetFallbackDictionaryDownloadDirectory() { - FilePath dict_dir_userdata; - PathService::Get(chrome::DIR_USER_DATA, &dict_dir_userdata); - dict_dir_userdata = dict_dir_userdata.AppendASCII("Dictionaries"); - return dict_dir_userdata; -} - -bool SaveBufferToFile(const std::string& data, - FilePath file_to_write) { - int num_bytes = data.length(); - return file_util::WriteFile(file_to_write, data.data(), num_bytes) == - num_bytes; -} - -} // namespace - -// Design: The spellchecker initializes hunspell_ in the Initialize() method. -// This is done using the dictionary file on disk, e.g. "en-US_1_1.bdic". -// Initialization of hunspell_ is held off during this process. If the -// dictionary is not available, we first attempt to download and save it. After -// the dictionary is downloaded and saved to disk (or the attempt to do so -// fails)), corresponding flags are set in spellchecker - in the IO thread. -// After the flags are cleared, a (final) attempt is made to initialize -// hunspell_. If it fails even then (dictionary could not download), no more -// attempts are made to initialize it. -class SaveDictionaryTask : public Task { - public: - SaveDictionaryTask(Task* on_dictionary_save_complete_callback_task, - const FilePath& first_attempt_file_name, - const FilePath& fallback_file_name, - const std::string& data) - : on_dictionary_save_complete_callback_task_( - on_dictionary_save_complete_callback_task), - first_attempt_file_name_(first_attempt_file_name), - fallback_file_name_(fallback_file_name), - data_(data) { - } - - private: - void Run(); - - bool SaveBufferToFile(const std::string& data, - FilePath file_to_write) { - int num_bytes = data.length(); - return file_util::WriteFile(file_to_write, data.data(), num_bytes) == - num_bytes; - } - - // factory object to invokelater back to spellchecker in io thread on - // download completion to change appropriate flags. - Task* on_dictionary_save_complete_callback_task_; - - // The file which will be stored in the first attempt. - FilePath first_attempt_file_name_; - - // The file which will be stored as a fallback. - FilePath fallback_file_name_; - - // The buffer which has to be stored to disk. - std::string data_; - - // This invokes back to io loop when downloading is over. - DISALLOW_COPY_AND_ASSIGN(SaveDictionaryTask); -}; - -void SaveDictionaryTask::Run() { - if (!SaveBufferToFile(data_, first_attempt_file_name_)) { - // Try saving it to |fallback_file_name_|, which almost surely has - // write permission. If even this fails, there is nothing to be done. - FilePath fallback_dir = fallback_file_name_.DirName(); - // Create the directory if it does not exist. - if (!file_util::PathExists(fallback_dir)) - file_util::CreateDirectory(fallback_dir); - SaveBufferToFile(data_, fallback_file_name_); - } // Unsuccessful save is taken care of in SpellChecker::Initialize(). - - // Set Flag that dictionary is not downloading anymore. - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, on_dictionary_save_complete_callback_task_); -} - -// Design: this task tries to read the dictionary from disk and load it into -// memory. It is executed on the file thread, and posts the results back to -// the IO thread. -// The task first checks for the existence of the dictionary in one of the two -// given locations. If it does not exist, the task informs the SpellChecker, -// which will try to download the directory and run a new ReadDictionaryTask. -class ReadDictionaryTask : public Task { - public: - ReadDictionaryTask(SpellChecker* spellchecker, - const FilePath& dict_file_name_app, - const FilePath& dict_file_name_usr) - : spellchecker_(spellchecker), - hunspell_(NULL), - bdict_file_(NULL), - custom_dictionary_file_name_( - spellchecker->custom_dictionary_file_name_), - dict_file_name_app_(dict_file_name_app), - dict_file_name_usr_(dict_file_name_usr) { - } - - virtual void Run() { - FilePath bdict_file_path; - if (file_util::PathExists(dict_file_name_app_)) { - bdict_file_path = dict_file_name_app_; - } else if (file_util::PathExists(dict_file_name_usr_)) { - bdict_file_path = dict_file_name_usr_; - } else { - Finish(false); - return; - } - - bdict_file_ = new file_util::MemoryMappedFile; - if (bdict_file_->Initialize(bdict_file_path)) { - TimeTicks start_time = TimeTicks::Now(); - - hunspell_ = - new Hunspell(bdict_file_->data(), bdict_file_->length()); - - // Add custom words to Hunspell. - std::string contents; - file_util::ReadFileToString(custom_dictionary_file_name_, &contents); - std::vector<std::string> list_of_words; - SplitString(contents, '\n', &list_of_words); - for (std::vector<std::string>::iterator it = list_of_words.begin(); - it != list_of_words.end(); ++it) { - hunspell_->add(it->c_str()); - } - - DHISTOGRAM_TIMES("Spellcheck.InitTime", - TimeTicks::Now() - start_time); - } else { - delete bdict_file_; - bdict_file_ = NULL; - } - - Finish(true); - } - - private: - void Finish(bool file_existed) { - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod( - spellchecker_.get(), &SpellChecker::HunspellInited, hunspell_, - bdict_file_, file_existed)); - } - - // The SpellChecker we are working for. - scoped_refptr<SpellChecker> spellchecker_; - Hunspell* hunspell_; - file_util::MemoryMappedFile* bdict_file_; - - FilePath custom_dictionary_file_name_; - FilePath dict_file_name_app_; - FilePath dict_file_name_usr_; - - DISALLOW_COPY_AND_ASSIGN(ReadDictionaryTask); -}; - -void SpellChecker::SpellCheckLanguages(std::vector<std::string>* languages) { - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); - ++i) { - languages->push_back(g_supported_spellchecker_languages[i].language); - } -} - -// This function returns the language-region version of language name. -// e.g. returns hi-IN for hi. -std::string SpellChecker::GetSpellCheckLanguageRegion( - std::string input_language) { - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); - ++i) { - std::string language( - g_supported_spellchecker_languages[i].language); - if (language == input_language) - return std::string( - g_supported_spellchecker_languages[i].language_region); - } - - return input_language; -} - - -std::string SpellChecker::GetLanguageFromLanguageRegion( - std::string input_language) { - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); - ++i) { - std::string language( - g_supported_spellchecker_languages[i].language_region); - if (language == input_language) - return std::string(g_supported_spellchecker_languages[i].language); - } - - return input_language; -} - -std::string SpellChecker::GetCorrespondingSpellCheckLanguage( - const std::string& language) { - // Look for exact match in the Spell Check language list. - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); - ++i) { - // First look for exact match in the language region of the list. - std::string spellcheck_language( - g_supported_spellchecker_languages[i].language); - if (spellcheck_language == language) - return language; - - // Next, look for exact match in the language_region part of the list. - std::string spellcheck_language_region( - g_supported_spellchecker_languages[i].language_region); - if (spellcheck_language_region == language) - return g_supported_spellchecker_languages[i].language; - } - - // Look for a match by comparing only language parts. All the 'en-RR' - // except for 'en-GB' exactly matched in the above loop, will match - // 'en-US'. This is not ideal because 'en-ZA', 'en-NZ' had - // better be matched with 'en-GB'. This does not handle cases like - // 'az-Latn-AZ' vs 'az-Arab-AZ', either, but we don't use 3-part - // locale ids with a script code in the middle, yet. - // TODO(jungshik): Add a better fallback. - std::string language_part(language, 0, language.find('-')); - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); - ++i) { - std::string spellcheck_language( - g_supported_spellchecker_languages[i].language_region); - if (spellcheck_language.substr(0, spellcheck_language.find('-')) == - language_part) - return spellcheck_language; - } - - // No match found - return blank. - return std::string(); -} - -// static -int SpellChecker::GetSpellCheckLanguages( - Profile* profile, - std::vector<std::string>* languages) { - StringPrefMember accept_languages_pref; - StringPrefMember dictionary_language_pref; - accept_languages_pref.Init(prefs::kAcceptLanguages, profile->GetPrefs(), - NULL); - dictionary_language_pref.Init(prefs::kSpellCheckDictionary, - profile->GetPrefs(), NULL); - std::string dictionary_language = - WideToASCII(dictionary_language_pref.GetValue()); - - // The current dictionary language should be there. - languages->push_back(dictionary_language); - - // Now scan through the list of accept languages, and find possible mappings - // from this list to the existing list of spell check languages. - std::vector<std::string> accept_languages; - - if (SpellCheckerPlatform::SpellCheckerAvailable()) { - SpellCheckerPlatform::GetAvailableLanguages(&accept_languages); - } else { - SplitString(WideToASCII(accept_languages_pref.GetValue()), ',', - &accept_languages); - } - for (std::vector<std::string>::const_iterator i = accept_languages.begin(); - i != accept_languages.end(); ++i) { - std::string language = GetCorrespondingSpellCheckLanguage(*i); - if (!language.empty() && - std::find(languages->begin(), languages->end(), language) == - languages->end()) - languages->push_back(language); - } - - for (size_t i = 0; i < languages->size(); ++i) { - if ((*languages)[i] == dictionary_language) - return i; - } - return -1; -} - -FilePath SpellChecker::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 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); -} - -SpellChecker::SpellChecker(const FilePath& dict_dir, - const std::string& language, - URLRequestContextGetter* request_context_getter, - const FilePath& custom_dictionary_file_name) - : given_dictionary_directory_(dict_dir), - custom_dictionary_file_name_(custom_dictionary_file_name), - tried_to_init_(false), - language_(language), - tried_to_download_dictionary_file_(false), - request_context_getter_(request_context_getter), - obtaining_dictionary_(false), - auto_spell_correct_turned_on_(false), - is_using_platform_spelling_engine_(false), - fetcher_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { - if (SpellCheckerPlatform::SpellCheckerAvailable()) { - SpellCheckerPlatform::Init(); - if (SpellCheckerPlatform::PlatformSupportsLanguage(language)) { - // If we have reached here, then we know that the current platform - // supports the given language and we will use it instead of hunspell. - SpellCheckerPlatform::SetLanguage(language); - is_using_platform_spelling_engine_ = true; - } - } - - // Get the corresponding BDIC file name. - bdic_file_name_ = GetVersionedFileName(language, dict_dir).BaseName(); - - // Get the path to the custom dictionary file. - if (custom_dictionary_file_name_.empty()) { - FilePath personal_file_directory; - PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); - custom_dictionary_file_name_ = - personal_file_directory.Append(chrome::kCustomDictionaryFileName); - } - - // Use this dictionary language as the default one of the - // SpellcheckCharAttribute object. - character_attributes_.SetDefaultLanguage(language); -} - -SpellChecker::~SpellChecker() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); -} - -void SpellChecker::StartDictionaryDownload(const FilePath& file_name) { - // 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(bdic_file_name_.ToWStringHack()))); - fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); - fetcher_->set_request_context(request_context_getter_); - obtaining_dictionary_ = true; - fetcher_->Start(); -} - -void SpellChecker::OnURLFetchComplete(const URLFetcher* source, - const GURL& url, - const URLRequestStatus& status, - int response_code, - const ResponseCookies& cookies, - const std::string& data) { - DCHECK(source); - if ((response_code / 100) != 2) { - obtaining_dictionary_ = false; - 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') { - obtaining_dictionary_ = false; - return; - } - - // Save the file in the file thread, and not here, the IO thread. - FilePath first_attempt_file_name = given_dictionary_directory_.Append( - bdic_file_name_); - FilePath user_data_dir = GetFallbackDictionaryDownloadDirectory(); - FilePath fallback_file_name = user_data_dir.Append(bdic_file_name_); - Task* dic_task = method_factory_. - NewRunnableMethod(&SpellChecker::OnDictionarySaveComplete); - ChromeThread::PostTask( - ChromeThread::FILE, FROM_HERE, - new SaveDictionaryTask( - dic_task, first_attempt_file_name, fallback_file_name, data)); -} - -void SpellChecker::OnDictionarySaveComplete() { - obtaining_dictionary_ = false; - // Now that the dictionary is downloaded, continue trying to download. - Initialize(); -} - -// Initialize SpellChecker. In this method, if the dictionary is not present -// in the local disk, it is fetched asynchronously. -bool SpellChecker::Initialize() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - - // Return false if the dictionary files are downloading. - if (obtaining_dictionary_) - return false; - - // Return false if tried to init and failed - don't try multiple times in - // this session. - if (tried_to_init_) - return hunspell_.get() != NULL; - - StatsScope<StatsCounterTimer> timer(chrome::Counters::spellcheck_init()); - - // The default place whether the spellcheck dictionary can reside is - // chrome::DIR_APP_DICTIONARIES. However, for systemwide installations, - // this directory may not have permissions for download. In that case, the - // alternate directory for download is chrome::DIR_USER_DATA. We have to check - // for the spellcheck dictionaries in both the directories. If not found in - // either one, it has to be downloaded in either of the two. - // TODO(sidchat): Some sort of UI to warn users that spellchecker is not - // working at all (due to failed dictionary download)? - - // File name for downloading in DIR_APP_DICTIONARIES. - FilePath dictionary_file_name_app = GetVersionedFileName(language_, - given_dictionary_directory_); - - // Filename for downloading in the fallback dictionary download directory, - // DIR_USER_DATA. - FilePath dict_dir_userdata = GetFallbackDictionaryDownloadDirectory(); - FilePath dictionary_file_name_usr = GetVersionedFileName(language_, - dict_dir_userdata); - - ChromeThread::PostTask( - ChromeThread::FILE, FROM_HERE, - new ReadDictionaryTask( - this, dictionary_file_name_app, dictionary_file_name_usr)); - - return hunspell_.get() != NULL; -} - -void SpellChecker::HunspellInited(Hunspell* hunspell, - file_util::MemoryMappedFile* bdict_file, - bool file_existed) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - - if (file_existed) - tried_to_init_ = true; - - if (!hunspell) { - if (!file_existed) { - // File didn't exist. We need to download a dictionary. - DoDictionaryDownload(); - } - return; - } - - - bdict_file_.reset(bdict_file); - hunspell_.reset(hunspell); - // Add all the custom words we've gotten while Hunspell was loading. - while (!custom_words_.empty()) { - hunspell_->add(custom_words_.front().c_str()); - custom_words_.pop(); - } -} - -void SpellChecker::DoDictionaryDownload() { - // Download the dictionary file. - if (request_context_getter_) { - if (!tried_to_download_dictionary_file_) { - FilePath dictionary_file_name_app = GetVersionedFileName(language_, - given_dictionary_directory_); - StartDictionaryDownload(dictionary_file_name_app); - tried_to_download_dictionary_file_ = true; - } else { - // Don't try to download a dictionary more than once. - tried_to_init_ = true; - } - } else { - NOTREACHED(); - } -} - -string16 SpellChecker::GetAutoCorrectionWord(const string16& word, int tag) { - string16 autocorrect_word; - if (!auto_spell_correct_turned_on_) - return autocorrect_word; // Return the empty string. - - int word_length = static_cast<int>(word.size()); - if (word_length < 2 || word_length > kMaxAutoCorrectWordSize) - return autocorrect_word; - - char16 misspelled_word[kMaxAutoCorrectWordSize + 1]; - const char16* word_char = word.c_str(); - for (int i = 0; i <= kMaxAutoCorrectWordSize; i++) { - if (i >= word_length) - misspelled_word[i] = NULL; - else - misspelled_word[i] = word_char[i]; - } - - // Swap adjacent characters and spellcheck. - int misspelling_start, misspelling_len; - for (int i = 0; i < word_length - 1; i++) { - // Swap. - std::swap(misspelled_word[i], misspelled_word[i + 1]); - - // Check spelling. - misspelling_start = misspelling_len = 0; - SpellCheckWord(misspelled_word, word_length, tag, &misspelling_start, - &misspelling_len, NULL); - - // Make decision: if only one swap produced a valid word, then we want to - // return it. If we found two or more, we don't do autocorrection. - if (misspelling_len == 0) { - if (autocorrect_word.empty()) { - autocorrect_word.assign(misspelled_word); - } else { - autocorrect_word.clear(); - break; - } - } - - // Restore the swapped characters. - std::swap(misspelled_word[i], misspelled_word[i + 1]); - } - return autocorrect_word; -} - -void SpellChecker::EnableAutoSpellCorrect(bool turn_on) { - auto_spell_correct_turned_on_ = turn_on; -} - -// Returns whether or not the given string is a valid contraction. -// This function is a fall-back when the SpellcheckWordIterator class -// returns a concatenated word which is not in the selected dictionary -// (e.g. "in'n'out") but each word is valid. -bool SpellChecker::IsValidContraction(const string16& contraction, int tag) { - SpellcheckWordIterator word_iterator; - word_iterator.Initialize(&character_attributes_, contraction.c_str(), - contraction.length(), false); - - string16 word; - int word_start; - int word_length; - while (word_iterator.GetNextWord(&word, &word_start, &word_length)) { - if (!CheckSpelling(word, tag)) - return false; - } - return true; -} - -bool SpellChecker::SpellCheckWord( - const char16* in_word, - int in_word_len, - int tag, - int* misspelling_start, - int* misspelling_len, - std::vector<string16>* optional_suggestions) { - DCHECK(in_word_len >= 0); - DCHECK(misspelling_start && misspelling_len) << "Out vars must be given."; - - // This must always be called on the same thread (normally the I/O thread). - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - - // Check if the platform spellchecker is being used. - if (!is_using_platform_spelling_engine_) { - // If it isn't, try and init hunspell. - Initialize(); - - // Check to see if hunspell was successfuly initialized. - if (!hunspell_.get()) - return true; // Unable to spellcheck, return word is OK. - } - - StatsScope<StatsRate> timer(chrome::Counters::spellcheck_lookup()); - - *misspelling_start = 0; - *misspelling_len = 0; - if (in_word_len == 0) - return true; // No input means always spelled correctly. - - SpellcheckWordIterator word_iterator; - string16 word; - int word_start; - int word_length; - word_iterator.Initialize(&character_attributes_, in_word, in_word_len, true); - while (word_iterator.GetNextWord(&word, &word_start, &word_length)) { - // Found a word (or a contraction) that the spellchecker can check the - // spelling of. - bool word_ok = CheckSpelling(word, tag); - if (word_ok) - continue; - - // If the given word is a concatenated word of two or more valid words - // (e.g. "hello:hello"), we should treat it as a valid word. - if (IsValidContraction(word, tag)) - continue; - - *misspelling_start = word_start; - *misspelling_len = word_length; - - // Get the list of suggested words. - if (optional_suggestions) - FillSuggestionList(word, optional_suggestions); - return false; - } - - return true; -} - -// This task is called in the file loop to write the new word to the custom -// dictionary in disc. -class AddWordToCustomDictionaryTask : public Task { - public: - AddWordToCustomDictionaryTask(const FilePath& file_name, - const string16& word) - : file_name_(file_name), - word_(UTF16ToUTF8(word)) { - } - - private: - void Run(); - - FilePath file_name_; - std::string word_; -}; - -void AddWordToCustomDictionaryTask::Run() { - // Add the word with a new line. Note that, although this would mean an - // extra line after the list of words, this is potentially harmless and - // faster, compared to verifying everytime whether to append a new line - // or not. - word_ += "\n"; - FILE* f = file_util::OpenFile(file_name_, "a+"); - if (f != NULL) - fputs(word_.c_str(), f); - file_util::CloseFile(f); -} - -void SpellChecker::AddWord(const string16& word) { - if (is_using_platform_spelling_engine_) { - SpellCheckerPlatform::AddWord(word); - return; - } - - // Check if the |hunspell_| has been initialized at all. - Initialize(); - - // Add the word to hunspell. - std::string word_to_add = UTF16ToUTF8(word); - // Don't attempt to add an empty word, or one larger than Hunspell can handle - if (!word_to_add.empty() && word_to_add.length() < MAXWORDLEN) { - // Either add the word to |hunspell_|, or, if |hunspell_| is still loading, - // defer it till after the load completes. - if (hunspell_.get()) - hunspell_->add(word_to_add.c_str()); - else - custom_words_.push(word_to_add); - } - - // Now add the word to the custom dictionary file. - ChromeThread::PostTask( - ChromeThread::FILE, FROM_HERE, - new AddWordToCustomDictionaryTask(custom_dictionary_file_name_, word)); -} - -bool SpellChecker::CheckSpelling(const string16& word_to_check, int tag) { - bool word_correct = false; - - TimeTicks begin_time = TimeTicks::Now(); - if (is_using_platform_spelling_engine_) { - word_correct = SpellCheckerPlatform::CheckSpelling(word_to_check, tag); - } else { - std::string word_to_check_utf8(UTF16ToUTF8(word_to_check)); - // Hunspell shouldn't let us exceed its max, but check just in case - if (word_to_check_utf8.length() < MAXWORDLEN) { - // |hunspell_->spell| returns 0 if the word is spelled correctly and - // non-zero otherwsie. - word_correct = (hunspell_->spell(word_to_check_utf8.c_str()) != 0); - } - } - DHISTOGRAM_TIMES("Spellcheck.CheckTime", TimeTicks::Now() - begin_time); - - return word_correct; -} - -void SpellChecker::FillSuggestionList( - const string16& wrong_word, - std::vector<string16>* optional_suggestions) { - if (is_using_platform_spelling_engine_) { - SpellCheckerPlatform::FillSuggestionList(wrong_word, optional_suggestions); - return; - } - char** suggestions; - TimeTicks begin_time = TimeTicks::Now(); - int number_of_suggestions = hunspell_->suggest(&suggestions, - UTF16ToUTF8(wrong_word).c_str()); - DHISTOGRAM_TIMES("Spellcheck.SuggestTime", - TimeTicks::Now() - begin_time); - - // Populate the vector of WideStrings. - for (int i = 0; i < number_of_suggestions; i++) { - if (i < kMaxSuggestions) - optional_suggestions->push_back(UTF8ToUTF16(suggestions[i])); - free(suggestions[i]); - } - if (suggestions != NULL) - free(suggestions); -} diff --git a/chrome/browser/spellchecker.h b/chrome/browser/spellchecker.h deleted file mode 100644 index 630f815..0000000 --- a/chrome/browser/spellchecker.h +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) 2006-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. - -#ifndef CHROME_BROWSER_SPELLCHECKER_H_ -#define CHROME_BROWSER_SPELLCHECKER_H_ - -#include <queue> -#include <string> -#include <vector> - -#include "app/l10n_util.h" -#include "base/string16.h" -#include "base/task.h" -#include "base/time.h" -#include "chrome/browser/chrome_thread.h" -#include "chrome/browser/net/url_fetcher.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/spellcheck_worditerator.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/pref_member.h" -#include "unicode/uscript.h" - -class FilePath; -class Hunspell; -class PrefService; -class Profile; -class URLFetcher; -class URLRequestContextGetter; - -namespace file_util { -class MemoryMappedFile; -} - -// The Browser's Spell Checker. It checks and suggests corrections. -// -// This object is not threadsafe. In normal usage (not unit tests) it lives on -// the I/O thread of the browser. It is threadsafe refcounted so that I/O thread -// and the profile on the main thread (which gives out references to it) can -// keep it. However, all usage of this must be on the I/O thread. -// -// This object should also be deleted on the I/O thread only. It owns a -// reference to URLRequestContext which in turn owns the cache, etc. and must be -// deleted on the I/O thread itself. -class SpellChecker - : public base::RefCountedThreadSafe< - SpellChecker, ChromeThread::DeleteOnIOThread>, - public URLFetcher::Delegate { - public: - // Creates the spellchecker by reading dictionaries from the given directory, - // and defaulting to the given language. Both strings must be provided. - // - // The request context is used to download dictionaries if they do not exist. - // This can be NULL if you don't want this (like in tests). - // The |custom_dictionary_file_name| should be left blank so that Spellchecker - // can figure out the custom dictionary file. It is non empty only for unit - // testing. - SpellChecker(const FilePath& dict_dir, - const std::string& language, - URLRequestContextGetter* request_context_getter, - const FilePath& custom_dictionary_file_name); - - // SpellCheck a word. - // Returns true if spelled correctly, false otherwise. - // If the spellchecker failed to initialize, always returns true. - // The |tag| parameter should either be a unique identifier for the document - // that the word came from (if the current platform requires it), or 0. - // In addition, finds the suggested words for a given word - // and puts them into |*optional_suggestions|. - // If the word is spelled correctly, the vector is empty. - // If optional_suggestions is NULL, suggested words will not be looked up. - // Note that Doing suggest lookups can be slow. - bool SpellCheckWord(const char16* in_word, - int in_word_len, - int tag, - int* misspelling_start, - int* misspelling_len, - std::vector<string16>* optional_suggestions); - - // Find a possible correctly spelled word for a misspelled word. Computes an - // empty string if input misspelled word is too long, there is ambiguity, or - // the correct spelling cannot be determined. - string16 GetAutoCorrectionWord(const string16& word, int tag); - - // Turn auto spell correct support ON or OFF. - // |turn_on| = true means turn ON; false means turn OFF. - void EnableAutoSpellCorrect(bool turn_on); - - // Add custom word to the dictionary, which means: - // a) Add it to the current hunspell object for immediate use, - // b) Add the word to a file in disk for custom dictionary. - void AddWord(const string16& word); - - // Get SpellChecker supported languages. - static void SpellCheckLanguages(std::vector<std::string>* languages); - - // This function computes a vector of strings which are to be displayed in - // the context menu over a text area for changing spell check languages. It - // returns the index of the current spell check language in the vector. - // TODO(port): this should take a vector of string16, but the implementation - // has some dependencies in l10n util that need porting first. - static int GetSpellCheckLanguages( - Profile* profile, - std::vector<std::string>* languages); - - // This function returns the corresponding language-region code for the - // spell check language. For example, for hi, it returns hi-IN. - static std::string GetSpellCheckLanguageRegion(std::string input_language); - - // This function returns ll (language code) from ll-RR where 'RR' (region - // code) is redundant. However, if the region code matters, it's preserved. - // That is, it returns 'hi' and 'en-GB' for 'hi-IN' and 'en-GB' respectively. - static std::string GetLanguageFromLanguageRegion(std::string input_language); - - private: - friend class ChromeThread; - friend class DeleteTask<SpellChecker>; - friend class ReadDictionaryTask; - FRIEND_TEST(SpellCheckTest, SpellCheckStrings_EN_US); - FRIEND_TEST(SpellCheckTest, SpellCheckSuggestions_EN_US); - FRIEND_TEST(SpellCheckTest, SpellCheckText); - FRIEND_TEST(SpellCheckTest, DISABLED_SpellCheckAddToDictionary_EN_US); - FRIEND_TEST(SpellCheckTest, - DISABLED_SpellCheckSuggestionsAddToDictionary_EN_US); - FRIEND_TEST(SpellCheckTest, GetAutoCorrectionWord_EN_US); - FRIEND_TEST(SpellCheckTest, IgnoreWords_EN_US); - - // Only delete on the I/O thread (see above). - ~SpellChecker(); - - // URLFetcher::Delegate implementation. Called when we finish downloading the - // spellcheck dictionary; saves the dictionary to disk. - virtual void OnURLFetchComplete(const URLFetcher* source, - const GURL& url, - const URLRequestStatus& status, - int response_code, - const ResponseCookies& cookies, - const std::string& data); - - // When called, relays the request to check the spelling to the proper - // backend, either hunspell or a platform-specific backend. - bool CheckSpelling(const string16& word_to_check, int tag); - - // When called, relays the request to fill the list with suggestions to - // the proper backend, either hunspell or a platform-specific backend. - void FillSuggestionList(const string16& wrong_word, - std::vector<string16>* optional_suggestions); - - // Initializes the Hunspell Dictionary. - bool Initialize(); - - // Called when |hunspell| is done loading, succesfully or not. If |hunspell| - // and |bdict_file| are non-NULL, assume ownership. - void HunspellInited(Hunspell* hunspell, - file_util::MemoryMappedFile* bdict_file, - bool file_existed); - - // Either start downloading a dictionary if we have not already, or do nothing - // if we have already tried to download one. - void DoDictionaryDownload(); - - // Returns whether or not the given word is a contraction of valid words - // (e.g. "word:word"). - bool IsValidContraction(const string16& word, int tag); - - // Return the file name of the dictionary, including the path and the version - // numbers. - FilePath GetVersionedFileName(const std::string& language, - const FilePath& dict_dir); - - static std::string GetCorrespondingSpellCheckLanguage( - const std::string& language); - - // Start downloading a dictionary from the server. On completion, the - // OnURLFetchComplete() function is invoked. - void StartDictionaryDownload(const FilePath& file_name); - - // This method is called in the IO thread after dictionary download has - // completed in FILE thread. - void OnDictionarySaveComplete(); - - // The given path to the directory whether SpellChecker first tries to - // download the spellcheck bdic dictionary file. - FilePath given_dictionary_directory_; - - // Path to the custom dictionary file. - FilePath custom_dictionary_file_name_; - - // BDIC file name (e.g. en-US_1_1.bdic). - FilePath bdic_file_name_; - - // We memory-map the BDict file. - scoped_ptr<file_util::MemoryMappedFile> bdict_file_; - - // The hunspell dictionary in use. - scoped_ptr<Hunspell> hunspell_; - - // Represents character attributes used for filtering out characters which - // are not supported by this SpellChecker object. - SpellcheckCharAttribute character_attributes_; - - // Flag indicating whether we've tried to initialize. If we've already - // attempted initialiation, we won't retry to avoid failure loops. - bool tried_to_init_; - - // The language that this spellchecker works in. - std::string language_; - - // This object must only be used on the same thread. However, it is normally - // created on the UI thread. This checks calls to SpellCheckWord and the - // destructor to make sure we're only ever running on the same thread. - // - // This will be NULL if it is not initialized yet (not initialized in the - // constructor since that's on a different thread). - MessageLoop* worker_loop_; - - // Flag indicating whether we tried to download the dictionary file. - bool tried_to_download_dictionary_file_; - - // Used for requests. MAY BE NULL which means don't try to download. - URLRequestContextGetter* request_context_getter_; - - // True when we're downloading or saving a dictionary. - bool obtaining_dictionary_; - - // Remember state for auto spell correct. - bool auto_spell_correct_turned_on_; - - // True if a platform-specific spellchecking engine is being used, - // and False if hunspell is being used. - bool is_using_platform_spelling_engine_; - - // URLFetcher to download a file in memory. - scoped_ptr<URLFetcher> fetcher_; - - // While Hunspell is loading, we add any new custom words to this queue. - // We will add them to |hunspell_| when it is done loading. - std::queue<std::string> custom_words_; - - // Used for generating callbacks to spellchecker, since spellchecker is a - // non-reference counted object. - ScopedRunnableMethodFactory<SpellChecker> method_factory_; - - DISALLOW_COPY_AND_ASSIGN(SpellChecker); -}; - -#endif // CHROME_BROWSER_SPELLCHECKER_H_ diff --git a/chrome/browser/spellchecker_common.h b/chrome/browser/spellchecker_common.h deleted file mode 100644 index 4d393ab..0000000 --- a/chrome/browser/spellchecker_common.h +++ /dev/null @@ -1,19 +0,0 @@ -// 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. - -#ifndef CHROME_BROWSER_SPELLCHECKER_COMMON_H_ -#define CHROME_BROWSER_SPELLCHECKER_COMMON_H_ - -#include <string> -#include <vector> - -// Some constants and typedefs that are common to all spellchecker -// files/classes/backends/platforms/whatever. - -static const int kMaxSuggestions = 5; // Max number of dictionary suggestions. - -static const int kMaxAutoCorrectWordSize = 8; - -#endif // CHROME_BROWSER_SPELLCHECKER_COMMON_H_ - diff --git a/chrome/browser/spellchecker_linux.cc b/chrome/browser/spellchecker_linux.cc index 9f0f144..8637edc 100644 --- a/chrome/browser/spellchecker_linux.cc +++ b/chrome/browser/spellchecker_linux.cc @@ -5,14 +5,13 @@ // If linux ever gains a platform specific spellchecker, it will be // implemented here. -#include "base/string16.h" -#include "chrome/browser/spellchecker_common.h" +#include "spellchecker_platform_engine.h" namespace SpellCheckerPlatform { bool SpellCheckerAvailable() { // As of Summer 2009, there is no commonly accepted platform spellchecker - // for linux, so we'll return false here. + // for Linux, so we'll return false here. return false; } @@ -54,7 +53,7 @@ void RemoveWord(const string16& word) {} int GetDocumentTag() { return 0; } -void IgnoreWord(const std::string& word) {} +void IgnoreWord(const string16& word) {} void CloseDocumentWithTag(int tag) {} diff --git a/chrome/browser/spellchecker_mac.mm b/chrome/browser/spellchecker_mac.mm index 72c06e1..70db304 100644 --- a/chrome/browser/spellchecker_mac.mm +++ b/chrome/browser/spellchecker_mac.mm @@ -5,14 +5,15 @@ // This file implements the interface defined in spellchecker_platform_engine.h // for the OS X platform. +#include "chrome/browser/spellchecker_platform_engine.h" + #import <Cocoa/Cocoa.h> #include "base/logging.h" #include "base/time.h" #include "base/histogram.h" #include "base/sys_string_conversions.h" -#include "chrome/browser/spellchecker_common.h" -#include "chrome/browser/spellchecker_platform_engine.h" +#include "chrome/common/spellcheck_common.h" using base::TimeTicks; namespace { @@ -175,7 +176,7 @@ void FillSuggestionList(const string16& wrong_word, TimeTicks::Now() - begin_time); for (int i = 0; i < static_cast<int>([guesses count]); i++) { - if (i < kMaxSuggestions) { + if (i < SpellCheckCommon::kMaxSuggestions) { optional_suggestions->push_back(base::SysNSStringToUTF16( [guesses objectAtIndex:i])); } diff --git a/chrome/browser/spellchecker_platform_engine.h b/chrome/browser/spellchecker_platform_engine.h index d9a0588..5762ab2 100644 --- a/chrome/browser/spellchecker_platform_engine.h +++ b/chrome/browser/spellchecker_platform_engine.h @@ -12,7 +12,6 @@ #include <vector> #include "base/string16.h" -#include "chrome/browser/spellchecker_common.h" namespace SpellCheckerPlatform { diff --git a/chrome/browser/spellchecker_platform_engine_unittest.cc b/chrome/browser/spellchecker_platform_engine_unittest.cc new file mode 100644 index 0000000..d4bf050 --- /dev/null +++ b/chrome/browser/spellchecker_platform_engine_unittest.cc @@ -0,0 +1,393 @@ +// 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 "base/string_util.h" +#include "chrome/browser/spellchecker_platform_engine.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(OS_MACOSX) +#define MAYBE_IgnoreWords_EN_US IgnoreWords_EN_US +#else +#define MAYBE_IgnoreWords_EN_US DISABLED_IgnoreWords_EN_US +#endif + +// Tests that words are properly ignored. Currently only enabled on OS X as it +// is the only platform to support ignoring words. Note that in this test, we +// supply a non-zero doc_tag, in order to test that ignored words are matched to +// the correct document. +TEST(PlatformSpellCheckTest, MAYBE_IgnoreWords_EN_US) { + static const struct { + // A misspelled word. + const char* input; + bool input_result; + } kTestCases[] = { + {"teh"}, + {"moer"}, + {"watre"}, + {"noen"}, + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { + string16 word(UTF8ToUTF16(kTestCases[i].input)); + std::vector<string16> suggestions; + size_t input_length = 0; + if (kTestCases[i].input != NULL) { + input_length = word.length(); + } + + int doc_tag = SpellCheckerPlatform::GetDocumentTag(); + bool result = SpellCheckerPlatform::CheckSpelling(word, doc_tag); + + // The word should show up as misspelled. + EXPECT_EQ(kTestCases[i].input_result, result); + + // Ignore the word. + SpellCheckerPlatform::IgnoreWord(word); + + // Spellcheck again. + result = SpellCheckerPlatform::CheckSpelling(word, doc_tag); + + // The word should now show up as correctly spelled. + EXPECT_EQ(!(kTestCases[i].input_result), result); + + // Close the docuemnt. Any words that we had previously ignored should no + // longer be ignored and thus should show up as misspelled. + SpellCheckerPlatform::CloseDocumentWithTag(doc_tag); + + // Spellcheck one more time. + result = SpellCheckerPlatform::CheckSpelling(word, doc_tag); + + // The word should now show be spelled wrong again + EXPECT_EQ(kTestCases[i].input_result, result); + } +} // Test IgnoreWords_EN_US + +#if defined(OS_MACOSX) +TEST(PlatformSpellCheckTest, SpellCheckSuggestions_EN_US) { + static const struct { + // A string to be tested. + const wchar_t* input; + + // A suggested word that should occur. + const wchar_t* suggested_word; + } kTestCases[] = { // A valid English word with a preceding whitespace + // We need to have separate test cases here, since hunspell and the OS X + // spellchecking service occasionally differ on what they consider a valid + // suggestion for a given word, although these lists could likely be + // integrated somewhat. The test cases for non-Mac are in + // chrome/renderer/spellcheck_unittest.cc + // These words come from the wikipedia page of the most commonly + // misspelled words in english. + // (http://en.wikipedia.org/wiki/Commonly_misspelled_words). + {L"absense", L"absence"}, + {L"acceptible", L"acceptable"}, + {L"accidentaly", L"accidentally"}, + {L"accomodate", L"accommodate"}, + {L"acheive", L"achieve"}, + {L"acknowlege", L"acknowledge"}, + {L"acquaintence", L"acquaintance"}, + {L"aquire", L"acquire"}, + {L"aquit", L"acquit"}, + {L"acrage", L"acreage"}, + {L"adress", L"address"}, + {L"adultary", L"adultery"}, + {L"advertize", L"advertise"}, + {L"adviseable", L"advisable"}, + {L"agression", L"aggression"}, + {L"alchohol", L"alcohol"}, + {L"alege", L"allege"}, + {L"allegaince", L"allegiance"}, + {L"allmost", L"almost"}, + // Ideally, this test should pass. It works in firefox, but not in hunspell + // or OS X. + // {L"alot", L"a lot"}, + {L"amatuer", L"amateur"}, + {L"ammend", L"amend"}, + {L"amung", L"among"}, + {L"anually", L"annually"}, + {L"apparant", L"apparent"}, + {L"artic", L"arctic"}, + {L"arguement", L"argument"}, + {L"athiest", L"atheist"}, + {L"athelete", L"athlete"}, + {L"avrage", L"average"}, + {L"awfull", L"awful"}, + {L"ballance", L"balance"}, + {L"basicly", L"basically"}, + {L"becuase", L"because"}, + {L"becomeing", L"becoming"}, + {L"befor", L"before"}, + {L"begining", L"beginning"}, + {L"beleive", L"believe"}, + {L"bellweather", L"bellwether"}, + {L"benifit", L"benefit"}, + {L"bouy", L"buoy"}, + {L"briliant", L"brilliant"}, + {L"burgler", L"burglar"}, + {L"camoflage", L"camouflage"}, + {L"carrer", L"career"}, + {L"carefull", L"careful"}, + {L"Carribean", L"Caribbean"}, + {L"catagory", L"category"}, + {L"cauhgt", L"caught"}, + {L"cieling", L"ceiling"}, + {L"cemetary", L"cemetery"}, + {L"certin", L"certain"}, + {L"changable", L"changeable"}, + {L"cheif", L"chief"}, + {L"citezen", L"citizen"}, + {L"collaegue", L"colleague"}, + {L"colum", L"column"}, + {L"comming", L"coming"}, + {L"commited", L"committed"}, + {L"compitition", L"competition"}, + {L"conceed", L"concede"}, + {L"congradulate", L"congratulate"}, + {L"consciencious", L"conscientious"}, + {L"concious", L"conscious"}, + {L"concensus", L"consensus"}, + {L"contraversy", L"controversy"}, + {L"conveniance", L"convenience"}, + {L"critecize", L"criticize"}, + {L"dacquiri", L"daiquiri"}, + {L"decieve", L"deceive"}, + {L"dicide", L"decide"}, + {L"definate", L"definite"}, + {L"definitly", L"definitely"}, + {L"deposite", L"deposit"}, + {L"desparate", L"desperate"}, + {L"develope", L"develop"}, + {L"diffrence", L"difference"}, + {L"dilema", L"dilemma"}, + {L"disapear", L"disappear"}, + {L"disapoint", L"disappoint"}, + {L"disasterous", L"disastrous"}, + {L"disipline", L"discipline"}, + {L"drunkeness", L"drunkenness"}, + {L"dumbell", L"dumbbell"}, + {L"durring", L"during"}, + {L"easely", L"easily"}, + {L"eigth", L"eight"}, + {L"embarass", L"embarrass"}, + {L"enviroment", L"environment"}, + {L"equiped", L"equipped"}, + {L"equiptment", L"equipment"}, + {L"exagerate", L"exaggerate"}, + {L"excede", L"exceed"}, + {L"exellent", L"excellent"}, + {L"exsept", L"except"}, + {L"exercize", L"exercise"}, + {L"exilerate", L"exhilarate"}, + {L"existance", L"existence"}, + {L"experiance", L"experience"}, + {L"experament", L"experiment"}, + {L"explaination", L"explanation"}, + {L"extreem", L"extreme"}, + {L"familier", L"familiar"}, + {L"facinating", L"fascinating"}, + {L"firey", L"fiery"}, + {L"finaly", L"finally"}, + {L"flourescent", L"fluorescent"}, + {L"foriegn", L"foreign"}, + {L"fourty", L"forty"}, + {L"foreward", L"forward"}, + {L"freind", L"friend"}, + {L"fullfil", L"fulfill"}, + {L"fundemental", L"fundamental"}, + {L"guage", L"gauge"}, + {L"generaly", L"generally"}, + {L"goverment", L"government"}, + {L"grammer", L"grammar"}, + {L"gratefull", L"grateful"}, + {L"garantee", L"guarantee"}, + {L"guidence", L"guidance"}, + {L"happyness", L"happiness"}, + {L"harrass", L"harass"}, + {L"heighth", L"height"}, + {L"heirarchy", L"hierarchy"}, + {L"humerous", L"humorous"}, + {L"hygene", L"hygiene"}, + {L"hipocrit", L"hypocrite"}, + {L"idenity", L"identity"}, + {L"ignorence", L"ignorance"}, + {L"imaginery", L"imaginary"}, + {L"immitate", L"imitate"}, + {L"immitation", L"imitation"}, + {L"imediately", L"immediately"}, + {L"incidently", L"incidentally"}, + {L"independant", L"independent"}, + {L"indispensible", L"indispensable"}, + {L"innoculate", L"inoculate"}, + {L"inteligence", L"intelligence"}, + {L"intresting", L"interesting"}, + {L"interuption", L"interruption"}, + {L"irrelevent", L"irrelevant"}, + {L"irritible", L"irritable"}, + {L"iland", L"island"}, + {L"jellous", L"jealous"}, + {L"knowlege", L"knowledge"}, + {L"labratory", L"laboratory"}, + {L"liesure", L"leisure"}, + {L"lenght", L"length"}, + {L"liason", L"liaison"}, + {L"libary", L"library"}, + {L"lisence", L"license"}, + {L"lonelyness", L"loneliness"}, + {L"lieing", L"lying"}, + {L"maintenence", L"maintenance"}, + {L"manuever", L"maneuver"}, + {L"marrige", L"marriage"}, + {L"mathmatics", L"mathematics"}, + {L"medcine", L"medicine"}, + {L"medeval", L"medieval"}, + {L"momento", L"memento"}, + {L"millenium", L"millennium"}, + {L"miniture", L"miniature"}, + {L"minite", L"minute"}, + {L"mischevous", L"mischievous"}, + {L"mispell", L"misspell"}, + // Maybe this one should pass, as it works in hunspell, but not in firefox. + // {L"misterius", L"mysterious"}, + {L"naturaly", L"naturally"}, + {L"neccessary", L"necessary"}, + {L"neice", L"niece"}, + {L"nieghbor", L"neighbor"}, + {L"nieghbour", L"neighbor"}, + {L"niether", L"neither"}, + {L"noticable", L"noticeable"}, + {L"occassion", L"occasion"}, + {L"occasionaly", L"occasionally"}, + {L"occurrance", L"occurrence"}, + {L"occured", L"occurred"}, + {L"oficial", L"official"}, + {L"offen", L"often"}, + {L"ommision", L"omission"}, + {L"oprate", L"operate"}, + {L"oppurtunity", L"opportunity"}, + {L"orignal", L"original"}, + {L"outragous", L"outrageous"}, + {L"parrallel", L"parallel"}, + {L"parliment", L"parliament"}, + {L"particurly", L"particularly"}, + {L"passtime", L"pastime"}, + {L"peculier", L"peculiar"}, + {L"percieve", L"perceive"}, + {L"pernament", L"permanent"}, + {L"perseverence", L"perseverance"}, + {L"personaly", L"personally"}, + {L"personell", L"personnel"}, + {L"persaude", L"persuade"}, + {L"pichure", L"picture"}, + {L"peice", L"piece"}, + {L"plagerize", L"plagiarize"}, + {L"playright", L"playwright"}, + {L"plesant", L"pleasant"}, + {L"pollitical", L"political"}, + {L"posession", L"possession"}, + {L"potatos", L"potatoes"}, + {L"practicle", L"practical"}, + {L"preceed", L"precede"}, + {L"predjudice", L"prejudice"}, + {L"presance", L"presence"}, + {L"privelege", L"privilege"}, + // This one should probably work. It does in FF and Hunspell. + // {L"probly", L"probably"}, + {L"proffesional", L"professional"}, + {L"professer", L"professor"}, + {L"promiss", L"promise"}, + {L"pronounciation", L"pronunciation"}, + {L"prufe", L"proof"}, + {L"psycology", L"psychology"}, + {L"publically", L"publicly"}, + {L"quanity", L"quantity"}, + {L"quarentine", L"quarantine"}, + {L"questionaire", L"questionnaire"}, + {L"readible", L"readable"}, + {L"realy", L"really"}, + {L"recieve", L"receive"}, + {L"reciept", L"receipt"}, + {L"reconize", L"recognize"}, + {L"recomend", L"recommend"}, + {L"refered", L"referred"}, + {L"referance", L"reference"}, + {L"relevent", L"relevant"}, + {L"religous", L"religious"}, + {L"repitition", L"repetition"}, + {L"restarant", L"restaurant"}, + {L"rythm", L"rhythm"}, + {L"rediculous", L"ridiculous"}, + {L"sacrefice", L"sacrifice"}, + {L"saftey", L"safety"}, + {L"sissors", L"scissors"}, + {L"secratary", L"secretary"}, + {L"sieze", L"seize"}, + {L"seperate", L"separate"}, + {L"sargent", L"sergeant"}, + {L"shineing", L"shining"}, + {L"similer", L"similar"}, + {L"sinceerly", L"sincerely"}, + {L"speach", L"speech"}, + {L"stoping", L"stopping"}, + {L"strenght", L"strength"}, + {L"succede", L"succeed"}, + {L"succesful", L"successful"}, + {L"supercede", L"supersede"}, + {L"surelly", L"surely"}, + {L"suprise", L"surprise"}, + {L"temperture", L"temperature"}, + {L"temprary", L"temporary"}, + {L"tomatos", L"tomatoes"}, + {L"tommorrow", L"tomorrow"}, + {L"tounge", L"tongue"}, + {L"truely", L"truly"}, + {L"twelth", L"twelfth"}, + {L"tyrany", L"tyranny"}, + {L"underate", L"underrate"}, + {L"untill", L"until"}, + {L"unuseual", L"unusual"}, + {L"upholstry", L"upholstery"}, + {L"usible", L"usable"}, + {L"useing", L"using"}, + {L"usualy", L"usually"}, + {L"vaccuum", L"vacuum"}, + {L"vegatarian", L"vegetarian"}, + {L"vehical", L"vehicle"}, + {L"visious", L"vicious"}, + {L"villege", L"village"}, + {L"wierd", L"weird"}, + {L"wellcome", L"welcome"}, + {L"wellfare", L"welfare"}, + {L"wilfull", L"willful"}, + {L"withold", L"withhold"}, + {L"writting", L"writing"}, + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { + std::vector<string16> suggestions; + size_t input_length = 0; + if (kTestCases[i].input != NULL) { + input_length = wcslen(kTestCases[i].input); + } + bool result = SpellCheckerPlatform::CheckSpelling( + WideToUTF16(kTestCases[i].input), 0); + EXPECT_FALSE(result); + + SpellCheckerPlatform::FillSuggestionList(WideToUTF16(kTestCases[i].input), + &suggestions); + + // Check if the suggested words occur. + bool suggested_word_is_present = false; + for (int j=0; j < static_cast<int>(suggestions.size()); j++) { + if (suggestions.at(j).compare(WideToUTF16(kTestCases[i].suggested_word)) + == 0) { + suggested_word_is_present = true; + break; + } + } + + EXPECT_TRUE(suggested_word_is_present); + } +} + +#endif // defined(OS_MACOSX) diff --git a/chrome/browser/spellchecker_win.cc b/chrome/browser/spellchecker_win.cc index cee7a98..1f318a0 100644 --- a/chrome/browser/spellchecker_win.cc +++ b/chrome/browser/spellchecker_win.cc @@ -7,8 +7,6 @@ #include "chrome/browser/spellchecker_platform_engine.h" -#include "chrome/browser/spellchecker_common.h" - namespace SpellCheckerPlatform { bool SpellCheckerAvailable() { diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc index 9f5665c6..841e770 100644 --- a/chrome/browser/tab_contents/render_view_context_menu.cc +++ b/chrome/browser/tab_contents/render_view_context_menu.cc @@ -20,15 +20,13 @@ #include "chrome/browser/profile.h" #include "chrome/browser/search_versus_navigate_classifier.h" #include "chrome/browser/search_engines/template_url_model.h" -#if defined(SPELLCHECKER_IN_RENDERER) #include "chrome/browser/spellcheck_host.h" -#endif -#include "chrome/browser/spellchecker.h" #include "chrome/browser/spellchecker_platform_engine.h" #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/platform_util.h" +#include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" #include "chrome/common/url_constants.h" #include "grit/generated_resources.h" @@ -273,7 +271,7 @@ void RenderViewContextMenu::AppendEditableItems() { // Add Spell Check languages to sub menu. std::vector<std::string> spellcheck_languages; - SpellChecker::GetSpellCheckLanguages(profile_, + SpellCheckHost::GetSpellCheckLanguages(profile_, &spellcheck_languages); DCHECK(spellcheck_languages.size() < IDC_SPELLCHECK_LANGUAGES_LAST - IDC_SPELLCHECK_LANGUAGES_FIRST); @@ -490,7 +488,7 @@ bool RenderViewContextMenu::ItemIsChecked(int id) const { return false; std::vector<std::string> languages; - return SpellChecker::GetSpellCheckLanguages(profile_, &languages) == + return SpellCheckHost::GetSpellCheckLanguages(profile_, &languages) == (id - IDC_SPELLCHECK_LANGUAGES_FIRST); } @@ -500,7 +498,7 @@ void RenderViewContextMenu::ExecuteItemCommand(int id) { id < IDC_SPELLCHECK_LANGUAGES_LAST) { const size_t language_number = id - IDC_SPELLCHECK_LANGUAGES_FIRST; std::vector<std::string> languages; - SpellChecker::GetSpellCheckLanguages(profile_, &languages); + SpellCheckHost::GetSpellCheckLanguages(profile_, &languages); if (language_number < languages.size()) { StringPrefMember dictionary_language; dictionary_language.Init(prefs::kSpellCheckDictionary, @@ -724,17 +722,13 @@ void RenderViewContextMenu::ExecuteItemCommand(int id) { source_tab_contents_->render_view_host()->ToggleSpellCheck(); break; case IDS_CONTENT_CONTEXT_ADD_TO_DICTIONARY: { -#if defined(SPELLCHECKER_IN_RENDERER) SpellCheckHost* spellcheck_host = profile_->GetSpellCheckHost(); if (!spellcheck_host) { NOTREACHED(); break; } spellcheck_host->AddWord(UTF16ToUTF8(params_.misspelled_word)); -#else - source_tab_contents_->render_view_host()->AddToDictionary( - params_.misspelled_word); -#endif + SpellCheckerPlatform::AddWord(params_.misspelled_word); break; } diff --git a/chrome/browser/views/options/languages_page_view.cc b/chrome/browser/views/options/languages_page_view.cc index d7c7604..542c66f 100644 --- a/chrome/browser/views/options/languages_page_view.cc +++ b/chrome/browser/views/options/languages_page_view.cc @@ -1,6 +1,7 @@ // 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 <windows.h> #include <shlobj.h> #include <vsstyle.h> @@ -21,11 +22,11 @@ #include "chrome/browser/language_combobox_model.h" #include "chrome/browser/language_order_table_model.h" #include "chrome/browser/shell_dialogs.h" -#include "chrome/browser/spellchecker.h" #include "chrome/browser/views/restart_message_box.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" +#include "chrome/common/spellcheck_common.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" @@ -350,7 +351,7 @@ void LanguagesPageView::InitControlLayout() { // Determine Locale Codes. std::vector<std::string> spell_check_languages; - SpellChecker::SpellCheckLanguages(&spell_check_languages); + SpellCheckCommon::SpellCheckLanguages(&spell_check_languages); dictionary_language_model_.reset(new LanguageComboboxModel(profile(), spell_check_languages)); change_dictionary_language_combobox_ = @@ -432,7 +433,7 @@ void LanguagesPageView::NotifyPrefChanged(const std::wstring* pref_name) { const std::string& lang_region = WideToASCII( dictionary_language_.GetValue()); dictionary_language_.SetValue(ASCIIToWide( - SpellChecker::GetLanguageFromLanguageRegion(lang_region))); + SpellCheckCommon::GetLanguageFromLanguageRegion(lang_region))); index = dictionary_language_model_->GetSelectedLanguageIndex( prefs::kSpellCheckDictionary); } diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 47ba1d3..e37fe8e 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -682,6 +682,8 @@ 'common/sandbox_init_wrapper_win.cc', 'common/sandbox_mac.h', 'common/sandbox_mac.mm', + 'common/spellcheck_common.cc', + 'common/spellcheck_common.h', 'common/security_filter_peer.cc', 'common/security_filter_peer.h', 'common/nacl_messages.h', @@ -2138,10 +2140,6 @@ 'browser/shell_integration_win.cc', 'browser/spellcheck_host.cc', 'browser/spellcheck_host.h', - 'browser/spellcheck_worditerator.cc', - 'browser/spellcheck_worditerator.h', - 'browser/spellchecker.cc', - 'browser/spellchecker.h', 'browser/spellchecker_common.h', 'browser/spellchecker_linux.cc', 'browser/spellchecker_mac.mm', @@ -3437,15 +3435,6 @@ '../third_party/tcmalloc/tcmalloc.gyp:tcmalloc', ], },], - # Mac-specific rules. - ['OS=="mac"', { - 'sources!': [ - 'renderer/spellchecker/spellcheck.cc', - 'renderer/spellchecker/spellcheck.h', - 'renderer/spellchecker/spellcheck_worditerator.cc', - 'renderer/spellchecker/spellcheck_worditerator.h', - ], - },], ], }, { @@ -4750,7 +4739,7 @@ 'browser/sessions/session_service_unittest.cc', 'browser/sessions/tab_restore_service_unittest.cc', 'browser/shell_integration_unittest.cc', - 'browser/spellcheck_unittest.cc', + 'browser/spellchecker_platform_engine_unittest.cc', 'browser/ssl/ssl_host_state_unittest.cc', 'browser/sync/glue/bookmark_model_worker_unittest.cc', 'browser/sync/glue/http_bridge_unittest.cc', @@ -4808,6 +4797,7 @@ 'renderer/render_view_unittest_mac.mm', 'renderer/render_widget_unittest.cc', 'renderer/renderer_main_unittest.cc', + 'renderer/spellchecker/spellcheck_unittest.cc', 'test/browser_with_test_window_test.cc', 'test/browser_with_test_window_test.h', 'test/file_test_utils.cc', diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index 781e252..c162cfc 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -544,12 +544,6 @@ class NotificationType { // Profile, and the details aren't used. 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. - SPELLCHECKER_REINITIALIZED, - // Sent when SpellCheckHost has been reloaded. The source is the profile, // the details are NoDetails. SPELLCHECK_HOST_REINITIALIZED, @@ -558,6 +552,12 @@ class NotificationType { // is the SpellCheckHost, the details are NoDetails. SPELLCHECK_WORD_ADDED, + // Sent by the profile when the automatic spell correction setting has been + // toggled. It exists as a notification rather than just letting interested + // parties listen for the pref change because some objects may outlive the + // profile. Source is profile, details is NoDetails. + SPELLCHECK_AUTOSPELL_TOGGLED, + // Sent when the bookmark bubble is shown for a particular URL. The source // is the profile, the details the URL. BOOKMARK_BUBBLE_SHOWN, diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index b883e87..ec9e869 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -833,7 +833,6 @@ IPC_BEGIN_MESSAGES(View) IPC_MESSAGE_CONTROL1(ViewMsg_SocketStream_Closed, int /* socket_id */) -#if defined(SPELLCHECKER_IN_RENDERER) // SpellChecker messages. // Passes some initialization params to the renderer's spellchecker. This can @@ -853,7 +852,6 @@ IPC_BEGIN_MESSAGES(View) // Toggle the auto spell correct functionality. IPC_MESSAGE_CONTROL1(ViewMsg_SpellChecker_EnableAutoSpellCorrect, bool /* enable */) -#endif IPC_END_MESSAGES(View) @@ -1130,11 +1128,6 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateSpellingPanelWithMisspelledWord, string16 /* the word to update the panel with */) - IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_GetAutoCorrectWord, - string16 /* word to check */, - int /* tag for the document containg the word */, - string16 /* autocorrected word */) - // Initiate a download based on user actions like 'ALT+click'. IPC_MESSAGE_ROUTED2(ViewHostMsg_DownloadUrl, GURL /* url */, @@ -2037,11 +2030,19 @@ IPC_BEGIN_MESSAGES(ViewHost) GURL /* URL of requestor */, std::string /* signed public key and challenge */) -#if defined(SPELLCHECKER_IN_RENDERER) // The renderer has tried to spell check a word, but couldn't because no // dictionary was available to load. Request that the browser find an // appropriate dictionary and return it. IPC_MESSAGE_CONTROL0(ViewHostMsg_SpellChecker_RequestDictionary) -#endif + + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_SpellChecker_PlatformCheckSpelling, + string16 /* word */, + int /* document tag */, + bool /* correct */) + + IPC_SYNC_MESSAGE_CONTROL1_1( + ViewHostMsg_SpellChecker_PlatformFillSuggestionList, + string16 /* word */, + std::vector<string16> /* suggestions */) IPC_END_MESSAGES(ViewHost) diff --git a/chrome/common/spellcheck_common.cc b/chrome/common/spellcheck_common.cc new file mode 100644 index 0000000..e06d2eb --- /dev/null +++ b/chrome/common/spellcheck_common.cc @@ -0,0 +1,174 @@ +// 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/common/spellcheck_common.h" + +#include "base/file_path.h" + +namespace SpellCheckCommon { + +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); +} + +std::string GetCorrespondingSpellCheckLanguage(const std::string& language) { + // Look for exact match in the Spell Check language list. + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); + ++i) { + // First look for exact match in the language region of the list. + std::string spellcheck_language( + g_supported_spellchecker_languages[i].language); + if (spellcheck_language == language) + return language; + + // Next, look for exact match in the language_region part of the list. + std::string spellcheck_language_region( + g_supported_spellchecker_languages[i].language_region); + if (spellcheck_language_region == language) + return g_supported_spellchecker_languages[i].language; + } + + // Look for a match by comparing only language parts. All the 'en-RR' + // except for 'en-GB' exactly matched in the above loop, will match + // 'en-US'. This is not ideal because 'en-ZA', 'en-NZ' had + // better be matched with 'en-GB'. This does not handle cases like + // 'az-Latn-AZ' vs 'az-Arab-AZ', either, but we don't use 3-part + // locale ids with a script code in the middle, yet. + // TODO(jungshik): Add a better fallback. + std::string language_part(language, 0, language.find('-')); + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); + ++i) { + std::string spellcheck_language( + g_supported_spellchecker_languages[i].language_region); + if (spellcheck_language.substr(0, spellcheck_language.find('-')) == + language_part) { + return spellcheck_language; + } + } + + // No match found - return blank. + return std::string(); +} + + +void SpellCheckLanguages(std::vector<std::string>* languages) { + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); + ++i) { + languages->push_back(g_supported_spellchecker_languages[i].language); + } +} + + +std::string GetLanguageFromLanguageRegion(std::string input_language) { + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); + ++i) { + std::string language( + g_supported_spellchecker_languages[i].language_region); + if (language == input_language) + return std::string(g_supported_spellchecker_languages[i].language); + } + + return input_language; +} + +} // namespace SpellCheckCommon diff --git a/chrome/common/spellcheck_common.h b/chrome/common/spellcheck_common.h new file mode 100644 index 0000000..5c2569e --- /dev/null +++ b/chrome/common/spellcheck_common.h @@ -0,0 +1,36 @@ +// 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. + +#ifndef CHROME_COMMON_SPELLCHECK_COMMON_H_ +#define CHROME_COMMON_SPELLCHECK_COMMON_H_ + +#include <string> +#include <vector> + +class FilePath; + +namespace SpellCheckCommon { + +// Max number of dictionary suggestions. +static const int kMaxSuggestions = 5; + +static const int kMaxAutoCorrectWordSize = 8; + +FilePath GetVersionedFileName(const std::string& input_language, + const FilePath& dict_dir); + +std::string GetCorrespondingSpellCheckLanguage(const std::string& language); + +// Get SpellChecker supported languages. +void SpellCheckLanguages(std::vector<std::string>* languages); + + +// This function returns ll (language code) from ll-RR where 'RR' (region +// code) is redundant. However, if the region code matters, it's preserved. +// That is, it returns 'hi' and 'en-GB' for 'hi-IN' and 'en-GB' respectively. +std::string GetLanguageFromLanguageRegion(std::string input_language); + +} // namespace SpellCheckCommon + +#endif // CHROME_COMMON_SPELLCHECK_COMMON_H_ diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc index 7779a01..0ca3603 100644 --- a/chrome/renderer/render_thread.cc +++ b/chrome/renderer/render_thread.cc @@ -53,9 +53,7 @@ #include "chrome/renderer/renderer_webkitclient_impl.h" #include "chrome/renderer/renderer_web_database_observer.h" #include "chrome/renderer/socket_stream_dispatcher.h" -#if defined(SPELLCHECKER_IN_RENDERER) #include "chrome/renderer/spellchecker/spellcheck.h" -#endif #include "chrome/renderer/user_script_slave.h" #include "ipc/ipc_message.h" #include "ipc/ipc_platform_file.h" @@ -158,9 +156,7 @@ void RenderThread::Init() { AddFilter(devtools_agent_filter_.get()); db_message_filter_ = new DBMessageFilter(); AddFilter(db_message_filter_.get()); -#if defined(SPELLCHECKER_IN_RENDERER) spellchecker_.reset(new SpellCheck()); -#endif #if defined(OS_POSIX) suicide_on_channel_error_filter_ = new SuicideOnChannelErrorFilter; @@ -341,14 +337,12 @@ void RenderThread::OnControlMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewMsg_SetIPCLoggingEnabled, OnSetIPCLoggingEnabled) #endif -#if defined(SPELLCHECKER_IN_RENDERER) IPC_MESSAGE_HANDLER(ViewMsg_SpellChecker_Init, OnInitSpellChecker) IPC_MESSAGE_HANDLER(ViewMsg_SpellChecker_WordAdded, OnSpellCheckWordAdded) IPC_MESSAGE_HANDLER(ViewMsg_SpellChecker_EnableAutoSpellCorrect, OnSpellCheckEnableAutoSpellCorrect) -#endif IPC_END_MESSAGE_MAP() } @@ -455,12 +449,6 @@ void RenderThread::SetCacheMode(bool enabled) { Send(new ViewHostMsg_SetCacheMode(enabled)); } -#if defined(SPELLCHECKER_IN_RENDERER) -void RenderThread::RequestSpellCheckDictionary() { - Send(new ViewHostMsg_SpellChecker_RequestDictionary); -} -#endif - static void* CreateHistogram( const char *name, int min, int max, size_t buckets) { Histogram* histogram = new Histogram(name, min, max, buckets); @@ -614,9 +602,7 @@ void RenderThread::OnExtensionMessageInvoke(const std::string& function_name, } void RenderThread::OnPurgeMemory() { -#if defined(SPELLCHECKER_IN_RENDERER) spellchecker_.reset(new SpellCheck()); -#endif EnsureWebKitInitialized(); @@ -659,7 +645,6 @@ void RenderThread::OnPurgePluginListCache(bool reload_pages) { plugin_refresh_allowed_ = true; } -#if defined(SPELLCHECKER_IN_RENDERER) void RenderThread::OnInitSpellChecker( IPC::PlatformFileForTransit bdict_file, const std::vector<std::string>& custom_words, @@ -677,4 +662,3 @@ void RenderThread::OnSpellCheckWordAdded(const std::string& word) { void RenderThread::OnSpellCheckEnableAutoSpellCorrect(bool enable) { spellchecker_->EnableAutoSpellCorrect(enable); } -#endif diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h index 44dc6ab..305607a 100644 --- a/chrome/renderer/render_thread.h +++ b/chrome/renderer/render_thread.h @@ -124,11 +124,9 @@ class RenderThread : public RenderThreadBase, return socket_stream_dispatcher_.get(); } -#if defined(SPELLCHECKER_IN_RENDERER) SpellCheck* spellchecker() const { return spellchecker_.get(); } -#endif bool plugin_refresh_allowed() const { return plugin_refresh_allowed_; } @@ -148,11 +146,6 @@ class RenderThread : public RenderThreadBase, // Sends a message to the browser to enable or disable the disk cache. void SetCacheMode(bool enabled); -#if defined(SPELLCHECKER_IN_RENDERER) - // Send a message to the browser to request a spellcheck dictionary. - void RequestSpellCheckDictionary(); -#endif - private: virtual void OnControlMessageReceived(const IPC::Message& msg); @@ -200,14 +193,12 @@ class RenderThread : public RenderThreadBase, void OnPurgeMemory(); void OnPurgePluginListCache(bool reload_pages); -#if defined(SPELLCHECKER_IN_RENDERER) void OnInitSpellChecker(IPC::PlatformFileForTransit bdict_file, const std::vector<std::string>& custom_words, const std::string& language, bool auto_spell_correct); void OnSpellCheckWordAdded(const std::string& word); void OnSpellCheckEnableAutoSpellCorrect(bool enable); -#endif // Gather usage statistics from the in-memory cache and inform our host. // These functions should be call periodically so that the host can make @@ -232,9 +223,7 @@ class RenderThread : public RenderThreadBase, scoped_ptr<WebKit::WebStorageEventDispatcher> dom_storage_event_dispatcher_; scoped_ptr<SocketStreamDispatcher> socket_stream_dispatcher_; scoped_ptr<RendererWebDatabaseObserver> renderer_web_database_observer_; -#if defined(SPELLCHECKER_IN_RENDERER) scoped_ptr<SpellCheck> spellchecker_; -#endif // Used on the renderer and IPC threads. scoped_refptr<DBMessageFilter> db_message_filter_; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 492823f..030222a 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -52,9 +52,7 @@ #include "chrome/renderer/plugin_channel_host.h" #include "chrome/renderer/print_web_view_helper.h" #include "chrome/renderer/render_process.h" -#if defined(SPELLCHECKER_IN_RENDERER) #include "chrome/renderer/spellchecker/spellcheck.h" -#endif #include "chrome/renderer/user_script_slave.h" #include "chrome/renderer/visitedlink_slave.h" #include "chrome/renderer/webplugin_delegate_pepper.h" @@ -1503,19 +1501,14 @@ void RenderView::spellCheck(const WebString& text, int& misspelled_length) { EnsureDocumentTag(); -#if defined(SPELLCHECKER_IN_RENDERER) string16 word(text); RenderThread* thread = RenderThread::current(); // Will be NULL during unit tests. if (thread) { - RenderThread::current()->spellchecker()->SpellCheckWord( + thread->spellchecker()->SpellCheckWord( word.c_str(), word.size(), document_tag_, &misspelled_offset, &misspelled_length, NULL); } -#else - Send(new ViewHostMsg_SpellCheck(routing_id_, text, document_tag_, - &misspelled_offset, &misspelled_length)); -#endif } WebString RenderView::autoCorrectWord(const WebKit::WebString& word) { @@ -1523,18 +1516,13 @@ WebString RenderView::autoCorrectWord(const WebKit::WebString& word) { const CommandLine& command_line = *CommandLine::ForCurrentProcess(); if (command_line.HasSwitch(switches::kExperimentalSpellcheckerFeatures)) { EnsureDocumentTag(); -#if defined(SPELLCHECKER_IN_RENDERER) RenderThread* thread = RenderThread::current(); // Will be NULL during unit tests. if (thread) { autocorrect_word = - RenderThread::current()->spellchecker()->GetAutoCorrectionWord( + thread->spellchecker()->GetAutoCorrectionWord( word, document_tag_); } -#else - Send(new ViewHostMsg_GetAutoCorrectWord( - routing_id_, word, document_tag_, &autocorrect_word)); -#endif } return autocorrect_word; } @@ -1619,7 +1607,19 @@ bool RenderView::runModalBeforeUnloadDialog( void RenderView::showContextMenu( WebFrame* frame, const WebContextMenuData& data) { - Send(new ViewHostMsg_ContextMenu(routing_id_, ContextMenuParams(data))); + ContextMenuParams params = ContextMenuParams(data); + if (!params.misspelled_word.empty() && RenderThread::current()) { + int misspelled_offset, misspelled_length; + bool misspelled = RenderThread::current()->spellchecker()->SpellCheckWord( + params.misspelled_word.c_str(), params.misspelled_word.size(), + document_tag_, + &misspelled_offset, &misspelled_length, + ¶ms.dictionary_suggestions); + if (!misspelled) + params.misspelled_word.clear(); + } + + Send(new ViewHostMsg_ContextMenu(routing_id_, params)); } void RenderView::setStatusText(const WebString& text) { @@ -2547,7 +2547,7 @@ void RenderView::didChangeContentsSize(WebFrame* frame, const WebSize& size) { // they're different. int width = webview()->mainFrame()->contentsPreferredWidth(); int height = webview()->mainFrame()->documentElementScrollHeight(); - + if (width != preferred_size_.width() || height != preferred_size_.height()) { preferred_size_.set_width(width); diff --git a/chrome/renderer/spellchecker/spellcheck.cc b/chrome/renderer/spellchecker/spellcheck.cc index 3b02b54..3fa20f8 100644 --- a/chrome/renderer/spellchecker/spellcheck.cc +++ b/chrome/renderer/spellchecker/spellcheck.cc @@ -7,18 +7,16 @@ #include "base/file_util.h" #include "base/histogram.h" #include "base/time.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/spellcheck_common.h" #include "chrome/renderer/render_thread.h" #include "third_party/hunspell/src/hunspell/hunspell.hxx" -static const int kMaxAutoCorrectWordSize = 8; -static const int kMaxSuggestions = 5; - using base::TimeTicks; SpellCheck::SpellCheck() : file_(base::kInvalidPlatformFileValue), auto_spell_correct_turned_on_(false), - // TODO(estade): initialize this properly. is_using_platform_spelling_engine_(false), initialized_(false) { // Wait till we check the first word before doing any initializing. @@ -34,6 +32,9 @@ void SpellCheck::Init(base::PlatformFile file, hunspell_.reset(); bdict_file_.reset(); file_ = file; + is_using_platform_spelling_engine_ = + file == base::kInvalidPlatformFileValue && !language.empty(); + character_attributes_.SetDefaultLanguage(language); custom_words_.insert(custom_words_.end(), @@ -58,8 +59,10 @@ bool SpellCheck::SpellCheckWord( return true; // Do nothing if spell checking is disabled. - if (initialized_ && file_ == base::kInvalidPlatformFileValue) + if (initialized_ && file_ == base::kInvalidPlatformFileValue && + !is_using_platform_spelling_engine_) { return true; + } *misspelling_start = 0; *misspelling_len = 0; @@ -100,15 +103,15 @@ string16 SpellCheck::GetAutoCorrectionWord(const string16& word, int tag) { return autocorrect_word; // Return the empty string. int word_length = static_cast<int>(word.size()); - if (word_length < 2 || word_length > kMaxAutoCorrectWordSize) + if (word_length < 2 || word_length > SpellCheckCommon::kMaxAutoCorrectWordSize) return autocorrect_word; if (InitializeIfNeeded()) return autocorrect_word; - char16 misspelled_word[kMaxAutoCorrectWordSize + 1]; + char16 misspelled_word[SpellCheckCommon::kMaxAutoCorrectWordSize + 1]; const char16* word_char = word.c_str(); - for (int i = 0; i <= kMaxAutoCorrectWordSize; i++) { + for (int i = 0; i <= SpellCheckCommon::kMaxAutoCorrectWordSize; i++) { if (i >= word_length) misspelled_word[i] = NULL; else @@ -188,15 +191,18 @@ void SpellCheck::AddWordToHunspell(const std::string& word) { } bool SpellCheck::InitializeIfNeeded() { + if (is_using_platform_spelling_engine_) + return false; + if (!initialized_) { - RenderThread::current()->RequestSpellCheckDictionary(); + RenderThread::current()->Send( + new ViewHostMsg_SpellChecker_RequestDictionary); initialized_ = true; return true; } // Check if the platform spellchecker is being used. - if (!is_using_platform_spelling_engine_ && - file_ != base::kInvalidPlatformFileValue) { + if (file_ != base::kInvalidPlatformFileValue) { // If it isn't, init hunspell. InitializeHunspell(); } @@ -210,8 +216,9 @@ bool SpellCheck::CheckSpelling(const string16& word_to_check, int tag) { bool word_correct = false; if (is_using_platform_spelling_engine_) { - // TODO(estade): sync IPC to browser. - word_correct = true; + RenderThread::current()->Send( + new ViewHostMsg_SpellChecker_PlatformCheckSpelling(word_to_check, tag, + &word_correct)); } else { std::string word_to_check_utf8(UTF16ToUTF8(word_to_check)); // Hunspell shouldn't let us exceed its max, but check just in case @@ -229,7 +236,9 @@ void SpellCheck::FillSuggestionList( const string16& wrong_word, std::vector<string16>* optional_suggestions) { if (is_using_platform_spelling_engine_) { - // TODO(estade): sync IPC to browser. + RenderThread::current()->Send( + new ViewHostMsg_SpellChecker_PlatformFillSuggestionList( + wrong_word, optional_suggestions)); return; } char** suggestions; @@ -238,7 +247,7 @@ void SpellCheck::FillSuggestionList( // Populate the vector of WideStrings. for (int i = 0; i < number_of_suggestions; i++) { - if (i < kMaxSuggestions) + if (i < SpellCheckCommon::kMaxSuggestions) optional_suggestions->push_back(UTF8ToUTF16(suggestions[i])); free(suggestions[i]); } diff --git a/chrome/renderer/spellchecker/spellcheck.h b/chrome/renderer/spellchecker/spellcheck.h index ef194bd..94b9a07 100644 --- a/chrome/renderer/spellchecker/spellcheck.h +++ b/chrome/renderer/spellchecker/spellcheck.h @@ -52,6 +52,9 @@ class SpellCheck { // Find a possible correctly spelled word for a misspelled word. Computes an // empty string if input misspelled word is too long, there is ambiguity, or // the correct spelling cannot be determined. + // NOTE: If using the platform spellchecker, this will send a *lot* of sync + // IPCs. We should probably refactor this if we ever plan to take it out from + // behind its command line flag. string16 GetAutoCorrectionWord(const string16& word, int tag); // Turn auto spell correct support ON or OFF. diff --git a/chrome/browser/spellcheck_unittest.cc b/chrome/renderer/spellchecker/spellcheck_unittest.cc index b50f802..2ed20a6 100644 --- a/chrome/browser/spellcheck_unittest.cc +++ b/chrome/renderer/spellchecker/spellcheck_unittest.cc @@ -7,31 +7,14 @@ #include "base/file_util.h" #include "base/message_loop.h" #include "base/path_service.h" +#include "base/platform_file.h" #include "base/sys_string_conversions.h" -#include "chrome/browser/chrome_thread.h" -#include "chrome/browser/spellchecker.h" -#include "chrome/browser/spellchecker_platform_engine.h" +#include "chrome/renderer/spellchecker/spellcheck.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/spellcheck_common.h" #include "testing/gtest/include/gtest/gtest.h" namespace { -const FilePath::CharType kTempCustomDictionaryFile[] = - FILE_PATH_LITERAL("temp_custom_dictionary.txt"); -} // namespace - -class SpellCheckTest : public testing::Test { - public: - SpellCheckTest() - : file_thread_(ChromeThread::FILE, &message_loop_), - io_thread_(ChromeThread::IO, &message_loop_) {} - - protected: - MessageLoop message_loop_; - - private: - ChromeThread file_thread_; - ChromeThread io_thread_; // To keep DCHECKs inside spell checker happy. -}; // Represents a special initialization function used only for the unit tests // in this file. @@ -49,6 +32,33 @@ FilePath GetHunspellDirectory() { return hunspell_directory; } +class SpellCheckTest : public testing::Test { + public: + SpellCheckTest() { + ReinitializeSpellCheck("en-US"); + } + + void ReinitializeSpellCheck(const std::string& language) { + spell_check_.reset(new SpellCheck()); + + FilePath hunspell_directory = GetHunspellDirectory(); + EXPECT_FALSE(hunspell_directory.empty()); + base::PlatformFile file = base::CreatePlatformFile( + SpellCheckCommon::GetVersionedFileName(language, hunspell_directory), + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL); + spell_check_->Init( + file, std::vector<std::string>(), language); + } + + virtual ~SpellCheckTest() { + } + + SpellCheck* spell_check() { return spell_check_.get(); } + + private: + scoped_ptr<SpellCheck> spell_check_; +}; + // Operates unit tests for the webkit_glue::SpellCheckWord() function // with the US English dictionary. // The unit tests in this function consist of: @@ -276,14 +286,6 @@ TEST_F(SpellCheckTest, SpellCheckStrings_EN_US) { {L"qwertyuiopasdf", false, 0, 14}, }; - FilePath hunspell_directory = GetHunspellDirectory(); - ASSERT_FALSE(hunspell_directory.empty()); - - scoped_refptr<SpellChecker> spell_checker(new SpellChecker( - hunspell_directory, "en-US", NULL, FilePath())); - spell_checker->Initialize(); - message_loop_.RunAllPending(); - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { size_t input_length = 0; if (kTestCases[i].input != NULL) { @@ -291,7 +293,7 @@ TEST_F(SpellCheckTest, SpellCheckStrings_EN_US) { } int misspelling_start; int misspelling_length; - bool result = spell_checker->SpellCheckWord( + bool result = spell_check()->SpellCheckWord( WideToUTF16(kTestCases[i].input).c_str(), static_cast<int>(input_length), 0, @@ -318,297 +320,7 @@ TEST_F(SpellCheckTest, SpellCheckSuggestions_EN_US) { // A suggested word that should occur. const wchar_t* suggested_word; - } kTestCases[] = { // A valid English word with a preceding whitespace - // We need to have separate test cases here, since hunspell and the OS X - // spellchecking service occasionally differ on what they consider a valid - // suggestion for a given word, although these lists could likely be - // integrated somewhat. -#if defined(OS_MACOSX) - // These words come from the wikipedia page of the most commonly - // misspelled words in english. - // (http://en.wikipedia.org/wiki/Commonly_misspelled_words). - {L"absense", false, 0, 0, L"absence"}, - {L"acceptible", false, 0, 0, L"acceptable"}, - {L"accidentaly", false, 0, 0, L"accidentally"}, - {L"accomodate", false, 0, 0, L"accommodate"}, - {L"acheive", false, 0, 0, L"achieve"}, - {L"acknowlege", false, 0, 0, L"acknowledge"}, - {L"acquaintence", false, 0, 0, L"acquaintance"}, - {L"aquire", false, 0, 0, L"acquire"}, - {L"aquit", false, 0, 0, L"acquit"}, - {L"acrage", false, 0, 0, L"acreage"}, - {L"adress", false, 0, 0, L"address"}, - {L"adultary", false, 0, 0, L"adultery"}, - {L"advertize", false, 0, 0, L"advertise"}, - {L"adviseable", false, 0, 0, L"advisable"}, - {L"agression", false, 0, 0, L"aggression"}, - {L"alchohol", false, 0, 0, L"alcohol"}, - {L"alege", false, 0, 0, L"allege"}, - {L"allegaince", false, 0, 0, L"allegiance"}, - {L"allmost", false, 0, 0, L"almost"}, - // Ideally, this test should pass. It works in firefox, but not in hunspell - // or OS X. - // {L"alot", false, 0, 0, L"a lot"}, - {L"amatuer", false, 0, 0, L"amateur"}, - {L"ammend", false, 0, 0, L"amend"}, - {L"amung", false, 0, 0, L"among"}, - {L"anually", false, 0, 0, L"annually"}, - {L"apparant", false, 0, 0, L"apparent"}, - {L"artic", false, 0, 0, L"arctic"}, - {L"arguement", false, 0, 0, L"argument"}, - {L"athiest", false, 0, 0, L"atheist"}, - {L"athelete", false, 0, 0, L"athlete"}, - {L"avrage", false, 0, 0, L"average"}, - {L"awfull", false, 0, 0, L"awful"}, - {L"ballance", false, 0, 0, L"balance"}, - {L"basicly", false, 0, 0, L"basically"}, - {L"becuase", false, 0, 0, L"because"}, - {L"becomeing", false, 0, 0, L"becoming"}, - {L"befor", false, 0, 0, L"before"}, - {L"begining", false, 0, 0, L"beginning"}, - {L"beleive", false, 0, 0, L"believe"}, - {L"bellweather", false, 0, 0, L"bellwether"}, - {L"benifit", false, 0, 0, L"benefit"}, - {L"bouy", false, 0, 0, L"buoy"}, - {L"briliant", false, 0, 0, L"brilliant"}, - {L"burgler", false, 0, 0, L"burglar"}, - {L"camoflage", false, 0, 0, L"camouflage"}, - {L"carrer", false, 0, 0, L"career"}, - {L"carefull", false, 0, 0, L"careful"}, - {L"Carribean", false, 0, 0, L"Caribbean"}, - {L"catagory", false, 0, 0, L"category"}, - {L"cauhgt", false, 0, 0, L"caught"}, - {L"cieling", false, 0, 0, L"ceiling"}, - {L"cemetary", false, 0, 0, L"cemetery"}, - {L"certin", false, 0, 0, L"certain"}, - {L"changable", false, 0, 0, L"changeable"}, - {L"cheif", false, 0, 0, L"chief"}, - {L"citezen", false, 0, 0, L"citizen"}, - {L"collaegue", false, 0, 0, L"colleague"}, - {L"colum", false, 0, 0, L"column"}, - {L"comming", false, 0, 0, L"coming"}, - {L"commited", false, 0, 0, L"committed"}, - {L"compitition", false, 0, 0, L"competition"}, - {L"conceed", false, 0, 0, L"concede"}, - {L"congradulate", false, 0, 0, L"congratulate"}, - {L"consciencious", false, 0, 0, L"conscientious"}, - {L"concious", false, 0, 0, L"conscious"}, - {L"concensus", false, 0, 0, L"consensus"}, - {L"contraversy", false, 0, 0, L"controversy"}, - {L"conveniance", false, 0, 0, L"convenience"}, - {L"critecize", false, 0, 0, L"criticize"}, - {L"dacquiri", false, 0, 0, L"daiquiri"}, - {L"decieve", false, 0, 0, L"deceive"}, - {L"dicide", false, 0, 0, L"decide"}, - {L"definate", false, 0, 0, L"definite"}, - {L"definitly", false, 0, 0, L"definitely"}, - {L"deposite", false, 0, 0, L"deposit"}, - {L"desparate", false, 0, 0, L"desperate"}, - {L"develope", false, 0, 0, L"develop"}, - {L"diffrence", false, 0, 0, L"difference"}, - {L"dilema", false, 0, 0, L"dilemma"}, - {L"disapear", false, 0, 0, L"disappear"}, - {L"disapoint", false, 0, 0, L"disappoint"}, - {L"disasterous", false, 0, 0, L"disastrous"}, - {L"disipline", false, 0, 0, L"discipline"}, - {L"drunkeness", false, 0, 0, L"drunkenness"}, - {L"dumbell", false, 0, 0, L"dumbbell"}, - {L"durring", false, 0, 0, L"during"}, - {L"easely", false, 0, 0, L"easily"}, - {L"eigth", false, 0, 0, L"eight"}, - {L"embarass", false, 0, 0, L"embarrass"}, - {L"enviroment", false, 0, 0, L"environment"}, - {L"equiped", false, 0, 0, L"equipped"}, - {L"equiptment", false, 0, 0, L"equipment"}, - {L"exagerate", false, 0, 0, L"exaggerate"}, - {L"excede", false, 0, 0, L"exceed"}, - {L"exellent", false, 0, 0, L"excellent"}, - {L"exsept", false, 0, 0, L"except"}, - {L"exercize", false, 0, 0, L"exercise"}, - {L"exilerate", false, 0, 0, L"exhilarate"}, - {L"existance", false, 0, 0, L"existence"}, - {L"experiance", false, 0, 0, L"experience"}, - {L"experament", false, 0, 0, L"experiment"}, - {L"explaination", false, 0, 0, L"explanation"}, - {L"extreem", false, 0, 0, L"extreme"}, - {L"familier", false, 0, 0, L"familiar"}, - {L"facinating", false, 0, 0, L"fascinating"}, - {L"firey", false, 0, 0, L"fiery"}, - {L"finaly", false, 0, 0, L"finally"}, - {L"flourescent", false, 0, 0, L"fluorescent"}, - {L"foriegn", false, 0, 0, L"foreign"}, - {L"fourty", false, 0, 0, L"forty"}, - {L"foreward", false, 0, 0, L"forward"}, - {L"freind", false, 0, 0, L"friend"}, - {L"fullfil", false, 0, 0, L"fulfill"}, - {L"fundemental", false, 0, 0, L"fundamental"}, - {L"guage", false, 0, 0, L"gauge"}, - {L"generaly", false, 0, 0, L"generally"}, - {L"goverment", false, 0, 0, L"government"}, - {L"grammer", false, 0, 0, L"grammar"}, - {L"gratefull", false, 0, 0, L"grateful"}, - {L"garantee", false, 0, 0, L"guarantee"}, - {L"guidence", false, 0, 0, L"guidance"}, - {L"happyness", false, 0, 0, L"happiness"}, - {L"harrass", false, 0, 0, L"harass"}, - {L"heighth", false, 0, 0, L"height"}, - {L"heirarchy", false, 0, 0, L"hierarchy"}, - {L"humerous", false, 0, 0, L"humorous"}, - {L"hygene", false, 0, 0, L"hygiene"}, - {L"hipocrit", false, 0, 0, L"hypocrite"}, - {L"idenity", false, 0, 0, L"identity"}, - {L"ignorence", false, 0, 0, L"ignorance"}, - {L"imaginery", false, 0, 0, L"imaginary"}, - {L"immitate", false, 0, 0, L"imitate"}, - {L"immitation", false, 0, 0, L"imitation"}, - {L"imediately", false, 0, 0, L"immediately"}, - {L"incidently", false, 0, 0, L"incidentally"}, - {L"independant", false, 0, 0, L"independent"}, - {L"indispensible", false, 0, 0, L"indispensable"}, - {L"innoculate", false, 0, 0, L"inoculate"}, - {L"inteligence", false, 0, 0, L"intelligence"}, - {L"intresting", false, 0, 0, L"interesting"}, - {L"interuption", false, 0, 0, L"interruption"}, - {L"irrelevent", false, 0, 0, L"irrelevant"}, - {L"irritible", false, 0, 0, L"irritable"}, - {L"iland", false, 0, 0, L"island"}, - {L"jellous", false, 0, 0, L"jealous"}, - {L"knowlege", false, 0, 0, L"knowledge"}, - {L"labratory", false, 0, 0, L"laboratory"}, - {L"liesure", false, 0, 0, L"leisure"}, - {L"lenght", false, 0, 0, L"length"}, - {L"liason", false, 0, 0, L"liaison"}, - {L"libary", false, 0, 0, L"library"}, - {L"lisence", false, 0, 0, L"license"}, - {L"lonelyness", false, 0, 0, L"loneliness"}, - {L"lieing", false, 0, 0, L"lying"}, - {L"maintenence", false, 0, 0, L"maintenance"}, - {L"manuever", false, 0, 0, L"maneuver"}, - {L"marrige", false, 0, 0, L"marriage"}, - {L"mathmatics", false, 0, 0, L"mathematics"}, - {L"medcine", false, 0, 0, L"medicine"}, - {L"medeval", false, 0, 0, L"medieval"}, - {L"momento", false, 0, 0, L"memento"}, - {L"millenium", false, 0, 0, L"millennium"}, - {L"miniture", false, 0, 0, L"miniature"}, - {L"minite", false, 0, 0, L"minute"}, - {L"mischevous", false, 0, 0, L"mischievous"}, - {L"mispell", false, 0, 0, L"misspell"}, - // Maybe this one should pass, as it works in hunspell, but not in firefox. - // {L"misterius", false, 0, 0, L"mysterious"}, - {L"naturaly", false, 0, 0, L"naturally"}, - {L"neccessary", false, 0, 0, L"necessary"}, - {L"neice", false, 0, 0, L"niece"}, - {L"nieghbor", false, 0, 0, L"neighbor"}, - {L"nieghbour", false, 0, 0, L"neighbor"}, - {L"niether", false, 0, 0, L"neither"}, - {L"noticable", false, 0, 0, L"noticeable"}, - {L"occassion", false, 0, 0, L"occasion"}, - {L"occasionaly", false, 0, 0, L"occasionally"}, - {L"occurrance", false, 0, 0, L"occurrence"}, - {L"occured", false, 0, 0, L"occurred"}, - {L"oficial", false, 0, 0, L"official"}, - {L"offen", false, 0, 0, L"often"}, - {L"ommision", false, 0, 0, L"omission"}, - {L"oprate", false, 0, 0, L"operate"}, - {L"oppurtunity", false, 0, 0, L"opportunity"}, - {L"orignal", false, 0, 0, L"original"}, - {L"outragous", false, 0, 0, L"outrageous"}, - {L"parrallel", false, 0, 0, L"parallel"}, - {L"parliment", false, 0, 0, L"parliament"}, - {L"particurly", false, 0, 0, L"particularly"}, - {L"passtime", false, 0, 0, L"pastime"}, - {L"peculier", false, 0, 0, L"peculiar"}, - {L"percieve", false, 0, 0, L"perceive"}, - {L"pernament", false, 0, 0, L"permanent"}, - {L"perseverence", false, 0, 0, L"perseverance"}, - {L"personaly", false, 0, 0, L"personally"}, - {L"personell", false, 0, 0, L"personnel"}, - {L"persaude", false, 0, 0, L"persuade"}, - {L"pichure", false, 0, 0, L"picture"}, - {L"peice", false, 0, 0, L"piece"}, - {L"plagerize", false, 0, 0, L"plagiarize"}, - {L"playright", false, 0, 0, L"playwright"}, - {L"plesant", false, 0, 0, L"pleasant"}, - {L"pollitical", false, 0, 0, L"political"}, - {L"posession", false, 0, 0, L"possession"}, - {L"potatos", false, 0, 0, L"potatoes"}, - {L"practicle", false, 0, 0, L"practical"}, - {L"preceed", false, 0, 0, L"precede"}, - {L"predjudice", false, 0, 0, L"prejudice"}, - {L"presance", false, 0, 0, L"presence"}, - {L"privelege", false, 0, 0, L"privilege"}, - // This one should probably work. It does in FF and Hunspell. - // {L"probly", false, 0, 0, L"probably"}, - {L"proffesional", false, 0, 0, L"professional"}, - {L"professer", false, 0, 0, L"professor"}, - {L"promiss", false, 0, 0, L"promise"}, - {L"pronounciation", false, 0, 0, L"pronunciation"}, - {L"prufe", false, 0, 0, L"proof"}, - {L"psycology", false, 0, 0, L"psychology"}, - {L"publically", false, 0, 0, L"publicly"}, - {L"quanity", false, 0, 0, L"quantity"}, - {L"quarentine", false, 0, 0, L"quarantine"}, - {L"questionaire", false, 0, 0, L"questionnaire"}, - {L"readible", false, 0, 0, L"readable"}, - {L"realy", false, 0, 0, L"really"}, - {L"recieve", false, 0, 0, L"receive"}, - {L"reciept", false, 0, 0, L"receipt"}, - {L"reconize", false, 0, 0, L"recognize"}, - {L"recomend", false, 0, 0, L"recommend"}, - {L"refered", false, 0, 0, L"referred"}, - {L"referance", false, 0, 0, L"reference"}, - {L"relevent", false, 0, 0, L"relevant"}, - {L"religous", false, 0, 0, L"religious"}, - {L"repitition", false, 0, 0, L"repetition"}, - {L"restarant", false, 0, 0, L"restaurant"}, - {L"rythm", false, 0, 0, L"rhythm"}, - {L"rediculous", false, 0, 0, L"ridiculous"}, - {L"sacrefice", false, 0, 0, L"sacrifice"}, - {L"saftey", false, 0, 0, L"safety"}, - {L"sissors", false, 0, 0, L"scissors"}, - {L"secratary", false, 0, 0, L"secretary"}, - {L"sieze", false, 0, 0, L"seize"}, - {L"seperate", false, 0, 0, L"separate"}, - {L"sargent", false, 0, 0, L"sergeant"}, - {L"shineing", false, 0, 0, L"shining"}, - {L"similer", false, 0, 0, L"similar"}, - {L"sinceerly", false, 0, 0, L"sincerely"}, - {L"speach", false, 0, 0, L"speech"}, - {L"stoping", false, 0, 0, L"stopping"}, - {L"strenght", false, 0, 0, L"strength"}, - {L"succede", false, 0, 0, L"succeed"}, - {L"succesful", false, 0, 0, L"successful"}, - {L"supercede", false, 0, 0, L"supersede"}, - {L"surelly", false, 0, 0, L"surely"}, - {L"suprise", false, 0, 0, L"surprise"}, - {L"temperture", false, 0, 0, L"temperature"}, - {L"temprary", false, 0, 0, L"temporary"}, - {L"tomatos", false, 0, 0, L"tomatoes"}, - {L"tommorrow", false, 0, 0, L"tomorrow"}, - {L"tounge", false, 0, 0, L"tongue"}, - {L"truely", false, 0, 0, L"truly"}, - {L"twelth", false, 0, 0, L"twelfth"}, - {L"tyrany", false, 0, 0, L"tyranny"}, - {L"underate", false, 0, 0, L"underrate"}, - {L"untill", false, 0, 0, L"until"}, - {L"unuseual", false, 0, 0, L"unusual"}, - {L"upholstry", false, 0, 0, L"upholstery"}, - {L"usible", false, 0, 0, L"usable"}, - {L"useing", false, 0, 0, L"using"}, - {L"usualy", false, 0, 0, L"usually"}, - {L"vaccuum", false, 0, 0, L"vacuum"}, - {L"vegatarian", false, 0, 0, L"vegetarian"}, - {L"vehical", false, 0, 0, L"vehicle"}, - {L"visious", false, 0, 0, L"vicious"}, - {L"villege", false, 0, 0, L"village"}, - {L"wierd", false, 0, 0, L"weird"}, - {L"wellcome", false, 0, 0, L"welcome"}, - {L"wellfare", false, 0, 0, L"welfare"}, - {L"wilfull", false, 0, 0, L"willful"}, - {L"withold", false, 0, 0, L"withhold"}, - {L"writting", false, 0, 0, L"writing"}, -#else + } kTestCases[] = { {L"ello", false, 0, 0, L"hello"}, {L"ello", false, 0, 0, L"cello"}, {L"wate", false, 0, 0, L"water"}, @@ -619,18 +331,9 @@ TEST_F(SpellCheckTest, SpellCheckSuggestions_EN_US) { {L"jum", false, 0, 0, L"hum"}, {L"jum", false, 0, 0, L"sum"}, {L"jum", false, 0, 0, L"um"}, -#endif // !OS_MACOSX // TODO (Sidchat): add many more examples. }; - FilePath hunspell_directory = GetHunspellDirectory(); - ASSERT_FALSE(hunspell_directory.empty()); - - scoped_refptr<SpellChecker> spell_checker(new SpellChecker( - hunspell_directory, "en-US", NULL, FilePath())); - spell_checker->Initialize(); - message_loop_.RunAllPending(); - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { std::vector<string16> suggestions; size_t input_length = 0; @@ -639,7 +342,7 @@ TEST_F(SpellCheckTest, SpellCheckSuggestions_EN_US) { } int misspelling_start; int misspelling_length; - bool result = spell_checker->SpellCheckWord( + bool result = spell_check()->SpellCheckWord( WideToUTF16(kTestCases[i].input).c_str(), static_cast<int>(input_length), 0, @@ -897,22 +600,15 @@ TEST_F(SpellCheckTest, SpellCheckText) { }, }; - FilePath hunspell_directory = GetHunspellDirectory(); - ASSERT_FALSE(hunspell_directory.empty()); - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { - scoped_refptr<SpellChecker> spell_checker(new SpellChecker( - hunspell_directory, kTestCases[i].language, NULL, FilePath())); - spell_checker->Initialize(); - message_loop_.RunAllPending(); - + ReinitializeSpellCheck(kTestCases[i].language); size_t input_length = 0; if (kTestCases[i].input != NULL) input_length = wcslen(kTestCases[i].input); int misspelling_start = 0; int misspelling_length = 0; - bool result = spell_checker->SpellCheckWord( + bool result = spell_check()->SpellCheckWord( WideToUTF16(kTestCases[i].input).c_str(), static_cast<int>(input_length), 0, @@ -925,164 +621,6 @@ TEST_F(SpellCheckTest, SpellCheckText) { } } -// This test Adds words to the SpellChecker and veifies that it remembers them. -TEST_F(SpellCheckTest, DISABLED_SpellCheckAddToDictionary_EN_US) { - static const struct { - // A string to be added to SpellChecker. - const wchar_t* word_to_add; - } kTestCases[] = { // Words to be added to the SpellChecker. - {L"Googley"}, - {L"Googleplex"}, - {L"Googler"}, - }; - - FilePath custom_dictionary_file(kTempCustomDictionaryFile); - FilePath hunspell_directory = GetHunspellDirectory(); - ASSERT_FALSE(hunspell_directory.empty()); - - scoped_refptr<SpellChecker> spell_checker(new SpellChecker( - hunspell_directory, "en-US", NULL, custom_dictionary_file)); - spell_checker->Initialize(); - message_loop_.RunAllPending(); - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { - // Add the word to spellchecker. - spell_checker->AddWord(WideToUTF16(kTestCases[i].word_to_add)); - - // Now check whether it is added to Spellchecker. - std::vector<string16> suggestions; - size_t input_length = 0; - if (kTestCases[i].word_to_add != NULL) { - input_length = wcslen(kTestCases[i].word_to_add); - } - int misspelling_start; - int misspelling_length; - bool result = spell_checker->SpellCheckWord( - WideToUTF16(kTestCases[i].word_to_add).c_str(), - static_cast<int>(input_length), - 0, - &misspelling_start, - &misspelling_length, - &suggestions); - - // Check for spelling. - EXPECT_TRUE(result); - } - - // Now initialize another spellchecker to see that AddToWord is permanent. - scoped_refptr<SpellChecker> spell_checker_new(new SpellChecker( - hunspell_directory, "en-US", NULL, custom_dictionary_file)); - spell_checker->Initialize(); - message_loop_.RunAllPending(); - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { - // Now check whether it is added to Spellchecker. - std::vector<string16> suggestions; - size_t input_length = 0; - if (kTestCases[i].word_to_add != NULL) { - input_length = wcslen(kTestCases[i].word_to_add); - } - int misspelling_start; - int misspelling_length; - bool result = spell_checker_new->SpellCheckWord( - WideToUTF16(kTestCases[i].word_to_add).c_str(), - static_cast<int>(input_length), - 0, - &misspelling_start, - &misspelling_length, - &suggestions); - - // Check for spelling. - EXPECT_TRUE(result); - } - - // Remove the temp custom dictionary file. - file_util::Delete(custom_dictionary_file, false); -} - -// SpellChecker should suggest custome words for misspelled words. -TEST_F(SpellCheckTest, DISABLED_SpellCheckSuggestionsAddToDictionary_EN_US) { - static const struct { - // A string to be added to SpellChecker. - const wchar_t* word_to_add; - } kTestCases[] = { // word to be added to SpellChecker - {L"Googley"}, - {L"Googleplex"}, - {L"Googler"}, - }; - - FilePath custom_dictionary_file(kTempCustomDictionaryFile); - FilePath hunspell_directory = GetHunspellDirectory(); - ASSERT_FALSE(hunspell_directory.empty()); - - scoped_refptr<SpellChecker> spell_checker(new SpellChecker( - hunspell_directory, "en-US", NULL, custom_dictionary_file)); - spell_checker->Initialize(); - message_loop_.RunAllPending(); - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { - // Add the word to spellchecker. - spell_checker->AddWord(WideToUTF16(kTestCases[i].word_to_add)); - } - - // Now check to see whether the custom words are suggested for - // misspelled but similar words. - static const struct { - // A string to be tested. - const wchar_t* input; - // An expected result for this test case. - // * true: the input string does not have any invalid words. - // * false: the input string has one or more invalid words. - bool expected_result; - // The position and the length of the first invalid word. - int misspelling_start; - int misspelling_length; - - // A suggested word that should occur. - const wchar_t* suggested_word; - } kTestCasesToBeTested[] = { - {L"oogley", false, 0, 0, L"Googley"}, - {L"oogler", false, 0, 0, L"Googler"}, - {L"oogleplex", false, 0, 0, L"Googleplex"}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCasesToBeTested); ++i) { - std::vector<string16> suggestions; - size_t input_length = 0; - if (kTestCasesToBeTested[i].input != NULL) { - input_length = wcslen(kTestCasesToBeTested[i].input); - } - int misspelling_start; - int misspelling_length; - bool result = spell_checker->SpellCheckWord( - WideToUTF16(kTestCasesToBeTested[i].input).c_str(), - static_cast<int>(input_length), - 0, - &misspelling_start, - &misspelling_length, - &suggestions); - - // Check for spelling. - EXPECT_EQ(result, kTestCasesToBeTested[i].expected_result); - - // Check if the suggested words occur. - bool suggested_word_is_present = false; - for (int j=0; j < static_cast<int>(suggestions.size()); j++) { - if (suggestions.at(j).compare( - WideToUTF16(kTestCasesToBeTested[i].suggested_word)) == - 0) { - suggested_word_is_present = true; - break; - } - } - - EXPECT_TRUE(suggested_word_is_present); - } - - // Remove the temp custom dictionary file. - file_util::Delete(custom_dictionary_file, false); -} - TEST_F(SpellCheckTest, GetAutoCorrectionWord_EN_US) { static const struct { // A misspelled word. @@ -1098,21 +636,13 @@ TEST_F(SpellCheckTest, GetAutoCorrectionWord_EN_US) { {"noen", ""}, {"what", ""}, }; - - FilePath hunspell_directory = GetHunspellDirectory(); - ASSERT_FALSE(hunspell_directory.empty()); - - scoped_refptr<SpellChecker> spell_checker(new SpellChecker( - hunspell_directory, "en-US", NULL, FilePath())); - spell_checker->EnableAutoSpellCorrect(true); - spell_checker->Initialize(); - message_loop_.RunAllPending(); + spell_check()->EnableAutoSpellCorrect(true); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { string16 misspelled_word(UTF8ToUTF16(kTestCases[i].input)); string16 expected_autocorrect_word( UTF8ToUTF16(kTestCases[i].expected_result)); - string16 autocorrect_word = spell_checker->GetAutoCorrectionWord( + string16 autocorrect_word = spell_check()->GetAutoCorrectionWord( misspelled_word, 0); // Check for spelling. @@ -1120,80 +650,4 @@ TEST_F(SpellCheckTest, GetAutoCorrectionWord_EN_US) { } } -#if defined(OS_MACOSX) -// Tests that words are properly ignored. Currently only enabled on OS X as it -// is the only platform to support ignoring words. Note that in this test, we -// supply a non-zero doc_tag, in order to test that ignored words are matched to -// the correct document. -TEST_F(SpellCheckTest, IgnoreWords_EN_US) { - static const struct { - // A misspelled word. - const char* input; - bool input_result; - } kTestCases[] = { - {"teh", false}, - {"moer", false}, - {"watre", false}, - {"noen", false}, - }; - - FilePath hunspell_directory = GetHunspellDirectory(); - ASSERT_FALSE(hunspell_directory.empty()); - - scoped_refptr<SpellChecker> spell_checker(new SpellChecker( - hunspell_directory, "en-US", NULL, FilePath())); - spell_checker->Initialize(); - message_loop_.RunAllPending(); - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { - string16 word(UTF8ToUTF16(kTestCases[i].input)); - std::vector<string16> suggestions; - size_t input_length = 0; - if (kTestCases[i].input != NULL) { - input_length = word.length(); - } - int misspelling_start; - int misspelling_length; - - int doc_tag = SpellCheckerPlatform::GetDocumentTag(); - bool result = spell_checker->SpellCheckWord(word.c_str(), - static_cast<int>(input_length), - doc_tag, - &misspelling_start, - &misspelling_length, - &suggestions); - - // The word should show up as misspelled. - EXPECT_EQ(kTestCases[i].input_result, result); - - // Ignore the word. - SpellCheckerPlatform::IgnoreWord(word); - - // Spellcheck again. - result = spell_checker->SpellCheckWord(word.c_str(), - static_cast<int>(input_length), - doc_tag, - &misspelling_start, - &misspelling_length, - &suggestions); - - // The word should now show up as correctly spelled. - EXPECT_EQ(!(kTestCases[i].input_result), result); - - // Close the docuemnt. Any words that we had previously ignored should no - // longer be ignored and thus should show up as misspelled. - SpellCheckerPlatform::CloseDocumentWithTag(doc_tag); - - // Spellcheck one more time. - result = spell_checker->SpellCheckWord(word.c_str(), - static_cast<int>(input_length), - doc_tag, - &misspelling_start, - &misspelling_length, - &suggestions); - - // The word should now show be spelled wrong again - EXPECT_EQ(kTestCases[i].input_result, result); - } -} // Test IgnoreWords_EN_US -#endif // OS_MACOSX +} // namespace diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index 40b6896..677bb7e 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -175,13 +175,8 @@ class TestingProfile : public Profile { virtual base::Time GetStartTime() const { return start_time_; } virtual TabRestoreService* GetTabRestoreService() { return NULL; } virtual void ResetTabRestoreService() {} - virtual void ReinitializeSpellChecker() {} - virtual SpellChecker* GetSpellChecker() { return NULL; } - virtual void DeleteSpellChecker() {} -#if defined(SPELLCHECKER_IN_RENDERER) virtual SpellCheckHost* GetSpellCheckHost() { return NULL; } virtual void ReinitializeSpellCheckHost(bool force) { } -#endif virtual WebKitContext* GetWebKitContext() { return NULL; } virtual WebKitContext* GetOffTheRecordWebKitContext() { return NULL; } virtual void MarkAsCleanShutdown() {} |