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

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

Issue 66073: Makes the omnibox show past searches and suggestions for keywords.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 8 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
« no previous file with comments | « chrome/browser/autocomplete/search_provider.h ('k') | chrome/browser/importer/importer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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/search_provider.h" 5 #include "chrome/browser/autocomplete/search_provider.h"
6 6
7 #include "base/message_loop.h" 7 #include "base/message_loop.h"
8 #include "base/string_util.h" 8 #include "base/string_util.h"
9 #include "chrome/browser/autocomplete/keyword_provider.h"
9 #include "chrome/browser/browser_process.h" 10 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/google_util.h" 11 #include "chrome/browser/google_util.h"
11 #include "chrome/browser/net/url_fixer_upper.h" 12 #include "chrome/browser/net/url_fixer_upper.h"
12 #include "chrome/browser/profile.h" 13 #include "chrome/browser/profile.h"
13 #include "chrome/browser/search_engines/template_url_model.h" 14 #include "chrome/browser/search_engines/template_url_model.h"
14 #include "chrome/common/json_value_serializer.h" 15 #include "chrome/common/json_value_serializer.h"
15 #include "chrome/common/l10n_util.h" 16 #include "chrome/common/l10n_util.h"
16 #include "chrome/common/pref_names.h" 17 #include "chrome/common/pref_names.h"
17 #include "chrome/common/pref_service.h" 18 #include "chrome/common/pref_service.h"
18 #include "chrome/common/url_constants.h" 19 #include "chrome/common/url_constants.h"
19 #include "googleurl/src/url_util.h" 20 #include "googleurl/src/url_util.h"
20 #include "grit/generated_resources.h" 21 #include "grit/generated_resources.h"
21 #include "net/base/escape.h" 22 #include "net/base/escape.h"
22 #include "net/http/http_response_headers.h" 23 #include "net/http/http_response_headers.h"
23 #include "net/url_request/url_request_status.h" 24 #include "net/url_request/url_request_status.h"
24 25
25 using base::Time; 26 using base::Time;
26 using base::TimeDelta; 27 using base::TimeDelta;
27 28
29 void SearchProvider::Providers::Set(const TemplateURL* default_provider,
30 const TemplateURL* keyword_provider) {
31 // TODO(pkasting): http://b/1162970 We shouldn't need to structure-copy
32 // this. Nor should we need |default_provider_| and |keyword_provider_|
33 // just to know whether the provider changed.
34 default_provider_ = default_provider;
35 if (default_provider)
36 cached_default_provider_ = *default_provider;
37 keyword_provider_ = keyword_provider;
38 if (keyword_provider)
39 cached_keyword_provider_ = *keyword_provider;
40 }
41
28 void SearchProvider::Start(const AutocompleteInput& input, 42 void SearchProvider::Start(const AutocompleteInput& input,
29 bool minimal_changes) { 43 bool minimal_changes) {
30 matches_.clear(); 44 matches_.clear();
31 45
32 // Can't return search/suggest results for bogus input or without a profile. 46 // Can't return search/suggest results for bogus input or without a profile.
33 if (!profile_ || (input.type() == AutocompleteInput::INVALID)) { 47 if (!profile_ || (input.type() == AutocompleteInput::INVALID)) {
34 Stop(); 48 Stop();
35 return; 49 return;
36 } 50 }
37 51
38 // Can't search without a default provider. 52 keyword_input_text_.clear();
39 const TemplateURL* const current_default_provider = 53 const TemplateURL* keyword_provider =
54 KeywordProvider::GetSubstitutingTemplateURLForInput(profile_, input,
55 &keyword_input_text_);
56 if (!TemplateURL::SupportsReplacement(keyword_provider) ||
57 keyword_input_text_.empty()) {
58 keyword_provider = NULL;
59 }
60
61 const TemplateURL* default_provider =
40 profile_->GetTemplateURLModel()->GetDefaultSearchProvider(); 62 profile_->GetTemplateURLModel()->GetDefaultSearchProvider();
41 // TODO(pkasting): http://b/1155786 Eventually we should not need all these 63 if (!TemplateURL::SupportsReplacement(default_provider))
42 // checks. 64 default_provider = NULL;
43 if (!current_default_provider || !current_default_provider->url() || 65
44 !current_default_provider->url()->SupportsReplacement()) { 66 if (keyword_provider == default_provider)
67 keyword_provider = NULL; // No use in querying the same provider twice.
68
69 if (!default_provider && !keyword_provider) {
70 // No valid providers.
45 Stop(); 71 Stop();
46 return; 72 return;
47 } 73 }
48 74
49 // If we're still running an old query but have since changed the query text 75 // If we're still running an old query but have since changed the query text
50 // or the default provider, abort the query. 76 // or the providers, abort the query.
51 if (!done_ && (!minimal_changes || 77 if (!done_ && (!minimal_changes ||
52 (last_default_provider_ != current_default_provider))) 78 !providers_.equals(default_provider, keyword_provider))) {
53 Stop(); 79 Stop();
80 }
54 81
55 // TODO(pkasting): http://b/1162970 We shouldn't need to structure-copy this. 82 providers_.Set(default_provider, keyword_provider);
56 // Nor should we need |last_default_provider_| just to know whether the
57 // provider changed.
58 default_provider_ = *current_default_provider;
59 last_default_provider_ = current_default_provider;
60 83
61 if (input.text().empty()) { 84 if (input.text().empty()) {
62 // User typed "?" alone. Give them a placeholder result indicating what 85 // User typed "?" alone. Give them a placeholder result indicating what
63 // this syntax does. 86 // this syntax does.
64 AutocompleteMatch match(this, 0, false, 87 if (default_provider) {
65 AutocompleteMatch::SEARCH_WHAT_YOU_TYPED); 88 AutocompleteMatch match(this, 0, false,
66 static const std::wstring kNoQueryInput( 89 AutocompleteMatch::SEARCH_WHAT_YOU_TYPED);
67 l10n_util::GetString(IDS_AUTOCOMPLETE_NO_QUERY)); 90 static const std::wstring kNoQueryInput(
68 match.contents.assign(l10n_util::GetStringF( 91 l10n_util::GetString(IDS_AUTOCOMPLETE_NO_QUERY));
69 IDS_AUTOCOMPLETE_SEARCH_CONTENTS, default_provider_.short_name(), 92 match.contents.assign(l10n_util::GetStringF(
70 kNoQueryInput)); 93 IDS_AUTOCOMPLETE_SEARCH_CONTENTS, default_provider->short_name(),
71 match.contents_class.push_back( 94 kNoQueryInput));
72 ACMatchClassification(0, ACMatchClassification::DIM)); 95 match.contents_class.push_back(
73 matches_.push_back(match); 96 ACMatchClassification(0, ACMatchClassification::DIM));
97 matches_.push_back(match);
98 }
74 Stop(); 99 Stop();
75 return; 100 return;
76 } 101 }
77 102
78 input_ = input; 103 input_ = input;
79 104
80 StartOrStopHistoryQuery(minimal_changes); 105 StartOrStopHistoryQuery(minimal_changes);
81 StartOrStopSuggestQuery(minimal_changes); 106 StartOrStopSuggestQuery(minimal_changes);
82 ConvertResultsToAutocompleteMatches(); 107 ConvertResultsToAutocompleteMatches();
83 } 108 }
84 109
85 void SearchProvider::Run() { 110 void SearchProvider::Run() {
86 // Start a new request with the current input. 111 // Start a new request with the current input.
87 DCHECK(!done_); 112 DCHECK(!done_);
88 const TemplateURLRef* const suggestions_url = 113 suggest_results_pending_ = 0;
89 default_provider_.suggestions_url(); 114 if (providers_.valid_suggest_for_keyword_provider()) {
90 DCHECK(suggestions_url->SupportsReplacement()); 115 suggest_results_pending_++;
91 fetcher_.reset(new URLFetcher(suggestions_url->ReplaceSearchTerms( 116 keyword_fetcher_.reset(
92 default_provider_, input_.text(), 117 CreateSuggestFetcher(providers_.keyword_provider(),
93 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()), 118 keyword_input_text_));
94 URLFetcher::GET, this)); 119 }
95 fetcher_->set_request_context(profile_->GetRequestContext()); 120 if (providers_.valid_suggest_for_default_provider()) {
96 fetcher_->Start(); 121 suggest_results_pending_++;
122 default_fetcher_.reset(
123 CreateSuggestFetcher(providers_.default_provider(), input_.text()));
124 }
125 // We should only get here if we have a suggest url for the keyword or default
126 // providers.
127 DCHECK(suggest_results_pending_ > 0);
97 } 128 }
98 129
99 void SearchProvider::Stop() { 130 void SearchProvider::Stop() {
100 StopHistory(); 131 StopHistory();
101 StopSuggest(); 132 StopSuggest();
102 done_ = true; 133 done_ = true;
103 } 134 }
104 135
105 void SearchProvider::OnURLFetchComplete(const URLFetcher* source, 136 void SearchProvider::OnURLFetchComplete(const URLFetcher* source,
106 const GURL& url, 137 const GURL& url,
107 const URLRequestStatus& status, 138 const URLRequestStatus& status,
108 int response_code, 139 int response_code,
109 const ResponseCookies& cookie, 140 const ResponseCookies& cookie,
110 const std::string& data) { 141 const std::string& data) {
111 DCHECK(!done_); 142 DCHECK(!done_);
112 suggest_results_pending_ = false; 143 suggest_results_pending_--;
113 suggest_results_.clear(); 144 DCHECK(suggest_results_pending_ >= 0); // Should never go negative.
114 navigation_results_.clear();
115 const net::HttpResponseHeaders* const response_headers = 145 const net::HttpResponseHeaders* const response_headers =
116 source->response_headers(); 146 source->response_headers();
117 std::string json_data(data); 147 std::string json_data(data);
118 // JSON is supposed to be UTF-8, but some suggest service providers send JSON 148 // JSON is supposed to be UTF-8, but some suggest service providers send JSON
119 // files in non-UTF-8 encodings. The actual encoding is usually specified in 149 // files in non-UTF-8 encodings. The actual encoding is usually specified in
120 // the Content-Type header field. 150 // the Content-Type header field.
121 if (response_headers) { 151 if (response_headers) {
122 std::string charset; 152 std::string charset;
123 if (response_headers->GetCharset(&charset)) { 153 if (response_headers->GetCharset(&charset)) {
124 std::wstring wide_data; 154 std::wstring wide_data;
125 // TODO(jungshik): Switch to CodePageToUTF8 after it's added. 155 // TODO(jungshik): Switch to CodePageToUTF8 after it's added.
126 if (CodepageToWide(data, charset.c_str(), 156 if (CodepageToWide(data, charset.c_str(),
127 OnStringUtilConversionError::FAIL, &wide_data)) 157 OnStringUtilConversionError::FAIL, &wide_data))
128 json_data = WideToUTF8(wide_data); 158 json_data = WideToUTF8(wide_data);
129 } 159 }
130 } 160 }
131 161
162 bool is_keyword_results = (source == keyword_fetcher_.get());
163 SuggestResults* suggest_results = is_keyword_results ?
164 &keyword_suggest_results_ : &default_suggest_results_;
165
132 if (status.is_success() && response_code == 200) { 166 if (status.is_success() && response_code == 200) {
133 JSONStringValueSerializer deserializer(json_data); 167 JSONStringValueSerializer deserializer(json_data);
134 deserializer.set_allow_trailing_comma(true); 168 deserializer.set_allow_trailing_comma(true);
135 scoped_ptr<Value> root_val(deserializer.Deserialize(NULL)); 169 scoped_ptr<Value> root_val(deserializer.Deserialize(NULL));
170 const std::wstring& input_text =
171 is_keyword_results ? keyword_input_text_ : input_.text();
136 have_suggest_results_ = 172 have_suggest_results_ =
137 root_val.get() && ParseSuggestResults(root_val.get()); 173 root_val.get() &&
174 ParseSuggestResults(root_val.get(), is_keyword_results, input_text,
175 suggest_results);
138 } 176 }
139 177
140 ConvertResultsToAutocompleteMatches(); 178 ConvertResultsToAutocompleteMatches();
141 listener_->OnProviderUpdate(!suggest_results_.empty()); 179 listener_->OnProviderUpdate(!suggest_results->empty());
142 } 180 }
143 181
144 void SearchProvider::StartOrStopHistoryQuery(bool minimal_changes) { 182 void SearchProvider::StartOrStopHistoryQuery(bool minimal_changes) {
145 // For the minimal_changes case, if we finished the previous query and still 183 // For the minimal_changes case, if we finished the previous query and still
146 // have its results, or are allowed to keep running it, just do that, rather 184 // have its results, or are allowed to keep running it, just do that, rather
147 // than starting a new query. 185 // than starting a new query.
148 if (minimal_changes && 186 if (minimal_changes &&
149 (have_history_results_ || (!done_ && !input_.synchronous_only()))) 187 (have_history_results_ || (!done_ && !input_.synchronous_only())))
150 return; 188 return;
151 189
152 // We can't keep running any previous query, so halt it. 190 // We can't keep running any previous query, so halt it.
153 StopHistory(); 191 StopHistory();
154 192
155 // We can't start a new query if we're only allowed synchronous results. 193 // We can't start a new query if we're only allowed synchronous results.
156 if (input_.synchronous_only()) 194 if (input_.synchronous_only())
157 return; 195 return;
158 196
159 // Start the history query. 197 // Request history for both the keyword and default provider.
160 HistoryService* const history_service = 198 if (providers_.valid_keyword_provider()) {
161 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); 199 ScheduleHistoryQuery(providers_.keyword_provider().id(),
162 history_service->GetMostRecentKeywordSearchTerms(default_provider_.id(), 200 keyword_input_text_);
163 input_.text(), static_cast<int>(max_matches()), 201 }
164 &history_request_consumer_, 202 if (providers_.valid_default_provider()) {
165 NewCallback(this, &SearchProvider::OnGotMostRecentKeywordSearchTerms)); 203 ScheduleHistoryQuery(providers_.default_provider().id(),
166 history_request_pending_ = true; 204 input_.text());
205 }
167 } 206 }
168 207
169 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { 208 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) {
170 // Don't send any queries to the server until some time has elapsed after 209 // Don't send any queries to the server until some time has elapsed after
171 // the last keypress, to avoid flooding the server with requests we are 210 // the last keypress, to avoid flooding the server with requests we are
172 // likely to end up throwing away anyway. 211 // likely to end up throwing away anyway.
173 static const int kQueryDelayMs = 200; 212 static const int kQueryDelayMs = 200;
174 213
175 if (!IsQuerySuitableForSuggest()) { 214 if (!IsQuerySuitableForSuggest()) {
176 StopSuggest(); 215 StopSuggest();
177 return; 216 return;
178 } 217 }
179 218
180 // For the minimal_changes case, if we finished the previous query and still 219 // For the minimal_changes case, if we finished the previous query and still
181 // have its results, or are allowed to keep running it, just do that, rather 220 // have its results, or are allowed to keep running it, just do that, rather
182 // than starting a new query. 221 // than starting a new query.
183 if (minimal_changes && 222 if (minimal_changes &&
184 (have_suggest_results_ || (!done_ && !input_.synchronous_only()))) 223 (have_suggest_results_ || (!done_ && !input_.synchronous_only())))
185 return; 224 return;
186 225
187 // We can't keep running any previous query, so halt it. 226 // We can't keep running any previous query, so halt it.
188 StopSuggest(); 227 StopSuggest();
189 228
190 // We can't start a new query if we're only allowed synchronous results. 229 // We can't start a new query if we're only allowed synchronous results.
191 if (input_.synchronous_only()) 230 if (input_.synchronous_only())
192 return; 231 return;
193 232
233 // We'll have at least one pending fetch. Set it to 1 now, but the value is
234 // correctly set in Run. As Run isn't invoked immediately we need to set this
235 // now, else we won't think we're waiting on results from the server when we
236 // really are.
237 suggest_results_pending_ = 1;
238
194 // Kick off a timer that will start the URL fetch if it completes before 239 // Kick off a timer that will start the URL fetch if it completes before
195 // the user types another character. 240 // the user types another character.
196 suggest_results_pending_ = true;
197
198 timer_.Stop();
199 timer_.Start(TimeDelta::FromMilliseconds(kQueryDelayMs), this, 241 timer_.Start(TimeDelta::FromMilliseconds(kQueryDelayMs), this,
200 &SearchProvider::Run); 242 &SearchProvider::Run);
201 } 243 }
202 244
203 bool SearchProvider::IsQuerySuitableForSuggest() const { 245 bool SearchProvider::IsQuerySuitableForSuggest() const {
204 // Don't run Suggest when off the record, the engine doesn't support it, or 246 // Don't run Suggest when off the record, the engine doesn't support it, or
205 // the user has disabled it. 247 // the user has disabled it.
206 if (profile_->IsOffTheRecord() || 248 if (profile_->IsOffTheRecord() ||
207 !default_provider_.suggestions_url() || 249 (!providers_.valid_suggest_for_keyword_provider() &&
250 !providers_.valid_suggest_for_default_provider()) ||
208 !profile_->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled)) 251 !profile_->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled))
209 return false; 252 return false;
210 253
211 // If the input type is URL, we take extra care so that private data in URL 254 // If the input type is URL, we take extra care so that private data in URL
212 // isn't sent to the server. 255 // isn't sent to the server.
213 if (input_.type() == AutocompleteInput::URL) { 256 if (input_.type() == AutocompleteInput::URL) {
214 // Don't query the server for URLs that aren't http/https/ftp. Sending 257 // Don't query the server for URLs that aren't http/https/ftp. Sending
215 // things like file: and data: is both a waste of time and a disclosure of 258 // things like file: and data: is both a waste of time and a disclosure of
216 // potentially private, local data. 259 // potentially private, local data.
217 if ((input_.scheme() != L"http") && (input_.scheme() != L"https") && 260 if ((input_.scheme() != L"http") && (input_.scheme() != L"https") &&
(...skipping 18 matching lines...) Expand all
236 if (input_.scheme() == L"https" && parts.path.is_nonempty()) 279 if (input_.scheme() == L"https" && parts.path.is_nonempty())
237 return false; 280 return false;
238 } 281 }
239 282
240 return true; 283 return true;
241 } 284 }
242 285
243 void SearchProvider::StopHistory() { 286 void SearchProvider::StopHistory() {
244 history_request_consumer_.CancelAllRequests(); 287 history_request_consumer_.CancelAllRequests();
245 history_request_pending_ = false; 288 history_request_pending_ = false;
246 history_results_.clear(); 289 keyword_history_results_.clear();
290 default_history_results_.clear();
247 have_history_results_ = false; 291 have_history_results_ = false;
248 } 292 }
249 293
250 void SearchProvider::StopSuggest() { 294 void SearchProvider::StopSuggest() {
251 suggest_results_pending_ = false; 295 suggest_results_pending_ = 0;
252 timer_.Stop(); 296 timer_.Stop();
253 fetcher_.reset(); // Stop any in-progress URL fetch. 297 // Stop any in-progress URL fetches.
254 suggest_results_.clear(); 298 keyword_fetcher_.reset();
299 default_fetcher_.reset();
300 keyword_suggest_results_.clear();
301 default_suggest_results_.clear();
302 keyword_navigation_results_.clear();
303 default_navigation_results_.clear();
255 have_suggest_results_ = false; 304 have_suggest_results_ = false;
256 } 305 }
257 306
307 void SearchProvider::ScheduleHistoryQuery(TemplateURL::IDType search_id,
308 const std::wstring& text) {
309 DCHECK(!text.empty());
310 HistoryService* const history_service =
311 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
312 HistoryService::Handle request_handle =
313 history_service->GetMostRecentKeywordSearchTerms(
314 search_id, text, static_cast<int>(max_matches()),
315 &history_request_consumer_,
316 NewCallback(this,
317 &SearchProvider::OnGotMostRecentKeywordSearchTerms));
318 history_request_consumer_.SetClientData(history_service, request_handle,
319 search_id);
320 history_request_pending_ = true;
321 }
322
258 void SearchProvider::OnGotMostRecentKeywordSearchTerms( 323 void SearchProvider::OnGotMostRecentKeywordSearchTerms(
259 CancelableRequestProvider::Handle handle, 324 CancelableRequestProvider::Handle handle,
260 HistoryResults* results) { 325 HistoryResults* results) {
261 history_request_pending_ = false; 326 HistoryService* history_service =
262 have_history_results_ = true; 327 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
263 history_results_ = *results; 328 DCHECK(history_service);
329 if (providers_.valid_keyword_provider() &&
330 (providers_.keyword_provider().id() ==
331 history_request_consumer_.GetClientData(history_service, handle))) {
332 keyword_history_results_ = *results;
333 } else {
334 default_history_results_ = *results;
335 }
264 ConvertResultsToAutocompleteMatches(); 336 ConvertResultsToAutocompleteMatches();
265 listener_->OnProviderUpdate(!history_results_.empty()); 337 listener_->OnProviderUpdate(!results->empty());
338
339 if (history_request_consumer_.PendingRequestCount() == 1) {
340 // Requests are removed AFTER the callback is invoked. If the count == 1,
341 // it means no more history requests are pending.
342 history_request_pending_ = false;
343 have_history_results_ = true;
344 }
266 } 345 }
267 346
268 bool SearchProvider::ParseSuggestResults(Value* root_val) { 347 URLFetcher* SearchProvider::CreateSuggestFetcher(const TemplateURL& provider,
348 const std::wstring& text) {
349 const TemplateURLRef* const suggestions_url = provider.suggestions_url();
350 DCHECK(suggestions_url->SupportsReplacement());
351 URLFetcher* fetcher = new URLFetcher(suggestions_url->ReplaceSearchTerms(
352 provider, text, TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()),
353 URLFetcher::GET, this);
354 fetcher->set_request_context(profile_->GetRequestContext());
355 fetcher->Start();
356 return fetcher;
357 }
358
359 bool SearchProvider::ParseSuggestResults(Value* root_val,
360 bool is_keyword,
361 const std::wstring& input_text,
362 SuggestResults* suggest_results) {
269 if (!root_val->IsType(Value::TYPE_LIST)) 363 if (!root_val->IsType(Value::TYPE_LIST))
270 return false; 364 return false;
271 ListValue* root_list = static_cast<ListValue*>(root_val); 365 ListValue* root_list = static_cast<ListValue*>(root_val);
272 366
273 Value* query_val; 367 Value* query_val;
274 std::wstring query_str; 368 std::wstring query_str;
275 Value* result_val; 369 Value* result_val;
276 if ((root_list->GetSize() < 2) || !root_list->Get(0, &query_val) || 370 if ((root_list->GetSize() < 2) || !root_list->Get(0, &query_val) ||
277 !query_val->GetAsString(&query_str) || (query_str != input_.text()) || 371 !query_val->GetAsString(&query_str) || (query_str != input_text) ||
278 !root_list->Get(1, &result_val) || !result_val->IsType(Value::TYPE_LIST)) 372 !root_list->Get(1, &result_val) || !result_val->IsType(Value::TYPE_LIST))
279 return false; 373 return false;
280 374
281 ListValue* description_list = NULL; 375 ListValue* description_list = NULL;
282 if (root_list->GetSize() > 2) { 376 if (root_list->GetSize() > 2) {
283 // 3rd element: Description list. 377 // 3rd element: Description list.
284 Value* description_val; 378 Value* description_val;
285 if (root_list->Get(2, &description_val) && 379 if (root_list->Get(2, &description_val) &&
286 description_val->IsType(Value::TYPE_LIST)) 380 description_val->IsType(Value::TYPE_LIST))
287 description_list = static_cast<ListValue*>(description_val); 381 description_list = static_cast<ListValue*>(description_val);
(...skipping 27 matching lines...) Expand all
315 if (!result_list->Get(i, &suggestion_val) || 409 if (!result_list->Get(i, &suggestion_val) ||
316 !suggestion_val->GetAsString(&suggestion_str)) 410 !suggestion_val->GetAsString(&suggestion_str))
317 return false; 411 return false;
318 412
319 Value* type_val; 413 Value* type_val;
320 std::wstring type_str; 414 std::wstring type_str;
321 if (type_list && type_list->Get(i, &type_val) && 415 if (type_list && type_list->Get(i, &type_val) &&
322 type_val->GetAsString(&type_str) && (type_str == L"NAVIGATION")) { 416 type_val->GetAsString(&type_str) && (type_str == L"NAVIGATION")) {
323 Value* site_val; 417 Value* site_val;
324 std::wstring site_name; 418 std::wstring site_name;
325 if ((navigation_results_.size() < max_matches()) && 419 NavigationResults& navigation_results =
420 is_keyword ? keyword_navigation_results_ :
421 default_navigation_results_;
422 if ((navigation_results.size() < max_matches()) &&
326 description_list && description_list->Get(i, &site_val) && 423 description_list && description_list->Get(i, &site_val) &&
327 site_val->IsType(Value::TYPE_STRING) && 424 site_val->IsType(Value::TYPE_STRING) &&
328 site_val->GetAsString(&site_name)) { 425 site_val->GetAsString(&site_name)) {
329 // We can't blindly trust the URL coming from the server to be valid. 426 // We can't blindly trust the URL coming from the server to be valid.
330 GURL result_url = 427 GURL result_url =
331 GURL(URLFixerUpper::FixupURL(WideToUTF8(suggestion_str), 428 GURL(URLFixerUpper::FixupURL(WideToUTF8(suggestion_str),
332 std::string())); 429 std::string()));
333 if (result_url.is_valid()) { 430 if (result_url.is_valid())
334 navigation_results_.push_back(NavigationResult(result_url, 431 navigation_results.push_back(NavigationResult(result_url, site_name));
335 site_name));
336 }
337 } 432 }
338 } else { 433 } else {
339 // TODO(kochi): Currently we treat a calculator result as a query, but it 434 // TODO(kochi): Currently we treat a calculator result as a query, but it
340 // is better to have better presentation for caluculator results. 435 // is better to have better presentation for caluculator results.
341 if (suggest_results_.size() < max_matches()) 436 if (suggest_results->size() < max_matches())
342 suggest_results_.push_back(suggestion_str); 437 suggest_results->push_back(suggestion_str);
343 } 438 }
344 } 439 }
345 440
346 return true; 441 return true;
347 } 442 }
348 443
349 void SearchProvider::ConvertResultsToAutocompleteMatches() { 444 void SearchProvider::ConvertResultsToAutocompleteMatches() {
350 // Convert all the results to matches and add them to a map, so we can keep 445 // Convert all the results to matches and add them to a map, so we can keep
351 // the most relevant match for each result. 446 // the most relevant match for each result.
352 MatchMap map; 447 MatchMap map;
353 const int did_not_accept_suggestion = suggest_results_.empty() ? 448 const Time no_time;
449 int did_not_accept_keyword_suggestion = keyword_suggest_results_.empty() ?
354 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : 450 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE :
355 TemplateURLRef::NO_SUGGESTION_CHOSEN; 451 TemplateURLRef::NO_SUGGESTION_CHOSEN;
356 const Time no_time; 452 // Keyword what you typed results are handled by the KeywordProvider.
357 AddMatchToMap(input_.text(), CalculateRelevanceForWhatYouTyped(),
358 AutocompleteMatch::SEARCH_WHAT_YOU_TYPED,
359 did_not_accept_suggestion, &map);
360 453
361 for (HistoryResults::const_iterator i(history_results_.begin()); 454 int did_not_accept_default_suggestion = default_suggest_results_.empty() ?
362 i != history_results_.end(); ++i) { 455 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE :
363 AddMatchToMap(i->term, CalculateRelevanceForHistory(i->time), 456 TemplateURLRef::NO_SUGGESTION_CHOSEN;
364 AutocompleteMatch::SEARCH_HISTORY, did_not_accept_suggestion, 457 if (providers_.valid_default_provider()) {
365 &map); 458 AddMatchToMap(input_.text(), CalculateRelevanceForWhatYouTyped(),
459 AutocompleteMatch::SEARCH_WHAT_YOU_TYPED,
460 did_not_accept_default_suggestion, false, &map);
366 } 461 }
367 462
368 for (size_t i = 0; i < suggest_results_.size(); ++i) { 463 AddHistoryResultsToMap(keyword_history_results_, true,
369 AddMatchToMap(suggest_results_[i], CalculateRelevanceForSuggestion(i), 464 did_not_accept_keyword_suggestion, &map);
370 AutocompleteMatch::SEARCH_SUGGEST, 465 AddHistoryResultsToMap(default_history_results_, false,
371 static_cast<int>(i), &map); 466 did_not_accept_default_suggestion, &map);
372 } 467
468 AddSuggestResultsToMap(keyword_suggest_results_, true,
469 did_not_accept_keyword_suggestion, &map);
470 AddSuggestResultsToMap(default_suggest_results_, false,
471 did_not_accept_default_suggestion, &map);
373 472
374 // Now add the most relevant matches from the map to |matches_|. 473 // Now add the most relevant matches from the map to |matches_|.
375 matches_.clear(); 474 matches_.clear();
376 for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i) 475 for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i)
377 matches_.push_back(i->second); 476 matches_.push_back(i->second);
378 477
379 if (!navigation_results_.empty()) { 478 AddNavigationResultsToMatches(keyword_navigation_results_, true);
380 // TODO(kochi): http://b/1170574 We add only one results for navigational 479 AddNavigationResultsToMatches(default_navigation_results_, false);
381 // suggestions. If we can get more useful information about the score,
382 // consider adding more results.
383 matches_.push_back(NavigationToMatch(navigation_results_.front(),
384 CalculateRelevanceForNavigation(0)));
385 }
386 480
387 const size_t max_total_matches = max_matches() + 1; // 1 for "what you typed" 481 const size_t max_total_matches = max_matches() + 1; // 1 for "what you typed"
388 std::partial_sort(matches_.begin(), 482 std::partial_sort(matches_.begin(),
389 matches_.begin() + std::min(max_total_matches, matches_.size()), 483 matches_.begin() + std::min(max_total_matches, matches_.size()),
390 matches_.end(), &AutocompleteMatch::MoreRelevant); 484 matches_.end(), &AutocompleteMatch::MoreRelevant);
391 if (matches_.size() > max_total_matches) 485 if (matches_.size() > max_total_matches)
392 matches_.erase(matches_.begin() + max_total_matches, matches_.end()); 486 matches_.erase(matches_.begin() + max_total_matches, matches_.end());
393 487
394 UpdateStarredStateOfMatches(); 488 UpdateStarredStateOfMatches();
395 489
396 // We're done when both asynchronous subcomponents have finished. We can't 490 // We're done when both asynchronous subcomponents have finished. We can't
397 // use CancelableRequestConsumer.HasPendingRequests() for history requests 491 // use CancelableRequestConsumer.HasPendingRequests() for history requests
398 // here. A pending request is not cleared until after the completion 492 // here. A pending request is not cleared until after the completion
399 // callback has returned, but we've reached here from inside that callback. 493 // callback has returned, but we've reached here from inside that callback.
400 // HasPendingRequests() would therefore return true, and if this is the last 494 // HasPendingRequests() would therefore return true, and if this is the last
401 // thing left to calculate for this query, we'll never mark the query "done". 495 // thing left to calculate for this query, we'll never mark the query "done".
402 done_ = !history_request_pending_ && 496 done_ = !history_request_pending_ && !suggest_results_pending_;
403 !suggest_results_pending_; 497 }
498
499 void SearchProvider::AddNavigationResultsToMatches(
500 const NavigationResults& navigation_results,
501 bool is_keyword) {
502 if (!navigation_results.empty()) {
503 // TODO(kochi): http://b/1170574 We add only one results for navigational
504 // suggestions. If we can get more useful information about the score,
505 // consider adding more results.
506 matches_.push_back(
507 NavigationToMatch(navigation_results.front(),
508 CalculateRelevanceForNavigation(0, is_keyword),
509 is_keyword));
510 }
511 }
512
513 void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results,
514 bool is_keyword,
515 int did_not_accept_suggestion,
516 MatchMap* map) {
517 for (HistoryResults::const_iterator i(results.begin()); i != results.end();
518 ++i) {
519 AddMatchToMap(i->term, CalculateRelevanceForHistory(i->time, is_keyword),
520 AutocompleteMatch::SEARCH_HISTORY, did_not_accept_suggestion,
521 is_keyword, map);
522 }
523 }
524
525 void SearchProvider::AddSuggestResultsToMap(
526 const SuggestResults& suggest_results,
527 bool is_keyword,
528 int did_not_accept_suggestion,
529 MatchMap* map) {
530 for (size_t i = 0; i < suggest_results.size(); ++i) {
531 AddMatchToMap(suggest_results[i],
532 CalculateRelevanceForSuggestion(suggest_results, i,
533 is_keyword),
534 AutocompleteMatch::SEARCH_SUGGEST,
535 static_cast<int>(i), is_keyword, map);
536 }
404 } 537 }
405 538
406 int SearchProvider::CalculateRelevanceForWhatYouTyped() const { 539 int SearchProvider::CalculateRelevanceForWhatYouTyped() const {
407 switch (input_.type()) { 540 switch (input_.type()) {
408 case AutocompleteInput::UNKNOWN: 541 case AutocompleteInput::UNKNOWN:
409 return 1300; 542 return providers_.valid_keyword_provider() ? 250 : 1300;
410 543
411 case AutocompleteInput::REQUESTED_URL: 544 case AutocompleteInput::REQUESTED_URL:
412 return 1200; 545 return providers_.valid_keyword_provider() ? 250 : 1200;
413 546
414 case AutocompleteInput::URL: 547 case AutocompleteInput::URL:
415 return 850; 548 return providers_.valid_keyword_provider() ? 250 : 850;
416 549
417 case AutocompleteInput::QUERY: 550 case AutocompleteInput::QUERY:
418 return 1300; 551 return providers_.valid_keyword_provider() ? 250 : 1300;
419 552
420 case AutocompleteInput::FORCED_QUERY: 553 case AutocompleteInput::FORCED_QUERY:
421 return 1500; 554 return providers_.valid_keyword_provider() ? 250 : 1500;
422 555
423 default: 556 default:
424 NOTREACHED(); 557 NOTREACHED();
425 return 0; 558 return 0;
426 } 559 }
427 } 560 }
428 561
429 int SearchProvider::CalculateRelevanceForHistory(const Time& time) const { 562 int SearchProvider::CalculateRelevanceForHistory(const Time& time,
563 bool is_keyword) const {
430 // The relevance of past searches falls off over time. This curve is chosen 564 // The relevance of past searches falls off over time. This curve is chosen
431 // so that the relevance of a search 15 minutes ago is discounted about 50 565 // so that the relevance of a search 15 minutes ago is discounted about 50
432 // points, while the relevance of a search two weeks ago is discounted about 566 // points, while the relevance of a search two weeks ago is discounted about
433 // 450 points. 567 // 450 points.
434 const double elapsed_time = std::max((Time::Now() - time).InSecondsF(), 0.); 568 const double elapsed_time = std::max((Time::Now() - time).InSecondsF(), 0.);
435 const int score_discount = static_cast<int>(6.5 * pow(elapsed_time, 0.3)); 569 const int score_discount = static_cast<int>(6.5 * pow(elapsed_time, 0.3));
436 570
437 // Don't let scores go below 0. Negative relevance scores are meaningful in 571 // Don't let scores go below 0. Negative relevance scores are meaningful in
438 // a different way. 572 // a different way.
439 int base_score; 573 int base_score;
574 bool is_primary = providers_.is_primary_provider(is_keyword);
440 switch (input_.type()) { 575 switch (input_.type()) {
441 case AutocompleteInput::UNKNOWN: 576 case AutocompleteInput::UNKNOWN:
442 case AutocompleteInput::REQUESTED_URL: 577 case AutocompleteInput::REQUESTED_URL:
443 base_score = 1050; 578 base_score = is_primary ? 1050 : 200;
444 break; 579 break;
445 580
446 case AutocompleteInput::URL: 581 case AutocompleteInput::URL:
447 base_score = 750; 582 base_score = is_primary ? 750 : 200;
448 break; 583 break;
449 584
450 case AutocompleteInput::QUERY: 585 case AutocompleteInput::QUERY:
451 case AutocompleteInput::FORCED_QUERY: 586 case AutocompleteInput::FORCED_QUERY:
452 base_score = 1250; 587 base_score = is_primary ? 1250 : 200;
453 break; 588 break;
454 589
455 default: 590 default:
456 NOTREACHED(); 591 NOTREACHED();
457 base_score = 0; 592 base_score = 0;
458 break; 593 break;
459 } 594 }
460 return std::max(0, base_score - score_discount); 595 return std::max(0, base_score - score_discount);
461 } 596 }
462 597
463 int SearchProvider::CalculateRelevanceForSuggestion( 598 int SearchProvider::CalculateRelevanceForSuggestion(
464 size_t suggestion_number) const { 599 const SuggestResults& suggest_results,
465 DCHECK(suggestion_number < suggest_results_.size()); 600 size_t suggestion_number,
601 bool is_keyword) const {
602 DCHECK(suggestion_number < suggest_results.size());
603 bool is_primary = providers_.is_primary_provider(is_keyword);
466 const int suggestion_value = 604 const int suggestion_value =
467 static_cast<int>(suggest_results_.size() - 1 - suggestion_number); 605 static_cast<int>(suggest_results.size() - 1 - suggestion_number);
468 switch (input_.type()) { 606 switch (input_.type()) {
469 case AutocompleteInput::UNKNOWN: 607 case AutocompleteInput::UNKNOWN:
470 case AutocompleteInput::REQUESTED_URL: 608 case AutocompleteInput::REQUESTED_URL:
471 return 600 + suggestion_value; 609 return suggestion_value + (is_primary ? 600 : 100);
472 610
473 case AutocompleteInput::URL: 611 case AutocompleteInput::URL:
474 return 300 + suggestion_value; 612 return suggestion_value + (is_primary ? 300 : 100);
475 613
476 case AutocompleteInput::QUERY: 614 case AutocompleteInput::QUERY:
477 case AutocompleteInput::FORCED_QUERY: 615 case AutocompleteInput::FORCED_QUERY:
478 return 800 + suggestion_value; 616 return suggestion_value + (is_primary ? 800 : 100);
479 617
480 default: 618 default:
481 NOTREACHED(); 619 NOTREACHED();
482 return 0; 620 return 0;
483 } 621 }
484 } 622 }
485 623
486 int SearchProvider::CalculateRelevanceForNavigation( 624 int SearchProvider::CalculateRelevanceForNavigation(
487 size_t suggestion_number) const { 625 size_t suggestion_number,
488 DCHECK(suggestion_number < navigation_results_.size()); 626 bool is_keyword) const {
627 DCHECK(
628 (is_keyword && suggestion_number < keyword_navigation_results_.size()) ||
629 (!is_keyword && suggestion_number < default_navigation_results_.size()));
489 // TODO(kochi): http://b/784900 Use relevance score from the NavSuggest 630 // TODO(kochi): http://b/784900 Use relevance score from the NavSuggest
490 // server if possible. 631 // server if possible.
632 bool is_primary = providers_.is_primary_provider(is_keyword);
491 switch (input_.type()) { 633 switch (input_.type()) {
492 case AutocompleteInput::QUERY: 634 case AutocompleteInput::QUERY:
493 case AutocompleteInput::FORCED_QUERY: 635 case AutocompleteInput::FORCED_QUERY:
494 return 1000 + static_cast<int>(suggestion_number); 636 return static_cast<int>(suggestion_number) + (is_primary ? 1000 : 150);
495 637
496 default: 638 default:
497 return 800 + static_cast<int>(suggestion_number); 639 return static_cast<int>(suggestion_number) + (is_primary ? 800 : 150);
498 } 640 }
499 } 641 }
500 642
501 void SearchProvider::AddMatchToMap(const std::wstring& query_string, 643 void SearchProvider::AddMatchToMap(const std::wstring& query_string,
502 int relevance, 644 int relevance,
503 AutocompleteMatch::Type type, 645 AutocompleteMatch::Type type,
504 int accepted_suggestion, 646 int accepted_suggestion,
647 bool is_keyword,
505 MatchMap* map) { 648 MatchMap* map) {
649 const std::wstring& input_text =
650 is_keyword ? keyword_input_text_ : input_.text();
506 AutocompleteMatch match(this, relevance, false, type); 651 AutocompleteMatch match(this, relevance, false, type);
507 std::vector<size_t> content_param_offsets; 652 std::vector<size_t> content_param_offsets;
653 const TemplateURL& provider = is_keyword ? providers_.keyword_provider() :
654 providers_.default_provider();
508 match.contents.assign(l10n_util::GetStringF(IDS_AUTOCOMPLETE_SEARCH_CONTENTS, 655 match.contents.assign(l10n_util::GetStringF(IDS_AUTOCOMPLETE_SEARCH_CONTENTS,
509 default_provider_.short_name(), 656 provider.short_name(),
510 query_string, 657 query_string,
511 &content_param_offsets)); 658 &content_param_offsets));
512 if (content_param_offsets.size() == 2) { 659 if (content_param_offsets.size() == 2) {
513 AutocompleteMatch::ClassifyLocationInString(content_param_offsets[1], 660 AutocompleteMatch::ClassifyLocationInString(content_param_offsets[1],
514 query_string.length(), 661 query_string.length(),
515 match.contents.length(), 662 match.contents.length(),
516 ACMatchClassification::NONE, 663 ACMatchClassification::NONE,
517 &match.contents_class); 664 &match.contents_class);
518 } else { 665 } else {
519 // |content_param_offsets| should only not be 2 if: 666 // |content_param_offsets| should only not be 2 if:
(...skipping 12 matching lines...) Expand all
532 // suggestion, non-Search results will suddenly appear. 679 // suggestion, non-Search results will suddenly appear.
533 size_t search_start = 0; 680 size_t search_start = 0;
534 if (input_.type() == AutocompleteInput::FORCED_QUERY) { 681 if (input_.type() == AutocompleteInput::FORCED_QUERY) {
535 match.fill_into_edit.assign(L"?"); 682 match.fill_into_edit.assign(L"?");
536 ++search_start; 683 ++search_start;
537 } 684 }
538 match.fill_into_edit.append(query_string); 685 match.fill_into_edit.append(query_string);
539 // NOTE: All Google suggestions currently start with the original input, but 686 // NOTE: All Google suggestions currently start with the original input, but
540 // not all Yahoo! suggestions do. 687 // not all Yahoo! suggestions do.
541 if (!input_.prevent_inline_autocomplete() && 688 if (!input_.prevent_inline_autocomplete() &&
542 !match.fill_into_edit.compare(search_start, input_.text().length(), 689 !match.fill_into_edit.compare(search_start, input_text.length(),
543 input_.text())) 690 input_text))
544 match.inline_autocomplete_offset = search_start + input_.text().length(); 691 match.inline_autocomplete_offset = search_start + input_text.length();
545 692
546 const TemplateURLRef* const search_url = default_provider_.url(); 693 const TemplateURLRef* const search_url = provider.url();
547 DCHECK(search_url->SupportsReplacement()); 694 DCHECK(search_url->SupportsReplacement());
548 match.destination_url = search_url->ReplaceSearchTerms(default_provider_, 695 match.destination_url = search_url->ReplaceSearchTerms(provider,
549 query_string, 696 query_string,
550 accepted_suggestion, 697 accepted_suggestion,
551 input_.text()); 698 input_text);
552 699
553 // Search results don't look like URLs. 700 // Search results don't look like URLs.
554 match.transition = PageTransition::GENERATED; 701 match.transition = PageTransition::GENERATED;
555 702
556 // Try to add |match| to |map|. If a match for |query_string| is already in 703 // Try to add |match| to |map|. If a match for |query_string| is already in
557 // |map|, replace it if |match| is more relevant. 704 // |map|, replace it if |match| is more relevant.
558 // NOTE: Keep this ToLower() call in sync with url_database.cc. 705 // NOTE: Keep this ToLower() call in sync with url_database.cc.
559 const std::pair<MatchMap::iterator, bool> i = map->insert( 706 const std::pair<MatchMap::iterator, bool> i = map->insert(
560 std::pair<std::wstring, AutocompleteMatch>( 707 std::pair<std::wstring, AutocompleteMatch>(
561 l10n_util::ToLower(query_string), match)); 708 l10n_util::ToLower(query_string), match));
562 // NOTE: We purposefully do a direct relevance comparison here instead of 709 // NOTE: We purposefully do a direct relevance comparison here instead of
563 // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added 710 // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added
564 // first" rather than "items alphabetically first" when the scores are equal. 711 // first" rather than "items alphabetically first" when the scores are equal.
565 // The only case this matters is when a user has results with the same score 712 // The only case this matters is when a user has results with the same score
566 // that differ only by capitalization; because the history system returns 713 // that differ only by capitalization; because the history system returns
567 // results sorted by recency, this means we'll pick the most recent such 714 // results sorted by recency, this means we'll pick the most recent such
568 // result even if the precision of our relevance score is too low to 715 // result even if the precision of our relevance score is too low to
569 // distinguish the two. 716 // distinguish the two.
570 if (!i.second && (match.relevance > i.first->second.relevance)) 717 if (!i.second && (match.relevance > i.first->second.relevance))
571 i.first->second = match; 718 i.first->second = match;
572 } 719 }
573 720
574 AutocompleteMatch SearchProvider::NavigationToMatch( 721 AutocompleteMatch SearchProvider::NavigationToMatch(
575 const NavigationResult& navigation, 722 const NavigationResult& navigation,
576 int relevance) { 723 int relevance,
724 bool is_keyword) {
725 const std::wstring& input_text =
726 is_keyword ? keyword_input_text_ : input_.text();
577 AutocompleteMatch match(this, relevance, false, 727 AutocompleteMatch match(this, relevance, false,
578 AutocompleteMatch::NAVSUGGEST); 728 AutocompleteMatch::NAVSUGGEST);
579 match.destination_url = navigation.url; 729 match.destination_url = navigation.url;
580 match.contents = StringForURLDisplay(navigation.url, true); 730 match.contents = StringForURLDisplay(navigation.url, true);
581 // TODO(kochi): Consider moving HistoryURLProvider::TrimHttpPrefix() to some 731 // TODO(kochi): Consider moving HistoryURLProvider::TrimHttpPrefix() to some
582 // public utility function. 732 // public utility function.
583 if (!url_util::FindAndCompareScheme(WideToUTF8(input_.text()), 733 if (!url_util::FindAndCompareScheme(WideToUTF8(input_text), "http", NULL))
584 "http", NULL))
585 TrimHttpPrefix(&match.contents); 734 TrimHttpPrefix(&match.contents);
586 AutocompleteMatch::ClassifyMatchInString(input_.text(), match.contents, 735 AutocompleteMatch::ClassifyMatchInString(input_text, match.contents,
587 ACMatchClassification::URL, 736 ACMatchClassification::URL,
588 &match.contents_class); 737 &match.contents_class);
589 738
590 match.description = navigation.site_name; 739 match.description = navigation.site_name;
591 AutocompleteMatch::ClassifyMatchInString(input_.text(), navigation.site_name, 740 AutocompleteMatch::ClassifyMatchInString(input_text, navigation.site_name,
592 ACMatchClassification::NONE, 741 ACMatchClassification::NONE,
593 &match.description_class); 742 &match.description_class);
594 743
595 // When the user forced a query, we need to make sure all the fill_into_edit 744 // When the user forced a query, we need to make sure all the fill_into_edit
596 // values preserve that property. Otherwise, if the user starts editing a 745 // values preserve that property. Otherwise, if the user starts editing a
597 // suggestion, non-Search results will suddenly appear. 746 // suggestion, non-Search results will suddenly appear.
598 if (input_.type() == AutocompleteInput::FORCED_QUERY) 747 if (input_.type() == AutocompleteInput::FORCED_QUERY)
599 match.fill_into_edit.assign(L"?"); 748 match.fill_into_edit.assign(L"?");
600 match.fill_into_edit.append(match.contents); 749 match.fill_into_edit.append(match.contents);
601 // TODO(pkasting): http://b/1112879 These should perhaps be 750 // TODO(pkasting): http://b/1112879 These should perhaps be
(...skipping 15 matching lines...) Expand all
617 const size_t after_slashes = std::min(url->length(), 766 const size_t after_slashes = std::min(url->length(),
618 static_cast<size_t>(scheme.end() + 3)); 767 static_cast<size_t>(scheme.end() + 3));
619 while ((prefix_len < after_slashes) && ((*url)[prefix_len] == L'/')) 768 while ((prefix_len < after_slashes) && ((*url)[prefix_len] == L'/'))
620 ++prefix_len; 769 ++prefix_len;
621 if (prefix_len == url->length()) 770 if (prefix_len == url->length())
622 url->clear(); 771 url->clear();
623 else 772 else
624 url->erase(url->begin(), url->begin() + prefix_len); 773 url->erase(url->begin(), url->begin() + prefix_len);
625 return prefix_len; 774 return prefix_len;
626 } 775 }
OLDNEW
« no previous file with comments | « chrome/browser/autocomplete/search_provider.h ('k') | chrome/browser/importer/importer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698