15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/shell/renderer/test_runner/spell_check_client.h"
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/shell/renderer/test_runner/mock_grammar_check.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/shell/renderer/test_runner/web_test_delegate.h"
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/shell/renderer/test_runner/web_test_proxy.h"
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h"
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace content {
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace {
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class HostMethodTask : public WebMethodTask<SpellCheckClient> {
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public:
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  typedef void (SpellCheckClient::*CallbackMethodType)();
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  HostMethodTask(SpellCheckClient* object, CallbackMethodType callback)
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      : WebMethodTask<SpellCheckClient>(object), callback_(callback) {}
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual ~HostMethodTask() {}
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual void RunIfValid() OVERRIDE { (object_->*callback_)(); }
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private:
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CallbackMethodType callback_;
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(HostMethodTask);
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SpellCheckClient::SpellCheckClient(WebTestProxyBase* web_test_proxy)
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : last_requested_text_checking_completion_(0),
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      web_test_proxy_(web_test_proxy) {
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SpellCheckClient::~SpellCheckClient() {
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void SpellCheckClient::SetDelegate(WebTestDelegate* delegate) {
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delegate_ = delegate;
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// blink::WebSpellCheckClient
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void SpellCheckClient::spellCheck(
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const blink::WebString& text,
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int& misspelled_offset,
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int& misspelled_length,
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    blink::WebVector<blink::WebString>* optional_suggestions) {
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Check the spelling of the given text.
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  spell_check_.SpellCheckWord(text, &misspelled_offset, &misspelled_length);
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void SpellCheckClient::checkTextOfParagraph(
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const blink::WebString& text,
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    blink::WebTextCheckingTypeMask mask,
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    blink::WebVector<blink::WebTextCheckingResult>* web_results) {
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<blink::WebTextCheckingResult> results;
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (mask & blink::WebTextCheckingTypeSpelling) {
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    size_t offset = 0;
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::string16 data = text;
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while (offset < data.length()) {
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int misspelled_position = 0;
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int misspelled_length = 0;
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      spell_check_.SpellCheckWord(
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          data.substr(offset), &misspelled_position, &misspelled_length);
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!misspelled_length)
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        break;
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      blink::WebTextCheckingResult result;
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      result.decoration = blink::WebTextDecorationTypeSpelling;
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      result.location = offset + misspelled_position;
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      result.length = misspelled_length;
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      results.push_back(result);
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      offset += misspelled_position + misspelled_length;
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (mask & blink::WebTextCheckingTypeGrammar)
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    MockGrammarCheck::CheckGrammarOfString(text, &results);
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  web_results->assign(results);
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void SpellCheckClient::requestCheckingOfText(
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const blink::WebString& text,
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const blink::WebVector<uint32_t>& markers,
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const blink::WebVector<unsigned>& marker_offsets,
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    blink::WebTextCheckingCompletion* completion) {
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (text.isEmpty()) {
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (completion)
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      completion->didCancelCheckingText();
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (last_requested_text_checking_completion_)
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    last_requested_text_checking_completion_->didCancelCheckingText();
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  last_requested_text_checking_completion_ = completion;
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  last_requested_text_check_string_ = text;
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (spell_check_.HasInCache(text))
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    FinishLastTextCheck();
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  else
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    delegate_->PostDelayedTask(
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        new HostMethodTask(this, &SpellCheckClient::FinishLastTextCheck), 0);
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void SpellCheckClient::FinishLastTextCheck() {
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!last_requested_text_checking_completion_)
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<blink::WebTextCheckingResult> results;
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int offset = 0;
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::string16 text = last_requested_text_check_string_;
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!spell_check_.IsMultiWordMisspelling(blink::WebString(text), &results)) {
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while (text.length()) {
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int misspelled_position = 0;
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int misspelled_length = 0;
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      spell_check_.SpellCheckWord(
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          blink::WebString(text), &misspelled_position, &misspelled_length);
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!misspelled_length)
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        break;
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      blink::WebVector<blink::WebString> suggestions;
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      spell_check_.FillSuggestionList(
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          blink::WebString(text.substr(misspelled_position, misspelled_length)),
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          &suggestions);
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      results.push_back(blink::WebTextCheckingResult(
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          blink::WebTextDecorationTypeSpelling,
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          offset + misspelled_position,
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          misspelled_length,
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          suggestions.isEmpty() ? blink::WebString() : suggestions[0]));
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      text = text.substr(misspelled_position + misspelled_length);
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      offset += misspelled_position + misspelled_length;
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    MockGrammarCheck::CheckGrammarOfString(last_requested_text_check_string_,
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                           &results);
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  last_requested_text_checking_completion_->didFinishCheckingText(results);
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  last_requested_text_checking_completion_ = 0;
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  web_test_proxy_->PostSpellCheckEvent(blink::WebString("FinishLastTextCheck"));
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)blink::WebString SpellCheckClient::autoCorrectWord(
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const blink::WebString& word) {
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Returns an empty string as Mac WebKit ('WebKitSupport/WebEditorClient.mm')
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // does. (If this function returns a non-empty string, WebKit replaces the
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // given misspelled string with the result one. This process executes some
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // editor commands and causes layout-test failures.)
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return blink::WebString();
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace content
153