autocomplete.cc revision 201ade2fbba22bfb27ae029f4d23fca6ded109a0
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 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 "app/l10n_util.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/basictypes.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/command_line.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/number_formatting.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
16513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/autocomplete/autocomplete_match.h"
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/autocomplete/history_quick_provider.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/history_url_provider.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/history_contents_provider.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/keyword_provider.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/search_provider.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_model.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/dom_ui/history_ui.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/external_protocol_handler.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/url_fixer_upper.h"
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h"
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/chrome_switches.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/notification_service.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/url_canon_ip.h"
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/url_util.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h"
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/registry_controlled_domain.h"
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request.h"
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteInput ----------------------------------------------------------
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteInput::AutocompleteInput()
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  : type_(INVALID),
47201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    initial_prevent_inline_autocomplete_(false),
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prevent_inline_autocomplete_(false),
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prefer_keyword_(false),
504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    allow_exact_keyword_match_(true),
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    synchronous_only_(false) {
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteInput::AutocompleteInput(const std::wstring& text,
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     const std::wstring& desired_tld,
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     bool prevent_inline_autocomplete,
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     bool prefer_keyword,
584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                     bool allow_exact_keyword_match,
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     bool synchronous_only)
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : desired_tld_(desired_tld),
61201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      initial_prevent_inline_autocomplete_(prevent_inline_autocomplete),
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      prevent_inline_autocomplete_(prevent_inline_autocomplete),
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      prefer_keyword_(prefer_keyword),
644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      allow_exact_keyword_match_(allow_exact_keyword_match),
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      synchronous_only_(synchronous_only) {
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Trim whitespace from edges of input; don't inline autocomplete if there
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // was trailing whitespace.
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (TrimWhitespace(text, TRIM_ALL, &text_) & TRIM_TRAILING)
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prevent_inline_autocomplete_ = true;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  type_ = Parse(text_, desired_tld, &parts_, &scheme_);
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type_ == INVALID)
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if ((type_ == UNKNOWN) || (type_ == REQUESTED_URL) || (type_ == URL)) {
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL canonicalized_url(URLFixerUpper::FixupURL(WideToUTF8(text_),
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   WideToUTF8(desired_tld_)));
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (canonicalized_url.is_valid() &&
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (!canonicalized_url.IsStandard() || canonicalized_url.SchemeIsFile() ||
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         !canonicalized_url.host().empty()))
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canonicalized_url_ = canonicalized_url;
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  RemoveForcedQueryStringIfNecessary(type_, &text_);
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteInput::~AutocompleteInput() {
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
92201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid AutocompleteInput::RemoveForcedQueryStringIfNecessary(Type type,
93201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                                           std::wstring* text) {
94201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (type == FORCED_QUERY && !text->empty() && (*text)[0] == L'?')
95201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    text->erase(0, 1);
96201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
97201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
98201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// static
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string AutocompleteInput::TypeToString(Type type) {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (type) {
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case INVALID:       return "invalid";
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case UNKNOWN:       return "unknown";
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case REQUESTED_URL: return "requested-url";
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case URL:           return "url";
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case QUERY:         return "query";
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case FORCED_QUERY:  return "forced-query";
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return std::string();
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteInput::Type AutocompleteInput::Parse(
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::wstring& text,
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::wstring& desired_tld,
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_parse::Parsed* parts,
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring* scheme) {
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const size_t first_non_white = text.find_first_not_of(kWhitespaceWide, 0);
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (first_non_white == std::wstring::npos)
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return INVALID;  // All whitespace.
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (text.at(first_non_white) == L'?') {
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the first non-whitespace character is a '?', we magically treat this
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // as a query.
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FORCED_QUERY;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ask our parsing back-end to help us understand what the user typed.  We
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // use the URLFixerUpper here because we want to be smart about what we
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // consider a scheme.  For example, we shouldn't consider www.google.com:80
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to have a scheme.
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  url_parse::Parsed local_parts;
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!parts)
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parts = &local_parts;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::wstring parsed_scheme(URLFixerUpper::SegmentURL(text, parts));
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (scheme)
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *scheme = parsed_scheme;
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (parsed_scheme == L"file") {
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // A user might or might not type a scheme when entering a file URL.  In
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // either case, |parsed_scheme| will tell us that this is a file URL, but
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // |parts->scheme| might be empty, e.g. if the user typed "C:\foo".
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return URL;
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the user typed a scheme, and it's HTTP or HTTPS, we know how to parse it
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // well enough that we can fall through to the heuristics below.  If it's
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // something else, we can just determine our action based on what we do with
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // any input of this scheme.  In theory we could do better with some schemes
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // (e.g. "ftp" or "view-source") but I'll wait to spend the effort on that
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // until I run into some cases that really need it.
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (parts->scheme.is_nonempty() &&
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (parsed_scheme != L"http") && (parsed_scheme != L"https")) {
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See if we know how to handle the URL internally.
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (URLRequest::IsHandledProtocol(WideToASCII(parsed_scheme)))
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return URL;
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // There are also some schemes that we convert to other things before they
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // reach the renderer or else the renderer handles internally without
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // reaching the URLRequest logic.  We thus won't catch these above, but we
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // should still claim to handle them.
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (LowerCaseEqualsASCII(parsed_scheme, chrome::kViewSourceScheme) ||
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LowerCaseEqualsASCII(parsed_scheme, chrome::kJavaScriptScheme) ||
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LowerCaseEqualsASCII(parsed_scheme, chrome::kDataScheme))
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return URL;
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Finally, check and see if the user has explicitly opened this scheme as
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // a URL before.  We need to do this last because some schemes may be in
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // here as "blocked" (e.g. "javascript") because we don't want pages to open
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // them, but users still can.
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // TODO(viettrungluu): get rid of conversion.
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    switch (ExternalProtocolHandler::GetBlockState(WideToUTF8(parsed_scheme))) {
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case ExternalProtocolHandler::DONT_BLOCK:
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return URL;
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case ExternalProtocolHandler::BLOCK:
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // If we don't want the user to open the URL, don't let it be navigated
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // to at all.
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return QUERY;
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // We don't know about this scheme.  It's likely to be a search operator
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // like "site:" or "link:".  We classify it as UNKNOWN so the user has
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // the option of treating it as a URL if we're wrong.
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Note that SegmentURL() is smart so we aren't tricked by "c:\foo" or
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // "www.example.com:81" in this case.
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return UNKNOWN;
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Either the user didn't type a scheme, in which case we need to distinguish
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // between an HTTP URL and a query, or the scheme is HTTP or HTTPS, in which
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // case we should reject invalid formulations.
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we have an empty host it can't be a URL.
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!parts->host.is_nonempty())
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return QUERY;
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Likewise, the RCDS can reject certain obviously-invalid hosts.  (We also
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // use the registry length later below.)
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::wstring host(text.substr(parts->host.begin, parts->host.len));
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const size_t registry_length =
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net::RegistryControlledDomainService::GetRegistryLength(host, false);
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (registry_length == std::wstring::npos) {
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Try to append the desired_tld.
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!desired_tld.empty()) {
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::wstring host_with_tld(host);
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (host[host.length() - 1] != '.')
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        host_with_tld += '.';
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      host_with_tld += desired_tld;
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (net::RegistryControlledDomainService::GetRegistryLength(
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          host_with_tld, false) != std::wstring::npos)
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return REQUESTED_URL;  // Something like "99999999999" that looks like a
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               // bad IP address, but becomes valid on attaching
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               // a TLD.
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return QUERY;  // Could be a broken IP address, etc.
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See if the hostname is valid.  While IE and GURL allow hostnames to contain
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // many other characters (perhaps for weird intranet machines), it's extremely
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // unlikely that a user would be trying to type those in for anything other
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // than a search query.
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  url_canon::CanonHostInfo host_info;
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string canonicalized_host(net::CanonicalizeHost(host, &host_info));
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if ((host_info.family == url_canon::CanonHostInfo::NEUTRAL) &&
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !net::IsCanonicalizedHostCompliant(canonicalized_host,
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         WideToUTF8(desired_tld))) {
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Invalid hostname.  There are several possible cases:
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // * Our checker is too strict and the user pasted in a real-world URL
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   that's "invalid" but resolves.  To catch these, we return UNKNOWN when
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   the user explicitly typed a scheme, so we'll still search by default
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   but we'll show the accidental search infobar if necessary.
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // * The user is typing a multi-word query.  If we see a space anywhere in
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   the hostname we assume this is a search and return QUERY.
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // * Our checker is too strict and the user is typing a real-world hostname
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   that's "invalid" but resolves.  We return UNKNOWN if the TLD is known.
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   Note that we explicitly excluded hosts with spaces above so that
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   "toys at amazon.com" will be treated as a search.
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // * The user is typing some garbage string.  Return QUERY.
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Thus we fall down in the following cases:
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // * Trying to navigate to a hostname with spaces
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // * Trying to navigate to a hostname with invalid characters and an unknown
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   TLD
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // These are rare, though probably possible in intranets.
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return (parts->scheme.is_nonempty() ||
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           ((registry_length != 0) && (host.find(' ') == std::wstring::npos))) ?
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        UNKNOWN : QUERY;
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // A port number is a good indicator that this is a URL.  However, it might
2563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // also be a query like "1.66:1" that looks kind of like an IP address and
2573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // port number. So here we only check for "port numbers" that are illegal and
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // thus mean this can't be navigated to (e.g. "1.2.3.4:garbage"), and we save
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // handling legal port numbers until after the "IP address" determination
2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // below.
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (parts->port.is_nonempty()) {
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int port;
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!base::StringToInt(WideToUTF8(
2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            text.substr(parts->port.begin, parts->port.len)), &port) ||
2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        (port < 0) || (port > 65535))
2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return QUERY;
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Now that we've ruled out all schemes other than http or https and done a
2703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // little more sanity checking, the presence of a scheme means this is likely
2713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // a URL.
2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (parts->scheme.is_nonempty())
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return URL;
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See if the host is an IP address.
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (host_info.family == url_canon::CanonHostInfo::IPV4) {
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the user originally typed a host that looks like an IP address (a
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // dotted quad), they probably want to open it.  If the original input was
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // something else (like a single number), they probably wanted to search for
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // it, unless they explicitly typed a scheme.  This is true even if the URL
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // appears to have a path: "1.2/45" is more likely a search (for the answer
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // to a math problem) than a URL.
2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (host_info.num_ipv4_components == 4)
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return URL;
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return desired_tld.empty() ? UNKNOWN : REQUESTED_URL;
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (host_info.family == url_canon::CanonHostInfo::IPV6)
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return URL;
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Now that we've ruled out invalid ports and queries that look like they have
2913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // a port, the presence of a port means this is likely a URL.
2923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (parts->port.is_nonempty())
2933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return URL;
2943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Presence of a password means this is likely a URL.  Note that unless the
2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // user has typed an explicit "http://" or similar, we'll probably think that
2973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // the username is some unknown scheme, and bail out in the scheme-handling
2983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // code above.
2993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (parts->password.is_nonempty())
3003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return URL;
3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The host doesn't look like a number, so see if the user's given us a path.
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (parts->path.is_nonempty()) {
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Most inputs with paths are URLs, even ones without known registries (e.g.
3053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // intranet URLs).  However, if there's no known registry and the path has
3063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // a space, this is more likely a query with a slash in the first term
3073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // (e.g. "ps/2 games") than a URL.  We can still open URLs with spaces in
3083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // the path by escaping the space, and we will still inline autocomplete
3093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // them if users have typed them in the past, but we default to searching
3103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // since that's the common case.
3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return ((registry_length == 0) &&
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            (text.substr(parts->path.begin, parts->path.len).find(' ') !=
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                std::wstring::npos)) ? UNKNOWN : URL;
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If we reach here with a username, our input looks like "user@host".
3173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Because there is no scheme explicitly specified, we think this is more
3183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // likely an email address than an HTTP auth attempt.  Hence, we search by
3193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // default and let users correct us on a case-by-case basis.
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (parts->username.is_nonempty())
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return UNKNOWN;
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We have a bare host string.  If it has a known TLD, it's probably a URL.
3243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (registry_length != 0)
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return URL;
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // No TLD that we know about.  This could be:
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // * A string that the user wishes to add a desired_tld to to get a URL.  If
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   we reach this point, we know there's no known TLD on the string, so the
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   fixup code will be willing to add one; thus this is a URL.
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // * A single word "foo"; possibly an intranet site, but more likely a search.
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   This is ideally an UNKNOWN, and we can let the Alternate Nav URL code
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   catch our mistakes.
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // * A URL with a valid TLD we don't know about yet.  If e.g. a registrar adds
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   "xxx" as a TLD, then until we add it to our data file, Chrome won't know
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   "foo.xxx" is a real URL.  So ideally this is a URL, but we can't really
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   distinguish this case from:
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // * A "URL-like" string that's not really a URL (like
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   "browser.tabs.closeButtons" or "java.awt.event.*").  This is ideally a
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   QUERY.  Since the above case and this one are indistinguishable, and this
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   case is likely to be much more common, just say these are both UNKNOWN,
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   which should default to the right thing and let users correct us on a
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   case-by-case basis.
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return desired_tld.empty() ? UNKNOWN : REQUESTED_URL;
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteInput::ParseForEmphasizeComponents(
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::wstring& text,
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::wstring& desired_tld,
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_parse::Component* scheme,
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_parse::Component* host) {
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  url_parse::Parsed parts;
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring scheme_str;
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Parse(text, desired_tld, &parts, &scheme_str);
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *scheme = parts.scheme;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *host = parts.host;
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int after_scheme_and_colon = parts.scheme.end() + 1;
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For the view-source scheme, we should emphasize the scheme and host of the
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // URL qualified by the view-source prefix.
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (LowerCaseEqualsASCII(scheme_str, chrome::kViewSourceScheme) &&
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (static_cast<int>(text.length()) > after_scheme_and_colon)) {
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Obtain the URL prefixed by view-source and parse it.
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring real_url(text.substr(after_scheme_and_colon));
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_parse::Parsed real_parts;
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AutocompleteInput::Parse(real_url, desired_tld, &real_parts, NULL);
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (real_parts.scheme.is_nonempty() || real_parts.host.is_nonempty()) {
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (real_parts.scheme.is_nonempty()) {
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        *scheme = url_parse::Component(
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            after_scheme_and_colon + real_parts.scheme.begin,
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            real_parts.scheme.len);
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        scheme->reset();
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (real_parts.host.is_nonempty()) {
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        *host = url_parse::Component(
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            after_scheme_and_colon + real_parts.host.begin,
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            real_parts.host.len);
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        host->reset();
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::wstring AutocompleteInput::FormattedStringWithEquivalentMeaning(
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url,
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::wstring& formatted_url) {
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!net::CanStripTrailingSlash(url))
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return formatted_url;
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::wstring url_with_path(formatted_url + L"/");
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (AutocompleteInput::Parse(formatted_url, std::wstring(), NULL, NULL) ==
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          AutocompleteInput::Parse(url_with_path, std::wstring(), NULL, NULL)) ?
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      formatted_url : url_with_path;
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteInput::Equals(const AutocompleteInput& other) const {
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (text_ == other.text_) &&
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (type_ == other.type_) &&
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (desired_tld_ == other.desired_tld_) &&
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (scheme_ == other.scheme_) &&
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (prevent_inline_autocomplete_ == other.prevent_inline_autocomplete_) &&
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (prefer_keyword_ == other.prefer_keyword_) &&
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (synchronous_only_ == other.synchronous_only_);
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteInput::Clear() {
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  text_.clear();
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  type_ = INVALID;
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  parts_ = url_parse::Parsed();
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scheme_.clear();
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  desired_tld_.clear();
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prevent_inline_autocomplete_ = false;
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefer_keyword_ = false;
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteProvider -------------------------------------------------------
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst size_t AutocompleteProvider::kMaxMatches = 3;
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteProvider::ACProviderListener::~ACProviderListener() {
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteProvider::AutocompleteProvider(ACProviderListener* listener,
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           Profile* profile,
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           const char* name)
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : profile_(profile),
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      listener_(listener),
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      done_(true),
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      name_(name) {
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteProvider::SetProfile(Profile* profile) {
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(profile);
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(done_);  // The controller should have already stopped us.
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_ = profile;
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteProvider::Stop() {
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  done_ = true;
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteProvider::DeleteMatch(const AutocompleteMatch& match) {
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteProvider::~AutocompleteProvider() {
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Stop();
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteProvider::HasHTTPScheme(const std::wstring& input) {
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string utf8_input(WideToUTF8(input));
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  url_parse::Component scheme;
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url_util::FindAndCompareScheme(utf8_input, chrome::kViewSourceScheme,
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     &scheme))
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    utf8_input.erase(0, scheme.end() + 1);
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return url_util::FindAndCompareScheme(utf8_input, chrome::kHttpScheme, NULL);
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteProvider::UpdateStarredStateOfMatches() {
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (matches_.empty())
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!profile_)
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkModel* bookmark_model = profile_->GetBookmarkModel();
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!bookmark_model || !bookmark_model->IsLoaded())
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ACMatches::iterator i = matches_.begin(); i != matches_.end(); ++i)
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    i->starred = bookmark_model->IsBookmarked(GURL(i->destination_url));
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::wstring AutocompleteProvider::StringForURLDisplay(const GURL& url,
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                       bool check_accept_lang,
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                       bool trim_http) const {
4823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string languages = (check_accept_lang && profile_) ?
4833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      profile_->GetPrefs()->GetString(prefs::kAcceptLanguages) : std::string();
4843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return UTF16ToWideHack(net::FormatUrl(
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url,
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      languages,
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP),
4883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      UnescapeRule::SPACES, NULL, NULL, NULL));
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteResult ---------------------------------------------------------
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst size_t AutocompleteResult::kMaxMatches = 6;
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::Selection::Clear() {
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  destination_url = GURL();
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  provider_affinity = NULL;
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  is_history_what_you_typed_match = false;
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteResult::AutocompleteResult() {
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reserve space for the max number of matches we'll show. The +1 accounts
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // for the history shortcut match as it isn't included in max_matches.
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  matches_.reserve(kMaxMatches + 1);
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // It's probably safe to do this in the initializer list, but there's little
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // penalty to doing it here and it ensures our object is fully constructed
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // before calling member functions.
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  default_match_ = end();
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
513731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickAutocompleteResult::~AutocompleteResult() {}
514731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::CopyFrom(const AutocompleteResult& rhs) {
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (this == &rhs)
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  matches_ = rhs.matches_;
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Careful!  You can't just copy iterators from another container, you have to
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // reconstruct them.
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  default_match_ = (rhs.default_match_ == rhs.end()) ?
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      end() : (begin() + (rhs.default_match_ - rhs.begin()));
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  alternate_nav_url_ = rhs.alternate_nav_url_;
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::AppendMatches(const ACMatches& matches) {
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::copy(matches.begin(), matches.end(), std::back_inserter(matches_));
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  default_match_ = end();
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  alternate_nav_url_ = GURL();
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::AddMatch(const AutocompleteMatch& match) {
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(default_match_ != end());
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ACMatches::iterator insertion_point =
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::upper_bound(begin(), end(), match, &AutocompleteMatch::MoreRelevant);
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ACMatches::iterator::difference_type default_offset =
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default_match_ - begin();
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if ((insertion_point - begin()) <= default_offset)
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ++default_offset;
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  matches_.insert(insertion_point, match);
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  default_match_ = begin() + default_offset;
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::SortAndCull(const AutocompleteInput& input) {
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove duplicates.
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::sort(matches_.begin(), matches_.end(),
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            &AutocompleteMatch::DestinationSortFunc);
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  matches_.erase(std::unique(matches_.begin(), matches_.end(),
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             &AutocompleteMatch::DestinationsEqual),
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 matches_.end());
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Find the top |kMaxMatches| matches.
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (matches_.size() > kMaxMatches) {
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::partial_sort(matches_.begin(), matches_.begin() + kMaxMatches,
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      matches_.end(), &AutocompleteMatch::MoreRelevant);
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    matches_.erase(matches_.begin() + kMaxMatches, matches_.end());
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // HistoryContentsProvider uses a negative relevance as a way to avoid
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // starving out other provider matches, yet we may end up using this match. To
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // make sure such matches are sorted correctly we search for all
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // relevances < 0 and negate them. If we change our relevance algorithm to
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // properly mix different providers' matches, this can go away.
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ACMatches::iterator i = matches_.begin(); i != matches_.end(); ++i) {
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (i->relevance < 0)
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      i->relevance = -i->relevance;
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Put the final result set in order.
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::sort(matches_.begin(), matches_.end(), &AutocompleteMatch::MoreRelevant);
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  default_match_ = begin();
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set the alternate nav URL.
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  alternate_nav_url_ = GURL();
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (((input.type() == AutocompleteInput::UNKNOWN) ||
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       (input.type() == AutocompleteInput::REQUESTED_URL)) &&
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (default_match_ != end()) &&
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (default_match_->transition != PageTransition::TYPED) &&
5813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      (default_match_->transition != PageTransition::KEYWORD) &&
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (input.canonicalized_url() != default_match_->destination_url))
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    alternate_nav_url_ = input.canonicalized_url();
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
586513209b27ff55e2841eac0e4120199c23acce758Ben Murdochsize_t AutocompleteResult::size() const {
587513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return matches_.size();
588513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
589513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
590513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool AutocompleteResult::empty() const {
591513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return matches_.empty();
592513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
593513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
594513209b27ff55e2841eac0e4120199c23acce758Ben MurdochAutocompleteResult::const_iterator AutocompleteResult::begin() const {
595513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return matches_.begin();
596513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
597513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
598513209b27ff55e2841eac0e4120199c23acce758Ben MurdochAutocompleteResult::iterator AutocompleteResult::begin() {
599513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return matches_.begin();
600513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
601513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
602513209b27ff55e2841eac0e4120199c23acce758Ben MurdochAutocompleteResult::const_iterator AutocompleteResult::end() const {
603513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return matches_.end();
604513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
605513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
606513209b27ff55e2841eac0e4120199c23acce758Ben MurdochAutocompleteResult::iterator AutocompleteResult::end() {
607513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return matches_.end();
608513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
609513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
610513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Returns the match at the given index.
611513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst AutocompleteMatch& AutocompleteResult::match_at(size_t index) const {
612513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(index < matches_.size());
613513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return matches_[index];
614513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
615513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
616731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid AutocompleteResult::Reset() {
617731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  matches_.clear();
618731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  default_match_ = end();
619731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
620731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#ifndef NDEBUG
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteResult::Validate() const {
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (const_iterator i(begin()); i != end(); ++i)
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    i->Validate();
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteController -----------------------------------------------------
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int AutocompleteController::kNoItemSelected = -1;
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The time we'll wait between sending updates to our observers (balances
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// flicker against lag).
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kUpdateDelayMs = 350;
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteController::AutocompleteController(Profile* profile)
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : updated_latest_result_(false),
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delay_interval_has_passed_(false),
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      have_committed_during_this_query_(false),
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      done_(true) {
643201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  search_provider_ = new SearchProvider(this, profile);
644201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  providers_.push_back(search_provider_);
645731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!CommandLine::ForCurrentProcess()->HasSwitch(
646731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      switches::kDisableHistoryQuickProvider))
6473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    providers_.push_back(new HistoryQuickProvider(this, profile));
648731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!CommandLine::ForCurrentProcess()->HasSwitch(
649731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      switches::kDisableHistoryURLProvider))
6503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    providers_.push_back(new HistoryURLProvider(this, profile));
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  providers_.push_back(new KeywordProvider(this, profile));
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  history_contents_provider_ = new HistoryContentsProvider(this, profile);
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  providers_.push_back(history_contents_provider_);
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i)
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*i)->AddRef();
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteController::~AutocompleteController() {
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The providers may have tasks outstanding that hold refs to them.  We need
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to ensure they won't call us back if they outlive us.  (Practically,
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // calling Stop() should also cancel those tasks and make it so that we hold
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the only refs.)  We also don't want to bother notifying anyone of our
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // result changes here, because the notification observer is in the midst of
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // shutdown too, so we don't ask Stop() to clear |result_| (and notify).
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.Reset();  // Not really necessary.
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Stop(false);
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i)
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*i)->Release();
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  providers_.clear();  // Not really necessary.
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::SetProfile(Profile* profile) {
675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Stop(true);
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i)
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*i)->SetProfile(profile);
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  input_.Clear();  // Ensure we don't try to do a "minimal_changes" query on a
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   // different profile.
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::Start(const std::wstring& text,
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   const std::wstring& desired_tld,
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   bool prevent_inline_autocomplete,
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   bool prefer_keyword,
6864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                   bool allow_exact_keyword_match,
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   bool synchronous_only) {
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::wstring old_input_text(input_.text());
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const bool old_synchronous_only = input_.synchronous_only();
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  input_ = AutocompleteInput(text, desired_tld, prevent_inline_autocomplete,
6914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      prefer_keyword, allow_exact_keyword_match, synchronous_only);
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See if we can avoid rerunning autocomplete when the query hasn't changed
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // much.  When the user presses or releases the ctrl key, the desired_tld
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // changes, and when the user finishes an IME composition, inline autocomplete
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // may no longer be prevented.  In both these cases the text itself hasn't
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // changed since the last query, and some providers can do much less work (and
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // get matches back more quickly).  Taking advantage of this reduces flicker.
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NOTE: This comes after constructing |input_| above since that construction
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // can change the text string (e.g. by stripping off a leading '?').
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const bool minimal_changes = (input_.text() == old_input_text) &&
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (input_.synchronous_only() == old_synchronous_only);
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we're interrupting an old query, and committing its result won't shrink
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the visible set (which would probably re-expand soon, thus looking very
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // flickery), then go ahead and commit what we've got, in order to feel more
7083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // responsive when the user is typing rapidly.  In this case it's important
7093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // that we don't update the edit, as the user has already changed its contents
7103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // and anything we might do with it (e.g. inline autocomplete) likely no
7113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // longer applies.
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!minimal_changes && !done_ && (latest_result_.size() >= result_.size()))
7133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CommitResult(false);
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the timer is already running, it could fire shortly after starting this
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // query, when we're likely to only have the synchronous results back, thus
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // almost certainly causing flicker.  Reset it, except when we haven't
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // committed anything for the past query, in which case the user is typing
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // quickly and we need to keep running the timer lest we lag too far behind.
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (have_committed_during_this_query_) {
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    update_delay_timer_.Stop();
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delay_interval_has_passed_ = false;
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Start the new query.
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  have_committed_during_this_query_ = false;
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ACProviders::iterator i(providers_.begin()); i != providers_.end();
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++i) {
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*i)->Start(input_, minimal_changes);
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (synchronous_only)
731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK((*i)->done());
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CheckIfDone();
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateLatestResult(true);
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::Stop(bool clear_result) {
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end();
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++i) {
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*i)->Stop();
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  update_delay_timer_.Stop();
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  updated_latest_result_ = false;
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delay_interval_has_passed_ = false;
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  done_ = true;
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (clear_result && !result_.empty()) {
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result_.Reset();
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NotificationService::current()->Notify(
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED,
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Source<AutocompleteController>(this),
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Details<const AutocompleteResult>(&result_));
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // NOTE: We don't notify AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED since
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // we're trying to only clear the popup, not touch the edit... this is all
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // a mess and should be cleaned up :(
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  latest_result_.CopyFrom(result_);
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::DeleteMatch(const AutocompleteMatch& match) {
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(match.deletable);
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  match.provider->DeleteMatch(match);  // This may synchronously call back to
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       // OnProviderUpdate().
7643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CommitResult(true);  // Ensure any new result gets committed immediately.  If
7653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                       // it was committed already or hasn't been modified, this
7663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                       // is harmless.
7673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
7683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid AutocompleteController::CommitIfQueryHasNeverBeenCommitted() {
7703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!have_committed_during_this_query_)
7713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CommitResult(true);
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::OnProviderUpdate(bool updated_matches) {
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CheckIfDone();
7763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (updated_matches || done_)
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UpdateLatestResult(false);
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::UpdateLatestResult(bool is_synchronous_pass) {
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add all providers' matches.
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  latest_result_.Reset();
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end();
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++i)
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    latest_result_.AppendMatches((*i)->matches());
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  updated_latest_result_ = true;
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Sort the matches and trim to a small number of "best" matches.
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  latest_result_.SortAndCull(input_);
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (history_contents_provider_)
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddHistoryContentsShortcut();
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#ifndef NDEBUG
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  latest_result_.Validate();
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (is_synchronous_pass) {
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!update_delay_timer_.IsRunning()) {
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      update_delay_timer_.Start(
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          TimeDelta::FromMilliseconds(kUpdateDelayMs),
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          this, &AutocompleteController::DelayTimerFired);
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NotificationService::current()->Notify(
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NotificationType::AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED,
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Source<AutocompleteController>(this),
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Details<const AutocompleteResult>(&latest_result_));
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If nothing is visible, commit immediately so that the first character the
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // user types produces an instant response.  If the query has finished and we
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // haven't ever committed a result set, commit immediately to minimize lag.
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Otherwise, only commit when it's been at least one delay interval since the
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // last commit, to minimize flicker.
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result_.empty() || (done_ && !have_committed_during_this_query_) ||
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delay_interval_has_passed_)
8183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CommitResult(true);
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::DelayTimerFired() {
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delay_interval_has_passed_ = true;
8233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CommitResult(true);
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid AutocompleteController::CommitResult(bool notify_default_match) {
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (done_) {
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    update_delay_timer_.Stop();
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delay_interval_has_passed_ = false;
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't send update notifications when nothing's actually changed.
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!updated_latest_result_)
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  updated_latest_result_ = false;
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delay_interval_has_passed_ = false;
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  have_committed_during_this_query_ = true;
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.CopyFrom(latest_result_);
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED,
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Source<AutocompleteController>(this),
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Details<const AutocompleteResult>(&result_));
8443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (notify_default_match) {
8453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // This notification must be sent after the other so the popup has time to
8463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // update its state before the edit calls into it.
8473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // TODO(pkasting): Eliminate this ordering requirement.
8483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NotificationService::current()->Notify(
8493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        NotificationType::AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED,
8503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        Source<AutocompleteController>(this),
8513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        Details<const AutocompleteResult>(&result_));
8523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!done_)
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    update_delay_timer_.Reset();
855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochACMatches AutocompleteController::GetMatchesNotInLatestResult(
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const AutocompleteProvider* provider) const {
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(provider);
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Determine the set of destination URLs.
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<GURL> destination_urls;
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (AutocompleteResult::const_iterator i(latest_result_.begin());
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != latest_result_.end(); ++i)
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    destination_urls.insert(i->destination_url);
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ACMatches matches;
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const ACMatches& provider_matches = provider->matches();
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ACMatches::const_iterator i = provider_matches.begin();
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != provider_matches.end(); ++i) {
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (destination_urls.find(i->destination_url) == destination_urls.end())
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      matches.push_back(*i);
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return matches;
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::AddHistoryContentsShortcut() {
879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(history_contents_provider_);
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Only check the history contents provider if the history contents provider
881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is done and has matches.
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!history_contents_provider_->done() ||
883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !history_contents_provider_->db_match_count()) {
884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if ((history_contents_provider_->db_match_count() <=
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          (latest_result_.size() + 1)) ||
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (history_contents_provider_->db_match_count() == 1)) {
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We only want to add a shortcut if we're not already showing the matches.
891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ACMatches matches(GetMatchesNotInLatestResult(history_contents_provider_));
892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (matches.empty())
893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (matches.size() == 1) {
895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Only one match not shown, add it. The relevance may be negative,
896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // which means we need to negate it to get the true relevance.
897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      AutocompleteMatch& match = matches.front();
898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (match.relevance < 0)
899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        match.relevance = -match.relevance;
900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      latest_result_.AddMatch(match);
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } // else, fall through and add item.
903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AutocompleteMatch match(NULL, 0, false, AutocompleteMatch::OPEN_HISTORY_PAGE);
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  match.fill_into_edit = input_.text();
907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Mark up the text such that the user input text is bold.
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t keyword_offset = std::wstring::npos;  // Offset into match.contents.
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (history_contents_provider_->db_match_count() ==
911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      history_contents_provider_->kMaxMatchCount) {
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // History contents searcher has maxed out.
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    match.contents = l10n_util::GetStringF(IDS_OMNIBOX_RECENT_HISTORY_MANY,
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           input_.text(),
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           &keyword_offset);
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We can report exact matches when there aren't too many.
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<size_t> content_param_offsets;
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    match.contents = l10n_util::GetStringF(
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        IDS_OMNIBOX_RECENT_HISTORY,
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        UTF16ToWide(base::FormatNumber(history_contents_provider_->
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           db_match_count())),
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        input_.text(),
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &content_param_offsets);
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // content_param_offsets is ordered based on supplied params, we expect
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // that the second one contains the query (first is the number).
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (content_param_offsets.size() == 2) {
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      keyword_offset = content_param_offsets[1];
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // See comments on an identical NOTREACHED() in search_provider.cc.
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NOTE: This comparison succeeds when keyword_offset == std::wstring::npos.
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (keyword_offset > 0) {
938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    match.contents_class.push_back(
939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ACMatchClassification(0, ACMatchClassification::NONE));
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  match.contents_class.push_back(
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ACMatchClassification(keyword_offset, ACMatchClassification::MATCH));
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (keyword_offset + input_.text().size() < match.contents.size()) {
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    match.contents_class.push_back(
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ACMatchClassification(keyword_offset + input_.text().size(),
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              ACMatchClassification::NONE));
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  match.destination_url =
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      HistoryUI::GetHistoryURLWithSearchText(WideToUTF16(input_.text()));
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  match.transition = PageTransition::AUTO_BOOKMARK;
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  match.provider = history_contents_provider_;
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  latest_result_.AddMatch(match);
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteController::CheckIfDone() {
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end();
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++i) {
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!(*i)->done()) {
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      done_ = false;
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  done_ = true;
964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
965