| 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 |