OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/omnibox/browser/shortcuts_provider.h" | 5 #include "components/omnibox/browser/shortcuts_provider.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <cmath> | 10 #include <cmath> |
(...skipping 10 matching lines...) Expand all Loading... | |
21 #include "base/time/time.h" | 21 #include "base/time/time.h" |
22 #include "base/trace_event/trace_event.h" | 22 #include "base/trace_event/trace_event.h" |
23 #include "components/history/core/browser/history_service.h" | 23 #include "components/history/core/browser/history_service.h" |
24 #include "components/metrics/proto/omnibox_input_type.pb.h" | 24 #include "components/metrics/proto/omnibox_input_type.pb.h" |
25 #include "components/omnibox/browser/autocomplete_i18n.h" | 25 #include "components/omnibox/browser/autocomplete_i18n.h" |
26 #include "components/omnibox/browser/autocomplete_input.h" | 26 #include "components/omnibox/browser/autocomplete_input.h" |
27 #include "components/omnibox/browser/autocomplete_match.h" | 27 #include "components/omnibox/browser/autocomplete_match.h" |
28 #include "components/omnibox/browser/autocomplete_provider_client.h" | 28 #include "components/omnibox/browser/autocomplete_provider_client.h" |
29 #include "components/omnibox/browser/autocomplete_result.h" | 29 #include "components/omnibox/browser/autocomplete_result.h" |
30 #include "components/omnibox/browser/history_provider.h" | 30 #include "components/omnibox/browser/history_provider.h" |
31 #include "components/omnibox/browser/match_compare.h" | |
31 #include "components/omnibox/browser/omnibox_field_trial.h" | 32 #include "components/omnibox/browser/omnibox_field_trial.h" |
33 #include "components/omnibox/browser/shortcut_match.h" | |
32 #include "components/omnibox/browser/url_prefix.h" | 34 #include "components/omnibox/browser/url_prefix.h" |
33 #include "components/prefs/pref_service.h" | 35 #include "components/prefs/pref_service.h" |
34 #include "components/url_formatter/url_fixer.h" | 36 #include "components/url_formatter/url_fixer.h" |
35 #include "url/third_party/mozilla/url_parse.h" | 37 #include "url/third_party/mozilla/url_parse.h" |
36 | 38 |
37 namespace { | 39 namespace { |
38 | 40 |
39 class DestinationURLEqualsURL { | 41 class DestinationURLEqualsURL { |
40 public: | 42 public: |
41 explicit DestinationURLEqualsURL(const GURL& url) : url_(url) {} | 43 explicit DestinationURLEqualsURL(const GURL& url) : url_(url) {} |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
131 // completely match the search term. | 133 // completely match the search term. |
132 base::string16 term_string(base::i18n::ToLower(input.text())); | 134 base::string16 term_string(base::i18n::ToLower(input.text())); |
133 DCHECK(!term_string.empty()); | 135 DCHECK(!term_string.empty()); |
134 | 136 |
135 int max_relevance; | 137 int max_relevance; |
136 if (!OmniboxFieldTrial::ShortcutsScoringMaxRelevance( | 138 if (!OmniboxFieldTrial::ShortcutsScoringMaxRelevance( |
137 input.current_page_classification(), &max_relevance)) | 139 input.current_page_classification(), &max_relevance)) |
138 max_relevance = kShortcutsProviderDefaultMaxRelevance; | 140 max_relevance = kShortcutsProviderDefaultMaxRelevance; |
139 TemplateURLService* template_url_service = client_->GetTemplateURLService(); | 141 TemplateURLService* template_url_service = client_->GetTemplateURLService(); |
140 const base::string16 fixed_up_input(FixupUserInput(input).second); | 142 const base::string16 fixed_up_input(FixupUserInput(input).second); |
143 | |
144 ShortcutMatches shortcut_matches; | |
141 for (ShortcutsBackend::ShortcutMap::const_iterator it = | 145 for (ShortcutsBackend::ShortcutMap::const_iterator it = |
142 FindFirstMatch(term_string, backend.get()); | 146 FindFirstMatch(term_string, backend.get()); |
143 it != backend->shortcuts_map().end() && | 147 it != backend->shortcuts_map().end() && |
144 base::StartsWith(it->first, term_string, | 148 base::StartsWith(it->first, term_string, |
145 base::CompareCase::SENSITIVE); | 149 base::CompareCase::SENSITIVE); |
146 ++it) { | 150 ++it) { |
147 // Don't return shortcuts with zero relevance. | 151 // Don't return shortcuts with zero relevance. |
148 int relevance = CalculateScore(term_string, it->second, max_relevance); | 152 int relevance = CalculateScore(term_string, it->second, max_relevance); |
149 if (relevance) { | 153 if (relevance) { |
150 matches_.push_back( | 154 const ShortcutsDatabase::Shortcut& shortcut = it->second; |
151 ShortcutToACMatch(it->second, relevance, input, fixed_up_input)); | 155 GURL stripped_destination_url(AutocompleteMatch::GURLToStrippedGURL( |
152 matches_.back().ComputeStrippedDestinationURL( | 156 shortcut.match_core.destination_url, |
153 input, client_->GetAcceptLanguages(), template_url_service); | 157 input, |
158 languages_, | |
159 template_url_service, | |
160 shortcut.match_core.keyword)); | |
161 shortcut_matches.push_back(ShortcutMatch(relevance, | |
162 stripped_destination_url, | |
163 &(it->second))); | |
Peter Kasting
2016/04/12 23:29:50
Nit: Shorter:
shortcut_matches.push_back(
Alexander Yashkin
2016/04/13 09:29:36
Done.
| |
154 } | 164 } |
155 } | 165 } |
156 // Remove duplicates. This is important because it's common to have multiple | 166 // Remove duplicates. This is important because it's common to have multiple |
157 // shortcuts pointing to the same URL, e.g., ma, mai, and mail all pointing | 167 // shortcuts pointing to the same URL, e.g., ma, mai, and mail all pointing |
158 // to mail.google.com, so typing "m" will return them all. If we then simply | 168 // to mail.google.com, so typing "m" will return them all. If we then simply |
159 // clamp to kMaxMatches and let the AutocompleteResult take care of | 169 // clamp to kMaxMatches and let the AutocompleteResult take care of |
160 // collapsing the duplicates, we'll effectively only be returning one match, | 170 // collapsing the duplicates, we'll effectively only be returning one match, |
161 // instead of several possibilities. | 171 // instead of several possibilities. |
162 // | 172 // |
163 // Note that while removing duplicates, we don't populate a match's | 173 // Note that while removing duplicates, we don't populate a match's |
164 // |duplicate_matches| field--duplicates don't need to be preserved in the | 174 // |duplicate_matches| field--duplicates don't need to be preserved in the |
165 // matches because they are only used for deletions, and this provider | 175 // matches because they are only used for deletions, and this provider |
166 // deletes matches based on the URL. | 176 // deletes matches based on the URL. |
167 AutocompleteResult::DedupMatchesByDestination( | 177 DedupShortcutMatchesByDestination(input.current_page_classification(), |
168 input.current_page_classification(), false, &matches_); | 178 &shortcut_matches); |
Peter Kasting
2016/04/12 23:29:50
After removing the call to AutocompleteResult::Ded
Alexander Yashkin
2016/04/13 09:29:36
Done.
| |
169 // Find best matches. | 179 // Find best matches. |
170 std::partial_sort( | 180 std::partial_sort( |
171 matches_.begin(), | 181 shortcut_matches.begin(), |
172 matches_.begin() + | 182 shortcut_matches.begin() + |
173 std::min(AutocompleteProvider::kMaxMatches, matches_.size()), | 183 std::min(AutocompleteProvider::kMaxMatches, shortcut_matches.size()), |
174 matches_.end(), &AutocompleteMatch::MoreRelevant); | 184 shortcut_matches.end(), |
175 if (matches_.size() > AutocompleteProvider::kMaxMatches) { | 185 ShortcutMatch::MoreRelevant); |
176 matches_.erase(matches_.begin() + AutocompleteProvider::kMaxMatches, | 186 if (shortcut_matches.size() > AutocompleteProvider::kMaxMatches) { |
177 matches_.end()); | 187 shortcut_matches.erase( |
188 shortcut_matches.begin() + AutocompleteProvider::kMaxMatches, | |
189 shortcut_matches.end()); | |
178 } | 190 } |
179 // Guarantee that all scores are decreasing (but do not assign any scores | 191 // Create and initialize autocomplete matches from shortcut matches. |
180 // below 1). | 192 // Also guarantee that all relevance scores are decreasing |
181 for (ACMatches::iterator it = matches_.begin(); it != matches_.end(); ++it) { | 193 // (but do not assign any scores below 1). |
182 max_relevance = std::min(max_relevance, it->relevance); | 194 WordMap terms_map(CreateWordMapForString(term_string)); |
183 it->relevance = max_relevance; | 195 matches_.reserve(shortcut_matches.size()); |
196 for (ShortcutMatch& match : shortcut_matches) { | |
197 max_relevance = std::min(max_relevance, match.relevance); | |
198 match.relevance = max_relevance; | |
184 if (max_relevance > 1) | 199 if (max_relevance > 1) |
185 --max_relevance; | 200 --max_relevance; |
201 matches_.push_back(ShortcutMatchToACMatch(match, input, fixed_up_input, | |
202 term_string, terms_map)); | |
186 } | 203 } |
187 } | 204 } |
188 | 205 |
189 AutocompleteMatch ShortcutsProvider::ShortcutToACMatch( | 206 AutocompleteMatch ShortcutsProvider::ShortcutMatchToACMatch( |
190 const ShortcutsDatabase::Shortcut& shortcut, | 207 const ShortcutMatch& shortcut_match, |
191 int relevance, | |
192 const AutocompleteInput& input, | 208 const AutocompleteInput& input, |
193 const base::string16& fixed_up_input_text) { | 209 const base::string16& fixed_up_input_text, |
210 const base::string16 term_string, | |
211 const WordMap& terms_map) { | |
194 DCHECK(!input.text().empty()); | 212 DCHECK(!input.text().empty()); |
213 const ShortcutsDatabase::Shortcut& shortcut = *shortcut_match.shortcut; | |
195 AutocompleteMatch match; | 214 AutocompleteMatch match; |
196 match.provider = this; | 215 match.provider = this; |
197 match.relevance = relevance; | 216 match.relevance = shortcut_match.relevance; |
198 match.deletable = true; | 217 match.deletable = true; |
199 match.fill_into_edit = shortcut.match_core.fill_into_edit; | 218 match.fill_into_edit = shortcut.match_core.fill_into_edit; |
200 match.destination_url = shortcut.match_core.destination_url; | 219 match.destination_url = shortcut.match_core.destination_url; |
201 DCHECK(match.destination_url.is_valid()); | 220 DCHECK(match.destination_url.is_valid()); |
202 match.contents = shortcut.match_core.contents; | 221 match.contents = shortcut.match_core.contents; |
203 match.contents_class = AutocompleteMatch::ClassificationsFromString( | 222 match.contents_class = AutocompleteMatch::ClassificationsFromString( |
204 shortcut.match_core.contents_class); | 223 shortcut.match_core.contents_class); |
205 match.description = shortcut.match_core.description; | 224 match.description = shortcut.match_core.description; |
206 match.description_class = AutocompleteMatch::ClassificationsFromString( | 225 match.description_class = AutocompleteMatch::ClassificationsFromString( |
207 shortcut.match_core.description_class); | 226 shortcut.match_core.description_class); |
208 match.transition = ui::PageTransitionFromInt(shortcut.match_core.transition); | 227 match.transition = ui::PageTransitionFromInt(shortcut.match_core.transition); |
209 match.type = static_cast<AutocompleteMatch::Type>(shortcut.match_core.type); | 228 match.type = static_cast<AutocompleteMatch::Type>(shortcut.match_core.type); |
210 match.keyword = shortcut.match_core.keyword; | 229 match.keyword = shortcut.match_core.keyword; |
230 match.stripped_destination_url = shortcut_match.stripped_destination_url; | |
211 match.RecordAdditionalInfo("number of hits", shortcut.number_of_hits); | 231 match.RecordAdditionalInfo("number of hits", shortcut.number_of_hits); |
212 match.RecordAdditionalInfo("last access time", shortcut.last_access_time); | 232 match.RecordAdditionalInfo("last access time", shortcut.last_access_time); |
213 match.RecordAdditionalInfo("original input text", | 233 match.RecordAdditionalInfo("original input text", |
214 base::UTF16ToUTF8(shortcut.text)); | 234 base::UTF16ToUTF8(shortcut.text)); |
215 | 235 |
216 // Set |inline_autocompletion| and |allowed_to_be_default_match| if possible. | 236 // Set |inline_autocompletion| and |allowed_to_be_default_match| if possible. |
217 // If the match is a search query this is easy: simply check whether the | 237 // If the match is a search query this is easy: simply check whether the |
218 // user text is a prefix of the query. If the match is a navigation, we | 238 // user text is a prefix of the query. If the match is a navigation, we |
219 // assume the fill_into_edit looks something like a URL, so we use | 239 // assume the fill_into_edit looks something like a URL, so we use |
220 // URLPrefix::GetInlineAutocompleteOffset() to try and strip off any prefixes | 240 // URLPrefix::GetInlineAutocompleteOffset() to try and strip off any prefixes |
(...skipping 19 matching lines...) Expand all Loading... | |
240 input.text(), fixed_up_input_text, true, match.fill_into_edit); | 260 input.text(), fixed_up_input_text, true, match.fill_into_edit); |
241 if (inline_autocomplete_offset != base::string16::npos) { | 261 if (inline_autocomplete_offset != base::string16::npos) { |
242 match.inline_autocompletion = | 262 match.inline_autocompletion = |
243 match.fill_into_edit.substr(inline_autocomplete_offset); | 263 match.fill_into_edit.substr(inline_autocomplete_offset); |
244 match.allowed_to_be_default_match = | 264 match.allowed_to_be_default_match = |
245 !HistoryProvider::PreventInlineAutocomplete(input) || | 265 !HistoryProvider::PreventInlineAutocomplete(input) || |
246 match.inline_autocompletion.empty(); | 266 match.inline_autocompletion.empty(); |
247 } | 267 } |
248 } | 268 } |
249 match.EnsureUWYTIsAllowedToBeDefault(input, | 269 match.EnsureUWYTIsAllowedToBeDefault(input, |
250 client_->GetAcceptLanguages(), | 270 languages_, |
251 client_->GetTemplateURLService()); | 271 client_->GetTemplateURLService()); |
252 | 272 |
253 // Try to mark pieces of the contents and description as matches if they | 273 // Try to mark pieces of the contents and description as matches if they |
254 // appear in |input.text()|. | 274 // appear in |input.text()|. |
255 const base::string16 term_string = base::i18n::ToLower(input.text()); | |
256 WordMap terms_map(CreateWordMapForString(term_string)); | |
257 if (!terms_map.empty()) { | 275 if (!terms_map.empty()) { |
258 match.contents_class = ClassifyAllMatchesInString( | 276 match.contents_class = ClassifyAllMatchesInString( |
259 term_string, terms_map, match.contents, match.contents_class); | 277 term_string, terms_map, match.contents, match.contents_class); |
260 match.description_class = ClassifyAllMatchesInString( | 278 match.description_class = ClassifyAllMatchesInString( |
261 term_string, terms_map, match.description, match.description_class); | 279 term_string, terms_map, match.description, match.description_class); |
262 } | 280 } |
263 return match; | 281 return match; |
264 } | 282 } |
265 | 283 |
266 // static | 284 // static |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
416 const double kMaxDecaySpeedDivisor = 5.0; | 434 const double kMaxDecaySpeedDivisor = 5.0; |
417 const double kNumUsesPerDecaySpeedDivisorIncrement = 5.0; | 435 const double kNumUsesPerDecaySpeedDivisorIncrement = 5.0; |
418 double decay_divisor = std::min( | 436 double decay_divisor = std::min( |
419 kMaxDecaySpeedDivisor, | 437 kMaxDecaySpeedDivisor, |
420 (shortcut.number_of_hits + kNumUsesPerDecaySpeedDivisorIncrement - 1) / | 438 (shortcut.number_of_hits + kNumUsesPerDecaySpeedDivisorIncrement - 1) / |
421 kNumUsesPerDecaySpeedDivisorIncrement); | 439 kNumUsesPerDecaySpeedDivisorIncrement); |
422 | 440 |
423 return static_cast<int>((base_score / exp(decay_exponent / decay_divisor)) + | 441 return static_cast<int>((base_score / exp(decay_exponent / decay_divisor)) + |
424 0.5); | 442 0.5); |
425 } | 443 } |
444 | |
445 // static | |
446 void ShortcutsProvider::DedupShortcutMatchesByDestination( | |
447 OmniboxEventProto::PageClassification page_classification, | |
448 std::vector<ShortcutMatch>* matches) { | |
449 DestinationSort<ShortcutMatch> destination_sort(page_classification); | |
Peter Kasting
2016/04/12 23:29:50
Nit: Seems like we could just inline this into the
Alexander Yashkin
2016/04/13 09:29:36
Done.
| |
450 // Sort matches such that duplicate matches are consecutive. | |
451 std::sort(matches->begin(), matches->end(), destination_sort); | |
452 | |
453 // Erase duplicate matches. | |
454 matches->erase( | |
455 std::unique(matches->begin(), | |
456 matches->end(), | |
457 &ShortcutMatch::DestinationsEqual), | |
458 matches->end()); | |
459 } | |
OLD | NEW |