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