Chromium Code Reviews| 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/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/bind.h" | 10 #include "base/bind.h" |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 #include "chrome/browser/profiles/profile.h" | 29 #include "chrome/browser/profiles/profile.h" |
| 30 #include "chrome/browser/search_engines/template_url_service.h" | 30 #include "chrome/browser/search_engines/template_url_service.h" |
| 31 #include "chrome/browser/search_engines/template_url_service_factory.h" | 31 #include "chrome/browser/search_engines/template_url_service_factory.h" |
| 32 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h" | 32 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h" |
| 33 #include "chrome/common/chrome_switches.h" | 33 #include "chrome/common/chrome_switches.h" |
| 34 #include "chrome/common/pref_names.h" | 34 #include "chrome/common/pref_names.h" |
| 35 #include "chrome/common/url_constants.h" | 35 #include "chrome/common/url_constants.h" |
| 36 #include "components/bookmarks/browser/bookmark_utils.h" | 36 #include "components/bookmarks/browser/bookmark_utils.h" |
| 37 #include "components/metrics/proto/omnibox_input_type.pb.h" | 37 #include "components/metrics/proto/omnibox_input_type.pb.h" |
| 38 #include "components/url_fixer/url_fixer.h" | 38 #include "components/url_fixer/url_fixer.h" |
| 39 #include "content/public/browser/browser_thread.h" | |
| 39 #include "net/base/net_util.h" | 40 #include "net/base/net_util.h" |
| 40 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 41 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 41 #include "url/gurl.h" | 42 #include "url/gurl.h" |
| 42 #include "url/url_parse.h" | 43 #include "url/url_parse.h" |
| 43 #include "url/url_util.h" | 44 #include "url/url_util.h" |
| 44 | 45 |
| 45 namespace { | 46 namespace { |
| 46 | 47 |
| 47 // Acts like the > operator for URLInfo classes. | 48 // Acts like the > operator for URLInfo classes. |
| 48 bool CompareHistoryMatch(const history::HistoryMatch& a, | 49 bool CompareHistoryMatch(const history::HistoryMatch& a, |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 221 // No entry, so create one. | 222 // No entry, so create one. |
| 222 history::HistoryMatch match(info, input_location, match_in_scheme, true); | 223 history::HistoryMatch match(info, input_location, match_in_scheme, true); |
| 223 if (promote) | 224 if (promote) |
| 224 matches->push_front(match); | 225 matches->push_front(match); |
| 225 else | 226 else |
| 226 matches->push_back(match); | 227 matches->push_back(match); |
| 227 | 228 |
| 228 return true; | 229 return true; |
| 229 } | 230 } |
| 230 | 231 |
| 232 // Returns whether |match| is suitable for inline autocompletion. | |
| 233 bool CanPromoteMatchForInlineAutocomplete(const history::HistoryMatch& match) { | |
| 234 // We can promote this match if it's been marked for promotion or typed at | |
| 235 // least n times, where n == 1 for "simple" (host-only) URLs and n == 2 for | |
| 236 // others. We set a higher bar for these long URLs because it's less likely | |
| 237 // that users will want to visit them again. Even though we don't increment | |
| 238 // the typed_count for pasted-in URLs, if the user manually edits the URL or | |
| 239 // types some long thing in by hand, we wouldn't want to immediately start | |
| 240 // autocompleting it. | |
| 241 return match.promoted || | |
| 242 (match.url_info.typed_count() && | |
| 243 ((match.url_info.typed_count() > 1) || match.IsHostOnly())); | |
| 244 } | |
| 245 | |
| 231 // Given the user's |input| and a |match| created from it, reduce the match's | 246 // Given the user's |input| and a |match| created from it, reduce the match's |
| 232 // URL to just a host. If this host still matches the user input, return it. | 247 // URL to just a host. If this host still matches the user input, return it. |
| 233 // Returns the empty string on failure. | 248 // Returns the empty string on failure. |
| 234 GURL ConvertToHostOnly(const history::HistoryMatch& match, | 249 GURL ConvertToHostOnly(const history::HistoryMatch& match, |
| 235 const base::string16& input) { | 250 const base::string16& input) { |
| 236 // See if we should try to do host-only suggestions for this URL. Nonstandard | 251 // See if we should try to do host-only suggestions for this URL. Nonstandard |
| 237 // schemes means there's no authority section, so suggesting the host name | 252 // schemes means there's no authority section, so suggesting the host name |
| 238 // is useless. File URLs are standard, but host suggestion is not useful for | 253 // is useless. File URLs are standard, but host suggestion is not useful for |
| 239 // them either. | 254 // them either. |
| 240 const GURL& url = match.url_info.url(); | 255 const GURL& url = match.url_info.url(); |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 384 // The user typed an intranet hostname that they've visited (albeit with a | 399 // The user typed an intranet hostname that they've visited (albeit with a |
| 385 // different port and/or path) before. | 400 // different port and/or path) before. |
| 386 url_row_ = history::URLRow(url); | 401 url_row_ = history::URLRow(url); |
| 387 type_ = UNVISITED_INTRANET; | 402 type_ = UNVISITED_INTRANET; |
| 388 } | 403 } |
| 389 } | 404 } |
| 390 | 405 |
| 391 HistoryURLProviderParams::HistoryURLProviderParams( | 406 HistoryURLProviderParams::HistoryURLProviderParams( |
| 392 const AutocompleteInput& input, | 407 const AutocompleteInput& input, |
| 393 bool trim_http, | 408 bool trim_http, |
| 409 const AutocompleteMatch& what_you_typed_match, | |
| 394 const std::string& languages, | 410 const std::string& languages, |
| 395 TemplateURL* default_search_provider, | 411 TemplateURL* default_search_provider, |
| 396 const SearchTermsData& search_terms_data) | 412 const SearchTermsData& search_terms_data) |
| 397 : message_loop(base::MessageLoop::current()), | 413 : message_loop(base::MessageLoop::current()), |
| 398 input(input), | 414 input(input), |
| 399 prevent_inline_autocomplete(input.prevent_inline_autocomplete()), | 415 prevent_inline_autocomplete(input.prevent_inline_autocomplete()), |
| 400 trim_http(trim_http), | 416 trim_http(trim_http), |
| 417 what_you_typed_match(what_you_typed_match), | |
| 401 failed(false), | 418 failed(false), |
| 402 languages(languages), | 419 languages(languages), |
| 403 dont_suggest_exact_input(false), | 420 dont_suggest_exact_input(false), |
| 404 default_search_provider(default_search_provider ? | 421 default_search_provider(default_search_provider ? |
| 405 new TemplateURL(default_search_provider->profile(), | 422 new TemplateURL(default_search_provider->profile(), |
| 406 default_search_provider->data()) : NULL), | 423 default_search_provider->data()) : NULL), |
| 407 search_terms_data(new SearchTermsDataSnapshot(search_terms_data)) { | 424 search_terms_data(new SearchTermsDataSnapshot(search_terms_data)) { |
| 408 } | 425 } |
| 409 | 426 |
| 410 HistoryURLProviderParams::~HistoryURLProviderParams() { | 427 HistoryURLProviderParams::~HistoryURLProviderParams() { |
| 411 } | 428 } |
| 412 | 429 |
| 413 HistoryURLProvider::HistoryURLProvider(AutocompleteProviderListener* listener, | 430 HistoryURLProvider::HistoryURLProvider(AutocompleteProviderListener* listener, |
| 414 Profile* profile) | 431 Profile* profile) |
| 415 : HistoryProvider(listener, profile, | 432 : HistoryProvider(listener, profile, |
| 416 AutocompleteProvider::TYPE_HISTORY_URL), | 433 AutocompleteProvider::TYPE_HISTORY_URL), |
| 417 params_(NULL), | 434 params_(NULL), |
| 418 cull_redirects_( | 435 cull_redirects_( |
| 419 !OmniboxFieldTrial::InHUPCullRedirectsFieldTrial() || | 436 !OmniboxFieldTrial::InHUPCullRedirectsFieldTrial() || |
| 420 !OmniboxFieldTrial::InHUPCullRedirectsFieldTrialExperimentGroup()), | 437 !OmniboxFieldTrial::InHUPCullRedirectsFieldTrialExperimentGroup()), |
| 421 create_shorter_match_( | 438 create_shorter_match_( |
| 422 !OmniboxFieldTrial::InHUPCreateShorterMatchFieldTrial() || | 439 !OmniboxFieldTrial::InHUPCreateShorterMatchFieldTrial() || |
| 423 !OmniboxFieldTrial:: | 440 !OmniboxFieldTrial:: |
| 424 InHUPCreateShorterMatchFieldTrialExperimentGroup()) { | 441 InHUPCreateShorterMatchFieldTrialExperimentGroup()) { |
| 425 // Initialize HUP scoring params based on the current experiment. | 442 // Initialize HUP scoring params based on the current experiment. |
| 426 OmniboxFieldTrial::GetExperimentalHUPScoringParams(&scoring_params_); | 443 OmniboxFieldTrial::GetExperimentalHUPScoringParams(&scoring_params_); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 439 | 456 |
| 440 // Cancel any in-progress query. | 457 // Cancel any in-progress query. |
| 441 Stop(false); | 458 Stop(false); |
| 442 | 459 |
| 443 matches_.clear(); | 460 matches_.clear(); |
| 444 | 461 |
| 445 if ((input.type() == metrics::OmniboxInputType::INVALID) || | 462 if ((input.type() == metrics::OmniboxInputType::INVALID) || |
| 446 (input.type() == metrics::OmniboxInputType::FORCED_QUERY)) | 463 (input.type() == metrics::OmniboxInputType::FORCED_QUERY)) |
| 447 return; | 464 return; |
| 448 | 465 |
| 449 // Create a match for exactly what the user typed. This will only be used as | 466 // Do some fixup on the user input before matching against it, so we provide |
| 450 // a fallback in case we can't get the history service or URL DB; otherwise, | 467 // good results for local file paths, input with spaces, etc. |
| 451 // we'll run this again in DoAutocomplete() and use that result instead. | 468 const FixupReturn fixup_return(FixupUserInput(input)); |
| 469 if (!fixup_return.first) | |
| 470 return; | |
|
Mark P
2014/06/17 17:43:25
This makes me nervous. Previously we'd create a a
Peter Kasting
2014/06/17 20:39:47
It wasn't conscious. The two pieces were written
Mark P
2014/06/17 21:35:35
Good point.
| |
| 471 url::Parsed parts; | |
| 472 url_fixer::SegmentURL(fixup_return.second, &parts); | |
| 473 AutocompleteInput fixed_up_input(input); | |
| 474 fixed_up_input.UpdateText(fixup_return.second, base::string16::npos, parts); | |
| 475 | |
| 476 // Create a match for what the user typed. | |
| 452 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()); | 477 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()); |
| 453 // Don't do this for queries -- while we can sometimes mark up a match for | 478 AutocompleteMatch what_you_typed_match(SuggestExactInput( |
| 454 // this, it's not what the user wants, and just adds noise. | 479 fixed_up_input.text(), fixed_up_input.canonicalized_url(), trim_http)); |
| 455 if (input.type() != metrics::OmniboxInputType::QUERY) { | 480 what_you_typed_match.relevance = CalculateRelevance(WHAT_YOU_TYPED, 0); |
| 456 AutocompleteMatch what_you_typed(SuggestExactInput( | 481 |
| 457 input.text(), input.canonicalized_url(), trim_http)); | 482 // Add the WYT match as a fallback in case we can't get the history service or |
| 458 what_you_typed.relevance = CalculateRelevance(WHAT_YOU_TYPED, 0); | 483 // URL DB; otherwise, we'll replace this match lower down. Don't do this for |
| 459 matches_.push_back(what_you_typed); | 484 // queries, though -- while we can sometimes mark up a match for them, it's |
| 460 } | 485 // not what the user wants, and just adds noise. |
| 486 if (fixed_up_input.type() != metrics::OmniboxInputType::QUERY) | |
| 487 matches_.push_back(what_you_typed_match); | |
| 461 | 488 |
| 462 // We'll need the history service to run both passes, so try to obtain it. | 489 // We'll need the history service to run both passes, so try to obtain it. |
| 463 if (!profile_) | 490 if (!profile_) |
| 464 return; | 491 return; |
| 465 HistoryService* const history_service = | 492 HistoryService* const history_service = |
| 466 HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); | 493 HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); |
| 467 if (!history_service) | 494 if (!history_service) |
| 468 return; | 495 return; |
| 469 | 496 |
| 470 // Get the default search provider and search terms data now since we have to | 497 // Get the default search provider and search terms data now since we have to |
| 471 // retrieve these on the UI thread, and the second pass runs on the history | 498 // retrieve these on the UI thread, and the second pass runs on the history |
| 472 // thread. |template_url_service| can be NULL when testing. | 499 // thread. |template_url_service| can be NULL when testing. |
| 473 TemplateURLService* template_url_service = | 500 TemplateURLService* template_url_service = |
| 474 TemplateURLServiceFactory::GetForProfile(profile_); | 501 TemplateURLServiceFactory::GetForProfile(profile_); |
| 475 TemplateURL* default_search_provider = template_url_service ? | 502 TemplateURL* default_search_provider = template_url_service ? |
| 476 template_url_service->GetDefaultSearchProvider() : NULL; | 503 template_url_service->GetDefaultSearchProvider() : NULL; |
| 477 UIThreadSearchTermsData data(profile_); | 504 UIThreadSearchTermsData data(profile_); |
| 478 | 505 |
| 479 // Do some fixup on the user input before matching against it, so we provide | |
| 480 // good results for local file paths, input with spaces, etc. | |
| 481 const FixupReturn fixup_return(FixupUserInput(input)); | |
| 482 if (!fixup_return.first) | |
| 483 return; | |
| 484 url::Parsed parts; | |
| 485 url_fixer::SegmentURL(fixup_return.second, &parts); | |
| 486 AutocompleteInput fixed_up_input(input); | |
| 487 fixed_up_input.UpdateText(fixup_return.second, base::string16::npos, parts); | |
| 488 | |
| 489 // Create the data structure for the autocomplete passes. We'll save this off | 506 // Create the data structure for the autocomplete passes. We'll save this off |
| 490 // onto the |params_| member for later deletion below if we need to run pass | 507 // onto the |params_| member for later deletion below if we need to run pass |
| 491 // 2. | 508 // 2. |
| 492 scoped_ptr<HistoryURLProviderParams> params( | 509 scoped_ptr<HistoryURLProviderParams> params( |
| 493 new HistoryURLProviderParams( | 510 new HistoryURLProviderParams( |
| 494 fixed_up_input, trim_http, | 511 fixed_up_input, trim_http, what_you_typed_match, |
| 495 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), | 512 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), |
| 496 default_search_provider, data)); | 513 default_search_provider, data)); |
| 497 // Note that we use the non-fixed-up input here, since fixup may strip | 514 // Note that we use the non-fixed-up input here, since fixup may strip |
| 498 // trailing whitespace. | 515 // trailing whitespace. |
| 499 params->prevent_inline_autocomplete = PreventInlineAutocomplete(input); | 516 params->prevent_inline_autocomplete = PreventInlineAutocomplete(input); |
| 500 | 517 |
| 501 // Pass 1: Get the in-memory URL database, and use it to find and promote | 518 // Pass 1: Get the in-memory URL database, and use it to find and promote |
| 502 // the inline autocomplete match, if any. | 519 // the inline autocomplete match, if any. |
| 503 history::URLDatabase* url_db = history_service->InMemoryDatabase(); | 520 history::URLDatabase* url_db = history_service->InMemoryDatabase(); |
| 504 // url_db can be NULL if it hasn't finished initializing (or failed to | 521 // url_db can be NULL if it hasn't finished initializing (or failed to |
| 505 // initialize). In this case all we can do is fall back on the second | 522 // initialize). In this case all we can do is fall back on the second |
| 506 // pass. | 523 // pass. |
| 507 // | 524 // |
| 508 // TODO(pkasting): We should just block here until this loads. Any time | 525 // TODO(pkasting): We should just block here until this loads. Any time |
| 509 // someone unloads the history backend, we'll get inconsistent inline | 526 // someone unloads the history backend, we'll get inconsistent inline |
| 510 // autocomplete behavior here. | 527 // autocomplete behavior here. |
| 511 if (url_db) { | 528 if (url_db) { |
| 512 DoAutocomplete(NULL, url_db, params.get()); | 529 DoAutocomplete(NULL, url_db, params.get()); |
| 513 // params->matches now has the matches we should expose to the provider. | 530 // params->matches now has the matches we should expose to the provider. |
| 514 // Pass 2 expects a "clean slate" set of matches. | 531 // Pass 2 expects a "clean slate" set of matches. |
| 515 matches_.clear(); | 532 matches_.clear(); |
| 516 matches_.swap(params->matches); | 533 matches_.swap(params->matches); |
| 517 UpdateStarredStateOfMatches(); | 534 UpdateStarredStateOfMatches(); |
| 535 params->what_you_typed_match = what_you_typed_match; | |
|
Mark P
2014/06/17 17:43:25
I don't understand why this is necessary. Didn't
Peter Kasting
2014/06/17 20:39:48
Running an autocomplete pass changes the What You
Mark P
2014/06/17 21:35:35
This is not an obvious side effect of DoAutocomple
| |
| 518 } | 536 } |
| 519 | 537 |
| 520 // Pass 2: Ask the history service to call us back on the history thread, | 538 // Pass 2: Ask the history service to call us back on the history thread, |
| 521 // where we can read the full on-disk DB. | 539 // where we can read the full on-disk DB. |
| 522 if (input.want_asynchronous_matches()) { | 540 if (input.want_asynchronous_matches()) { |
| 523 done_ = false; | 541 done_ = false; |
| 524 params_ = params.release(); // This object will be destroyed in | 542 params_ = params.release(); // This object will be destroyed in |
| 525 // QueryComplete() once we're done with it. | 543 // QueryComplete() once we're done with it. |
| 526 history_service->ScheduleAutocomplete(this, params_); | 544 history_service->ScheduleAutocomplete(this, params_); |
| 527 } | 545 } |
| 528 } | 546 } |
| 529 | 547 |
| 530 void HistoryURLProvider::Stop(bool clear_cached_results) { | 548 void HistoryURLProvider::Stop(bool clear_cached_results) { |
| 531 done_ = true; | 549 done_ = true; |
| 532 | 550 |
| 533 if (params_) | 551 if (params_) |
| 534 params_->cancel_flag.Set(); | 552 params_->cancel_flag.Set(); |
| 535 } | 553 } |
| 536 | 554 |
| 537 AutocompleteMatch HistoryURLProvider::SuggestExactInput( | 555 AutocompleteMatch HistoryURLProvider::SuggestExactInput( |
| 538 const base::string16& text, | 556 const base::string16& text, |
| 539 const GURL& destination_url, | 557 const GURL& destination_url, |
| 540 bool trim_http) { | 558 bool trim_http) { |
| 559 // The FormattedStringWithEquivalentMeaning() call below requires callers to | |
| 560 // be on the UI thread. | |
| 561 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI) || | |
| 562 !content::BrowserThread::IsMessageLoopValid(content::BrowserThread::UI)); | |
|
Mark P
2014/06/17 17:43:25
elsewhere we usually use
IsThreadInitialized
rathe
Peter Kasting
2014/06/17 20:39:47
Done.
| |
| 563 | |
| 541 AutocompleteMatch match(this, 0, false, | 564 AutocompleteMatch match(this, 0, false, |
| 542 AutocompleteMatchType::URL_WHAT_YOU_TYPED); | 565 AutocompleteMatchType::URL_WHAT_YOU_TYPED); |
| 543 | 566 |
| 544 if (destination_url.is_valid()) { | 567 if (destination_url.is_valid()) { |
| 545 match.destination_url = destination_url; | 568 match.destination_url = destination_url; |
| 546 | 569 |
| 547 // Trim off "http://" if the user didn't type it. | 570 // Trim off "http://" if the user didn't type it. |
| 548 // NOTE: We use TrimHttpPrefix() here rather than StringForURLDisplay() to | 571 // NOTE: We use TrimHttpPrefix() here rather than StringForURLDisplay() to |
| 549 // strip the scheme as we need to know the offset so we can adjust the | 572 // strip the scheme as we need to know the offset so we can adjust the |
| 550 // |match_location| below. StringForURLDisplay() and TrimHttpPrefix() have | 573 // |match_location| below. StringForURLDisplay() and TrimHttpPrefix() have |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 656 history::ScoredHistoryMatch::FilterTermMatchesByWordStarts( | 679 history::ScoredHistoryMatch::FilterTermMatchesByWordStarts( |
| 657 description_matches, offsets, description_word_starts, 0, | 680 description_matches, offsets, description_word_starts, 0, |
| 658 std::string::npos); | 681 std::string::npos); |
| 659 return SpansFromTermMatch( | 682 return SpansFromTermMatch( |
| 660 description_matches, clean_description.length(), false); | 683 description_matches, clean_description.length(), false); |
| 661 } | 684 } |
| 662 | 685 |
| 663 void HistoryURLProvider::DoAutocomplete(history::HistoryBackend* backend, | 686 void HistoryURLProvider::DoAutocomplete(history::HistoryBackend* backend, |
| 664 history::URLDatabase* db, | 687 history::URLDatabase* db, |
| 665 HistoryURLProviderParams* params) { | 688 HistoryURLProviderParams* params) { |
| 666 VisitClassifier classifier(this, params->input, db); | 689 // Get the matching URLs from the DB. |
| 667 // Create a What You Typed match, which we'll need below. | |
| 668 // | |
| 669 // We display this to the user when there's a reasonable chance they actually | |
| 670 // care: | |
| 671 // * Their input can be opened as a URL, and | |
| 672 // * We parsed the input as a URL, or it starts with an explicit "http:" or | |
| 673 // "https:". | |
| 674 // that is when their input can be opened as a URL. | |
| 675 // Otherwise, this is just low-quality noise. In the cases where we've parsed | |
| 676 // as UNKNOWN, we'll still show an accidental search infobar if need be. | |
| 677 bool have_what_you_typed_match = | |
| 678 (params->input.type() != metrics::OmniboxInputType::QUERY) && | |
| 679 ((params->input.type() != metrics::OmniboxInputType::UNKNOWN) || | |
| 680 (classifier.type() == VisitClassifier::UNVISITED_INTRANET) || | |
| 681 !params->trim_http || | |
| 682 (AutocompleteInput::NumNonHostComponents(params->input.parts()) > 0)); | |
| 683 AutocompleteMatch what_you_typed_match(SuggestExactInput( | |
| 684 params->input.text(), params->input.canonicalized_url(), | |
| 685 params->trim_http)); | |
| 686 what_you_typed_match.relevance = CalculateRelevance(WHAT_YOU_TYPED, 0); | |
| 687 | |
| 688 // Get the matching URLs from the DB | |
| 689 history::URLRows url_matches; | 690 history::URLRows url_matches; |
| 690 history::HistoryMatches history_matches; | 691 history::HistoryMatches history_matches; |
| 691 | 692 |
| 692 const URLPrefixes& prefixes = URLPrefix::GetURLPrefixes(); | 693 const URLPrefixes& prefixes = URLPrefix::GetURLPrefixes(); |
| 693 for (URLPrefixes::const_iterator i(prefixes.begin()); i != prefixes.end(); | 694 for (URLPrefixes::const_iterator i(prefixes.begin()); i != prefixes.end(); |
| 694 ++i) { | 695 ++i) { |
| 695 if (params->cancel_flag.IsSet()) | 696 if (params->cancel_flag.IsSet()) |
| 696 return; // Canceled in the middle of a query, give up. | 697 return; // Canceled in the middle of a query, give up. |
| 698 | |
| 697 // We only need kMaxMatches results in the end, but before we get there we | 699 // We only need kMaxMatches results in the end, but before we get there we |
| 698 // need to promote lower-quality matches that are prefixes of higher-quality | 700 // need to promote lower-quality matches that are prefixes of higher-quality |
| 699 // matches, and remove lower-quality redirects. So we ask for more results | 701 // matches, and remove lower-quality redirects. So we ask for more results |
| 700 // than we need, of every prefix type, in hopes this will give us far more | 702 // than we need, of every prefix type, in hopes this will give us far more |
| 701 // than enough to work with. CullRedirects() will then reduce the list to | 703 // than enough to work with. CullRedirects() will then reduce the list to |
| 702 // the best kMaxMatches results. | 704 // the best kMaxMatches results. |
| 703 db->AutocompleteForPrefix( | 705 db->AutocompleteForPrefix( |
| 704 base::UTF16ToUTF8(i->prefix + params->input.text()), | 706 base::UTF16ToUTF8(i->prefix + params->input.text()), kMaxMatches * 2, |
| 705 kMaxMatches * 2, | 707 !backend, &url_matches); |
| 706 (backend == NULL), | |
| 707 &url_matches); | |
| 708 for (history::URLRows::const_iterator j(url_matches.begin()); | 708 for (history::URLRows::const_iterator j(url_matches.begin()); |
| 709 j != url_matches.end(); ++j) { | 709 j != url_matches.end(); ++j) { |
| 710 const URLPrefix* best_prefix = | 710 const URLPrefix* best_prefix = URLPrefix::BestURLPrefix( |
| 711 URLPrefix::BestURLPrefix(base::UTF8ToUTF16(j->url().spec()), | 711 base::UTF8ToUTF16(j->url().spec()), base::string16()); |
| 712 base::string16()); | 712 DCHECK(best_prefix); |
| 713 DCHECK(best_prefix != NULL); | 713 history_matches.push_back(history::HistoryMatch( |
| 714 history_matches.push_back(history::HistoryMatch(*j, i->prefix.length(), | 714 *j, i->prefix.length(), !i->num_components, |
| 715 i->num_components == 0, | |
| 716 i->num_components >= best_prefix->num_components)); | 715 i->num_components >= best_prefix->num_components)); |
| 717 } | 716 } |
| 718 } | 717 } |
| 719 | 718 |
| 720 // Create sorted list of suggestions. | 719 // Create sorted list of suggestions. |
| 721 CullPoorMatches(*params, &history_matches); | 720 CullPoorMatches(*params, &history_matches); |
| 722 SortAndDedupMatches(&history_matches); | 721 SortAndDedupMatches(&history_matches); |
| 722 | |
| 723 // Try to create a shorter suggestion from the best match. | |
| 724 // We allow the what you typed match to be displayed when there's a reasonable | |
| 725 // chance the user actually cares: | |
| 726 // * Their input can be opened as a URL, and | |
| 727 // * We parsed the input as a URL, or it starts with an explicit "http:" or | |
| 728 // "https:". | |
| 729 // Otherwise, this is just low-quality noise. In the cases where we've parsed | |
| 730 // as UNKNOWN, we'll still show an accidental search infobar if need be. | |
| 731 VisitClassifier classifier(this, params->input, db); | |
| 732 bool have_what_you_typed_match = | |
| 733 (params->input.type() != metrics::OmniboxInputType::QUERY) && | |
| 734 ((params->input.type() != metrics::OmniboxInputType::UNKNOWN) || | |
| 735 (classifier.type() == VisitClassifier::UNVISITED_INTRANET) || | |
| 736 !params->trim_http || | |
| 737 (AutocompleteInput::NumNonHostComponents(params->input.parts()) > 0)); | |
| 723 PromoteOrCreateShorterSuggestion(db, *params, have_what_you_typed_match, | 738 PromoteOrCreateShorterSuggestion(db, *params, have_what_you_typed_match, |
| 724 what_you_typed_match, &history_matches); | 739 &history_matches); |
| 725 | 740 |
| 726 // Try to promote a match as an exact/inline autocomplete match. This also | 741 // Try to promote a match as an exact/inline autocomplete match. This also |
| 727 // moves it to the front of |history_matches|, so skip over it when | 742 // moves it to the front of |history_matches|, so skip over it when |
| 728 // converting the rest of the matches. | 743 // converting the rest of the matches. |
| 729 size_t first_match = 1; | 744 size_t first_match = 1; |
| 730 size_t exact_suggestion = 0; | 745 size_t exact_suggestion = 0; |
| 731 // Checking |is_history_what_you_typed_match| tells us whether | 746 // Checking params->what_you_typed_match.is_history_what_you_typed_match tells |
| 732 // SuggestExactInput() succeeded in constructing a valid match. | 747 // us whether SuggestExactInput() succeeded in constructing a valid match. |
| 733 if (what_you_typed_match.is_history_what_you_typed_match && | 748 if (params->what_you_typed_match.is_history_what_you_typed_match && |
| 734 (!backend || !params->dont_suggest_exact_input) && | 749 (!backend || !params->dont_suggest_exact_input) && |
| 735 FixupExactSuggestion(db, params->input, classifier, &what_you_typed_match, | 750 FixupExactSuggestion(db, classifier, params, &history_matches)) { |
| 736 &history_matches)) { | |
| 737 // Got an exact match for the user's input. Treat it as the best match | 751 // Got an exact match for the user's input. Treat it as the best match |
| 738 // regardless of the input type. | 752 // regardless of the input type. |
| 739 exact_suggestion = 1; | 753 exact_suggestion = 1; |
| 740 params->matches.push_back(what_you_typed_match); | 754 params->matches.push_back(params->what_you_typed_match); |
| 741 } else if (params->prevent_inline_autocomplete || | 755 } else if (params->prevent_inline_autocomplete || |
| 742 history_matches.empty() || | 756 history_matches.empty() || |
| 743 !PromoteMatchForInlineAutocomplete(history_matches.front(), params)) { | 757 !PromoteMatchForInlineAutocomplete(history_matches.front(), params)) { |
| 744 // Failed to promote any URLs for inline autocompletion. Use the What You | 758 // Failed to promote any URLs for inline autocompletion. Use the What You |
| 745 // Typed match, if we have it. | 759 // Typed match, if we have it. |
| 746 first_match = 0; | 760 first_match = 0; |
| 747 if (have_what_you_typed_match) | 761 if (have_what_you_typed_match) |
| 748 params->matches.push_back(what_you_typed_match); | 762 params->matches.push_back(params->what_you_typed_match); |
| 749 } | 763 } |
| 750 | 764 |
| 751 // This is the end of the synchronous pass. | 765 // This is the end of the synchronous pass. |
| 752 if (!backend) | 766 if (!backend) |
| 753 return; | 767 return; |
| 754 | 768 |
| 755 // Determine relevancy of highest scoring match, if any. | 769 // Determine relevancy of highest scoring match, if any. |
| 756 int relevance = -1; | 770 int relevance = -1; |
| 757 for (ACMatches::const_iterator it = params->matches.begin(); | 771 for (ACMatches::const_iterator it = params->matches.begin(); |
| 758 it != params->matches.end(); ++it) { | 772 it != params->matches.end(); ++it) { |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 787 // The experimental scoring must not change the top result's score. | 801 // The experimental scoring must not change the top result's score. |
| 788 if (!params->matches.empty()) { | 802 if (!params->matches.empty()) { |
| 789 relevance = CalculateRelevanceScoreUsingScoringParams(match, relevance, | 803 relevance = CalculateRelevanceScoreUsingScoringParams(match, relevance, |
| 790 scoring_params_); | 804 scoring_params_); |
| 791 ac_match.relevance = relevance; | 805 ac_match.relevance = relevance; |
| 792 } | 806 } |
| 793 params->matches.push_back(ac_match); | 807 params->matches.push_back(ac_match); |
| 794 } | 808 } |
| 795 } | 809 } |
| 796 | 810 |
| 797 // Called on the main thread when the query is complete. | |
|
Mark P
2014/06/17 17:43:25
Is this incorrect? Why did you remove it?
Peter Kasting
2014/06/17 20:39:47
This comment is already present in the header.
| |
| 798 void HistoryURLProvider::QueryComplete( | 811 void HistoryURLProvider::QueryComplete( |
| 799 HistoryURLProviderParams* params_gets_deleted) { | 812 HistoryURLProviderParams* params_gets_deleted) { |
| 800 // Ensure |params_gets_deleted| gets deleted on exit. | 813 // Ensure |params_gets_deleted| gets deleted on exit. |
| 801 scoped_ptr<HistoryURLProviderParams> params(params_gets_deleted); | 814 scoped_ptr<HistoryURLProviderParams> params(params_gets_deleted); |
| 802 | 815 |
| 803 // If the user hasn't already started another query, clear our member pointer | 816 // If the user hasn't already started another query, clear our member pointer |
| 804 // so we can't write into deleted memory. | 817 // so we can't write into deleted memory. |
| 805 if (params_ == params_gets_deleted) | 818 if (params_ == params_gets_deleted) |
| 806 params_ = NULL; | 819 params_ = NULL; |
| 807 | 820 |
| 808 // Don't send responses for queries that have been canceled. | 821 // Don't send responses for queries that have been canceled. |
| 809 if (params->cancel_flag.IsSet()) | 822 if (params->cancel_flag.IsSet()) |
| 810 return; // Already set done_ when we canceled, no need to set it again. | 823 return; // Already set done_ when we canceled, no need to set it again. |
| 811 | 824 |
| 812 // Don't modify |matches_| if the query failed, since it might have a default | 825 // Don't modify |matches_| if the query failed, since it might have a default |
| 813 // match in it, whereas |params->matches| will be empty. | 826 // match in it, whereas |params->matches| will be empty. |
| 814 if (!params->failed) { | 827 if (!params->failed) { |
| 815 matches_.swap(params->matches); | 828 matches_.swap(params->matches); |
| 816 UpdateStarredStateOfMatches(); | 829 UpdateStarredStateOfMatches(); |
| 817 } | 830 } |
| 818 | 831 |
| 819 done_ = true; | 832 done_ = true; |
| 820 listener_->OnProviderUpdate(true); | 833 listener_->OnProviderUpdate(true); |
| 821 } | 834 } |
| 822 | 835 |
| 823 bool HistoryURLProvider::FixupExactSuggestion( | 836 bool HistoryURLProvider::FixupExactSuggestion( |
| 824 history::URLDatabase* db, | 837 history::URLDatabase* db, |
| 825 const AutocompleteInput& input, | |
| 826 const VisitClassifier& classifier, | 838 const VisitClassifier& classifier, |
| 827 AutocompleteMatch* match, | 839 HistoryURLProviderParams* params, |
| 828 history::HistoryMatches* matches) const { | 840 history::HistoryMatches* matches) const { |
| 829 DCHECK(match != NULL); | |
| 830 DCHECK(matches != NULL); | 841 DCHECK(matches != NULL); |
|
Mark P
2014/06/17 17:43:25
Perhaps DCHECK(params!=NULL)
Peter Kasting
2014/06/17 20:39:48
I could, but I don't think it adds much. I intend
| |
| 831 | 842 |
| 832 MatchType type = INLINE_AUTOCOMPLETE; | 843 MatchType type = INLINE_AUTOCOMPLETE; |
| 833 switch (classifier.type()) { | 844 switch (classifier.type()) { |
| 834 case VisitClassifier::INVALID: | 845 case VisitClassifier::INVALID: |
| 835 return false; | 846 return false; |
| 836 case VisitClassifier::UNVISITED_INTRANET: | 847 case VisitClassifier::UNVISITED_INTRANET: |
| 837 type = UNVISITED_INTRANET; | 848 type = UNVISITED_INTRANET; |
| 838 break; | 849 break; |
| 839 default: | 850 default: |
| 840 DCHECK_EQ(VisitClassifier::VISITED, classifier.type()); | 851 DCHECK_EQ(VisitClassifier::VISITED, classifier.type()); |
| 841 // We have data for this match, use it. | 852 // We have data for this match, use it. |
| 842 match->deletable = true; | 853 params->what_you_typed_match.deletable = true; |
| 843 match->description = classifier.url_row().title(); | 854 params->what_you_typed_match.description = classifier.url_row().title(); |
| 844 RecordAdditionalInfoFromUrlRow(classifier.url_row(), match); | 855 RecordAdditionalInfoFromUrlRow(classifier.url_row(), |
| 845 match->description_class = | 856 ¶ms->what_you_typed_match); |
| 846 ClassifyDescription(input.text(), match->description); | 857 params->what_you_typed_match.description_class = ClassifyDescription( |
| 858 params->input.text(), params->what_you_typed_match.description); | |
| 847 if (!classifier.url_row().typed_count()) { | 859 if (!classifier.url_row().typed_count()) { |
| 848 // If we reach here, we must be in the second pass, and we must not have | 860 // If we reach here, we must be in the second pass, and we must not have |
| 849 // this row's data available during the first pass. That means we | 861 // this row's data available during the first pass. That means we |
| 850 // either scored it as WHAT_YOU_TYPED or UNVISITED_INTRANET, and to | 862 // either scored it as WHAT_YOU_TYPED or UNVISITED_INTRANET, and to |
| 851 // maintain the ordering between passes consistent, we need to score it | 863 // maintain the ordering between passes consistent, we need to score it |
| 852 // the same way here. | 864 // the same way here. |
| 853 type = CanFindIntranetURL(db, input) ? | 865 type = CanFindIntranetURL(db, params->input) ? |
| 854 UNVISITED_INTRANET : WHAT_YOU_TYPED; | 866 UNVISITED_INTRANET : WHAT_YOU_TYPED; |
| 855 } | 867 } |
| 856 break; | 868 break; |
| 857 } | 869 } |
| 858 | 870 |
| 859 const GURL& url = match->destination_url; | 871 const GURL& url = params->what_you_typed_match.destination_url; |
| 860 const url::Parsed& parsed = url.parsed_for_possibly_invalid_spec(); | 872 const url::Parsed& parsed = url.parsed_for_possibly_invalid_spec(); |
| 861 // If the what-you-typed result looks like a single word (which can be | 873 // If the what-you-typed result looks like a single word (which can be |
| 862 // interpreted as an intranet address) followed by a pound sign ("#"), | 874 // interpreted as an intranet address) followed by a pound sign ("#"), |
| 863 // leave the score for the url-what-you-typed result as is. It will be | 875 // leave the score for the url-what-you-typed result as is. It will be |
| 864 // outscored by a search query from the SearchProvider. This test fixes | 876 // outscored by a search query from the SearchProvider. This test fixes |
| 865 // cases such as "c#" and "c# foo" where the user has visited an intranet | 877 // cases such as "c#" and "c# foo" where the user has visited an intranet |
| 866 // site "c". We want the search-what-you-typed score to beat the | 878 // site "c". We want the search-what-you-typed score to beat the |
| 867 // URL-what-you-typed score in this case. Most of the below test tries to | 879 // URL-what-you-typed score in this case. Most of the below test tries to |
| 868 // make sure that this code does not trigger if the user did anything to | 880 // make sure that this code does not trigger if the user did anything to |
| 869 // indicate the desired match is a URL. For instance, "c/# foo" will not | 881 // indicate the desired match is a URL. For instance, "c/# foo" will not |
| 870 // pass the test because that will be classified as input type URL. The | 882 // pass the test because that will be classified as input type URL. The |
| 871 // parsed.CountCharactersBefore() in the test looks for the presence of a | 883 // parsed.CountCharactersBefore() in the test looks for the presence of a |
| 872 // reference fragment in the URL by checking whether the position differs | 884 // reference fragment in the URL by checking whether the position differs |
| 873 // included the delimiter (pound sign) versus not including the delimiter. | 885 // included the delimiter (pound sign) versus not including the delimiter. |
| 874 // (One cannot simply check url.ref() because it will not distinguish | 886 // (One cannot simply check url.ref() because it will not distinguish |
| 875 // between the input "c" and the input "c#", both of which will have empty | 887 // between the input "c" and the input "c#", both of which will have empty |
| 876 // reference fragments.) | 888 // reference fragments.) |
| 877 if ((type == UNVISITED_INTRANET) && | 889 if ((type == UNVISITED_INTRANET) && |
| 878 (input.type() != metrics::OmniboxInputType::URL) && | 890 (params->input.type() != metrics::OmniboxInputType::URL) && |
| 879 url.username().empty() && url.password().empty() && url.port().empty() && | 891 url.username().empty() && url.password().empty() && url.port().empty() && |
| 880 (url.path() == "/") && url.query().empty() && | 892 (url.path() == "/") && url.query().empty() && |
| 881 (parsed.CountCharactersBefore(url::Parsed::REF, true) != | 893 (parsed.CountCharactersBefore(url::Parsed::REF, true) != |
| 882 parsed.CountCharactersBefore(url::Parsed::REF, false))) { | 894 parsed.CountCharactersBefore(url::Parsed::REF, false))) { |
| 883 return false; | 895 return false; |
| 884 } | 896 } |
| 885 | 897 |
| 886 match->relevance = CalculateRelevance(type, 0); | 898 params->what_you_typed_match.relevance = CalculateRelevance(type, 0); |
| 887 | 899 |
| 888 // If there are any other matches, then don't promote this match here, in | 900 // If there are any other matches, then don't promote this match here, in |
| 889 // hopes the caller will be able to inline autocomplete a better suggestion. | 901 // hopes the caller will be able to inline autocomplete a better suggestion. |
| 890 // DoAutocomplete() will fall back on this match if inline autocompletion | 902 // DoAutocomplete() will fall back on this match if inline autocompletion |
| 891 // fails. This matches how we react to never-visited URL inputs in the non- | 903 // fails. This matches how we react to never-visited URL inputs in the non- |
| 892 // intranet case. | 904 // intranet case. |
| 893 if (type == UNVISITED_INTRANET && !matches->empty()) | 905 if (type == UNVISITED_INTRANET && !matches->empty()) |
| 894 return false; | 906 return false; |
| 895 | 907 |
| 896 // Put it on the front of the HistoryMatches for redirect culling. | 908 // Put it on the front of the HistoryMatches for redirect culling. |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 916 net::registry_controlled_domains::GetRegistryLength( | 928 net::registry_controlled_domains::GetRegistryLength( |
| 917 host, | 929 host, |
| 918 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, | 930 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, |
| 919 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); | 931 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); |
| 920 return registry_length == 0 && db->IsTypedHost(host); | 932 return registry_length == 0 && db->IsTypedHost(host); |
| 921 } | 933 } |
| 922 | 934 |
| 923 bool HistoryURLProvider::PromoteMatchForInlineAutocomplete( | 935 bool HistoryURLProvider::PromoteMatchForInlineAutocomplete( |
| 924 const history::HistoryMatch& match, | 936 const history::HistoryMatch& match, |
| 925 HistoryURLProviderParams* params) { | 937 HistoryURLProviderParams* params) { |
| 926 // Promote the first match if it's been marked for promotion or typed at least | 938 if (!CanPromoteMatchForInlineAutocomplete(match)) |
| 927 // n times, where n == 1 for "simple" (host-only) URLs and n == 2 for others. | |
| 928 // We set a higher bar for these long URLs because it's less likely that users | |
| 929 // will want to visit them again. Even though we don't increment the | |
| 930 // typed_count for pasted-in URLs, if the user manually edits the URL or types | |
| 931 // some long thing in by hand, we wouldn't want to immediately start | |
| 932 // autocompleting it. | |
| 933 if (!match.promoted && | |
| 934 (!match.url_info.typed_count() || | |
| 935 ((match.url_info.typed_count() == 1) && | |
| 936 !match.IsHostOnly()))) | |
| 937 return false; | 939 return false; |
| 938 | 940 |
| 939 // In the case where the user has typed "foo.com" and visited (but not typed) | 941 // In the case where the user has typed "foo.com" and visited (but not typed) |
| 940 // "foo/", and the input is "foo", we can reach here for "foo.com" during the | 942 // "foo/", and the input is "foo", we can reach here for "foo.com" during the |
| 941 // first pass but have the second pass suggest the exact input as a better | 943 // first pass but have the second pass suggest the exact input as a better |
| 942 // URL. Since we need both passes to agree, and since during the first pass | 944 // URL. Since we need both passes to agree, and since during the first pass |
| 943 // there's no way to know about "foo/", make reaching this point prevent any | 945 // there's no way to know about "foo/", make reaching this point prevent any |
| 944 // future pass from suggesting the exact input as a better match. | 946 // future pass from suggesting the exact input as a better match. |
| 945 if (params) { | 947 params->dont_suggest_exact_input = true; |
| 946 params->dont_suggest_exact_input = true; | 948 params->matches.push_back(HistoryMatchToACMatch( |
| 947 AutocompleteMatch ac_match = HistoryMatchToACMatch( | 949 *params, match, INLINE_AUTOCOMPLETE, |
| 948 *params, match, INLINE_AUTOCOMPLETE, | 950 CalculateRelevance(INLINE_AUTOCOMPLETE, 0))); |
| 949 CalculateRelevance(INLINE_AUTOCOMPLETE, 0)); | |
| 950 params->matches.push_back(ac_match); | |
| 951 } | |
| 952 return true; | 951 return true; |
| 953 } | 952 } |
| 954 | 953 |
| 955 // See if a shorter version of the best match should be created, and if so place | |
| 956 // it at the front of |matches|. This can suggest history URLs that are | |
| 957 // prefixes of the best match (if they've been visited enough, compared to the | |
| 958 // best match), or create host-only suggestions even when they haven't been | |
| 959 // visited before: if the user visited http://example.com/asdf once, we'll | |
| 960 // suggest http://example.com/ even if they've never been to it. | |
| 961 void HistoryURLProvider::PromoteOrCreateShorterSuggestion( | 954 void HistoryURLProvider::PromoteOrCreateShorterSuggestion( |
| 962 history::URLDatabase* db, | 955 history::URLDatabase* db, |
| 963 const HistoryURLProviderParams& params, | 956 const HistoryURLProviderParams& params, |
| 964 bool have_what_you_typed_match, | 957 bool have_what_you_typed_match, |
| 965 const AutocompleteMatch& what_you_typed_match, | |
| 966 history::HistoryMatches* matches) { | 958 history::HistoryMatches* matches) { |
| 967 if (matches->empty()) | 959 if (matches->empty()) |
| 968 return; // No matches, nothing to do. | 960 return; // No matches, nothing to do. |
| 969 | 961 |
| 970 // Determine the base URL from which to search, and whether that URL could | 962 // Determine the base URL from which to search, and whether that URL could |
| 971 // itself be added as a match. We can add the base iff it's not "effectively | 963 // itself be added as a match. We can add the base iff it's not "effectively |
| 972 // the same" as any "what you typed" match. | 964 // the same" as any "what you typed" match. |
| 973 const history::HistoryMatch& match = matches->front(); | 965 const history::HistoryMatch& match = matches->front(); |
| 974 GURL search_base = ConvertToHostOnly(match, params.input.text()); | 966 GURL search_base = ConvertToHostOnly(match, params.input.text()); |
| 975 bool can_add_search_base_to_matches = !have_what_you_typed_match; | 967 bool can_add_search_base_to_matches = !have_what_you_typed_match; |
| 976 if (search_base.is_empty()) { | 968 if (search_base.is_empty()) { |
| 977 // Search from what the user typed when we couldn't reduce the best match | 969 // Search from what the user typed when we couldn't reduce the best match |
| 978 // to a host. Careful: use a substring of |match| here, rather than the | 970 // to a host. Careful: use a substring of |match| here, rather than the |
| 979 // first match in |params|, because they might have different prefixes. If | 971 // first match in |params|, because they might have different prefixes. If |
| 980 // the user typed "google.com", |what_you_typed_match| will hold | 972 // the user typed "google.com", params->what_you_typed_match will hold |
| 981 // "http://google.com/", but |match| might begin with | 973 // "http://google.com/", but |match| might begin with |
| 982 // "http://www.google.com/". | 974 // "http://www.google.com/". |
| 983 // TODO: this should be cleaned up, and is probably incorrect for IDN. | 975 // TODO: this should be cleaned up, and is probably incorrect for IDN. |
| 984 std::string new_match = match.url_info.url().possibly_invalid_spec(). | 976 std::string new_match = match.url_info.url().possibly_invalid_spec(). |
| 985 substr(0, match.input_location + params.input.text().length()); | 977 substr(0, match.input_location + params.input.text().length()); |
| 986 search_base = GURL(new_match); | 978 search_base = GURL(new_match); |
| 987 // TODO(mrossetti): There is a degenerate case where the following may | |
| 988 // cause a failure: http://www/~someword/fubar.html. Diagnose. | |
| 989 // See: http://crbug.com/50101 | |
| 990 if (search_base.is_empty()) | 979 if (search_base.is_empty()) |
| 991 return; // Can't construct a valid URL from which to start a search. | 980 return; // Can't construct a valid URL from which to start a search. |
| 992 } else if (!can_add_search_base_to_matches) { | 981 } else if (!can_add_search_base_to_matches) { |
| 993 can_add_search_base_to_matches = | 982 can_add_search_base_to_matches = |
| 994 (search_base != what_you_typed_match.destination_url); | 983 (search_base != params.what_you_typed_match.destination_url); |
| 995 } | 984 } |
| 996 if (search_base == match.url_info.url()) | 985 if (search_base == match.url_info.url()) |
| 997 return; // Couldn't shorten |match|, so no range of URLs to search over. | 986 return; // Couldn't shorten |match|, so no range of URLs to search over. |
| 998 | 987 |
| 999 // Search the DB for short URLs between our base and |match|. | 988 // Search the DB for short URLs between our base and |match|. |
| 1000 history::URLRow info(search_base); | 989 history::URLRow info(search_base); |
| 1001 bool promote = true; | 990 bool promote = true; |
| 1002 // A short URL is only worth suggesting if it's been visited at least a third | 991 // A short URL is only worth suggesting if it's been visited at least a third |
| 1003 // as often as the longer URL. | 992 // as often as the longer URL. |
| 1004 const int min_visit_count = ((match.url_info.visit_count() - 1) / 3) + 1; | 993 const int min_visit_count = ((match.url_info.visit_count() - 1) / 3) + 1; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1016 return; // Couldn't find anything and can't add the search base, bail. | 1005 return; // Couldn't find anything and can't add the search base, bail. |
| 1017 | 1006 |
| 1018 // Try to get info on the search base itself. Promote it to the top if the | 1007 // Try to get info on the search base itself. Promote it to the top if the |
| 1019 // original best match isn't good enough to autocomplete. | 1008 // original best match isn't good enough to autocomplete. |
| 1020 db->GetRowForURL(search_base, &info); | 1009 db->GetRowForURL(search_base, &info); |
| 1021 promote = match.url_info.typed_count() <= 1; | 1010 promote = match.url_info.typed_count() <= 1; |
| 1022 } | 1011 } |
| 1023 | 1012 |
| 1024 // Promote or add the desired URL to the list of matches. | 1013 // Promote or add the desired URL to the list of matches. |
| 1025 bool ensure_can_inline = | 1014 bool ensure_can_inline = |
| 1026 promote && PromoteMatchForInlineAutocomplete(match, NULL); | 1015 promote && CanPromoteMatchForInlineAutocomplete(match); |
| 1027 ensure_can_inline &= CreateOrPromoteMatch(info, match.input_location, | 1016 ensure_can_inline &= CreateOrPromoteMatch(info, match.input_location, |
| 1028 match.match_in_scheme, matches, create_shorter_match_, promote); | 1017 match.match_in_scheme, matches, create_shorter_match_, promote); |
| 1029 if (ensure_can_inline) | 1018 if (ensure_can_inline) |
| 1030 matches->front().promoted = true; | 1019 matches->front().promoted = true; |
| 1031 } | 1020 } |
| 1032 | 1021 |
| 1033 void HistoryURLProvider::CullPoorMatches( | 1022 void HistoryURLProvider::CullPoorMatches( |
| 1034 const HistoryURLProviderParams& params, | 1023 const HistoryURLProviderParams& params, |
| 1035 history::HistoryMatches* matches) const { | 1024 history::HistoryMatches* matches) const { |
| 1036 const base::Time& threshold(history::AutocompleteAgeThreshold()); | 1025 const base::Time& threshold(history::AutocompleteAgeThreshold()); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1156 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, | 1145 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, |
| 1157 match.contents.length(), ACMatchClassification::URL, | 1146 match.contents.length(), ACMatchClassification::URL, |
| 1158 &match.contents_class); | 1147 &match.contents_class); |
| 1159 } | 1148 } |
| 1160 match.description = info.title(); | 1149 match.description = info.title(); |
| 1161 match.description_class = | 1150 match.description_class = |
| 1162 ClassifyDescription(params.input.text(), match.description); | 1151 ClassifyDescription(params.input.text(), match.description); |
| 1163 RecordAdditionalInfoFromUrlRow(info, &match); | 1152 RecordAdditionalInfoFromUrlRow(info, &match); |
| 1164 return match; | 1153 return match; |
| 1165 } | 1154 } |
| OLD | NEW |