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