| 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 "base/i18n/case_conversion.h" | 9 #include "base/i18n/case_conversion.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/strings/utf_offset_string_conversions.h" | 12 #include "base/strings/utf_offset_string_conversions.h" |
| 13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
| 14 #include "components/bookmarks/browser/bookmark_client.h" | |
| 15 #include "components/bookmarks/browser/bookmark_match.h" | 14 #include "components/bookmarks/browser/bookmark_match.h" |
| 16 #include "components/bookmarks/browser/bookmark_utils.h" | 15 #include "components/bookmarks/browser/bookmark_utils.h" |
| 17 #include "components/bookmarks/browser/titled_url_node.h" | 16 #include "components/bookmarks/browser/titled_url_node.h" |
| 17 #include "components/bookmarks/browser/titled_url_node_sorter.h" |
| 18 #include "components/query_parser/snippet.h" | 18 #include "components/query_parser/snippet.h" |
| 19 #include "third_party/icu/source/common/unicode/normalizer2.h" | 19 #include "third_party/icu/source/common/unicode/normalizer2.h" |
| 20 #include "third_party/icu/source/common/unicode/utypes.h" | 20 #include "third_party/icu/source/common/unicode/utypes.h" |
| 21 | 21 |
| 22 namespace bookmarks { | 22 namespace bookmarks { |
| 23 | 23 |
| 24 using UrlTypedCountMap = BookmarkClient::UrlTypedCountMap; | |
| 25 | |
| 26 namespace { | 24 namespace { |
| 27 | 25 |
| 28 using UrlNodeMap = std::unordered_map<const GURL*, const TitledUrlNode*>; | |
| 29 using UrlTypedCountPair = std::pair<const GURL*, int>; | |
| 30 using UrlTypedCountPairs = std::vector<UrlTypedCountPair>; | |
| 31 | |
| 32 // Returns a normalized version of the UTF16 string |text|. If it fails to | 26 // Returns a normalized version of the UTF16 string |text|. If it fails to |
| 33 // normalize the string, returns |text| itself as a best-effort. | 27 // normalize the string, returns |text| itself as a best-effort. |
| 34 base::string16 Normalize(const base::string16& text) { | 28 base::string16 Normalize(const base::string16& text) { |
| 35 UErrorCode status = U_ZERO_ERROR; | 29 UErrorCode status = U_ZERO_ERROR; |
| 36 const icu::Normalizer2* normalizer2 = | 30 const icu::Normalizer2* normalizer2 = |
| 37 icu::Normalizer2::getInstance(nullptr, "nfkc", UNORM2_COMPOSE, status); | 31 icu::Normalizer2::getInstance(nullptr, "nfkc", UNORM2_COMPOSE, status); |
| 38 if (U_FAILURE(status)) { | 32 if (U_FAILURE(status)) { |
| 39 // Log and crash right away to capture the error code in the crash report. | 33 // Log and crash right away to capture the error code in the crash report. |
| 40 LOG(FATAL) << "failed to create a normalizer: " << u_errorName(status); | 34 LOG(FATAL) << "failed to create a normalizer: " << u_errorName(status); |
| 41 } | 35 } |
| 42 icu::UnicodeString unicode_text( | 36 icu::UnicodeString unicode_text( |
| 43 text.data(), static_cast<int32_t>(text.length())); | 37 text.data(), static_cast<int32_t>(text.length())); |
| 44 icu::UnicodeString unicode_normalized_text; | 38 icu::UnicodeString unicode_normalized_text; |
| 45 normalizer2->normalize(unicode_text, unicode_normalized_text, status); | 39 normalizer2->normalize(unicode_text, unicode_normalized_text, status); |
| 46 if (U_FAILURE(status)) { | 40 if (U_FAILURE(status)) { |
| 47 // This should not happen. Log the error and fall back. | 41 // This should not happen. Log the error and fall back. |
| 48 LOG(ERROR) << "normalization failed: " << u_errorName(status); | 42 LOG(ERROR) << "normalization failed: " << u_errorName(status); |
| 49 return text; | 43 return text; |
| 50 } | 44 } |
| 51 return base::string16(unicode_normalized_text.getBuffer(), | 45 return base::string16(unicode_normalized_text.getBuffer(), |
| 52 unicode_normalized_text.length()); | 46 unicode_normalized_text.length()); |
| 53 } | 47 } |
| 54 | 48 |
| 55 // Sort functor for UrlTypedCountPairs. We sort in decreasing order of typed | |
| 56 // count so that the best matches will always be added to the results. | |
| 57 struct UrlTypedCountPairSortFunctor { | |
| 58 bool operator()(const UrlTypedCountPair& a, | |
| 59 const UrlTypedCountPair& b) const { | |
| 60 return a.second > b.second; | |
| 61 } | |
| 62 }; | |
| 63 | |
| 64 // Extract the GURL stored in an UrlTypedCountPair and use it to look up the | |
| 65 // corresponding TitledUrlNode. | |
| 66 class UrlTypedCountPairNodeLookupFunctor { | |
| 67 public: | |
| 68 explicit UrlTypedCountPairNodeLookupFunctor(UrlNodeMap& url_node_map) | |
| 69 : url_node_map_(url_node_map) { | |
| 70 } | |
| 71 | |
| 72 const TitledUrlNode* operator()(const UrlTypedCountPair& pair) const { | |
| 73 return url_node_map_[pair.first]; | |
| 74 } | |
| 75 | |
| 76 private: | |
| 77 UrlNodeMap& url_node_map_; | |
| 78 }; | |
| 79 | |
| 80 } // namespace | 49 } // namespace |
| 81 | 50 |
| 82 BookmarkIndex::BookmarkIndex(BookmarkClient* client) | 51 BookmarkIndex::BookmarkIndex(std::unique_ptr<TitledUrlNodeSorter> sorter) |
| 83 : client_(client) { | 52 : sorter_(std::move(sorter)) { |
| 84 DCHECK(client_); | |
| 85 } | 53 } |
| 86 | 54 |
| 87 BookmarkIndex::~BookmarkIndex() { | 55 BookmarkIndex::~BookmarkIndex() { |
| 88 } | 56 } |
| 89 | 57 |
| 90 void BookmarkIndex::Add(const TitledUrlNode* node) { | 58 void BookmarkIndex::Add(const TitledUrlNode* node) { |
| 91 std::vector<base::string16> terms = | 59 std::vector<base::string16> terms = |
| 92 ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle())); | 60 ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle())); |
| 93 for (size_t i = 0; i < terms.size(); ++i) | 61 for (size_t i = 0; i < terms.size(); ++i) |
| 94 RegisterNode(terms[i], node); | 62 RegisterNode(terms[i], node); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 // will run backwards to assure higher relevance will be attributed to the | 111 // will run backwards to assure higher relevance will be attributed to the |
| 144 // best matches. | 112 // best matches. |
| 145 for (TitledUrlNodes::const_iterator i = sorted_nodes.begin(); | 113 for (TitledUrlNodes::const_iterator i = sorted_nodes.begin(); |
| 146 i != sorted_nodes.end() && results->size() < max_count; | 114 i != sorted_nodes.end() && results->size() < max_count; |
| 147 ++i) | 115 ++i) |
| 148 AddMatchToResults(*i, &parser, query_nodes, results); | 116 AddMatchToResults(*i, &parser, query_nodes, results); |
| 149 } | 117 } |
| 150 | 118 |
| 151 void BookmarkIndex::SortMatches(const TitledUrlNodeSet& matches, | 119 void BookmarkIndex::SortMatches(const TitledUrlNodeSet& matches, |
| 152 TitledUrlNodes* sorted_nodes) const { | 120 TitledUrlNodes* sorted_nodes) const { |
| 153 sorted_nodes->reserve(matches.size()); | 121 if (sorter_) { |
| 154 if (client_->SupportsTypedCountForUrls()) { | 122 sorter_->SortMatches(matches, sorted_nodes); |
| 155 UrlNodeMap url_node_map; | |
| 156 UrlTypedCountMap url_typed_count_map; | |
| 157 for (auto node : matches) { | |
| 158 const GURL& url = node->GetTitledUrlNodeUrl(); | |
| 159 url_node_map.insert(std::make_pair(&url, node)); | |
| 160 url_typed_count_map.insert(std::make_pair(&url, 0)); | |
| 161 } | |
| 162 | |
| 163 client_->GetTypedCountForUrls(&url_typed_count_map); | |
| 164 | |
| 165 UrlTypedCountPairs url_typed_counts; | |
| 166 std::copy(url_typed_count_map.begin(), | |
| 167 url_typed_count_map.end(), | |
| 168 std::back_inserter(url_typed_counts)); | |
| 169 std::sort(url_typed_counts.begin(), | |
| 170 url_typed_counts.end(), | |
| 171 UrlTypedCountPairSortFunctor()); | |
| 172 std::transform(url_typed_counts.begin(), | |
| 173 url_typed_counts.end(), | |
| 174 std::back_inserter(*sorted_nodes), | |
| 175 UrlTypedCountPairNodeLookupFunctor(url_node_map)); | |
| 176 } else { | 123 } else { |
| 177 sorted_nodes->insert(sorted_nodes->end(), matches.begin(), matches.end()); | 124 sorted_nodes->insert(sorted_nodes->end(), matches.begin(), matches.end()); |
| 178 } | 125 } |
| 179 } | 126 } |
| 180 | 127 |
| 181 void BookmarkIndex::AddMatchToResults( | 128 void BookmarkIndex::AddMatchToResults( |
| 182 const TitledUrlNode* node, | 129 const TitledUrlNode* node, |
| 183 query_parser::QueryParser* parser, | 130 query_parser::QueryParser* parser, |
| 184 const query_parser::QueryNodeVector& query_nodes, | 131 const query_parser::QueryNodeVector& query_nodes, |
| 185 std::vector<BookmarkMatch>* results) { | 132 std::vector<BookmarkMatch>* results) { |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 // We can get here if the node has the same term more than once. For | 251 // We can get here if the node has the same term more than once. For |
| 305 // example, a node with the title 'foo foo' would end up here. | 252 // example, a node with the title 'foo foo' would end up here. |
| 306 return; | 253 return; |
| 307 } | 254 } |
| 308 i->second.erase(node); | 255 i->second.erase(node); |
| 309 if (i->second.empty()) | 256 if (i->second.empty()) |
| 310 index_.erase(i); | 257 index_.erase(i); |
| 311 } | 258 } |
| 312 | 259 |
| 313 } // namespace bookmarks | 260 } // namespace bookmarks |
| OLD | NEW |