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