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