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
|
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// The |Feedback| object keeps track of each instance of user feedback in a map
// |misspellings_|. This is a map from uint32_t hashes to |Misspelling| objects.
//
// Each misspelling should be present in only one renderer process. The
// |Feedback| objects keeps track of misspelling-renderer relationship in the
// |renderers_| map of renderer process identifiers to a set of hashes.
//
// When the user adds a misspelling to their custom dictionary, all of the
// |Misspelling| objects with the same misspelled string are updated. The
// |Feedback| object facilitates efficient access to these misspellings through
// a |text_| map of misspelled strings to a set of hashes.
#include "components/spellcheck/browser/feedback.h"
#include <algorithm>
#include <iterator>
#include <limits>
#include "base/logging.h"
#include "base/stl_util.h"
namespace spellcheck {
Feedback::Feedback(size_t max_total_text_size)
: max_total_text_size_(max_total_text_size), total_text_size_(0) {
DCHECK_GE(max_total_text_size, 1024U);
}
Feedback::~Feedback() {}
Misspelling* Feedback::GetMisspelling(uint32_t hash) {
HashMisspellingMap::iterator misspelling_it = misspellings_.find(hash);
if (misspelling_it == misspellings_.end())
return nullptr;
return &misspelling_it->second;
}
void Feedback::FinalizeRemovedMisspellings(
int renderer_process_id,
const std::vector<uint32_t>& remaining_markers) {
RendererHashesMap::iterator renderer_it =
renderers_.find(renderer_process_id);
if (renderer_it == renderers_.end() || renderer_it->second.empty())
return;
HashCollection& renderer_hashes = renderer_it->second;
HashCollection remaining_hashes(remaining_markers.begin(),
remaining_markers.end());
std::vector<HashCollection::value_type> removed_hashes =
base::STLSetDifference<std::vector<HashCollection::value_type>>(
renderer_hashes, remaining_hashes);
for (auto hash : removed_hashes) {
HashMisspellingMap::iterator misspelling_it = misspellings_.find(hash);
if (misspelling_it != misspellings_.end() &&
!misspelling_it->second.action.IsFinal()) {
misspelling_it->second.action.Finalize();
}
}
}
bool Feedback::RendererHasMisspellings(int renderer_process_id) const {
RendererHashesMap::const_iterator renderer_it =
renderers_.find(renderer_process_id);
return renderer_it != renderers_.end() && !renderer_it->second.empty();
}
std::vector<Misspelling> Feedback::GetMisspellingsInRenderer(
int renderer_process_id) const {
std::vector<Misspelling> misspellings_in_renderer;
RendererHashesMap::const_iterator renderer_it =
renderers_.find(renderer_process_id);
if (renderer_it == renderers_.end() || renderer_it->second.empty())
return misspellings_in_renderer;
const HashCollection& renderer_hashes = renderer_it->second;
for (HashCollection::const_iterator hash_it = renderer_hashes.begin();
hash_it != renderer_hashes.end(); ++hash_it) {
HashMisspellingMap::const_iterator misspelling_it =
misspellings_.find(*hash_it);
if (misspelling_it != misspellings_.end())
misspellings_in_renderer.push_back(misspelling_it->second);
}
return misspellings_in_renderer;
}
void Feedback::EraseFinalizedMisspellings(int renderer_process_id) {
RendererHashesMap::iterator renderer_it =
renderers_.find(renderer_process_id);
if (renderer_it == renderers_.end())
return;
HashCollection& renderer_hashes = renderer_it->second;
for (HashCollection::const_iterator hash_it = renderer_hashes.begin();
hash_it != renderer_hashes.end();) {
HashMisspellingMap::iterator misspelling_it = misspellings_.find(*hash_it);
HashCollection::iterator erasable_hash_it = hash_it;
++hash_it;
if (misspelling_it == misspellings_.end())
continue;
const Misspelling& misspelling = misspelling_it->second;
if (!misspelling.action.IsFinal())
continue;
renderer_hashes.erase(erasable_hash_it);
text_[GetMisspelledString(misspelling)].erase(misspelling.hash);
size_t approximate_size = ApproximateSerializedSize(misspelling_it->second);
// Prevent underlfow.
if (total_text_size_ >= approximate_size)
total_text_size_ -= approximate_size;
else
total_text_size_ = 0;
misspellings_.erase(misspelling_it);
}
if (renderer_hashes.empty())
renderers_.erase(renderer_it);
}
bool Feedback::HasMisspelling(uint32_t hash) const {
return !!misspellings_.count(hash);
}
void Feedback::AddMisspelling(int renderer_process_id,
const Misspelling& misspelling) {
HashMisspellingMap::iterator misspelling_it =
misspellings_.find(misspelling.hash);
if (misspelling_it != misspellings_.end()) {
const Misspelling& existing_misspelling = misspelling_it->second;
text_[GetMisspelledString(existing_misspelling)].erase(misspelling.hash);
for (RendererHashesMap::iterator renderer_it = renderers_.begin();
renderer_it != renderers_.end();) {
HashCollection& renderer_hashes = renderer_it->second;
RendererHashesMap::iterator erasable_renderer_it = renderer_it;
++renderer_it;
renderer_hashes.erase(misspelling.hash);
if (renderer_hashes.empty())
renderers_.erase(erasable_renderer_it);
}
} else {
size_t approximate_size = ApproximateSerializedSize(misspelling);
// Prevent overflow.
if (total_text_size_ <=
std::numeric_limits<size_t>::max() - approximate_size) {
total_text_size_ += approximate_size;
}
if (total_text_size_ >= max_total_text_size_)
return;
}
misspellings_[misspelling.hash] = misspelling;
text_[GetMisspelledString(misspelling)].insert(misspelling.hash);
renderers_[renderer_process_id].insert(misspelling.hash);
}
bool Feedback::Empty() const {
return misspellings_.empty();
}
std::vector<int> Feedback::GetRendersWithMisspellings() const {
std::vector<int> renderers_with_misspellings;
for (const auto& renderer : renderers_) {
if (!renderer.second.empty())
renderers_with_misspellings.push_back(renderer.first);
}
return renderers_with_misspellings;
}
void Feedback::FinalizeAllMisspellings() {
for (auto& misspelling : misspellings_) {
if (!misspelling.second.action.IsFinal())
misspelling.second.action.Finalize();
}
}
std::vector<Misspelling> Feedback::GetAllMisspellings() const {
std::vector<Misspelling> all_misspellings;
for (const auto& misspelling : misspellings_)
all_misspellings.push_back(misspelling.second);
return all_misspellings;
}
void Feedback::Clear() {
total_text_size_ = 0;
misspellings_.clear();
text_.clear();
renderers_.clear();
}
const std::set<uint32_t>& Feedback::FindMisspellings(
const base::string16& misspelled_text) const {
const TextHashesMap::const_iterator text_it = text_.find(misspelled_text);
return text_it == text_.end() ? empty_hash_collection_ : text_it->second;
}
} // namespace spellcheck
|