Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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 |
| 11 // misspelling as already displayed to the user, then |FeedbackSender| reuses | 11 // misspelling as already displayed to the user, then |FeedbackSender| reuses |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 start + result.length, | 86 start + result.length, |
| 87 text, | 87 text, |
| 88 chrome::spellcheck_common::kContextWordCount); | 88 chrome::spellcheck_common::kContextWordCount); |
| 89 return Misspelling(context, | 89 return Misspelling(context, |
| 90 start, | 90 start, |
| 91 result.length, | 91 result.length, |
| 92 std::vector<base::string16>(1, result.replacement), | 92 std::vector<base::string16>(1, result.replacement), |
| 93 result.hash); | 93 result.hash); |
| 94 } | 94 } |
| 95 | 95 |
| 96 // Builds suggestion info from |suggestions|. The caller owns the result. | 96 // Builds suggestion info from |suggestions|. |
| 97 base::ListValue* BuildSuggestionInfo( | 97 scoped_ptr<base::ListValue> BuildSuggestionInfo( |
| 98 const std::vector<Misspelling>& suggestions, | 98 const std::vector<Misspelling>& misspellings, |
| 99 bool is_first_feedback_batch) { | 99 bool is_first_feedback_batch) { |
| 100 base::ListValue* list = new base::ListValue; | 100 scoped_ptr<base::ListValue> list(new base::ListValue); |
| 101 for (std::vector<Misspelling>::const_iterator suggestion_it = | 101 for (const auto& raw_misspelling : misspellings) { |
| 102 suggestions.begin(); | 102 scoped_ptr<base::DictionaryValue> misspelling( |
| 103 suggestion_it != suggestions.end(); | 103 SerializeMisspelling(raw_misspelling)); |
| 104 ++suggestion_it) { | 104 misspelling->SetBoolean("isFirstInSession", is_first_feedback_batch); |
| 105 base::DictionaryValue* suggestion = SerializeMisspelling(*suggestion_it); | 105 misspelling->SetBoolean("isAutoCorrection", false); |
| 106 suggestion->SetBoolean("isFirstInSession", is_first_feedback_batch); | 106 list->Append(misspelling.release()); |
| 107 suggestion->SetBoolean("isAutoCorrection", false); | |
| 108 list->Append(suggestion); | |
| 109 } | 107 } |
| 110 return list; | 108 return list; |
| 111 } | 109 } |
| 112 | 110 |
| 113 // Builds feedback parameters from |suggestion_info|, |language|, and |country|. | 111 // Builds feedback parameters from |suggestion_info|, |language|, and |country|. |
| 114 // Takes ownership of |suggestion_list|. The caller owns the result. | 112 // Takes ownership of |suggestion_list|. |
| 115 base::DictionaryValue* BuildParams(base::ListValue* suggestion_info, | 113 scoped_ptr<base::DictionaryValue> BuildParams( |
| 116 const std::string& language, | 114 scoped_ptr<base::ListValue> suggestion_info, |
| 117 const std::string& country) { | 115 const std::string& language, |
| 118 base::DictionaryValue* params = new base::DictionaryValue; | 116 const std::string& country) { |
| 119 params->Set("suggestionInfo", suggestion_info); | 117 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue); |
| 118 params->Set("suggestionInfo", suggestion_info.release()); | |
| 120 params->SetString("key", google_apis::GetAPIKey()); | 119 params->SetString("key", google_apis::GetAPIKey()); |
| 121 params->SetString("language", language); | 120 params->SetString("language", language); |
| 122 params->SetString("originCountry", country); | 121 params->SetString("originCountry", country); |
| 123 params->SetString("clientName", "Chrome"); | 122 params->SetString("clientName", "Chrome"); |
| 124 return params; | 123 return params; |
| 125 } | 124 } |
| 126 | 125 |
| 127 // Builds feedback data from |params|. Takes ownership of |params|. The caller | 126 // Builds feedback data from |params|. Takes ownership of |params|. |
| 128 // owns the result. | 127 scoped_ptr<base::Value> BuildFeedbackValue( |
| 129 base::Value* BuildFeedbackValue(base::DictionaryValue* params, | 128 scoped_ptr<base::DictionaryValue> params, |
| 130 const std::string& api_version) { | 129 const std::string& api_version) { |
| 131 base::DictionaryValue* result = new base::DictionaryValue; | 130 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue); |
| 132 result->Set("params", params); | 131 result->Set("params", params.release()); |
| 133 result->SetString("method", "spelling.feedback"); | 132 result->SetString("method", "spelling.feedback"); |
| 134 result->SetString("apiVersion", api_version); | 133 result->SetString("apiVersion", api_version); |
| 135 return result; | 134 return std::move(result); |
|
groby-ooo-7-16
2016/02/09 20:20:26
Does this need to be std::move? The move ctor _sho
Kevin Bailey
2016/02/09 22:26:39
../../chrome/browser/spellchecker/feedback_sender.
| |
| 136 } | 135 } |
| 137 | 136 |
| 138 // Returns true if the misspelling location is within text bounds. | 137 // Returns true if the misspelling location is within text bounds. |
| 139 bool IsInBounds(int misspelling_location, | 138 bool IsInBounds(int misspelling_location, |
| 140 int misspelling_length, | 139 int misspelling_length, |
| 141 size_t text_length) { | 140 size_t text_length) { |
| 142 return misspelling_location >= 0 && misspelling_length > 0 && | 141 return misspelling_location >= 0 && misspelling_length > 0 && |
| 143 static_cast<size_t>(misspelling_location) < text_length && | 142 static_cast<size_t>(misspelling_location) < text_length && |
| 144 static_cast<size_t>(misspelling_location + misspelling_length) <= | 143 static_cast<size_t>(misspelling_location + misspelling_length) <= |
| 145 text_length; | 144 text_length; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 void FeedbackSender::AddedToDictionary(uint32_t hash) { | 198 void FeedbackSender::AddedToDictionary(uint32_t hash) { |
| 200 Misspelling* misspelling = feedback_.GetMisspelling(hash); | 199 Misspelling* misspelling = feedback_.GetMisspelling(hash); |
| 201 // GetMisspelling() returns null for flushed feedback. Feedback is flushed | 200 // GetMisspelling() returns null for flushed feedback. Feedback is flushed |
| 202 // when the session expires every |kSessionHours| hours. | 201 // when the session expires every |kSessionHours| hours. |
| 203 if (!misspelling) | 202 if (!misspelling) |
| 204 return; | 203 return; |
| 205 misspelling->action.set_type(SpellcheckAction::TYPE_ADD_TO_DICT); | 204 misspelling->action.set_type(SpellcheckAction::TYPE_ADD_TO_DICT); |
| 206 misspelling->timestamp = base::Time::Now(); | 205 misspelling->timestamp = base::Time::Now(); |
| 207 const std::set<uint32_t>& hashes = | 206 const std::set<uint32_t>& hashes = |
| 208 feedback_.FindMisspellings(GetMisspelledString(*misspelling)); | 207 feedback_.FindMisspellings(GetMisspelledString(*misspelling)); |
| 209 for (std::set<uint32_t>::const_iterator hash_it = hashes.begin(); | 208 for (uint32_t hash : hashes) { |
| 210 hash_it != hashes.end(); ++hash_it) { | 209 Misspelling* duplicate_misspelling = feedback_.GetMisspelling(hash); |
| 211 Misspelling* duplicate_misspelling = feedback_.GetMisspelling(*hash_it); | |
| 212 if (!duplicate_misspelling || duplicate_misspelling->action.IsFinal()) | 210 if (!duplicate_misspelling || duplicate_misspelling->action.IsFinal()) |
| 213 continue; | 211 continue; |
| 214 duplicate_misspelling->action.set_type(SpellcheckAction::TYPE_ADD_TO_DICT); | 212 duplicate_misspelling->action.set_type(SpellcheckAction::TYPE_ADD_TO_DICT); |
| 215 duplicate_misspelling->timestamp = misspelling->timestamp; | 213 duplicate_misspelling->timestamp = misspelling->timestamp; |
| 216 } | 214 } |
| 217 } | 215 } |
| 218 | 216 |
| 219 void FeedbackSender::RecordInDictionary(uint32_t hash) { | 217 void FeedbackSender::RecordInDictionary(uint32_t hash) { |
| 220 Misspelling* misspelling = feedback_.GetMisspelling(hash); | 218 Misspelling* misspelling = feedback_.GetMisspelling(hash); |
| 221 // GetMisspelling() returns null for flushed feedback. Feedback is flushed | 219 // GetMisspelling() returns null for flushed feedback. Feedback is flushed |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 276 return; | 274 return; |
| 277 | 275 |
| 278 // Generate a map of marker offsets to marker hashes. This map helps to | 276 // Generate a map of marker offsets to marker hashes. This map helps to |
| 279 // efficiently lookup feedback data based on the position of the misspelling | 277 // efficiently lookup feedback data based on the position of the misspelling |
| 280 // in text. | 278 // in text. |
| 281 typedef std::map<size_t, uint32_t> MarkerMap; | 279 typedef std::map<size_t, uint32_t> MarkerMap; |
| 282 MarkerMap marker_map; | 280 MarkerMap marker_map; |
| 283 for (size_t i = 0; i < markers.size(); ++i) | 281 for (size_t i = 0; i < markers.size(); ++i) |
| 284 marker_map[markers[i].offset] = markers[i].hash; | 282 marker_map[markers[i].offset] = markers[i].hash; |
| 285 | 283 |
| 286 for (std::vector<SpellCheckResult>::iterator result_it = results->begin(); | 284 for (auto& result : *results) { |
| 287 result_it != results->end(); | 285 if (!IsInBounds(result.location, result.length, text.length())) |
| 288 ++result_it) { | |
| 289 if (!IsInBounds(result_it->location, result_it->length, text.length())) | |
| 290 continue; | 286 continue; |
| 291 MarkerMap::const_iterator marker_it = marker_map.find(result_it->location); | 287 MarkerMap::const_iterator marker_it = marker_map.find(result.location); |
| 292 if (marker_it != marker_map.end() && | 288 if (marker_it != marker_map.end() && |
| 293 feedback_.HasMisspelling(marker_it->second)) { | 289 feedback_.HasMisspelling(marker_it->second)) { |
| 294 // If the renderer already has a marker for this spellcheck result, then | 290 // If the renderer already has a marker for this spellcheck result, then |
| 295 // set the hash of the spellcheck result to be the same as the marker. | 291 // set the hash of the spellcheck result to be the same as the marker. |
| 296 result_it->hash = marker_it->second; | 292 result.hash = marker_it->second; |
| 297 } else { | 293 } else { |
| 298 // If the renderer does not yet have a marker for this spellcheck result, | 294 // If the renderer does not yet have a marker for this spellcheck result, |
| 299 // then generate a new hash for the spellcheck result. | 295 // then generate a new hash for the spellcheck result. |
| 300 result_it->hash = BuildHash(session_start_, ++misspelling_counter_); | 296 result.hash = BuildHash(session_start_, ++misspelling_counter_); |
| 301 } | 297 } |
| 302 // Save the feedback data for the spellcheck result. | 298 // Save the feedback data for the spellcheck result. |
| 303 feedback_.AddMisspelling(renderer_process_id, | 299 feedback_.AddMisspelling(renderer_process_id, BuildFeedback(result, text)); |
| 304 BuildFeedback(*result_it, text)); | |
| 305 } | 300 } |
| 306 } | 301 } |
| 307 | 302 |
| 308 void FeedbackSender::OnLanguageCountryChange(const std::string& language, | 303 void FeedbackSender::OnLanguageCountryChange(const std::string& language, |
| 309 const std::string& country) { | 304 const std::string& country) { |
| 310 FlushFeedback(); | 305 FlushFeedback(); |
| 311 language_ = language; | 306 language_ = language; |
| 312 country_ = country; | 307 country_ = country; |
| 313 } | 308 } |
| 314 | 309 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 368 it.Advance()) { | 363 it.Advance()) { |
| 369 alive_renderers.insert(it.GetCurrentValue()->GetID()); | 364 alive_renderers.insert(it.GetCurrentValue()->GetID()); |
| 370 it.GetCurrentValue()->Send(new SpellCheckMsg_RequestDocumentMarkers()); | 365 it.GetCurrentValue()->Send(new SpellCheckMsg_RequestDocumentMarkers()); |
| 371 } | 366 } |
| 372 | 367 |
| 373 // Asynchronously send out the feedback for all the renderers that are no | 368 // Asynchronously send out the feedback for all the renderers that are no |
| 374 // longer alive. | 369 // longer alive. |
| 375 std::vector<int> known_renderers = feedback_.GetRendersWithMisspellings(); | 370 std::vector<int> known_renderers = feedback_.GetRendersWithMisspellings(); |
| 376 std::sort(known_renderers.begin(), known_renderers.end()); | 371 std::sort(known_renderers.begin(), known_renderers.end()); |
| 377 std::vector<int> dead_renderers = | 372 std::vector<int> dead_renderers = |
| 378 base::STLSetDifference<std::vector<int> >(known_renderers, | 373 base::STLSetDifference<std::vector<int>>(known_renderers, |
| 379 alive_renderers); | 374 alive_renderers); |
| 380 for (std::vector<int>::const_iterator it = dead_renderers.begin(); | 375 for (int renderer : dead_renderers) { |
|
groby-ooo-7-16
2016/02/09 20:20:26
nit: renderer_process_id (I wish we had a type for
Kevin Bailey
2016/02/09 22:26:39
Done.
| |
| 381 it != dead_renderers.end(); | |
| 382 ++it) { | |
| 383 base::ThreadTaskRunnerHandle::Get()->PostTask( | 376 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 384 FROM_HERE, base::Bind(&FeedbackSender::OnReceiveDocumentMarkers, | 377 FROM_HERE, base::Bind(&FeedbackSender::OnReceiveDocumentMarkers, |
| 385 AsWeakPtr(), *it, std::vector<uint32_t>())); | 378 AsWeakPtr(), renderer, std::vector<uint32_t>())); |
| 386 } | 379 } |
| 387 } | 380 } |
| 388 | 381 |
| 389 void FeedbackSender::FlushFeedback() { | 382 void FeedbackSender::FlushFeedback() { |
| 390 if (feedback_.Empty()) | 383 if (feedback_.Empty()) |
| 391 return; | 384 return; |
| 392 feedback_.FinalizeAllMisspellings(); | 385 feedback_.FinalizeAllMisspellings(); |
| 393 SendFeedback(feedback_.GetAllMisspellings(), | 386 SendFeedback(feedback_.GetAllMisspellings(), |
| 394 renderers_sent_feedback_.empty()); | 387 renderers_sent_feedback_.empty()); |
| 395 feedback_.Clear(); | 388 feedback_.Clear(); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 413 net::URLFetcher* sender = | 406 net::URLFetcher* sender = |
| 414 net::URLFetcher::Create(kUrlFetcherId, feedback_service_url_, | 407 net::URLFetcher::Create(kUrlFetcherId, feedback_service_url_, |
| 415 net::URLFetcher::POST, this).release(); | 408 net::URLFetcher::POST, this).release(); |
| 416 data_use_measurement::DataUseUserData::AttachToFetcher( | 409 data_use_measurement::DataUseUserData::AttachToFetcher( |
| 417 sender, data_use_measurement::DataUseUserData::SPELL_CHECKER); | 410 sender, data_use_measurement::DataUseUserData::SPELL_CHECKER); |
| 418 sender->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 411 sender->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 419 net::LOAD_DO_NOT_SAVE_COOKIES); | 412 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 420 sender->SetUploadData("application/json", feedback); | 413 sender->SetUploadData("application/json", feedback); |
| 421 senders_.push_back(sender); | 414 senders_.push_back(sender); |
| 422 | 415 |
| 423 // Request context is NULL in testing. | 416 // Request context is nullptr in testing. |
| 424 if (request_context_.get()) { | 417 if (request_context_.get()) { |
| 425 sender->SetRequestContext(request_context_.get()); | 418 sender->SetRequestContext(request_context_.get()); |
| 426 sender->Start(); | 419 sender->Start(); |
| 427 } | 420 } |
| 428 } | 421 } |
| 429 | 422 |
| 430 } // namespace spellcheck | 423 } // namespace spellcheck |
| OLD | NEW |