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" 11a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chrome/browser/autocomplete/history_provider.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/metrics/proto/omnibox_input_type.pb.h" 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/omnibox/autocomplete_input.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) 43116680a4aac90f2aa7413d9095a592090648e557Ben MurdochBuiltinProvider::BuiltinProvider() 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : AutocompleteProvider(AutocompleteProvider::TYPE_BUILTIN) { 45558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch std::vector<std::string> builtins( 46558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch chrome::kChromeHostURLs, 47558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch chrome::kChromeHostURLs + chrome::kNumberOfChromeHostURLs); 48558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch std::sort(builtins.begin(), builtins.end()); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<std::string>::iterator i(builtins.begin()); 50558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch i != builtins.end(); ++i) 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) builtins_.push_back(base::ASCIIToUTF16(*i)); 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if !defined(OS_ANDROID) 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 settings(base::ASCIIToUTF16(chrome::kChromeUISettingsHost) + 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ASCIIToUTF16("/")); 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < arraysize(kChromeSettingsSubPages); i++) { 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) builtins_.push_back( 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) settings + base::ASCIIToUTF16(kChromeSettingsSubPages[i])); 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BuiltinProvider::Start(const AutocompleteInput& input, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool minimal_changes) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matches_.clear(); 66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if ((input.type() == metrics::OmniboxInputType::INVALID) || 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (input.type() == metrics::OmniboxInputType::FORCED_QUERY) || 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (input.type() == metrics::OmniboxInputType::QUERY)) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const size_t kAboutSchemeLength = strlen(url::kAboutScheme); 72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const base::string16 kAbout = 73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::ASCIIToUTF16(url::kAboutScheme) + 7446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::ASCIIToUTF16(url::kStandardSchemeSeparator); 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16 kChrome = base::ASCIIToUTF16(content::kChromeUIScheme) + 7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::ASCIIToUTF16(url::kStandardSchemeSeparator); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kUrl = ACMatchClassification::URL; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kMatch = kUrl | ACMatchClassification::MATCH; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 text = input.text(); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool starting_chrome = StartsWith(kChrome, text, false); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (starting_chrome || StartsWith(kAbout, text, false)) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ACMatchClassifications styles; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Highlight the input portion matching "chrome://"; or if the user has 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // input "about:" (with optional slashes), highlight the whole "chrome://". 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool highlight = starting_chrome || text.length() > kAboutSchemeLength; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) styles.push_back(ACMatchClassification(0, highlight ? kMatch : kUrl)); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t offset = starting_chrome ? text.length() : kChrome.length(); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (highlight) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) styles.push_back(ACMatchClassification(offset, kUrl)); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Include some common builtin chrome URLs as the user types the scheme. 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AddMatch(base::ASCIIToUTF16(chrome::kChromeUIChromeURLsURL), 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16(), styles); 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if !defined(OS_ANDROID) 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AddMatch(base::ASCIIToUTF16(chrome::kChromeUISettingsURL), 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16(), styles); 98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AddMatch(base::ASCIIToUTF16(chrome::kChromeUIVersionURL), 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16(), styles); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Match input about: or chrome: URL input against builtin chrome URLs. 103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) GURL url = url_fixer::FixupURL(base::UTF16ToUTF8(text), std::string()); 1041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // BuiltinProvider doesn't know how to suggest valid ?query or #fragment 1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // extensions to chrome: URLs. 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (url.SchemeIs(content::kChromeUIScheme) && url.has_host() && 1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) !url.has_query() && !url.has_ref()) { 10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Suggest about:blank for substrings, taking URL fixup into account. 10946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Chrome does not support trailing slashes or paths for about:blank. 11046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const base::string16 blank_host = base::ASCIIToUTF16("blank"); 11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const base::string16 host = base::UTF8ToUTF16(url.host()); 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (StartsWith(text, base::ASCIIToUTF16(url::kAboutScheme), false) && 11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) StartsWith(blank_host, host, false) && (url.path().length() <= 1) && 11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) !EndsWith(text, base::ASCIIToUTF16("/"), false)) { 11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) ACMatchClassifications styles; 11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) styles.push_back(ACMatchClassification(0, kMatch)); 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::string16 match = base::ASCIIToUTF16(url::kAboutBlankURL); 11846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Measure the length of the matching host after the "about:" scheme. 11946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const size_t corrected_length = kAboutSchemeLength + 1 + host.length(); 12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (blank_host.length() > host.length()) 12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) styles.push_back(ACMatchClassification(corrected_length, kUrl)); 12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) AddMatch(match, match.substr(corrected_length), styles); 12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Include the path for sub-pages (e.g. "chrome://settings/browser"). 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 host_and_path = base::UTF8ToUTF16(url.host() + url.path()); 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::TrimString(host_and_path, base::ASCIIToUTF16("/"), &host_and_path); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t match_length = kChrome.length() + host_and_path.length(); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (Builtins::const_iterator i(builtins_.begin()); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (i != builtins_.end()) && (matches_.size() < kMaxMatches); ++i) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (StartsWith(*i, host_and_path, false)) { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ACMatchClassifications styles; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Highlight the "chrome://" scheme, even for input "about:foo". 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) styles.push_back(ACMatchClassification(0, kMatch)); 135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 match_string = kChrome + *i; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (match_string.length() > match_length) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) styles.push_back(ACMatchClassification(match_length, kUrl)); 1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) AddMatch(match_string, match_string.substr(match_length), styles); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < matches_.size(); ++i) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matches_[i].relevance = kRelevance + matches_.size() - (i + 1); 146a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!HistoryProvider::PreventInlineAutocomplete(input) && 147a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch (matches_.size() == 1)) { 1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // If there's only one possible completion of the user's input and 1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // allowing completions is okay, give the match a high enough score to 1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // allow it to beat url-what-you-typed and be inlined. 1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) matches_[0].relevance = 1250; 1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) matches_[0].allowed_to_be_default_match = true; 1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BuiltinProvider::~BuiltinProvider() {} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BuiltinProvider::AddMatch(const base::string16& match_string, 159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& inline_completion, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ACMatchClassifications& styles) { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutocompleteMatch match(this, kRelevance, false, 16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AutocompleteMatchType::NAVSUGGEST); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match.fill_into_edit = match_string; 1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) match.inline_autocompletion = inline_completion; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match.destination_url = GURL(match_string); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match.contents = match_string; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match.contents_class = styles; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matches_.push_back(match); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 170