| 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 "chrome/browser/spellchecker/spellcheck_custom_dictionary.h" | 5 #include "chrome/browser/spellchecker/spellcheck_custom_dictionary.h" |
| 6 | 6 |
| 7 #include <functional> | 7 #include <functional> |
| 8 | 8 |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/files/important_file_writer.h" | 10 #include "base/files/important_file_writer.h" |
| 11 #include "base/md5.h" | 11 #include "base/md5.h" |
| 12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/strings/string_split.h" | 13 #include "base/strings/string_split.h" |
| 14 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h" | 14 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h" |
| 15 #include "chrome/common/chrome_constants.h" | 15 #include "chrome/common/chrome_constants.h" |
| 16 #include "chrome/common/spellcheck_messages.h" | 16 #include "chrome/common/spellcheck_messages.h" |
| 17 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
| 18 #include "sync/api/sync_change.h" | 18 #include "sync/api/sync_change.h" |
| 19 #include "sync/api/sync_data.h" | 19 #include "sync/api/sync_data.h" |
| 20 #include "sync/api/sync_error_factory.h" | 20 #include "sync/api/sync_error_factory.h" |
| 21 #include "sync/protocol/sync.pb.h" | 21 #include "sync/protocol/sync.pb.h" |
| 22 | 22 |
| 23 using content::BrowserThread; | 23 using content::BrowserThread; |
| 24 using chrome::spellcheck_common::WordList; | 24 using chrome::spellcheck_common::WordList; |
| 25 using chrome::spellcheck_common::WordSet; |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 | 28 |
| 28 // Filename extension for backup dictionary file. | 29 // Filename extension for backup dictionary file. |
| 29 const base::FilePath::CharType BACKUP_EXTENSION[] = FILE_PATH_LITERAL("backup"); | 30 const base::FilePath::CharType BACKUP_EXTENSION[] = FILE_PATH_LITERAL("backup"); |
| 30 | 31 |
| 31 // Prefix for the checksum in the dictionary file. | 32 // Prefix for the checksum in the dictionary file. |
| 32 const char CHECKSUM_PREFIX[] = "checksum_v1 = "; | 33 const char CHECKSUM_PREFIX[] = "checksum_v1 = "; |
| 33 | 34 |
| 34 // The status of the checksum in a custom spellcheck dictionary. | 35 // The status of the checksum in a custom spellcheck dictionary. |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 } | 119 } |
| 119 std::string checksum = base::MD5String(content.str()); | 120 std::string checksum = base::MD5String(content.str()); |
| 120 content << CHECKSUM_PREFIX << checksum; | 121 content << CHECKSUM_PREFIX << checksum; |
| 121 file_util::CopyFile(path, path.AddExtension(BACKUP_EXTENSION)); | 122 file_util::CopyFile(path, path.AddExtension(BACKUP_EXTENSION)); |
| 122 base::ImportantFileWriter::WriteFileAtomically(path, content.str()); | 123 base::ImportantFileWriter::WriteFileAtomically(path, content.str()); |
| 123 } | 124 } |
| 124 | 125 |
| 125 // Removes duplicate and invalid words from |to_add| word list and sorts it. | 126 // Removes duplicate and invalid words from |to_add| word list and sorts it. |
| 126 // Looks for duplicates in both |to_add| and |existing| word lists. Returns a | 127 // Looks for duplicates in both |to_add| and |existing| word lists. Returns a |
| 127 // bitmap of |ChangeSanitationResult| values. | 128 // bitmap of |ChangeSanitationResult| values. |
| 128 int SanitizeWordsToAdd(const WordList& existing, WordList& to_add) { | 129 int SanitizeWordsToAdd(const WordSet& existing, WordList& to_add) { |
| 129 // Do not add duplicate words. | 130 // Do not add duplicate words. |
| 130 std::sort(to_add.begin(), to_add.end()); | 131 std::sort(to_add.begin(), to_add.end()); |
| 131 WordList new_words; | 132 WordList new_words; |
| 132 std::set_difference(to_add.begin(), | 133 std::set_difference(to_add.begin(), |
| 133 to_add.end(), | 134 to_add.end(), |
| 134 existing.begin(), | 135 existing.begin(), |
| 135 existing.end(), | 136 existing.end(), |
| 136 std::back_inserter(new_words)); | 137 std::back_inserter(new_words)); |
| 137 new_words.erase(std::unique(new_words.begin(), new_words.end()), | 138 new_words.erase(std::unique(new_words.begin(), new_words.end()), |
| 138 new_words.end()); | 139 new_words.end()); |
| 139 int result = VALID_CHANGE; | 140 int result = VALID_CHANGE; |
| 140 if (to_add.size() != new_words.size()) | 141 if (to_add.size() != new_words.size()) |
| 141 result |= DETECTED_DUPLICATE_WORDS; | 142 result |= DETECTED_DUPLICATE_WORDS; |
| 142 // Do not add invalid words. | 143 // Do not add invalid words. |
| 143 size_t size = new_words.size(); | 144 size_t size = new_words.size(); |
| 144 new_words.erase(std::remove_if(new_words.begin(), | 145 new_words.erase(std::remove_if(new_words.begin(), |
| 145 new_words.end(), | 146 new_words.end(), |
| 146 IsInvalidWord), | 147 IsInvalidWord), |
| 147 new_words.end()); | 148 new_words.end()); |
| 148 if (size != new_words.size()) | 149 if (size != new_words.size()) |
| 149 result |= DETECTED_INVALID_WORDS; | 150 result |= DETECTED_INVALID_WORDS; |
| 150 // Save the sanitized words to be added. | 151 // Save the sanitized words to be added. |
| 151 std::swap(to_add, new_words); | 152 std::swap(to_add, new_words); |
| 152 return result; | 153 return result; |
| 153 } | 154 } |
| 154 | 155 |
| 155 // Removes word from |to_remove| that are missing from |existing| word list and | 156 // Removes word from |to_remove| that are missing from |existing| word list and |
| 156 // sorts |to_remove|. Returns a bitmap of |ChangeSanitationResult| values. | 157 // sorts |to_remove|. Returns a bitmap of |ChangeSanitationResult| values. |
| 157 int SanitizeWordsToRemove(const WordList& existing, WordList& to_remove) { | 158 int SanitizeWordsToRemove(const WordSet& existing, WordList& to_remove) { |
| 158 // Do not remove words that are missing from the dictionary. | 159 // Do not remove words that are missing from the dictionary. |
| 159 std::sort(to_remove.begin(), to_remove.end()); | 160 std::sort(to_remove.begin(), to_remove.end()); |
| 160 WordList found_words; | 161 WordList found_words; |
| 161 std::set_intersection(existing.begin(), | 162 std::set_intersection(existing.begin(), |
| 162 existing.end(), | 163 existing.end(), |
| 163 to_remove.begin(), | 164 to_remove.begin(), |
| 164 to_remove.end(), | 165 to_remove.end(), |
| 165 std::back_inserter(found_words)); | 166 std::back_inserter(found_words)); |
| 166 int result = VALID_CHANGE; | 167 int result = VALID_CHANGE; |
| 167 if (to_remove.size() > found_words.size()) | 168 if (to_remove.size() > found_words.size()) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 191 } | 192 } |
| 192 | 193 |
| 193 void SpellcheckCustomDictionary::Change::AddWord(const std::string& word) { | 194 void SpellcheckCustomDictionary::Change::AddWord(const std::string& word) { |
| 194 to_add_.push_back(word); | 195 to_add_.push_back(word); |
| 195 } | 196 } |
| 196 | 197 |
| 197 void SpellcheckCustomDictionary::Change::RemoveWord(const std::string& word) { | 198 void SpellcheckCustomDictionary::Change::RemoveWord(const std::string& word) { |
| 198 to_remove_.push_back(word); | 199 to_remove_.push_back(word); |
| 199 } | 200 } |
| 200 | 201 |
| 201 int SpellcheckCustomDictionary::Change::Sanitize(const WordList& words) { | 202 int SpellcheckCustomDictionary::Change::Sanitize(const WordSet& words) { |
| 202 int result = VALID_CHANGE; | 203 int result = VALID_CHANGE; |
| 203 if (!to_add_.empty()) | 204 if (!to_add_.empty()) |
| 204 result |= SanitizeWordsToAdd(words, to_add_); | 205 result |= SanitizeWordsToAdd(words, to_add_); |
| 205 if (!to_remove_.empty()) | 206 if (!to_remove_.empty()) |
| 206 result |= SanitizeWordsToRemove(words, to_remove_); | 207 result |= SanitizeWordsToRemove(words, to_remove_); |
| 207 return result; | 208 return result; |
| 208 } | 209 } |
| 209 | 210 |
| 210 const WordList& SpellcheckCustomDictionary::Change::to_add() const { | 211 const WordList& SpellcheckCustomDictionary::Change::to_add() const { |
| 211 return to_add_; | 212 return to_add_; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 224 : custom_dictionary_path_(), | 225 : custom_dictionary_path_(), |
| 225 weak_ptr_factory_(this), | 226 weak_ptr_factory_(this), |
| 226 is_loaded_(false) { | 227 is_loaded_(false) { |
| 227 custom_dictionary_path_ = | 228 custom_dictionary_path_ = |
| 228 path.Append(chrome::kCustomDictionaryFileName); | 229 path.Append(chrome::kCustomDictionaryFileName); |
| 229 } | 230 } |
| 230 | 231 |
| 231 SpellcheckCustomDictionary::~SpellcheckCustomDictionary() { | 232 SpellcheckCustomDictionary::~SpellcheckCustomDictionary() { |
| 232 } | 233 } |
| 233 | 234 |
| 234 const WordList& SpellcheckCustomDictionary::GetWords() const { | 235 const WordSet& SpellcheckCustomDictionary::GetWords() const { |
| 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 236 return words_; | 237 return words_; |
| 237 } | 238 } |
| 238 | 239 |
| 239 bool SpellcheckCustomDictionary::AddWord(const std::string& word) { | 240 bool SpellcheckCustomDictionary::AddWord(const std::string& word) { |
| 240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 241 std::sort(words_.begin(), words_.end()); | |
| 242 Change dictionary_change; | 242 Change dictionary_change; |
| 243 dictionary_change.AddWord(word); | 243 dictionary_change.AddWord(word); |
| 244 int result = dictionary_change.Sanitize(GetWords()); | 244 int result = dictionary_change.Sanitize(GetWords()); |
| 245 Apply(dictionary_change); | 245 Apply(dictionary_change); |
| 246 Notify(dictionary_change); | 246 Notify(dictionary_change); |
| 247 Sync(dictionary_change); | 247 Sync(dictionary_change); |
| 248 Save(dictionary_change); | 248 Save(dictionary_change); |
| 249 return result == VALID_CHANGE; | 249 return result == VALID_CHANGE; |
| 250 } | 250 } |
| 251 | 251 |
| 252 bool SpellcheckCustomDictionary::RemoveWord(const std::string& word) { | 252 bool SpellcheckCustomDictionary::RemoveWord(const std::string& word) { |
| 253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 254 std::sort(words_.begin(), words_.end()); | |
| 255 Change dictionary_change; | 254 Change dictionary_change; |
| 256 dictionary_change.RemoveWord(word); | 255 dictionary_change.RemoveWord(word); |
| 257 int result = dictionary_change.Sanitize(GetWords()); | 256 int result = dictionary_change.Sanitize(GetWords()); |
| 258 Apply(dictionary_change); | 257 Apply(dictionary_change); |
| 259 Notify(dictionary_change); | 258 Notify(dictionary_change); |
| 260 Sync(dictionary_change); | 259 Sync(dictionary_change); |
| 261 Save(dictionary_change); | 260 Save(dictionary_change); |
| 262 return result == VALID_CHANGE; | 261 return result == VALID_CHANGE; |
| 263 } | 262 } |
| 264 | 263 |
| 264 bool SpellcheckCustomDictionary::HasWord(const std::string& word) { |
| 265 return !!words_.count(word); |
| 266 } |
| 267 |
| 265 void SpellcheckCustomDictionary::AddObserver(Observer* observer) { | 268 void SpellcheckCustomDictionary::AddObserver(Observer* observer) { |
| 266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 267 observers_.AddObserver(observer); | 270 observers_.AddObserver(observer); |
| 268 } | 271 } |
| 269 | 272 |
| 270 void SpellcheckCustomDictionary::RemoveObserver(Observer* observer) { | 273 void SpellcheckCustomDictionary::RemoveObserver(Observer* observer) { |
| 271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 272 observers_.RemoveObserver(observer); | 275 observers_.RemoveObserver(observer); |
| 273 } | 276 } |
| 274 | 277 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 // Build a list of words to add locally. | 313 // Build a list of words to add locally. |
| 311 WordList to_add_locally; | 314 WordList to_add_locally; |
| 312 for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin(); | 315 for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin(); |
| 313 it != initial_sync_data.end(); | 316 it != initial_sync_data.end(); |
| 314 ++it) { | 317 ++it) { |
| 315 DCHECK_EQ(syncer::DICTIONARY, it->GetDataType()); | 318 DCHECK_EQ(syncer::DICTIONARY, it->GetDataType()); |
| 316 to_add_locally.push_back(it->GetSpecifics().dictionary().word()); | 319 to_add_locally.push_back(it->GetSpecifics().dictionary().word()); |
| 317 } | 320 } |
| 318 | 321 |
| 319 // Add remote words locally. | 322 // Add remote words locally. |
| 320 std::sort(words_.begin(), words_.end()); | |
| 321 Change to_change_locally(to_add_locally); | 323 Change to_change_locally(to_add_locally); |
| 322 to_change_locally.Sanitize(GetWords()); | 324 to_change_locally.Sanitize(GetWords()); |
| 323 Apply(to_change_locally); | 325 Apply(to_change_locally); |
| 324 Notify(to_change_locally); | 326 Notify(to_change_locally); |
| 325 Save(to_change_locally); | 327 Save(to_change_locally); |
| 326 | 328 |
| 327 // Add as many as possible local words remotely. | 329 // Add as many as possible local words remotely. |
| 328 std::sort(words_.begin(), words_.end()); | |
| 329 std::sort(to_add_locally.begin(), to_add_locally.end()); | 330 std::sort(to_add_locally.begin(), to_add_locally.end()); |
| 330 WordList to_add_remotely; | 331 WordList to_add_remotely; |
| 331 std::set_difference(words_.begin(), | 332 std::set_difference(words_.begin(), |
| 332 words_.end(), | 333 words_.end(), |
| 333 to_add_locally.begin(), | 334 to_add_locally.begin(), |
| 334 to_add_locally.end(), | 335 to_add_locally.end(), |
| 335 std::back_inserter(to_add_remotely)); | 336 std::back_inserter(to_add_remotely)); |
| 336 | 337 |
| 337 // Send local changes to the sync server. | 338 // Send local changes to the sync server. |
| 338 Change to_change_remotely(to_add_remotely); | 339 Change to_change_remotely(to_add_remotely); |
| 339 syncer::SyncMergeResult result(type); | 340 syncer::SyncMergeResult result(type); |
| 340 result.set_error(Sync(to_change_remotely)); | 341 result.set_error(Sync(to_change_remotely)); |
| 341 return result; | 342 return result; |
| 342 } | 343 } |
| 343 | 344 |
| 344 void SpellcheckCustomDictionary::StopSyncing(syncer::ModelType type) { | 345 void SpellcheckCustomDictionary::StopSyncing(syncer::ModelType type) { |
| 345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 346 DCHECK_EQ(syncer::DICTIONARY, type); | 347 DCHECK_EQ(syncer::DICTIONARY, type); |
| 347 sync_processor_.reset(); | 348 sync_processor_.reset(); |
| 348 sync_error_handler_.reset(); | 349 sync_error_handler_.reset(); |
| 349 } | 350 } |
| 350 | 351 |
| 351 syncer::SyncDataList SpellcheckCustomDictionary::GetAllSyncData( | 352 syncer::SyncDataList SpellcheckCustomDictionary::GetAllSyncData( |
| 352 syncer::ModelType type) const { | 353 syncer::ModelType type) const { |
| 353 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 354 DCHECK_EQ(syncer::DICTIONARY, type); | 355 DCHECK_EQ(syncer::DICTIONARY, type); |
| 355 syncer::SyncDataList data; | 356 syncer::SyncDataList data; |
| 356 std::string word; | 357 std::string word; |
| 357 size_t i = 0; | 358 size_t i = 0; |
| 358 for (WordList::const_iterator it = words_.begin(); | 359 for (WordSet::const_iterator it = words_.begin(); |
| 359 it != words_.end() && | 360 it != words_.end() && |
| 360 i < chrome::spellcheck_common::MAX_SYNCABLE_DICTIONARY_WORDS; | 361 i < chrome::spellcheck_common::MAX_SYNCABLE_DICTIONARY_WORDS; |
| 361 ++it, ++i) { | 362 ++it, ++i) { |
| 362 word = *it; | 363 word = *it; |
| 363 sync_pb::EntitySpecifics specifics; | 364 sync_pb::EntitySpecifics specifics; |
| 364 specifics.mutable_dictionary()->set_word(word); | 365 specifics.mutable_dictionary()->set_word(word); |
| 365 data.push_back(syncer::SyncData::CreateLocalData(word, word, specifics)); | 366 data.push_back(syncer::SyncData::CreateLocalData(word, word, specifics)); |
| 366 } | 367 } |
| 367 return data; | 368 return data; |
| 368 } | 369 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 385 dictionary_change.RemoveWord(word); | 386 dictionary_change.RemoveWord(word); |
| 386 break; | 387 break; |
| 387 default: | 388 default: |
| 388 return sync_error_handler_->CreateAndUploadError( | 389 return sync_error_handler_->CreateAndUploadError( |
| 389 FROM_HERE, | 390 FROM_HERE, |
| 390 "Processing sync changes failed on change type " + | 391 "Processing sync changes failed on change type " + |
| 391 syncer::SyncChange::ChangeTypeToString(it->change_type())); | 392 syncer::SyncChange::ChangeTypeToString(it->change_type())); |
| 392 } | 393 } |
| 393 } | 394 } |
| 394 | 395 |
| 395 std::sort(words_.begin(), words_.end()); | |
| 396 dictionary_change.Sanitize(GetWords()); | 396 dictionary_change.Sanitize(GetWords()); |
| 397 Apply(dictionary_change); | 397 Apply(dictionary_change); |
| 398 Notify(dictionary_change); | 398 Notify(dictionary_change); |
| 399 Save(dictionary_change); | 399 Save(dictionary_change); |
| 400 | 400 |
| 401 return syncer::SyncError(); | 401 return syncer::SyncError(); |
| 402 } | 402 } |
| 403 | 403 |
| 404 // static | 404 // static |
| 405 WordList SpellcheckCustomDictionary::LoadDictionaryFile( | 405 WordList SpellcheckCustomDictionary::LoadDictionaryFile( |
| 406 const base::FilePath& path) { | 406 const base::FilePath& path) { |
| 407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 408 WordList words; | 408 WordList words; |
| 409 LoadDictionaryFileReliably(words, path); | 409 LoadDictionaryFileReliably(words, path); |
| 410 if (!words.empty() && VALID_CHANGE != SanitizeWordsToAdd(WordList(), words)) | 410 if (!words.empty() && VALID_CHANGE != SanitizeWordsToAdd(WordSet(), words)) |
| 411 SaveDictionaryFileReliably(words, path); | 411 SaveDictionaryFileReliably(words, path); |
| 412 SpellCheckHostMetrics::RecordCustomWordCountStats(words.size()); | 412 SpellCheckHostMetrics::RecordCustomWordCountStats(words.size()); |
| 413 return words; | 413 return words; |
| 414 } | 414 } |
| 415 | 415 |
| 416 // static | 416 // static |
| 417 void SpellcheckCustomDictionary::UpdateDictionaryFile( | 417 void SpellcheckCustomDictionary::UpdateDictionaryFile( |
| 418 const SpellcheckCustomDictionary::Change& dictionary_change, | 418 const SpellcheckCustomDictionary::Change& dictionary_change, |
| 419 const base::FilePath& path) { | 419 const base::FilePath& path) { |
| 420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 437 dictionary_change.to_remove().begin(), | 437 dictionary_change.to_remove().begin(), |
| 438 dictionary_change.to_remove().end(), | 438 dictionary_change.to_remove().end(), |
| 439 std::back_inserter(remaining)); | 439 std::back_inserter(remaining)); |
| 440 std::swap(custom_words, remaining); | 440 std::swap(custom_words, remaining); |
| 441 | 441 |
| 442 SaveDictionaryFileReliably(custom_words, path); | 442 SaveDictionaryFileReliably(custom_words, path); |
| 443 } | 443 } |
| 444 | 444 |
| 445 void SpellcheckCustomDictionary::OnLoaded(WordList custom_words) { | 445 void SpellcheckCustomDictionary::OnLoaded(WordList custom_words) { |
| 446 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 446 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 447 std::sort(words_.begin(), words_.end()); | |
| 448 Change dictionary_change(custom_words); | 447 Change dictionary_change(custom_words); |
| 449 dictionary_change.Sanitize(GetWords()); | 448 dictionary_change.Sanitize(GetWords()); |
| 450 Apply(dictionary_change); | 449 Apply(dictionary_change); |
| 451 Sync(dictionary_change); | 450 Sync(dictionary_change); |
| 452 is_loaded_ = true; | 451 is_loaded_ = true; |
| 453 FOR_EACH_OBSERVER(Observer, observers_, OnCustomDictionaryLoaded()); | 452 FOR_EACH_OBSERVER(Observer, observers_, OnCustomDictionaryLoaded()); |
| 454 } | 453 } |
| 455 | 454 |
| 456 void SpellcheckCustomDictionary::Apply( | 455 void SpellcheckCustomDictionary::Apply( |
| 457 const SpellcheckCustomDictionary::Change& dictionary_change) { | 456 const SpellcheckCustomDictionary::Change& dictionary_change) { |
| 458 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 457 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 459 if (!dictionary_change.to_add().empty()) { | 458 if (!dictionary_change.to_add().empty()) { |
| 460 words_.insert(words_.end(), | 459 words_.insert(dictionary_change.to_add().begin(), |
| 461 dictionary_change.to_add().begin(), | |
| 462 dictionary_change.to_add().end()); | 460 dictionary_change.to_add().end()); |
| 463 } | 461 } |
| 464 if (!dictionary_change.to_remove().empty()) { | 462 if (!dictionary_change.to_remove().empty()) { |
| 465 std::sort(words_.begin(), words_.end()); | 463 WordSet updated_words; |
| 466 WordList updated_words; | |
| 467 std::set_difference(words_.begin(), | 464 std::set_difference(words_.begin(), |
| 468 words_.end(), | 465 words_.end(), |
| 469 dictionary_change.to_remove().begin(), | 466 dictionary_change.to_remove().begin(), |
| 470 dictionary_change.to_remove().end(), | 467 dictionary_change.to_remove().end(), |
| 471 std::back_inserter(updated_words)); | 468 std::inserter(updated_words, updated_words.end())); |
| 472 std::swap(words_, updated_words); | 469 std::swap(words_, updated_words); |
| 473 } | 470 } |
| 474 } | 471 } |
| 475 | 472 |
| 476 void SpellcheckCustomDictionary::Save( | 473 void SpellcheckCustomDictionary::Save( |
| 477 const SpellcheckCustomDictionary::Change& dictionary_change) { | 474 const SpellcheckCustomDictionary::Change& dictionary_change) { |
| 478 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 475 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 479 BrowserThread::PostTask( | 476 BrowserThread::PostTask( |
| 480 BrowserThread::FILE, | 477 BrowserThread::FILE, |
| 481 FROM_HERE, | 478 FROM_HERE, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 | 542 |
| 546 void SpellcheckCustomDictionary::Notify( | 543 void SpellcheckCustomDictionary::Notify( |
| 547 const SpellcheckCustomDictionary::Change& dictionary_change) { | 544 const SpellcheckCustomDictionary::Change& dictionary_change) { |
| 548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 545 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 549 if (!IsLoaded() || dictionary_change.empty()) | 546 if (!IsLoaded() || dictionary_change.empty()) |
| 550 return; | 547 return; |
| 551 FOR_EACH_OBSERVER(Observer, | 548 FOR_EACH_OBSERVER(Observer, |
| 552 observers_, | 549 observers_, |
| 553 OnCustomDictionaryChanged(dictionary_change)); | 550 OnCustomDictionaryChanged(dictionary_change)); |
| 554 } | 551 } |
| OLD | NEW |