Chromium Code Reviews| Index: content/browser/browser_plugin/browser_plugin_web_contents_observer.cc |
| 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 0000000000000000000000000000000000000000..fb2b3746ed0841bdaa79f337b19da0470b3401ab |
| --- /dev/null |
| +++ b/content/browser/browser_plugin/browser_plugin_web_contents_observer.cc |
| @@ -0,0 +1,246 @@ |
| +// 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/common/view_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" |
| + |
| +typedef std::map<content::WebContents*, |
| + content::BrowserPluginWebContentsObserver*> Instances; |
| + |
| +namespace { |
| +base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER; |
| +} // namespace |
| + |
| +namespace content { |
| + |
| +// static |
| +BrowserPluginWebContentsObserver* |
| +BrowserPluginWebContentsObserver::Get( |
| + WebContents* web_contents) { |
| + Instances::iterator it = g_instances.Get().find(web_contents); |
| + if (it != g_instances.Get().end()) |
| + return it->second; |
| + return new BrowserPluginWebContentsObserver(web_contents); |
| +} |
| + |
| +BrowserPluginWebContentsObserver::BrowserPluginWebContentsObserver( |
| + WebContents* web_contents) |
| + : WebContentsObserver(web_contents), |
| + host_(NULL), |
| + instance_id_(0) { |
| + registrar_.Add(this, |
| + NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, |
| + Source<RenderViewHost>( |
| + web_contents->GetRenderViewHost())); |
| + g_instances.Get()[web_contents] = this; |
| +} |
| + |
| +BrowserPluginWebContentsObserver::~BrowserPluginWebContentsObserver() { |
| + g_instances.Get().erase(web_contents()); |
| +} |
| + |
| +bool BrowserPluginWebContentsObserver::OnMessageReceived( |
| + const IPC::Message& message) { |
| + bool handled = true; |
| + IPC_BEGIN_MESSAGE_MAP(BrowserPluginWebContentsObserver, message) |
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_ChannelCreated, |
| + OnRendererPluginChannelCreated) |
| + IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToBrowserPlugin, |
| + OnOpenChannelToBrowserPlugin) |
| + IPC_MESSAGE_HANDLER(ViewHostMsg_GuestReady, OnMsgGuestReady) |
| + IPC_MESSAGE_HANDLER(ViewHostMsg_ResizeGuest, OnMsgResizeGuest) |
| + IPC_MESSAGE_UNHANDLED(handled = false) |
| + IPC_END_MESSAGE_MAP_EX() |
| + return handled; |
| +} |
| + |
| +void BrowserPluginWebContentsObserver::OnMsgGuestReady() { |
|
jam
2012/04/04 00:54:45
nit: just name handlers OnFoo, no need for "OnMsgF
Fady Samuel
2012/04/04 16:45:40
Done.
|
| + // 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. |
| + PpapiMsg_CreateChannel* msg = |
| + new PpapiMsg_CreateChannel(host()->GetRenderProcessHost()->GetHandle(), |
| + host()->GetRenderProcessHost()->GetID()); |
| + msg->set_routing_id(web_contents()->GetRenderViewHost()->GetRoutingID()); |
| + msg->set_unblock(true); |
|
jam
2012/04/04 00:54:45
are you sure you want this (set the unblock flag)?
Fady Samuel
2012/04/04 16:45:40
I believe you're right, I don't want the set_unblo
jam
2012/04/04 21:07:19
ping. are you sure you need this? check the docume
Fady Samuel
2012/04/05 19:35:40
Removed.
|
| + // 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::OnMsgResizeGuest( |
| + 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); |
| + WebContents* guest_web_contents = |
| + 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_web_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_web_contents->GetController().LoadURL( |
| + url, |
| + Referrer(), |
| + PAGE_TRANSITION_HOME_PAGE, |
| + std::string()); |
| + |
| + guest_render_view_host->GetView()->SetSize(size); |
| + BrowserPluginWebContentsObserver* guest_observer = Get(guest_web_contents); |
| + guest_observer->set_host(web_contents()); |
| + guest_observer->set_instance_id(instance_id); |
| + |
| + AddGuest(guest_web_contents, frame_id); |
| +} |
| + |
| +// Called when a new plugin <--> renderer channel has been created. |
|
jam
2012/04/04 00:54:45
nit: no need to document message handlers above th
Fady Samuel
2012/04/04 16:45:40
Done.
|
| +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 browser loading placeholder that we're done. |
| + // and that it can begin using the guest renderer. |
| + host()->GetRenderProcessHost()->Send( |
| + new ViewMsg_GuestReady_ACK( |
| + host()->GetRenderViewHost()->GetRoutingID(), |
| + instance_id(), |
| + renderers_plugin_handle, |
| + channel_handle)); |
| +} |
| + |
| +void BrowserPluginWebContentsObserver::AddGuest( |
| + WebContents* guest, |
| + int64 frame_id) { |
| + guests_[guest] = frame_id; |
| +} |
| + |
| +void BrowserPluginWebContentsObserver::RemoveGuest( |
| + WebContents* guest) { |
| + guests_.erase(guest); |
| +} |
| + |
| +void BrowserPluginWebContentsObserver::DestroyGuests() { |
| + for (GuestMap::const_iterator it = guests_.begin(); |
| + it != guests_.end(); ++it) { |
| + const WebContents* contents = it->first; |
| + delete contents; |
| + } |
| + guests_.clear(); |
| +} |
| + |
| +void BrowserPluginWebContentsObserver::DidCommitProvisionalLoadForFrame( |
| + int64 frame_id, |
| + bool is_main_frame, |
| + const GURL& url, |
| + PageTransition transition_type) { |
| + GuestSet guests_to_delete; |
| + for (GuestMap::const_iterator it = guests_.begin(); |
| + it != guests_.end(); ++it) { |
| + WebContents* 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) { |
| + WebContents* contents = it->first; |
| + if (visible) |
| + contents->ShowContents(); |
| + else |
| + contents->HideContents(); |
| + } |
| +} |
| + |
| +} // namespace content |