omnibox_ui_handler.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright (c) 2012 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/webui/omnibox/omnibox_ui_handler.h" 6 7#include <string> 8 9#include "base/auto_reset.h" 10#include "base/bind.h" 11#include "base/strings/string16.h" 12#include "base/strings/stringprintf.h" 13#include "base/strings/utf_string_conversions.h" 14#include "base/time/time.h" 15#include "base/values.h" 16#include "chrome/browser/autocomplete/autocomplete_classifier.h" 17#include "chrome/browser/autocomplete/autocomplete_controller.h" 18#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" 19#include "chrome/browser/bookmarks/bookmark_model_factory.h" 20#include "chrome/browser/history/history_service.h" 21#include "chrome/browser/history/history_service_factory.h" 22#include "chrome/browser/search/search.h" 23#include "chrome/browser/search_engines/template_url_service_factory.h" 24#include "components/bookmarks/browser/bookmark_model.h" 25#include "components/history/core/browser/url_database.h" 26#include "components/metrics/proto/omnibox_event.pb.h" 27#include "components/omnibox/autocomplete_match.h" 28#include "components/omnibox/autocomplete_provider.h" 29#include "components/search_engines/template_url.h" 30#include "content/public/browser/web_ui.h" 31#include "mojo/common/common_type_converters.h" 32 33namespace mojo { 34 35template <> 36class TypeConverter<mojo::Array<AutocompleteAdditionalInfoPtr>, 37 AutocompleteMatch::AdditionalInfo> { 38 public: 39 static mojo::Array<AutocompleteAdditionalInfoPtr> ConvertFrom( 40 const AutocompleteMatch::AdditionalInfo& input) { 41 mojo::Array<AutocompleteAdditionalInfoPtr> array(input.size()); 42 size_t index = 0; 43 for (AutocompleteMatch::AdditionalInfo::const_iterator i = input.begin(); 44 i != input.end(); ++i, index++) { 45 AutocompleteAdditionalInfoPtr item(AutocompleteAdditionalInfo::New()); 46 item->key = i->first; 47 item->value = i->second; 48 array[index] = item.Pass(); 49 } 50 return array.Pass(); 51 } 52}; 53 54template <> 55class TypeConverter<AutocompleteMatchMojoPtr, AutocompleteMatch> { 56 public: 57 static AutocompleteMatchMojoPtr ConvertFrom(const AutocompleteMatch& input) { 58 AutocompleteMatchMojoPtr result(AutocompleteMatchMojo::New()); 59 if (input.provider != NULL) { 60 result->provider_name = input.provider->GetName(); 61 result->provider_done = input.provider->done(); 62 } 63 result->relevance = input.relevance; 64 result->deletable = input.deletable; 65 result->fill_into_edit = mojo::String::From(input.fill_into_edit); 66 result->inline_autocompletion = 67 mojo::String::From(input.inline_autocompletion); 68 result->destination_url = input.destination_url.spec(); 69 result->contents = mojo::String::From(input.contents); 70 // At this time, we're not bothering to send along the long vector that 71 // represent contents classification. i.e., for each character, what 72 // type of text it is. 73 result->description = mojo::String::From(input.description); 74 // At this time, we're not bothering to send along the long vector that 75 // represents description classification. i.e., for each character, what 76 // type of text it is. 77 result->transition = input.transition; 78 result->is_history_what_you_typed_match = 79 input.is_history_what_you_typed_match; 80 result->allowed_to_be_default_match = input.allowed_to_be_default_match; 81 result->type = AutocompleteMatchType::ToString(input.type); 82 if (input.associated_keyword.get() != NULL) { 83 result->associated_keyword = 84 mojo::String::From(input.associated_keyword->keyword); 85 } 86 result->keyword = mojo::String::From(input.keyword); 87 result->duplicates = static_cast<int32>(input.duplicate_matches.size()); 88 result->from_previous = input.from_previous; 89 90 result->additional_info = 91 mojo::Array<AutocompleteAdditionalInfoPtr>::From(input.additional_info); 92 return result.Pass(); 93 } 94}; 95 96template <> 97class TypeConverter<AutocompleteResultsForProviderMojoPtr, 98 scoped_refptr<AutocompleteProvider> > { 99 public: 100 static AutocompleteResultsForProviderMojoPtr ConvertFrom( 101 const scoped_refptr<AutocompleteProvider>& input) { 102 AutocompleteResultsForProviderMojoPtr result( 103 AutocompleteResultsForProviderMojo::New()); 104 result->provider_name = input->GetName(); 105 result->results = 106 mojo::Array<AutocompleteMatchMojoPtr>::From(input->matches()); 107 return result.Pass(); 108 } 109}; 110 111} // namespace mojo 112 113OmniboxUIHandler::OmniboxUIHandler(Profile* profile) 114 : profile_(profile) { 115 ResetController(); 116} 117 118OmniboxUIHandler::~OmniboxUIHandler() {} 119 120void OmniboxUIHandler::OnResultChanged(bool default_match_changed) { 121 OmniboxResultMojoPtr result(OmniboxResultMojo::New()); 122 result->done = controller_->done(); 123 result->time_since_omnibox_started_ms = 124 (base::Time::Now() - time_omnibox_started_).InMilliseconds(); 125 const base::string16 host = input_.text().substr( 126 input_.parts().host.begin, 127 input_.parts().host.len); 128 result->host = mojo::String::From(host); 129 bool is_typed_host; 130 if (!LookupIsTypedHost(host, &is_typed_host)) 131 is_typed_host = false; 132 result->is_typed_host = is_typed_host; 133 134 { 135 // Copy to an ACMatches to make conversion easier. Since this isn't 136 // performance critical we don't worry about the cost here. 137 ACMatches matches(controller_->result().begin(), 138 controller_->result().end()); 139 result->combined_results = 140 mojo::Array<AutocompleteMatchMojoPtr>::From(matches); 141 } 142 result->results_by_provider = 143 mojo::Array<AutocompleteResultsForProviderMojoPtr>::From( 144 controller_->providers()); 145 146 // Fill AutocompleteMatchMojo::starred. 147 BookmarkModel* bookmark_model = BookmarkModelFactory::GetForProfile(profile_); 148 if (bookmark_model) { 149 for (size_t i = 0; i < result->combined_results.size(); ++i) { 150 result->combined_results[i]->starred = bookmark_model->IsBookmarked( 151 GURL(result->combined_results[i]->destination_url)); 152 } 153 for (size_t i = 0; i < result->results_by_provider.size(); ++i) { 154 const AutocompleteResultsForProviderMojo& result_by_provider = 155 *result->results_by_provider[i]; 156 for (size_t j = 0; j < result_by_provider.results.size(); ++j) { 157 result_by_provider.results[j]->starred = bookmark_model->IsBookmarked( 158 GURL(result_by_provider.results[j]->destination_url)); 159 } 160 } 161 } 162 163 client()->HandleNewAutocompleteResult(result.Pass()); 164} 165 166bool OmniboxUIHandler::LookupIsTypedHost(const base::string16& host, 167 bool* is_typed_host) const { 168 HistoryService* const history_service = 169 HistoryServiceFactory::GetForProfile(profile_, 170 Profile::EXPLICIT_ACCESS); 171 if (!history_service) 172 return false; 173 history::URLDatabase* url_db = history_service->InMemoryDatabase(); 174 if (!url_db) 175 return false; 176 *is_typed_host = url_db->IsTypedHost(base::UTF16ToUTF8(host)); 177 return true; 178} 179 180void OmniboxUIHandler::StartOmniboxQuery(const mojo::String& input_string, 181 int32_t cursor_position, 182 bool prevent_inline_autocomplete, 183 bool prefer_keyword, 184 int32_t page_classification) { 185 // Reset the controller. If we don't do this, then the 186 // AutocompleteController might inappropriately set its |minimal_changes| 187 // variable (or something else) and some providers will short-circuit 188 // important logic and return stale results. In short, we want the 189 // actual results to not depend on the state of the previous request. 190 ResetController(); 191 time_omnibox_started_ = base::Time::Now(); 192 input_ = AutocompleteInput( 193 input_string.To<base::string16>(), cursor_position, base::string16(), 194 GURL(), 195 static_cast<metrics::OmniboxEventProto::PageClassification>( 196 page_classification), 197 prevent_inline_autocomplete, prefer_keyword, true, true, 198 ChromeAutocompleteSchemeClassifier(profile_)); 199 controller_->Start(input_); 200} 201 202void OmniboxUIHandler::ResetController() { 203 controller_.reset(new AutocompleteController(profile_, 204 TemplateURLServiceFactory::GetForProfile(profile_), 205 this, 206 AutocompleteClassifier::kDefaultOmniboxProviders)); 207} 208