summaryrefslogtreecommitdiff
path: root/chromium/content/renderer/browser_plugin
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
committerZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
commit679147eead574d186ebf3069647b4c23e8ccace6 (patch)
treefc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/content/renderer/browser_plugin
downloadqtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz
Initial import.
Diffstat (limited to 'chromium/content/renderer/browser_plugin')
-rw-r--r--chromium/content/renderer/browser_plugin/OWNERS1
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin.cc1343
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin.h376
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_backing_store.cc99
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_backing_store.h66
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_bindings.cc760
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_bindings.h71
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_browsertest.cc632
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_browsertest.h53
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_compositing_helper.cc356
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_compositing_helper.h109
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_manager.cc65
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_manager.h88
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_manager_factory.h21
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_manager_impl.cc111
-rw-r--r--chromium/content/renderer/browser_plugin/browser_plugin_manager_impl.h56
-rw-r--r--chromium/content/renderer/browser_plugin/mock_browser_plugin.cc18
-rw-r--r--chromium/content/renderer/browser_plugin/mock_browser_plugin.h29
-rw-r--r--chromium/content/renderer/browser_plugin/mock_browser_plugin_manager.cc79
-rw-r--r--chromium/content/renderer/browser_plugin/mock_browser_plugin_manager.h50
20 files changed, 4383 insertions, 0 deletions
diff --git a/chromium/content/renderer/browser_plugin/OWNERS b/chromium/content/renderer/browser_plugin/OWNERS
new file mode 100644
index 00000000000..c92691f05e4
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/OWNERS
@@ -0,0 +1 @@
+fsamuel@chromium.org
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin.cc b/chromium/content/renderer/browser_plugin/browser_plugin.cc
new file mode 100644
index 00000000000..cf0bdcc54b9
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin.cc
@@ -0,0 +1,1343 @@
+// Copyright 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/command_line.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/common/browser_plugin/browser_plugin_constants.h"
+#include "content/common/browser_plugin/browser_plugin_messages.h"
+#include "content/common/view_messages.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/content_switches.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_compositing_helper.h"
+#include "content/renderer/browser_plugin/browser_plugin_manager.h"
+#include "content/renderer/cursor_utils.h"
+#include "content/renderer/drop_data_builder.h"
+#include "content/renderer/render_process_impl.h"
+#include "content/renderer/render_thread_impl.h"
+#include "content/renderer/sad_plugin.h"
+#include "content/renderer/v8_value_converter_impl.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebDOMCustomEvent.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "third_party/WebKit/public/web/WebPluginParams.h"
+#include "third_party/WebKit/public/web/WebScriptSource.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+
+#if defined (OS_WIN)
+#include "base/sys_info.h"
+#endif
+
+using WebKit::WebCanvas;
+using WebKit::WebPluginContainer;
+using WebKit::WebPluginParams;
+using WebKit::WebPoint;
+using WebKit::WebRect;
+using WebKit::WebURL;
+using WebKit::WebVector;
+
+namespace content {
+
+namespace {
+
+static std::string GetInternalEventName(const char* event_name) {
+ return base::StringPrintf("-internal-%s", event_name);
+}
+
+typedef std::map<WebKit::WebPluginContainer*,
+ BrowserPlugin*> PluginContainerMap;
+static base::LazyInstance<PluginContainerMap> g_plugin_container_map =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+BrowserPlugin::BrowserPlugin(
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebPluginParams& params)
+ : guest_instance_id_(browser_plugin::kInstanceIDNone),
+ attached_(false),
+ render_view_(render_view->AsWeakPtr()),
+ render_view_routing_id_(render_view->GetRoutingID()),
+ container_(NULL),
+ damage_buffer_sequence_id_(0),
+ resize_ack_received_(true),
+ last_device_scale_factor_(1.0f),
+ sad_guest_(NULL),
+ guest_crashed_(false),
+ auto_size_ack_pending_(false),
+ persist_storage_(false),
+ valid_partition_id_(true),
+ content_window_routing_id_(MSG_ROUTING_NONE),
+ plugin_focused_(false),
+ visible_(true),
+ before_first_navigation_(true),
+ mouse_locked_(false),
+ browser_plugin_manager_(render_view->GetBrowserPluginManager()),
+ compositing_enabled_(false),
+ weak_ptr_factory_(this) {
+}
+
+BrowserPlugin::~BrowserPlugin() {
+ // If the BrowserPlugin has never navigated then the browser process and
+ // BrowserPluginManager don't know about it and so there is nothing to do
+ // here.
+ if (!HasGuestInstanceID())
+ return;
+ browser_plugin_manager()->RemoveBrowserPlugin(guest_instance_id_);
+ browser_plugin_manager()->Send(
+ new BrowserPluginHostMsg_PluginDestroyed(render_view_routing_id_,
+ guest_instance_id_));
+}
+
+/*static*/
+BrowserPlugin* BrowserPlugin::FromContainer(
+ WebKit::WebPluginContainer* container) {
+ PluginContainerMap* browser_plugins = g_plugin_container_map.Pointer();
+ PluginContainerMap::iterator it = browser_plugins->find(container);
+ return it == browser_plugins->end() ? NULL : it->second;
+}
+
+bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(BrowserPlugin, message)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_Attach_ACK, OnAttachACK)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_BuffersSwapped, OnBuffersSwapped)
+ IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped,
+ OnCompositorFrameSwapped(message))
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestContentWindowReady,
+ OnGuestContentWindowReady)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetMouseLock, OnSetMouseLock)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
+ OnShouldAcceptTouchEvents)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_UpdatedName, OnUpdatedName)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_UpdateRect, OnUpdateRect)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
+ const std::string& attribute_value) {
+ if (!container())
+ return;
+
+ WebKit::WebElement element = container()->element();
+ WebKit::WebString web_attribute_name =
+ WebKit::WebString::fromUTF8(attribute_name);
+ if (!HasDOMAttribute(attribute_name) ||
+ (std::string(element.getAttribute(web_attribute_name).utf8()) !=
+ attribute_value)) {
+ element.setAttribute(web_attribute_name,
+ WebKit::WebString::fromUTF8(attribute_value));
+ }
+}
+
+void BrowserPlugin::RemoveDOMAttribute(const std::string& attribute_name) {
+ if (!container())
+ return;
+
+ container()->element().removeAttribute(
+ WebKit::WebString::fromUTF8(attribute_name));
+}
+
+std::string BrowserPlugin::GetDOMAttributeValue(
+ const std::string& attribute_name) const {
+ if (!container())
+ return std::string();
+
+ return container()->element().getAttribute(
+ WebKit::WebString::fromUTF8(attribute_name)).utf8();
+}
+
+bool BrowserPlugin::HasDOMAttribute(const std::string& attribute_name) const {
+ if (!container())
+ return false;
+
+ return container()->element().hasAttribute(
+ WebKit::WebString::fromUTF8(attribute_name));
+}
+
+std::string BrowserPlugin::GetNameAttribute() const {
+ return GetDOMAttributeValue(browser_plugin::kAttributeName);
+}
+
+std::string BrowserPlugin::GetSrcAttribute() const {
+ return GetDOMAttributeValue(browser_plugin::kAttributeSrc);
+}
+
+bool BrowserPlugin::GetAutoSizeAttribute() const {
+ return HasDOMAttribute(browser_plugin::kAttributeAutoSize);
+}
+
+int BrowserPlugin::GetMaxHeightAttribute() const {
+ int max_height;
+ base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxHeight),
+ &max_height);
+ return max_height;
+}
+
+int BrowserPlugin::GetMaxWidthAttribute() const {
+ int max_width;
+ base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxWidth),
+ &max_width);
+ return max_width;
+}
+
+int BrowserPlugin::GetMinHeightAttribute() const {
+ int min_height;
+ base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinHeight),
+ &min_height);
+ return min_height;
+}
+
+int BrowserPlugin::GetMinWidthAttribute() const {
+ int min_width;
+ base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinWidth),
+ &min_width);
+ return min_width;
+}
+
+int BrowserPlugin::GetAdjustedMaxHeight() const {
+ int max_height = GetMaxHeightAttribute();
+ return max_height ? max_height : height();
+}
+
+int BrowserPlugin::GetAdjustedMaxWidth() const {
+ int max_width = GetMaxWidthAttribute();
+ return max_width ? max_width : width();
+}
+
+int BrowserPlugin::GetAdjustedMinHeight() const {
+ int min_height = GetMinHeightAttribute();
+ // FrameView.cpp does not allow this value to be <= 0, so when the value is
+ // unset (or set to 0), we set it to the container size.
+ min_height = min_height ? min_height : height();
+ // For autosize, minHeight should not be bigger than maxHeight.
+ return std::min(min_height, GetAdjustedMaxHeight());
+}
+
+int BrowserPlugin::GetAdjustedMinWidth() const {
+ int min_width = GetMinWidthAttribute();
+ // FrameView.cpp does not allow this value to be <= 0, so when the value is
+ // unset (or set to 0), we set it to the container size.
+ min_width = min_width ? min_width : width();
+ // For autosize, minWidth should not be bigger than maxWidth.
+ return std::min(min_width, GetAdjustedMaxWidth());
+}
+
+std::string BrowserPlugin::GetPartitionAttribute() const {
+ return GetDOMAttributeValue(browser_plugin::kAttributePartition);
+}
+
+void BrowserPlugin::ParseNameAttribute() {
+ if (!HasGuestInstanceID())
+ return;
+ browser_plugin_manager()->Send(
+ new BrowserPluginHostMsg_SetName(render_view_routing_id_,
+ guest_instance_id_,
+ GetNameAttribute()));
+}
+
+bool BrowserPlugin::ParseSrcAttribute(std::string* error_message) {
+ if (!valid_partition_id_) {
+ *error_message = browser_plugin::kErrorInvalidPartition;
+ return false;
+ }
+ std::string src = GetSrcAttribute();
+ if (src.empty())
+ return true;
+
+ // If we haven't created the guest yet, do so now. We will navigate it right
+ // after creation. If |src| is empty, we can delay the creation until we
+ // actually need it.
+ if (!HasGuestInstanceID()) {
+ // On initial navigation, we request an instance ID from the browser
+ // process. We essentially ignore all subsequent calls to SetSrcAttribute
+ // until we receive an instance ID. |before_first_navigation_|
+ // prevents BrowserPlugin from allocating more than one instance ID.
+ // Upon receiving an instance ID from the browser process, we continue
+ // the process of navigation by populating the
+ // BrowserPluginHostMsg_Attach_Params with the current state of
+ // BrowserPlugin and sending a BrowserPluginHostMsg_CreateGuest to the
+ // browser process in order to create a new guest.
+ if (before_first_navigation_) {
+ browser_plugin_manager()->AllocateInstanceID(this);
+ before_first_navigation_ = false;
+ }
+ return true;
+ }
+
+ browser_plugin_manager()->Send(
+ new BrowserPluginHostMsg_NavigateGuest(render_view_routing_id_,
+ guest_instance_id_,
+ src));
+ return true;
+}
+
+void BrowserPlugin::ParseAutoSizeAttribute() {
+ auto_size_ack_pending_ = true;
+ last_view_size_ = plugin_rect_.size();
+ UpdateGuestAutoSizeState(GetAutoSizeAttribute());
+}
+
+void BrowserPlugin::PopulateAutoSizeParameters(
+ BrowserPluginHostMsg_AutoSize_Params* params, bool current_auto_size) {
+ params->enable = current_auto_size;
+ // No need to populate the params if autosize is off.
+ if (current_auto_size) {
+ params->max_size = gfx::Size(GetAdjustedMaxWidth(), GetAdjustedMaxHeight());
+ params->min_size = gfx::Size(GetAdjustedMinWidth(), GetAdjustedMinHeight());
+ }
+}
+
+void BrowserPlugin::UpdateGuestAutoSizeState(bool current_auto_size) {
+ // If we haven't yet heard back from the guest about the last resize request,
+ // then we don't issue another request until we do in
+ // BrowserPlugin::UpdateRect.
+ if (!HasGuestInstanceID() || !resize_ack_received_)
+ return;
+ BrowserPluginHostMsg_AutoSize_Params auto_size_params;
+ BrowserPluginHostMsg_ResizeGuest_Params resize_guest_params;
+ if (current_auto_size) {
+ GetDamageBufferWithSizeParams(&auto_size_params, &resize_guest_params);
+ } else {
+ GetDamageBufferWithSizeParams(NULL, &resize_guest_params);
+ }
+ resize_ack_received_ = false;
+ browser_plugin_manager()->Send(
+ new BrowserPluginHostMsg_SetAutoSize(render_view_routing_id_,
+ guest_instance_id_,
+ auto_size_params,
+ resize_guest_params));
+}
+
+// static
+bool BrowserPlugin::UsesDamageBuffer(
+ const BrowserPluginMsg_UpdateRect_Params& params) {
+ return params.damage_buffer_sequence_id != 0 || params.needs_ack;
+}
+
+bool BrowserPlugin::UsesPendingDamageBuffer(
+ const BrowserPluginMsg_UpdateRect_Params& params) {
+ if (!pending_damage_buffer_)
+ return false;
+ return damage_buffer_sequence_id_ == params.damage_buffer_sequence_id;
+}
+
+void BrowserPlugin::OnInstanceIDAllocated(int guest_instance_id) {
+ CHECK(guest_instance_id != browser_plugin::kInstanceIDNone);
+ before_first_navigation_ = false;
+ guest_instance_id_ = guest_instance_id;
+ browser_plugin_manager()->AddBrowserPlugin(guest_instance_id, this);
+
+ std::map<std::string, base::Value*> props;
+ props[browser_plugin::kWindowID] =
+ new base::FundamentalValue(guest_instance_id);
+ TriggerEvent(browser_plugin::kEventInternalInstanceIDAllocated, &props);
+}
+
+void BrowserPlugin::Attach(scoped_ptr<base::DictionaryValue> extra_params) {
+ BrowserPluginHostMsg_Attach_Params attach_params;
+ attach_params.focused = ShouldGuestBeFocused();
+ attach_params.visible = visible_;
+ attach_params.name = GetNameAttribute();
+ attach_params.storage_partition_id = storage_partition_id_;
+ attach_params.persist_storage = persist_storage_;
+ attach_params.src = GetSrcAttribute();
+ GetDamageBufferWithSizeParams(&attach_params.auto_size_params,
+ &attach_params.resize_guest_params);
+
+ browser_plugin_manager()->Send(
+ new BrowserPluginHostMsg_Attach(render_view_routing_id_,
+ guest_instance_id_, attach_params,
+ *extra_params));
+}
+
+void BrowserPlugin::DidCommitCompositorFrame() {
+ if (compositing_helper_.get())
+ compositing_helper_->DidCommitCompositorFrame();
+}
+
+void BrowserPlugin::OnAdvanceFocus(int guest_instance_id, bool reverse) {
+ DCHECK(render_view_.get());
+ render_view_->GetWebView()->advanceFocus(reverse);
+}
+
+void BrowserPlugin::OnAttachACK(
+ int guest_instance_id,
+ const BrowserPluginMsg_Attach_ACK_Params& params) {
+ // Update BrowserPlugin attributes to match the state of the guest.
+ if (!params.name.empty())
+ OnUpdatedName(guest_instance_id, params.name);
+ if (!params.storage_partition_id.empty()) {
+ std::string partition_name =
+ (params.persist_storage ? browser_plugin::kPersistPrefix : "") +
+ params.storage_partition_id;
+ UpdateDOMAttribute(browser_plugin::kAttributePartition, partition_name);
+ }
+ attached_ = true;
+}
+
+void BrowserPlugin::OnBuffersSwapped(
+ int guest_instance_id,
+ const BrowserPluginMsg_BuffersSwapped_Params& params) {
+ DCHECK(guest_instance_id == guest_instance_id_);
+ EnableCompositing(true);
+
+ compositing_helper_->OnBuffersSwapped(params.size,
+ params.mailbox_name,
+ params.route_id,
+ params.host_id,
+ GetDeviceScaleFactor());
+}
+
+void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) {
+ BrowserPluginMsg_CompositorFrameSwapped::Param param;
+ if (!BrowserPluginMsg_CompositorFrameSwapped::Read(&message, &param))
+ return;
+ scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
+ param.b.AssignTo(frame.get());
+
+ EnableCompositing(true);
+ compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
+ param.c /* route_id */,
+ param.d /* output_surface_id */,
+ param.e /* host_id */);
+}
+
+void BrowserPlugin::OnGuestContentWindowReady(int guest_instance_id,
+ int content_window_routing_id) {
+ DCHECK(content_window_routing_id != MSG_ROUTING_NONE);
+ content_window_routing_id_ = content_window_routing_id;
+}
+
+void BrowserPlugin::OnGuestGone(int guest_instance_id) {
+ guest_crashed_ = true;
+
+ // Queue up showing the sad graphic to give content embedders an opportunity
+ // to fire their listeners and potentially overlay the webview with custom
+ // behavior. If the BrowserPlugin is destroyed in the meantime, then the
+ // task will not be executed.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&BrowserPlugin::ShowSadGraphic,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BrowserPlugin::OnSetCursor(int guest_instance_id,
+ const WebCursor& cursor) {
+ cursor_ = cursor;
+}
+
+void BrowserPlugin::OnSetMouseLock(int guest_instance_id,
+ bool enable) {
+ if (enable) {
+ if (mouse_locked_)
+ return;
+ render_view_->mouse_lock_dispatcher()->LockMouse(this);
+ } else {
+ if (!mouse_locked_) {
+ OnLockMouseACK(false);
+ return;
+ }
+ render_view_->mouse_lock_dispatcher()->UnlockMouse(this);
+ }
+}
+
+void BrowserPlugin::OnShouldAcceptTouchEvents(int guest_instance_id,
+ bool accept) {
+ if (container()) {
+ container()->requestTouchEventType(accept ?
+ WebKit::WebPluginContainer::TouchEventRequestTypeRaw :
+ WebKit::WebPluginContainer::TouchEventRequestTypeNone);
+ }
+}
+
+void BrowserPlugin::OnUpdatedName(int guest_instance_id,
+ const std::string& name) {
+ UpdateDOMAttribute(browser_plugin::kAttributeName, name);
+}
+
+void BrowserPlugin::OnUpdateRect(
+ int guest_instance_id,
+ const BrowserPluginMsg_UpdateRect_Params& params) {
+ // If the guest has updated pixels then it is no longer crashed.
+ guest_crashed_ = false;
+
+ bool use_new_damage_buffer = !backing_store_;
+ BrowserPluginHostMsg_AutoSize_Params auto_size_params;
+ BrowserPluginHostMsg_ResizeGuest_Params resize_guest_params;
+ // If we have a pending damage buffer, and the guest has begun to use the
+ // damage buffer then we know the guest will no longer use the current
+ // damage buffer. At this point, we drop the current damage buffer, and
+ // mark the pending damage buffer as the current damage buffer.
+ if (UsesPendingDamageBuffer(params)) {
+ SwapDamageBuffers();
+ use_new_damage_buffer = true;
+ }
+
+ bool auto_size = GetAutoSizeAttribute();
+ // We receive a resize ACK in regular mode, but not in autosize.
+ // In SW, |resize_ack_received_| is reset in SwapDamageBuffers().
+ // In HW mode, we need to do it here so we can continue sending
+ // resize messages when needed.
+ if (params.is_resize_ack ||
+ (!params.needs_ack && (auto_size || auto_size_ack_pending_))) {
+ resize_ack_received_ = true;
+ }
+
+ auto_size_ack_pending_ = false;
+
+ if ((!auto_size && (width() != params.view_size.width() ||
+ height() != params.view_size.height())) ||
+ (auto_size && (!InAutoSizeBounds(params.view_size))) ||
+ GetDeviceScaleFactor() != params.scale_factor) {
+ // We are HW accelerated, render widget does not expect an ack,
+ // but we still need to update the size.
+ if (!params.needs_ack) {
+ UpdateGuestAutoSizeState(auto_size);
+ return;
+ }
+
+ if (!resize_ack_received_) {
+ // The guest has not yet responded to the last resize request, and
+ // so we don't want to do anything at this point other than ACK the guest.
+ if (auto_size)
+ PopulateAutoSizeParameters(&auto_size_params, auto_size);
+ } else {
+ // If we have no pending damage buffer, then the guest has not caught up
+ // with the BrowserPlugin container. We now tell the guest about the new
+ // container size.
+ if (auto_size) {
+ GetDamageBufferWithSizeParams(&auto_size_params,
+ &resize_guest_params);
+ } else {
+ GetDamageBufferWithSizeParams(NULL, &resize_guest_params);
+ }
+ }
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateRect_ACK(
+ render_view_routing_id_,
+ guest_instance_id_,
+ true,
+ auto_size_params,
+ resize_guest_params));
+ return;
+ }
+
+ if (auto_size && (params.view_size != last_view_size_)) {
+ if (backing_store_)
+ backing_store_->Clear(SK_ColorWHITE);
+ last_view_size_ = params.view_size;
+ }
+
+ if (UsesDamageBuffer(params)) {
+
+ // If we are seeing damage buffers, HW compositing should be turned off.
+ EnableCompositing(false);
+
+ // If we are now using a new damage buffer, then that means that the guest
+ // has updated its size state in response to a resize request. We change
+ // the backing store's size to accomodate the new damage buffer size.
+ if (use_new_damage_buffer) {
+ int backing_store_width = auto_size ? GetAdjustedMaxWidth() : width();
+ int backing_store_height = auto_size ? GetAdjustedMaxHeight(): height();
+ backing_store_.reset(
+ new BrowserPluginBackingStore(
+ gfx::Size(backing_store_width, backing_store_height),
+ params.scale_factor));
+ }
+
+ // If we just transitioned from the compositing path to the software path
+ // then we might not yet have a damage buffer.
+ if (current_damage_buffer_) {
+ // Update the backing store.
+ if (!params.scroll_rect.IsEmpty()) {
+ backing_store_->ScrollBackingStore(params.scroll_delta,
+ params.scroll_rect,
+ params.view_size);
+ }
+ backing_store_->PaintToBackingStore(params.bitmap_rect,
+ params.copy_rects,
+ current_damage_buffer_->memory());
+ // Invalidate the container.
+ // If the BrowserPlugin is scheduled to be deleted, then container_ will
+ // be NULL so we shouldn't attempt to access it.
+ if (container_)
+ container_->invalidate();
+ }
+ }
+
+ // BrowserPluginHostMsg_UpdateRect_ACK is used by both the compositing and
+ // software paths to piggyback updated autosize parameters.
+ if (auto_size)
+ PopulateAutoSizeParameters(&auto_size_params, auto_size);
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateRect_ACK(
+ render_view_routing_id_,
+ guest_instance_id_,
+ UsesDamageBuffer(params),
+ auto_size_params,
+ resize_guest_params));
+}
+
+void BrowserPlugin::ParseSizeContraintsChanged() {
+ bool auto_size = GetAutoSizeAttribute();
+ if (auto_size)
+ UpdateGuestAutoSizeState(true);
+}
+
+bool BrowserPlugin::InAutoSizeBounds(const gfx::Size& size) const {
+ return size.width() <= GetAdjustedMaxWidth() &&
+ size.height() <= GetAdjustedMaxHeight();
+}
+
+NPObject* BrowserPlugin::GetContentWindow() const {
+ if (content_window_routing_id_ == MSG_ROUTING_NONE)
+ return NULL;
+ RenderViewImpl* guest_render_view = RenderViewImpl::FromRoutingID(
+ content_window_routing_id_);
+ if (!guest_render_view)
+ return NULL;
+ WebKit::WebFrame* guest_frame = guest_render_view->GetWebView()->mainFrame();
+ return guest_frame->windowObject();
+}
+
+// static
+bool BrowserPlugin::AttachWindowTo(const WebKit::WebNode& node, int window_id) {
+ if (node.isNull())
+ return false;
+
+ if (!node.isElementNode())
+ return false;
+
+ WebKit::WebElement shim_element = node.toConst<WebKit::WebElement>();
+ // The shim containing the BrowserPlugin must be attached to a document.
+ if (shim_element.document().isNull())
+ return false;
+
+ WebKit::WebNode shadow_root = shim_element.shadowRoot();
+ if (shadow_root.isNull() || !shadow_root.hasChildNodes())
+ return false;
+
+ WebKit::WebNode plugin_element = shadow_root.firstChild();
+ WebKit::WebPluginContainer* plugin_container =
+ plugin_element.pluginContainer();
+ if (!plugin_container)
+ return false;
+
+ BrowserPlugin* browser_plugin =
+ BrowserPlugin::FromContainer(plugin_container);
+ if (!browser_plugin)
+ return false;
+
+ // If the BrowserPlugin has already begun to navigate then we shouldn't allow
+ // attaching a different guest.
+ //
+ // Navigation happens in two stages.
+ // 1. BrowserPlugin requests an instance ID from the browser process.
+ // 2. The browser process returns an instance ID and BrowserPlugin is
+ // "Attach"ed to that instance ID.
+ // If the instance ID is new then a new guest will be created.
+ // If the instance ID corresponds to an unattached guest then BrowserPlugin
+ // is attached to that guest.
+ //
+ // Between step 1, and step 2, BrowserPlugin::AttachWindowTo may be called.
+ // The check below ensures that BrowserPlugin:Attach does not get called with
+ // a different instance ID after step 1 has happened.
+ // TODO(fsamuel): We may wish to support reattaching guests in the future:
+ // http://crbug.com/156219.
+ if (browser_plugin->HasNavigated())
+ return false;
+
+ browser_plugin->OnInstanceIDAllocated(window_id);
+ return true;
+}
+
+bool BrowserPlugin::HasNavigated() const {
+ return !before_first_navigation_;
+}
+
+bool BrowserPlugin::HasGuestInstanceID() const {
+ return guest_instance_id_ != browser_plugin::kInstanceIDNone;
+}
+
+bool BrowserPlugin::ParsePartitionAttribute(std::string* error_message) {
+ if (HasNavigated()) {
+ *error_message = browser_plugin::kErrorAlreadyNavigated;
+ return false;
+ }
+
+ std::string input = GetPartitionAttribute();
+
+ // Since the "persist:" prefix is in ASCII, StartsWith will work fine on
+ // UTF-8 encoded |partition_id|. If the prefix is a match, we can safely
+ // remove the prefix without splicing in the middle of a multi-byte codepoint.
+ // We can use the rest of the string as UTF-8 encoded one.
+ if (StartsWithASCII(input, browser_plugin::kPersistPrefix, true)) {
+ size_t index = input.find(":");
+ CHECK(index != std::string::npos);
+ // It is safe to do index + 1, since we tested for the full prefix above.
+ input = input.substr(index + 1);
+ if (input.empty()) {
+ valid_partition_id_ = false;
+ *error_message = browser_plugin::kErrorInvalidPartition;
+ return false;
+ }
+ persist_storage_ = true;
+ } else {
+ persist_storage_ = false;
+ }
+
+ valid_partition_id_ = true;
+ storage_partition_id_ = input;
+ return true;
+}
+
+bool BrowserPlugin::CanRemovePartitionAttribute(std::string* error_message) {
+ if (HasGuestInstanceID())
+ *error_message = browser_plugin::kErrorCannotRemovePartition;
+ return !HasGuestInstanceID();
+}
+
+void BrowserPlugin::ShowSadGraphic() {
+ // We won't paint the contents of the current backing store again so we might
+ // as well toss it out and save memory.
+ backing_store_.reset();
+ // If the BrowserPlugin is scheduled to be deleted, then container_ will be
+ // NULL so we shouldn't attempt to access it.
+ if (container_)
+ container_->invalidate();
+ // Turn off compositing so we can display the sad graphic.
+ EnableCompositing(false);
+}
+
+void BrowserPlugin::ParseAttributes() {
+ // TODO(mthiesse): Handle errors here?
+ std::string error;
+ ParsePartitionAttribute(&error);
+
+ // Parse the 'src' attribute last, as it will set the has_navigated_ flag to
+ // true, which prevents changing the 'partition' attribute.
+ ParseSrcAttribute(&error);
+}
+
+float BrowserPlugin::GetDeviceScaleFactor() const {
+ if (!render_view_.get())
+ return 1.0f;
+ return render_view_->GetWebView()->deviceScaleFactor();
+}
+
+void BrowserPlugin::UpdateDeviceScaleFactor(float device_scale_factor) {
+ if (last_device_scale_factor_ == device_scale_factor || !resize_ack_received_)
+ return;
+
+ BrowserPluginHostMsg_ResizeGuest_Params params;
+ PopulateResizeGuestParameters(&params, plugin_rect());
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
+ render_view_routing_id_,
+ guest_instance_id_,
+ params));
+}
+
+void BrowserPlugin::TriggerEvent(const std::string& event_name,
+ std::map<std::string, base::Value*>* props) {
+ if (!container())
+ return;
+
+ WebKit::WebFrame* frame = container()->element().document().frame();
+ if (!frame)
+ return;
+
+ v8::HandleScope handle_scope;
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Context::Scope context_scope(context);
+
+ std::string json_string;
+ if (props) {
+ base::DictionaryValue dict;
+ for (std::map<std::string, base::Value*>::iterator iter = props->begin(),
+ end = props->end(); iter != end; ++iter) {
+ dict.Set(iter->first, iter->second);
+ }
+
+ JSONStringValueSerializer serializer(&json_string);
+ if (!serializer.Serialize(dict))
+ return;
+ }
+
+ WebKit::WebDOMEvent dom_event = frame->document().createEvent("CustomEvent");
+ WebKit::WebDOMCustomEvent event = dom_event.to<WebKit::WebDOMCustomEvent>();
+
+ // The events triggered directly from the plugin <object> are internal events
+ // whose implementation details can (and likely will) change over time. The
+ // wrapper/shim (e.g. <webview> tag) should receive these events, and expose a
+ // more appropriate (and stable) event to the consumers as part of the API.
+ event.initCustomEvent(
+ WebKit::WebString::fromUTF8(GetInternalEventName(event_name.c_str())),
+ false, false,
+ WebKit::WebSerializedScriptValue::serialize(
+ v8::String::New(json_string.c_str(), json_string.size())));
+ container()->element().dispatchEvent(event);
+}
+
+void BrowserPlugin::OnTrackedObjectGarbageCollected(int id) {
+ // Remove from alive objects.
+ std::map<int, TrackedV8ObjectID*>::iterator iter =
+ tracked_v8_objects_.find(id);
+ if (iter != tracked_v8_objects_.end())
+ tracked_v8_objects_.erase(iter);
+
+ std::map<std::string, base::Value*> props;
+ props[browser_plugin::kId] = new base::FundamentalValue(id);
+ TriggerEvent(browser_plugin::kEventInternalTrackedObjectGone, &props);
+}
+
+void BrowserPlugin::TrackObjectLifetime(const NPVariant* request, int id) {
+ // An object of a given ID can only be tracked once.
+ if (tracked_v8_objects_.find(id) != tracked_v8_objects_.end())
+ return;
+
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::Persistent<v8::Value> weak_request(
+ isolate, WebKit::WebBindings::toV8Value(request));
+
+ TrackedV8ObjectID* new_item =
+ new std::pair<int, base::WeakPtr<BrowserPlugin> >(
+ id, weak_ptr_factory_.GetWeakPtr());
+
+ std::pair<std::map<int, TrackedV8ObjectID*>::iterator, bool>
+ result = tracked_v8_objects_.insert(
+ std::make_pair(id, new_item));
+ CHECK(result.second); // Inserted in the map.
+ TrackedV8ObjectID* request_item = result.first->second;
+ weak_request.MakeWeak(static_cast<void*>(request_item),
+ WeakCallbackForTrackedObject);
+}
+
+// static
+void BrowserPlugin::WeakCallbackForTrackedObject(
+ v8::Isolate* isolate, v8::Persistent<v8::Value>* object, void* param) {
+
+ TrackedV8ObjectID* item_ptr = static_cast<TrackedV8ObjectID*>(param);
+ int object_id = item_ptr->first;
+ base::WeakPtr<BrowserPlugin> plugin = item_ptr->second;
+ delete item_ptr;
+
+ object->Dispose();
+ if (plugin.get()) {
+ // Asynchronously remove item from |tracked_v8_objects_|.
+ // Note that we are using weak pointer for the following PostTask, so we
+ // don't need to worry about BrowserPlugin going away.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&BrowserPlugin::OnTrackedObjectGarbageCollected,
+ plugin,
+ object_id));
+ }
+}
+
+void BrowserPlugin::UpdateGuestFocusState() {
+ if (!HasGuestInstanceID())
+ return;
+ bool should_be_focused = ShouldGuestBeFocused();
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetFocus(
+ render_view_routing_id_,
+ guest_instance_id_,
+ should_be_focused));
+}
+
+bool BrowserPlugin::ShouldGuestBeFocused() const {
+ bool embedder_focused = false;
+ if (render_view_.get())
+ embedder_focused = render_view_->has_focus();
+ return plugin_focused_ && embedder_focused;
+}
+
+WebKit::WebPluginContainer* BrowserPlugin::container() const {
+ return container_;
+}
+
+bool BrowserPlugin::initialize(WebPluginContainer* container) {
+ if (!container)
+ return false;
+
+ if (!GetContentClient()->renderer()->AllowBrowserPlugin(container))
+ return false;
+
+ // Tell |container| to allow this plugin to use script objects.
+ npp_.reset(new NPP_t);
+ container->allowScriptObjects();
+
+ bindings_.reset(new BrowserPluginBindings(this));
+ container_ = container;
+ container_->setWantsWheelEvents(true);
+ ParseAttributes();
+ g_plugin_container_map.Get().insert(std::make_pair(container_, this));
+ return true;
+}
+
+void BrowserPlugin::EnableCompositing(bool enable) {
+ if (compositing_enabled_ == enable)
+ return;
+
+ compositing_enabled_ = enable;
+ if (enable) {
+ // No need to keep the backing store and damage buffer around if we're now
+ // compositing.
+ backing_store_.reset();
+ current_damage_buffer_.reset();
+ if (!compositing_helper_.get()) {
+ compositing_helper_ =
+ new BrowserPluginCompositingHelper(container_,
+ browser_plugin_manager(),
+ guest_instance_id_,
+ render_view_routing_id_);
+ }
+ } else {
+ // We're switching back to the software path. We create a new damage
+ // buffer that can accommodate the current size of the container.
+ BrowserPluginHostMsg_ResizeGuest_Params params;
+ PopulateResizeGuestParameters(&params, plugin_rect());
+ // Request a full repaint from the guest even if its size is not actually
+ // changing.
+ params.repaint = true;
+ resize_ack_received_ = false;
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
+ render_view_routing_id_,
+ guest_instance_id_,
+ params));
+ }
+ compositing_helper_->EnableCompositing(enable);
+}
+
+void BrowserPlugin::destroy() {
+ // If the plugin was initialized then it has a valid |npp_| identifier, and
+ // the |container_| must clear references to the plugin's script objects.
+ DCHECK(!npp_ || container_);
+ if (container_)
+ container_->clearScriptObjects();
+
+ // The BrowserPlugin's WebPluginContainer is deleted immediately after this
+ // call returns, so let's not keep a reference to it around.
+ g_plugin_container_map.Get().erase(container_);
+ container_ = NULL;
+ if (compositing_helper_.get())
+ compositing_helper_->OnContainerDestroy();
+ // Will be a no-op if the mouse is not currently locked.
+ if (render_view_.get())
+ render_view_->mouse_lock_dispatcher()->OnLockTargetDestroyed(this);
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+NPObject* BrowserPlugin::scriptableObject() {
+ if (!bindings_)
+ return NULL;
+
+ 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;
+}
+
+NPP BrowserPlugin::pluginNPP() {
+ return npp_.get();
+}
+
+bool BrowserPlugin::supportsKeyboardFocus() const {
+ return true;
+}
+
+bool BrowserPlugin::supportsEditCommands() const {
+ return true;
+}
+
+bool BrowserPlugin::canProcessDrag() const {
+ return true;
+}
+
+void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
+ if (guest_crashed_) {
+ if (!sad_guest_) // Lazily initialize bitmap.
+ sad_guest_ = content::GetContentClient()->renderer()->
+ GetSadWebViewBitmap();
+ // content_shell does not have the sad plugin bitmap, so we'll paint black
+ // instead to make it clear that something went wrong.
+ if (sad_guest_) {
+ 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 black or 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(guest_crashed_ ? SK_ColorBLACK : SK_ColorWHITE);
+ canvas->drawRect(image_data_rect, paint);
+ // Stay a solid color if we have never set a non-empty src, or we don't have a
+ // backing store.
+ if (!backing_store_.get() || !HasGuestInstanceID())
+ 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);
+}
+
+bool BrowserPlugin::InBounds(const gfx::Point& position) const {
+ // Note that even for plugins that are rotated using rotate transformations,
+ // we use the the |plugin_rect_| provided by updateGeometry, which means we
+ // will be off if |position| is within the plugin rect but does not fall
+ // within the actual plugin boundary. Not supporting such edge case is OK
+ // since this function should not be used for making security-sensitive
+ // decisions.
+ // This also does not take overlapping plugins into account.
+ bool result = position.x() >= plugin_rect_.x() &&
+ position.x() < plugin_rect_.x() + plugin_rect_.width() &&
+ position.y() >= plugin_rect_.y() &&
+ position.y() < plugin_rect_.y() + plugin_rect_.height();
+ return result;
+}
+
+gfx::Point BrowserPlugin::ToLocalCoordinates(const gfx::Point& point) const {
+ if (container_)
+ return container_->windowToLocalPoint(WebKit::WebPoint(point));
+ return gfx::Point(point.x() - plugin_rect_.x(), point.y() - plugin_rect_.y());
+}
+
+// static
+bool BrowserPlugin::ShouldForwardToBrowserPlugin(
+ const IPC::Message& message) {
+ switch (message.type()) {
+ case BrowserPluginMsg_AdvanceFocus::ID:
+ case BrowserPluginMsg_Attach_ACK::ID:
+ case BrowserPluginMsg_BuffersSwapped::ID:
+ case BrowserPluginMsg_CompositorFrameSwapped::ID:
+ case BrowserPluginMsg_GuestContentWindowReady::ID:
+ case BrowserPluginMsg_GuestGone::ID:
+ case BrowserPluginMsg_SetCursor::ID:
+ case BrowserPluginMsg_SetMouseLock::ID:
+ case BrowserPluginMsg_ShouldAcceptTouchEvents::ID:
+ case BrowserPluginMsg_UpdatedName::ID:
+ case BrowserPluginMsg_UpdateRect::ID:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+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 (!attached())
+ return;
+
+ // In AutoSize mode, guests don't care when the BrowserPlugin container is
+ // resized. If |!resize_ack_received_|, then we are still waiting on a
+ // previous resize to be ACK'ed and so we don't issue additional resizes
+ // until the previous one is ACK'ed.
+ // TODO(mthiesse): Assess the performance of calling GetAutoSizeAttribute() on
+ // resize.
+ if (!resize_ack_received_ ||
+ (old_width == window_rect.width && old_height == window_rect.height) ||
+ GetAutoSizeAttribute()) {
+ // Let the browser know about the updated view rect.
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateGeometry(
+ render_view_routing_id_, guest_instance_id_, plugin_rect_));
+ return;
+ }
+
+ BrowserPluginHostMsg_ResizeGuest_Params params;
+ PopulateResizeGuestParameters(&params, plugin_rect());
+ resize_ack_received_ = false;
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
+ render_view_routing_id_,
+ guest_instance_id_,
+ params));
+}
+
+void BrowserPlugin::SwapDamageBuffers() {
+ current_damage_buffer_.reset(pending_damage_buffer_.release());
+ resize_ack_received_ = true;
+}
+
+void BrowserPlugin::PopulateResizeGuestParameters(
+ BrowserPluginHostMsg_ResizeGuest_Params* params,
+ const gfx::Rect& view_rect) {
+ params->size_changed = true;
+ params->view_rect = view_rect;
+ params->scale_factor = GetDeviceScaleFactor();
+ if (last_device_scale_factor_ != params->scale_factor){
+ params->repaint = true;
+ last_device_scale_factor_ = params->scale_factor;
+ }
+
+ // In HW compositing mode, we do not need a damage buffer.
+ if (compositing_enabled_)
+ return;
+
+ const size_t stride = skia::PlatformCanvasStrideForWidth(view_rect.width());
+ // Make sure the size of the damage buffer is at least four bytes so that we
+ // can fit in a magic word to verify that the memory is shared correctly.
+ size_t size =
+ std::max(sizeof(unsigned int),
+ static_cast<size_t>(view_rect.height() *
+ stride *
+ GetDeviceScaleFactor() *
+ GetDeviceScaleFactor()));
+
+ params->damage_buffer_size = size;
+ pending_damage_buffer_.reset(
+ CreateDamageBuffer(size, &params->damage_buffer_handle));
+ if (!pending_damage_buffer_)
+ NOTREACHED();
+ params->damage_buffer_sequence_id = ++damage_buffer_sequence_id_;
+}
+
+void BrowserPlugin::GetDamageBufferWithSizeParams(
+ BrowserPluginHostMsg_AutoSize_Params* auto_size_params,
+ BrowserPluginHostMsg_ResizeGuest_Params* resize_guest_params) {
+ if (auto_size_params)
+ PopulateAutoSizeParameters(auto_size_params, GetAutoSizeAttribute());
+ gfx::Size view_size = (auto_size_params && auto_size_params->enable) ?
+ auto_size_params->max_size : gfx::Size(width(), height());
+ if (view_size.IsEmpty())
+ return;
+ resize_ack_received_ = false;
+ gfx::Rect view_rect = gfx::Rect(plugin_rect_.origin(), view_size);
+ PopulateResizeGuestParameters(resize_guest_params, view_rect);
+}
+
+#if defined(OS_POSIX)
+base::SharedMemory* BrowserPlugin::CreateDamageBuffer(
+ const size_t size,
+ base::SharedMemoryHandle* damage_buffer_handle) {
+ scoped_ptr<base::SharedMemory> shared_buf(
+ content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
+ size).release());
+
+ if (shared_buf) {
+ if (shared_buf->Map(size)) {
+ // Insert the magic word.
+ *static_cast<unsigned int*>(shared_buf->memory()) = 0xdeadbeef;
+ shared_buf->ShareToProcess(base::GetCurrentProcessHandle(),
+ damage_buffer_handle);
+ return shared_buf.release();
+ }
+ }
+ NOTREACHED();
+ return NULL;
+}
+#elif defined(OS_WIN)
+base::SharedMemory* BrowserPlugin::CreateDamageBuffer(
+ const size_t size,
+ base::SharedMemoryHandle* damage_buffer_handle) {
+ scoped_ptr<base::SharedMemory> shared_buf(new base::SharedMemory());
+
+ if (!shared_buf->CreateAndMapAnonymous(size)) {
+ NOTREACHED() << "Buffer allocation failed";
+ return NULL;
+ }
+
+ // Insert the magic word.
+ *static_cast<unsigned int*>(shared_buf->memory()) = 0xdeadbeef;
+ if (shared_buf->ShareToProcess(base::GetCurrentProcessHandle(),
+ damage_buffer_handle))
+ return shared_buf.release();
+ NOTREACHED();
+ return NULL;
+}
+#endif
+
+void BrowserPlugin::updateFocus(bool focused) {
+ if (plugin_focused_ == focused)
+ return;
+
+ bool old_guest_focus_state = ShouldGuestBeFocused();
+ plugin_focused_ = focused;
+
+ if (ShouldGuestBeFocused() != old_guest_focus_state)
+ UpdateGuestFocusState();
+}
+
+void BrowserPlugin::updateVisibility(bool visible) {
+ if (visible_ == visible)
+ return;
+
+ visible_ = visible;
+ if (!HasGuestInstanceID())
+ return;
+
+ if (compositing_helper_.get())
+ compositing_helper_->UpdateVisibility(visible);
+
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetVisibility(
+ render_view_routing_id_,
+ guest_instance_id_,
+ visible));
+}
+
+bool BrowserPlugin::acceptsInputEvents() {
+ return true;
+}
+
+bool BrowserPlugin::handleInputEvent(const WebKit::WebInputEvent& event,
+ WebKit::WebCursorInfo& cursor_info) {
+ if (guest_crashed_ || !HasGuestInstanceID())
+ return false;
+
+ if (event.type == WebKit::WebInputEvent::ContextMenu)
+ return true;
+
+ const WebKit::WebInputEvent* modified_event = &event;
+ scoped_ptr<WebKit::WebTouchEvent> touch_event;
+ // WebKit gives BrowserPlugin a list of touches that are down, but the browser
+ // process expects a list of all touches. We modify the TouchEnd event here to
+ // match these expectations.
+ if (event.type == WebKit::WebInputEvent::TouchEnd) {
+ const WebKit::WebTouchEvent* orig_touch_event =
+ static_cast<const WebKit::WebTouchEvent*>(&event);
+ touch_event.reset(new WebKit::WebTouchEvent());
+ memcpy(touch_event.get(), orig_touch_event, sizeof(WebKit::WebTouchEvent));
+ if (touch_event->changedTouchesLength > 0) {
+ memcpy(&touch_event->touches[touch_event->touchesLength],
+ &touch_event->changedTouches,
+ touch_event->changedTouchesLength * sizeof(WebKit::WebTouchPoint));
+ }
+ touch_event->touchesLength += touch_event->changedTouchesLength;
+ modified_event = touch_event.get();
+ }
+
+ if (WebKit::WebInputEvent::isKeyboardEventType(event.type) &&
+ !edit_commands_.empty()) {
+ browser_plugin_manager()->Send(
+ new BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent(
+ render_view_routing_id_,
+ guest_instance_id_,
+ edit_commands_));
+ edit_commands_.clear();
+ }
+
+ browser_plugin_manager()->Send(
+ new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
+ guest_instance_id_,
+ plugin_rect_,
+ modified_event));
+ GetWebKitCursorInfo(cursor_, &cursor_info);
+ return true;
+}
+
+bool BrowserPlugin::handleDragStatusUpdate(WebKit::WebDragStatus drag_status,
+ const WebKit::WebDragData& drag_data,
+ WebKit::WebDragOperationsMask mask,
+ const WebKit::WebPoint& position,
+ const WebKit::WebPoint& screen) {
+ if (guest_crashed_ || !HasGuestInstanceID())
+ return false;
+ browser_plugin_manager()->Send(
+ new BrowserPluginHostMsg_DragStatusUpdate(
+ render_view_routing_id_,
+ guest_instance_id_,
+ drag_status,
+ DropDataBuilder::Build(drag_data),
+ mask,
+ position));
+ return true;
+}
+
+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) {
+}
+
+bool BrowserPlugin::executeEditCommand(const WebKit::WebString& name) {
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
+ render_view_routing_id_,
+ guest_instance_id_,
+ name.utf8()));
+
+ // BrowserPlugin swallows edit commands.
+ return true;
+}
+
+bool BrowserPlugin::executeEditCommand(const WebKit::WebString& name,
+ const WebKit::WebString& value) {
+ edit_commands_.push_back(EditCommand(name.utf8(), value.utf8()));
+ // BrowserPlugin swallows edit commands.
+ return true;
+}
+
+void BrowserPlugin::OnLockMouseACK(bool succeeded) {
+ mouse_locked_ = succeeded;
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_LockMouse_ACK(
+ render_view_routing_id_,
+ guest_instance_id_,
+ succeeded));
+}
+
+void BrowserPlugin::OnMouseLockLost() {
+ mouse_locked_ = false;
+ browser_plugin_manager()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK(
+ render_view_routing_id_,
+ guest_instance_id_));
+}
+
+bool BrowserPlugin::HandleMouseLockedInputEvent(
+ const WebKit::WebMouseEvent& event) {
+ browser_plugin_manager()->Send(
+ new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
+ guest_instance_id_,
+ plugin_rect_,
+ &event));
+ return true;
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin.h b/chromium/content/renderer/browser_plugin/browser_plugin.h
new file mode 100644
index 00000000000..89481196bec
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin.h
@@ -0,0 +1,376 @@
+// Copyright 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/public/web/WebPlugin.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner_helpers.h"
+#if defined(OS_WIN)
+#include "base/memory/shared_memory.h"
+#endif
+#include "base/values.h"
+#include "content/public/common/browser_plugin_permission_type.h"
+#include "content/renderer/browser_plugin/browser_plugin_backing_store.h"
+#include "content/renderer/browser_plugin/browser_plugin_bindings.h"
+#include "content/renderer/mouse_lock_dispatcher.h"
+#include "content/renderer/render_view_impl.h"
+#include "third_party/WebKit/public/web/WebDragStatus.h"
+
+struct BrowserPluginHostMsg_AutoSize_Params;
+struct BrowserPluginHostMsg_ResizeGuest_Params;
+struct BrowserPluginMsg_Attach_ACK_Params;
+struct BrowserPluginMsg_BuffersSwapped_Params;
+struct BrowserPluginMsg_UpdateRect_Params;
+
+namespace content {
+
+class BrowserPluginCompositingHelper;
+class BrowserPluginManager;
+class MockBrowserPlugin;
+
+class CONTENT_EXPORT BrowserPlugin :
+ NON_EXPORTED_BASE(public WebKit::WebPlugin),
+ public MouseLockDispatcher::LockTarget {
+ public:
+ RenderViewImpl* render_view() const { return render_view_.get(); }
+ int render_view_routing_id() const { return render_view_routing_id_; }
+ int guest_instance_id() const { return guest_instance_id_; }
+ bool attached() const { return attached_; }
+
+ static BrowserPlugin* FromContainer(WebKit::WebPluginContainer* container);
+
+ bool OnMessageReceived(const IPC::Message& msg);
+
+ // Update Browser Plugin's DOM Node attribute |attribute_name| with the value
+ // |attribute_value|.
+ void UpdateDOMAttribute(const std::string& attribute_name,
+ const std::string& attribute_value);
+ // Remove the DOM Node attribute with the name |attribute_name|.
+ void RemoveDOMAttribute(const std::string& attribute_name);
+ // Get Browser Plugin's DOM Node attribute |attribute_name|'s value.
+ std::string GetDOMAttributeValue(const std::string& attribute_name) const;
+ // Checks if the attribute |attribute_name| exists in the DOM.
+ bool HasDOMAttribute(const std::string& attribute_name) const;
+
+ // Get the name attribute value.
+ std::string GetNameAttribute() const;
+ // Parse the name attribute value.
+ void ParseNameAttribute();
+ // Get the src attribute value of the BrowserPlugin instance.
+ std::string GetSrcAttribute() const;
+ // Parse the src attribute value of the BrowserPlugin instance.
+ bool ParseSrcAttribute(std::string* error_message);
+ // Get the autosize attribute value.
+ bool GetAutoSizeAttribute() const;
+ // Parses the autosize attribute value.
+ void ParseAutoSizeAttribute();
+ // Get the maxheight attribute value.
+ int GetMaxHeightAttribute() const;
+ // Get the maxwidth attribute value.
+ int GetMaxWidthAttribute() const;
+ // Get the minheight attribute value.
+ int GetMinHeightAttribute() const;
+ // Get the minwidth attribute value.
+ int GetMinWidthAttribute() const;
+ // Parse the minwidth, maxwidth, minheight, and maxheight attribute values.
+ void ParseSizeContraintsChanged();
+ // The partition identifier string is stored as UTF-8.
+ std::string GetPartitionAttribute() const;
+ // This method can be successfully called only before the first navigation for
+ // this instance of BrowserPlugin. If an error occurs, the |error_message| is
+ // set appropriately to indicate the failure reason.
+ bool ParsePartitionAttribute(std::string* error_message);
+ // True if the partition attribute can be removed.
+ bool CanRemovePartitionAttribute(std::string* error_message);
+
+ bool InAutoSizeBounds(const gfx::Size& size) const;
+
+ // Get the guest's DOMWindow proxy.
+ NPObject* GetContentWindow() const;
+
+ // Returns whether the guest process has crashed.
+ bool guest_crashed() const { return guest_crashed_; }
+ // Returns whether this BrowserPlugin has requested an instance ID.
+ bool HasNavigated() const;
+ // Returns whether this BrowserPlugin has allocated an instance ID.
+ bool HasGuestInstanceID() const;
+
+ // Attaches the window identified by |window_id| to the the given node
+ // encapsulating a BrowserPlugin.
+ static bool AttachWindowTo(const WebKit::WebNode& node,
+ int window_id);
+
+ // Informs the guest of an updated focus state.
+ void UpdateGuestFocusState();
+ // Indicates whether the guest should be focused.
+ bool ShouldGuestBeFocused() const;
+
+ // Embedder's device scale factor changed, we need to update the guest
+ // renderer.
+ void UpdateDeviceScaleFactor(float device_scale_factor);
+
+ // A request to enable hardware compositing.
+ void EnableCompositing(bool enable);
+ // A request from content client to track lifetime of a JavaScript object.
+ // This is used to track permission request objects, and new window API
+ // window objects.
+ void TrackObjectLifetime(const NPVariant* request, int id);
+
+ // Returns true if |point| lies within the bounds of the plugin rectangle.
+ // Not OK to use this function for making security-sensitive decision since it
+ // can return false positives when the plugin has rotation transformation
+ // applied.
+ bool InBounds(const gfx::Point& point) const;
+
+ gfx::Point ToLocalCoordinates(const gfx::Point& point) const;
+
+ // Called when a guest instance ID has been allocated by the browser process.
+ void OnInstanceIDAllocated(int guest_instance_id);
+ // Provided that a guest instance ID has been allocated, this method attaches
+ // this BrowserPlugin instance to that guest. |extra_params| are parameters
+ // passed in by the content embedder to the browser process.
+ void Attach(scoped_ptr<base::DictionaryValue> extra_params);
+
+ // Notify the plugin about a compositor commit so that frame ACKs could be
+ // sent, if needed.
+ void DidCommitCompositorFrame();
+
+ // Returns whether a message should be forwarded to BrowserPlugin.
+ static bool ShouldForwardToBrowserPlugin(const IPC::Message& message);
+
+ // 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 struct _NPP* pluginNPP() OVERRIDE;
+ virtual bool supportsKeyboardFocus() const OVERRIDE;
+ virtual bool supportsEditCommands() const OVERRIDE;
+ virtual bool canProcessDrag() const 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 bool handleDragStatusUpdate(WebKit::WebDragStatus drag_status,
+ const WebKit::WebDragData& drag_data,
+ WebKit::WebDragOperationsMask mask,
+ const WebKit::WebPoint& position,
+ const WebKit::WebPoint& screen) 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;
+ virtual bool executeEditCommand(const WebKit::WebString& name) OVERRIDE;
+ virtual bool executeEditCommand(const WebKit::WebString& name,
+ const WebKit::WebString& value) OVERRIDE;
+
+ // MouseLockDispatcher::LockTarget implementation.
+ virtual void OnLockMouseACK(bool succeeded) OVERRIDE;
+ virtual void OnMouseLockLost() OVERRIDE;
+ virtual bool HandleMouseLockedInputEvent(
+ const WebKit::WebMouseEvent& event) OVERRIDE;
+
+ private:
+ 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 RenderView has a unique instance_id that is used to track per-
+ // BrowserPlugin state in the browser process. Once a BrowserPlugin does
+ // an initial navigation or is attached to a newly created guest, it acquires
+ // a guest_instance_id as well. The guest instance ID uniquely identifies a
+ // guest WebContents that's hosted by this BrowserPlugin.
+ BrowserPlugin(
+ 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(); }
+ gfx::Rect plugin_rect() { return plugin_rect_; }
+ // Gets the Max Height value used for auto size.
+ int GetAdjustedMaxHeight() const;
+ // Gets the Max Width value used for auto size.
+ int GetAdjustedMaxWidth() const;
+ // Gets the Min Height value used for auto size.
+ int GetAdjustedMinHeight() const;
+ // Gets the Min Width value used for auto size.
+ int GetAdjustedMinWidth() const;
+ BrowserPluginManager* browser_plugin_manager() const {
+ return browser_plugin_manager_.get();
+ }
+
+ // Virtual to allow for mocking in tests.
+ virtual float GetDeviceScaleFactor() const;
+
+ void ShowSadGraphic();
+
+ // Parses the attributes of the browser plugin from the element's attributes
+ // and sets them appropriately.
+ void ParseAttributes();
+
+ // Triggers the event-listeners for |event_name|. Note that the function
+ // frees all the values in |props|.
+ void TriggerEvent(const std::string& event_name,
+ std::map<std::string, base::Value*>* props);
+
+ // Creates and maps a shared damage buffer.
+ virtual base::SharedMemory* CreateDamageBuffer(
+ const size_t size,
+ base::SharedMemoryHandle* shared_memory_handle);
+ // Swaps out the |current_damage_buffer_| with the |pending_damage_buffer_|.
+ void SwapDamageBuffers();
+
+ // Populates BrowserPluginHostMsg_ResizeGuest_Params with resize state and
+ // allocates a new |pending_damage_buffer_| if in software rendering mode.
+ void PopulateResizeGuestParameters(
+ BrowserPluginHostMsg_ResizeGuest_Params* params,
+ const gfx::Rect& view_size);
+
+ // Populates BrowserPluginHostMsg_AutoSize_Params object with autosize state.
+ void PopulateAutoSizeParameters(
+ BrowserPluginHostMsg_AutoSize_Params* params, bool current_auto_size);
+
+ // Populates both AutoSize and ResizeGuest parameters based on the current
+ // autosize state.
+ void GetDamageBufferWithSizeParams(
+ BrowserPluginHostMsg_AutoSize_Params* auto_size_params,
+ BrowserPluginHostMsg_ResizeGuest_Params* resize_guest_params);
+
+ // Informs the guest of an updated autosize state.
+ void UpdateGuestAutoSizeState(bool current_auto_size);
+
+ // Indicates whether a damage buffer was used by the guest process for the
+ // provided |params|.
+ static bool UsesDamageBuffer(
+ const BrowserPluginMsg_UpdateRect_Params& params);
+
+ // Indicates whether the |pending_damage_buffer_| was used to copy over pixels
+ // given the provided |params|.
+ bool UsesPendingDamageBuffer(
+ const BrowserPluginMsg_UpdateRect_Params& params);
+
+ // Called when the tracked object of |id| ID becomes unreachable in
+ // JavaScript.
+ void OnTrackedObjectGarbageCollected(int id);
+ // V8 garbage collection callback for |object|.
+ static void WeakCallbackForTrackedObject(v8::Isolate* isolate,
+ v8::Persistent<v8::Value>* object,
+ void* param);
+
+ // IPC message handlers.
+ // Please keep in alphabetical order.
+ void OnAdvanceFocus(int instance_id, bool reverse);
+ void OnAttachACK(int instance_id,
+ const BrowserPluginMsg_Attach_ACK_Params& ack_params);
+ void OnBuffersSwapped(int instance_id,
+ const BrowserPluginMsg_BuffersSwapped_Params& params);
+ void OnCompositorFrameSwapped(const IPC::Message& message);
+ void OnGuestContentWindowReady(int instance_id,
+ int content_window_routing_id);
+ void OnGuestGone(int instance_id);
+ void OnSetCursor(int instance_id, const WebCursor& cursor);
+ void OnSetMouseLock(int instance_id, bool enable);
+ void OnShouldAcceptTouchEvents(int instance_id, bool accept);
+ void OnUpdatedName(int instance_id, const std::string& name);
+ void OnUpdateRect(int instance_id,
+ const BrowserPluginMsg_UpdateRect_Params& params);
+
+ // This is the browser-process-allocated instance ID that uniquely identifies
+ // a guest WebContents.
+ int guest_instance_id_;
+ // This indicates whether this BrowserPlugin has been attached to a
+ // WebContents.
+ bool attached_;
+ base::WeakPtr<RenderViewImpl> render_view_;
+ // We cache the |render_view_|'s routing ID because we need it on destruction.
+ // If the |render_view_| is destroyed before the BrowserPlugin is destroyed
+ // then we will attempt to access a NULL pointer.
+ int render_view_routing_id_;
+ WebKit::WebPluginContainer* container_;
+ scoped_ptr<BrowserPluginBindings> bindings_;
+ scoped_ptr<BrowserPluginBackingStore> backing_store_;
+ scoped_ptr<base::SharedMemory> current_damage_buffer_;
+ scoped_ptr<base::SharedMemory> pending_damage_buffer_;
+ uint32 damage_buffer_sequence_id_;
+ bool resize_ack_received_;
+ gfx::Rect plugin_rect_;
+ float last_device_scale_factor_;
+ // Bitmap for crashed plugin. Lazily initialized, non-owning pointer.
+ SkBitmap* sad_guest_;
+ bool guest_crashed_;
+ scoped_ptr<BrowserPluginHostMsg_ResizeGuest_Params> pending_resize_params_;
+ bool auto_size_ack_pending_;
+ std::string storage_partition_id_;
+ bool persist_storage_;
+ bool valid_partition_id_;
+ int content_window_routing_id_;
+ bool plugin_focused_;
+ // Tracks the visibility of the browser plugin regardless of the whole
+ // embedder RenderView's visibility.
+ bool visible_;
+
+ WebCursor cursor_;
+
+ gfx::Size last_view_size_;
+ bool before_first_navigation_;
+ bool mouse_locked_;
+
+ typedef std::pair<int, base::WeakPtr<BrowserPlugin> > TrackedV8ObjectID;
+ std::map<int, TrackedV8ObjectID*> tracked_v8_objects_;
+
+ // BrowserPlugin outlives RenderViewImpl in Chrome Apps and so we need to
+ // store the BrowserPlugin's BrowserPluginManager in a member variable to
+ // avoid accessing the RenderViewImpl.
+ scoped_refptr<BrowserPluginManager> browser_plugin_manager_;
+
+ // Used for HW compositing.
+ bool compositing_enabled_;
+ scoped_refptr<BrowserPluginCompositingHelper> compositing_helper_;
+
+ // Used to identify the plugin to WebBindings.
+ scoped_ptr<struct _NPP> npp_;
+
+ // Weak factory used in v8 |MakeWeak| callback, since the v8 callback might
+ // get called after BrowserPlugin has been destroyed.
+ base::WeakPtrFactory<BrowserPlugin> weak_ptr_factory_;
+
+ std::vector<EditCommand> edit_commands_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserPlugin);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_H_
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_backing_store.cc b/chromium/content/renderer/browser_plugin/browser_plugin_backing_store.cc
new file mode 100644
index 00000000000..60e57067e5e
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_backing_store.cc
@@ -0,0 +1,99 @@
+// 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/gfx/rect_conversions.h"
+#include "ui/gfx/size_conversions.h"
+#include "ui/gfx/vector2d_conversions.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 = gfx::ToFlooredSize(gfx::ScaleSize(size, 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,
+ void* bitmap) {
+ if (bitmap_rect.IsEmpty())
+ return;
+
+ gfx::Rect pixel_bitmap_rect = gfx::ToFlooredRectDeprecated(
+ gfx::ScaleRect(bitmap_rect, 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 (!bitmap)
+ 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(bitmap);
+ for (size_t i = 0; i < copy_rects.size(); i++) {
+ const gfx::Rect& pixel_copy_rect = gfx::ToEnclosingRect(
+ gfx::ScaleRect(copy_rects[i], 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(
+ const gfx::Vector2d& delta,
+ const gfx::Rect& clip_rect,
+ const gfx::Size& view_size) {
+ gfx::Rect pixel_rect = gfx::ToEnclosingRect(
+ gfx::ScaleRect(clip_rect, scale_factor_));
+ gfx::Vector2d pixel_delta = gfx::ToFlooredVector2d(
+ gfx::ScaleVector2d(delta, scale_factor_));
+
+ int x = std::min(pixel_rect.x(), pixel_rect.x() - pixel_delta.x());
+ int y = std::min(pixel_rect.y(), pixel_rect.y() - pixel_delta.y());
+ int w = pixel_rect.width() + abs(pixel_delta.x());
+ int h = pixel_rect.height() + abs(pixel_delta.y());
+ SkIRect rect = SkIRect::MakeXYWH(x, y, w, h);
+ bitmap_.scrollRect(&rect, pixel_delta.x(), pixel_delta.y());
+}
+
+void BrowserPluginBackingStore::Clear(SkColor clear_color) {
+ canvas_->clear(clear_color);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_backing_store.h b/chromium/content/renderer/browser_plugin/browser_plugin_backing_store.h
new file mode 100644
index 00000000000..5b030321fc7
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_backing_store.h
@@ -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.
+
+#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"
+#include "ui/gfx/vector2d.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,
+ void* bitmap);
+
+ void ScrollBackingStore(const gfx::Vector2d& delta,
+ const gfx::Rect& clip_rect,
+ const gfx::Size& view_size);
+
+ void Clear(SkColor clear_color);
+
+ 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/chromium/content/renderer/browser_plugin/browser_plugin_bindings.cc b/chromium/content/renderer/browser_plugin/browser_plugin_bindings.cc
new file mode 100644
index 00000000000..26f00504e32
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_bindings.cc
@@ -0,0 +1,760 @@
+// 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/message_loop/message_loop.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/common/browser_plugin/browser_plugin_constants.h"
+#include "content/public/renderer/v8_value_converter.h"
+#include "content/renderer/browser_plugin/browser_plugin.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebDOMMessageEvent.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebNode.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "v8/include/v8.h"
+
+using WebKit::WebBindings;
+using WebKit::WebElement;
+using WebKit::WebDOMEvent;
+using WebKit::WebDOMMessageEvent;
+using WebKit::WebPluginContainer;
+using WebKit::WebString;
+
+namespace content {
+
+namespace {
+
+BrowserPluginBindings* GetBindings(NPObject* object) {
+ return static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(object)->
+ message_channel.get();
+}
+
+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);
+}
+
+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;
+}
+
+// Depending on where the attribute comes from it could be a string, int32,
+// or a double. Javascript tends to produce an int32 or a string, but setting
+// the value from the developer tools console may also produce a double.
+int IntFromNPVariant(const NPVariant& variant) {
+ int value = 0;
+ switch (variant.type) {
+ case NPVariantType_Double:
+ value = NPVARIANT_TO_DOUBLE(variant);
+ break;
+ case NPVariantType_Int32:
+ value = NPVARIANT_TO_INT32(variant);
+ break;
+ case NPVariantType_String:
+ base::StringToInt(StringFromNPVariant(variant), &value);
+ break;
+ default:
+ break;
+ }
+ return value;
+}
+
+//------------------------------------------------------------------------------
+// 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;
+
+ BrowserPluginBindings* bindings = GetBindings(np_obj);
+ if (!bindings)
+ return false;
+
+ return bindings->HasMethod(name);
+}
+
+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;
+
+ return bindings->InvokeMethod(name, args, arg_count, result);
+}
+
+bool BrowserPluginBindingsInvokeDefault(NPObject* np_obj,
+ const NPVariant* args,
+ uint32 arg_count,
+ NPVariant* result) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BrowserPluginBindingsHasProperty(NPObject* np_obj, NPIdentifier name) {
+ if (!np_obj)
+ return false;
+
+ BrowserPluginBindings* bindings = GetBindings(np_obj);
+ if (!bindings)
+ return false;
+
+ return bindings->HasProperty(name);
+}
+
+bool BrowserPluginBindingsGetProperty(NPObject* np_obj, NPIdentifier name,
+ NPVariant* result) {
+ if (!np_obj)
+ return false;
+
+ if (!result)
+ return false;
+
+ // All attributes from here on rely on the bindings, so retrieve it once and
+ // return on failure.
+ BrowserPluginBindings* bindings = GetBindings(np_obj);
+ if (!bindings)
+ return false;
+
+ return bindings->GetProperty(name, result);
+}
+
+bool BrowserPluginBindingsSetProperty(NPObject* np_obj, NPIdentifier name,
+ const NPVariant* variant) {
+ if (!np_obj)
+ return false;
+ if (!variant)
+ return false;
+
+ // All attributes from here on rely on the bindings, so retrieve it once and
+ // return on failure.
+ BrowserPluginBindings* bindings = GetBindings(np_obj);
+ if (!bindings)
+ return false;
+
+ if (variant->type == NPVariantType_Null)
+ return bindings->RemoveProperty(np_obj, name);
+
+ return bindings->SetProperty(np_obj, name, variant);
+}
+
+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
+
+// BrowserPluginMethodBinding --------------------------------------------------
+
+class BrowserPluginMethodBinding {
+ public:
+ BrowserPluginMethodBinding(const char name[], uint32 arg_count)
+ : name_(name),
+ arg_count_(arg_count) {
+ }
+
+ virtual ~BrowserPluginMethodBinding() {}
+
+ bool MatchesName(NPIdentifier name) const {
+ return WebBindings::getStringIdentifier(name_.c_str()) == name;
+ }
+
+ uint32 arg_count() const { return arg_count_; }
+
+ virtual bool Invoke(BrowserPluginBindings* bindings,
+ const NPVariant* args,
+ NPVariant* result) = 0;
+
+ private:
+ std::string name_;
+ uint32 arg_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginMethodBinding);
+};
+
+class BrowserPluginBindingAttach: public BrowserPluginMethodBinding {
+ public:
+ BrowserPluginBindingAttach()
+ : BrowserPluginMethodBinding(
+ browser_plugin::kMethodInternalAttach, 1) {
+ }
+
+ virtual bool Invoke(BrowserPluginBindings* bindings,
+ const NPVariant* args,
+ NPVariant* result) OVERRIDE {
+ if (!bindings->instance()->render_view())
+ return false;
+
+ scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
+ v8::Handle<v8::Value> obj(WebKit::WebBindings::toV8Value(&args[0]));
+ scoped_ptr<base::Value> value(
+ converter->FromV8Value(obj, bindings->instance()->render_view()->
+ GetWebView()->mainFrame()->mainWorldScriptContext()));
+ if (!value)
+ return false;
+
+ if (!value->IsType(Value::TYPE_DICTIONARY))
+ return false;
+
+ scoped_ptr<base::DictionaryValue> extra_params(
+ static_cast<base::DictionaryValue*>(value.release()));
+ bindings->instance()->Attach(extra_params.Pass());
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingAttach);
+};
+
+class BrowserPluginBindingAttachWindowTo : public BrowserPluginMethodBinding {
+ public:
+ BrowserPluginBindingAttachWindowTo()
+ : BrowserPluginMethodBinding(
+ browser_plugin::kMethodInternalAttachWindowTo, 2) {
+ }
+
+ virtual bool Invoke(BrowserPluginBindings* bindings,
+ const NPVariant* args,
+ NPVariant* result) OVERRIDE {
+ WebKit::WebNode node;
+ WebBindings::getNode(NPVARIANT_TO_OBJECT(args[0]), &node);
+ int window_id = IntFromNPVariant(args[1]);
+ BOOLEAN_TO_NPVARIANT(BrowserPlugin::AttachWindowTo(node, window_id),
+ *result);
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingAttachWindowTo);
+};
+
+// Note: This is a method that is used internally by the <webview> shim only.
+// This should not be exposed to developers.
+class BrowserPluginBindingTrackObjectLifetime
+ : public BrowserPluginMethodBinding {
+ public:
+ BrowserPluginBindingTrackObjectLifetime()
+ : BrowserPluginMethodBinding(
+ browser_plugin::kMethodInternalTrackObjectLifetime, 2) {
+ }
+
+ virtual bool Invoke(BrowserPluginBindings* bindings,
+ const NPVariant* args,
+ NPVariant* result) OVERRIDE {
+ bindings->instance()->TrackObjectLifetime(args, IntFromNPVariant(args[1]));
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingTrackObjectLifetime);
+};
+
+// BrowserPluginPropertyBinding ------------------------------------------------
+
+class BrowserPluginPropertyBinding {
+ public:
+ explicit BrowserPluginPropertyBinding(const char name[]) : name_(name) {}
+ virtual ~BrowserPluginPropertyBinding() {}
+ const std::string& name() const { return name_; }
+ bool MatchesName(NPIdentifier name) const {
+ return WebBindings::getStringIdentifier(name_.c_str()) == name;
+ }
+ virtual bool GetProperty(BrowserPluginBindings* bindings,
+ NPVariant* result) = 0;
+ virtual bool SetProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj,
+ const NPVariant* variant) = 0;
+ virtual void RemoveProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj) = 0;
+ // Updates the DOM Attribute value with the current property value.
+ void UpdateDOMAttribute(BrowserPluginBindings* bindings,
+ std::string new_value) {
+ bindings->instance()->UpdateDOMAttribute(name(), new_value);
+ }
+ private:
+ std::string name_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBinding);
+};
+
+class BrowserPluginPropertyBindingAutoSize
+ : public BrowserPluginPropertyBinding {
+ public:
+ BrowserPluginPropertyBindingAutoSize()
+ : BrowserPluginPropertyBinding(browser_plugin::kAttributeAutoSize) {
+ }
+ virtual bool GetProperty(BrowserPluginBindings* bindings,
+ NPVariant* result) OVERRIDE {
+ bool auto_size = bindings->instance()->GetAutoSizeAttribute();
+ BOOLEAN_TO_NPVARIANT(auto_size, *result);
+ return true;
+ }
+ virtual bool SetProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj,
+ const NPVariant* variant) OVERRIDE {
+ std::string value = StringFromNPVariant(*variant);
+ if (!bindings->instance()->HasDOMAttribute(name())) {
+ UpdateDOMAttribute(bindings, value);
+ bindings->instance()->ParseAutoSizeAttribute();
+ } else {
+ UpdateDOMAttribute(bindings, value);
+ }
+ return true;
+ }
+ virtual void RemoveProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj) OVERRIDE {
+ bindings->instance()->RemoveDOMAttribute(name());
+ bindings->instance()->ParseAutoSizeAttribute();
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingAutoSize);
+};
+
+class BrowserPluginPropertyBindingContentWindow
+ : public BrowserPluginPropertyBinding {
+ public:
+ BrowserPluginPropertyBindingContentWindow()
+ : BrowserPluginPropertyBinding(browser_plugin::kAttributeContentWindow) {
+ }
+ virtual bool GetProperty(BrowserPluginBindings* bindings,
+ NPVariant* result) OVERRIDE {
+ NPObject* obj = bindings->instance()->GetContentWindow();
+ if (obj) {
+ result->type = NPVariantType_Object;
+ result->value.objectValue = WebBindings::retainObject(obj);
+ }
+ return true;
+ }
+ virtual bool SetProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj,
+ const NPVariant* variant) OVERRIDE {
+ return false;
+ }
+ virtual void RemoveProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj) OVERRIDE {}
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingContentWindow);
+};
+
+class BrowserPluginPropertyBindingMaxHeight
+ : public BrowserPluginPropertyBinding {
+ public:
+ BrowserPluginPropertyBindingMaxHeight()
+ : BrowserPluginPropertyBinding(browser_plugin::kAttributeMaxHeight) {
+ }
+ virtual bool GetProperty(BrowserPluginBindings* bindings,
+ NPVariant* result) OVERRIDE {
+ int max_height = bindings->instance()->GetMaxHeightAttribute();
+ INT32_TO_NPVARIANT(max_height, *result);
+ return true;
+ }
+ virtual bool SetProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj,
+ const NPVariant* variant) OVERRIDE {
+ int new_value = IntFromNPVariant(*variant);
+ if (bindings->instance()->GetMaxHeightAttribute() != new_value) {
+ UpdateDOMAttribute(bindings, base::IntToString(new_value));
+ bindings->instance()->ParseSizeContraintsChanged();
+ }
+ return true;
+ }
+ virtual void RemoveProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj) OVERRIDE {
+ bindings->instance()->RemoveDOMAttribute(name());
+ bindings->instance()->ParseSizeContraintsChanged();
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMaxHeight);
+};
+
+class BrowserPluginPropertyBindingMaxWidth
+ : public BrowserPluginPropertyBinding {
+ public:
+ BrowserPluginPropertyBindingMaxWidth()
+ : BrowserPluginPropertyBinding(browser_plugin::kAttributeMaxWidth) {
+ }
+ virtual bool GetProperty(BrowserPluginBindings* bindings,
+ NPVariant* result) OVERRIDE {
+ int max_width = bindings->instance()->GetMaxWidthAttribute();
+ INT32_TO_NPVARIANT(max_width, *result);
+ return true;
+ }
+ virtual bool SetProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj,
+ const NPVariant* variant) OVERRIDE {
+ int new_value = IntFromNPVariant(*variant);
+ if (bindings->instance()->GetMaxWidthAttribute() != new_value) {
+ UpdateDOMAttribute(bindings, base::IntToString(new_value));
+ bindings->instance()->ParseSizeContraintsChanged();
+ }
+ return true;
+ }
+ virtual void RemoveProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj) OVERRIDE {
+ bindings->instance()->RemoveDOMAttribute(name());
+ bindings->instance()->ParseSizeContraintsChanged();
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMaxWidth);
+};
+
+class BrowserPluginPropertyBindingMinHeight
+ : public BrowserPluginPropertyBinding {
+ public:
+ BrowserPluginPropertyBindingMinHeight()
+ : BrowserPluginPropertyBinding(browser_plugin::kAttributeMinHeight) {
+ }
+ virtual bool GetProperty(BrowserPluginBindings* bindings,
+ NPVariant* result) OVERRIDE {
+ int min_height = bindings->instance()->GetMinHeightAttribute();
+ INT32_TO_NPVARIANT(min_height, *result);
+ return true;
+ }
+ virtual bool SetProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj,
+ const NPVariant* variant) OVERRIDE {
+ int new_value = IntFromNPVariant(*variant);
+ if (bindings->instance()->GetMinHeightAttribute() != new_value) {
+ UpdateDOMAttribute(bindings, base::IntToString(new_value));
+ bindings->instance()->ParseSizeContraintsChanged();
+ }
+ return true;
+ }
+ virtual void RemoveProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj) OVERRIDE {
+ bindings->instance()->RemoveDOMAttribute(name());
+ bindings->instance()->ParseSizeContraintsChanged();
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMinHeight);
+};
+
+class BrowserPluginPropertyBindingMinWidth
+ : public BrowserPluginPropertyBinding {
+ public:
+ BrowserPluginPropertyBindingMinWidth()
+ : BrowserPluginPropertyBinding(browser_plugin::kAttributeMinWidth) {
+ }
+ virtual bool GetProperty(BrowserPluginBindings* bindings,
+ NPVariant* result) OVERRIDE {
+ int min_width = bindings->instance()->GetMinWidthAttribute();
+ INT32_TO_NPVARIANT(min_width, *result);
+ return true;
+ }
+ virtual bool SetProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj,
+ const NPVariant* variant) OVERRIDE {
+ int new_value = IntFromNPVariant(*variant);
+ if (bindings->instance()->GetMinWidthAttribute() != new_value) {
+ UpdateDOMAttribute(bindings, base::IntToString(new_value));
+ bindings->instance()->ParseSizeContraintsChanged();
+ }
+ return true;
+ }
+ virtual void RemoveProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj) OVERRIDE {
+ bindings->instance()->RemoveDOMAttribute(name());
+ bindings->instance()->ParseSizeContraintsChanged();
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingMinWidth);
+};
+
+class BrowserPluginPropertyBindingName
+ : public BrowserPluginPropertyBinding {
+ public:
+ BrowserPluginPropertyBindingName()
+ : BrowserPluginPropertyBinding(browser_plugin::kAttributeName) {
+ }
+ virtual bool GetProperty(BrowserPluginBindings* bindings,
+ NPVariant* result) OVERRIDE {
+ std::string name = bindings->instance()->GetNameAttribute();
+ return StringToNPVariant(name, result);
+ }
+ virtual bool SetProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj,
+ const NPVariant* variant) OVERRIDE {
+ std::string new_value = StringFromNPVariant(*variant);
+ if (bindings->instance()->GetNameAttribute() != new_value) {
+ UpdateDOMAttribute(bindings, new_value);
+ bindings->instance()->ParseNameAttribute();
+ }
+ return true;
+ }
+ virtual void RemoveProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj) OVERRIDE {
+ bindings->instance()->RemoveDOMAttribute(name());
+ bindings->instance()->ParseNameAttribute();
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingName);
+};
+
+class BrowserPluginPropertyBindingPartition
+ : public BrowserPluginPropertyBinding {
+ public:
+ BrowserPluginPropertyBindingPartition()
+ : BrowserPluginPropertyBinding(browser_plugin::kAttributePartition) {
+ }
+ virtual bool GetProperty(BrowserPluginBindings* bindings,
+ NPVariant* result) OVERRIDE {
+ std::string partition_id = bindings->instance()->GetPartitionAttribute();
+ return StringToNPVariant(partition_id, result);
+ }
+ virtual bool SetProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj,
+ const NPVariant* variant) OVERRIDE {
+ std::string new_value = StringFromNPVariant(*variant);
+ std::string old_value = bindings->instance()->GetPartitionAttribute();
+ if (old_value != new_value) {
+ UpdateDOMAttribute(bindings, new_value);
+ std::string error_message;
+ if (!bindings->instance()->ParsePartitionAttribute(&error_message)) {
+ // Reset to old value on error.
+ UpdateDOMAttribute(bindings, old_value);
+ // Exceptions must be set as the last operation before returning to
+ // script.
+ WebBindings::setException(
+ np_obj, static_cast<const NPUTF8 *>(error_message.c_str()));
+ return false;
+ }
+ }
+ return true;
+ }
+ virtual void RemoveProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj) OVERRIDE {
+ std::string error_message;
+ if (bindings->instance()->CanRemovePartitionAttribute(&error_message)) {
+ bindings->instance()->RemoveDOMAttribute(name());
+ } else {
+ WebBindings::setException(
+ np_obj, static_cast<const NPUTF8 *>(error_message.c_str()));
+ }
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingPartition);
+};
+
+class BrowserPluginPropertyBindingSrc : public BrowserPluginPropertyBinding {
+ public:
+ BrowserPluginPropertyBindingSrc()
+ : BrowserPluginPropertyBinding(browser_plugin::kAttributeSrc) {
+ }
+ virtual bool GetProperty(BrowserPluginBindings* bindings,
+ NPVariant* result) OVERRIDE {
+ std::string src = bindings->instance()->GetSrcAttribute();
+ return StringToNPVariant(src, result);
+ }
+ virtual bool SetProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj,
+ const NPVariant* variant) OVERRIDE {
+ std::string new_value = StringFromNPVariant(*variant);
+ // We should not be issuing navigation IPCs if we attempt to set the
+ // src property to the empty string. Instead, we want to simply restore
+ // the src attribute back to its old value.
+ if (new_value.empty()) {
+ RemoveProperty(bindings, np_obj);
+ return true;
+ }
+ std::string old_value = bindings->instance()->GetSrcAttribute();
+ bool guest_crashed = bindings->instance()->guest_crashed();
+ if ((old_value != new_value) || guest_crashed) {
+ // If the new value was empty then we're effectively resetting the
+ // attribute to the old value here. This will be picked up by <webview>'s
+ // mutation observer and will restore the src attribute after it has been
+ // removed.
+ UpdateDOMAttribute(bindings, new_value);
+ std::string error_message;
+ if (!bindings->instance()->ParseSrcAttribute(&error_message)) {
+ // Reset to old value on error.
+ UpdateDOMAttribute(bindings, old_value);
+ // Exceptions must be set as the last operation before returning to
+ // script.
+ WebBindings::setException(
+ np_obj, static_cast<const NPUTF8 *>(error_message.c_str()));
+ return false;
+ }
+ }
+ return true;
+ }
+ virtual void RemoveProperty(BrowserPluginBindings* bindings,
+ NPObject* np_obj) OVERRIDE {
+ std::string old_value = bindings->instance()->GetSrcAttribute();
+ if (old_value.empty())
+ return;
+ // Remove the DOM attribute to trigger the mutation observer when it is
+ // restored to its original value again.
+ bindings->instance()->RemoveDOMAttribute(name());
+ UpdateDOMAttribute(bindings, old_value);
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginPropertyBindingSrc);
+};
+
+
+// BrowserPluginBindings ------------------------------------------------------
+
+BrowserPluginBindings::BrowserPluginNPObject::BrowserPluginNPObject() {
+}
+
+BrowserPluginBindings::BrowserPluginNPObject::~BrowserPluginNPObject() {
+}
+
+BrowserPluginBindings::BrowserPluginBindings(BrowserPlugin* instance)
+ : instance_(instance),
+ np_object_(NULL),
+ weak_ptr_factory_(this) {
+ NPObject* obj =
+ WebBindings::createObject(instance->pluginNPP(),
+ &browser_plugin_message_class);
+ np_object_ = static_cast<BrowserPluginBindings::BrowserPluginNPObject*>(obj);
+ np_object_->message_channel = weak_ptr_factory_.GetWeakPtr();
+
+ method_bindings_.push_back(new BrowserPluginBindingAttach);
+ method_bindings_.push_back(new BrowserPluginBindingAttachWindowTo);
+ method_bindings_.push_back(new BrowserPluginBindingTrackObjectLifetime);
+
+ property_bindings_.push_back(new BrowserPluginPropertyBindingAutoSize);
+ property_bindings_.push_back(new BrowserPluginPropertyBindingContentWindow);
+ property_bindings_.push_back(new BrowserPluginPropertyBindingMaxHeight);
+ property_bindings_.push_back(new BrowserPluginPropertyBindingMaxWidth);
+ property_bindings_.push_back(new BrowserPluginPropertyBindingMinHeight);
+ property_bindings_.push_back(new BrowserPluginPropertyBindingMinWidth);
+ property_bindings_.push_back(new BrowserPluginPropertyBindingName);
+ property_bindings_.push_back(new BrowserPluginPropertyBindingPartition);
+ property_bindings_.push_back(new BrowserPluginPropertyBindingSrc);
+}
+
+BrowserPluginBindings::~BrowserPluginBindings() {
+ WebBindings::releaseObject(np_object_);
+}
+
+bool BrowserPluginBindings::HasMethod(NPIdentifier name) const {
+ for (BindingList::const_iterator iter = method_bindings_.begin();
+ iter != method_bindings_.end();
+ ++iter) {
+ if ((*iter)->MatchesName(name))
+ return true;
+ }
+ return false;
+}
+
+bool BrowserPluginBindings::InvokeMethod(NPIdentifier name,
+ const NPVariant* args,
+ uint32 arg_count,
+ NPVariant* result) {
+ for (BindingList::iterator iter = method_bindings_.begin();
+ iter != method_bindings_.end();
+ ++iter) {
+ if ((*iter)->MatchesName(name) && (*iter)->arg_count() == arg_count)
+ return (*iter)->Invoke(this, args, result);
+ }
+ return false;
+}
+
+bool BrowserPluginBindings::HasProperty(NPIdentifier name) const {
+ for (PropertyBindingList::const_iterator iter = property_bindings_.begin();
+ iter != property_bindings_.end();
+ ++iter) {
+ if ((*iter)->MatchesName(name))
+ return true;
+ }
+ return false;
+}
+
+bool BrowserPluginBindings::SetProperty(NPObject* np_obj,
+ NPIdentifier name,
+ const NPVariant* variant) {
+ for (PropertyBindingList::iterator iter = property_bindings_.begin();
+ iter != property_bindings_.end();
+ ++iter) {
+ if ((*iter)->MatchesName(name)) {
+ if ((*iter)->SetProperty(this, np_obj, variant)) {
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+bool BrowserPluginBindings::RemoveProperty(NPObject* np_obj,
+ NPIdentifier name) {
+ for (PropertyBindingList::iterator iter = property_bindings_.begin();
+ iter != property_bindings_.end();
+ ++iter) {
+ if ((*iter)->MatchesName(name)) {
+ (*iter)->RemoveProperty(this, np_obj);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BrowserPluginBindings::GetProperty(NPIdentifier name, NPVariant* result) {
+ for (PropertyBindingList::iterator iter = property_bindings_.begin();
+ iter != property_bindings_.end();
+ ++iter) {
+ if ((*iter)->MatchesName(name))
+ return (*iter)->GetProperty(this, result);
+ }
+ return false;
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_bindings.h b/chromium/content/renderer/browser_plugin/browser_plugin_bindings.h
new file mode 100644
index 00000000000..91e8ced8439
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_bindings.h
@@ -0,0 +1,71 @@
+// 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/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "ppapi/shared_impl/resource.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+namespace content {
+
+class BrowserPlugin;
+class BrowserPluginMethodBinding;
+class BrowserPluginPropertyBinding;
+
+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_; }
+
+ bool HasMethod(NPIdentifier name) const;
+
+ bool InvokeMethod(NPIdentifier name,
+ const NPVariant* args,
+ uint32 arg_count,
+ NPVariant* result);
+
+ bool HasProperty(NPIdentifier name) const;
+ bool SetProperty(NPObject* np_obj,
+ NPIdentifier name,
+ const NPVariant* variant);
+ bool GetProperty(NPIdentifier name, NPVariant* result);
+ bool RemoveProperty(NPObject *np_obj, NPIdentifier name);
+ private:
+ BrowserPlugin* instance_;
+ // The NPObject we use to expose postMessage to JavaScript.
+ BrowserPluginNPObject* np_object_;
+
+ typedef ScopedVector<BrowserPluginMethodBinding> BindingList;
+ BindingList method_bindings_;
+ typedef ScopedVector<BrowserPluginPropertyBinding> PropertyBindingList;
+ PropertyBindingList property_bindings_;
+
+ // 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/chromium/content/renderer/browser_plugin/browser_plugin_browsertest.cc b/chromium/content/renderer/browser_plugin/browser_plugin_browsertest.cc
new file mode 100644
index 00000000000..693752c618a
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_browsertest.cc
@@ -0,0 +1,632 @@
+// 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/files/file_path.h"
+#include "base/memory/singleton.h"
+#include "base/path_service.h"
+#include "base/pickle.h"
+#include "content/public/common/content_constants.h"
+#include "content/renderer/browser_plugin/browser_plugin.h"
+#include "content/renderer/browser_plugin/browser_plugin_manager_factory.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/public/web/WebCursorInfo.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebScriptSource.h"
+
+namespace {
+const char kHTMLForBrowserPluginObject[] =
+ "<object id='browserplugin' width='640px' height='480px'"
+ " src='foo' type='%s'>";
+
+const char kHTMLForBrowserPluginWithAllAttributes[] =
+ "<object id='browserplugin' width='640' height='480' type='%s'"
+ " autosize maxheight='600' maxwidth='800' minheight='240'"
+ " minwidth='320' name='Jim' partition='someid' src='foo'>";
+
+const char kHTMLForSourcelessPluginObject[] =
+ "<object id='browserplugin' width='640px' height='480px' type='%s'>";
+
+const char kHTMLForPartitionedPluginObject[] =
+ "<object id='browserplugin' width='640px' height='480px'"
+ " src='foo' type='%s' partition='someid'>";
+
+const char kHTMLForInvalidPartitionedPluginObject[] =
+ "<object id='browserplugin' width='640px' height='480px'"
+ " type='%s' partition='persist:'>";
+
+const char kHTMLForPartitionedPersistedPluginObject[] =
+ "<object id='browserplugin' width='640px' height='480px'"
+ " src='foo' type='%s' partition='persist:someid'>";
+
+std::string GetHTMLForBrowserPluginObject() {
+ return base::StringPrintf(kHTMLForBrowserPluginObject,
+ content::kBrowserPluginMimeType);
+}
+
+} // namespace
+
+namespace content {
+
+class TestContentRendererClient : public ContentRendererClient {
+ public:
+ TestContentRendererClient() : ContentRendererClient() {
+ }
+ virtual ~TestContentRendererClient() {
+ }
+ virtual bool AllowBrowserPlugin(
+ WebKit::WebPluginContainer* container) OVERRIDE {
+ // Allow BrowserPlugin for tests.
+ return true;
+ }
+};
+
+// Test factory for creating test instances of BrowserPluginManager.
+class TestBrowserPluginManagerFactory : public BrowserPluginManagerFactory {
+ public:
+ virtual MockBrowserPluginManager* CreateBrowserPluginManager(
+ RenderViewImpl* render_view) OVERRIDE {
+ return new MockBrowserPluginManager(render_view);
+ }
+
+ // Singleton getter.
+ static TestBrowserPluginManagerFactory* GetInstance() {
+ return Singleton<TestBrowserPluginManagerFactory>::get();
+ }
+
+ protected:
+ TestBrowserPluginManagerFactory() {}
+ virtual ~TestBrowserPluginManagerFactory() {}
+
+ private:
+ // For Singleton.
+ friend struct DefaultSingletonTraits<TestBrowserPluginManagerFactory>;
+
+ DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginManagerFactory);
+};
+
+BrowserPluginTest::BrowserPluginTest() {}
+
+BrowserPluginTest::~BrowserPluginTest() {}
+
+void BrowserPluginTest::SetUp() {
+ test_content_renderer_client_.reset(new TestContentRendererClient);
+ SetRendererClientForTesting(test_content_renderer_client_.get());
+ BrowserPluginManager::set_factory_for_testing(
+ TestBrowserPluginManagerFactory::GetInstance());
+ content::RenderViewTest::SetUp();
+}
+
+void BrowserPluginTest::TearDown() {
+ BrowserPluginManager::set_factory_for_testing(
+ TestBrowserPluginManagerFactory::GetInstance());
+ content::RenderViewTest::TearDown();
+ test_content_renderer_client_.reset();
+}
+
+std::string BrowserPluginTest::ExecuteScriptAndReturnString(
+ const std::string& script) {
+ v8::HandleScope handle_scope;
+ 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_ptr<char[]> str(new char[length]);
+ v8_str->WriteUtf8(str.get(), length);
+ return str.get();
+}
+
+int BrowserPluginTest::ExecuteScriptAndReturnInt(
+ const std::string& script) {
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
+ WebKit::WebScriptSource(WebKit::WebString::fromUTF8(script.c_str())));
+ if (value.IsEmpty() || !value->IsInt32())
+ return 0;
+
+ return value->Int32Value();
+}
+
+// A return value of false means that a value was not present. The return value
+// of the script is stored in |result|
+bool BrowserPluginTest::ExecuteScriptAndReturnBool(
+ const std::string& script, bool* result) {
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
+ WebKit::WebScriptSource(WebKit::WebString::fromUTF8(script.c_str())));
+ if (value.IsEmpty() || !value->IsBoolean())
+ return false;
+
+ *result = value->BooleanValue();
+ return true;
+}
+
+MockBrowserPlugin* BrowserPluginTest::GetCurrentPlugin() {
+ BrowserPluginHostMsg_Attach_Params params;
+ return GetCurrentPluginWithAttachParams(&params);
+}
+
+MockBrowserPlugin* BrowserPluginTest::GetCurrentPluginWithAttachParams(
+ BrowserPluginHostMsg_Attach_Params* params) {
+ int instance_id = 0;
+ const IPC::Message* msg =
+ browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_Attach::ID);
+ if (!msg)
+ return NULL;
+
+ PickleIterator iter(*msg);
+ if (!iter.ReadInt(&instance_id))
+ return NULL;
+
+ if (!IPC::ParamTraits<BrowserPluginHostMsg_Attach_Params>::Read(
+ msg, &iter, params))
+ return NULL;
+
+ MockBrowserPlugin* browser_plugin = static_cast<MockBrowserPlugin*>(
+ browser_plugin_manager()->GetBrowserPlugin(instance_id));
+
+ BrowserPluginMsg_Attach_ACK_Params attach_ack_params;
+ browser_plugin->OnAttachACK(instance_id, attach_ack_params);
+
+ return browser_plugin;
+}
+
+// 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 |pending_damage_buffer_| 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 in Attach is correct.
+ BrowserPluginHostMsg_Attach_Params params;
+ MockBrowserPlugin* browser_plugin = GetCurrentPluginWithAttachParams(&params);
+
+ EXPECT_EQ(640, params.resize_guest_params.view_rect.width());
+ EXPECT_EQ(480, params.resize_guest_params.view_rect.height());
+ ASSERT_TRUE(browser_plugin);
+ // Now the browser plugin is expecting a UpdateRect resize.
+ int instance_id = browser_plugin->guest_instance_id();
+ EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
+
+ // Send the BrowserPlugin an UpdateRect equal to its container size with
+ // the same damage buffer. That should clear |pending_damage_buffer_|.
+ BrowserPluginMsg_UpdateRect_Params update_rect_params;
+ update_rect_params.damage_buffer_sequence_id =
+ browser_plugin->damage_buffer_sequence_id_;
+ update_rect_params.view_size = gfx::Size(640, 480);
+ update_rect_params.scale_factor = 1.0f;
+ update_rect_params.is_resize_ack = true;
+ update_rect_params.needs_ack = true;
+ BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
+ browser_plugin->OnMessageReceived(msg);
+ EXPECT_FALSE(browser_plugin->pending_damage_buffer_.get());
+}
+
+// This test verifies that all attributes (present at the time of writing) are
+// parsed on initialization. However, this test does minimal checking of
+// correct behavior.
+TEST_F(BrowserPluginTest, ParseAllAttributes) {
+ std::string html = base::StringPrintf(kHTMLForBrowserPluginWithAllAttributes,
+ content::kBrowserPluginMimeType);
+ LoadHTML(html.c_str());
+ bool result;
+ bool has_value = ExecuteScriptAndReturnBool(
+ "document.getElementById('browserplugin').autosize", &result);
+ EXPECT_TRUE(has_value);
+ EXPECT_TRUE(result);
+ int maxHeight = ExecuteScriptAndReturnInt(
+ "document.getElementById('browserplugin').maxheight");
+ EXPECT_EQ(600, maxHeight);
+ int maxWidth = ExecuteScriptAndReturnInt(
+ "document.getElementById('browserplugin').maxwidth");
+ EXPECT_EQ(800, maxWidth);
+ int minHeight = ExecuteScriptAndReturnInt(
+ "document.getElementById('browserplugin').minheight");
+ EXPECT_EQ(240, minHeight);
+ int minWidth = ExecuteScriptAndReturnInt(
+ "document.getElementById('browserplugin').minwidth");
+ EXPECT_EQ(320, minWidth);
+ std::string name = ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').name");
+ EXPECT_STREQ("Jim", name.c_str());
+ std::string partition = ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').partition");
+ EXPECT_STREQ("someid", partition.c_str());
+ std::string src = ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').src");
+ EXPECT_STREQ("foo", src.c_str());
+}
+
+// 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.
+ {
+ BrowserPluginHostMsg_Attach_Params params;
+ MockBrowserPlugin* browser_plugin =
+ GetCurrentPluginWithAttachParams(&params);
+ ASSERT_TRUE(browser_plugin);
+ EXPECT_EQ("foo", params.src);
+ }
+
+ browser_plugin_manager()->sink().ClearMessages();
+ // Navigate to bar and observe the associated
+ // BrowserPluginHostMsg_NavigateGuest message.
+ // Verify that the src attribute is updated as well.
+ ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
+ {
+ // Verify that we do not get a Attach on subsequent navigations.
+ const IPC::Message* create_msg =
+ browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_Attach::ID);
+ ASSERT_FALSE(create_msg);
+
+ const IPC::Message* msg =
+ browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_NavigateGuest::ID);
+ ASSERT_TRUE(msg);
+
+ int instance_id = 0;
+ std::string src;
+ BrowserPluginHostMsg_NavigateGuest::Read(msg, &instance_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());
+ MockBrowserPlugin* browser_plugin = GetCurrentPlugin();
+ ASSERT_TRUE(browser_plugin);
+ int instance_id = browser_plugin->guest_instance_id();
+ EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
+ // Send an UpdateRect to the BrowserPlugin to make it use the pending damage
+ // buffer.
+ {
+ // 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;
+ update_rect_params.needs_ack = true;
+ // By sending |damage_buffer_sequence_id| back to BrowserPlugin on
+ // UpdateRect, then the BrowserPlugin knows that the browser process has
+ // received and has begun to use the |pending_damage_buffer_|.
+ update_rect_params.damage_buffer_sequence_id =
+ browser_plugin->damage_buffer_sequence_id_;
+ BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
+ browser_plugin->OnMessageReceived(msg);
+ EXPECT_EQ(NULL, browser_plugin->pending_damage_buffer_.get());
+ }
+
+ 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 one resize messsage in the sink. BrowserPlugin will not issue
+ // subsequent resize requests until the first request is satisfied by the
+ // guest. The rest of the messages could be
+ // BrowserPluginHostMsg_UpdateGeometry msgs.
+ EXPECT_LE(1u, browser_plugin_manager()->sink().message_count());
+ for (size_t i = 0; i < browser_plugin_manager()->sink().message_count();
+ ++i) {
+ const IPC::Message* msg = browser_plugin_manager()->sink().GetMessageAt(i);
+ if (msg->type() != BrowserPluginHostMsg_ResizeGuest::ID)
+ EXPECT_EQ(msg->type(), BrowserPluginHostMsg_UpdateGeometry::ID);
+ }
+ const IPC::Message* msg =
+ browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_ResizeGuest::ID);
+ ASSERT_TRUE(msg);
+ BrowserPluginHostMsg_ResizeGuest_Params params;
+ BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, &params);
+ EXPECT_EQ(641, params.view_rect.width());
+ EXPECT_EQ(480, params.view_rect.height());
+ // This indicates that the BrowserPlugin has sent out a previous resize
+ // request but has not yet received an UpdateRect for that request.
+ EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
+
+ {
+ // We send a stale UpdateRect to the BrowserPlugin.
+ BrowserPluginMsg_UpdateRect_Params update_rect_params;
+ update_rect_params.view_size = gfx::Size(641, 480);
+ update_rect_params.scale_factor = 1.0f;
+ update_rect_params.is_resize_ack = true;
+ update_rect_params.needs_ack = true;
+ update_rect_params.damage_buffer_sequence_id =
+ browser_plugin->damage_buffer_sequence_id_;
+ BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
+ browser_plugin->OnMessageReceived(msg);
+ // This tells us that the BrowserPlugin is still expecting another
+ // UpdateRect with the most recent size.
+ EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
+ }
+ // Send the BrowserPlugin another UpdateRect, but this time with a size
+ // that matches the size of the container.
+ {
+ 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;
+ update_rect_params.needs_ack = true;
+ update_rect_params.damage_buffer_sequence_id =
+ browser_plugin->damage_buffer_sequence_id_;
+ BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
+ browser_plugin->OnMessageReceived(msg);
+ // The BrowserPlugin has finally received an UpdateRect that satisifes
+ // its current size, and so it is happy.
+ EXPECT_FALSE(browser_plugin->pending_damage_buffer_.get());
+ }
+}
+
+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));
+}
+
+// This test verifies that PluginDestroyed messages do not get sent from a
+// BrowserPlugin that has never navigated.
+TEST_F(BrowserPluginTest, RemovePluginBeforeNavigation) {
+ std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
+ content::kBrowserPluginMimeType);
+ LoadHTML(html.c_str());
+ EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_PluginDestroyed::ID));
+ ExecuteJavaScript("x = document.getElementById('browserplugin'); "
+ "x.parentNode.removeChild(x);");
+ ProcessPendingMessages();
+ EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_PluginDestroyed::ID));
+}
+
+// Verify that the 'partition' attribute on the browser plugin is parsed
+// correctly.
+TEST_F(BrowserPluginTest, PartitionAttribute) {
+ std::string html = base::StringPrintf(kHTMLForPartitionedPluginObject,
+ content::kBrowserPluginMimeType);
+ LoadHTML(html.c_str());
+ std::string partition_value = ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').partition");
+ EXPECT_STREQ("someid", partition_value.c_str());
+
+ html = base::StringPrintf(kHTMLForPartitionedPersistedPluginObject,
+ content::kBrowserPluginMimeType);
+ LoadHTML(html.c_str());
+ partition_value = ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').partition");
+ EXPECT_STREQ("persist:someid", partition_value.c_str());
+
+ // Verify that once HTML has defined a source and partition, we cannot change
+ // the partition anymore.
+ ExecuteJavaScript(
+ "try {"
+ " document.getElementById('browserplugin').partition = 'foo';"
+ " document.title = 'success';"
+ "} catch (e) { document.title = e.message; }");
+ std::string title = ExecuteScriptAndReturnString("document.title");
+ EXPECT_STREQ(
+ "The object has already navigated, so its partition cannot be changed.",
+ title.c_str());
+
+ // Load a browser tag without 'src' defined.
+ html = base::StringPrintf(kHTMLForSourcelessPluginObject,
+ content::kBrowserPluginMimeType);
+ LoadHTML(html.c_str());
+
+ // Ensure we don't parse just "persist:" string and return exception.
+ ExecuteJavaScript(
+ "try {"
+ " document.getElementById('browserplugin').partition = 'persist:';"
+ " document.title = 'success';"
+ "} catch (e) { document.title = e.message; }");
+ title = ExecuteScriptAndReturnString("document.title");
+ EXPECT_STREQ("Invalid partition attribute.", title.c_str());
+}
+
+// This test verifies that BrowserPlugin enters an error state when the
+// partition attribute is invalid.
+TEST_F(BrowserPluginTest, InvalidPartition) {
+ std::string html = base::StringPrintf(kHTMLForInvalidPartitionedPluginObject,
+ content::kBrowserPluginMimeType);
+ LoadHTML(html.c_str());
+ // Attempt to navigate with an invalid partition.
+ {
+ ExecuteJavaScript(
+ "try {"
+ " document.getElementById('browserplugin').src = 'bar';"
+ " document.title = 'success';"
+ "} catch (e) { document.title = e.message; }");
+ std::string title = ExecuteScriptAndReturnString("document.title");
+ EXPECT_STREQ("Invalid partition attribute.", title.c_str());
+ // Verify that the 'src' attribute has not been updated.
+ EXPECT_EQ("", ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').src"));
+ }
+
+ // Verify that the BrowserPlugin accepts changes to its src attribue after
+ // setting the partition to a valid value.
+ ExecuteJavaScript(
+ "document.getElementById('browserplugin').partition = 'persist:foo'");
+ ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
+ EXPECT_EQ("bar", ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').src"));
+ ProcessPendingMessages();
+ // Verify that the BrowserPlugin does not 'deadlock': it can recover from
+ // the partition ID error state.
+ {
+ ExecuteJavaScript(
+ "try {"
+ " document.getElementById('browserplugin').partition = 'persist:1337';"
+ " document.title = 'success';"
+ "} catch (e) { document.title = e.message; }");
+ std::string title = ExecuteScriptAndReturnString("document.title");
+ EXPECT_STREQ(
+ "The object has already navigated, so its partition cannot be changed.",
+ title.c_str());
+ ExecuteJavaScript("document.getElementById('browserplugin').src = '42'");
+ EXPECT_EQ("42", ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').src"));
+ }
+}
+
+// Test to verify that after the first navigation, the partition attribute
+// cannot be modified.
+TEST_F(BrowserPluginTest, ImmutableAttributesAfterNavigation) {
+ std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
+ content::kBrowserPluginMimeType);
+ LoadHTML(html.c_str());
+
+ ExecuteJavaScript(
+ "document.getElementById('browserplugin').partition = 'storage'");
+ std::string partition_value = ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').partition");
+ EXPECT_STREQ("storage", partition_value.c_str());
+
+ std::string src_value = ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').src");
+ EXPECT_STREQ("", src_value.c_str());
+
+ ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
+ ProcessPendingMessages();
+ {
+ BrowserPluginHostMsg_Attach_Params params;
+ MockBrowserPlugin* browser_plugin =
+ GetCurrentPluginWithAttachParams(&params);
+ ASSERT_TRUE(browser_plugin);
+
+ EXPECT_STREQ("storage", params.storage_partition_id.c_str());
+ EXPECT_FALSE(params.persist_storage);
+ EXPECT_STREQ("bar", params.src.c_str());
+ }
+
+ // Setting the partition should throw an exception and the value should not
+ // change.
+ ExecuteJavaScript(
+ "try {"
+ " document.getElementById('browserplugin').partition = 'someid';"
+ " document.title = 'success';"
+ "} catch (e) { document.title = e.message; }");
+
+ std::string title = ExecuteScriptAndReturnString("document.title");
+ EXPECT_STREQ(
+ "The object has already navigated, so its partition cannot be changed.",
+ title.c_str());
+
+ partition_value = ExecuteScriptAndReturnString(
+ "document.getElementById('browserplugin').partition");
+ EXPECT_STREQ("storage", partition_value.c_str());
+}
+
+TEST_F(BrowserPluginTest, AutoSizeAttributes) {
+ std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
+ content::kBrowserPluginMimeType);
+ LoadHTML(html.c_str());
+ const char* kSetAutoSizeParametersAndNavigate =
+ "var browserplugin = document.getElementById('browserplugin');"
+ "browserplugin.autosize = true;"
+ "browserplugin.minwidth = 42;"
+ "browserplugin.minheight = 43;"
+ "browserplugin.maxwidth = 1337;"
+ "browserplugin.maxheight = 1338;"
+ "browserplugin.src = 'foobar';";
+ const char* kDisableAutoSize =
+ "document.getElementById('browserplugin').removeAttribute('autosize');";
+
+ int instance_id = 0;
+ // Set some autosize parameters before navigating then navigate.
+ // Verify that the BrowserPluginHostMsg_Attach message contains
+ // the correct autosize parameters.
+ ExecuteJavaScript(kSetAutoSizeParametersAndNavigate);
+ ProcessPendingMessages();
+
+ BrowserPluginHostMsg_Attach_Params params;
+ MockBrowserPlugin* browser_plugin =
+ GetCurrentPluginWithAttachParams(&params);
+ ASSERT_TRUE(browser_plugin);
+
+ EXPECT_TRUE(params.auto_size_params.enable);
+ EXPECT_EQ(42, params.auto_size_params.min_size.width());
+ EXPECT_EQ(43, params.auto_size_params.min_size.height());
+ EXPECT_EQ(1337, params.auto_size_params.max_size.width());
+ EXPECT_EQ(1338, params.auto_size_params.max_size.height());
+
+ // Verify that we are waiting for the browser process to grab the new
+ // damage buffer.
+ EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
+ // Disable autosize. AutoSize state will not be sent to the guest until
+ // the guest has responded to the last resize request.
+ ExecuteJavaScript(kDisableAutoSize);
+ ProcessPendingMessages();
+
+ const IPC::Message* auto_size_msg =
+ browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_SetAutoSize::ID);
+ EXPECT_FALSE(auto_size_msg);
+
+ // Send the BrowserPlugin an UpdateRect equal to its |max_size| with
+ // the same damage buffer.
+ BrowserPluginMsg_UpdateRect_Params update_rect_params;
+ update_rect_params.damage_buffer_sequence_id =
+ browser_plugin->damage_buffer_sequence_id_;
+ update_rect_params.view_size = gfx::Size(1337, 1338);
+ update_rect_params.scale_factor = 1.0f;
+ update_rect_params.is_resize_ack = true;
+ update_rect_params.needs_ack = true;
+ BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
+ browser_plugin->OnMessageReceived(msg);
+
+ // Verify that the autosize state has been updated.
+ {
+ const IPC::Message* auto_size_msg =
+ browser_plugin_manager()->sink().GetUniqueMessageMatching(
+ BrowserPluginHostMsg_UpdateRect_ACK::ID);
+ ASSERT_TRUE(auto_size_msg);
+
+ int instance_id = 0;
+ bool needs_ack = false;
+ BrowserPluginHostMsg_AutoSize_Params auto_size_params;
+ BrowserPluginHostMsg_ResizeGuest_Params resize_params;
+ BrowserPluginHostMsg_UpdateRect_ACK::Read(auto_size_msg,
+ &instance_id,
+ &needs_ack,
+ &auto_size_params,
+ &resize_params);
+ EXPECT_FALSE(auto_size_params.enable);
+ // These value are not populated (as an optimization) if autosize is
+ // disabled.
+ EXPECT_EQ(0, auto_size_params.min_size.width());
+ EXPECT_EQ(0, auto_size_params.min_size.height());
+ EXPECT_EQ(0, auto_size_params.max_size.width());
+ EXPECT_EQ(0, auto_size_params.max_size.height());
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_browsertest.h b/chromium/content/renderer/browser_plugin/browser_plugin_browsertest.h
new file mode 100644
index 00000000000..28676901378
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_browsertest.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_BROWSERETEST_H_
+#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_BROWSERETEST_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "content/common/browser_plugin/browser_plugin_messages.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/public/platform/WebSize.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+class RenderThreadImpl;
+
+namespace content {
+
+class MockBrowserPlugin;
+class TestContentRendererClient;
+
+class BrowserPluginTest : public RenderViewTest {
+ public:
+ BrowserPluginTest();
+ virtual ~BrowserPluginTest();
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+ MockBrowserPluginManager* browser_plugin_manager() const {
+ return static_cast<MockBrowserPluginManager*>(
+ static_cast<RenderViewImpl*>(view_)->GetBrowserPluginManager());
+ }
+ std::string ExecuteScriptAndReturnString(const std::string& script);
+ int ExecuteScriptAndReturnInt(const std::string& script);
+ bool ExecuteScriptAndReturnBool(const std::string& script, bool* result);
+ // Returns NULL if there is no plugin.
+ MockBrowserPlugin* GetCurrentPlugin();
+ // Returns NULL if there is no plugin.
+ MockBrowserPlugin* GetCurrentPluginWithAttachParams(
+ BrowserPluginHostMsg_Attach_Params* params);
+ private:
+ scoped_ptr<TestContentRendererClient> test_content_renderer_client_;
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_BROWSERETEST_H_
+
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_compositing_helper.cc b/chromium/content/renderer/browser_plugin/browser_plugin_compositing_helper.cc
new file mode 100644
index 00000000000..7d02f31aea9
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_compositing_helper.cc
@@ -0,0 +1,356 @@
+// Copyright (c) 2013 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_compositing_helper.h"
+
+#include "cc/layers/delegated_renderer_layer.h"
+#include "cc/layers/solid_color_layer.h"
+#include "cc/layers/texture_layer.h"
+#include "cc/output/context_provider.h"
+#include "content/common/browser_plugin/browser_plugin_messages.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
+#include "content/renderer/browser_plugin/browser_plugin_manager.h"
+#include "content/renderer/render_thread_impl.h"
+#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "ui/gfx/size_conversions.h"
+#include "webkit/renderer/compositor_bindings/web_layer_impl.h"
+
+namespace content {
+
+BrowserPluginCompositingHelper::SwapBuffersInfo::SwapBuffersInfo()
+ : route_id(0),
+ output_surface_id(0),
+ host_id(0),
+ software_frame_id(0),
+ shared_memory(NULL) {
+}
+
+BrowserPluginCompositingHelper::BrowserPluginCompositingHelper(
+ WebKit::WebPluginContainer* container,
+ BrowserPluginManager* manager,
+ int instance_id,
+ int host_routing_id)
+ : instance_id_(instance_id),
+ host_routing_id_(host_routing_id),
+ last_route_id_(0),
+ last_output_surface_id_(0),
+ last_host_id_(0),
+ last_mailbox_valid_(false),
+ ack_pending_(true),
+ container_(container),
+ browser_plugin_manager_(manager) {
+}
+
+BrowserPluginCompositingHelper::~BrowserPluginCompositingHelper() {
+}
+
+void BrowserPluginCompositingHelper::DidCommitCompositorFrame() {
+ if (!delegated_layer_.get() || !ack_pending_)
+ return;
+
+ cc::CompositorFrameAck ack;
+ delegated_layer_->TakeUnusedResourcesForChildCompositor(&ack.resources);
+
+ browser_plugin_manager_->Send(
+ new BrowserPluginHostMsg_CompositorFrameACK(
+ host_routing_id_,
+ instance_id_,
+ last_route_id_,
+ last_output_surface_id_,
+ last_host_id_,
+ ack));
+
+ ack_pending_ = false;
+}
+
+void BrowserPluginCompositingHelper::EnableCompositing(bool enable) {
+ if (enable && !background_layer_.get()) {
+ background_layer_ = cc::SolidColorLayer::Create();
+ background_layer_->SetMasksToBounds(true);
+ background_layer_->SetBackgroundColor(
+ SkColorSetARGBInline(255, 255, 255, 255));
+ web_layer_.reset(new webkit::WebLayerImpl(background_layer_));
+ }
+
+ container_->setWebLayer(enable ? web_layer_.get() : NULL);
+}
+
+void BrowserPluginCompositingHelper::CheckSizeAndAdjustLayerBounds(
+ const gfx::Size& new_size,
+ float device_scale_factor,
+ cc::Layer* layer) {
+ if (buffer_size_ != new_size) {
+ buffer_size_ = new_size;
+ // The container size is in DIP, so is the layer size.
+ // Buffer size is in physical pixels, so we need to adjust
+ // it by the device scale factor.
+ gfx::Size device_scale_adjusted_size = gfx::ToFlooredSize(
+ gfx::ScaleSize(buffer_size_, 1.0f / device_scale_factor));
+ layer->SetBounds(device_scale_adjusted_size);
+ }
+}
+
+void BrowserPluginCompositingHelper::MailboxReleased(
+ SwapBuffersInfo mailbox,
+ unsigned sync_point,
+ bool lost_resource) {
+ if (mailbox.type == SOFTWARE_COMPOSITOR_FRAME) {
+ delete mailbox.shared_memory;
+ mailbox.shared_memory = NULL;
+ } else if (lost_resource) {
+ // Reset mailbox's name if the resource was lost.
+ mailbox.name.SetZero();
+ }
+
+ // This means the GPU process crashed or guest crashed.
+ if (last_host_id_ != mailbox.host_id ||
+ last_output_surface_id_ != mailbox.output_surface_id ||
+ last_route_id_ != mailbox.route_id)
+ return;
+
+ // We need to send an ACK to for every buffer sent to us.
+ // However, if a buffer is freed up from
+ // the compositor in cases like switching back to SW mode without a new
+ // buffer arriving, no ACK is needed.
+ if (!ack_pending_) {
+ last_mailbox_valid_ = false;
+ return;
+ }
+ ack_pending_ = false;
+ switch (mailbox.type) {
+ case TEXTURE_IMAGE_TRANSPORT: {
+ std::string mailbox_name(reinterpret_cast<const char*>(mailbox.name.name),
+ sizeof(mailbox.name.name));
+ browser_plugin_manager_->Send(
+ new BrowserPluginHostMsg_BuffersSwappedACK(
+ host_routing_id_,
+ instance_id_,
+ mailbox.route_id,
+ mailbox.host_id,
+ mailbox_name,
+ sync_point));
+ break;
+ }
+ case GL_COMPOSITOR_FRAME: {
+ cc::CompositorFrameAck ack;
+ ack.gl_frame_data.reset(new cc::GLFrameData());
+ ack.gl_frame_data->mailbox = mailbox.name;
+ ack.gl_frame_data->size = mailbox.size;
+ ack.gl_frame_data->sync_point = sync_point;
+
+ browser_plugin_manager_->Send(
+ new BrowserPluginHostMsg_CompositorFrameACK(
+ host_routing_id_,
+ instance_id_,
+ mailbox.route_id,
+ mailbox.output_surface_id,
+ mailbox.host_id,
+ ack));
+ break;
+ }
+ case SOFTWARE_COMPOSITOR_FRAME: {
+ cc::CompositorFrameAck ack;
+ ack.last_software_frame_id = mailbox.software_frame_id;
+
+ browser_plugin_manager_->Send(
+ new BrowserPluginHostMsg_CompositorFrameACK(
+ host_routing_id_,
+ instance_id_,
+ mailbox.route_id,
+ mailbox.output_surface_id,
+ mailbox.host_id,
+ ack));
+ break;
+ }
+ }
+}
+
+void BrowserPluginCompositingHelper::OnContainerDestroy() {
+ if (container_)
+ container_->setWebLayer(NULL);
+ container_ = NULL;
+
+ texture_layer_ = NULL;
+ delegated_layer_ = NULL;
+ background_layer_ = NULL;
+ web_layer_.reset();
+}
+
+void BrowserPluginCompositingHelper::OnBuffersSwappedPrivate(
+ const SwapBuffersInfo& mailbox,
+ unsigned sync_point,
+ float device_scale_factor) {
+ DCHECK(!delegated_layer_.get());
+ // If these mismatch, we are either just starting up, GPU process crashed or
+ // guest renderer crashed.
+ // In this case, we are communicating with a new image transport
+ // surface and must ACK with the new ID's and an empty mailbox.
+ if (last_route_id_ != mailbox.route_id ||
+ last_output_surface_id_ != mailbox.output_surface_id ||
+ last_host_id_ != mailbox.host_id)
+ last_mailbox_valid_ = false;
+
+ last_route_id_ = mailbox.route_id;
+ last_output_surface_id_ = mailbox.output_surface_id;
+ last_host_id_ = mailbox.host_id;
+
+ ack_pending_ = true;
+ // Browser plugin getting destroyed, do a fast ACK.
+ if (!background_layer_.get()) {
+ MailboxReleased(mailbox, sync_point, false);
+ return;
+ }
+
+ if (!texture_layer_.get()) {
+ texture_layer_ = cc::TextureLayer::CreateForMailbox(NULL);
+ texture_layer_->SetIsDrawable(true);
+ texture_layer_->SetContentsOpaque(true);
+
+ background_layer_->AddChild(texture_layer_);
+ }
+
+ // The size of browser plugin container is not always equal to the size
+ // of the buffer that arrives here. This could be for a number of reasons,
+ // including autosize and a resize in progress.
+ // During resize, the container size changes first and then some time
+ // later, a new buffer with updated size will arrive. During this process,
+ // we need to make sure that things are still displayed pixel perfect.
+ // We accomplish this by modifying bounds of the texture layer only
+ // when a new buffer arrives.
+ // Visually, this will either display a smaller part of the buffer
+ // or introduce a gutter around it.
+ CheckSizeAndAdjustLayerBounds(mailbox.size,
+ device_scale_factor,
+ texture_layer_.get());
+
+ bool is_software_frame = mailbox.type == SOFTWARE_COMPOSITOR_FRAME;
+ bool current_mailbox_valid = is_software_frame ?
+ mailbox.shared_memory != NULL : !mailbox.name.IsZero();
+ if (!is_software_frame && !last_mailbox_valid_) {
+ SwapBuffersInfo empty_info = mailbox;
+ empty_info.name.SetZero();
+ MailboxReleased(empty_info, 0, false);
+ if (!current_mailbox_valid)
+ return;
+ }
+
+ cc::TextureMailbox texture_mailbox;
+ if (current_mailbox_valid) {
+ cc::TextureMailbox::ReleaseCallback callback =
+ base::Bind(&BrowserPluginCompositingHelper::MailboxReleased,
+ scoped_refptr<BrowserPluginCompositingHelper>(this),
+ mailbox);
+ if (is_software_frame) {
+ texture_mailbox = cc::TextureMailbox(mailbox.shared_memory,
+ mailbox.size, callback);
+ } else {
+ texture_mailbox = cc::TextureMailbox(mailbox.name, callback, sync_point);
+ }
+ }
+
+ texture_layer_->SetFlipped(!is_software_frame);
+ texture_layer_->SetTextureMailbox(texture_mailbox);
+ texture_layer_->SetNeedsDisplay();
+ last_mailbox_valid_ = current_mailbox_valid;
+}
+
+void BrowserPluginCompositingHelper::OnBuffersSwapped(
+ const gfx::Size& size,
+ const std::string& mailbox_name,
+ int gpu_route_id,
+ int gpu_host_id,
+ float device_scale_factor) {
+ SwapBuffersInfo swap_info;
+ swap_info.name.SetName(reinterpret_cast<const int8*>(mailbox_name.data()));
+ swap_info.type = TEXTURE_IMAGE_TRANSPORT;
+ swap_info.size = size;
+ swap_info.route_id = gpu_route_id;
+ swap_info.output_surface_id = 0;
+ swap_info.host_id = gpu_host_id;
+ OnBuffersSwappedPrivate(swap_info, 0, device_scale_factor);
+}
+
+void BrowserPluginCompositingHelper::OnCompositorFrameSwapped(
+ scoped_ptr<cc::CompositorFrame> frame,
+ int route_id,
+ uint32 output_surface_id,
+ int host_id) {
+ if (frame->gl_frame_data) {
+ SwapBuffersInfo swap_info;
+ swap_info.name = frame->gl_frame_data->mailbox;
+ swap_info.type = GL_COMPOSITOR_FRAME;
+ swap_info.size = frame->gl_frame_data->size;
+ swap_info.route_id = route_id;
+ swap_info.output_surface_id = output_surface_id;
+ swap_info.host_id = host_id;
+ OnBuffersSwappedPrivate(swap_info,
+ frame->gl_frame_data->sync_point,
+ frame->metadata.device_scale_factor);
+ return;
+ }
+
+ if (frame->software_frame_data) {
+ cc::SoftwareFrameData* frame_data = frame->software_frame_data.get();
+
+ SwapBuffersInfo swap_info;
+ swap_info.type = SOFTWARE_COMPOSITOR_FRAME;
+ swap_info.size = frame_data->size;
+ swap_info.route_id = route_id;
+ swap_info.output_surface_id = output_surface_id;
+ swap_info.host_id = host_id;
+ swap_info.software_frame_id = frame_data->id;
+
+ scoped_ptr<base::SharedMemory> shared_memory(
+ new base::SharedMemory(frame_data->handle, true));
+ const size_t size_in_bytes = 4 * frame_data->size.GetArea();
+ if (!shared_memory->Map(size_in_bytes)) {
+ LOG(ERROR) << "Failed to map shared memory of size "
+ << size_in_bytes;
+ // Send ACK right away.
+ ack_pending_ = true;
+ MailboxReleased(swap_info, 0, false);
+ return;
+ }
+
+ swap_info.shared_memory = shared_memory.release();
+ OnBuffersSwappedPrivate(swap_info, 0,
+ frame->metadata.device_scale_factor);
+ return;
+ }
+
+ DCHECK(!texture_layer_.get());
+ if (!delegated_layer_.get()) {
+ delegated_layer_ = cc::DelegatedRendererLayer::Create(NULL);
+ delegated_layer_->SetIsDrawable(true);
+ delegated_layer_->SetContentsOpaque(true);
+
+ background_layer_->AddChild(delegated_layer_);
+ }
+
+ cc::DelegatedFrameData *frame_data = frame->delegated_frame_data.get();
+ if (!frame_data)
+ return;
+
+ CheckSizeAndAdjustLayerBounds(
+ frame_data->render_pass_list.back()->output_rect.size(),
+ frame->metadata.device_scale_factor,
+ delegated_layer_.get());
+
+ delegated_layer_->SetFrameData(frame->delegated_frame_data.Pass());
+ last_route_id_ = route_id;
+ last_output_surface_id_ = output_surface_id;
+ last_host_id_ = host_id;
+ ack_pending_ = true;
+}
+
+void BrowserPluginCompositingHelper::UpdateVisibility(bool visible) {
+ if (texture_layer_.get())
+ texture_layer_->SetIsDrawable(visible);
+ if (delegated_layer_.get())
+ delegated_layer_->SetIsDrawable(visible);
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_compositing_helper.h b/chromium/content/renderer/browser_plugin/browser_plugin_compositing_helper.h
new file mode 100644
index 00000000000..268a9b46259
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_compositing_helper.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2013 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_COMPOSITING_HELPER_H_
+#define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_COMPOSITING_HELPER_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "ui/gfx/size.h"
+
+namespace base {
+class SharedMemory;
+}
+
+namespace cc {
+class CompositorFrame;
+class Layer;
+class SolidColorLayer;
+class TextureLayer;
+class DelegatedRendererLayer;
+}
+
+namespace WebKit {
+class WebPluginContainer;
+class WebLayer;
+}
+
+namespace content {
+
+class BrowserPluginManager;
+
+class CONTENT_EXPORT BrowserPluginCompositingHelper :
+ public base::RefCounted<BrowserPluginCompositingHelper> {
+ public:
+ BrowserPluginCompositingHelper(WebKit::WebPluginContainer* container,
+ BrowserPluginManager* manager,
+ int instance_id,
+ int host_routing_id);
+ void DidCommitCompositorFrame();
+ void EnableCompositing(bool);
+ void OnContainerDestroy();
+ void OnBuffersSwapped(const gfx::Size& size,
+ const std::string& mailbox_name,
+ int gpu_route_id,
+ int gpu_host_id,
+ float device_scale_factor);
+ void OnCompositorFrameSwapped(scoped_ptr<cc::CompositorFrame> frame,
+ int route_id,
+ uint32 output_surface_id,
+ int host_id);
+ void UpdateVisibility(bool);
+ protected:
+ // Friend RefCounted so that the dtor can be non-public.
+ friend class base::RefCounted<BrowserPluginCompositingHelper>;
+ private:
+ enum SwapBuffersType {
+ TEXTURE_IMAGE_TRANSPORT,
+ GL_COMPOSITOR_FRAME,
+ SOFTWARE_COMPOSITOR_FRAME,
+ };
+ struct SwapBuffersInfo {
+ SwapBuffersInfo();
+
+ gpu::Mailbox name;
+ SwapBuffersType type;
+ gfx::Size size;
+ int route_id;
+ uint32 output_surface_id;
+ int host_id;
+ unsigned software_frame_id;
+ base::SharedMemory* shared_memory;
+ };
+ ~BrowserPluginCompositingHelper();
+ void CheckSizeAndAdjustLayerBounds(const gfx::Size& new_size,
+ float device_scale_factor,
+ cc::Layer* layer);
+ void OnBuffersSwappedPrivate(const SwapBuffersInfo& mailbox,
+ unsigned sync_point,
+ float device_scale_factor);
+ void MailboxReleased(SwapBuffersInfo mailbox,
+ unsigned sync_point,
+ bool lost_resource);
+ int instance_id_;
+ int host_routing_id_;
+ int last_route_id_;
+ uint32 last_output_surface_id_;
+ int last_host_id_;
+ bool last_mailbox_valid_;
+ bool ack_pending_;
+
+ gfx::Size buffer_size_;
+
+ scoped_refptr<cc::SolidColorLayer> background_layer_;
+ scoped_refptr<cc::TextureLayer> texture_layer_;
+ scoped_refptr<cc::DelegatedRendererLayer> delegated_layer_;
+ scoped_ptr<WebKit::WebLayer> web_layer_;
+ WebKit::WebPluginContainer* container_;
+
+ scoped_refptr<BrowserPluginManager> browser_plugin_manager_;
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_COMPOSITING_HELPER_H_
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_manager.cc b/chromium/content/renderer/browser_plugin/browser_plugin_manager.cc
new file mode 100644
index 00000000000..03120d82f78
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_manager.cc
@@ -0,0 +1,65 @@
+// 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"
+#include "content/renderer/browser_plugin/browser_plugin_manager_factory.h"
+#include "content/renderer/browser_plugin/browser_plugin_manager_impl.h"
+
+namespace content {
+
+// static
+BrowserPluginManagerFactory* BrowserPluginManager::factory_ = NULL;
+
+BrowserPluginManager* BrowserPluginManager::Create(
+ RenderViewImpl* render_view) {
+ if (factory_)
+ return factory_->CreateBrowserPluginManager(render_view);
+ return new BrowserPluginManagerImpl(render_view);
+}
+
+BrowserPluginManager::BrowserPluginManager(RenderViewImpl* render_view)
+ : RenderViewObserver(render_view),
+ render_view_(render_view->AsWeakPtr()) {
+}
+
+BrowserPluginManager::~BrowserPluginManager() {
+}
+
+void BrowserPluginManager::AddBrowserPlugin(
+ int guest_instance_id,
+ BrowserPlugin* browser_plugin) {
+ instances_.AddWithID(browser_plugin, guest_instance_id);
+}
+
+void BrowserPluginManager::RemoveBrowserPlugin(int guest_instance_id) {
+ instances_.Remove(guest_instance_id);
+}
+
+BrowserPlugin* BrowserPluginManager::GetBrowserPlugin(
+ int guest_instance_id) const {
+ return instances_.Lookup(guest_instance_id);
+}
+
+void BrowserPluginManager::UpdateDeviceScaleFactor(float device_scale_factor) {
+ IDMap<BrowserPlugin>::iterator iter(&instances_);
+ while (!iter.IsAtEnd()) {
+ iter.GetCurrentValue()->UpdateDeviceScaleFactor(device_scale_factor);
+ iter.Advance();
+ }
+}
+
+void BrowserPluginManager::UpdateFocusState() {
+ IDMap<BrowserPlugin>::iterator iter(&instances_);
+ while (!iter.IsAtEnd()) {
+ iter.GetCurrentValue()->UpdateGuestFocusState();
+ iter.Advance();
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_manager.h b/chromium/content/renderer/browser_plugin/browser_plugin_manager.h
new file mode 100644
index 00000000000..54c4bbdbacb
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_manager.h
@@ -0,0 +1,88 @@
+// 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/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "content/public/renderer/render_view_observer.h"
+#include "ipc/ipc_sender.h"
+
+namespace WebKit {
+class WebFrame;
+struct WebPluginParams;
+}
+
+namespace content {
+
+class BrowserPlugin;
+class BrowserPluginManagerFactory;
+class RenderViewImpl;
+
+// BrowserPluginManager manages the routing of messages to the appropriate
+// BrowserPlugin object based on its instance ID.
+class CONTENT_EXPORT BrowserPluginManager
+ : public RenderViewObserver,
+ public base::RefCounted<BrowserPluginManager> {
+ public:
+ // Returns the one BrowserPluginManager for this process.
+ static BrowserPluginManager* Create(RenderViewImpl* render_view);
+
+ // Overrides factory for testing. Default (NULL) value indicates regular
+ // (non-test) environment.
+ static void set_factory_for_testing(BrowserPluginManagerFactory* factory) {
+ BrowserPluginManager::factory_ = factory;
+ }
+
+ explicit BrowserPluginManager(RenderViewImpl* render_view);
+
+ // 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;
+ virtual void AllocateInstanceID(BrowserPlugin* browser_plugin) = 0;
+
+ void AddBrowserPlugin(int guest_instance_id, BrowserPlugin* browser_plugin);
+ void RemoveBrowserPlugin(int guest_instance_id);
+ BrowserPlugin* GetBrowserPlugin(int guest_instance_id) const;
+ void UpdateDeviceScaleFactor(float device_scale_factor);
+ void UpdateFocusState();
+ RenderViewImpl* render_view() const { return render_view_.get(); }
+
+ // RenderViewObserver implementation.
+
+ // BrowserPluginManager must override the default Send behavior.
+ virtual bool Send(IPC::Message* msg) OVERRIDE = 0;
+
+ // Don't destroy the BrowserPluginManager when the RenderViewImpl goes away.
+ // BrowserPluginManager's lifetime is managed by a reference count. Once
+ // the host RenderViewImpl and all BrowserPlugins release their references,
+ // then the BrowserPluginManager will be destroyed.
+ virtual void OnDestruct() OVERRIDE {}
+
+ protected:
+ // Friend RefCounted so that the dtor can be non-public.
+ friend class base::RefCounted<BrowserPluginManager>;
+
+ // Static factory instance (always NULL for non-test).
+ static BrowserPluginManagerFactory* factory_;
+
+ virtual ~BrowserPluginManager();
+ // This map is keyed by guest instance IDs.
+ IDMap<BrowserPlugin> instances_;
+ base::WeakPtr<RenderViewImpl> render_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_H_
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_manager_factory.h b/chromium/content/renderer/browser_plugin/browser_plugin_manager_factory.h
new file mode 100644
index 00000000000..3178fededbd
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_manager_factory.h
@@ -0,0 +1,21 @@
+// 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_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_FACTORY_H_
+#define CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_FACTORY_H_
+
+namespace content {
+
+class CONTENT_EXPORT BrowserPluginManagerFactory {
+ public:
+ virtual BrowserPluginManager* CreateBrowserPluginManager(
+ RenderViewImpl* render_view) = 0;
+
+ protected:
+ virtual ~BrowserPluginManagerFactory() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_FACTORY_H_
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_manager_impl.cc b/chromium/content/renderer/browser_plugin/browser_plugin_manager_impl.cc
new file mode 100644
index 00000000000..2f7cdac4620
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_manager_impl.cc
@@ -0,0 +1,111 @@
+// 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/browser_plugin_constants.h"
+#include "content/common/browser_plugin/browser_plugin_messages.h"
+#include "content/renderer/browser_plugin/browser_plugin.h"
+#include "content/renderer/render_thread_impl.h"
+#include "ui/gfx/point.h"
+#include "webkit/common/cursors/webcursor.h"
+
+namespace content {
+
+BrowserPluginManagerImpl::BrowserPluginManagerImpl(
+ RenderViewImpl* render_view)
+ : BrowserPluginManager(render_view),
+ request_id_counter_(0) {
+}
+
+BrowserPluginManagerImpl::~BrowserPluginManagerImpl() {
+}
+
+BrowserPlugin* BrowserPluginManagerImpl::CreateBrowserPlugin(
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params) {
+ return new BrowserPlugin(render_view, frame, params);
+}
+
+void BrowserPluginManagerImpl::AllocateInstanceID(
+ BrowserPlugin* browser_plugin) {
+ int request_id = ++request_id_counter_;
+ pending_allocate_guest_instance_id_requests_.AddWithID(browser_plugin,
+ request_id);
+ Send(new BrowserPluginHostMsg_AllocateInstanceID(
+ browser_plugin->render_view_routing_id(), request_id));
+}
+
+bool BrowserPluginManagerImpl::Send(IPC::Message* msg) {
+ return RenderThread::Get()->Send(msg);
+}
+
+bool BrowserPluginManagerImpl::OnMessageReceived(
+ const IPC::Message& message) {
+ if (BrowserPlugin::ShouldForwardToBrowserPlugin(message)) {
+ int guest_instance_id = browser_plugin::kInstanceIDNone;
+ // All allowed messages must have |guest_instance_id| as their first
+ // parameter.
+ PickleIterator iter(message);
+ bool success = iter.ReadInt(&guest_instance_id);
+ DCHECK(success);
+ BrowserPlugin* plugin = GetBrowserPlugin(guest_instance_id);
+ if (plugin && plugin->OnMessageReceived(message))
+ return true;
+ }
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(BrowserPluginManagerImpl, message)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_AllocateInstanceID_ACK,
+ OnAllocateInstanceIDACK)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_PluginAtPositionRequest,
+ OnPluginAtPositionRequest);
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void BrowserPluginManagerImpl::DidCommitCompositorFrame() {
+ IDMap<BrowserPlugin>::iterator iter(&instances_);
+ while (!iter.IsAtEnd()) {
+ iter.GetCurrentValue()->DidCommitCompositorFrame();
+ iter.Advance();
+ }
+}
+
+void BrowserPluginManagerImpl::OnAllocateInstanceIDACK(
+ const IPC::Message& message,
+ int request_id,
+ int guest_instance_id) {
+ BrowserPlugin* plugin =
+ pending_allocate_guest_instance_id_requests_.Lookup(request_id);
+ if (!plugin)
+ return;
+ pending_allocate_guest_instance_id_requests_.Remove(request_id);
+ plugin->OnInstanceIDAllocated(guest_instance_id);
+}
+
+void BrowserPluginManagerImpl::OnPluginAtPositionRequest(
+ const IPC::Message& message,
+ int request_id,
+ const gfx::Point& position) {
+ int guest_instance_id = browser_plugin::kInstanceIDNone;
+ IDMap<BrowserPlugin>::iterator it(&instances_);
+ gfx::Point local_position = position;
+ while (!it.IsAtEnd()) {
+ const BrowserPlugin* plugin = it.GetCurrentValue();
+ if (!plugin->guest_crashed() && plugin->InBounds(position)) {
+ guest_instance_id = plugin->guest_instance_id();
+ local_position = plugin->ToLocalCoordinates(position);
+ break;
+ }
+ it.Advance();
+ }
+
+ Send(new BrowserPluginHostMsg_PluginAtPositionResponse(
+ message.routing_id(), guest_instance_id, request_id, local_position));
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/browser_plugin_manager_impl.h b/chromium/content/renderer/browser_plugin/browser_plugin_manager_impl.h
new file mode 100644
index 00000000000..9045d9d1d6b
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/browser_plugin_manager_impl.h
@@ -0,0 +1,56 @@
+// 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 "ui/gfx/size.h"
+
+struct BrowserPluginMsg_UpdateRect_Params;
+class WebCursor;
+
+namespace gfx {
+class Point;
+}
+
+namespace content {
+
+class BrowserPluginManagerImpl : public BrowserPluginManager {
+ public:
+ explicit BrowserPluginManagerImpl(RenderViewImpl* render_view);
+
+ // BrowserPluginManager implementation.
+ virtual BrowserPlugin* CreateBrowserPlugin(
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params) OVERRIDE;
+ virtual void AllocateInstanceID(BrowserPlugin* browser_plugin) OVERRIDE;
+
+ // IPC::Sender implementation.
+ virtual bool Send(IPC::Message* msg) OVERRIDE;
+
+ // RenderViewObserver override. Call on render thread.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ virtual void DidCommitCompositorFrame() OVERRIDE;
+
+ private:
+ virtual ~BrowserPluginManagerImpl();
+
+ void OnAllocateInstanceIDACK(const IPC::Message& message,
+ int request_id,
+ int guest_instance_id);
+ void OnPluginAtPositionRequest(const IPC::Message& message,
+ int request_id,
+ const gfx::Point& position);
+
+ int request_id_counter_;
+ IDMap<BrowserPlugin> pending_allocate_guest_instance_id_requests_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginManagerImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_IMPL_H_
diff --git a/chromium/content/renderer/browser_plugin/mock_browser_plugin.cc b/chromium/content/renderer/browser_plugin/mock_browser_plugin.cc
new file mode 100644
index 00000000000..39b2d2dc047
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/mock_browser_plugin.cc
@@ -0,0 +1,18 @@
+// 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"
+#include "content/renderer/render_process_impl.h"
+
+namespace content {
+
+MockBrowserPlugin::MockBrowserPlugin(RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params)
+ : BrowserPlugin(render_view, frame, params) {
+}
+
+MockBrowserPlugin::~MockBrowserPlugin() {}
+
+} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/mock_browser_plugin.h b/chromium/content/renderer/browser_plugin/mock_browser_plugin.h
new file mode 100644
index 00000000000..acd001b64ca
--- /dev/null
+++ b/chromium/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(RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params);
+
+ virtual ~MockBrowserPlugin();
+
+ // Allow poking at a few private members.
+ using BrowserPlugin::OnAttachACK;
+ using BrowserPlugin::guest_crashed_;
+ using BrowserPlugin::pending_damage_buffer_;
+ using BrowserPlugin::damage_buffer_sequence_id_;
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_MOCK_BROWSER_PLUGIN_H_
diff --git a/chromium/content/renderer/browser_plugin/mock_browser_plugin_manager.cc b/chromium/content/renderer/browser_plugin/mock_browser_plugin_manager.cc
new file mode 100644
index 00000000000..c3b8fd8e72a
--- /dev/null
+++ b/chromium/content/renderer/browser_plugin/mock_browser_plugin_manager.cc
@@ -0,0 +1,79 @@
+// 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 "base/message_loop/message_loop.h"
+#include "content/common/browser_plugin/browser_plugin_messages.h"
+#include "content/renderer/browser_plugin/mock_browser_plugin.h"
+#include "ipc/ipc_message.h"
+
+namespace content {
+
+MockBrowserPluginManager::MockBrowserPluginManager(
+ RenderViewImpl* render_view)
+ : BrowserPluginManager(render_view),
+ guest_instance_id_counter_(0) {
+}
+
+MockBrowserPluginManager::~MockBrowserPluginManager() {
+}
+
+BrowserPlugin* MockBrowserPluginManager::CreateBrowserPlugin(
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params) {
+ return new MockBrowserPlugin(render_view, frame, params);
+}
+
+void MockBrowserPluginManager::AllocateInstanceID(
+ BrowserPlugin* browser_plugin) {
+ int guest_instance_id = ++guest_instance_id_counter_;
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MockBrowserPluginManager::AllocateInstanceIDACK,
+ this,
+ base::Unretained(browser_plugin),
+ guest_instance_id));
+}
+
+void MockBrowserPluginManager::AllocateInstanceIDACK(
+ BrowserPlugin* browser_plugin,
+ int guest_instance_id) {
+ browser_plugin->OnInstanceIDAllocated(guest_instance_id);
+ scoped_ptr<base::DictionaryValue> extra_params(new base::DictionaryValue());
+ browser_plugin->Attach(extra_params.Pass());
+}
+
+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_) {
+ 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());
+ }
+ OnMessageReceived(*msg);
+ }
+ delete msg;
+ return true;
+}
+
+bool MockBrowserPluginManager::OnMessageReceived(
+ const IPC::Message& message) {
+ // Save the message in the sink.
+ sink_.OnMessageReceived(message);
+ return false;
+}
+
+} // namespace content
diff --git a/chromium/content/renderer/browser_plugin/mock_browser_plugin_manager.h b/chromium/content/renderer/browser_plugin/mock_browser_plugin_manager.h
new file mode 100644
index 00000000000..eda85f15f9b
--- /dev/null
+++ b/chromium/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_MOCK_BROWSER_PLUGIN_MANAGER_H_
+#define CONTENT_RENDERER_BROWSER_PLUGIN_MOCK_BROWSER_PLUGIN_MANAGER_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(RenderViewImpl* render_view);
+
+ // BrowserPluginManager implementation.
+ virtual BrowserPlugin* CreateBrowserPlugin(
+ RenderViewImpl* render_view,
+ WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params) OVERRIDE;
+ virtual void AllocateInstanceID(BrowserPlugin* browser_plugin) OVERRIDE;
+
+ // Provides access to the messages that have been received by this thread.
+ IPC::TestSink& sink() { return sink_; }
+
+ // RenderViewObserver override.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ virtual bool Send(IPC::Message* msg) OVERRIDE;
+ protected:
+ virtual ~MockBrowserPluginManager();
+ void AllocateInstanceIDACK(BrowserPlugin* browser_plugin,
+ int guest_instance_id);
+
+ IPC::TestSink sink_;
+
+ // The last known good deserializer for sync messages.
+ scoped_ptr<IPC::MessageReplyDeserializer> reply_deserializer_;
+
+ int guest_instance_id_counter_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockBrowserPluginManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_BROWSER_PLUGIN_MOCK_BROWSER_PLUGIN_MANAGER_H_