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, |
+ ®istration)) { |
+ 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, |
+ ®istration) || |
+ !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, ®istration); |
+ 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, ®istration)) { |
+ 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, |
+ ®istration)) { |
+ 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, |
+ ®istration) || |
+ !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 |