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/bookmark_provider.h" | 5 #include "chrome/browser/autocomplete/bookmark_provider.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/prefs/pref_service.h" | 11 #include "base/prefs/pref_service.h" |
12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
13 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
14 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" | 14 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" |
15 #include "chrome/browser/autocomplete/history_provider.h" | 15 #include "chrome/browser/autocomplete/history_provider.h" |
16 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | 16 #include "chrome/browser/bookmarks/bookmark_model_factory.h" |
17 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
18 #include "chrome/common/pref_names.h" | 18 #include "chrome/common/pref_names.h" |
19 #include "components/bookmarks/browser/bookmark_match.h" | 19 #include "components/bookmarks/browser/bookmark_match.h" |
20 #include "components/bookmarks/browser/bookmark_model.h" | 20 #include "components/bookmarks/browser/bookmark_model.h" |
21 #include "components/metrics/proto/omnibox_input_type.pb.h" | 21 #include "components/metrics/proto/omnibox_input_type.pb.h" |
22 #include "components/omnibox/autocomplete_result.h" | 22 #include "components/omnibox/autocomplete_result.h" |
23 #include "components/omnibox/omnibox_field_trial.h" | |
24 #include "components/omnibox/url_prefix.h" | 23 #include "components/omnibox/url_prefix.h" |
25 #include "net/base/net_util.h" | 24 #include "net/base/net_util.h" |
26 | 25 |
27 using bookmarks::BookmarkMatch; | 26 using bookmarks::BookmarkMatch; |
28 | 27 |
29 typedef std::vector<BookmarkMatch> BookmarkMatches; | 28 typedef std::vector<BookmarkMatch> BookmarkMatches; |
30 | 29 |
31 namespace { | 30 namespace { |
32 | 31 |
33 // Removes leading spaces from |title| before displaying, otherwise it looks | 32 // Removes leading spaces from |title| before displaying, otherwise it looks |
(...skipping 16 matching lines...) Expand all Loading... |
50 } | 49 } |
51 } | 50 } |
52 | 51 |
53 } // namespace | 52 } // namespace |
54 | 53 |
55 // BookmarkProvider ------------------------------------------------------------ | 54 // BookmarkProvider ------------------------------------------------------------ |
56 | 55 |
57 BookmarkProvider::BookmarkProvider(Profile* profile) | 56 BookmarkProvider::BookmarkProvider(Profile* profile) |
58 : AutocompleteProvider(AutocompleteProvider::TYPE_BOOKMARK), | 57 : AutocompleteProvider(AutocompleteProvider::TYPE_BOOKMARK), |
59 profile_(profile), | 58 profile_(profile), |
60 bookmark_model_(NULL), | 59 bookmark_model_(NULL) { |
61 score_using_url_matches_(OmniboxFieldTrial::BookmarksIndexURLsValue()) { | |
62 if (profile) { | 60 if (profile) { |
63 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile); | 61 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile); |
64 languages_ = profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); | 62 languages_ = profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); |
65 } | 63 } |
66 } | 64 } |
67 | 65 |
68 void BookmarkProvider::Start(const AutocompleteInput& input, | 66 void BookmarkProvider::Start(const AutocompleteInput& input, |
69 bool minimal_changes) { | 67 bool minimal_changes) { |
70 if (minimal_changes) | 68 if (minimal_changes) |
71 return; | 69 return; |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 // giving more points for matches that appear earlier in the string: | 239 // giving more points for matches that appear earlier in the string: |
242 // ((string_length - position of match start) / string_length). | 240 // ((string_length - position of match start) / string_length). |
243 // | 241 // |
244 // Example: Given a bookmark title of 'abcde fghijklm', with a title length | 242 // Example: Given a bookmark title of 'abcde fghijklm', with a title length |
245 // of 14, and two different search terms, 'abcde' and 'fghij', with | 243 // of 14, and two different search terms, 'abcde' and 'fghij', with |
246 // start positions of 0 and 6, respectively, 'abcde' will score higher | 244 // start positions of 0 and 6, respectively, 'abcde' will score higher |
247 // (with a a partial factor of (14-0)/14 = 1.000 ) than 'fghij' (with | 245 // (with a a partial factor of (14-0)/14 = 1.000 ) than 'fghij' (with |
248 // a partial factor of (14-6)/14 = 0.571 ). (In this example neither | 246 // a partial factor of (14-6)/14 = 0.571 ). (In this example neither |
249 // term matches in the URL.) | 247 // term matches in the URL.) |
250 // | 248 // |
251 // Once all match factors have been calculated they are summed. If URL | 249 // Once all match factors have been calculated they are summed. If there |
252 // matches are not considered, the resulting sum will never be greater than | 250 // are no URL matches, the resulting sum will never be greater than the |
253 // the length of the bookmark title because of the way the bookmark model | 251 // length of the bookmark title because of the way the bookmark model matches |
254 // matches and removes overlaps. (In particular, the bookmark model only | 252 // and removes overlaps. (In particular, the bookmark model only |
255 // matches terms to the beginning of words and it removes all overlapping | 253 // matches terms to the beginning of words and it removes all overlapping |
256 // matches, keeping only the longest. Together these mean that each | 254 // matches, keeping only the longest. Together these mean that each |
257 // character is included in at most one match.) If URL matches are | 255 // character is included in at most one match.) If there are matches in the |
258 // considered, the sum can be greater. | 256 // URL, the sum can be greater. |
259 // | 257 // |
260 // This sum is then normalized by the length of the bookmark title (if URL | 258 // This sum is then normalized by the length of the bookmark title + 10 |
261 // matches are not considered) or by the length of the bookmark title + 10 | 259 // and capped at 1.0. The +10 is to expand the scoring range so fewer |
262 // (if URL matches are considered) and capped at 1.0. (If URL matches | 260 // bookmarks will hit the 1.0 cap and hence lose all ability to distinguish |
263 // are considered, we want to expand the scoring range so fewer bookmarks | 261 // between these high-quality bookmarks. |
264 // will hit the 1.0 cap and hence lose all ability to distinguish between | |
265 // these high-quality bookmarks.) | |
266 // | 262 // |
267 // The normalized value is multiplied against the scoring range available, | 263 // The normalized value is multiplied against the scoring range available, |
268 // which is 299. The 299 is calculated by subtracting the minimum possible | 264 // which is 299. The 299 is calculated by subtracting the minimum possible |
269 // score, 900, from the maximum possible score, 1199. This product, ranging | 265 // score, 900, from the maximum possible score, 1199. This product, ranging |
270 // from 0 to 299, is added to the minimum possible score, 900, giving the | 266 // from 0 to 299, is added to the minimum possible score, 900, giving the |
271 // preliminary score. | 267 // preliminary score. |
272 // | 268 // |
273 // If the preliminary score is less than the maximum possible score, 1199, | 269 // If the preliminary score is less than the maximum possible score, 1199, |
274 // it can be boosted up to that maximum possible score if the URL referenced | 270 // it can be boosted up to that maximum possible score if the URL referenced |
275 // by the bookmark is also referenced by any of the user's other bookmarks. | 271 // by the bookmark is also referenced by any of the user's other bookmarks. |
276 // A count of how many times the bookmark's URL is referenced is determined | 272 // A count of how many times the bookmark's URL is referenced is determined |
277 // and, for each additional reference beyond the one for the bookmark being | 273 // and, for each additional reference beyond the one for the bookmark being |
278 // scored up to a maximum of three, the score is boosted by a fixed amount | 274 // scored up to a maximum of three, the score is boosted by a fixed amount |
279 // given by |kURLCountBoost|, below. | 275 // given by |kURLCountBoost|, below. |
280 // | 276 // |
281 if (score_using_url_matches_) { | 277 |
282 // Pretend empty titles are identical to the URL. | 278 // Pretend empty titles are identical to the URL. |
283 if (title.empty()) | 279 if (title.empty()) |
284 title = base::ASCIIToUTF16(url.spec()); | 280 title = base::ASCIIToUTF16(url.spec()); |
285 } else { | |
286 DCHECK(!title.empty()); | |
287 } | |
288 ScoringFunctor title_position_functor = | 281 ScoringFunctor title_position_functor = |
289 for_each(bookmark_match.title_match_positions.begin(), | 282 for_each(bookmark_match.title_match_positions.begin(), |
290 bookmark_match.title_match_positions.end(), | 283 bookmark_match.title_match_positions.end(), |
291 ScoringFunctor(title.size())); | 284 ScoringFunctor(title.size())); |
292 ScoringFunctor url_position_functor = | 285 ScoringFunctor url_position_functor = |
293 for_each(bookmark_match.url_match_positions.begin(), | 286 for_each(bookmark_match.url_match_positions.begin(), |
294 bookmark_match.url_match_positions.end(), | 287 bookmark_match.url_match_positions.end(), |
295 ScoringFunctor(bookmark_match.node->url().spec().length())); | 288 ScoringFunctor(bookmark_match.node->url().spec().length())); |
296 const double summed_factors = title_position_functor.ScoringFactor() + | 289 const double summed_factors = title_position_functor.ScoringFactor() + |
297 (score_using_url_matches_ ? url_position_functor.ScoringFactor() : 0); | 290 url_position_functor.ScoringFactor(); |
298 const double normalized_sum = std::min( | 291 const double normalized_sum = |
299 summed_factors / (title.size() + (score_using_url_matches_ ? 10 : 0)), | 292 std::min(summed_factors / (title.size() + 10), 1.0); |
300 1.0); | |
301 const int kBaseBookmarkScore = 900; | 293 const int kBaseBookmarkScore = 900; |
302 const int kMaxBookmarkScore = 1199; | 294 const int kMaxBookmarkScore = 1199; |
303 const double kBookmarkScoreRange = | 295 const double kBookmarkScoreRange = |
304 static_cast<double>(kMaxBookmarkScore - kBaseBookmarkScore); | 296 static_cast<double>(kMaxBookmarkScore - kBaseBookmarkScore); |
305 match.relevance = static_cast<int>(normalized_sum * kBookmarkScoreRange) + | 297 match.relevance = static_cast<int>(normalized_sum * kBookmarkScoreRange) + |
306 kBaseBookmarkScore; | 298 kBaseBookmarkScore; |
307 // Don't waste any time searching for additional referenced URLs if we | 299 // Don't waste any time searching for additional referenced URLs if we |
308 // already have a perfect title match. | 300 // already have a perfect title match. |
309 if (match.relevance >= kMaxBookmarkScore) | 301 if (match.relevance >= kMaxBookmarkScore) |
310 return match; | 302 return match; |
(...skipping 10 matching lines...) Expand all Loading... |
321 | 313 |
322 // static | 314 // static |
323 ACMatchClassifications BookmarkProvider::ClassificationsFromMatch( | 315 ACMatchClassifications BookmarkProvider::ClassificationsFromMatch( |
324 const query_parser::Snippet::MatchPositions& positions, | 316 const query_parser::Snippet::MatchPositions& positions, |
325 size_t text_length, | 317 size_t text_length, |
326 bool is_url) { | 318 bool is_url) { |
327 ACMatchClassification::Style url_style = | 319 ACMatchClassification::Style url_style = |
328 is_url ? ACMatchClassification::URL : ACMatchClassification::NONE; | 320 is_url ? ACMatchClassification::URL : ACMatchClassification::NONE; |
329 ACMatchClassifications classifications; | 321 ACMatchClassifications classifications; |
330 if (positions.empty()) { | 322 if (positions.empty()) { |
331 classifications.push_back( | 323 if (text_length > 0) |
332 ACMatchClassification(0, url_style)); | 324 classifications.push_back(ACMatchClassification(0, url_style)); |
333 return classifications; | 325 return classifications; |
334 } | 326 } |
335 | 327 |
336 for (query_parser::Snippet::MatchPositions::const_iterator i = | 328 for (query_parser::Snippet::MatchPositions::const_iterator i = |
337 positions.begin(); | 329 positions.begin(); |
338 i != positions.end(); | 330 i != positions.end(); |
339 ++i) { | 331 ++i) { |
340 AutocompleteMatch::ACMatchClassifications new_class; | 332 AutocompleteMatch::ACMatchClassifications new_class; |
341 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first, | 333 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first, |
342 text_length, url_style, &new_class); | 334 text_length, url_style, &new_class); |
343 classifications = AutocompleteMatch::MergeClassifications( | 335 classifications = AutocompleteMatch::MergeClassifications( |
344 classifications, new_class); | 336 classifications, new_class); |
345 } | 337 } |
346 return classifications; | 338 return classifications; |
347 } | 339 } |
OLD | NEW |