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_host.h" | |
| 6 | |
| 7 #include "base/utf_string_conversions.h" | |
| 8 #include "content/browser/browser_plugin/browser_plugin_host_helper.h" | |
| 9 #include "content/browser/renderer_host/render_view_host_impl.h" | |
| 10 #include "content/browser/web_contents/web_contents_impl.h" | |
| 11 #include "content/common/browser_plugin_messages.h" | |
| 12 #include "content/common/view_messages.h" | |
| 13 #include "content/port/browser/render_widget_host_view_port.h" | |
| 14 #include "content/public/browser/notification_details.h" | |
| 15 #include "content/public/browser/notification_service.h" | |
| 16 #include "content/public/browser/notification_source.h" | |
| 17 #include "content/public/browser/notification_types.h" | |
| 18 #include "content/public/browser/render_process_host.h" | |
| 19 #include "content/public/browser/render_widget_host_view.h" | |
| 20 #include "content/public/browser/site_instance.h" | |
| 21 #include "content/public/browser/web_contents_view.h" | |
| 22 #include "content/public/common/result_codes.h" | |
| 23 #include "content/public/common/url_constants.h" | |
| 24 | |
| 25 namespace content { | |
| 26 | |
| 27 namespace { | |
| 28 const int kGuestHangTimeout = 5000; | |
| 29 } | |
| 30 | |
| 31 BrowserPluginHost::BrowserPluginHost( | |
| 32 WebContentsImpl* web_contents) | |
| 33 : WebContentsObserver(web_contents), | |
| 34 embedder_render_process_host_(NULL), | |
| 35 instance_id_(0), | |
| 36 damage_buffer_(NULL), | |
| 37 pending_update_counter_(0) { | |
| 38 // Listen to visibility changes so that an embedder hides its guests | |
| 39 // as well. | |
| 40 registrar_.Add(this, | |
| 41 NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED, | |
| 42 Source<WebContents>(web_contents)); | |
| 43 // Construct plumbing helpers when a new RenderViewHost is created for | |
| 44 // this BrowserPluginHost's WebContentsImpl. | |
| 45 registrar_.Add(this, | |
| 46 NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED, | |
| 47 Source<WebContents>(web_contents)); | |
| 48 } | |
| 49 | |
| 50 BrowserPluginHost::~BrowserPluginHost() { | |
| 51 if (damage_buffer_) | |
| 52 delete damage_buffer_; | |
| 53 } | |
| 54 | |
| 55 BrowserPluginHost* BrowserPluginHost::GetGuestByInstanceID( | |
| 56 int container_id) const { | |
| 57 ContainerInstanceMap::const_iterator it = | |
| 58 guests_by_instance_id_.find(container_id); | |
| 59 if (it != guests_by_instance_id_.end()) | |
| 60 return it->second; | |
| 61 return NULL; | |
| 62 } | |
| 63 | |
| 64 void BrowserPluginHost::AddGuest(int instance_id, | |
| 65 BrowserPluginHost* guest, | |
| 66 int64 frame_id) { | |
| 67 DCHECK(guests_by_instance_id_.find(instance_id) == | |
| 68 guests_by_instance_id_.end()); | |
| 69 guests_by_instance_id_[instance_id] = guest; | |
| 70 guests_[guest->web_contents()] = frame_id; | |
| 71 } | |
| 72 | |
| 73 bool BrowserPluginHost::TakeFocus(bool reverse) { | |
| 74 embedder_render_process_host()->Send( | |
| 75 new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse)); | |
| 76 return true; | |
| 77 } | |
| 78 | |
| 79 void BrowserPluginHost::RendererUnresponsive(WebContents* source) { | |
| 80 base::ProcessHandle process_handle = | |
| 81 web_contents()->GetRenderProcessHost()->GetHandle(); | |
| 82 base::KillProcess(process_handle, RESULT_CODE_HUNG, false); | |
|
Charlie Reis
2012/08/13 17:50:14
I don't think we want to kill an unresponsive rend
Fady Samuel
2012/08/13 21:30:08
Discussed offline. For the time being this still n
| |
| 83 } | |
| 84 | |
| 85 bool BrowserPluginHost::OnMessageReceived(const IPC::Message& message) { | |
| 86 return false; | |
| 87 } | |
| 88 | |
| 89 void BrowserPluginHost::NavigateOrCreateGuest( | |
| 90 RenderViewHost* render_view_host, | |
| 91 int instance_id, | |
| 92 long long frame_id, | |
|
Charlie Reis
2012/08/13 17:50:14
Most frame_ids in view_messages.h are int64. Why
Fady Samuel
2012/08/13 21:30:08
Done.
| |
| 93 const std::string& src, | |
| 94 const gfx::Size& size) { | |
| 95 BrowserPluginHost* guest = | |
| 96 GetGuestByInstanceID(instance_id); | |
| 97 WebContentsImpl* guest_web_contents = | |
| 98 guest ? | |
| 99 static_cast<WebContentsImpl*>(guest->web_contents()): NULL; | |
|
Charlie Reis
2012/08/13 17:50:14
This feels awkward. Why not just set it to null h
| |
| 100 GURL url(src); | |
| 101 if (!guest) { | |
| 102 std::string host = render_view_host->GetSiteInstance()->GetSite().host(); | |
| 103 GURL guest_url( | |
| 104 base::StringPrintf("%s://%s", chrome::kGuestScheme, host.c_str())); | |
|
Charlie Reis
2012/08/13 17:50:14
nit: guest_url -> guest_site
| |
| 105 // The SiteInstance of a given guest is based on the fact that it's a guest | |
| 106 // in addition to which platform application the guest belongs to, rather | |
| 107 // than the URL that the guest is being navigated to. | |
|
Charlie Reis
2012/08/13 17:50:14
nit: Please move this comment above the host decla
| |
| 108 SiteInstance* guest_site_instance = | |
| 109 SiteInstance::CreateForURL(web_contents()->GetBrowserContext(), | |
| 110 guest_url); | |
|
Charlie Reis
2012/08/13 17:50:14
nit: Wrong indent (should be even with the first a
| |
| 111 guest_web_contents = | |
| 112 static_cast<WebContentsImpl*>( | |
| 113 WebContents::Create( | |
| 114 web_contents()->GetBrowserContext(), | |
| 115 guest_site_instance, | |
| 116 MSG_ROUTING_NONE, | |
| 117 NULL, // base WebContents | |
| 118 NULL // session storage namespace | |
| 119 )); | |
| 120 guest = guest_web_contents->browser_plugin_host(); | |
|
Charlie Reis
2012/08/13 17:50:14
I find it odd that all WebContents automatically h
| |
| 121 guest->set_embedder_render_process_host( | |
| 122 render_view_host->GetProcess()); | |
| 123 guest->set_instance_id(instance_id); | |
| 124 guest_web_contents->GetMutableRendererPrefs()-> | |
| 125 throttle_input_events = false; | |
| 126 AddGuest(instance_id, guest, frame_id); | |
| 127 } | |
| 128 guest->web_contents()->SetDelegate(guest); | |
| 129 guest->web_contents()->GetController().LoadURL( | |
| 130 url, | |
| 131 Referrer(), | |
| 132 PAGE_TRANSITION_AUTO_SUBFRAME, | |
| 133 std::string()); | |
| 134 if (!size.IsEmpty()) | |
| 135 guest_web_contents->GetView()->SizeContents(size); | |
| 136 } | |
| 137 | |
| 138 void BrowserPluginHost::SetDamageBuffer(TransportDIB* damage_buffer, | |
| 139 const gfx::Size& size, | |
| 140 float scale_factor) { | |
| 141 if (damage_buffer_) | |
| 142 delete damage_buffer_; | |
| 143 damage_buffer_ = damage_buffer; | |
| 144 damage_buffer_size_ = size; | |
| 145 damage_buffer_scale_factor_ = scale_factor; | |
| 146 } | |
| 147 | |
| 148 void BrowserPluginHost::ResizeGuest(int instance_id, | |
| 149 TransportDIB* damage_buffer, | |
| 150 int width, int height, | |
| 151 bool resize_pending, | |
| 152 float scale_factor) { | |
| 153 BrowserPluginHost* guest = GetGuestByInstanceID(instance_id); | |
| 154 if (!guest) | |
| 155 return; | |
| 156 WebContentsImpl* guest_web_contents = | |
| 157 guest ? static_cast<WebContentsImpl*>(guest->web_contents()): NULL; | |
|
Charlie Reis
2012/08/13 17:50:14
nit: Space before :
| |
| 158 guest->SetDamageBuffer(damage_buffer, gfx::Size(width, height), scale_factor); | |
|
Charlie Reis
2012/08/13 17:50:14
Won't this crash if guest is null? (You just null
| |
| 159 if (!resize_pending) | |
| 160 guest_web_contents->GetView()->SizeContents(gfx::Size(width, height)); | |
| 161 } | |
| 162 | |
| 163 void BrowserPluginHost::UpdateRect( | |
| 164 RenderViewHost* render_view_host, | |
| 165 const ViewHostMsg_UpdateRect_Params& params) { | |
| 166 // This handler is only of interest to us for the 2D software rendering path. | |
| 167 // needs_ack should always be true for the 2D path. | |
| 168 // TODO(fsamuel): Do we need to do something different in the 3D case? | |
| 169 if (!params.needs_ack) | |
| 170 return; | |
| 171 | |
| 172 // Only copy damage if the guest's view size is equal to the damage buffer's | |
| 173 // size and the guest's scale factor is equal to the damage buffer's scale | |
| 174 // factor. | |
| 175 if (params.view_size.width() == damage_buffer_size().width() && | |
| 176 params.view_size.height() == damage_buffer_size().height() && | |
| 177 params.scale_factor == damage_buffer_scale_factor()) { | |
| 178 TransportDIB* dib = render_view_host->GetProcess()-> | |
| 179 GetTransportDIB(params.bitmap); | |
| 180 if (dib) { | |
| 181 void* guest_memory = dib->memory(); | |
| 182 void* embedder_memory = damage_buffer_->memory(); | |
| 183 int size = std::min(dib->size(), damage_buffer_->size()); | |
| 184 memcpy(embedder_memory, guest_memory, size); | |
| 185 } | |
| 186 } | |
| 187 DCHECK(embedder_render_process_host()); | |
| 188 BrowserPluginMsg_UpdateRect_Params relay_params; | |
| 189 relay_params.bitmap_rect = params.bitmap_rect; | |
| 190 relay_params.dx = params.dx; | |
| 191 relay_params.dy = params.dy; | |
| 192 relay_params.scroll_rect = params.scroll_rect; | |
| 193 relay_params.copy_rects = params.copy_rects; | |
| 194 relay_params.view_size = params.view_size; | |
| 195 relay_params.scale_factor = params.scale_factor; | |
| 196 relay_params.is_resize_ack = ViewHostMsg_UpdateRect_Flags::is_resize_ack( | |
| 197 params.flags); | |
| 198 | |
| 199 // We need to send the ACK to the same render_view_host that issued | |
| 200 // the UpdateRect. We keep track of this correspondence via a message_id. | |
| 201 int message_id = pending_update_counter_++; | |
| 202 pending_updates_.AddWithID(render_view_host, message_id); | |
| 203 | |
| 204 gfx::Size param_size = gfx::Size( | |
| 205 params.view_size.width(), | |
| 206 params.view_size.height()); | |
| 207 content::NotificationService::current()->Notify( | |
| 208 NOTIFICATION_BROWSER_PLUGIN_UPDATE_RECT, | |
| 209 content::Source<BrowserPluginHost>(this), | |
| 210 content::Details<const gfx::Size>(¶m_size)); | |
| 211 | |
| 212 embedder_render_process_host()->Send( | |
| 213 new BrowserPluginMsg_UpdateRect(instance_id(), | |
| 214 message_id, | |
| 215 relay_params)); | |
| 216 } | |
| 217 | |
| 218 void BrowserPluginHost::UpdateRectACK(int message_id, | |
| 219 const gfx::Size& size) { | |
| 220 RenderViewHost* render_view_host = pending_updates_.Lookup(message_id); | |
| 221 // If the guest has crashed since it sent the initial ViewHostMsg_UpdateRect | |
| 222 // then the pending_updates_ map will have been cleared. | |
| 223 if (!render_view_host) | |
| 224 return; | |
| 225 pending_updates_.Remove(message_id); | |
| 226 render_view_host->Send( | |
| 227 new ViewMsg_UpdateRect_ACK(render_view_host->GetRoutingID())); | |
| 228 if (!size.IsEmpty()) | |
| 229 render_view_host->GetView()->SetSize(size); | |
| 230 } | |
| 231 | |
| 232 void BrowserPluginHost::HandleInputEvent( | |
| 233 RenderViewHost* render_view_host, | |
| 234 const gfx::Rect& guest_rect, | |
| 235 const WebKit::WebInputEvent& event, | |
| 236 IPC::Message* reply_message) { | |
| 237 guest_rect_ = guest_rect; | |
| 238 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>( | |
| 239 web_contents()->GetRenderViewHost()); | |
| 240 IPC::Message* message = new ViewMsg_HandleInputEvent( | |
| 241 guest_rvh->GetRoutingID()); | |
| 242 | |
| 243 // Copy the WebInputEvent and modify the event type. The guest expects | |
| 244 // WebInputEvent::RawKeyDowns and not KeyDowns. | |
| 245 scoped_array<char> input_buffer(new char[event.size]); | |
| 246 memcpy(input_buffer.get(), &event, event.size); | |
| 247 WebKit::WebInputEvent* input_event = | |
| 248 reinterpret_cast<WebKit::WebInputEvent*>(input_buffer.get()); | |
| 249 if (event.type == WebKit::WebInputEvent::KeyDown) | |
| 250 input_event->type = WebKit::WebInputEvent::RawKeyDown; | |
| 251 | |
| 252 message->WriteData(input_buffer.get(), event.size); | |
| 253 // TODO(fsamuel): What do we need to do here? This is for keyboard shortcuts. | |
| 254 if (input_event->type == WebKit::WebInputEvent::RawKeyDown) | |
| 255 message->WriteBool(false); | |
| 256 guest_rvh->Send(message); | |
| 257 | |
| 258 DCHECK(!pending_input_event_reply_.get()); | |
| 259 pending_input_event_reply_.reset(reply_message); | |
| 260 guest_rvh->StartHangMonitorTimeout( | |
| 261 base::TimeDelta::FromMilliseconds(kGuestHangTimeout)); | |
| 262 } | |
| 263 | |
| 264 void BrowserPluginHost::HandleInputEventAck(RenderViewHost* render_view_host, | |
| 265 bool handled) { | |
| 266 DCHECK(pending_input_event_reply_.get()); | |
| 267 IPC::Message* reply_message = pending_input_event_reply_.release(); | |
| 268 BrowserPluginHostMsg_HandleInputEvent::WriteReplyParams(reply_message, | |
| 269 handled, | |
| 270 cursor_); | |
| 271 embedder_render_process_host()->Send(reply_message); | |
| 272 RenderViewHostImpl* guest_rvh = | |
| 273 static_cast<RenderViewHostImpl*>(render_view_host); | |
| 274 guest_rvh->StopHangMonitorTimeout(); | |
| 275 } | |
| 276 | |
| 277 void BrowserPluginHost::SetFocus(bool focused) { | |
| 278 RenderViewHost* render_view_host = web_contents()->GetRenderViewHost(); | |
| 279 render_view_host->Send( | |
| 280 new ViewMsg_SetFocus(render_view_host->GetRoutingID(), focused)); | |
| 281 } | |
| 282 | |
| 283 void BrowserPluginHost::ShowWidget(RenderViewHost* render_view_host, | |
| 284 int route_id, | |
| 285 const gfx::Rect& initial_pos) { | |
| 286 RenderWidgetHostView* popup_rwhv = | |
| 287 static_cast<WebContentsImpl*>(web_contents())-> | |
| 288 GetCreatedWidget(route_id); | |
| 289 | |
| 290 RenderWidgetHostViewPort* widget_host_view = | |
| 291 RenderWidgetHostViewPort::FromRWHV(popup_rwhv); | |
| 292 if (!widget_host_view) | |
| 293 return; | |
| 294 gfx::Rect screen_pos(initial_pos); | |
| 295 screen_pos.Offset(guest_rect_.origin()); | |
| 296 widget_host_view->InitAsPopup(web_contents()->GetRenderWidgetHostView(), | |
| 297 screen_pos); | |
| 298 RenderWidgetHostImpl* render_widget_host_impl = | |
| 299 RenderWidgetHostImpl::From(widget_host_view->GetRenderWidgetHost()); | |
| 300 render_widget_host_impl->Init(); | |
| 301 render_widget_host_impl->set_allow_privileged_mouse_lock(false); | |
| 302 } | |
| 303 | |
| 304 void BrowserPluginHost::SetCursor(const WebCursor& cursor) { | |
| 305 cursor_ = cursor; | |
| 306 } | |
| 307 | |
| 308 void BrowserPluginHost::DestroyGuests() { | |
| 309 for (GuestMap::const_iterator it = guests_.begin(); | |
| 310 it != guests_.end(); ++it) { | |
| 311 WebContents* web_contents = it->first; | |
| 312 delete web_contents; | |
| 313 } | |
| 314 guests_.clear(); | |
| 315 guests_by_instance_id_.clear(); | |
| 316 } | |
| 317 | |
| 318 void BrowserPluginHost::DestroyGuestByInstanceID(int instance_id) { | |
| 319 | |
|
Charlie Reis
2012/08/13 17:50:14
nit: No empty line.
| |
| 320 BrowserPluginHost* guest = GetGuestByInstanceID(instance_id); | |
| 321 if (!guest) | |
| 322 return; | |
| 323 WebContents* guest_web_contents = guest->web_contents(); | |
| 324 DCHECK(guest_web_contents); | |
| 325 delete guest_web_contents; | |
| 326 | |
| 327 GuestMap::iterator guest_it = guests_.find(guest_web_contents); | |
| 328 DCHECK(guest_it != guests_.end()); | |
| 329 | |
| 330 guests_.erase(guest_it); | |
| 331 guests_by_instance_id_.erase(instance_id); | |
| 332 } | |
| 333 | |
| 334 void BrowserPluginHost::DidCommitProvisionalLoadForFrame( | |
| 335 int64 frame_id, | |
| 336 bool is_main_frame, | |
| 337 const GURL& url, | |
| 338 PageTransition transition_type, | |
| 339 RenderViewHost* render_view_host) { | |
| 340 // Clean-up guests that lie in the frame that we're navigating. | |
| 341 typedef std::set<WebContents*> GuestSet; | |
| 342 GuestSet guests_to_delete; | |
|
Charlie Reis
2012/08/13 17:50:14
This looks like it finds all the guests in the fra
| |
| 343 for (GuestMap::const_iterator it = guests_.begin(); | |
| 344 it != guests_.end(); ++it) { | |
| 345 WebContents* web_contents = it->first; | |
| 346 if (it->second == frame_id) { | |
|
Charlie Reis
2012/08/13 17:50:14
nit: No braces needed for one-line if.
| |
| 347 guests_to_delete.insert(web_contents); | |
| 348 } | |
| 349 } | |
| 350 for (GuestSet::const_iterator it = guests_to_delete.begin(); | |
| 351 it != guests_to_delete.end(); ++it) { | |
| 352 int instance_id = static_cast<WebContentsImpl*>(*it)-> | |
| 353 browser_plugin_host()->instance_id(); | |
| 354 DestroyGuestByInstanceID(instance_id); | |
| 355 } | |
| 356 // If this is a guest, inform its embedder of the updated URL. | |
| 357 // TODO(creis, fsamuel): Ensure this is safe/secure. | |
| 358 if (is_main_frame && embedder_render_process_host()) { | |
| 359 embedder_render_process_host()->Send( | |
| 360 new BrowserPluginMsg_DidNavigate(instance_id(), url)); | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 void BrowserPluginHost::RenderViewDeleted(RenderViewHost* render_view_host) { | |
| 365 DestroyGuests(); | |
| 366 } | |
| 367 | |
| 368 void BrowserPluginHost::RenderViewGone(base::TerminationStatus status) { | |
| 369 DestroyGuests(); | |
| 370 if (embedder_render_process_host()) { | |
| 371 if (pending_input_event_reply_.get()) { | |
| 372 IPC::Message* reply_message = pending_input_event_reply_.release(); | |
| 373 BrowserPluginHostMsg_HandleInputEvent::WriteReplyParams(reply_message, | |
| 374 false, | |
| 375 cursor_); | |
| 376 embedder_render_process_host()->Send(reply_message); | |
| 377 } | |
| 378 embedder_render_process_host()->Send( | |
| 379 new BrowserPluginMsg_GuestCrashed(instance_id())); | |
| 380 IDMap<RenderViewHost>::const_iterator iter(&pending_updates_); | |
| 381 while (!iter.IsAtEnd()) { | |
| 382 pending_updates_.Remove(iter.GetCurrentKey()); | |
| 383 iter.Advance(); | |
| 384 } | |
| 385 content::NotificationService::current()->Notify( | |
| 386 NOTIFICATION_BROWSER_PLUGIN_GUEST_CRASHED, | |
| 387 content::Source<BrowserPluginHost>(this), | |
| 388 content::NotificationService::NoDetails()); | |
| 389 } | |
| 390 } | |
| 391 | |
| 392 void BrowserPluginHost::Observe( | |
| 393 int type, | |
| 394 const NotificationSource& source, | |
| 395 const NotificationDetails& details) { | |
| 396 switch (type) { | |
| 397 case NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: { | |
| 398 RenderViewHost* render_view_host = | |
| 399 Details<RenderViewHost>(details).ptr(); | |
| 400 // BrowserPluginHostHelper is destroyed when its associated RenderViewHost | |
| 401 // is destroyed. | |
| 402 new BrowserPluginHostHelper(this, render_view_host); | |
| 403 break; | |
| 404 } | |
| 405 case NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED: { | |
| 406 bool visible = *Details<bool>(details).ptr(); | |
| 407 // If the embedder is hidden we need to hide the guests as well. | |
| 408 for (GuestMap::const_iterator it = guests_.begin(); | |
| 409 it != guests_.end(); ++it) { | |
| 410 WebContents* web_contents = it->first; | |
| 411 if (visible) | |
| 412 web_contents->WasShown(); | |
| 413 else | |
| 414 web_contents->WasHidden(); | |
| 415 } | |
| 416 break; | |
| 417 } | |
| 418 default: | |
| 419 NOTREACHED() << "Unexpected notification type: " << type; | |
| 420 } | |
| 421 } | |
| 422 | |
| 423 } // namespace content | |
| OLD | NEW |