summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/spellchecker/spellcheck_language.cc
blob: c7ad42df1d734bc445b0349fdcc4e9bf6f3db9bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/renderer/spellchecker/spellcheck_language.h"

#include "base/logging.h"
#include "chrome/renderer/spellchecker/spellcheck_worditerator.h"
#include "chrome/renderer/spellchecker/spelling_engine.h"


SpellcheckLanguage::SpellcheckLanguage()
    : platform_spelling_engine_(CreateNativeSpellingEngine()) {
}

SpellcheckLanguage::~SpellcheckLanguage() {
}

void SpellcheckLanguage::Init(base::File file, const std::string& language) {
  DCHECK(platform_spelling_engine_.get());
  platform_spelling_engine_->Init(file.Pass());

  character_attributes_.SetDefaultLanguage(language);
  text_iterator_.Reset();
  contraction_iterator_.Reset();
}

bool SpellcheckLanguage::InitializeIfNeeded() {
  DCHECK(platform_spelling_engine_.get());
  return platform_spelling_engine_->InitializeIfNeeded();
}

bool SpellcheckLanguage::SpellCheckWord(
    const base::char16* in_word,
    int in_word_len,
    int tag,
    int* misspelling_start,
    int* misspelling_len,
    std::vector<base::string16>* optional_suggestions) {
  DCHECK(in_word_len >= 0);
  DCHECK(misspelling_start && misspelling_len) << "Out vars must be given.";

  // Do nothing if we need to delay initialization. (Rather than blocking,
  // report the word as correctly spelled.)
  if (InitializeIfNeeded())
    return true;

  // Do nothing if spell checking is disabled.
  if (!platform_spelling_engine_.get() ||
      !platform_spelling_engine_->IsEnabled())
    return true;

  *misspelling_start = 0;
  *misspelling_len = 0;
  if (in_word_len == 0)
    return true;  // No input means always spelled correctly.

  base::string16 word;
  int word_start;
  int word_length;
  if (!text_iterator_.IsInitialized() &&
      !text_iterator_.Initialize(&character_attributes_, true)) {
      // We failed to initialize text_iterator_, return as spelled correctly.
      VLOG(1) << "Failed to initialize SpellcheckWordIterator";
      return true;
  }

  text_iterator_.SetText(in_word, in_word_len);
  DCHECK(platform_spelling_engine_.get());
  while (text_iterator_.GetNextWord(&word, &word_start, &word_length)) {
    // Found a word (or a contraction) that the spellchecker can check the
    // spelling of.
    if (platform_spelling_engine_->CheckSpelling(word, tag))
      continue;

    // If the given word is a concatenated word of two or more valid words
    // (e.g. "hello:hello"), we should treat it as a valid word.
    if (IsValidContraction(word, tag))
      continue;

    *misspelling_start = word_start;
    *misspelling_len = word_length;

    // Get the list of suggested words.
    if (optional_suggestions) {
      platform_spelling_engine_->FillSuggestionList(word,
                                                    optional_suggestions);
    }
    return false;
  }

  return true;
}

// Returns whether or not the given string is a valid contraction.
// This function is a fall-back when the SpellcheckWordIterator class
// returns a concatenated word which is not in the selected dictionary
// (e.g. "in'n'out") but each word is valid.
bool SpellcheckLanguage::IsValidContraction(const base::string16& contraction,
                                            int tag) {
  if (!contraction_iterator_.IsInitialized() &&
      !contraction_iterator_.Initialize(&character_attributes_, false)) {
    // We failed to initialize the word iterator, return as spelled correctly.
    VLOG(1) << "Failed to initialize contraction_iterator_";
    return true;
  }

  contraction_iterator_.SetText(contraction.c_str(), contraction.length());

  base::string16 word;
  int word_start;
  int word_length;

  DCHECK(platform_spelling_engine_.get());
  while (contraction_iterator_.GetNextWord(&word, &word_start, &word_length)) {
    if (!platform_spelling_engine_->CheckSpelling(word, tag))
      return false;
  }
  return true;
}

bool SpellcheckLanguage::IsEnabled() {
  DCHECK(platform_spelling_engine_.get());
  return platform_spelling_engine_->IsEnabled();
}