| 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 |