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/callback.h" | 10 #include "base/callback.h" |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 match.contents_class.push_back( | 300 match.contents_class.push_back( |
301 ACMatchClassification(input_position, ACMatchClassification::NONE)); | 301 ACMatchClassification(input_position, ACMatchClassification::NONE)); |
302 size_t next_fragment_position = input_position + input_text.length(); | 302 size_t next_fragment_position = input_position + input_text.length(); |
303 if (next_fragment_position < query_string.length()) { | 303 if (next_fragment_position < query_string.length()) { |
304 match.contents_class.push_back( | 304 match.contents_class.push_back( |
305 ACMatchClassification(next_fragment_position, | 305 ACMatchClassification(next_fragment_position, |
306 ACMatchClassification::MATCH)); | 306 ACMatchClassification::MATCH)); |
307 } | 307 } |
308 } | 308 } |
309 } else { | 309 } else { |
310 // Otherwise, we're dealing with the "default search" result which has no | 310 // Otherwise, |match| is a verbatim (what-you-typed) match, either for the |
311 // completion. | 311 // default provider or a keyword search provider. |
312 match.contents_class.push_back( | 312 match.contents_class.push_back( |
313 ACMatchClassification(0, ACMatchClassification::NONE)); | 313 ACMatchClassification(0, ACMatchClassification::NONE)); |
| 314 match.allowed_to_be_default_match = true; |
314 } | 315 } |
315 | 316 |
316 // When the user forced a query, we need to make sure all the fill_into_edit | 317 // When the user forced a query, we need to make sure all the fill_into_edit |
317 // values preserve that property. Otherwise, if the user starts editing a | 318 // values preserve that property. Otherwise, if the user starts editing a |
318 // suggestion, non-Search results will suddenly appear. | 319 // suggestion, non-Search results will suddenly appear. |
319 if (input.type() == AutocompleteInput::FORCED_QUERY) | 320 if (input.type() == AutocompleteInput::FORCED_QUERY) |
320 match.fill_into_edit.assign(ASCIIToUTF16("?")); | 321 match.fill_into_edit.assign(ASCIIToUTF16("?")); |
321 if (is_keyword) | 322 if (is_keyword) |
322 match.fill_into_edit.append(match.keyword + char16(' ')); | 323 match.fill_into_edit.append(match.keyword + char16(' ')); |
323 if (!input.prevent_inline_autocomplete() && | 324 if (!input.prevent_inline_autocomplete() && |
324 StartsWith(query_string, input_text, false)) { | 325 StartsWith(query_string, input_text, false)) { |
325 match.inline_autocompletion = query_string.substr(input_text.length()); | 326 match.inline_autocompletion = query_string.substr(input_text.length()); |
| 327 match.allowed_to_be_default_match = true; |
326 } | 328 } |
327 match.fill_into_edit.append(query_string); | 329 match.fill_into_edit.append(query_string); |
328 | 330 |
329 const TemplateURLRef& search_url = template_url->url_ref(); | 331 const TemplateURLRef& search_url = template_url->url_ref(); |
330 DCHECK(search_url.SupportsReplacement()); | 332 DCHECK(search_url.SupportsReplacement()); |
331 match.search_terms_args.reset( | 333 match.search_terms_args.reset( |
332 new TemplateURLRef::SearchTermsArgs(query_string)); | 334 new TemplateURLRef::SearchTermsArgs(query_string)); |
333 match.search_terms_args->original_query = input_text; | 335 match.search_terms_args->original_query = input_text; |
334 match.search_terms_args->accepted_suggestion = accepted_suggestion; | 336 match.search_terms_args->accepted_suggestion = accepted_suggestion; |
335 match.search_terms_args->omnibox_start_margin = omnibox_start_margin; | 337 match.search_terms_args->omnibox_start_margin = omnibox_start_margin; |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
505 if (input.text().empty()) { | 507 if (input.text().empty()) { |
506 // User typed "?" alone. Give them a placeholder result indicating what | 508 // User typed "?" alone. Give them a placeholder result indicating what |
507 // this syntax does. | 509 // this syntax does. |
508 if (default_provider) { | 510 if (default_provider) { |
509 AutocompleteMatch match; | 511 AutocompleteMatch match; |
510 match.provider = this; | 512 match.provider = this; |
511 match.contents.assign(l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE)); | 513 match.contents.assign(l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE)); |
512 match.contents_class.push_back( | 514 match.contents_class.push_back( |
513 ACMatchClassification(0, ACMatchClassification::NONE)); | 515 ACMatchClassification(0, ACMatchClassification::NONE)); |
514 match.keyword = providers_.default_provider(); | 516 match.keyword = providers_.default_provider(); |
| 517 match.allowed_to_be_default_match = true; |
515 matches_.push_back(match); | 518 matches_.push_back(match); |
516 } | 519 } |
517 Stop(false); | 520 Stop(false); |
518 return; | 521 return; |
519 } | 522 } |
520 | 523 |
521 input_ = input; | 524 input_ = input; |
522 | 525 |
523 DoHistoryQuery(minimal_changes); | 526 DoHistoryQuery(minimal_changes); |
524 StartOrStopSuggestQuery(minimal_changes); | 527 StartOrStopSuggestQuery(minimal_changes); |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1058 return matches_.front().relevance < | 1061 return matches_.front().relevance < |
1059 CalculateRelevanceForVerbatimIgnoringKeywordModeState(); | 1062 CalculateRelevanceForVerbatimIgnoringKeywordModeState(); |
1060 } | 1063 } |
1061 | 1064 |
1062 bool SearchProvider::IsTopMatchSearchWithURLInput() const { | 1065 bool SearchProvider::IsTopMatchSearchWithURLInput() const { |
1063 return input_.type() == AutocompleteInput::URL && | 1066 return input_.type() == AutocompleteInput::URL && |
1064 matches_.front().relevance > CalculateRelevanceForVerbatim() && | 1067 matches_.front().relevance > CalculateRelevanceForVerbatim() && |
1065 matches_.front().type != AutocompleteMatchType::NAVSUGGEST; | 1068 matches_.front().type != AutocompleteMatchType::NAVSUGGEST; |
1066 } | 1069 } |
1067 | 1070 |
1068 bool SearchProvider::IsTopMatchNotInlinable() const { | 1071 bool SearchProvider::HasValidDefaultMatch( |
1069 // Note: this test assumes the SEARCH_OTHER_ENGINE match corresponds to | 1072 bool autocomplete_result_will_reorder_for_default_match) const { |
1070 // the verbatim search query on the keyword engine. SearchProvider should | 1073 // One of the SearchProvider matches may need to be the overall default. If |
1071 // not create any other match of type SEARCH_OTHER_ENGINE. | 1074 // AutocompleteResult is allowed to reorder matches, this means we simply |
1072 return | 1075 // need at least one match in the list to be |allowed_to_be_default_match|. |
1073 matches_.front().type != AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED && | 1076 // If no reordering is possible, however, then our first match needs to have |
1074 matches_.front().type != AutocompleteMatchType::SEARCH_OTHER_ENGINE && | 1077 // this flag. |
1075 matches_.front().inline_autocompletion.empty() && | 1078 for (ACMatches::const_iterator it = matches_.begin(); it != matches_.end(); |
1076 matches_.front().fill_into_edit != input_.text(); | 1079 ++it) { |
| 1080 if (it->allowed_to_be_default_match) |
| 1081 return true; |
| 1082 if (!autocomplete_result_will_reorder_for_default_match) |
| 1083 return false; |
| 1084 } |
| 1085 return false; |
1077 } | 1086 } |
1078 | 1087 |
1079 void SearchProvider::UpdateMatches() { | 1088 void SearchProvider::UpdateMatches() { |
1080 ConvertResultsToAutocompleteMatches(); | 1089 ConvertResultsToAutocompleteMatches(); |
1081 | 1090 |
1082 // Check constraints that may be violated by suggested relevances. | 1091 // Check constraints that may be violated by suggested relevances. |
1083 if (!matches_.empty() && | 1092 if (!matches_.empty() && |
1084 (default_results_.HasServerProvidedScores() || | 1093 (default_results_.HasServerProvidedScores() || |
1085 keyword_results_.HasServerProvidedScores())) { | 1094 keyword_results_.HasServerProvidedScores())) { |
1086 // These blocks attempt to repair undesirable behavior by suggested | 1095 // These blocks attempt to repair undesirable behavior by suggested |
1087 // relevances with minimal impact, preserving other suggested relevances. | 1096 // relevances with minimal impact, preserving other suggested relevances. |
1088 if (IsTopMatchNavigationInKeywordMode()) { | 1097 if (IsTopMatchNavigationInKeywordMode()) { |
1089 // Correct the suggested relevance scores if the top match is a | 1098 // Correct the suggested relevance scores if the top match is a |
1090 // navigation in keyword mode, since inlining a navigation match | 1099 // navigation in keyword mode, since inlining a navigation match |
1091 // would break the user out of keyword mode. By the way, if the top | 1100 // would break the user out of keyword mode. By the way, if the top |
1092 // match is a non-keyword match (query or navsuggestion) in keyword | 1101 // match is a non-keyword match (query or navsuggestion) in keyword |
1093 // mode, the user would also break out of keyword mode. However, | 1102 // mode, the user would also break out of keyword mode. However, |
1094 // that situation is impossible given the current scoring paradigm | 1103 // that situation is impossible given the current scoring paradigm |
1095 // and the fact that only one search engine (Google) provides suggested | 1104 // and the fact that only one search engine (Google) provides suggested |
1096 // relevance scores at this time. | 1105 // relevance scores at this time. |
1097 DemoteKeywordNavigationMatchesPastTopQuery(); | 1106 DemoteKeywordNavigationMatchesPastTopQuery(); |
1098 ConvertResultsToAutocompleteMatches(); | 1107 ConvertResultsToAutocompleteMatches(); |
1099 DCHECK(!IsTopMatchNavigationInKeywordMode()); | 1108 DCHECK(!IsTopMatchNavigationInKeywordMode()); |
1100 } | 1109 } |
1101 if (IsTopMatchScoreTooLow()) { | 1110 // True if the omnibox will reorder matches as necessary to make the top |
| 1111 // one something that is allowed to be the default match. |
| 1112 const bool omnibox_will_reorder_for_legal_default_match = |
| 1113 OmniboxFieldTrial::ReorderForLegalDefaultMatch( |
| 1114 input_.current_page_classification()); |
| 1115 if (!omnibox_will_reorder_for_legal_default_match && |
| 1116 IsTopMatchScoreTooLow()) { |
1102 // Disregard the suggested verbatim relevance if the top score is below | 1117 // Disregard the suggested verbatim relevance if the top score is below |
1103 // the usual verbatim value. For example, a BarProvider may rely on | 1118 // the usual verbatim value. For example, a BarProvider may rely on |
1104 // SearchProvider's verbatim or inlineable matches for input "foo" to | 1119 // SearchProvider's verbatim or inlineable matches for input "foo" (all |
1105 // always outrank its own lowly-ranked non-inlineable "bar" match. | 1120 // allowed to be default match) to always outrank its own lowly-ranked |
| 1121 // "bar" matches that shouldn't be the default match. This only needs |
| 1122 // to be enforced when the omnibox will not reorder results to make a |
| 1123 // legal default match first. |
1106 default_results_.verbatim_relevance = -1; | 1124 default_results_.verbatim_relevance = -1; |
1107 keyword_results_.verbatim_relevance = -1; | 1125 keyword_results_.verbatim_relevance = -1; |
1108 ConvertResultsToAutocompleteMatches(); | 1126 ConvertResultsToAutocompleteMatches(); |
1109 } | 1127 } |
1110 if (IsTopMatchSearchWithURLInput()) { | 1128 if (IsTopMatchSearchWithURLInput()) { |
1111 // Disregard the suggested search and verbatim relevances if the input | 1129 // Disregard the suggested search and verbatim relevances if the input |
1112 // type is URL and the top match is a highly-ranked search suggestion. | 1130 // type is URL and the top match is a highly-ranked search suggestion. |
1113 // For example, prevent a search for "foo.com" from outranking another | 1131 // For example, prevent a search for "foo.com" from outranking another |
1114 // provider's navigation for "foo.com" or "foo.com/url_from_history". | 1132 // provider's navigation for "foo.com" or "foo.com/url_from_history". |
1115 ApplyCalculatedSuggestRelevance(&keyword_results_.suggest_results); | 1133 ApplyCalculatedSuggestRelevance(&keyword_results_.suggest_results); |
1116 ApplyCalculatedSuggestRelevance(&default_results_.suggest_results); | 1134 ApplyCalculatedSuggestRelevance(&default_results_.suggest_results); |
1117 default_results_.verbatim_relevance = -1; | 1135 default_results_.verbatim_relevance = -1; |
1118 keyword_results_.verbatim_relevance = -1; | 1136 keyword_results_.verbatim_relevance = -1; |
1119 ConvertResultsToAutocompleteMatches(); | 1137 ConvertResultsToAutocompleteMatches(); |
1120 } | 1138 } |
1121 if (IsTopMatchNotInlinable()) { | 1139 if (!HasValidDefaultMatch(omnibox_will_reorder_for_legal_default_match)) { |
1122 // Disregard suggested relevances if the top match is not a verbatim match | 1140 // If the omnibox is not going to reorder results to put a legal default |
1123 // or inlinable. For example, input "foo" should not invoke a search for | 1141 // match at the top, then this provider needs to guarantee that its top |
1124 // "bar", which would happen if the "bar" search match outranked all other | 1142 // scoring result is a legal default match (i.e., it's either a verbatim |
1125 // matches. | 1143 // match or inlinable). For example, input "foo" should not invoke a |
| 1144 // search for "bar", which would happen if the "bar" search match |
| 1145 // outranked all other matches. On the other hand, if the omnibox will |
| 1146 // reorder matches as necessary to put a legal default match at the top, |
| 1147 // all we need to guarantee is that SearchProvider returns a legal |
| 1148 // default match. (The omnibox always needs at least one legal default |
| 1149 // match, and it relies on SearchProvider to always return one.) |
1126 ApplyCalculatedRelevance(); | 1150 ApplyCalculatedRelevance(); |
1127 ConvertResultsToAutocompleteMatches(); | 1151 ConvertResultsToAutocompleteMatches(); |
1128 } | 1152 } |
1129 DCHECK(!IsTopMatchNavigationInKeywordMode()); | 1153 DCHECK(!IsTopMatchNavigationInKeywordMode()); |
1130 DCHECK(!IsTopMatchScoreTooLow()); | 1154 DCHECK(omnibox_will_reorder_for_legal_default_match || |
| 1155 !IsTopMatchScoreTooLow()); |
1131 DCHECK(!IsTopMatchSearchWithURLInput()); | 1156 DCHECK(!IsTopMatchSearchWithURLInput()); |
1132 DCHECK(!IsTopMatchNotInlinable()); | 1157 DCHECK(HasValidDefaultMatch(omnibox_will_reorder_for_legal_default_match)); |
1133 } | 1158 } |
1134 | 1159 |
1135 UpdateStarredStateOfMatches(); | 1160 UpdateStarredStateOfMatches(); |
1136 UpdateDone(); | 1161 UpdateDone(); |
1137 } | 1162 } |
1138 | 1163 |
1139 void SearchProvider::AddNavigationResultsToMatches( | 1164 void SearchProvider::AddNavigationResultsToMatches( |
1140 const NavigationResults& navigation_results, | 1165 const NavigationResults& navigation_results, |
1141 ACMatches* matches) { | 1166 ACMatches* matches) { |
1142 for (NavigationResults::const_iterator it = navigation_results.begin(); | 1167 for (NavigationResults::const_iterator it = navigation_results.begin(); |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1443 const net::FormatUrlTypes format_types = | 1468 const net::FormatUrlTypes format_types = |
1444 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP); | 1469 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP); |
1445 match.fill_into_edit += | 1470 match.fill_into_edit += |
1446 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(), | 1471 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(), |
1447 net::FormatUrl(navigation.url(), languages, format_types, | 1472 net::FormatUrl(navigation.url(), languages, format_types, |
1448 net::UnescapeRule::SPACES, NULL, NULL, | 1473 net::UnescapeRule::SPACES, NULL, NULL, |
1449 &inline_autocomplete_offset)); | 1474 &inline_autocomplete_offset)); |
1450 if (!input_.prevent_inline_autocomplete() && | 1475 if (!input_.prevent_inline_autocomplete() && |
1451 (inline_autocomplete_offset != string16::npos)) { | 1476 (inline_autocomplete_offset != string16::npos)) { |
1452 DCHECK(inline_autocomplete_offset <= match.fill_into_edit.length()); | 1477 DCHECK(inline_autocomplete_offset <= match.fill_into_edit.length()); |
| 1478 match.allowed_to_be_default_match = true; |
1453 match.inline_autocompletion = | 1479 match.inline_autocompletion = |
1454 match.fill_into_edit.substr(inline_autocomplete_offset); | 1480 match.fill_into_edit.substr(inline_autocomplete_offset); |
1455 } | 1481 } |
1456 | 1482 |
1457 match.contents = net::FormatUrl(navigation.url(), languages, | 1483 match.contents = net::FormatUrl(navigation.url(), languages, |
1458 format_types, net::UnescapeRule::SPACES, NULL, NULL, &match_start); | 1484 format_types, net::UnescapeRule::SPACES, NULL, NULL, &match_start); |
1459 // If the first match in the untrimmed string was inside a scheme that we | 1485 // If the first match in the untrimmed string was inside a scheme that we |
1460 // trimmed, look for a subsequent match. | 1486 // trimmed, look for a subsequent match. |
1461 if (match_start == string16::npos) | 1487 if (match_start == string16::npos) |
1462 match_start = match.contents.find(input); | 1488 match_start = match.contents.find(input); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1516 it->set_relevance(max_query_relevance); | 1542 it->set_relevance(max_query_relevance); |
1517 it->set_relevance_from_server(relevance_from_server); | 1543 it->set_relevance_from_server(relevance_from_server); |
1518 } | 1544 } |
1519 } | 1545 } |
1520 | 1546 |
1521 void SearchProvider::UpdateDone() { | 1547 void SearchProvider::UpdateDone() { |
1522 // We're done when the timer isn't running, there are no suggest queries | 1548 // We're done when the timer isn't running, there are no suggest queries |
1523 // pending, and we're not waiting on Instant. | 1549 // pending, and we're not waiting on Instant. |
1524 done_ = !timer_.IsRunning() && (suggest_results_pending_ == 0); | 1550 done_ = !timer_.IsRunning() && (suggest_results_pending_ == 0); |
1525 } | 1551 } |
OLD | NEW |