spellcheck.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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/renderer/spellchecker/spellcheck.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 8b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/render_messages.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/spellcheck_common.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/spellcheck_messages.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/spellcheck_result.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/renderer/spellchecker/spellcheck_language.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/renderer/spellchecker/spellcheck_provider.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/renderer/render_thread.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/renderer/render_view.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/renderer/render_view_visitor.h" 197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h" 207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebTextCheckingResult.h" 214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "third_party/WebKit/public/web/WebTextDecorationType.h" 227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebView.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebVector; 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebTextCheckingResult; 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebTextDecorationType; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class UpdateSpellcheckEnabled : public content::RenderViewVisitor { 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) explicit UpdateSpellcheckEnabled(bool enabled) : enabled_(enabled) {} 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool Visit(content::RenderView* render_view) OVERRIDE; 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool enabled_; // New spellcheck-enabled state. 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(UpdateSpellcheckEnabled); 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool UpdateSpellcheckEnabled::Visit(content::RenderView* render_view) { 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SpellCheckProvider* provider = SpellCheckProvider::Get(render_view); 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(provider); 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) provider->EnableSpellcheck(enabled_); 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class DocumentMarkersCollector : public content::RenderViewVisitor { 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DocumentMarkersCollector() {} 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual ~DocumentMarkersCollector() {} 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::vector<uint32>& markers() const { return markers_; } 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual bool Visit(content::RenderView* render_view) OVERRIDE; 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<uint32> markers_; 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DocumentMarkersCollector); 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DocumentMarkersCollector::Visit(content::RenderView* render_view) { 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!render_view || !render_view->GetWebView()) 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) WebVector<uint32> markers; 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) render_view->GetWebView()->spellingMarkers(&markers); 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < markers.size(); ++i) 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) markers_.push_back(markers[i]); 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Visit all render views. 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SpellCheck::SpellcheckRequest { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SpellcheckRequest(const base::string16& text, 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebTextCheckingCompletion* completion) 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : text_(text), completion_(completion) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(completion); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~SpellcheckRequest() {} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 text() { return text_; } 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebTextCheckingCompletion* completion() { return completion_; } 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 text_; // Text to be checked in this task. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The interface to send the misspelled ranges to WebKit. 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebTextCheckingCompletion* completion_; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(SpellcheckRequest); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Initializes SpellCheck object. 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// spellcheck_enabled_ currently MUST be set to true, due to peculiarities of 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the initialization sequence. 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Since it defaults to true, newly created SpellCheckProviders will enable 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// spellchecking. After the first word is typed, the provider requests a check, 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// which in turn triggers the delayed initialization sequence in SpellCheck. 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This does send a message to the browser side, which triggers the creation 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// of the SpellcheckService. That does create the observer for the preference 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// responsible for enabling/disabling checking, which allows subsequent changes 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// to that preference to be sent to all SpellCheckProviders. 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Setting |spellcheck_enabled_| to false by default prevents that mechanism, 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// and as such the SpellCheckProviders will never be notified of different 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// values. 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(groby): Simplify this. 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SpellCheck::SpellCheck() 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : auto_spell_correct_turned_on_(false), 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spellcheck_enabled_(true) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellCheck::~SpellCheck() { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellCheck::OnControlMessageReceived(const IPC::Message& message) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool handled = true; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(SpellCheck, message) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckMsg_Init, OnInit) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckMsg_CustomDictionaryChanged, 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnCustomDictionaryChanged) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableAutoSpellCorrect, 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnEnableAutoSpellCorrect) 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableSpellCheck, OnEnableSpellCheck) 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckMsg_RequestDocumentMarkers, 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OnRequestDocumentMarkers) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_END_MESSAGE_MAP() 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return handled; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file, 13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::set<std::string>& custom_words, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& language, 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool auto_spell_correct) { 137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch Init(IPC::PlatformFileForTransitToFile(bdict_file), 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) custom_words, language); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auto_spell_correct_turned_on_ = auto_spell_correct; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PostDelayedSpellCheckTask(pending_request_param_.release()); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellCheck::OnCustomDictionaryChanged( 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<std::string>& words_added, 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<std::string>& words_removed) { 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) custom_dictionary_.OnCustomDictionaryChanged(words_added, words_removed); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::OnEnableAutoSpellCorrect(bool enable) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auto_spell_correct_turned_on_ = enable; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellCheck::OnEnableSpellCheck(bool enable) { 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spellcheck_enabled_ = enable; 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UpdateSpellcheckEnabled updater(enable); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::RenderView::ForEach(&updater); 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpellCheck::OnRequestDocumentMarkers() { 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DocumentMarkersCollector collector; 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::RenderView::ForEach(&collector); 164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::RenderThread::Get()->Send( 165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) new SpellCheckHostMsg_RespondDocumentMarkers(collector.markers())); 166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(groby): Make sure we always have a spelling engine, even before Init() 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is called. 170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid SpellCheck::Init(base::File file, 17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::set<std::string>& custom_words, 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& language) { 173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch spellcheck_.Init(file.Pass(), language); 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) custom_dictionary_.Init(custom_words); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellCheck::SpellCheckWord( 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::char16* in_word, 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int in_word_len, 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int tag, 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* misspelling_start, 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* misspelling_len, 183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<base::string16>* optional_suggestions) { 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(in_word_len >= 0); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(misspelling_start && misspelling_len) << "Out vars must be given."; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do nothing if we need to delay initialization. (Rather than blocking, 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // report the word as correctly spelled.) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (InitializeIfNeeded()) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return spellcheck_.SpellCheckWord(in_word, in_word_len, 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tag, 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) misspelling_start, misspelling_len, 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) optional_suggestions); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellCheck::SpellCheckParagraph( 199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& text, 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebVector<WebTextCheckingResult>* results) { 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mac has its own spell checker, so this method will not be used. 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(results); 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<WebTextCheckingResult> textcheck_results; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t length = text.length(); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t offset = 0; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Spellcheck::SpellCheckWord() automatically breaks text into words and 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // checks the spellings of the extracted words. This function sets the 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // position and length of the first misspelled word and returns false when 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the text includes misspelled words. Therefore, we just repeat calling the 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // function until it returns true to check the whole text. 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int misspelling_start = 0; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int misspelling_length = 0; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (offset <= length) { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SpellCheckWord(&text[offset], 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length - offset, 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &misspelling_start, 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &misspelling_length, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL)) { 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results->assign(textcheck_results); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!custom_dictionary_.SpellCheckWord( 2277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch text, misspelling_start + offset, misspelling_length)) { 228a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 replacement; 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) textcheck_results.push_back(WebTextCheckingResult( 230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebTextDecorationTypeSpelling, 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) misspelling_start + offset, 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) misspelling_length, 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) replacement)); 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += misspelling_start + misspelling_length; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results->assign(textcheck_results); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // This function is only invoked for spell checker functionality that runs 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // on the render thread. OSX builds don't have that. 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NOTREACHED(); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 247a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)base::string16 SpellCheck::GetAutoCorrectionWord(const base::string16& word, 248a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int tag) { 249a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 autocorrect_word; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!auto_spell_correct_turned_on_) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return autocorrect_word; // Return the empty string. 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int word_length = static_cast<int>(word.size()); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (word_length < 2 || 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) word_length > chrome::spellcheck_common::kMaxAutoCorrectWordSize) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return autocorrect_word; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (InitializeIfNeeded()) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return autocorrect_word; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::char16 misspelled_word[ 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::spellcheck_common::kMaxAutoCorrectWordSize + 1]; 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::char16* word_char = word.c_str(); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i <= chrome::spellcheck_common::kMaxAutoCorrectWordSize; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++i) { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i >= word_length) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) misspelled_word[i] = 0; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) misspelled_word[i] = word_char[i]; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Swap adjacent characters and spellcheck. 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int misspelling_start, misspelling_len; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < word_length - 1; i++) { 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Swap. 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::swap(misspelled_word[i], misspelled_word[i + 1]); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check spelling. 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) misspelling_start = misspelling_len = 0; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpellCheckWord(misspelled_word, word_length, tag, &misspelling_start, 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &misspelling_len, NULL); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make decision: if only one swap produced a valid word, then we want to 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // return it. If we found two or more, we don't do autocorrection. 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (misspelling_len == 0) { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (autocorrect_word.empty()) { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) autocorrect_word.assign(misspelled_word); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) autocorrect_word.clear(); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Restore the swapped characters. 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::swap(misspelled_word[i], misspelled_word[i + 1]); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return autocorrect_word; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) // OSX uses its own spell checker 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::RequestTextChecking( 302a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& text, 303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebTextCheckingCompletion* completion) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clean up the previous request before starting a new request. 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pending_request_param_.get()) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_request_param_->completion()->didCancelCheckingText(); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_request_param_.reset(new SpellcheckRequest( 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) text, completion)); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We will check this text after we finish loading the hunspell dictionary. 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (InitializeIfNeeded()) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PostDelayedSpellCheckTask(pending_request_param_.release()); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellCheck::InitializeIfNeeded() { 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return spellcheck_.InitializeIfNeeded(); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) // OSX doesn't have |pending_request_param_| 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::PostDelayedSpellCheckTask(SpellcheckRequest* request) { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!request) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MessageLoopProxy::current()->PostTask(FROM_HERE, 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SpellCheck::PerformSpellCheck, 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AsWeakPtr(), 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Owned(request))); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) // Mac uses its native engine instead. 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::PerformSpellCheck(SpellcheckRequest* param) { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(param); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!spellcheck_.IsEnabled()) { 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) param->completion()->didCancelCheckingText(); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) WebVector<blink::WebTextCheckingResult> results; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpellCheckParagraph(param->text(), &results); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) param->completion()->didFinishCheckingText(results); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::CreateTextCheckingResults( 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ResultFilter filter, 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int line_offset, 351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& line_text, 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<SpellCheckResult>& spellcheck_results, 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebVector<WebTextCheckingResult>* textcheck_results) { 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Double-check misspelled words with our spellchecker and attach grammar 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // markers to them if our spellchecker tells they are correct words, i.e. they 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are probably contextually-misspelled words. 3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::char16* text = line_text.c_str(); 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<WebTextCheckingResult> list; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < spellcheck_results.size(); ++i) { 3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SpellCheckResult::Decoration decoration = spellcheck_results[i].decoration; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int word_location = spellcheck_results[i].location; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int word_length = spellcheck_results[i].length; 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int misspelling_start = 0; 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int misspelling_length = 0; 3654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (decoration == SpellCheckResult::SPELLING && 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) filter == USE_NATIVE_CHECKER) { 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SpellCheckWord(text + word_location, word_length, 0, 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &misspelling_start, &misspelling_length, NULL)) { 3694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) decoration = SpellCheckResult::GRAMMAR; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!custom_dictionary_.SpellCheckWord( 3737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch line_text, word_location, word_length)) { 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) list.push_back(WebTextCheckingResult( 3754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static_cast<WebTextDecorationType>(decoration), 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) word_location + line_offset, 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) word_length, 37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) spellcheck_results[i].replacement, 37990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) spellcheck_results[i].hash)); 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) textcheck_results->assign(list); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 384