Skip to content

Commit

Permalink
Renderer-side changes for browser plugin
Browse files Browse the repository at this point in the history
Major Classes:

BrowserPluginChannelManager: Manages GuestToEmbedderChannels. It essentially wraps a map that is keyed on channel names.

GuestToEmbedderChannel: Is a Dispatcher. Receives/Sends Ppapi messages. Keeps track of all RenderViews that have an associated PP_Instance in a map (RenderViews that are guests). brettw@ might want to have a look here?

BrowserPluginRegistry: Wrapper around map that keeps track of Browser Plugin PluginModules keyed on the guest process id. This is similar to the PepperPluginRegistry but has a different key type.

BrowserPluginVarSerializationRules: Temporary do nothing class as suggested by brettw@

BrowserPlugin: Towards becoming a wrapper around a WebPluginContainerImpl that swaps out WebPluginImpl/WebViewPlugin on navigation. We get a blank WebViewPlugin (is this a best thing to do to get a blank placeholder?) if we have an empty src attribute or while we're navigating for the first time. Otherwise, on cross-process navigations, we substitute one WebPluginImpl for another WebPluginImpl. TODO: BrowserPlugin should track the lifetime of WebPluginContainerImpl, but right now it lives forever which is bad. Will fix this in a subsequent patch. This requires some WebKit changes first.

BUG=117897
TEST=manually

Review URL: https://chromiumcodereview.appspot.com/9968097

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@138416 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
fsamuel@chromium.org committed May 23, 2012
1 parent 28599f4 commit 468e490
Show file tree
Hide file tree
Showing 21 changed files with 1,248 additions and 291 deletions.
62 changes: 39 additions & 23 deletions content/common/browser_plugin_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,76 @@
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"
#include "ppapi/c/pp_instance.h"
#include "ui/gfx/size.h"

#define IPC_MESSAGE_START BrowserPluginMsgStart

// Browser plugin messages

// -----------------------------------------------------------------------------
// These messages are from the host renderer to the browser process
// These messages are from the embedder to the browser process

// A renderer sends this to the browser process when it wants to
// create a browser plugin. The browser will create a guest renderer process
// if necessary.
IPC_MESSAGE_ROUTED4(BrowserPluginHostMsg_OpenChannel,
IPC_MESSAGE_ROUTED4(BrowserPluginHostMsg_NavigateFromEmbedder,
int /* plugin instance id*/,
long long /* frame id */,
std::string /* src */,
gfx::Size /* size */)

// Initially before we create a guest renderer, browser plugin containers
// have a placeholder called BrowserPlugin where each BrowserPlugin has a unique
// ID. During pepper plugin initialization, the embedder page and the plugin
// negotiate an ID of type PP_Instance. The browser talks to the guest
// RenderView via yet another identifier called the routing ID. The browser
// has to keep track of how all these identifiers are associated with one
// another.
// For reference:
// 1. The embedder page sees the guest renderer as a plugin and so it talks
// to the guest via the PP_Instance identifer.
// 2. The guest renderer talks to the browser and vice versa via a routing ID.
// 3. The BrowserPlugin ID uniquely identifies a browser plugin container
// instance within an embedder.
// This identifier exists prior to the existence of the routing ID and the
// PP_Instance identifier.
// The purpose of this message is to tell the browser to map a PP_Instance
// identifier to BrowserPlugin identifier.
IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_MapInstance,
int /* container_id */,
PP_Instance /* instance */)

// -----------------------------------------------------------------------------
// These messages are from the browser process to the guest renderer.

// Creates a channel to talk to a renderer. The guest renderer will respond
// with BrowserPluginHostMsg_ChannelCreated.
IPC_MESSAGE_CONTROL2(BrowserPluginMsg_CreateChannel,
base::ProcessHandle /* host_renderer_process_handle */,
int /* host_renderer_id */)
IPC_MESSAGE_CONTROL2(BrowserPluginMsg_CompleteNavigation,
int /* guest_routing_id */,
PP_Instance /* instance */)

