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 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
248 : AutocompleteProvider(listener, profile, | 248 : AutocompleteProvider(listener, profile, |
249 AutocompleteProvider::TYPE_SEARCH), | 249 AutocompleteProvider::TYPE_SEARCH), |
250 providers_(TemplateURLServiceFactory::GetForProfile(profile)), | 250 providers_(TemplateURLServiceFactory::GetForProfile(profile)), |
251 suggest_results_pending_(0), | 251 suggest_results_pending_(0), |
252 field_trial_triggered_(false), | 252 field_trial_triggered_(false), |
253 field_trial_triggered_in_session_(false), | 253 field_trial_triggered_in_session_(false), |
254 omnibox_start_margin_(-1), | 254 omnibox_start_margin_(-1), |
255 prevent_search_history_inlining_( | 255 prevent_search_history_inlining_( |
256 OmniboxFieldTrial::SearchHistoryPreventInlining()), | 256 OmniboxFieldTrial::SearchHistoryPreventInlining()), |
257 disable_search_history_( | 257 disable_search_history_( |
258 OmniboxFieldTrial::SearchHistoryDisable()) { | 258 OmniboxFieldTrial::SearchHistoryDisable()), |
259 omnibox_will_reorder_for_legal_default_match_( | |
260 OmniboxFieldTrial::InReorderForLegalDefaultMatchGroup()) { | |
259 } | 261 } |
260 | 262 |
261 // static | 263 // static |
262 AutocompleteMatch SearchProvider::CreateSearchSuggestion( | 264 AutocompleteMatch SearchProvider::CreateSearchSuggestion( |
263 AutocompleteProvider* autocomplete_provider, | 265 AutocompleteProvider* autocomplete_provider, |
264 int relevance, | 266 int relevance, |
265 AutocompleteMatch::Type type, | 267 AutocompleteMatch::Type type, |
266 const TemplateURL* template_url, | 268 const TemplateURL* template_url, |
267 const string16& query_string, | 269 const string16& query_string, |
268 const string16& input_text, | 270 const string16& input_text, |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
304 match.contents_class.push_back( | 306 match.contents_class.push_back( |
305 ACMatchClassification(input_position, ACMatchClassification::NONE)); | 307 ACMatchClassification(input_position, ACMatchClassification::NONE)); |
306 size_t next_fragment_position = input_position + input_text.length(); | 308 size_t next_fragment_position = input_position + input_text.length(); |
307 if (next_fragment_position < query_string.length()) { | 309 if (next_fragment_position < query_string.length()) { |
308 match.contents_class.push_back( | 310 match.contents_class.push_back( |
309 ACMatchClassification(next_fragment_position, | 311 ACMatchClassification(next_fragment_position, |
310 ACMatchClassification::MATCH)); | 312 ACMatchClassification::MATCH)); |
311 } | 313 } |
312 } | 314 } |
313 } else { | 315 } else { |
314 // Otherwise, we're dealing with the "default search" result which has no | 316 // Otherwise, we're dealing with the "default search" result which has no |
msw
2013/07/23 21:55:33
nit: please update this comment to something like:
Mark P
2013/07/26 16:48:13
Did something like that with some editing.
| |
315 // completion. | 317 // completion. |
316 match.contents_class.push_back( | 318 match.contents_class.push_back( |
317 ACMatchClassification(0, ACMatchClassification::NONE)); | 319 ACMatchClassification(0, ACMatchClassification::NONE)); |
320 match.allowed_to_be_default_match = true; | |
318 } | 321 } |
319 | 322 |
320 // When the user forced a query, we need to make sure all the fill_into_edit | 323 // When the user forced a query, we need to make sure all the fill_into_edit |
321 // values preserve that property. Otherwise, if the user starts editing a | 324 // values preserve that property. Otherwise, if the user starts editing a |
322 // suggestion, non-Search results will suddenly appear. | 325 // suggestion, non-Search results will suddenly appear. |
323 if (input.type() == AutocompleteInput::FORCED_QUERY) | 326 if (input.type() == AutocompleteInput::FORCED_QUERY) |
324 match.fill_into_edit.assign(ASCIIToUTF16("?")); | 327 match.fill_into_edit.assign(ASCIIToUTF16("?")); |
325 if (is_keyword) | 328 if (is_keyword) |
326 match.fill_into_edit.append(match.keyword + char16(' ')); | 329 match.fill_into_edit.append(match.keyword + char16(' ')); |
327 if (!input.prevent_inline_autocomplete() && | 330 if (!input.prevent_inline_autocomplete() && |
328 StartsWith(query_string, input_text, false)) { | 331 StartsWith(query_string, input_text, false)) { |
329 match.inline_autocompletion = query_string.substr(input_text.length()); | 332 match.inline_autocompletion = query_string.substr(input_text.length()); |
333 match.allowed_to_be_default_match = true; | |
330 } | 334 } |
331 match.fill_into_edit.append(query_string); | 335 match.fill_into_edit.append(query_string); |
332 | 336 |
333 const TemplateURLRef& search_url = template_url->url_ref(); | 337 const TemplateURLRef& search_url = template_url->url_ref(); |
334 DCHECK(search_url.SupportsReplacement()); | 338 DCHECK(search_url.SupportsReplacement()); |
335 match.search_terms_args.reset( | 339 match.search_terms_args.reset( |
336 new TemplateURLRef::SearchTermsArgs(query_string)); | 340 new TemplateURLRef::SearchTermsArgs(query_string)); |
337 match.search_terms_args->original_query = input_text; | 341 match.search_terms_args->original_query = input_text; |
338 match.search_terms_args->accepted_suggestion = accepted_suggestion; | 342 match.search_terms_args->accepted_suggestion = accepted_suggestion; |
339 match.search_terms_args->omnibox_start_margin = omnibox_start_margin; | 343 match.search_terms_args->omnibox_start_margin = omnibox_start_margin; |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
509 if (input.text().empty()) { | 513 if (input.text().empty()) { |
510 // User typed "?" alone. Give them a placeholder result indicating what | 514 // User typed "?" alone. Give them a placeholder result indicating what |
511 // this syntax does. | 515 // this syntax does. |
512 if (default_provider) { | 516 if (default_provider) { |
513 AutocompleteMatch match; | 517 AutocompleteMatch match; |
514 match.provider = this; | 518 match.provider = this; |
515 match.contents.assign(l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE)); | 519 match.contents.assign(l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE)); |
516 match.contents_class.push_back( | 520 match.contents_class.push_back( |
517 ACMatchClassification(0, ACMatchClassification::NONE)); | 521 ACMatchClassification(0, ACMatchClassification::NONE)); |
518 match.keyword = providers_.default_provider(); | 522 match.keyword = providers_.default_provider(); |
523 match.allowed_to_be_default_match = true; | |
519 matches_.push_back(match); | 524 matches_.push_back(match); |
520 } | 525 } |
521 Stop(false); | 526 Stop(false); |
522 return; | 527 return; |
523 } | 528 } |
524 | 529 |
525 input_ = input; | 530 input_ = input; |
526 | 531 |
527 DoHistoryQuery(minimal_changes); | 532 DoHistoryQuery(minimal_changes); |
528 StartOrStopSuggestQuery(minimal_changes); | 533 StartOrStopSuggestQuery(minimal_changes); |
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1061 return matches_.front().relevance < | 1066 return matches_.front().relevance < |
1062 CalculateRelevanceForVerbatimIgnoringKeywordModeState(); | 1067 CalculateRelevanceForVerbatimIgnoringKeywordModeState(); |
1063 } | 1068 } |
1064 | 1069 |
1065 bool SearchProvider::IsTopMatchSearchWithURLInput() const { | 1070 bool SearchProvider::IsTopMatchSearchWithURLInput() const { |
1066 return input_.type() == AutocompleteInput::URL && | 1071 return input_.type() == AutocompleteInput::URL && |
1067 matches_.front().relevance > CalculateRelevanceForVerbatim() && | 1072 matches_.front().relevance > CalculateRelevanceForVerbatim() && |
1068 matches_.front().type != AutocompleteMatchType::NAVSUGGEST; | 1073 matches_.front().type != AutocompleteMatchType::NAVSUGGEST; |
1069 } | 1074 } |
1070 | 1075 |
1071 bool SearchProvider::IsTopMatchNotInlinable() const { | 1076 bool SearchProvider::IsTopMatchNotAllowedToBeDefaultMatch() const { |
1072 // Note: this test assumes the SEARCH_OTHER_ENGINE match corresponds to | 1077 return !matches_.front().allowed_to_be_default_match; |
1073 // the verbatim search query on the keyword engine. SearchProvider should | 1078 } |
1074 // not create any other match of type SEARCH_OTHER_ENGINE. | 1079 |
1075 return | 1080 bool SearchProvider::LacksDefaultMatch() const { |
1076 matches_.front().type != AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED && | 1081 for (ACMatches::const_iterator it = matches_.begin(); it != matches_.end(); |
1077 matches_.front().type != AutocompleteMatchType::SEARCH_OTHER_ENGINE && | 1082 ++it) { |
1078 matches_.front().inline_autocompletion.empty() && | 1083 if (it->allowed_to_be_default_match) |
1079 matches_.front().fill_into_edit != input_.text(); | 1084 return false; |
1085 } | |
1086 return true; | |
1080 } | 1087 } |
1081 | 1088 |
1082 void SearchProvider::UpdateMatches() { | 1089 void SearchProvider::UpdateMatches() { |
1083 ConvertResultsToAutocompleteMatches(); | 1090 ConvertResultsToAutocompleteMatches(); |
1084 | 1091 |
1085 // Check constraints that may be violated by suggested relevances. | 1092 // Check constraints that may be violated by suggested relevances. |
1086 if (!matches_.empty() && | 1093 if (!matches_.empty() && |
1087 (default_results_.HasServerProvidedScores() || | 1094 (default_results_.HasServerProvidedScores() || |
1088 keyword_results_.HasServerProvidedScores())) { | 1095 keyword_results_.HasServerProvidedScores())) { |
1089 // These blocks attempt to repair undesirable behavior by suggested | 1096 // These blocks attempt to repair undesirable behavior by suggested |
1090 // relevances with minimal impact, preserving other suggested relevances. | 1097 // relevances with minimal impact, preserving other suggested relevances. |
1091 if (IsTopMatchNavigationInKeywordMode()) { | 1098 if (IsTopMatchNavigationInKeywordMode()) { |
1092 // Correct the suggested relevance scores if the top match is a | 1099 // Correct the suggested relevance scores if the top match is a |
1093 // navigation in keyword mode, since inlining a navigation match | 1100 // navigation in keyword mode, since inlining a navigation match |
1094 // would break the user out of keyword mode. By the way, if the top | 1101 // would break the user out of keyword mode. By the way, if the top |
1095 // match is a non-keyword match (query or navsuggestion) in keyword | 1102 // match is a non-keyword match (query or navsuggestion) in keyword |
1096 // mode, the user would also break out of keyword mode. However, | 1103 // mode, the user would also break out of keyword mode. However, |
1097 // that situation is impossible given the current scoring paradigm | 1104 // that situation is impossible given the current scoring paradigm |
1098 // and the fact that only one search engine (Google) provides suggested | 1105 // and the fact that only one search engine (Google) provides suggested |
1099 // relevance scores at this time. | 1106 // relevance scores at this time. |
1100 DemoteKeywordNavigationMatchesPastTopQuery(); | 1107 DemoteKeywordNavigationMatchesPastTopQuery(); |
1101 ConvertResultsToAutocompleteMatches(); | 1108 ConvertResultsToAutocompleteMatches(); |
1102 DCHECK(!IsTopMatchNavigationInKeywordMode()); | 1109 DCHECK(!IsTopMatchNavigationInKeywordMode()); |
1103 } | 1110 } |
1104 if (IsTopMatchScoreTooLow()) { | 1111 if (!omnibox_will_reorder_for_legal_default_match_ && |
1112 IsTopMatchScoreTooLow()) { | |
1105 // Disregard the suggested verbatim relevance if the top score is below | 1113 // Disregard the suggested verbatim relevance if the top score is below |
1106 // the usual verbatim value. For example, a BarProvider may rely on | 1114 // the usual verbatim value. For example, a BarProvider may rely on |
1107 // SearchProvider's verbatim or inlineable matches for input "foo" to | 1115 // SearchProvider's verbatim or inlineable matches for input "foo" (all |
1108 // always outrank its own lowly-ranked non-inlineable "bar" match. | 1116 // allowed to be default match) to always outrank its own lowly-ranked |
1117 // "bar" matches that shouldn't be the default match. This only needs | |
1118 // to be enforced when the omnibox will not reorder results to make a | |
1119 // legal default match first. | |
1109 default_results_.verbatim_relevance = -1; | 1120 default_results_.verbatim_relevance = -1; |
1110 keyword_results_.verbatim_relevance = -1; | 1121 keyword_results_.verbatim_relevance = -1; |
1111 ConvertResultsToAutocompleteMatches(); | 1122 ConvertResultsToAutocompleteMatches(); |
1112 } | 1123 } |
1113 if (IsTopMatchSearchWithURLInput()) { | 1124 if (IsTopMatchSearchWithURLInput()) { |
1114 // Disregard the suggested search and verbatim relevances if the input | 1125 // Disregard the suggested search and verbatim relevances if the input |
1115 // type is URL and the top match is a highly-ranked search suggestion. | 1126 // type is URL and the top match is a highly-ranked search suggestion. |
1116 // For example, prevent a search for "foo.com" from outranking another | 1127 // For example, prevent a search for "foo.com" from outranking another |
1117 // provider's navigation for "foo.com" or "foo.com/url_from_history". | 1128 // provider's navigation for "foo.com" or "foo.com/url_from_history". |
1118 ApplyCalculatedSuggestRelevance(&keyword_results_.suggest_results); | 1129 ApplyCalculatedSuggestRelevance(&keyword_results_.suggest_results); |
1119 ApplyCalculatedSuggestRelevance(&default_results_.suggest_results); | 1130 ApplyCalculatedSuggestRelevance(&default_results_.suggest_results); |
1120 default_results_.verbatim_relevance = -1; | 1131 default_results_.verbatim_relevance = -1; |
1121 keyword_results_.verbatim_relevance = -1; | 1132 keyword_results_.verbatim_relevance = -1; |
1122 ConvertResultsToAutocompleteMatches(); | 1133 ConvertResultsToAutocompleteMatches(); |
1123 } | 1134 } |
1124 if (IsTopMatchNotInlinable()) { | 1135 if (omnibox_will_reorder_for_legal_default_match_ ? |
1125 // Disregard suggested relevances if the top match is not a verbatim match | 1136 LacksDefaultMatch() : IsTopMatchNotAllowedToBeDefaultMatch()) { |
1126 // or inlinable. For example, input "foo" should not invoke a search for | 1137 // If the omnibox is not going to reorder results to put a legal default |
1127 // "bar", which would happen if the "bar" search match outranked all other | 1138 // match at the top, then this provider needs to guarantee that its top |
1128 // matches. | 1139 // scoring result is a legal default match (i.e., it's either a verbatim |
1140 // match or inlinable). For example, input "foo" should not invoke a | |
1141 // search for "bar", which would happen if the "bar" search match | |
1142 // outranked all other matches. On the other hand, if the omnibox will | |
1143 // reorder matches as necessary to put a legal default match at the top, | |
1144 // all we need to guarantee is that SearchProvider returns a legal | |
1145 // default match. (The omnibox always needs at least one legal default | |
1146 // match, and it relies on SearchProvider to always return one.) | |
1129 ApplyCalculatedRelevance(); | 1147 ApplyCalculatedRelevance(); |
1130 ConvertResultsToAutocompleteMatches(); | 1148 ConvertResultsToAutocompleteMatches(); |
1131 } | 1149 } |
1132 DCHECK(!IsTopMatchNavigationInKeywordMode()); | 1150 DCHECK(!IsTopMatchNavigationInKeywordMode()); |
1133 DCHECK(!IsTopMatchScoreTooLow()); | 1151 DCHECK(omnibox_will_reorder_for_legal_default_match_ || |
1152 !IsTopMatchScoreTooLow()); | |
1134 DCHECK(!IsTopMatchSearchWithURLInput()); | 1153 DCHECK(!IsTopMatchSearchWithURLInput()); |
1135 DCHECK(!IsTopMatchNotInlinable()); | 1154 DCHECK(omnibox_will_reorder_for_legal_default_match_ || |
1155 !IsTopMatchNotAllowedToBeDefaultMatch()); | |
1156 DCHECK(!LacksDefaultMatch()); | |
1136 } | 1157 } |
1137 | 1158 |
1138 UpdateStarredStateOfMatches(); | 1159 UpdateStarredStateOfMatches(); |
1139 UpdateDone(); | 1160 UpdateDone(); |
1140 } | 1161 } |
1141 | 1162 |
1142 void SearchProvider::AddNavigationResultsToMatches( | 1163 void SearchProvider::AddNavigationResultsToMatches( |
1143 const NavigationResults& navigation_results, | 1164 const NavigationResults& navigation_results, |
1144 ACMatches* matches) { | 1165 ACMatches* matches) { |
1145 for (NavigationResults::const_iterator it = navigation_results.begin(); | 1166 for (NavigationResults::const_iterator it = navigation_results.begin(); |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1441 const net::FormatUrlTypes format_types = | 1462 const net::FormatUrlTypes format_types = |
1442 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP); | 1463 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP); |
1443 match.fill_into_edit += | 1464 match.fill_into_edit += |
1444 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(), | 1465 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(), |
1445 net::FormatUrl(navigation.url(), languages, format_types, | 1466 net::FormatUrl(navigation.url(), languages, format_types, |
1446 net::UnescapeRule::SPACES, NULL, NULL, | 1467 net::UnescapeRule::SPACES, NULL, NULL, |
1447 &inline_autocomplete_offset)); | 1468 &inline_autocomplete_offset)); |
1448 if (!input_.prevent_inline_autocomplete() && | 1469 if (!input_.prevent_inline_autocomplete() && |
1449 (inline_autocomplete_offset != string16::npos)) { | 1470 (inline_autocomplete_offset != string16::npos)) { |
1450 DCHECK(inline_autocomplete_offset <= match.fill_into_edit.length()); | 1471 DCHECK(inline_autocomplete_offset <= match.fill_into_edit.length()); |
1472 match.allowed_to_be_default_match = | |
1473 (inline_autocomplete_offset != string16::npos); | |
1451 match.inline_autocompletion = | 1474 match.inline_autocompletion = |
1452 match.fill_into_edit.substr(inline_autocomplete_offset); | 1475 match.fill_into_edit.substr(inline_autocomplete_offset); |
1453 } | 1476 } |
1454 | 1477 |
1455 match.contents = net::FormatUrl(navigation.url(), languages, | 1478 match.contents = net::FormatUrl(navigation.url(), languages, |
1456 format_types, net::UnescapeRule::SPACES, NULL, NULL, &match_start); | 1479 format_types, net::UnescapeRule::SPACES, NULL, NULL, &match_start); |
1457 // If the first match in the untrimmed string was inside a scheme that we | 1480 // If the first match in the untrimmed string was inside a scheme that we |
1458 // trimmed, look for a subsequent match. | 1481 // trimmed, look for a subsequent match. |
1459 if (match_start == string16::npos) | 1482 if (match_start == string16::npos) |
1460 match_start = match.contents.find(input); | 1483 match_start = match.contents.find(input); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1514 it->set_relevance(max_query_relevance); | 1537 it->set_relevance(max_query_relevance); |
1515 it->set_relevance_from_server(relevance_from_server); | 1538 it->set_relevance_from_server(relevance_from_server); |
1516 } | 1539 } |
1517 } | 1540 } |
1518 | 1541 |
1519 void SearchProvider::UpdateDone() { | 1542 void SearchProvider::UpdateDone() { |
1520 // We're done when the timer isn't running, there are no suggest queries | 1543 // We're done when the timer isn't running, there are no suggest queries |
1521 // pending, and we're not waiting on Instant. | 1544 // pending, and we're not waiting on Instant. |
1522 done_ = !timer_.IsRunning() && (suggest_results_pending_ == 0); | 1545 done_ = !timer_.IsRunning() && (suggest_results_pending_ == 0); |
1523 } | 1546 } |
OLD | NEW |