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 |