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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 |
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_autocomplete_offset = | 332 match.inline_autocomplete_offset = |
330 match.fill_into_edit.length() + input_text.length(); | 333 match.fill_into_edit.length() + input_text.length(); |
334 match.allowed_to_be_default_match = true; | |
331 } | 335 } |
332 match.fill_into_edit.append(query_string); | 336 match.fill_into_edit.append(query_string); |
333 | 337 |
334 const TemplateURLRef& search_url = template_url->url_ref(); | 338 const TemplateURLRef& search_url = template_url->url_ref(); |
335 DCHECK(search_url.SupportsReplacement()); | 339 DCHECK(search_url.SupportsReplacement()); |
336 match.search_terms_args.reset( | 340 match.search_terms_args.reset( |
337 new TemplateURLRef::SearchTermsArgs(query_string)); | 341 new TemplateURLRef::SearchTermsArgs(query_string)); |
338 match.search_terms_args->original_query = input_text; | 342 match.search_terms_args->original_query = input_text; |
339 match.search_terms_args->accepted_suggestion = accepted_suggestion; | 343 match.search_terms_args->accepted_suggestion = accepted_suggestion; |
340 match.search_terms_args->omnibox_start_margin = omnibox_start_margin; | 344 match.search_terms_args->omnibox_start_margin = omnibox_start_margin; |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
510 if (input.text().empty()) { | 514 if (input.text().empty()) { |
511 // User typed "?" alone. Give them a placeholder result indicating what | 515 // User typed "?" alone. Give them a placeholder result indicating what |
512 // this syntax does. | 516 // this syntax does. |
513 if (default_provider) { | 517 if (default_provider) { |
514 AutocompleteMatch match; | 518 AutocompleteMatch match; |
515 match.provider = this; | 519 match.provider = this; |
516 match.contents.assign(l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE)); | 520 match.contents.assign(l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE)); |
517 match.contents_class.push_back( | 521 match.contents_class.push_back( |
518 ACMatchClassification(0, ACMatchClassification::NONE)); | 522 ACMatchClassification(0, ACMatchClassification::NONE)); |
519 match.keyword = providers_.default_provider(); | 523 match.keyword = providers_.default_provider(); |
524 match.allowed_to_be_default_match = true; | |
520 matches_.push_back(match); | 525 matches_.push_back(match); |
521 } | 526 } |
522 Stop(false); | 527 Stop(false); |
523 return; | 528 return; |
524 } | 529 } |
525 | 530 |
526 input_ = input; | 531 input_ = input; |
527 | 532 |
528 DoHistoryQuery(minimal_changes); | 533 DoHistoryQuery(minimal_changes); |
529 StartOrStopSuggestQuery(minimal_changes); | 534 StartOrStopSuggestQuery(minimal_changes); |
(...skipping 535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1065 | 1070 |
1066 bool SearchProvider::IsTopMatchHighRankSearchForURL() const { | 1071 bool SearchProvider::IsTopMatchHighRankSearchForURL() const { |
1067 return input_.type() == AutocompleteInput::URL && | 1072 return input_.type() == AutocompleteInput::URL && |
1068 matches_.front().relevance > CalculateRelevanceForVerbatim() && | 1073 matches_.front().relevance > CalculateRelevanceForVerbatim() && |
1069 (matches_.front().type == AutocompleteMatchType::SEARCH_SUGGEST || | 1074 (matches_.front().type == AutocompleteMatchType::SEARCH_SUGGEST || |
1070 matches_.front().type == | 1075 matches_.front().type == |
1071 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED || | 1076 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED || |
1072 matches_.front().type == AutocompleteMatchType::SEARCH_OTHER_ENGINE); | 1077 matches_.front().type == AutocompleteMatchType::SEARCH_OTHER_ENGINE); |
1073 } | 1078 } |
1074 | 1079 |
1075 bool SearchProvider::IsTopMatchNotInlinable() const { | 1080 bool SearchProvider::IsTopMatchNotAllowedToBeDefaultMatch() const { |
msw
2013/07/18 06:23:57
This function is almost what I'd expect Autocomple
Mark P
2013/07/21 20:31:05
Comment moot given the discussion you and Peter ha
|
msw
2013/07/18 06:23:57
Can you combine these two functions? It'd make mor
Mark P
2013/07/21 20:31:05
I see your desire, but I'd like to keep them separ
msw
2013/07/23 21:55:32
A combined function would check that either (1) or
Mark P
2013/07/26 16:48:13
Please suggest a good combined name. I can't thin
msw
2013/07/26 20:04:49
LacksValidDefaultMatch or HasValidDefaultMatch see
Mark P
2013/07/26 23:55:24
Used the first to parallel the other constraint te
|
1076 // Note: this test assumes the SEARCH_OTHER_ENGINE match corresponds to | 1081 return !matches_.front().allowed_to_be_default_match; |
1077 // the verbatim search query on the keyword engine. SearchProvider should | 1082 } |
1078 // not create any other match of type SEARCH_OTHER_ENGINE. | 1083 |
1079 return | 1084 bool SearchProvider::LacksDefaultMatch() const { |
1080 matches_.front().type != AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED && | 1085 for (ACMatches::const_iterator it = matches_.begin(); it != matches_.end(); |
1081 matches_.front().type != AutocompleteMatchType::SEARCH_OTHER_ENGINE && | 1086 ++it) { |
1082 matches_.front().inline_autocomplete_offset == string16::npos && | 1087 if (it->allowed_to_be_default_match) |
1083 matches_.front().fill_into_edit != input_.text(); | 1088 return false; |
1089 } | |
1090 return true; | |
1084 } | 1091 } |
1085 | 1092 |
1086 void SearchProvider::UpdateMatches() { | 1093 void SearchProvider::UpdateMatches() { |
1087 ConvertResultsToAutocompleteMatches(); | 1094 ConvertResultsToAutocompleteMatches(); |
1088 | 1095 |
1089 // Check constraints that may be violated by suggested relevances. | 1096 // Check constraints that may be violated by suggested relevances. |
1090 if (!matches_.empty() && | 1097 if (!matches_.empty() && |
1091 (default_results_.HasServerProvidedScores() || | 1098 (default_results_.HasServerProvidedScores() || |
1092 keyword_results_.HasServerProvidedScores())) { | 1099 keyword_results_.HasServerProvidedScores())) { |
1093 // These blocks attempt to repair undesirable behavior by suggested | 1100 // These blocks attempt to repair undesirable behavior by suggested |
1094 // relevances with minimal impact, preserving other suggested relevances. | 1101 // relevances with minimal impact, preserving other suggested relevances. |
1095 if (IsTopMatchNavigationInKeywordMode()) { | 1102 if (IsTopMatchNavigationInKeywordMode()) { |
1096 // Correct the suggested relevance scores if the top match is a | 1103 // Correct the suggested relevance scores if the top match is a |
1097 // navigation in keyword mode, since inlining a navigation match | 1104 // navigation in keyword mode, since inlining a navigation match |
1098 // would break the user out of keyword mode. By the way, if the top | 1105 // would break the user out of keyword mode. By the way, if the top |
1099 // match is a non-keyword match (query or navsuggestion) in keyword | 1106 // match is a non-keyword match (query or navsuggestion) in keyword |
1100 // mode, the user would also break out of keyword mode. However, | 1107 // mode, the user would also break out of keyword mode. However, |
1101 // that situation is impossible given the current scoring paradigm | 1108 // that situation is impossible given the current scoring paradigm |
1102 // and the fact that only one search engine (Google) provides suggested | 1109 // and the fact that only one search engine (Google) provides suggested |
1103 // relevance scores at this time. | 1110 // relevance scores at this time. |
1104 DemoteKeywordNavigationMatchesPastTopQuery(); | 1111 DemoteKeywordNavigationMatchesPastTopQuery(); |
1105 ConvertResultsToAutocompleteMatches(); | 1112 ConvertResultsToAutocompleteMatches(); |
1106 DCHECK(!IsTopMatchNavigationInKeywordMode()); | 1113 DCHECK(!IsTopMatchNavigationInKeywordMode()); |
1107 } | 1114 } |
1108 if (IsTopMatchScoreTooLow()) { | 1115 if (!omnibox_will_reorder_for_legal_default_match_ && |
1116 IsTopMatchScoreTooLow()) { | |
1109 // Disregard the suggested verbatim relevance if the top score is below | 1117 // Disregard the suggested verbatim relevance if the top score is below |
1110 // the usual verbatim value. For example, a BarProvider may rely on | 1118 // the usual verbatim value. For example, a BarProvider may rely on |
1111 // SearchProvider's verbatim or inlineable matches for input "foo" to | 1119 // SearchProvider's verbatim or inlineable matches for input "foo" (all |
1112 // 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. | |
1113 default_results_.verbatim_relevance = -1; | 1124 default_results_.verbatim_relevance = -1; |
1114 keyword_results_.verbatim_relevance = -1; | 1125 keyword_results_.verbatim_relevance = -1; |
1115 ConvertResultsToAutocompleteMatches(); | 1126 ConvertResultsToAutocompleteMatches(); |
1116 } | 1127 } |
1117 if (IsTopMatchHighRankSearchForURL()) { | 1128 if (IsTopMatchHighRankSearchForURL()) { |
1118 // Disregard the suggested search and verbatim relevances if the input | 1129 // Disregard the suggested search and verbatim relevances if the input |
1119 // 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. |
1120 // For example, prevent a search for "foo.com" from outranking another | 1131 // For example, prevent a search for "foo.com" from outranking another |
1121 // 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". |
1122 ApplyCalculatedSuggestRelevance(&keyword_results_.suggest_results); | 1133 ApplyCalculatedSuggestRelevance(&keyword_results_.suggest_results); |
1123 ApplyCalculatedSuggestRelevance(&default_results_.suggest_results); | 1134 ApplyCalculatedSuggestRelevance(&default_results_.suggest_results); |
1124 default_results_.verbatim_relevance = -1; | 1135 default_results_.verbatim_relevance = -1; |
1125 keyword_results_.verbatim_relevance = -1; | 1136 keyword_results_.verbatim_relevance = -1; |
1126 ConvertResultsToAutocompleteMatches(); | 1137 ConvertResultsToAutocompleteMatches(); |
1127 } | 1138 } |
1128 if (IsTopMatchNotInlinable()) { | 1139 if (omnibox_will_reorder_for_legal_default_match_ ? |
1129 // Disregard suggested relevances if the top match is not a verbatim match | 1140 LacksDefaultMatch() : IsTopMatchNotAllowedToBeDefaultMatch()) { |
1130 // or inlinable. For example, input "foo" should not invoke a search for | 1141 // Disregard suggested relevances if either: |
1131 // "bar", which would happen if the "bar" search match outranked all other | 1142 // * No matches are allowed to be the default match. SearchProvider is |
1132 // matches. | 1143 // supposed to return a legal default match for any input. We need |
1144 // to make sure it does so. This constraint should be true always, | |
1145 // but we only need to check it if | |
1146 // |omnibox_will_reorder_for_legal_default_match_|. (If that were | |
1147 // false, the first part of the test above will suffice.) | |
msw
2013/07/18 06:23:57
I don't follow "the first part of the test above w
Mark P
2013/07/21 20:31:05
I rewrote this comment. It was confusing because
| |
1148 // * The top match is not allowed to be the default match (i.e., it's not | |
1149 // either a verbatim match or inlinable). For example, input "foo" | |
1150 // should not invoke a search for "bar", which would happen if the | |
1151 // "bar" search match outranked all other matches. We only care | |
1152 // about this condition if the omnibox itself will not reorder | |
1153 // matches to put a legal default match on top. | |
1133 ApplyCalculatedRelevance(); | 1154 ApplyCalculatedRelevance(); |
1134 ConvertResultsToAutocompleteMatches(); | 1155 ConvertResultsToAutocompleteMatches(); |
1135 } | 1156 } |
1136 DCHECK(!IsTopMatchNavigationInKeywordMode()); | 1157 DCHECK(!IsTopMatchNavigationInKeywordMode()); |
1137 DCHECK(!IsTopMatchScoreTooLow()); | 1158 DCHECK(omnibox_will_reorder_for_legal_default_match_ || |
1159 !IsTopMatchScoreTooLow()); | |
1138 DCHECK(!IsTopMatchHighRankSearchForURL()); | 1160 DCHECK(!IsTopMatchHighRankSearchForURL()); |
1139 DCHECK(!IsTopMatchNotInlinable()); | 1161 DCHECK(omnibox_will_reorder_for_legal_default_match_ || |
1162 !IsTopMatchNotAllowedToBeDefaultMatch()); | |
1163 DCHECK(!LacksDefaultMatch()); | |
1140 } | 1164 } |
1141 | 1165 |
1142 UpdateStarredStateOfMatches(); | 1166 UpdateStarredStateOfMatches(); |
1143 UpdateDone(); | 1167 UpdateDone(); |
1144 } | 1168 } |
1145 | 1169 |
1146 void SearchProvider::AddNavigationResultsToMatches( | 1170 void SearchProvider::AddNavigationResultsToMatches( |
1147 const NavigationResults& navigation_results, | 1171 const NavigationResults& navigation_results, |
1148 ACMatches* matches) { | 1172 ACMatches* matches) { |
1149 for (NavigationResults::const_iterator it = navigation_results.begin(); | 1173 for (NavigationResults::const_iterator it = navigation_results.begin(); |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1442 | 1466 |
1443 const std::string languages( | 1467 const std::string languages( |
1444 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); | 1468 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); |
1445 const net::FormatUrlTypes format_types = | 1469 const net::FormatUrlTypes format_types = |
1446 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP); | 1470 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP); |
1447 match.fill_into_edit += | 1471 match.fill_into_edit += |
1448 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(), | 1472 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(), |
1449 net::FormatUrl(navigation.url(), languages, format_types, | 1473 net::FormatUrl(navigation.url(), languages, format_types, |
1450 net::UnescapeRule::SPACES, NULL, NULL, | 1474 net::UnescapeRule::SPACES, NULL, NULL, |
1451 &inline_autocomplete_offset)); | 1475 &inline_autocomplete_offset)); |
1452 if (!input_.prevent_inline_autocomplete()) | 1476 if (!input_.prevent_inline_autocomplete()) { |
1477 match.allowed_to_be_default_match = | |
1478 (inline_autocomplete_offset != string16::npos); | |
1453 match.inline_autocomplete_offset = inline_autocomplete_offset; | 1479 match.inline_autocomplete_offset = inline_autocomplete_offset; |
1480 } | |
1454 DCHECK((match.inline_autocomplete_offset == string16::npos) || | 1481 DCHECK((match.inline_autocomplete_offset == string16::npos) || |
1455 (match.inline_autocomplete_offset <= match.fill_into_edit.length())); | 1482 (match.inline_autocomplete_offset <= match.fill_into_edit.length())); |
1456 | 1483 |
1457 match.contents = net::FormatUrl(navigation.url(), languages, | 1484 match.contents = net::FormatUrl(navigation.url(), languages, |
1458 format_types, net::UnescapeRule::SPACES, NULL, NULL, &match_start); | 1485 format_types, net::UnescapeRule::SPACES, NULL, NULL, &match_start); |
1459 // If the first match in the untrimmed string was inside a scheme that we | 1486 // If the first match in the untrimmed string was inside a scheme that we |
1460 // trimmed, look for a subsequent match. | 1487 // trimmed, look for a subsequent match. |
1461 if (match_start == string16::npos) | 1488 if (match_start == string16::npos) |
1462 match_start = match.contents.find(input); | 1489 match_start = match.contents.find(input); |
1463 // Safe if |match_start| is npos; also safe if the input is longer than the | 1490 // Safe if |match_start| is npos; also safe if the input is longer than the |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1516 it->set_relevance(max_query_relevance); | 1543 it->set_relevance(max_query_relevance); |
1517 it->set_relevance_from_server(relevance_from_server); | 1544 it->set_relevance_from_server(relevance_from_server); |
1518 } | 1545 } |
1519 } | 1546 } |
1520 | 1547 |
1521 void SearchProvider::UpdateDone() { | 1548 void SearchProvider::UpdateDone() { |
1522 // We're done when the timer isn't running, there are no suggest queries | 1549 // We're done when the timer isn't running, there are no suggest queries |
1523 // pending, and we're not waiting on Instant. | 1550 // pending, and we're not waiting on Instant. |
1524 done_ = !timer_.IsRunning() && (suggest_results_pending_ == 0); | 1551 done_ = !timer_.IsRunning() && (suggest_results_pending_ == 0); |
1525 } | 1552 } |
OLD | NEW |