| 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 |