1 // Copyright (c) 2012 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/builtin_provider.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "components/metrics/proto/omnibox_input_type.pb.h"
12 #include "components/omnibox/autocomplete_input.h"
13 #include "components/omnibox/autocomplete_provider_client.h"
14 #include "components/omnibox/history_provider.h"
15 #include "components/url_fixer/url_fixer.h"
17 const int BuiltinProvider::kRelevance
= 860;
19 BuiltinProvider::BuiltinProvider(AutocompleteProviderClient
* client
)
20 : AutocompleteProvider(AutocompleteProvider::TYPE_BUILTIN
),
22 builtins_
= client_
->GetBuiltinURLs();
25 void BuiltinProvider::Start(const AutocompleteInput
& input
,
26 bool minimal_changes
) {
28 if (input
.from_omnibox_focus() ||
29 (input
.type() == metrics::OmniboxInputType::INVALID
) ||
30 (input
.type() == metrics::OmniboxInputType::FORCED_QUERY
) ||
31 (input
.type() == metrics::OmniboxInputType::QUERY
))
34 const size_t kAboutSchemeLength
= strlen(url::kAboutScheme
);
35 const base::string16 kAbout
=
36 base::ASCIIToUTF16(url::kAboutScheme
) +
37 base::ASCIIToUTF16(url::kStandardSchemeSeparator
);
38 const base::string16 embedderAbout
=
39 base::UTF8ToUTF16(client_
->GetEmbedderRepresentationOfAboutScheme()) +
40 base::ASCIIToUTF16(url::kStandardSchemeSeparator
);
42 const int kUrl
= ACMatchClassification::URL
;
43 const int kMatch
= kUrl
| ACMatchClassification::MATCH
;
45 base::string16 text
= input
.text();
46 bool starting_about
= base::StartsWith(embedderAbout
, text
, false);
47 if (starting_about
|| base::StartsWith(kAbout
, text
, false)) {
48 ACMatchClassifications styles
;
49 // Highlight the input portion matching |embedderAbout|; or if the user has
50 // input "about:" (with optional slashes), highlight the whole
52 bool highlight
= starting_about
|| text
.length() > kAboutSchemeLength
;
53 styles
.push_back(ACMatchClassification(0, highlight
? kMatch
: kUrl
));
54 size_t offset
= starting_about
? text
.length() : embedderAbout
.length();
56 styles
.push_back(ACMatchClassification(offset
, kUrl
));
57 // Include some common builtin URLs as the user types the scheme.
58 for (base::string16 url
: client_
->GetBuiltinsToProvideAsUserTypes())
59 AddMatch(url
, base::string16(), styles
);
61 // Match input about: or |embedderAbout| URL input against builtin URLs.
62 GURL url
= url_fixer::FixupURL(base::UTF16ToUTF8(text
), std::string());
63 // BuiltinProvider doesn't know how to suggest valid ?query or #fragment
64 // extensions to builtin URLs.
66 client_
->GetEmbedderRepresentationOfAboutScheme().c_str()) &&
67 url
.has_host() && !url
.has_query() && !url
.has_ref()) {
68 // Suggest about:blank for substrings, taking URL fixup into account.
69 // Chrome does not support trailing slashes or paths for about:blank.
70 const base::string16 blank_host
= base::ASCIIToUTF16("blank");
71 const base::string16 host
= base::UTF8ToUTF16(url
.host());
72 if (base::StartsWith(text
, base::ASCIIToUTF16(url::kAboutScheme
),
74 base::StartsWith(blank_host
, host
, false) &&
75 (url
.path().length() <= 1) &&
76 !base::EndsWith(text
, base::ASCIIToUTF16("/"), false)) {
77 ACMatchClassifications styles
;
78 styles
.push_back(ACMatchClassification(0, kMatch
));
79 base::string16 match
= base::ASCIIToUTF16(url::kAboutBlankURL
);
80 // Measure the length of the matching host after the "about:" scheme.
81 const size_t corrected_length
= kAboutSchemeLength
+ 1 + host
.length();
82 if (blank_host
.length() > host
.length())
83 styles
.push_back(ACMatchClassification(corrected_length
, kUrl
));
84 AddMatch(match
, match
.substr(corrected_length
), styles
);
87 // Include the path for sub-pages (e.g. "chrome://settings/browser").
88 base::string16 host_and_path
= base::UTF8ToUTF16(url
.host() + url
.path());
89 base::TrimString(host_and_path
, base::ASCIIToUTF16("/"), &host_and_path
);
90 size_t match_length
= embedderAbout
.length() + host_and_path
.length();
91 for (Builtins::const_iterator
i(builtins_
.begin());
92 (i
!= builtins_
.end()) && (matches_
.size() < kMaxMatches
); ++i
) {
93 if (base::StartsWith(*i
, host_and_path
, false)) {
94 ACMatchClassifications styles
;
95 // Highlight |embedderAbout|, even for input "about:foo".
96 styles
.push_back(ACMatchClassification(0, kMatch
));
97 base::string16 match_string
= embedderAbout
+ *i
;
98 if (match_string
.length() > match_length
)
99 styles
.push_back(ACMatchClassification(match_length
, kUrl
));
100 AddMatch(match_string
, match_string
.substr(match_length
), styles
);
106 for (size_t i
= 0; i
< matches_
.size(); ++i
)
107 matches_
[i
].relevance
= kRelevance
+ matches_
.size() - (i
+ 1);
108 if (!HistoryProvider::PreventInlineAutocomplete(input
) &&
109 (matches_
.size() == 1)) {
110 // If there's only one possible completion of the user's input and
111 // allowing completions is okay, give the match a high enough score to
112 // allow it to beat url-what-you-typed and be inlined.
113 matches_
[0].relevance
= 1250;
114 matches_
[0].allowed_to_be_default_match
= true;
118 BuiltinProvider::~BuiltinProvider() {}
120 void BuiltinProvider::AddMatch(const base::string16
& match_string
,
121 const base::string16
& inline_completion
,
122 const ACMatchClassifications
& styles
) {
123 AutocompleteMatch
match(this, kRelevance
, false,
124 AutocompleteMatchType::NAVSUGGEST
);
125 match
.fill_into_edit
= match_string
;
126 match
.inline_autocompletion
= inline_completion
;
127 match
.destination_url
= GURL(match_string
);
128 match
.contents
= match_string
;
129 match
.contents_class
= styles
;
130 matches_
.push_back(match
);