| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/omnibox/browser/bookmark_provider.h" | 5 #include "components/omnibox/browser/bookmark_provider.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <functional> | 8 #include <functional> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 13 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 14 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
| 15 #include "components/bookmarks/browser/bookmark_match.h" | |
| 16 #include "components/bookmarks/browser/bookmark_model.h" | 15 #include "components/bookmarks/browser/bookmark_model.h" |
| 16 #include "components/bookmarks/browser/titled_url_match.h" |
| 17 #include "components/metrics/proto/omnibox_input_type.pb.h" | 17 #include "components/metrics/proto/omnibox_input_type.pb.h" |
| 18 #include "components/omnibox/browser/autocomplete_provider_client.h" | 18 #include "components/omnibox/browser/autocomplete_provider_client.h" |
| 19 #include "components/omnibox/browser/autocomplete_result.h" | 19 #include "components/omnibox/browser/autocomplete_result.h" |
| 20 #include "components/omnibox/browser/history_provider.h" | 20 #include "components/omnibox/browser/history_provider.h" |
| 21 #include "components/omnibox/browser/url_prefix.h" | 21 #include "components/omnibox/browser/url_prefix.h" |
| 22 #include "components/prefs/pref_service.h" | 22 #include "components/prefs/pref_service.h" |
| 23 #include "components/url_formatter/url_formatter.h" | 23 #include "components/url_formatter/url_formatter.h" |
| 24 #include "url/url_constants.h" | 24 #include "url/url_constants.h" |
| 25 | 25 |
| 26 using bookmarks::BookmarkMatch; | |
| 27 using BookmarkMatches = std::vector<BookmarkMatch>; | |
| 28 using bookmarks::BookmarkNode; | 26 using bookmarks::BookmarkNode; |
| 27 using bookmarks::TitledUrlMatch; |
| 28 using TitledUrlMatches = std::vector<TitledUrlMatch>; |
| 29 | 29 |
| 30 namespace { | 30 namespace { |
| 31 | 31 |
| 32 // Removes leading spaces from |title| before displaying, otherwise it looks | 32 // Removes leading spaces from |title| before displaying, otherwise it looks |
| 33 // funny. In the process, corrects |title_match_positions| so the correct | 33 // funny. In the process, corrects |title_match_positions| so the correct |
| 34 // characters are highlighted. | 34 // characters are highlighted. |
| 35 void CorrectTitleAndMatchPositions( | 35 void CorrectTitleAndMatchPositions( |
| 36 base::string16* title, | 36 base::string16* title, |
| 37 BookmarkMatch::MatchPositions* title_match_positions) { | 37 TitledUrlMatch::MatchPositions* title_match_positions) { |
| 38 size_t leading_whitespace_chars = title->length(); | 38 size_t leading_whitespace_chars = title->length(); |
| 39 base::TrimWhitespace(*title, base::TRIM_LEADING, title); | 39 base::TrimWhitespace(*title, base::TRIM_LEADING, title); |
| 40 leading_whitespace_chars-= title->length(); | 40 leading_whitespace_chars-= title->length(); |
| 41 if (leading_whitespace_chars == 0) | 41 if (leading_whitespace_chars == 0) |
| 42 return; | 42 return; |
| 43 for (query_parser::Snippet::MatchPositions::iterator it = | 43 for (query_parser::Snippet::MatchPositions::iterator it = |
| 44 title_match_positions->begin(); | 44 title_match_positions->begin(); |
| 45 it != title_match_positions->end(); ++it) { | 45 it != title_match_positions->end(); ++it) { |
| 46 (*it) = query_parser::Snippet::MatchPosition( | 46 (*it) = query_parser::Snippet::MatchPosition( |
| 47 it->first - leading_whitespace_chars, | 47 it->first - leading_whitespace_chars, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 71 DoAutocomplete(input); | 71 DoAutocomplete(input); |
| 72 } | 72 } |
| 73 | 73 |
| 74 BookmarkProvider::~BookmarkProvider() {} | 74 BookmarkProvider::~BookmarkProvider() {} |
| 75 | 75 |
| 76 void BookmarkProvider::DoAutocomplete(const AutocompleteInput& input) { | 76 void BookmarkProvider::DoAutocomplete(const AutocompleteInput& input) { |
| 77 // We may not have a bookmark model for some unit tests. | 77 // We may not have a bookmark model for some unit tests. |
| 78 if (!bookmark_model_) | 78 if (!bookmark_model_) |
| 79 return; | 79 return; |
| 80 | 80 |
| 81 BookmarkMatches matches; | 81 TitledUrlMatches matches; |
| 82 // Retrieve enough bookmarks so that we have a reasonable probability of | 82 // Retrieve enough bookmarks so that we have a reasonable probability of |
| 83 // suggesting the one that the user desires. | 83 // suggesting the one that the user desires. |
| 84 const size_t kMaxBookmarkMatches = 50; | 84 const size_t kMaxBookmarkMatches = 50; |
| 85 | 85 |
| 86 // GetBookmarksMatching returns bookmarks matching the user's | 86 // GetBookmarksMatching returns bookmarks matching the user's |
| 87 // search terms using the following rules: | 87 // search terms using the following rules: |
| 88 // - The search text is broken up into search terms. Each term is searched | 88 // - The search text is broken up into search terms. Each term is searched |
| 89 // for separately. | 89 // for separately. |
| 90 // - Term matches are always performed against the start of a word. 'def' | 90 // - Term matches are always performed against the start of a word. 'def' |
| 91 // will match against 'define' but not against 'indefinite'. | 91 // will match against 'define' but not against 'indefinite'. |
| 92 // - Terms must be at least three characters in length in order to perform | 92 // - Terms must be at least three characters in length in order to perform |
| 93 // partial word matches. Any term of lesser length will only be used as an | 93 // partial word matches. Any term of lesser length will only be used as an |
| 94 // exact match. 'def' will match against 'define' but 'de' will not match. | 94 // exact match. 'def' will match against 'define' but 'de' will not match. |
| 95 // - A search containing multiple terms will return results with those words | 95 // - A search containing multiple terms will return results with those words |
| 96 // occuring in any order. | 96 // occuring in any order. |
| 97 // - Terms enclosed in quotes comprises a phrase that must match exactly. | 97 // - Terms enclosed in quotes comprises a phrase that must match exactly. |
| 98 // - Multiple terms enclosed in quotes will require those exact words in that | 98 // - Multiple terms enclosed in quotes will require those exact words in that |
| 99 // exact order to match. | 99 // exact order to match. |
| 100 // | 100 // |
| 101 // Please refer to the code for BookmarkIndex::GetBookmarksMatching for | 101 // Please refer to the code for TitledUrlIndex::GetResultsMatching for |
| 102 // complete details of how searches are performed against the user's | 102 // complete details of how searches are performed against the user's |
| 103 // bookmarks. | 103 // bookmarks. |
| 104 bookmark_model_->GetBookmarksMatching(input.text(), | 104 bookmark_model_->GetBookmarksMatching(input.text(), |
| 105 kMaxBookmarkMatches, | 105 kMaxBookmarkMatches, |
| 106 &matches); | 106 &matches); |
| 107 if (matches.empty()) | 107 if (matches.empty()) |
| 108 return; // There were no matches. | 108 return; // There were no matches. |
| 109 const base::string16 fixed_up_input(FixupUserInput(input).second); | 109 const base::string16 fixed_up_input(FixupUserInput(input).second); |
| 110 for (BookmarkMatches::const_iterator i = matches.begin(); i != matches.end(); | 110 for (TitledUrlMatches::const_iterator i = matches.begin(); i != matches.end(); |
| 111 ++i) { | 111 ++i) { |
| 112 // Create and score the AutocompleteMatch. If its score is 0 then the | 112 // Create and score the AutocompleteMatch. If its score is 0 then the |
| 113 // match is discarded. | 113 // match is discarded. |
| 114 AutocompleteMatch match(BookmarkMatchToACMatch(input, fixed_up_input, *i)); | 114 AutocompleteMatch match(TitledUrlMatchToACMatch(input, fixed_up_input, *i)); |
| 115 if (match.relevance > 0) | 115 if (match.relevance > 0) |
| 116 matches_.push_back(match); | 116 matches_.push_back(match); |
| 117 } | 117 } |
| 118 | 118 |
| 119 // Sort and clip the resulting matches. | 119 // Sort and clip the resulting matches. |
| 120 size_t num_matches = | 120 size_t num_matches = |
| 121 std::min(matches_.size(), AutocompleteProvider::kMaxMatches); | 121 std::min(matches_.size(), AutocompleteProvider::kMaxMatches); |
| 122 std::partial_sort(matches_.begin(), matches_.begin() + num_matches, | 122 std::partial_sort(matches_.begin(), matches_.begin() + num_matches, |
| 123 matches_.end(), AutocompleteMatch::MoreRelevant); | 123 matches_.end(), AutocompleteMatch::MoreRelevant); |
| 124 matches_.resize(num_matches); | 124 matches_.resize(num_matches); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 148 | 148 |
| 149 double ScoringFactor() { return scoring_factor_; } | 149 double ScoringFactor() { return scoring_factor_; } |
| 150 | 150 |
| 151 private: | 151 private: |
| 152 double title_length_; | 152 double title_length_; |
| 153 double scoring_factor_; | 153 double scoring_factor_; |
| 154 }; | 154 }; |
| 155 | 155 |
| 156 } // namespace | 156 } // namespace |
| 157 | 157 |
| 158 AutocompleteMatch BookmarkProvider::BookmarkMatchToACMatch( | 158 AutocompleteMatch BookmarkProvider::TitledUrlMatchToACMatch( |
| 159 const AutocompleteInput& input, | 159 const AutocompleteInput& input, |
| 160 const base::string16& fixed_up_input_text, | 160 const base::string16& fixed_up_input_text, |
| 161 const BookmarkMatch& bookmark_match) { | 161 const TitledUrlMatch& bookmark_match) { |
| 162 // The AutocompleteMatch we construct is non-deletable because the only | 162 // The AutocompleteMatch we construct is non-deletable because the only |
| 163 // way to support this would be to delete the underlying bookmark, which is | 163 // way to support this would be to delete the underlying bookmark, which is |
| 164 // unlikely to be what the user intends. | 164 // unlikely to be what the user intends. |
| 165 AutocompleteMatch match(this, 0, false, | 165 AutocompleteMatch match(this, 0, false, |
| 166 AutocompleteMatchType::BOOKMARK_TITLE); | 166 AutocompleteMatchType::BOOKMARK_TITLE); |
| 167 base::string16 title(bookmark_match.node->GetTitledUrlNodeTitle()); | 167 base::string16 title(bookmark_match.node->GetTitledUrlNodeTitle()); |
| 168 BookmarkMatch::MatchPositions new_title_match_positions = | 168 TitledUrlMatch::MatchPositions new_title_match_positions = |
| 169 bookmark_match.title_match_positions; | 169 bookmark_match.title_match_positions; |
| 170 CorrectTitleAndMatchPositions(&title, &new_title_match_positions); | 170 CorrectTitleAndMatchPositions(&title, &new_title_match_positions); |
| 171 const GURL& url(bookmark_match.node->GetTitledUrlNodeUrl()); | 171 const GURL& url(bookmark_match.node->GetTitledUrlNodeUrl()); |
| 172 const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec()); | 172 const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec()); |
| 173 size_t inline_autocomplete_offset = URLPrefix::GetInlineAutocompleteOffset( | 173 size_t inline_autocomplete_offset = URLPrefix::GetInlineAutocompleteOffset( |
| 174 input.text(), fixed_up_input_text, false, url_utf16); | 174 input.text(), fixed_up_input_text, false, url_utf16); |
| 175 match.destination_url = url; | 175 match.destination_url = url; |
| 176 const size_t match_start = bookmark_match.url_match_positions.empty() ? | 176 const size_t match_start = bookmark_match.url_match_positions.empty() ? |
| 177 0 : bookmark_match.url_match_positions[0].first; | 177 0 : bookmark_match.url_match_positions[0].first; |
| 178 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()) && | 178 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()) && |
| 179 ((match_start == base::string16::npos) || (match_start != 0)); | 179 ((match_start == base::string16::npos) || (match_start != 0)); |
| 180 std::vector<size_t> offsets = BookmarkMatch::OffsetsFromMatchPositions( | 180 std::vector<size_t> offsets = TitledUrlMatch::OffsetsFromMatchPositions( |
| 181 bookmark_match.url_match_positions); | 181 bookmark_match.url_match_positions); |
| 182 // In addition to knowing how |offsets| is transformed, we need to know how | 182 // In addition to knowing how |offsets| is transformed, we need to know how |
| 183 // |inline_autocomplete_offset| is transformed. We add it to the end of | 183 // |inline_autocomplete_offset| is transformed. We add it to the end of |
| 184 // |offsets|, compute how everything is transformed, then remove it from the | 184 // |offsets|, compute how everything is transformed, then remove it from the |
| 185 // end. | 185 // end. |
| 186 offsets.push_back(inline_autocomplete_offset); | 186 offsets.push_back(inline_autocomplete_offset); |
| 187 match.contents = url_formatter::FormatUrlWithOffsets( | 187 match.contents = url_formatter::FormatUrlWithOffsets( |
| 188 url, url_formatter::kFormatUrlOmitAll & | 188 url, url_formatter::kFormatUrlOmitAll & |
| 189 ~(trim_http ? 0 : url_formatter::kFormatUrlOmitHTTP), | 189 ~(trim_http ? 0 : url_formatter::kFormatUrlOmitHTTP), |
| 190 net::UnescapeRule::SPACES, nullptr, nullptr, &offsets); | 190 net::UnescapeRule::SPACES, nullptr, nullptr, &offsets); |
| 191 inline_autocomplete_offset = offsets.back(); | 191 inline_autocomplete_offset = offsets.back(); |
| 192 offsets.pop_back(); | 192 offsets.pop_back(); |
| 193 BookmarkMatch::MatchPositions new_url_match_positions = | 193 TitledUrlMatch::MatchPositions new_url_match_positions = |
| 194 BookmarkMatch::ReplaceOffsetsInMatchPositions( | 194 TitledUrlMatch::ReplaceOffsetsInMatchPositions( |
| 195 bookmark_match.url_match_positions, offsets); | 195 bookmark_match.url_match_positions, offsets); |
| 196 match.contents_class = | 196 match.contents_class = |
| 197 ClassificationsFromMatch(new_url_match_positions, | 197 ClassificationsFromMatch(new_url_match_positions, |
| 198 match.contents.size(), | 198 match.contents.size(), |
| 199 true); | 199 true); |
| 200 match.fill_into_edit = | 200 match.fill_into_edit = |
| 201 AutocompleteInput::FormattedStringWithEquivalentMeaning( | 201 AutocompleteInput::FormattedStringWithEquivalentMeaning( |
| 202 url, match.contents, client_->GetSchemeClassifier()); | 202 url, match.contents, client_->GetSchemeClassifier()); |
| 203 if (inline_autocomplete_offset != base::string16::npos) { | 203 if (inline_autocomplete_offset != base::string16::npos) { |
| 204 // |inline_autocomplete_offset| may be beyond the end of the | 204 // |inline_autocomplete_offset| may be beyond the end of the |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 i != positions.end(); | 333 i != positions.end(); |
| 334 ++i) { | 334 ++i) { |
| 335 AutocompleteMatch::ACMatchClassifications new_class; | 335 AutocompleteMatch::ACMatchClassifications new_class; |
| 336 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first, | 336 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first, |
| 337 text_length, url_style, &new_class); | 337 text_length, url_style, &new_class); |
| 338 classifications = AutocompleteMatch::MergeClassifications( | 338 classifications = AutocompleteMatch::MergeClassifications( |
| 339 classifications, new_class); | 339 classifications, new_class); |
| 340 } | 340 } |
| 341 return classifications; | 341 return classifications; |
| 342 } | 342 } |
| OLD | NEW |