1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/omnibox/omnibox_controller.h" 6 7 #include "base/metrics/histogram.h" 8 #include "chrome/browser/autocomplete/autocomplete_classifier.h" 9 #include "chrome/browser/autocomplete/autocomplete_match.h" 10 #include "chrome/browser/autocomplete/search_provider.h" 11 #include "chrome/browser/net/predictor.h" 12 #include "chrome/browser/predictors/autocomplete_action_predictor.h" 13 #include "chrome/browser/prerender/prerender_field_trial.h" 14 #include "chrome/browser/prerender/prerender_manager.h" 15 #include "chrome/browser/prerender/prerender_manager_factory.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/search/search.h" 18 #include "chrome/browser/ui/omnibox/omnibox_edit_controller.h" 19 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" 20 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" 21 #include "chrome/browser/ui/omnibox/omnibox_popup_view.h" 22 #include "extensions/common/constants.h" 23 #include "ui/gfx/rect.h" 24 25 26 OmniboxController::OmniboxController(OmniboxEditModel* omnibox_edit_model, 27 Profile* profile) 28 : omnibox_edit_model_(omnibox_edit_model), 29 profile_(profile) { 30 autocomplete_controller_.reset(new AutocompleteController(profile, this, 31 chrome::IsInstantExtendedAPIEnabled() ? 32 AutocompleteClassifier::kInstantExtendedOmniboxProviders : 33 AutocompleteClassifier::kDefaultOmniboxProviders)); 34 } 35 36 OmniboxController::~OmniboxController() { 37 } 38 39 void OmniboxController::StartAutocomplete( 40 string16 user_text, 41 size_t cursor_position, 42 const GURL& current_url, 43 AutocompleteInput::PageClassification current_page_classification, 44 bool prevent_inline_autocomplete, 45 bool prefer_keyword, 46 bool allow_exact_keyword_match) const { 47 ClearPopupKeywordMode(); 48 popup_->SetHoveredLine(OmniboxPopupModel::kNoMatch); 49 50 // We don't explicitly clear OmniboxPopupModel::manually_selected_match, as 51 // Start ends up invoking OmniboxPopupModel::OnResultChanged which clears it. 52 autocomplete_controller_->Start(AutocompleteInput( 53 user_text, cursor_position, string16(), current_url, 54 current_page_classification, prevent_inline_autocomplete, 55 prefer_keyword, allow_exact_keyword_match, 56 AutocompleteInput::ALL_MATCHES)); 57 } 58 59 void OmniboxController::OnResultChanged(bool default_match_changed) { 60 const bool was_open = popup_->IsOpen(); 61 if (default_match_changed) { 62 // The default match has changed, we need to let the OmniboxEditModel know 63 // about new inline autocomplete text (blue highlight). 64 const AutocompleteResult& result = this->result(); 65 const AutocompleteResult::const_iterator match(result.default_match()); 66 if (match != result.end()) { 67 current_match_ = *match; 68 if (!prerender::IsOmniboxEnabled(profile_)) 69 DoPreconnect(*match); 70 omnibox_edit_model_->OnCurrentMatchChanged(); 71 } else { 72 InvalidateCurrentMatch(); 73 popup_->OnResultChanged(); 74 omnibox_edit_model_->OnPopupDataChanged(string16(), NULL, string16(), 75 false); 76 } 77 } else { 78 popup_->OnResultChanged(); 79 } 80 81 if (!popup_->IsOpen() && was_open) { 82 // Accept the temporary text as the user text, because it makes little sense 83 // to have temporary text when the popup is closed. 84 omnibox_edit_model_->AcceptTemporaryTextAsUserText(); 85 } 86 } 87 88 void OmniboxController::InvalidateCurrentMatch() { 89 current_match_ = AutocompleteMatch(); 90 } 91 92 void OmniboxController::ClearPopupKeywordMode() const { 93 if (popup_->IsOpen() && 94 popup_->selected_line_state() == OmniboxPopupModel::KEYWORD) 95 popup_->SetSelectedLineState(OmniboxPopupModel::NORMAL); 96 } 97 98 void OmniboxController::DoPreconnect(const AutocompleteMatch& match) { 99 if (!match.destination_url.SchemeIs(extensions::kExtensionScheme)) { 100 // Warm up DNS Prefetch cache, or preconnect to a search service. 101 UMA_HISTOGRAM_ENUMERATION("Autocomplete.MatchType", match.type, 102 AutocompleteMatchType::NUM_TYPES); 103 if (profile_->GetNetworkPredictor()) { 104 profile_->GetNetworkPredictor()->AnticipateOmniboxUrl( 105 match.destination_url, 106 predictors::AutocompleteActionPredictor::IsPreconnectable(match)); 107 } 108 // We could prefetch the alternate nav URL, if any, but because there 109 // can be many of these as a user types an initial series of characters, 110 // the OS DNS cache could suffer eviction problems for minimal gain. 111 } 112 } 113