| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "chrome/browser/autocomplete/autocomplete_controller.h" | 5 #include "chrome/browser/autocomplete/autocomplete_controller.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 namespace { | 43 namespace { |
| 44 | 44 |
| 45 // Converts the given match to a type (and possibly subtype) based on the AQS | 45 // Converts the given match to a type (and possibly subtype) based on the AQS |
| 46 // specification. For more details, see | 46 // specification. For more details, see |
| 47 // http://goto.google.com/binary-clients-logging. | 47 // http://goto.google.com/binary-clients-logging. |
| 48 void AutocompleteMatchToAssistedQuery( | 48 void AutocompleteMatchToAssistedQuery( |
| 49 const AutocompleteMatch::Type& match, size_t* type, size_t* subtype) { | 49 const AutocompleteMatch::Type& match, size_t* type, size_t* subtype) { |
| 50 // This type indicates a native chrome suggestion. | 50 // This type indicates a native chrome suggestion. |
| 51 *type = 69; | 51 *type = 69; |
| 52 // Default value, indicating no subtype. | 52 // Default value, indicating no subtype. |
| 53 *subtype = string16::npos; | 53 *subtype = base::string16::npos; |
| 54 | 54 |
| 55 switch (match) { | 55 switch (match) { |
| 56 case AutocompleteMatchType::SEARCH_SUGGEST: { | 56 case AutocompleteMatchType::SEARCH_SUGGEST: { |
| 57 *type = 0; | 57 *type = 0; |
| 58 return; | 58 return; |
| 59 } | 59 } |
| 60 case AutocompleteMatchType::NAVSUGGEST: { | 60 case AutocompleteMatchType::NAVSUGGEST: { |
| 61 *type = 5; | 61 *type = 5; |
| 62 return; | 62 return; |
| 63 } | 63 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 // the existing available autocompletions string, encoding according to the | 105 // the existing available autocompletions string, encoding according to the |
| 106 // spec. | 106 // spec. |
| 107 void AppendAvailableAutocompletion(size_t type, | 107 void AppendAvailableAutocompletion(size_t type, |
| 108 size_t subtype, | 108 size_t subtype, |
| 109 int count, | 109 int count, |
| 110 std::string* autocompletions) { | 110 std::string* autocompletions) { |
| 111 if (!autocompletions->empty()) | 111 if (!autocompletions->empty()) |
| 112 autocompletions->append("j"); | 112 autocompletions->append("j"); |
| 113 base::StringAppendF(autocompletions, "%" PRIuS, type); | 113 base::StringAppendF(autocompletions, "%" PRIuS, type); |
| 114 // Subtype is optional - string16::npos indicates no subtype. | 114 // Subtype is optional - string16::npos indicates no subtype. |
| 115 if (subtype != string16::npos) | 115 if (subtype != base::string16::npos) |
| 116 base::StringAppendF(autocompletions, "i%" PRIuS, subtype); | 116 base::StringAppendF(autocompletions, "i%" PRIuS, subtype); |
| 117 if (count > 1) | 117 if (count > 1) |
| 118 base::StringAppendF(autocompletions, "l%d", count); | 118 base::StringAppendF(autocompletions, "l%d", count); |
| 119 } | 119 } |
| 120 | 120 |
| 121 // Returns whether the autocompletion is trivial enough that we consider it | 121 // Returns whether the autocompletion is trivial enough that we consider it |
| 122 // an autocompletion for which the omnibox autocompletion code did not add | 122 // an autocompletion for which the omnibox autocompletion code did not add |
| 123 // any value. | 123 // any value. |
| 124 bool IsTrivialAutocompletion(const AutocompleteMatch& match) { | 124 bool IsTrivialAutocompletion(const AutocompleteMatch& match) { |
| 125 return match.type == AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED || | 125 return match.type == AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED || |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 result_.Reset(); // Not really necessary. | 208 result_.Reset(); // Not really necessary. |
| 209 Stop(false); | 209 Stop(false); |
| 210 | 210 |
| 211 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) | 211 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) |
| 212 (*i)->Release(); | 212 (*i)->Release(); |
| 213 | 213 |
| 214 providers_.clear(); // Not really necessary. | 214 providers_.clear(); // Not really necessary. |
| 215 } | 215 } |
| 216 | 216 |
| 217 void AutocompleteController::Start(const AutocompleteInput& input) { | 217 void AutocompleteController::Start(const AutocompleteInput& input) { |
| 218 const string16 old_input_text(input_.text()); | 218 const base::string16 old_input_text(input_.text()); |
| 219 const AutocompleteInput::MatchesRequested old_matches_requested = | 219 const AutocompleteInput::MatchesRequested old_matches_requested = |
| 220 input_.matches_requested(); | 220 input_.matches_requested(); |
| 221 input_ = input; | 221 input_ = input; |
| 222 | 222 |
| 223 // See if we can avoid rerunning autocomplete when the query hasn't changed | 223 // See if we can avoid rerunning autocomplete when the query hasn't changed |
| 224 // much. When the user presses or releases the ctrl key, the desired_tld | 224 // much. When the user presses or releases the ctrl key, the desired_tld |
| 225 // changes, and when the user finishes an IME composition, inline autocomplete | 225 // changes, and when the user finishes an IME composition, inline autocomplete |
| 226 // may no longer be prevented. In both these cases the text itself hasn't | 226 // may no longer be prevented. In both these cases the text itself hasn't |
| 227 // changed since the last query, and some providers can do much less work (and | 227 // changed since the last query, and some providers can do much less work (and |
| 228 // get matches back more quickly). Taking advantage of this reduces flicker. | 228 // get matches back more quickly). Taking advantage of this reduces flicker. |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 result_.Reset(); | 299 result_.Reset(); |
| 300 // NOTE: We pass in false since we're trying to only clear the popup, not | 300 // NOTE: We pass in false since we're trying to only clear the popup, not |
| 301 // touch the edit... this is all a mess and should be cleaned up :( | 301 // touch the edit... this is all a mess and should be cleaned up :( |
| 302 NotifyChanged(false); | 302 NotifyChanged(false); |
| 303 } | 303 } |
| 304 } | 304 } |
| 305 | 305 |
| 306 void AutocompleteController::StartZeroSuggest( | 306 void AutocompleteController::StartZeroSuggest( |
| 307 const GURL& url, | 307 const GURL& url, |
| 308 AutocompleteInput::PageClassification page_classification, | 308 AutocompleteInput::PageClassification page_classification, |
| 309 const string16& permanent_text) { | 309 const base::string16& permanent_text) { |
| 310 if (zero_suggest_provider_ != NULL) { | 310 if (zero_suggest_provider_ != NULL) { |
| 311 DCHECK(!in_start_); // We should not be already running a query. | 311 DCHECK(!in_start_); // We should not be already running a query. |
| 312 in_zero_suggest_ = true; | 312 in_zero_suggest_ = true; |
| 313 zero_suggest_provider_->StartZeroSuggest( | 313 zero_suggest_provider_->StartZeroSuggest( |
| 314 url, page_classification, permanent_text); | 314 url, page_classification, permanent_text); |
| 315 } | 315 } |
| 316 } | 316 } |
| 317 | 317 |
| 318 void AutocompleteController::StopZeroSuggest() { | 318 void AutocompleteController::StopZeroSuggest() { |
| 319 if (zero_suggest_provider_ != NULL) { | 319 if (zero_suggest_provider_ != NULL) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 match->destination_url = | 400 match->destination_url = |
| 401 GURL(template_url->url_ref().ReplaceSearchTerms(search_terms_args)); | 401 GURL(template_url->url_ref().ReplaceSearchTerms(search_terms_args)); |
| 402 } | 402 } |
| 403 | 403 |
| 404 void AutocompleteController::UpdateResult( | 404 void AutocompleteController::UpdateResult( |
| 405 bool regenerate_result, | 405 bool regenerate_result, |
| 406 bool force_notify_default_match_changed) { | 406 bool force_notify_default_match_changed) { |
| 407 const bool last_default_was_valid = result_.default_match() != result_.end(); | 407 const bool last_default_was_valid = result_.default_match() != result_.end(); |
| 408 // The following three variables are only set and used if | 408 // The following three variables are only set and used if |
| 409 // |last_default_was_valid|. | 409 // |last_default_was_valid|. |
| 410 string16 last_default_fill_into_edit, last_default_keyword, | 410 base::string16 last_default_fill_into_edit, last_default_keyword, |
| 411 last_default_associated_keyword; | 411 last_default_associated_keyword; |
| 412 if (last_default_was_valid) { | 412 if (last_default_was_valid) { |
| 413 last_default_fill_into_edit = result_.default_match()->fill_into_edit; | 413 last_default_fill_into_edit = result_.default_match()->fill_into_edit; |
| 414 last_default_keyword = result_.default_match()->keyword; | 414 last_default_keyword = result_.default_match()->keyword; |
| 415 if (result_.default_match()->associated_keyword != NULL) | 415 if (result_.default_match()->associated_keyword != NULL) |
| 416 last_default_associated_keyword = | 416 last_default_associated_keyword = |
| 417 result_.default_match()->associated_keyword->keyword; | 417 result_.default_match()->associated_keyword->keyword; |
| 418 } | 418 } |
| 419 | 419 |
| 420 if (regenerate_result) | 420 if (regenerate_result) |
| (...skipping 19 matching lines...) Expand all Loading... |
| 440 // This conditional needs to match the conditional in Start that invokes | 440 // This conditional needs to match the conditional in Start that invokes |
| 441 // StartExpireTimer. | 441 // StartExpireTimer. |
| 442 result_.CopyOldMatches(input_, last_result, profile_); | 442 result_.CopyOldMatches(input_, last_result, profile_); |
| 443 } | 443 } |
| 444 | 444 |
| 445 UpdateKeywordDescriptions(&result_); | 445 UpdateKeywordDescriptions(&result_); |
| 446 UpdateAssociatedKeywords(&result_); | 446 UpdateAssociatedKeywords(&result_); |
| 447 UpdateAssistedQueryStats(&result_); | 447 UpdateAssistedQueryStats(&result_); |
| 448 | 448 |
| 449 const bool default_is_valid = result_.default_match() != result_.end(); | 449 const bool default_is_valid = result_.default_match() != result_.end(); |
| 450 string16 default_associated_keyword; | 450 base::string16 default_associated_keyword; |
| 451 if (default_is_valid && | 451 if (default_is_valid && |
| 452 (result_.default_match()->associated_keyword != NULL)) { | 452 (result_.default_match()->associated_keyword != NULL)) { |
| 453 default_associated_keyword = | 453 default_associated_keyword = |
| 454 result_.default_match()->associated_keyword->keyword; | 454 result_.default_match()->associated_keyword->keyword; |
| 455 } | 455 } |
| 456 // We've gotten async results. Send notification that the default match | 456 // We've gotten async results. Send notification that the default match |
| 457 // updated if fill_into_edit, associated_keyword, or keyword differ. (The | 457 // updated if fill_into_edit, associated_keyword, or keyword differ. (The |
| 458 // second can change if we've just started Chrome and the keyword database | 458 // second can change if we've just started Chrome and the keyword database |
| 459 // finishes loading while processing this request. The third can change | 459 // finishes loading while processing this request. The third can change |
| 460 // if we swapped from interpreting the input as a search--which gets | 460 // if we swapped from interpreting the input as a search--which gets |
| (...skipping 12 matching lines...) Expand all Loading... |
| 473 last_time_default_match_changed_ = base::TimeTicks::Now(); | 473 last_time_default_match_changed_ = base::TimeTicks::Now(); |
| 474 | 474 |
| 475 NotifyChanged(force_notify_default_match_changed || notify_default_match); | 475 NotifyChanged(force_notify_default_match_changed || notify_default_match); |
| 476 } | 476 } |
| 477 | 477 |
| 478 void AutocompleteController::UpdateAssociatedKeywords( | 478 void AutocompleteController::UpdateAssociatedKeywords( |
| 479 AutocompleteResult* result) { | 479 AutocompleteResult* result) { |
| 480 if (!keyword_provider_) | 480 if (!keyword_provider_) |
| 481 return; | 481 return; |
| 482 | 482 |
| 483 std::set<string16> keywords; | 483 std::set<base::string16> keywords; |
| 484 for (ACMatches::iterator match(result->begin()); match != result->end(); | 484 for (ACMatches::iterator match(result->begin()); match != result->end(); |
| 485 ++match) { | 485 ++match) { |
| 486 string16 keyword(match->GetSubstitutingExplicitlyInvokedKeyword(profile_)); | 486 base::string16 keyword( |
| 487 match->GetSubstitutingExplicitlyInvokedKeyword(profile_)); |
| 487 if (!keyword.empty()) { | 488 if (!keyword.empty()) { |
| 488 keywords.insert(keyword); | 489 keywords.insert(keyword); |
| 489 continue; | 490 continue; |
| 490 } | 491 } |
| 491 | 492 |
| 492 // Only add the keyword if the match does not have a duplicate keyword with | 493 // Only add the keyword if the match does not have a duplicate keyword with |
| 493 // a more relevant match. | 494 // a more relevant match. |
| 494 keyword = match->associated_keyword.get() ? | 495 keyword = match->associated_keyword.get() ? |
| 495 match->associated_keyword->keyword : | 496 match->associated_keyword->keyword : |
| 496 keyword_provider_->GetKeywordForText(match->fill_into_edit); | 497 keyword_provider_->GetKeywordForText(match->fill_into_edit); |
| 497 if (!keyword.empty() && !keywords.count(keyword)) { | 498 if (!keyword.empty() && !keywords.count(keyword)) { |
| 498 keywords.insert(keyword); | 499 keywords.insert(keyword); |
| 499 | 500 |
| 500 if (!match->associated_keyword.get()) | 501 if (!match->associated_keyword.get()) |
| 501 match->associated_keyword.reset(new AutocompleteMatch( | 502 match->associated_keyword.reset(new AutocompleteMatch( |
| 502 keyword_provider_->CreateVerbatimMatch(match->fill_into_edit, | 503 keyword_provider_->CreateVerbatimMatch(match->fill_into_edit, |
| 503 keyword, input_))); | 504 keyword, input_))); |
| 504 } else { | 505 } else { |
| 505 match->associated_keyword.reset(); | 506 match->associated_keyword.reset(); |
| 506 } | 507 } |
| 507 } | 508 } |
| 508 } | 509 } |
| 509 | 510 |
| 510 void AutocompleteController::UpdateKeywordDescriptions( | 511 void AutocompleteController::UpdateKeywordDescriptions( |
| 511 AutocompleteResult* result) { | 512 AutocompleteResult* result) { |
| 512 string16 last_keyword; | 513 base::string16 last_keyword; |
| 513 for (AutocompleteResult::iterator i(result->begin()); i != result->end(); | 514 for (AutocompleteResult::iterator i(result->begin()); i != result->end(); |
| 514 ++i) { | 515 ++i) { |
| 515 if ((i->provider->type() == AutocompleteProvider::TYPE_KEYWORD && | 516 if ((i->provider->type() == AutocompleteProvider::TYPE_KEYWORD && |
| 516 !i->keyword.empty()) || | 517 !i->keyword.empty()) || |
| 517 (i->provider->type() == AutocompleteProvider::TYPE_SEARCH && | 518 (i->provider->type() == AutocompleteProvider::TYPE_SEARCH && |
| 518 AutocompleteMatch::IsSearchType(i->type))) { | 519 AutocompleteMatch::IsSearchType(i->type))) { |
| 519 i->description.clear(); | 520 i->description.clear(); |
| 520 i->description_class.clear(); | 521 i->description_class.clear(); |
| 521 DCHECK(!i->keyword.empty()); | 522 DCHECK(!i->keyword.empty()); |
| 522 if (i->keyword != last_keyword) { | 523 if (i->keyword != last_keyword) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 542 } | 543 } |
| 543 | 544 |
| 544 void AutocompleteController::UpdateAssistedQueryStats( | 545 void AutocompleteController::UpdateAssistedQueryStats( |
| 545 AutocompleteResult* result) { | 546 AutocompleteResult* result) { |
| 546 if (result->empty()) | 547 if (result->empty()) |
| 547 return; | 548 return; |
| 548 | 549 |
| 549 // Build the impressions string (the AQS part after "."). | 550 // Build the impressions string (the AQS part after "."). |
| 550 std::string autocompletions; | 551 std::string autocompletions; |
| 551 int count = 0; | 552 int count = 0; |
| 552 size_t last_type = string16::npos; | 553 size_t last_type = base::string16::npos; |
| 553 size_t last_subtype = string16::npos; | 554 size_t last_subtype = base::string16::npos; |
| 554 for (ACMatches::iterator match(result->begin()); match != result->end(); | 555 for (ACMatches::iterator match(result->begin()); match != result->end(); |
| 555 ++match) { | 556 ++match) { |
| 556 size_t type = string16::npos; | 557 size_t type = base::string16::npos; |
| 557 size_t subtype = string16::npos; | 558 size_t subtype = base::string16::npos; |
| 558 AutocompleteMatchToAssistedQuery(match->type, &type, &subtype); | 559 AutocompleteMatchToAssistedQuery(match->type, &type, &subtype); |
| 559 if (last_type != string16::npos && | 560 if (last_type != base::string16::npos && |
| 560 (type != last_type || subtype != last_subtype)) { | 561 (type != last_type || subtype != last_subtype)) { |
| 561 AppendAvailableAutocompletion( | 562 AppendAvailableAutocompletion( |
| 562 last_type, last_subtype, count, &autocompletions); | 563 last_type, last_subtype, count, &autocompletions); |
| 563 count = 1; | 564 count = 1; |
| 564 } else { | 565 } else { |
| 565 count++; | 566 count++; |
| 566 } | 567 } |
| 567 last_type = type; | 568 last_type = type; |
| 568 last_subtype = subtype; | 569 last_subtype = subtype; |
| 569 } | 570 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 632 // the disruptive effect of belated omnibox updates, updates that | 633 // the disruptive effect of belated omnibox updates, updates that |
| 633 // come after the user has had to time to read the whole dropdown | 634 // come after the user has had to time to read the whole dropdown |
| 634 // and doesn't expect it to change. | 635 // and doesn't expect it to change. |
| 635 const int kStopTimeMS = 1500; | 636 const int kStopTimeMS = 1500; |
| 636 stop_timer_.Start(FROM_HERE, | 637 stop_timer_.Start(FROM_HERE, |
| 637 base::TimeDelta::FromMilliseconds(kStopTimeMS), | 638 base::TimeDelta::FromMilliseconds(kStopTimeMS), |
| 638 base::Bind(&AutocompleteController::Stop, | 639 base::Bind(&AutocompleteController::Stop, |
| 639 base::Unretained(this), | 640 base::Unretained(this), |
| 640 false)); | 641 false)); |
| 641 } | 642 } |
| OLD | NEW |