1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_controller.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/metrics/histogram.h" 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_classifier.h" 990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/net/predictor.h" 1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/predictors/autocomplete_action_predictor.h" 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/prerender/prerender_field_trial.h" 1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/prerender/prerender_manager.h" 1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/prerender/prerender_manager_factory.h" 1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/profiles/profile.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/search/search.h" 16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/search_engines/template_url_service_factory.h" 1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_edit_controller.h" 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_edit_model.h" 1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_popup_model.h" 2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_popup_view.h" 21424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/common/instant_types.h" 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/omnibox/autocomplete_match.h" 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/omnibox/search_provider.h" 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/search/search.h" 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "extensions/common/constants.h" 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gfx/rect.h" 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 28424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace { 29424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 30424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Returns the AutocompleteMatch that the InstantController should prefetch, if 31424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// any. 32424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// 33424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// The SearchProvider may mark some suggestions to be prefetched based on 34424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// instructions from the suggest server. If such a match ranks sufficiently 356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// highly or if kAllowPrefetchNonDefaultMatch field trial is enabled, we'll 366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// return it. 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// 386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// If the kAllowPrefetchNonDefaultMatch field trial is enabled we return the 396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// prefetch suggestion even if it is not the default match. Otherwise we only 406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// care about matches that are the default or the very first entry in the 416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// dropdown (which can happen for non-default matches only if we're hiding a top 426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// verbatim match) or the second entry in the dropdown (which can happen for 436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// non-default matches when a top verbatim match is shown); for other matches, 446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// we think the likelihood of the user selecting them is low enough that 456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// prefetching isn't worth doing. 46424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const AutocompleteMatch* GetMatchToPrefetch(const AutocompleteResult& result) { 476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (chrome::ShouldAllowPrefetchNonDefaultMatch()) { 486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const AutocompleteResult::const_iterator prefetch_match = std::find_if( 496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) result.begin(), result.end(), SearchProvider::ShouldPrefetch); 506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return prefetch_match != result.end() ? &(*prefetch_match) : NULL; 516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If the default match should be prefetched, do that. 54424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) const AutocompleteResult::const_iterator default_match( 55424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) result.default_match()); 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if ((default_match != result.end()) && 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SearchProvider::ShouldPrefetch(*default_match)) 58424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return &(*default_match); 59424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Otherwise, if the top match is a verbatim match and the very next match 616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // is prefetchable, fetch that. 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if ((result.ShouldHideTopMatch() || 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result.TopMatchIsStandaloneVerbatimMatch()) && 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) (result.size() > 1) && 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SearchProvider::ShouldPrefetch(result.match_at(1))) 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return &result.match_at(1); 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return NULL; 69424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 70424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 71424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} // namespace 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)OmniboxController::OmniboxController(OmniboxEditModel* omnibox_edit_model, 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Profile* profile) 7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) : omnibox_edit_model_(omnibox_edit_model), 764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) profile_(profile), 77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) popup_(NULL), 78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch autocomplete_controller_(new AutocompleteController(profile, 79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch TemplateURLServiceFactory::GetForProfile(profile), this, 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) AutocompleteClassifier::kDefaultOmniboxProviders)) { 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)OmniboxController::~OmniboxController() { 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void OmniboxController::StartAutocomplete( 875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const AutocompleteInput& input) const { 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ClearPopupKeywordMode(); 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) popup_->SetHoveredLine(OmniboxPopupModel::kNoMatch); 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // We don't explicitly clear OmniboxPopupModel::manually_selected_match, as 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Start ends up invoking OmniboxPopupModel::OnResultChanged which clears it. 935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu autocomplete_controller_->Start(input); 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void OmniboxController::OnResultChanged(bool default_match_changed) { 9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const bool was_open = popup_->IsOpen(); 9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (default_match_changed) { 9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // The default match has changed, we need to let the OmniboxEditModel know 10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // about new inline autocomplete text (blue highlight). 1016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const AutocompleteResult::const_iterator match(result().default_match()); 1026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (match != result().end()) { 1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) current_match_ = *match; 10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!prerender::IsOmniboxEnabled(profile_)) 10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) DoPreconnect(*match); 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch omnibox_edit_model_->OnCurrentMatchChanged(); 1077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } else { 1087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) InvalidateCurrentMatch(); 1097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) popup_->OnResultChanged(); 110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) omnibox_edit_model_->OnPopupDataChanged(base::string16(), NULL, 111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16(), false); 11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } else { 11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) popup_->OnResultChanged(); 11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!popup_->IsOpen() && was_open) { 11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Accept the temporary text as the user text, because it makes little sense 11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // to have temporary text when the popup is closed. 12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) omnibox_edit_model_->AcceptTemporaryTextAsUserText(); 1217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 1226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (chrome::IsInstantExtendedAPIEnabled() && 1246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ((default_match_changed && result().default_match() != result().end()) || 1256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) (chrome::ShouldAllowPrefetchNonDefaultMatch() && !result().empty()))) { 1266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) InstantSuggestion prefetch_suggestion; 1276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const AutocompleteMatch* match_to_prefetch = GetMatchToPrefetch(result()); 1286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (match_to_prefetch) { 1296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) prefetch_suggestion.text = match_to_prefetch->contents; 1306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) prefetch_suggestion.metadata = 1316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) SearchProvider::GetSuggestMetadata(*match_to_prefetch); 1326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 1336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Send the prefetch suggestion unconditionally to the InstantPage. If 1346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // there is no suggestion to prefetch, we need to send a blank query to 1356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // clear the prefetched results. 1366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) omnibox_edit_model_->SetSuggestionToPrefetch(prefetch_suggestion); 1376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void OmniboxController::InvalidateCurrentMatch() { 1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) current_match_ = AutocompleteMatch(); 1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OmniboxController::ClearPopupKeywordMode() const { 14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (popup_->IsOpen() && 14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) popup_->selected_line_state() == OmniboxPopupModel::KEYWORD) 14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) popup_->SetSelectedLineState(OmniboxPopupModel::NORMAL); 14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OmniboxController::DoPreconnect(const AutocompleteMatch& match) { 15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!match.destination_url.SchemeIs(extensions::kExtensionScheme)) { 15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Warm up DNS Prefetch cache, or preconnect to a search service. 15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Autocomplete.MatchType", match.type, 15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AutocompleteMatchType::NUM_TYPES); 15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (profile_->GetNetworkPredictor()) { 15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) profile_->GetNetworkPredictor()->AnticipateOmniboxUrl( 15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) match.destination_url, 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch predictors::AutocompleteActionPredictor::IsPreconnectable(match)); 15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // We could prefetch the alternate nav URL, if any, but because there 16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // can be many of these as a user types an initial series of characters, 16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // the OS DNS cache could suffer eviction problems for minimal gain. 16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 165