diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-08-01 12:59:39 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2016-08-04 12:40:43 +0000 |
commit | 28b1110370900897ab652cb420c371fab8857ad4 (patch) | |
tree | 41b32127d23b0df4f2add2a27e12dc87bddb260e /chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc | |
parent | 399c965b6064c440ddcf4015f5f8e9d131c7a0a6 (diff) |
BASELINE: Update Chromium to 53.0.2785.41
Also adds a few extra files for extensions.
Change-Id: Iccdd55d98660903331cf8b7b29188da781830af4
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc')
-rw-r--r-- | chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc b/chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc new file mode 100644 index 00000000000..04ab949662f --- /dev/null +++ b/chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc @@ -0,0 +1,402 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/omnibox/omnibox_api.h" + +#include <stddef.h> + +#include <utility> + +#include "base/lazy_instance.h" +#include "base/memory/ptr_util.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" +#include "chrome/browser/extensions/tab_helper.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/search_engines/template_url_service_factory.h" +#include "chrome/common/extensions/api/omnibox.h" +#include "chrome/common/extensions/api/omnibox/omnibox_handler.h" +#include "components/search_engines/template_url.h" +#include "components/search_engines/template_url_service.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_prefs_factory.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/notification_types.h" +#include "ui/gfx/image/image.h" + +namespace extensions { + +namespace omnibox = api::omnibox; +namespace SendSuggestions = omnibox::SendSuggestions; +namespace SetDefaultSuggestion = omnibox::SetDefaultSuggestion; + +namespace { + +const char kSuggestionContent[] = "content"; +const char kCurrentTabDisposition[] = "currentTab"; +const char kForegroundTabDisposition[] = "newForegroundTab"; +const char kBackgroundTabDisposition[] = "newBackgroundTab"; + +// Pref key for omnibox.setDefaultSuggestion. +const char kOmniboxDefaultSuggestion[] = "omnibox_default_suggestion"; + +#if defined(OS_LINUX) +static const int kOmniboxIconPaddingLeft = 2; +static const int kOmniboxIconPaddingRight = 2; +#elif defined(OS_MACOSX) +static const int kOmniboxIconPaddingLeft = 0; +static const int kOmniboxIconPaddingRight = 2; +#else +static const int kOmniboxIconPaddingLeft = 0; +static const int kOmniboxIconPaddingRight = 0; +#endif + +std::unique_ptr<omnibox::SuggestResult> GetOmniboxDefaultSuggestion( + Profile* profile, + const std::string& extension_id) { + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile); + + std::unique_ptr<omnibox::SuggestResult> suggestion; + const base::DictionaryValue* dict = NULL; + if (prefs && prefs->ReadPrefAsDictionary(extension_id, + kOmniboxDefaultSuggestion, + &dict)) { + suggestion.reset(new omnibox::SuggestResult); + omnibox::SuggestResult::Populate(*dict, suggestion.get()); + } + return suggestion; +} + +// Tries to set the omnibox default suggestion; returns true on success or +// false on failure. +bool SetOmniboxDefaultSuggestion( + Profile* profile, + const std::string& extension_id, + const omnibox::DefaultSuggestResult& suggestion) { + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile); + if (!prefs) + return false; + + std::unique_ptr<base::DictionaryValue> dict = suggestion.ToValue(); + // Add the content field so that the dictionary can be used to populate an + // omnibox::SuggestResult. + dict->SetWithoutPathExpansion(kSuggestionContent, new base::StringValue("")); + prefs->UpdateExtensionPref(extension_id, + kOmniboxDefaultSuggestion, + dict.release()); + + return true; +} + +// Returns a string used as a template URL string of the extension. +std::string GetTemplateURLStringForExtension(const std::string& extension_id) { + // This URL is not actually used for navigation. It holds the extension's ID. + return std::string(extensions::kExtensionScheme) + "://" + + extension_id + "/?q={searchTerms}"; +} + +} // namespace + +// static +void ExtensionOmniboxEventRouter::OnInputStarted( + Profile* profile, const std::string& extension_id) { + std::unique_ptr<Event> event(new Event( + events::OMNIBOX_ON_INPUT_STARTED, omnibox::OnInputStarted::kEventName, + base::WrapUnique(new base::ListValue()))); + event->restrict_to_browser_context = profile; + EventRouter::Get(profile) + ->DispatchEventToExtension(extension_id, std::move(event)); +} + +// static +bool ExtensionOmniboxEventRouter::OnInputChanged( + Profile* profile, const std::string& extension_id, + const std::string& input, int suggest_id) { + EventRouter* event_router = EventRouter::Get(profile); + if (!event_router->ExtensionHasEventListener( + extension_id, omnibox::OnInputChanged::kEventName)) + return false; + + std::unique_ptr<base::ListValue> args(new base::ListValue()); + args->Set(0, new base::StringValue(input)); + args->Set(1, new base::FundamentalValue(suggest_id)); + + std::unique_ptr<Event> event(new Event(events::OMNIBOX_ON_INPUT_CHANGED, + omnibox::OnInputChanged::kEventName, + std::move(args))); + event->restrict_to_browser_context = profile; + event_router->DispatchEventToExtension(extension_id, std::move(event)); + return true; +} + +// static +void ExtensionOmniboxEventRouter::OnInputEntered( + content::WebContents* web_contents, + const std::string& extension_id, + const std::string& input, + WindowOpenDisposition disposition) { + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + + const Extension* extension = + ExtensionRegistry::Get(profile)->enabled_extensions().GetByID( + extension_id); + CHECK(extension); + extensions::TabHelper::FromWebContents(web_contents)-> + active_tab_permission_granter()->GrantIfRequested(extension); + + std::unique_ptr<base::ListValue> args(new base::ListValue()); + args->Set(0, new base::StringValue(input)); + if (disposition == NEW_FOREGROUND_TAB) + args->Set(1, new base::StringValue(kForegroundTabDisposition)); + else if (disposition == NEW_BACKGROUND_TAB) + args->Set(1, new base::StringValue(kBackgroundTabDisposition)); + else + args->Set(1, new base::StringValue(kCurrentTabDisposition)); + + std::unique_ptr<Event> event(new Event(events::OMNIBOX_ON_INPUT_ENTERED, + omnibox::OnInputEntered::kEventName, + std::move(args))); + event->restrict_to_browser_context = profile; + EventRouter::Get(profile) + ->DispatchEventToExtension(extension_id, std::move(event)); + + content::NotificationService::current()->Notify( + extensions::NOTIFICATION_EXTENSION_OMNIBOX_INPUT_ENTERED, + content::Source<Profile>(profile), + content::NotificationService::NoDetails()); +} + +// static +void ExtensionOmniboxEventRouter::OnInputCancelled( + Profile* profile, const std::string& extension_id) { + std::unique_ptr<Event> event(new Event( + events::OMNIBOX_ON_INPUT_CANCELLED, omnibox::OnInputCancelled::kEventName, + base::WrapUnique(new base::ListValue()))); + event->restrict_to_browser_context = profile; + EventRouter::Get(profile) + ->DispatchEventToExtension(extension_id, std::move(event)); +} + +OmniboxAPI::OmniboxAPI(content::BrowserContext* context) + : profile_(Profile::FromBrowserContext(context)), + url_service_(TemplateURLServiceFactory::GetForProfile(profile_)), + extension_registry_observer_(this) { + extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); + if (url_service_) { + template_url_sub_ = url_service_->RegisterOnLoadedCallback( + base::Bind(&OmniboxAPI::OnTemplateURLsLoaded, + base::Unretained(this))); + } + + // Use monochrome icons for Omnibox icons. + omnibox_popup_icon_manager_.set_monochrome(true); + omnibox_icon_manager_.set_monochrome(true); + omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft, + 0, kOmniboxIconPaddingRight)); +} + +void OmniboxAPI::Shutdown() { + template_url_sub_.reset(); +} + +OmniboxAPI::~OmniboxAPI() { +} + +static base::LazyInstance<BrowserContextKeyedAPIFactory<OmniboxAPI> > + g_factory = LAZY_INSTANCE_INITIALIZER; + +// static +BrowserContextKeyedAPIFactory<OmniboxAPI>* OmniboxAPI::GetFactoryInstance() { + return g_factory.Pointer(); +} + +// static +OmniboxAPI* OmniboxAPI::Get(content::BrowserContext* context) { + return BrowserContextKeyedAPIFactory<OmniboxAPI>::Get(context); +} + +void OmniboxAPI::OnExtensionLoaded(content::BrowserContext* browser_context, + const Extension* extension) { + const std::string& keyword = OmniboxInfo::GetKeyword(extension); + if (!keyword.empty()) { + // Load the omnibox icon so it will be ready to display in the URL bar. + omnibox_popup_icon_manager_.LoadIcon(profile_, extension); + omnibox_icon_manager_.LoadIcon(profile_, extension); + + if (url_service_) { + url_service_->Load(); + if (url_service_->loaded()) { + url_service_->RegisterOmniboxKeyword( + extension->id(), extension->name(), keyword, + GetTemplateURLStringForExtension(extension->id())); + } else { + pending_extensions_.insert(extension); + } + } + } +} + +void OmniboxAPI::OnExtensionUnloaded(content::BrowserContext* browser_context, + const Extension* extension, + UnloadedExtensionInfo::Reason reason) { + if (!OmniboxInfo::GetKeyword(extension).empty() && url_service_) { + if (url_service_->loaded()) { + url_service_->RemoveExtensionControlledTURL( + extension->id(), TemplateURL::OMNIBOX_API_EXTENSION); + } else { + pending_extensions_.erase(extension); + } + } +} + +gfx::Image OmniboxAPI::GetOmniboxIcon(const std::string& extension_id) { + return gfx::Image::CreateFrom1xBitmap( + omnibox_icon_manager_.GetIcon(extension_id)); +} + +gfx::Image OmniboxAPI::GetOmniboxPopupIcon(const std::string& extension_id) { + return gfx::Image::CreateFrom1xBitmap( + omnibox_popup_icon_manager_.GetIcon(extension_id)); +} + +void OmniboxAPI::OnTemplateURLsLoaded() { + // Register keywords for pending extensions. + template_url_sub_.reset(); + for (PendingExtensions::const_iterator i(pending_extensions_.begin()); + i != pending_extensions_.end(); ++i) { + url_service_->RegisterOmniboxKeyword( + (*i)->id(), (*i)->name(), OmniboxInfo::GetKeyword(*i), + GetTemplateURLStringForExtension((*i)->id())); + } + pending_extensions_.clear(); +} + +template <> +void BrowserContextKeyedAPIFactory<OmniboxAPI>::DeclareFactoryDependencies() { + DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); + DependsOn(ExtensionPrefsFactory::GetInstance()); + DependsOn(TemplateURLServiceFactory::GetInstance()); +} + +bool OmniboxSendSuggestionsFunction::RunSync() { + std::unique_ptr<SendSuggestions::Params> params( + SendSuggestions::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + + content::NotificationService::current()->Notify( + extensions::NOTIFICATION_EXTENSION_OMNIBOX_SUGGESTIONS_READY, + content::Source<Profile>(GetProfile()->GetOriginalProfile()), + content::Details<SendSuggestions::Params>(params.get())); + + return true; +} + +bool OmniboxSetDefaultSuggestionFunction::RunSync() { + std::unique_ptr<SetDefaultSuggestion::Params> params( + SetDefaultSuggestion::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + + if (SetOmniboxDefaultSuggestion( + GetProfile(), extension_id(), params->suggestion)) { + content::NotificationService::current()->Notify( + extensions::NOTIFICATION_EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED, + content::Source<Profile>(GetProfile()->GetOriginalProfile()), + content::NotificationService::NoDetails()); + } + + return true; +} + +// This function converts style information populated by the JSON schema +// compiler into an ACMatchClassifications object. +ACMatchClassifications StyleTypesToACMatchClassifications( + const omnibox::SuggestResult &suggestion) { + ACMatchClassifications match_classifications; + if (suggestion.description_styles) { + base::string16 description = base::UTF8ToUTF16(suggestion.description); + std::vector<int> styles(description.length(), 0); + + for (const omnibox::SuggestResult::DescriptionStylesType& style : + *suggestion.description_styles) { + int length = style.length ? *style.length : description.length(); + size_t offset = style.offset >= 0 + ? style.offset + : std::max(0, static_cast<int>(description.length()) + + style.offset); + + int type_class; + switch (style.type) { + case omnibox::DESCRIPTION_STYLE_TYPE_URL: + type_class = AutocompleteMatch::ACMatchClassification::URL; + break; + case omnibox::DESCRIPTION_STYLE_TYPE_MATCH: + type_class = AutocompleteMatch::ACMatchClassification::MATCH; + break; + case omnibox::DESCRIPTION_STYLE_TYPE_DIM: + type_class = AutocompleteMatch::ACMatchClassification::DIM; + break; + default: + type_class = AutocompleteMatch::ACMatchClassification::NONE; + return match_classifications; + } + + for (size_t j = offset; j < offset + length && j < styles.size(); ++j) + styles[j] |= type_class; + } + + for (size_t i = 0; i < styles.size(); ++i) { + if (i == 0 || styles[i] != styles[i-1]) + match_classifications.push_back( + ACMatchClassification(i, styles[i])); + } + } else { + match_classifications.push_back( + ACMatchClassification(0, ACMatchClassification::NONE)); + } + + return match_classifications; +} + +void ApplyDefaultSuggestionForExtensionKeyword( + Profile* profile, + const TemplateURL* keyword, + const base::string16& remaining_input, + AutocompleteMatch* match) { + DCHECK(keyword->GetType() == TemplateURL::OMNIBOX_API_EXTENSION); + + std::unique_ptr<omnibox::SuggestResult> suggestion( + GetOmniboxDefaultSuggestion(profile, keyword->GetExtensionId())); + if (!suggestion || suggestion->description.empty()) + return; // fall back to the universal default + + const base::string16 kPlaceholderText(base::ASCIIToUTF16("%s")); + const base::string16 kReplacementText(base::ASCIIToUTF16("<input>")); + + base::string16 description = base::UTF8ToUTF16(suggestion->description); + ACMatchClassifications& description_styles = match->contents_class; + description_styles = StyleTypesToACMatchClassifications(*suggestion); + + // Replace "%s" with the user's input and adjust the style offsets to the + // new length of the description. + size_t placeholder(description.find(kPlaceholderText, 0)); + if (placeholder != base::string16::npos) { + base::string16 replacement = + remaining_input.empty() ? kReplacementText : remaining_input; + description.replace(placeholder, kPlaceholderText.length(), replacement); + + for (size_t i = 0; i < description_styles.size(); ++i) { + if (description_styles[i].offset > placeholder) + description_styles[i].offset += replacement.length() - 2; + } + } + + match->contents.assign(description); +} + +} // namespace extensions |