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 |