Convert Spellcheck host MessageFilter IPC to mojo
Remove chrome/browser/spellchecker/spellcheck_message_filter and its
unittest. Replace it with a mojo implementation of same that exposes
an interface to renderers for calling spell-check-host API available
in the browser process:
- RequestDictionary, NotifyChecked, CallSpellingService.
Update browser tests / unit tests to use the new mojo implementation
and add a mojom::SpellCheckHost unit test:
- chrome_site_per_process_browsertest.cc
- spellcheck_service_browsertest.cc
- spellcheck_provider_hunspell_unittest.cc
- spell_check_host_impl_unittest.cc
Bug: 714480
Change-Id: I7e6a46245a908fe4600b1d3d86f2d9dc884f79ea
Reviewed-on: https://chromium-review.googlesource.com/505648
Reviewed-by: Mike West <[email protected]>
Reviewed-by: Jochen Eisinger <[email protected]>
Reviewed-by: Sam McNally <[email protected]>
Reviewed-by: Rouslan Solomakhin <[email protected]>
Reviewed-by: Johan Tibell <[email protected]>
Commit-Queue: Noel Gordon <[email protected]>
Cr-Commit-Position: refs/heads/master@{#475395}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index b259642..74fb59d 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2025,14 +2025,14 @@
}
if (enable_spellcheck) {
sources += [
+ "spellchecker/spell_check_host_impl.cc",
+ "spellchecker/spell_check_host_impl.h",
"spellchecker/spellcheck_custom_dictionary.cc",
"spellchecker/spellcheck_custom_dictionary.h",
"spellchecker/spellcheck_factory.cc",
"spellchecker/spellcheck_factory.h",
"spellchecker/spellcheck_hunspell_dictionary.cc",
"spellchecker/spellcheck_hunspell_dictionary.h",
- "spellchecker/spellcheck_message_filter.cc",
- "spellchecker/spellcheck_message_filter.h",
"spellchecker/spellcheck_message_filter_platform_mac.cc",
"spellchecker/spellcheck_service.cc",
"spellchecker/spellcheck_service.h",
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index e90776d..840d9a1 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -359,7 +359,7 @@
#endif
#if BUILDFLAG(ENABLE_SPELLCHECK)
-#include "chrome/browser/spellchecker/spellcheck_message_filter.h"
+#include "chrome/browser/spellchecker/spell_check_host_impl.h"
#endif
#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
@@ -1205,9 +1205,6 @@
#if BUILDFLAG(ENABLE_PRINTING)
host->AddFilter(new printing::PrintingMessageFilter(id, profile));
#endif
-#if BUILDFLAG(ENABLE_SPELLCHECK)
- host->AddFilter(new SpellCheckMessageFilter(id));
-#endif
#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
host->AddFilter(new SpellCheckMessageFilterPlatform(id));
#endif
@@ -3071,6 +3068,11 @@
registry->AddInterface(
base::Bind(&BudgetServiceImpl::Create, render_process_host->GetID()),
ui_task_runner);
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+ registry->AddInterface(
+ base::Bind(&SpellCheckHostImpl::Create, render_process_host->GetID()),
+ ui_task_runner);
+#endif
registry->AddInterface(
base::Bind(&rappor::RapporRecorderImpl::Create,
g_browser_process->rappor_service()),
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index 887404b..8f8676b 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -13,6 +13,7 @@
"metrics::mojom::LeakDetector",
"mojom::ModuleEventSink",
"rappor::mojom::RapporRecorder",
+ "spellcheck::mojom::SpellCheckHost",
"startup_metric_utils::mojom::StartupMetricHost",
"translate::mojom::ContentTranslateDriver"
],
diff --git a/chrome/browser/chrome_site_per_process_browsertest.cc b/chrome/browser/chrome_site_per_process_browsertest.cc
index 1c6047f..27e813c 100644
--- a/chrome/browser/chrome_site_per_process_browsertest.cc
+++ b/chrome/browser/chrome_site_per_process_browsertest.cc
@@ -38,7 +38,9 @@
#include "url/gurl.h"
#if BUILDFLAG(ENABLE_SPELLCHECK)
+#include "components/spellcheck/common/spellcheck.mojom.h"
#include "components/spellcheck/common/spellcheck_messages.h"
+#include "services/service_manager/public/cpp/bind_source_info.h"
#endif
class ChromeSitePerProcessTest : public InProcessBrowserTest {
@@ -560,58 +562,87 @@
}
#if BUILDFLAG(ENABLE_SPELLCHECK)
-// Class to sniff incoming IPCs for spell check messages.
-class TestSpellCheckMessageFilter : public content::BrowserMessageFilter {
+// Class to sniff incoming spellcheck IPC / Mojo SpellCheckHost messages.
+class TestSpellCheckMessageFilter : public content::BrowserMessageFilter,
+ spellcheck::mojom::SpellCheckHost {
public:
explicit TestSpellCheckMessageFilter(content::RenderProcessHost* process_host)
: content::BrowserMessageFilter(SpellCheckMsgStart),
process_host_(process_host),
text_received_(false),
message_loop_runner_(
- base::MakeRefCounted<content::MessageLoopRunner>()) {}
+ base::MakeRefCounted<content::MessageLoopRunner>()),
+ binding_(this) {}
- bool OnMessageReceived(const IPC::Message& message) override {
- IPC_BEGIN_MESSAGE_MAP(TestSpellCheckMessageFilter, message)
-#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- IPC_MESSAGE_HANDLER(SpellCheckHostMsg_CallSpellingService, HandleMessage)
-#else
- IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RequestTextCheck, HandleMessage)
-#endif
- IPC_END_MESSAGE_MAP()
- return false;
- }
+ content::RenderProcessHost* process() const { return process_host_; }
- base::string16 last_text() const { return last_text_; }
+ const base::string16& text() const { return text_; }
void Wait() {
if (!text_received_)
message_loop_runner_->Run();
}
- content::RenderProcessHost* process() const { return process_host_; }
+ bool OnMessageReceived(const IPC::Message& message) override {
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ IPC_BEGIN_MESSAGE_MAP(TestSpellCheckMessageFilter, message)
+ // TODO(crbug.com/714480): convert the RequestTextCheck IPC to mojo.
+ IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RequestTextCheck, HandleMessage)
+ IPC_END_MESSAGE_MAP()
+#endif
+ return false;
+ }
+
+#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ void ShellCheckHostRequest(const service_manager::BindSourceInfo& source_info,
+ spellcheck::mojom::SpellCheckHostRequest request) {
+ EXPECT_FALSE(binding_.is_bound());
+ binding_.Bind(std::move(request));
+ }
+#endif
private:
~TestSpellCheckMessageFilter() override {}
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void HandleMessage(int, int, const base::string16& text) {
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(&TestSpellCheckMessageFilter::HandleMessageOnUI, this,
- text));
+ base::BindOnce(&TestSpellCheckMessageFilter::HandleMessageOnUIThread,
+ this, text));
}
+#endif
- void HandleMessageOnUI(const base::string16& text) {
- last_text_ = text;
+ void HandleMessageOnUIThread(const base::string16& text) {
if (!text_received_) {
text_received_ = true;
+ text_ = text;
message_loop_runner_->Quit();
+ } else {
+ NOTREACHED();
}
}
+ // spellcheck::mojom::SpellCheckHost:
+ void RequestDictionary() override {}
+
+ void NotifyChecked(const base::string16& word, bool misspelled) override {}
+
+ void CallSpellingService(const base::string16& text,
+ CallSpellingServiceCallback callback) override {
+#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ std::move(callback).Run(true, std::vector<SpellCheckResult>());
+ binding_.Close();
+ HandleMessageOnUIThread(text);
+#endif
+ }
+
content::RenderProcessHost* process_host_;
bool text_received_;
- base::string16 last_text_;
+ base::string16 text_;
scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+ mojo::Binding<spellcheck::mojom::SpellCheckHost> binding_;
DISALLOW_COPY_AND_ASSIGN(TestSpellCheckMessageFilter);
};
@@ -629,6 +660,28 @@
ChromeContentBrowserClient::RenderProcessWillLaunch(process_host);
}
+#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ void ExposeInterfacesToRenderer(
+ service_manager::BinderRegistry* registry,
+ content::AssociatedInterfaceRegistry* associated_registry,
+ content::RenderProcessHost* render_process_host) override {
+ // Expose the default interfaces.
+ ChromeContentBrowserClient::ExposeInterfacesToRenderer(
+ registry, associated_registry, render_process_host);
+
+ scoped_refptr<TestSpellCheckMessageFilter> filter =
+ GetSpellCheckMessageFilterForProcess(render_process_host);
+ CHECK(filter);
+
+ // Override the default SpellCheckHost interface.
+ auto ui_task_runner = content::BrowserThread::GetTaskRunnerForThread(
+ content::BrowserThread::UI);
+ registry->AddInterface(
+ base::Bind(&TestSpellCheckMessageFilter::ShellCheckHostRequest, filter),
+ ui_task_runner);
+ }
+#endif // !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+
// Retrieves the registered filter for the given RenderProcessHost. It will
// return nullptr if the RenderProcessHost was initialized while a different
// instance of ContentBrowserClient was in action.
@@ -661,14 +714,15 @@
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
- content::RenderFrameHost* subframe =
+ content::RenderFrameHost* cross_site_subframe =
ChildFrameAt(web_contents->GetMainFrame(), 0);
+
scoped_refptr<TestSpellCheckMessageFilter> filter =
browser_client.GetSpellCheckMessageFilterForProcess(
- subframe->GetProcess());
+ cross_site_subframe->GetProcess());
filter->Wait();
- EXPECT_EQ(base::ASCIIToUTF16("zz."), filter->last_text());
+ EXPECT_EQ(base::ASCIIToUTF16("zz."), filter->text());
content::SetBrowserClientForTesting(old_browser_client);
}
diff --git a/chrome/browser/spellchecker/spell_check_host_impl.cc b/chrome/browser/spellchecker/spell_check_host_impl.cc
new file mode 100644
index 0000000..788a19c
--- /dev/null
+++ b/chrome/browser/spellchecker/spell_check_host_impl.cc
@@ -0,0 +1,133 @@
+// Copyright 2017 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/spell_check_host_impl.h"
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/spellchecker/spellcheck_custom_dictionary.h"
+#include "chrome/browser/spellchecker/spellcheck_factory.h"
+#include "chrome/browser/spellchecker/spellcheck_service.h"
+#include "components/spellcheck/browser/spellcheck_host_metrics.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+SpellCheckHostImpl::SpellCheckHostImpl(int render_process_id)
+ : render_process_id_(render_process_id) {}
+
+SpellCheckHostImpl::~SpellCheckHostImpl() = default;
+
+// static
+void SpellCheckHostImpl::Create(
+ int render_process_id,
+ const service_manager::BindSourceInfo& source_info,
+ spellcheck::mojom::SpellCheckHostRequest request) {
+ mojo::MakeStrongBinding(
+ base::MakeUnique<SpellCheckHostImpl>(render_process_id),
+ std::move(request));
+}
+
+void SpellCheckHostImpl::RequestDictionary() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ // The renderer has requested that we initialize its spellchecker. This
+ // generally should only be called once per session, as after the first
+ // call, future renderers will be passed the initialization information
+ // on startup (or when the dictionary changes in some way).
+ SpellcheckService* spellcheck = GetSpellcheckService();
+ if (!spellcheck)
+ return; // Teardown.
+
+ // The spellchecker initialization already started and finished; just
+ // send it to the renderer.
+ spellcheck->InitForRenderer(
+ content::RenderProcessHost::FromID(render_process_id_));
+
+ // TODO(rlp): Ensure that we do not initialize the hunspell dictionary
+ // more than once if we get requests from different renderers.
+}
+
+void SpellCheckHostImpl::NotifyChecked(const base::string16& word,
+ bool misspelled) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ SpellcheckService* spellcheck = GetSpellcheckService();
+ if (!spellcheck)
+ return; // Teardown.
+ if (spellcheck->GetMetrics())
+ spellcheck->GetMetrics()->RecordCheckedWordStats(word, misspelled);
+}
+
+void SpellCheckHostImpl::CallSpellingService(
+ const base::string16& text,
+ CallSpellingServiceCallback callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ if (text.empty()) {
+ std::move(callback).Run(false, std::vector<SpellCheckResult>());
+ mojo::ReportBadMessage(__FUNCTION__);
+ return;
+ }
+
+#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ content::RenderProcessHost* host =
+ content::RenderProcessHost::FromID(render_process_id_);
+
+ // Checks the user profile and sends a JSON-RPC request to the Spelling
+ // service if a user enables the "Ask Google for suggestions" option. When
+ // a response is received (including an error) from the remote Spelling
+ // service, calls CallSpellingServiceDone.
+ client_.RequestTextCheck(
+ host ? host->GetBrowserContext() : nullptr,
+ SpellingServiceClient::SPELLCHECK, text,
+ base::Bind(&SpellCheckHostImpl::CallSpellingServiceDone,
+ base::Unretained(this), base::Passed(&callback)));
+#else
+ std::move(callback).Run(false, std::vector<SpellCheckResult>());
+#endif
+}
+
+#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+void SpellCheckHostImpl::CallSpellingServiceDone(
+ CallSpellingServiceCallback callback,
+ bool success,
+ const base::string16& text,
+ const std::vector<SpellCheckResult>& service_results) const {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ SpellcheckService* spellcheck = GetSpellcheckService();
+ if (!spellcheck) { // Teardown.
+ std::move(callback).Run(false, std::vector<SpellCheckResult>());
+ return;
+ }
+
+ std::vector<SpellCheckResult> results = FilterCustomWordResults(
+ base::UTF16ToUTF8(text), *spellcheck->GetCustomDictionary(),
+ service_results);
+
+ std::move(callback).Run(success, results);
+}
+
+// static
+std::vector<SpellCheckResult> SpellCheckHostImpl::FilterCustomWordResults(
+ const std::string& text,
+ const SpellcheckCustomDictionary& custom_dictionary,
+ const std::vector<SpellCheckResult>& service_results) {
+ std::vector<SpellCheckResult> results;
+ for (const auto& result : service_results) {
+ const std::string word = text.substr(result.location, result.length);
+ if (!custom_dictionary.HasWord(word))
+ results.push_back(result);
+ }
+
+ return results;
+}
+#endif // !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+
+SpellcheckService* SpellCheckHostImpl::GetSpellcheckService() const {
+ return SpellcheckServiceFactory::GetForRenderProcessId(render_process_id_);
+}
diff --git a/chrome/browser/spellchecker/spell_check_host_impl.h b/chrome/browser/spellchecker/spell_check_host_impl.h
new file mode 100644
index 0000000..9349fa1
--- /dev/null
+++ b/chrome/browser/spellchecker/spell_check_host_impl.h
@@ -0,0 +1,74 @@
+// Copyright 2017 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_SPELL_CHECK_HOST_IMPL_H_
+#define CHROME_BROWSER_SPELLCHECKER_SPELL_CHECK_HOST_IMPL_H_
+
+#include "base/macros.h"
+#include "components/spellcheck/browser/spelling_service_client.h"
+#include "components/spellcheck/common/spellcheck.mojom.h"
+#include "components/spellcheck/spellcheck_build_features.h"
+
+#if !BUILDFLAG(ENABLE_SPELLCHECK)
+#error "Spellcheck should be enabled."
+#endif
+
+class SpellcheckCustomDictionary;
+class SpellcheckService;
+
+struct SpellCheckResult;
+
+namespace service_manager {
+struct BindSourceInfo;
+}
+
+class SpellCheckHostImpl : public spellcheck::mojom::SpellCheckHost {
+ public:
+ explicit SpellCheckHostImpl(int render_process_id);
+ ~SpellCheckHostImpl() override;
+
+ static void Create(int render_process_id,
+ const service_manager::BindSourceInfo& source_info,
+ spellcheck::mojom::SpellCheckHostRequest request);
+
+ private:
+ friend class TestSpellCheckHostImpl;
+
+ // spellcheck::mojom::SpellCheckHost:
+ void RequestDictionary() override;
+ void NotifyChecked(const base::string16& word, bool misspelled) override;
+ void CallSpellingService(const base::string16& text,
+ CallSpellingServiceCallback callback) override;
+
+#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ // Invoked when the remote Spelling service has finished checking the
+ // text of a CallSpellingService request.
+ void CallSpellingServiceDone(
+ CallSpellingServiceCallback callback,
+ bool success,
+ const base::string16& text,
+ const std::vector<SpellCheckResult>& service_results) const;
+
+ // Filter out spelling corrections of custom dictionary words from the
+ // Spelling service results.
+ static std::vector<SpellCheckResult> FilterCustomWordResults(
+ const std::string& text,
+ const SpellcheckCustomDictionary& custom_dictionary,
+ const std::vector<SpellCheckResult>& service_results);
+#endif
+
+ // Returns the SpellcheckService of our |render_process_id_|. The return
+ // is null if the render process is being shut down.
+ virtual SpellcheckService* GetSpellcheckService() const;
+
+ // The process ID of our render process host.
+ const int render_process_id_;
+
+ // A JSON-RPC client that calls the remote Spelling service.
+ SpellingServiceClient client_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellCheckHostImpl);
+};
+
+#endif // CHROME_BROWSER_SPELLCHECKER_SPELL_CHECK_HOST_IMPL_H_
diff --git a/chrome/browser/spellchecker/spell_check_host_impl_unittest.cc b/chrome/browser/spellchecker/spell_check_host_impl_unittest.cc
new file mode 100644
index 0000000..22cadb6
--- /dev/null
+++ b/chrome/browser/spellchecker/spell_check_host_impl_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright 2017 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/spell_check_host_impl.h"
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/spellchecker/spellcheck_factory.h"
+#include "chrome/browser/spellchecker/spellcheck_service.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#error !BUILDFLAG(USE_BROWSER_SPELLCHECKER) is required for these tests.
+#endif
+
+class TestSpellCheckHostImpl {
+ public:
+ TestSpellCheckHostImpl()
+ : spellcheck_(base::MakeUnique<SpellcheckService>(&testing_profile_)) {}
+
+ SpellcheckCustomDictionary& GetCustomDictionary() const {
+ EXPECT_NE(nullptr, spellcheck_.get());
+ SpellcheckCustomDictionary* custom_dictionary =
+ spellcheck_->GetCustomDictionary();
+ return *custom_dictionary;
+ }
+
+ std::vector<SpellCheckResult> FilterCustomWordResults(
+ const std::string& text,
+ const std::vector<SpellCheckResult>& service_results) const {
+ return SpellCheckHostImpl::FilterCustomWordResults(
+ text, GetCustomDictionary(), service_results);
+ }
+
+ private:
+ content::TestBrowserThreadBundle thread_bundle_;
+ TestingProfile testing_profile_;
+ std::unique_ptr<SpellcheckService> spellcheck_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSpellCheckHostImpl);
+};
+
+// Spelling corrections of custom dictionary words should be removed from the
+// results returned by the remote Spelling service.
+TEST(SpellCheckHostImplTest, CustomSpellingResults) {
+ std::vector<SpellCheckResult> service_results;
+ service_results.push_back(SpellCheckResult(SpellCheckResult::SPELLING, 0, 6,
+ base::ASCIIToUTF16("Hello")));
+ service_results.push_back(SpellCheckResult(SpellCheckResult::SPELLING, 7, 5,
+ base::ASCIIToUTF16("World")));
+ TestSpellCheckHostImpl host_impl;
+ host_impl.GetCustomDictionary().AddWord("Helllo");
+ std::vector<SpellCheckResult> results =
+ host_impl.FilterCustomWordResults("Helllo Warld", service_results);
+ ASSERT_EQ(1u, results.size());
+
+ EXPECT_EQ(service_results[1].decoration, results[0].decoration);
+ EXPECT_EQ(service_results[1].location, results[0].location);
+ EXPECT_EQ(service_results[1].length, results[0].length);
+ EXPECT_EQ(service_results[1].replacement, results[0].replacement);
+}
+
+// Spelling corrections of words that are not in the custom dictionary should
+// be retained in the results returned by the remote Spelling service.
+TEST(SpellCheckHostImplTest, SpellingServiceResults) {
+ std::vector<SpellCheckResult> service_results;
+ service_results.push_back(SpellCheckResult(SpellCheckResult::SPELLING, 0, 6,
+ base::ASCIIToUTF16("Hello")));
+ service_results.push_back(SpellCheckResult(SpellCheckResult::SPELLING, 7, 5,
+ base::ASCIIToUTF16("World")));
+ TestSpellCheckHostImpl host_impl;
+ host_impl.GetCustomDictionary().AddWord("Hulo");
+ std::vector<SpellCheckResult> results =
+ host_impl.FilterCustomWordResults("Helllo Warld", service_results);
+ ASSERT_EQ(service_results.size(), results.size());
+
+ for (size_t i = 0; i < results.size(); ++i) {
+ EXPECT_EQ(service_results[i].decoration, results[i].decoration);
+ EXPECT_EQ(service_results[i].location, results[i].location);
+ EXPECT_EQ(service_results[i].length, results[i].length);
+ EXPECT_EQ(service_results[i].replacement, results[i].replacement);
+ }
+}
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter.cc b/chrome/browser/spellchecker/spellcheck_message_filter.cc
deleted file mode 100644
index 7f69a55..0000000
--- a/chrome/browser/spellchecker/spellcheck_message_filter.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright (c) 2012 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/spellcheck_message_filter.h"
-
-#include <algorithm>
-#include <functional>
-
-#include "base/bind.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/spellchecker/spellcheck_factory.h"
-#include "chrome/browser/spellchecker/spellcheck_service.h"
-#include "components/prefs/pref_service.h"
-#include "components/spellcheck/browser/spellcheck_host_metrics.h"
-#include "components/spellcheck/browser/spelling_service_client.h"
-#include "components/spellcheck/common/spellcheck_messages.h"
-#include "components/spellcheck/spellcheck_build_features.h"
-#include "content/public/browser/render_process_host.h"
-#include "net/url_request/url_fetcher.h"
-
-using content::BrowserThread;
-
-SpellCheckMessageFilter::SpellCheckMessageFilter(int render_process_id)
- : BrowserMessageFilter(SpellCheckMsgStart),
- render_process_id_(render_process_id),
- client_(new SpellingServiceClient) {
-}
-
-void SpellCheckMessageFilter::OverrideThreadForMessage(
- const IPC::Message& message, BrowserThread::ID* thread) {
- // IPC messages arrive on IO thread, but spellcheck data lives on UI thread.
- // The message filter overrides the thread for these messages because they
- // access spellcheck data.
- if (message.type() == SpellCheckHostMsg_RequestDictionary::ID ||
- message.type() == SpellCheckHostMsg_NotifyChecked::ID)
- *thread = BrowserThread::UI;
-#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- if (message.type() == SpellCheckHostMsg_CallSpellingService::ID)
- *thread = BrowserThread::UI;
-#endif
-}
-
-bool SpellCheckMessageFilter::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(SpellCheckMessageFilter, message)
- IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RequestDictionary,
- OnSpellCheckerRequestDictionary)
- IPC_MESSAGE_HANDLER(SpellCheckHostMsg_NotifyChecked,
- OnNotifyChecked)
-#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- IPC_MESSAGE_HANDLER(SpellCheckHostMsg_CallSpellingService,
- OnCallSpellingService)
-#endif
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-SpellCheckMessageFilter::~SpellCheckMessageFilter() {}
-
-void SpellCheckMessageFilter::OnSpellCheckerRequestDictionary() {
- content::RenderProcessHost* host =
- content::RenderProcessHost::FromID(render_process_id_);
- if (!host)
- return; // Teardown.
- // 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
- // (or when the dictionary changes in some way).
- SpellcheckService* spellcheck_service =
- SpellcheckServiceFactory::GetForContext(host->GetBrowserContext());
-
- DCHECK(spellcheck_service);
- // The spellchecker initialization already started and finished; just send
- // it to the renderer.
- spellcheck_service->InitForRenderer(host);
-
- // TODO(rlp): Ensure that we do not initialize the hunspell dictionary more
- // than once if we get requests from different renderers.
-}
-
-void SpellCheckMessageFilter::OnNotifyChecked(const base::string16& word,
- bool misspelled) {
- SpellcheckService* spellcheck = GetSpellcheckService();
- // Spellcheck service may not be available for a renderer process that is
- // shutting down.
- if (!spellcheck)
- return;
- if (spellcheck->GetMetrics())
- spellcheck->GetMetrics()->RecordCheckedWordStats(word, misspelled);
-}
-
-#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
-void SpellCheckMessageFilter::OnCallSpellingService(
- int route_id,
- int identifier,
- const base::string16& text) {
- DCHECK(!text.empty());
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- CallSpellingService(text, route_id, identifier);
-}
-
-void SpellCheckMessageFilter::OnTextCheckComplete(
- int route_id,
- int identifier,
- bool success,
- const base::string16& text,
- const std::vector<SpellCheckResult>& results) {
- SpellcheckService* spellcheck = GetSpellcheckService();
- // Spellcheck service may not be available for a renderer process that is
- // shutting down.
- if (!spellcheck)
- return;
- std::vector<SpellCheckResult> results_copy = results;
-
- // Erase custom dictionary words from the spellcheck results and record
- // in-dictionary feedback.
- std::vector<SpellCheckResult>::iterator write_iter;
- std::vector<SpellCheckResult>::iterator iter;
- std::string text_copy = base::UTF16ToUTF8(text);
- for (iter = write_iter = results_copy.begin();
- iter != results_copy.end();
- ++iter) {
- if (!spellcheck->GetCustomDictionary()->HasWord(
- text_copy.substr(iter->location, iter->length))) {
- if (write_iter != iter)
- *write_iter = *iter;
- ++write_iter;
- }
- }
- results_copy.erase(write_iter, results_copy.end());
-
- Send(new SpellCheckMsg_RespondSpellingService(
- route_id, identifier, success, text, results_copy));
-}
-
-// CallSpellingService always executes the callback OnTextCheckComplete.
-// (Which, in turn, sends a SpellCheckMsg_RespondSpellingService)
-void SpellCheckMessageFilter::CallSpellingService(const base::string16& text,
- int route_id,
- int identifier) {
- content::RenderProcessHost* host =
- content::RenderProcessHost::FromID(render_process_id_);
-
- client_->RequestTextCheck(
- host ? host->GetBrowserContext() : NULL,
- SpellingServiceClient::SPELLCHECK, text,
- base::Bind(&SpellCheckMessageFilter::OnTextCheckComplete,
- base::Unretained(this), route_id, identifier));
-}
-#endif
-
-SpellcheckService* SpellCheckMessageFilter::GetSpellcheckService() const {
- return SpellcheckServiceFactory::GetForRenderProcessId(render_process_id_);
-}
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter.h b/chrome/browser/spellchecker/spellcheck_message_filter.h
deleted file mode 100644
index 8f62b1e5..0000000
--- a/chrome/browser/spellchecker/spellcheck_message_filter.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2012 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_SPELLCHECK_MESSAGE_FILTER_H_
-#define CHROME_BROWSER_SPELLCHECKER_SPELLCHECK_MESSAGE_FILTER_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/compiler_specific.h"
-#include "components/spellcheck/browser/spelling_service_client.h"
-#include "components/spellcheck/spellcheck_build_features.h"
-#include "content/public/browser/browser_message_filter.h"
-
-class SpellcheckService;
-struct SpellCheckResult;
-
-// A message filter implementation that receives spell checker requests from
-// SpellCheckProvider.
-class SpellCheckMessageFilter : public content::BrowserMessageFilter {
- public:
- explicit SpellCheckMessageFilter(int render_process_id);
-
- // content::BrowserMessageFilter implementation.
- void OverrideThreadForMessage(const IPC::Message& message,
- content::BrowserThread::ID* thread) override;
- bool OnMessageReceived(const IPC::Message& message) override;
-
- private:
- friend class TestingSpellCheckMessageFilter;
-
- ~SpellCheckMessageFilter() override;
-
- void OnSpellCheckerRequestDictionary();
- void OnNotifyChecked(const base::string16& word, bool misspelled);
-#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- void OnCallSpellingService(int route_id,
- int identifier,
- const base::string16& text);
-
- // A callback function called when the Spelling service finishes checking
- // text. Sends the given results to a renderer.
- void OnTextCheckComplete(
- int route_id,
- int identifier,
- bool success,
- const base::string16& text,
- const std::vector<SpellCheckResult>& results);
-
- // Checks the user profile and sends a JSON-RPC request to the Spelling
- // service if a user enables the "Ask Google for suggestions" option. When we
- // receive a response (including an error) from the service, it calls
- // OnTextCheckComplete. When this function is called before we receive a
- // response for the previous request, this function cancels the previous
- // request and sends a new one.
- void CallSpellingService(const base::string16& text,
- int route_id,
- int identifier);
-#endif
-
- // Can be overridden for testing.
- virtual SpellcheckService* GetSpellcheckService() const;
-
- int render_process_id_;
-
- // A JSON-RPC client that calls the Spelling service in the background.
- std::unique_ptr<SpellingServiceClient> client_;
-};
-
-#endif // CHROME_BROWSER_SPELLCHECKER_SPELLCHECK_MESSAGE_FILTER_H_
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc b/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc
deleted file mode 100644
index 62d445f9..0000000
--- a/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright (c) 2013 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 <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <tuple>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/spellchecker/spellcheck_factory.h"
-#include "chrome/browser/spellchecker/spellcheck_message_filter.h"
-#include "chrome/browser/spellchecker/spellcheck_service.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/spellcheck/common/spellcheck_messages.h"
-#include "components/spellcheck/spellcheck_build_features.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "ipc/ipc_message.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class TestingSpellCheckMessageFilter : public SpellCheckMessageFilter {
- public:
- TestingSpellCheckMessageFilter()
- : SpellCheckMessageFilter(0),
- spellcheck_(new SpellcheckService(&profile_)) {}
-
- bool Send(IPC::Message* message) override {
- sent_messages.push_back(base::WrapUnique(message));
- return true;
- }
-
- SpellcheckService* GetSpellcheckService() const override {
- return spellcheck_.get();
- }
-
-#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- void OnTextCheckComplete(int route_id,
- int identifier,
- bool success,
- const base::string16& text,
- const std::vector<SpellCheckResult>& results) {
- SpellCheckMessageFilter::OnTextCheckComplete(route_id, identifier, success,
- text, results);
- }
-#endif
-
- std::vector<std::unique_ptr<IPC::Message>> sent_messages;
-
- private:
- ~TestingSpellCheckMessageFilter() override {}
-
- content::TestBrowserThreadBundle thread_bundle_;
- TestingProfile profile_;
- std::unique_ptr<SpellcheckService> spellcheck_;
-
- DISALLOW_COPY_AND_ASSIGN(TestingSpellCheckMessageFilter);
-};
-
-TEST(SpellCheckMessageFilterTest, TestOverrideThread) {
- static const uint32_t kSpellcheckMessages[] = {
- SpellCheckHostMsg_RequestDictionary::ID,
- SpellCheckHostMsg_NotifyChecked::ID,
-#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- SpellCheckHostMsg_CallSpellingService::ID,
-#endif
- };
- content::BrowserThread::ID thread;
- IPC::Message message;
- scoped_refptr<TestingSpellCheckMessageFilter> filter(
- new TestingSpellCheckMessageFilter);
- for (size_t i = 0; i < arraysize(kSpellcheckMessages); ++i) {
- message.SetHeaderValues(
- 0, kSpellcheckMessages[i], IPC::Message::PRIORITY_NORMAL);
- thread = content::BrowserThread::IO;
- filter->OverrideThreadForMessage(message, &thread);
- EXPECT_EQ(content::BrowserThread::UI, thread);
- }
-}
-
-#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
-TEST(SpellCheckMessageFilterTest, OnTextCheckCompleteTestCustomDictionary) {
- static const std::string kCustomWord = "Helllo";
- static const int kRouteId = 0;
- static const int kCallbackId = 0;
- static const base::string16 kText = base::ASCIIToUTF16("Helllo warld.");
- static const bool kSuccess = true;
- static const SpellCheckResult::Decoration kDecoration =
- SpellCheckResult::SPELLING;
- static const int kLocation = 7;
- static const int kLength = 5;
- static const base::string16 kReplacement = base::ASCIIToUTF16("world");
-
- std::vector<SpellCheckResult> results;
- results.push_back(SpellCheckResult(
- SpellCheckResult::SPELLING, 0, 6, base::ASCIIToUTF16("Hello")));
- results.push_back(
- SpellCheckResult(kDecoration, kLocation, kLength, kReplacement));
-
- scoped_refptr<TestingSpellCheckMessageFilter> filter(
- new TestingSpellCheckMessageFilter);
- filter->GetSpellcheckService()->GetCustomDictionary()->AddWord(kCustomWord);
- filter->OnTextCheckComplete(kRouteId, kCallbackId, kSuccess, kText, results);
- ASSERT_EQ(1U, filter->sent_messages.size());
-
- SpellCheckMsg_RespondSpellingService::Param params;
- bool ok = SpellCheckMsg_RespondSpellingService::Read(
- filter->sent_messages[0].get(), ¶ms);
- int sent_identifier = std::get<0>(params);
- bool sent_success = std::get<1>(params);
- base::string16 sent_text = std::get<2>(params);
- std::vector<SpellCheckResult> sent_results = std::get<3>(params);
- EXPECT_TRUE(ok);
- EXPECT_EQ(kCallbackId, sent_identifier);
- EXPECT_EQ(kSuccess, sent_success);
- EXPECT_EQ(kText, sent_text);
- ASSERT_EQ(1U, sent_results.size());
- EXPECT_EQ(kDecoration, sent_results[0].decoration);
- EXPECT_EQ(kLocation, sent_results[0].location);
- EXPECT_EQ(kLength, sent_results[0].length);
- EXPECT_EQ(kReplacement, sent_results[0].replacement);
-}
-
-TEST(SpellCheckMessageFilterTest, OnTextCheckCompleteTest) {
- std::vector<SpellCheckResult> results;
- results.push_back(SpellCheckResult(
- SpellCheckResult::SPELLING, 0, 6, base::ASCIIToUTF16("Hello")));
- results.push_back(SpellCheckResult(
- SpellCheckResult::SPELLING, 7, 7, base::ASCIIToUTF16("world")));
-
- scoped_refptr<TestingSpellCheckMessageFilter> filter(
- new TestingSpellCheckMessageFilter);
- filter->OnTextCheckComplete(1, 1, true, base::ASCIIToUTF16("Helllo walrd"),
- results);
- ASSERT_EQ(1U, filter->sent_messages.size());
-
- SpellCheckMsg_RespondSpellingService::Param params;
- bool ok = SpellCheckMsg_RespondSpellingService::Read(
- filter->sent_messages[0].get(), ¶ms);
- EXPECT_TRUE(ok);
-
- std::vector<SpellCheckResult> sent_results = std::get<3>(params);
- EXPECT_EQ(2U, sent_results.size());
-}
-#endif
diff --git a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
index 5abe4b7..2afbf90 100644
--- a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
+++ b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
@@ -4,54 +4,40 @@
#include "chrome/browser/spellchecker/spellcheck_service.h"
-#include <stddef.h>
-#include <stdint.h>
#include <string>
-#include <tuple>
#include <vector>
-#include "base/command_line.h"
#include "base/macros.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/test/histogram_tester.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/spellchecker/spell_check_host_impl.h"
#include "chrome/browser/spellchecker/spellcheck_factory.h"
+#include "chrome/browser/spellchecker/spellcheck_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/prefs/pref_service.h"
#include "components/spellcheck/browser/pref_names.h"
#include "components/spellcheck/common/spellcheck.mojom.h"
#include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/common/spellcheck_result.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_utils.h"
-#include "url/gurl.h"
+#include "services/service_manager/public/cpp/bind_source_info.h"
using content::BrowserContext;
-
-namespace {
-
-// A corrupted BDICT data used in DeleteCorruptedBDICT. Please do not use this
-// BDICT data for other tests.
-const uint8_t kCorruptedBDICT[] = {
- 0x42, 0x44, 0x69, 0x63, 0x02, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
- 0x3b, 0x00, 0x00, 0x00, 0x65, 0x72, 0xe0, 0xac, 0x27, 0xc7, 0xda, 0x66,
- 0x6d, 0x1e, 0xa6, 0x35, 0xd1, 0xf6, 0xb7, 0x35, 0x32, 0x00, 0x00, 0x00,
- 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
- 0x0a, 0x0a, 0x41, 0x46, 0x20, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6,
- 0x49, 0x00, 0x68, 0x02, 0x73, 0x06, 0x74, 0x0b, 0x77, 0x11, 0x79, 0x15,
-};
-
-} // namespace
+using content::RenderProcessHost;
class SpellcheckServiceBrowserTest : public InProcessBrowserTest,
public spellcheck::mojom::SpellChecker {
@@ -69,13 +55,13 @@
renderer_.reset();
}
- BrowserContext* GetContext() {
+ RenderProcessHost* GetRenderer() const { return renderer_.get(); }
+
+ BrowserContext* GetContext() const {
return static_cast<BrowserContext*>(browser()->profile());
}
- PrefService* GetPrefs() {
- return prefs_;
- }
+ PrefService* GetPrefs() const { return prefs_; }
void InitSpellcheck(bool enable_spellcheck,
const std::string& single_dictionary,
@@ -208,6 +194,11 @@
EXPECT_EQ(2u, words_added.size());
}
+ protected:
+ // Quits the RunLoop on Mojo request flow completion.
+ base::OnceClosure quit_;
+
+ private:
// Mocked RenderProcessHost.
std::unique_ptr<content::MockRenderProcessHost> renderer_;
@@ -217,9 +208,6 @@
// Binding to receive the SpellChecker request flow.
mojo::Binding<spellcheck::mojom::SpellChecker> binding_;
- // Quits the RunLoop on SpellChecker request flow completion.
- base::OnceClosure quit_;
-
// Used to verify the SpellChecker request flow.
bool bound_connection_closed_;
bool custom_dictionary_changed_called_;
@@ -229,6 +217,64 @@
DISALLOW_COPY_AND_ASSIGN(SpellcheckServiceBrowserTest);
};
+class SpellcheckServiceHostBrowserTest : public SpellcheckServiceBrowserTest {
+ public:
+ SpellcheckServiceHostBrowserTest() = default;
+
+ void RequestDictionary() {
+ spellcheck::mojom::SpellCheckHostPtr interface;
+ RequestSpellCheckHost(&interface);
+
+ interface->RequestDictionary();
+ }
+
+ void NotifyChecked() {
+ spellcheck::mojom::SpellCheckHostPtr interface;
+ RequestSpellCheckHost(&interface);
+
+ const bool misspelt = true;
+ base::UTF8ToUTF16("hallo", 5, &word_);
+ interface->NotifyChecked(word_, misspelt);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void CallSpellingService() {
+ spellcheck::mojom::SpellCheckHostPtr interface;
+ RequestSpellCheckHost(&interface);
+
+ base::UTF8ToUTF16("hello", 5, &word_);
+ interface->CallSpellingService(
+ word_,
+ base::Bind(&SpellcheckServiceHostBrowserTest::SpellingServiceDone,
+ base::Unretained(this)));
+
+ base::RunLoop run_loop;
+ quit_ = run_loop.QuitClosure();
+ run_loop.Run();
+
+ EXPECT_TRUE(spelling_service_done_called_);
+ }
+
+ private:
+ void RequestSpellCheckHost(spellcheck::mojom::SpellCheckHostPtr* interface) {
+ SpellCheckHostImpl::Create(GetRenderer()->GetID(),
+ service_manager::BindSourceInfo(),
+ mojo::MakeRequest(interface));
+ }
+
+ void SpellingServiceDone(bool success,
+ const std::vector<::SpellCheckResult>& results) {
+ spelling_service_done_called_ = true;
+ if (quit_)
+ std::move(quit_).Run();
+ }
+
+ bool spelling_service_done_called_ = false;
+ base::string16 word_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellcheckServiceHostBrowserTest);
+};
+
// Removing a spellcheck language from accept languages should remove it from
// spellcheck languages list as well.
IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest,
@@ -334,9 +380,49 @@
EXPECT_TRUE(GetCustomDictionaryChangedState());
}
+// Starting with only a single-language spellcheck setting, the host should
+// initialize the renderer's spellcheck system, and the same if the renderer
+// explicity requests the spellcheck dictionaries.
+IN_PROC_BROWSER_TEST_F(SpellcheckServiceHostBrowserTest, RequestDictionary) {
+ InitSpellcheck(true, "en-US", "");
+ EXPECT_TRUE(GetEnableSpellcheckState());
+
+ RequestDictionary();
+ EXPECT_TRUE(GetEnableSpellcheckState());
+}
+
+// When the renderer notifies that it corrected a word, the render process
+// host should record UMA stats about the correction.
+IN_PROC_BROWSER_TEST_F(SpellcheckServiceHostBrowserTest, NotifyChecked) {
+ const char kMisspellRatio[] = "SpellCheck.MisspellRatio";
+
+ base::HistogramTester tester;
+ tester.ExpectTotalCount(kMisspellRatio, 0);
+ NotifyChecked();
+ tester.ExpectTotalCount(kMisspellRatio, 1);
+}
+
+#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+// When the renderer requests the spelling service for correcting text, the
+// render process host should call the remote spelling service.
+IN_PROC_BROWSER_TEST_F(SpellcheckServiceHostBrowserTest, CallSpellingService) {
+ CallSpellingService();
+}
+#endif // !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+
// Tests that we can delete a corrupted BDICT file used by hunspell. We do not
// run this test on Mac because Mac does not use hunspell by default.
IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest, DeleteCorruptedBDICT) {
+ // Corrupted BDICT data: please do not use this BDICT data for other tests.
+ const uint8_t kCorruptedBDICT[] = {
+ 0x42, 0x44, 0x69, 0x63, 0x02, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x3b, 0x00, 0x00, 0x00, 0x65, 0x72, 0xe0, 0xac, 0x27, 0xc7, 0xda, 0x66,
+ 0x6d, 0x1e, 0xa6, 0x35, 0xd1, 0xf6, 0xb7, 0x35, 0x32, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
+ 0x0a, 0x0a, 0x41, 0x46, 0x20, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6,
+ 0x49, 0x00, 0x68, 0x02, 0x73, 0x06, 0x74, 0x0b, 0x77, 0x11, 0x79, 0x15,
+ };
+
// Write the corrupted BDICT data to create a corrupted BDICT file.
base::FilePath dict_dir;
ASSERT_TRUE(PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir));