// 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(); }