// -----------------------------------------------------------------------------
// These messages are from the guest renderer to the browser process

// Reply to BrowserPluginMsg_CreateChannel. The handle will be NULL if the
// channel could not be established. This could be because the IPC could not be
// created for some weird reason, but more likely that the renderer failed to
// initialize properly.
IPC_MESSAGE_CONTROL1(BrowserPluginHostMsg_ChannelCreated,
IPC::ChannelHandle /* handle */)

// Indicates the guest renderer is ready in response to a ViewMsg_New
IPC_MESSAGE_ROUTED0(BrowserPluginHostMsg_GuestReady)
IPC_MESSAGE_ROUTED1(BrowserPluginHostMsg_ConnectToChannel,
IPC::ChannelHandle /* handle */)

// A host renderer sends this message to the browser when it wants
// A embedder sends this message to the browser when it wants
// to resize a guest plugin container so that the guest is relaid out
// according to the new size.
IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_ResizeGuest,
int32, /* width */
int32 /* height */)

IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_NavigateFromGuest,
PP_Instance /* instance */,
std::string /* src */)

// -----------------------------------------------------------------------------
// These messages are from the browser process to the host renderer.
// These messages are from the browser process to the embedder.

// A guest instance is ready to be placed.
IPC_MESSAGE_ROUTED3(BrowserPluginMsg_GuestReady_ACK,
int /* instance id */,
base::ProcessHandle /* plugin_process_handle */,
IPC::ChannelHandle /* handle to channel */)

IPC_MESSAGE_CONTROL3(BrowserPluginMsg_LoadGuest,
int /* instance id */,
int /* guest_process_id */,
IPC::ChannelHandle /* channel_handle */)

12 changes: 10 additions & 2 deletions content/content_renderer.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,18 @@
'renderer/pepper/pepper_proxy_channel_delegate_impl.h',
'renderer/plugin_channel_host.cc',
'renderer/plugin_channel_host.h',
'renderer/browser_plugin/browser_plugin.cc',
'renderer/browser_plugin/browser_plugin.h',
'renderer/browser_plugin/browser_plugin_channel_manager.cc',
'renderer/browser_plugin/browser_plugin_channel_manager.h',
'renderer/browser_plugin/browser_plugin_constants.cc',
'renderer/browser_plugin/browser_plugin_constants.h',
'renderer/browser_plugin/browser_plugin_placeholder.cc',
'renderer/browser_plugin/browser_plugin_placeholder.h',
'renderer/browser_plugin/browser_plugin_registry.cc',
'renderer/browser_plugin/browser_plugin_registry.h',
'renderer/browser_plugin/browser_plugin_var_serialization_rules.cc',
'renderer/browser_plugin/browser_plugin_var_serialization_rules.h',
'renderer/browser_plugin/guest_to_embedder_channel.cc',
'renderer/browser_plugin/guest_to_embedder_channel.h',
'renderer/render_process.h',
'renderer/render_process_impl.cc',
'renderer/render_process_impl.h',
Expand Down
167 changes: 167 additions & 0 deletions content/renderer/browser_plugin/browser_plugin.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// 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 "content/renderer/browser_plugin/browser_plugin.h"

#include "base/atomic_sequence_num.h"
#include "base/id_map.h"
#include "base/lazy_instance.h"
#include "base/process.h"
#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/values.h"
#include "content/common/browser_plugin_messages.h"
#include "content/public/common/url_constants.h"
#include "content/renderer/render_view_impl.h"
#include "ipc/ipc_channel_handle.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPlugin.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
#include "webkit/plugins/ppapi/ppapi_webplugin_impl.h"
#include "webkit/plugins/webview_plugin.h"

static int g_next_id = 0;

