| 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 |