OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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/base_search_provider.h" |
| 6 |
| 7 #include "base/strings/string16.h" |
| 8 #include "base/strings/string_util.h" |
| 9 #include "chrome/browser/autocomplete/autocomplete_input.h" |
| 10 #include "chrome/browser/autocomplete/autocomplete_match.h" |
| 11 #include "chrome/browser/autocomplete/autocomplete_provider.h" |
| 12 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" |
| 13 #include "chrome/browser/autocomplete/url_prefix.h" |
| 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "net/base/escape.h" |
| 16 #include "net/base/net_util.h" |
| 17 #include "net/url_request/url_fetcher_delegate.h" |
| 18 #include "url/gurl.h" |
| 19 |
| 20 // BaseSearchProvider --------------------------------------------------------- |
| 21 |
| 22 BaseSearchProvider::BaseSearchProvider(AutocompleteProviderListener* listener, |
| 23 Profile* profile, |
| 24 AutocompleteProvider::Type type) |
| 25 : AutocompleteProvider(listener, profile, type) {} |
| 26 |
| 27 // BaseSearchProvider::Result -------------------------------------------------- |
| 28 |
| 29 BaseSearchProvider::Result::Result(bool from_keyword_provider, |
| 30 int relevance, |
| 31 bool relevance_from_server) |
| 32 : from_keyword_provider_(from_keyword_provider), |
| 33 relevance_(relevance), |
| 34 relevance_from_server_(relevance_from_server) {} |
| 35 |
| 36 BaseSearchProvider::Result::~Result() {} |
| 37 |
| 38 // BaseSearchProvider::SuggestResult ------------------------------------------- |
| 39 |
| 40 BaseSearchProvider::SuggestResult::SuggestResult( |
| 41 const base::string16& suggestion, |
| 42 AutocompleteMatchType::Type type, |
| 43 const base::string16& match_contents, |
| 44 const base::string16& annotation, |
| 45 const std::string& suggest_query_params, |
| 46 const std::string& deletion_url, |
| 47 bool from_keyword_provider, |
| 48 int relevance, |
| 49 bool relevance_from_server, |
| 50 bool should_prefetch, |
| 51 const base::string16& input_text) |
| 52 : Result(from_keyword_provider, relevance, relevance_from_server), |
| 53 suggestion_(suggestion), |
| 54 type_(type), |
| 55 annotation_(annotation), |
| 56 suggest_query_params_(suggest_query_params), |
| 57 deletion_url_(deletion_url), |
| 58 should_prefetch_(should_prefetch) { |
| 59 match_contents_ = match_contents; |
| 60 DCHECK(!match_contents_.empty()); |
| 61 ClassifyMatchContents(true, input_text); |
| 62 } |
| 63 |
| 64 BaseSearchProvider::SuggestResult::~SuggestResult() {} |
| 65 |
| 66 void BaseSearchProvider::SuggestResult::ClassifyMatchContents( |
| 67 const bool allow_bolding_all, |
| 68 const base::string16& input_text) { |
| 69 size_t input_position = match_contents_.find(input_text); |
| 70 if (!allow_bolding_all && (input_position == base::string16::npos)) { |
| 71 // Bail if the code below to update the bolding would bold the whole |
| 72 // string. Note that the string may already be entirely bolded; if |
| 73 // so, leave it as is. |
| 74 return; |
| 75 } |
| 76 match_contents_class_.clear(); |
| 77 // We do intra-string highlighting for suggestions - the suggested segment |
| 78 // will be highlighted, e.g. for input_text = "you" the suggestion may be |
| 79 // "youtube", so we'll bold the "tube" section: you*tube*. |
| 80 if (input_text != match_contents_) { |
| 81 if (input_position == base::string16::npos) { |
| 82 // The input text is not a substring of the query string, e.g. input |
| 83 // text is "slasdot" and the query string is "slashdot", so we bold the |
| 84 // whole thing. |
| 85 match_contents_class_.push_back( |
| 86 ACMatchClassification(0, ACMatchClassification::MATCH)); |
| 87 } else { |
| 88 // We don't iterate over the string here annotating all matches because |
| 89 // it looks odd to have every occurrence of a substring that may be as |
| 90 // short as a single character highlighted in a query suggestion result, |
| 91 // e.g. for input text "s" and query string "southwest airlines", it |
| 92 // looks odd if both the first and last s are highlighted. |
| 93 if (input_position != 0) { |
| 94 match_contents_class_.push_back( |
| 95 ACMatchClassification(0, ACMatchClassification::MATCH)); |
| 96 } |
| 97 match_contents_class_.push_back( |
| 98 ACMatchClassification(input_position, ACMatchClassification::NONE)); |
| 99 size_t next_fragment_position = input_position + input_text.length(); |
| 100 if (next_fragment_position < match_contents_.length()) { |
| 101 match_contents_class_.push_back(ACMatchClassification( |
| 102 next_fragment_position, ACMatchClassification::MATCH)); |
| 103 } |
| 104 } |
| 105 } else { |
| 106 // Otherwise, match_contents_ is a verbatim (what-you-typed) match, either |
| 107 // for the default provider or a keyword search provider. |
| 108 match_contents_class_.push_back( |
| 109 ACMatchClassification(0, ACMatchClassification::NONE)); |
| 110 } |
| 111 } |
| 112 |
| 113 bool BaseSearchProvider::SuggestResult::IsInlineable( |
| 114 const base::string16& input) const { |
| 115 return StartsWith(suggestion_, input, false); |
| 116 } |
| 117 |
| 118 int BaseSearchProvider::SuggestResult::CalculateRelevance( |
| 119 const AutocompleteInput& input, |
| 120 bool keyword_provider_requested) const { |
| 121 if (!from_keyword_provider_ && keyword_provider_requested) |
| 122 return 100; |
| 123 return ((input.type() == AutocompleteInput::URL) ? 300 : 600); |
| 124 } |
| 125 |
| 126 // BaseSearchProvider::NavigationResult ---------------------------------------- |
| 127 |
| 128 BaseSearchProvider::NavigationResult::NavigationResult( |
| 129 const AutocompleteProvider& provider, |
| 130 const GURL& url, |
| 131 const base::string16& description, |
| 132 bool from_keyword_provider, |
| 133 int relevance, |
| 134 bool relevance_from_server, |
| 135 const base::string16& input_text, |
| 136 const std::string& languages) |
| 137 : Result(from_keyword_provider, relevance, relevance_from_server), |
| 138 url_(url), |
| 139 formatted_url_(AutocompleteInput::FormattedStringWithEquivalentMeaning( |
| 140 url, |
| 141 provider.StringForURLDisplay(url, true, false))), |
| 142 description_(description) { |
| 143 DCHECK(url_.is_valid()); |
| 144 CalculateAndClassifyMatchContents(true, input_text, languages); |
| 145 } |
| 146 |
| 147 BaseSearchProvider::NavigationResult::~NavigationResult() {} |
| 148 |
| 149 void BaseSearchProvider::NavigationResult::CalculateAndClassifyMatchContents( |
| 150 const bool allow_bolding_nothing, |
| 151 const base::string16& input_text, |
| 152 const std::string& languages) { |
| 153 // First look for the user's input inside the formatted url as it would be |
| 154 // without trimming the scheme, so we can find matches at the beginning of the |
| 155 // scheme. |
| 156 const URLPrefix* prefix = |
| 157 URLPrefix::BestURLPrefix(formatted_url_, input_text); |
| 158 size_t match_start = (prefix == NULL) ? formatted_url_.find(input_text) |
| 159 : prefix->prefix.length(); |
| 160 bool trim_http = !AutocompleteInput::HasHTTPScheme(input_text) && |
| 161 (!prefix || (match_start != 0)); |
| 162 const net::FormatUrlTypes format_types = |
| 163 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP); |
| 164 |
| 165 base::string16 match_contents = net::FormatUrl(url_, |
| 166 languages, |
| 167 format_types, |
| 168 net::UnescapeRule::SPACES, |
| 169 NULL, |
| 170 NULL, |
| 171 &match_start); |
| 172 // If the first match in the untrimmed string was inside a scheme that we |
| 173 // trimmed, look for a subsequent match. |
| 174 if (match_start == base::string16::npos) |
| 175 match_start = match_contents.find(input_text); |
| 176 // Update |match_contents_| and |match_contents_class_| if it's allowed. |
| 177 if (allow_bolding_nothing || (match_start != base::string16::npos)) { |
| 178 match_contents_ = match_contents; |
| 179 // Safe if |match_start| is npos; also safe if the input is longer than the |
| 180 // remaining contents after |match_start|. |
| 181 AutocompleteMatch::ClassifyLocationInString(match_start, |
| 182 input_text.length(), |
| 183 match_contents_.length(), |
| 184 ACMatchClassification::URL, |
| 185 &match_contents_class_); |
| 186 } |
| 187 } |
| 188 |
| 189 bool BaseSearchProvider::NavigationResult::IsInlineable( |
| 190 const base::string16& input) const { |
| 191 return URLPrefix::BestURLPrefix(formatted_url_, input) != NULL; |
| 192 } |
| 193 |
| 194 int BaseSearchProvider::NavigationResult::CalculateRelevance( |
| 195 const AutocompleteInput& input, |
| 196 bool keyword_provider_requested) const { |
| 197 return (from_keyword_provider_ || !keyword_provider_requested) ? 800 : 150; |
| 198 } |
| 199 |
| 200 // BaseSearchProvider::Results ------------------------------------------------- |
| 201 |
| 202 BaseSearchProvider::Results::Results() : verbatim_relevance(-1) {} |
| 203 |
| 204 BaseSearchProvider::Results::~Results() {} |
| 205 |
| 206 void BaseSearchProvider::Results::Clear() { |
| 207 suggest_results.clear(); |
| 208 navigation_results.clear(); |
| 209 verbatim_relevance = -1; |
| 210 metadata.clear(); |
| 211 } |
| 212 |
| 213 bool BaseSearchProvider::Results::HasServerProvidedScores() const { |
| 214 if (verbatim_relevance >= 0) |
| 215 return true; |
| 216 |
| 217 // Right now either all results of one type will be server-scored or they will |
| 218 // all be locally scored, but in case we change this later, we'll just check |
| 219 // them all. |
| 220 for (SuggestResults::const_iterator i(suggest_results.begin()); |
| 221 i != suggest_results.end(); |
| 222 ++i) { |
| 223 if (i->relevance_from_server()) |
| 224 return true; |
| 225 } |
| 226 for (NavigationResults::const_iterator i(navigation_results.begin()); |
| 227 i != navigation_results.end(); |
| 228 ++i) { |
| 229 if (i->relevance_from_server()) |
| 230 return true; |
| 231 } |
| 232 |
| 233 return false; |
| 234 } |
| 235 |
| 236 // BaseSearchProvider --------------------------------------------------------- |
| 237 |
| 238 BaseSearchProvider::~BaseSearchProvider() {} |
OLD | NEW |