15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/builtin_provider.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include <algorithm> 8558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_input.h" 12a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chrome/browser/autocomplete/history_provider.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/metrics/proto/omnibox_input_type.pb.h" 15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/url_fixer/url_fixer.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if !defined(OS_ANDROID) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This list should be kept in sync with chrome/common/url_constants.h. 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Only include useful sub-pages, confirmation alerts are not useful. 22558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst char* const kChromeSettingsSubPages[] = { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kAutofillSubPage, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kClearBrowserDataSubPage, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kContentSettingsSubPage, 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kContentSettingsExceptionsSubPage, 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kImportDataSubPage, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kLanguageOptionsSubPage, 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kPasswordManagerSubPage, 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) chrome::kResetProfileSettingsSubPage, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kSearchEnginesSubPage, 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kSyncSetupSubPage, 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kInternetOptionsSubPage, 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif // !defined(OS_ANDROID) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst int BuiltinProvider::kRelevance = 860; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BuiltinProvider::BuiltinProvider(AutocompleteProviderListener* listener, 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : AutocompleteProvider(listener, profile, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutocompleteProvider::TYPE_BUILTIN) { 47558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch std::vector<std::string> builtins( 48558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch chrome::kChromeHostURLs, 49558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch chrome::kChromeHostURLs + chrome::kNumberOfChromeHostURLs); 50558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch std::sort(builtins.begin(), builtins.end()); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<std::string>::iterator i(builtins.begin()); 52558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch i != builtins.end(); ++i) 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) builtins_.push_back(base::ASCIIToUTF16(*i)); 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if !defined(OS_ANDROID) 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 settings(base::ASCIIToUTF16(chrome::kChromeUISettingsHost) + 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ASCIIToUTF16("/")); 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < arraysize(kChromeSettingsSubPages); i++) { 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) builtins_.push_back( 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) settings + base::ASCIIToUTF16(kChromeSettingsSubPages[i])); 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BuiltinProvider::Start(const AutocompleteInput& input, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool minimal_changes) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matches_.clear(); 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if ((input.type() == metrics::OmniboxInputType::INVALID) || 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (input.type() == metrics::OmniboxInputType::FORCED_QUERY) || 70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (input.type() == metrics::OmniboxInputType::QUERY)) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const size_t kAboutSchemeLength = strlen(url::kAboutScheme); 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const base::string16 kAbout = 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::ASCIIToUTF16(url::kAboutScheme) + 7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::ASCIIToUTF16(url::kStandardSchemeSeparator); 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16 kChrome = base::ASCIIToUTF16(content::kChromeUIScheme) + 7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::ASCIIToUTF16(url::kStandardSchemeSeparator); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kUrl = ACMatchClassification::URL; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kMatch = kUrl | ACMatchClassification::MATCH; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 text = input.text(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool starting_chrome = StartsWith(kChrome, text, false); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (starting_chrome || StartsWith(kAbout, text, false)) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ACMatchClassifications styles; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Highlight the input portion matching "chrome://"; or if the user has 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // input "about:" (with optional slashes), highlight the whole "chrome://". 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool highlight = starting_chrome || text.length() > kAboutSchemeLength; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) styles.push_back(ACMatchClassification(0, highlight ? kMatch : kUrl)); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t offset = starting_chrome ? text.length() : kChrome.length(); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (highlight) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) styles.push_back(ACMatchClassification(offset, kUrl)); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Include some common builtin chrome URLs as the user types the scheme. 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AddMatch(base::ASCIIToUTF16(chrome::kChromeUIChromeURLsURL), 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16(), styles); 97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if !defined(OS_ANDROID) 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AddMatch(base::ASCIIToUTF16(chrome::kChromeUISettingsURL), 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16(), styles); 100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AddMatch(base::ASCIIToUTF16(chrome::kChromeUIVersionURL), 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16(), styles); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Match input about: or chrome: URL input against builtin chrome URLs. 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) GURL url = url_fixer::FixupURL(base::UTF16ToUTF8(text), std::string()); 1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // BuiltinProvider doesn't know how to suggest valid ?query or #fragment 1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // extensions to chrome: URLs. 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (url.SchemeIs(content::kChromeUIScheme) && url.has_host() && 1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) !url.has_query() && !url.has_ref()) { 11046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Suggest about:blank for substrings, taking URL fixup into account. 11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Chrome does not support trailing slashes or paths for about:blank. 11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const base::string16 blank_host = base::ASCIIToUTF16("blank"); 11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const base::string16 host = base::UTF8ToUTF16(url.host()); 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (StartsWith(text, base::ASCIIToUTF16(url::kAboutScheme), false) && 11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) StartsWith(blank_host, host, false) && (url.path().length() <= 1) && 11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) !EndsWith(text, base::ASCIIToUTF16("/"), false)) { 11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) ACMatchClassifications styles; 11846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) styles.push_back(ACMatchClassification(0, kMatch)); 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::string16 match = base::ASCIIToUTF16(url::kAboutBlankURL); 12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Measure the length of the matching host after the "about:" scheme. 12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const size_t corrected_length = kAboutSchemeLength + 1 + host.length(); 12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (blank_host.length() > host.length()) 12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) styles.push_back(ACMatchClassification(corrected_length, kUrl)); 12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) AddMatch(match, match.substr(corrected_length), styles); 12546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 12646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Include the path for sub-pages (e.g. "chrome://settings/browser"). 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 host_and_path = base::UTF8ToUTF16(url.host() + url.path()); 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::TrimString(host_and_path, base::ASCIIToUTF16("/"), &host_and_path); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t match_length = kChrome.length() + host_and_path.length(); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (Builtins::const_iterator i(builtins_.begin()); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (i != builtins_.end()) && (matches_.size() < kMaxMatches); ++i) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (StartsWith(*i, host_and_path, false)) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ACMatchClassifications styles; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Highlight the "chrome://" scheme, even for input "about:foo". 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) styles.push_back(ACMatchClassification(0, kMatch)); 137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 match_string = kChrome + *i; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (match_string.length() > match_length) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) styles.push_back(ACMatchClassification(match_length, kUrl)); 1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) AddMatch(match_string, match_string.substr(match_length), styles); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < matches_.size(); ++i) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matches_[i].relevance = kRelevance + matches_.size() - (i + 1); 148a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!HistoryProvider::PreventInlineAutocomplete(input) && 149a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch (matches_.size() == 1)) { 1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // If there's only one possible completion of the user's input and 1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // allowing completions is okay, give the match a high enough score to 1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // allow it to beat url-what-you-typed and be inlined. 1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) matches_[0].relevance = 1250; 1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) matches_[0].allowed_to_be_default_match = true; 1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BuiltinProvider::~BuiltinProvider() {} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BuiltinProvider::AddMatch(const base::string16& match_string, 161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& inline_completion, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ACMatchClassifications& styles) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutocompleteMatch match(this, kRelevance, false, 16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AutocompleteMatchType::NAVSUGGEST); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match.fill_into_edit = match_string; 1663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) match.inline_autocompletion = inline_completion; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match.destination_url = GURL(match_string); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match.contents = match_string; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match.contents_class = styles; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matches_.push_back(match); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 172