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
,
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())
51 // Do nothing if spell checking is disabled.
52 if (!platform_spelling_engine_
.get() ||
53 !platform_spelling_engine_
->IsEnabled())
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.
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";
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
);
88 // Found a word (or a contraction) that the spellchecker can check the
90 if (platform_spelling_engine_
->CheckSpelling(word
, tag
))
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
))
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
;
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
,
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_";
125 contraction_iterator_
.SetText(contraction
.c_str(), contraction
.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
,
137 if (status
== SpellcheckWordIterator::IS_SKIPPABLE
)
140 if (!platform_spelling_engine_
->CheckSpelling(word
, tag
))
146 bool SpellcheckLanguage::IsEnabled() {
147 DCHECK(platform_spelling_engine_
.get());
148 return platform_spelling_engine_
->IsEnabled();