| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "hunspell_engine.h" | 5 #include "hunspell_engine.h" |
| 6 | 6 |
| 7 #include <algorithm> |
| 8 #include <iterator> |
| 9 |
| 7 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| 8 #include "base/time.h" | 11 #include "base/time.h" |
| 9 #include "chrome/common/spellcheck_common.h" | 12 #include "chrome/common/spellcheck_common.h" |
| 10 #include "chrome/common/spellcheck_messages.h" | 13 #include "chrome/common/spellcheck_messages.h" |
| 11 #include "content/public/renderer/render_thread.h" | 14 #include "content/public/renderer/render_thread.h" |
| 12 #include "third_party/hunspell/src/hunspell/hunspell.hxx" | 15 #include "third_party/hunspell/src/hunspell/hunspell.hxx" |
| 13 | 16 |
| 14 using base::TimeTicks; | 17 using base::TimeTicks; |
| 15 using content::RenderThread; | 18 using content::RenderThread; |
| 16 | 19 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 | 65 |
| 63 bdict_file_.reset(new file_util::MemoryMappedFile); | 66 bdict_file_.reset(new file_util::MemoryMappedFile); |
| 64 | 67 |
| 65 if (bdict_file_->Initialize(file_)) { | 68 if (bdict_file_->Initialize(file_)) { |
| 66 TimeTicks debug_start_time = base::Histogram::DebugNow(); | 69 TimeTicks debug_start_time = base::Histogram::DebugNow(); |
| 67 | 70 |
| 68 hunspell_.reset( | 71 hunspell_.reset( |
| 69 new Hunspell(bdict_file_->data(), bdict_file_->length())); | 72 new Hunspell(bdict_file_->data(), bdict_file_->length())); |
| 70 | 73 |
| 71 // Add custom words to Hunspell. | 74 // Add custom words to Hunspell. |
| 72 chrome::spellcheck_common::WordList::iterator it; | 75 AddWordsToHunspell(custom_words_); |
| 73 for (it = custom_words_.begin(); it != custom_words_.end(); ++it) | |
| 74 AddWordToHunspell(*it); | |
| 75 | 76 |
| 76 DHISTOGRAM_TIMES("Spellcheck.InitTime", | 77 DHISTOGRAM_TIMES("Spellcheck.InitTime", |
| 77 base::Histogram::DebugNow() - debug_start_time); | 78 base::Histogram::DebugNow() - debug_start_time); |
| 78 } else { | 79 } else { |
| 79 NOTREACHED() << "Could not mmap spellchecker dictionary."; | 80 NOTREACHED() << "Could not mmap spellchecker dictionary."; |
| 80 } | 81 } |
| 81 } | 82 } |
| 82 | 83 |
| 83 void HunspellEngine::AddWordToHunspell(const std::string& word) { | 84 void HunspellEngine::AddWordsToHunspell(const std::vector<std::string>& words) { |
| 84 if (!word.empty() && word.length() < MAXWORDLEN) | 85 std::string word; |
| 85 hunspell_->add(word.c_str()); | 86 for (chrome::spellcheck_common::WordList::const_iterator it = words.begin(); |
| 87 it != words.end(); |
| 88 ++it) { |
| 89 word = *it; |
| 90 if (!word.empty() && |
| 91 word.length() <= |
| 92 chrome::spellcheck_common::MAX_CUSTOM_DICTIONARY_WORD_BYTES) { |
| 93 hunspell_->add(word.c_str()); |
| 94 } |
| 95 } |
| 86 } | 96 } |
| 87 | 97 |
| 88 void HunspellEngine::RemoveWordFromHunspell(const std::string& word) { | 98 void HunspellEngine::RemoveWordsFromHunspell( |
| 89 if (!word.empty() && word.length() < MAXWORDLEN) | 99 const std::vector<std::string>& words) { |
| 90 hunspell_->remove(word.c_str()); | 100 std::string word; |
| 101 for (std::vector<std::string>::const_iterator it = words.begin(); |
| 102 it != words.end(); |
| 103 ++it) { |
| 104 word = *it; |
| 105 if (!word.empty() && |
| 106 word.length() <= |
| 107 chrome::spellcheck_common::MAX_CUSTOM_DICTIONARY_WORD_BYTES) { |
| 108 hunspell_->remove(word.c_str()); |
| 109 } |
| 110 } |
| 91 } | 111 } |
| 92 | 112 |
| 93 bool HunspellEngine::CheckSpelling(const string16& word_to_check, int tag) { | 113 bool HunspellEngine::CheckSpelling(const string16& word_to_check, int tag) { |
| 94 bool word_correct = false; | 114 bool word_correct = false; |
| 95 std::string word_to_check_utf8(UTF16ToUTF8(word_to_check)); | 115 std::string word_to_check_utf8(UTF16ToUTF8(word_to_check)); |
| 96 // Hunspell shouldn't let us exceed its max, but check just in case | 116 // Hunspell shouldn't let us exceed its max, but check just in case |
| 97 if (word_to_check_utf8.length() < kMaxCheckedLen) { | 117 if (word_to_check_utf8.length() < kMaxCheckedLen) { |
| 98 if (hunspell_.get()) { | 118 if (hunspell_.get()) { |
| 99 // |hunspell_->spell| returns 0 if the word is spelled correctly and | 119 // |hunspell_->spell| returns 0 if the word is spelled correctly and |
| 100 // non-zero otherwsie. | 120 // non-zero otherwise. |
| 101 word_correct = (hunspell_->spell(word_to_check_utf8.c_str()) != 0); | 121 word_correct = (hunspell_->spell(word_to_check_utf8.c_str()) != 0); |
| 102 } else { | 122 } else { |
| 103 // If |hunspell_| is NULL here, an error has occurred, but it's better | 123 // If |hunspell_| is NULL here, an error has occurred, but it's better |
| 104 // to check rather than crash. | 124 // to check rather than crash. |
| 105 word_correct = true; | 125 word_correct = true; |
| 106 } | 126 } |
| 107 } | 127 } |
| 108 | 128 |
| 109 return word_correct; | 129 return word_correct; |
| 110 } | 130 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 129 // Populate the vector of WideStrings. | 149 // Populate the vector of WideStrings. |
| 130 for (int i = 0; i < number_of_suggestions; ++i) { | 150 for (int i = 0; i < number_of_suggestions; ++i) { |
| 131 if (i < chrome::spellcheck_common::kMaxSuggestions) | 151 if (i < chrome::spellcheck_common::kMaxSuggestions) |
| 132 optional_suggestions->push_back(UTF8ToUTF16(suggestions[i])); | 152 optional_suggestions->push_back(UTF8ToUTF16(suggestions[i])); |
| 133 free(suggestions[i]); | 153 free(suggestions[i]); |
| 134 } | 154 } |
| 135 if (suggestions != NULL) | 155 if (suggestions != NULL) |
| 136 free(suggestions); | 156 free(suggestions); |
| 137 } | 157 } |
| 138 | 158 |
| 139 void HunspellEngine::OnWordAdded(const std::string& word) { | 159 void HunspellEngine::OnCustomDictionaryChanged( |
| 160 const std::vector<std::string>& words_added, |
| 161 const std::vector<std::string>& words_removed) { |
| 140 if (!hunspell_.get()) { | 162 if (!hunspell_.get()) { |
| 141 // Save it for later---add it when hunspell is initialized. | 163 // Save it for later---add it when hunspell is initialized. |
| 142 custom_words_.push_back(word); | 164 custom_words_.insert(custom_words_.end(), |
| 165 words_added.begin(), |
| 166 words_added.end()); |
| 167 // Remove words. |
| 168 std::vector<std::string> words_removed_copy(words_removed); |
| 169 std::sort(words_removed_copy.begin(), words_removed_copy.end()); |
| 170 std::sort(custom_words_.begin(), custom_words_.end()); |
| 171 std::vector<std::string> updated_custom_words; |
| 172 std::set_difference(custom_words_.begin(), |
| 173 custom_words_.end(), |
| 174 words_removed_copy.begin(), |
| 175 words_removed_copy.end(), |
| 176 std::back_inserter(updated_custom_words)); |
| 177 std::swap(custom_words_, updated_custom_words); |
| 143 } else { | 178 } else { |
| 144 AddWordToHunspell(word); | 179 AddWordsToHunspell(words_added); |
| 180 RemoveWordsFromHunspell(words_removed); |
| 145 } | 181 } |
| 146 } | 182 } |
| 147 | 183 |
| 148 void HunspellEngine::OnWordRemoved(const std::string& word) { | |
| 149 if (!hunspell_.get()) { | |
| 150 chrome::spellcheck_common::WordList::iterator it = std::find( | |
| 151 custom_words_.begin(), custom_words_.end(), word); | |
| 152 if (it != custom_words_.end()) | |
| 153 custom_words_.erase(it); | |
| 154 } else { | |
| 155 RemoveWordFromHunspell(word); | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 bool HunspellEngine::InitializeIfNeeded() { | 184 bool HunspellEngine::InitializeIfNeeded() { |
| 160 if (!initialized_ && !dictionary_requested_) { | 185 if (!initialized_ && !dictionary_requested_) { |
| 161 // RenderThread will not exist in test. | 186 // RenderThread will not exist in test. |
| 162 if (RenderThread::Get()) | 187 if (RenderThread::Get()) |
| 163 RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary); | 188 RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary); |
| 164 dictionary_requested_ = true; | 189 dictionary_requested_ = true; |
| 165 return true; | 190 return true; |
| 166 } | 191 } |
| 167 | 192 |
| 168 // Don't initialize if hunspell is disabled. | 193 // Don't initialize if hunspell is disabled. |
| 169 if (file_ != base::kInvalidPlatformFileValue) | 194 if (file_ != base::kInvalidPlatformFileValue) |
| 170 InitializeHunspell(); | 195 InitializeHunspell(); |
| 171 | 196 |
| 172 return !initialized_; | 197 return !initialized_; |
| 173 } | 198 } |
| 174 | 199 |
| 175 bool HunspellEngine::IsEnabled() { | 200 bool HunspellEngine::IsEnabled() { |
| 176 return file_ != base::kInvalidPlatformFileValue; | 201 return file_ != base::kInvalidPlatformFileValue; |
| 177 } | 202 } |
| OLD | NEW |