| 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
|
|
|
|
|