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/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_match.h" | |
16 #include "components/bookmarks/browser/bookmark_model.h" | 15 #include "components/bookmarks/browser/bookmark_model.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/history_provider.h" |
21 #include "components/omnibox/browser/url_prefix.h" | 21 #include "components/omnibox/browser/url_prefix.h" |
22 #include "components/prefs/pref_service.h" | 22 #include "components/prefs/pref_service.h" |
23 #include "components/url_formatter/url_formatter.h" | 23 #include "components/url_formatter/url_formatter.h" |
24 #include "url/url_constants.h" | 24 #include "url/url_constants.h" |
25 | 25 |
26 using bookmarks::BookmarkMatch; | |
27 using BookmarkMatches = std::vector<BookmarkMatch>; | |
28 using bookmarks::BookmarkNode; | 26 using bookmarks::BookmarkNode; |
| 27 using bookmarks::TitledUrlMatch; |
| 28 using TitledUrlMatches = std::vector<TitledUrlMatch>; |
29 | 29 |
30 namespace { | 30 namespace { |
31 | 31 |
32 // Removes leading spaces from |title| before displaying, otherwise it looks | 32 // Removes leading spaces from |title| before displaying, otherwise it looks |
33 // funny. In the process, corrects |title_match_positions| so the correct | 33 // funny. In the process, corrects |title_match_positions| so the correct |
34 // characters are highlighted. | 34 // characters are highlighted. |
35 void CorrectTitleAndMatchPositions( | 35 void CorrectTitleAndMatchPositions( |
36 base::string16* title, | 36 base::string16* title, |
37 BookmarkMatch::MatchPositions* title_match_positions) { | 37 TitledUrlMatch::MatchPositions* title_match_positions) { |
38 size_t leading_whitespace_chars = title->length(); | 38 size_t leading_whitespace_chars = title->length(); |
39 base::TrimWhitespace(*title, base::TRIM_LEADING, title); | 39 base::TrimWhitespace(*title, base::TRIM_LEADING, title); |
40 leading_whitespace_chars-= title->length(); | 40 leading_whitespace_chars-= title->length(); |
41 if (leading_whitespace_chars == 0) | 41 if (leading_whitespace_chars == 0) |
42 return; | 42 return; |
43 for (query_parser::Snippet::MatchPositions::iterator it = | 43 for (query_parser::Snippet::MatchPositions::iterator it = |
44 title_match_positions->begin(); | 44 title_match_positions->begin(); |
45 it != title_match_positions->end(); ++it) { | 45 it != title_match_positions->end(); ++it) { |
46 (*it) = query_parser::Snippet::MatchPosition( | 46 (*it) = query_parser::Snippet::MatchPosition( |
47 it->first - leading_whitespace_chars, | 47 it->first - leading_whitespace_chars, |
(...skipping 23 matching lines...) Expand all Loading... |
71 DoAutocomplete(input); | 71 DoAutocomplete(input); |
72 } | 72 } |
73 | 73 |
74 BookmarkProvider::~BookmarkProvider() {} | 74 BookmarkProvider::~BookmarkProvider() {} |
75 | 75 |
76 void BookmarkProvider::DoAutocomplete(const AutocompleteInput& input) { | 76 void BookmarkProvider::DoAutocomplete(const AutocompleteInput& input) { |
77 // We may not have a bookmark model for some unit tests. | 77 // We may not have a bookmark model for some unit tests. |
78 if (!bookmark_model_) | 78 if (!bookmark_model_) |
79 return; | 79 return; |
80 | 80 |
81 BookmarkMatches matches; | 81 TitledUrlMatches matches; |
82 // Retrieve enough bookmarks so that we have a reasonable probability of | 82 // Retrieve enough bookmarks so that we have a reasonable probability of |
83 // suggesting the one that the user desires. | 83 // suggesting the one that the user desires. |
84 const size_t kMaxBookmarkMatches = 50; | 84 const size_t kMaxBookmarkMatches = 50; |
85 | 85 |
86 // GetBookmarksMatching returns bookmarks matching the user's | 86 // GetBookmarksMatching returns bookmarks matching the user's |
87 // search terms using the following rules: | 87 // search terms using the following rules: |
88 // - The search text is broken up into search terms. Each term is searched | 88 // - The search text is broken up into search terms. Each term is searched |
89 // for separately. | 89 // for separately. |
90 // - Term matches are always performed against the start of a word. 'def' | 90 // - Term matches are always performed against the start of a word. 'def' |
91 // will match against 'define' but not against 'indefinite'. | 91 // will match against 'define' but not against 'indefinite'. |
92 // - Terms must be at least three characters in length in order to perform | 92 // - Terms must be at least three characters in length in order to perform |
93 // partial word matches. Any term of lesser length will only be used as an | 93 // partial word matches. Any term of lesser length will only be used as an |
94 // exact match. 'def' will match against 'define' but 'de' will not match. | 94 // exact match. 'def' will match against 'define' but 'de' will not match. |
95 // - A search containing multiple terms will return results with those words | 95 // - A search containing multiple terms will return results with those words |
96 // occuring in any order. | 96 // occuring in any order. |
97 // - Terms enclosed in quotes comprises a phrase that must match exactly. | 97 // - Terms enclosed in quotes comprises a phrase that must match exactly. |
98 // - Multiple terms enclosed in quotes will require those exact words in that | 98 // - Multiple terms enclosed in quotes will require those exact words in that |
99 // exact order to match. | 99 // exact order to match. |
100 // | 100 // |
101 // Please refer to the code for BookmarkIndex::GetBookmarksMatching for | 101 // Please refer to the code for TitledUrlIndex::GetResultsMatching for |
102 // complete details of how searches are performed against the user's | 102 // complete details of how searches are performed against the user's |
103 // bookmarks. | 103 // bookmarks. |
104 bookmark_model_->GetBookmarksMatching(input.text(), | 104 bookmark_model_->GetBookmarksMatching(input.text(), |
105 kMaxBookmarkMatches, | 105 kMaxBookmarkMatches, |
106 &matches); | 106 &matches); |
107 if (matches.empty()) | 107 if (matches.empty()) |
108 return; // There were no matches. | 108 return; // There were no matches. |
109 const base::string16 fixed_up_input(FixupUserInput(input).second); | 109 const base::string16 fixed_up_input(FixupUserInput(input).second); |
110 for (BookmarkMatches::const_iterator i = matches.begin(); i != matches.end(); | 110 for (TitledUrlMatches::const_iterator i = matches.begin(); i != matches.end(); |
111 ++i) { | 111 ++i) { |
112 // Create and score the AutocompleteMatch. If its score is 0 then the | 112 // Create and score the AutocompleteMatch. If its score is 0 then the |
113 // match is discarded. | 113 // match is discarded. |
114 AutocompleteMatch match(BookmarkMatchToACMatch(input, fixed_up_input, *i)); | 114 AutocompleteMatch match(TitledUrlMatchToACMatch(input, fixed_up_input, *i)); |
115 if (match.relevance > 0) | 115 if (match.relevance > 0) |
116 matches_.push_back(match); | 116 matches_.push_back(match); |
117 } | 117 } |
118 | 118 |
119 // Sort and clip the resulting matches. | 119 // Sort and clip the resulting matches. |
120 size_t num_matches = | 120 size_t num_matches = |
121 std::min(matches_.size(), AutocompleteProvider::kMaxMatches); | 121 std::min(matches_.size(), AutocompleteProvider::kMaxMatches); |
122 std::partial_sort(matches_.begin(), matches_.begin() + num_matches, | 122 std::partial_sort(matches_.begin(), matches_.begin() + num_matches, |
123 matches_.end(), AutocompleteMatch::MoreRelevant); | 123 matches_.end(), AutocompleteMatch::MoreRelevant); |
124 matches_.resize(num_matches); | 124 matches_.resize(num_matches); |
(...skipping 23 matching lines...) Expand all Loading... |
148 | 148 |
149 double ScoringFactor() { return scoring_factor_; } | 149 double ScoringFactor() { return scoring_factor_; } |
150 | 150 |
151 private: | 151 private: |
152 double title_length_; | 152 double title_length_; |
153 double scoring_factor_; | 153 double scoring_factor_; |
154 }; | 154 }; |
155 | 155 |
156 } // namespace | 156 } // namespace |
157 | 157 |
158 AutocompleteMatch BookmarkProvider::BookmarkMatchToACMatch( | 158 AutocompleteMatch BookmarkProvider::TitledUrlMatchToACMatch( |
159 const AutocompleteInput& input, | 159 const AutocompleteInput& input, |
160 const base::string16& fixed_up_input_text, | 160 const base::string16& fixed_up_input_text, |
161 const BookmarkMatch& bookmark_match) { | 161 const TitledUrlMatch& bookmark_match) { |
162 // The AutocompleteMatch we construct is non-deletable because the only | 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 | 163 // way to support this would be to delete the underlying bookmark, which is |
164 // unlikely to be what the user intends. | 164 // unlikely to be what the user intends. |
165 AutocompleteMatch match(this, 0, false, | 165 AutocompleteMatch match(this, 0, false, |
166 AutocompleteMatchType::BOOKMARK_TITLE); | 166 AutocompleteMatchType::BOOKMARK_TITLE); |
167 base::string16 title(bookmark_match.node->GetTitledUrlNodeTitle()); | 167 base::string16 title(bookmark_match.node->GetTitledUrlNodeTitle()); |
168 BookmarkMatch::MatchPositions new_title_match_positions = | 168 TitledUrlMatch::MatchPositions new_title_match_positions = |
169 bookmark_match.title_match_positions; | 169 bookmark_match.title_match_positions; |
170 CorrectTitleAndMatchPositions(&title, &new_title_match_positions); | 170 CorrectTitleAndMatchPositions(&title, &new_title_match_positions); |
171 const GURL& url(bookmark_match.node->GetTitledUrlNodeUrl()); | 171 const GURL& url(bookmark_match.node->GetTitledUrlNodeUrl()); |
172 const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec()); | 172 const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec()); |
173 size_t inline_autocomplete_offset = URLPrefix::GetInlineAutocompleteOffset( | 173 size_t inline_autocomplete_offset = URLPrefix::GetInlineAutocompleteOffset( |
174 input.text(), fixed_up_input_text, false, url_utf16); | 174 input.text(), fixed_up_input_text, false, url_utf16); |
175 match.destination_url = url; | 175 match.destination_url = url; |
176 const size_t match_start = bookmark_match.url_match_positions.empty() ? | 176 const size_t match_start = bookmark_match.url_match_positions.empty() ? |
177 0 : bookmark_match.url_match_positions[0].first; | 177 0 : bookmark_match.url_match_positions[0].first; |
178 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()) && | 178 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()) && |
179 ((match_start == base::string16::npos) || (match_start != 0)); | 179 ((match_start == base::string16::npos) || (match_start != 0)); |
180 std::vector<size_t> offsets = BookmarkMatch::OffsetsFromMatchPositions( | 180 std::vector<size_t> offsets = TitledUrlMatch::OffsetsFromMatchPositions( |
181 bookmark_match.url_match_positions); | 181 bookmark_match.url_match_positions); |
182 // In addition to knowing how |offsets| is transformed, we need to know how | 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 | 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 | 184 // |offsets|, compute how everything is transformed, then remove it from the |
185 // end. | 185 // end. |
186 offsets.push_back(inline_autocomplete_offset); | 186 offsets.push_back(inline_autocomplete_offset); |
187 match.contents = url_formatter::FormatUrlWithOffsets( | 187 match.contents = url_formatter::FormatUrlWithOffsets( |
188 url, url_formatter::kFormatUrlOmitAll & | 188 url, url_formatter::kFormatUrlOmitAll & |
189 ~(trim_http ? 0 : url_formatter::kFormatUrlOmitHTTP), | 189 ~(trim_http ? 0 : url_formatter::kFormatUrlOmitHTTP), |
190 net::UnescapeRule::SPACES, nullptr, nullptr, &offsets); | 190 net::UnescapeRule::SPACES, nullptr, nullptr, &offsets); |
191 inline_autocomplete_offset = offsets.back(); | 191 inline_autocomplete_offset = offsets.back(); |
192 offsets.pop_back(); | 192 offsets.pop_back(); |
193 BookmarkMatch::MatchPositions new_url_match_positions = | 193 TitledUrlMatch::MatchPositions new_url_match_positions = |
194 BookmarkMatch::ReplaceOffsetsInMatchPositions( | 194 TitledUrlMatch::ReplaceOffsetsInMatchPositions( |
195 bookmark_match.url_match_positions, offsets); | 195 bookmark_match.url_match_positions, offsets); |
196 match.contents_class = | 196 match.contents_class = |
197 ClassificationsFromMatch(new_url_match_positions, | 197 ClassificationsFromMatch(new_url_match_positions, |
198 match.contents.size(), | 198 match.contents.size(), |
199 true); | 199 true); |
200 match.fill_into_edit = | 200 match.fill_into_edit = |
201 AutocompleteInput::FormattedStringWithEquivalentMeaning( | 201 AutocompleteInput::FormattedStringWithEquivalentMeaning( |
202 url, match.contents, client_->GetSchemeClassifier()); | 202 url, match.contents, client_->GetSchemeClassifier()); |
203 if (inline_autocomplete_offset != base::string16::npos) { | 203 if (inline_autocomplete_offset != base::string16::npos) { |
204 // |inline_autocomplete_offset| may be beyond the end of the | 204 // |inline_autocomplete_offset| may be beyond the end of the |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
333 i != positions.end(); | 333 i != positions.end(); |
334 ++i) { | 334 ++i) { |
335 AutocompleteMatch::ACMatchClassifications new_class; | 335 AutocompleteMatch::ACMatchClassifications new_class; |
336 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first, | 336 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first, |
337 text_length, url_style, &new_class); | 337 text_length, url_style, &new_class); |
338 classifications = AutocompleteMatch::MergeClassifications( | 338 classifications = AutocompleteMatch::MergeClassifications( |
339 classifications, new_class); | 339 classifications, new_class); |
340 } | 340 } |
341 return classifications; | 341 return classifications; |
342 } | 342 } |
OLD | NEW |