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. 4 5 #include "chrome/renderer/spellchecker/spellcheck_language.h" 6 7 #include "base/logging.h" 8 #include "chrome/renderer/spellchecker/spellcheck_worditerator.h" 9 #include "chrome/renderer/spellchecker/spelling_engine.h" 10 11 12 SpellcheckLanguage::SpellcheckLanguage() 13 : platform_spelling_engine_(CreateNativeSpellingEngine()) { 14 } 15 16 SpellcheckLanguage::~SpellcheckLanguage() { 17 } 18 19 void SpellcheckLanguage::Init(base::File file, const std::string& language) { 20 DCHECK(platform_spelling_engine_.get()); 21 platform_spelling_engine_->Init(file.Pass()); 22 23 character_attributes_.SetDefaultLanguage(language); 24 text_iterator_.Reset(); 25 contraction_iterator_.Reset(); 26 } 27 28 bool SpellcheckLanguage::InitializeIfNeeded() { 29 DCHECK(platform_spelling_engine_.get()); 30 return platform_spelling_engine_->InitializeIfNeeded(); 31 } 32 33 bool SpellcheckLanguage::SpellCheckWord( 34 const base::char16* in_word, 35 int in_word_len, 36 int tag, 37 int* misspelling_start, 38 int* misspelling_len, 39 std::vector<base::string16>* optional_suggestions) { 40 DCHECK(in_word_len >= 0); 41 DCHECK(misspelling_start && misspelling_len) << "Out vars must be given."; 42 43 // Do nothing if we need to delay initialization. (Rather than blocking, 44 // report the word as correctly spelled.) 45 if (InitializeIfNeeded()) 46 return true; 47 48 // Do nothing if spell checking is disabled. 49 if (!platform_spelling_engine_.get() || 50 !platform_spelling_engine_->IsEnabled()) 51 return true; 52 53 *misspelling_start = 0; 54 *misspelling_len = 0; 55 if (in_word_len == 0) 56 return true; // No input means always spelled correctly. 57 58 base::string16 word; 59 int word_start; 60 int word_length; 61 if (!text_iterator_.IsInitialized() && 62 !text_iterator_.Initialize(&character_attributes_, true)) { 63 // We failed to initialize text_iterator_, return as spelled correctly. 64 VLOG(1) << "Failed to initialize SpellcheckWordIterator"; 65 return true; 66 } 67 68 text_iterator_.SetText(in_word, in_word_len); 69 DCHECK(platform_spelling_engine_.get()); 70 while (text_iterator_.GetNextWord(&word, &word_start, &word_length)) { 71 // Found a word (or a contraction) that the spellchecker can check the 72 // spelling of. 73 if (platform_spelling_engine_->CheckSpelling(word, tag)) 74 continue; 75 76 // If the given word is a concatenated word of two or more valid words 77 // (e.g. "hello:hello"), we should treat it as a valid word. 78 if (IsValidContraction(word, tag)) 79 continue; 80 81 *misspelling_start = word_start; 82 *misspelling_len = word_length; 83 84 // Get the list of suggested words. 85 if (optional_suggestions) { 86 platform_spelling_engine_->FillSuggestionList(word, 87 optional_suggestions); 88 } 89 return false; 90 } 91 92 return true; 93 } 94 95 // Returns whether or not the given string is a valid contraction. 96 // This function is a fall-back when the SpellcheckWordIterator class 97 // returns a concatenated word which is not in the selected dictionary 98 // (e.g. "in'n'out") but each word is valid. 99 bool SpellcheckLanguage::IsValidContraction(const base::string16& contraction, 100 int tag) { 101 if (!contraction_iterator_.IsInitialized() && 102 !contraction_iterator_.Initialize(&character_attributes_, false)) { 103 // We failed to initialize the word iterator, return as spelled correctly. 104 VLOG(1) << "Failed to initialize contraction_iterator_"; 105 return true; 106 } 107 108 contraction_iterator_.SetText(contraction.c_str(), contraction.length()); 109 110 base::string16 word; 111 int word_start; 112 int word_length; 113 114 DCHECK(platform_spelling_engine_.get()); 115 while (contraction_iterator_.GetNextWord(&word, &word_start, &word_length)) { 116 if (!platform_spelling_engine_->CheckSpelling(word, tag)) 117 return false; 118 } 119 return true; 120 } 121 122 bool SpellcheckLanguage::IsEnabled() { 123 DCHECK(platform_spelling_engine_.get()); 124 return platform_spelling_engine_->IsEnabled(); 125 } 126