spellcheck_message_filter.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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) 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <algorithm> 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <functional> 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/utf_string_conversions.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_factory.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_host_metrics.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/spellchecker/spellcheck_service.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spelling_service_client.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/common/spellcheck_marker.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/spellcheck_messages.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellCheckMessageFilter::SpellCheckMessageFilter(int render_process_id) 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : render_process_id_(render_process_id), 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) client_(new SpellingServiceClient) { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheckMessageFilter::OverrideThreadForMessage( 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const IPC::Message& message, BrowserThread::ID* thread) { 33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // IPC messages arrive on IO thread, but spellcheck data lives on UI thread. 34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // The message filter overrides the thread for these messages because they 35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // access spellcheck data. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (message.type() == SpellCheckHostMsg_RequestDictionary::ID || 37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) message.type() == SpellCheckHostMsg_NotifyChecked::ID || 38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) message.type() == SpellCheckHostMsg_RespondDocumentMarkers::ID) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *thread = BrowserThread::UI; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (message.type() == SpellCheckHostMsg_CallSpellingService::ID) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *thread = BrowserThread::UI; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellCheckMessageFilter::OnMessageReceived(const IPC::Message& message, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* message_was_ok) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool handled = true; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP_EX(SpellCheckMessageFilter, message, *message_was_ok) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RequestDictionary, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnSpellCheckerRequestDictionary) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckHostMsg_NotifyChecked, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnNotifyChecked) 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RespondDocumentMarkers, 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OnRespondDocumentMarkers) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckHostMsg_CallSpellingService, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnCallSpellingService) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_END_MESSAGE_MAP() 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return handled; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellCheckMessageFilter::~SpellCheckMessageFilter() {} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheckMessageFilter::OnSpellCheckerRequestDictionary() { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderProcessHost* host = 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderProcessHost::FromID(render_process_id_); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!host) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Teardown. 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext()); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The renderer has requested that we initialize its spellchecker. This should 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // generally only be called once per session, as after the first call, all 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // future renderers will be passed the initialization information on startup 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (or when the dictionary changes in some way). 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SpellcheckService* spellcheck_service = 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SpellcheckServiceFactory::GetForProfile(profile); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(spellcheck_service); 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The spellchecker initialization already started and finished; just send 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // it to the renderer. 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spellcheck_service->InitForRenderer(host); 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(rlp): Ensure that we do not initialize the hunspell dictionary more 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // than once if we get requests from different renderers. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheckMessageFilter::OnNotifyChecked(const string16& word, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool misspelled) { 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SpellcheckService* spellcheck = GetSpellcheckService(); 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Spellcheck service may not be available for a renderer process that is 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // shutting down. 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!spellcheck) 95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (spellcheck->GetMetrics()) 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch spellcheck->GetMetrics()->RecordCheckedWordStats(word, misspelled); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpellCheckMessageFilter::OnRespondDocumentMarkers( 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::vector<uint32>& markers) { 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SpellcheckService* spellcheck = GetSpellcheckService(); 103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Spellcheck service may not be available for a renderer process that is 104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // shutting down. 105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!spellcheck) 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) spellcheck->GetFeedbackSender()->OnReceiveDocumentMarkers( 108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) render_process_id_, markers); 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheckMessageFilter::OnCallSpellingService( 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int route_id, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int identifier, 11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const string16& text, 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::vector<SpellCheckMarker> markers) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!text.empty()); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Erase invalid markers (with offsets out of boundaries of text length). 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) markers.erase( 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::remove_if( 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) markers.begin(), 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) markers.end(), 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::not1(SpellCheckMarker::IsValidPredicate(text.length()))), 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) markers.end()); 12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) CallSpellingService(text, route_id, identifier, markers); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheckMessageFilter::OnTextCheckComplete( 130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int route_id, 131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int identifier, 13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::vector<SpellCheckMarker>& markers, 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& text, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<SpellCheckResult>& results) { 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SpellcheckService* spellcheck = GetSpellcheckService(); 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Spellcheck service may not be available for a renderer process that is 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // shutting down. 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!spellcheck) 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::vector<SpellCheckResult> results_copy = results; 14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) spellcheck->GetFeedbackSender()->OnSpellcheckResults( 14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) &results_copy, render_process_id_, text, markers); 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Erase custom dictionary words from the spellcheck results and record 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // in-dictionary feedback. 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::vector<SpellCheckResult>::iterator write_iter; 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::vector<SpellCheckResult>::iterator iter; 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string text_copy = UTF16ToUTF8(text); 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (iter = write_iter = results_copy.begin(); 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch iter != results_copy.end(); 152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ++iter) { 153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (spellcheck->GetCustomDictionary()->HasWord( 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch text_copy.substr(iter->location, iter->length))) { 155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch spellcheck->GetFeedbackSender()->RecordInDictionary(iter->hash); 156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (write_iter != iter) 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *write_iter = *iter; 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ++write_iter; 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch results_copy.erase(write_iter, results_copy.end()); 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Send(new SpellCheckMsg_RespondSpellingService( 16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) route_id, identifier, success, text, results_copy)); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// CallSpellingService always executes the callback OnTextCheckComplete. 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// (Which, in turn, sends a SpellCheckMsg_RespondSpellingService) 17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SpellCheckMessageFilter::CallSpellingService( 17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const string16& text, 17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int route_id, 17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int identifier, 17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::vector<SpellCheckMarker>& markers) { 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Profile* profile = NULL; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderProcessHost* host = 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderProcessHost::FromID(render_process_id_); 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (host) 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profile = Profile::FromBrowserContext(host->GetBrowserContext()); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client_->RequestTextCheck( 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile, 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SpellingServiceClient::SPELLCHECK, 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) text, 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&SpellCheckMessageFilter::OnTextCheckComplete, 186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::Unretained(this), 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) route_id, 18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) identifier, 18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) markers)); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpellcheckService* SpellCheckMessageFilter::GetSpellcheckService() const { 194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return SpellcheckServiceFactory::GetForRenderProcessId(render_process_id_); 195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 196