Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4593)

Unified Diff: chrome/browser/tab_contents/introducer_handler.cc

Issue 6880275: Web Introducer overview Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/tab_contents/introducer_handler.cc
===================================================================
--- chrome/browser/tab_contents/introducer_handler.cc (revision 0)
+++ chrome/browser/tab_contents/introducer_handler.cc (revision 0)
@@ -0,0 +1,506 @@
+// Copyright (c) 2011 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/tab_contents/introducer_handler.h"
+
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/common/pref_names.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/browser/renderer_host/render_process_host.h"
+#include "content/browser/renderer_host/render_view_host.h"
+#include "content/browser/tab_contents/tab_contents_observer.h"
+#include "content/browser/worker_host/message_port_service.h"
+#include "content/common/introducer_messages.h"
+#include "grit/generated_resources.h"
+#include "net/base/data_url.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/simple_menu_model.h"
+#include "ui/gfx/favicon_size.h"
+#include "webkit/glue/context_menu.h"
+#include "webkit/glue/image_decoder.h"
+
+static SkBitmap ImageFromDataUrl(const GURL& icon) {
+ std::string mime_type, charset, data;
+ if (!net::DataURL::Parse(icon, &mime_type, &charset, &data)) {
+ return SkBitmap();
+ }
+ webkit_glue::ImageDecoder decoder(gfx::Size(kFaviconSize, kFaviconSize));
+ return decoder.Decode(reinterpret_cast<const unsigned char*>(data.data()),
+ data.size());
+}
+
+static void InstallReturn(TabContents* tab, int request_id, bool accepted) {
+ RenderViewHost* host = tab->render_view_host();
+ if (host) {
+ host->Send(new IntroducerMsg_InstallReturn(host->routing_id(),
+ request_id, accepted));
+ }
+}
+
+static bool UpdateRegistration(TabContents* tab,
+ const std::string& registrant, const GURL& icon,
+ const string16& name, const GURL& home) {
+ Profile* profile = tab->profile();
+ PrefService* prefs = profile->IsOffTheRecord() ?
+ profile->GetOffTheRecordPrefs() : profile->GetPrefs();
+ DictionaryValue* registrations =
+ prefs->GetMutableDictionary(prefs::kIntroducerRegistrations);
+ if (!registrations) { return false; }
+ DictionaryValue* registration = NULL;
+ if (!registrations->GetDictionaryWithoutPathExpansion(registrant,
+ &registration)) {
+ registration = new DictionaryValue();
+ registrations->SetWithoutPathExpansion(registrant, registration);
+ }
+ registration->SetString("icon", icon.spec());
+ registration->SetString("name", name);
+ registration->SetString("home", home.spec());
+ if (!profile->IsOffTheRecord()) {
+ prefs->ScheduleSavePersistentPrefs();
+ }
+ return true;
+}
+
+class InstallInfoBar : public ConfirmInfoBarDelegate {
+ public:
+ InstallInfoBar(
+ TabContents* tab,
+ int request_id,
+ const std::string& registrant,
+ const GURL& icon,
+ const string16& name,
+ const GURL& home) :
+ ConfirmInfoBarDelegate(tab),
+ tab_(tab),
+ request_id_(request_id),
+ registrant_(registrant),
+ icon_(icon),
+ name_(name),
+ home_(home),
+ decoded_icon_(ImageFromDataUrl(icon)) {}
+
+ virtual void InfoBarClosed() { delete this; }
+ virtual SkBitmap* GetIcon() const {
+ return const_cast<SkBitmap*>(&decoded_icon_);
+ }
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringFUTF16(IDS_INTRODUCER_INSTALL_QUESTION, name_);
+ }
+ virtual bool Accept() {
+ if (!UpdateRegistration(tab_, registrant_, icon_, name_, home_)) {
+ return false;
+ }
+ InstallReturn(tab_, request_id_, true);
+ return true;
+ }
+ virtual bool Cancel() {
+ InstallReturn(tab_, request_id_, false);
+ return true;
+ }
+
+ private:
+ TabContents* tab_;
+ const int request_id_;
+ const std::string registrant_;
+ const GURL icon_;
+ const string16 name_;
+ const GURL home_;
+ SkBitmap decoded_icon_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstallInfoBar);
+};
+
+struct AcceptContext {
+ webkit_glue::IntroductionContext introduction;
+ std::string expected_registrant;
+ int customer_render_process_id;
+ int customer_render_view_id;
+ scoped_ptr<IPC::Message> connect_return;
+
+ AcceptContext() : customer_render_process_id(0),
+ customer_render_view_id(0) {}
+};
+
+class IntroducerHandler : public TabContentsObserver {
+ public:
+ explicit IntroducerHandler(TabContents* tab) : TabContentsObserver(tab) {}
+ virtual ~IntroducerHandler() {}
+
+ virtual bool OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+
+ IPC_BEGIN_MESSAGE_MAP(IntroducerHandler, message)
+ IPC_MESSAGE_HANDLER(IntroducerHostMsg_Install, OnInstall)
+ IPC_MESSAGE_HANDLER(IntroducerHostMsg_Uninstall, OnUninstall)
+ IPC_MESSAGE_HANDLER(IntroducerHostMsg_Offer, OnOffer)
+ IPC_MESSAGE_HANDLER(IntroducerHostMsg_Rescind, OnRescind)
+ IPC_MESSAGE_HANDLER(IntroducerHostMsg_Connect, OnConnect)
+ IPC_MESSAGE_HANDLER(IntroducerHostMsg_Accept, OnAccept)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+ }
+
+ private:
+
+ void OnInstall(const IPC::Message& message, int request_id,
+ const std::string& registrant, const GURL& icon,
+ const string16& name, const GURL& home) {
+ TabContents* tab = tab_contents();
+ Profile* profile = tab->profile();
+ PrefService* prefs = profile->IsOffTheRecord() ?
+ profile->GetOffTheRecordPrefs() : profile->GetPrefs();
+ const DictionaryValue* registrations =
+ prefs->GetDictionary(prefs::kIntroducerRegistrations);
+ DictionaryValue* registration = NULL;
+ std::string prior_icon;
+ string16 prior_name;
+ if (!registrations ||
+ !registrations->GetDictionaryWithoutPathExpansion(registrant,
+ &registration) ||
+ !registration->GetString("icon", &prior_icon) ||
+ prior_icon != icon.spec() ||
+ !registration->GetString("name", &prior_name) ||
+ prior_name != name) {
+ tab->AddInfoBar(new InstallInfoBar(tab, request_id,
+ registrant, icon, name, home));
+ } else {
+ InstallReturn(tab, request_id,
+ UpdateRegistration(tab, registrant, icon, name, home));
+ }
+ }
+
+ void OnUninstall(const IPC::Message& message, int request_id,
+ const std::string& registrant) {
+ TabContents* tab = tab_contents();
+ Profile* profile = tab->profile();
+ PrefService* prefs = profile->IsOffTheRecord() ?
+ profile->GetOffTheRecordPrefs() : profile->GetPrefs();
+ DictionaryValue* registrations =
+ prefs->GetMutableDictionary(prefs::kIntroducerRegistrations);
+ if (registrations) {
+ registrations->RemoveWithoutPathExpansion(registrant, NULL);
+ }
+ InstallReturn(tab, request_id, true);
+ }
+
+ void OnOffer(const IPC::Message& message, int request_id,
+ const std::string& registrant,
+ IntroducerHostMsg_Offer_Params args) {
+ TabContents* tab = tab_contents();
+ Profile* profile = tab->profile();
+ PrefService* prefs = profile->IsOffTheRecord() ?
+ profile->GetOffTheRecordPrefs() : profile->GetPrefs();
+ DictionaryValue* registrations =
+ prefs->GetMutableDictionary(prefs::kIntroducerRegistrations);
+ DictionaryValue* registration = NULL;
+ const bool agreed = registrations && registrations->
+ GetDictionaryWithoutPathExpansion(registrant, &registration);
+ if (agreed) {
+ DictionaryValue* services = NULL;
+ if (!registration->GetDictionary("services", &services)) {
+ services = new DictionaryValue();
+ registration->Set("services", services);
+ }
+ DictionaryValue* service = new DictionaryValue();
+ service->SetString("label", args.label);
+ DictionaryValue* supports = new DictionaryValue();
+ for (std::vector<std::string>::iterator i = args.supports.begin(),
+ end = args.supports.end();
+ i != end; ++i) {
+ supports->SetWithoutPathExpansion(*i, Value::CreateNullValue());
+ }
+ service->Set("supports", supports);
+ if (!args.window.is_empty()) {
+ service->SetString("window", args.window.spec());
+ }
+ if (!args.frame.is_empty()) {
+ service->SetString("frame", args.frame.spec());
+ }
+ int hits = 0;
+ DictionaryValue* prior = NULL;
+ if (services->GetDictionaryWithoutPathExpansion(args.id, &prior)) {
+ prior->GetInteger("hits", &hits);
+ }
+ service->SetInteger("hits", hits);
+ services->SetWithoutPathExpansion(args.id, service);
+ if (!profile->IsOffTheRecord()) {
+ prefs->ScheduleSavePersistentPrefs();
+ }
+ }
+ InstallReturn(tab, request_id, agreed);
+ }
+
+ void OnRescind(const IPC::Message& message, int request_id,
+ const std::string& registrant, const std::string& id) {
+ TabContents* tab = tab_contents();
+ Profile* profile = tab->profile();
+ PrefService* prefs = profile->IsOffTheRecord() ?
+ profile->GetOffTheRecordPrefs() : profile->GetPrefs();
+ DictionaryValue* registrations =
+ prefs->GetMutableDictionary(prefs::kIntroducerRegistrations);
+ DictionaryValue* registration = NULL;
+ if (registrations && registrations->
+ GetDictionaryWithoutPathExpansion(registrant, &registration)) {
+ DictionaryValue* services = NULL;
+ if (registration->GetDictionary("services", &services)) {
+ if (services->RemoveWithoutPathExpansion(id, NULL)) {
+ if (!profile->IsOffTheRecord()) {
+ prefs->ScheduleSavePersistentPrefs();
+ }
+ }
+ }
+ }
+ InstallReturn(tab, request_id, true);
+ }
+
+ void OnConnect(const IPC::Message& message, int request_id,
+ const std::string& customer,
+ int64 frame_id,
+ const std::vector<std::string>& wanted,
+ int port_id) {
+ ContextMenuParams params;
+ params.introduction_context.request_id = request_id;
+ params.introduction_context.customer = customer;
+ params.introduction_context.frame_id = frame_id;
+ params.introduction_context.wanted = wanted;
+ params.introduction_context.port_id = port_id;
+ RenderViewHostDelegate::View* view =
+ tab_contents()->render_view_host()->delegate()->GetViewDelegate();
+ if (view) {
+ view->ShowContextMenu(params);
+ } else {
+ IntroducerService::Dismiss(tab_contents(), request_id);
+ }
+ }
+
+ void OnAccept(const IPC::Message& message, int request_id, int64 src,
+ const std::string& registrant, int port_id) {
+ scoped_ptr<AcceptContext> accept_context(pending_[src]);
+ pending_.erase(src);
+ RenderViewHost* service_host = tab_contents()->render_view_host();
+ if (accept_context.get()) {
+ RenderViewHost* customer_host = RenderViewHost::FromID(
+ accept_context->customer_render_process_id,
+ accept_context->customer_render_view_id);
+ if (accept_context->expected_registrant == registrant) {
+ MessagePortService* ports = MessagePortService::GetInstance();
+ ports->Entangle(port_id, accept_context->introduction.port_id);
+ ports->Entangle(accept_context->introduction.port_id, port_id);
+ service_host->Send(new IntroducerMsg_AcceptReturn(
+ service_host->routing_id(), request_id,
+ accept_context->introduction.customer,
+ accept_context->introduction.wanted));
+ if (customer_host) {
+ customer_host->Send(accept_context->connect_return.release());
+ }
+ } else {
+ service_host->Send(new IntroducerMsg_AcceptReturn(
+ service_host->routing_id(), request_id,
+ "", std::vector<std::string>()));
+ if (customer_host) {
+ customer_host->Send(new IntroducerMsg_ConnectReturn(
+ customer_host->routing_id(),
+ accept_context->introduction.request_id,
+ std::vector<std::string>()));
+ }
+ }
+ } else {
+ service_host->Send(new IntroducerMsg_AcceptReturn(
+ service_host->routing_id(), request_id,
+ "", std::vector<std::string>()));
+ }
+ }
+
+ private:
+ friend class IntroducerService;
+ std::map<int64,AcceptContext*> pending_;
+
+ DISALLOW_COPY_AND_ASSIGN(IntroducerHandler);
+};
+
+// static
+TabContentsObserver* IntroducerService::Make(TabContents* tab) {
+ return new IntroducerHandler(tab);
+}
+
+// static
+void IntroducerService::RegisterUserPrefs(PrefService* user_prefs) {
+ if (!user_prefs->FindPreference(prefs::kIntroducerRegistrations)) {
+ user_prefs->RegisterDictionaryPref(prefs::kIntroducerRegistrations);
+ }
+}
+
+// static
+bool IntroducerService::InitMenu(
+ TabContents* tab, Profile* profile,
+ const ContextMenuParams& params,
+ std::map< int, std::pair<std::string,std::string> >* commands,
+ ui::SimpleMenuModel* menu) {
+ const std::vector<std::string>& wanted = params.introduction_context.wanted;
+ if (!wanted.empty()) {
+ PrefService* prefs = profile->IsOffTheRecord() ?
+ profile->GetOffTheRecordPrefs() : profile->GetPrefs();
+ const DictionaryValue* registrations =
+ prefs->GetDictionary(prefs::kIntroducerRegistrations);
+ if (registrations) {
+ int command_id = IDC_INTRODUCER_CONTEXT_CUSTOM_FIRST;
+ std::vector<int> priority;
+ for (DictionaryValue::key_iterator i = registrations->begin_keys(),
+ i_last = registrations->end_keys();
+ command_id < IDC_INTRODUCER_CONTEXT_CUSTOM_LAST && i != i_last; ++i) {
+ DictionaryValue* registration = NULL;
+ if (registrations->GetDictionaryWithoutPathExpansion(*i,
+ &registration)) {
+ SkBitmap icon;
+ DictionaryValue* services = NULL;
+ if (registration->GetDictionary("services", &services)) {
+ for (DictionaryValue::key_iterator j = services->begin_keys(),
+ j_last = services->end_keys();
+ command_id < IDC_INTRODUCER_CONTEXT_CUSTOM_LAST && j != j_last;
+ ++j) {
+ DictionaryValue* service = NULL;
+ if (services->GetDictionaryWithoutPathExpansion(*j, &service)) {
+ if (service->HasKey("window") ||
+ (params.introduction_context.frame_id &&
+ service->HasKey("frame"))) {
+ DictionaryValue* supports = NULL;
+ if (service->GetDictionary("supports", &supports)) {
+ for (std::vector<std::string>::const_iterator
+ k = wanted.begin(),
+ k_last = wanted.end(); k != k_last; ++k) {
+ if (supports->HasKey(*k)) {
+ int hits = 0;
+ service->GetInteger("hits", &hits);
+ int index = menu->GetItemCount();
+ std::vector<int>::iterator l_first = priority.begin(),
+ l = priority.end();
+ for (; l != l_first; --l, --index) {
+ if (*(l - 1) >= hits) {
+ break;
+ }
+ }
+ priority.insert(l, hits);
+ string16 label;
+ service->GetString("label", &label);
+ menu->InsertItemAt(index, command_id, label);
+ if (icon.isNull()) {
+ std::string icon_url;
+ if (registration->GetString("icon", &icon_url)) {
+ icon = ImageFromDataUrl(GURL(icon_url));
+ }
+ }
+ menu->SetIcon(index, icon);
+ (*commands)[command_id] = std::make_pair(*i, *j);
+ command_id += 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0 != params.introduction_context.request_id;
+}
+
+// static
+bool IntroducerService::Introduce(
+ TabContents* tab, Profile* profile, const ContextMenuParams& params,
+ const std::pair<std::string,std::string>& selection) {
+ PrefService* prefs = profile->IsOffTheRecord() ?
+ profile->GetOffTheRecordPrefs() : profile->GetPrefs();
+ DictionaryValue* registrations =
+ prefs->GetMutableDictionary(prefs::kIntroducerRegistrations);
+ DictionaryValue* registration = NULL;
+ DictionaryValue* services = NULL;
+ DictionaryValue* service = NULL;
+ if (!registrations ||
+ !registrations->GetDictionaryWithoutPathExpansion(selection.first,
+ &registration) ||
+ !registration->GetDictionary("services", &services) ||
+ !services->GetDictionaryWithoutPathExpansion(selection.second,
+ &service)) {
+ return false;
+ }
+ int hits = 0;
+ service->GetInteger("hits", &hits);
+ service->SetInteger("hits", hits + 1);
+ std::vector<std::string> agreed;
+ const std::vector<std::string>& wanted = params.introduction_context.wanted;
+ DictionaryValue* supports = NULL;
+ if (service->GetDictionary("supports", &supports)) {
+ for (std::vector<std::string>::const_iterator i = wanted.begin(),
+ i_last = wanted.end();
+ i != i_last; ++i) {
+ if (supports->HasKey(*i)) {
+ agreed.push_back(*i);
+ }
+ }
+ }
+ if (!profile->IsOffTheRecord()) {
+ prefs->ScheduleSavePersistentPrefs();
+ }
+
+ RenderViewHost* host = tab->render_view_host();
+ if (!host) {
+ return false;
+ }
+ scoped_ptr<AcceptContext> accept_context(new AcceptContext());
+ accept_context->introduction = params.introduction_context;
+ accept_context->expected_registrant = selection.first;
+ accept_context->customer_render_process_id = host->process()->id();
+ accept_context->customer_render_view_id = host->routing_id();
+ accept_context->connect_return.reset(new IntroducerMsg_ConnectReturn(
+ host->routing_id(), params.introduction_context.request_id, agreed));
+
+ std::string frame;
+ if (params.introduction_context.frame_id &&
+ service->GetString("frame", &frame)) {
+ IntroducerHandler* handler =
+ static_cast<IntroducerHandler*>(tab->introducer_handler_.get());
+ handler->pending_[params.introduction_context.frame_id] =
+ accept_context.release();
+ host->Send(new IntroducerMsg_ConnectNavigation(
+ host->routing_id(), params.introduction_context.request_id, GURL(frame)));
+ return true;
+ }
+
+ std::string window;
+ if (service->GetString("window", &window)) {
+ Browser* browser = BrowserList::GetLastActive();
+ if (browser) {
+ TabContentsWrapper* service_tab = browser->CreateTabContentsForURL(
+ GURL(window), GURL(), profile, PageTransition::LINK, false, NULL);
+ browser->tabstrip_model()->AppendTabContents(service_tab, true);
+ IntroducerHandler* handler = static_cast<IntroducerHandler*>(
+ service_tab->tab_contents()->introducer_handler_.get());
+ handler->pending_[0] = accept_context.release();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// static
+void IntroducerService::Dismiss(TabContents* tab, int request_id) {
+ RenderViewHost* host = tab->render_view_host();
+ if (host) {
+ host->Send(new IntroducerMsg_ConnectReturn(host->routing_id(), request_id,
+ std::vector<std::string>()));
+ }
+}
Property changes on: chrome/browser/tab_contents/introducer_handler.cc
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « chrome/browser/tab_contents/introducer_handler.h ('k') | chrome/browser/tab_contents/render_view_context_menu.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698