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