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

Side by Side Diff: components/omnibox/browser/bookmark_provider.cc

Issue 2583763003: Factor out AutocompleteMatch creation from BookmarkProvider (Closed)
Patch Set: copyright years, bookmarks namespace Created 3 years, 11 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
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 "components/omnibox/browser/bookmark_provider.h" 5 #include "components/omnibox/browser/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/macros.h" 11 #include "base/macros.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 "base/trace_event/trace_event.h" 14 #include "base/trace_event/trace_event.h"
15 #include "components/bookmarks/browser/bookmark_model.h" 15 #include "components/bookmarks/browser/bookmark_model.h"
16 #include "components/bookmarks/browser/titled_url_match.h" 16 #include "components/bookmarks/browser/titled_url_match.h"
17 #include "components/metrics/proto/omnibox_input_type.pb.h" 17 #include "components/metrics/proto/omnibox_input_type.pb.h"
18 #include "components/omnibox/browser/autocomplete_provider_client.h" 18 #include "components/omnibox/browser/autocomplete_provider_client.h"
19 #include "components/omnibox/browser/autocomplete_result.h" 19 #include "components/omnibox/browser/autocomplete_result.h"
20 #include "components/omnibox/browser/history_provider.h" 20 #include "components/omnibox/browser/titled_url_match_utils.h"
21 #include "components/omnibox/browser/url_prefix.h"
22 #include "components/prefs/pref_service.h" 21 #include "components/prefs/pref_service.h"
23 #include "components/url_formatter/url_formatter.h"
24 #include "url/url_constants.h" 22 #include "url/url_constants.h"
25 23
26 using bookmarks::BookmarkNode; 24 using bookmarks::BookmarkNode;
27 using bookmarks::TitledUrlMatch; 25 using bookmarks::TitledUrlMatch;
28 using TitledUrlMatches = std::vector<TitledUrlMatch>; 26 using TitledUrlMatches = std::vector<TitledUrlMatch>;
29 27
30 namespace {
31
32 // Removes leading spaces from |title| before displaying, otherwise it looks
33 // funny. In the process, corrects |title_match_positions| so the correct
34 // characters are highlighted.
35 void CorrectTitleAndMatchPositions(
36 base::string16* title,
37 TitledUrlMatch::MatchPositions* title_match_positions) {
38 size_t leading_whitespace_chars = title->length();
39 base::TrimWhitespace(*title, base::TRIM_LEADING, title);
40 leading_whitespace_chars-= title->length();
41 if (leading_whitespace_chars == 0)
42 return;
43 for (query_parser::Snippet::MatchPositions::iterator it =
44 title_match_positions->begin();
45 it != title_match_positions->end(); ++it) {
46 (*it) = query_parser::Snippet::MatchPosition(
47 it->first - leading_whitespace_chars,
48 it->second - leading_whitespace_chars);
49 }
50 }
51
52 } // namespace
53
54 // BookmarkProvider ------------------------------------------------------------ 28 // BookmarkProvider ------------------------------------------------------------
55 29
56 BookmarkProvider::BookmarkProvider(AutocompleteProviderClient* client) 30 BookmarkProvider::BookmarkProvider(AutocompleteProviderClient* client)
57 : AutocompleteProvider(AutocompleteProvider::TYPE_BOOKMARK), 31 : AutocompleteProvider(AutocompleteProvider::TYPE_BOOKMARK),
58 client_(client), 32 client_(client),
59 bookmark_model_(client ? client_->GetBookmarkModel() : nullptr) {} 33 bookmark_model_(client ? client_->GetBookmarkModel() : nullptr) {}
60 34
61 void BookmarkProvider::Start(const AutocompleteInput& input, 35 void BookmarkProvider::Start(const AutocompleteInput& input,
62 bool minimal_changes) { 36 bool minimal_changes) {
63 TRACE_EVENT0("omnibox", "BookmarkProvider::Start"); 37 TRACE_EVENT0("omnibox", "BookmarkProvider::Start");
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 // 74 //
101 // Please refer to the code for TitledUrlIndex::GetResultsMatching for 75 // Please refer to the code for TitledUrlIndex::GetResultsMatching for
102 // complete details of how searches are performed against the user's 76 // complete details of how searches are performed against the user's
103 // bookmarks. 77 // bookmarks.
104 bookmark_model_->GetBookmarksMatching(input.text(), 78 bookmark_model_->GetBookmarksMatching(input.text(),
105 kMaxBookmarkMatches, 79 kMaxBookmarkMatches,
106 &matches); 80 &matches);
107 if (matches.empty()) 81 if (matches.empty())
108 return; // There were no matches. 82 return; // There were no matches.
109 const base::string16 fixed_up_input(FixupUserInput(input).second); 83 const base::string16 fixed_up_input(FixupUserInput(input).second);
110 for (TitledUrlMatches::const_iterator i = matches.begin(); i != matches.end(); 84 for (const auto& bookmark_match : matches) {
111 ++i) { 85 // Score the TitledUrlMatch. If its score is greater than 0 then the
112 // Create and score the AutocompleteMatch. If its score is 0 then the 86 // AutocompleteMatch is created and added to matches_.
113 // match is discarded. 87 int relevance = CalculateBookmarkMatchRelevance(bookmark_match);
114 AutocompleteMatch match(TitledUrlMatchToACMatch(input, fixed_up_input, *i)); 88 if (relevance > 0) {
115 if (match.relevance > 0) 89 matches_.push_back(TitledUrlMatchToAutocompleteMatch(
116 matches_.push_back(match); 90 bookmark_match, AutocompleteMatchType::BOOKMARK_TITLE, relevance,
91 this, client_->GetSchemeClassifier(), input, fixed_up_input));
92 }
117 } 93 }
118 94
119 // Sort and clip the resulting matches. 95 // Sort and clip the resulting matches.
120 size_t num_matches = 96 size_t num_matches =
121 std::min(matches_.size(), AutocompleteProvider::kMaxMatches); 97 std::min(matches_.size(), AutocompleteProvider::kMaxMatches);
122 std::partial_sort(matches_.begin(), matches_.begin() + num_matches, 98 std::partial_sort(matches_.begin(), matches_.begin() + num_matches,
123 matches_.end(), AutocompleteMatch::MoreRelevant); 99 matches_.end(), AutocompleteMatch::MoreRelevant);
124 matches_.resize(num_matches); 100 matches_.resize(num_matches);
125 } 101 }
126 102
(...skipping 21 matching lines...) Expand all
148 124
149 double ScoringFactor() { return scoring_factor_; } 125 double ScoringFactor() { return scoring_factor_; }
150 126
151 private: 127 private:
152 double title_length_; 128 double title_length_;
153 double scoring_factor_; 129 double scoring_factor_;
154 }; 130 };
155 131
156 } // namespace 132 } // namespace
157 133
158 AutocompleteMatch BookmarkProvider::TitledUrlMatchToACMatch( 134 int BookmarkProvider::CalculateBookmarkMatchRelevance(
159 const AutocompleteInput& input, 135 const TitledUrlMatch& bookmark_match) const {
160 const base::string16& fixed_up_input_text,
161 const TitledUrlMatch& bookmark_match) {
162 // The AutocompleteMatch we construct is non-deletable because the only
163 // way to support this would be to delete the underlying bookmark, which is
164 // unlikely to be what the user intends.
165 AutocompleteMatch match(this, 0, false,
166 AutocompleteMatchType::BOOKMARK_TITLE);
167 base::string16 title(bookmark_match.node->GetTitledUrlNodeTitle());
168 TitledUrlMatch::MatchPositions new_title_match_positions =
169 bookmark_match.title_match_positions;
170 CorrectTitleAndMatchPositions(&title, &new_title_match_positions);
171 const GURL& url(bookmark_match.node->GetTitledUrlNodeUrl());
172 const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec());
173 size_t inline_autocomplete_offset = URLPrefix::GetInlineAutocompleteOffset(
174 input.text(), fixed_up_input_text, false, url_utf16);
175 match.destination_url = url;
176 const size_t match_start = bookmark_match.url_match_positions.empty() ?
177 0 : bookmark_match.url_match_positions[0].first;
178 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()) &&
179 ((match_start == base::string16::npos) || (match_start != 0));
180 std::vector<size_t> offsets = TitledUrlMatch::OffsetsFromMatchPositions(
181 bookmark_match.url_match_positions);
182 // In addition to knowing how |offsets| is transformed, we need to know how
183 // |inline_autocomplete_offset| is transformed. We add it to the end of
184 // |offsets|, compute how everything is transformed, then remove it from the
185 // end.
186 offsets.push_back(inline_autocomplete_offset);
187 match.contents = url_formatter::FormatUrlWithOffsets(
188 url, url_formatter::kFormatUrlOmitAll &
189 ~(trim_http ? 0 : url_formatter::kFormatUrlOmitHTTP),
190 net::UnescapeRule::SPACES, nullptr, nullptr, &offsets);
191 inline_autocomplete_offset = offsets.back();
192 offsets.pop_back();
193 TitledUrlMatch::MatchPositions new_url_match_positions =
194 TitledUrlMatch::ReplaceOffsetsInMatchPositions(
195 bookmark_match.url_match_positions, offsets);
196 match.contents_class =
197 ClassificationsFromMatch(new_url_match_positions,
198 match.contents.size(),
199 true);
200 match.fill_into_edit =
201 AutocompleteInput::FormattedStringWithEquivalentMeaning(
202 url, match.contents, client_->GetSchemeClassifier());
203 if (inline_autocomplete_offset != base::string16::npos) {
204 // |inline_autocomplete_offset| may be beyond the end of the
205 // |fill_into_edit| if the user has typed an URL with a scheme and the
206 // last character typed is a slash. That slash is removed by the
207 // FormatURLWithOffsets call above.
208 if (inline_autocomplete_offset < match.fill_into_edit.length()) {
209 match.inline_autocompletion =
210 match.fill_into_edit.substr(inline_autocomplete_offset);
211 }
212 match.allowed_to_be_default_match = match.inline_autocompletion.empty() ||
213 !HistoryProvider::PreventInlineAutocomplete(input);
214 }
215 match.description = title;
216 match.description_class =
217 ClassificationsFromMatch(bookmark_match.title_match_positions,
218 match.description.size(),
219 false);
220
221 // Summary on how a relevance score is determined for the match: 136 // Summary on how a relevance score is determined for the match:
222 // 137 //
223 // For each match within the bookmark's title or URL (or both), calculate a 138 // For each match within the bookmark's title or URL (or both), calculate a
224 // 'factor', sum up those factors, then use the sum to figure out a value 139 // 'factor', sum up those factors, then use the sum to figure out a value
225 // between the base score and the maximum score. 140 // between the base score and the maximum score.
226 // 141 //
227 // The factor for each match is the product of: 142 // The factor for each match is the product of:
228 // 143 //
229 // 1) how many characters in the bookmark's title/URL are part of this match. 144 // 1) how many characters in the bookmark's title/URL are part of this match.
230 // This is capped at the length of the bookmark's title 145 // This is capped at the length of the bookmark's title
(...skipping 30 matching lines...) Expand all
261 // possible score. This product is added to the minimum possible score to 176 // possible score. This product is added to the minimum possible score to
262 // give the preliminary score. 177 // give the preliminary score.
263 // 178 //
264 // If the preliminary score is less than the maximum possible score, 1199, 179 // If the preliminary score is less than the maximum possible score, 1199,
265 // it can be boosted up to that maximum possible score if the URL referenced 180 // it can be boosted up to that maximum possible score if the URL referenced
266 // by the bookmark is also referenced by any of the user's other bookmarks. 181 // by the bookmark is also referenced by any of the user's other bookmarks.
267 // A count of how many times the bookmark's URL is referenced is determined 182 // A count of how many times the bookmark's URL is referenced is determined
268 // and, for each additional reference beyond the one for the bookmark being 183 // and, for each additional reference beyond the one for the bookmark being
269 // scored up to a maximum of three, the score is boosted by a fixed amount 184 // scored up to a maximum of three, the score is boosted by a fixed amount
270 // given by |kURLCountBoost|, below. 185 // given by |kURLCountBoost|, below.
271 // 186
187 base::string16 title(bookmark_match.node->GetTitledUrlNodeTitle());
188 const GURL& url(bookmark_match.node->GetTitledUrlNodeUrl());
272 189
273 // Pretend empty titles are identical to the URL. 190 // Pretend empty titles are identical to the URL.
274 if (title.empty()) 191 if (title.empty())
275 title = base::ASCIIToUTF16(url.spec()); 192 title = base::ASCIIToUTF16(url.spec());
276 ScoringFunctor title_position_functor = 193 ScoringFunctor title_position_functor =
277 for_each(bookmark_match.title_match_positions.begin(), 194 for_each(bookmark_match.title_match_positions.begin(),
278 bookmark_match.title_match_positions.end(), 195 bookmark_match.title_match_positions.end(),
279 ScoringFunctor(title.size())); 196 ScoringFunctor(title.size()));
280 ScoringFunctor url_position_functor = 197 ScoringFunctor url_position_functor =
281 for_each(bookmark_match.url_match_positions.begin(), 198 for_each(bookmark_match.url_match_positions.begin(),
282 bookmark_match.url_match_positions.end(), 199 bookmark_match.url_match_positions.end(),
283 ScoringFunctor( 200 ScoringFunctor(
284 bookmark_match.node->GetTitledUrlNodeUrl().spec().length())); 201 bookmark_match.node->GetTitledUrlNodeUrl().spec().length()));
285 const double title_match_strength = title_position_functor.ScoringFactor(); 202 const double title_match_strength = title_position_functor.ScoringFactor();
286 const double summed_factors = title_match_strength + 203 const double summed_factors = title_match_strength +
287 url_position_functor.ScoringFactor(); 204 url_position_functor.ScoringFactor();
288 const double normalized_sum = 205 const double normalized_sum =
289 std::min(summed_factors / (title.size() + 10), 1.0); 206 std::min(summed_factors / (title.size() + 10), 1.0);
290 // Bookmarks with javascript scheme ("bookmarklets") that do not have title 207 // Bookmarks with javascript scheme ("bookmarklets") that do not have title
291 // matches get a lower base and lower maximum score because returning them 208 // matches get a lower base and lower maximum score because returning them
292 // for matches in their (often very long) URL looks stupid and is often not 209 // for matches in their (often very long) URL looks stupid and is often not
293 // intended by the user. 210 // intended by the user.
294 const bool bookmarklet_without_title_match = 211 const bool bookmarklet_without_title_match =
295 url.SchemeIs(url::kJavaScriptScheme) && (title_match_strength == 0.0); 212 url.SchemeIs(url::kJavaScriptScheme) && (title_match_strength == 0.0);
296 const int kBaseBookmarkScore = bookmarklet_without_title_match ? 400 : 900; 213 const int kBaseBookmarkScore = bookmarklet_without_title_match ? 400 : 900;
297 const int kMaxBookmarkScore = bookmarklet_without_title_match ? 799 : 1199; 214 const int kMaxBookmarkScore = bookmarklet_without_title_match ? 799 : 1199;
298 const double kBookmarkScoreRange = 215 const double kBookmarkScoreRange =
299 static_cast<double>(kMaxBookmarkScore - kBaseBookmarkScore); 216 static_cast<double>(kMaxBookmarkScore - kBaseBookmarkScore);
300 match.relevance = static_cast<int>(normalized_sum * kBookmarkScoreRange) + 217 int relevance = static_cast<int>(normalized_sum * kBookmarkScoreRange) +
301 kBaseBookmarkScore; 218 kBaseBookmarkScore;
302 // Don't waste any time searching for additional referenced URLs if we 219 // Don't waste any time searching for additional referenced URLs if we
303 // already have a perfect title match. 220 // already have a perfect title match.
304 if (match.relevance >= kMaxBookmarkScore) 221 if (relevance >= kMaxBookmarkScore)
305 return match; 222 return relevance;
306 // Boost the score if the bookmark's URL is referenced by other bookmarks. 223 // Boost the score if the bookmark's URL is referenced by other bookmarks.
307 const int kURLCountBoost[4] = { 0, 75, 125, 150 }; 224 const int kURLCountBoost[4] = { 0, 75, 125, 150 };
308 std::vector<const BookmarkNode*> nodes; 225 std::vector<const BookmarkNode*> nodes;
309 bookmark_model_->GetNodesByURL(url, &nodes); 226 bookmark_model_->GetNodesByURL(url, &nodes);
310 DCHECK_GE(std::min(arraysize(kURLCountBoost), nodes.size()), 1U); 227 DCHECK_GE(std::min(arraysize(kURLCountBoost), nodes.size()), 1U);
311 match.relevance += 228 relevance +=
312 kURLCountBoost[std::min(arraysize(kURLCountBoost), nodes.size()) - 1]; 229 kURLCountBoost[std::min(arraysize(kURLCountBoost), nodes.size()) - 1];
313 match.relevance = std::min(kMaxBookmarkScore, match.relevance); 230 relevance = std::min(kMaxBookmarkScore, relevance);
314 return match; 231 return relevance;
315 } 232 }
316
317 // static
318 ACMatchClassifications BookmarkProvider::ClassificationsFromMatch(
319 const query_parser::Snippet::MatchPositions& positions,
320 size_t text_length,
321 bool is_url) {
322 ACMatchClassification::Style url_style =
323 is_url ? ACMatchClassification::URL : ACMatchClassification::NONE;
324 ACMatchClassifications classifications;
325 if (positions.empty()) {
326 if (text_length > 0)
327 classifications.push_back(ACMatchClassification(0, url_style));
328 return classifications;
329 }
330
331 for (query_parser::Snippet::MatchPositions::const_iterator i =
332 positions.begin();
333 i != positions.end();
334 ++i) {
335 AutocompleteMatch::ACMatchClassifications new_class;
336 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first,
337 text_length, url_style, &new_class);
338 classifications = AutocompleteMatch::MergeClassifications(
339 classifications, new_class);
340 }
341 return classifications;
342 }
OLDNEW
« no previous file with comments | « components/omnibox/browser/bookmark_provider.h ('k') | components/omnibox/browser/bookmark_provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698