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; 2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using blink::WebString; 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebTextCheckingResult; 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebTextDecorationType; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class UpdateSpellcheckEnabled : public content::RenderViewVisitor { 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) explicit UpdateSpellcheckEnabled(bool enabled) : enabled_(enabled) {} 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool Visit(content::RenderView* render_view) OVERRIDE; 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool enabled_; // New spellcheck-enabled state. 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(UpdateSpellcheckEnabled); 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool UpdateSpellcheckEnabled::Visit(content::RenderView* render_view) { 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SpellCheckProvider* provider = SpellCheckProvider::Get(render_view); 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(provider); 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) provider->EnableSpellcheck(enabled_); 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class DocumentMarkersCollector : public content::RenderViewVisitor { 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DocumentMarkersCollector() {} 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual ~DocumentMarkersCollector() {} 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::vector<uint32>& markers() const { return markers_; } 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual bool Visit(content::RenderView* render_view) OVERRIDE; 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<uint32> markers_; 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DocumentMarkersCollector); 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DocumentMarkersCollector::Visit(content::RenderView* render_view) { 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!render_view || !render_view->GetWebView()) 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) WebVector<uint32> markers; 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) render_view->GetWebView()->spellingMarkers(&markers); 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < markers.size(); ++i) 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) markers_.push_back(markers[i]); 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Visit all render views. 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)class DocumentMarkersRemover : public content::RenderViewVisitor { 7203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) public: 7303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) explicit DocumentMarkersRemover(const std::vector<std::string>& words); 7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) virtual ~DocumentMarkersRemover() OVERRIDE {} 7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) virtual bool Visit(content::RenderView* render_view) OVERRIDE; 7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) private: 7803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) WebVector<WebString> words_; 7903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DocumentMarkersRemover); 8003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}; 8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 8203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)DocumentMarkersRemover::DocumentMarkersRemover( 8303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const std::vector<std::string>& words) 8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) : words_(words.size()) { 8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (size_t i = 0; i < words.size(); ++i) 8603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) words_[i] = WebString::fromUTF8(words[i]); 8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool DocumentMarkersRemover::Visit(content::RenderView* render_view) { 9003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (render_view && render_view->GetWebView()) 9103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) render_view->GetWebView()->removeSpellingMarkersUnderWords(words_); 9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return true; 9303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 9403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SpellCheck::SpellcheckRequest { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SpellcheckRequest(const base::string16& text, 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebTextCheckingCompletion* completion) 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : text_(text), completion_(completion) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(completion); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~SpellcheckRequest() {} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 text() { return text_; } 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebTextCheckingCompletion* completion() { return completion_; } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 text_; // Text to be checked in this task. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The interface to send the misspelled ranges to WebKit. 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebTextCheckingCompletion* completion_; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(SpellcheckRequest); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Initializes SpellCheck object. 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// spellcheck_enabled_ currently MUST be set to true, due to peculiarities of 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the initialization sequence. 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Since it defaults to true, newly created SpellCheckProviders will enable 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// spellchecking. After the first word is typed, the provider requests a check, 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// which in turn triggers the delayed initialization sequence in SpellCheck. 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This does send a message to the browser side, which triggers the creation 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// of the SpellcheckService. That does create the observer for the preference 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// responsible for enabling/disabling checking, which allows subsequent changes 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// to that preference to be sent to all SpellCheckProviders. 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Setting |spellcheck_enabled_| to false by default prevents that mechanism, 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// and as such the SpellCheckProviders will never be notified of different 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// values. 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(groby): Simplify this. 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SpellCheck::SpellCheck() 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : auto_spell_correct_turned_on_(false), 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spellcheck_enabled_(true) { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellCheck::~SpellCheck() { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellCheck::OnControlMessageReceived(const IPC::Message& message) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool handled = true; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(SpellCheck, message) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckMsg_Init, OnInit) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckMsg_CustomDictionaryChanged, 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnCustomDictionaryChanged) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableAutoSpellCorrect, 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnEnableAutoSpellCorrect) 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableSpellCheck, OnEnableSpellCheck) 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) IPC_MESSAGE_HANDLER(SpellCheckMsg_RequestDocumentMarkers, 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OnRequestDocumentMarkers) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_END_MESSAGE_MAP() 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return handled; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file, 15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::set<std::string>& custom_words, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& language, 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool auto_spell_correct) { 162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch Init(IPC::PlatformFileForTransitToFile(bdict_file), 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) custom_words, language); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auto_spell_correct_turned_on_ = auto_spell_correct; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PostDelayedSpellCheckTask(pending_request_param_.release()); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellCheck::OnCustomDictionaryChanged( 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<std::string>& words_added, 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<std::string>& words_removed) { 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) custom_dictionary_.OnCustomDictionaryChanged(words_added, words_removed); 17403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (words_added.empty()) 17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return; 17603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DocumentMarkersRemover markersRemover(words_added); 17703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) content::RenderView::ForEach(&markersRemover); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::OnEnableAutoSpellCorrect(bool enable) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) auto_spell_correct_turned_on_ = enable; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpellCheck::OnEnableSpellCheck(bool enable) { 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spellcheck_enabled_ = enable; 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UpdateSpellcheckEnabled updater(enable); 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::RenderView::ForEach(&updater); 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpellCheck::OnRequestDocumentMarkers() { 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DocumentMarkersCollector collector; 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::RenderView::ForEach(&collector); 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::RenderThread::Get()->Send( 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) new SpellCheckHostMsg_RespondDocumentMarkers(collector.markers())); 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(groby): Make sure we always have a spelling engine, even before Init() 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is called. 199effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid SpellCheck::Init(base::File file, 20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::set<std::string>& custom_words, 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& language) { 202effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch spellcheck_.Init(file.Pass(), language); 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) custom_dictionary_.Init(custom_words); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellCheck::SpellCheckWord( 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::char16* in_word, 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int in_word_len, 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int tag, 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* misspelling_start, 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* misspelling_len, 212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<base::string16>* optional_suggestions) { 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(in_word_len >= 0); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(misspelling_start && misspelling_len) << "Out vars must be given."; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do nothing if we need to delay initialization. (Rather than blocking, 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // report the word as correctly spelled.) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (InitializeIfNeeded()) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return spellcheck_.SpellCheckWord(in_word, in_word_len, 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tag, 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) misspelling_start, misspelling_len, 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) optional_suggestions); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellCheck::SpellCheckParagraph( 228a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& text, 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebVector<WebTextCheckingResult>* results) { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mac has its own spell checker, so this method will not be used. 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(results); 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<WebTextCheckingResult> textcheck_results; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t length = text.length(); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t offset = 0; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Spellcheck::SpellCheckWord() automatically breaks text into words and 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // checks the spellings of the extracted words. This function sets the 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // position and length of the first misspelled word and returns false when 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the text includes misspelled words. Therefore, we just repeat calling the 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // function until it returns true to check the whole text. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int misspelling_start = 0; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int misspelling_length = 0; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (offset <= length) { 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SpellCheckWord(&text[offset], 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length - offset, 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &misspelling_start, 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &misspelling_length, 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL)) { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results->assign(textcheck_results); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!custom_dictionary_.SpellCheckWord( 2567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch text, misspelling_start + offset, misspelling_length)) { 257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 replacement; 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) textcheck_results.push_back(WebTextCheckingResult( 259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebTextDecorationTypeSpelling, 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) misspelling_start + offset, 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) misspelling_length, 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) replacement)); 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset += misspelling_start + misspelling_length; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results->assign(textcheck_results); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // This function is only invoked for spell checker functionality that runs 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // on the render thread. OSX builds don't have that. 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NOTREACHED(); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 276a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)base::string16 SpellCheck::GetAutoCorrectionWord(const base::string16& word, 277a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int tag) { 278a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 autocorrect_word; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!auto_spell_correct_turned_on_) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return autocorrect_word; // Return the empty string. 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int word_length = static_cast<int>(word.size()); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (word_length < 2 || 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) word_length > chrome::spellcheck_common::kMaxAutoCorrectWordSize) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return autocorrect_word; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (InitializeIfNeeded()) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return autocorrect_word; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::char16 misspelled_word[ 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::spellcheck_common::kMaxAutoCorrectWordSize + 1]; 2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::char16* word_char = word.c_str(); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i <= chrome::spellcheck_common::kMaxAutoCorrectWordSize; 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++i) { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i >= word_length) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) misspelled_word[i] = 0; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) misspelled_word[i] = word_char[i]; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Swap adjacent characters and spellcheck. 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int misspelling_start, misspelling_len; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < word_length - 1; i++) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Swap. 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::swap(misspelled_word[i], misspelled_word[i + 1]); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check spelling. 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) misspelling_start = misspelling_len = 0; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpellCheckWord(misspelled_word, word_length, tag, &misspelling_start, 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &misspelling_len, NULL); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make decision: if only one swap produced a valid word, then we want to 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // return it. If we found two or more, we don't do autocorrection. 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (misspelling_len == 0) { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (autocorrect_word.empty()) { 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) autocorrect_word.assign(misspelled_word); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) autocorrect_word.clear(); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Restore the swapped characters. 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::swap(misspelled_word[i], misspelled_word[i + 1]); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return autocorrect_word; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) // OSX uses its own spell checker 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::RequestTextChecking( 331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& text, 332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebTextCheckingCompletion* completion) { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clean up the previous request before starting a new request. 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pending_request_param_.get()) 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_request_param_->completion()->didCancelCheckingText(); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_request_param_.reset(new SpellcheckRequest( 338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) text, completion)); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We will check this text after we finish loading the hunspell dictionary. 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (InitializeIfNeeded()) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PostDelayedSpellCheckTask(pending_request_param_.release()); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellCheck::InitializeIfNeeded() { 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return spellcheck_.InitializeIfNeeded(); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) // OSX doesn't have |pending_request_param_| 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::PostDelayedSpellCheckTask(SpellcheckRequest* request) { 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!request) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MessageLoopProxy::current()->PostTask(FROM_HERE, 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SpellCheck::PerformSpellCheck, 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AsWeakPtr(), 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Owned(request))); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX) // Mac uses its native engine instead. 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::PerformSpellCheck(SpellcheckRequest* param) { 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(param); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!spellcheck_.IsEnabled()) { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) param->completion()->didCancelCheckingText(); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) WebVector<blink::WebTextCheckingResult> results; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpellCheckParagraph(param->text(), &results); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) param->completion()->didFinishCheckingText(results); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpellCheck::CreateTextCheckingResults( 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ResultFilter filter, 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int line_offset, 380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& line_text, 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<SpellCheckResult>& spellcheck_results, 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebVector<WebTextCheckingResult>* textcheck_results) { 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Double-check misspelled words with our spellchecker and attach grammar 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // markers to them if our spellchecker tells they are correct words, i.e. they 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are probably contextually-misspelled words. 3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::char16* text = line_text.c_str(); 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<WebTextCheckingResult> list; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < spellcheck_results.size(); ++i) { 3894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SpellCheckResult::Decoration decoration = spellcheck_results[i].decoration; 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int word_location = spellcheck_results[i].location; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int word_length = spellcheck_results[i].length; 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int misspelling_start = 0; 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int misspelling_length = 0; 3944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (decoration == SpellCheckResult::SPELLING && 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) filter == USE_NATIVE_CHECKER) { 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SpellCheckWord(text + word_location, word_length, 0, 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &misspelling_start, &misspelling_length, NULL)) { 3984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) decoration = SpellCheckResult::GRAMMAR; 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!custom_dictionary_.SpellCheckWord( 4027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch line_text, word_location, word_length)) { 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) list.push_back(WebTextCheckingResult( 4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static_cast<WebTextDecorationType>(decoration), 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) word_location + line_offset, 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) word_length, 40790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) spellcheck_results[i].replacement, 40890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) spellcheck_results[i].hash)); 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) textcheck_results->assign(list); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 413