Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/autocomplete/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/auto_reset.h" | 10 #include "base/auto_reset.h" |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 213 | 213 |
| 214 void SearchProvider::ClearInstantSuggestion() { | 214 void SearchProvider::ClearInstantSuggestion() { |
| 215 default_provider_suggestion_ = InstantSuggestion(); | 215 default_provider_suggestion_ = InstantSuggestion(); |
| 216 if (done_ || instant_finalized_) | 216 if (done_ || instant_finalized_) |
| 217 return; | 217 return; |
| 218 instant_finalized_ = true; | 218 instant_finalized_ = true; |
| 219 UpdateMatches(); | 219 UpdateMatches(); |
| 220 listener_->OnProviderUpdate(true); | 220 listener_->OnProviderUpdate(true); |
| 221 } | 221 } |
| 222 | 222 |
| 223 bool SearchProvider::GetSearchWhatYouTypedMatch(const string16& query, | |
| 224 const string16& original_query, | |
| 225 int relevance, | |
| 226 int accepted_suggestion, | |
| 227 bool is_keyword, | |
| 228 AutocompleteMatch* match) { | |
| 229 // Bail out now if we don't actually have a valid provider. | |
| 230 match->keyword = is_keyword ? providers_.keyword_provider() : | |
|
Peter Kasting
2013/04/12 00:29:01
Nit: Wrap this like the old code (break after '?'
sreeram
2013/04/12 22:36:18
Done.
| |
| 231 providers_.default_provider(); | |
| 232 const TemplateURL* provider_url = match->GetTemplateURL(profile_, false); | |
| 233 if (provider_url == NULL) | |
| 234 return false; | |
| 235 | |
| 236 match->provider = this; | |
| 237 match->relevance = relevance; | |
| 238 match->contents = query; | |
| 239 // We're dealing with the "default search" result which has no completion. | |
| 240 match->contents_class.push_back( | |
| 241 ACMatchClassification(0, ACMatchClassification::NONE)); | |
| 242 | |
| 243 if (is_keyword) { | |
| 244 match->fill_into_edit = match->keyword + char16(' ') + query; | |
| 245 match->transition = content::PAGE_TRANSITION_KEYWORD; | |
| 246 match->type = AutocompleteMatch::SEARCH_OTHER_ENGINE; | |
| 247 } else { | |
| 248 match->fill_into_edit = query; | |
| 249 match->transition = content::PAGE_TRANSITION_GENERATED; | |
| 250 match->type = AutocompleteMatch::SEARCH_WHAT_YOU_TYPED; | |
| 251 } | |
| 252 | |
| 253 const TemplateURLRef& search_url = provider_url->url_ref(); | |
| 254 DCHECK(search_url.SupportsReplacement()); | |
| 255 | |
| 256 match->search_terms_args.reset(new TemplateURLRef::SearchTermsArgs(query)); | |
| 257 match->search_terms_args->original_query = original_query; | |
| 258 match->search_terms_args->accepted_suggestion = accepted_suggestion; | |
| 259 | |
| 260 // This is the destination URL sans assisted query stats. This must be set so | |
| 261 // the AutocompleteController can properly de-dupe; the controller will | |
| 262 // eventually overwrite it before it reaches the user. | |
| 263 match->destination_url = | |
| 264 GURL(search_url.ReplaceSearchTerms(*match->search_terms_args.get())); | |
| 265 | |
| 266 return true; | |
| 267 } | |
| 268 | |
| 223 void SearchProvider::Start(const AutocompleteInput& input, | 269 void SearchProvider::Start(const AutocompleteInput& input, |
| 224 bool minimal_changes) { | 270 bool minimal_changes) { |
| 225 // Do our best to load the model as early as possible. This will reduce | 271 // Do our best to load the model as early as possible. This will reduce |
| 226 // odds of having the model not ready when really needed (a non-empty input). | 272 // odds of having the model not ready when really needed (a non-empty input). |
| 227 TemplateURLService* model = providers_.template_url_service(); | 273 TemplateURLService* model = providers_.template_url_service(); |
| 228 DCHECK(model); | 274 DCHECK(model); |
| 229 model->Load(); | 275 model->Load(); |
| 230 | 276 |
| 231 matches_.clear(); | 277 matches_.clear(); |
| 232 field_trial_triggered_ = false; | 278 field_trial_triggered_ = false; |
| (...skipping 1085 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1318 return std::max(0, base_score - score_discount); | 1364 return std::max(0, base_score - score_discount); |
| 1319 } | 1365 } |
| 1320 | 1366 |
| 1321 void SearchProvider::AddMatchToMap(const string16& query_string, | 1367 void SearchProvider::AddMatchToMap(const string16& query_string, |
| 1322 const string16& input_text, | 1368 const string16& input_text, |
| 1323 int relevance, | 1369 int relevance, |
| 1324 AutocompleteMatch::Type type, | 1370 AutocompleteMatch::Type type, |
| 1325 int accepted_suggestion, | 1371 int accepted_suggestion, |
| 1326 bool is_keyword, | 1372 bool is_keyword, |
| 1327 MatchMap* map) { | 1373 MatchMap* map) { |
| 1328 AutocompleteMatch match(this, relevance, false, type); | 1374 AutocompleteMatch match; |
| 1329 std::vector<size_t> content_param_offsets; | 1375 // We start with a "what you typed" match (even if it's not the correct type) |
| 1330 // Bail out now if we don't actually have a valid provider. | 1376 // so that we get the benefit of common fields being filled in. We override |
| 1331 match.keyword = is_keyword ? | 1377 // fields below if the "what you typed" values for them are inappropriate. |
| 1332 providers_.keyword_provider() : providers_.default_provider(); | 1378 if (!GetSearchWhatYouTypedMatch(query_string, input_text, relevance, |
| 1333 const TemplateURL* provider_url = match.GetTemplateURL(profile_, false); | 1379 accepted_suggestion, is_keyword, &match)) |
| 1334 if (provider_url == NULL) | |
| 1335 return; | 1380 return; |
| 1336 | 1381 |
| 1337 match.contents.assign(query_string); | 1382 match.type = type; |
|
Peter Kasting
2013/04/12 00:29:01
Can we eliminate this, or the fill_into_edit mucki
sreeram
2013/04/12 22:36:18
I don't think it makes sense for "SuggestExactInpu
Peter Kasting
2013/04/12 22:50:59
Hmm. Maybe I shouldn't have been so hasty to sugg
| |
| 1383 | |
| 1338 // We do intra-string highlighting for suggestions - the suggested segment | 1384 // We do intra-string highlighting for suggestions - the suggested segment |
| 1339 // will be highlighted, e.g. for input_text = "you" the suggestion may be | 1385 // will be highlighted, e.g. for input_text = "you" the suggestion may be |
| 1340 // "youtube", so we'll bold the "tube" section: you*tube*. | 1386 // "youtube", so we'll bold the "tube" section: you*tube*. |
| 1341 if (input_text != query_string) { | 1387 if (input_text != query_string) { |
| 1388 match.contents_class.clear(); | |
| 1342 size_t input_position = match.contents.find(input_text); | 1389 size_t input_position = match.contents.find(input_text); |
| 1343 if (input_position == string16::npos) { | 1390 if (input_position == string16::npos) { |
| 1344 // The input text is not a substring of the query string, e.g. input | 1391 // The input text is not a substring of the query string, e.g. input |
| 1345 // text is "slasdot" and the query string is "slashdot", so we bold the | 1392 // text is "slasdot" and the query string is "slashdot", so we bold the |
| 1346 // whole thing. | 1393 // whole thing. |
| 1347 match.contents_class.push_back( | 1394 match.contents_class.push_back( |
| 1348 ACMatchClassification(0, ACMatchClassification::MATCH)); | 1395 ACMatchClassification(0, ACMatchClassification::MATCH)); |
| 1349 } else { | 1396 } else { |
| 1350 // TODO(beng): ACMatchClassification::MATCH now seems to just mean | 1397 // TODO(beng): ACMatchClassification::MATCH now seems to just mean |
| 1351 // "bold" this. Consider modifying the terminology. | 1398 // "bold" this. Consider modifying the terminology. |
| 1352 // We don't iterate over the string here annotating all matches because | 1399 // We don't iterate over the string here annotating all matches because |
| 1353 // it looks odd to have every occurrence of a substring that may be as | 1400 // it looks odd to have every occurrence of a substring that may be as |
| 1354 // short as a single character highlighted in a query suggestion result, | 1401 // short as a single character highlighted in a query suggestion result, |
| 1355 // e.g. for input text "s" and query string "southwest airlines", it | 1402 // e.g. for input text "s" and query string "southwest airlines", it |
| 1356 // looks odd if both the first and last s are highlighted. | 1403 // looks odd if both the first and last s are highlighted. |
| 1357 if (input_position != 0) { | 1404 if (input_position != 0) { |
| 1358 match.contents_class.push_back( | 1405 match.contents_class.push_back( |
| 1359 ACMatchClassification(0, ACMatchClassification::NONE)); | 1406 ACMatchClassification(0, ACMatchClassification::NONE)); |
| 1360 } | 1407 } |
| 1361 match.contents_class.push_back( | 1408 match.contents_class.push_back( |
| 1362 ACMatchClassification(input_position, ACMatchClassification::DIM)); | 1409 ACMatchClassification(input_position, ACMatchClassification::DIM)); |
| 1363 size_t next_fragment_position = input_position + input_text.length(); | 1410 size_t next_fragment_position = input_position + input_text.length(); |
| 1364 if (next_fragment_position < query_string.length()) { | 1411 if (next_fragment_position < query_string.length()) { |
| 1365 match.contents_class.push_back( | 1412 match.contents_class.push_back( |
| 1366 ACMatchClassification(next_fragment_position, | 1413 ACMatchClassification(next_fragment_position, |
| 1367 ACMatchClassification::NONE)); | 1414 ACMatchClassification::NONE)); |
| 1368 } | 1415 } |
| 1369 } | 1416 } |
| 1370 } else { | |
| 1371 // Otherwise, we're dealing with the "default search" result which has no | |
| 1372 // completion. | |
| 1373 match.contents_class.push_back( | |
| 1374 ACMatchClassification(0, ACMatchClassification::NONE)); | |
| 1375 } | 1417 } |
| 1376 | 1418 |
| 1377 // When the user forced a query, we need to make sure all the fill_into_edit | 1419 // When the user forced a query, we need to make sure all the fill_into_edit |
| 1378 // values preserve that property. Otherwise, if the user starts editing a | 1420 // values preserve that property. Otherwise, if the user starts editing a |
| 1379 // suggestion, non-Search results will suddenly appear. | 1421 // suggestion, non-Search results will suddenly appear. |
| 1422 match.fill_into_edit.clear(); | |
| 1380 if (input_.type() == AutocompleteInput::FORCED_QUERY) | 1423 if (input_.type() == AutocompleteInput::FORCED_QUERY) |
| 1381 match.fill_into_edit.assign(ASCIIToUTF16("?")); | 1424 match.fill_into_edit.assign(ASCIIToUTF16("?")); |
| 1382 if (is_keyword) | 1425 if (is_keyword) |
| 1383 match.fill_into_edit.append(match.keyword + char16(' ')); | 1426 match.fill_into_edit.append(match.keyword + char16(' ')); |
| 1384 if (!input_.prevent_inline_autocomplete() && | 1427 if (!input_.prevent_inline_autocomplete() && |
| 1385 StartsWith(query_string, input_text, false)) { | 1428 StartsWith(query_string, input_text, false)) { |
| 1386 match.inline_autocomplete_offset = | 1429 match.inline_autocomplete_offset = |
| 1387 match.fill_into_edit.length() + input_text.length(); | 1430 match.fill_into_edit.length() + input_text.length(); |
| 1388 } | 1431 } |
| 1389 match.fill_into_edit.append(query_string); | 1432 match.fill_into_edit.append(query_string); |
| 1390 | 1433 |
| 1391 const TemplateURLRef& search_url = provider_url->url_ref(); | |
| 1392 DCHECK(search_url.SupportsReplacement()); | |
| 1393 match.search_terms_args.reset( | |
| 1394 new TemplateURLRef::SearchTermsArgs(query_string)); | |
| 1395 match.search_terms_args->original_query = input_text; | |
| 1396 match.search_terms_args->accepted_suggestion = accepted_suggestion; | |
| 1397 // This is the destination URL sans assisted query stats. This must be set | |
| 1398 // so the AutocompleteController can properly de-dupe; the controller will | |
| 1399 // eventually overwrite it before it reaches the user. | |
| 1400 match.destination_url = | |
| 1401 GURL(search_url.ReplaceSearchTerms(*match.search_terms_args.get())); | |
| 1402 | |
| 1403 // Search results don't look like URLs. | |
| 1404 match.transition = is_keyword ? | |
| 1405 content::PAGE_TRANSITION_KEYWORD : content::PAGE_TRANSITION_GENERATED; | |
| 1406 | |
| 1407 // Try to add |match| to |map|. If a match for |query_string| is already in | 1434 // Try to add |match| to |map|. If a match for |query_string| is already in |
| 1408 // |map|, replace it if |match| is more relevant. | 1435 // |map|, replace it if |match| is more relevant. |
| 1409 // NOTE: Keep this ToLower() call in sync with url_database.cc. | 1436 // NOTE: Keep this ToLower() call in sync with url_database.cc. |
| 1410 const std::pair<MatchMap::iterator, bool> i = map->insert( | 1437 const std::pair<MatchMap::iterator, bool> i = map->insert( |
| 1411 std::pair<string16, AutocompleteMatch>( | 1438 std::pair<string16, AutocompleteMatch>( |
| 1412 base::i18n::ToLower(query_string), match)); | 1439 base::i18n::ToLower(query_string), match)); |
| 1413 // NOTE: We purposefully do a direct relevance comparison here instead of | 1440 // NOTE: We purposefully do a direct relevance comparison here instead of |
| 1414 // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added | 1441 // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added |
| 1415 // first" rather than "items alphabetically first" when the scores are equal. | 1442 // first" rather than "items alphabetically first" when the scores are equal. |
| 1416 // The only case this matters is when a user has results with the same score | 1443 // The only case this matters is when a user has results with the same score |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1514 it->set_relevance(max_query_relevance); | 1541 it->set_relevance(max_query_relevance); |
| 1515 } | 1542 } |
| 1516 } | 1543 } |
| 1517 | 1544 |
| 1518 void SearchProvider::UpdateDone() { | 1545 void SearchProvider::UpdateDone() { |
| 1519 // We're done when the timer isn't running, there are no suggest queries | 1546 // We're done when the timer isn't running, there are no suggest queries |
| 1520 // pending, and we're not waiting on Instant. | 1547 // pending, and we're not waiting on Instant. |
| 1521 done_ = (!timer_.IsRunning() && (suggest_results_pending_ == 0) && | 1548 done_ = (!timer_.IsRunning() && (suggest_results_pending_ == 0) && |
| 1522 (instant_finalized_ || !chrome::IsInstantEnabled(profile_))); | 1549 (instant_finalized_ || !chrome::IsInstantEnabled(profile_))); |
| 1523 } | 1550 } |
| OLD | NEW |