Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(495)

Side by Side Diff: chrome/browser/spellchecker/spellcheck_custom_dictionary.cc

Issue 15940004: Add HasWord(string) method to SpellcheckCustomDictionary (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Clarified message direction (browser-to-renderer) in spellcheck_messages.h Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698