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 "chrome/browser/autocomplete/history_quick_provider.h" | 5 #include "chrome/browser/autocomplete/history_quick_provider.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/i18n/break_iterator.h" | 11 #include "base/i18n/break_iterator.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/metrics/field_trial.h" | 13 #include "base/metrics/field_trial.h" |
14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
15 #include "base/prefs/pref_service.h" | 15 #include "base/prefs/pref_service.h" |
16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
17 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
18 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
19 #include "base/time/time.h" | 19 #include "base/time/time.h" |
20 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" | 20 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" |
21 #include "chrome/browser/autocomplete/history_url_provider.h" | 21 #include "chrome/browser/autocomplete/history_url_provider.h" |
| 22 #include "chrome/browser/autocomplete/scored_history_match_builder_impl.h" |
| 23 #include "chrome/browser/bookmarks/bookmark_model_factory.h" |
22 #include "chrome/browser/history/history_service.h" | 24 #include "chrome/browser/history/history_service.h" |
23 #include "chrome/browser/history/history_service_factory.h" | 25 #include "chrome/browser/history/history_service_factory.h" |
24 #include "chrome/browser/history/in_memory_url_index.h" | 26 #include "chrome/browser/history/in_memory_url_index.h" |
25 #include "chrome/browser/history/scored_history_match.h" | |
26 #include "chrome/browser/profiles/profile.h" | 27 #include "chrome/browser/profiles/profile.h" |
27 #include "chrome/browser/search_engines/template_url_service_factory.h" | 28 #include "chrome/browser/search_engines/template_url_service_factory.h" |
28 #include "chrome/common/chrome_switches.h" | 29 #include "chrome/common/chrome_switches.h" |
29 #include "chrome/common/pref_names.h" | 30 #include "chrome/common/pref_names.h" |
30 #include "chrome/common/url_constants.h" | 31 #include "chrome/common/url_constants.h" |
| 32 #include "components/bookmarks/browser/bookmark_model.h" |
31 #include "components/history/core/browser/history_database.h" | 33 #include "components/history/core/browser/history_database.h" |
32 #include "components/history/core/browser/in_memory_url_index_types.h" | 34 #include "components/history/core/browser/in_memory_url_index_types.h" |
33 #include "components/metrics/proto/omnibox_input_type.pb.h" | 35 #include "components/metrics/proto/omnibox_input_type.pb.h" |
34 #include "components/omnibox/autocomplete_match_type.h" | 36 #include "components/omnibox/autocomplete_match_type.h" |
35 #include "components/omnibox/autocomplete_result.h" | 37 #include "components/omnibox/autocomplete_result.h" |
36 #include "components/omnibox/omnibox_field_trial.h" | 38 #include "components/omnibox/omnibox_field_trial.h" |
37 #include "components/search_engines/template_url.h" | 39 #include "components/search_engines/template_url.h" |
38 #include "components/search_engines/template_url_service.h" | 40 #include "components/search_engines/template_url_service.h" |
39 #include "content/public/browser/notification_source.h" | 41 #include "content/public/browser/notification_source.h" |
40 #include "content/public/browser/notification_types.h" | 42 #include "content/public/browser/notification_types.h" |
41 #include "net/base/escape.h" | 43 #include "net/base/escape.h" |
42 #include "net/base/net_util.h" | 44 #include "net/base/net_util.h" |
43 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 45 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
44 #include "url/url_parse.h" | 46 #include "url/url_parse.h" |
45 #include "url/url_util.h" | 47 #include "url/url_util.h" |
46 | 48 |
47 using history::InMemoryURLIndex; | 49 using history::InMemoryURLIndex; |
48 using history::ScoredHistoryMatch; | 50 using history::ScoredHistoryMatch; |
49 using history::ScoredHistoryMatches; | 51 using history::ScoredHistoryMatches; |
50 | 52 |
| 53 namespace { |
| 54 |
| 55 // Returns whether |url| is bookmarked in |bookmark_model| (which can be null |
| 56 // during testing). Used for ScoredHistoryMatchBuilderImpl. |
| 57 bool IsBookmarked(bookmarks::BookmarkModel* bookmark_model, const GURL& url) { |
| 58 return bookmark_model && bookmark_model->IsBookmarked(url); |
| 59 } |
| 60 |
| 61 } // namespace |
| 62 |
51 bool HistoryQuickProvider::disabled_ = false; | 63 bool HistoryQuickProvider::disabled_ = false; |
52 | 64 |
53 HistoryQuickProvider::HistoryQuickProvider(Profile* profile) | 65 HistoryQuickProvider::HistoryQuickProvider(Profile* profile) |
54 : HistoryProvider(profile, AutocompleteProvider::TYPE_HISTORY_QUICK), | 66 : HistoryProvider(profile, AutocompleteProvider::TYPE_HISTORY_QUICK), |
55 languages_(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)) { | 67 languages_(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)) { |
56 } | 68 } |
57 | 69 |
58 void HistoryQuickProvider::Start(const AutocompleteInput& input, | 70 void HistoryQuickProvider::Start(const AutocompleteInput& input, |
59 bool minimal_changes, | 71 bool minimal_changes, |
60 bool called_due_to_focus) { | 72 bool called_due_to_focus) { |
(...skipping 22 matching lines...) Expand all Loading... |
83 name, 1, 1000, 50, base::Histogram::kUmaTargetedHistogramFlag); | 95 name, 1, 1000, 50, base::Histogram::kUmaTargetedHistogramFlag); |
84 counter->Add(static_cast<int>((end_time - start_time).InMilliseconds())); | 96 counter->Add(static_cast<int>((end_time - start_time).InMilliseconds())); |
85 } | 97 } |
86 } | 98 } |
87 } | 99 } |
88 | 100 |
89 HistoryQuickProvider::~HistoryQuickProvider() {} | 101 HistoryQuickProvider::~HistoryQuickProvider() {} |
90 | 102 |
91 void HistoryQuickProvider::DoAutocomplete() { | 103 void HistoryQuickProvider::DoAutocomplete() { |
92 // Get the matching URLs from the DB. | 104 // Get the matching URLs from the DB. |
93 ScoredHistoryMatches matches = GetIndex()->HistoryItemsForTerms( | 105 ScoredHistoryMatches matches; |
94 autocomplete_input_.text(), | 106 { |
95 autocomplete_input_.cursor_position(), | 107 ScoredHistoryMatchBuilderImpl builder(base::Bind( |
96 AutocompleteProvider::kMaxMatches); | 108 &IsBookmarked, |
| 109 base::Unretained(BookmarkModelFactory::GetForProfile(profile_)))); |
| 110 matches = GetIndex()->HistoryItemsForTerms( |
| 111 autocomplete_input_.text(), autocomplete_input_.cursor_position(), |
| 112 AutocompleteProvider::kMaxMatches, builder); |
| 113 } |
97 if (matches.empty()) | 114 if (matches.empty()) |
98 return; | 115 return; |
99 | 116 |
100 // Figure out if HistoryURL provider has a URL-what-you-typed match | 117 // Figure out if HistoryURL provider has a URL-what-you-typed match |
101 // that ought to go first and what its score will be. | 118 // that ought to go first and what its score will be. |
102 bool will_have_url_what_you_typed_match_first = false; | 119 bool will_have_url_what_you_typed_match_first = false; |
103 int url_what_you_typed_match_score = -1; // undefined | 120 int url_what_you_typed_match_score = -1; // undefined |
104 // These are necessary (but not sufficient) conditions for the omnibox | 121 // These are necessary (but not sufficient) conditions for the omnibox |
105 // input to be a URL-what-you-typed match. The username test checks that | 122 // input to be a URL-what-you-typed match. The username test checks that |
106 // either the username does not exist (a regular URL such as http://site/) | 123 // either the username does not exist (a regular URL such as http://site/) |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 // a URL-what-you-typed match. (We want URL-what-you-typed matches for | 209 // a URL-what-you-typed match. (We want URL-what-you-typed matches for |
193 // visited URLs to beat out any longer URLs, no matter how frequently | 210 // visited URLs to beat out any longer URLs, no matter how frequently |
194 // they're visited.) The strength of this reduction depends on the | 211 // they're visited.) The strength of this reduction depends on the |
195 // likely score for the URL-what-you-typed result. | 212 // likely score for the URL-what-you-typed result. |
196 | 213 |
197 // |template_url_service| or |template_url| can be NULL in unit tests. | 214 // |template_url_service| or |template_url| can be NULL in unit tests. |
198 TemplateURLService* template_url_service = | 215 TemplateURLService* template_url_service = |
199 TemplateURLServiceFactory::GetForProfile(profile_); | 216 TemplateURLServiceFactory::GetForProfile(profile_); |
200 TemplateURL* template_url = template_url_service ? | 217 TemplateURL* template_url = template_url_service ? |
201 template_url_service->GetDefaultSearchProvider() : NULL; | 218 template_url_service->GetDefaultSearchProvider() : NULL; |
202 int max_match_score = matches.begin()->raw_score(); | 219 int max_match_score = matches.begin()->raw_score; |
203 if (will_have_url_what_you_typed_match_first) { | 220 if (will_have_url_what_you_typed_match_first) { |
204 max_match_score = std::min(max_match_score, | 221 max_match_score = std::min(max_match_score, |
205 url_what_you_typed_match_score - 1); | 222 url_what_you_typed_match_score - 1); |
206 } | 223 } |
207 for (ScoredHistoryMatches::const_iterator match_iter = matches.begin(); | 224 for (ScoredHistoryMatches::const_iterator match_iter = matches.begin(); |
208 match_iter != matches.end(); ++match_iter) { | 225 match_iter != matches.end(); ++match_iter) { |
209 const ScoredHistoryMatch& history_match(*match_iter); | 226 const ScoredHistoryMatch& history_match(*match_iter); |
210 // Culls results corresponding to queries from the default search engine. | 227 // Culls results corresponding to queries from the default search engine. |
211 // These are low-quality, difficult-to-understand matches for users, and the | 228 // These are low-quality, difficult-to-understand matches for users, and the |
212 // SearchProvider should surface past queries in a better way anyway. | 229 // SearchProvider should surface past queries in a better way anyway. |
213 if (!template_url || | 230 if (!template_url || |
214 !template_url->IsSearchURL(history_match.url_info.url(), | 231 !template_url->IsSearchURL(history_match.url_info.url(), |
215 template_url_service->search_terms_data())) { | 232 template_url_service->search_terms_data())) { |
216 // Set max_match_score to the score we'll assign this result: | 233 // Set max_match_score to the score we'll assign this result: |
217 max_match_score = std::min(max_match_score, history_match.raw_score()); | 234 max_match_score = std::min(max_match_score, history_match.raw_score); |
218 matches_.push_back(QuickMatchToACMatch(history_match, max_match_score)); | 235 matches_.push_back(QuickMatchToACMatch(history_match, max_match_score)); |
219 // Mark this max_match_score as being used: | 236 // Mark this max_match_score as being used: |
220 max_match_score--; | 237 max_match_score--; |
221 } | 238 } |
222 } | 239 } |
223 } | 240 } |
224 | 241 |
225 AutocompleteMatch HistoryQuickProvider::QuickMatchToACMatch( | 242 AutocompleteMatch HistoryQuickProvider::QuickMatchToACMatch( |
226 const ScoredHistoryMatch& history_match, | 243 const ScoredHistoryMatch& history_match, |
227 int score) { | 244 int score) { |
228 const history::URLRow& info = history_match.url_info; | 245 const history::URLRow& info = history_match.url_info; |
229 AutocompleteMatch match( | 246 AutocompleteMatch match( |
230 this, score, !!info.visit_count(), | 247 this, score, !!info.visit_count(), |
231 history_match.url_matches().empty() ? | 248 history_match.url_matches.empty() ? |
232 AutocompleteMatchType::HISTORY_TITLE : | 249 AutocompleteMatchType::HISTORY_TITLE : |
233 AutocompleteMatchType::HISTORY_URL); | 250 AutocompleteMatchType::HISTORY_URL); |
234 match.typed_count = info.typed_count(); | 251 match.typed_count = info.typed_count(); |
235 match.destination_url = info.url(); | 252 match.destination_url = info.url(); |
236 DCHECK(match.destination_url.is_valid()); | 253 DCHECK(match.destination_url.is_valid()); |
237 | 254 |
238 // Format the URL autocomplete presentation. | 255 // Format the URL autocomplete presentation. |
239 const net::FormatUrlTypes format_types = net::kFormatUrlOmitAll & | 256 const net::FormatUrlTypes format_types = net::kFormatUrlOmitAll & |
240 ~(!history_match.match_in_scheme ? 0 : net::kFormatUrlOmitHTTP); | 257 ~(!history_match.match_in_scheme ? 0 : net::kFormatUrlOmitHTTP); |
241 match.fill_into_edit = | 258 match.fill_into_edit = |
242 AutocompleteInput::FormattedStringWithEquivalentMeaning( | 259 AutocompleteInput::FormattedStringWithEquivalentMeaning( |
243 info.url(), | 260 info.url(), |
244 net::FormatUrl(info.url(), languages_, format_types, | 261 net::FormatUrl(info.url(), languages_, format_types, |
245 net::UnescapeRule::SPACES, NULL, NULL, NULL), | 262 net::UnescapeRule::SPACES, NULL, NULL, NULL), |
246 ChromeAutocompleteSchemeClassifier(profile_)); | 263 ChromeAutocompleteSchemeClassifier(profile_)); |
247 std::vector<size_t> offsets = | 264 std::vector<size_t> offsets = |
248 OffsetsFromTermMatches(history_match.url_matches()); | 265 OffsetsFromTermMatches(history_match.url_matches); |
249 base::OffsetAdjuster::Adjustments adjustments; | 266 base::OffsetAdjuster::Adjustments adjustments; |
250 match.contents = net::FormatUrlWithAdjustments( | 267 match.contents = net::FormatUrlWithAdjustments( |
251 info.url(), languages_, format_types, net::UnescapeRule::SPACES, NULL, | 268 info.url(), languages_, format_types, net::UnescapeRule::SPACES, NULL, |
252 NULL, &adjustments); | 269 NULL, &adjustments); |
253 base::OffsetAdjuster::AdjustOffsets(adjustments, &offsets); | 270 base::OffsetAdjuster::AdjustOffsets(adjustments, &offsets); |
254 history::TermMatches new_matches = | 271 history::TermMatches new_matches = |
255 ReplaceOffsetsInTermMatches(history_match.url_matches(), offsets); | 272 ReplaceOffsetsInTermMatches(history_match.url_matches, offsets); |
256 match.contents_class = | 273 match.contents_class = |
257 SpansFromTermMatch(new_matches, match.contents.length(), true); | 274 SpansFromTermMatch(new_matches, match.contents.length(), true); |
258 | 275 |
259 // Set |inline_autocompletion| and |allowed_to_be_default_match| if possible. | 276 // Set |inline_autocompletion| and |allowed_to_be_default_match| if possible. |
260 if (history_match.can_inline()) { | 277 if (history_match.can_inline) { |
261 DCHECK(!new_matches.empty()); | 278 DCHECK(!new_matches.empty()); |
262 size_t inline_autocomplete_offset = new_matches[0].offset + | 279 size_t inline_autocomplete_offset = new_matches[0].offset + |
263 new_matches[0].length; | 280 new_matches[0].length; |
264 // |inline_autocomplete_offset| may be beyond the end of the | 281 // |inline_autocomplete_offset| may be beyond the end of the |
265 // |fill_into_edit| if the user has typed an URL with a scheme and the | 282 // |fill_into_edit| if the user has typed an URL with a scheme and the |
266 // last character typed is a slash. That slash is removed by the | 283 // last character typed is a slash. That slash is removed by the |
267 // FormatURLWithOffsets call above. | 284 // FormatURLWithOffsets call above. |
268 if (inline_autocomplete_offset < match.fill_into_edit.length()) { | 285 if (inline_autocomplete_offset < match.fill_into_edit.length()) { |
269 match.inline_autocompletion = | 286 match.inline_autocompletion = |
270 match.fill_into_edit.substr(inline_autocomplete_offset); | 287 match.fill_into_edit.substr(inline_autocomplete_offset); |
271 } | 288 } |
272 match.allowed_to_be_default_match = match.inline_autocompletion.empty() || | 289 match.allowed_to_be_default_match = match.inline_autocompletion.empty() || |
273 !PreventInlineAutocomplete(autocomplete_input_); | 290 !PreventInlineAutocomplete(autocomplete_input_); |
274 } | 291 } |
275 match.EnsureUWYTIsAllowedToBeDefault( | 292 match.EnsureUWYTIsAllowedToBeDefault( |
276 autocomplete_input_.canonicalized_url(), | 293 autocomplete_input_.canonicalized_url(), |
277 TemplateURLServiceFactory::GetForProfile(profile_)); | 294 TemplateURLServiceFactory::GetForProfile(profile_)); |
278 | 295 |
279 // Format the description autocomplete presentation. | 296 // Format the description autocomplete presentation. |
280 match.description = info.title(); | 297 match.description = info.title(); |
281 match.description_class = SpansFromTermMatch( | 298 match.description_class = SpansFromTermMatch( |
282 history_match.title_matches(), match.description.length(), false); | 299 history_match.title_matches, match.description.length(), false); |
283 | 300 |
284 match.RecordAdditionalInfo("typed count", info.typed_count()); | 301 match.RecordAdditionalInfo("typed count", info.typed_count()); |
285 match.RecordAdditionalInfo("visit count", info.visit_count()); | 302 match.RecordAdditionalInfo("visit count", info.visit_count()); |
286 match.RecordAdditionalInfo("last visit", info.last_visit()); | 303 match.RecordAdditionalInfo("last visit", info.last_visit()); |
287 | 304 |
288 return match; | 305 return match; |
289 } | 306 } |
290 | 307 |
291 history::InMemoryURLIndex* HistoryQuickProvider::GetIndex() { | 308 history::InMemoryURLIndex* HistoryQuickProvider::GetIndex() { |
292 if (index_for_testing_.get()) | 309 if (index_for_testing_.get()) |
293 return index_for_testing_.get(); | 310 return index_for_testing_.get(); |
294 | 311 |
295 HistoryService* const history_service = HistoryServiceFactory::GetForProfile( | 312 HistoryService* const history_service = HistoryServiceFactory::GetForProfile( |
296 profile_, ServiceAccessType::EXPLICIT_ACCESS); | 313 profile_, ServiceAccessType::EXPLICIT_ACCESS); |
297 if (!history_service) | 314 if (!history_service) |
298 return NULL; | 315 return NULL; |
299 | 316 |
300 return history_service->InMemoryIndex(); | 317 return history_service->InMemoryIndex(); |
301 } | 318 } |
OLD | NEW |