summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/common/browser_plugin_messages.h152
-rw-r--r--content/common/content_message_generator.h1
-rw-r--r--content/content_common.gypi1
-rw-r--r--content/content_renderer.gypi10
-rw-r--r--content/content_tests.gypi6
-rw-r--r--content/public/common/content_constants.cc3
-rw-r--r--content/public/common/content_constants.h3
-rw-r--r--content/renderer/browser_plugin/browser_plugin.cc401
-rw-r--r--content/renderer/browser_plugin/browser_plugin.h148
-rw-r--r--content/renderer/browser_plugin/browser_plugin_backing_store.cc90
-rw-r--r--content/renderer/browser_plugin/browser_plugin_backing_store.h64
-rw-r--r--content/renderer/browser_plugin/browser_plugin_bindings.cc253
-rw-r--r--content/renderer/browser_plugin/browser_plugin_bindings.h53
-rw-r--r--content/renderer/browser_plugin/browser_plugin_browsertest.cc307
-rw-r--r--content/renderer/browser_plugin/browser_plugin_browsertest.h42
-rw-r--r--content/renderer/browser_plugin/browser_plugin_manager.cc47
-rw-r--r--content/renderer/browser_plugin/browser_plugin_manager.h58
-rw-r--r--content/renderer/browser_plugin/browser_plugin_manager_impl.cc74
-rw-r--r--content/renderer/browser_plugin/browser_plugin_manager_impl.h44
-rw-r--r--content/renderer/browser_plugin/mock_browser_plugin.cc19
-rw-r--r--content/renderer/browser_plugin/mock_browser_plugin.h29
-rw-r--r--content/renderer/browser_plugin/mock_browser_plugin_manager.cc66
-rw-r--r--content/renderer/browser_plugin/mock_browser_plugin_manager.h50
-rw-r--r--content/renderer/render_view_impl.cc9
-rw-r--r--ipc/ipc_message_utils.h1
25 files changed, 1931 insertions, 0 deletions
diff --git a/content/common/browser_plugin_messages.h b/content/common/browser_plugin_messages.h
new file mode 100644
index 0000000..af68c71
--- /dev/null
+++ b/content/common/browser_plugin_messages.h
@@ -0,0 +1,152 @@
+// 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.
+
+// Multiply-included message header, no traditional include guard.
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/process.h"
+#include "content/common/content_export.h"
+#include "content/public/common/common_param_traits.h"
+#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_utils.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/size.h"
+#include "webkit/glue/webcursor.h"
+
+#undef IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
+
+#define IPC_MESSAGE_START BrowserPluginMsgStart
+
+// Browser plugin messages
+
+// -----------------------------------------------------------------------------
+// These messages are from the embedder to the browser process.
+
+// Tells the guest to focus or defocus itself.
+IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_SetFocus,
+ int /* instance_id */,
+ bool /* enable */)
+
+// Message payload includes:
+// 1. A blob that should be cast to WebInputEvent
+// 2. An optional boolean value indicating if a RawKeyDown event is associated
+// to a keyboard shortcut of the browser.
+IPC_SYNC_MESSAGE_ROUTED0_2(BrowserPluginHostMsg_HandleInputEvent,
+ bool /* handled */,
+ WebCursor /* cursor */)
+
+// An ACK to the guest process letting it know that the embedder has handled
+// the previous frame and is ready for the next frame. If the guest sent the
+// embedder a bitmap that does not match the size of the BrowserPlugin's
+// container, the BrowserPlugin requests a new size as well.
+IPC_MESSAGE_ROUTED3(BrowserPluginHostMsg_UpdateRect_ACK,
+ int /* instance_id */,
+ int /* message_id */,
+ gfx::Size /* repaint_view_size */)
+
+// A BrowserPlugin sends this to the browser process when it wants to navigate
+// to a given src URL. If a guest WebContents already exists, it will navigate
+// that WebContents. If not, it will create the WebContents, associate it with
+// the BrowserPlugin's browser-side BrowserPluginHost as a guest, and navigate
+// it to the requested URL.
+IPC_MESSAGE_ROUTED3(BrowserPluginHostMsg_NavigateOrCreateGuest,
+ int /* instance_id*/,
+ long long /* frame_id */,
+ std::string /* src */)
+
+// When a BrowserPlugin has been removed from the embedder's DOM, it informs
+// the browser process to cleanup the guest.
+IPC_MESSAGE_ROUTED1(BrowserPluginHostMsg_PluginDestroyed,
+ int /* instance_id */)
+
+// -----------------------------------------------------------------------------
+// These messages are from the guest renderer to the browser process
+
+IPC_STRUCT_BEGIN(BrowserPluginHostMsg_ResizeGuest_Params)
+ // A handle to the new buffer to use to transport damage to the
+ // embedder renderer process.
+ IPC_STRUCT_MEMBER(TransportDIB::Id, damage_buffer_id)
+ // The new width of the plugin container.
+ IPC_STRUCT_MEMBER(int, width)
+ // The new height of the plugin container.
+ IPC_STRUCT_MEMBER(int, height)
+ // Indicates whether the embedder is currently waiting on a ACK from the
+ // guest for a previous resize request.
+ IPC_STRUCT_MEMBER(bool, resize_pending)
+ // Indicates the scale factor of the embedder WebView.
+ IPC_STRUCT_MEMBER(float, scale_factor)
+IPC_STRUCT_END()
+
+// 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_SYNC_MESSAGE_ROUTED2_0(BrowserPluginHostMsg_ResizeGuest,
+ int /* instance_id*/,
+ BrowserPluginHostMsg_ResizeGuest_Params)
+
+// -----------------------------------------------------------------------------
+// These messages are from the browser process to the embedder.
+
+// When the guest navigates, the browser process informs the embedder through
+// the BrowserPluginMsg_DidNavigate message.
+IPC_MESSAGE_CONTROL2(BrowserPluginMsg_DidNavigate,
+ int /* instance_id */,
+ GURL /* url */)
+
+// When the guest crashes, the browser process informs the embedder through this
+// message.
+IPC_MESSAGE_CONTROL1(BrowserPluginMsg_GuestCrashed,
+ int /* instance_id */)
+
+IPC_STRUCT_BEGIN(BrowserPluginMsg_UpdateRect_Params)
+ // The position and size of the bitmap.
+ IPC_STRUCT_MEMBER(gfx::Rect, bitmap_rect)
+
+ // The scroll offset. Only one of these can be non-zero, and if they are
+ // both zero, then it means there is no scrolling and the scroll_rect is
+ // ignored.
+ IPC_STRUCT_MEMBER(int, dx)
+ IPC_STRUCT_MEMBER(int, dy)
+
+ // The rectangular region to scroll.
+ IPC_STRUCT_MEMBER(gfx::Rect, scroll_rect)
+
+ // The scroll offset of the render view.
+ IPC_STRUCT_MEMBER(gfx::Point, scroll_offset)
+
+ // The regions of the bitmap (in view coords) that contain updated pixels.
+ // In the case of scrolling, this includes the scroll damage rect.
+ IPC_STRUCT_MEMBER(std::vector<gfx::Rect>, copy_rects)
+
+ // The size of the RenderView when this message was generated. This is
+ // included so the host knows how large the view is from the perspective of
+ // the renderer process. This is necessary in case a resize operation is in
+ // progress. If auto-resize is enabled, this should update the corresponding
+ // view size.
+ IPC_STRUCT_MEMBER(gfx::Size, view_size)
+
+ // All the above coordinates are in DIP. This is the scale factor needed
+ // to convert them to pixels.
+ IPC_STRUCT_MEMBER(float, scale_factor)
+
+ // Is this UpdateRect an ACK to a resize request?
+ IPC_STRUCT_MEMBER(bool, is_resize_ack)
+IPC_STRUCT_END()
+
+// When the user tabs to the end of the tab stops of a guest, the browser
+// process informs the embedder to tab out of the browser plugin.
+IPC_MESSAGE_CONTROL2(BrowserPluginMsg_AdvanceFocus,
+ int /* instance_id */,
+ bool /* reverse */)
+
+// The guest has damage it wants to convey to the embedder so that it can
+// update its backing store.
+IPC_MESSAGE_CONTROL3(BrowserPluginMsg_UpdateRect,
+ int /* instance_id */,
+ int /* message_id */,
+ BrowserPluginMsg_UpdateRect_Params)
diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h
index 11ac327..e5cdb48 100644
--- a/content/common/content_message_generator.h
+++ b/content/common/content_message_generator.h
@@ -8,6 +8,7 @@
#include "content/common/accessibility_messages.h"
#include "content/common/appcache_messages.h"
+#include "content/common/browser_plugin_messages.h"
#include "content/common/clipboard_messages.h"
#include "content/common/database_messages.h"
#include "content/common/desktop_notification_messages.h"
diff --git a/content/content_common.gypi b/content/content_common.gypi
index b85bf05..725c330 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -123,6 +123,7 @@
'common/appcache/appcache_dispatcher.cc',
'common/appcache/appcache_dispatcher.h',
'common/appcache_messages.h',
+ 'common/browser_plugin_messages.h',
'common/child_histogram_message_filter.cc',
'common/child_histogram_message_filter.h',
'common/child_process.cc',
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index b8467b1..69cb8a2 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -179,6 +179,16 @@
'renderer/plugin_channel_host.h',
'renderer/browser_plugin/old/browser_plugin_channel_manager.cc',
'renderer/browser_plugin/old/browser_plugin_channel_manager.h',
+ 'renderer/browser_plugin/browser_plugin.cc',
+ 'renderer/browser_plugin/browser_plugin.h',
+ 'renderer/browser_plugin/browser_plugin_backing_store.h',
+ 'renderer/browser_plugin/browser_plugin_backing_store.cc',
+ 'renderer/browser_plugin/browser_plugin_bindings.h',
+ 'renderer/browser_plugin/browser_plugin_bindings.cc',
+ 'renderer/browser_plugin/browser_plugin_manager.h',
+ 'renderer/browser_plugin/browser_plugin_manager.cc',
+ 'renderer/browser_plugin/browser_plugin_manager_impl.h',
+ 'renderer/browser_plugin/browser_plugin_manager_impl.cc',
'renderer/browser_plugin/old/browser_plugin_constants.cc',
'renderer/browser_plugin/old/browser_plugin_constants.h',
'renderer/browser_plugin/old/browser_plugin_registry.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 8548e7d..590da0d 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -584,6 +584,12 @@
'browser/speech/speech_recognition_browsertest.cc',
'browser/webkit_browsertest.cc',
'browser/worker_host/test/worker_browsertest.cc',
+ 'renderer/browser_plugin/mock_browser_plugin.h',
+ 'renderer/browser_plugin/mock_browser_plugin.cc',
+ 'renderer/browser_plugin/mock_browser_plugin_manager.h',
+ 'renderer/browser_plugin/mock_browser_plugin_manager.cc',
+ 'renderer/browser_plugin/browser_plugin_browsertest.h',
+ 'renderer/browser_plugin/browser_plugin_browsertest.cc',
'renderer/mouse_lock_dispatcher_browsertest.cc',
'renderer/pepper/pepper_file_chooser_host_unittest.cc',
'renderer/render_view_browsertest.cc',
diff --git a/content/public/common/content_constants.cc b/content/public/common/content_constants.cc
index 66cd854..b8e205f9 100644
--- a/content/public/common/content_constants.cc
+++ b/content/public/common/content_constants.cc
@@ -11,6 +11,9 @@ const FilePath::CharType kPepperDataDirname[] =
FILE_PATH_LITERAL("Pepper Data");
const char kBrowserPluginMimeType[] = "application/browser-plugin";
+// TODO(fsamuel): Remove this once upstreaming of the new browser plugin is
+// complete.
+const char kBrowserPluginNewMimeType[] = "application/new-browser-plugin";
// This number used to be limited to 32 in the past (see b/535234).
const size_t kMaxRendererProcessCount = 82;
diff --git a/content/public/common/content_constants.h b/content/public/common/content_constants.h
index 9097181..12bd7dc 100644
--- a/content/public/common/content_constants.h
+++ b/content/public/common/content_constants.h
@@ -23,6 +23,9 @@ CONTENT_EXPORT extern const FilePath::CharType kPepperDataDirname[];
// The MIME type used for the browser plugin.
CONTENT_EXPORT extern const char kBrowserPluginMimeType[];
+// TODO(fsamuel): Remove this once upstreaming of the new browser plugin is
+// complete.
+CONTENT_EXPORT extern const char kBrowserPluginNewMimeType[];
CONTENT_EXPORT extern const size_t kMaxRendererProcessCount;
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
new file mode 100644
index 0000000..e7bb338
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -0,0 +1,401 @@
+// 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/message_loop.h"
+#include "base/string_util.h"
+#include "content/common/browser_plugin_messages.h"
+#include "content/public/common/content_client.h"
+#include "content/public/renderer/content_renderer_client.h"
+#include "content/renderer/browser_plugin/browser_plugin_bindings.h"
+#include "content/renderer/browser_plugin/browser_plugin_manager.h"
+#include "content/renderer/render_process_impl.h"
+#include "content/renderer/render_thread_impl.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginParams.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
+#include "webkit/plugins/sad_plugin.h"
+
+using WebKit::WebCanvas;
+using WebKit::WebPlugin;
+using WebKit::WebPluginContainer;
+using WebKit::WebPluginParams;
+using WebKit::WebPoint;
+using WebKit::WebString;
+using WebKit::WebRect;
+using WebKit::WebURL;
+using WebKit::WebVector;
+
+namespace content {
+
+namespace {
+const char kNavigationEventName[] = "navigation";
+const char* kSrcAttribute = "src";
+}
+
+BrowserPlugin::BrowserPlugin(
+ int instance_id,
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebPluginParams& params)
+ : instance_id_(instance_id),
+ render_view_(render_view),
+ container_(NULL),
+ damage_buffer_(NULL),
+ sad_guest_(NULL),
+ guest_crashed_(false),
+ resize_pending_(false),
+ parent_frame_(frame->identifier()) {
+ BrowserPluginManager::Get()->AddBrowserPlugin(instance_id, this);
+ bindings_.reset(new BrowserPluginBindings(this));
+
+ std::string src;
+ if (ParseSrcAttribute(params, &src))
+ SetSrcAttribute(src);
+}
+
+BrowserPlugin::~BrowserPlugin() {
+ if (damage_buffer_) {
+ RenderProcess::current()->FreeTransportDIB(damage_buffer_);
+ damage_buffer_ = NULL;
+ }
+ RemoveEventListeners();
+ BrowserPluginManager::Get()->RemoveBrowserPlugin(instance_id_);
+ BrowserPluginManager::Get()->Send(
+ new BrowserPluginHostMsg_PluginDestroyed(
+ render_view_->GetRoutingID(),
+ instance_id_));
+}
+
+void BrowserPlugin::Cleanup() {
+ if (damage_buffer_) {
+ RenderProcess::current()->FreeTransportDIB(damage_buffer_);
+ damage_buffer_ = NULL;
+ }
+}
+
+std::string BrowserPlugin::GetSrcAttribute() const {
+ return src_;
+}
+
+void BrowserPlugin::SetSrcAttribute(const std::string& src) {
+ if (src == src_ && !guest_crashed_)
+ return;
+ if (!src.empty()) {
+ BrowserPluginManager::Get()->Send(
+ new BrowserPluginHostMsg_NavigateOrCreateGuest(
+ render_view_->GetRoutingID(),
+ instance_id_,
+ parent_frame_,
+ src));
+ }
+ src_ = src;
+ guest_crashed_ = false;
+}
+
+bool BrowserPlugin::ParseSrcAttribute(
+ const WebKit::WebPluginParams& params,
+ std::string* src) {
+ // Get the src attribute from the attributes vector
+ for (unsigned i = 0; i < params.attributeNames.size(); ++i) {
+ std::string attributeName = params.attributeNames[i].utf8();
+ if (LowerCaseEqualsASCII(attributeName, kSrcAttribute)) {
+ *src = params.attributeValues[i].utf8();
+ return true;
+ }
+ }
+ return false;
+}
+
+float BrowserPlugin::GetDeviceScaleFactor() const {
+ if (!render_view_)
+ return 1.0f;
+ return render_view_->GetWebView()->deviceScaleFactor();
+}
+
+void BrowserPlugin::RemoveEventListeners() {
+ EventListenerMap::iterator event_listener_map_iter =
+ event_listener_map_.begin();
+ for (; event_listener_map_iter != event_listener_map_.end();
+ ++event_listener_map_iter) {
+ EventListeners& listeners =
+ event_listener_map_[event_listener_map_iter->first];
+ EventListeners::iterator it = listeners.begin();
+ for (; it != listeners.end(); ++it) {
+ it->Dispose();
+ }
+ }
+ event_listener_map_.clear();
+}
+
+void BrowserPlugin::UpdateRect(
+ int message_id,
+ const BrowserPluginMsg_UpdateRect_Params& params) {
+ if (width() != params.view_size.width() ||
+ height() != params.view_size.height()) {
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UpdateRect_ACK(
+ render_view_->GetRoutingID(),
+ instance_id_,
+ message_id,
+ gfx::Size(width(), height())));
+ return;
+ }
+
+ float backing_store_scale_factor =
+ backing_store_.get() ? backing_store_->GetScaleFactor() : 1.0f;
+
+ if (params.is_resize_ack ||
+ backing_store_scale_factor != params.scale_factor) {
+ resize_pending_ = !params.is_resize_ack;
+ backing_store_.reset(
+ new BrowserPluginBackingStore(gfx::Size(width(), height()),
+ params.scale_factor));
+ }
+
+ // Update the backing store.
+ if (!params.scroll_rect.IsEmpty()) {
+ backing_store_->ScrollBackingStore(params.dx,
+ params.dy,
+ params.scroll_rect,
+ params.view_size);
+ }
+ for (unsigned i = 0; i < params.copy_rects.size(); i++) {
+ backing_store_->PaintToBackingStore(params.bitmap_rect,
+ params.copy_rects,
+ damage_buffer_);
+ }
+ // Invalidate the container.
+ container_->invalidate();
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UpdateRect_ACK(
+ render_view_->GetRoutingID(),
+ instance_id_,
+ message_id,
+ gfx::Size()));
+}
+
+void BrowserPlugin::GuestCrashed() {
+ guest_crashed_ = true;
+ container_->invalidate();
+}
+
+void BrowserPlugin::DidNavigate(const GURL& url) {
+ src_ = url.spec();
+ if (!HasListeners(kNavigationEventName))
+ return;
+
+ EventListeners& listeners = event_listener_map_[kNavigationEventName];
+ EventListeners::iterator it = listeners.begin();
+ for (; it != listeners.end(); ++it) {
+ v8::Context::Scope context_scope(v8::Context::New());
+ v8::HandleScope handle_scope;
+ v8::Local<v8::Value> param =
+ v8::Local<v8::Value>::New(v8::String::New(src_.c_str()));
+ container()->element().document().frame()->
+ callFunctionEvenIfScriptDisabled(*it,
+ v8::Object::New(),
+ 1,
+ &param);
+ }
+}
+
+void BrowserPlugin::AdvanceFocus(bool reverse) {
+ // We do not have a RenderView when we are testing.
+ if (render_view_)
+ render_view_->GetWebView()->advanceFocus(reverse);
+}
+
+bool BrowserPlugin::HasListeners(const std::string& event_name) {
+ return event_listener_map_.find(event_name) != event_listener_map_.end();
+}
+
+bool BrowserPlugin::AddEventListener(const std::string& event_name,
+ v8::Local<v8::Function> function) {
+ EventListeners& listeners = event_listener_map_[event_name];
+ for (unsigned int i = 0; i < listeners.size(); ++i) {
+ if (listeners[i] == function)
+ return false;
+ }
+ v8::Persistent<v8::Function> persistent_function =
+ v8::Persistent<v8::Function>::New(function);
+ listeners.push_back(persistent_function);
+ return true;
+}
+
+bool BrowserPlugin::RemoveEventListener(const std::string& event_name,
+ v8::Local<v8::Function> function) {
+ if (event_listener_map_.find(event_name) == event_listener_map_.end())
+ return false;
+
+ EventListeners& listeners = event_listener_map_[event_name];
+ EventListeners::iterator it = listeners.begin();
+ for (; it != listeners.end(); ++it) {
+ if (*it == function) {
+ it->Dispose();
+ listeners.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
+WebKit::WebPluginContainer* BrowserPlugin::container() const {
+ return container_;
+}
+
+bool BrowserPlugin::initialize(WebPluginContainer* container) {
+ container_ = container;
+ return true;
+}
+
+void BrowserPlugin::destroy() {
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+NPObject* BrowserPlugin::scriptableObject() {
+ NPObject* browser_plugin_np_object(bindings_->np_object());
+ // The object is expected to be retained before it is returned.
+ WebKit::WebBindings::retainObject(browser_plugin_np_object);
+ return browser_plugin_np_object;
+}
+
+void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
+ if (guest_crashed_) {
+ if (!sad_guest_) // Lazily initialize bitmap.
+ sad_guest_ = content::GetContentClient()->renderer()->
+ GetSadPluginBitmap();
+ // TODO(fsamuel): Do we want to paint something other than a sad plugin
+ // on crash? See http://www.crbug.com/140266.
+ webkit::PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
+ return;
+ }
+ SkAutoCanvasRestore auto_restore(canvas, true);
+ canvas->translate(plugin_rect_.x(), plugin_rect_.y());
+ SkRect image_data_rect = SkRect::MakeXYWH(
+ SkIntToScalar(0),
+ SkIntToScalar(0),
+ SkIntToScalar(plugin_rect_.width()),
+ SkIntToScalar(plugin_rect_.height()));
+ canvas->clipRect(image_data_rect);
+ // Paint white in case we have nothing in our backing store or we need to
+ // show a gutter.
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawRect(image_data_rect, paint);
+ // Stay at white if we have no src set, or we don't yet have a backing store.
+ if (!backing_store_.get() || src_.empty())
+ return;
+ float inverse_scale_factor = 1.0f / backing_store_->GetScaleFactor();
+ canvas->scale(inverse_scale_factor, inverse_scale_factor);
+ canvas->drawBitmap(backing_store_->GetBitmap(), 0, 0);
+}
+
+void BrowserPlugin::updateGeometry(
+ const WebRect& window_rect,
+ const WebRect& clip_rect,
+ const WebVector<WebRect>& cut_outs_rects,
+ bool is_visible) {
+ int old_width = width();
+ int old_height = height();
+ plugin_rect_ = window_rect;
+ if (old_width == window_rect.width &&
+ old_height == window_rect.height)
+ return;
+
+ const size_t stride = skia::PlatformCanvas::StrideForWidth(window_rect.width);
+ const size_t size = window_rect.height *
+ stride *
+ GetDeviceScaleFactor() *
+ GetDeviceScaleFactor();
+
+ // Don't drop the old damage buffer until after we've made sure that the
+ // browser process has dropped it.
+ TransportDIB* new_damage_buffer =
+ RenderProcess::current()->CreateTransportDIB(size);
+ DCHECK(new_damage_buffer);
+
+ BrowserPluginHostMsg_ResizeGuest_Params params;
+ params.damage_buffer_id = new_damage_buffer->id();
+ params.width = window_rect.width;
+ params.height = window_rect.height;
+ params.resize_pending = resize_pending_;
+ params.scale_factor = GetDeviceScaleFactor();
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ResizeGuest(
+ render_view_->GetRoutingID(),
+ instance_id_,
+ params));
+ resize_pending_ = true;
+
+ if (damage_buffer_) {
+ RenderProcess::current()->FreeTransportDIB(damage_buffer_);
+ damage_buffer_ = NULL;
+ }
+ damage_buffer_ = new_damage_buffer;
+}
+
+void BrowserPlugin::updateFocus(bool focused) {
+ BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_SetFocus(
+ render_view_->GetRoutingID(),
+ instance_id_,
+ focused));
+}
+
+void BrowserPlugin::updateVisibility(bool visible) {
+}
+
+bool BrowserPlugin::acceptsInputEvents() {
+ return true;
+}
+
+bool BrowserPlugin::handleInputEvent(const WebKit::WebInputEvent& event,
+ WebKit::WebCursorInfo& cursor_info) {
+ if (guest_crashed_ || src_.empty())
+ return false;
+ bool handled = false;
+ WebCursor cursor;
+ IPC::Message* message =
+ new BrowserPluginHostMsg_HandleInputEvent(
+ render_view_->GetRoutingID(),
+ &handled,
+ &cursor);
+ message->WriteInt(instance_id_);
+ message->WriteData(reinterpret_cast<const char*>(&plugin_rect_),
+ sizeof(gfx::Rect));
+ message->WriteData(reinterpret_cast<const char*>(&event), event.size);
+ BrowserPluginManager::Get()->Send(message);
+ cursor.GetCursorInfo(&cursor_info);
+ return handled;
+}
+
+void BrowserPlugin::didReceiveResponse(
+ const WebKit::WebURLResponse& response) {
+}
+
+void BrowserPlugin::didReceiveData(const char* data, int data_length) {
+}
+
+void BrowserPlugin::didFinishLoading() {
+}
+
+void BrowserPlugin::didFailLoading(const WebKit::WebURLError& error) {
+}
+
+void BrowserPlugin::didFinishLoadingFrameRequest(const WebKit::WebURL& url,
+ void* notify_data) {
+}
+
+void BrowserPlugin::didFailLoadingFrameRequest(
+ const WebKit::WebURL& url,
+ void* notify_data,
+ const WebKit::WebURLError& error) {
+}
+
+} // namespace content
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
new file mode 100644
index 0000000..c7f095a
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -0,0 +1,148 @@
+// 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_
+
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebPlugin.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "content/renderer/browser_plugin/browser_plugin_backing_store.h"
+#include "content/renderer/browser_plugin/browser_plugin_bindings.h"
+#include "content/renderer/render_view_impl.h"
+
+struct BrowserPluginMsg_UpdateRect_Params;
+
+namespace content {
+
+class BrowserPluginManager;
+class MockBrowserPlugin;
+
+class CONTENT_EXPORT BrowserPlugin :
+ NON_EXPORTED_BASE(public WebKit::WebPlugin) {
+ public:
+ // Called only by tests to clean up before we blow away the MockRenderProcess.
+ void Cleanup();
+
+ // Get the src attribute value of the BrowserPlugin instance if the guest
+ // has not crashed.
+ std::string GetSrcAttribute() const;
+ // Set the src attribute value of the BrowserPlugin instance and reset
+ // the guest_crashed_ flag.
+ void SetSrcAttribute(const std::string& src);
+
+ // Inform the BrowserPlugin to update its backing store with the pixels in
+ // its damage buffer.
+ void UpdateRect(int message_id,
+ const BrowserPluginMsg_UpdateRect_Params& params);
+ // Inform the BrowserPlugin that its guest has crashed.
+ void GuestCrashed();
+ // Informs the BrowserPlugin that the guest has navigated to a new URL.
+ void DidNavigate(const GURL& url);
+ // Tells the BrowserPlugin to advance the focus to the next (or previous)
+ // element.
+ void AdvanceFocus(bool reverse);
+
+ // Indicates whether there are any Javascript listeners attached to a
+ // provided event_name.
+ bool HasListeners(const std::string& event_name);
+ // Add a custom event listener to this BrowserPlugin instance.
+ bool AddEventListener(const std::string& event_name,
+ v8::Local<v8::Function> function);
+ // Remove a custom event listener from this BrowserPlugin instance.
+ bool RemoveEventListener(const std::string& event_name,
+ v8::Local<v8::Function> function);
+
+ // WebKit::WebPlugin implementation.
+ virtual WebKit::WebPluginContainer* container() const OVERRIDE;
+ virtual bool initialize(WebKit::WebPluginContainer* container) OVERRIDE;
+ virtual void destroy() OVERRIDE;
+ virtual NPObject* scriptableObject() OVERRIDE;
+ virtual void paint(
+ WebKit::WebCanvas* canvas,
+ const WebKit::WebRect& rect) OVERRIDE;
+ virtual void updateGeometry(
+ const WebKit::WebRect& frame_rect,
+ const WebKit::WebRect& clip_rect,
+ const WebKit::WebVector<WebKit::WebRect>& cut_outs_rects,
+ bool is_visible) OVERRIDE;
+ virtual void updateFocus(bool focused) OVERRIDE;
+ virtual void updateVisibility(bool visible) OVERRIDE;
+ virtual bool acceptsInputEvents() OVERRIDE;
+ virtual bool handleInputEvent(
+ const WebKit::WebInputEvent& event,
+ WebKit::WebCursorInfo& cursor_info) OVERRIDE;
+ virtual void didReceiveResponse(
+ const WebKit::WebURLResponse& response) OVERRIDE;
+ virtual void didReceiveData(const char* data, int data_length) OVERRIDE;
+ virtual void didFinishLoading() OVERRIDE;
+ virtual void didFailLoading(const WebKit::WebURLError& error) OVERRIDE;
+ virtual void didFinishLoadingFrameRequest(
+ const WebKit::WebURL& url,
+ void* notify_data) OVERRIDE;
+ virtual void didFailLoadingFrameRequest(
+ const WebKit::WebURL& url,
+ void* notify_data,
+ const WebKit::WebURLError& error) OVERRIDE;
+ protected:
+ friend class base::DeleteHelper<BrowserPlugin>;
+ // Only the manager is allowed to create a BrowserPlugin.
+ friend class BrowserPluginManagerImpl;
+ friend class MockBrowserPluginManager;
+
+ // For unit/integration tests.
+ friend class MockBrowserPlugin;
+
+ // A BrowserPlugin object is a controller that represents an instance of a
+ // browser plugin within the embedder renderer process. Each BrowserPlugin
+ // within a process has a unique instance_id that is used to route messages
+ // to it. It takes in a RenderViewImpl that it's associated with along
+ // with the frame within which it lives and the initial attributes assigned
+ // to it on creation.
+ BrowserPlugin(
+ int instance_id,
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params);
+
+ virtual ~BrowserPlugin();
+
+ int width() const { return plugin_rect_.width(); }
+ int height() const { return plugin_rect_.height(); }
+
+ // Virtual to allow for mocking in tests.
+ virtual float GetDeviceScaleFactor() const;
+
+ // Parses the source URL of the browser plugin from the element's attributes
+ // and outputs them.
+ bool ParseSrcAttribute(const WebKit::WebPluginParams& params,
+ std::string* src);
+
+ // Cleanup event listener state to free v8 resources when a BrowserPlugin
+ // is destroyed.
+ void RemoveEventListeners();
+
+ int instance_id_;
+ RenderViewImpl* render_view_;
+ WebKit::WebPluginContainer* container_;
+ scoped_ptr<BrowserPluginBindings> bindings_;
+ scoped_ptr<BrowserPluginBackingStore> backing_store_;
+ TransportDIB* damage_buffer_;
+ gfx::Rect plugin_rect_;
+ // Bitmap for crashed plugin. Lazily initialized, non-owning pointer.
+ SkBitmap* sad_guest_;
+ bool guest_crashed_;
+ bool resize_pending_;
+ long long parent_frame_;
+ std::string src_;
+ typedef std::vector<v8::Persistent<v8::Function> > EventListeners;
+ typedef std::map<std::string, EventListeners> EventListenerMap;
+ EventListenerMap event_listener_map_;
+ DISALLOW_COPY_AND_ASSIGN(BrowserPlugin);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_H_
diff --git a/content/renderer/browser_plugin/browser_plugin_backing_store.cc b/content/renderer/browser_plugin/browser_plugin_backing_store.cc
new file mode 100644
index 0000000..5b4d104
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin_backing_store.cc
@@ -0,0 +1,90 @@
+// 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_backing_store.h"
+
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/rect.h"
+#include "ui/surface/transport_dib.h"
+
+namespace content {
+
+// Max height and width for layers
+static const int kMaxSize = 23170;
+
+BrowserPluginBackingStore::BrowserPluginBackingStore(
+ const gfx::Size& size,
+ float scale_factor)
+ : size_(size),
+ scale_factor_(scale_factor) {
+ gfx::Size pixel_size = size.Scale(scale_factor);
+ bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
+ pixel_size.width(), pixel_size.height());
+ bitmap_.allocPixels();
+ canvas_.reset(new SkCanvas(bitmap_));
+}
+
+BrowserPluginBackingStore::~BrowserPluginBackingStore() {
+}
+
+void BrowserPluginBackingStore::PaintToBackingStore(
+ const gfx::Rect& bitmap_rect,
+ const std::vector<gfx::Rect>& copy_rects,
+ TransportDIB* dib) {
+ if (bitmap_rect.IsEmpty())
+ return;
+
+ gfx::Rect pixel_bitmap_rect = bitmap_rect.Scale(scale_factor_);
+
+ const int width = pixel_bitmap_rect.width();
+ const int height = pixel_bitmap_rect.height();
+
+ if (width <= 0 || width > kMaxSize ||
+ height <= 0 || height > kMaxSize)
+ return;
+
+ if (!dib)
+ return;
+
+ SkPaint copy_paint;
+ copy_paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+
+ SkBitmap sk_bitmap;
+ sk_bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ sk_bitmap.setPixels(dib->memory());
+ for (size_t i = 0; i < copy_rects.size(); i++) {
+ const gfx::Rect& pixel_copy_rect = copy_rects[i].Scale(scale_factor_);
+ int x = pixel_copy_rect.x() - pixel_bitmap_rect.x();
+ int y = pixel_copy_rect.y() - pixel_bitmap_rect.y();
+ SkIRect srcrect = SkIRect::MakeXYWH(x, y,
+ pixel_copy_rect.width(),
+ pixel_copy_rect.height());
+
+ SkRect dstrect = SkRect::MakeXYWH(
+ SkIntToScalar(pixel_copy_rect.x()),
+ SkIntToScalar(pixel_copy_rect.y()),
+ SkIntToScalar(pixel_copy_rect.width()),
+ SkIntToScalar(pixel_copy_rect.height()));
+ canvas_.get()->drawBitmapRect(sk_bitmap, &srcrect, dstrect, &copy_paint);
+ }
+}
+
+void BrowserPluginBackingStore::ScrollBackingStore(
+ int dx,
+ int dy,
+ const gfx::Rect& clip_rect,
+ const gfx::Size& view_size) {
+ gfx::Rect pixel_rect = clip_rect.Scale(scale_factor_);
+ int pixel_dx = dx * scale_factor_;
+ int pixel_dy = dy * scale_factor_;
+
+ int x = std::min(pixel_rect.x(), pixel_rect.x() - pixel_dx);
+ int y = std::min(pixel_rect.y(), pixel_rect.y() - pixel_dy);
+ int w = pixel_rect.width() + abs(pixel_dx);
+ int h = pixel_rect.height() + abs(pixel_dy);
+ SkIRect rect = SkIRect::MakeXYWH(x, y, w, h);
+ bitmap_.scrollRect(&rect, pixel_dx, pixel_dy);
+}
+
+} // namespace content
diff --git a/content/renderer/browser_plugin/browser_plugin_backing_store.h b/content/renderer/browser_plugin/browser_plugin_backing_store.h
new file mode 100644
index 0000000..f3e378a
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin_backing_store.h
@@ -0,0 +1,64 @@
+// 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_BACKING_STORE_H__
+#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_BACKING_STORE_H__
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/size.h"
+
+class SkCanvas;
+class TransportDIB;
+
+namespace gfx {
+class Canvas;
+class Point;
+class Rect;
+}
+
+namespace content {
+
+// The BrowserPluginBackingStore is a wrapper around an SkBitmap that is used
+// in the software rendering path of the browser plugin. The backing store has
+// two write operations:
+// 1. PaintToBackingStore copies pixel regions to the bitmap.
+// 2. ScrollBackingStore scrolls a region of the bitmap by dx, and dy.
+// These are called in response to changes in the guest relayed via
+// BrowserPluginMsg_UpdateRect. See BrowserPlugin::UpdateRect.
+class BrowserPluginBackingStore {
+ public:
+ BrowserPluginBackingStore(const gfx::Size& size, float scale_factor);
+ virtual ~BrowserPluginBackingStore();
+
+ void PaintToBackingStore(
+ const gfx::Rect& bitmap_rect,
+ const std::vector<gfx::Rect>& copy_rects,
+ TransportDIB* dib);
+
+ void ScrollBackingStore(int dx,
+ int dy,
+ const gfx::Rect& clip_rect,
+ const gfx::Size& view_size);
+
+ const gfx::Size& GetSize() const { return size_; }
+
+ const SkBitmap& GetBitmap() const { return bitmap_; }
+
+ float GetScaleFactor() const { return scale_factor_; }
+
+ private:
+ gfx::Size size_;
+ SkBitmap bitmap_;
+ scoped_ptr<SkCanvas> canvas_;
+ float scale_factor_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginBackingStore);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_BACKING_STORE_H__
diff --git a/content/renderer/browser_plugin/browser_plugin_bindings.cc b/content/renderer/browser_plugin/browser_plugin_bindings.cc
new file mode 100644
index 0000000..d8c75ad
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin_bindings.cc
@@ -0,0 +1,253 @@
+// 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_bindings.h"
+
+#include <cstdlib>
+#include <string>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/string16.h"
+#include "base/string_split.h"
+#include "base/utf_string_conversions.h"
+#include "content/renderer/browser_plugin/browser_plugin.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDOMMessageEvent.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSerializedScriptValue.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
+#include "v8/include/v8.h"
+
+using WebKit::WebBindings;
+using WebKit::WebElement;
+using WebKit::WebDOMEvent;
+using WebKit::WebDOMMessageEvent;
+using WebKit::WebPluginContainer;
+using WebKit::WebSerializedScriptValue;
+using WebKit::WebString;
+
+namespace content {
+
+namespace {
+
+const char kAddEventListener[] = "addEventListener";
+const char kRemoveEventListener[] = "removeEventListener";
+const char kSrcAttribute[] = "src";
+
+BrowserPluginBindings* GetBindings(NPObject* object) {
+ return static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(object)->
+ message_channel;
+}
+
+bool IdentifierIsAddEventListener(NPIdentifier identifier) {
+ return WebBindings::getStringIdentifier(kAddEventListener) == identifier;
+}
+
+bool IdentifierIsRemoveEventListener(NPIdentifier identifier) {
+ return WebBindings::getStringIdentifier(kRemoveEventListener) == identifier;
+}
+
+bool IdentifierIsSrcAttribute(NPIdentifier identifier) {
+ return WebBindings::getStringIdentifier(kSrcAttribute) == identifier;
+}
+
+std::string StringFromNPVariant(const NPVariant& variant) {
+ if (!NPVARIANT_IS_STRING(variant))
+ return std::string();
+ const NPString& np_string = NPVARIANT_TO_STRING(variant);
+ return std::string(np_string.UTF8Characters, np_string.UTF8Length);
+}
+
+string16 String16FromNPVariant(const NPVariant& variant) {
+ if (!NPVARIANT_IS_STRING(variant))
+ return string16();
+ const NPString& np_string = NPVARIANT_TO_STRING(variant);
+ string16 wstr;
+ if (!UTF8ToUTF16(np_string.UTF8Characters, np_string.UTF8Length, &wstr))
+ return string16();
+ return wstr;
+}
+
+bool StringToNPVariant(const std::string &in, NPVariant *variant) {
+ size_t length = in.size();
+ NPUTF8 *chars = static_cast<NPUTF8 *>(malloc(length));
+ if (!chars) {
+ VOID_TO_NPVARIANT(*variant);
+ return false;
+ }
+ memcpy(chars, in.c_str(), length);
+ STRINGN_TO_NPVARIANT(chars, length, *variant);
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// Implementations of NPClass functions. These are here to:
+// - Implement src attribute.
+//------------------------------------------------------------------------------
+NPObject* BrowserPluginBindingsAllocate(NPP npp, NPClass* the_class) {
+ return new BrowserPluginBindings::BrowserPluginNPObject;
+}
+
+void BrowserPluginBindingsDeallocate(NPObject* object) {
+ BrowserPluginBindings::BrowserPluginNPObject* instance =
+ static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(object);
+ delete instance;
+}
+
+bool BrowserPluginBindingsHasMethod(NPObject* np_obj, NPIdentifier name) {
+ if (!np_obj)
+ return false;
+
+ if (IdentifierIsAddEventListener(name))
+ return true;
+
+ if (IdentifierIsRemoveEventListener(name))
+ return true;
+
+ return false;
+}
+
+bool BrowserPluginBindingsInvoke(NPObject* np_obj, NPIdentifier name,
+ const NPVariant* args, uint32 arg_count,
+ NPVariant* result) {
+ if (!np_obj)
+ return false;
+
+ BrowserPluginBindings* bindings = GetBindings(np_obj);
+ if (!bindings)
+ return false;
+
+ if (IdentifierIsAddEventListener(name) && (arg_count == 2)) {
+ std::string event_name = StringFromNPVariant(args[0]);
+ if (event_name.empty())
+ return false;
+
+ v8::Local<v8::Value> value =
+ v8::Local<v8::Value>::New(WebBindings::toV8Value(&args[1]));
+ if (value.IsEmpty() || !value->IsFunction())
+ return false;
+
+ v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value);
+ return bindings->instance()->AddEventListener(event_name, function);
+ }
+
+ if (IdentifierIsRemoveEventListener(name) && arg_count == 2) {
+ std::string event_name = StringFromNPVariant(args[0]);
+ if (event_name.empty())
+ return false;
+
+ v8::Local<v8::Value> value =
+ v8::Local<v8::Value>::New(WebBindings::toV8Value(&args[1]));
+
+ if (value.IsEmpty() || !value->IsFunction())
+ return false;
+
+ v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value);
+ return bindings->instance()->RemoveEventListener(event_name, function);
+ }
+
+ return false;
+}
+
+bool BrowserPluginBindingsInvokeDefault(NPObject* np_obj,
+ const NPVariant* args,
+ uint32 arg_count,
+ NPVariant* result) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BrowserPluginBindingsHasProperty(NPObject* np_obj, NPIdentifier name) {
+ return IdentifierIsSrcAttribute(name);
+}
+
+bool BrowserPluginBindingsGetProperty(NPObject* np_obj, NPIdentifier name,
+ NPVariant* result) {
+ if (!np_obj)
+ return false;
+
+ if (IdentifierIsAddEventListener(name) ||
+ IdentifierIsRemoveEventListener(name))
+ return false;
+
+ if (IdentifierIsSrcAttribute(name)) {
+ BrowserPluginBindings* bindings = GetBindings(np_obj);
+ if (!bindings)
+ return false;
+ std::string src = bindings->instance()->GetSrcAttribute();
+ return StringToNPVariant(src, result);
+ }
+
+ return false;
+}
+
+bool BrowserPluginBindingsSetProperty(NPObject* np_obj, NPIdentifier name,
+ const NPVariant* variant) {
+ if (!np_obj)
+ return false;
+
+ if (IdentifierIsSrcAttribute(name)) {
+ std::string src = StringFromNPVariant(*variant);
+ BrowserPluginBindings* bindings = GetBindings(np_obj);
+ if (!bindings)
+ return false;
+ bindings->instance()->SetSrcAttribute(src);
+ return true;
+ }
+ return false;
+}
+
+bool BrowserPluginBindingsEnumerate(NPObject *np_obj, NPIdentifier **value,
+ uint32_t *count) {
+ NOTIMPLEMENTED();
+ return true;
+}
+
+NPClass browser_plugin_message_class = {
+ NP_CLASS_STRUCT_VERSION,
+ &BrowserPluginBindingsAllocate,
+ &BrowserPluginBindingsDeallocate,
+ NULL,
+ &BrowserPluginBindingsHasMethod,
+ &BrowserPluginBindingsInvoke,
+ &BrowserPluginBindingsInvokeDefault,
+ &BrowserPluginBindingsHasProperty,
+ &BrowserPluginBindingsGetProperty,
+ &BrowserPluginBindingsSetProperty,
+ NULL,
+ &BrowserPluginBindingsEnumerate,
+};
+
+} // namespace
+
+// BrowserPluginBindings ------------------------------------------------------
+
+BrowserPluginBindings::BrowserPluginNPObject::BrowserPluginNPObject() {
+}
+
+BrowserPluginBindings::BrowserPluginNPObject::~BrowserPluginNPObject() {
+}
+
+BrowserPluginBindings::BrowserPluginBindings(BrowserPlugin* instance)
+ : instance_(instance),
+ np_object_(NULL),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
+ NPObject* obj =
+ WebBindings::createObject(NULL, &browser_plugin_message_class);
+ np_object_ = static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(obj);
+ np_object_->message_channel = weak_ptr_factory_.GetWeakPtr();
+}
+
+BrowserPluginBindings::~BrowserPluginBindings() {
+ WebBindings::releaseObject(np_object_);
+}
+
+} // namespace content
diff --git a/content/renderer/browser_plugin/browser_plugin_bindings.h b/content/renderer/browser_plugin/browser_plugin_bindings.h
new file mode 100644
index 0000000..2d9fa2d
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin_bindings.h
@@ -0,0 +1,53 @@
+// 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_BINDINGS_H__
+#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_BINDINGS_H__
+
+#include "base/memory/weak_ptr.h"
+#include "ppapi/shared_impl/resource.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+namespace WebKit {
+class WebSerializedScriptValue;
+}
+
+namespace content {
+
+class BrowserPlugin;
+
+class BrowserPluginBindings {
+ public:
+ // BrowserPluginNPObject is a simple struct that adds a pointer back to a
+ // BrowserPluginBindings instance. This way, we can use an NPObject to allow
+ // JavaScript interactions without forcing BrowserPluginBindings to inherit
+ // from NPObject.
+ struct BrowserPluginNPObject : public NPObject {
+ BrowserPluginNPObject();
+ ~BrowserPluginNPObject();
+
+ base::WeakPtr<BrowserPluginBindings> message_channel;
+ };
+
+ explicit BrowserPluginBindings(BrowserPlugin* instance);
+ ~BrowserPluginBindings();
+
+ NPObject* np_object() const { return np_object_; }
+
+ BrowserPlugin* instance() const { return instance_; }
+ private:
+ BrowserPlugin* instance_;
+ // The NPObject we use to expose postMessage to JavaScript.
+ BrowserPluginNPObject* np_object_;
+
+ // This is used to ensure pending tasks will not fire after this object is
+ // destroyed.
+ base::WeakPtrFactory<BrowserPluginBindings> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindings);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_BINDINGS_H__
diff --git a/content/renderer/browser_plugin/browser_plugin_browsertest.cc b/content/renderer/browser_plugin/browser_plugin_browsertest.cc
new file mode 100644
index 0000000..5815eea
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin_browsertest.cc
@@ -0,0 +1,307 @@
+// 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_browsertest.h"
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "content/common/browser_plugin_messages.h"
+#include "content/public/common/content_constants.h"
+#include "content/renderer/browser_plugin/browser_plugin.h"
+#include "content/renderer/browser_plugin/mock_browser_plugin.h"
+#include "content/renderer/browser_plugin/mock_browser_plugin_manager.h"
+#include "content/renderer/render_thread_impl.h"
+#include "content/renderer/renderer_webkitplatformsupport_impl.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h"
+
+namespace {
+const char kHTMLForBrowserPluginObject[] =
+ "<object id='browserplugin' width='640px' height='480px'"
+ " src='foo' type='%s'>";
+
+std::string GetHTMLForBrowserPluginObject() {
+ return StringPrintf(kHTMLForBrowserPluginObject,
+ content::kBrowserPluginNewMimeType);
+}
+
+}
+
+namespace content {
+
+BrowserPluginTest::BrowserPluginTest() {}
+
+BrowserPluginTest::~BrowserPluginTest() {}
+
+void BrowserPluginTest::SetUp() {
+ GetContentClient()->set_renderer_for_testing(&content_renderer_client_);
+ content::RenderViewTest::SetUp();
+ browser_plugin_manager_.reset(new MockBrowserPluginManager());
+}
+
+void BrowserPluginTest::TearDown() {
+ browser_plugin_manager_->Cleanup();
+ content::RenderViewTest::TearDown();
+}
+
+std::string BrowserPluginTest::ExecuteScriptAndReturnString(
+ const std::string& script) {
+ v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
+ WebKit::WebScriptSource(WebKit::WebString::fromUTF8(script.c_str())));
+ if (value.IsEmpty() || !value->IsString())
+ return std::string();
+
+ v8::Local<v8::String> v8_str = value->ToString();
+ int length = v8_str->Utf8Length() + 1;
+ scoped_array<char> str(new char[length]);
+ v8_str->WriteUtf8(str.get(), length);
+ return str.get();
+}
+
+// This test verifies that an initial resize occurs when we instantiate the
+// browser plugin. This test also verifies that the browser plugin is waiting
+// for a BrowserPluginMsg_UpdateRect in response. We issue an UpdateRect, and
+// we observe an UpdateRect_ACK, with the resize_pending_ reset, indiciating
+// that the BrowserPlugin is not waiting for any more UpdateRects to
+// satisfy its resize request.
+TEST_F(BrowserPluginTest, InitialResize) {
+ LoadHTML(GetHTMLForBrowserPluginObject().c_str());
+ // Verify that the information based on ResizeGuest is correct, and
+ // use its TransportDIB::Id to paint.
+ const IPC::Message* msg =
+ browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_ResizeGuest::ID);
+ ASSERT_TRUE(msg);
+ PickleIterator iter = IPC::SyncMessage::GetDataIterator(msg);
+ BrowserPluginHostMsg_ResizeGuest::SendParam resize_params;
+ ASSERT_TRUE(IPC::ReadParam(msg, &iter, &resize_params));
+ int instance_id = resize_params.a;
+ BrowserPluginHostMsg_ResizeGuest_Params params(resize_params.b);
+ EXPECT_EQ(640, params.width);
+ EXPECT_EQ(480, params.height);
+ // Verify that the browser plugin wasn't already waiting on a resize when this
+ // resize happened.
+ EXPECT_EQ(false, params.resize_pending);
+
+ MockBrowserPlugin* browser_plugin =
+ static_cast<MockBrowserPlugin*>(
+ browser_plugin_manager()->GetBrowserPlugin(instance_id));
+ ASSERT_TRUE(browser_plugin);
+ // Now the browser plugin is expecting a UpdateRect resize.
+ EXPECT_TRUE(browser_plugin->resize_pending_);
+
+ // Send the BrowserPlugin an UpdateRect equal to its container size.
+ // That should clear the resize_pending_ flag.
+ BrowserPluginMsg_UpdateRect_Params update_rect_params;
+ update_rect_params.view_size = gfx::Size(640, 480);
+ update_rect_params.scale_factor = 1.0f;
+ update_rect_params.is_resize_ack = true;
+ browser_plugin->UpdateRect(0, update_rect_params);
+ EXPECT_FALSE(browser_plugin->resize_pending_);
+}
+
+// Verify that the src attribute on the browser plugin works as expected.
+TEST_F(BrowserPluginTest, SrcAttribute) {
+ LoadHTML(GetHTMLForBrowserPluginObject().c_str());
+ // Verify that we're reporting the correct URL to navigate to based on the
+ // src attribute.
+ {
+ const IPC::Message* msg =
+ browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_NavigateOrCreateGuest::ID);
+ ASSERT_TRUE(msg);
+
+ int instance_id;
+ long long frame_id;
+ std::string src;
+ BrowserPluginHostMsg_NavigateOrCreateGuest::Read(
+ msg,
+ &instance_id,
+ &frame_id,
+ &src);
+ EXPECT_EQ("foo", src);
+ }
+
+ browser_plugin_manager()->sink().ClearMessages();
+ // Navigate to bar and observe the associated
+ // BrowserPluginHostMsg_NavigateOrCreateGuest message.
+ // Verify that the src attribute is updated as well.
+ ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
+ {
+ const IPC::Message* msg =
+ browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_NavigateOrCreateGuest::ID);
+ ASSERT_TRUE(msg);
+
+ int instance_id;
+ long long frame_id;
+ std::string src;
+ BrowserPluginHostMsg_NavigateOrCreateGuest::Read(
+ msg,
+ &instance_id,
+ &frame_id,
+ &src);
+ EXPECT_EQ("bar", src);
+ std::string src_value =
+ ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').src");
+ EXPECT_EQ("bar", src_value);
+ }
+}
+
+TEST_F(BrowserPluginTest, ResizeFlowControl) {
+ LoadHTML(GetHTMLForBrowserPluginObject().c_str());
+ browser_plugin_manager()->sink().ClearMessages();
+
+ // Resize the browser plugin three times.
+ ExecuteJavaScript("document.getElementById('browserplugin').width = '641px'");
+ ProcessPendingMessages();
+ ExecuteJavaScript("document.getElementById('browserplugin').width = '642px'");
+ ProcessPendingMessages();
+ ExecuteJavaScript("document.getElementById('browserplugin').width = '643px'");
+ ProcessPendingMessages();
+
+ // Expect to see three messsages in the sink.
+ EXPECT_EQ(3u, browser_plugin_manager()->sink().message_count());
+ const IPC::Message* msg =
+ browser_plugin_manager()->sink().GetFirstMessageMatching(
+ BrowserPluginHostMsg_ResizeGuest::ID);
+ ASSERT_TRUE(msg);
+ PickleIterator iter = IPC::SyncMessage::GetDataIterator(msg);
+ BrowserPluginHostMsg_ResizeGuest::SendParam resize_params;
+ ASSERT_TRUE(IPC::ReadParam(msg, &iter, &resize_params));
+ int instance_id = resize_params.a;
+ BrowserPluginHostMsg_ResizeGuest_Params params(resize_params.b);
+ EXPECT_EQ(641, params.width);
+ EXPECT_EQ(480, params.height);
+ // This indicates that the BrowserPlugin has sent out a previous resize
+ // request but has not yet received an UpdateRect for that request.
+ // We send this resize regardless to update the damage buffer in the
+ // browser process, so it's ready when the guest sends the appropriate
+ // UpdateRect.
+ EXPECT_TRUE(params.resize_pending);
+
+ MockBrowserPlugin* browser_plugin =
+ static_cast<MockBrowserPlugin*>(
+ browser_plugin_manager()->GetBrowserPlugin(instance_id));
+ ASSERT_TRUE(browser_plugin);
+ {
+ // We send a stale UpdateRect to the BrowserPlugin.
+ BrowserPluginMsg_UpdateRect_Params update_rect_params;
+ update_rect_params.view_size = gfx::Size(640, 480);
+ update_rect_params.scale_factor = 1.0f;
+ update_rect_params.is_resize_ack = true;
+ browser_plugin->UpdateRect(0, update_rect_params);
+ // This tells us that the BrowserPlugin is still expecting another
+ // UpdateRect with the most recent size.
+ EXPECT_TRUE(browser_plugin->resize_pending_);
+ }
+ {
+ BrowserPluginMsg_UpdateRect_Params update_rect_params;
+ update_rect_params.view_size = gfx::Size(643, 480);
+ update_rect_params.scale_factor = 1.0f;
+ update_rect_params.is_resize_ack = true;
+ browser_plugin->UpdateRect(0, update_rect_params);
+ // The BrowserPlugin has finally received an UpdateRect that satisifes
+ // its current size, and so it is happy.
+ EXPECT_FALSE(browser_plugin->resize_pending_);
+ }
+}
+
+TEST_F(BrowserPluginTest, GuestCrash) {
+ LoadHTML(GetHTMLForBrowserPluginObject().c_str());
+
+ // Grab the BrowserPlugin's instance ID from its resize message.
+ const IPC::Message* msg =
+ browser_plugin_manager()->sink().GetFirstMessageMatching(
+ BrowserPluginHostMsg_ResizeGuest::ID);
+ ASSERT_TRUE(msg);
+ PickleIterator iter = IPC::SyncMessage::GetDataIterator(msg);
+ BrowserPluginHostMsg_ResizeGuest::SendParam resize_params;
+ ASSERT_TRUE(IPC::ReadParam(msg, &iter, &resize_params));
+ int instance_id = resize_params.a;
+
+ MockBrowserPlugin* browser_plugin =
+ static_cast<MockBrowserPlugin*>(
+ browser_plugin_manager()->GetBrowserPlugin(instance_id));
+ ASSERT_TRUE(browser_plugin);
+
+ WebKit::WebCursorInfo cursor_info;
+ // Send an event and verify that the event is deported.
+ browser_plugin->handleInputEvent(WebKit::WebMouseEvent(),
+ cursor_info);
+ EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_HandleInputEvent::ID));
+ browser_plugin_manager()->sink().ClearMessages();
+
+ // Pretend that the guest has crashed
+ browser_plugin->GuestCrashed();
+ // Send an event and verify that events are no longer deported.
+ browser_plugin->handleInputEvent(WebKit::WebMouseEvent(),
+ cursor_info);
+ EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_HandleInputEvent::ID));
+
+ // Navigate and verify that the guest_crashed_ flag has been reset.
+ browser_plugin->SetSrcAttribute("bar");
+ EXPECT_FALSE(browser_plugin->guest_crashed_);
+
+}
+
+TEST_F(BrowserPluginTest, RemovePlugin) {
+ LoadHTML(GetHTMLForBrowserPluginObject().c_str());
+ EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_PluginDestroyed::ID));
+ ExecuteJavaScript("x = document.getElementById('browserplugin'); "
+ "x.parentNode.removeChild(x);");
+ ProcessPendingMessages();
+ EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_PluginDestroyed::ID));
+}
+
+TEST_F(BrowserPluginTest, CustomEvents) {
+ const char* kAddEventListener =
+ "var url;"
+ "function nav(u) {"
+ " url = u;"
+ "}"
+ "document.getElementById('browserplugin')."
+ " addEventListener('navigation', nav);";
+ const char* kRemoveEventListener =
+ "document.getElementById('browserplugin')."
+ " removeEventListener('navigation', nav);";
+ const char* kGoogleURL = "http://www.google.com/";
+ const char* kGoogleNewsURL = "http://news.google.com/";
+
+ LoadHTML(GetHTMLForBrowserPluginObject().c_str());
+ ExecuteJavaScript(kAddEventListener);
+ // Grab the BrowserPlugin's instance ID from its resize message.
+ const IPC::Message* msg =
+ browser_plugin_manager()->sink().GetFirstMessageMatching(
+ BrowserPluginHostMsg_ResizeGuest::ID);
+ ASSERT_TRUE(msg);
+ PickleIterator iter = IPC::SyncMessage::GetDataIterator(msg);
+ BrowserPluginHostMsg_ResizeGuest::SendParam resize_params;
+ ASSERT_TRUE(IPC::ReadParam(msg, &iter, &resize_params));
+ int instance_id = resize_params.a;
+
+ MockBrowserPlugin* browser_plugin =
+ static_cast<MockBrowserPlugin*>(
+ browser_plugin_manager()->GetBrowserPlugin(instance_id));
+ ASSERT_TRUE(browser_plugin);
+
+ browser_plugin->DidNavigate(GURL(kGoogleURL));
+ EXPECT_EQ(kGoogleURL, ExecuteScriptAndReturnString("url"));
+
+ ExecuteJavaScript(kRemoveEventListener);
+ browser_plugin->DidNavigate(GURL(kGoogleNewsURL));
+ // The URL variable should not change because we've removed the event
+ // listener.
+ EXPECT_EQ(kGoogleURL, ExecuteScriptAndReturnString("url"));
+}
+
+} // namespace content
diff --git a/content/renderer/browser_plugin/browser_plugin_browsertest.h b/content/renderer/browser_plugin/browser_plugin_browsertest.h
new file mode 100644
index 0000000..c4db5f2
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin_browsertest.h
@@ -0,0 +1,42 @@
+// 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_BROWSERETEST_H_
+#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_BROWSERETEST_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "content/public/renderer/content_renderer_client.h"
+#include "content/public/test/render_view_test.h"
+#include "content/renderer/browser_plugin/mock_browser_plugin_manager.h"
+#include "content/renderer/render_view_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
+
+class RenderThreadImpl;
+
+namespace content {
+
+class BrowserPluginTest : public RenderViewTest {
+ public:
+ BrowserPluginTest();
+ virtual ~BrowserPluginTest();
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+ MockBrowserPluginManager* browser_plugin_manager() const {
+ return browser_plugin_manager_.get();
+ }
+ std::string ExecuteScriptAndReturnString(const std::string& script);
+ private:
+ scoped_ptr<MockBrowserPluginManager> browser_plugin_manager_;
+ ContentRendererClient content_renderer_client_;
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_BROWSERETEST_H_
+
diff --git a/content/renderer/browser_plugin/browser_plugin_manager.cc b/content/renderer/browser_plugin/browser_plugin_manager.cc
new file mode 100644
index 0000000..06fe358
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin_manager.cc
@@ -0,0 +1,47 @@
+// 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_manager.h"
+
+#include "base/lazy_instance.h"
+#include "base/threading/thread_local.h"
+#include "content/public/renderer/render_thread.h"
+#include "content/renderer/browser_plugin/browser_plugin.h"
+
+namespace content {
+
+static base::LazyInstance<base::ThreadLocalPointer<
+ BrowserPluginManager> > lazy_tls = LAZY_INSTANCE_INITIALIZER;
+
+BrowserPluginManager* BrowserPluginManager::Get() {
+ return lazy_tls.Pointer()->Get();
+}
+
+BrowserPluginManager::BrowserPluginManager() {
+ lazy_tls.Pointer()->Set(this);
+ RenderThread::Get()->AddObserver(this);
+}
+
+BrowserPluginManager::~BrowserPluginManager() {
+ lazy_tls.Pointer()->Set(NULL);
+}
+
+void BrowserPluginManager::AddBrowserPlugin(
+ int instance_id,
+ BrowserPlugin* browser_plugin) {
+ DCHECK(CalledOnValidThread());
+ instances_.AddWithID(browser_plugin, instance_id);
+}
+
+void BrowserPluginManager::RemoveBrowserPlugin(int instance_id) {
+ DCHECK(CalledOnValidThread());
+ instances_.Remove(instance_id);
+}
+
+BrowserPlugin* BrowserPluginManager::GetBrowserPlugin(int instance_id) const {
+ DCHECK(CalledOnValidThread());
+ return instances_.Lookup(instance_id);
+}
+
+} // namespace content
diff --git a/content/renderer/browser_plugin/browser_plugin_manager.h b/content/renderer/browser_plugin/browser_plugin_manager.h
new file mode 100644
index 0000000..4720bb1
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin_manager.h
@@ -0,0 +1,58 @@
+// 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_MANAGER_H_
+#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_H_
+
+#include "base/id_map.h"
+#include "base/threading/non_thread_safe.h"
+#include "content/public/renderer/render_process_observer.h"
+#include "ipc/ipc_sender.h"
+
+class RenderViewImpl;
+
+namespace WebKit {
+class WebFrame;
+struct WebPluginParams;
+}
+
+namespace content {
+
+class BrowserPlugin;
+
+// BrowserPluginManager manages the routing of messages to the appropriate
+// BrowserPlugin object based on its instance ID. There is only one
+// BrowserPluginManager per renderer process, and it should only be accessed
+// by the render thread.
+class CONTENT_EXPORT BrowserPluginManager : public IPC::Sender,
+ public RenderProcessObserver,
+ public base::NonThreadSafe {
+ public:
+ // Returns the one BrowserPluginManager for this process.
+ static BrowserPluginManager* Get();
+
+ BrowserPluginManager();
+ virtual ~BrowserPluginManager();
+
+ // Creates a new BrowserPlugin object with a unique identifier.
+ // BrowserPlugin is responsible for associating itself with the
+ // BrowserPluginManager via AddBrowserPlugin. When it is destroyed, it is
+ // responsible for removing its association via RemoveBrowserPlugin.
+ virtual BrowserPlugin* CreateBrowserPlugin(
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params) = 0;
+
+ void AddBrowserPlugin(int instance_id, BrowserPlugin* browser_plugin);
+ void RemoveBrowserPlugin(int instance_id);
+ BrowserPlugin* GetBrowserPlugin(int instance_id) const;
+
+ protected:
+ IDMap<BrowserPlugin> instances_;
+ int browser_plugin_counter_;
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_H_
diff --git a/content/renderer/browser_plugin/browser_plugin_manager_impl.cc b/content/renderer/browser_plugin/browser_plugin_manager_impl.cc
new file mode 100644
index 0000000..32d3573
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin_manager_impl.cc
@@ -0,0 +1,74 @@
+// 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_manager_impl.h"
+
+#include "content/common/browser_plugin_messages.h"
+#include "content/renderer/browser_plugin/browser_plugin.h"
+#include "content/renderer/render_thread_impl.h"
+
+namespace content {
+
+BrowserPluginManagerImpl::BrowserPluginManagerImpl() {
+}
+
+BrowserPluginManagerImpl::~BrowserPluginManagerImpl() {
+}
+
+BrowserPlugin* BrowserPluginManagerImpl::CreateBrowserPlugin(
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params) {
+ return new BrowserPlugin(browser_plugin_counter_++,
+ render_view,
+ frame,
+ params);
+}
+
+bool BrowserPluginManagerImpl::Send(IPC::Message* msg) {
+ return RenderThread::Get()->Send(msg);
+}
+
+bool BrowserPluginManagerImpl::OnControlMessageReceived(
+ const IPC::Message& message) {
+ DCHECK(CalledOnValidThread());
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(BrowserPluginManagerImpl, message)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_UpdateRect, OnUpdateRect)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestCrashed,OnGuestCrashed)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_DidNavigate, OnDidNavigate)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void BrowserPluginManagerImpl::OnUpdateRect(
+ int instance_id,
+ int message_id,
+ const BrowserPluginMsg_UpdateRect_Params& params) {
+ BrowserPlugin* plugin = GetBrowserPlugin(instance_id);
+ if (plugin)
+ plugin->UpdateRect(message_id, params);
+}
+
+void BrowserPluginManagerImpl::OnGuestCrashed(int instance_id) {
+ BrowserPlugin* plugin = GetBrowserPlugin(instance_id);
+ if (plugin)
+ plugin->GuestCrashed();
+}
+
+void BrowserPluginManagerImpl::OnDidNavigate(int instance_id, const GURL& url) {
+ BrowserPlugin* plugin = GetBrowserPlugin(instance_id);
+ if (plugin)
+ plugin->DidNavigate(url);
+}
+
+void BrowserPluginManagerImpl::OnAdvanceFocus(int instance_id, bool reverse) {
+ BrowserPlugin* plugin = GetBrowserPlugin(instance_id);
+ if (plugin)
+ plugin->AdvanceFocus(reverse);
+}
+
+} // namespace content
diff --git a/content/renderer/browser_plugin/browser_plugin_manager_impl.h b/content/renderer/browser_plugin/browser_plugin_manager_impl.h
new file mode 100644
index 0000000..7f3c8c9
--- /dev/null
+++ b/content/renderer/browser_plugin/browser_plugin_manager_impl.h
@@ -0,0 +1,44 @@
+// 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_MANAGER_IMPL_H_
+#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_IMPL_H_
+
+#include "content/renderer/browser_plugin/browser_plugin_manager.h"
+#include "googleurl/src/gurl.h"
+
+struct BrowserPluginMsg_UpdateRect_Params;
+
+namespace content {
+
+class BrowserPluginManagerImpl : public BrowserPluginManager {
+ public:
+ BrowserPluginManagerImpl();
+ virtual ~BrowserPluginManagerImpl();
+
+ // BrowserPluginManager implementation.
+ virtual BrowserPlugin* CreateBrowserPlugin(
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params) OVERRIDE;
+
+ // IPC::Sender implementation.
+ virtual bool Send(IPC::Message* msg) OVERRIDE;
+
+ // RenderProcessObserver override. Call on render thread.
+ virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
+ private:
+ void OnUpdateRect(int instance_id,
+ int message_id,
+ const BrowserPluginMsg_UpdateRect_Params& params);
+ void OnGuestCrashed(int instance_id);
+ void OnDidNavigate(int instance_id, const GURL& url);
+ void OnAdvanceFocus(int instance_id, bool reverse);
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginManagerImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_IMPL_H_
diff --git a/content/renderer/browser_plugin/mock_browser_plugin.cc b/content/renderer/browser_plugin/mock_browser_plugin.cc
new file mode 100644
index 0000000..82803aa
--- /dev/null
+++ b/content/renderer/browser_plugin/mock_browser_plugin.cc
@@ -0,0 +1,19 @@
+// 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/mock_browser_plugin.h"
+
+namespace content {
+
+MockBrowserPlugin::MockBrowserPlugin(
+ int id,
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params)
+ : BrowserPlugin(id, render_view, frame, params) {
+}
+
+MockBrowserPlugin::~MockBrowserPlugin() {}
+
+} // namespace content
diff --git a/content/renderer/browser_plugin/mock_browser_plugin.h b/content/renderer/browser_plugin/mock_browser_plugin.h
new file mode 100644
index 0000000..b34a621
--- /dev/null
+++ b/content/renderer/browser_plugin/mock_browser_plugin.h
@@ -0,0 +1,29 @@
+// 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_MOCK_BROWSER_PLUGIN_H_
+#define CONTENT_RENDERER_BROWSER_PLUGIN_MOCK_BROWSER_PLUGIN_H_
+
+#include "content/renderer/browser_plugin/browser_plugin.h"
+
+namespace content {
+
+class MockBrowserPlugin : public BrowserPlugin {
+ public:
+ MockBrowserPlugin(
+ int id,
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params);
+
+ virtual ~MockBrowserPlugin();
+
+ // Allow poking at a few private members.
+ using BrowserPlugin::guest_crashed_;
+ using BrowserPlugin::resize_pending_;
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_MOCK_BROWSER_PLUGIN_H_
diff --git a/content/renderer/browser_plugin/mock_browser_plugin_manager.cc b/content/renderer/browser_plugin/mock_browser_plugin_manager.cc
new file mode 100644
index 0000000..9544635
--- /dev/null
+++ b/content/renderer/browser_plugin/mock_browser_plugin_manager.cc
@@ -0,0 +1,66 @@
+// 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/mock_browser_plugin_manager.h"
+
+#include "ipc/ipc_message.h"
+#include "content/renderer/browser_plugin/mock_browser_plugin.h"
+
+namespace content {
+
+MockBrowserPluginManager::MockBrowserPluginManager() {
+}
+
+MockBrowserPluginManager::~MockBrowserPluginManager() {
+}
+
+BrowserPlugin* MockBrowserPluginManager::CreateBrowserPlugin(
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params) {
+ return new MockBrowserPlugin(browser_plugin_counter_++,
+ render_view,
+ frame,
+ params);
+}
+
+void MockBrowserPluginManager::Cleanup() {
+ IDMap<BrowserPlugin>::iterator iter(&instances_);
+ while (!iter.IsAtEnd()) {
+ iter.GetCurrentValue()->Cleanup();
+ iter.Advance();
+ }
+}
+
+bool MockBrowserPluginManager::Send(IPC::Message* msg) {
+ // This is a copy-and-paste from MockRenderThread::Send.
+ // We need to simulate a synchronous channel, thus we are going to receive
+ // through this function messages, messages with reply and reply messages.
+ // We can only handle one synchronous message at a time.
+ if (msg->is_reply()) {
+ if (reply_deserializer_.get()) {
+ reply_deserializer_->SerializeOutputParameters(*msg);
+ reply_deserializer_.reset();
+ }
+ } else {
+ if (msg->is_sync()) {
+ // We actually need to handle deleting the reply deserializer for sync
+ // messages.
+ reply_deserializer_.reset(
+ static_cast<IPC::SyncMessage*>(msg)->GetReplyDeserializer());
+ }
+ OnControlMessageReceived(*msg);
+ }
+ delete msg;
+ return true;
+}
+
+bool MockBrowserPluginManager::OnControlMessageReceived(
+ const IPC::Message& message) {
+ // Save the message in the sink.
+ sink_.OnMessageReceived(message);
+ return false;
+}
+
+} // namespace content
diff --git a/content/renderer/browser_plugin/mock_browser_plugin_manager.h b/content/renderer/browser_plugin/mock_browser_plugin_manager.h
new file mode 100644
index 0000000..90be1cd
--- /dev/null
+++ b/content/renderer/browser_plugin/mock_browser_plugin_manager.h
@@ -0,0 +1,50 @@
+// 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_MANAGER_IMPL_H_
+#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_IMPL_H_
+
+#include "content/renderer/browser_plugin/browser_plugin_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "ipc/ipc_message_utils.h"
+#include "ipc/ipc_test_sink.h"
+
+namespace content {
+
+class MockBrowserPluginManager : public BrowserPluginManager {
+ public:
+ MockBrowserPluginManager();
+ virtual ~MockBrowserPluginManager();
+
+ // BrowserPluginManager implementation.
+ virtual BrowserPlugin* CreateBrowserPlugin(
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params) OVERRIDE;
+
+ // Iterate over all BrowserPlugins and tell them to cleanup after themselves
+ // before we blow away the MockRenderProcess.
+ void Cleanup();
+
+ // Provides access to the messages that have been received by this thread.
+ IPC::TestSink& sink() { return sink_; }
+
+ // IPC::Sender implementation.
+ virtual bool Send(IPC::Message* msg) OVERRIDE;
+
+ // RenderProcessObserver override.
+ virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
+ private:
+ IPC::TestSink sink_;
+
+ // The last known good deserializer for sync messages.
+ scoped_ptr<IPC::MessageReplyDeserializer> reply_deserializer_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockBrowserPluginManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_TESTS_BROWSER_PLUGIN_MANAGER_IMPL_H_
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index ab56160..c147033 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -55,6 +55,8 @@
#include "content/public/renderer/navigation_state.h"
#include "content/public/renderer/render_view_observer.h"
#include "content/public/renderer/render_view_visitor.h"
+#include "content/renderer/browser_plugin/browser_plugin.h"
+#include "content/renderer/browser_plugin/browser_plugin_manager.h"
#include "content/renderer/browser_plugin/old/old_browser_plugin.h"
#include "content/renderer/browser_plugin/old/browser_plugin_channel_manager.h"
#include "content/renderer/browser_plugin/old/browser_plugin_constants.h"
@@ -2317,6 +2319,13 @@ WebPlugin* RenderViewImpl::createPlugin(WebFrame* frame,
return plugin;
}
+ // TODO(fsamuel): Remove this once upstreaming of the new browser plugin is
+ // complete.
+ if (UTF16ToASCII(params.mimeType) == content::kBrowserPluginNewMimeType) {
+ return content::BrowserPluginManager::Get()->
+ CreateBrowserPlugin(this, frame, params);
+ }
+
if (UTF16ToASCII(params.mimeType) == content::kBrowserPluginMimeType)
return content::old::BrowserPlugin::Create(this, frame, params);
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index d4cec0e..168b2bc 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -102,6 +102,7 @@ enum IPCMessageStart {
PrerenderMsgStart,
ChromotingMsgStart,
OldBrowserPluginMsgStart,
+ BrowserPluginMsgStart,
LastIPCMsgStart // Must come last.
};