| // 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/web_contents/web_contents_impl.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( |
| WebContentsImpl* web_contents) |
| : WebContentsObserver(web_contents), |
| host_(NULL), |
| instance_id_(0) { |
| registrar_.Add(this, |
| NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, |
| Source<RenderViewHost>( |
| web_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() |
| 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); |
| WebContentsImpl* guest_web_contents = |
| static_cast<WebContentsImpl*>( |
| WebContents::Create( |
| browser_context, |
| site_instance, |
| MSG_ROUTING_NONE, |
| NULL, // base WebContents |
| 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 = |
| guest_web_contents->browser_plugin_web_contents_observer(); |
| guest_observer->set_host(static_cast<WebContentsImpl*>(web_contents())); |
| guest_observer->set_instance_id(instance_id); |
| |
| AddGuest(guest_web_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(WebContentsImpl* guest, |
| int64 frame_id) { |
| guests_[guest] = frame_id; |
| } |
| |
| void BrowserPluginWebContentsObserver::RemoveGuest(WebContentsImpl* guest) { |
| guests_.erase(guest); |
| } |
| |
| void BrowserPluginWebContentsObserver::DestroyGuests() { |
| for (GuestMap::const_iterator it = guests_.begin(); |
| it != guests_.end(); ++it) { |
| const WebContentsImpl* web_contents = it->first; |
| delete web_contents; |
| } |
| guests_.clear(); |
| } |
| |
| void BrowserPluginWebContentsObserver::DidCommitProvisionalLoadForFrame( |
| int64 frame_id, |
| bool is_main_frame, |
| const GURL& url, |
| PageTransition transition_type) { |
| typedef std::set<WebContentsImpl*> GuestSet; |
| GuestSet guests_to_delete; |
| for (GuestMap::const_iterator it = guests_.begin(); |
| it != guests_.end(); ++it) { |
| WebContentsImpl* web_contents = it->first; |
| if (it->second == frame_id) { |
| guests_to_delete.insert(web_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) { |
| WebContentsImpl* web_contents = it->first; |
| if (visible) |
| web_contents->ShowContents(); |
| else |
| web_contents->HideContents(); |
| } |
| } |
| |
| } // namespace content |