Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: chrome/browser/autocomplete/history_quick_provider.cc

Issue 6652008: Implemented substring matching within page titles. Fixed bug where URL was be... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/string_util.h" 9 #include "base/string_util.h"
10 #include "base/logging.h" 10 #include "base/logging.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/prefs/pref_service.h" 13 #include "chrome/browser/prefs/pref_service.h"
15 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/history/in_memory_url_index.h" 15 #include "chrome/browser/history/in_memory_url_index.h"
17 #include "chrome/browser/net/url_fixer_upper.h" 16 #include "chrome/browser/net/url_fixer_upper.h"
18 #include "chrome/common/notification_source.h" 17 #include "chrome/common/notification_source.h"
19 #include "chrome/common/notification_type.h" 18 #include "chrome/common/notification_type.h"
20 #include "chrome/common/pref_names.h" 19 #include "chrome/common/pref_names.h"
21 #include "chrome/common/url_constants.h" 20 #include "chrome/common/url_constants.h"
22 #include "content/browser/plugin_service.h" 21 #include "googleurl/src/url_parse.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
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 size_t prefix_end;
102 string16 unstripped_url = net::FormatUrl(info.url(), languages_,
103 net::kFormatUrlOmitNothing, UnescapeRule::SPACES, NULL, &prefix_end,
104 NULL);
105 size_t adjust = HasHTTPScheme(unstripped_url) ? prefix_end : 0;
106
101 int score = CalculateRelevance(history_match.raw_score, 107 int score = CalculateRelevance(history_match.raw_score,
102 autocomplete_input_.type(), 108 autocomplete_input_.type(),
103 match_type, match_number); 109 NORMAL, match_number);
104 AutocompleteMatch match(this, score, !!info.visit_count(), 110 AutocompleteMatch::Type match_type = history_match.url_matches.empty() ?
Peter Kasting 2011/03/09 02:31:48 Nit: Just inline this into the next expression.
mrossetti 2011/03/10 01:31:14 Done.
105 AutocompleteMatch::HISTORY_URL); 111 AutocompleteMatch::HISTORY_URL : AutocompleteMatch::HISTORY_TITLE;
112 AutocompleteMatch match(this, score, !!info.visit_count(), match_type);
106 match.destination_url = info.url(); 113 match.destination_url = info.url();
107 DCHECK(match.destination_url.is_valid()); 114 DCHECK(match.destination_url.is_valid());
108 size_t inline_autocomplete_offset = 115 size_t inline_autocomplete_offset =
109 history_match.input_location + autocomplete_input_.text().length(); 116 history_match.input_location + autocomplete_input_.text().length();
110 const net::FormatUrlTypes format_types = net::kFormatUrlOmitAll & 117 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 = 118 match.fill_into_edit =
116 AutocompleteInput::FormattedStringWithEquivalentMeaning(info.url(), 119 AutocompleteInput::FormattedStringWithEquivalentMeaning(info.url(),
117 net::FormatUrl(info.url(), languages, format_types, 120 net::FormatUrl(info.url(), languages_, format_types,
118 UnescapeRule::SPACES, NULL, NULL, 121 UnescapeRule::SPACES, NULL, NULL,
119 &inline_autocomplete_offset)); 122 &inline_autocomplete_offset));
120 if (!autocomplete_input_.prevent_inline_autocomplete()) 123 if (!autocomplete_input_.prevent_inline_autocomplete())
121 match.inline_autocomplete_offset = inline_autocomplete_offset; 124 match.inline_autocomplete_offset = inline_autocomplete_offset;
122 DCHECK((match.inline_autocomplete_offset == string16::npos) || 125 DCHECK((match.inline_autocomplete_offset == string16::npos) ||
123 (match.inline_autocomplete_offset <= match.fill_into_edit.length())); 126 (match.inline_autocomplete_offset <= match.fill_into_edit.length()));
124 127
125 size_t match_start = history_match.input_location; 128 // Format the URL autocomplete presentation.
126 match.contents = net::FormatUrl(info.url(), languages, format_types, 129 match.contents = net::FormatUrl(info.url(), languages_, format_types,
127 UnescapeRule::SPACES, NULL, NULL, 130 UnescapeRule::SPACES, NULL, NULL, NULL);
128 &match_start); 131 match.contents_class = SpansFromTermMatch(history_match.url_matches,
129 if ((match_start != string16::npos) && 132 match.contents.size(), adjust);
130 (inline_autocomplete_offset != string16::npos) && 133
131 (inline_autocomplete_offset != match_start)) { 134 // 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(); 135 match.description = info.title();
142 AutocompleteMatch::ClassifyMatchInString(autocomplete_input_.text(), 136 match.description_class = SpansFromTermMatch(history_match.title_matches,
143 info.title(), 137 match.description.size(), 0);
144 ACMatchClassification::NONE,
145 &match.description_class);
146 138
147 return match; 139 return match;
148 } 140 }
149 141
150 history::InMemoryURLIndex* HistoryQuickProvider::GetIndex() { 142 history::InMemoryURLIndex* HistoryQuickProvider::GetIndex() {
151 if (index_for_testing_.get()) 143 if (index_for_testing_.get())
152 return index_for_testing_.get(); 144 return index_for_testing_.get();
153 145
154 HistoryService* const history_service = 146 HistoryService* const history_service =
155 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); 147 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
156 if (!history_service) 148 if (!history_service)
157 return NULL; 149 return NULL;
158 150
159 return history_service->InMemoryIndex(); 151 return history_service->InMemoryIndex();
160 } 152 }
161 153
162 void HistoryQuickProvider::SetIndexForTesting( 154 void HistoryQuickProvider::SetIndexForTesting(
163 history::InMemoryURLIndex* index) { 155 history::InMemoryURLIndex* index) {
164 DCHECK(index); 156 DCHECK(index);
165 index_for_testing_.reset(index); 157 index_for_testing_.reset(index);
166 } 158 }
167 159
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 160 // static
184 int HistoryQuickProvider::CalculateRelevance(int raw_score, 161 int HistoryQuickProvider::CalculateRelevance(int raw_score,
185 AutocompleteInput::Type input_type, 162 AutocompleteInput::Type input_type,
186 MatchType match_type, 163 MatchType match_type,
187 size_t match_number) { 164 size_t match_number) {
188 switch (match_type) { 165 switch (match_type) {
189 case INLINE_AUTOCOMPLETE: 166 case INLINE_AUTOCOMPLETE:
190 return 1400; 167 return 1400;
191 168
192 case WHAT_YOU_TYPED: 169 case WHAT_YOU_TYPED:
193 return 1200; 170 return 1200;
194 171
195 default: 172 default:
196 return 900 + static_cast<int>(match_number); 173 return 900 + static_cast<int>(match_number);
197 } 174 }
198 } 175 }
176
177 // static
178 ACMatchClassifications HistoryQuickProvider::SpansFromTermMatch(
179 const history::TermMatches& matches, size_t text_length, size_t adjust) {
Peter Kasting 2011/03/09 02:31:48 Nit: One arg per line
mrossetti 2011/03/10 01:31:14 Yep, I reread the style guide and get it now.
180 ACMatchClassifications spans;
181 if (matches.empty()) {
182 if (text_length)
183 spans.push_back(ACMatchClassification(0, ACMatchClassification::NONE));
184 return spans;
185 }
186 if (matches[0].offset > adjust)
187 spans.push_back(ACMatchClassification(0, ACMatchClassification::NONE));
188 size_t match_count = matches.size();
189 for (size_t i = 0; i < match_count; ++i) {
190 size_t offset = matches[i].offset - adjust;
Peter Kasting 2011/03/09 02:31:48 It's not obvious from the surrounding code that |a
mrossetti 2011/03/10 01:31:14 Ah! Excellent catch! I've modified the scoring fun
Peter Kasting 2011/03/10 02:13:43 BTW, something you should know about scoring. Pre
191 spans.push_back(ACMatchClassification(offset,
192 ACMatchClassification::MATCH));
193 // Skip all adjacent matches.
194 offset += matches[i].length;
Peter Kasting 2011/03/09 02:31:48 Nit: Shorter: do { offset += matches[i]
mrossetti 2011/03/10 01:31:14 Sweet!
195 while ((i + 1 < match_count) && (offset == matches[i+1].offset - adjust)) {
196 ++i;
197 offset += matches[i].length;
198 }
199 if (offset < text_length) {
200 spans.push_back(ACMatchClassification(offset,
201 ACMatchClassification::NONE));
202 }
203 }
204
205 return spans;
206 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698