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 <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <functional> | 10 #include <functional> |
11 #include <iterator> | 11 #include <iterator> |
12 #include <list> | 12 #include <list> |
13 | 13 |
14 #include "base/i18n/case_conversion.h" | 14 #include "base/i18n/case_conversion.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/memory/scoped_vector.h" | |
17 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
18 #include "base/strings/utf_offset_string_conversions.h" | 17 #include "base/strings/utf_offset_string_conversions.h" |
19 #include "build/build_config.h" | 18 #include "build/build_config.h" |
20 #include "components/bookmarks/browser/bookmark_client.h" | 19 #include "components/bookmarks/browser/bookmark_client.h" |
21 #include "components/bookmarks/browser/bookmark_match.h" | 20 #include "components/bookmarks/browser/bookmark_match.h" |
22 #include "components/bookmarks/browser/bookmark_node.h" | 21 #include "components/bookmarks/browser/bookmark_node.h" |
23 #include "components/bookmarks/browser/bookmark_utils.h" | 22 #include "components/bookmarks/browser/bookmark_utils.h" |
24 #include "components/query_parser/snippet.h" | 23 #include "components/query_parser/snippet.h" |
25 #include "third_party/icu/source/common/unicode/normalizer2.h" | 24 #include "third_party/icu/source/common/unicode/normalizer2.h" |
26 #include "third_party/icu/source/common/unicode/utypes.h" | 25 #include "third_party/icu/source/common/unicode/utypes.h" |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 } | 125 } |
127 } | 126 } |
128 | 127 |
129 Nodes sorted_nodes; | 128 Nodes sorted_nodes; |
130 SortMatches(matches, &sorted_nodes); | 129 SortMatches(matches, &sorted_nodes); |
131 | 130 |
132 // We use a QueryParser to fill in match positions for us. It's not the most | 131 // We use a QueryParser to fill in match positions for us. It's not the most |
133 // efficient way to go about this, but by the time we get here we know what | 132 // efficient way to go about this, but by the time we get here we know what |
134 // matches and so this shouldn't be performance critical. | 133 // matches and so this shouldn't be performance critical. |
135 query_parser::QueryParser parser; | 134 query_parser::QueryParser parser; |
136 ScopedVector<query_parser::QueryNode> query_nodes; | 135 query_parser::QueryNodeVector query_nodes; |
137 parser.ParseQueryNodes(query, matching_algorithm, &query_nodes.get()); | 136 parser.ParseQueryNodes(query, matching_algorithm, &query_nodes); |
138 | 137 |
139 // The highest typed counts should be at the beginning of the results vector | 138 // The highest typed counts should be at the beginning of the results vector |
140 // so that the best matches will always be included in the results. The loop | 139 // so that the best matches will always be included in the results. The loop |
141 // that calculates result relevance in HistoryContentsProvider::ConvertResults | 140 // that calculates result relevance in HistoryContentsProvider::ConvertResults |
142 // will run backwards to assure higher relevance will be attributed to the | 141 // will run backwards to assure higher relevance will be attributed to the |
143 // best matches. | 142 // best matches. |
144 for (Nodes::const_iterator i = sorted_nodes.begin(); | 143 for (Nodes::const_iterator i = sorted_nodes.begin(); |
145 i != sorted_nodes.end() && results->size() < max_count; | 144 i != sorted_nodes.end() && results->size() < max_count; |
146 ++i) | 145 ++i) |
147 AddMatchToResults(*i, &parser, query_nodes.get(), results); | 146 AddMatchToResults(*i, &parser, query_nodes, results); |
148 } | 147 } |
149 | 148 |
150 void BookmarkIndex::SortMatches(const NodeSet& matches, | 149 void BookmarkIndex::SortMatches(const NodeSet& matches, |
151 Nodes* sorted_nodes) const { | 150 Nodes* sorted_nodes) const { |
152 sorted_nodes->reserve(matches.size()); | 151 sorted_nodes->reserve(matches.size()); |
153 if (client_->SupportsTypedCountForNodes()) { | 152 if (client_->SupportsTypedCountForNodes()) { |
154 NodeTypedCountPairs node_typed_counts; | 153 NodeTypedCountPairs node_typed_counts; |
155 client_->GetTypedCountForNodes(matches, &node_typed_counts); | 154 client_->GetTypedCountForNodes(matches, &node_typed_counts); |
156 std::sort(node_typed_counts.begin(), | 155 std::sort(node_typed_counts.begin(), |
157 node_typed_counts.end(), | 156 node_typed_counts.end(), |
158 NodeTypedCountPairSortFunctor()); | 157 NodeTypedCountPairSortFunctor()); |
159 std::transform(node_typed_counts.begin(), | 158 std::transform(node_typed_counts.begin(), |
160 node_typed_counts.end(), | 159 node_typed_counts.end(), |
161 std::back_inserter(*sorted_nodes), | 160 std::back_inserter(*sorted_nodes), |
162 NodeTypedCountPairExtractNodeFunctor()); | 161 NodeTypedCountPairExtractNodeFunctor()); |
163 } else { | 162 } else { |
164 sorted_nodes->insert(sorted_nodes->end(), matches.begin(), matches.end()); | 163 sorted_nodes->insert(sorted_nodes->end(), matches.begin(), matches.end()); |
165 } | 164 } |
166 } | 165 } |
167 | 166 |
168 void BookmarkIndex::AddMatchToResults( | 167 void BookmarkIndex::AddMatchToResults( |
169 const BookmarkNode* node, | 168 const BookmarkNode* node, |
170 query_parser::QueryParser* parser, | 169 query_parser::QueryParser* parser, |
171 const query_parser::QueryNodeStarVector& query_nodes, | 170 const query_parser::QueryNodeVector& query_nodes, |
172 std::vector<BookmarkMatch>* results) { | 171 std::vector<BookmarkMatch>* results) { |
173 // Check that the result matches the query. The previous search | 172 // Check that the result matches the query. The previous search |
174 // was a simple per-word search, while the more complex matching | 173 // was a simple per-word search, while the more complex matching |
175 // of QueryParser may filter it out. For example, the query | 174 // of QueryParser may filter it out. For example, the query |
176 // ["thi"] will match the bookmark titled [Thinking], but since | 175 // ["thi"] will match the bookmark titled [Thinking], but since |
177 // ["thi"] is quoted we don't want to do a prefix match. | 176 // ["thi"] is quoted we don't want to do a prefix match. |
178 query_parser::QueryWordVector title_words, url_words; | 177 query_parser::QueryWordVector title_words, url_words; |
179 const base::string16 lower_title = | 178 const base::string16 lower_title = |
180 base::i18n::ToLower(Normalize(node->GetTitle())); | 179 base::i18n::ToLower(Normalize(node->GetTitle())); |
181 parser->ExtractQueryWords(lower_title, &title_words); | 180 parser->ExtractQueryWords(lower_title, &title_words); |
182 base::OffsetAdjuster::Adjustments adjustments; | 181 base::OffsetAdjuster::Adjustments adjustments; |
183 parser->ExtractQueryWords( | 182 parser->ExtractQueryWords( |
184 CleanUpUrlForMatching(node->url(), &adjustments), | 183 CleanUpUrlForMatching(node->url(), &adjustments), |
185 &url_words); | 184 &url_words); |
186 query_parser::Snippet::MatchPositions title_matches, url_matches; | 185 query_parser::Snippet::MatchPositions title_matches, url_matches; |
187 for (size_t i = 0; i < query_nodes.size(); ++i) { | 186 for (const auto& node : query_nodes) { |
188 const bool has_title_matches = | 187 const bool has_title_matches = |
189 query_nodes[i]->HasMatchIn(title_words, &title_matches); | 188 node->HasMatchIn(title_words, &title_matches); |
190 const bool has_url_matches = | 189 const bool has_url_matches = node->HasMatchIn(url_words, &url_matches); |
191 query_nodes[i]->HasMatchIn(url_words, &url_matches); | |
192 if (!has_title_matches && !has_url_matches) | 190 if (!has_title_matches && !has_url_matches) |
193 return; | 191 return; |
194 query_parser::QueryParser::SortAndCoalesceMatchPositions(&title_matches); | 192 query_parser::QueryParser::SortAndCoalesceMatchPositions(&title_matches); |
195 query_parser::QueryParser::SortAndCoalesceMatchPositions(&url_matches); | 193 query_parser::QueryParser::SortAndCoalesceMatchPositions(&url_matches); |
196 } | 194 } |
197 BookmarkMatch match; | 195 BookmarkMatch match; |
198 if (lower_title.length() == node->GetTitle().length()) { | 196 if (lower_title.length() == node->GetTitle().length()) { |
199 // Only use title matches if the lowercase string is the same length | 197 // Only use title matches if the lowercase string is the same length |
200 // as the original string, otherwise the matches are meaningless. | 198 // as the original string, otherwise the matches are meaningless. |
201 // TODO(mpearson): revise match positions appropriately. | 199 // TODO(mpearson): revise match positions appropriately. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 // We can get here if the node has the same term more than once. For | 283 // We can get here if the node has the same term more than once. For |
286 // example, a bookmark with the title 'foo foo' would end up here. | 284 // example, a bookmark with the title 'foo foo' would end up here. |
287 return; | 285 return; |
288 } | 286 } |
289 i->second.erase(node); | 287 i->second.erase(node); |
290 if (i->second.empty()) | 288 if (i->second.empty()) |
291 index_.erase(i); | 289 index_.erase(i); |
292 } | 290 } |
293 | 291 |
294 } // namespace bookmarks | 292 } // namespace bookmarks |
OLD | NEW |