1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/autocomplete.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/basictypes.h" 103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/command_line.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/number_formatting.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/metrics/histogram.h" 133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h" 16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/autocomplete/autocomplete_controller_delegate.h" 17513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/autocomplete/autocomplete_match.h" 18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/autocomplete/builtin_provider.h" 19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/autocomplete/extension_app_provider.h" 20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/autocomplete/history_contents_provider.h" 213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/autocomplete/history_quick_provider.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/history_url_provider.h" 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/keyword_provider.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/search_provider.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_model.h" 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/external_protocol_handler.h" 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/url_fixer_upper.h" 283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h" 2921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/webui/history_ui.h" 313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/chrome_switches.h" 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h" 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h" 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h" 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/url_canon_ip.h" 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/url_util.h" 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h" 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h" 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/registry_controlled_domain.h" 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request.h" 4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta; 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteInput ---------------------------------------------------------- 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteInput::AutocompleteInput() 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : type_(INVALID), 51201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch initial_prevent_inline_autocomplete_(false), 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prevent_inline_autocomplete_(false), 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefer_keyword_(false), 544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch allow_exact_keyword_match_(true), 55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen matches_requested_(ALL_MATCHES) { 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenAutocompleteInput::AutocompleteInput(const string16& text, 5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& desired_tld, 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool prevent_inline_autocomplete, 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool prefer_keyword, 624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch bool allow_exact_keyword_match, 63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MatchesRequested matches_requested) 6472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : original_text_(text), 6572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen desired_tld_(desired_tld), 66201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch initial_prevent_inline_autocomplete_(prevent_inline_autocomplete), 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prevent_inline_autocomplete_(prevent_inline_autocomplete), 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefer_keyword_(prefer_keyword), 694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch allow_exact_keyword_match_(allow_exact_keyword_match), 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen matches_requested_(matches_requested) { 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Trim whitespace from edges of input; don't inline autocomplete if there 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // was trailing whitespace. 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (TrimWhitespace(text, TRIM_ALL, &text_) & TRIM_TRAILING) 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prevent_inline_autocomplete_ = true; 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen GURL canonicalized_url; 7721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen type_ = Parse(text_, desired_tld, &parts_, &scheme_, &canonicalized_url); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type_ == INVALID) 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 8221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (((type_ == UNKNOWN) || (type_ == REQUESTED_URL) || (type_ == URL)) && 8321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen canonicalized_url.is_valid() && 8421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen (!canonicalized_url.IsStandard() || canonicalized_url.SchemeIsFile() || 8521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen !canonicalized_url.host().empty())) 8621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen canonicalized_url_ = canonicalized_url; 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 88201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch RemoveForcedQueryStringIfNecessary(type_, &text_); 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteInput::~AutocompleteInput() { 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 95201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid AutocompleteInput::RemoveForcedQueryStringIfNecessary(Type type, 9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16* text) { 97201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if (type == FORCED_QUERY && !text->empty() && (*text)[0] == L'?') 98201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch text->erase(0, 1); 99201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch} 100201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 101201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// static 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string AutocompleteInput::TypeToString(Type type) { 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (type) { 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case INVALID: return "invalid"; 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case UNKNOWN: return "unknown"; 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case REQUESTED_URL: return "requested-url"; 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case URL: return "url"; 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case QUERY: return "query"; 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case FORCED_QUERY: return "forced-query"; 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return std::string(); 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteInput::Type AutocompleteInput::Parse( 11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& text, 12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& desired_tld, 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_parse::Parsed* parts, 12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16* scheme, 12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen GURL* canonicalized_url) { 12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const size_t first_non_white = text.find_first_not_of(kWhitespaceUTF16, 0); 12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (first_non_white == string16::npos) 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return INVALID; // All whitespace. 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (text.at(first_non_white) == L'?') { 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the first non-whitespace character is a '?', we magically treat this 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // as a query. 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FORCED_QUERY; 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ask our parsing back-end to help us understand what the user typed. We 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // use the URLFixerUpper here because we want to be smart about what we 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // consider a scheme. For example, we shouldn't consider www.google.com:80 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to have a scheme. 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_parse::Parsed local_parts; 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!parts) 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parts = &local_parts; 14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16 parsed_scheme(URLFixerUpper::SegmentURL(text, parts)); 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (scheme) 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *scheme = parsed_scheme; 14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (canonicalized_url) { 14572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *canonicalized_url = URLFixerUpper::FixupURL(UTF16ToUTF8(text), 14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UTF16ToUTF8(desired_tld)); 14721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (LowerCaseEqualsASCII(parsed_scheme, chrome::kFileScheme)) { 1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // A user might or might not type a scheme when entering a file URL. In 1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // either case, |parsed_scheme| will tell us that this is a file URL, but 1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |parts->scheme| might be empty, e.g. if the user typed "C:\foo". 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return URL; 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the user typed a scheme, and it's HTTP or HTTPS, we know how to parse it 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // well enough that we can fall through to the heuristics below. If it's 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // something else, we can just determine our action based on what we do with 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // any input of this scheme. In theory we could do better with some schemes 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (e.g. "ftp" or "view-source") but I'll wait to spend the effort on that 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // until I run into some cases that really need it. 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (parts->scheme.is_nonempty() && 16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen !LowerCaseEqualsASCII(parsed_scheme, chrome::kHttpScheme) && 16472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen !LowerCaseEqualsASCII(parsed_scheme, chrome::kHttpsScheme)) { 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See if we know how to handle the URL internally. 16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (net::URLRequest::IsHandledProtocol(UTF16ToASCII(parsed_scheme))) 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return URL; 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // There are also some schemes that we convert to other things before they 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // reach the renderer or else the renderer handles internally without 17121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // reaching the net::URLRequest logic. We thus won't catch these above, but 17221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // we should still claim to handle them. 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (LowerCaseEqualsASCII(parsed_scheme, chrome::kViewSourceScheme) || 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LowerCaseEqualsASCII(parsed_scheme, chrome::kJavaScriptScheme) || 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LowerCaseEqualsASCII(parsed_scheme, chrome::kDataScheme)) 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return URL; 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Finally, check and see if the user has explicitly opened this scheme as 17921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // a URL before, or if the "scheme" is actually a username. We need to do 18021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // this last because some schemes (e.g. "javascript") may be treated as 18121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // "blocked" by the external protocol handler because we don't want pages to 18221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // open them, but users still can. 1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // TODO(viettrungluu): get rid of conversion. 18472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ExternalProtocolHandler::BlockState block_state = 18572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ExternalProtocolHandler::GetBlockState(UTF16ToUTF8(parsed_scheme)); 18672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen switch (block_state) { 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case ExternalProtocolHandler::DONT_BLOCK: 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return URL; 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case ExternalProtocolHandler::BLOCK: 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we don't want the user to open the URL, don't let it be navigated 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to at all. 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return QUERY; 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 19521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen default: { 19621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // We don't know about this scheme. It might be that the user typed a 19721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // URL of the form "username:password@foo.com". 19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16 http_scheme_prefix = 19972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASCIIToUTF16(std::string(chrome::kHttpScheme) + 20072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen chrome::kStandardSchemeSeparator); 20121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen url_parse::Parsed http_parts; 20272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16 http_scheme; 20321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen GURL http_canonicalized_url; 20421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen Type http_type = Parse(http_scheme_prefix + text, desired_tld, 20521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &http_parts, &http_scheme, 20621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &http_canonicalized_url); 20772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DCHECK_EQ(std::string(chrome::kHttpScheme), UTF16ToUTF8(http_scheme)); 20821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 20921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if ((http_type == URL || http_type == REQUESTED_URL) && 21021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen http_parts.username.is_nonempty() && 21121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen http_parts.password.is_nonempty()) { 21221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Manually re-jigger the parsed parts to match |text| (without the 21321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // http scheme added). 21421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen http_parts.scheme.reset(); 21521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen url_parse::Component* components[] = { 21621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &http_parts.username, 21721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &http_parts.password, 21821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &http_parts.host, 21921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &http_parts.port, 22021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &http_parts.path, 22121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &http_parts.query, 22221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &http_parts.ref, 22321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen }; 22421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen for (size_t i = 0; i < arraysize(components); ++i) { 22521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen URLFixerUpper::OffsetComponent( 22621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen -static_cast<int>(http_scheme_prefix.size()), components[i]); 22721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 22821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 22921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen *parts = http_parts; 23021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (scheme) 23121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen scheme->clear(); 23221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (canonicalized_url) 23321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen *canonicalized_url = http_canonicalized_url; 23421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 23521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return http_type; 23621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 23721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 23821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // We don't know about this scheme and it doesn't look like the user 23921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // typed a username and password. It's likely to be a search operator 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // like "site:" or "link:". We classify it as UNKNOWN so the user has 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the option of treating it as a URL if we're wrong. 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Note that SegmentURL() is smart so we aren't tricked by "c:\foo" or 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // "www.example.com:81" in this case. 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return UNKNOWN; 24521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Either the user didn't type a scheme, in which case we need to distinguish 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // between an HTTP URL and a query, or the scheme is HTTP or HTTPS, in which 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // case we should reject invalid formulations. 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we have an empty host it can't be a URL. 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!parts->host.is_nonempty()) 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return QUERY; 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Likewise, the RCDS can reject certain obviously-invalid hosts. (We also 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // use the registry length later below.) 25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16 host(text.substr(parts->host.begin, parts->host.len)); 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const size_t registry_length = 26172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen net::RegistryControlledDomainService::GetRegistryLength(UTF16ToUTF8(host), 26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen false); 26372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (registry_length == std::string::npos) { 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Try to append the desired_tld. 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!desired_tld.empty()) { 26672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16 host_with_tld(host); 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (host[host.length() - 1] != '.') 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host_with_tld += '.'; 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host_with_tld += desired_tld; 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (net::RegistryControlledDomainService::GetRegistryLength( 27172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UTF16ToUTF8(host_with_tld), false) != std::string::npos) 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return REQUESTED_URL; // Something like "99999999999" that looks like a 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // bad IP address, but becomes valid on attaching 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a TLD. 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return QUERY; // Could be a broken IP address, etc. 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See if the hostname is valid. While IE and GURL allow hostnames to contain 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // many other characters (perhaps for weird intranet machines), it's extremely 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // unlikely that a user would be trying to type those in for anything other 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // than a search query. 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_canon::CanonHostInfo host_info; 28572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::string canonicalized_host(net::CanonicalizeHost(UTF16ToUTF8(host), 28672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen &host_info)); 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((host_info.family == url_canon::CanonHostInfo::NEUTRAL) && 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !net::IsCanonicalizedHostCompliant(canonicalized_host, 28972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UTF16ToUTF8(desired_tld))) { 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Invalid hostname. There are several possible cases: 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * Our checker is too strict and the user pasted in a real-world URL 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // that's "invalid" but resolves. To catch these, we return UNKNOWN when 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the user explicitly typed a scheme, so we'll still search by default 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // but we'll show the accidental search infobar if necessary. 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * The user is typing a multi-word query. If we see a space anywhere in 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the hostname we assume this is a search and return QUERY. 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * Our checker is too strict and the user is typing a real-world hostname 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // that's "invalid" but resolves. We return UNKNOWN if the TLD is known. 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Note that we explicitly excluded hosts with spaces above so that 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // "toys at amazon.com" will be treated as a search. 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * The user is typing some garbage string. Return QUERY. 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Thus we fall down in the following cases: 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * Trying to navigate to a hostname with spaces 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * Trying to navigate to a hostname with invalid characters and an unknown 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TLD 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // These are rare, though probably possible in intranets. 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return (parts->scheme.is_nonempty() || 30972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ((registry_length != 0) && (host.find(' ') == string16::npos))) ? 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UNKNOWN : QUERY; 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // A port number is a good indicator that this is a URL. However, it might 3143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // also be a query like "1.66:1" that looks kind of like an IP address and 3153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // port number. So here we only check for "port numbers" that are illegal and 3163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // thus mean this can't be navigated to (e.g. "1.2.3.4:garbage"), and we save 3173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // handling legal port numbers until after the "IP address" determination 3183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // below. 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (parts->port.is_nonempty()) { 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int port; 32172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!base::StringToInt(text.substr(parts->port.begin, parts->port.len), 32272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen &port) || 3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (port < 0) || (port > 65535)) 3243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return QUERY; 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Now that we've ruled out all schemes other than http or https and done a 3283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // little more sanity checking, the presence of a scheme means this is likely 3293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // a URL. 3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (parts->scheme.is_nonempty()) 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return URL; 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See if the host is an IP address. 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (host_info.family == url_canon::CanonHostInfo::IPV4) { 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the user originally typed a host that looks like an IP address (a 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // dotted quad), they probably want to open it. If the original input was 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // something else (like a single number), they probably wanted to search for 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // it, unless they explicitly typed a scheme. This is true even if the URL 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // appears to have a path: "1.2/45" is more likely a search (for the answer 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to a math problem) than a URL. 3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (host_info.num_ipv4_components == 4) 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return URL; 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return desired_tld.empty() ? UNKNOWN : REQUESTED_URL; 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (host_info.family == url_canon::CanonHostInfo::IPV6) 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return URL; 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Now that we've ruled out invalid ports and queries that look like they have 3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // a port, the presence of a port means this is likely a URL. 3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (parts->port.is_nonempty()) 3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return URL; 3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Presence of a password means this is likely a URL. Note that unless the 3543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // user has typed an explicit "http://" or similar, we'll probably think that 3553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // the username is some unknown scheme, and bail out in the scheme-handling 3563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // code above. 3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (parts->password.is_nonempty()) 3583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return URL; 3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The host doesn't look like a number, so see if the user's given us a path. 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (parts->path.is_nonempty()) { 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Most inputs with paths are URLs, even ones without known registries (e.g. 3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // intranet URLs). However, if there's no known registry and the path has 3643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // a space, this is more likely a query with a slash in the first term 3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // (e.g. "ps/2 games") than a URL. We can still open URLs with spaces in 3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // the path by escaping the space, and we will still inline autocomplete 3673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // them if users have typed them in the past, but we default to searching 3683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // since that's the common case. 3693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return ((registry_length == 0) && 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (text.substr(parts->path.begin, parts->path.len).find(' ') != 37172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16::npos)) ? UNKNOWN : URL; 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If we reach here with a username, our input looks like "user@host". 3753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Because there is no scheme explicitly specified, we think this is more 3763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // likely an email address than an HTTP auth attempt. Hence, we search by 3773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // default and let users correct us on a case-by-case basis. 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (parts->username.is_nonempty()) 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return UNKNOWN; 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We have a bare host string. If it has a known TLD, it's probably a URL. 3823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (registry_length != 0) 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return URL; 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // No TLD that we know about. This could be: 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * A string that the user wishes to add a desired_tld to to get a URL. If 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we reach this point, we know there's no known TLD on the string, so the 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // fixup code will be willing to add one; thus this is a URL. 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * A single word "foo"; possibly an intranet site, but more likely a search. 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This is ideally an UNKNOWN, and we can let the Alternate Nav URL code 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // catch our mistakes. 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * A URL with a valid TLD we don't know about yet. If e.g. a registrar adds 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // "xxx" as a TLD, then until we add it to our data file, Chrome won't know 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // "foo.xxx" is a real URL. So ideally this is a URL, but we can't really 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // distinguish this case from: 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // * A "URL-like" string that's not really a URL (like 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // "browser.tabs.closeButtons" or "java.awt.event.*"). This is ideally a 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // QUERY. Since the above case and this one are indistinguishable, and this 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // case is likely to be much more common, just say these are both UNKNOWN, 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // which should default to the right thing and let users correct us on a 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // case-by-case basis. 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return desired_tld.empty() ? UNKNOWN : REQUESTED_URL; 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteInput::ParseForEmphasizeComponents( 40772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& text, 40872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& desired_tld, 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_parse::Component* scheme, 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_parse::Component* host) { 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_parse::Parsed parts; 41272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16 scheme_str; 41321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen Parse(text, desired_tld, &parts, &scheme_str, NULL); 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *scheme = parts.scheme; 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *host = parts.host; 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int after_scheme_and_colon = parts.scheme.end() + 1; 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For the view-source scheme, we should emphasize the scheme and host of the 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // URL qualified by the view-source prefix. 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (LowerCaseEqualsASCII(scheme_str, chrome::kViewSourceScheme) && 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (static_cast<int>(text.length()) > after_scheme_and_colon)) { 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Obtain the URL prefixed by view-source and parse it. 42472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16 real_url(text.substr(after_scheme_and_colon)); 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_parse::Parsed real_parts; 42621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen AutocompleteInput::Parse(real_url, desired_tld, &real_parts, NULL, NULL); 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (real_parts.scheme.is_nonempty() || real_parts.host.is_nonempty()) { 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (real_parts.scheme.is_nonempty()) { 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *scheme = url_parse::Component( 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch after_scheme_and_colon + real_parts.scheme.begin, 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch real_parts.scheme.len); 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scheme->reset(); 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (real_parts.host.is_nonempty()) { 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *host = url_parse::Component( 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch after_scheme_and_colon + real_parts.host.begin, 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch real_parts.host.len); 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host->reset(); 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 44772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstring16 AutocompleteInput::FormattedStringWithEquivalentMeaning( 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& url, 44972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& formatted_url) { 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!net::CanStripTrailingSlash(url)) 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return formatted_url; 45272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16 url_with_path(formatted_url + char16('/')); 45372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return (AutocompleteInput::Parse(formatted_url, string16(), NULL, NULL, 45421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen NULL) == 45572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen AutocompleteInput::Parse(url_with_path, string16(), NULL, NULL, 45621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen NULL)) ? 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch formatted_url : url_with_path; 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteInput::Equals(const AutocompleteInput& other) const { 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return (text_ == other.text_) && 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (type_ == other.type_) && 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (desired_tld_ == other.desired_tld_) && 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (scheme_ == other.scheme_) && 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (prevent_inline_autocomplete_ == other.prevent_inline_autocomplete_) && 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (prefer_keyword_ == other.prefer_keyword_) && 468ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (matches_requested_ == other.matches_requested_); 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteInput::Clear() { 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch text_.clear(); 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_ = INVALID; 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parts_ = url_parse::Parsed(); 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scheme_.clear(); 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch desired_tld_.clear(); 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prevent_inline_autocomplete_ = false; 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefer_keyword_ = false; 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteProvider ------------------------------------------------------- 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst size_t AutocompleteProvider::kMaxMatches = 3; 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteProvider::ACProviderListener::~ACProviderListener() { 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteProvider::AutocompleteProvider(ACProviderListener* listener, 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Profile* profile, 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const char* name) 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : profile_(profile), 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch listener_(listener), 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch done_(true), 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name_(name) { 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteProvider::SetProfile(Profile* profile) { 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(profile); 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(done_); // The controller should have already stopped us. 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_ = profile; 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteProvider::Stop() { 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch done_ = true; 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteProvider::DeleteMatch(const AutocompleteMatch& match) { 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteProvider::~AutocompleteProvider() { 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Stop(); 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 51672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool AutocompleteProvider::HasHTTPScheme(const string16& input) { 51772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string utf8_input(UTF16ToUTF8(input)); 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_parse::Component scheme; 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (url_util::FindAndCompareScheme(utf8_input, chrome::kViewSourceScheme, 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &scheme)) 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch utf8_input.erase(0, scheme.end() + 1); 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return url_util::FindAndCompareScheme(utf8_input, chrome::kHttpScheme, NULL); 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteProvider::UpdateStarredStateOfMatches() { 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (matches_.empty()) 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!profile_) 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkModel* bookmark_model = profile_->GetBookmarkModel(); 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!bookmark_model || !bookmark_model->IsLoaded()) 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ACMatches::iterator i = matches_.begin(); i != matches_.end(); ++i) 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i->starred = bookmark_model->IsBookmarked(GURL(i->destination_url)); 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstring16 AutocompleteProvider::StringForURLDisplay(const GURL& url, 54072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool check_accept_lang, 54172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool trim_http) const { 5423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string languages = (check_accept_lang && profile_) ? 5433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick profile_->GetPrefs()->GetString(prefs::kAcceptLanguages) : std::string(); 54472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return net::FormatUrl( 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url, 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch languages, 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP), 54872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UnescapeRule::SPACES, NULL, NULL, NULL); 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteResult --------------------------------------------------------- 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst size_t AutocompleteResult::kMaxMatches = 6; 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::Selection::Clear() { 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch destination_url = GURL(); 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch provider_affinity = NULL; 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_history_what_you_typed_match = false; 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteResult::AutocompleteResult() { 56372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Reserve space for the max number of matches we'll show. 56472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen matches_.reserve(kMaxMatches); 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // It's probably safe to do this in the initializer list, but there's little 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // penalty to doing it here and it ensures our object is fully constructed 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // before calling member functions. 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_match_ = end(); 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickAutocompleteResult::~AutocompleteResult() {} 573731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::CopyFrom(const AutocompleteResult& rhs) { 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (this == &rhs) 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch matches_ = rhs.matches_; 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Careful! You can't just copy iterators from another container, you have to 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // reconstruct them. 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_match_ = (rhs.default_match_ == rhs.end()) ? 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end() : (begin() + (rhs.default_match_ - rhs.begin())); 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch alternate_nav_url_ = rhs.alternate_nav_url_; 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 587dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid AutocompleteResult::CopyOldMatches(const AutocompleteInput& input, 588dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const AutocompleteResult& old_matches) { 589dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (old_matches.empty()) 590dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return; 59172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 59272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (empty()) { 59372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // If we've got no matches we can copy everything from the last result. 59472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CopyFrom(old_matches); 59572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (ACMatches::iterator i = begin(); i != end(); ++i) 59672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen i->from_previous = true; 59772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return; 59872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 59972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 60072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // In hopes of providing a stable popup we try to keep the number of matches 60172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // per provider consistent. Other schemes (such as blindly copying the most 60272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // relevant matches) typically result in many successive 'What You Typed' 60372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // results filling all the matches, which looks awful. 604dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // 605dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Instead of starting with the current matches and then adding old matches 606dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // until we hit our overall limit, we copy enough old matches so that each 607dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // provider has at least as many as before, and then use SortAndCull() to 608dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // clamp globally. This way, old high-relevance matches will starve new 609dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // low-relevance matches, under the assumption that the new matches will 610dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // ultimately be similar. If the assumption holds, this prevents seeing the 611dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // new low-relevance match appear and then quickly get pushed off the bottom; 612dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // if it doesn't, then once the providers are done and we expire the old 613dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // matches, the new ones will all become visible, so we won't have lost 614dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // anything permanently. 615dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ProviderToMatches matches_per_provider, old_matches_per_provider; 616dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen BuildProviderToMatches(&matches_per_provider); 617dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen old_matches.BuildProviderToMatches(&old_matches_per_provider); 618dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (ProviderToMatches::const_iterator i = old_matches_per_provider.begin(); 619dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen i != old_matches_per_provider.end(); ++i) { 620dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen MergeMatchesByProvider(i->second, matches_per_provider[i->first]); 62172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 622dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 623dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SortAndCull(input); 62472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 62572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::AppendMatches(const ACMatches& matches) { 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::copy(matches.begin(), matches.end(), std::back_inserter(matches_)); 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_match_ = end(); 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch alternate_nav_url_ = GURL(); 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::AddMatch(const AutocompleteMatch& match) { 633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(default_match_ != end()); 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ACMatches::iterator insertion_point = 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::upper_bound(begin(), end(), match, &AutocompleteMatch::MoreRelevant); 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ACMatches::iterator::difference_type default_offset = 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_match_ - begin(); 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((insertion_point - begin()) <= default_offset) 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++default_offset; 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch matches_.insert(insertion_point, match); 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_match_ = begin() + default_offset; 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::SortAndCull(const AutocompleteInput& input) { 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Remove duplicates. 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::sort(matches_.begin(), matches_.end(), 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &AutocompleteMatch::DestinationSortFunc); 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch matches_.erase(std::unique(matches_.begin(), matches_.end(), 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &AutocompleteMatch::DestinationsEqual), 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch matches_.end()); 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 65272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Sort and trim to the most relevant kMaxMatches matches. 65372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const size_t num_matches = std::min(kMaxMatches, matches_.size()); 65472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::partial_sort(matches_.begin(), matches_.begin() + num_matches, 65572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen matches_.end(), &AutocompleteMatch::MoreRelevant); 65672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen matches_.resize(num_matches); 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_match_ = begin(); 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set the alternate nav URL. 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch alternate_nav_url_ = GURL(); 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (((input.type() == AutocompleteInput::UNKNOWN) || 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (input.type() == AutocompleteInput::REQUESTED_URL)) && 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (default_match_ != end()) && 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (default_match_->transition != PageTransition::TYPED) && 6663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (default_match_->transition != PageTransition::KEYWORD) && 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (input.canonicalized_url() != default_match_->destination_url)) 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch alternate_nav_url_ = input.canonicalized_url(); 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 67172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool AutocompleteResult::HasCopiedMatches() const { 67272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (ACMatches::const_iterator i = begin(); i != end(); ++i) { 67372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (i->from_previous) 67472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 67572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 67672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 67772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 67872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 679513209b27ff55e2841eac0e4120199c23acce758Ben Murdochsize_t AutocompleteResult::size() const { 680513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return matches_.size(); 681513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 682513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 683513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool AutocompleteResult::empty() const { 684513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return matches_.empty(); 685513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 686513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 687513209b27ff55e2841eac0e4120199c23acce758Ben MurdochAutocompleteResult::const_iterator AutocompleteResult::begin() const { 688513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return matches_.begin(); 689513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 690513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 691513209b27ff55e2841eac0e4120199c23acce758Ben MurdochAutocompleteResult::iterator AutocompleteResult::begin() { 692513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return matches_.begin(); 693513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 694513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 695513209b27ff55e2841eac0e4120199c23acce758Ben MurdochAutocompleteResult::const_iterator AutocompleteResult::end() const { 696513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return matches_.end(); 697513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 698513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 699513209b27ff55e2841eac0e4120199c23acce758Ben MurdochAutocompleteResult::iterator AutocompleteResult::end() { 700513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return matches_.end(); 701513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 702513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 703513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Returns the match at the given index. 704513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst AutocompleteMatch& AutocompleteResult::match_at(size_t index) const { 705513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch DCHECK(index < matches_.size()); 706513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return matches_[index]; 707513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 708513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 709731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid AutocompleteResult::Reset() { 710731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick matches_.clear(); 711731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick default_match_ = end(); 712731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 713731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 71472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid AutocompleteResult::Swap(AutocompleteResult* other) { 71572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const size_t default_match_offset = default_match_ - begin(); 71672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const size_t other_default_match_offset = 71772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen other->default_match_ - other->begin(); 71872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen matches_.swap(other->matches_); 71972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen default_match_ = begin() + other_default_match_offset; 72072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen other->default_match_ = other->begin() + default_match_offset; 72172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen alternate_nav_url_.Swap(&(other->alternate_nav_url_)); 72272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 72372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#ifndef NDEBUG 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::Validate() const { 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (const_iterator i(begin()); i != end(); ++i) 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i->Validate(); 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 731dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid AutocompleteResult::BuildProviderToMatches( 732dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ProviderToMatches* provider_to_matches) const { 73372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (ACMatches::const_iterator i = begin(); i != end(); ++i) 734dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen (*provider_to_matches)[i->provider].push_back(*i); 73572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 73672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 73772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static 73872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool AutocompleteResult::HasMatchByDestination(const AutocompleteMatch& match, 739dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const ACMatches& matches) { 740dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (ACMatches::const_iterator i = matches.begin(); i != matches.end(); ++i) { 741dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (i->destination_url == match.destination_url) 74272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 74372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 74472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 74572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 74672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 747dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid AutocompleteResult::MergeMatchesByProvider(const ACMatches& old_matches, 748dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const ACMatches& new_matches) { 74972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (new_matches.size() >= old_matches.size()) 75072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return; 75172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 75272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen size_t delta = old_matches.size() - new_matches.size(); 75372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const int max_relevance = (new_matches.empty() ? 754dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen matches_.front().relevance : new_matches[0].relevance) - 1; 75572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Because the goal is a visibly-stable popup, rather than one that preserves 75672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // the highest-relevance matches, we copy in the lowest-relevance matches 75772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // first. This means that within each provider's "group" of matches, any 75872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // synchronous matches (which tend to have the highest scores) will 75972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // "overwrite" the initial matches from that provider's previous results, 76072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // minimally disturbing the rest of the matches. 761dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (ACMatches::const_reverse_iterator i = old_matches.rbegin(); 762dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen i != old_matches.rend() && delta > 0; ++i) { 763dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!HasMatchByDestination(*i, new_matches)) { 764dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutocompleteMatch match = *i; 76572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen match.relevance = std::min(max_relevance, match.relevance); 76672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen match.from_previous = true; 76772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen AddMatch(match); 76872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen delta--; 76972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 77072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 77172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 77272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteController ----------------------------------------------------- 774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int AutocompleteController::kNoItemSelected = -1; 776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Amount of time (in ms) between when the user stops typing and when we remove 77872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// any copied entries. We do this from the time the user stopped typing as some 77972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// providers (such as SearchProvider) wait for the user to stop typing before 78072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// they initiate a query. 78172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic const int kExpireTimeMS = 500; 782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 783dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenAutocompleteController::AutocompleteController( 784dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Profile* profile, 785dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutocompleteControllerDelegate* delegate) 786dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen : delegate_(delegate), 787dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen done_(true), 78872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen in_start_(false) { 789201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch search_provider_ = new SearchProvider(this, profile); 790201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch providers_.push_back(search_provider_); 791dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (CommandLine::ForCurrentProcess()->HasSwitch( 792dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen switches::kEnableHistoryQuickProvider) && 793dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen !CommandLine::ForCurrentProcess()->HasSwitch( 794dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen switches::kDisableHistoryQuickProvider)) 7953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick providers_.push_back(new HistoryQuickProvider(this, profile)); 796731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!CommandLine::ForCurrentProcess()->HasSwitch( 797731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick switches::kDisableHistoryURLProvider)) 7983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick providers_.push_back(new HistoryURLProvider(this, profile)); 799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch providers_.push_back(new KeywordProvider(this, profile)); 80072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen providers_.push_back(new HistoryContentsProvider(this, profile)); 801dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen providers_.push_back(new BuiltinProvider(this, profile)); 802ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen providers_.push_back(new ExtensionAppProvider(this, profile)); 803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) 804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (*i)->AddRef(); 805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 807c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteController::~AutocompleteController() { 808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The providers may have tasks outstanding that hold refs to them. We need 809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to ensure they won't call us back if they outlive us. (Practically, 810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // calling Stop() should also cancel those tasks and make it so that we hold 811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the only refs.) We also don't want to bother notifying anyone of our 812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // result changes here, because the notification observer is in the midst of 813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // shutdown too, so we don't ask Stop() to clear |result_| (and notify). 814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch result_.Reset(); // Not really necessary. 815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Stop(false); 816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) 818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (*i)->Release(); 819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch providers_.clear(); // Not really necessary. 821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::SetProfile(Profile* profile) { 824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Stop(true); 825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) 826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (*i)->SetProfile(profile); 827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input_.Clear(); // Ensure we don't try to do a "minimal_changes" query on a 828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // different profile. 829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 831ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid AutocompleteController::Start( 832ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const string16& text, 833ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const string16& desired_tld, 834ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool prevent_inline_autocomplete, 835ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool prefer_keyword, 836ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool allow_exact_keyword_match, 837ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen AutocompleteInput::MatchesRequested matches_requested) { 83872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16 old_input_text(input_.text()); 839ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const AutocompleteInput::MatchesRequested old_matches_requested = 840ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen input_.matches_requested(); 841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input_ = AutocompleteInput(text, desired_tld, prevent_inline_autocomplete, 842ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen prefer_keyword, allow_exact_keyword_match, matches_requested); 843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See if we can avoid rerunning autocomplete when the query hasn't changed 845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // much. When the user presses or releases the ctrl key, the desired_tld 846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // changes, and when the user finishes an IME composition, inline autocomplete 847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // may no longer be prevented. In both these cases the text itself hasn't 848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // changed since the last query, and some providers can do much less work (and 849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // get matches back more quickly). Taking advantage of this reduces flicker. 850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: This comes after constructing |input_| above since that construction 852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // can change the text string (e.g. by stripping off a leading '?'). 853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const bool minimal_changes = (input_.text() == old_input_text) && 854ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (input_.matches_requested() == old_matches_requested); 855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 85672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen expire_timer_.Stop(); 857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start the new query. 85972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen in_start_ = true; 860ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::TimeTicks start_time = base::TimeTicks::Now(); 861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); 862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++i) { 863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (*i)->Start(input_, minimal_changes); 864ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (matches_requested != AutocompleteInput::ALL_MATCHES) 865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK((*i)->done()); 866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 867ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (matches_requested == AutocompleteInput::ALL_MATCHES && text.size() < 6) { 868ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::TimeTicks end_time = base::TimeTicks::Now(); 869ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::string name = "Omnibox.QueryTime." + base::IntToString(text.size()); 870ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::Histogram* counter = base::Histogram::FactoryGet( 871ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen name, 1, 1000, 50, base::Histogram::kUmaTargetedHistogramFlag); 872ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen counter->Add(static_cast<int>((end_time - start_time).InMilliseconds())); 873ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 87472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen in_start_ = false; 875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CheckIfDone(); 87672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UpdateResult(true); 87772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 87872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!done_) 87972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen StartExpireTimer(); 880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::Stop(bool clear_result) { 883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); 884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++i) { 885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (*i)->Stop(); 886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 88872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen expire_timer_.Stop(); 889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch done_ = true; 890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (clear_result && !result_.empty()) { 891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch result_.Reset(); 89272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // NOTE: We pass in false since we're trying to only clear the popup, not 89372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // touch the edit... this is all a mess and should be cleaned up :( 89472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NotifyChanged(false); 895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::DeleteMatch(const AutocompleteMatch& match) { 899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(match.deletable); 900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match.provider->DeleteMatch(match); // This may synchronously call back to 901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // OnProviderUpdate(). 90272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // If DeleteMatch resulted in a callback to OnProviderUpdate and we're 90372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // not done, we might attempt to redisplay the deleted match. Make sure 90472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // we aren't displaying it by removing any old entries. 90572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ExpireCopiedEntries(); 9063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 9073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 90872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid AutocompleteController::ExpireCopiedEntries() { 909dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Clear out the results. This ensures no results from the previous result set 910dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // are copied over. 911dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen result_.Reset(); 912dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // We allow matches from the previous result set to starve out matches from 913dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // the new result set. This means in order to expire matches we have to query 914dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // the providers again. 915dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen UpdateResult(false); 916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::OnProviderUpdate(bool updated_matches) { 919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CheckIfDone(); 92072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Multiple providers may provide synchronous results, so we only update the 92172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // results if we're not in Start(). 92272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!in_start_ && (updated_matches || done_)) 92372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UpdateResult(false); 924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 92672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid AutocompleteController::UpdateResult(bool is_synchronous_pass) { 92772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen AutocompleteResult last_result; 92872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen last_result.Swap(&result_); 92972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); 931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++i) 93272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result_.AppendMatches((*i)->matches()); 933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Sort the matches and trim to a small number of "best" matches. 93572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result_.SortAndCull(input_); 936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 93772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Need to validate before invoking CopyOldMatches as the old matches are not 93872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // valid against the current input. 939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#ifndef NDEBUG 94072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result_.Validate(); 941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 94372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!done_) { 94472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // This conditional needs to match the conditional in Start that invokes 94572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // StartExpireTimer. 946dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen result_.CopyOldMatches(input_, last_result); 947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 94972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool notify_default_match = is_synchronous_pass; 95072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!is_synchronous_pass) { 95172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const bool last_default_was_valid = 95272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen last_result.default_match() != last_result.end(); 95372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const bool default_is_valid = result_.default_match() != result_.end(); 95472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // We've gotten async results. Send notification that the default match 95572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // updated if fill_into_edit differs. We don't check the URL as that may 95672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // change for the default match even though the fill into edit hasn't 95772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // changed (see SearchProvider for one case of this). 95872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen notify_default_match = 95972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (last_default_was_valid != default_is_valid) || 96072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (default_is_valid && 96172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (result_.default_match()->fill_into_edit != 96272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen last_result.default_match()->fill_into_edit)); 963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 96572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NotifyChanged(notify_default_match); 96672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 96872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid AutocompleteController::NotifyChanged(bool notify_default_match) { 969dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (delegate_) 970dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen delegate_->OnResultChanged(notify_default_match); 971dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (done_) { 972dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen NotificationService::current()->Notify( 973dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_READY, 974dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Source<AutocompleteController>(this), 975dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen NotificationService::NoDetails()); 976dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::CheckIfDone() { 980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); 981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++i) { 982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!(*i)->done()) { 983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch done_ = false; 984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch done_ = true; 988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 98972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 99072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid AutocompleteController::StartExpireTimer() { 99172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (result_.HasCopiedMatches()) 99272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen expire_timer_.Start(base::TimeDelta::FromMilliseconds(kExpireTimeMS), 99372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen this, &AutocompleteController::ExpireCopiedEntries); 99472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 995