spellcheck_message_filter.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_message_filter.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_factory.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_service.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spelling_service_client.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/common/spellcheck_marker.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/spellcheck_messages.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellCheckMessageFilter::SpellCheckMessageFilter(int render_process_id)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : render_process_id_(render_process_id),
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      client_(new SpellingServiceClient) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheckMessageFilter::OverrideThreadForMessage(
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const IPC::Message& message, BrowserThread::ID* thread) {
29b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // IPC messages arrive on IO thread, but spellcheck data lives on UI thread.
30b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // The message filter overrides the thread for these messages because they
31b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // access spellcheck data.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (message.type() == SpellCheckHostMsg_RequestDictionary::ID ||
33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      message.type() == SpellCheckHostMsg_NotifyChecked::ID ||
34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      message.type() == SpellCheckHostMsg_RespondDocumentMarkers::ID)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *thread = BrowserThread::UI;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (message.type() == SpellCheckHostMsg_CallSpellingService::ID)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *thread = BrowserThread::UI;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellCheckMessageFilter::OnMessageReceived(const IPC::Message& message,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                bool* message_was_ok) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool handled = true;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_BEGIN_MESSAGE_MAP_EX(SpellCheckMessageFilter, message, *message_was_ok)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RequestDictionary,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        OnSpellCheckerRequestDictionary)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(SpellCheckHostMsg_NotifyChecked,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        OnNotifyChecked)
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RespondDocumentMarkers,
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        OnRespondDocumentMarkers)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(SpellCheckHostMsg_CallSpellingService,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        OnCallSpellingService)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_UNHANDLED(handled = false)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_END_MESSAGE_MAP()
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handled;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellCheckMessageFilter::~SpellCheckMessageFilter() {}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheckMessageFilter::OnSpellCheckerRequestDictionary() {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::RenderProcessHost* host =
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RenderProcessHost::FromID(render_process_id_);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!host)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Teardown.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The renderer has requested that we initialize its spellchecker. This should
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // generally only be called once per session, as after the first call, all
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // future renderers will be passed the initialization information on startup
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (or when the dictionary changes in some way).
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SpellcheckService* spellcheck_service =
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SpellcheckServiceFactory::GetForProfile(profile);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(spellcheck_service);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The spellchecker initialization already started and finished; just send
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it to the renderer.
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  spellcheck_service->InitForRenderer(host);
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(rlp): Ensure that we do not initialize the hunspell dictionary more
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // than once if we get requests from different renderers.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheckMessageFilter::OnNotifyChecked(const string16& word,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              bool misspelled) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::RenderProcessHost* host =
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RenderProcessHost::FromID(render_process_id_);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!host)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Teardown.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delegates to SpellCheckHost which tracks the stats of our spellchecker.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SpellcheckService* spellcheck_service =
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SpellcheckServiceFactory::GetForProfile(profile);
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(spellcheck_service);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (spellcheck_service->GetMetrics())
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    spellcheck_service->GetMetrics()->RecordCheckedWordStats(word, misspelled);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpellCheckMessageFilter::OnRespondDocumentMarkers(
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::vector<uint32>& markers) {
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SpellcheckService* spellcheck =
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      SpellcheckServiceFactory::GetForRenderProcessId(render_process_id_);
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(spellcheck);
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  spellcheck->GetFeedbackSender()->OnReceiveDocumentMarkers(render_process_id_,
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                            markers);
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheckMessageFilter::OnCallSpellingService(
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int route_id,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int identifier,
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const string16& text,
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<SpellCheckMarker>& markers) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!text.empty());
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CallSpellingService(text, route_id, identifier, markers);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheckMessageFilter::OnTextCheckComplete(
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int route_id,
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int identifier,
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<SpellCheckMarker>& markers,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success,
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string16& text,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<SpellCheckResult>& results) {
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SpellcheckService* spellcheck =
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      SpellcheckServiceFactory::GetForRenderProcessId(render_process_id_);
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(spellcheck);
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<SpellCheckResult> results_copy = results;
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  spellcheck->GetFeedbackSender()->OnSpellcheckResults(
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      &results_copy, render_process_id_, text, markers);
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Send(new SpellCheckMsg_RespondSpellingService(
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      route_id, identifier, success, text, results_copy));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// CallSpellingService always executes the callback OnTextCheckComplete.
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// (Which, in turn, sends a SpellCheckMsg_RespondSpellingService)
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SpellCheckMessageFilter::CallSpellingService(
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const string16& text,
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int route_id,
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int identifier,
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<SpellCheckMarker>& markers) {
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Profile* profile = NULL;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::RenderProcessHost* host =
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RenderProcessHost::FromID(render_process_id_);
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (host)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    profile = Profile::FromBrowserContext(host->GetBrowserContext());
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client_->RequestTextCheck(
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    profile,
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SpellingServiceClient::SPELLCHECK,
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    text,
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Bind(&SpellCheckMessageFilter::OnTextCheckComplete,
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               base::Unretained(this),
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               route_id,
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               identifier,
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               markers));
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
161