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/search_provider.h" | 5 #include "chrome/browser/autocomplete/search_provider.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 cached_keyword_provider_ = *keyword_provider; | 56 cached_keyword_provider_ = *keyword_provider; |
57 } | 57 } |
58 | 58 |
59 SearchProvider::SearchProvider(ACProviderListener* listener, Profile* profile) | 59 SearchProvider::SearchProvider(ACProviderListener* listener, Profile* profile) |
60 : AutocompleteProvider(listener, profile, "Search"), | 60 : AutocompleteProvider(listener, profile, "Search"), |
61 suggest_results_pending_(0), | 61 suggest_results_pending_(0), |
62 have_suggest_results_(false), | 62 have_suggest_results_(false), |
63 instant_finalized_(false) { | 63 instant_finalized_(false) { |
64 } | 64 } |
65 | 65 |
66 void SearchProvider::FinalizeInstantQuery(const std::wstring& input_text, | 66 void SearchProvider::FinalizeInstantQuery(const string16& input_text, |
67 const std::wstring& suggest_text) { | 67 const string16& suggest_text) { |
68 if (done_ || instant_finalized_) | 68 if (done_ || instant_finalized_) |
69 return; | 69 return; |
70 | 70 |
71 instant_finalized_ = true; | 71 instant_finalized_ = true; |
72 UpdateDone(); | 72 UpdateDone(); |
73 | 73 |
74 if (input_text.empty()) { | 74 if (input_text.empty()) { |
75 // We only need to update the listener if we're actually done. | 75 // We only need to update the listener if we're actually done. |
76 if (done_) | 76 if (done_) |
77 listener_->OnProviderUpdate(false); | 77 listener_->OnProviderUpdate(false); |
78 return; | 78 return; |
79 } | 79 } |
80 | 80 |
81 default_provider_suggest_text_ = suggest_text; | 81 default_provider_suggest_text_ = suggest_text; |
82 | 82 |
83 std::wstring adjusted_input_text(input_text); | 83 string16 adjusted_input_text(input_text); |
84 AutocompleteInput::RemoveForcedQueryStringIfNecessary(input_.type(), | 84 AutocompleteInput::RemoveForcedQueryStringIfNecessary(input_.type(), |
85 &adjusted_input_text); | 85 &adjusted_input_text); |
86 | 86 |
87 const std::wstring text = adjusted_input_text + suggest_text; | 87 const string16 text = adjusted_input_text + suggest_text; |
88 // Remove any matches that are identical to |text|. We don't use the | 88 // Remove any matches that are identical to |text|. We don't use the |
89 // destination_url for comparison as it varies depending upon the index passed | 89 // destination_url for comparison as it varies depending upon the index passed |
90 // to TemplateURL::ReplaceSearchTerms. | 90 // to TemplateURL::ReplaceSearchTerms. |
91 for (ACMatches::iterator i = matches_.begin(); i != matches_.end();) { | 91 for (ACMatches::iterator i = matches_.begin(); i != matches_.end();) { |
92 // Reset the description/description_class of all searches. We'll set the | 92 // Reset the description/description_class of all searches. We'll set the |
93 // description of the new first match in the call to | 93 // description of the new first match in the call to |
94 // UpdateFirstSearchMatchDescription() below. | 94 // UpdateFirstSearchMatchDescription() below. |
95 if ((i->type == AutocompleteMatch::SEARCH_HISTORY) || | 95 if ((i->type == AutocompleteMatch::SEARCH_HISTORY) || |
96 (i->type == AutocompleteMatch::SEARCH_SUGGEST) || | 96 (i->type == AutocompleteMatch::SEARCH_SUGGEST) || |
97 (i->type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED)) { | 97 (i->type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED)) { |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 } | 173 } |
174 | 174 |
175 providers_.Set(default_provider, keyword_provider); | 175 providers_.Set(default_provider, keyword_provider); |
176 | 176 |
177 if (input.text().empty()) { | 177 if (input.text().empty()) { |
178 // User typed "?" alone. Give them a placeholder result indicating what | 178 // User typed "?" alone. Give them a placeholder result indicating what |
179 // this syntax does. | 179 // this syntax does. |
180 if (default_provider) { | 180 if (default_provider) { |
181 AutocompleteMatch match; | 181 AutocompleteMatch match; |
182 match.provider = this; | 182 match.provider = this; |
183 match.contents.assign(UTF16ToWideHack( | 183 match.contents.assign(l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE)); |
184 l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE))); | |
185 match.contents_class.push_back( | 184 match.contents_class.push_back( |
186 ACMatchClassification(0, ACMatchClassification::NONE)); | 185 ACMatchClassification(0, ACMatchClassification::NONE)); |
187 matches_.push_back(match); | 186 matches_.push_back(match); |
188 UpdateFirstSearchMatchDescription(); | 187 UpdateFirstSearchMatchDescription(); |
189 } | 188 } |
190 Stop(); | 189 Stop(); |
191 return; | 190 return; |
192 } | 191 } |
193 | 192 |
194 input_ = input; | 193 input_ = input; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 DCHECK_GE(suggest_results_pending_, 0); // Should never go negative. | 236 DCHECK_GE(suggest_results_pending_, 0); // Should never go negative. |
238 const net::HttpResponseHeaders* const response_headers = | 237 const net::HttpResponseHeaders* const response_headers = |
239 source->response_headers(); | 238 source->response_headers(); |
240 std::string json_data(data); | 239 std::string json_data(data); |
241 // JSON is supposed to be UTF-8, but some suggest service providers send JSON | 240 // JSON is supposed to be UTF-8, but some suggest service providers send JSON |
242 // files in non-UTF-8 encodings. The actual encoding is usually specified in | 241 // files in non-UTF-8 encodings. The actual encoding is usually specified in |
243 // the Content-Type header field. | 242 // the Content-Type header field. |
244 if (response_headers) { | 243 if (response_headers) { |
245 std::string charset; | 244 std::string charset; |
246 if (response_headers->GetCharset(&charset)) { | 245 if (response_headers->GetCharset(&charset)) { |
247 std::wstring wide_data; | 246 string16 data_16; |
248 // TODO(jungshik): Switch to CodePageToUTF8 after it's added. | 247 // TODO(jungshik): Switch to CodePageToUTF8 after it's added. |
249 if (base::CodepageToWide(data, charset.c_str(), | 248 if (base::CodepageToUTF16(data, charset.c_str(), |
250 base::OnStringConversionError::FAIL, | 249 base::OnStringConversionError::FAIL, |
251 &wide_data)) | 250 &data_16)) |
252 json_data = WideToUTF8(wide_data); | 251 json_data = UTF16ToUTF8(data_16); |
253 } | 252 } |
254 } | 253 } |
255 | 254 |
256 bool is_keyword_results = (source == keyword_fetcher_.get()); | 255 bool is_keyword_results = (source == keyword_fetcher_.get()); |
257 SuggestResults* suggest_results = is_keyword_results ? | 256 SuggestResults* suggest_results = is_keyword_results ? |
258 &keyword_suggest_results_ : &default_suggest_results_; | 257 &keyword_suggest_results_ : &default_suggest_results_; |
259 | 258 |
260 if (status.is_success() && response_code == 200) { | 259 if (status.is_success() && response_code == 200) { |
261 JSONStringValueSerializer deserializer(json_data); | 260 JSONStringValueSerializer deserializer(json_data); |
262 deserializer.set_allow_trailing_comma(true); | 261 deserializer.set_allow_trailing_comma(true); |
263 scoped_ptr<Value> root_val(deserializer.Deserialize(NULL, NULL)); | 262 scoped_ptr<Value> root_val(deserializer.Deserialize(NULL, NULL)); |
264 const std::wstring& input_text = | 263 const string16& input_text = |
265 is_keyword_results ? keyword_input_text_ : input_.text(); | 264 is_keyword_results ? keyword_input_text_ : input_.text(); |
266 have_suggest_results_ = | 265 have_suggest_results_ = |
267 root_val.get() && | 266 root_val.get() && |
268 ParseSuggestResults(root_val.get(), is_keyword_results, input_text, | 267 ParseSuggestResults(root_val.get(), is_keyword_results, input_text, |
269 suggest_results); | 268 suggest_results); |
270 } | 269 } |
271 | 270 |
272 ConvertResultsToAutocompleteMatches(); | 271 ConvertResultsToAutocompleteMatches(); |
273 listener_->OnProviderUpdate(!suggest_results->empty()); | 272 listener_->OnProviderUpdate(!suggest_results->empty()); |
274 } | 273 } |
(...skipping 14 matching lines...) Expand all Loading... |
289 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | 288 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); |
290 history::URLDatabase* url_db = history_service ? | 289 history::URLDatabase* url_db = history_service ? |
291 history_service->InMemoryDatabase() : NULL; | 290 history_service->InMemoryDatabase() : NULL; |
292 if (!url_db) | 291 if (!url_db) |
293 return; | 292 return; |
294 | 293 |
295 // Request history for both the keyword and default provider. | 294 // Request history for both the keyword and default provider. |
296 if (providers_.valid_keyword_provider()) { | 295 if (providers_.valid_keyword_provider()) { |
297 url_db->GetMostRecentKeywordSearchTerms( | 296 url_db->GetMostRecentKeywordSearchTerms( |
298 providers_.keyword_provider().id(), | 297 providers_.keyword_provider().id(), |
299 WideToUTF16(keyword_input_text_), | 298 keyword_input_text_, |
300 static_cast<int>(kMaxMatches), | 299 static_cast<int>(kMaxMatches), |
301 &keyword_history_results_); | 300 &keyword_history_results_); |
302 } | 301 } |
303 if (providers_.valid_default_provider()) { | 302 if (providers_.valid_default_provider()) { |
304 url_db->GetMostRecentKeywordSearchTerms( | 303 url_db->GetMostRecentKeywordSearchTerms( |
305 providers_.default_provider().id(), | 304 providers_.default_provider().id(), |
306 WideToUTF16(input_.text()), | 305 input_.text(), |
307 static_cast<int>(kMaxMatches), | 306 static_cast<int>(kMaxMatches), |
308 &default_history_results_); | 307 &default_history_results_); |
309 } | 308 } |
310 } | 309 } |
311 | 310 |
312 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { | 311 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { |
313 // Don't send any queries to the server until some time has elapsed after | 312 // Don't send any queries to the server until some time has elapsed after |
314 // the last keypress, to avoid flooding the server with requests we are | 313 // the last keypress, to avoid flooding the server with requests we are |
315 // likely to end up throwing away anyway. | 314 // likely to end up throwing away anyway. |
316 static const int kQueryDelayMs = 200; | 315 static const int kQueryDelayMs = 200; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 // Next we check the scheme. If this is UNKNOWN/REQUESTED_URL/URL with a | 365 // Next we check the scheme. If this is UNKNOWN/REQUESTED_URL/URL with a |
367 // scheme that isn't http/https/ftp, we shouldn't send it. Sending things | 366 // scheme that isn't http/https/ftp, we shouldn't send it. Sending things |
368 // like file: and data: is both a waste of time and a disclosure of | 367 // like file: and data: is both a waste of time and a disclosure of |
369 // potentially private, local data. Other "schemes" may actually be | 368 // potentially private, local data. Other "schemes" may actually be |
370 // usernames, and we don't want to send passwords. If the scheme is OK, we | 369 // usernames, and we don't want to send passwords. If the scheme is OK, we |
371 // still need to check other cases below. If this is QUERY, then the presence | 370 // still need to check other cases below. If this is QUERY, then the presence |
372 // of these schemes means the user explicitly typed one, and thus this is | 371 // of these schemes means the user explicitly typed one, and thus this is |
373 // probably a URL that's being entered and happens to currently be invalid -- | 372 // probably a URL that's being entered and happens to currently be invalid -- |
374 // in which case we again want to run our checks below. Other QUERY cases are | 373 // in which case we again want to run our checks below. Other QUERY cases are |
375 // less likely to be URLs and thus we assume we're OK. | 374 // less likely to be URLs and thus we assume we're OK. |
376 if ((input_.scheme() != L"http") && (input_.scheme() != L"https") && | 375 if (!LowerCaseEqualsASCII(input_.scheme(), chrome::kHttpScheme) && |
377 (input_.scheme() != L"ftp")) | 376 !LowerCaseEqualsASCII(input_.scheme(), chrome::kHttpsScheme) && |
| 377 !LowerCaseEqualsASCII(input_.scheme(), chrome::kFtpScheme)) |
378 return (input_.type() == AutocompleteInput::QUERY); | 378 return (input_.type() == AutocompleteInput::QUERY); |
379 | 379 |
380 // Don't send URLs with usernames, queries or refs. Some of these are | 380 // Don't send URLs with usernames, queries or refs. Some of these are |
381 // private, and the Suggest server is unlikely to have any useful results | 381 // private, and the Suggest server is unlikely to have any useful results |
382 // for any of them. Also don't send URLs with ports, as we may initially | 382 // for any of them. Also don't send URLs with ports, as we may initially |
383 // think that a username + password is a host + port (and we don't want to | 383 // think that a username + password is a host + port (and we don't want to |
384 // send usernames/passwords), and even if the port really is a port, the | 384 // send usernames/passwords), and even if the port really is a port, the |
385 // server is once again unlikely to have and useful results. | 385 // server is once again unlikely to have and useful results. |
386 const url_parse::Parsed& parts = input_.parts(); | 386 const url_parse::Parsed& parts = input_.parts(); |
387 if (parts.username.is_nonempty() || parts.port.is_nonempty() || | 387 if (parts.username.is_nonempty() || parts.port.is_nonempty() || |
388 parts.query.is_nonempty() || parts.ref.is_nonempty()) | 388 parts.query.is_nonempty() || parts.ref.is_nonempty()) |
389 return false; | 389 return false; |
390 | 390 |
391 // Don't send anything for https except the hostname. Hostnames are OK | 391 // Don't send anything for https except the hostname. Hostnames are OK |
392 // because they are visible when the TCP connection is established, but the | 392 // because they are visible when the TCP connection is established, but the |
393 // specific path may reveal private information. | 393 // specific path may reveal private information. |
394 if ((input_.scheme() == L"https") && parts.path.is_nonempty()) | 394 if (LowerCaseEqualsASCII(input_.scheme(), chrome::kHttpsScheme) && |
| 395 parts.path.is_nonempty()) |
395 return false; | 396 return false; |
396 | 397 |
397 return true; | 398 return true; |
398 } | 399 } |
399 | 400 |
400 void SearchProvider::StopSuggest() { | 401 void SearchProvider::StopSuggest() { |
401 suggest_results_pending_ = 0; | 402 suggest_results_pending_ = 0; |
402 timer_.Stop(); | 403 timer_.Stop(); |
403 // Stop any in-progress URL fetches. | 404 // Stop any in-progress URL fetches. |
404 keyword_fetcher_.reset(); | 405 keyword_fetcher_.reset(); |
405 default_fetcher_.reset(); | 406 default_fetcher_.reset(); |
406 keyword_suggest_results_.clear(); | 407 keyword_suggest_results_.clear(); |
407 default_suggest_results_.clear(); | 408 default_suggest_results_.clear(); |
408 keyword_navigation_results_.clear(); | 409 keyword_navigation_results_.clear(); |
409 default_navigation_results_.clear(); | 410 default_navigation_results_.clear(); |
410 have_suggest_results_ = false; | 411 have_suggest_results_ = false; |
411 } | 412 } |
412 | 413 |
413 URLFetcher* SearchProvider::CreateSuggestFetcher(int id, | 414 URLFetcher* SearchProvider::CreateSuggestFetcher(int id, |
414 const TemplateURL& provider, | 415 const TemplateURL& provider, |
415 const std::wstring& text) { | 416 const string16& text) { |
416 const TemplateURLRef* const suggestions_url = provider.suggestions_url(); | 417 const TemplateURLRef* const suggestions_url = provider.suggestions_url(); |
417 DCHECK(suggestions_url->SupportsReplacement()); | 418 DCHECK(suggestions_url->SupportsReplacement()); |
418 URLFetcher* fetcher = URLFetcher::Create(id, | 419 URLFetcher* fetcher = URLFetcher::Create(id, |
419 GURL(suggestions_url->ReplaceSearchTerms( | 420 GURL(suggestions_url->ReplaceSearchTerms( |
420 provider, WideToUTF16Hack(text), | 421 provider, text, |
421 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16())), | 422 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16())), |
422 URLFetcher::GET, this); | 423 URLFetcher::GET, this); |
423 fetcher->set_request_context(profile_->GetRequestContext()); | 424 fetcher->set_request_context(profile_->GetRequestContext()); |
424 fetcher->Start(); | 425 fetcher->Start(); |
425 return fetcher; | 426 return fetcher; |
426 } | 427 } |
427 | 428 |
428 bool SearchProvider::ParseSuggestResults(Value* root_val, | 429 bool SearchProvider::ParseSuggestResults(Value* root_val, |
429 bool is_keyword, | 430 bool is_keyword, |
430 const std::wstring& input_text, | 431 const string16& input_text, |
431 SuggestResults* suggest_results) { | 432 SuggestResults* suggest_results) { |
432 if (!root_val->IsType(Value::TYPE_LIST)) | 433 if (!root_val->IsType(Value::TYPE_LIST)) |
433 return false; | 434 return false; |
434 ListValue* root_list = static_cast<ListValue*>(root_val); | 435 ListValue* root_list = static_cast<ListValue*>(root_val); |
435 | 436 |
436 Value* query_val; | 437 Value* query_val; |
437 string16 query_str; | 438 string16 query_str; |
438 Value* result_val; | 439 Value* result_val; |
439 if ((root_list->GetSize() < 2) || !root_list->Get(0, &query_val) || | 440 if ((root_list->GetSize() < 2) || !root_list->Get(0, &query_val) || |
440 !query_val->GetAsString(&query_str) || | 441 !query_val->GetAsString(&query_str) || |
441 (query_str != WideToUTF16Hack(input_text)) || | 442 (query_str != input_text) || |
442 !root_list->Get(1, &result_val) || !result_val->IsType(Value::TYPE_LIST)) | 443 !root_list->Get(1, &result_val) || !result_val->IsType(Value::TYPE_LIST)) |
443 return false; | 444 return false; |
444 | 445 |
445 ListValue* description_list = NULL; | 446 ListValue* description_list = NULL; |
446 if (root_list->GetSize() > 2) { | 447 if (root_list->GetSize() > 2) { |
447 // 3rd element: Description list. | 448 // 3rd element: Description list. |
448 Value* description_val; | 449 Value* description_val; |
449 if (root_list->Get(2, &description_val) && | 450 if (root_list->Get(2, &description_val) && |
450 description_val->IsType(Value::TYPE_LIST)) | 451 description_val->IsType(Value::TYPE_LIST)) |
451 description_list = static_cast<ListValue*>(description_val); | 452 description_list = static_cast<ListValue*>(description_val); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 is_keyword ? keyword_navigation_results_ : | 497 is_keyword ? keyword_navigation_results_ : |
497 default_navigation_results_; | 498 default_navigation_results_; |
498 if ((navigation_results.size() < kMaxMatches) && | 499 if ((navigation_results.size() < kMaxMatches) && |
499 description_list && description_list->Get(i, &site_val) && | 500 description_list && description_list->Get(i, &site_val) && |
500 site_val->IsType(Value::TYPE_STRING) && | 501 site_val->IsType(Value::TYPE_STRING) && |
501 site_val->GetAsString(&site_name)) { | 502 site_val->GetAsString(&site_name)) { |
502 // We can't blindly trust the URL coming from the server to be valid. | 503 // We can't blindly trust the URL coming from the server to be valid. |
503 GURL result_url(URLFixerUpper::FixupURL(UTF16ToUTF8(suggestion_str), | 504 GURL result_url(URLFixerUpper::FixupURL(UTF16ToUTF8(suggestion_str), |
504 std::string())); | 505 std::string())); |
505 if (result_url.is_valid()) { | 506 if (result_url.is_valid()) { |
506 navigation_results.push_back(NavigationResult(result_url, | 507 navigation_results.push_back(NavigationResult(result_url, site_name)); |
507 UTF16ToWideHack(site_name))); | |
508 } | 508 } |
509 } | 509 } |
510 } else { | 510 } else { |
511 // TODO(kochi): Currently we treat a calculator result as a query, but it | 511 // TODO(kochi): Currently we treat a calculator result as a query, but it |
512 // is better to have better presentation for caluculator results. | 512 // is better to have better presentation for caluculator results. |
513 if (suggest_results->size() < kMaxMatches) | 513 if (suggest_results->size() < kMaxMatches) |
514 suggest_results->push_back(UTF16ToWideHack(suggestion_str)); | 514 suggest_results->push_back(suggestion_str); |
515 } | 515 } |
516 } | 516 } |
517 | 517 |
518 return true; | 518 return true; |
519 } | 519 } |
520 | 520 |
521 void SearchProvider::ConvertResultsToAutocompleteMatches() { | 521 void SearchProvider::ConvertResultsToAutocompleteMatches() { |
522 // Convert all the results to matches and add them to a map, so we can keep | 522 // Convert all the results to matches and add them to a map, so we can keep |
523 // the most relevant match for each result. | 523 // the most relevant match for each result. |
524 MatchMap map; | 524 MatchMap map; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 // match having a relevance greater than the previous, but they might be | 605 // match having a relevance greater than the previous, but they might be |
606 // equal. If we didn't force the relevance to decrease and we ended up in a | 606 // equal. If we didn't force the relevance to decrease and we ended up in a |
607 // situation where the relevance was equal, then which was shown first would | 607 // situation where the relevance was equal, then which was shown first would |
608 // be random. | 608 // be random. |
609 // This uses >= to handle the case where 3 or more results have the same | 609 // This uses >= to handle the case where 3 or more results have the same |
610 // relevance. | 610 // relevance. |
611 int relevance = CalculateRelevanceForHistory(i->time, is_keyword); | 611 int relevance = CalculateRelevanceForHistory(i->time, is_keyword); |
612 if (i != results.begin() && relevance >= last_relevance) | 612 if (i != results.begin() && relevance >= last_relevance) |
613 relevance = last_relevance - 1; | 613 relevance = last_relevance - 1; |
614 last_relevance = relevance; | 614 last_relevance = relevance; |
615 AddMatchToMap(UTF16ToWide(i->term), | 615 AddMatchToMap(i->term, |
616 is_keyword ? keyword_input_text_ : input_.text(), | 616 is_keyword ? keyword_input_text_ : input_.text(), |
617 relevance, | 617 relevance, |
618 AutocompleteMatch::SEARCH_HISTORY, did_not_accept_suggestion, | 618 AutocompleteMatch::SEARCH_HISTORY, did_not_accept_suggestion, |
619 is_keyword, input_.initial_prevent_inline_autocomplete(), | 619 is_keyword, input_.initial_prevent_inline_autocomplete(), |
620 map); | 620 map); |
621 } | 621 } |
622 } | 622 } |
623 | 623 |
624 void SearchProvider::AddSuggestResultsToMap( | 624 void SearchProvider::AddSuggestResultsToMap( |
625 const SuggestResults& suggest_results, | 625 const SuggestResults& suggest_results, |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 int SearchProvider::CalculateRelevanceForNavigation(size_t num_results, | 710 int SearchProvider::CalculateRelevanceForNavigation(size_t num_results, |
711 size_t result_number, | 711 size_t result_number, |
712 bool is_keyword) const { | 712 bool is_keyword) const { |
713 DCHECK(result_number < num_results); | 713 DCHECK(result_number < num_results); |
714 // TODO(kochi): http://b/784900 Use relevance score from the NavSuggest | 714 // TODO(kochi): http://b/784900 Use relevance score from the NavSuggest |
715 // server if possible. | 715 // server if possible. |
716 return (providers_.is_primary_provider(is_keyword) ? 800 : 150) + | 716 return (providers_.is_primary_provider(is_keyword) ? 800 : 150) + |
717 static_cast<int>(num_results - 1 - result_number); | 717 static_cast<int>(num_results - 1 - result_number); |
718 } | 718 } |
719 | 719 |
720 void SearchProvider::AddMatchToMap(const std::wstring& query_string, | 720 void SearchProvider::AddMatchToMap(const string16& query_string, |
721 const std::wstring& input_text, | 721 const string16& input_text, |
722 int relevance, | 722 int relevance, |
723 AutocompleteMatch::Type type, | 723 AutocompleteMatch::Type type, |
724 int accepted_suggestion, | 724 int accepted_suggestion, |
725 bool is_keyword, | 725 bool is_keyword, |
726 bool prevent_inline_autocomplete, | 726 bool prevent_inline_autocomplete, |
727 MatchMap* map) { | 727 MatchMap* map) { |
728 AutocompleteMatch match(this, relevance, false, type); | 728 AutocompleteMatch match(this, relevance, false, type); |
729 std::vector<size_t> content_param_offsets; | 729 std::vector<size_t> content_param_offsets; |
730 const TemplateURL& provider = is_keyword ? providers_.keyword_provider() : | 730 const TemplateURL& provider = is_keyword ? providers_.keyword_provider() : |
731 providers_.default_provider(); | 731 providers_.default_provider(); |
732 match.contents.assign(query_string); | 732 match.contents.assign(query_string); |
733 // We do intra-string highlighting for suggestions - the suggested segment | 733 // We do intra-string highlighting for suggestions - the suggested segment |
734 // will be highlighted, e.g. for input_text = "you" the suggestion may be | 734 // will be highlighted, e.g. for input_text = "you" the suggestion may be |
735 // "youtube", so we'll bold the "tube" section: you*tube*. | 735 // "youtube", so we'll bold the "tube" section: you*tube*. |
736 if (input_text != query_string) { | 736 if (input_text != query_string) { |
737 size_t input_position = match.contents.find(input_text); | 737 size_t input_position = match.contents.find(input_text); |
738 if (input_position == std::wstring::npos) { | 738 if (input_position == string16::npos) { |
739 // The input text is not a substring of the query string, e.g. input | 739 // The input text is not a substring of the query string, e.g. input |
740 // text is "slasdot" and the query string is "slashdot", so we bold the | 740 // text is "slasdot" and the query string is "slashdot", so we bold the |
741 // whole thing. | 741 // whole thing. |
742 match.contents_class.push_back( | 742 match.contents_class.push_back( |
743 ACMatchClassification(0, ACMatchClassification::MATCH)); | 743 ACMatchClassification(0, ACMatchClassification::MATCH)); |
744 } else { | 744 } else { |
745 // TODO(beng): ACMatchClassification::MATCH now seems to just mean | 745 // TODO(beng): ACMatchClassification::MATCH now seems to just mean |
746 // "bold" this. Consider modifying the terminology. | 746 // "bold" this. Consider modifying the terminology. |
747 // We don't iterate over the string here annotating all matches because | 747 // We don't iterate over the string here annotating all matches because |
748 // it looks odd to have every occurrence of a substring that may be as | 748 // it looks odd to have every occurrence of a substring that may be as |
(...skipping 18 matching lines...) Expand all Loading... |
767 // completion. | 767 // completion. |
768 match.contents_class.push_back( | 768 match.contents_class.push_back( |
769 ACMatchClassification(0, ACMatchClassification::NONE)); | 769 ACMatchClassification(0, ACMatchClassification::NONE)); |
770 } | 770 } |
771 | 771 |
772 // When the user forced a query, we need to make sure all the fill_into_edit | 772 // When the user forced a query, we need to make sure all the fill_into_edit |
773 // values preserve that property. Otherwise, if the user starts editing a | 773 // values preserve that property. Otherwise, if the user starts editing a |
774 // suggestion, non-Search results will suddenly appear. | 774 // suggestion, non-Search results will suddenly appear. |
775 size_t search_start = 0; | 775 size_t search_start = 0; |
776 if (input_.type() == AutocompleteInput::FORCED_QUERY) { | 776 if (input_.type() == AutocompleteInput::FORCED_QUERY) { |
777 match.fill_into_edit.assign(L"?"); | 777 match.fill_into_edit.assign(ASCIIToUTF16("?")); |
778 ++search_start; | 778 ++search_start; |
779 } | 779 } |
780 if (is_keyword) { | 780 if (is_keyword) { |
781 match.fill_into_edit.append(UTF16ToWideHack( | 781 match.fill_into_edit.append( |
782 providers_.keyword_provider().keyword() + char16(' '))); | 782 providers_.keyword_provider().keyword() + char16(' ')); |
783 match.template_url = &providers_.keyword_provider(); | 783 match.template_url = &providers_.keyword_provider(); |
784 } | 784 } |
785 match.fill_into_edit.append(query_string); | 785 match.fill_into_edit.append(query_string); |
786 // Not all suggestions start with the original input. | 786 // Not all suggestions start with the original input. |
787 if (!prevent_inline_autocomplete && | 787 if (!prevent_inline_autocomplete && |
788 !match.fill_into_edit.compare(search_start, input_text.length(), | 788 !match.fill_into_edit.compare(search_start, input_text.length(), |
789 input_text)) | 789 input_text)) |
790 match.inline_autocomplete_offset = search_start + input_text.length(); | 790 match.inline_autocomplete_offset = search_start + input_text.length(); |
791 | 791 |
792 const TemplateURLRef* const search_url = provider.url(); | 792 const TemplateURLRef* const search_url = provider.url(); |
793 DCHECK(search_url->SupportsReplacement()); | 793 DCHECK(search_url->SupportsReplacement()); |
794 match.destination_url = | 794 match.destination_url = |
795 GURL(search_url->ReplaceSearchTerms(provider, | 795 GURL(search_url->ReplaceSearchTerms(provider, |
796 WideToUTF16Hack(query_string), | 796 query_string, |
797 accepted_suggestion, | 797 accepted_suggestion, |
798 WideToUTF16Hack(input_text))); | 798 input_text)); |
799 | 799 |
800 // Search results don't look like URLs. | 800 // Search results don't look like URLs. |
801 match.transition = | 801 match.transition = |
802 is_keyword ? PageTransition::KEYWORD : PageTransition::GENERATED; | 802 is_keyword ? PageTransition::KEYWORD : PageTransition::GENERATED; |
803 | 803 |
804 // Try to add |match| to |map|. If a match for |query_string| is already in | 804 // Try to add |match| to |map|. If a match for |query_string| is already in |
805 // |map|, replace it if |match| is more relevant. | 805 // |map|, replace it if |match| is more relevant. |
806 // NOTE: Keep this ToLower() call in sync with url_database.cc. | 806 // NOTE: Keep this ToLower() call in sync with url_database.cc. |
807 const std::pair<MatchMap::iterator, bool> i = map->insert( | 807 const std::pair<MatchMap::iterator, bool> i = map->insert( |
808 std::pair<std::wstring, AutocompleteMatch>( | 808 std::pair<string16, AutocompleteMatch>( |
809 UTF16ToWide(l10n_util::ToLower(WideToUTF16(query_string))), match)); | 809 l10n_util::ToLower(query_string), match)); |
810 // NOTE: We purposefully do a direct relevance comparison here instead of | 810 // NOTE: We purposefully do a direct relevance comparison here instead of |
811 // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added | 811 // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added |
812 // first" rather than "items alphabetically first" when the scores are equal. | 812 // first" rather than "items alphabetically first" when the scores are equal. |
813 // The only case this matters is when a user has results with the same score | 813 // The only case this matters is when a user has results with the same score |
814 // that differ only by capitalization; because the history system returns | 814 // that differ only by capitalization; because the history system returns |
815 // results sorted by recency, this means we'll pick the most recent such | 815 // results sorted by recency, this means we'll pick the most recent such |
816 // result even if the precision of our relevance score is too low to | 816 // result even if the precision of our relevance score is too low to |
817 // distinguish the two. | 817 // distinguish the two. |
818 if (!i.second && (match.relevance > i.first->second.relevance)) | 818 if (!i.second && (match.relevance > i.first->second.relevance)) |
819 i.first->second = match; | 819 i.first->second = match; |
820 } | 820 } |
821 | 821 |
822 AutocompleteMatch SearchProvider::NavigationToMatch( | 822 AutocompleteMatch SearchProvider::NavigationToMatch( |
823 const NavigationResult& navigation, | 823 const NavigationResult& navigation, |
824 int relevance, | 824 int relevance, |
825 bool is_keyword) { | 825 bool is_keyword) { |
826 const std::wstring& input_text = | 826 const string16& input_text = |
827 is_keyword ? keyword_input_text_ : input_.text(); | 827 is_keyword ? keyword_input_text_ : input_.text(); |
828 AutocompleteMatch match(this, relevance, false, | 828 AutocompleteMatch match(this, relevance, false, |
829 AutocompleteMatch::NAVSUGGEST); | 829 AutocompleteMatch::NAVSUGGEST); |
830 match.destination_url = navigation.url; | 830 match.destination_url = navigation.url; |
831 match.contents = | 831 match.contents = |
832 StringForURLDisplay(navigation.url, true, !HasHTTPScheme(input_text)); | 832 StringForURLDisplay(navigation.url, true, !HasHTTPScheme(input_text)); |
833 AutocompleteMatch::ClassifyMatchInString(input_text, match.contents, | 833 AutocompleteMatch::ClassifyMatchInString(input_text, match.contents, |
834 ACMatchClassification::URL, | 834 ACMatchClassification::URL, |
835 &match.contents_class); | 835 &match.contents_class); |
836 | 836 |
837 match.description = navigation.site_name; | 837 match.description = navigation.site_name; |
838 AutocompleteMatch::ClassifyMatchInString(input_text, navigation.site_name, | 838 AutocompleteMatch::ClassifyMatchInString(input_text, navigation.site_name, |
839 ACMatchClassification::NONE, | 839 ACMatchClassification::NONE, |
840 &match.description_class); | 840 &match.description_class); |
841 | 841 |
842 // When the user forced a query, we need to make sure all the fill_into_edit | 842 // When the user forced a query, we need to make sure all the fill_into_edit |
843 // values preserve that property. Otherwise, if the user starts editing a | 843 // values preserve that property. Otherwise, if the user starts editing a |
844 // suggestion, non-Search results will suddenly appear. | 844 // suggestion, non-Search results will suddenly appear. |
845 if (input_.type() == AutocompleteInput::FORCED_QUERY) | 845 if (input_.type() == AutocompleteInput::FORCED_QUERY) |
846 match.fill_into_edit.assign(L"?"); | 846 match.fill_into_edit.assign(ASCIIToUTF16("?")); |
847 match.fill_into_edit.append( | 847 match.fill_into_edit.append( |
848 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url, | 848 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url, |
849 match.contents)); | 849 match.contents)); |
850 // TODO(pkasting): http://b/1112879 These should perhaps be | 850 // TODO(pkasting): http://b/1112879 These should perhaps be |
851 // inline-autocompletable? | 851 // inline-autocompletable? |
852 | 852 |
853 return match; | 853 return match; |
854 } | 854 } |
855 | 855 |
856 void SearchProvider::UpdateDone() { | 856 void SearchProvider::UpdateDone() { |
857 // We're done when there are no more suggest queries pending (this is set to 1 | 857 // We're done when there are no more suggest queries pending (this is set to 1 |
858 // when the timer is started) and we're not waiting on instant. | 858 // when the timer is started) and we're not waiting on instant. |
859 done_ = ((suggest_results_pending_ == 0) && | 859 done_ = ((suggest_results_pending_ == 0) && |
860 (instant_finalized_ || !InstantController::IsEnabled(profile_))); | 860 (instant_finalized_ || !InstantController::IsEnabled(profile_))); |
861 } | 861 } |
862 | 862 |
863 void SearchProvider::UpdateFirstSearchMatchDescription() { | 863 void SearchProvider::UpdateFirstSearchMatchDescription() { |
864 if (!providers_.valid_default_provider() || matches_.empty()) | 864 if (!providers_.valid_default_provider() || matches_.empty()) |
865 return; | 865 return; |
866 | 866 |
867 for (ACMatches::iterator i = matches_.begin(); i != matches_.end(); ++i) { | 867 for (ACMatches::iterator i = matches_.begin(); i != matches_.end(); ++i) { |
868 AutocompleteMatch& match = *i; | 868 AutocompleteMatch& match = *i; |
869 switch (match.type) { | 869 switch (match.type) { |
870 case AutocompleteMatch::SEARCH_WHAT_YOU_TYPED: | 870 case AutocompleteMatch::SEARCH_WHAT_YOU_TYPED: |
871 case AutocompleteMatch::SEARCH_HISTORY: | 871 case AutocompleteMatch::SEARCH_HISTORY: |
872 case AutocompleteMatch::SEARCH_SUGGEST: | 872 case AutocompleteMatch::SEARCH_SUGGEST: |
873 match.description.assign( | 873 match.description.assign(l10n_util::GetStringFUTF16( |
874 UTF16ToWideHack(l10n_util::GetStringFUTF16( | 874 IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION, |
875 IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION, | 875 providers_.default_provider(). |
876 providers_.default_provider(). | 876 AdjustedShortNameForLocaleDirection())); |
877 AdjustedShortNameForLocaleDirection()))); | |
878 match.description_class.push_back( | 877 match.description_class.push_back( |
879 ACMatchClassification(0, ACMatchClassification::DIM)); | 878 ACMatchClassification(0, ACMatchClassification::DIM)); |
880 // Only the first search match gets a description. | 879 // Only the first search match gets a description. |
881 return; | 880 return; |
882 | 881 |
883 default: | 882 default: |
884 break; | 883 break; |
885 } | 884 } |
886 } | 885 } |
887 } | 886 } |
OLD | NEW |