| 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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 | 52 |
| 50 bdict_file_.reset(new file_util::MemoryMappedFile); | 53 bdict_file_.reset(new file_util::MemoryMappedFile); |
| 51 | 54 |
| 52 if (bdict_file_->Initialize(file_)) { | 55 if (bdict_file_->Initialize(file_)) { |
| 53 TimeTicks debug_start_time = base::Histogram::DebugNow(); | 56 TimeTicks debug_start_time = base::Histogram::DebugNow(); |
| 54 | 57 |
| 55 hunspell_.reset( | 58 hunspell_.reset( |
| 56 new Hunspell(bdict_file_->data(), bdict_file_->length())); | 59 new Hunspell(bdict_file_->data(), bdict_file_->length())); |
| 57 | 60 |
| 58 // Add custom words to Hunspell. | 61 // Add custom words to Hunspell. |
| 59 chrome::spellcheck_common::WordList::iterator it; | 62 AddWordsToHunspell(custom_words_); |
| 60 for (it = custom_words_.begin(); it != custom_words_.end(); ++it) | |
| 61 AddWordToHunspell(*it); | |
| 62 | 63 |
| 63 DHISTOGRAM_TIMES("Spellcheck.InitTime", | 64 DHISTOGRAM_TIMES("Spellcheck.InitTime", |
| 64 base::Histogram::DebugNow() - debug_start_time); | 65 base::Histogram::DebugNow() - debug_start_time); |
| 65 } else { | 66 } else { |
| 66 NOTREACHED() << "Could not mmap spellchecker dictionary."; | 67 NOTREACHED() << "Could not mmap spellchecker dictionary."; |
| 67 } | 68 } |
| 68 } | 69 } |
| 69 | 70 |
| 70 void HunspellEngine::AddWordToHunspell(const std::string& word) { | 71 void HunspellEngine::AddWordsToHunspell(const std::vector<std::string>& words) { |
| 71 if (!word.empty() && word.length() < MAXWORDLEN) | 72 std::string word; |
| 72 hunspell_->add(word.c_str()); | 73 for (chrome::spellcheck_common::WordList::const_iterator it = words.begin(); |
| 74 it != words.end(); |
| 75 ++it) { |
| 76 word = *it; |
| 77 if (!word.empty() && |
| 78 word.length() <= |
| 79 chrome::spellcheck_common::MAX_CUSTOM_DICTIONARY_WORD_BYTES) { |
| 80 hunspell_->add(word.c_str()); |
| 81 } |
| 82 } |
| 73 } | 83 } |
| 74 | 84 |
| 75 void HunspellEngine::RemoveWordFromHunspell(const std::string& word) { | 85 void HunspellEngine::RemoveWordsFromHunspell( |
| 76 if (!word.empty() && word.length() < MAXWORDLEN) | 86 const std::vector<std::string>& words) { |
| 77 hunspell_->remove(word.c_str()); | 87 std::string word; |
| 88 for (std::vector<std::string>::const_iterator it = words.begin(); |
| 89 it != words.end(); |
| 90 ++it) { |
| 91 word = *it; |
| 92 if (!word.empty() && |
| 93 word.length() <= |
| 94 chrome::spellcheck_common::MAX_CUSTOM_DICTIONARY_WORD_BYTES) { |
| 95 hunspell_->remove(word.c_str()); |
| 96 } |
| 97 } |
| 78 } | 98 } |
| 79 | 99 |
| 80 bool HunspellEngine::CheckSpelling(const string16& word_to_check, int tag) { | 100 bool HunspellEngine::CheckSpelling(const string16& word_to_check, int tag) { |
| 81 bool word_correct = false; | 101 bool word_correct = false; |
| 82 std::string word_to_check_utf8(UTF16ToUTF8(word_to_check)); | 102 std::string word_to_check_utf8(UTF16ToUTF8(word_to_check)); |
| 83 // Hunspell shouldn't let us exceed its max, but check just in case | 103 // Hunspell shouldn't let us exceed its max, but check just in case |
| 84 if (word_to_check_utf8.length() < MAXWORDLEN) { | 104 if (word_to_check_utf8.length() <= |
| 105 chrome::spellcheck_common::MAX_CUSTOM_DICTIONARY_WORD_BYTES) { |
| 85 if (hunspell_.get()) { | 106 if (hunspell_.get()) { |
| 86 // |hunspell_->spell| returns 0 if the word is spelled correctly and | 107 // |hunspell_->spell| returns 0 if the word is spelled correctly and |
| 87 // non-zero otherwsie. | 108 // non-zero otherwise. |
| 88 word_correct = (hunspell_->spell(word_to_check_utf8.c_str()) != 0); | 109 word_correct = (hunspell_->spell(word_to_check_utf8.c_str()) != 0); |
| 89 } else { | 110 } else { |
| 90 // If |hunspell_| is NULL here, an error has occurred, but it's better | 111 // If |hunspell_| is NULL here, an error has occurred, but it's better |
| 91 // to check rather than crash. | 112 // to check rather than crash. |
| 92 word_correct = true; | 113 word_correct = true; |
| 93 } | 114 } |
| 94 } | 115 } |
| 95 | 116 |
| 96 return word_correct; | 117 return word_correct; |
| 97 } | 118 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 112 // Populate the vector of WideStrings. | 133 // Populate the vector of WideStrings. |
| 113 for (int i = 0; i < number_of_suggestions; ++i) { | 134 for (int i = 0; i < number_of_suggestions; ++i) { |
| 114 if (i < chrome::spellcheck_common::kMaxSuggestions) | 135 if (i < chrome::spellcheck_common::kMaxSuggestions) |
| 115 optional_suggestions->push_back(UTF8ToUTF16(suggestions[i])); | 136 optional_suggestions->push_back(UTF8ToUTF16(suggestions[i])); |
| 116 free(suggestions[i]); | 137 free(suggestions[i]); |
| 117 } | 138 } |
| 118 if (suggestions != NULL) | 139 if (suggestions != NULL) |
| 119 free(suggestions); | 140 free(suggestions); |
| 120 } | 141 } |
| 121 | 142 |
| 122 void HunspellEngine::OnWordAdded(const std::string& word) { | 143 void HunspellEngine::OnCustomDictionaryChanged( |
| 144 const std::vector<std::string>& words_added, |
| 145 const std::vector<std::string>& words_removed) { |
| 123 if (!hunspell_.get()) { | 146 if (!hunspell_.get()) { |
| 124 // Save it for later---add it when hunspell is initialized. | 147 // Save it for later---add it when hunspell is initialized. |
| 125 custom_words_.push_back(word); | 148 custom_words_.insert(custom_words_.end(), |
| 149 words_added.begin(), |
| 150 words_added.end()); |
| 151 // Remove words. |
| 152 std::vector<std::string> words_removed_copy(words_removed); |
| 153 std::sort(words_removed_copy.begin(), words_removed_copy.end()); |
| 154 std::sort(custom_words_.begin(), custom_words_.end()); |
| 155 std::vector<std::string> updated_custom_words; |
| 156 std::set_difference(custom_words_.begin(), |
| 157 custom_words_.end(), |
| 158 words_removed_copy.begin(), |
| 159 words_removed_copy.end(), |
| 160 std::back_inserter(updated_custom_words)); |
| 161 std::swap(custom_words_, updated_custom_words); |
| 126 } else { | 162 } else { |
| 127 AddWordToHunspell(word); | 163 AddWordsToHunspell(words_added); |
| 164 RemoveWordsFromHunspell(words_removed); |
| 128 } | 165 } |
| 129 } | 166 } |
| 130 | 167 |
| 131 void HunspellEngine::OnWordRemoved(const std::string& word) { | |
| 132 if (!hunspell_.get()) { | |
| 133 chrome::spellcheck_common::WordList::iterator it = std::find( | |
| 134 custom_words_.begin(), custom_words_.end(), word); | |
| 135 if (it != custom_words_.end()) | |
| 136 custom_words_.erase(it); | |
| 137 } else { | |
| 138 RemoveWordFromHunspell(word); | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 bool HunspellEngine::InitializeIfNeeded() { | 168 bool HunspellEngine::InitializeIfNeeded() { |
| 143 if (!initialized_ && !dictionary_requested_) { | 169 if (!initialized_ && !dictionary_requested_) { |
| 144 // RenderThread will not exist in test. | 170 // RenderThread will not exist in test. |
| 145 if (RenderThread::Get()) | 171 if (RenderThread::Get()) |
| 146 RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary); | 172 RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary); |
| 147 dictionary_requested_ = true; | 173 dictionary_requested_ = true; |
| 148 return true; | 174 return true; |
| 149 } | 175 } |
| 150 | 176 |
| 151 // Don't initialize if hunspell is disabled. | 177 // Don't initialize if hunspell is disabled. |
| 152 if (file_ != base::kInvalidPlatformFileValue) | 178 if (file_ != base::kInvalidPlatformFileValue) |
| 153 InitializeHunspell(); | 179 InitializeHunspell(); |
| 154 | 180 |
| 155 return !initialized_; | 181 return !initialized_; |
| 156 } | 182 } |
| 157 | 183 |
| 158 bool HunspellEngine::IsEnabled() { | 184 bool HunspellEngine::IsEnabled() { |
| 159 return file_ != base::kInvalidPlatformFileValue; | 185 return file_ != base::kInvalidPlatformFileValue; |
| 160 } | 186 } |
| OLD | NEW |