// The global list of all Browser Plugin Placeholders within a process.
base::LazyInstance<IDMap<BrowserPlugin> >::Leaky
g_all_browser_plugins = LAZY_INSTANCE_INITIALIZER;

using WebKit::WebPlugin;
using WebKit::WebPluginContainer;
using webkit::WebViewPlugin;

void Register(int id, BrowserPlugin* browser_plugin) {
g_all_browser_plugins.Get().AddWithID(browser_plugin, id);
}

void Unregister(int id) {
if (g_all_browser_plugins.Get().Lookup(id))
g_all_browser_plugins.Get().Remove(id);
}

// static
WebKit::WebPlugin* BrowserPlugin::Create(
RenderViewImpl* render_view,
WebKit::WebFrame* frame,
const WebKit::WebPluginParams& params) {
// TODO(fsamuel): Figure out what the lifetime is of this class.
// It seems we need to blow away this object once a WebPluginContainer is
// gone. How do we detect it's gone? A WebKit change perhaps?
BrowserPlugin* browser_plugin = new BrowserPlugin(
render_view, frame, params, "");
return browser_plugin->placeholder();
}

// static
BrowserPlugin* BrowserPlugin::FromID(int id) {
return g_all_browser_plugins.Get().Lookup(id);
}

BrowserPlugin::BrowserPlugin(
RenderViewImpl* render_view,
WebKit::WebFrame* frame,
const WebKit::WebPluginParams& params,
const std::string& html_data)
: render_view_(render_view),
plugin_params_(params),
placeholder_(webkit::WebViewPlugin::Create(
NULL,
render_view->GetWebkitPreferences(),
html_data,
GURL(chrome::kAboutBlankURL))),
plugin_(NULL) {
id_ = ++g_next_id;
Register(id_, this);

// By default we do not navigate and simply stay with an
// about:blank placeholder.
gfx::Size size;
std::string src;
ParsePluginParameters(0, 0, "", &size, &src);

if (!src.empty()) {
render_view->Send(new BrowserPluginHostMsg_NavigateFromEmbedder(
render_view->GetRoutingID(),
id_,
frame->identifier(),
src,
size));
}
}

BrowserPlugin::~BrowserPlugin() {
Unregister(id_);
}

void BrowserPlugin::ParsePluginParameters(
int default_width,
int default_height,
const std::string& default_src,
gfx::Size* size,
std::string* src) {
int width = default_width;
int height = default_height;

// Get the plugin parameters from the attributes vector
for (unsigned i = 0; i < plugin_params_.attributeNames.size(); ++i) {
std::string attributeName = plugin_params_.attributeNames[i].utf8();
if (LowerCaseEqualsASCII(attributeName, "width")) {
std::string attributeValue = plugin_params_.attributeValues[i].utf8();
CHECK(base::StringToInt(attributeValue, &width));
} else if (LowerCaseEqualsASCII(attributeName, "height")) {
std::string attributeValue = plugin_params_.attributeValues[i].utf8();
CHECK(base::StringToInt(attributeValue, &height));
} else if (LowerCaseEqualsASCII(attributeName, "src")) {
*src = plugin_params_.attributeValues[i].utf8();
}
}
// If we didn't find the attributes set or they're not sensible,
// we reset our attributes to the default.
if (src->empty()) {
*src = default_src;
}

size->SetSize(width, height);
}

void BrowserPlugin::LoadGuest(
int guest_process_id,
const IPC::ChannelHandle& channel_handle) {
webkit::ppapi::WebPluginImpl* new_guest =
render_view()->CreateBrowserPlugin(channel_handle,
guest_process_id,
plugin_params());
Replace(new_guest);
}

