190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file. 490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/ui/app_list/search/omnibox_provider.h" 690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_classifier.h" 890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_controller.h" 9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model_factory.h" 11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/search_engines/template_url_service_factory.h" 1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/ui/app_list/search/chrome_search_result.h" 1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/ui/browser_navigator.h" 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/bookmarks/browser/bookmark_model.h" 156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "components/metrics/proto/omnibox_event.pb.h" 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/omnibox/autocomplete_input.h" 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/omnibox/autocomplete_match.h" 1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "grit/theme_resources.h" 1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace app_list { 2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace { 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)int ACMatchStyleToTagStyle(int styles) { 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int tag_styles = 0; 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (styles & ACMatchClassification::URL) 2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tag_styles |= SearchResult::Tag::URL; 2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (styles & ACMatchClassification::MATCH) 3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tag_styles |= SearchResult::Tag::MATCH; 3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (styles & ACMatchClassification::DIM) 3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tag_styles |= SearchResult::Tag::DIM; 3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return tag_styles; 3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Translates ACMatchClassifications into SearchResult tags. 3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ACMatchClassificationsToTags( 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& text, 4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const ACMatchClassifications& text_classes, 4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SearchResult::Tags* tags) { 4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int tag_styles = SearchResult::Tag::NONE; 4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) size_t tag_start = 0; 4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (size_t i = 0; i < text_classes.size(); ++i) { 4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const ACMatchClassification& text_class = text_classes[i]; 4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Closes current tag. 4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (tag_styles != SearchResult::Tag::NONE) { 5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tags->push_back(SearchResult::Tag( 5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tag_styles, tag_start, text_class.offset)); 5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tag_styles = SearchResult::Tag::NONE; 5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (text_class.style == ACMatchClassification::NONE) 5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) continue; 5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tag_start = text_class.offset; 5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tag_styles = ACMatchStyleToTagStyle(text_class.style); 6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (tag_styles != SearchResult::Tag::NONE) { 6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tags->push_back(SearchResult::Tag( 6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tag_styles, tag_start, text.length())); 6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class OmniboxResult : public ChromeSearchResult { 6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public: 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) OmniboxResult(Profile* profile, 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) AutocompleteController* autocomplete_controller, 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const AutocompleteMatch& match) 7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) : profile_(profile), 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) autocomplete_controller_(autocomplete_controller), 7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) match_(match) { 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (match_.search_terms_args) { 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) match_.search_terms_args->from_app_list = true; 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) autocomplete_controller_->UpdateMatchDestinationURL( 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *match_.search_terms_args, &match_); 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) set_id(match_.destination_url.spec()); 8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Derive relevance from omnibox relevance and normalize it to [0, 1]. 8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // The magic number 1500 is the highest score of an omnibox result. 8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // See comments in autocomplete_provider.h. 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) set_relevance(match_.relevance / 1500.0); 8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) UpdateIcon(); 8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) UpdateTitleAndDetails(); 9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual ~OmniboxResult() {} 9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // ChromeSearchResult overides: 9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual void Open(int event_flags) OVERRIDE { 9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) chrome::NavigateParams params(profile_, 9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) match_.destination_url, 9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) match_.transition); 9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) params.disposition = ui::DispositionFromEventFlags(event_flags); 9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) chrome::Navigate(¶ms); 10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual void InvokeAction(int action_index, int event_flags) OVERRIDE {} 10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual scoped_ptr<ChromeSearchResult> Duplicate() OVERRIDE { 10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return scoped_ptr<ChromeSearchResult>( 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) new OmniboxResult(profile_, autocomplete_controller_, match_)).Pass(); 10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual ChromeSearchResultType GetType() OVERRIDE { 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return OMNIBOX_SEARCH_RESULT; 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private: 11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) void UpdateIcon() { 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BookmarkModel* bookmark_model = 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BookmarkModelFactory::GetForProfile(profile_); 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool is_bookmarked = 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bookmark_model && bookmark_model->IsBookmarked(match_.destination_url); 1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int resource_id = is_bookmarked ? 12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type); 12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) resource_id)); 12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) void UpdateTitleAndDetails() { 12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) set_title(match_.contents); 12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SearchResult::Tags title_tags; 12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ACMatchClassificationsToTags(match_.contents, 12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) match_.contents_class, 13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) &title_tags); 13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) set_title_tags(title_tags); 13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) set_details(match_.description); 13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SearchResult::Tags details_tags; 13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ACMatchClassificationsToTags(match_.description, 13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) match_.description_class, 13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) &details_tags); 13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) set_details_tags(details_tags); 13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Profile* profile_; 1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) AutocompleteController* autocomplete_controller_; 14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AutocompleteMatch match_; 14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(OmniboxResult); 14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}; 14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace 14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)OmniboxProvider::OmniboxProvider(Profile* profile) 15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) : profile_(profile), 15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) controller_(new AutocompleteController( 15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) profile, 154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch TemplateURLServiceFactory::GetForProfile(profile), 15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) this, 156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch AutocompleteClassifier::kDefaultOmniboxProviders & 157c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch ~AutocompleteProvider::TYPE_ZERO_SUGGEST)) { 15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)OmniboxProvider::~OmniboxProvider() {} 16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OmniboxProvider::Start(const base::string16& query) { 163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller_->Start(AutocompleteInput( 164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch query, base::string16::npos, base::string16(), GURL(), 165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch metrics::OmniboxEventProto::INVALID_SPEC, false, false, true, true, 166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ChromeAutocompleteSchemeClassifier(profile_))); 16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OmniboxProvider::Stop() { 17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) controller_->Stop(false); 17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OmniboxProvider::PopulateFromACResult(const AutocompleteResult& result) { 17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ClearResults(); 17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (ACMatches::const_iterator it = result.begin(); 17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) it != result.end(); 17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ++it) { 17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!it->destination_url.is_valid()) 17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) continue; 18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Add(scoped_ptr<SearchResult>( 1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) new OmniboxResult(profile_, controller_.get(), *it))); 18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OmniboxProvider::OnResultChanged(bool default_match_changed) { 18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const AutocompleteResult& result = controller_->result(); 18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PopulateFromACResult(result); 18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace app_list 192