builtin_provider.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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" 13558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chrome/common/net/url_fixer_upper.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if !defined(OS_ANDROID) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This list should be kept in sync with chrome/common/url_constants.h. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Only include useful sub-pages, confirmation alerts are not useful. 21558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst char* const kChromeSettingsSubPages[] = { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kAutofillSubPage, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kClearBrowserDataSubPage, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kContentSettingsSubPage, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kContentSettingsExceptionsSubPage, 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kImportDataSubPage, 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kLanguageOptionsSubPage, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kPasswordManagerSubPage, 29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) chrome::kResetProfileSettingsSubPage, 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kSearchEnginesSubPage, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kSyncSetupSubPage, 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kInternetOptionsSubPage, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif // !defined(OS_ANDROID) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst int BuiltinProvider::kRelevance = 860; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BuiltinProvider::BuiltinProvider(AutocompleteProviderListener* listener, 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : AutocompleteProvider(listener, profile, 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutocompleteProvider::TYPE_BUILTIN) { 46558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch std::vector<std::string> builtins( 47558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch chrome::kChromeHostURLs, 48558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch chrome::kChromeHostURLs + chrome::kNumberOfChromeHostURLs); 49558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch std::sort(builtins.begin(), builtins.end()); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<std::string>::iterator i(builtins.begin()); 51558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch i != builtins.end(); ++i) 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) builtins_.push_back(base::ASCIIToUTF16(*i)); 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if !defined(OS_ANDROID) 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 settings(base::ASCIIToUTF16(chrome::kChromeUISettingsHost) + 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ASCIIToUTF16("/")); 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < arraysize(kChromeSettingsSubPages); i++) { 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) builtins_.push_back( 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) settings + base::ASCIIToUTF16(kChromeSettingsSubPages[i])); 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BuiltinProvider::Start(const AutocompleteInput& input, 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool minimal_changes) { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matches_.clear(); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((input.type() == AutocompleteInput::INVALID) || 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (input.type() == AutocompleteInput::FORCED_QUERY) || 691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) (input.type() == AutocompleteInput::QUERY)) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const size_t kAboutSchemeLength = strlen(content::kAboutScheme); 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const base::string16 kAbout = base::ASCIIToUTF16(content::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. 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GURL url = URLFixerUpper::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()); 11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (StartsWith(text, base::ASCIIToUTF16(content::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)); 11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::string16 match = base::ASCIIToUTF16(content::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