void BrowserPlugin::Replace(
webkit::ppapi::WebPluginImpl* new_plugin) {
WebKit::WebPlugin* current_plugin =
plugin_ ? static_cast<WebKit::WebPlugin*>(plugin_) : placeholder_;
WebKit::WebPluginContainer* container = current_plugin->container();
if (!new_plugin || !new_plugin->initialize(container))
return;

// Clear the container's backing texture ID and the script objects.
if (plugin_)
plugin_->instance()->BindGraphics(plugin_->instance()->pp_instance(), 0);

// Inform the browser process of the association between the browser plugin's
// instance ID and the pepper channel's PP_Instance identifier.
render_view()->Send(new BrowserPluginHostMsg_MapInstance(
render_view()->GetRoutingID(),
id_,
new_plugin->instance()->pp_instance()));
// TODO(fsamuel): We should delay the swapping out of the current plugin
// until after the guest's WebGraphicsContext3D has been initialized. That
// way, we immediately have something to render onto the screen.
container->setPlugin(new_plugin);
container->invalidate();
container->reportGeometry();
if (plugin_)
plugin_->destroy();
plugin_ = new_plugin;
}
91 changes: 91 additions & 0 deletions content/renderer/browser_plugin/browser_plugin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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.

#ifndef CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_H_
#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_H_
#pragma once

#include "base/process.h"
#include "content/renderer/render_view_impl.h"
#include "ipc/ipc_channel_handle.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginParams.h"
#include "ui/gfx/size.h"
#include "webkit/plugins/webview_plugin.h"

namespace content {
class RenderView;
}

namespace WebKit {
class WebPlugin;
}

// A browser plugin is a plugin container that hosts an out-of-process "guest"
// RenderView. Loading up a new process, creating a new RenderView, navigating
// to a given URL, and establishing a guest-to-embedder channel can take
// hundreds of milliseconds. Furthermore, a RenderView's associated browser-side
// WebContents, RenderViewHost, and SiteInstance must be created and accessed on
// the UI thread of the browser process.
//
// To avoid blocking the embedder RenderView and to avoid introducing the
// potential for deadlock, BrowserPlugin attaches a placeholder that takes
// place of the guest RenderView until the guest has established a connection
// with its embedder RenderView. This permits asynchronously loading of the
// guest while the embedder RenderView is permitted to continue to receive and
// process events.
//
// Furthermore, certain navigations can swap to a new guest RenderView on an
// different process. BrowserPlugin is the consistent facade that the embedder's
// WebKit instance talks to regardless of which process it's communicating with.
class BrowserPlugin {
public:
// Creates a new WebViewPlugin with a BrowserPlugin as a delegate.
static WebKit::WebPlugin* Create(
RenderViewImpl* render_view,
WebKit::WebFrame* frame,
const WebKit::WebPluginParams& params);

static BrowserPlugin* FromID(int id);

webkit::WebViewPlugin* placeholder() { return placeholder_; }

webkit::ppapi::WebPluginImpl* plugin() { return plugin_; }

const WebKit::WebPluginParams& plugin_params() const {
return plugin_params_;
}

void LoadGuest(int guest_process_id,
const IPC::ChannelHandle& channel_handle);

RenderViewImpl* render_view() { return render_view_; }

private:
BrowserPlugin(RenderViewImpl* render_view,
WebKit::WebFrame* frame,
const WebKit::WebPluginParams& params,
const std::string& html_data);
virtual ~BrowserPlugin();

// Parses the width, height, and source URL of the browser plugin
// from the element's attributes and outputs them. If not found, it outputs
// the defaults specified here as parameters.
void ParsePluginParameters(int default_width, int default_height,
const std::string& default_src,
gfx::Size* size,
std::string* src);
// Replace the current guest with a new guest.
void Replace(webkit::ppapi::WebPluginImpl* new_plugin);

RenderViewImpl* render_view_;
WebKit::WebPluginParams plugin_params_;
webkit::WebViewPlugin* placeholder_;
webkit::ppapi::WebPluginImpl* plugin_;
int id_;

DISALLOW_COPY_AND_ASSIGN(BrowserPlugin);
};

#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_H_
Loading

0 comments on commit 468e490

Please sign in to comment.