// 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::PlatformFile file,
const std::string& language) {
DCHECK(platform_spelling_engine_.get());
platform_spelling_engine_->Init(file);
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 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();
}