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.
5 #include "chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h"
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/chrome_autocomplete_provider_client.h"
17 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
18 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
19 #include "chrome/browser/history/history_service_factory.h"
20 #include "chrome/browser/search/search.h"
21 #include "chrome/browser/search_engines/template_url_service_factory.h"
22 #include "components/bookmarks/browser/bookmark_model.h"
23 #include "components/history/core/browser/history_service.h"
24 #include "components/history/core/browser/url_database.h"
25 #include "components/metrics/proto/omnibox_event.pb.h"
26 #include "components/omnibox/browser/autocomplete_classifier.h"
27 #include "components/omnibox/browser/autocomplete_controller.h"
28 #include "components/omnibox/browser/autocomplete_match.h"
29 #include "components/omnibox/browser/autocomplete_provider.h"
30 #include "components/search_engines/template_url.h"
31 #include "content/public/browser/web_ui.h"
32 #include "mojo/common/common_type_converters.h"
34 using bookmarks::BookmarkModel
;
39 struct TypeConverter
<mojo::Array
<AutocompleteAdditionalInfoPtr
>,
40 AutocompleteMatch::AdditionalInfo
> {
41 static mojo::Array
<AutocompleteAdditionalInfoPtr
> Convert(
42 const AutocompleteMatch::AdditionalInfo
& input
) {
43 mojo::Array
<AutocompleteAdditionalInfoPtr
> array(input
.size());
45 for (AutocompleteMatch::AdditionalInfo::const_iterator i
= input
.begin();
46 i
!= input
.end(); ++i
, index
++) {
47 AutocompleteAdditionalInfoPtr
item(AutocompleteAdditionalInfo::New());
49 item
->value
= i
->second
;
50 array
[index
] = item
.Pass();
57 struct TypeConverter
<AutocompleteMatchMojoPtr
, AutocompleteMatch
> {
58 static AutocompleteMatchMojoPtr
Convert(const AutocompleteMatch
& input
) {
59 AutocompleteMatchMojoPtr
result(AutocompleteMatchMojo::New());
60 if (input
.provider
!= NULL
) {
61 result
->provider_name
= input
.provider
->GetName();
62 result
->provider_done
= input
.provider
->done();
64 result
->relevance
= input
.relevance
;
65 result
->deletable
= input
.deletable
;
66 result
->fill_into_edit
= mojo::String::From(input
.fill_into_edit
);
67 result
->inline_autocompletion
=
68 mojo::String::From(input
.inline_autocompletion
);
69 result
->destination_url
= input
.destination_url
.spec();
70 result
->contents
= mojo::String::From(input
.contents
);
71 // At this time, we're not bothering to send along the long vector that
72 // represent contents classification. i.e., for each character, what
73 // type of text it is.
74 result
->description
= mojo::String::From(input
.description
);
75 // At this time, we're not bothering to send along the long vector that
76 // represents description classification. i.e., for each character, what
77 // type of text it is.
78 result
->transition
= input
.transition
;
79 result
->allowed_to_be_default_match
= input
.allowed_to_be_default_match
;
80 result
->type
= AutocompleteMatchType::ToString(input
.type
);
81 if (input
.associated_keyword
.get() != NULL
) {
82 result
->associated_keyword
=
83 mojo::String::From(input
.associated_keyword
->keyword
);
85 result
->keyword
= mojo::String::From(input
.keyword
);
86 result
->duplicates
= static_cast<int32
>(input
.duplicate_matches
.size());
87 result
->from_previous
= input
.from_previous
;
89 result
->additional_info
=
90 mojo::Array
<AutocompleteAdditionalInfoPtr
>::From(input
.additional_info
);
96 struct TypeConverter
<AutocompleteResultsForProviderMojoPtr
,
97 scoped_refptr
<AutocompleteProvider
> > {
98 static AutocompleteResultsForProviderMojoPtr
Convert(
99 const scoped_refptr
<AutocompleteProvider
>& input
) {
100 AutocompleteResultsForProviderMojoPtr
result(
101 AutocompleteResultsForProviderMojo::New());
102 result
->provider_name
= input
->GetName();
104 mojo::Array
<AutocompleteMatchMojoPtr
>::From(input
->matches());
105 return result
.Pass();
111 OmniboxUIHandler::OmniboxUIHandler(
113 mojo::InterfaceRequest
<OmniboxUIHandlerMojo
> request
)
115 binding_(this, request
.Pass()) {
119 OmniboxUIHandler::~OmniboxUIHandler() {
122 void OmniboxUIHandler::OnResultChanged(bool default_match_changed
) {
123 OmniboxResultMojoPtr
result(OmniboxResultMojo::New());
124 result
->done
= controller_
->done();
125 result
->time_since_omnibox_started_ms
=
126 (base::Time::Now() - time_omnibox_started_
).InMilliseconds();
127 const base::string16 host
= input_
.text().substr(
128 input_
.parts().host
.begin
,
129 input_
.parts().host
.len
);
130 result
->host
= mojo::String::From(host
);
132 if (!LookupIsTypedHost(host
, &is_typed_host
))
133 is_typed_host
= false;
134 result
->is_typed_host
= is_typed_host
;
137 // Copy to an ACMatches to make conversion easier. Since this isn't
138 // performance critical we don't worry about the cost here.
139 ACMatches
matches(controller_
->result().begin(),
140 controller_
->result().end());
141 result
->combined_results
=
142 mojo::Array
<AutocompleteMatchMojoPtr
>::From(matches
);
144 result
->results_by_provider
=
145 mojo::Array
<AutocompleteResultsForProviderMojoPtr
>::From(
146 controller_
->providers());
148 // Fill AutocompleteMatchMojo::starred.
149 BookmarkModel
* bookmark_model
= BookmarkModelFactory::GetForProfile(profile_
);
150 if (bookmark_model
) {
151 for (size_t i
= 0; i
< result
->combined_results
.size(); ++i
) {
152 result
->combined_results
[i
]->starred
= bookmark_model
->IsBookmarked(
153 GURL(result
->combined_results
[i
]->destination_url
));
155 for (size_t i
= 0; i
< result
->results_by_provider
.size(); ++i
) {
156 const AutocompleteResultsForProviderMojo
& result_by_provider
=
157 *result
->results_by_provider
[i
];
158 for (size_t j
= 0; j
< result_by_provider
.results
.size(); ++j
) {
159 result_by_provider
.results
[j
]->starred
= bookmark_model
->IsBookmarked(
160 GURL(result_by_provider
.results
[j
]->destination_url
));
165 page_
->HandleNewAutocompleteResult(result
.Pass());
168 bool OmniboxUIHandler::LookupIsTypedHost(const base::string16
& host
,
169 bool* is_typed_host
) const {
170 history::HistoryService
* const history_service
=
171 HistoryServiceFactory::GetForProfile(profile_
,
172 ServiceAccessType::EXPLICIT_ACCESS
);
173 if (!history_service
)
175 history::URLDatabase
* url_db
= history_service
->InMemoryDatabase();
178 *is_typed_host
= url_db
->IsTypedHost(base::UTF16ToUTF8(host
));
182 void OmniboxUIHandler::StartOmniboxQuery(const mojo::String
& input_string
,
183 int32_t cursor_position
,
184 bool prevent_inline_autocomplete
,
186 int32_t page_classification
,
187 OmniboxPagePtr page
) {
188 // Reset the controller. If we don't do this, then the
189 // AutocompleteController might inappropriately set its |minimal_changes|
190 // variable (or something else) and some providers will short-circuit
191 // important logic and return stale results. In short, we want the
192 // actual results to not depend on the state of the previous request.
195 time_omnibox_started_
= base::Time::Now();
196 input_
= AutocompleteInput(
197 input_string
.To
<base::string16
>(), cursor_position
, std::string(), GURL(),
198 static_cast<metrics::OmniboxEventProto::PageClassification
>(
199 page_classification
),
200 prevent_inline_autocomplete
, prefer_keyword
, true, true, false,
201 ChromeAutocompleteSchemeClassifier(profile_
));
202 controller_
->Start(input_
);
205 void OmniboxUIHandler::ResetController() {
206 controller_
.reset(new AutocompleteController(
207 make_scoped_ptr(new ChromeAutocompleteProviderClient(profile_
)), this,
208 AutocompleteClassifier::kDefaultOmniboxProviders
));