Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: chrome/browser/autocomplete/search_provider.cc

Issue 67693004: Omnibox: Don't Let Users Escape Keyword Mode Accidentally (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: new approach Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 1190 matching lines...) Expand 10 before | Expand all | Expand 10 after
1201 std::string(), 1201 std::string(),
1202 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 1202 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
1203 false, 1203 false,
1204 input_.text(), 1204 input_.text(),
1205 string16(), 1205 string16(),
1206 input_.text(), 1206 input_.text(),
1207 did_not_accept_default_suggestion, 1207 did_not_accept_default_suggestion,
1208 std::string(), 1208 std::string(),
1209 &map); 1209 &map);
1210 } 1210 }
1211 const TemplateURL* keyword_url = NULL;
1211 if (!keyword_input_.text().empty()) { 1212 if (!keyword_input_.text().empty()) {
1212 const TemplateURL* keyword_url = providers_.GetKeywordProviderURL(); 1213 keyword_url = providers_.GetKeywordProviderURL();
1213 // We only create the verbatim search query match for a keyword 1214 // We only create the verbatim search query match for a keyword
1214 // if it's not an extension keyword. Extension keywords are handled 1215 // if it's not an extension keyword. Extension keywords are handled
1215 // in KeywordProvider::Start(). (Extensions are complicated...) 1216 // in KeywordProvider::Start(). (Extensions are complicated...)
1216 // Note: in this provider, SEARCH_OTHER_ENGINE must correspond 1217 // Note: in this provider, SEARCH_OTHER_ENGINE must correspond
1217 // to the keyword verbatim search query. Do not create other matches 1218 // to the keyword verbatim search query. Do not create other matches
1218 // of type SEARCH_OTHER_ENGINE. 1219 // of type SEARCH_OTHER_ENGINE.
1219 if (keyword_url && 1220 if (keyword_url &&
1220 (keyword_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION)) { 1221 (keyword_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION)) {
1221 bool keyword_relevance_from_server; 1222 bool keyword_relevance_from_server;
1222 const int keyword_verbatim_relevance = 1223 const int keyword_verbatim_relevance =
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1300 ACMatches::const_iterator SearchProvider::FindTopMatch( 1301 ACMatches::const_iterator SearchProvider::FindTopMatch(
1301 bool autocomplete_result_will_reorder_for_default_match) const { 1302 bool autocomplete_result_will_reorder_for_default_match) const {
1302 if (!autocomplete_result_will_reorder_for_default_match) 1303 if (!autocomplete_result_will_reorder_for_default_match)
1303 return matches_.begin(); 1304 return matches_.begin();
1304 ACMatches::const_iterator it = matches_.begin(); 1305 ACMatches::const_iterator it = matches_.begin();
1305 while ((it != matches_.end()) && !it->allowed_to_be_default_match) 1306 while ((it != matches_.end()) && !it->allowed_to_be_default_match)
1306 ++it; 1307 ++it;
1307 return it; 1308 return it;
1308 } 1309 }
1309 1310
1310 bool SearchProvider::IsTopMatchNavigationInKeywordMode( 1311 bool SearchProvider::IsTopMatchNavigation(
1311 bool autocomplete_result_will_reorder_for_default_match) const { 1312 bool autocomplete_result_will_reorder_for_default_match) const {
1312 ACMatches::const_iterator first_match = 1313 ACMatches::const_iterator first_match =
1313 FindTopMatch(autocomplete_result_will_reorder_for_default_match); 1314 FindTopMatch(autocomplete_result_will_reorder_for_default_match);
1314 return !providers_.keyword_provider().empty() && 1315 return (first_match != matches_.end()) &&
1315 (first_match != matches_.end()) &&
1316 (first_match->type == AutocompleteMatchType::NAVSUGGEST); 1316 (first_match->type == AutocompleteMatchType::NAVSUGGEST);
1317 } 1317 }
1318 1318
1319 bool SearchProvider::HasKeywordMatchThatCanBeDefault(
1320 bool autocomplete_result_will_reorder_for_default_match) const {
1321 // In regular (non-reorder) mode we don't care about the
1322 // |allowed_to_be_default_match| state, so return true saying
1323 // everything is fine.
1324 if (!autocomplete_result_will_reorder_for_default_match)
1325 return true;
1326 const TemplateURL* keyword_url = providers_.GetKeywordProviderURL();
1327 if (keyword_url == NULL) // not in keyword mode -> say everything's okay
1328 return true;
1329 for (ACMatches::const_iterator it = matches_.begin(); it != matches_.end();
1330 ++it) {
1331 if ((it->keyword == keyword_url->keyword()) &&
1332 it->allowed_to_be_default_match)
1333 return true;
1334 }
1335 return false;
1336 }
1337
1319 bool SearchProvider::IsTopMatchScoreTooLow( 1338 bool SearchProvider::IsTopMatchScoreTooLow(
1320 bool autocomplete_result_will_reorder_for_default_match) const { 1339 bool autocomplete_result_will_reorder_for_default_match) const {
1321 // In reorder mode, there's no such thing as a score that's too low. 1340 // In reorder mode, there's no such thing as a score that's too low.
1322 if (autocomplete_result_will_reorder_for_default_match) 1341 if (autocomplete_result_will_reorder_for_default_match)
1323 return false; 1342 return false;
1324 1343
1325 // Here we use CalculateRelevanceForVerbatimIgnoringKeywordModeState() 1344 // Here we use CalculateRelevanceForVerbatimIgnoringKeywordModeState()
1326 // rather than CalculateRelevanceForVerbatim() because the latter returns 1345 // rather than CalculateRelevanceForVerbatim() because the latter returns
1327 // a very low score (250) if keyword mode is active. This is because 1346 // a very low score (250) if keyword mode is active. This is because
1328 // when keyword mode is active the user probably wants the keyword matches, 1347 // when keyword mode is active the user probably wants the keyword matches,
(...skipping 28 matching lines...) Expand all
1357 if (it->allowed_to_be_default_match) 1376 if (it->allowed_to_be_default_match)
1358 return true; 1377 return true;
1359 if (!autocomplete_result_will_reorder_for_default_match) 1378 if (!autocomplete_result_will_reorder_for_default_match)
1360 return false; 1379 return false;
1361 } 1380 }
1362 return false; 1381 return false;
1363 } 1382 }
1364 1383
1365 void SearchProvider::UpdateMatches() { 1384 void SearchProvider::UpdateMatches() {
1366 base::TimeTicks update_matches_start_time(base::TimeTicks::Now()); 1385 base::TimeTicks update_matches_start_time(base::TimeTicks::Now());
1386 const TemplateURL* keyword_url = providers_.GetKeywordProviderURL();
1367 ConvertResultsToAutocompleteMatches(); 1387 ConvertResultsToAutocompleteMatches();
1368 1388
1389 // True if the omnibox will reorder matches as necessary to make the first
1390 // one something that is allowed to be the default match.
1391 const bool omnibox_will_reorder_for_legal_default_match =
1392 OmniboxFieldTrial::ReorderForLegalDefaultMatch(
1393 input_.current_page_classification());
1394
1369 // Check constraints that may be violated by suggested relevances. 1395 // Check constraints that may be violated by suggested relevances.
1370 if (!matches_.empty() && 1396 if (!matches_.empty() &&
1371 (default_results_.HasServerProvidedScores() || 1397 (default_results_.HasServerProvidedScores() ||
1372 keyword_results_.HasServerProvidedScores())) { 1398 keyword_results_.HasServerProvidedScores())) {
1373 // These blocks attempt to repair undesirable behavior by suggested 1399 // These blocks attempt to repair undesirable behavior by suggested
1374 // relevances with minimal impact, preserving other suggested relevances. 1400 // relevances with minimal impact, preserving other suggested relevances.
1375 1401
1376 // True if the omnibox will reorder matches as necessary to make the first 1402 if ((keyword_url != NULL) &&
1377 // one something that is allowed to be the default match. 1403 IsTopMatchNavigation(omnibox_will_reorder_for_legal_default_match)) {
1378 const bool omnibox_will_reorder_for_legal_default_match =
1379 OmniboxFieldTrial::ReorderForLegalDefaultMatch(
1380 input_.current_page_classification());
1381 if (IsTopMatchNavigationInKeywordMode(
1382 omnibox_will_reorder_for_legal_default_match)) {
1383 // Correct the suggested relevance scores if the top match is a 1404 // Correct the suggested relevance scores if the top match is a
1384 // navigation in keyword mode, since inlining a navigation match 1405 // navigation in keyword mode, since inlining a navigation match
1385 // would break the user out of keyword mode. By the way, if the top 1406 // would break the user out of keyword mode. We only need to do this
1386 // match is a non-keyword match (query or navsuggestion) in keyword 1407 // correction in regular (non-reorder) mode; in reorder mode, we rely
1387 // mode, the user would also break out of keyword mode. However, 1408 // on the fact that navigation matches are marked as not allowed to be
1388 // that situation is impossible given the current scoring paradigm 1409 // the default match.
1389 // and the fact that only one search engine (Google) provides suggested
1390 // relevance scores at this time.
1391 DemoteKeywordNavigationMatchesPastTopQuery(); 1410 DemoteKeywordNavigationMatchesPastTopQuery();
1392 ConvertResultsToAutocompleteMatches(); 1411 ConvertResultsToAutocompleteMatches();
1393 DCHECK(!IsTopMatchNavigationInKeywordMode( 1412 DCHECK(!IsTopMatchNavigation(
1394 omnibox_will_reorder_for_legal_default_match)); 1413 omnibox_will_reorder_for_legal_default_match));
1395 } 1414 }
1415 if ((keyword_url != NULL) && !HasKeywordMatchThatCanBeDefault(
1416 omnibox_will_reorder_for_legal_default_match)) {
1417 // In keyword mode, disregard the keyword verbatim suggested relevance
1418 // if necessary so there at least one keyword match that's allowed to
1419 // be the default match.
1420 keyword_results_.verbatim_relevance = -1;
1421 ConvertResultsToAutocompleteMatches();
1422 }
1396 if (IsTopMatchScoreTooLow(omnibox_will_reorder_for_legal_default_match)) { 1423 if (IsTopMatchScoreTooLow(omnibox_will_reorder_for_legal_default_match)) {
1397 // Disregard the suggested verbatim relevance if the top score is below 1424 // Disregard the suggested verbatim relevance if the top score is below
1398 // the usual verbatim value. For example, a BarProvider may rely on 1425 // the usual verbatim value. For example, a BarProvider may rely on
1399 // SearchProvider's verbatim or inlineable matches for input "foo" (all 1426 // SearchProvider's verbatim or inlineable matches for input "foo" (all
1400 // allowed to be default match) to always outrank its own lowly-ranked 1427 // allowed to be default match) to always outrank its own lowly-ranked
1401 // "bar" matches that shouldn't be the default match. 1428 // "bar" matches that shouldn't be the default match.
1402 default_results_.verbatim_relevance = -1; 1429 default_results_.verbatim_relevance = -1;
1403 keyword_results_.verbatim_relevance = -1; 1430 keyword_results_.verbatim_relevance = -1;
1404 ConvertResultsToAutocompleteMatches(); 1431 ConvertResultsToAutocompleteMatches();
1405 } 1432 }
(...skipping 16 matching lines...) Expand all
1422 // match or inlinable). For example, input "foo" should not invoke a 1449 // match or inlinable). For example, input "foo" should not invoke a
1423 // search for "bar", which would happen if the "bar" search match 1450 // search for "bar", which would happen if the "bar" search match
1424 // outranked all other matches. On the other hand, if the omnibox will 1451 // outranked all other matches. On the other hand, if the omnibox will
1425 // reorder matches as necessary to put a legal default match at the top, 1452 // reorder matches as necessary to put a legal default match at the top,
1426 // all we need to guarantee is that SearchProvider returns a legal 1453 // all we need to guarantee is that SearchProvider returns a legal
1427 // default match. (The omnibox always needs at least one legal default 1454 // default match. (The omnibox always needs at least one legal default
1428 // match, and it relies on SearchProvider to always return one.) 1455 // match, and it relies on SearchProvider to always return one.)
1429 ApplyCalculatedRelevance(); 1456 ApplyCalculatedRelevance();
1430 ConvertResultsToAutocompleteMatches(); 1457 ConvertResultsToAutocompleteMatches();
1431 } 1458 }
1432 DCHECK(!IsTopMatchNavigationInKeywordMode( 1459 DCHECK((keyword_url == NULL) ||
1460 !IsTopMatchNavigation(omnibox_will_reorder_for_legal_default_match));
1461 DCHECK((keyword_url == NULL) || HasKeywordMatchThatCanBeDefault(
1433 omnibox_will_reorder_for_legal_default_match)); 1462 omnibox_will_reorder_for_legal_default_match));
1434 DCHECK(!IsTopMatchScoreTooLow( 1463 DCHECK(!IsTopMatchScoreTooLow(
1435 omnibox_will_reorder_for_legal_default_match)); 1464 omnibox_will_reorder_for_legal_default_match));
1436 DCHECK(!IsTopMatchSearchWithURLInput( 1465 DCHECK(!IsTopMatchSearchWithURLInput(
1437 omnibox_will_reorder_for_legal_default_match)); 1466 omnibox_will_reorder_for_legal_default_match));
1438 DCHECK(HasValidDefaultMatch(omnibox_will_reorder_for_legal_default_match)); 1467 DCHECK(HasValidDefaultMatch(omnibox_will_reorder_for_legal_default_match));
1439 } 1468 }
1440 1469
1470 if ((keyword_url != NULL) && HasKeywordMatchThatCanBeDefault(
1471 omnibox_will_reorder_for_legal_default_match)) {
1472 // If there is a keyword match that is allowed to be the default match,
Mark P 2013/11/17 02:18:34 I can move this block into a subroutine if you app
1473 // then prohibit default provider matches from being the defaul match lest
1474 // such matches cause the user to break out of keyword mode.
1475 for (ACMatches::const_iterator keyword_match_it = matches_.begin();
1476 keyword_match_it != matches_.end(); ++keyword_match_it) {
1477 if (keyword_match_it->allowed_to_be_default_match &&
1478 (keyword_match_it->keyword == keyword_url->keyword())) {
1479 // Found one such match.
1480 for (ACMatches::iterator it = matches_.begin(); it != matches_.end();
1481 ++it) {
1482 if (it->keyword != keyword_url->keyword())
1483 it->allowed_to_be_default_match = false;
1484 }
1485 break;
1486 }
1487 }
1488 }
1489
1441 base::TimeTicks update_starred_start_time(base::TimeTicks::Now()); 1490 base::TimeTicks update_starred_start_time(base::TimeTicks::Now());
1442 UpdateStarredStateOfMatches(); 1491 UpdateStarredStateOfMatches();
1443 UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.UpdateStarredTime", 1492 UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.UpdateStarredTime",
1444 base::TimeTicks::Now() - update_starred_start_time); 1493 base::TimeTicks::Now() - update_starred_start_time);
1445 UpdateDone(); 1494 UpdateDone();
1446 UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.UpdateMatchesTime", 1495 UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.UpdateMatchesTime",
1447 base::TimeTicks::Now() - update_matches_start_time); 1496 base::TimeTicks::Now() - update_matches_start_time);
1448 } 1497 }
1449 1498
1450 void SearchProvider::AddNavigationResultsToMatches( 1499 void SearchProvider::AddNavigationResultsToMatches(
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after
1832 // Preserve the forced query '?' prefix in |match.fill_into_edit|. 1881 // Preserve the forced query '?' prefix in |match.fill_into_edit|.
1833 // Otherwise, user edits to a suggestion would show non-Search results. 1882 // Otherwise, user edits to a suggestion would show non-Search results.
1834 if (input_.type() == AutocompleteInput::FORCED_QUERY) { 1883 if (input_.type() == AutocompleteInput::FORCED_QUERY) {
1835 match.fill_into_edit.insert(0, ASCIIToUTF16("?")); 1884 match.fill_into_edit.insert(0, ASCIIToUTF16("?"));
1836 if (inline_autocomplete_offset != string16::npos) 1885 if (inline_autocomplete_offset != string16::npos)
1837 ++inline_autocomplete_offset; 1886 ++inline_autocomplete_offset;
1838 } 1887 }
1839 if (!input_.prevent_inline_autocomplete() && 1888 if (!input_.prevent_inline_autocomplete() &&
1840 (inline_autocomplete_offset != string16::npos)) { 1889 (inline_autocomplete_offset != string16::npos)) {
1841 DCHECK(inline_autocomplete_offset <= match.fill_into_edit.length()); 1890 DCHECK(inline_autocomplete_offset <= match.fill_into_edit.length());
1842 match.allowed_to_be_default_match = true; 1891 // Navsuggestions can only be the default match when there is no
1892 // keyword provider active lest it appears first and breaks the user
1893 // out of keyword mode.
1894 match.allowed_to_be_default_match =
1895 (providers_.GetKeywordProviderURL() == NULL);
1843 match.inline_autocompletion = 1896 match.inline_autocompletion =
1844 match.fill_into_edit.substr(inline_autocomplete_offset); 1897 match.fill_into_edit.substr(inline_autocomplete_offset);
1845 } 1898 }
1846 1899
1847 match.contents = net::FormatUrl(navigation.url(), languages, 1900 match.contents = net::FormatUrl(navigation.url(), languages,
1848 format_types, net::UnescapeRule::SPACES, NULL, NULL, &match_start); 1901 format_types, net::UnescapeRule::SPACES, NULL, NULL, &match_start);
1849 // If the first match in the untrimmed string was inside a scheme that we 1902 // If the first match in the untrimmed string was inside a scheme that we
1850 // trimmed, look for a subsequent match. 1903 // trimmed, look for a subsequent match.
1851 if (match_start == string16::npos) 1904 if (match_start == string16::npos)
1852 match_start = match.contents.find(input); 1905 match_start = match.contents.find(input);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1907 it->set_relevance(max_query_relevance); 1960 it->set_relevance(max_query_relevance);
1908 it->set_relevance_from_server(relevance_from_server); 1961 it->set_relevance_from_server(relevance_from_server);
1909 } 1962 }
1910 } 1963 }
1911 1964
1912 void SearchProvider::UpdateDone() { 1965 void SearchProvider::UpdateDone() {
1913 // We're done when the timer isn't running, there are no suggest queries 1966 // We're done when the timer isn't running, there are no suggest queries
1914 // pending, and we're not waiting on Instant. 1967 // pending, and we're not waiting on Instant.
1915 done_ = !timer_.IsRunning() && (suggest_results_pending_ == 0); 1968 done_ = !timer_.IsRunning() && (suggest_results_pending_ == 0);
1916 } 1969 }
OLDNEW
« no previous file with comments | « chrome/browser/autocomplete/search_provider.h ('k') | chrome/browser/autocomplete/search_provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698