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