diff options
-rw-r--r-- | content/browser/browser_plugin/browser_plugin_web_contents_observer.cc | 229 | ||||
-rw-r--r-- | content/browser/browser_plugin/browser_plugin_web_contents_observer.h | 94 | ||||
-rw-r--r-- | content/browser/tab_contents/tab_contents.cc | 4 | ||||
-rw-r--r-- | content/browser/tab_contents/tab_contents.h | 8 | ||||
-rw-r--r-- | content/common/browser_plugin_messages.h | 72 | ||||
-rw-r--r-- | content/common/content_message_generator.h | 1 | ||||
-rw-r--r-- | content/content_browser.gypi | 2 | ||||
-rw-r--r-- | content/content_common.gypi | 1 | ||||
-rw-r--r-- | ipc/ipc_message_utils.h | 1 |
9 files changed, 412 insertions, 0 deletions
diff --git a/content/browser/browser_plugin/browser_plugin_web_contents_observer.cc b/content/browser/browser_plugin/browser_plugin_web_contents_observer.cc new file mode 100644 index 0000000..0811a8d --- /dev/null +++ b/content/browser/browser_plugin/browser_plugin_web_contents_observer.cc @@ -0,0 +1,229 @@ +// 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/browser/browser_plugin/browser_plugin_web_contents_observer.h" + +#include "base/lazy_instance.h" +#include "content/browser/renderer_host/render_view_host_impl.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/common/browser_plugin_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/notification_types.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_widget_host.h" +#include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/site_instance.h" +#include "content/public/browser/web_contents.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace content { + +BrowserPluginWebContentsObserver::BrowserPluginWebContentsObserver( + TabContents* tab_contents) + : WebContentsObserver(tab_contents), + host_(NULL), + instance_id_(0) { + registrar_.Add(this, + NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, + Source<RenderViewHost>( + tab_contents->GetRenderViewHost())); +} + +BrowserPluginWebContentsObserver::~BrowserPluginWebContentsObserver() { +} + +bool BrowserPluginWebContentsObserver::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(BrowserPluginWebContentsObserver, message) + IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ChannelCreated, + OnRendererPluginChannelCreated) + IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_OpenChannel, + OnOpenChannelToBrowserPlugin) + IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_GuestReady, OnGuestReady) + IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP_EX() + return handled; +} + +void BrowserPluginWebContentsObserver::OnGuestReady() { + // We only care about handling this message on guests. + if (!host()) + return; + + // The renderer is now ready to receive ppapi messages. + // Let's tell it create a channel with the embedder/host. + BrowserPluginMsg_CreateChannel* msg = + new BrowserPluginMsg_CreateChannel( + host()->GetRenderProcessHost()->GetHandle(), + host()->GetRenderProcessHost()->GetID()); + msg->set_routing_id(web_contents()->GetRenderViewHost()->GetRoutingID()); + // TODO(fsamuel): If we aren't able to successfully send this message + // to the guest then that probably means it crashed. Is there anything + // we can do that's cleaner than failing a check? + CHECK(Send(msg)); +} + +void BrowserPluginWebContentsObserver::OnResizeGuest( + int width, int height) { + // Tell the RenderWidgetHostView to adjust its size. + web_contents()->GetRenderViewHost()->GetView()->SetSize( + gfx::Size(width, height)); +} + +void BrowserPluginWebContentsObserver::OnOpenChannelToBrowserPlugin( + int instance_id, + long long frame_id, + const std::string& src, + const gfx::Size& size) { + BrowserContext* browser_context = + web_contents()->GetRenderViewHost()->GetProcess()->GetBrowserContext(); + DCHECK(browser_context); + + GURL url(src); + SiteInstance* site_instance = + SiteInstance::CreateForURL( + browser_context, url); + TabContents* guest_tab_contents = + static_cast<TabContents*>( + WebContents::Create( + browser_context, + site_instance, + MSG_ROUTING_NONE, + NULL, // base tab contents + NULL // session storage namespace + )); + // TODO(fsamuel): Set the WebContentsDelegate here. + RenderViewHostImpl* guest_render_view_host = + static_cast<RenderViewHostImpl*>( + guest_tab_contents->GetRenderViewHost()); + + // We need to make sure that the RenderViewHost knows that it's + // hosting a guest RenderView so that it informs the RenderView + // on a ViewMsg_New. Guest RenderViews will avoid compositing + // until a guest-to-host channel has been initialized. + guest_render_view_host->set_guest(true); + + guest_tab_contents->GetController().LoadURL( + url, + Referrer(), + PAGE_TRANSITION_HOME_PAGE, + std::string()); + + guest_render_view_host->GetView()->SetSize(size); + BrowserPluginWebContentsObserver* guest_observer = + guest_tab_contents->browser_plugin_web_contents_observer(); + guest_observer->set_host(static_cast<TabContents*>(web_contents())); + guest_observer->set_instance_id(instance_id); + + AddGuest(guest_tab_contents, frame_id); +} + +void BrowserPluginWebContentsObserver::OnRendererPluginChannelCreated( + const IPC::ChannelHandle& channel_handle) { + DCHECK(host()); + // Prepare the handle to send to the renderer. + base::ProcessHandle plugin_process = + web_contents()->GetRenderProcessHost()->GetHandle(); +#if defined(OS_WIN) + base::ProcessHandle renderer_process = + host()->GetRenderProcessHost()->GetHandle(); + int renderer_id = host()->GetRenderProcessHost()->GetID(); + + base::ProcessHandle renderers_plugin_handle = NULL; + ::DuplicateHandle(::GetCurrentProcess(), plugin_process, + renderer_process, &renderers_plugin_handle, + 0, FALSE, DUPLICATE_SAME_ACCESS); +#elif defined(OS_POSIX) + // Don't need to duplicate anything on POSIX since it's just a PID. + base::ProcessHandle renderers_plugin_handle = plugin_process; +#endif + // Tell the BrowserPLuginPlaceholder in the host that we're done + // and that it can begin using the guest renderer. + host()->GetRenderProcessHost()->Send( + new BrowserPluginMsg_GuestReady_ACK( + host()->GetRenderViewHost()->GetRoutingID(), + instance_id(), + renderers_plugin_handle, + channel_handle)); +} + +void BrowserPluginWebContentsObserver::AddGuest( + TabContents* guest, + int64 frame_id) { + guests_[guest] = frame_id; +} + +void BrowserPluginWebContentsObserver::RemoveGuest(TabContents* guest) { + guests_.erase(guest); +} + +void BrowserPluginWebContentsObserver::DestroyGuests() { + for (GuestMap::const_iterator it = guests_.begin(); + it != guests_.end(); ++it) { + const TabContents* contents = it->first; + delete contents; + } + guests_.clear(); +} + +void BrowserPluginWebContentsObserver::DidCommitProvisionalLoadForFrame( + int64 frame_id, + bool is_main_frame, + const GURL& url, + PageTransition transition_type) { + typedef std::set<TabContents*> GuestSet; + GuestSet guests_to_delete; + for (GuestMap::const_iterator it = guests_.begin(); + it != guests_.end(); ++it) { + TabContents* contents = it->first; + if (it->second == frame_id) { + guests_to_delete.insert(contents); + } + } + for (GuestSet::const_iterator it = guests_to_delete.begin(); + it != guests_to_delete.end(); ++it) { + delete *it; + guests_.erase(*it); + } +} + +void BrowserPluginWebContentsObserver::RenderViewDeleted( + RenderViewHost* render_view_host) { + DestroyGuests(); +} + +void BrowserPluginWebContentsObserver::RenderViewGone( + base::TerminationStatus status) { + DestroyGuests(); +} + +void BrowserPluginWebContentsObserver::WebContentsDestroyed( + WebContents* web_contents) { + DestroyGuests(); +} + +void BrowserPluginWebContentsObserver::Observe( + int type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED); + bool visible = *Details<bool>(details).ptr(); + + // If the host is hidden we need to hide the guests as well. + for (GuestMap::const_iterator it = guests_.begin(); + it != guests_.end(); ++it) { + TabContents* contents = it->first; + if (visible) + contents->ShowContents(); + else + contents->HideContents(); + } +} + +} // namespace content diff --git a/content/browser/browser_plugin/browser_plugin_web_contents_observer.h b/content/browser/browser_plugin/browser_plugin_web_contents_observer.h new file mode 100644 index 0000000..fc7722f --- /dev/null +++ b/content/browser/browser_plugin/browser_plugin_web_contents_observer.h @@ -0,0 +1,94 @@ +// 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_WEB_CONTENTS_OBSERVER_H__ +#define CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_WEB_CONTENTS_OBSERVER_H__ +#pragma once + +#include <map> + +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/web_contents_observer.h" +#include "ui/gfx/size.h" + +class TabContents; + +namespace content { + +class BrowserPluginWebContentsObserver: public WebContentsObserver, + public NotificationObserver { + public: + BrowserPluginWebContentsObserver(TabContents* web_contents); + + virtual ~BrowserPluginWebContentsObserver(); + + // A Host BrowserPluginWebContentsObserver keeps track of + // its guests so that if it navigates away, its associated RenderView + // crashes or it is hidden, it takes appropriate action on the guest. + void AddGuest(TabContents* guest, int64 frame_id); + + void RemoveGuest(TabContents* guest); + + TabContents* host() const { return host_; } + + void set_host(TabContents* host) { host_ = host; } + + int instance_id() const { return instance_id_; } + + void set_instance_id(int instance_id) { instance_id_ = instance_id; } + + // WebContentObserver implementation. + + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + virtual void DidCommitProvisionalLoadForFrame( + int64 frame_id, + bool is_main_frame, + const GURL& url, + PageTransition transition_type) OVERRIDE; + + virtual void RenderViewDeleted( + RenderViewHost* render_view_host) OVERRIDE; + + virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE; + + virtual void WebContentsDestroyed(WebContents* tab) OVERRIDE; + + private: + typedef std::map<TabContents*, int64> GuestMap; + + void OnOpenChannelToBrowserPlugin(int32 instance_id, + long long frame_id, + const std::string& src, + const gfx::Size& size); + + void OnGuestReady(); + + void OnResizeGuest(int width, int height); + + void OnRendererPluginChannelCreated(const IPC::ChannelHandle& handle); + + void DestroyGuests(); + + // NotificationObserver method override. + virtual void Observe(int type, + const NotificationSource& source, + const NotificationDetails& details) OVERRIDE; + + // A scoped container for notification registries. + NotificationRegistrar registrar_; + + TabContents* host_; + + // An identifier that uniquely identifies a browser plugin container + // within a host. + int instance_id_; + + GuestMap guests_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_WEB_CONTENTS_OBSERVER_H_ diff --git a/content/browser/tab_contents/tab_contents.cc b/content/browser/tab_contents/tab_contents.cc index cd36641..bbaf198 100644 --- a/content/browser/tab_contents/tab_contents.cc +++ b/content/browser/tab_contents/tab_contents.cc @@ -14,6 +14,7 @@ #include "base/string_util.h" #include "base/time.h" #include "base/utf_string_conversions.h" +#include "content/browser/browser_plugin/browser_plugin_web_contents_observer.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/debugger/devtools_manager_impl.h" #include "content/browser/download/download_stats.h" @@ -307,6 +308,9 @@ TabContents::TabContents(content::BrowserContext* browser_context, java_bridge_dispatcher_host_manager_.reset( new JavaBridgeDispatcherHostManager(this)); #endif + + browser_plugin_web_contents_observer_.reset( + new content::BrowserPluginWebContentsObserver(this)); } TabContents::~TabContents() { diff --git a/content/browser/tab_contents/tab_contents.h b/content/browser/tab_contents/tab_contents.h index 2fe0ec3..7110bf7 100644 --- a/content/browser/tab_contents/tab_contents.h +++ b/content/browser/tab_contents/tab_contents.h @@ -14,6 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "base/property_bag.h" +#include "content/browser/browser_plugin/browser_plugin_web_contents_observer.h" #include "content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h" #include "content/browser/tab_contents/navigation_controller_impl.h" #include "content/browser/tab_contents/render_view_host_manager.h" @@ -124,6 +125,11 @@ class CONTENT_EXPORT TabContents return java_bridge_dispatcher_host_manager_.get(); } + content::BrowserPluginWebContentsObserver* + browser_plugin_web_contents_observer() const { + return browser_plugin_web_contents_observer_.get(); + } + // Like GetController from WebContents, but returns the concrete object. NavigationControllerImpl& GetControllerImpl(); @@ -560,6 +566,8 @@ class CONTENT_EXPORT TabContents scoped_ptr<JavaBridgeDispatcherHostManager> java_bridge_dispatcher_host_manager_; + scoped_ptr<content::BrowserPluginWebContentsObserver> + browser_plugin_web_contents_observer_; // SavePackage, lazily created. scoped_refptr<SavePackage> save_package_; diff --git a/content/common/browser_plugin_messages.h b/content/common/browser_plugin_messages.h new file mode 100644 index 0000000..db40c45 --- /dev/null +++ b/content/common/browser_plugin_messages.h @@ -0,0 +1,72 @@ +// 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/size.h" + +#define IPC_MESSAGE_START BrowserPluginMsgStart + +// Browser plugin messages + +// ----------------------------------------------------------------------------- +// These messages are from the host renderer to the browser process + +// A renderer sends this to the browser process when it wants to +// create a browser plugin. The browser will create a guest renderer process +// if necessary. +IPC_MESSAGE_ROUTED4(BrowserPluginHostMsg_OpenChannel, + int /* plugin instance id*/, + long long /* frame id */, + std::string /* src */, + gfx::Size /* size */) + +// ----------------------------------------------------------------------------- +// These messages are from the browser process to the guest renderer. + +// Creates a channel to talk to a renderer. The guest renderer will respond +// with BrowserPluginHostMsg_ChannelCreated. +IPC_MESSAGE_CONTROL2(BrowserPluginMsg_CreateChannel, + base::ProcessHandle /* host_renderer_process_handle */, + int /* host_renderer_id */) + +// ----------------------------------------------------------------------------- +// These messages are from the guest renderer to the browser process + +// Reply to BrowserPluginMsg_CreateChannel. The handle will be NULL if the +// channel could not be established. This could be because the IPC could not be +// created for some weird reason, but more likely that the renderer failed to +// initialize properly. +IPC_MESSAGE_CONTROL1(BrowserPluginHostMsg_ChannelCreated, + IPC::ChannelHandle /* handle */) + +// Indicates the guest renderer is ready in response to a ViewMsg_New +IPC_MESSAGE_ROUTED0(BrowserPluginHostMsg_GuestReady) + +// A host renderer sends this message to the browser when it wants +// to resize a guest plugin container so that the guest is relaid out +// according to the new size. +IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_ResizeGuest, + int32, /* width */ + int32 /* height */) + +// ----------------------------------------------------------------------------- +// These messages are from the browser process to the host renderer. + +// A guest instance is ready to be placed. +IPC_MESSAGE_ROUTED3(BrowserPluginMsg_GuestReady_ACK, + int /* instance id */, + base::ProcessHandle /* plugin_process_handle */, + IPC::ChannelHandle /* handle to channel */) + + diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h index 9ef7371..82e650e 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_browser.gypi b/content/content_browser.gypi index 21b21d7..712d888 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -188,6 +188,8 @@ 'browser/browser_main_loop.cc', 'browser/browser_main_loop.h', 'browser/browser_main_runner.cc', + 'browser/browser_plugin/browser_plugin_web_contents_observer.cc', + 'browser/browser_plugin/browser_plugin_web_contents_observer.h', 'browser/browser_process_sub_thread.cc', 'browser/browser_process_sub_thread.h', 'browser/browser_thread_impl.cc', diff --git a/content/content_common.gypi b/content/content_common.gypi index 25f42b7..117339a 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -96,6 +96,7 @@ 'common/appcache/appcache_dispatcher.cc', 'common/appcache/appcache_dispatcher.h', 'common/appcache_messages.h', + 'common/browser_plugin_messages.h', 'common/child_process.cc', 'common/child_process.h', 'common/child_process_host_impl.cc', diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h index dc4a4be..8772b67 100644 --- a/ipc/ipc_message_utils.h +++ b/ipc/ipc_message_utils.h @@ -101,6 +101,7 @@ enum IPCMessageStart { AccessibilityMsgStart, PrerenderMsgStart, ChromotingMsgStart, + BrowserPluginMsgStart, LastIPCMsgStart // Must come last. }; |