cc: Convert LTHCommon tests to LayerImpl
[chromium-blink-merge.git] / components / omnibox / browser / autocomplete_input.cc
blobc8b744a5ec4872992ff70408d7938765ce94215a
1 // Copyright 2014 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.
5 #include "components/omnibox/browser/autocomplete_input.h"
7 #include "base/strings/string_split.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "components/metrics/proto/omnibox_event.pb.h"
11 #include "components/omnibox/browser/autocomplete_scheme_classifier.h"
12 #include "components/omnibox/browser/omnibox_field_trial.h"
13 #include "components/url_fixer/url_fixer.h"
14 #include "net/base/net_util.h"
15 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
16 #include "url/url_canon_ip.h"
17 #include "url/url_util.h"
19 namespace {
21 // Hardcode constant to avoid any dependencies on content/.
22 const char kViewSourceScheme[] = "view-source";
24 void AdjustCursorPositionIfNecessary(size_t num_leading_chars_removed,
25 size_t* cursor_position) {
26 if (*cursor_position == base::string16::npos)
27 return;
28 if (num_leading_chars_removed < *cursor_position)
29 *cursor_position -= num_leading_chars_removed;
30 else
31 *cursor_position = 0;
34 // Finds all terms in |text| that start with http:// or https:// plus at least
35 // one more character and puts the text after the prefix in
36 // |terms_prefixed_by_http_or_https|.
37 void PopulateTermsPrefixedByHttpOrHttps(
38 const base::string16& text,
39 std::vector<base::string16>* terms_prefixed_by_http_or_https) {
40 // Split on whitespace rather than use ICU's word iterator because, for
41 // example, ICU's iterator may break on punctuation (such as ://) or decide
42 // to split a single term in a hostname (if it seems to think that the
43 // hostname is multiple words). Neither of these behaviors is desirable.
44 const std::string separator(url::kStandardSchemeSeparator);
45 for (const auto& term :
46 base::SplitString(text, base::ASCIIToUTF16(" "),
47 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
48 const std::string term_utf8(base::UTF16ToUTF8(term));
49 static const char* kSchemes[2] = { url::kHttpScheme, url::kHttpsScheme };
50 for (const char* scheme : kSchemes) {
51 const std::string prefix(scheme + separator);
52 // Doing an ASCII comparison is okay because prefix is ASCII.
53 if (base::StartsWith(term_utf8, prefix,
54 base::CompareCase::INSENSITIVE_ASCII) &&
55 (term_utf8.length() > prefix.length())) {
56 terms_prefixed_by_http_or_https->push_back(
57 term.substr(prefix.length()));
63 } // namespace
65 AutocompleteInput::AutocompleteInput()
66 : cursor_position_(base::string16::npos),
67 current_page_classification_(metrics::OmniboxEventProto::INVALID_SPEC),
68 type_(metrics::OmniboxInputType::INVALID),
69 prevent_inline_autocomplete_(false),
70 prefer_keyword_(false),
71 allow_exact_keyword_match_(true),
72 want_asynchronous_matches_(true),
73 from_omnibox_focus_(false) {
76 AutocompleteInput::AutocompleteInput(
77 const base::string16& text,
78 size_t cursor_position,
79 const std::string& desired_tld,
80 const GURL& current_url,
81 metrics::OmniboxEventProto::PageClassification current_page_classification,
82 bool prevent_inline_autocomplete,
83 bool prefer_keyword,
84 bool allow_exact_keyword_match,
85 bool want_asynchronous_matches,
86 bool from_omnibox_focus,
87 const AutocompleteSchemeClassifier& scheme_classifier)
88 : cursor_position_(cursor_position),
89 current_url_(current_url),
90 current_page_classification_(current_page_classification),
91 prevent_inline_autocomplete_(prevent_inline_autocomplete),
92 prefer_keyword_(prefer_keyword),
93 allow_exact_keyword_match_(allow_exact_keyword_match),
94 want_asynchronous_matches_(want_asynchronous_matches),
95 from_omnibox_focus_(from_omnibox_focus) {
96 DCHECK(cursor_position <= text.length() ||
97 cursor_position == base::string16::npos)
98 << "Text: '" << text << "', cp: " << cursor_position;
99 // None of the providers care about leading white space so we always trim it.
100 // Providers that care about trailing white space handle trimming themselves.
101 if ((base::TrimWhitespace(text, base::TRIM_LEADING, &text_) &
102 base::TRIM_LEADING) != 0)
103 AdjustCursorPositionIfNecessary(text.length() - text_.length(),
104 &cursor_position_);
106 GURL canonicalized_url;
107 type_ = Parse(text_, desired_tld, scheme_classifier, &parts_, &scheme_,
108 &canonicalized_url);
109 PopulateTermsPrefixedByHttpOrHttps(text_, &terms_prefixed_by_http_or_https_);
111 if (type_ == metrics::OmniboxInputType::INVALID)
112 return;
114 if (((type_ == metrics::OmniboxInputType::UNKNOWN) ||
115 (type_ == metrics::OmniboxInputType::URL)) &&
116 canonicalized_url.is_valid() &&
117 (!canonicalized_url.IsStandard() || canonicalized_url.SchemeIsFile() ||
118 canonicalized_url.SchemeIsFileSystem() ||
119 !canonicalized_url.host().empty()))
120 canonicalized_url_ = canonicalized_url;
122 size_t chars_removed = RemoveForcedQueryStringIfNecessary(type_, &text_);
123 AdjustCursorPositionIfNecessary(chars_removed, &cursor_position_);
124 if (chars_removed) {
125 // Remove spaces between opening question mark and first actual character.
126 base::string16 trimmed_text;
127 if ((base::TrimWhitespace(text_, base::TRIM_LEADING, &trimmed_text) &
128 base::TRIM_LEADING) != 0) {
129 AdjustCursorPositionIfNecessary(text_.length() - trimmed_text.length(),
130 &cursor_position_);
131 text_ = trimmed_text;
136 AutocompleteInput::~AutocompleteInput() {
139 // static
140 size_t AutocompleteInput::RemoveForcedQueryStringIfNecessary(
141 metrics::OmniboxInputType::Type type,
142 base::string16* text) {
143 if ((type != metrics::OmniboxInputType::FORCED_QUERY) || text->empty() ||
144 (*text)[0] != L'?')
145 return 0;
146 // Drop the leading '?'.
147 text->erase(0, 1);
148 return 1;
151 // static
152 std::string AutocompleteInput::TypeToString(
153 metrics::OmniboxInputType::Type type) {
154 switch (type) {
155 case metrics::OmniboxInputType::INVALID: return "invalid";
156 case metrics::OmniboxInputType::UNKNOWN: return "unknown";
157 case metrics::OmniboxInputType::DEPRECATED_REQUESTED_URL:
158 return "deprecated-requested-url";
159 case metrics::OmniboxInputType::URL: return "url";
160 case metrics::OmniboxInputType::QUERY: return "query";
161 case metrics::OmniboxInputType::FORCED_QUERY: return "forced-query";
163 return std::string();
166 // static
167 metrics::OmniboxInputType::Type AutocompleteInput::Parse(
168 const base::string16& text,
169 const std::string& desired_tld,
170 const AutocompleteSchemeClassifier& scheme_classifier,
171 url::Parsed* parts,
172 base::string16* scheme,
173 GURL* canonicalized_url) {
174 size_t first_non_white = text.find_first_not_of(base::kWhitespaceUTF16, 0);
175 if (first_non_white == base::string16::npos)
176 return metrics::OmniboxInputType::INVALID; // All whitespace.
178 if (text[first_non_white] == L'?') {
179 // If the first non-whitespace character is a '?', we magically treat this
180 // as a query.
181 return metrics::OmniboxInputType::FORCED_QUERY;
184 // Ask our parsing back-end to help us understand what the user typed. We
185 // use the URLFixerUpper here because we want to be smart about what we
186 // consider a scheme. For example, we shouldn't consider www.google.com:80
187 // to have a scheme.
188 url::Parsed local_parts;
189 if (!parts)
190 parts = &local_parts;
191 const base::string16 parsed_scheme(url_fixer::SegmentURL(text, parts));
192 if (scheme)
193 *scheme = parsed_scheme;
194 const std::string parsed_scheme_utf8(base::UTF16ToUTF8(parsed_scheme));
196 // If we can't canonicalize the user's input, the rest of the autocomplete
197 // system isn't going to be able to produce a navigable URL match for it.
198 // So we just return QUERY immediately in these cases.
199 GURL placeholder_canonicalized_url;
200 if (!canonicalized_url)
201 canonicalized_url = &placeholder_canonicalized_url;
202 *canonicalized_url =
203 url_fixer::FixupURL(base::UTF16ToUTF8(text), desired_tld);
204 if (!canonicalized_url->is_valid())
205 return metrics::OmniboxInputType::QUERY;
207 if (base::LowerCaseEqualsASCII(parsed_scheme_utf8, url::kFileScheme)) {
208 // A user might or might not type a scheme when entering a file URL. In
209 // either case, |parsed_scheme_utf8| will tell us that this is a file URL,
210 // but |parts->scheme| might be empty, e.g. if the user typed "C:\foo".
211 return metrics::OmniboxInputType::URL;
214 // If the user typed a scheme, and it's HTTP or HTTPS, we know how to parse it
215 // well enough that we can fall through to the heuristics below. If it's
216 // something else, we can just determine our action based on what we do with
217 // any input of this scheme. In theory we could do better with some schemes
218 // (e.g. "ftp" or "view-source") but I'll wait to spend the effort on that
219 // until I run into some cases that really need it.
220 if (parts->scheme.is_nonempty() &&
221 !base::LowerCaseEqualsASCII(parsed_scheme_utf8, url::kHttpScheme) &&
222 !base::LowerCaseEqualsASCII(parsed_scheme_utf8, url::kHttpsScheme)) {
223 metrics::OmniboxInputType::Type type =
224 scheme_classifier.GetInputTypeForScheme(parsed_scheme_utf8);
225 if (type != metrics::OmniboxInputType::INVALID)
226 return type;
228 // We don't know about this scheme. It might be that the user typed a
229 // URL of the form "username:password@foo.com".
230 const base::string16 http_scheme_prefix =
231 base::ASCIIToUTF16(std::string(url::kHttpScheme) +
232 url::kStandardSchemeSeparator);
233 url::Parsed http_parts;
234 base::string16 http_scheme;
235 GURL http_canonicalized_url;
236 metrics::OmniboxInputType::Type http_type =
237 Parse(http_scheme_prefix + text, desired_tld, scheme_classifier,
238 &http_parts, &http_scheme, &http_canonicalized_url);
239 DCHECK_EQ(std::string(url::kHttpScheme),
240 base::UTF16ToUTF8(http_scheme));
242 if ((http_type == metrics::OmniboxInputType::URL) &&
243 http_parts.username.is_nonempty() &&
244 http_parts.password.is_nonempty()) {
245 // Manually re-jigger the parsed parts to match |text| (without the
246 // http scheme added).
247 http_parts.scheme.reset();
248 url::Component* components[] = {
249 &http_parts.username,
250 &http_parts.password,
251 &http_parts.host,
252 &http_parts.port,
253 &http_parts.path,
254 &http_parts.query,
255 &http_parts.ref,
257 for (size_t i = 0; i < arraysize(components); ++i) {
258 url_fixer::OffsetComponent(
259 -static_cast<int>(http_scheme_prefix.length()), components[i]);
262 *parts = http_parts;
263 if (scheme)
264 scheme->clear();
265 *canonicalized_url = http_canonicalized_url;
267 return metrics::OmniboxInputType::URL;
270 // We don't know about this scheme and it doesn't look like the user
271 // typed a username and password. It's likely to be a search operator
272 // like "site:" or "link:". We classify it as UNKNOWN so the user has
273 // the option of treating it as a URL if we're wrong.
274 // Note that SegmentURL() is smart so we aren't tricked by "c:\foo" or
275 // "www.example.com:81" in this case.
276 return metrics::OmniboxInputType::UNKNOWN;
279 // Either the user didn't type a scheme, in which case we need to distinguish
280 // between an HTTP URL and a query, or the scheme is HTTP or HTTPS, in which
281 // case we should reject invalid formulations.
283 // If we have an empty host it can't be a valid HTTP[S] URL. (This should
284 // only trigger for input that begins with a colon, which GURL will parse as a
285 // valid, non-standard URL; for standard URLs, an empty host would have
286 // resulted in an invalid |canonicalized_url| above.)
287 if (!canonicalized_url->has_host())
288 return metrics::OmniboxInputType::QUERY;
290 // Determine the host family. We get this information by (re-)canonicalizing
291 // the already-canonicalized host rather than using the user's original input,
292 // in case fixup affected the result here (e.g. an input that looks like an
293 // IPv4 address but with a non-empty desired TLD would return IPV4 before
294 // fixup and NEUTRAL afterwards, and we want to treat it as NEUTRAL).
295 url::CanonHostInfo host_info;
296 net::CanonicalizeHost(canonicalized_url->host(), &host_info);
298 // Check if the canonicalized host has a known TLD, which we'll want to know
299 // below.
300 const size_t registry_length =
301 net::registry_controlled_domains::GetRegistryLength(
302 canonicalized_url->host(),
303 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
304 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
305 DCHECK_NE(std::string::npos, registry_length);
306 const bool has_known_tld = registry_length != 0;
308 // See if the hostname is valid. While IE and GURL allow hostnames to contain
309 // many other characters (perhaps for weird intranet machines), it's extremely
310 // unlikely that a user would be trying to type those in for anything other
311 // than a search query.
312 const base::string16 original_host(
313 text.substr(parts->host.begin, parts->host.len));
314 if ((host_info.family == url::CanonHostInfo::NEUTRAL) &&
315 !net::IsCanonicalizedHostCompliant(canonicalized_url->host())) {
316 // Invalid hostname. There are several possible cases:
317 // * The user is typing a multi-word query. If we see a space anywhere in
318 // the input host we assume this is a search and return QUERY. (We check
319 // the input string instead of canonicalized_url->host() in case fixup
320 // escaped the space.)
321 // * The user is typing some garbage string. Return QUERY.
322 // * Our checker is too strict and the user is typing a real-world URL
323 // that's "invalid" but resolves. To catch these, we return UNKNOWN when
324 // the user explicitly typed a scheme or when the hostname has a known
325 // TLD, so we'll still search by default but we'll show the accidental
326 // search infobar if necessary.
328 // This means we would block the following kinds of navigation attempts:
329 // * Navigations to a hostname with spaces
330 // * Navigations to a hostname with invalid characters and an unknown TLD
331 // These might be possible in intranets, but we're not going to support them
332 // without concrete evidence that doing so is necessary.
333 return (parts->scheme.is_nonempty() ||
334 (has_known_tld && (original_host.find(' ') == base::string16::npos))) ?
335 metrics::OmniboxInputType::UNKNOWN : metrics::OmniboxInputType::QUERY;
338 // For hostnames that look like IP addresses, distinguish between IPv6
339 // addresses, which are basically guaranteed to be navigations, and IPv4
340 // addresses, which are much fuzzier.
341 if (host_info.family == url::CanonHostInfo::IPV6)
342 return metrics::OmniboxInputType::URL;
343 if (host_info.family == url::CanonHostInfo::IPV4) {
344 // The host may be a real IP address, or something that looks a bit like it
345 // (e.g. "1.2" or "3232235521"). We check whether it was convertible to an
346 // IP with a non-zero first octet; IPs with first octet zero are "source
347 // IPs" and are almost never navigable as destination addresses.
349 // The one exception to this is 0.0.0.0; on many systems, attempting to
350 // navigate to this IP actually navigates to localhost. To support this
351 // case, when the converted IP is 0.0.0.0, we go ahead and run the "did the
352 // user actually type four components" test in the conditional below, so
353 // that we'll allow explicit attempts to navigate to "0.0.0.0". If the
354 // input was anything else (e.g. "0"), we'll fall through to returning QUERY
355 // afterwards.
356 if ((host_info.address[0] != 0) ||
357 ((host_info.address[1] == 0) && (host_info.address[2] == 0) &&
358 (host_info.address[3] == 0))) {
359 // This is theoretically a navigable IP. We have four cases. The first
360 // three are:
361 // * If the user typed four distinct components, this is an IP for sure.
362 // * If the user typed two or three components, this is almost certainly a
363 // query, especially for two components (as in "13.5/7.25"), but we'll
364 // allow navigation for an explicit scheme or trailing slash below.
365 // * If the user typed one component, this is likely a query, but could be
366 // a non-dotted-quad version of an IP address.
367 // Unfortunately, since we called CanonicalizeHost() on the
368 // already-canonicalized host, all of these cases will have been changed
369 // to have four components (e.g. 13.2 -> 13.0.0.2), so we have to call
370 // CanonicalizeHost() again, this time on the original input, so that we
371 // can get the correct number of IP components.
373 // The fourth case is that the user typed something ambiguous like ".1.2"
374 // that fixup converted to an IP address ("1.0.0.2"). In this case the
375 // call to CanonicalizeHost() will return NEUTRAL here. Since it's not
376 // clear what the user intended, we fall back to our other heuristics.
377 net::CanonicalizeHost(base::UTF16ToUTF8(original_host), &host_info);
378 if ((host_info.family == url::CanonHostInfo::IPV4) &&
379 (host_info.num_ipv4_components == 4))
380 return metrics::OmniboxInputType::URL;
383 // By this point, if we have an "IP" with first octet zero, we know it
384 // wasn't "0.0.0.0", so mark it as non-navigable.
385 if (host_info.address[0] == 0)
386 return metrics::OmniboxInputType::QUERY;
389 // Now that we've ruled out all schemes other than http or https and done a
390 // little more sanity checking, the presence of a scheme means this is likely
391 // a URL.
392 if (parts->scheme.is_nonempty())
393 return metrics::OmniboxInputType::URL;
395 // Trailing slashes force the input to be treated as a URL.
396 if (parts->path.is_nonempty()) {
397 base::char16 c = text[parts->path.end() - 1];
398 if ((c == '\\') || (c == '/'))
399 return metrics::OmniboxInputType::URL;
402 // Handle the cases we detected in the IPv4 code above as "almost certainly a
403 // query" now that we know the user hasn't tried to force navigation via a
404 // scheme/trailing slash.
405 if ((host_info.family == url::CanonHostInfo::IPV4) &&
406 (host_info.num_ipv4_components > 1))
407 return metrics::OmniboxInputType::QUERY;
409 // If there is more than one recognized non-host component, this is likely to
410 // be a URL, even if the TLD is unknown (in which case this is likely an
411 // intranet URL).
412 if (NumNonHostComponents(*parts) > 1)
413 return metrics::OmniboxInputType::URL;
415 // If we reach here with a username, our input looks something like
416 // "user@host". Unless there is a desired TLD, we think this is more likely
417 // an email address than an HTTP auth attempt, so we search by default. (When
418 // there _is_ a desired TLD, the user hit ctrl-enter, and we assume that
419 // implies an attempted navigation.)
420 if (canonicalized_url->has_username() && desired_tld.empty())
421 return metrics::OmniboxInputType::UNKNOWN;
423 // If the host has a known TLD or a port, it's probably a URL. Note that we
424 // special-case "localhost" as a known hostname.
425 if (has_known_tld || (canonicalized_url->host() == "localhost") ||
426 canonicalized_url->has_port())
427 return metrics::OmniboxInputType::URL;
429 // If the input looks like a word followed by a pound sign and possibly more
430 // characters ("c#" or "c# foo"), this is almost certainly an attempt to
431 // search. We try to be conservative here by not firing on cases like "c/#"
432 // or "c?#" that might actually indicate some cryptic attempt to access an
433 // intranet host, and by placing this check late enough that other tests
434 // (e.g., for a non-empty TLD or a non-empty scheme) will have already
435 // returned URL.
436 if (!OmniboxFieldTrial::PreventUWYTDefaultForNonURLInputs() &&
437 !parts->path.is_valid() && !canonicalized_url->has_query() &&
438 canonicalized_url->has_ref())
439 return metrics::OmniboxInputType::QUERY;
441 // No scheme, username, port, and no known TLD on the host.
442 // This could be:
443 // * A single word "foo"; possibly an intranet site, but more likely a search.
444 // This is ideally an UNKNOWN, and we can let the Alternate Nav URL code
445 // catch our mistakes.
446 // * A URL with a valid TLD we don't know about yet. If e.g. a registrar adds
447 // "xxx" as a TLD, then until we add it to our data file, Chrome won't know
448 // "foo.xxx" is a real URL. So ideally this is a URL, but we can't really
449 // distinguish this case from:
450 // * A "URL-like" string that's not really a URL (like
451 // "browser.tabs.closeButtons" or "java.awt.event.*"). This is ideally a
452 // QUERY. Since this is indistinguishable from the case above, and this
453 // case is much more likely, claim these are UNKNOWN, which should default
454 // to the right thing and let users correct us on a case-by-case basis.
455 return metrics::OmniboxInputType::UNKNOWN;
458 // static
459 void AutocompleteInput::ParseForEmphasizeComponents(
460 const base::string16& text,
461 const AutocompleteSchemeClassifier& scheme_classifier,
462 url::Component* scheme,
463 url::Component* host) {
464 url::Parsed parts;
465 base::string16 scheme_str;
466 Parse(text, std::string(), scheme_classifier, &parts, &scheme_str, NULL);
468 *scheme = parts.scheme;
469 *host = parts.host;
471 int after_scheme_and_colon = parts.scheme.end() + 1;
472 // For the view-source scheme, we should emphasize the scheme and host of the
473 // URL qualified by the view-source prefix.
474 if (base::LowerCaseEqualsASCII(scheme_str, kViewSourceScheme) &&
475 (static_cast<int>(text.length()) > after_scheme_and_colon)) {
476 // Obtain the URL prefixed by view-source and parse it.
477 base::string16 real_url(text.substr(after_scheme_and_colon));
478 url::Parsed real_parts;
479 AutocompleteInput::Parse(real_url, std::string(), scheme_classifier,
480 &real_parts, NULL, NULL);
481 if (real_parts.scheme.is_nonempty() || real_parts.host.is_nonempty()) {
482 if (real_parts.scheme.is_nonempty()) {
483 *scheme = url::Component(
484 after_scheme_and_colon + real_parts.scheme.begin,
485 real_parts.scheme.len);
486 } else {
487 scheme->reset();
489 if (real_parts.host.is_nonempty()) {
490 *host = url::Component(after_scheme_and_colon + real_parts.host.begin,
491 real_parts.host.len);
492 } else {
493 host->reset();
496 } else if (base::LowerCaseEqualsASCII(scheme_str, url::kFileSystemScheme) &&
497 parts.inner_parsed() && parts.inner_parsed()->scheme.is_valid()) {
498 *host = parts.inner_parsed()->host;
502 // static
503 base::string16 AutocompleteInput::FormattedStringWithEquivalentMeaning(
504 const GURL& url,
505 const base::string16& formatted_url,
506 const AutocompleteSchemeClassifier& scheme_classifier) {
507 if (!net::CanStripTrailingSlash(url))
508 return formatted_url;
509 const base::string16 url_with_path(formatted_url + base::char16('/'));
510 return (AutocompleteInput::Parse(formatted_url, std::string(),
511 scheme_classifier, NULL, NULL, NULL) ==
512 AutocompleteInput::Parse(url_with_path, std::string(),
513 scheme_classifier, NULL, NULL, NULL)) ?
514 formatted_url : url_with_path;
517 // static
518 int AutocompleteInput::NumNonHostComponents(const url::Parsed& parts) {
519 int num_nonhost_components = 0;
520 if (parts.scheme.is_nonempty())
521 ++num_nonhost_components;
522 if (parts.username.is_nonempty())
523 ++num_nonhost_components;
524 if (parts.password.is_nonempty())
525 ++num_nonhost_components;
526 if (parts.port.is_nonempty())
527 ++num_nonhost_components;
528 if (parts.path.is_nonempty())
529 ++num_nonhost_components;
530 if (parts.query.is_nonempty())
531 ++num_nonhost_components;
532 if (parts.ref.is_nonempty())
533 ++num_nonhost_components;
534 return num_nonhost_components;
537 // static
538 bool AutocompleteInput::HasHTTPScheme(const base::string16& input) {
539 std::string utf8_input(base::UTF16ToUTF8(input));
540 url::Component scheme;
541 if (url::FindAndCompareScheme(utf8_input, kViewSourceScheme, &scheme)) {
542 utf8_input.erase(0, scheme.end() + 1);
544 return url::FindAndCompareScheme(utf8_input, url::kHttpScheme, NULL);
547 void AutocompleteInput::UpdateText(const base::string16& text,
548 size_t cursor_position,
549 const url::Parsed& parts) {
550 DCHECK(cursor_position <= text.length() ||
551 cursor_position == base::string16::npos)
552 << "Text: '" << text << "', cp: " << cursor_position;
553 text_ = text;
554 cursor_position_ = cursor_position;
555 parts_ = parts;
558 void AutocompleteInput::Clear() {
559 text_.clear();
560 cursor_position_ = base::string16::npos;
561 current_url_ = GURL();
562 current_page_classification_ = metrics::OmniboxEventProto::INVALID_SPEC;
563 type_ = metrics::OmniboxInputType::INVALID;
564 parts_ = url::Parsed();
565 scheme_.clear();
566 canonicalized_url_ = GURL();
567 prevent_inline_autocomplete_ = false;
568 prefer_keyword_ = false;
569 allow_exact_keyword_match_ = false;
570 want_asynchronous_matches_ = true;
571 from_omnibox_focus_ = false;
572 terms_prefixed_by_http_or_https_.clear();