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. 4 5 #include "chrome/browser/autocomplete/builtin_provider.h" 6 7 #include <algorithm> 8 9 #include "base/strings/string_util.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/autocomplete/history_provider.h" 12 #include "chrome/common/url_constants.h" 13 #include "components/metrics/proto/omnibox_input_type.pb.h" 14 #include "components/omnibox/autocomplete_input.h" 15 #include "components/url_fixer/url_fixer.h" 16 17 namespace { 18 19 #if !defined(OS_ANDROID) 20 // This list should be kept in sync with chrome/common/url_constants.h. 21 // Only include useful sub-pages, confirmation alerts are not useful. 22 const char* const kChromeSettingsSubPages[] = { 23 chrome::kAutofillSubPage, 24 chrome::kClearBrowserDataSubPage, 25 chrome::kContentSettingsSubPage, 26 chrome::kContentSettingsExceptionsSubPage, 27 chrome::kImportDataSubPage, 28 chrome::kLanguageOptionsSubPage, 29 chrome::kPasswordManagerSubPage, 30 chrome::kResetProfileSettingsSubPage, 31 chrome::kSearchEnginesSubPage, 32 chrome::kSyncSetupSubPage, 33 #if defined(OS_CHROMEOS) 34 chrome::kInternetOptionsSubPage, 35 #endif 36 }; 37 #endif // !defined(OS_ANDROID) 38 39 } // namespace 40 41 const int BuiltinProvider::kRelevance = 860; 42 43 BuiltinProvider::BuiltinProvider() 44 : AutocompleteProvider(AutocompleteProvider::TYPE_BUILTIN) { 45 std::vector<std::string> builtins( 46 chrome::kChromeHostURLs, 47 chrome::kChromeHostURLs + chrome::kNumberOfChromeHostURLs); 48 std::sort(builtins.begin(), builtins.end()); 49 for (std::vector<std::string>::iterator i(builtins.begin()); 50 i != builtins.end(); ++i) 51 builtins_.push_back(base::ASCIIToUTF16(*i)); 52 53 #if !defined(OS_ANDROID) 54 base::string16 settings(base::ASCIIToUTF16(chrome::kChromeUISettingsHost) + 55 base::ASCIIToUTF16("/")); 56 for (size_t i = 0; i < arraysize(kChromeSettingsSubPages); i++) { 57 builtins_.push_back( 58 settings + base::ASCIIToUTF16(kChromeSettingsSubPages[i])); 59 } 60 #endif 61 } 62 63 void BuiltinProvider::Start(const AutocompleteInput& input, 64 bool minimal_changes) { 65 matches_.clear(); 66 if ((input.type() == metrics::OmniboxInputType::INVALID) || 67 (input.type() == metrics::OmniboxInputType::FORCED_QUERY) || 68 (input.type() == metrics::OmniboxInputType::QUERY)) 69 return; 70 71 const size_t kAboutSchemeLength = strlen(url::kAboutScheme); 72 const base::string16 kAbout = 73 base::ASCIIToUTF16(url::kAboutScheme) + 74 base::ASCIIToUTF16(url::kStandardSchemeSeparator); 75 const base::string16 kChrome = base::ASCIIToUTF16(content::kChromeUIScheme) + 76 base::ASCIIToUTF16(url::kStandardSchemeSeparator); 77 78 const int kUrl = ACMatchClassification::URL; 79 const int kMatch = kUrl | ACMatchClassification::MATCH; 80 81 base::string16 text = input.text(); 82 bool starting_chrome = StartsWith(kChrome, text, false); 83 if (starting_chrome || StartsWith(kAbout, text, false)) { 84 ACMatchClassifications styles; 85 // Highlight the input portion matching "chrome://"; or if the user has 86 // input "about:" (with optional slashes), highlight the whole "chrome://". 87 bool highlight = starting_chrome || text.length() > kAboutSchemeLength; 88 styles.push_back(ACMatchClassification(0, highlight ? kMatch : kUrl)); 89 size_t offset = starting_chrome ? text.length() : kChrome.length(); 90 if (highlight) 91 styles.push_back(ACMatchClassification(offset, kUrl)); 92 // Include some common builtin chrome URLs as the user types the scheme. 93 AddMatch(base::ASCIIToUTF16(chrome::kChromeUIChromeURLsURL), 94 base::string16(), styles); 95 #if !defined(OS_ANDROID) 96 AddMatch(base::ASCIIToUTF16(chrome::kChromeUISettingsURL), 97 base::string16(), styles); 98 #endif 99 AddMatch(base::ASCIIToUTF16(chrome::kChromeUIVersionURL), 100 base::string16(), styles); 101 } else { 102 // Match input about: or chrome: URL input against builtin chrome URLs. 103 GURL url = url_fixer::FixupURL(base::UTF16ToUTF8(text), std::string()); 104 // BuiltinProvider doesn't know how to suggest valid ?query or #fragment 105 // extensions to chrome: URLs. 106 if (url.SchemeIs(content::kChromeUIScheme) && url.has_host() && 107 !url.has_query() && !url.has_ref()) { 108 // Suggest about:blank for substrings, taking URL fixup into account. 109 // Chrome does not support trailing slashes or paths for about:blank. 110 const base::string16 blank_host = base::ASCIIToUTF16("blank"); 111 const base::string16 host = base::UTF8ToUTF16(url.host()); 112 if (StartsWith(text, base::ASCIIToUTF16(url::kAboutScheme), false) && 113 StartsWith(blank_host, host, false) && (url.path().length() <= 1) && 114 !EndsWith(text, base::ASCIIToUTF16("/"), false)) { 115 ACMatchClassifications styles; 116 styles.push_back(ACMatchClassification(0, kMatch)); 117 base::string16 match = base::ASCIIToUTF16(url::kAboutBlankURL); 118 // Measure the length of the matching host after the "about:" scheme. 119 const size_t corrected_length = kAboutSchemeLength + 1 + host.length(); 120 if (blank_host.length() > host.length()) 121 styles.push_back(ACMatchClassification(corrected_length, kUrl)); 122 AddMatch(match, match.substr(corrected_length), styles); 123 } 124 125 // Include the path for sub-pages (e.g. "chrome://settings/browser"). 126 base::string16 host_and_path = base::UTF8ToUTF16(url.host() + url.path()); 127 base::TrimString(host_and_path, base::ASCIIToUTF16("/"), &host_and_path); 128 size_t match_length = kChrome.length() + host_and_path.length(); 129 for (Builtins::const_iterator i(builtins_.begin()); 130 (i != builtins_.end()) && (matches_.size() < kMaxMatches); ++i) { 131 if (StartsWith(*i, host_and_path, false)) { 132 ACMatchClassifications styles; 133 // Highlight the "chrome://" scheme, even for input "about:foo". 134 styles.push_back(ACMatchClassification(0, kMatch)); 135 base::string16 match_string = kChrome + *i; 136 if (match_string.length() > match_length) 137 styles.push_back(ACMatchClassification(match_length, kUrl)); 138 AddMatch(match_string, match_string.substr(match_length), styles); 139 } 140 } 141 } 142 } 143 144 for (size_t i = 0; i < matches_.size(); ++i) 145 matches_[i].relevance = kRelevance + matches_.size() - (i + 1); 146 if (!HistoryProvider::PreventInlineAutocomplete(input) && 147 (matches_.size() == 1)) { 148 // If there's only one possible completion of the user's input and 149 // allowing completions is okay, give the match a high enough score to 150 // allow it to beat url-what-you-typed and be inlined. 151 matches_[0].relevance = 1250; 152 matches_[0].allowed_to_be_default_match = true; 153 } 154 } 155 156 BuiltinProvider::~BuiltinProvider() {} 157 158 void BuiltinProvider::AddMatch(const base::string16& match_string, 159 const base::string16& inline_completion, 160 const ACMatchClassifications& styles) { 161 AutocompleteMatch match(this, kRelevance, false, 162 AutocompleteMatchType::NAVSUGGEST); 163 match.fill_into_edit = match_string; 164 match.inline_autocompletion = inline_completion; 165 match.destination_url = GURL(match_string); 166 match.contents = match_string; 167 match.contents_class = styles; 168 matches_.push_back(match); 169 } 170