[spellcheck] Don't spellcheck in removed language.

If you remove from chrome://settings/languages a language that has "Use
this language for spellchecking" selected, then this language will
continue to be used for spellchecking. This patch fixes the issue by
listening to changes in accept languages and disabling spellcheck for
any language that is no longer in accept languages.

BUG=584519

Review URL: https://codereview.chromium.org/1673783003

Cr-Commit-Position: refs/heads/master@{#374485}
diff --git a/chrome/browser/spellchecker/spellcheck_service.cc b/chrome/browser/spellchecker/spellcheck_service.cc
index 68d72e8f..b766b24 100644
--- a/chrome/browser/spellchecker/spellcheck_service.cc
+++ b/chrome/browser/spellchecker/spellcheck_service.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/spellchecker/spellcheck_service.h"
 
+#include <algorithm>
+
 #include "base/logging.h"
 #include "base/strings/string_split.h"
 #include "base/supports_user_data.h"
@@ -76,7 +78,6 @@
   }
 
   single_dictionary_pref.SetValue("");
-
 #endif  // defined(USE_BROWSER_SPELLCHECKER)
 
   std::string language_code;
@@ -96,7 +97,10 @@
       prefs::kSpellCheckUseSpellingService,
       base::Bind(&SpellcheckService::OnUseSpellingServiceChanged,
                  base::Unretained(this)));
-
+  pref_change_registrar_.Add(
+      prefs::kAcceptLanguages,
+      base::Bind(&SpellcheckService::OnAcceptLanguagesChanged,
+                 base::Unretained(this)));
   pref_change_registrar_.Add(
       prefs::kEnableContinuousSpellcheck,
       base::Bind(&SpellcheckService::InitForAllRenderers,
@@ -336,6 +340,31 @@
   UpdateFeedbackSenderState();
 }
 
+void SpellcheckService::OnAcceptLanguagesChanged() {
+  PrefService* prefs = user_prefs::UserPrefs::Get(context_);
+  std::vector<std::string> accept_languages =
+      base::SplitString(prefs->GetString(prefs::kAcceptLanguages), ",",
+                        base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  std::transform(
+      accept_languages.begin(), accept_languages.end(),
+      accept_languages.begin(),
+      &chrome::spellcheck_common::GetCorrespondingSpellCheckLanguage);
+
+  StringListPrefMember dictionaries_pref;
+  dictionaries_pref.Init(prefs::kSpellCheckDictionaries, prefs);
+  std::vector<std::string> dictionaries = dictionaries_pref.GetValue();
+  std::vector<std::string> filtered_dictionaries;
+
+  for (const auto& dictionary : dictionaries) {
+    if (std::find(accept_languages.begin(), accept_languages.end(),
+                  dictionary) != accept_languages.end()) {
+      filtered_dictionaries.push_back(dictionary);
+    }
+  }
+
+  dictionaries_pref.SetValue(filtered_dictionaries);
+}
+
 void SpellcheckService::UpdateFeedbackSenderState() {
   std::string feedback_language;
   if (!hunspell_dictionaries_.empty())
diff --git a/chrome/browser/spellchecker/spellcheck_service.h b/chrome/browser/spellchecker/spellcheck_service.h
index 6c45907..b2a03b4 100644
--- a/chrome/browser/spellchecker/spellcheck_service.h
+++ b/chrome/browser/spellchecker/spellcheck_service.h
@@ -156,6 +156,11 @@
   // Notification handler for changes to prefs::kSpellCheckUseSpellingService.
   void OnUseSpellingServiceChanged();
 
+  // Notification handler for changes to prefs::kAcceptLanguages. Removes from
+  // prefs::kSpellCheckDictionaries any languages that are not in
+  // prefs::kAcceptLanguages.
+  void OnAcceptLanguagesChanged();
+
   // Enables the feedback sender if spelling server is available and enabled.
   // Otherwise disables the feedback sender.
   void UpdateFeedbackSenderState();
diff --git a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
index 91d15cc..4459884 100644
--- a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
+++ b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
@@ -13,6 +13,8 @@
 #include "base/macros.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/tuple.h"
 #include "base/values.h"
@@ -86,11 +88,13 @@
 
   void InitSpellcheck(bool enable_spellcheck,
                       const std::string& single_dictionary,
-                      const std::vector<std::string>& multiple_dictionaries) {
+                      const std::string& multiple_dictionaries) {
     prefs_->SetBoolean(prefs::kEnableContinuousSpellcheck, enable_spellcheck);
     prefs_->SetString(prefs::kSpellCheckDictionary, single_dictionary);
     base::ListValue dictionaries_value;
-    dictionaries_value.AppendStrings(multiple_dictionaries);
+    dictionaries_value.AppendStrings(
+        base::SplitString(multiple_dictionaries, ",", base::TRIM_WHITESPACE,
+                          base::SPLIT_WANT_NONEMPTY));
     prefs_->Set(prefs::kSpellCheckDictionaries, dictionaries_value);
     SpellcheckService* spellcheck =
         SpellcheckServiceFactory::GetForRenderProcessId(renderer_->GetID());
@@ -108,14 +112,32 @@
     prefs_->SetString(prefs::kSpellCheckDictionary, single_dictionary);
   }
 
-  void SetMultiLingualDictionaries(
-      const std::vector<std::string>& multiple_dictionaries) {
+  void SetMultiLingualDictionaries(const std::string& multiple_dictionaries) {
     ScopedPreferenceChange scope(&renderer_->sink());
     base::ListValue dictionaries_value;
-    dictionaries_value.AppendStrings(multiple_dictionaries);
+    dictionaries_value.AppendStrings(
+        base::SplitString(multiple_dictionaries, ",", base::TRIM_WHITESPACE,
+                          base::SPLIT_WANT_NONEMPTY));
     prefs_->Set(prefs::kSpellCheckDictionaries, dictionaries_value);
   }
 
+  std::string GetMultilingualDictionaries() {
+    const base::ListValue* list_value =
+        prefs_->GetList(prefs::kSpellCheckDictionaries);
+    std::vector<std::string> dictionaries;
+    for (const auto& item_value : *list_value) {
+      std::string dictionary;
+      EXPECT_TRUE(item_value->GetAsString(&dictionary));
+      dictionaries.push_back(dictionary);
+    }
+    return base::JoinString(dictionaries, ",");
+  }
+
+  void SetAcceptLanguages(const std::string& accept_languages) {
+    ScopedPreferenceChange scope(&renderer_->sink());
+    prefs_->SetString(prefs::kAcceptLanguages, accept_languages);
+  }
+
   // Returns the boolean parameter sent in the first
   // SpellCheckMsg_EnableSpellCheck message. For example, if spellcheck service
   // sent the SpellCheckMsg_EnableSpellCheck(true) message, then this method
@@ -143,14 +165,29 @@
   PrefService* prefs_;
 };
 
+// Removing a spellcheck language from accept languages should remove it from
+// spellcheck languages list as well.
+IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest,
+                       RemoveSpellcheckLanguageFromAcceptLanguages) {
+  InitSpellcheck(true, "", "en-US,fr");
+  SetAcceptLanguages("en-US,es,ru");
+  EXPECT_EQ("en-US", GetMultilingualDictionaries());
+}
+
+// Keeping spellcheck languages in accept languages should not alter spellcheck
+// languages list.
+IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest,
+                       KeepSpellcheckLanguagesInAcceptLanguages) {
+  InitSpellcheck(true, "", "en-US,fr");
+  SetAcceptLanguages("en-US,fr,es");
+  EXPECT_EQ("en-US,fr", GetMultilingualDictionaries());
+}
+
 // Starting with spellcheck enabled should send the 'enable spellcheck' message
 // to the renderer. Consequently disabling spellcheck should send the 'disable
 // spellcheck' message to the renderer.
 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest, StartWithSpellcheck) {
-  std::vector<std::string> dictionaries;
-  dictionaries.push_back("en-US");
-  dictionaries.push_back("fr");
-  InitSpellcheck(true, "", dictionaries);
+  InitSpellcheck(true, "", "en-US,fr");
   EXPECT_TRUE(GetFirstEnableSpellcheckMessageParam());
 
   EnableSpellcheck(false);
@@ -162,10 +199,10 @@
 // languages should disable spellcheck.
 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest,
                        StartWithSingularLanguagePreference) {
-  InitSpellcheck(true, "en-US", std::vector<std::string>());
+  InitSpellcheck(true, "en-US", "");
   EXPECT_TRUE(GetFirstEnableSpellcheckMessageParam());
 
-  SetMultiLingualDictionaries(std::vector<std::string>());
+  SetMultiLingualDictionaries("");
   EXPECT_FALSE(GetFirstEnableSpellcheckMessageParam());
 }
 
