Chromium Code Reviews| 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 "chrome/browser/autocomplete/bookmark_provider.h" | 5 #include "chrome/browser/autocomplete/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/prefs/pref_service.h" | 11 #include "base/prefs/pref_service.h" |
| 12 #include "base/strings/utf_string_conversions.h" | |
| 12 #include "chrome/browser/autocomplete/autocomplete_result.h" | 13 #include "chrome/browser/autocomplete/autocomplete_result.h" |
| 14 #include "chrome/browser/autocomplete/url_prefix.h" | |
| 13 #include "chrome/browser/bookmarks/bookmark_model.h" | 15 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 14 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | 16 #include "chrome/browser/bookmarks/bookmark_model_factory.h" |
| 15 #include "chrome/browser/bookmarks/bookmark_title_match.h" | 17 #include "chrome/browser/bookmarks/bookmark_title_match.h" |
| 16 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
| 17 #include "chrome/common/pref_names.h" | 19 #include "chrome/common/pref_names.h" |
| 18 #include "net/base/net_util.h" | 20 #include "net/base/net_util.h" |
| 19 | 21 |
| 20 typedef std::vector<BookmarkTitleMatch> TitleMatches; | 22 typedef std::vector<BookmarkTitleMatch> TitleMatches; |
| 21 | 23 |
| 22 // BookmarkProvider ------------------------------------------------------------ | 24 // BookmarkProvider ------------------------------------------------------------ |
| 23 | 25 |
| 24 BookmarkProvider::BookmarkProvider( | 26 BookmarkProvider::BookmarkProvider( |
| 25 AutocompleteProviderListener* listener, | 27 AutocompleteProviderListener* listener, |
| 26 Profile* profile) | 28 Profile* profile) |
| 27 : AutocompleteProvider(listener, profile, | 29 : AutocompleteProvider(listener, profile, |
| 28 AutocompleteProvider::TYPE_BOOKMARK), | 30 AutocompleteProvider::TYPE_BOOKMARK), |
| 29 bookmark_model_(NULL) { | 31 bookmark_model_(NULL) { |
| 30 if (profile) { | 32 if (profile) { |
| 31 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile); | 33 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile); |
| 32 languages_ = profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); | 34 languages_ = profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); |
| 33 } | 35 } |
| 34 } | 36 } |
| 35 | 37 |
| 36 void BookmarkProvider::Start(const AutocompleteInput& input, | 38 void BookmarkProvider::Start(const AutocompleteInput& input, |
| 37 bool minimal_changes) { | 39 bool minimal_changes) { |
| 38 if (minimal_changes) | 40 if (minimal_changes) |
| 39 return; | 41 return; |
| 40 matches_.clear(); | 42 matches_.clear(); |
| 41 | 43 |
| 42 // Short-circuit any matching when inline autocompletion is disabled and | |
| 43 // we're looking for BEST_MATCH because none of the BookmarkProvider's | |
| 44 // matches can score high enough to qualify. | |
| 45 if (input.text().empty() || | 44 if (input.text().empty() || |
| 46 ((input.type() != AutocompleteInput::UNKNOWN) && | 45 ((input.type() != AutocompleteInput::UNKNOWN) && |
| 47 (input.type() != AutocompleteInput::QUERY)) || | 46 (input.type() != AutocompleteInput::QUERY))) |
| 48 ((input.matches_requested() == AutocompleteInput::BEST_MATCH) && | |
| 49 input.prevent_inline_autocomplete())) | |
| 50 return; | 47 return; |
| 51 | 48 |
| 52 DoAutocomplete(input, | 49 DoAutocomplete(input, |
| 53 input.matches_requested() == AutocompleteInput::BEST_MATCH); | 50 input.matches_requested() == AutocompleteInput::BEST_MATCH); |
| 54 } | 51 } |
| 55 | 52 |
| 56 BookmarkProvider::~BookmarkProvider() {} | 53 BookmarkProvider::~BookmarkProvider() {} |
| 57 | 54 |
| 58 void BookmarkProvider::DoAutocomplete(const AutocompleteInput& input, | 55 void BookmarkProvider::DoAutocomplete(const AutocompleteInput& input, |
| 59 bool best_match) { | 56 bool best_match) { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 87 // for all matched terms. | 84 // for all matched terms. |
| 88 // | 85 // |
| 89 // Please refer to the code for BookmarkIndex::GetBookmarksWithTitlesMatching | 86 // Please refer to the code for BookmarkIndex::GetBookmarksWithTitlesMatching |
| 90 // for complete details of how title searches are performed against the user's | 87 // for complete details of how title searches are performed against the user's |
| 91 // bookmarks. | 88 // bookmarks. |
| 92 bookmark_model_->GetBookmarksWithTitlesMatching(input.text(), | 89 bookmark_model_->GetBookmarksWithTitlesMatching(input.text(), |
| 93 kMaxBookmarkMatches, | 90 kMaxBookmarkMatches, |
| 94 &matches); | 91 &matches); |
| 95 if (matches.empty()) | 92 if (matches.empty()) |
| 96 return; // There were no matches. | 93 return; // There were no matches. |
| 94 AutocompleteInput fixed_up_input; | |
| 95 // If the input fails to get fixed up, pretend the fixed up version is the | |
| 96 // original. | |
| 97 if (!FixupUserInput(&fixed_up_input)) | |
| 98 fixed_up_input = input; | |
| 97 for (TitleMatches::const_iterator i = matches.begin(); i != matches.end(); | 99 for (TitleMatches::const_iterator i = matches.begin(); i != matches.end(); |
| 98 ++i) { | 100 ++i) { |
| 99 // Create and score the AutocompleteMatch. If its score is 0 then the | 101 // Create and score the AutocompleteMatch. If its score is 0 then the |
| 100 // match is discarded. | 102 // match is discarded. |
| 101 AutocompleteMatch match(TitleMatchToACMatch(*i)); | 103 AutocompleteMatch match(TitleMatchToACMatch(input, fixed_up_input, *i)); |
| 102 if (match.relevance > 0) | 104 if (match.relevance > 0) |
| 103 matches_.push_back(match); | 105 matches_.push_back(match); |
| 104 } | 106 } |
| 105 | 107 |
| 106 // Sort and clip the resulting matches. | 108 // Sort and clip the resulting matches. |
| 107 size_t max_matches = best_match ? 1 : AutocompleteProvider::kMaxMatches; | 109 size_t max_matches = best_match ? 1 : AutocompleteProvider::kMaxMatches; |
| 108 if (matches_.size() > max_matches) { | 110 if (matches_.size() > max_matches) { |
| 109 std::partial_sort(matches_.begin(), | 111 std::partial_sort(matches_.begin(), |
| 110 matches_.begin() + max_matches, | 112 matches_.begin() + max_matches, |
| 111 matches_.end(), | 113 matches_.end(), |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 146 double ScoringFactor() { return scoring_factor_; } | 148 double ScoringFactor() { return scoring_factor_; } |
| 147 | 149 |
| 148 private: | 150 private: |
| 149 double title_length_; | 151 double title_length_; |
| 150 double scoring_factor_; | 152 double scoring_factor_; |
| 151 }; | 153 }; |
| 152 | 154 |
| 153 } // namespace | 155 } // namespace |
| 154 | 156 |
| 155 AutocompleteMatch BookmarkProvider::TitleMatchToACMatch( | 157 AutocompleteMatch BookmarkProvider::TitleMatchToACMatch( |
| 158 const AutocompleteInput& input, | |
| 159 const AutocompleteInput& fixed_up_input, | |
| 156 const BookmarkTitleMatch& title_match) { | 160 const BookmarkTitleMatch& title_match) { |
| 157 // The AutocompleteMatch we construct is non-deletable because the only | 161 // The AutocompleteMatch we construct is non-deletable because the only |
| 158 // way to support this would be to delete the underlying bookmark, which is | 162 // way to support this would be to delete the underlying bookmark, which is |
| 159 // unlikely to be what the user intends. | 163 // unlikely to be what the user intends. |
| 160 AutocompleteMatch match(this, 0, false, | 164 AutocompleteMatch match(this, 0, false, |
| 161 AutocompleteMatchType::BOOKMARK_TITLE); | 165 AutocompleteMatchType::BOOKMARK_TITLE); |
| 162 const base::string16& title(title_match.node->GetTitle()); | 166 const base::string16& title(title_match.node->GetTitle()); |
| 163 DCHECK(!title.empty()); | 167 DCHECK(!title.empty()); |
| 168 | |
| 169 // Determine |inline_autocomplete_offset|. | |
|
Peter Kasting
2014/04/09 00:53:32
This whole block looks suspiciously similar to wha
Mark P
2014/04/09 02:44:42
I thought about this as I was transferred code her
Mark P
2014/04/09 20:21:41
I found a bug this code, causing me to change my m
| |
| 164 const GURL& url(title_match.node->url()); | 170 const GURL& url(title_match.node->url()); |
| 171 const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec()); | |
| 172 const URLPrefix* best_prefix = URLPrefix::BestURLPrefix(url_utf16, | |
| 173 input.text()); | |
| 174 base::string16 matching_string = input.text(); | |
| 175 // If we failed to find a best_prefix initially, try again using a fixed-up | |
| 176 // version of the user input. This is especially useful to get about: URLs | |
| 177 // to inline against chrome:// URLs. (about: URLs are fixed up to the | |
| 178 // chrome:// scheme.) | |
| 179 if ((best_prefix == NULL) && !fixed_up_input.text().empty() && | |
| 180 (fixed_up_input.text() != input.text())) { | |
| 181 best_prefix = URLPrefix::BestURLPrefix(url_utf16, fixed_up_input.text()); | |
| 182 matching_string = fixed_up_input.text(); | |
| 183 } | |
| 184 size_t inline_autocomplete_offset = | |
| 185 (best_prefix != NULL) ? | |
| 186 (best_prefix->prefix.length() + matching_string.length()) : | |
| 187 base::string16::npos; | |
| 188 | |
| 165 match.destination_url = url; | 189 match.destination_url = url; |
| 190 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()) && | |
| 191 ((best_prefix != NULL) || (inline_autocomplete_offset != 0)); | |
|
Peter Kasting
2014/04/09 00:53:32
I don't think I understand this conditional.
Woul
Mark P
2014/04/09 02:44:42
Oops, you're right. It should be best_prefix == N
| |
| 166 match.contents = net::FormatUrl(url, languages_, | 192 match.contents = net::FormatUrl(url, languages_, |
| 167 net::kFormatUrlOmitAll & net::kFormatUrlOmitHTTP, | 193 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP), |
| 168 net::UnescapeRule::SPACES, NULL, NULL, NULL); | 194 net::UnescapeRule::SPACES, NULL, NULL, &inline_autocomplete_offset); |
| 169 match.contents_class.push_back( | 195 match.contents_class.push_back( |
| 170 ACMatchClassification(0, ACMatchClassification::URL)); | 196 ACMatchClassification(0, ACMatchClassification::URL)); |
| 171 match.fill_into_edit = | 197 match.fill_into_edit = |
| 172 AutocompleteInput::FormattedStringWithEquivalentMeaning(url, | 198 AutocompleteInput::FormattedStringWithEquivalentMeaning(url, |
| 173 match.contents); | 199 match.contents); |
| 200 if (inline_autocomplete_offset != base::string16::npos) { | |
| 201 // |inline_autocomplete_offset| may be beyond the end of the | |
| 202 // |fill_into_edit| if the user has typed an URL with a scheme and the | |
| 203 // last character typed is a slash. That slash is removed by the | |
| 204 // FormatURLWithOffsets call above. | |
| 205 if (inline_autocomplete_offset < match.fill_into_edit.length()) { | |
| 206 match.inline_autocompletion = | |
| 207 match.fill_into_edit.substr(inline_autocomplete_offset); | |
| 208 } | |
| 209 match.allowed_to_be_default_match = match.inline_autocompletion.empty() || | |
| 210 !input.prevent_inline_autocomplete(); | |
| 211 } | |
| 174 match.description = title; | 212 match.description = title; |
| 175 match.description_class = | 213 match.description_class = |
| 176 ClassificationsFromMatch(title_match.match_positions, | 214 ClassificationsFromMatch(title_match.match_positions, |
| 177 match.description.size()); | 215 match.description.size()); |
| 178 match.starred = true; | 216 match.starred = true; |
| 179 | 217 |
| 180 // Summary on how a relevance score is determined for the match: | 218 // Summary on how a relevance score is determined for the match: |
| 181 // | 219 // |
| 182 // For each term matching within the bookmark's title (as given by the set of | 220 // For each term matching within the bookmark's title (as given by the set of |
| 183 // Snippet::MatchPositions) calculate a 'factor', sum up those factors, then | 221 // Snippet::MatchPositions) calculate a 'factor', sum up those factors, then |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 for (Snippet::MatchPositions::const_iterator i = positions.begin(); | 303 for (Snippet::MatchPositions::const_iterator i = positions.begin(); |
| 266 i != positions.end(); ++i) { | 304 i != positions.end(); ++i) { |
| 267 AutocompleteMatch::ACMatchClassifications new_class; | 305 AutocompleteMatch::ACMatchClassifications new_class; |
| 268 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first, | 306 AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first, |
| 269 text_length, 0, &new_class); | 307 text_length, 0, &new_class); |
| 270 classifications = AutocompleteMatch::MergeClassifications( | 308 classifications = AutocompleteMatch::MergeClassifications( |
| 271 classifications, new_class); | 309 classifications, new_class); |
| 272 } | 310 } |
| 273 return classifications; | 311 return classifications; |
| 274 } | 312 } |
| OLD | NEW |