spellcheck_message_filter.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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.
4
5#include "chrome/browser/spellchecker/spellcheck_message_filter.h"
6
7#include "base/bind.h"
8#include "base/prefs/pref_service.h"
9#include "chrome/browser/profiles/profile.h"
10#include "chrome/browser/spellchecker/spellcheck_factory.h"
11#include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
12#include "chrome/browser/spellchecker/spellcheck_service.h"
13#include "chrome/browser/spellchecker/spelling_service_client.h"
14#include "chrome/common/pref_names.h"
15#include "chrome/common/spellcheck_messages.h"
16#include "content/public/browser/render_process_host.h"
17#include "net/url_request/url_fetcher.h"
18
19using content::BrowserThread;
20
21SpellCheckMessageFilter::SpellCheckMessageFilter(int render_process_id)
22    : render_process_id_(render_process_id),
23      client_(new SpellingServiceClient)
24#if !defined(OS_MACOSX)
25      ,
26      route_id_(0),
27      identifier_(0)
28#endif
29      {
30}
31
32void SpellCheckMessageFilter::OverrideThreadForMessage(
33    const IPC::Message& message, BrowserThread::ID* thread) {
34  if (message.type() == SpellCheckHostMsg_RequestDictionary::ID ||
35      message.type() == SpellCheckHostMsg_NotifyChecked::ID)
36    *thread = BrowserThread::UI;
37#if !defined(OS_MACOSX)
38  if (message.type() == SpellCheckHostMsg_CallSpellingService::ID)
39    *thread = BrowserThread::UI;
40#endif
41}
42
43bool SpellCheckMessageFilter::OnMessageReceived(const IPC::Message& message,
44                                                bool* message_was_ok) {
45  bool handled = true;
46  IPC_BEGIN_MESSAGE_MAP_EX(SpellCheckMessageFilter, message, *message_was_ok)
47    IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RequestDictionary,
48                        OnSpellCheckerRequestDictionary)
49    IPC_MESSAGE_HANDLER(SpellCheckHostMsg_NotifyChecked,
50                        OnNotifyChecked)
51#if !defined(OS_MACOSX)
52    IPC_MESSAGE_HANDLER(SpellCheckHostMsg_CallSpellingService,
53                        OnCallSpellingService)
54#endif
55    IPC_MESSAGE_UNHANDLED(handled = false)
56  IPC_END_MESSAGE_MAP()
57  return handled;
58}
59
60SpellCheckMessageFilter::~SpellCheckMessageFilter() {}
61
62void SpellCheckMessageFilter::OnSpellCheckerRequestDictionary() {
63  content::RenderProcessHost* host =
64      content::RenderProcessHost::FromID(render_process_id_);
65  if (!host)
66    return;  // Teardown.
67  Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
68  // The renderer has requested that we initialize its spellchecker. This should
69  // generally only be called once per session, as after the first call, all
70  // future renderers will be passed the initialization information on startup
71  // (or when the dictionary changes in some way).
72  SpellcheckService* spellcheck_service =
73      SpellcheckServiceFactory::GetForProfile(profile);
74
75  DCHECK(spellcheck_service);
76  // The spellchecker initialization already started and finished; just send
77  // it to the renderer.
78  spellcheck_service->InitForRenderer(host);
79
80  // TODO(rlp): Ensure that we do not initialize the hunspell dictionary more
81  // than once if we get requests from different renderers.
82}
83
84void SpellCheckMessageFilter::OnNotifyChecked(const string16& word,
85                                              bool misspelled) {
86  content::RenderProcessHost* host =
87      content::RenderProcessHost::FromID(render_process_id_);
88  if (!host)
89    return;  // Teardown.
90  // Delegates to SpellCheckHost which tracks the stats of our spellchecker.
91  Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
92  SpellcheckService* spellcheck_service =
93      SpellcheckServiceFactory::GetForProfile(profile);
94  DCHECK(spellcheck_service);
95  if (spellcheck_service->GetMetrics())
96    spellcheck_service->GetMetrics()->RecordCheckedWordStats(word, misspelled);
97}
98
99#if !defined(OS_MACOSX)
100void SpellCheckMessageFilter::OnCallSpellingService(
101    int route_id,
102    int identifier,
103    int document_tag,
104    const string16& text) {
105  DCHECK(!text.empty());
106  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
107  route_id_ = route_id;
108  identifier_ = identifier;
109  CallSpellingService(document_tag, text);
110}
111
112void SpellCheckMessageFilter::OnTextCheckComplete(
113    int tag,
114    bool success,
115    const string16& text,
116    const std::vector<SpellCheckResult>& results) {
117  Send(new SpellCheckMsg_RespondSpellingService(route_id_,
118                                                identifier_,
119                                                tag,
120                                                success,
121                                                text,
122                                                results));
123}
124
125// CallSpellingService always executes the callback OnTextCheckComplete.
126// (Which, in turn, sends a SpellCheckMsg_RespondSpellingService)
127void SpellCheckMessageFilter::CallSpellingService(int document_tag,
128                                                  const string16& text) {
129  Profile* profile = NULL;
130  content::RenderProcessHost* host =
131      content::RenderProcessHost::FromID(render_process_id_);
132  if (host)
133    profile = Profile::FromBrowserContext(host->GetBrowserContext());
134
135  client_->RequestTextCheck(
136    profile, SpellingServiceClient::SPELLCHECK, text,
137    base::Bind(&SpellCheckMessageFilter::OnTextCheckComplete,
138               base::Unretained(this), document_tag));
139}
140#endif
141