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 |