@@ -174,13 +211,10 @@
 // languages should disable spellcheck.
 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest,
                        StartWithMultiLanguagePreference) {
-  std::vector<std::string> dictionaries;
-  dictionaries.push_back("en-US");
-  dictionaries.push_back("fr");
-  InitSpellcheck(true, "", dictionaries);
+  InitSpellcheck(true, "", "en-US,fr");
   EXPECT_TRUE(GetFirstEnableSpellcheckMessageParam());
 
-  SetMultiLingualDictionaries(std::vector<std::string>());
+  SetMultiLingualDictionaries("");
   EXPECT_FALSE(GetFirstEnableSpellcheckMessageParam());
 }
 
@@ -189,13 +223,10 @@
 // removing spellcheck languages should disable spellcheck.
 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest,
                        StartWithBothLanguagePreferences) {
-  std::vector<std::string> dictionaries;
-  dictionaries.push_back("en-US");
-  dictionaries.push_back("fr");
-  InitSpellcheck(true, "en-US", dictionaries);
+  InitSpellcheck(true, "en-US", "en-US,fr");
   EXPECT_TRUE(GetFirstEnableSpellcheckMessageParam());
 
-  SetMultiLingualDictionaries(std::vector<std::string>());
+  SetMultiLingualDictionaries("");
   EXPECT_FALSE(GetFirstEnableSpellcheckMessageParam());
 }
 
@@ -203,10 +234,10 @@
 // message to the renderer. Consequently adding spellchecking languages should
 // enable spellcheck.
 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest, StartWithoutLanguages) {
-  InitSpellcheck(true, "", std::vector<std::string>());
+  InitSpellcheck(true, "", "");
   EXPECT_FALSE(GetFirstEnableSpellcheckMessageParam());
 
-  SetMultiLingualDictionaries(std::vector<std::string>(1, "en-US"));
+  SetMultiLingualDictionaries("en-US");
   EXPECT_TRUE(GetFirstEnableSpellcheckMessageParam());
 }
 
@@ -214,10 +245,7 @@
 // message to the renderer. Consequently enabling spellcheck should send the
 // 'enable spellcheck' message to the renderer.
 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest, StartWithoutSpellcheck) {
-  std::vector<std::string> dictionaries;
-  dictionaries.push_back("en-US");
-  dictionaries.push_back("fr");
-  InitSpellcheck(false, "", dictionaries);
+  InitSpellcheck(false, "", "en-US,fr");
   EXPECT_FALSE(GetFirstEnableSpellcheckMessageParam());
 
   EnableSpellcheck(true);