Home | History | Annotate | Download | only in autocomplete
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/autocomplete/autocomplete.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/command_line.h"
     11 #include "base/i18n/number_formatting.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/string_number_conversions.h"
     14 #include "base/string_util.h"
     15 #include "base/utf_string_conversions.h"
     16 #include "chrome/browser/autocomplete/autocomplete_controller_delegate.h"
     17 #include "chrome/browser/autocomplete/autocomplete_match.h"
     18 #include "chrome/browser/autocomplete/builtin_provider.h"
     19 #include "chrome/browser/autocomplete/extension_app_provider.h"
     20 #include "chrome/browser/autocomplete/history_contents_provider.h"
     21 #include "chrome/browser/autocomplete/history_quick_provider.h"
     22 #include "chrome/browser/autocomplete/history_url_provider.h"
     23 #include "chrome/browser/autocomplete/keyword_provider.h"
     24 #include "chrome/browser/autocomplete/search_provider.h"
     25 #include "chrome/browser/bookmarks/bookmark_model.h"
     26 #include "chrome/browser/external_protocol_handler.h"
     27 #include "chrome/browser/net/url_fixer_upper.h"
     28 #include "chrome/browser/prefs/pref_service.h"
     29 #include "chrome/browser/profiles/profile.h"
     30 #include "chrome/browser/ui/webui/history_ui.h"
     31 #include "chrome/common/chrome_switches.h"
     32 #include "chrome/common/pref_names.h"
     33 #include "chrome/common/url_constants.h"
     34 #include "content/common/notification_service.h"
     35 #include "googleurl/src/gurl.h"
     36 #include "googleurl/src/url_canon_ip.h"
     37 #include "googleurl/src/url_util.h"
     38 #include "grit/generated_resources.h"
     39 #include "grit/theme_resources.h"
     40 #include "net/base/net_util.h"
     41 #include "net/base/registry_controlled_domain.h"
     42 #include "net/url_request/url_request.h"
     43 #include "ui/base/l10n/l10n_util.h"
     44 
     45 using base::TimeDelta;
     46 
     47 // AutocompleteInput ----------------------------------------------------------
     48 
     49 AutocompleteInput::AutocompleteInput()
     50   : type_(INVALID),
     51     initial_prevent_inline_autocomplete_(false),
     52     prevent_inline_autocomplete_(false),
     53     prefer_keyword_(false),
     54     allow_exact_keyword_match_(true),
     55     matches_requested_(ALL_MATCHES) {
     56 }
     57 
     58 AutocompleteInput::AutocompleteInput(const string16& text,
     59                                      const string16& desired_tld,
     60                                      bool prevent_inline_autocomplete,
     61                                      bool prefer_keyword,
     62                                      bool allow_exact_keyword_match,
     63                                      MatchesRequested matches_requested)
     64     : original_text_(text),
     65       desired_tld_(desired_tld),
     66       initial_prevent_inline_autocomplete_(prevent_inline_autocomplete),
     67       prevent_inline_autocomplete_(prevent_inline_autocomplete),
     68       prefer_keyword_(prefer_keyword),
     69       allow_exact_keyword_match_(allow_exact_keyword_match),
     70       matches_requested_(matches_requested) {
     71   // Trim whitespace from edges of input; don't inline autocomplete if there
     72   // was trailing whitespace.
     73   if (TrimWhitespace(text, TRIM_ALL, &text_) & TRIM_TRAILING)
     74     prevent_inline_autocomplete_ = true;
     75 
     76   GURL canonicalized_url;
     77   type_ = Parse(text_, desired_tld, &parts_, &scheme_, &canonicalized_url);
     78 
     79   if (type_ == INVALID)
     80     return;
     81 
     82   if (((type_ == UNKNOWN) || (type_ == REQUESTED_URL) || (type_ == URL)) &&
     83       canonicalized_url.is_valid() &&
     84       (!canonicalized_url.IsStandard() || canonicalized_url.SchemeIsFile() ||
     85        !canonicalized_url.host().empty()))
     86     canonicalized_url_ = canonicalized_url;
     87 
     88   RemoveForcedQueryStringIfNecessary(type_, &text_);
     89 }
     90 
     91 AutocompleteInput::~AutocompleteInput() {
     92 }
     93 
     94 // static
     95 void AutocompleteInput::RemoveForcedQueryStringIfNecessary(Type type,
     96                                                            string16* text) {
     97   if (type == FORCED_QUERY && !text->empty() && (*text)[0] == L'?')
     98     text->erase(0, 1);
     99 }
    100 
    101 // static
    102 std::string AutocompleteInput::TypeToString(Type type) {
    103   switch (type) {
    104     case INVALID:       return "invalid";
    105     case UNKNOWN:       return "unknown";
    106     case REQUESTED_URL: return "requested-url";
    107     case URL:           return "url";
    108     case QUERY:         return "query";
    109     case FORCED_QUERY:  return "forced-query";
    110 
    111     default:
    112       NOTREACHED();
    113       return std::string();
    114   }
    115 }
    116 
    117 // static
    118 AutocompleteInput::Type AutocompleteInput::Parse(
    119     const string16& text,
    120     const string16& desired_tld,
    121     url_parse::Parsed* parts,
    122     string16* scheme,
    123     GURL* canonicalized_url) {
    124   const size_t first_non_white = text.find_first_not_of(kWhitespaceUTF16, 0);
    125   if (first_non_white == string16::npos)
    126     return INVALID;  // All whitespace.
    127 
    128   if (text.at(first_non_white) == L'?') {
    129     // If the first non-whitespace character is a '?', we magically treat this
    130     // as a query.
    131     return FORCED_QUERY;
    132   }
    133 
    134   // Ask our parsing back-end to help us understand what the user typed.  We
    135   // use the URLFixerUpper here because we want to be smart about what we
    136   // consider a scheme.  For example, we shouldn't consider www.google.com:80
    137   // to have a scheme.
    138   url_parse::Parsed local_parts;
    139   if (!parts)
    140     parts = &local_parts;
    141   const string16 parsed_scheme(URLFixerUpper::SegmentURL(text, parts));
    142   if (scheme)
    143     *scheme = parsed_scheme;
    144   if (canonicalized_url) {
    145     *canonicalized_url = URLFixerUpper::FixupURL(UTF16ToUTF8(text),
    146                                                  UTF16ToUTF8(desired_tld));
    147   }
    148 
    149   if (LowerCaseEqualsASCII(parsed_scheme, chrome::kFileScheme)) {
    150     // A user might or might not type a scheme when entering a file URL.  In
    151     // either case, |parsed_scheme| will tell us that this is a file URL, but
    152     // |parts->scheme| might be empty, e.g. if the user typed "C:\foo".
    153     return URL;
    154   }
    155 
    156   // If the user typed a scheme, and it's HTTP or HTTPS, we know how to parse it
    157   // well enough that we can fall through to the heuristics below.  If it's
    158   // something else, we can just determine our action based on what we do with
    159   // any input of this scheme.  In theory we could do better with some schemes
    160   // (e.g. "ftp" or "view-source") but I'll wait to spend the effort on that
    161   // until I run into some cases that really need it.
    162   if (parts->scheme.is_nonempty() &&
    163       !LowerCaseEqualsASCII(parsed_scheme, chrome::kHttpScheme) &&
    164       !LowerCaseEqualsASCII(parsed_scheme, chrome::kHttpsScheme)) {
    165     // See if we know how to handle the URL internally.
    166     if (net::URLRequest::IsHandledProtocol(UTF16ToASCII(parsed_scheme)))
    167       return URL;
    168 
    169     // There are also some schemes that we convert to other things before they
    170     // reach the renderer or else the renderer handles internally without
    171     // reaching the net::URLRequest logic.  We thus won't catch these above, but
    172     // we should still claim to handle them.
    173     if (LowerCaseEqualsASCII(parsed_scheme, chrome::kViewSourceScheme) ||
    174         LowerCaseEqualsASCII(parsed_scheme, chrome::kJavaScriptScheme) ||
    175         LowerCaseEqualsASCII(parsed_scheme, chrome::kDataScheme))
    176       return URL;
    177 
    178     // Finally, check and see if the user has explicitly opened this scheme as
    179     // a URL before, or if the "scheme" is actually a username.  We need to do
    180     // this last because some schemes (e.g. "javascript") may be treated as
    181     // "blocked" by the external protocol handler because we don't want pages to
    182     // open them, but users still can.
    183     // TODO(viettrungluu): get rid of conversion.
    184     ExternalProtocolHandler::BlockState block_state =
    185         ExternalProtocolHandler::GetBlockState(UTF16ToUTF8(parsed_scheme));
    186     switch (block_state) {
    187       case ExternalProtocolHandler::DONT_BLOCK:
    188         return URL;
    189 
    190       case ExternalProtocolHandler::BLOCK:
    191         // If we don't want the user to open the URL, don't let it be navigated
    192         // to at all.
    193         return QUERY;
    194 
    195       default: {
    196         // We don't know about this scheme.  It might be that the user typed a
    197         // URL of the form "username:password (at) foo.com".
    198         const string16 http_scheme_prefix =
    199             ASCIIToUTF16(std::string(chrome::kHttpScheme) +
    200                          chrome::kStandardSchemeSeparator);
    201         url_parse::Parsed http_parts;
    202         string16 http_scheme;
    203         GURL http_canonicalized_url;
    204         Type http_type = Parse(http_scheme_prefix + text, desired_tld,
    205                                &http_parts, &http_scheme,
    206                                &http_canonicalized_url);
    207         DCHECK_EQ(std::string(chrome::kHttpScheme), UTF16ToUTF8(http_scheme));
    208 
    209         if ((http_type == URL || http_type == REQUESTED_URL) &&
    210             http_parts.username.is_nonempty() &&
    211             http_parts.password.is_nonempty()) {
    212           // Manually re-jigger the parsed parts to match |text| (without the
    213           // http scheme added).
    214           http_parts.scheme.reset();
    215           url_parse::Component* components[] = {
    216             &http_parts.username,
    217             &http_parts.password,
    218             &http_parts.host,
    219             &http_parts.port,
    220             &http_parts.path,
    221             &http_parts.query,
    222             &http_parts.ref,
    223           };
    224           for (size_t i = 0; i < arraysize(components); ++i) {
    225             URLFixerUpper::OffsetComponent(
    226                 -static_cast<int>(http_scheme_prefix.size()), components[i]);
    227           }
    228 
    229           *parts = http_parts;
    230           if (scheme)
    231             scheme->clear();
    232           if (canonicalized_url)
    233             *canonicalized_url = http_canonicalized_url;
    234 
    235           return http_type;
    236         }
    237 
    238         // We don't know about this scheme and it doesn't look like the user
    239         // typed a username and password.  It's likely to be a search operator
    240         // like "site:" or "link:".  We classify it as UNKNOWN so the user has
    241         // the option of treating it as a URL if we're wrong.
    242         // Note that SegmentURL() is smart so we aren't tricked by "c:\foo" or
    243         // "www.example.com:81" in this case.
    244         return UNKNOWN;
    245       }
    246     }
    247   }
    248 
    249   // Either the user didn't type a scheme, in which case we need to distinguish
    250   // between an HTTP URL and a query, or the scheme is HTTP or HTTPS, in which
    251   // case we should reject invalid formulations.
    252 
    253   // If we have an empty host it can't be a URL.
    254   if (!parts->host.is_nonempty())
    255     return QUERY;
    256 
    257   // Likewise, the RCDS can reject certain obviously-invalid hosts.  (We also
    258   // use the registry length later below.)
    259   const string16 host(text.substr(parts->host.begin, parts->host.len));
    260   const size_t registry_length =
    261       net::RegistryControlledDomainService::GetRegistryLength(UTF16ToUTF8(host),
    262                                                               false);
    263   if (registry_length == std::string::npos) {
    264     // Try to append the desired_tld.
    265     if (!desired_tld.empty()) {
    266       string16 host_with_tld(host);
    267       if (host[host.length() - 1] != '.')
    268         host_with_tld += '.';
    269       host_with_tld += desired_tld;
    270       if (net::RegistryControlledDomainService::GetRegistryLength(
    271           UTF16ToUTF8(host_with_tld), false) != std::string::npos)
    272         return REQUESTED_URL;  // Something like "99999999999" that looks like a
    273                                // bad IP address, but becomes valid on attaching
    274                                // a TLD.
    275     }
    276     return QUERY;  // Could be a broken IP address, etc.
    277   }
    278 
    279 
    280   // See if the hostname is valid.  While IE and GURL allow hostnames to contain
    281   // many other characters (perhaps for weird intranet machines), it's extremely
    282   // unlikely that a user would be trying to type those in for anything other
    283   // than a search query.
    284   url_canon::CanonHostInfo host_info;
    285   const std::string canonicalized_host(net::CanonicalizeHost(UTF16ToUTF8(host),
    286                                                              &host_info));
    287   if ((host_info.family == url_canon::CanonHostInfo::NEUTRAL) &&
    288       !net::IsCanonicalizedHostCompliant(canonicalized_host,
    289                                          UTF16ToUTF8(desired_tld))) {
    290     // Invalid hostname.  There are several possible cases:
    291     // * Our checker is too strict and the user pasted in a real-world URL
    292     //   that's "invalid" but resolves.  To catch these, we return UNKNOWN when
    293     //   the user explicitly typed a scheme, so we'll still search by default
    294     //   but we'll show the accidental search infobar if necessary.
    295     // * The user is typing a multi-word query.  If we see a space anywhere in
    296     //   the hostname we assume this is a search and return QUERY.
    297     // * Our checker is too strict and the user is typing a real-world hostname
    298     //   that's "invalid" but resolves.  We return UNKNOWN if the TLD is known.
    299     //   Note that we explicitly excluded hosts with spaces above so that
    300     //   "toys at amazon.com" will be treated as a search.
    301     // * The user is typing some garbage string.  Return QUERY.
    302     //
    303     // Thus we fall down in the following cases:
    304     // * Trying to navigate to a hostname with spaces
    305     // * Trying to navigate to a hostname with invalid characters and an unknown
    306     //   TLD
    307     // These are rare, though probably possible in intranets.
    308     return (parts->scheme.is_nonempty() ||
    309            ((registry_length != 0) && (host.find(' ') == string16::npos))) ?
    310         UNKNOWN : QUERY;
    311   }
    312 
    313   // A port number is a good indicator that this is a URL.  However, it might
    314   // also be a query like "1.66:1" that looks kind of like an IP address and
    315   // port number. So here we only check for "port numbers" that are illegal and
    316   // thus mean this can't be navigated to (e.g. "1.2.3.4:garbage"), and we save
    317   // handling legal port numbers until after the "IP address" determination
    318   // below.
    319   if (parts->port.is_nonempty()) {
    320     int port;
    321     if (!base::StringToInt(text.substr(parts->port.begin, parts->port.len),
    322                            &port) ||
    323         (port < 0) || (port > 65535))
    324       return QUERY;
    325   }
    326 
    327   // Now that we've ruled out all schemes other than http or https and done a
    328   // little more sanity checking, the presence of a scheme means this is likely
    329   // a URL.
    330   if (parts->scheme.is_nonempty())
    331     return URL;
    332 
    333   // See if the host is an IP address.
    334   if (host_info.family == url_canon::CanonHostInfo::IPV4) {
    335     // If the user originally typed a host that looks like an IP address (a
    336     // dotted quad), they probably want to open it.  If the original input was
    337     // something else (like a single number), they probably wanted to search for
    338     // it, unless they explicitly typed a scheme.  This is true even if the URL
    339     // appears to have a path: "1.2/45" is more likely a search (for the answer
    340     // to a math problem) than a URL.
    341     if (host_info.num_ipv4_components == 4)
    342       return URL;
    343     return desired_tld.empty() ? UNKNOWN : REQUESTED_URL;
    344   }
    345   if (host_info.family == url_canon::CanonHostInfo::IPV6)
    346     return URL;
    347 
    348   // Now that we've ruled out invalid ports and queries that look like they have
    349   // a port, the presence of a port means this is likely a URL.
    350   if (parts->port.is_nonempty())
    351     return URL;
    352 
    353   // Presence of a password means this is likely a URL.  Note that unless the
    354   // user has typed an explicit "http://" or similar, we'll probably think that
    355   // the username is some unknown scheme, and bail out in the scheme-handling
    356   // code above.
    357   if (parts->password.is_nonempty())
    358     return URL;
    359 
    360   // The host doesn't look like a number, so see if the user's given us a path.
    361   if (parts->path.is_nonempty()) {
    362     // Most inputs with paths are URLs, even ones without known registries (e.g.
    363     // intranet URLs).  However, if there's no known registry and the path has
    364     // a space, this is more likely a query with a slash in the first term
    365     // (e.g. "ps/2 games") than a URL.  We can still open URLs with spaces in
    366     // the path by escaping the space, and we will still inline autocomplete
    367     // them if users have typed them in the past, but we default to searching
    368     // since that's the common case.
    369     return ((registry_length == 0) &&
    370             (text.substr(parts->path.begin, parts->path.len).find(' ') !=
    371                 string16::npos)) ? UNKNOWN : URL;
    372   }
    373 
    374   // If we reach here with a username, our input looks like "user@host".
    375   // Because there is no scheme explicitly specified, we think this is more
    376   // likely an email address than an HTTP auth attempt.  Hence, we search by
    377   // default and let users correct us on a case-by-case basis.
    378   if (parts->username.is_nonempty())
    379     return UNKNOWN;
    380 
    381   // We have a bare host string.  If it has a known TLD, it's probably a URL.
    382   if (registry_length != 0)
    383     return URL;
    384 
    385   // No TLD that we know about.  This could be:
    386   // * A string that the user wishes to add a desired_tld to to get a URL.  If
    387   //   we reach this point, we know there's no known TLD on the string, so the
    388   //   fixup code will be willing to add one; thus this is a URL.
    389   // * A single word "foo"; possibly an intranet site, but more likely a search.
    390   //   This is ideally an UNKNOWN, and we can let the Alternate Nav URL code
    391   //   catch our mistakes.
    392   // * A URL with a valid TLD we don't know about yet.  If e.g. a registrar adds
    393   //   "xxx" as a TLD, then until we add it to our data file, Chrome won't know
    394   //   "foo.xxx" is a real URL.  So ideally this is a URL, but we can't really
    395   //   distinguish this case from:
    396   // * A "URL-like" string that's not really a URL (like
    397   //   "browser.tabs.closeButtons" or "java.awt.event.*").  This is ideally a
    398   //   QUERY.  Since the above case and this one are indistinguishable, and this
    399   //   case is likely to be much more common, just say these are both UNKNOWN,
    400   //   which should default to the right thing and let users correct us on a
    401   //   case-by-case basis.
    402   return desired_tld.empty() ? UNKNOWN : REQUESTED_URL;
    403 }
    404 
    405 // static
    406 void AutocompleteInput::ParseForEmphasizeComponents(
    407     const string16& text,
    408     const string16& desired_tld,
    409     url_parse::Component* scheme,
    410     url_parse::Component* host) {
    411   url_parse::Parsed parts;
    412   string16 scheme_str;
    413   Parse(text, desired_tld, &parts, &scheme_str, NULL);
    414 
    415   *scheme = parts.scheme;
    416   *host = parts.host;
    417 
    418   int after_scheme_and_colon = parts.scheme.end() + 1;
    419   // For the view-source scheme, we should emphasize the scheme and host of the
    420   // URL qualified by the view-source prefix.
    421   if (LowerCaseEqualsASCII(scheme_str, chrome::kViewSourceScheme) &&
    422       (static_cast<int>(text.length()) > after_scheme_and_colon)) {
    423     // Obtain the URL prefixed by view-source and parse it.
    424     string16 real_url(text.substr(after_scheme_and_colon));
    425     url_parse::Parsed real_parts;
    426     AutocompleteInput::Parse(real_url, desired_tld, &real_parts, NULL, NULL);
    427     if (real_parts.scheme.is_nonempty() || real_parts.host.is_nonempty()) {
    428       if (real_parts.scheme.is_nonempty()) {
    429         *scheme = url_parse::Component(
    430             after_scheme_and_colon + real_parts.scheme.begin,
    431             real_parts.scheme.len);
    432       } else {
    433         scheme->reset();
    434       }
    435       if (real_parts.host.is_nonempty()) {
    436         *host = url_parse::Component(
    437             after_scheme_and_colon + real_parts.host.begin,
    438             real_parts.host.len);
    439       } else {
    440         host->reset();
    441       }
    442     }
    443   }
    444 }
    445 
    446 // static
    447 string16 AutocompleteInput::FormattedStringWithEquivalentMeaning(
    448     const GURL& url,
    449     const string16& formatted_url) {
    450   if (!net::CanStripTrailingSlash(url))
    451     return formatted_url;
    452   const string16 url_with_path(formatted_url + char16('/'));
    453   return (AutocompleteInput::Parse(formatted_url, string16(), NULL, NULL,
    454                                    NULL) ==
    455           AutocompleteInput::Parse(url_with_path, string16(), NULL, NULL,
    456                                    NULL)) ?
    457       formatted_url : url_with_path;
    458 }
    459 
    460 
    461 bool AutocompleteInput::Equals(const AutocompleteInput& other) const {
    462   return (text_ == other.text_) &&
    463          (type_ == other.type_) &&
    464          (desired_tld_ == other.desired_tld_) &&
    465          (scheme_ == other.scheme_) &&
    466          (prevent_inline_autocomplete_ == other.prevent_inline_autocomplete_) &&
    467          (prefer_keyword_ == other.prefer_keyword_) &&
    468          (matches_requested_ == other.matches_requested_);
    469 }
    470 
    471 void AutocompleteInput::Clear() {
    472   text_.clear();
    473   type_ = INVALID;
    474   parts_ = url_parse::Parsed();
    475   scheme_.clear();
    476   desired_tld_.clear();
    477   prevent_inline_autocomplete_ = false;
    478   prefer_keyword_ = false;
    479 }
    480 
    481 // AutocompleteProvider -------------------------------------------------------
    482 
    483 // static
    484 const size_t AutocompleteProvider::kMaxMatches = 3;
    485 
    486 AutocompleteProvider::ACProviderListener::~ACProviderListener() {
    487 }
    488 
    489 AutocompleteProvider::AutocompleteProvider(ACProviderListener* listener,
    490                                            Profile* profile,
    491                                            const char* name)
    492     : profile_(profile),
    493       listener_(listener),
    494       done_(true),
    495       name_(name) {
    496 }
    497 
    498 void AutocompleteProvider::SetProfile(Profile* profile) {
    499   DCHECK(profile);
    500   DCHECK(done_);  // The controller should have already stopped us.
    501   profile_ = profile;
    502 }
    503 
    504 void AutocompleteProvider::Stop() {
    505   done_ = true;
    506 }
    507 
    508 void AutocompleteProvider::DeleteMatch(const AutocompleteMatch& match) {
    509 }
    510 
    511 AutocompleteProvider::~AutocompleteProvider() {
    512   Stop();
    513 }
    514 
    515 // static
    516 bool AutocompleteProvider::HasHTTPScheme(const string16& input) {
    517   std::string utf8_input(UTF16ToUTF8(input));
    518   url_parse::Component scheme;
    519   if (url_util::FindAndCompareScheme(utf8_input, chrome::kViewSourceScheme,
    520                                      &scheme))
    521     utf8_input.erase(0, scheme.end() + 1);
    522   return url_util::FindAndCompareScheme(utf8_input, chrome::kHttpScheme, NULL);
    523 }
    524 
    525 void AutocompleteProvider::UpdateStarredStateOfMatches() {
    526   if (matches_.empty())
    527     return;
    528 
    529   if (!profile_)
    530     return;
    531   BookmarkModel* bookmark_model = profile_->GetBookmarkModel();
    532   if (!bookmark_model || !bookmark_model->IsLoaded())
    533     return;
    534 
    535   for (ACMatches::iterator i = matches_.begin(); i != matches_.end(); ++i)
    536     i->starred = bookmark_model->IsBookmarked(GURL(i->destination_url));
    537 }
    538 
    539 string16 AutocompleteProvider::StringForURLDisplay(const GURL& url,
    540                                                    bool check_accept_lang,
    541                                                    bool trim_http) const {
    542   std::string languages = (check_accept_lang && profile_) ?
    543       profile_->GetPrefs()->GetString(prefs::kAcceptLanguages) : std::string();
    544   return net::FormatUrl(
    545       url,
    546       languages,
    547       net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP),
    548       UnescapeRule::SPACES, NULL, NULL, NULL);
    549 }
    550 
    551 // AutocompleteResult ---------------------------------------------------------
    552 
    553 // static
    554 const size_t AutocompleteResult::kMaxMatches = 6;
    555 
    556 void AutocompleteResult::Selection::Clear() {
    557   destination_url = GURL();
    558   provider_affinity = NULL;
    559   is_history_what_you_typed_match = false;
    560 }
    561 
    562 AutocompleteResult::AutocompleteResult() {
    563   // Reserve space for the max number of matches we'll show.
    564   matches_.reserve(kMaxMatches);
    565 
    566   // It's probably safe to do this in the initializer list, but there's little
    567   // penalty to doing it here and it ensures our object is fully constructed
    568   // before calling member functions.
    569   default_match_ = end();
    570 }
    571 
    572 AutocompleteResult::~AutocompleteResult() {}
    573 
    574 void AutocompleteResult::CopyFrom(const AutocompleteResult& rhs) {
    575   if (this == &rhs)
    576     return;
    577 
    578   matches_ = rhs.matches_;
    579   // Careful!  You can't just copy iterators from another container, you have to
    580   // reconstruct them.
    581   default_match_ = (rhs.default_match_ == rhs.end()) ?
    582       end() : (begin() + (rhs.default_match_ - rhs.begin()));
    583 
    584   alternate_nav_url_ = rhs.alternate_nav_url_;
    585 }
    586 
    587 void AutocompleteResult::CopyOldMatches(const AutocompleteInput& input,
    588                                         const AutocompleteResult& old_matches) {
    589   if (old_matches.empty())
    590     return;
    591 
    592   if (empty()) {
    593     // If we've got no matches we can copy everything from the last result.
    594     CopyFrom(old_matches);
    595     for (ACMatches::iterator i = begin(); i != end(); ++i)
    596       i->from_previous = true;
    597     return;
    598   }
    599 
    600   // In hopes of providing a stable popup we try to keep the number of matches
    601   // per provider consistent. Other schemes (such as blindly copying the most
    602   // relevant matches) typically result in many successive 'What You Typed'
    603   // results filling all the matches, which looks awful.
    604   //
    605   // Instead of starting with the current matches and then adding old matches
    606   // until we hit our overall limit, we copy enough old matches so that each
    607   // provider has at least as many as before, and then use SortAndCull() to
    608   // clamp globally. This way, old high-relevance matches will starve new
    609   // low-relevance matches, under the assumption that the new matches will
    610   // ultimately be similar.  If the assumption holds, this prevents seeing the
    611   // new low-relevance match appear and then quickly get pushed off the bottom;
    612   // if it doesn't, then once the providers are done and we expire the old
    613   // matches, the new ones will all become visible, so we won't have lost
    614   // anything permanently.
    615   ProviderToMatches matches_per_provider, old_matches_per_provider;
    616   BuildProviderToMatches(&matches_per_provider);
    617   old_matches.BuildProviderToMatches(&old_matches_per_provider);
    618   for (ProviderToMatches::const_iterator i = old_matches_per_provider.begin();
    619        i != old_matches_per_provider.end(); ++i) {
    620     MergeMatchesByProvider(i->second, matches_per_provider[i->first]);
    621   }
    622 
    623   SortAndCull(input);
    624 }
    625 
    626 void AutocompleteResult::AppendMatches(const ACMatches& matches) {
    627   std::copy(matches.begin(), matches.end(), std::back_inserter(matches_));
    628   default_match_ = end();
    629   alternate_nav_url_ = GURL();
    630 }
    631 
    632 void AutocompleteResult::AddMatch(const AutocompleteMatch& match) {
    633   DCHECK(default_match_ != end());
    634   ACMatches::iterator insertion_point =
    635       std::upper_bound(begin(), end(), match, &AutocompleteMatch::MoreRelevant);
    636   ACMatches::iterator::difference_type default_offset =
    637       default_match_ - begin();
    638   if ((insertion_point - begin()) <= default_offset)
    639     ++default_offset;
    640   matches_.insert(insertion_point, match);
    641   default_match_ = begin() + default_offset;
    642 }
    643 
    644 void AutocompleteResult::SortAndCull(const AutocompleteInput& input) {
    645   // Remove duplicates.
    646   std::sort(matches_.begin(), matches_.end(),
    647             &AutocompleteMatch::DestinationSortFunc);
    648   matches_.erase(std::unique(matches_.begin(), matches_.end(),
    649                              &AutocompleteMatch::DestinationsEqual),
    650                  matches_.end());
    651 
    652   // Sort and trim to the most relevant kMaxMatches matches.
    653   const size_t num_matches = std::min(kMaxMatches, matches_.size());
    654   std::partial_sort(matches_.begin(), matches_.begin() + num_matches,
    655                     matches_.end(), &AutocompleteMatch::MoreRelevant);
    656   matches_.resize(num_matches);
    657 
    658   default_match_ = begin();
    659 
    660   // Set the alternate nav URL.
    661   alternate_nav_url_ = GURL();
    662   if (((input.type() == AutocompleteInput::UNKNOWN) ||
    663        (input.type() == AutocompleteInput::REQUESTED_URL)) &&
    664       (default_match_ != end()) &&
    665       (default_match_->transition != PageTransition::TYPED) &&
    666       (default_match_->transition != PageTransition::KEYWORD) &&
    667       (input.canonicalized_url() != default_match_->destination_url))
    668     alternate_nav_url_ = input.canonicalized_url();
    669 }
    670 
    671 bool AutocompleteResult::HasCopiedMatches() const {
    672   for (ACMatches::const_iterator i = begin(); i != end(); ++i) {
    673     if (i->from_previous)
    674       return true;
    675   }
    676   return false;
    677 }
    678 
    679 size_t AutocompleteResult::size() const {
    680   return matches_.size();
    681 }
    682 
    683 bool AutocompleteResult::empty() const {
    684   return matches_.empty();
    685 }
    686 
    687 AutocompleteResult::const_iterator AutocompleteResult::begin() const {
    688   return matches_.begin();
    689 }
    690 
    691 AutocompleteResult::iterator AutocompleteResult::begin() {
    692   return matches_.begin();
    693 }
    694 
    695 AutocompleteResult::const_iterator AutocompleteResult::end() const {
    696   return matches_.end();
    697 }
    698 
    699 AutocompleteResult::iterator AutocompleteResult::end() {
    700   return matches_.end();
    701 }
    702 
    703 // Returns the match at the given index.
    704 const AutocompleteMatch& AutocompleteResult::match_at(size_t index) const {
    705   DCHECK(index < matches_.size());
    706   return matches_[index];
    707 }
    708 
    709 void AutocompleteResult::Reset() {
    710   matches_.clear();
    711   default_match_ = end();
    712 }
    713 
    714 void AutocompleteResult::Swap(AutocompleteResult* other) {
    715   const size_t default_match_offset = default_match_ - begin();
    716   const size_t other_default_match_offset =
    717       other->default_match_ - other->begin();
    718   matches_.swap(other->matches_);
    719   default_match_ = begin() + other_default_match_offset;
    720   other->default_match_ = other->begin() + default_match_offset;
    721   alternate_nav_url_.Swap(&(other->alternate_nav_url_));
    722 }
    723 
    724 #ifndef NDEBUG
    725 void AutocompleteResult::Validate() const {
    726   for (const_iterator i(begin()); i != end(); ++i)
    727     i->Validate();
    728 }
    729 #endif
    730 
    731 void AutocompleteResult::BuildProviderToMatches(
    732     ProviderToMatches* provider_to_matches) const {
    733   for (ACMatches::const_iterator i = begin(); i != end(); ++i)
    734     (*provider_to_matches)[i->provider].push_back(*i);
    735 }
    736 
    737 // static
    738 bool AutocompleteResult::HasMatchByDestination(const AutocompleteMatch& match,
    739                                                const ACMatches& matches) {
    740   for (ACMatches::const_iterator i = matches.begin(); i != matches.end(); ++i) {
    741     if (i->destination_url == match.destination_url)
    742       return true;
    743   }
    744   return false;
    745 }
    746 
    747 void AutocompleteResult::MergeMatchesByProvider(const ACMatches& old_matches,
    748                                                 const ACMatches& new_matches) {
    749   if (new_matches.size() >= old_matches.size())
    750     return;
    751 
    752   size_t delta = old_matches.size() - new_matches.size();
    753   const int max_relevance = (new_matches.empty() ?
    754       matches_.front().relevance : new_matches[0].relevance) - 1;
    755   // Because the goal is a visibly-stable popup, rather than one that preserves
    756   // the highest-relevance matches, we copy in the lowest-relevance matches
    757   // first. This means that within each provider's "group" of matches, any
    758   // synchronous matches (which tend to have the highest scores) will
    759   // "overwrite" the initial matches from that provider's previous results,
    760   // minimally disturbing the rest of the matches.
    761   for (ACMatches::const_reverse_iterator i = old_matches.rbegin();
    762        i != old_matches.rend() && delta > 0; ++i) {
    763     if (!HasMatchByDestination(*i, new_matches)) {
    764       AutocompleteMatch match = *i;
    765       match.relevance = std::min(max_relevance, match.relevance);
    766       match.from_previous = true;
    767       AddMatch(match);
    768       delta--;
    769     }
    770   }
    771 }
    772 
    773 // AutocompleteController -----------------------------------------------------
    774 
    775 const int AutocompleteController::kNoItemSelected = -1;
    776 
    777 // Amount of time (in ms) between when the user stops typing and when we remove
    778 // any copied entries. We do this from the time the user stopped typing as some
    779 // providers (such as SearchProvider) wait for the user to stop typing before
    780 // they initiate a query.
    781 static const int kExpireTimeMS = 500;
    782 
    783 AutocompleteController::AutocompleteController(
    784     Profile* profile,
    785     AutocompleteControllerDelegate* delegate)
    786     : delegate_(delegate),
    787       done_(true),
    788       in_start_(false) {
    789   search_provider_ = new SearchProvider(this, profile);
    790   providers_.push_back(search_provider_);
    791   if (CommandLine::ForCurrentProcess()->HasSwitch(
    792           switches::kEnableHistoryQuickProvider) &&
    793       !CommandLine::ForCurrentProcess()->HasSwitch(
    794           switches::kDisableHistoryQuickProvider))
    795     providers_.push_back(new HistoryQuickProvider(this, profile));
    796   if (!CommandLine::ForCurrentProcess()->HasSwitch(
    797       switches::kDisableHistoryURLProvider))
    798     providers_.push_back(new HistoryURLProvider(this, profile));
    799   providers_.push_back(new KeywordProvider(this, profile));
    800   providers_.push_back(new HistoryContentsProvider(this, profile));
    801   providers_.push_back(new BuiltinProvider(this, profile));
    802   providers_.push_back(new ExtensionAppProvider(this, profile));
    803   for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i)
    804     (*i)->AddRef();
    805 }
    806 
    807 AutocompleteController::~AutocompleteController() {
    808   // The providers may have tasks outstanding that hold refs to them.  We need
    809   // to ensure they won't call us back if they outlive us.  (Practically,
    810   // calling Stop() should also cancel those tasks and make it so that we hold
    811   // the only refs.)  We also don't want to bother notifying anyone of our
    812   // result changes here, because the notification observer is in the midst of
    813   // shutdown too, so we don't ask Stop() to clear |result_| (and notify).
    814   result_.Reset();  // Not really necessary.
    815   Stop(false);
    816 
    817   for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i)
    818     (*i)->Release();
    819 
    820   providers_.clear();  // Not really necessary.
    821 }
    822 
    823 void AutocompleteController::SetProfile(Profile* profile) {
    824   Stop(true);
    825   for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i)
    826     (*i)->SetProfile(profile);
    827   input_.Clear();  // Ensure we don't try to do a "minimal_changes" query on a
    828                    // different profile.
    829 }
    830 
    831 void AutocompleteController::Start(
    832     const string16& text,
    833     const string16& desired_tld,
    834     bool prevent_inline_autocomplete,
    835     bool prefer_keyword,
    836     bool allow_exact_keyword_match,
    837     AutocompleteInput::MatchesRequested matches_requested) {
    838   const string16 old_input_text(input_.text());
    839   const AutocompleteInput::MatchesRequested old_matches_requested =
    840       input_.matches_requested();
    841   input_ = AutocompleteInput(text, desired_tld, prevent_inline_autocomplete,
    842       prefer_keyword, allow_exact_keyword_match, matches_requested);
    843 
    844   // See if we can avoid rerunning autocomplete when the query hasn't changed
    845   // much.  When the user presses or releases the ctrl key, the desired_tld
    846   // changes, and when the user finishes an IME composition, inline autocomplete
    847   // may no longer be prevented.  In both these cases the text itself hasn't
    848   // changed since the last query, and some providers can do much less work (and
    849   // get matches back more quickly).  Taking advantage of this reduces flicker.
    850   //
    851   // NOTE: This comes after constructing |input_| above since that construction
    852   // can change the text string (e.g. by stripping off a leading '?').
    853   const bool minimal_changes = (input_.text() == old_input_text) &&
    854       (input_.matches_requested() == old_matches_requested);
    855 
    856   expire_timer_.Stop();
    857 
    858   // Start the new query.
    859   in_start_ = true;
    860   base::TimeTicks start_time = base::TimeTicks::Now();
    861   for (ACProviders::iterator i(providers_.begin()); i != providers_.end();
    862        ++i) {
    863     (*i)->Start(input_, minimal_changes);
    864     if (matches_requested != AutocompleteInput::ALL_MATCHES)
    865       DCHECK((*i)->done());
    866   }
    867   if (matches_requested == AutocompleteInput::ALL_MATCHES && text.size() < 6) {
    868     base::TimeTicks end_time = base::TimeTicks::Now();
    869     std::string name = "Omnibox.QueryTime." + base::IntToString(text.size());
    870     base::Histogram* counter = base::Histogram::FactoryGet(
    871         name, 1, 1000, 50, base::Histogram::kUmaTargetedHistogramFlag);
    872     counter->Add(static_cast<int>((end_time - start_time).InMilliseconds()));
    873   }
    874   in_start_ = false;
    875   CheckIfDone();
    876   UpdateResult(true);
    877 
    878   if (!done_)
    879     StartExpireTimer();
    880 }
    881 
    882 void AutocompleteController::Stop(bool clear_result) {
    883   for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end();
    884        ++i) {
    885     (*i)->Stop();
    886   }
    887 
    888   expire_timer_.Stop();
    889   done_ = true;
    890   if (clear_result && !result_.empty()) {
    891     result_.Reset();
    892     // NOTE: We pass in false since we're trying to only clear the popup, not
    893     // touch the edit... this is all a mess and should be cleaned up :(
    894     NotifyChanged(false);
    895   }
    896 }
    897 
    898 void AutocompleteController::DeleteMatch(const AutocompleteMatch& match) {
    899   DCHECK(match.deletable);
    900   match.provider->DeleteMatch(match);  // This may synchronously call back to
    901                                        // OnProviderUpdate().
    902   // If DeleteMatch resulted in a callback to OnProviderUpdate and we're
    903   // not done, we might attempt to redisplay the deleted match. Make sure
    904   // we aren't displaying it by removing any old entries.
    905   ExpireCopiedEntries();
    906 }
    907 
    908 void AutocompleteController::ExpireCopiedEntries() {
    909   // Clear out the results. This ensures no results from the previous result set
    910   // are copied over.
    911   result_.Reset();
    912   // We allow matches from the previous result set to starve out matches from
    913   // the new result set. This means in order to expire matches we have to query
    914   // the providers again.
    915   UpdateResult(false);
    916 }
    917 
    918 void AutocompleteController::OnProviderUpdate(bool updated_matches) {
    919   CheckIfDone();
    920   // Multiple providers may provide synchronous results, so we only update the
    921   // results if we're not in Start().
    922   if (!in_start_ && (updated_matches || done_))
    923     UpdateResult(false);
    924 }
    925 
    926 void AutocompleteController::UpdateResult(bool is_synchronous_pass) {
    927   AutocompleteResult last_result;
    928   last_result.Swap(&result_);
    929 
    930   for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end();
    931        ++i)
    932     result_.AppendMatches((*i)->matches());
    933 
    934   // Sort the matches and trim to a small number of "best" matches.
    935   result_.SortAndCull(input_);
    936 
    937   // Need to validate before invoking CopyOldMatches as the old matches are not
    938   // valid against the current input.
    939 #ifndef NDEBUG
    940   result_.Validate();
    941 #endif
    942 
    943   if (!done_) {
    944     // This conditional needs to match the conditional in Start that invokes
    945     // StartExpireTimer.
    946     result_.CopyOldMatches(input_, last_result);
    947   }
    948 
    949   bool notify_default_match = is_synchronous_pass;
    950   if (!is_synchronous_pass) {
    951     const bool last_default_was_valid =
    952         last_result.default_match() != last_result.end();
    953     const bool default_is_valid = result_.default_match() != result_.end();
    954     // We've gotten async results. Send notification that the default match
    955     // updated if fill_into_edit differs. We don't check the URL as that may
    956     // change for the default match even though the fill into edit hasn't
    957     // changed (see SearchProvider for one case of this).
    958     notify_default_match =
    959         (last_default_was_valid != default_is_valid) ||
    960         (default_is_valid &&
    961          (result_.default_match()->fill_into_edit !=
    962           last_result.default_match()->fill_into_edit));
    963   }
    964 
    965   NotifyChanged(notify_default_match);
    966 }
    967 
    968 void AutocompleteController::NotifyChanged(bool notify_default_match) {
    969   if (delegate_)
    970     delegate_->OnResultChanged(notify_default_match);
    971   if (done_) {
    972     NotificationService::current()->Notify(
    973         NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_READY,
    974         Source<AutocompleteController>(this),
    975         NotificationService::NoDetails());
    976   }
    977 }
    978 
    979 void AutocompleteController::CheckIfDone() {
    980   for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end();
    981        ++i) {
    982     if (!(*i)->done()) {
    983       done_ = false;
    984       return;
    985     }
    986   }
    987   done_ = true;
    988 }
    989 
    990 void AutocompleteController::StartExpireTimer() {
    991   if (result_.HasCopiedMatches())
    992     expire_timer_.Start(base::TimeDelta::FromMilliseconds(kExpireTimeMS),
    993                         this, &AutocompleteController::ExpireCopiedEntries);
    994 }
    995