OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 // The |FeedbackSender| object stores the user feedback to spellcheck | 5 // The |FeedbackSender| object stores the user feedback to spellcheck |
6 // suggestions in a |Feedback| object. | 6 // suggestions in a |Feedback| object. |
7 // | 7 // |
8 // When spelling service returns spellcheck results, these results first arrive | 8 // When spelling service returns spellcheck results, these results first arrive |
9 // in |FeedbackSender| to assign hash identifiers for each | 9 // in |FeedbackSender| to assign hash identifiers for each |
10 // misspelling-suggestion pair. If the spelling service identifies the same | 10 // misspelling-suggestion pair. If the spelling service identifies the same |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 const size_t kMaxFeedbackSizeBytes = 10 * 1024 * 1024; // 10 MB | 62 const size_t kMaxFeedbackSizeBytes = 10 * 1024 * 1024; // 10 MB |
63 | 63 |
64 // The default URL where feedback data is sent. | 64 // The default URL where feedback data is sent. |
65 const char kFeedbackServiceURL[] = "https://www.googleapis.com/rpc"; | 65 const char kFeedbackServiceURL[] = "https://www.googleapis.com/rpc"; |
66 | 66 |
67 // The minimum number of seconds between sending batches of feedback. | 67 // The minimum number of seconds between sending batches of feedback. |
68 const int kMinIntervalSeconds = 5; | 68 const int kMinIntervalSeconds = 5; |
69 | 69 |
70 // Returns a hash of |session_start|, the current timestamp, and | 70 // Returns a hash of |session_start|, the current timestamp, and |
71 // |suggestion_index|. | 71 // |suggestion_index|. |
72 uint32 BuildHash(const base::Time& session_start, size_t suggestion_index) { | 72 uint32_t BuildHash(const base::Time& session_start, size_t suggestion_index) { |
73 return base::Hash( | 73 return base::Hash( |
74 base::StringPrintf("%" PRId64 "%" PRId64 "%" PRIuS, | 74 base::StringPrintf("%" PRId64 "%" PRId64 "%" PRIuS, |
75 session_start.ToInternalValue(), | 75 session_start.ToInternalValue(), |
76 base::Time::Now().ToInternalValue(), | 76 base::Time::Now().ToInternalValue(), |
77 suggestion_index)); | 77 suggestion_index)); |
78 } | 78 } |
79 | 79 |
80 // Returns a pending feedback data structure for the spellcheck |result| and | 80 // Returns a pending feedback data structure for the spellcheck |result| and |
81 // |text|. | 81 // |text|. |
82 Misspelling BuildFeedback(const SpellCheckResult& result, | 82 Misspelling BuildFeedback(const SpellCheckResult& result, |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 switches::kSpellingServiceFeedbackUrl)) { | 178 switches::kSpellingServiceFeedbackUrl)) { |
179 feedback_service_url_ = | 179 feedback_service_url_ = |
180 GURL(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 180 GURL(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
181 switches::kSpellingServiceFeedbackUrl)); | 181 switches::kSpellingServiceFeedbackUrl)); |
182 } | 182 } |
183 } | 183 } |
184 | 184 |
185 FeedbackSender::~FeedbackSender() { | 185 FeedbackSender::~FeedbackSender() { |
186 } | 186 } |
187 | 187 |
188 void FeedbackSender::SelectedSuggestion(uint32 hash, int suggestion_index) { | 188 void FeedbackSender::SelectedSuggestion(uint32_t hash, int suggestion_index) { |
189 Misspelling* misspelling = feedback_.GetMisspelling(hash); | 189 Misspelling* misspelling = feedback_.GetMisspelling(hash); |
190 // GetMisspelling() returns null for flushed feedback. Feedback is flushed | 190 // GetMisspelling() returns null for flushed feedback. Feedback is flushed |
191 // when the session expires every |kSessionHours| hours. | 191 // when the session expires every |kSessionHours| hours. |
192 if (!misspelling) | 192 if (!misspelling) |
193 return; | 193 return; |
194 misspelling->action.set_type(SpellcheckAction::TYPE_SELECT); | 194 misspelling->action.set_type(SpellcheckAction::TYPE_SELECT); |
195 misspelling->action.set_index(suggestion_index); | 195 misspelling->action.set_index(suggestion_index); |
196 misspelling->timestamp = base::Time::Now(); | 196 misspelling->timestamp = base::Time::Now(); |
197 } | 197 } |
198 | 198 |
199 void FeedbackSender::AddedToDictionary(uint32 hash) { | 199 void FeedbackSender::AddedToDictionary(uint32_t hash) { |
200 Misspelling* misspelling = feedback_.GetMisspelling(hash); | 200 Misspelling* misspelling = feedback_.GetMisspelling(hash); |
201 // GetMisspelling() returns null for flushed feedback. Feedback is flushed | 201 // GetMisspelling() returns null for flushed feedback. Feedback is flushed |
202 // when the session expires every |kSessionHours| hours. | 202 // when the session expires every |kSessionHours| hours. |
203 if (!misspelling) | 203 if (!misspelling) |
204 return; | 204 return; |
205 misspelling->action.set_type(SpellcheckAction::TYPE_ADD_TO_DICT); | 205 misspelling->action.set_type(SpellcheckAction::TYPE_ADD_TO_DICT); |
206 misspelling->timestamp = base::Time::Now(); | 206 misspelling->timestamp = base::Time::Now(); |
207 const std::set<uint32>& hashes = | 207 const std::set<uint32_t>& hashes = |
208 feedback_.FindMisspellings(GetMisspelledString(*misspelling)); | 208 feedback_.FindMisspellings(GetMisspelledString(*misspelling)); |
209 for (std::set<uint32>::const_iterator hash_it = hashes.begin(); | 209 for (std::set<uint32_t>::const_iterator hash_it = hashes.begin(); |
210 hash_it != hashes.end(); | 210 hash_it != hashes.end(); ++hash_it) { |
211 ++hash_it) { | |
212 Misspelling* duplicate_misspelling = feedback_.GetMisspelling(*hash_it); | 211 Misspelling* duplicate_misspelling = feedback_.GetMisspelling(*hash_it); |
213 if (!duplicate_misspelling || duplicate_misspelling->action.IsFinal()) | 212 if (!duplicate_misspelling || duplicate_misspelling->action.IsFinal()) |
214 continue; | 213 continue; |
215 duplicate_misspelling->action.set_type(SpellcheckAction::TYPE_ADD_TO_DICT); | 214 duplicate_misspelling->action.set_type(SpellcheckAction::TYPE_ADD_TO_DICT); |
216 duplicate_misspelling->timestamp = misspelling->timestamp; | 215 duplicate_misspelling->timestamp = misspelling->timestamp; |
217 } | 216 } |
218 } | 217 } |
219 | 218 |
220 void FeedbackSender::RecordInDictionary(uint32 hash) { | 219 void FeedbackSender::RecordInDictionary(uint32_t hash) { |
221 Misspelling* misspelling = feedback_.GetMisspelling(hash); | 220 Misspelling* misspelling = feedback_.GetMisspelling(hash); |
222 // GetMisspelling() returns null for flushed feedback. Feedback is flushed | 221 // GetMisspelling() returns null for flushed feedback. Feedback is flushed |
223 // when the session expires every |kSessionHours| hours. | 222 // when the session expires every |kSessionHours| hours. |
224 if (!misspelling) | 223 if (!misspelling) |
225 return; | 224 return; |
226 misspelling->action.set_type(SpellcheckAction::TYPE_IN_DICTIONARY); | 225 misspelling->action.set_type(SpellcheckAction::TYPE_IN_DICTIONARY); |
227 } | 226 } |
228 | 227 |
229 void FeedbackSender::IgnoredSuggestions(uint32 hash) { | 228 void FeedbackSender::IgnoredSuggestions(uint32_t hash) { |
230 Misspelling* misspelling = feedback_.GetMisspelling(hash); | 229 Misspelling* misspelling = feedback_.GetMisspelling(hash); |
231 // GetMisspelling() returns null for flushed feedback. Feedback is flushed | 230 // GetMisspelling() returns null for flushed feedback. Feedback is flushed |
232 // when the session expires every |kSessionHours| hours. | 231 // when the session expires every |kSessionHours| hours. |
233 if (!misspelling) | 232 if (!misspelling) |
234 return; | 233 return; |
235 misspelling->action.set_type(SpellcheckAction::TYPE_PENDING_IGNORE); | 234 misspelling->action.set_type(SpellcheckAction::TYPE_PENDING_IGNORE); |
236 misspelling->timestamp = base::Time::Now(); | 235 misspelling->timestamp = base::Time::Now(); |
237 } | 236 } |
238 | 237 |
239 void FeedbackSender::ManuallyCorrected(uint32 hash, | 238 void FeedbackSender::ManuallyCorrected(uint32_t hash, |
240 const base::string16& correction) { | 239 const base::string16& correction) { |
241 Misspelling* misspelling = feedback_.GetMisspelling(hash); | 240 Misspelling* misspelling = feedback_.GetMisspelling(hash); |
242 // GetMisspelling() returns null for flushed feedback. Feedback is flushed | 241 // GetMisspelling() returns null for flushed feedback. Feedback is flushed |
243 // when the session expires every |kSessionHours| hours. | 242 // when the session expires every |kSessionHours| hours. |
244 if (!misspelling) | 243 if (!misspelling) |
245 return; | 244 return; |
246 misspelling->action.set_type(SpellcheckAction::TYPE_MANUALLY_CORRECTED); | 245 misspelling->action.set_type(SpellcheckAction::TYPE_MANUALLY_CORRECTED); |
247 misspelling->action.set_value(correction); | 246 misspelling->action.set_value(correction); |
248 misspelling->timestamp = base::Time::Now(); | 247 misspelling->timestamp = base::Time::Now(); |
249 } | 248 } |
250 | 249 |
251 void FeedbackSender::OnReceiveDocumentMarkers( | 250 void FeedbackSender::OnReceiveDocumentMarkers( |
252 int renderer_process_id, | 251 int renderer_process_id, |
253 const std::vector<uint32>& markers) { | 252 const std::vector<uint32_t>& markers) { |
254 if ((base::Time::Now() - session_start_).InHours() >= | 253 if ((base::Time::Now() - session_start_).InHours() >= |
255 chrome::spellcheck_common::kSessionHours) { | 254 chrome::spellcheck_common::kSessionHours) { |
256 FlushFeedback(); | 255 FlushFeedback(); |
257 return; | 256 return; |
258 } | 257 } |
259 | 258 |
260 if (!feedback_.RendererHasMisspellings(renderer_process_id)) | 259 if (!feedback_.RendererHasMisspellings(renderer_process_id)) |
261 return; | 260 return; |
262 | 261 |
263 feedback_.FinalizeRemovedMisspellings(renderer_process_id, markers); | 262 feedback_.FinalizeRemovedMisspellings(renderer_process_id, markers); |
264 SendFeedback(feedback_.GetMisspellingsInRenderer(renderer_process_id), | 263 SendFeedback(feedback_.GetMisspellingsInRenderer(renderer_process_id), |
265 !renderers_sent_feedback_.count(renderer_process_id)); | 264 !renderers_sent_feedback_.count(renderer_process_id)); |
266 renderers_sent_feedback_.insert(renderer_process_id); | 265 renderers_sent_feedback_.insert(renderer_process_id); |
267 feedback_.EraseFinalizedMisspellings(renderer_process_id); | 266 feedback_.EraseFinalizedMisspellings(renderer_process_id); |
268 } | 267 } |
269 | 268 |
270 void FeedbackSender::OnSpellcheckResults( | 269 void FeedbackSender::OnSpellcheckResults( |
271 int renderer_process_id, | 270 int renderer_process_id, |
272 const base::string16& text, | 271 const base::string16& text, |
273 const std::vector<SpellCheckMarker>& markers, | 272 const std::vector<SpellCheckMarker>& markers, |
274 std::vector<SpellCheckResult>* results) { | 273 std::vector<SpellCheckResult>* results) { |
275 // Don't collect feedback if not going to send it. | 274 // Don't collect feedback if not going to send it. |
276 if (!timer_.IsRunning()) | 275 if (!timer_.IsRunning()) |
277 return; | 276 return; |
278 | 277 |
279 // Generate a map of marker offsets to marker hashes. This map helps to | 278 // Generate a map of marker offsets to marker hashes. This map helps to |
280 // efficiently lookup feedback data based on the position of the misspelling | 279 // efficiently lookup feedback data based on the position of the misspelling |
281 // in text. | 280 // in text. |
282 typedef std::map<size_t, uint32> MarkerMap; | 281 typedef std::map<size_t, uint32_t> MarkerMap; |
283 MarkerMap marker_map; | 282 MarkerMap marker_map; |
284 for (size_t i = 0; i < markers.size(); ++i) | 283 for (size_t i = 0; i < markers.size(); ++i) |
285 marker_map[markers[i].offset] = markers[i].hash; | 284 marker_map[markers[i].offset] = markers[i].hash; |
286 | 285 |
287 for (std::vector<SpellCheckResult>::iterator result_it = results->begin(); | 286 for (std::vector<SpellCheckResult>::iterator result_it = results->begin(); |
288 result_it != results->end(); | 287 result_it != results->end(); |
289 ++result_it) { | 288 ++result_it) { |
290 if (!IsInBounds(result_it->location, result_it->length, text.length())) | 289 if (!IsInBounds(result_it->location, result_it->length, text.length())) |
291 continue; | 290 continue; |
292 MarkerMap::const_iterator marker_it = marker_map.find(result_it->location); | 291 MarkerMap::const_iterator marker_it = marker_map.find(result_it->location); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 std::vector<int> known_renderers = feedback_.GetRendersWithMisspellings(); | 375 std::vector<int> known_renderers = feedback_.GetRendersWithMisspellings(); |
377 std::sort(known_renderers.begin(), known_renderers.end()); | 376 std::sort(known_renderers.begin(), known_renderers.end()); |
378 std::vector<int> dead_renderers = | 377 std::vector<int> dead_renderers = |
379 base::STLSetDifference<std::vector<int> >(known_renderers, | 378 base::STLSetDifference<std::vector<int> >(known_renderers, |
380 alive_renderers); | 379 alive_renderers); |
381 for (std::vector<int>::const_iterator it = dead_renderers.begin(); | 380 for (std::vector<int>::const_iterator it = dead_renderers.begin(); |
382 it != dead_renderers.end(); | 381 it != dead_renderers.end(); |
383 ++it) { | 382 ++it) { |
384 base::ThreadTaskRunnerHandle::Get()->PostTask( | 383 base::ThreadTaskRunnerHandle::Get()->PostTask( |
385 FROM_HERE, base::Bind(&FeedbackSender::OnReceiveDocumentMarkers, | 384 FROM_HERE, base::Bind(&FeedbackSender::OnReceiveDocumentMarkers, |
386 AsWeakPtr(), *it, std::vector<uint32>())); | 385 AsWeakPtr(), *it, std::vector<uint32_t>())); |
387 } | 386 } |
388 } | 387 } |
389 | 388 |
390 void FeedbackSender::FlushFeedback() { | 389 void FeedbackSender::FlushFeedback() { |
391 if (feedback_.Empty()) | 390 if (feedback_.Empty()) |
392 return; | 391 return; |
393 feedback_.FinalizeAllMisspellings(); | 392 feedback_.FinalizeAllMisspellings(); |
394 SendFeedback(feedback_.GetAllMisspellings(), | 393 SendFeedback(feedback_.GetAllMisspellings(), |
395 renderers_sent_feedback_.empty()); | 394 renderers_sent_feedback_.empty()); |
396 feedback_.Clear(); | 395 feedback_.Clear(); |
(...skipping 25 matching lines...) Expand all Loading... |
422 senders_.push_back(sender); | 421 senders_.push_back(sender); |
423 | 422 |
424 // Request context is NULL in testing. | 423 // Request context is NULL in testing. |
425 if (request_context_.get()) { | 424 if (request_context_.get()) { |
426 sender->SetRequestContext(request_context_.get()); | 425 sender->SetRequestContext(request_context_.get()); |
427 sender->Start(); | 426 sender->Start(); |
428 } | 427 } |
429 } | 428 } |
430 | 429 |
431 } // namespace spellcheck | 430 } // namespace spellcheck |
OLD | NEW |