OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/bookmarks/browser/bookmark_index.h" | 5 #include "components/bookmarks/browser/bookmark_index.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <iterator> | 9 #include <iterator> |
10 #include <list> | 10 #include <list> |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 for (size_t i = 0; i < terms.size(); ++i) | 128 for (size_t i = 0; i < terms.size(); ++i) |
129 UnregisterNode(terms[i], node); | 129 UnregisterNode(terms[i], node); |
130 terms = | 130 terms = |
131 ExtractQueryWords(CleanUpUrlForMatching(node->url(), languages_, NULL)); | 131 ExtractQueryWords(CleanUpUrlForMatching(node->url(), languages_, NULL)); |
132 for (size_t i = 0; i < terms.size(); ++i) | 132 for (size_t i = 0; i < terms.size(); ++i) |
133 UnregisterNode(terms[i], node); | 133 UnregisterNode(terms[i], node); |
134 } | 134 } |
135 | 135 |
136 void BookmarkIndex::GetBookmarksMatching(const base::string16& input_query, | 136 void BookmarkIndex::GetBookmarksMatching(const base::string16& input_query, |
137 size_t max_count, | 137 size_t max_count, |
| 138 bool always_prefix_search, |
138 std::vector<BookmarkMatch>* results) { | 139 std::vector<BookmarkMatch>* results) { |
139 const base::string16 query = Normalize(input_query); | 140 const base::string16 query = Normalize(input_query); |
140 std::vector<base::string16> terms = ExtractQueryWords(query); | 141 std::vector<base::string16> terms = ExtractQueryWords(query); |
141 if (terms.empty()) | 142 if (terms.empty()) |
142 return; | 143 return; |
143 | 144 |
144 Matches matches; | 145 Matches matches; |
145 for (size_t i = 0; i < terms.size(); ++i) { | 146 for (size_t i = 0; i < terms.size(); ++i) { |
146 if (!GetBookmarksMatchingTerm(terms[i], i == 0, &matches)) | 147 if (!GetBookmarksMatchingTerm( |
| 148 terms[i], i == 0, always_prefix_search, &matches)) { |
147 return; | 149 return; |
| 150 } |
148 } | 151 } |
149 | 152 |
150 Nodes sorted_nodes; | 153 Nodes sorted_nodes; |
151 SortMatches(matches, &sorted_nodes); | 154 SortMatches(matches, &sorted_nodes); |
152 | 155 |
153 // We use a QueryParser to fill in match positions for us. It's not the most | 156 // We use a QueryParser to fill in match positions for us. It's not the most |
154 // efficient way to go about this, but by the time we get here we know what | 157 // efficient way to go about this, but by the time we get here we know what |
155 // matches and so this shouldn't be performance critical. | 158 // matches and so this shouldn't be performance critical. |
156 query_parser::QueryParser parser; | 159 query_parser::QueryParser parser; |
157 ScopedVector<query_parser::QueryNode> query_nodes; | 160 ScopedVector<query_parser::QueryNode> query_nodes; |
158 parser.ParseQueryNodes(query, &query_nodes.get()); | 161 parser.ParseQueryNodes(query, always_prefix_search, &query_nodes.get()); |
159 | 162 |
160 // The highest typed counts should be at the beginning of the results vector | 163 // The highest typed counts should be at the beginning of the results vector |
161 // so that the best matches will always be included in the results. The loop | 164 // so that the best matches will always be included in the results. The loop |
162 // that calculates result relevance in HistoryContentsProvider::ConvertResults | 165 // that calculates result relevance in HistoryContentsProvider::ConvertResults |
163 // will run backwards to assure higher relevance will be attributed to the | 166 // will run backwards to assure higher relevance will be attributed to the |
164 // best matches. | 167 // best matches. |
165 for (Nodes::const_iterator i = sorted_nodes.begin(); | 168 for (Nodes::const_iterator i = sorted_nodes.begin(); |
166 i != sorted_nodes.end() && results->size() < max_count; | 169 i != sorted_nodes.end() && results->size() < max_count; |
167 ++i) | 170 ++i) |
168 AddMatchToResults(*i, &parser, query_nodes.get(), results); | 171 AddMatchToResults(*i, &parser, query_nodes.get(), results); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 BookmarkMatch::OffsetsFromMatchPositions(url_matches); | 243 BookmarkMatch::OffsetsFromMatchPositions(url_matches); |
241 base::OffsetAdjuster::UnadjustOffsets(adjustments, &offsets); | 244 base::OffsetAdjuster::UnadjustOffsets(adjustments, &offsets); |
242 url_matches = | 245 url_matches = |
243 BookmarkMatch::ReplaceOffsetsInMatchPositions(url_matches, offsets); | 246 BookmarkMatch::ReplaceOffsetsInMatchPositions(url_matches, offsets); |
244 match.url_match_positions.swap(url_matches); | 247 match.url_match_positions.swap(url_matches); |
245 match.node = node; | 248 match.node = node; |
246 results->push_back(match); | 249 results->push_back(match); |
247 } | 250 } |
248 | 251 |
249 bool BookmarkIndex::GetBookmarksMatchingTerm(const base::string16& term, | 252 bool BookmarkIndex::GetBookmarksMatchingTerm(const base::string16& term, |
250 bool first_term, | 253 bool first_term, |
251 Matches* matches) { | 254 bool always_prefix_search, |
| 255 Matches* matches) { |
252 Index::const_iterator i = index_.lower_bound(term); | 256 Index::const_iterator i = index_.lower_bound(term); |
253 if (i == index_.end()) | 257 if (i == index_.end()) |
254 return false; | 258 return false; |
255 | 259 |
256 if (!query_parser::QueryParser::IsWordLongEnoughForPrefixSearch(term)) { | 260 if (!always_prefix_search && |
| 261 !query_parser::QueryParser::IsWordLongEnoughForPrefixSearch(term)) { |
257 // Term is too short for prefix match, compare using exact match. | 262 // Term is too short for prefix match, compare using exact match. |
258 if (i->first != term) | 263 if (i->first != term) |
259 return false; // No bookmarks with this term. | 264 return false; // No bookmarks with this term. |
260 | 265 |
261 if (first_term) { | 266 if (first_term) { |
262 Match match; | 267 Match match; |
263 match.terms.push_back(i); | 268 match.terms.push_back(i); |
264 matches->push_back(match); | 269 matches->push_back(match); |
265 return true; | 270 return true; |
266 } | 271 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 } | 332 } |
328 } | 333 } |
329 } | 334 } |
330 | 335 |
331 std::vector<base::string16> BookmarkIndex::ExtractQueryWords( | 336 std::vector<base::string16> BookmarkIndex::ExtractQueryWords( |
332 const base::string16& query) { | 337 const base::string16& query) { |
333 std::vector<base::string16> terms; | 338 std::vector<base::string16> terms; |
334 if (query.empty()) | 339 if (query.empty()) |
335 return std::vector<base::string16>(); | 340 return std::vector<base::string16>(); |
336 query_parser::QueryParser parser; | 341 query_parser::QueryParser parser; |
337 parser.ParseQueryWords(base::i18n::ToLower(query), &terms); | 342 parser.ParseQueryWords(base::i18n::ToLower(query), |
| 343 false, /* always_prefix_search */ |
| 344 &terms); |
338 return terms; | 345 return terms; |
339 } | 346 } |
340 | 347 |
341 void BookmarkIndex::RegisterNode(const base::string16& term, | 348 void BookmarkIndex::RegisterNode(const base::string16& term, |
342 const BookmarkNode* node) { | 349 const BookmarkNode* node) { |
343 index_[term].insert(node); | 350 index_[term].insert(node); |
344 } | 351 } |
345 | 352 |
346 void BookmarkIndex::UnregisterNode(const base::string16& term, | 353 void BookmarkIndex::UnregisterNode(const base::string16& term, |
347 const BookmarkNode* node) { | 354 const BookmarkNode* node) { |
348 Index::iterator i = index_.find(term); | 355 Index::iterator i = index_.find(term); |
349 if (i == index_.end()) { | 356 if (i == index_.end()) { |
350 // We can get here if the node has the same term more than once. For | 357 // We can get here if the node has the same term more than once. For |
351 // example, a bookmark with the title 'foo foo' would end up here. | 358 // example, a bookmark with the title 'foo foo' would end up here. |
352 return; | 359 return; |
353 } | 360 } |
354 i->second.erase(node); | 361 i->second.erase(node); |
355 if (i->second.empty()) | 362 if (i->second.empty()) |
356 index_.erase(i); | 363 index_.erase(i); |
357 } | 364 } |
358 | 365 |
359 } // namespace bookmarks | 366 } // namespace bookmarks |
OLD | NEW |