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