| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/history_quick_provider.h" | 5 #include "chrome/browser/autocomplete/history_quick_provider.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/i18n/break_iterator.h" | 8 #include "base/i18n/break_iterator.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "base/utf_string_conversions.h" | 11 #include "base/utf_string_conversions.h" |
| 12 #include "chrome/browser/autocomplete/autocomplete_match.h" | |
| 13 #include "chrome/browser/history/history.h" | 12 #include "chrome/browser/history/history.h" |
| 14 #include "chrome/browser/history/in_memory_url_index.h" | 13 #include "chrome/browser/history/in_memory_url_index.h" |
| 15 #include "chrome/browser/net/url_fixer_upper.h" | 14 #include "chrome/browser/net/url_fixer_upper.h" |
| 16 #include "chrome/browser/prefs/pref_service.h" | 15 #include "chrome/browser/prefs/pref_service.h" |
| 17 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
| 18 #include "chrome/common/pref_names.h" | 17 #include "chrome/common/pref_names.h" |
| 19 #include "chrome/common/url_constants.h" | 18 #include "chrome/common/url_constants.h" |
| 20 #include "content/browser/plugin_service.h" | 19 #include "googleurl/src/url_parse.h" |
| 21 #include "content/common/notification_source.h" | 20 #include "content/common/notification_source.h" |
| 22 #include "content/common/notification_type.h" | 21 #include "content/common/notification_type.h" |
| 23 #include "googleurl/src/url_util.h" | 22 #include "googleurl/src/url_util.h" |
| 24 #include "net/base/escape.h" | 23 #include "net/base/escape.h" |
| 25 #include "net/base/net_util.h" | 24 #include "net/base/net_util.h" |
| 26 | 25 |
| 27 using history::InMemoryURLIndex; | 26 using history::InMemoryURLIndex; |
| 28 using history::ScoredHistoryMatch; | 27 using history::ScoredHistoryMatch; |
| 29 using history::ScoredHistoryMatches; | 28 using history::ScoredHistoryMatches; |
| 30 | 29 |
| 31 HistoryQuickProvider::HistoryQuickProvider(ACProviderListener* listener, | 30 HistoryQuickProvider::HistoryQuickProvider(ACProviderListener* listener, |
| 32 Profile* profile) | 31 Profile* profile) |
| 33 : HistoryProvider(listener, profile, "HistoryQuickProvider"), | 32 : HistoryProvider(listener, profile, "HistoryQuickProvider"), |
| 34 trim_http_(false), | |
| 35 languages_(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)) {} | 33 languages_(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)) {} |
| 36 | 34 |
| 37 HistoryQuickProvider::~HistoryQuickProvider() {} | 35 HistoryQuickProvider::~HistoryQuickProvider() {} |
| 38 | 36 |
| 39 void HistoryQuickProvider::Start(const AutocompleteInput& input, | 37 void HistoryQuickProvider::Start(const AutocompleteInput& input, |
| 40 bool minimal_changes) { | 38 bool minimal_changes) { |
| 41 matches_.clear(); | 39 matches_.clear(); |
| 42 | 40 |
| 43 if ((input.type() == AutocompleteInput::INVALID) || | 41 if ((input.type() == AutocompleteInput::INVALID) || |
| 44 (input.type() == AutocompleteInput::FORCED_QUERY)) | 42 (input.type() == AutocompleteInput::FORCED_QUERY)) |
| 45 return; | 43 return; |
| 46 | 44 |
| 47 autocomplete_input_ = input; | 45 autocomplete_input_ = input; |
| 48 trim_http_ = !HasHTTPScheme(input.text()); | |
| 49 | 46 |
| 50 // Do some fixup on the user input before matching against it, so we provide | 47 // Do some fixup on the user input before matching against it, so we provide |
| 51 // good results for local file paths, input with spaces, etc. | 48 // good results for local file paths, input with spaces, etc. |
| 52 // NOTE: This purposefully doesn't take input.desired_tld() into account; if | 49 // NOTE: This purposefully doesn't take input.desired_tld() into account; if |
| 53 // it did, then holding "ctrl" would change all the results from the | 50 // it did, then holding "ctrl" would change all the results from the |
| 54 // HistoryQuickProvider provider, not just the What You Typed Result. | 51 // HistoryQuickProvider provider, not just the What You Typed Result. |
| 55 const string16 fixed_text(FixupUserInput(input)); | 52 const string16 fixed_text(FixupUserInput(input)); |
| 56 if (fixed_text.empty()) { | 53 if (fixed_text.empty()) { |
| 57 // Conceivably fixup could result in an empty string (although I don't | 54 // Conceivably fixup could result in an empty string (although I don't |
| 58 // have cases where this happens offhand). We can't do anything with | 55 // have cases where this happens offhand). We can't do anything with |
| (...skipping 14 matching lines...) Expand all Loading... |
| 73 // HistoryQuickProvider matches are currently not deletable. | 70 // HistoryQuickProvider matches are currently not deletable. |
| 74 // TODO(mrossetti): Determine when a match should be deletable. | 71 // TODO(mrossetti): Determine when a match should be deletable. |
| 75 void HistoryQuickProvider::DeleteMatch(const AutocompleteMatch& match) {} | 72 void HistoryQuickProvider::DeleteMatch(const AutocompleteMatch& match) {} |
| 76 | 73 |
| 77 void HistoryQuickProvider::DoAutocomplete() { | 74 void HistoryQuickProvider::DoAutocomplete() { |
| 78 // Get the matching URLs from the DB. | 75 // Get the matching URLs from the DB. |
| 79 string16 term_string = autocomplete_input_.text(); | 76 string16 term_string = autocomplete_input_.text(); |
| 80 term_string = UnescapeURLComponent(term_string, | 77 term_string = UnescapeURLComponent(term_string, |
| 81 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); | 78 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); |
| 82 history::InMemoryURLIndex::String16Vector terms( | 79 history::InMemoryURLIndex::String16Vector terms( |
| 83 HistoryQuickProvider::WordVectorFromString16(term_string)); | 80 InMemoryURLIndex::WordVectorFromString16(term_string, false)); |
| 84 ScoredHistoryMatches matches = GetIndex()->HistoryItemsForTerms(terms); | 81 ScoredHistoryMatches matches = GetIndex()->HistoryItemsForTerms(terms); |
| 82 if (matches.empty()) |
| 83 return; |
| 85 | 84 |
| 86 size_t match_num = matches.size() - 1; | 85 size_t match_num = matches.size() - 1; |
| 87 for (ScoredHistoryMatches::const_iterator match_iter = matches.begin(); | 86 for (ScoredHistoryMatches::const_iterator match_iter = matches.begin(); |
| 88 match_iter != matches.end(); ++match_iter, --match_num) { | 87 match_iter != matches.end(); ++match_iter, --match_num) { |
| 89 const ScoredHistoryMatch& history_match(*match_iter); | 88 const ScoredHistoryMatch& history_match(*match_iter); |
| 90 AutocompleteMatch ac_match = | 89 if (history_match.raw_score > 0) { |
| 91 QuickMatchToACMatch(history_match, NORMAL, match_num); | 90 AutocompleteMatch ac_match = |
| 92 matches_.push_back(ac_match); | 91 QuickMatchToACMatch(history_match, match_num); |
| 92 matches_.push_back(ac_match); |
| 93 } |
| 93 } | 94 } |
| 94 } | 95 } |
| 95 | 96 |
| 96 AutocompleteMatch HistoryQuickProvider::QuickMatchToACMatch( | 97 AutocompleteMatch HistoryQuickProvider::QuickMatchToACMatch( |
| 97 const ScoredHistoryMatch& history_match, | 98 const ScoredHistoryMatch& history_match, |
| 98 MatchType match_type, | |
| 99 size_t match_number) { | 99 size_t match_number) { |
| 100 const history::URLRow& info = history_match.url_info; | 100 const history::URLRow& info = history_match.url_info; |
| 101 int score = CalculateRelevance(history_match.raw_score, | 101 int score = CalculateRelevance(history_match.raw_score, |
| 102 autocomplete_input_.type(), | 102 autocomplete_input_.type(), |
| 103 match_type, match_number); | 103 NORMAL, match_number); |
| 104 AutocompleteMatch match(this, score, !!info.visit_count(), | 104 AutocompleteMatch match(this, score, !!info.visit_count(), |
| 105 AutocompleteMatch::HISTORY_URL); | 105 history_match.url_matches.empty() ? |
| 106 AutocompleteMatch::HISTORY_URL : |
| 107 AutocompleteMatch::HISTORY_TITLE); |
| 106 match.destination_url = info.url(); | 108 match.destination_url = info.url(); |
| 107 DCHECK(match.destination_url.is_valid()); | 109 DCHECK(match.destination_url.is_valid()); |
| 108 size_t inline_autocomplete_offset = | 110 size_t inline_autocomplete_offset = |
| 109 history_match.input_location + autocomplete_input_.text().length(); | 111 history_match.input_location + autocomplete_input_.text().length(); |
| 110 const net::FormatUrlTypes format_types = net::kFormatUrlOmitAll & | 112 const net::FormatUrlTypes format_types = net::kFormatUrlOmitAll; |
| 111 ~((trim_http_ && !history_match.match_in_scheme) ? | |
| 112 0 : net::kFormatUrlOmitHTTP); | |
| 113 std::string languages = | |
| 114 match_type == WHAT_YOU_TYPED ? std::string() : languages_; | |
| 115 match.fill_into_edit = | 113 match.fill_into_edit = |
| 116 AutocompleteInput::FormattedStringWithEquivalentMeaning(info.url(), | 114 AutocompleteInput::FormattedStringWithEquivalentMeaning(info.url(), |
| 117 net::FormatUrl(info.url(), languages, format_types, | 115 net::FormatUrl(info.url(), languages_, format_types, |
| 118 UnescapeRule::SPACES, NULL, NULL, | 116 UnescapeRule::SPACES, NULL, NULL, |
| 119 &inline_autocomplete_offset)); | 117 &inline_autocomplete_offset)); |
| 120 if (!autocomplete_input_.prevent_inline_autocomplete()) | 118 if (!autocomplete_input_.prevent_inline_autocomplete()) |
| 121 match.inline_autocomplete_offset = inline_autocomplete_offset; | 119 match.inline_autocomplete_offset = inline_autocomplete_offset; |
| 122 DCHECK((match.inline_autocomplete_offset == string16::npos) || | 120 DCHECK((match.inline_autocomplete_offset == string16::npos) || |
| 123 (match.inline_autocomplete_offset <= match.fill_into_edit.length())); | 121 (match.inline_autocomplete_offset <= match.fill_into_edit.length())); |
| 124 | 122 |
| 125 size_t match_start = history_match.input_location; | 123 // Format the URL autocomplete presentation. |
| 126 match.contents = net::FormatUrl(info.url(), languages, format_types, | 124 match.contents = net::FormatUrl(info.url(), languages_, format_types, |
| 127 UnescapeRule::SPACES, NULL, NULL, | 125 UnescapeRule::SPACES, NULL, NULL, NULL); |
| 128 &match_start); | 126 match.contents_class = SpansFromTermMatch(history_match.url_matches, |
| 129 if ((match_start != string16::npos) && | 127 match.contents.size(), 0); |
| 130 (inline_autocomplete_offset != string16::npos) && | 128 |
| 131 (inline_autocomplete_offset != match_start)) { | 129 // Format the description autocomplete presentation. |
| 132 DCHECK(inline_autocomplete_offset > match_start); | |
| 133 AutocompleteMatch::ClassifyLocationInString(match_start, | |
| 134 inline_autocomplete_offset - match_start, match.contents.length(), | |
| 135 ACMatchClassification::URL, &match.contents_class); | |
| 136 } else { | |
| 137 AutocompleteMatch::ClassifyLocationInString(string16::npos, 0, | |
| 138 match.contents.length(), ACMatchClassification::URL, | |
| 139 &match.contents_class); | |
| 140 } | |
| 141 match.description = info.title(); | 130 match.description = info.title(); |
| 142 AutocompleteMatch::ClassifyMatchInString(autocomplete_input_.text(), | 131 match.description_class = SpansFromTermMatch(history_match.title_matches, |
| 143 info.title(), | 132 match.description.size(), 0); |
| 144 ACMatchClassification::NONE, | |
| 145 &match.description_class); | |
| 146 | 133 |
| 147 return match; | 134 return match; |
| 148 } | 135 } |
| 149 | 136 |
| 150 history::InMemoryURLIndex* HistoryQuickProvider::GetIndex() { | 137 history::InMemoryURLIndex* HistoryQuickProvider::GetIndex() { |
| 151 if (index_for_testing_.get()) | 138 if (index_for_testing_.get()) |
| 152 return index_for_testing_.get(); | 139 return index_for_testing_.get(); |
| 153 | 140 |
| 154 HistoryService* const history_service = | 141 HistoryService* const history_service = |
| 155 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | 142 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); |
| 156 if (!history_service) | 143 if (!history_service) |
| 157 return NULL; | 144 return NULL; |
| 158 | 145 |
| 159 return history_service->InMemoryIndex(); | 146 return history_service->InMemoryIndex(); |
| 160 } | 147 } |
| 161 | 148 |
| 162 void HistoryQuickProvider::SetIndexForTesting( | 149 void HistoryQuickProvider::SetIndexForTesting( |
| 163 history::InMemoryURLIndex* index) { | 150 history::InMemoryURLIndex* index) { |
| 164 DCHECK(index); | 151 DCHECK(index); |
| 165 index_for_testing_.reset(index); | 152 index_for_testing_.reset(index); |
| 166 } | 153 } |
| 167 | 154 |
| 168 // Utility Functions | |
| 169 | |
| 170 history::InMemoryURLIndex::String16Vector | |
| 171 HistoryQuickProvider::WordVectorFromString16(const string16& uni_string) { | |
| 172 history::InMemoryURLIndex::String16Vector words; | |
| 173 base::BreakIterator iter(&uni_string, base::BreakIterator::BREAK_WORD); | |
| 174 if (iter.Init()) { | |
| 175 while (iter.Advance()) { | |
| 176 if (iter.IsWord()) | |
| 177 words.push_back(iter.GetString()); | |
| 178 } | |
| 179 } | |
| 180 return words; | |
| 181 } | |
| 182 | |
| 183 // static | 155 // static |
| 184 int HistoryQuickProvider::CalculateRelevance(int raw_score, | 156 int HistoryQuickProvider::CalculateRelevance(int raw_score, |
| 185 AutocompleteInput::Type input_type, | 157 AutocompleteInput::Type input_type, |
| 186 MatchType match_type, | 158 MatchType match_type, |
| 187 size_t match_number) { | 159 size_t match_number) { |
| 188 switch (match_type) { | 160 switch (match_type) { |
| 189 case INLINE_AUTOCOMPLETE: | 161 case INLINE_AUTOCOMPLETE: |
| 190 return 1400; | 162 return 1400; |
| 191 | 163 |
| 192 case WHAT_YOU_TYPED: | 164 case WHAT_YOU_TYPED: |
| 193 return 1200; | 165 return 1200; |
| 194 | 166 |
| 195 default: | 167 default: |
| 196 return 900 + static_cast<int>(match_number); | 168 return 900 + static_cast<int>(match_number); |
| 197 } | 169 } |
| 198 } | 170 } |
| 171 |
| 172 // static |
| 173 ACMatchClassifications HistoryQuickProvider::SpansFromTermMatch( |
| 174 const history::TermMatches& matches, |
| 175 size_t text_length, |
| 176 size_t adjust) { |
| 177 ACMatchClassifications spans; |
| 178 if (matches.empty()) { |
| 179 if (text_length) |
| 180 spans.push_back(ACMatchClassification(0, ACMatchClassification::DIM)); |
| 181 return spans; |
| 182 } |
| 183 if (matches[0].offset > adjust) |
| 184 spans.push_back(ACMatchClassification(0, ACMatchClassification::NONE)); |
| 185 size_t match_count = matches.size(); |
| 186 for (size_t i = 0; i < match_count;) { |
| 187 size_t offset = matches[i].offset - adjust; |
| 188 spans.push_back(ACMatchClassification(offset, |
| 189 ACMatchClassification::MATCH)); |
| 190 // Skip all adjacent matches. |
| 191 do { |
| 192 offset += matches[i].length; |
| 193 ++i; |
| 194 } while ((i < match_count) && (offset == matches[i].offset - adjust)); |
| 195 if (offset < text_length) { |
| 196 spans.push_back(ACMatchClassification(offset, |
| 197 ACMatchClassification::NONE)); |
| 198 } |
| 199 } |
| 200 |
| 201 return spans; |
| 202 } |
| OLD | NEW |