Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / renderer / spellchecker / spellcheck_language.cc
blobc56c033050d1a291fc8c29c2fb9a644259fa8ca4
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/renderer/spellchecker/spellcheck_language.h"
7 #include "base/logging.h"
8 #include "chrome/renderer/spellchecker/spellcheck_worditerator.h"
9 #include "chrome/renderer/spellchecker/spelling_engine.h"
12 SpellcheckLanguage::SpellcheckLanguage()
13 : platform_spelling_engine_(CreateNativeSpellingEngine()) {
16 SpellcheckLanguage::~SpellcheckLanguage() {
19 void SpellcheckLanguage::Init(base::File file, const std::string& language) {
20 DCHECK(platform_spelling_engine_.get());
21 platform_spelling_engine_->Init(file.Pass());
23 character_attributes_.SetDefaultLanguage(language);
24 text_iterator_.Reset();
25 contraction_iterator_.Reset();
28 bool SpellcheckLanguage::InitializeIfNeeded() {
29 DCHECK(platform_spelling_engine_.get());
30 return platform_spelling_engine_->InitializeIfNeeded();
33 SpellcheckLanguage::SpellcheckWordResult SpellcheckLanguage::SpellCheckWord(
34 const base::char16* text_begin,
35 int position_in_text,
36 int text_length,
37 int tag,
38 int* skip_or_misspelling_start,
39 int* skip_or_misspelling_len,
40 std::vector<base::string16>* optional_suggestions) {
41 int remaining_text_len = text_length - position_in_text;
42 DCHECK(remaining_text_len >= 0);
43 DCHECK(skip_or_misspelling_start && skip_or_misspelling_len)
44 << "Out vars must be given.";
46 // Do nothing if we need to delay initialization. (Rather than blocking,
47 // report the word as correctly spelled.)
48 if (InitializeIfNeeded())
49 return IS_CORRECT;
51 // Do nothing if spell checking is disabled.
52 if (!platform_spelling_engine_.get() ||
53 !platform_spelling_engine_->IsEnabled())
54 return IS_CORRECT;
56 *skip_or_misspelling_start = 0;
57 *skip_or_misspelling_len = 0;
58 if (remaining_text_len == 0)
59 return IS_CORRECT; // No input means always spelled correctly.
61 base::string16 word;
62 int word_start;
63 int word_length;
64 if (!text_iterator_.IsInitialized() &&
65 !text_iterator_.Initialize(&character_attributes_, true)) {
66 // We failed to initialize text_iterator_, return as spelled correctly.
67 VLOG(1) << "Failed to initialize SpellcheckWordIterator";
68 return IS_CORRECT;
71 text_iterator_.SetText(text_begin + position_in_text, remaining_text_len);
72 DCHECK(platform_spelling_engine_.get());
73 for (SpellcheckWordIterator::WordIteratorStatus status =
74 text_iterator_.GetNextWord(&word, &word_start, &word_length);
75 status != SpellcheckWordIterator::IS_END_OF_TEXT;
76 status = text_iterator_.GetNextWord(&word, &word_start, &word_length)) {
77 // Found a character that is not able to be spellchecked so determine how
78 // long the sequence of uncheckable characters is and then return.
79 if (status == SpellcheckWordIterator::IS_SKIPPABLE) {
80 *skip_or_misspelling_start = position_in_text + word_start;
81 while (status == SpellcheckWordIterator::IS_SKIPPABLE) {
82 *skip_or_misspelling_len += word_length;
83 status = text_iterator_.GetNextWord(&word, &word_start, &word_length);
85 return IS_SKIPPABLE;
88 // Found a word (or a contraction) that the spellchecker can check the
89 // spelling of.
90 if (platform_spelling_engine_->CheckSpelling(word, tag))
91 continue;
93 // If the given word is a concatenated word of two or more valid words
94 // (e.g. "hello:hello"), we should treat it as a valid word.
95 if (IsValidContraction(word, tag))
96 continue;
98 *skip_or_misspelling_start = position_in_text + word_start;
99 *skip_or_misspelling_len = word_length;
101 // Get the list of suggested words.
102 if (optional_suggestions) {
103 platform_spelling_engine_->FillSuggestionList(word,
104 optional_suggestions);
106 return IS_MISSPELLED;
109 return IS_CORRECT;
112 // Returns whether or not the given string is a valid contraction.
113 // This function is a fall-back when the SpellcheckWordIterator class
114 // returns a concatenated word which is not in the selected dictionary
115 // (e.g. "in'n'out") but each word is valid.
116 bool SpellcheckLanguage::IsValidContraction(const base::string16& contraction,
117 int tag) {
118 if (!contraction_iterator_.IsInitialized() &&
119 !contraction_iterator_.Initialize(&character_attributes_, false)) {
120 // We failed to initialize the word iterator, return as spelled correctly.
121 VLOG(1) << "Failed to initialize contraction_iterator_";
122 return true;
125 contraction_iterator_.SetText(contraction.c_str(), contraction.length());
127 base::string16 word;
128 int word_start;
129 int word_length;
131 DCHECK(platform_spelling_engine_.get());
132 for (SpellcheckWordIterator::WordIteratorStatus status =
133 contraction_iterator_.GetNextWord(&word, &word_start, &word_length);
134 status != SpellcheckWordIterator::IS_END_OF_TEXT;
135 status = contraction_iterator_.GetNextWord(&word, &word_start,
136 &word_length)) {
137 if (status == SpellcheckWordIterator::IS_SKIPPABLE)
138 continue;
140 if (!platform_spelling_engine_->CheckSpelling(word, tag))
141 return false;
143 return true;
146 bool SpellcheckLanguage::IsEnabled() {
147 DCHECK(platform_spelling_engine_.get());
148 return platform_spelling_engine_->IsEnabled();