OLD | NEW |
| (Empty) |
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 <algorithm> | |
8 #include <functional> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/strings/utf_string_conversions.h" | |
12 #include "chrome/browser/spellchecker/spellcheck_factory.h" | |
13 #include "chrome/browser/spellchecker/spellcheck_service.h" | |
14 #include "components/prefs/pref_service.h" | |
15 #include "components/spellcheck/browser/spellcheck_host_metrics.h" | |
16 #include "components/spellcheck/browser/spelling_service_client.h" | |
17 #include "components/spellcheck/common/spellcheck_messages.h" | |
18 #include "components/spellcheck/spellcheck_build_features.h" | |
19 #include "content/public/browser/render_process_host.h" | |
20 #include "net/url_request/url_fetcher.h" | |
21 | |
22 using content::BrowserThread; | |
23 | |
24 SpellCheckMessageFilter::SpellCheckMessageFilter(int render_process_id) | |
25 : BrowserMessageFilter(SpellCheckMsgStart), | |
26 render_process_id_(render_process_id), | |
27 client_(new SpellingServiceClient) { | |
28 } | |
29 | |
30 void SpellCheckMessageFilter::OverrideThreadForMessage( | |
31 const IPC::Message& message, BrowserThread::ID* thread) { | |
32 // IPC messages arrive on IO thread, but spellcheck data lives on UI thread. | |
33 // The message filter overrides the thread for these messages because they | |
34 // access spellcheck data. | |
35 if (message.type() == SpellCheckHostMsg_RequestDictionary::ID || | |
36 message.type() == SpellCheckHostMsg_NotifyChecked::ID) | |
37 *thread = BrowserThread::UI; | |
38 #if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) | |
39 if (message.type() == SpellCheckHostMsg_CallSpellingService::ID) | |
40 *thread = BrowserThread::UI; | |
41 #endif | |
42 } | |
43 | |
44 bool SpellCheckMessageFilter::OnMessageReceived(const IPC::Message& message) { | |
45 bool handled = true; | |
46 IPC_BEGIN_MESSAGE_MAP(SpellCheckMessageFilter, message) | |
47 IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RequestDictionary, | |
48 OnSpellCheckerRequestDictionary) | |
49 IPC_MESSAGE_HANDLER(SpellCheckHostMsg_NotifyChecked, | |
50 OnNotifyChecked) | |
51 #if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) | |
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 | |
60 SpellCheckMessageFilter::~SpellCheckMessageFilter() {} | |
61 | |
62 void SpellCheckMessageFilter::OnSpellCheckerRequestDictionary() { | |
63 content::RenderProcessHost* host = | |
64 content::RenderProcessHost::FromID(render_process_id_); | |
65 if (!host) | |
66 return; // Teardown. | |
67 // The renderer has requested that we initialize its spellchecker. This should | |
68 // generally only be called once per session, as after the first call, all | |
69 // future renderers will be passed the initialization information on startup | |
70 // (or when the dictionary changes in some way). | |
71 SpellcheckService* spellcheck_service = | |
72 SpellcheckServiceFactory::GetForContext(host->GetBrowserContext()); | |
73 | |
74 DCHECK(spellcheck_service); | |
75 // The spellchecker initialization already started and finished; just send | |
76 // it to the renderer. | |
77 spellcheck_service->InitForRenderer(host); | |
78 | |
79 // TODO(rlp): Ensure that we do not initialize the hunspell dictionary more | |
80 // than once if we get requests from different renderers. | |
81 } | |
82 | |
83 void SpellCheckMessageFilter::OnNotifyChecked(const base::string16& word, | |
84 bool misspelled) { | |
85 SpellcheckService* spellcheck = GetSpellcheckService(); | |
86 // Spellcheck service may not be available for a renderer process that is | |
87 // shutting down. | |
88 if (!spellcheck) | |
89 return; | |
90 if (spellcheck->GetMetrics()) | |
91 spellcheck->GetMetrics()->RecordCheckedWordStats(word, misspelled); | |
92 } | |
93 | |
94 #if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) | |
95 void SpellCheckMessageFilter::OnCallSpellingService( | |
96 int route_id, | |
97 int identifier, | |
98 const base::string16& text) { | |
99 DCHECK(!text.empty()); | |
100 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
101 CallSpellingService(text, route_id, identifier); | |
102 } | |
103 | |
104 void SpellCheckMessageFilter::OnTextCheckComplete( | |
105 int route_id, | |
106 int identifier, | |
107 bool success, | |
108 const base::string16& text, | |
109 const std::vector<SpellCheckResult>& results) { | |
110 SpellcheckService* spellcheck = GetSpellcheckService(); | |
111 // Spellcheck service may not be available for a renderer process that is | |
112 // shutting down. | |
113 if (!spellcheck) | |
114 return; | |
115 std::vector<SpellCheckResult> results_copy = results; | |
116 | |
117 // Erase custom dictionary words from the spellcheck results and record | |
118 // in-dictionary feedback. | |
119 std::vector<SpellCheckResult>::iterator write_iter; | |
120 std::vector<SpellCheckResult>::iterator iter; | |
121 std::string text_copy = base::UTF16ToUTF8(text); | |
122 for (iter = write_iter = results_copy.begin(); | |
123 iter != results_copy.end(); | |
124 ++iter) { | |
125 if (!spellcheck->GetCustomDictionary()->HasWord( | |
126 text_copy.substr(iter->location, iter->length))) { | |
127 if (write_iter != iter) | |
128 *write_iter = *iter; | |
129 ++write_iter; | |
130 } | |
131 } | |
132 results_copy.erase(write_iter, results_copy.end()); | |
133 | |
134 Send(new SpellCheckMsg_RespondSpellingService( | |
135 route_id, identifier, success, text, results_copy)); | |
136 } | |
137 | |
138 // CallSpellingService always executes the callback OnTextCheckComplete. | |
139 // (Which, in turn, sends a SpellCheckMsg_RespondSpellingService) | |
140 void SpellCheckMessageFilter::CallSpellingService(const base::string16& text, | |
141 int route_id, | |
142 int identifier) { | |
143 content::RenderProcessHost* host = | |
144 content::RenderProcessHost::FromID(render_process_id_); | |
145 | |
146 client_->RequestTextCheck( | |
147 host ? host->GetBrowserContext() : NULL, | |
148 SpellingServiceClient::SPELLCHECK, text, | |
149 base::Bind(&SpellCheckMessageFilter::OnTextCheckComplete, | |
150 base::Unretained(this), route_id, identifier)); | |
151 } | |
152 #endif | |
153 | |
154 SpellcheckService* SpellCheckMessageFilter::GetSpellcheckService() const { | |
155 return SpellcheckServiceFactory::GetForRenderProcessId(render_process_id_); | |
156 } | |
OLD | NEW |