Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / spellchecker / spellcheck_service.cc
blob5606978df3c72e4e0ed1bdbb74cabb0a8978adff
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/spellchecker/spellcheck_service.h"
7 #include "base/logging.h"
8 #include "base/prefs/pref_member.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string_split.h"
11 #include "base/supports_user_data.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "chrome/browser/spellchecker/feedback_sender.h"
14 #include "chrome/browser/spellchecker/spellcheck_factory.h"
15 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
16 #include "chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h"
17 #include "chrome/browser/spellchecker/spellcheck_platform.h"
18 #include "chrome/browser/spellchecker/spelling_service_client.h"
19 #include "chrome/common/pref_names.h"
20 #include "chrome/common/spellcheck_bdict_language.h"
21 #include "chrome/common/spellcheck_common.h"
22 #include "chrome/common/spellcheck_messages.h"
23 #include "components/user_prefs/user_prefs.h"
24 #include "content/public/browser/browser_context.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/notification_types.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "ipc/ipc_platform_file.h"
31 using content::BrowserThread;
33 // TODO(rlp): I do not like globals, but keeping these for now during
34 // transition.
35 // An event used by browser tests to receive status events from this class and
36 // its derived classes.
37 base::WaitableEvent* g_status_event = NULL;
38 SpellcheckService::EventType g_status_type =
39 SpellcheckService::BDICT_NOTINITIALIZED;
41 SpellcheckService::SpellcheckService(content::BrowserContext* context)
42 : context_(context),
43 weak_ptr_factory_(this) {
44 DCHECK_CURRENTLY_ON(BrowserThread::UI);
45 PrefService* prefs = user_prefs::UserPrefs::Get(context);
46 pref_change_registrar_.Init(prefs);
47 StringListPrefMember dictionaries_pref;
48 dictionaries_pref.Init(prefs::kSpellCheckDictionaries, prefs);
49 std::string first_of_dictionaries;
50 if (!dictionaries_pref.GetValue().empty())
51 first_of_dictionaries = dictionaries_pref.GetValue().front();
53 // For preference migration, set the new preference kSpellCheckDictionaries
54 // to be the same as the old kSpellCheckDictionary.
55 StringPrefMember single_dictionary_pref;
56 single_dictionary_pref.Init(prefs::kSpellCheckDictionary, prefs);
57 std::string single_dictionary = single_dictionary_pref.GetValue();
59 if (first_of_dictionaries.empty() && !single_dictionary.empty()) {
60 first_of_dictionaries = single_dictionary;
61 dictionaries_pref.SetValue(
62 std::vector<std::string>(1, first_of_dictionaries));
65 single_dictionary_pref.SetValue("");
67 std::string language_code;
68 std::string country_code;
69 chrome::spellcheck_common::GetISOLanguageCountryCodeFromLocale(
70 first_of_dictionaries,
71 &language_code,
72 &country_code);
73 feedback_sender_.reset(new spellcheck::FeedbackSender(
74 context->GetRequestContext(), language_code, country_code));
76 pref_change_registrar_.Add(
77 prefs::kEnableAutoSpellCorrect,
78 base::Bind(&SpellcheckService::OnEnableAutoSpellCorrectChanged,
79 base::Unretained(this)));
80 pref_change_registrar_.Add(
81 prefs::kSpellCheckDictionaries,
82 base::Bind(&SpellcheckService::OnSpellCheckDictionariesChanged,
83 base::Unretained(this)));
84 if (!chrome::spellcheck_common::IsMultilingualSpellcheckEnabled()) {
85 pref_change_registrar_.Add(
86 prefs::kSpellCheckUseSpellingService,
87 base::Bind(&SpellcheckService::OnUseSpellingServiceChanged,
88 base::Unretained(this)));
91 pref_change_registrar_.Add(
92 prefs::kEnableContinuousSpellcheck,
93 base::Bind(&SpellcheckService::InitForAllRenderers,
94 base::Unretained(this)));
96 OnSpellCheckDictionariesChanged();
98 custom_dictionary_.reset(new SpellcheckCustomDictionary(context_->GetPath()));
99 custom_dictionary_->AddObserver(this);
100 custom_dictionary_->Load();
102 registrar_.Add(this,
103 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
104 content::NotificationService::AllSources());
107 SpellcheckService::~SpellcheckService() {
108 // Remove pref observers
109 pref_change_registrar_.RemoveAll();
112 base::WeakPtr<SpellcheckService> SpellcheckService::GetWeakPtr() {
113 return weak_ptr_factory_.GetWeakPtr();
116 #if !defined(OS_MACOSX)
117 // static
118 size_t SpellcheckService::GetSpellCheckLanguages(
119 base::SupportsUserData* context,
120 std::vector<std::string>* languages) {
121 PrefService* prefs = user_prefs::UserPrefs::Get(context);
122 StringPrefMember accept_languages_pref;
123 accept_languages_pref.Init(prefs::kAcceptLanguages, prefs);
125 std::vector<std::string> accept_languages = base::SplitString(
126 accept_languages_pref.GetValue(), ",",
127 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
129 StringListPrefMember dictionaries_pref;
130 dictionaries_pref.Init(prefs::kSpellCheckDictionaries, prefs);
131 *languages = dictionaries_pref.GetValue();
132 size_t enabled_spellcheck_languages = languages->size();
134 for (std::vector<std::string>::const_iterator i = accept_languages.begin();
135 i != accept_languages.end(); ++i) {
136 std::string language =
137 chrome::spellcheck_common::GetCorrespondingSpellCheckLanguage(*i);
138 if (!language.empty() &&
139 std::find(languages->begin(), languages->end(), language) ==
140 languages->end()) {
141 languages->push_back(language);
145 return enabled_spellcheck_languages;
147 #endif // !OS_MACOSX
149 // static
150 bool SpellcheckService::SignalStatusEvent(
151 SpellcheckService::EventType status_type) {
152 DCHECK_CURRENTLY_ON(BrowserThread::UI);
154 if (!g_status_event)
155 return false;
156 g_status_type = status_type;
157 g_status_event->Signal();
158 return true;
161 void SpellcheckService::StartRecordingMetrics(bool spellcheck_enabled) {
162 metrics_.reset(new SpellCheckHostMetrics());
163 metrics_->RecordEnabledStats(spellcheck_enabled);
164 OnUseSpellingServiceChanged();
167 void SpellcheckService::InitForRenderer(content::RenderProcessHost* process) {
168 DCHECK_CURRENTLY_ON(BrowserThread::UI);
170 content::BrowserContext* context = process->GetBrowserContext();
171 if (SpellcheckServiceFactory::GetForContext(context) != this)
172 return;
174 PrefService* prefs = user_prefs::UserPrefs::Get(context);
175 std::vector<SpellCheckBDictLanguage> bdict_languages;
177 for (const auto& hunspell_dictionary : hunspell_dictionaries_) {
178 bdict_languages.push_back(SpellCheckBDictLanguage());
179 bdict_languages.back().language = hunspell_dictionary->GetLanguage();
180 bdict_languages.back().file =
181 hunspell_dictionary->GetDictionaryFile().IsValid()
182 ? IPC::GetFileHandleForProcess(
183 hunspell_dictionary->GetDictionaryFile().GetPlatformFile(),
184 process->GetHandle(), false)
185 : IPC::InvalidPlatformFileForTransit();
188 process->Send(new SpellCheckMsg_Init(
189 bdict_languages, custom_dictionary_->GetWords(),
190 prefs->GetBoolean(prefs::kEnableAutoSpellCorrect)));
191 process->Send(new SpellCheckMsg_EnableSpellCheck(
192 prefs->GetBoolean(prefs::kEnableContinuousSpellcheck)));
195 SpellCheckHostMetrics* SpellcheckService::GetMetrics() const {
196 return metrics_.get();
199 SpellcheckCustomDictionary* SpellcheckService::GetCustomDictionary() {
200 return custom_dictionary_.get();
203 const ScopedVector<SpellcheckHunspellDictionary>&
204 SpellcheckService::GetHunspellDictionaries() {
205 return hunspell_dictionaries_;
208 spellcheck::FeedbackSender* SpellcheckService::GetFeedbackSender() {
209 return feedback_sender_.get();
212 bool SpellcheckService::LoadExternalDictionary(std::string language,
213 std::string locale,
214 std::string path,
215 DictionaryFormat format) {
216 return false;
219 bool SpellcheckService::UnloadExternalDictionary(std::string path) {
220 return false;
223 void SpellcheckService::Observe(int type,
224 const content::NotificationSource& source,
225 const content::NotificationDetails& details) {
226 DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CREATED);
227 content::RenderProcessHost* process =
228 content::Source<content::RenderProcessHost>(source).ptr();
229 InitForRenderer(process);
232 void SpellcheckService::OnCustomDictionaryLoaded() {
233 InitForAllRenderers();
236 void SpellcheckService::OnCustomDictionaryChanged(
237 const SpellcheckCustomDictionary::Change& dictionary_change) {
238 for (content::RenderProcessHost::iterator i(
239 content::RenderProcessHost::AllHostsIterator());
240 !i.IsAtEnd(); i.Advance()) {
241 i.GetCurrentValue()->Send(new SpellCheckMsg_CustomDictionaryChanged(
242 dictionary_change.to_add(),
243 dictionary_change.to_remove()));
247 void SpellcheckService::OnHunspellDictionaryInitialized() {
248 InitForAllRenderers();
251 void SpellcheckService::OnHunspellDictionaryDownloadBegin() {
254 void SpellcheckService::OnHunspellDictionaryDownloadSuccess() {
257 void SpellcheckService::OnHunspellDictionaryDownloadFailure() {
260 // static
261 void SpellcheckService::AttachStatusEvent(base::WaitableEvent* status_event) {
262 DCHECK_CURRENTLY_ON(BrowserThread::UI);
264 g_status_event = status_event;
267 // static
268 SpellcheckService::EventType SpellcheckService::GetStatusEvent() {
269 DCHECK_CURRENTLY_ON(BrowserThread::UI);
270 return g_status_type;
273 void SpellcheckService::InitForAllRenderers() {
274 DCHECK_CURRENTLY_ON(BrowserThread::UI);
275 for (content::RenderProcessHost::iterator i(
276 content::RenderProcessHost::AllHostsIterator());
277 !i.IsAtEnd(); i.Advance()) {
278 content::RenderProcessHost* process = i.GetCurrentValue();
279 if (process && process->GetHandle())
280 InitForRenderer(process);
284 void SpellcheckService::OnEnableAutoSpellCorrectChanged() {
285 bool enabled = pref_change_registrar_.prefs()->GetBoolean(
286 prefs::kEnableAutoSpellCorrect);
287 for (content::RenderProcessHost::iterator i(
288 content::RenderProcessHost::AllHostsIterator());
289 !i.IsAtEnd(); i.Advance()) {
290 content::RenderProcessHost* process = i.GetCurrentValue();
291 process->Send(new SpellCheckMsg_EnableAutoSpellCorrect(enabled));
295 void SpellcheckService::OnSpellCheckDictionariesChanged() {
296 for (auto& hunspell_dictionary : hunspell_dictionaries_)
297 hunspell_dictionary->RemoveObserver(this);
299 PrefService* prefs = user_prefs::UserPrefs::Get(context_);
300 DCHECK(prefs);
302 const base::ListValue* dictionary_values =
303 prefs->GetList(prefs::kSpellCheckDictionaries);
305 hunspell_dictionaries_.clear();
306 for (const base::Value* dictionary_value : *dictionary_values) {
307 std::string dictionary;
308 dictionary_value->GetAsString(&dictionary);
309 hunspell_dictionaries_.push_back(new SpellcheckHunspellDictionary(
310 dictionary, context_->GetRequestContext(), this));
311 hunspell_dictionaries_.back()->AddObserver(this);
312 hunspell_dictionaries_.back()->Load();
315 std::string feedback_language;
316 dictionary_values->GetString(0, &feedback_language);
317 std::string language_code;
318 std::string country_code;
319 chrome::spellcheck_common::GetISOLanguageCountryCodeFromLocale(
320 feedback_language, &language_code, &country_code);
321 feedback_sender_->OnLanguageCountryChange(language_code, country_code);
322 UpdateFeedbackSenderState();
325 void SpellcheckService::OnUseSpellingServiceChanged() {
326 bool enabled = pref_change_registrar_.prefs()->GetBoolean(
327 prefs::kSpellCheckUseSpellingService);
328 if (metrics_)
329 metrics_->RecordSpellingServiceStats(enabled);
330 UpdateFeedbackSenderState();
333 void SpellcheckService::UpdateFeedbackSenderState() {
334 if (SpellingServiceClient::IsAvailable(
335 context_, SpellingServiceClient::SPELLCHECK)) {
336 feedback_sender_->StartFeedbackCollection();
337 } else {
338 feedback_sender_->StopFeedbackCollection();