1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SPELLCHECKER_SPELLCHECK_CUSTOM_DICTIONARY_H_
#define CHROME_BROWSER_SPELLCHECKER_SPELLCHECK_CUSTOM_DICTIONARY_H_
#include <memory>
#include <set>
#include <string>
#include "base/cancelable_callback.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/task/sequenced_task_runner.h"
#include "components/spellcheck/browser/spellcheck_dictionary.h"
#include "components/sync/model/model_error.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/model/syncable_service.h"
namespace base {
class Location;
}
namespace syncer {
class SyncChangeProcessor;
}
// Defines a custom dictionary where users can add their own words. All words
// must be UTF8, between 1 and 99 bytes long, and without leading or trailing
// ASCII whitespace. The dictionary contains its own checksum when saved on
// disk. Example dictionary file contents:
//
// bar
// foo
// checksum_v1 = ec3df4034567e59e119fcf87f2d9bad4
//
class SpellcheckCustomDictionary final : public SpellcheckDictionary,
public syncer::SyncableService {
public:
// A change to the dictionary.
class Change {
public:
Change();
Change(const Change&) = delete;
Change& operator=(const Change&) = delete;
~Change();
// Adds |word| in this change.
void AddWord(const std::string& word);
// Adds |words| in this change.
void AddWords(const std::set<std::string>& words);
// Removes |word| in this change.
void RemoveWord(const std::string& word);
// Clear the whole dictionary before doing other operations. When saved,
// also deletes the backup file.
void Clear();
// Prepares this change to be applied to |words| by removing duplicate and
// invalid words from words to be added and removing missing words from
// words to be removed. Returns a bitmap of |ChangeSanitationResult| values.
int Sanitize(const std::set<std::string>& words);
// Returns the words to be added in this change.
const std::set<std::string>& to_add() const { return to_add_; }
// Returns the words to be removed in this change.
const std::set<std::string>& to_remove() const {
return to_remove_;
}
// Returns true if the dictionary should be cleared first.
bool clear() const { return clear_; }
// Returns true if there are no changes to be made. Otherwise returns false.
bool empty() const {
return !clear_ && to_add_.empty() && to_remove_.empty();
}
private:
// The words to be added.
std::set<std::string> to_add_;
// The words to be removed.
std::set<std::string> to_remove_;
// Whether to clear everything before adding words.
bool clear_ = false;
};
// Interface to implement for dictionary load and change observers.
class Observer {
public:
// Called when the custom dictionary has been loaded.
virtual void OnCustomDictionaryLoaded() = 0;
// Called when the custom dictionary has been changed.
virtual void OnCustomDictionaryChanged(const Change& dictionary_change) = 0;
};
struct LoadFileResult {
LoadFileResult();
LoadFileResult(const LoadFileResult&) = delete;
LoadFileResult& operator=(const LoadFileResult&) = delete;
~LoadFileResult();
// The contents of the custom dictionary file or its backup. Does not
// contain data that failed checksum. Does not contain invalid words.
std::set<std::string> words;
// True when the custom dictionary file on disk has a valid checksum and
// contains only valid words.
bool is_valid_file;
};
// The dictionary will be saved in |dictionary_directory_name|.
explicit SpellcheckCustomDictionary(
const base::FilePath& dictionary_directory_name);
SpellcheckCustomDictionary(const SpellcheckCustomDictionary&) = delete;
SpellcheckCustomDictionary& operator=(const SpellcheckCustomDictionary&) =
delete;
~SpellcheckCustomDictionary() override;
// Returns the in-memory cache of words in the custom dictionary.
const std::set<std::string>& GetWords() const;
// Adds |word| to the dictionary, schedules a write to disk, and notifies
// observers of the change. Returns true if |word| is valid and not a
// duplicate. Otherwise returns false.
bool AddWord(const std::string& word);
// Removes |word| from the dictionary, schedules a write to disk, and notifies
// observers of the change. Returns true if |word| was found. Otherwise
// returns false.
bool RemoveWord(const std::string& word);
// Returns true if the dictionary contains |word|. Otherwise returns false.
bool HasWord(const std::string& word) const;
// Removes all words in the dictionary, and schedules a write to disk.
void Clear();
// Adds |observer| to be notified of dictionary events and changes.
void AddObserver(Observer* observer);
// Removes |observer| to stop notifications of dictionary events and changes.
void RemoveObserver(Observer* observer);
// Returns true if the dictionary has been loaded. Otherwise returns false.
bool IsLoaded();
// Returns true if the dictionary is being synced. Otherwise returns false.
bool IsSyncing();
// Overridden from SpellcheckDictionary:
void Load() override;
// Overridden from syncer::SyncableService:
void WaitUntilReadyToSync(base::OnceClosure done) override;
std::optional<syncer::ModelError> MergeDataAndStartSyncing(
syncer::DataType type,
const syncer::SyncDataList& initial_sync_data,
std::unique_ptr<syncer::SyncChangeProcessor> sync_processor) override;
void StopSyncing(syncer::DataType type) override;
syncer::SyncDataList GetAllSyncDataForTesting(syncer::DataType type) const;
std::optional<syncer::ModelError> ProcessSyncChanges(
const base::Location& from_here,
const syncer::SyncChangeList& change_list) override;
base::WeakPtr<SyncableService> AsWeakPtr() override;
private:
friend class DictionarySyncIntegrationTestHelper;
friend class SpellcheckCustomDictionaryTest;
FRIEND_TEST_ALL_PREFIXES(ChromeBrowsingDataRemoverDelegateTest,
WipeCustomDictionaryData);
// Returns the list of words in the custom spellcheck dictionary at |path|.
// Validates that the custom dictionary file does not have duplicates and
// contains only valid words. Must be called on the FILE thread.
static std::unique_ptr<LoadFileResult> LoadDictionaryFile(
const base::FilePath& path);
// Applies the change in |dictionary_change| to the custom spellcheck
// dictionary. Assumes that |dictionary_change| has been sanitized. Must be
// called on the FILE thread. Takes ownership of |dictionary_change|.
static void UpdateDictionaryFile(std::unique_ptr<Change> dictionary_change,
const base::FilePath& path);
// The reply point for PostTaskAndReplyWithResult, called when
// LoadDictionaryFile finishes reading the dictionary file.
void OnLoaded(std::unique_ptr<LoadFileResult> result);
// Applies the |dictionary_change| to the in-memory copy of the dictionary.
void Apply(const Change& dictionary_change);
// Schedules a write of the words in |load_file_result| to disk when the
// custom dictionary file is invalid.
void FixInvalidFile(std::unique_ptr<LoadFileResult> load_file_result);
// Schedules a write of |dictionary_change| to disk. Takes ownership of
// |dictionary_change| to pass it to the FILE thread.
void Save(std::unique_ptr<Change> dictionary_change);
// Notifies the sync service of the |dictionary_change|. Syncs up to the
// maximum syncable words on the server. Disables syncing of this dictionary
// if the server contains the maximum number of syncable words.
std::optional<syncer::ModelError> Sync(const Change& dictionary_change);
// Notifies observers of the dictionary change if the dictionary has been
// changed.
void Notify(const Change& dictionary_change);
// Task runner where the file operations takes place.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// In-memory cache of the custom words file.
std::set<std::string> words_;
// The path to the custom dictionary file.
base::FilePath custom_dictionary_path_;
// Observers for dictionary load and content changes.
base::ObserverList<Observer>::Unchecked observers_;
// Used to send local changes to the sync infrastructure.
std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
// True if the dictionary has been loaded. Otherwise false.
bool is_loaded_;
base::OnceClosure wait_until_ready_to_sync_cb_;
// A post-startup task to fix the invalid custom dictionary file.
base::CancelableOnceClosure fix_invalid_file_;
// Used to create weak pointers for an instance of this class.
base::WeakPtrFactory<SpellcheckCustomDictionary> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_SPELLCHECKER_SPELLCHECK_CUSTOM_DICTIONARY_H_
|