Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/history_url_provider.h" | 5 #include "chrome/browser/autocomplete/history_url_provider.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 if (what_you_typed_match.is_history_what_you_typed_match && | 238 if (what_you_typed_match.is_history_what_you_typed_match && |
| 239 (!backend || !params->dont_suggest_exact_input) && | 239 (!backend || !params->dont_suggest_exact_input) && |
| 240 FixupExactSuggestion(db, params->input, &what_you_typed_match, | 240 FixupExactSuggestion(db, params->input, &what_you_typed_match, |
| 241 &history_matches)) { | 241 &history_matches)) { |
| 242 // Got an exact match for the user's input. Treat it as the best match | 242 // Got an exact match for the user's input. Treat it as the best match |
| 243 // regardless of the input type. | 243 // regardless of the input type. |
| 244 exact_suggestion = 1; | 244 exact_suggestion = 1; |
| 245 params->matches.push_back(what_you_typed_match); | 245 params->matches.push_back(what_you_typed_match); |
| 246 } else if (params->prevent_inline_autocomplete || | 246 } else if (params->prevent_inline_autocomplete || |
| 247 history_matches.empty() || | 247 history_matches.empty() || |
| 248 !PromoteMatchForInlineAutocomplete(params, history_matches.front())) { | 248 !PromoteMatchForInlineAutocomplete(params, history_matches.front(), |
| 249 history_matches)) { | |
| 249 // Failed to promote any URLs for inline autocompletion. Use the What You | 250 // Failed to promote any URLs for inline autocompletion. Use the What You |
| 250 // Typed match, if we have it. | 251 // Typed match, if we have it. |
| 251 first_match = 0; | 252 first_match = 0; |
| 252 if (have_what_you_typed_match) | 253 if (have_what_you_typed_match) |
| 253 params->matches.push_back(what_you_typed_match); | 254 params->matches.push_back(what_you_typed_match); |
| 254 } | 255 } |
| 255 | 256 |
| 256 // This is the end of the synchronous pass. | 257 // This is the end of the synchronous pass. |
| 257 if (!backend) | 258 if (!backend) |
| 258 return; | 259 return; |
| 259 | 260 |
| 260 // Remove redirects and trim list to size. We want to provide up to | 261 // Remove redirects and trim list to size. We want to provide up to |
| 261 // kMaxMatches results plus the What You Typed result, if it was added to | 262 // kMaxMatches results plus the What You Typed result, if it was added to |
| 262 // |history_matches| above. | 263 // |history_matches| above. |
| 263 CullRedirects(backend, &history_matches, kMaxMatches + exact_suggestion); | 264 CullRedirects(backend, &history_matches, kMaxMatches + exact_suggestion); |
| 264 | 265 |
| 265 // Convert the history matches to autocomplete matches. | 266 // Convert the history matches to autocomplete matches. |
| 266 for (size_t i = first_match; i < history_matches.size(); ++i) { | 267 for (size_t i = first_match; i < history_matches.size(); ++i) { |
| 267 const HistoryMatch& match = history_matches[i]; | 268 const HistoryMatch& match = history_matches[i]; |
| 268 DCHECK(!have_what_you_typed_match || | 269 DCHECK(!have_what_you_typed_match || |
| 269 (match.url_info.url() != | 270 (match.url_info.url() != |
| 270 GURL(params->matches.front().destination_url))); | 271 GURL(params->matches.front().destination_url))); |
| 271 params->matches.push_back(HistoryMatchToACMatch(params, match, NORMAL, | 272 AutocompleteMatch ac_match = |
| 272 history_matches.size() - 1 - i)); | 273 HistoryMatchToACMatch(params, match, history_matches, NORMAL, |
| 274 history_matches.size() - 1 - i); | |
| 275 UMA_HISTOGRAM_COUNTS_100("Autocomplete.Confidence_HistoryUrl", | |
| 276 ac_match.confidence * 100); | |
| 277 params->matches.push_back(ac_match); | |
| 273 } | 278 } |
| 274 } | 279 } |
| 275 | 280 |
| 276 // Called on the main thread when the query is complete. | 281 // Called on the main thread when the query is complete. |
| 277 void HistoryURLProvider::QueryComplete( | 282 void HistoryURLProvider::QueryComplete( |
| 278 HistoryURLProviderParams* params_gets_deleted) { | 283 HistoryURLProviderParams* params_gets_deleted) { |
| 279 // Ensure |params_gets_deleted| gets deleted on exit. | 284 // Ensure |params_gets_deleted| gets deleted on exit. |
| 280 scoped_ptr<HistoryURLProviderParams> params(params_gets_deleted); | 285 scoped_ptr<HistoryURLProviderParams> params(params_gets_deleted); |
| 281 | 286 |
| 282 // If the user hasn't already started another query, clear our member pointer | 287 // If the user hasn't already started another query, clear our member pointer |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 295 UpdateStarredStateOfMatches(); | 300 UpdateStarredStateOfMatches(); |
| 296 } | 301 } |
| 297 | 302 |
| 298 done_ = true; | 303 done_ = true; |
| 299 listener_->OnProviderUpdate(true); | 304 listener_->OnProviderUpdate(true); |
| 300 } | 305 } |
| 301 | 306 |
| 302 AutocompleteMatch HistoryURLProvider::SuggestExactInput( | 307 AutocompleteMatch HistoryURLProvider::SuggestExactInput( |
| 303 const AutocompleteInput& input, | 308 const AutocompleteInput& input, |
| 304 bool trim_http) { | 309 bool trim_http) { |
| 310 // TODO(dominich): Find a confidence measure for this. | |
| 305 AutocompleteMatch match(this, | 311 AutocompleteMatch match(this, |
| 306 CalculateRelevance(input.type(), WHAT_YOU_TYPED, 0), false, | 312 CalculateRelevance(input.type(), WHAT_YOU_TYPED, 0), 0.0f, false, |
| 307 AutocompleteMatch::URL_WHAT_YOU_TYPED); | 313 AutocompleteMatch::URL_WHAT_YOU_TYPED); |
| 314 UMA_HISTOGRAM_COUNTS_100("Autocomplete.Confidence_HistoryUrl", | |
| 315 match.confidence * 100); | |
| 308 | 316 |
| 309 const GURL& url = input.canonicalized_url(); | 317 const GURL& url = input.canonicalized_url(); |
| 310 if (url.is_valid()) { | 318 if (url.is_valid()) { |
| 311 match.destination_url = url; | 319 match.destination_url = url; |
| 312 | 320 |
| 313 // Trim off "http://" if the user didn't type it. | 321 // Trim off "http://" if the user didn't type it. |
| 314 // NOTE: We use TrimHttpPrefix() here rather than StringForURLDisplay() to | 322 // NOTE: We use TrimHttpPrefix() here rather than StringForURLDisplay() to |
| 315 // strip the scheme as we need to know the offset so we can adjust the | 323 // strip the scheme as we need to know the offset so we can adjust the |
| 316 // |match_location| below. StringForURLDisplay() and TrimHttpPrefix() have | 324 // |match_location| below. StringForURLDisplay() and TrimHttpPrefix() have |
| 317 // slightly different behavior as well (the latter will strip even without | 325 // slightly different behavior as well (the latter will strip even without |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 404 // Promote as an exact match. | 412 // Promote as an exact match. |
| 405 match->relevance = CalculateRelevance(input.type(), type, 0); | 413 match->relevance = CalculateRelevance(input.type(), type, 0); |
| 406 | 414 |
| 407 // Put it on the front of the HistoryMatches for redirect culling. | 415 // Put it on the front of the HistoryMatches for redirect culling. |
| 408 EnsureMatchPresent(info, string16::npos, false, matches, true); | 416 EnsureMatchPresent(info, string16::npos, false, matches, true); |
| 409 return true; | 417 return true; |
| 410 } | 418 } |
| 411 | 419 |
| 412 bool HistoryURLProvider::PromoteMatchForInlineAutocomplete( | 420 bool HistoryURLProvider::PromoteMatchForInlineAutocomplete( |
| 413 HistoryURLProviderParams* params, | 421 HistoryURLProviderParams* params, |
| 414 const HistoryMatch& match) { | 422 const HistoryMatch& match, |
| 423 const HistoryMatches& matches) { | |
| 415 // Promote the first match if it's been typed at least n times, where n == 1 | 424 // Promote the first match if it's been typed at least n times, where n == 1 |
| 416 // for "simple" (host-only) URLs and n == 2 for others. We set a higher bar | 425 // for "simple" (host-only) URLs and n == 2 for others. We set a higher bar |
| 417 // for these long URLs because it's less likely that users will want to visit | 426 // for these long URLs because it's less likely that users will want to visit |
| 418 // them again. Even though we don't increment the typed_count for pasted-in | 427 // them again. Even though we don't increment the typed_count for pasted-in |
| 419 // URLs, if the user manually edits the URL or types some long thing in by | 428 // URLs, if the user manually edits the URL or types some long thing in by |
| 420 // hand, we wouldn't want to immediately start autocompleting it. | 429 // hand, we wouldn't want to immediately start autocompleting it. |
| 421 if (!match.url_info.typed_count() || | 430 if (!match.url_info.typed_count() || |
| 422 ((match.url_info.typed_count() == 1) && | 431 ((match.url_info.typed_count() == 1) && |
| 423 !history::IsHostOnly(match.url_info.url()))) | 432 !history::IsHostOnly(match.url_info.url()))) |
| 424 return false; | 433 return false; |
| 425 | 434 |
| 426 // In the case where the user has typed "foo.com" and visited (but not typed) | 435 // In the case where the user has typed "foo.com" and visited (but not typed) |
| 427 // "foo/", and the input is "foo", we can reach here for "foo.com" during the | 436 // "foo/", and the input is "foo", we can reach here for "foo.com" during the |
| 428 // first pass but have the second pass suggest the exact input as a better | 437 // first pass but have the second pass suggest the exact input as a better |
| 429 // URL. Since we need both passes to agree, and since during the first pass | 438 // URL. Since we need both passes to agree, and since during the first pass |
| 430 // there's no way to know about "foo/", make reaching this point prevent any | 439 // there's no way to know about "foo/", make reaching this point prevent any |
| 431 // future pass from suggesting the exact input as a better match. | 440 // future pass from suggesting the exact input as a better match. |
| 432 params->dont_suggest_exact_input = true; | 441 params->dont_suggest_exact_input = true; |
| 433 params->matches.push_back(HistoryMatchToACMatch(params, match, | 442 params->matches.push_back(HistoryMatchToACMatch(params, match, matches, |
| 434 INLINE_AUTOCOMPLETE, 0)); | 443 INLINE_AUTOCOMPLETE, 0)); |
| 435 return true; | 444 return true; |
| 436 } | 445 } |
| 437 | 446 |
| 438 HistoryURLProvider::~HistoryURLProvider() {} | 447 HistoryURLProvider::~HistoryURLProvider() {} |
| 439 | 448 |
| 440 // static | 449 // static |
| 441 history::Prefixes HistoryURLProvider::GetPrefixes() { | 450 history::Prefixes HistoryURLProvider::GetPrefixes() { |
| 442 // We'll complete text following these prefixes. | 451 // We'll complete text following these prefixes. |
| 443 // NOTE: There's no requirement that these be in any particular order. | 452 // NOTE: There's no requirement that these be in any particular order. |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 464 | 473 |
| 465 case WHAT_YOU_TYPED: | 474 case WHAT_YOU_TYPED: |
| 466 return 1200; | 475 return 1200; |
| 467 | 476 |
| 468 default: | 477 default: |
| 469 return 900 + static_cast<int>(match_number); | 478 return 900 + static_cast<int>(match_number); |
| 470 } | 479 } |
| 471 } | 480 } |
| 472 | 481 |
| 473 // static | 482 // static |
| 483 float HistoryURLProvider::CalculateConfidence( | |
| 484 const history::HistoryMatch& match, | |
| 485 const history::HistoryMatches& matches) { | |
|
mrossetti
2011/08/09 23:40:43
I think this should just be the precalculated sum
| |
| 486 // TODO(dominich): Take into account bookmarked page? | |
| 487 // TODO(dominich): See CompareHistoryMatch for more measures to include. | |
| 488 // Using typed count in place of visit count as: | |
| 489 // - It's a better indicator of what the user wants to open given that they | |
| 490 // are typing in the address bar (users tend to open certain URLs by typing | |
| 491 // and others by e.g. bookmarks, so visit_count is a good indicator of | |
| 492 // overall interest but a bad one for specifically omnibox interest). | |
| 493 // - Since the DB query is sorted by typed_count, the results may be | |
| 494 // effectively a random selection as far as visit_counts are concerned | |
| 495 // (meaning many high-visit_count-URLs may be present in one query and | |
| 496 // absent in a similar one), leading to wild swings in confidence for the | |
| 497 // same result across distinct queries. | |
| 498 float numerator = match.url_info.typed_count(); | |
| 499 float denominator = 0.0f; | |
| 500 for (history::HistoryMatches::const_iterator it = matches.begin(); | |
|
mrossetti
2011/08/09 23:40:43
Same thought as with the HistoryQuickProvider: why
dominich
2011/08/10 16:10:13
Once the algorithm for the calculation settles to
| |
| 501 it != matches.end(); ++it) { | |
| 502 denominator += it->url_info.typed_count(); | |
| 503 } | |
| 504 DCHECK(denominator > 0); | |
| 505 return numerator / denominator; | |
| 506 } | |
| 507 | |
| 508 // static | |
| 474 void HistoryURLProvider::PromoteOrCreateShorterSuggestion( | 509 void HistoryURLProvider::PromoteOrCreateShorterSuggestion( |
| 475 history::URLDatabase* db, | 510 history::URLDatabase* db, |
| 476 const HistoryURLProviderParams& params, | 511 const HistoryURLProviderParams& params, |
| 477 bool have_what_you_typed_match, | 512 bool have_what_you_typed_match, |
| 478 const AutocompleteMatch& what_you_typed_match, | 513 const AutocompleteMatch& what_you_typed_match, |
| 479 HistoryMatches* matches) { | 514 HistoryMatches* matches) { |
| 480 if (matches->empty()) | 515 if (matches->empty()) |
| 481 return; // No matches, nothing to do. | 516 return; // No matches, nothing to do. |
| 482 | 517 |
| 483 // Determine the base URL from which to search, and whether that URL could | 518 // Determine the base URL from which to search, and whether that URL could |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 767 next = matches->erase(next); | 802 next = matches->erase(next); |
| 768 if (static_cast<size_t>(next - matches->begin()) < next_index) | 803 if (static_cast<size_t>(next - matches->begin()) < next_index) |
| 769 next_index--; | 804 next_index--; |
| 770 } | 805 } |
| 771 return next_index; | 806 return next_index; |
| 772 } | 807 } |
| 773 | 808 |
| 774 AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch( | 809 AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch( |
| 775 HistoryURLProviderParams* params, | 810 HistoryURLProviderParams* params, |
| 776 const HistoryMatch& history_match, | 811 const HistoryMatch& history_match, |
| 812 const HistoryMatches& history_matches, | |
| 777 MatchType match_type, | 813 MatchType match_type, |
| 778 size_t match_number) { | 814 size_t match_number) { |
| 779 const history::URLRow& info = history_match.url_info; | 815 const history::URLRow& info = history_match.url_info; |
| 780 AutocompleteMatch match(this, | 816 AutocompleteMatch match(this, |
| 781 CalculateRelevance(params->input.type(), match_type, match_number), | 817 CalculateRelevance(params->input.type(), match_type, match_number), |
| 818 CalculateConfidence(history_match, history_matches), | |
| 782 !!info.visit_count(), AutocompleteMatch::HISTORY_URL); | 819 !!info.visit_count(), AutocompleteMatch::HISTORY_URL); |
| 783 match.destination_url = info.url(); | 820 match.destination_url = info.url(); |
| 784 DCHECK(match.destination_url.is_valid()); | 821 DCHECK(match.destination_url.is_valid()); |
| 785 size_t inline_autocomplete_offset = | 822 size_t inline_autocomplete_offset = |
| 786 history_match.input_location + params->input.text().length(); | 823 history_match.input_location + params->input.text().length(); |
| 787 std::string languages = (match_type == WHAT_YOU_TYPED) ? | 824 std::string languages = (match_type == WHAT_YOU_TYPED) ? |
| 788 std::string() : params->languages; | 825 std::string() : params->languages; |
| 789 const net::FormatUrlTypes format_types = net::kFormatUrlOmitAll & | 826 const net::FormatUrlTypes format_types = net::kFormatUrlOmitAll & |
| 790 ~((params->trim_http && !history_match.match_in_scheme) ? | 827 ~((params->trim_http && !history_match.match_in_scheme) ? |
| 791 0 : net::kFormatUrlOmitHTTP); | 828 0 : net::kFormatUrlOmitHTTP); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 815 &match.contents_class); | 852 &match.contents_class); |
| 816 } | 853 } |
| 817 match.description = info.title(); | 854 match.description = info.title(); |
| 818 AutocompleteMatch::ClassifyMatchInString(params->input.text(), | 855 AutocompleteMatch::ClassifyMatchInString(params->input.text(), |
| 819 info.title(), | 856 info.title(), |
| 820 ACMatchClassification::NONE, | 857 ACMatchClassification::NONE, |
| 821 &match.description_class); | 858 &match.description_class); |
| 822 | 859 |
| 823 return match; | 860 return match; |
| 824 } | 861 } |
| OLD | NEW |