Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/browser_plugin/browser_plugin_web_contents_observer.h" | |
| 6 | |
| 7 #include "base/lazy_instance.h" | |
| 8 #include "content/browser/renderer_host/render_view_host_impl.h" | |
| 9 #include "content/common/view_messages.h" | |
| 10 #include "content/public/browser/browser_thread.h" | |
| 11 #include "content/public/browser/notification_details.h" | |
| 12 #include "content/public/browser/notification_source.h" | |
| 13 #include "content/public/browser/notification_types.h" | |
| 14 #include "content/public/browser/render_process_host.h" | |
| 15 #include "content/public/browser/render_widget_host.h" | |
| 16 #include "content/public/browser/render_widget_host_view.h" | |
| 17 #include "content/public/browser/render_view_host.h" | |
| 18 #include "content/public/browser/site_instance.h" | |
| 19 #include "content/public/browser/web_contents.h" | |
| 20 #include "ppapi/proxy/ppapi_messages.h" | |
| 21 | |
| 22 typedef std::map<content::WebContents*, | |
| 23 content::BrowserPluginWebContentsObserver*> Instances; | |
| 24 | |
| 25 namespace { | |
| 26 base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER; | |
| 27 } // namespace | |
| 28 | |
| 29 namespace content { | |
| 30 | |
| 31 // static | |
| 32 BrowserPluginWebContentsObserver* | |
| 33 BrowserPluginWebContentsObserver::Get( | |
| 34 WebContents* web_contents) { | |
| 35 Instances::iterator it = g_instances.Get().find(web_contents); | |
| 36 if (it != g_instances.Get().end()) | |
| 37 return it->second; | |
| 38 return new BrowserPluginWebContentsObserver(web_contents); | |
| 39 } | |
| 40 | |
| 41 BrowserPluginWebContentsObserver::BrowserPluginWebContentsObserver( | |
| 42 WebContents* web_contents) | |
| 43 : WebContentsObserver(web_contents), | |
| 44 host_(NULL), | |
| 45 instance_id_(0) { | |
| 46 registrar_.Add(this, | |
| 47 NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, | |
| 48 Source<RenderViewHost>( | |
| 49 web_contents->GetRenderViewHost())); | |
| 50 g_instances.Get()[web_contents] = this; | |
| 51 } | |
| 52 | |
| 53 BrowserPluginWebContentsObserver::~BrowserPluginWebContentsObserver() { | |
| 54 g_instances.Get().erase(web_contents()); | |
| 55 } | |
| 56 | |
| 57 bool BrowserPluginWebContentsObserver::OnMessageReceived( | |
| 58 const IPC::Message& message) { | |
| 59 bool handled = true; | |
| 60 IPC_BEGIN_MESSAGE_MAP(BrowserPluginWebContentsObserver, message) | |
| 61 IPC_MESSAGE_HANDLER(PpapiHostMsg_ChannelCreated, | |
| 62 OnRendererPluginChannelCreated) | |
| 63 IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToBrowserPlugin, | |
| 64 OnOpenChannelToBrowserPlugin) | |
| 65 IPC_MESSAGE_HANDLER(ViewHostMsg_GuestReady, OnMsgGuestReady) | |
| 66 IPC_MESSAGE_HANDLER(ViewHostMsg_ResizeGuest, OnMsgResizeGuest) | |
| 67 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 68 IPC_END_MESSAGE_MAP_EX() | |
| 69 return handled; | |
| 70 } | |
| 71 | |
| 72 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.
| |
| 73 // We only care about handling this message on guests. | |
| 74 if (!host()) | |
| 75 return; | |
| 76 | |
| 77 // The renderer is now ready to receive ppapi messages. | |
| 78 // Let's tell it create a channel with the embedder/host. | |
| 79 PpapiMsg_CreateChannel* msg = | |
| 80 new PpapiMsg_CreateChannel(host()->GetRenderProcessHost()->GetHandle(), | |
| 81 host()->GetRenderProcessHost()->GetID()); | |
| 82 msg->set_routing_id(web_contents()->GetRenderViewHost()->GetRoutingID()); | |
| 83 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.
| |
| 84 // TODO(fsamuel): If we aren't able to successfully send this message | |
| 85 // to the guest then that probably means it crashed. Is there anything | |
| 86 // we can do that's cleaner than failing a check? | |
| 87 CHECK(Send(msg)); | |
| 88 } | |
| 89 | |
| 90 void BrowserPluginWebContentsObserver::OnMsgResizeGuest( | |
| 91 int width, int height) { | |
| 92 // Tell the RenderWidgetHostView to adjust its size. | |
| 93 web_contents()->GetRenderViewHost()->GetView()->SetSize( | |
| 94 gfx::Size(width, height)); | |
| 95 } | |
| 96 | |
| 97 void BrowserPluginWebContentsObserver::OnOpenChannelToBrowserPlugin( | |
| 98 int instance_id, | |
| 99 long long frame_id, | |
| 100 const std::string& src, | |
| 101 const gfx::Size& size) { | |
| 102 BrowserContext* browser_context = | |
| 103 web_contents()->GetRenderViewHost()->GetProcess()->GetBrowserContext(); | |
| 104 DCHECK(browser_context); | |
| 105 | |
| 106 GURL url(src); | |
| 107 SiteInstance* site_instance = | |
| 108 SiteInstance::CreateForURL( | |
| 109 browser_context, url); | |
| 110 WebContents* guest_web_contents = | |
| 111 WebContents::Create( | |
| 112 browser_context, | |
| 113 site_instance, | |
| 114 MSG_ROUTING_NONE, | |
| 115 NULL, // base tab contents | |
| 116 NULL // session storage namespace | |
| 117 ); | |
| 118 // TODO(fsamuel): Set the WebContentsDelegate here. | |
| 119 RenderViewHostImpl* guest_render_view_host = | |
| 120 static_cast<RenderViewHostImpl*>( | |
| 121 guest_web_contents->GetRenderViewHost()); | |
| 122 | |
| 123 // We need to make sure that the RenderViewHost knows that it's | |
| 124 // hosting a guest RenderView so that it informs the RenderView | |
| 125 // on a ViewMsg_New. Guest RenderViews will avoid compositing | |
| 126 // until a guest-to-host channel has been initialized. | |
| 127 guest_render_view_host->set_guest(true); | |
| 128 | |
| 129 guest_web_contents->GetController().LoadURL( | |
| 130 url, | |
| 131 Referrer(), | |
| 132 PAGE_TRANSITION_HOME_PAGE, | |
| 133 std::string()); | |
| 134 | |
| 135 guest_render_view_host->GetView()->SetSize(size); | |
| 136 BrowserPluginWebContentsObserver* guest_observer = Get(guest_web_contents); | |
| 137 guest_observer->set_host(web_contents()); | |
| 138 guest_observer->set_instance_id(instance_id); | |
| 139 | |
| 140 AddGuest(guest_web_contents, frame_id); | |
| 141 } | |
| 142 | |
| 143 // 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.
| |
| 144 void BrowserPluginWebContentsObserver::OnRendererPluginChannelCreated( | |
| 145 const IPC::ChannelHandle& channel_handle) { | |
| 146 DCHECK(host()); | |
| 147 // Prepare the handle to send to the renderer. | |
| 148 base::ProcessHandle plugin_process = | |
| 149 web_contents()->GetRenderProcessHost()->GetHandle(); | |
| 150 #if defined(OS_WIN) | |
| 151 base::ProcessHandle renderer_process = | |
| 152 host()->GetRenderProcessHost()->GetHandle(); | |
| 153 int renderer_id = host()->GetRenderProcessHost()->GetID(); | |
| 154 | |
| 155 base::ProcessHandle renderers_plugin_handle = NULL; | |
| 156 ::DuplicateHandle(::GetCurrentProcess(), plugin_process, | |
| 157 renderer_process, &renderers_plugin_handle, | |
| 158 0, FALSE, DUPLICATE_SAME_ACCESS); | |
| 159 #elif defined(OS_POSIX) | |
| 160 // Don't need to duplicate anything on POSIX since it's just a PID. | |
| 161 base::ProcessHandle renderers_plugin_handle = plugin_process; | |
| 162 #endif | |
| 163 // Tell the browser loading placeholder that we're done. | |
| 164 // and that it can begin using the guest renderer. | |
| 165 host()->GetRenderProcessHost()->Send( | |
| 166 new ViewMsg_GuestReady_ACK( | |
| 167 host()->GetRenderViewHost()->GetRoutingID(), | |
| 168 instance_id(), | |
| 169 renderers_plugin_handle, | |
| 170 channel_handle)); | |
| 171 } | |
| 172 | |
| 173 void BrowserPluginWebContentsObserver::AddGuest( | |
| 174 WebContents* guest, | |
| 175 int64 frame_id) { | |
| 176 guests_[guest] = frame_id; | |
| 177 } | |
| 178 | |
| 179 void BrowserPluginWebContentsObserver::RemoveGuest( | |
| 180 WebContents* guest) { | |
| 181 guests_.erase(guest); | |
| 182 } | |
| 183 | |
| 184 void BrowserPluginWebContentsObserver::DestroyGuests() { | |
| 185 for (GuestMap::const_iterator it = guests_.begin(); | |
| 186 it != guests_.end(); ++it) { | |
| 187 const WebContents* contents = it->first; | |
| 188 delete contents; | |
| 189 } | |
| 190 guests_.clear(); | |
| 191 } | |
| 192 | |
| 193 void BrowserPluginWebContentsObserver::DidCommitProvisionalLoadForFrame( | |
| 194 int64 frame_id, | |
| 195 bool is_main_frame, | |
| 196 const GURL& url, | |
| 197 PageTransition transition_type) { | |
| 198 GuestSet guests_to_delete; | |
| 199 for (GuestMap::const_iterator it = guests_.begin(); | |
| 200 it != guests_.end(); ++it) { | |
| 201 WebContents* contents = it->first; | |
| 202 if (it->second == frame_id) { | |
| 203 guests_to_delete.insert(contents); | |
| 204 } | |
| 205 } | |
| 206 for (GuestSet::const_iterator it = guests_to_delete.begin(); | |
| 207 it != guests_to_delete.end(); ++it) { | |
| 208 delete *it; | |
| 209 guests_.erase(*it); | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 void BrowserPluginWebContentsObserver::RenderViewDeleted( | |
| 214 RenderViewHost* render_view_host) { | |
| 215 DestroyGuests(); | |
| 216 } | |
| 217 | |
| 218 void BrowserPluginWebContentsObserver::RenderViewGone( | |
| 219 base::TerminationStatus status) { | |
| 220 DestroyGuests(); | |
| 221 } | |
| 222 | |
| 223 void BrowserPluginWebContentsObserver::WebContentsDestroyed( | |
| 224 WebContents* web_contents) { | |
| 225 DestroyGuests(); | |
| 226 } | |
| 227 | |
| 228 void BrowserPluginWebContentsObserver::Observe( | |
| 229 int type, | |
| 230 const NotificationSource& source, | |
| 231 const NotificationDetails& details) { | |
| 232 DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED); | |
| 233 bool visible = *Details<bool>(details).ptr(); | |
| 234 | |
| 235 // If the host is hidden we need to hide the guests as well. | |
| 236 for (GuestMap::const_iterator it = guests_.begin(); | |
| 237 it != guests_.end(); ++it) { | |
| 238 WebContents* contents = it->first; | |
| 239 if (visible) | |
| 240 contents->ShowContents(); | |
| 241 else | |
| 242 contents->HideContents(); | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 } // namespace content | |
| OLD | NEW |