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/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_factory.h"
21 #include "chrome/browser/search/search.h"
22 #include "chrome/browser/search_engines/template_url_service_factory.h"
23 #include "components/bookmarks/browser/bookmark_model.h"
24 #include "components/history/core/browser/history_service.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"
33 using bookmarks::BookmarkModel
;
38 struct TypeConverter
<mojo::Array
<AutocompleteAdditionalInfoPtr
>,
39 AutocompleteMatch::AdditionalInfo
> {
40 static mojo::Array
<AutocompleteAdditionalInfoPtr
> Convert(
41 const AutocompleteMatch::AdditionalInfo
& input
) {
42 mojo::Array
<AutocompleteAdditionalInfoPtr
> array(input
.size());
44 for (AutocompleteMatch::AdditionalInfo::const_iterator i
= input
.begin();
45 i
!= input
.end(); ++i
, index
++) {
46 AutocompleteAdditionalInfoPtr
item(AutocompleteAdditionalInfo::New());
48 item
->value
= i
->second
;
49 array
[index
] = item
.Pass();
56 struct TypeConverter
<AutocompleteMatchMojoPtr
, AutocompleteMatch
> {
57 static AutocompleteMatchMojoPtr
Convert(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();
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
->allowed_to_be_default_match
= input
.allowed_to_be_default_match
;
79 result
->type
= AutocompleteMatchType::ToString(input
.type
);
80 if (input
.associated_keyword
.get() != NULL
) {
81 result
->associated_keyword
=
82 mojo::String::From(input
.associated_keyword
->keyword
);
84 result
->keyword
= mojo::String::From(input
.keyword
);
85 result
->duplicates
= static_cast<int32
>(input
.duplicate_matches
.size());
86 result
->from_previous
= input
.from_previous
;
88 result
->additional_info
=
89 mojo::Array
<AutocompleteAdditionalInfoPtr
>::From(input
.additional_info
);
95 struct TypeConverter
<AutocompleteResultsForProviderMojoPtr
,
96 scoped_refptr
<AutocompleteProvider
> > {
97 static AutocompleteResultsForProviderMojoPtr
Convert(
98 const scoped_refptr
<AutocompleteProvider
>& input
) {
99 AutocompleteResultsForProviderMojoPtr
result(
100 AutocompleteResultsForProviderMojo::New());
101 result
->provider_name
= input
->GetName();
103 mojo::Array
<AutocompleteMatchMojoPtr
>::From(input
->matches());
104 return result
.Pass();
110 OmniboxUIHandler::OmniboxUIHandler(
112 mojo::InterfaceRequest
<OmniboxUIHandlerMojo
> request
)
114 binding_(this, request
.Pass()) {
118 OmniboxUIHandler::~OmniboxUIHandler() {
121 void OmniboxUIHandler::OnResultChanged(bool default_match_changed
) {
122 OmniboxResultMojoPtr
result(OmniboxResultMojo::New());
123 result
->done
= controller_
->done();
124 result
->time_since_omnibox_started_ms
=
125 (base::Time::Now() - time_omnibox_started_
).InMilliseconds();
126 const base::string16 host
= input_
.text().substr(
127 input_
.parts().host
.begin
,
128 input_
.parts().host
.len
);
129 result
->host
= mojo::String::From(host
);
131 if (!LookupIsTypedHost(host
, &is_typed_host
))
132 is_typed_host
= false;
133 result
->is_typed_host
= is_typed_host
;
136 // Copy to an ACMatches to make conversion easier. Since this isn't
137 // performance critical we don't worry about the cost here.
138 ACMatches
matches(controller_
->result().begin(),
139 controller_
->result().end());
140 result
->combined_results
=
141 mojo::Array
<AutocompleteMatchMojoPtr
>::From(matches
);
143 result
->results_by_provider
=
144 mojo::Array
<AutocompleteResultsForProviderMojoPtr
>::From(
145 controller_
->providers());
147 // Fill AutocompleteMatchMojo::starred.
148 BookmarkModel
* bookmark_model
= BookmarkModelFactory::GetForProfile(profile_
);
149 if (bookmark_model
) {
150 for (size_t i
= 0; i
< result
->combined_results
.size(); ++i
) {
151 result
->combined_results
[i
]->starred
= bookmark_model
->IsBookmarked(
152 GURL(result
->combined_results
[i
]->destination_url
));
154 for (size_t i
= 0; i
< result
->results_by_provider
.size(); ++i
) {
155 const AutocompleteResultsForProviderMojo
& result_by_provider
=
156 *result
->results_by_provider
[i
];
157 for (size_t j
= 0; j
< result_by_provider
.results
.size(); ++j
) {
158 result_by_provider
.results
[j
]->starred
= bookmark_model
->IsBookmarked(
159 GURL(result_by_provider
.results
[j
]->destination_url
));
164 page_
->HandleNewAutocompleteResult(result
.Pass());
167 bool OmniboxUIHandler::LookupIsTypedHost(const base::string16
& host
,
168 bool* is_typed_host
) const {
169 history::HistoryService
* const history_service
=
170 HistoryServiceFactory::GetForProfile(profile_
,
171 ServiceAccessType::EXPLICIT_ACCESS
);
172 if (!history_service
)
174 history::URLDatabase
* url_db
= history_service
->InMemoryDatabase();
177 *is_typed_host
= url_db
->IsTypedHost(base::UTF16ToUTF8(host
));
181 void OmniboxUIHandler::StartOmniboxQuery(const mojo::String
& input_string
,
182 int32_t cursor_position
,
183 bool prevent_inline_autocomplete
,
185 int32_t page_classification
,
186 OmniboxPagePtr page
) {
187 // Reset the controller. If we don't do this, then the
188 // AutocompleteController might inappropriately set its |minimal_changes|
189 // variable (or something else) and some providers will short-circuit
190 // important logic and return stale results. In short, we want the
191 // actual results to not depend on the state of the previous request.
194 time_omnibox_started_
= base::Time::Now();
195 input_
= AutocompleteInput(
196 input_string
.To
<base::string16
>(), cursor_position
, std::string(), GURL(),
197 static_cast<metrics::OmniboxEventProto::PageClassification
>(
198 page_classification
),
199 prevent_inline_autocomplete
, prefer_keyword
, true, true,
200 ChromeAutocompleteSchemeClassifier(profile_
));
201 controller_
->Start(input_
);
204 void OmniboxUIHandler::ResetController() {
205 controller_
.reset(new AutocompleteController(profile_
,
206 TemplateURLServiceFactory::GetForProfile(profile_
),
208 AutocompleteClassifier::kDefaultOmniboxProviders
));