Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: chrome/browser/autocomplete/bookmark_provider.cc

Issue 184663002: Omnibox: Make URLs of Bookmarks Searchable (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: pkasting and tfarina's comments Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/utf_string_conversions.h" 12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/autocomplete/autocomplete_result.h" 13 #include "chrome/browser/autocomplete/autocomplete_result.h"
14 #include "chrome/browser/autocomplete/history_provider.h" 14 #include "chrome/browser/autocomplete/history_provider.h"
15 #include "chrome/browser/autocomplete/url_prefix.h" 15 #include "chrome/browser/autocomplete/url_prefix.h"
16 #include "chrome/browser/bookmarks/bookmark_model.h" 16 #include "chrome/browser/bookmarks/bookmark_model.h"
17 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 17 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
18 #include "chrome/browser/omnibox/omnibox_field_trial.h"
18 #include "chrome/browser/profiles/profile.h" 19 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/common/pref_names.h" 20 #include "chrome/common/pref_names.h"
20 #include "components/bookmarks/core/browser/bookmark_title_match.h" 21 #include "components/bookmarks/core/browser/bookmark_match.h"
21 #include "net/base/net_util.h" 22 #include "net/base/net_util.h"
22 23
23 typedef std::vector<BookmarkTitleMatch> TitleMatches; 24 typedef std::vector<BookmarkMatch> BookmarkMatches;
24 25
25 // BookmarkProvider ------------------------------------------------------------ 26 // BookmarkProvider ------------------------------------------------------------
26 27
27 BookmarkProvider::BookmarkProvider( 28 BookmarkProvider::BookmarkProvider(
28 AutocompleteProviderListener* listener, 29 AutocompleteProviderListener* listener,
29 Profile* profile) 30 Profile* profile)
30 : AutocompleteProvider(listener, profile, 31 : AutocompleteProvider(listener, profile,
31 AutocompleteProvider::TYPE_BOOKMARK), 32 AutocompleteProvider::TYPE_BOOKMARK),
32 bookmark_model_(NULL) { 33 bookmark_model_(NULL),
34 score_using_url_matches_(OmniboxFieldTrial::BookmarksIndexURLsValue()) {
33 if (profile) { 35 if (profile) {
34 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile); 36 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile);
35 languages_ = profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); 37 languages_ = profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
36 } 38 }
37 } 39 }
38 40
39 void BookmarkProvider::Start(const AutocompleteInput& input, 41 void BookmarkProvider::Start(const AutocompleteInput& input,
40 bool minimal_changes) { 42 bool minimal_changes) {
41 if (minimal_changes) 43 if (minimal_changes)
42 return; 44 return;
43 matches_.clear(); 45 matches_.clear();
44 46
45 if (input.text().empty() || 47 if (input.text().empty() ||
46 ((input.type() != AutocompleteInput::UNKNOWN) && 48 (input.type() == AutocompleteInput::FORCED_QUERY))
47 (input.type() != AutocompleteInput::QUERY)))
48 return; 49 return;
49 50
50 DoAutocomplete(input, 51 DoAutocomplete(input,
51 input.matches_requested() == AutocompleteInput::BEST_MATCH); 52 input.matches_requested() == AutocompleteInput::BEST_MATCH);
52 } 53 }
53 54
54 BookmarkProvider::~BookmarkProvider() {} 55 BookmarkProvider::~BookmarkProvider() {}
55 56
56 void BookmarkProvider::DoAutocomplete(const AutocompleteInput& input, 57 void BookmarkProvider::DoAutocomplete(const AutocompleteInput& input,
57 bool best_match) { 58 bool best_match) {
58 // We may not have a bookmark model for some unit tests. 59 // We may not have a bookmark model for some unit tests.
59 if (!bookmark_model_) 60 if (!bookmark_model_)
60 return; 61 return;
61 62
62 TitleMatches matches; 63 BookmarkMatches matches;
63 // Retrieve enough bookmarks so that we have a reasonable probability of 64 // Retrieve enough bookmarks so that we have a reasonable probability of
64 // suggesting the one that the user desires. 65 // suggesting the one that the user desires.
65 const size_t kMaxBookmarkMatches = 50; 66 const size_t kMaxBookmarkMatches = 50;
66 67
67 // GetBookmarksWithTitlesMatching returns bookmarks matching the user's 68 // GetBookmarksMatching returns bookmarks matching the user's
68 // search terms using the following rules: 69 // search terms using the following rules:
69 // - The search text is broken up into search terms. Each term is searched 70 // - The search text is broken up into search terms. Each term is searched
70 // for separately. 71 // for separately.
71 // - Term matches are always performed against the start of a word. 'def' 72 // - Term matches are always performed against the start of a word. 'def'
72 // will match against 'define' but not against 'indefinite'. 73 // will match against 'define' but not against 'indefinite'.
73 // - Terms must be at least three characters in length in order to perform 74 // - Terms must be at least three characters in length in order to perform
74 // partial word matches. Any term of lesser length will only be used as an 75 // partial word matches. Any term of lesser length will only be used as an
75 // exact match. 'def' will match against 'define' but 'de' will not match. 76 // exact match. 'def' will match against 'define' but 'de' will not match.
76 // - A search containing multiple terms will return results with those words 77 // - A search containing multiple terms will return results with those words
77 // occuring in any order. 78 // occuring in any order.
78 // - Terms enclosed in quotes comprises a phrase that must match exactly. 79 // - Terms enclosed in quotes comprises a phrase that must match exactly.
79 // - Multiple terms enclosed in quotes will require those exact words in that 80 // - Multiple terms enclosed in quotes will require those exact words in that
80 // exact order to match. 81 // exact order to match.
81 // 82 //
82 // Note: GetBookmarksWithTitlesMatching() will never return a match span 83 // Please refer to the code for BookmarkIndex::GetBookmarksMatching for
83 // greater than the length of the title against which it is being matched, 84 // complete details of how searches are performed against the user's
84 // nor can those spans ever overlap because the match spans are coalesced
85 // for all matched terms.
86 //
87 // Please refer to the code for BookmarkIndex::GetBookmarksWithTitlesMatching
88 // for complete details of how title searches are performed against the user's
89 // bookmarks. 85 // bookmarks.
90 bookmark_model_->GetBookmarksWithTitlesMatching(input.text(), 86 bookmark_model_->GetBookmarksMatching(input.text(),
91 kMaxBookmarkMatches, 87 kMaxBookmarkMatches,
92 &matches); 88 &matches);
93 if (matches.empty()) 89 if (matches.empty())
94 return; // There were no matches. 90 return; // There were no matches.
95 AutocompleteInput fixed_up_input(input); 91 AutocompleteInput fixed_up_input(input);
96 FixupUserInput(&fixed_up_input); 92 FixupUserInput(&fixed_up_input);
97 for (TitleMatches::const_iterator i = matches.begin(); i != matches.end(); 93 for (BookmarkMatches::const_iterator i = matches.begin(); i != matches.end();
98 ++i) { 94 ++i) {
99 // Create and score the AutocompleteMatch. If its score is 0 then the 95 // Create and score the AutocompleteMatch. If its score is 0 then the
100 // match is discarded. 96 // match is discarded.
101 AutocompleteMatch match(TitleMatchToACMatch(input, fixed_up_input, *i)); 97 AutocompleteMatch match(BookmarkMatchToACMatch(input, fixed_up_input, *i));
102 if (match.relevance > 0) 98 if (match.relevance > 0)
103 matches_.push_back(match); 99 matches_.push_back(match);
104 } 100 }
105 101
106 // Sort and clip the resulting matches. 102 // Sort and clip the resulting matches.
107 size_t max_matches = best_match ? 1 : AutocompleteProvider::kMaxMatches; 103 size_t max_matches = best_match ? 1 : AutocompleteProvider::kMaxMatches;
108 if (matches_.size() > max_matches) { 104 if (matches_.size() > max_matches) {
109 std::partial_sort(matches_.begin(), 105 std::partial_sort(matches_.begin(),
110 matches_.begin() + max_matches, 106 matches_.begin() + max_matches,
111 matches_.end(), 107 matches_.end(),
112 AutocompleteMatch::MoreRelevant); 108 AutocompleteMatch::MoreRelevant);
113 matches_.resize(max_matches); 109 matches_.resize(max_matches);
114 } else { 110 } else {
115 std::sort(matches_.begin(), matches_.end(), 111 std::sort(matches_.begin(), matches_.end(),
116 AutocompleteMatch::MoreRelevant); 112 AutocompleteMatch::MoreRelevant);
117 } 113 }
118 } 114 }
119 115
120 namespace { 116 namespace {
121 117
122 // for_each helper functor that calculates a match factor for each query term 118 // for_each helper functor that calculates a match factor for each query term
123 // when calculating the final score. 119 // when calculating the final score.
124 // 120 //
125 // Calculate a 'factor' from 0.0 to 1.0 based on 1) how much of the bookmark's 121 // Calculate a 'factor' from 0 to the bookmark's title length for a match
126 // title the term matches, and 2) where the match is positioned within the 122 // based on 1) how many characters match and 2) where the match is positioned.
127 // bookmark's title. A full length match earns a 1.0. A half-length match earns
128 // at most a 0.5 and at least a 0.25. A single character match against a title
129 // that is 100 characters long where the match is at the first character will
130 // earn a 0.01 and at the last character will earn a 0.0001.
131 class ScoringFunctor { 123 class ScoringFunctor {
132 public: 124 public:
133 // |title_length| is the length of the bookmark title against which this 125 // |title_length| is the length of the bookmark title against which this
134 // match will be scored. 126 // match will be scored.
135 explicit ScoringFunctor(size_t title_length) 127 explicit ScoringFunctor(size_t title_length)
136 : title_length_(static_cast<double>(title_length)), 128 : title_length_(static_cast<double>(title_length)),
137 scoring_factor_(0.0) { 129 scoring_factor_(0.0) {
138 } 130 }
139 131
140 void operator()(const query_parser::Snippet::MatchPosition& match) { 132 void operator()(const query_parser::Snippet::MatchPosition& match) {
141 double term_length = static_cast<double>(match.second - match.first); 133 double term_length = static_cast<double>(match.second - match.first);
142 scoring_factor_ += term_length / title_length_ * 134 scoring_factor_ += term_length *
143 (title_length_ - match.first) / title_length_; 135 (title_length_ - match.first) / title_length_;
144 } 136 }
145 137
146 double ScoringFactor() { return scoring_factor_; } 138 double ScoringFactor() { return scoring_factor_; }
147 139
148 private: 140 private:
149 double title_length_; 141 double title_length_;
150 double scoring_factor_; 142 double scoring_factor_;
151 }; 143 };
152 144
153 } // namespace 145 } // namespace
154 146
155 AutocompleteMatch BookmarkProvider::TitleMatchToACMatch( 147 AutocompleteMatch BookmarkProvider::BookmarkMatchToACMatch(
156 const AutocompleteInput& input, 148 const AutocompleteInput& input,
157 const AutocompleteInput& fixed_up_input, 149 const AutocompleteInput& fixed_up_input,
158 const BookmarkTitleMatch& title_match) { 150 const BookmarkMatch& bookmark_match) {
159 // The AutocompleteMatch we construct is non-deletable because the only 151 // The AutocompleteMatch we construct is non-deletable because the only
160 // way to support this would be to delete the underlying bookmark, which is 152 // way to support this would be to delete the underlying bookmark, which is
161 // unlikely to be what the user intends. 153 // unlikely to be what the user intends.
162 AutocompleteMatch match(this, 0, false, 154 AutocompleteMatch match(this, 0, false,
163 AutocompleteMatchType::BOOKMARK_TITLE); 155 AutocompleteMatchType::BOOKMARK_TITLE);
164 const base::string16& title(title_match.node->GetTitle()); 156 base::string16 title(bookmark_match.node->GetTitle());
165 DCHECK(!title.empty()); 157 const GURL& url(bookmark_match.node->url());
166
167 const GURL& url(title_match.node->url());
168 const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec()); 158 const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec());
169 size_t match_start, inline_autocomplete_offset; 159 size_t inline_autocomplete_offset = URLPrefix::GetInlineAutocompleteOffset(
170 URLPrefix::ComputeMatchStartAndInlineAutocompleteOffset( 160 input, fixed_up_input, false, url_utf16);
171 input, fixed_up_input, false, url_utf16, &match_start,
172 &inline_autocomplete_offset);
173 match.destination_url = url; 161 match.destination_url = url;
162 const size_t match_start = bookmark_match.url_match_positions.empty() ?
163 0 : bookmark_match.url_match_positions[0].first;
174 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()) && 164 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()) &&
175 ((match_start == base::string16::npos) || (match_start != 0)); 165 ((match_start == base::string16::npos) || (match_start != 0));
176 match.contents = net::FormatUrl(url, languages_, 166 std::vector<size_t> offsets = BookmarkMatch::OffsetsFromMatchPositions(
167 bookmark_match.url_match_positions);
168 // In addition to knowing how |offsets| is transformed, we need to know how
169 // |inline_autocomplete_offset| is transformed. We add it to the end of
170 // |offsets|, compute how everything is transformed, then remove it from the
171 // end.
172 offsets.push_back(inline_autocomplete_offset);
173 match.contents = net::FormatUrlWithOffsets(url, languages_,
177 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP), 174 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP),
178 net::UnescapeRule::SPACES, NULL, NULL, &inline_autocomplete_offset); 175 net::UnescapeRule::SPACES, NULL, NULL, &offsets);
179 match.contents_class.push_back( 176 inline_autocomplete_offset = offsets.back();
180 ACMatchClassification(0, ACMatchClassification::URL)); 177 offsets.pop_back();
178 BookmarkMatch::MatchPositions new_url_match_positions =
179 BookmarkMatch::ReplaceOffsetsInMatchPositions(
180 bookmark_match.url_match_positions, offsets);
181 match.contents_class =
182 ClassificationsFromMatch(new_url_match_positions,
183 match.contents.size(),
184 true);
181 match.fill_into_edit = 185 match.fill_into_edit =
182 AutocompleteInput::FormattedStringWithEquivalentMeaning(url, 186 AutocompleteInput::FormattedStringWithEquivalentMeaning(url,
183 match.contents); 187 match.contents);
184 if (inline_autocomplete_offset != base::string16::npos) { 188 if (inline_autocomplete_offset != base::string16::npos) {
185 // |inline_autocomplete_offset| may be beyond the end of the 189 // |inline_autocomplete_offset| may be beyond the end of the
186 // |fill_into_edit| if the user has typed an URL with a scheme and the 190 // |fill_into_edit| if the user has typed an URL with a scheme and the
187 // last character typed is a slash. That slash is removed by the 191 // last character typed is a slash. That slash is removed by the
188 // FormatURLWithOffsets call above. 192 // FormatURLWithOffsets call above.
189 if (inline_autocomplete_offset < match.fill_into_edit.length()) { 193 if (inline_autocomplete_offset < match.fill_into_edit.length()) {
190 match.inline_autocompletion = 194 match.inline_autocompletion =
191 match.fill_into_edit.substr(inline_autocomplete_offset); 195 match.fill_into_edit.substr(inline_autocomplete_offset);
192 } 196 }
193 match.allowed_to_be_default_match = match.inline_autocompletion.empty() || 197 match.allowed_to_be_default_match = match.inline_autocompletion.empty() ||
194 !HistoryProvider::PreventInlineAutocomplete(input); 198 !HistoryProvider::PreventInlineAutocomplete(input);
195 } 199 }
196 match.description = title; 200 match.description = title;
197 match.description_class = 201 match.description_class =
198 ClassificationsFromMatch(title_match.match_positions, 202 ClassificationsFromMatch(bookmark_match.title_match_positions,
199 match.description.size()); 203 match.description.size(),
204 false);
200 match.starred = true; 205 match.starred = true;
201 206
202 // Summary on how a relevance score is determined for the match: 207 // Summary on how a relevance score is determined for the match:
203 // 208 //
204 // For each term matching within the bookmark's title (as given by the set of 209 // For each match within the bookmark's title or URL (or both), calculate a
205 // Snippet::MatchPositions) calculate a 'factor', sum up those factors, then 210 // 'factor', sum up those factors, then use the sum to figure out a value
206 // use the sum to figure out a value between the base score and the maximum 211 // between the base score and the maximum score.
207 // score.
208 // 212 //
209 // The factor for each term is the product of: 213 // The factor for each match is the product of:
210 // 214 //
211 // 1) how much of the bookmark's title has been matched by the term: 215 // 1) how many characters in the bookmark's title/URL are part of this match.
212 // (term length / title length). 216 // This is capped at the length of the bookmark's title
217 // to prevent terms that match in both the title and the URL from
218 // scoring too strongly.
213 // 219 //
214 // Example: Given a bookmark title 'abcde fghijklm', with a title length 220 // 2) where the match occurs within the bookmark's title or URL,
215 // of 14, and two different search terms, 'abcde' and 'fghijklm', with 221 // giving more points for matches that appear earlier in the string:
216 // term lengths of 5 and 8, respectively, 'fghijklm' will score higher 222 // ((string_length - position of match start) / string_length).
217 // (with a partial factor of 8/14 = 0.571) than 'abcde' (5/14 = 0.357).
218 //
219 // 2) where the term match occurs within the bookmark's title, giving more
220 // points for matches that appear earlier in the title:
221 // ((title length - position of match start) / title_length).
222 // 223 //
223 // Example: Given a bookmark title of 'abcde fghijklm', with a title length 224 // Example: Given a bookmark title of 'abcde fghijklm', with a title length
224 // of 14, and two different search terms, 'abcde' and 'fghij', with 225 // of 14, and two different search terms, 'abcde' and 'fghij', with
225 // start positions of 0 and 6, respectively, 'abcde' will score higher 226 // start positions of 0 and 6, respectively, 'abcde' will score higher
226 // (with a a partial factor of (14-0)/14 = 1.000 ) than 'fghij' (with 227 // (with a a partial factor of (14-0)/14 = 1.000 ) than 'fghij' (with
227 // a partial factor of (14-6)/14 = 0.571 ). 228 // a partial factor of (14-6)/14 = 0.571 ). (In this example neither
229 // term matches in the URL.)
228 // 230 //
229 // Once all term factors have been calculated they are summed. The resulting 231 // Once all match factors have been calculated they are summed. If URL
230 // sum will never be greater than 1.0 because of the way the bookmark model 232 // matches are not considered, the resulting sum will never be greater than
231 // matches and removes overlaps. (In particular, the bookmark model only 233 // the length of the bookmark title because of the way the bookmark model
234 // matches and removes overlaps. (In particular, the bookmark model only
232 // matches terms to the beginning of words and it removes all overlapping 235 // matches terms to the beginning of words and it removes all overlapping
233 // matches, keeping only the longest. Together these mean that each 236 // matches, keeping only the longest. Together these mean that each
234 // character is included in at most one match. This property ensures the 237 // character is included in at most one match.) If URL matches are
235 // sum of factors is at most 1.) This sum is then multiplied against the 238 // considered, the sum can be greater.
236 // scoring range available, which is 299. The 299 is calculated by 239 //
237 // subtracting the minimum possible score, 900, from the maximum possible 240 // This sum is then normalized by the length of the bookmark title (if URL
238 // score, 1199. This product, ranging from 0 to 299, is added to the minimum 241 // matches are not considered) or by the length of the bookmark title + 10
239 // possible score, 900, giving the preliminary score. 242 // (if URL matches are considered) and capped at 1.0. (If URL matches
243 // are considered, we want to expand the scoring range so fewer bookmarks
244 // will hit the 1.0 cap and hence lose all ability to distinguish between
245 // these high-quality bookmarks.)
246 //
247 // The normalized value is multiplied against the scoring range available,
248 // which is 299. The 299 is calculated by subtracting the minimum possible
249 // score, 900, from the maximum possible score, 1199. This product, ranging
250 // from 0 to 299, is added to the minimum possible score, 900, giving the
251 // preliminary score.
240 // 252 //
241 // If the preliminary score is less than the maximum possible score, 1199, 253 // If the preliminary score is less than the maximum possible score, 1199,
242 // it can be boosted up to that maximum possible score if the URL referenced 254 // it can be boosted up to that maximum possible score if the URL referenced
243 // by the bookmark is also referenced by any of the user's other bookmarks. 255 // by the bookmark is also referenced by any of the user's other bookmarks.
244 // A count of how many times the bookmark's URL is referenced is determined 256 // A count of how many times the bookmark's URL is referenced is determined
245 // and, for each additional reference beyond the one for the bookmark being 257 // and, for each additional reference beyond the one for the bookmark being
246 // scored up to a maximum of three, the score is boosted by a fixed amount 258 // scored up to a maximum of three, the score is boosted by a fixed amount
247 // given by |kURLCountBoost|, below. 259 // given by |kURLCountBoost|, below.
248 // 260 //
249 ScoringFunctor position_functor = 261 if (score_using_url_matches_) {
250 for_each(title_match.match_positions.begin(), 262 // Pretend empty titles are identical to the URL.
251 title_match.match_positions.end(), ScoringFunctor(title.size())); 263 if (title.empty())
264 title = base::ASCIIToUTF16(url.spec());
265 } else {
266 DCHECK(!title.empty());
267 }
268 ScoringFunctor title_position_functor =
269 for_each(bookmark_match.title_match_positions.begin(),
270 bookmark_match.title_match_positions.end(),
271 ScoringFunctor(title.size()));
272 ScoringFunctor url_position_functor =
273 for_each(bookmark_match.url_match_positions.begin(),
274 bookmark_match.url_match_positions.end(),
275 ScoringFunctor(bookmark_match.node->url().spec().length()));
276 const double summed_factors = title_position_functor.ScoringFactor() +
277 (score_using_url_matches_ ? url_position_functor.ScoringFactor() : 0);
278 const double normalized_sum = std::min(
279 summed_factors / (title.size() + (score_using_url_matches_ ? 10 : 0)),
280 1.0);
252 const int kBaseBookmarkScore = 900; 281 const int kBaseBookmarkScore = 900;
253 const int kMaxBookmarkScore = AutocompleteResult::kLowestDefaultScore - 1; 282 const int kMaxBookmarkScore = AutocompleteResult::kLowestDefaultScore - 1;
254 const double kBookmarkScoreRange = 283 const double kBookmarkScoreRange =
255 static_cast<double>(kMaxBookmarkScore - kBaseBookmarkScore); 284 static_cast<double>(kMaxBookmarkScore - kBaseBookmarkScore);
256 // It's not likely that GetBookmarksWithTitlesMatching will return overlapping 285 match.relevance = static_cast<int>(normalized_sum * kBookmarkScoreRange) +
257 // matches but let's play it safe. 286 kBaseBookmarkScore;
258 match.relevance = std::min(kMaxBookmarkScore,
259 static_cast<int>(position_functor.ScoringFactor() * kBookmarkScoreRange) +
260 kBaseBookmarkScore);
261 // Don't waste any time searching for additional referenced URLs if we 287 // Don't waste any time searching for additional referenced URLs if we
262 // already have a perfect title match. 288 // already have a perfect title match.
263 if (match.relevance >= kMaxBookmarkScore) 289 if (match.relevance >= kMaxBookmarkScore)
264 return match; 290 return match;
265 // Boost the score if the bookmark's URL is referenced by other bookmarks. 291 // Boost the score if the bookmark's URL is referenced by other bookmarks.
266 const int kURLCountBoost[4] = { 0, 75, 125, 150 }; 292 const int kURLCountBoost[4] = { 0, 75, 125, 150 };
267 std::vector<const BookmarkNode*> nodes; 293 std::vector<const BookmarkNode*> nodes;
268 bookmark_model_->GetNodesByURL(url, &nodes); 294 bookmark_model_->GetNodesByURL(url, &nodes);
269 DCHECK_GE(std::min(arraysize(kURLCountBoost), nodes.size()), 1U); 295 DCHECK_GE(std::min(arraysize(kURLCountBoost), nodes.size()), 1U);
270 match.relevance += 296 match.relevance +=
271 kURLCountBoost[std::min(arraysize(kURLCountBoost), nodes.size()) - 1]; 297 kURLCountBoost[std::min(arraysize(kURLCountBoost), nodes.size()) - 1];
272 match.relevance = std::min(kMaxBookmarkScore, match.relevance); 298 match.relevance = std::min(kMaxBookmarkScore, match.relevance);
273 return match; 299 return match;
274 } 300 }
275 301
276 // static 302 // static
277 ACMatchClassifications BookmarkProvider::ClassificationsFromMatch( 303 ACMatchClassifications BookmarkProvider::ClassificationsFromMatch(
278 const query_parser::Snippet::MatchPositions& positions, 304 const query_parser::Snippet::MatchPositions& positions,
279 size_t text_length) { 305 size_t text_length,
306 bool is_url) {
307 ACMatchClassification::Style url_style =
308 is_url ? ACMatchClassification::URL : ACMatchClassification::NONE;
280 ACMatchClassifications classifications; 309 ACMatchClassifications classifications;
281 if (positions.empty()) { 310 if (positions.empty()) {
282 classifications.push_back( 311 classifications.push_back(
283 ACMatchClassification(0, ACMatchClassification::NONE)); 312 ACMatchClassification(0, url_style));
284 return classifications; 313 return classifications;
285 } 314 }
286 315
287 for (query_parser::Snippet::MatchPositions::const_iterator i = 316 for (query_parser::Snippet::MatchPositions::const_iterator i =
288 positions.begin(); 317 positions.begin();
289 i != positions.end(); 318 i != positions.end();
290 ++i) { 319 ++i) {
291 AutocompleteMatch::ACMatchClassifications new_class; 320 AutocompleteMatch::ACMatchClassifications new_class;
292 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first, 321 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first,
293 text_length, 0, &new_class); 322 text_length, url_style, &new_class);
294 classifications = AutocompleteMatch::MergeClassifications( 323 classifications = AutocompleteMatch::MergeClassifications(
295 classifications, new_class); 324 classifications, new_class);
296 } 325 }
297 return classifications; 326 return classifications;
298 } 327 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698