Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/ui/webui/omnibox/omnibox_ui_handler.h" | 5 #include "chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/strings/string16.h" | 11 #include "base/strings/string16.h" |
| 12 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
| 13 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 15 #include "base/values.h" | 15 #include "base/values.h" |
| 16 #include "chrome/browser/autocomplete/autocomplete_classifier.h" | 16 #include "chrome/browser/autocomplete/autocomplete_classifier.h" |
| 17 #include "chrome/browser/autocomplete/autocomplete_controller.h" | 17 #include "chrome/browser/autocomplete/autocomplete_controller.h" |
| 18 #include "chrome/browser/autocomplete/autocomplete_input.h" | 18 #include "chrome/browser/autocomplete/autocomplete_input.h" |
| 19 #include "chrome/browser/autocomplete/autocomplete_match.h" | 19 #include "chrome/browser/autocomplete/autocomplete_match.h" |
| 20 #include "chrome/browser/autocomplete/autocomplete_provider.h" | 20 #include "chrome/browser/autocomplete/autocomplete_provider.h" |
| 21 #include "chrome/browser/history/history_service.h" | 21 #include "chrome/browser/history/history_service.h" |
| 22 #include "chrome/browser/history/history_service_factory.h" | 22 #include "chrome/browser/history/history_service_factory.h" |
| 23 #include "chrome/browser/history/url_database.h" | 23 #include "chrome/browser/history/url_database.h" |
| 24 #include "chrome/browser/search/search.h" | 24 #include "chrome/browser/search/search.h" |
| 25 #include "chrome/browser/search_engines/template_url.h" | 25 #include "chrome/browser/search_engines/template_url.h" |
| 26 #include "content/public/browser/web_ui.h" | 26 #include "content/public/browser/web_ui.h" |
| 27 #include "mojo/common/common_type_converters.h" | |
| 28 #include "mojo/public/cpp/bindings/allocation_scope.h" | |
| 27 | 29 |
| 28 OmniboxUIHandler::OmniboxUIHandler(Profile* profile): profile_(profile) { | 30 // TODO(sky): remove these namespaces. |
| 31 using chrome::AutocompleteAdditionalInfo; | |
| 32 using chrome::AutocompleteMatchMojo; | |
| 33 using chrome::AutocompleteResultsForProviderMojo; | |
| 34 using chrome::OmniboxResultMojo; | |
| 35 | |
| 36 namespace mojo { | |
| 37 | |
| 38 template <> | |
| 39 class TypeConverter<mojo::Array<AutocompleteAdditionalInfo>, | |
| 40 AutocompleteMatch::AdditionalInfo> { | |
| 41 public: | |
| 42 static mojo::Array<AutocompleteAdditionalInfo> ConvertFrom( | |
| 43 const AutocompleteMatch::AdditionalInfo& input, | |
| 44 Buffer* buf) { | |
| 45 mojo::Array<AutocompleteAdditionalInfo>::Builder array_builder( | |
| 46 input.size()); | |
|
darin (slow to review)
2014/04/07 14:35:26
nit: consider passing |buf| to each of the Builder
sky
2014/04/07 14:53:23
Done.
| |
| 47 size_t index = 0; | |
| 48 for (AutocompleteMatch::AdditionalInfo::const_iterator i = input.begin(); | |
| 49 i != input.end(); ++i, index++) { | |
| 50 AutocompleteAdditionalInfo::Builder item_builder; | |
| 51 item_builder.set_key(i->first); | |
| 52 item_builder.set_value(i->second); | |
| 53 array_builder[index] = item_builder.Finish(); | |
| 54 } | |
| 55 return array_builder.Finish(); | |
| 56 } | |
| 57 }; | |
| 58 | |
| 59 template <> | |
| 60 class TypeConverter<AutocompleteMatchMojo, AutocompleteMatch> { | |
| 61 public: | |
| 62 static AutocompleteMatchMojo ConvertFrom(const AutocompleteMatch& input, | |
| 63 Buffer* buf) { | |
| 64 AutocompleteMatchMojo::Builder builder; | |
| 65 if (input.provider != NULL) { | |
| 66 builder.set_provider_name(input.provider->GetName()); | |
| 67 builder.set_provider_done(input.provider->done()); | |
| 68 } | |
| 69 builder.set_relevance(input.relevance); | |
| 70 builder.set_deletable(input.deletable); | |
| 71 builder.set_fill_into_edit(input.fill_into_edit); | |
| 72 builder.set_inline_autocompletion(input.inline_autocompletion); | |
| 73 builder.set_destination_url(input.destination_url.spec()); | |
| 74 builder.set_contents(input.contents); | |
| 75 // At this time, we're not bothering to send along the long vector that | |
| 76 // represent contents classification. i.e., for each character, what | |
| 77 // type of text it is. | |
| 78 builder.set_description(input.description); | |
| 79 // At this time, we're not bothering to send along the long vector that | |
| 80 // represents description classification. i.e., for each character, what | |
| 81 // type of text it is. | |
| 82 builder.set_transition(input.transition); | |
| 83 builder.set_is_history_what_you_typed_match( | |
| 84 input.is_history_what_you_typed_match); | |
| 85 builder.set_allowed_to_be_default_match(input.allowed_to_be_default_match); | |
| 86 builder.set_type(AutocompleteMatchType::ToString(input.type)); | |
| 87 if (input.associated_keyword.get() != NULL) | |
| 88 builder.set_associated_keyword(input.associated_keyword->keyword); | |
| 89 builder.set_keyword(input.keyword); | |
| 90 builder.set_starred(input.starred); | |
| 91 builder.set_duplicates(static_cast<int>(input.duplicate_matches.size())); | |
|
darin (slow to review)
2014/04/07 14:35:26
nit: you might want to be explicit here: int -> in
sky
2014/04/07 14:53:23
Done.
| |
| 92 builder.set_from_previous(input.from_previous); | |
| 93 | |
| 94 builder.set_additional_info(input.additional_info); | |
| 95 return builder.Finish(); | |
| 96 } | |
| 97 }; | |
| 98 | |
| 99 template <> | |
| 100 class TypeConverter<AutocompleteResultsForProviderMojo, AutocompleteProvider*> { | |
| 101 public: | |
| 102 static AutocompleteResultsForProviderMojo ConvertFrom( | |
| 103 const AutocompleteProvider* input, | |
| 104 Buffer* buf) { | |
| 105 AutocompleteResultsForProviderMojo::Builder builder; | |
| 106 builder.set_provider_name(input->GetName()); | |
| 107 builder.set_results(input->matches()); | |
| 108 return builder.Finish(); | |
| 109 } | |
| 110 }; | |
| 111 | |
| 112 } // namespace mojo | |
| 113 | |
| 114 OmniboxUIHandler::OmniboxUIHandler(chrome::ScopedOmniboxPageHandle handle, | |
| 115 Profile* profile) | |
| 116 : page_(handle.Pass(), this), | |
| 117 profile_(profile) { | |
| 29 ResetController(); | 118 ResetController(); |
| 30 } | 119 } |
| 31 | 120 |
| 32 OmniboxUIHandler::~OmniboxUIHandler() {} | 121 OmniboxUIHandler::~OmniboxUIHandler() {} |
| 33 | 122 |
| 34 void OmniboxUIHandler::RegisterMessages() { | |
| 35 web_ui()->RegisterMessageCallback("startOmniboxQuery", | |
| 36 base::Bind(&OmniboxUIHandler::StartOmniboxQuery, | |
| 37 base::Unretained(this))); | |
| 38 } | |
| 39 | |
| 40 // This function gets called when the AutocompleteController possibly | |
| 41 // has new results. We package those results in a DictionaryValue | |
| 42 // object result_to_output and call the javascript function | |
| 43 // handleNewAutocompleteResult. Here's an example populated | |
| 44 // result_to_output object: | |
| 45 // { | |
| 46 // 'done': false, | |
| 47 // 'time_since_omnibox_started_ms': 15, | |
| 48 // 'host': 'mai', | |
| 49 // 'is_typed_host': false, | |
| 50 // 'combined_results' : { | |
| 51 // 'num_items': 4, | |
| 52 // 'item_0': { | |
| 53 // 'destination_url': 'http://mail.google.com', | |
| 54 // 'provider_name': 'HistoryURL', | |
| 55 // 'relevance': 1410, | |
| 56 // ... | |
| 57 // } | |
| 58 // 'item_1: { | |
| 59 // ... | |
| 60 // } | |
| 61 // ... | |
| 62 // } | |
| 63 // 'results_by_provider': { | |
| 64 // 'HistoryURL' : { | |
| 65 // 'num_items': 3, | |
| 66 // ... | |
| 67 // } | |
| 68 // 'Search' : { | |
| 69 // 'num_items': 1, | |
| 70 // ... | |
| 71 // } | |
| 72 // ... | |
| 73 // } | |
| 74 // } | |
| 75 // For reference, the javascript code that unpacks this object and | |
| 76 // displays it is in chrome/browser/resources/omnibox.js | |
| 77 void OmniboxUIHandler::OnResultChanged(bool default_match_changed) { | 123 void OmniboxUIHandler::OnResultChanged(bool default_match_changed) { |
| 78 base::DictionaryValue result_to_output; | 124 mojo::AllocationScope scope; |
| 79 // Fill in general information. | 125 OmniboxResultMojo::Builder builder; |
| 80 result_to_output.SetBoolean("done", controller_->done()); | 126 builder.set_done(controller_->done()); |
| 81 result_to_output.SetInteger("time_since_omnibox_started_ms", | 127 builder.set_time_since_omnibox_started_ms( |
| 82 (base::Time::Now() - time_omnibox_started_).InMilliseconds()); | 128 (base::Time::Now() - time_omnibox_started_).InMilliseconds()); |
| 83 const base::string16& host = controller_->input().text().substr( | 129 const base::string16 host = controller_->input().text().substr( |
| 84 controller_->input().parts().host.begin, | 130 controller_->input().parts().host.begin, |
| 85 controller_->input().parts().host.len); | 131 controller_->input().parts().host.len); |
| 86 result_to_output.SetString("host", host); | 132 builder.set_host(host); |
| 87 bool is_typed_host; | 133 bool is_typed_host; |
| 88 if (LookupIsTypedHost(host, &is_typed_host)) { | 134 if (!LookupIsTypedHost(host, &is_typed_host)) |
| 89 // If we successfully looked up whether the host part of the omnibox | 135 is_typed_host = false; |
| 90 // input (this interprets the input as a host plus optional path) as | 136 builder.set_is_typed_host(is_typed_host); |
| 91 // a typed host, then record this information in the output. | 137 |
| 92 result_to_output.SetBoolean("is_typed_host", is_typed_host); | 138 { |
| 139 // Copy to an ACMatches to make conversion easier. Since this isn't | |
| 140 // performance critical we don't worry about the cost here. | |
| 141 ACMatches matches(controller_->result().begin(), | |
| 142 controller_->result().end()); | |
| 143 builder.set_combined_results(matches); | |
| 93 } | 144 } |
| 94 // Fill in the merged/combined results the controller has provided. | 145 builder.set_results_by_provider(*controller_->providers()); |
| 95 AddResultToDictionary("combined_results", controller_->result().begin(), | 146 page_->HandleNewAutocompleteResult(builder.Finish()); |
| 96 controller_->result().end(), &result_to_output); | |
| 97 // Fill results from each individual provider as well. | |
| 98 for (ACProviders::const_iterator it(controller_->providers()->begin()); | |
| 99 it != controller_->providers()->end(); ++it) { | |
| 100 AddResultToDictionary( | |
| 101 std::string("results_by_provider.") + (*it)->GetName(), | |
| 102 (*it)->matches().begin(), (*it)->matches().end(), &result_to_output); | |
| 103 } | |
| 104 // Add done; send the results. | |
| 105 web_ui()->CallJavascriptFunction("omniboxDebug.handleNewAutocompleteResult", | |
| 106 result_to_output); | |
| 107 } | |
| 108 | |
| 109 // For details on the format of the DictionaryValue that this function | |
| 110 // populates, see the comments by OnResultChanged(). | |
| 111 void OmniboxUIHandler::AddResultToDictionary(const std::string& prefix, | |
| 112 ACMatches::const_iterator it, | |
| 113 ACMatches::const_iterator end, | |
| 114 base::DictionaryValue* output) { | |
| 115 int i = 0; | |
| 116 for (; it != end; ++it, ++i) { | |
| 117 std::string item_prefix(prefix + base::StringPrintf(".item_%d", i)); | |
| 118 if (it->provider != NULL) { | |
| 119 output->SetString(item_prefix + ".provider_name", | |
| 120 it->provider->GetName()); | |
| 121 output->SetBoolean(item_prefix + ".provider_done", it->provider->done()); | |
| 122 } | |
| 123 output->SetInteger(item_prefix + ".relevance", it->relevance); | |
| 124 output->SetBoolean(item_prefix + ".deletable", it->deletable); | |
| 125 output->SetString(item_prefix + ".fill_into_edit", it->fill_into_edit); | |
| 126 output->SetString(item_prefix + ".inline_autocompletion", | |
| 127 it->inline_autocompletion); | |
| 128 output->SetString(item_prefix + ".destination_url", | |
| 129 it->destination_url.spec()); | |
| 130 output->SetString(item_prefix + ".contents", it->contents); | |
| 131 // At this time, we're not bothering to send along the long vector that | |
| 132 // represent contents classification. i.e., for each character, what | |
| 133 // type of text it is. | |
| 134 output->SetString(item_prefix + ".description", it->description); | |
| 135 // At this time, we're not bothering to send along the long vector that | |
| 136 // represents description classification. i.e., for each character, what | |
| 137 // type of text it is. | |
| 138 output->SetInteger(item_prefix + ".transition", it->transition); | |
| 139 output->SetBoolean(item_prefix + ".is_history_what_you_typed_match", | |
| 140 it->is_history_what_you_typed_match); | |
| 141 output->SetBoolean(item_prefix + ".allowed_to_be_default_match", | |
| 142 it->allowed_to_be_default_match); | |
| 143 output->SetString(item_prefix + ".type", | |
| 144 AutocompleteMatchType::ToString(it->type)); | |
| 145 if (it->associated_keyword.get() != NULL) { | |
| 146 output->SetString(item_prefix + ".associated_keyword", | |
| 147 it->associated_keyword->keyword); | |
| 148 } | |
| 149 output->SetString(item_prefix + ".keyword", it->keyword); | |
| 150 output->SetBoolean(item_prefix + ".starred", it->starred); | |
| 151 output->SetInteger(item_prefix + ".duplicates", | |
| 152 static_cast<int>(it->duplicate_matches.size())); | |
| 153 output->SetBoolean(item_prefix + ".from_previous", it->from_previous); | |
| 154 for (AutocompleteMatch::AdditionalInfo::const_iterator j = | |
| 155 it->additional_info.begin(); j != it->additional_info.end(); ++j) { | |
| 156 output->SetString(item_prefix + ".additional_info." + j->first, | |
| 157 j->second); | |
| 158 } | |
| 159 } | |
| 160 output->SetInteger(prefix + ".num_items", i); | |
| 161 } | 147 } |
| 162 | 148 |
| 163 bool OmniboxUIHandler::LookupIsTypedHost(const base::string16& host, | 149 bool OmniboxUIHandler::LookupIsTypedHost(const base::string16& host, |
| 164 bool* is_typed_host) const { | 150 bool* is_typed_host) const { |
| 165 HistoryService* const history_service = | 151 HistoryService* const history_service = |
| 166 HistoryServiceFactory::GetForProfile(profile_, | 152 HistoryServiceFactory::GetForProfile(profile_, |
| 167 Profile::EXPLICIT_ACCESS); | 153 Profile::EXPLICIT_ACCESS); |
| 168 if (!history_service) | 154 if (!history_service) |
| 169 return false; | 155 return false; |
| 170 history::URLDatabase* url_db = history_service->InMemoryDatabase(); | 156 history::URLDatabase* url_db = history_service->InMemoryDatabase(); |
| 171 if (!url_db) | 157 if (!url_db) |
| 172 return false; | 158 return false; |
| 173 *is_typed_host = url_db->IsTypedHost(base::UTF16ToUTF8(host)); | 159 *is_typed_host = url_db->IsTypedHost(base::UTF16ToUTF8(host)); |
| 174 return true; | 160 return true; |
| 175 } | 161 } |
| 176 | 162 |
| 177 void OmniboxUIHandler::StartOmniboxQuery(const base::ListValue* input) { | 163 void OmniboxUIHandler::StartOmniboxQuery(const mojo::String& input_string, |
| 178 DCHECK_EQ(5u, input->GetSize()); | 164 int32_t cursor_position, |
| 179 base::string16 input_string; | 165 bool prevent_inline_autocomplete, |
| 180 bool return_val = input->GetString(0, &input_string); | 166 bool prefer_keyword, |
| 181 DCHECK(return_val); | 167 int32_t page_classification) { |
| 182 int cursor_position; | |
| 183 return_val = input->GetInteger(1, &cursor_position); | |
| 184 DCHECK(return_val); | |
| 185 bool prevent_inline_autocomplete; | |
| 186 return_val = input->GetBoolean(2, &prevent_inline_autocomplete); | |
| 187 DCHECK(return_val); | |
| 188 bool prefer_keyword; | |
| 189 return_val = input->GetBoolean(3, &prefer_keyword); | |
| 190 DCHECK(return_val); | |
| 191 int current_page_classification; | |
| 192 return_val = input->GetInteger(4, ¤t_page_classification); | |
| 193 DCHECK(return_val); | |
| 194 // Reset the controller. If we don't do this, then the | 168 // Reset the controller. If we don't do this, then the |
| 195 // AutocompleteController might inappropriately set its |minimal_changes| | 169 // AutocompleteController might inappropriately set its |minimal_changes| |
| 196 // variable (or something else) and some providers will short-circuit | 170 // variable (or something else) and some providers will short-circuit |
| 197 // important logic and return stale results. In short, we want the | 171 // important logic and return stale results. In short, we want the |
| 198 // actual results to not depend on the state of the previous request. | 172 // actual results to not depend on the state of the previous request. |
| 199 ResetController(); | 173 ResetController(); |
| 200 time_omnibox_started_ = base::Time::Now(); | 174 time_omnibox_started_ = base::Time::Now(); |
| 201 controller_->Start(AutocompleteInput( | 175 controller_->Start(AutocompleteInput( |
| 202 input_string, | 176 input_string, |
| 203 cursor_position, | 177 cursor_position, |
| 204 base::string16(), // user's desired tld (top-level domain) | 178 base::string16(), // user's desired tld (top-level domain) |
| 205 GURL(), | 179 GURL(), |
| 206 static_cast<AutocompleteInput::PageClassification>( | 180 static_cast<AutocompleteInput::PageClassification>( |
| 207 current_page_classification), | 181 page_classification), |
| 208 prevent_inline_autocomplete, | 182 prevent_inline_autocomplete, |
| 209 prefer_keyword, | 183 prefer_keyword, |
| 210 true, // allow exact keyword matches | 184 true, // allow exact keyword matches |
| 211 AutocompleteInput::ALL_MATCHES)); // want all matches | 185 AutocompleteInput::ALL_MATCHES)); // want all matches |
| 212 } | 186 } |
| 213 | 187 |
| 214 void OmniboxUIHandler::ResetController() { | 188 void OmniboxUIHandler::ResetController() { |
| 215 controller_.reset(new AutocompleteController(profile_, this, | 189 controller_.reset(new AutocompleteController(profile_, this, |
| 216 AutocompleteClassifier::kDefaultOmniboxProviders)); | 190 AutocompleteClassifier::kDefaultOmniboxProviders)); |
| 217 } | 191 } |
| OLD | NEW |