| OLD | NEW |
| (Empty) |
| 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 "components/metrics/proto/omnibox_input_type.pb.h" | |
| 12 #include "components/omnibox/autocomplete_input.h" | |
| 13 #include "components/omnibox/autocomplete_provider_client.h" | |
| 14 #include "components/omnibox/history_provider.h" | |
| 15 #include "components/url_fixer/url_fixer.h" | |
| 16 | |
| 17 const int BuiltinProvider::kRelevance = 860; | |
| 18 | |
| 19 BuiltinProvider::BuiltinProvider(AutocompleteProviderClient* client) | |
| 20 : AutocompleteProvider(AutocompleteProvider::TYPE_BUILTIN), | |
| 21 client_(client) { | |
| 22 builtins_ = client_->GetBuiltinURLs(); | |
| 23 } | |
| 24 | |
| 25 void BuiltinProvider::Start(const AutocompleteInput& input, | |
| 26 bool minimal_changes) { | |
| 27 matches_.clear(); | |
| 28 if (input.from_omnibox_focus() || | |
| 29 (input.type() == metrics::OmniboxInputType::INVALID) || | |
| 30 (input.type() == metrics::OmniboxInputType::FORCED_QUERY) || | |
| 31 (input.type() == metrics::OmniboxInputType::QUERY)) | |
| 32 return; | |
| 33 | |
| 34 const size_t kAboutSchemeLength = strlen(url::kAboutScheme); | |
| 35 const base::string16 kAbout = | |
| 36 base::ASCIIToUTF16(url::kAboutScheme) + | |
| 37 base::ASCIIToUTF16(url::kStandardSchemeSeparator); | |
| 38 const base::string16 embedderAbout = | |
| 39 base::UTF8ToUTF16(client_->GetEmbedderRepresentationOfAboutScheme()) + | |
| 40 base::ASCIIToUTF16(url::kStandardSchemeSeparator); | |
| 41 | |
| 42 const int kUrl = ACMatchClassification::URL; | |
| 43 const int kMatch = kUrl | ACMatchClassification::MATCH; | |
| 44 | |
| 45 base::string16 text = input.text(); | |
| 46 bool starting_about = base::StartsWith(embedderAbout, text, false); | |
| 47 if (starting_about || base::StartsWith(kAbout, text, false)) { | |
| 48 ACMatchClassifications styles; | |
| 49 // Highlight the input portion matching |embedderAbout|; or if the user has | |
| 50 // input "about:" (with optional slashes), highlight the whole | |
| 51 // |embedderAbout|. | |
| 52 bool highlight = starting_about || text.length() > kAboutSchemeLength; | |
| 53 styles.push_back(ACMatchClassification(0, highlight ? kMatch : kUrl)); | |
| 54 size_t offset = starting_about ? text.length() : embedderAbout.length(); | |
| 55 if (highlight) | |
| 56 styles.push_back(ACMatchClassification(offset, kUrl)); | |
| 57 // Include some common builtin URLs as the user types the scheme. | |
| 58 for (base::string16 url : client_->GetBuiltinsToProvideAsUserTypes()) | |
| 59 AddMatch(url, base::string16(), styles); | |
| 60 } else { | |
| 61 // Match input about: or |embedderAbout| URL input against builtin URLs. | |
| 62 GURL url = url_fixer::FixupURL(base::UTF16ToUTF8(text), std::string()); | |
| 63 // BuiltinProvider doesn't know how to suggest valid ?query or #fragment | |
| 64 // extensions to builtin URLs. | |
| 65 if (url.SchemeIs( | |
| 66 client_->GetEmbedderRepresentationOfAboutScheme().c_str()) && | |
| 67 url.has_host() && !url.has_query() && !url.has_ref()) { | |
| 68 // Suggest about:blank for substrings, taking URL fixup into account. | |
| 69 // Chrome does not support trailing slashes or paths for about:blank. | |
| 70 const base::string16 blank_host = base::ASCIIToUTF16("blank"); | |
| 71 const base::string16 host = base::UTF8ToUTF16(url.host()); | |
| 72 if (base::StartsWith(text, base::ASCIIToUTF16(url::kAboutScheme), | |
| 73 false) && | |
| 74 base::StartsWith(blank_host, host, false) && | |
| 75 (url.path().length() <= 1) && | |
| 76 !base::EndsWith(text, base::ASCIIToUTF16("/"), false)) { | |
| 77 ACMatchClassifications styles; | |
| 78 styles.push_back(ACMatchClassification(0, kMatch)); | |
| 79 base::string16 match = base::ASCIIToUTF16(url::kAboutBlankURL); | |
| 80 // Measure the length of the matching host after the "about:" scheme. | |
| 81 const size_t corrected_length = kAboutSchemeLength + 1 + host.length(); | |
| 82 if (blank_host.length() > host.length()) | |
| 83 styles.push_back(ACMatchClassification(corrected_length, kUrl)); | |
| 84 AddMatch(match, match.substr(corrected_length), styles); | |
| 85 } | |
| 86 | |
| 87 // Include the path for sub-pages (e.g. "chrome://settings/browser"). | |
| 88 base::string16 host_and_path = base::UTF8ToUTF16(url.host() + url.path()); | |
| 89 base::TrimString(host_and_path, base::ASCIIToUTF16("/"), &host_and_path); | |
| 90 size_t match_length = embedderAbout.length() + host_and_path.length(); | |
| 91 for (Builtins::const_iterator i(builtins_.begin()); | |
| 92 (i != builtins_.end()) && (matches_.size() < kMaxMatches); ++i) { | |
| 93 if (base::StartsWith(*i, host_and_path, false)) { | |
| 94 ACMatchClassifications styles; | |
| 95 // Highlight |embedderAbout|, even for input "about:foo". | |
| 96 styles.push_back(ACMatchClassification(0, kMatch)); | |
| 97 base::string16 match_string = embedderAbout + *i; | |
| 98 if (match_string.length() > match_length) | |
| 99 styles.push_back(ACMatchClassification(match_length, kUrl)); | |
| 100 AddMatch(match_string, match_string.substr(match_length), styles); | |
| 101 } | |
| 102 } | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 for (size_t i = 0; i < matches_.size(); ++i) | |
| 107 matches_[i].relevance = kRelevance + matches_.size() - (i + 1); | |
| 108 if (!HistoryProvider::PreventInlineAutocomplete(input) && | |
| 109 (matches_.size() == 1)) { | |
| 110 // If there's only one possible completion of the user's input and | |
| 111 // allowing completions is okay, give the match a high enough score to | |
| 112 // allow it to beat url-what-you-typed and be inlined. | |
| 113 matches_[0].relevance = 1250; | |
| 114 matches_[0].allowed_to_be_default_match = true; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 BuiltinProvider::~BuiltinProvider() {} | |
| 119 | |
| 120 void BuiltinProvider::AddMatch(const base::string16& match_string, | |
| 121 const base::string16& inline_completion, | |
| 122 const ACMatchClassifications& styles) { | |
| 123 AutocompleteMatch match(this, kRelevance, false, | |
| 124 AutocompleteMatchType::NAVSUGGEST); | |
| 125 match.fill_into_edit = match_string; | |
| 126 match.inline_autocompletion = inline_completion; | |
| 127 match.destination_url = GURL(match_string); | |
| 128 match.contents = match_string; | |
| 129 match.contents_class = styles; | |
| 130 matches_.push_back(match); | |
| 131 } | |
| OLD | NEW |