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