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_guest.h" 6 7 #include <algorithm> 8 9 #include "base/message_loop/message_loop.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "content/browser/browser_plugin/browser_plugin_embedder.h" 12 #include "content/browser/browser_thread_impl.h" 13 #include "content/browser/child_process_security_policy_impl.h" 14 #include "content/browser/frame_host/render_frame_host_impl.h" 15 #include "content/browser/frame_host/render_widget_host_view_guest.h" 16 #include "content/browser/loader/resource_dispatcher_host_impl.h" 17 #include "content/browser/renderer_host/render_view_host_impl.h" 18 #include "content/browser/renderer_host/render_widget_host_impl.h" 19 #include "content/browser/renderer_host/render_widget_host_view_base.h" 20 #include "content/browser/web_contents/web_contents_impl.h" 21 #include "content/browser/web_contents/web_contents_view_guest.h" 22 #include "content/common/browser_plugin/browser_plugin_messages.h" 23 #include "content/common/content_constants_internal.h" 24 #include "content/common/drag_messages.h" 25 #include "content/common/input_messages.h" 26 #include "content/common/view_messages.h" 27 #include "content/public/browser/browser_context.h" 28 #include "content/public/browser/browser_plugin_guest_manager.h" 29 #include "content/public/browser/content_browser_client.h" 30 #include "content/public/browser/render_widget_host_view.h" 31 #include "content/public/browser/user_metrics.h" 32 #include "content/public/browser/web_contents_observer.h" 33 #include "content/public/common/drop_data.h" 34 #include "third_party/WebKit/public/platform/WebCursorInfo.h" 35 36 #if defined(OS_MACOSX) 37 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h" 38 #endif 39 40 namespace content { 41 42 class BrowserPluginGuest::EmbedderWebContentsObserver 43 : public WebContentsObserver { 44 public: 45 explicit EmbedderWebContentsObserver(BrowserPluginGuest* guest) 46 : WebContentsObserver(guest->embedder_web_contents()), 47 browser_plugin_guest_(guest) { 48 } 49 50 virtual ~EmbedderWebContentsObserver() { 51 } 52 53 // WebContentsObserver implementation. 54 virtual void WasShown() OVERRIDE { 55 browser_plugin_guest_->EmbedderVisibilityChanged(true); 56 } 57 58 virtual void WasHidden() OVERRIDE { 59 browser_plugin_guest_->EmbedderVisibilityChanged(false); 60 } 61 62 private: 63 BrowserPluginGuest* browser_plugin_guest_; 64 65 DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver); 66 }; 67 68 BrowserPluginGuest::BrowserPluginGuest( 69 int instance_id, 70 bool has_render_view, 71 WebContentsImpl* web_contents) 72 : WebContentsObserver(web_contents), 73 embedder_web_contents_(NULL), 74 instance_id_(instance_id), 75 guest_device_scale_factor_(1.0f), 76 focused_(false), 77 mouse_locked_(false), 78 pending_lock_request_(false), 79 guest_visible_(false), 80 guest_opaque_(true), 81 embedder_visible_(true), 82 auto_size_enabled_(false), 83 copy_request_id_(0), 84 has_render_view_(has_render_view), 85 last_seen_auto_size_enabled_(false), 86 is_in_destruction_(false), 87 last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE), 88 last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT), 89 last_can_compose_inline_(true), 90 delegate_(NULL), 91 weak_ptr_factory_(this) { 92 DCHECK(web_contents); 93 } 94 95 void BrowserPluginGuest::WillDestroy() { 96 is_in_destruction_ = true; 97 embedder_web_contents_ = NULL; 98 delegate_ = NULL; 99 } 100 101 base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() { 102 return weak_ptr_factory_.GetWeakPtr(); 103 } 104 105 bool BrowserPluginGuest::LockMouse(bool allowed) { 106 if (!attached() || (mouse_locked_ == allowed)) 107 return false; 108 109 return embedder_web_contents()->GotResponseToLockMouseRequest(allowed); 110 } 111 112 void BrowserPluginGuest::Destroy() { 113 if (!delegate_) 114 return; 115 delegate_->Destroy(); 116 } 117 118 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder( 119 const IPC::Message& message) { 120 bool handled = true; 121 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message) 122 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK, 123 OnCompositorFrameSwappedACK) 124 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CopyFromCompositingSurfaceAck, 125 OnCopyFromCompositingSurfaceAck) 126 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate, 127 OnDragStatusUpdate) 128 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand, 129 OnExecuteEditCommand) 130 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete, 131 OnExtendSelectionAndDelete) 132 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent, 133 OnHandleInputEvent) 134 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition, 135 OnImeConfirmComposition) 136 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition, 137 OnImeSetComposition) 138 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck) 139 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed) 140 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources, 141 OnReclaimCompositorResources) 142 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest) 143 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetAutoSize, OnSetAutoSize) 144 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent, 145 OnSetEditCommandsForNextKeyEvent) 146 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus) 147 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetContentsOpaque, 148 OnSetContentsOpaque) 149 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility) 150 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck) 151 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry) 152 IPC_MESSAGE_UNHANDLED(handled = false) 153 IPC_END_MESSAGE_MAP() 154 return handled; 155 } 156 157 void BrowserPluginGuest::Initialize( 158 const BrowserPluginHostMsg_Attach_Params& params, 159 WebContentsImpl* embedder_web_contents, 160 const base::DictionaryValue& extra_params) { 161 focused_ = params.focused; 162 guest_visible_ = params.visible; 163 guest_opaque_ = params.opaque; 164 guest_window_rect_ = gfx::Rect(params.origin, 165 params.resize_guest_params.view_size); 166 167 auto_size_enabled_ = params.auto_size_params.enable; 168 max_auto_size_ = params.auto_size_params.max_size; 169 min_auto_size_ = params.auto_size_params.min_size; 170 171 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to 172 // be attached. 173 embedder_web_contents_ = embedder_web_contents; 174 175 WebContentsViewGuest* new_view = 176 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView()); 177 new_view->OnGuestInitialized(embedder_web_contents->GetView()); 178 179 RendererPreferences* renderer_prefs = 180 GetWebContents()->GetMutableRendererPrefs(); 181 std::string guest_user_agent_override = renderer_prefs->user_agent_override; 182 // Copy renderer preferences (and nothing else) from the embedder's 183 // WebContents to the guest. 184 // 185 // For GTK and Aura this is necessary to get proper renderer configuration 186 // values for caret blinking interval, colors related to selection and 187 // focus. 188 *renderer_prefs = *embedder_web_contents_->GetMutableRendererPrefs(); 189 renderer_prefs->user_agent_override = guest_user_agent_override; 190 191 // We would like the guest to report changes to frame names so that we can 192 // update the BrowserPlugin's corresponding 'name' attribute. 193 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed. 194 renderer_prefs->report_frame_name_changes = true; 195 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated 196 // navigations still continue to function inside the app. 197 renderer_prefs->browser_handles_all_top_level_requests = false; 198 // Disable "client blocked" error page for browser plugin. 199 renderer_prefs->disable_client_blocked_error_page = true; 200 201 embedder_web_contents_observer_.reset(new EmbedderWebContentsObserver(this)); 202 203 OnSetAutoSize( 204 instance_id_, params.auto_size_params, params.resize_guest_params); 205 206 // Create a swapped out RenderView for the guest in the embedder render 207 // process, so that the embedder can access the guest's window object. 208 int guest_routing_id = 209 GetWebContents()->CreateSwappedOutRenderView( 210 embedder_web_contents_->GetSiteInstance()); 211 SendMessageToEmbedder( 212 new BrowserPluginMsg_GuestContentWindowReady(instance_id_, 213 guest_routing_id)); 214 215 WebPreferences prefs = GetWebContents()->GetWebkitPrefs(); 216 prefs.navigate_on_drag_drop = false; 217 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs); 218 219 // Enable input method for guest if it's enabled for the embedder. 220 if (static_cast<RenderViewHostImpl*>( 221 embedder_web_contents_->GetRenderViewHost())->input_method_active()) { 222 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>( 223 GetWebContents()->GetRenderViewHost()); 224 guest_rvh->SetInputMethodActive(true); 225 } 226 227 // Inform the embedder of the guest's attachment. 228 SendMessageToEmbedder(new BrowserPluginMsg_Attach_ACK(instance_id_)); 229 } 230 231 BrowserPluginGuest::~BrowserPluginGuest() { 232 } 233 234 // static 235 BrowserPluginGuest* BrowserPluginGuest::Create( 236 int instance_id, 237 SiteInstance* guest_site_instance, 238 WebContentsImpl* web_contents, 239 scoped_ptr<base::DictionaryValue> extra_params, 240 BrowserPluginGuest* opener) { 241 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create")); 242 BrowserPluginGuest* guest = new BrowserPluginGuest( 243 instance_id, web_contents->opener() != NULL, web_contents); 244 web_contents->SetBrowserPluginGuest(guest); 245 WebContents* opener_web_contents = NULL; 246 if (opener) { 247 opener_web_contents = opener->GetWebContents(); 248 guest_site_instance = opener_web_contents->GetSiteInstance(); 249 } 250 BrowserPluginGuestDelegate* delegate = NULL; 251 GetContentClient()->browser()->GuestWebContentsCreated( 252 instance_id, 253 guest_site_instance, 254 web_contents, 255 opener_web_contents, 256 &delegate, 257 extra_params.Pass()); 258 if (delegate) { 259 delegate->RegisterDestructionCallback( 260 base::Bind(&BrowserPluginGuest::WillDestroy, 261 base::Unretained(guest))); 262 guest->set_delegate(delegate); 263 } 264 return guest; 265 } 266 267 // static 268 bool BrowserPluginGuest::IsGuest(WebContentsImpl* web_contents) { 269 return web_contents && web_contents->GetBrowserPluginGuest(); 270 } 271 272 // static 273 bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) { 274 return render_view_host && IsGuest( 275 static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost( 276 render_view_host))); 277 } 278 279 RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() { 280 if (!attached()) 281 return NULL; 282 return embedder_web_contents_->GetRenderWidgetHostView(); 283 } 284 285 void BrowserPluginGuest::UpdateVisibility() { 286 OnSetVisibility(instance_id_, visible()); 287 } 288 289 void BrowserPluginGuest::CopyFromCompositingSurface( 290 gfx::Rect src_subrect, 291 gfx::Size dst_size, 292 const base::Callback<void(bool, const SkBitmap&)>& callback) { 293 copy_request_callbacks_.insert(std::make_pair(++copy_request_id_, callback)); 294 SendMessageToEmbedder( 295 new BrowserPluginMsg_CopyFromCompositingSurface(instance_id(), 296 copy_request_id_, src_subrect, dst_size)); 297 } 298 299 BrowserPluginGuestManager* 300 BrowserPluginGuest::GetBrowserPluginGuestManager() const { 301 return GetWebContents()->GetBrowserContext()->GetGuestManager(); 302 } 303 304 // screen. 305 gfx::Rect BrowserPluginGuest::ToGuestRect(const gfx::Rect& bounds) { 306 gfx::Rect guest_rect(bounds); 307 guest_rect.Offset(guest_window_rect_.OffsetFromOrigin()); 308 return guest_rect; 309 } 310 311 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) { 312 embedder_visible_ = visible; 313 UpdateVisibility(); 314 } 315 316 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) { 317 SendMessageToEmbedder( 318 new BrowserPluginMsg_SetMouseLock(instance_id(), allow)); 319 } 320 321 WebContentsImpl* BrowserPluginGuest::GetWebContents() const { 322 return static_cast<WebContentsImpl*>(web_contents()); 323 } 324 325 gfx::Point BrowserPluginGuest::GetScreenCoordinates( 326 const gfx::Point& relative_position) const { 327 gfx::Point screen_pos(relative_position); 328 screen_pos += guest_window_rect_.OffsetFromOrigin(); 329 return screen_pos; 330 } 331 332 bool BrowserPluginGuest::InAutoSizeBounds(const gfx::Size& size) const { 333 return size.width() <= max_auto_size_.width() && 334 size.height() <= max_auto_size_.height(); 335 } 336 337 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) { 338 if (!attached()) { 339 // Some pages such as data URLs, javascript URLs, and about:blank 340 // do not load external resources and so they load prior to attachment. 341 // As a result, we must save all these IPCs until attachment and then 342 // forward them so that the embedder gets a chance to see and process 343 // the load events. 344 pending_messages_.push_back(linked_ptr<IPC::Message>(msg)); 345 return; 346 } 347 msg->set_routing_id(embedder_web_contents_->GetRoutingID()); 348 embedder_web_contents_->Send(msg); 349 } 350 351 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y, 352 int screen_x, int screen_y, blink::WebDragOperation operation) { 353 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y, 354 screen_x, screen_y, operation); 355 } 356 357 void BrowserPluginGuest::EndSystemDrag() { 358 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>( 359 GetWebContents()->GetRenderViewHost()); 360 guest_rvh->DragSourceSystemDragEnded(); 361 } 362 363 void BrowserPluginGuest::SendQueuedMessages() { 364 if (!attached()) 365 return; 366 367 while (!pending_messages_.empty()) { 368 linked_ptr<IPC::Message> message_ptr = pending_messages_.front(); 369 pending_messages_.pop_front(); 370 SendMessageToEmbedder(message_ptr.release()); 371 } 372 } 373 374 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame( 375 int64 frame_id, 376 const base::string16& frame_unique_name, 377 bool is_main_frame, 378 const GURL& url, 379 PageTransition transition_type, 380 RenderViewHost* render_view_host) { 381 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate")); 382 } 383 384 void BrowserPluginGuest::RenderViewReady() { 385 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost(); 386 // TODO(fsamuel): Investigate whether it's possible to update state earlier 387 // here (see http://crbug.com/158151). 388 Send(new InputMsg_SetFocus(routing_id(), focused_)); 389 UpdateVisibility(); 390 if (auto_size_enabled_) 391 rvh->EnableAutoResize(min_auto_size_, max_auto_size_); 392 else 393 rvh->DisableAutoResize(full_size_); 394 395 OnSetContentsOpaque(instance_id_, guest_opaque_); 396 397 RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay_ms( 398 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)); 399 } 400 401 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) { 402 SendMessageToEmbedder(new BrowserPluginMsg_GuestGone(instance_id())); 403 switch (status) { 404 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: 405 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed")); 406 break; 407 case base::TERMINATION_STATUS_PROCESS_CRASHED: 408 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed")); 409 break; 410 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: 411 RecordAction( 412 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath")); 413 break; 414 default: 415 break; 416 } 417 } 418 419 // static 420 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest( 421 const IPC::Message& message) { 422 switch (message.type()) { 423 case BrowserPluginHostMsg_CompositorFrameSwappedACK::ID: 424 case BrowserPluginHostMsg_CopyFromCompositingSurfaceAck::ID: 425 case BrowserPluginHostMsg_DragStatusUpdate::ID: 426 case BrowserPluginHostMsg_ExecuteEditCommand::ID: 427 case BrowserPluginHostMsg_ExtendSelectionAndDelete::ID: 428 case BrowserPluginHostMsg_HandleInputEvent::ID: 429 case BrowserPluginHostMsg_ImeConfirmComposition::ID: 430 case BrowserPluginHostMsg_ImeSetComposition::ID: 431 case BrowserPluginHostMsg_LockMouse_ACK::ID: 432 case BrowserPluginHostMsg_PluginDestroyed::ID: 433 case BrowserPluginHostMsg_ReclaimCompositorResources::ID: 434 case BrowserPluginHostMsg_ResizeGuest::ID: 435 case BrowserPluginHostMsg_SetAutoSize::ID: 436 case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID: 437 case BrowserPluginHostMsg_SetFocus::ID: 438 case BrowserPluginHostMsg_SetContentsOpaque::ID: 439 case BrowserPluginHostMsg_SetVisibility::ID: 440 case BrowserPluginHostMsg_UnlockMouse_ACK::ID: 441 case BrowserPluginHostMsg_UpdateGeometry::ID: 442 return true; 443 default: 444 return false; 445 } 446 } 447 448 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) { 449 bool handled = true; 450 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message) 451 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers, 452 OnHasTouchEventHandlers) 453 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse) 454 IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnSetCursor) 455 #if defined(OS_MACOSX) 456 // MacOSX creates and populates platform-specific select drop-down menus 457 // whereas other platforms merely create a popup window that the guest 458 // renderer process paints inside. 459 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowPopup, OnShowPopup) 460 #endif 461 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget) 462 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus) 463 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged, 464 OnTextInputStateChanged) 465 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition, 466 OnImeCancelComposition) 467 #if defined(OS_MACOSX) || defined(USE_AURA) 468 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCompositionRangeChanged, 469 OnImeCompositionRangeChanged) 470 #endif 471 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse) 472 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect) 473 IPC_MESSAGE_UNHANDLED(handled = false) 474 IPC_END_MESSAGE_MAP() 475 return handled; 476 } 477 478 void BrowserPluginGuest::Attach( 479 WebContentsImpl* embedder_web_contents, 480 const BrowserPluginHostMsg_Attach_Params& params, 481 const base::DictionaryValue& extra_params) { 482 if (attached()) 483 return; 484 485 if (delegate_) 486 delegate_->WillAttach(embedder_web_contents, extra_params); 487 488 // If a RenderView has already been created for this new window, then we need 489 // to initialize the browser-side state now so that the RenderFrameHostManager 490 // does not create a new RenderView on navigation. 491 if (has_render_view_) { 492 static_cast<RenderViewHostImpl*>( 493 GetWebContents()->GetRenderViewHost())->Init(); 494 WebContentsViewGuest* new_view = 495 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView()); 496 new_view->CreateViewForWidget(web_contents()->GetRenderViewHost()); 497 } 498 499 Initialize(params, embedder_web_contents, extra_params); 500 501 SendQueuedMessages(); 502 503 if (delegate_) 504 delegate_->DidAttach(); 505 506 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached")); 507 } 508 509 void BrowserPluginGuest::OnCompositorFrameSwappedACK( 510 int instance_id, 511 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) { 512 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id, 513 params.output_surface_id, 514 params.producing_host_id, 515 params.ack); 516 } 517 518 void BrowserPluginGuest::OnDragStatusUpdate(int instance_id, 519 blink::WebDragStatus drag_status, 520 const DropData& drop_data, 521 blink::WebDragOperationsMask mask, 522 const gfx::Point& location) { 523 RenderViewHost* host = GetWebContents()->GetRenderViewHost(); 524 switch (drag_status) { 525 case blink::WebDragStatusEnter: 526 embedder_web_contents_->GetBrowserPluginEmbedder()->DragEnteredGuest( 527 this); 528 host->DragTargetDragEnter(drop_data, location, location, mask, 0); 529 break; 530 case blink::WebDragStatusOver: 531 host->DragTargetDragOver(location, location, mask, 0); 532 break; 533 case blink::WebDragStatusLeave: 534 embedder_web_contents_->GetBrowserPluginEmbedder()->DragLeftGuest(this); 535 host->DragTargetDragLeave(); 536 break; 537 case blink::WebDragStatusDrop: 538 host->DragTargetDrop(location, location, 0); 539 EndSystemDrag(); 540 break; 541 case blink::WebDragStatusUnknown: 542 NOTREACHED(); 543 } 544 } 545 546 void BrowserPluginGuest::OnExecuteEditCommand(int instance_id, 547 const std::string& name) { 548 Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string())); 549 } 550 551 void BrowserPluginGuest::OnImeSetComposition( 552 int instance_id, 553 const std::string& text, 554 const std::vector<blink::WebCompositionUnderline>& underlines, 555 int selection_start, 556 int selection_end) { 557 Send(new ViewMsg_ImeSetComposition(routing_id(), 558 base::UTF8ToUTF16(text), underlines, 559 selection_start, selection_end)); 560 } 561 562 void BrowserPluginGuest::OnImeConfirmComposition( 563 int instance_id, 564 const std::string& text, 565 bool keep_selection) { 566 Send(new ViewMsg_ImeConfirmComposition(routing_id(), 567 base::UTF8ToUTF16(text), 568 gfx::Range::InvalidRange(), 569 keep_selection)); 570 } 571 572 void BrowserPluginGuest::OnExtendSelectionAndDelete( 573 int instance_id, 574 int before, 575 int after) { 576 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>( 577 web_contents()->GetFocusedFrame()); 578 if (rfh) 579 rfh->ExtendSelectionAndDelete(before, after); 580 } 581 582 void BrowserPluginGuest::OnReclaimCompositorResources( 583 int instance_id, 584 const FrameHostMsg_ReclaimCompositorResources_Params& params) { 585 RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id, 586 params.output_surface_id, 587 params.renderer_host_id, 588 params.ack); 589 } 590 591 void BrowserPluginGuest::OnHandleInputEvent( 592 int instance_id, 593 const gfx::Rect& guest_window_rect, 594 const blink::WebInputEvent* event) { 595 guest_window_rect_ = guest_window_rect; 596 // If the embedder's RWHV is destroyed then that means that the embedder's 597 // window has been closed but the embedder's WebContents has not yet been 598 // destroyed. Computing screen coordinates of a BrowserPlugin only makes sense 599 // if there is a visible embedder. 600 if (embedder_web_contents_->GetRenderWidgetHostView()) { 601 guest_screen_rect_ = guest_window_rect; 602 guest_screen_rect_.Offset( 603 embedder_web_contents_->GetRenderWidgetHostView()-> 604 GetViewBounds().OffsetFromOrigin()); 605 } 606 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>( 607 GetWebContents()->GetRenderViewHost()); 608 609 if (blink::WebInputEvent::isMouseEventType(event->type)) { 610 guest_rvh->ForwardMouseEvent( 611 *static_cast<const blink::WebMouseEvent*>(event)); 612 return; 613 } 614 615 if (event->type == blink::WebInputEvent::MouseWheel) { 616 guest_rvh->ForwardWheelEvent( 617 *static_cast<const blink::WebMouseWheelEvent*>(event)); 618 return; 619 } 620 621 if (blink::WebInputEvent::isKeyboardEventType(event->type)) { 622 RenderViewHostImpl* embedder_rvh = static_cast<RenderViewHostImpl*>( 623 embedder_web_contents_->GetRenderViewHost()); 624 if (!embedder_rvh->GetLastKeyboardEvent()) 625 return; 626 NativeWebKeyboardEvent keyboard_event( 627 *embedder_rvh->GetLastKeyboardEvent()); 628 guest_rvh->ForwardKeyboardEvent(keyboard_event); 629 return; 630 } 631 632 if (blink::WebInputEvent::isTouchEventType(event->type)) { 633 guest_rvh->ForwardTouchEventWithLatencyInfo( 634 *static_cast<const blink::WebTouchEvent*>(event), 635 ui::LatencyInfo()); 636 return; 637 } 638 639 if (blink::WebInputEvent::isGestureEventType(event->type)) { 640 guest_rvh->ForwardGestureEvent( 641 *static_cast<const blink::WebGestureEvent*>(event)); 642 return; 643 } 644 } 645 646 void BrowserPluginGuest::OnLockMouse(bool user_gesture, 647 bool last_unlocked_by_target, 648 bool privileged) { 649 if (pending_lock_request_) { 650 // Immediately reject the lock because only one pointerLock may be active 651 // at a time. 652 Send(new ViewMsg_LockMouse_ACK(routing_id(), false)); 653 return; 654 } 655 656 if (!delegate_) 657 return; 658 659 pending_lock_request_ = true; 660 661 delegate_->RequestPointerLockPermission( 662 user_gesture, 663 last_unlocked_by_target, 664 base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse, 665 weak_ptr_factory_.GetWeakPtr())); 666 } 667 668 void BrowserPluginGuest::OnLockMouseAck(int instance_id, bool succeeded) { 669 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded)); 670 pending_lock_request_ = false; 671 if (succeeded) 672 mouse_locked_ = true; 673 } 674 675 void BrowserPluginGuest::OnPluginDestroyed(int instance_id) { 676 Destroy(); 677 } 678 679 void BrowserPluginGuest::OnResizeGuest( 680 int instance_id, 681 const BrowserPluginHostMsg_ResizeGuest_Params& params) { 682 if (!params.size_changed) 683 return; 684 // BrowserPlugin manages resize flow control itself and does not depend 685 // on RenderWidgetHost's mechanisms for flow control, so we reset those flags 686 // here. If we are setting the size for the first time before navigating then 687 // BrowserPluginGuest does not yet have a RenderViewHost. 688 if (GetWebContents()->GetRenderViewHost()) { 689 RenderWidgetHostImpl* render_widget_host = 690 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost()); 691 render_widget_host->ResetSizeAndRepaintPendingFlags(); 692 693 if (guest_device_scale_factor_ != params.scale_factor) { 694 guest_device_scale_factor_ = params.scale_factor; 695 render_widget_host->NotifyScreenInfoChanged(); 696 } 697 } 698 // When autosize is turned off and as a result there is a layout change, we 699 // send a sizechanged event. 700 if (!auto_size_enabled_ && last_seen_auto_size_enabled_ && 701 !params.view_size.IsEmpty() && delegate_) { 702 delegate_->SizeChanged(last_seen_view_size_, params.view_size); 703 last_seen_auto_size_enabled_ = false; 704 } 705 // Just resize the WebContents and repaint if needed. 706 full_size_ = params.view_size; 707 if (!params.view_size.IsEmpty()) 708 GetWebContents()->GetView()->SizeContents(params.view_size); 709 if (params.repaint) 710 Send(new ViewMsg_Repaint(routing_id(), params.view_size)); 711 } 712 713 void BrowserPluginGuest::OnSetFocus(int instance_id, bool focused) { 714 focused_ = focused; 715 Send(new InputMsg_SetFocus(routing_id(), focused)); 716 if (!focused && mouse_locked_) 717 OnUnlockMouse(); 718 719 // Restore the last seen state of text input to the view. 720 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>( 721 web_contents()->GetRenderWidgetHostView()); 722 if (rwhv) { 723 ViewHostMsg_TextInputState_Params params; 724 params.type = last_text_input_type_; 725 params.mode = last_input_mode_; 726 params.can_compose_inline = last_can_compose_inline_; 727 rwhv->TextInputStateChanged(params); 728 } 729 } 730 731 void BrowserPluginGuest::OnSetAutoSize( 732 int instance_id, 733 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params, 734 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) { 735 bool old_auto_size_enabled = auto_size_enabled_; 736 gfx::Size old_max_size = max_auto_size_; 737 gfx::Size old_min_size = min_auto_size_; 738 auto_size_enabled_ = auto_size_params.enable; 739 max_auto_size_ = auto_size_params.max_size; 740 min_auto_size_ = auto_size_params.min_size; 741 if (auto_size_enabled_ && (!old_auto_size_enabled || 742 (old_max_size != max_auto_size_) || 743 (old_min_size != min_auto_size_))) { 744 RecordAction( 745 base::UserMetricsAction("BrowserPlugin.Guest.EnableAutoResize")); 746 GetWebContents()->GetRenderViewHost()->EnableAutoResize( 747 min_auto_size_, max_auto_size_); 748 // TODO(fsamuel): If we're changing autosize parameters, then we force 749 // the guest to completely repaint itself. 750 // Ideally, we shouldn't need to do this unless |max_auto_size_| has 751 // changed. 752 // However, even in that case, layout may not change and so we may 753 // not get a full frame worth of pixels. 754 Send(new ViewMsg_Repaint(routing_id(), max_auto_size_)); 755 } else if (!auto_size_enabled_ && old_auto_size_enabled) { 756 GetWebContents()->GetRenderViewHost()->DisableAutoResize( 757 resize_guest_params.view_size); 758 } 759 OnResizeGuest(instance_id_, resize_guest_params); 760 } 761 762 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent( 763 int instance_id, 764 const std::vector<EditCommand>& edit_commands) { 765 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(), 766 edit_commands)); 767 } 768 769 void BrowserPluginGuest::OnSetContentsOpaque(int instance_id, bool opaque) { 770 guest_opaque_ = opaque; 771 Send(new ViewMsg_SetBackgroundOpaque(routing_id(), guest_opaque_)); 772 } 773 774 void BrowserPluginGuest::OnSetVisibility(int instance_id, bool visible) { 775 guest_visible_ = visible; 776 if (embedder_visible_ && guest_visible_) 777 GetWebContents()->WasShown(); 778 else 779 GetWebContents()->WasHidden(); 780 } 781 782 void BrowserPluginGuest::OnUnlockMouse() { 783 SendMessageToEmbedder( 784 new BrowserPluginMsg_SetMouseLock(instance_id(), false)); 785 } 786 787 void BrowserPluginGuest::OnUnlockMouseAck(int instance_id) { 788 // mouse_locked_ could be false here if the lock attempt was cancelled due 789 // to window focus, or for various other reasons before the guest was informed 790 // of the lock's success. 791 if (mouse_locked_) 792 Send(new ViewMsg_MouseLockLost(routing_id())); 793 mouse_locked_ = false; 794 } 795 796 void BrowserPluginGuest::OnCopyFromCompositingSurfaceAck( 797 int instance_id, 798 int request_id, 799 const SkBitmap& bitmap) { 800 CHECK(copy_request_callbacks_.count(request_id)); 801 if (!copy_request_callbacks_.count(request_id)) 802 return; 803 const CopyRequestCallback& callback = copy_request_callbacks_[request_id]; 804 callback.Run(!bitmap.empty() && !bitmap.isNull(), bitmap); 805 copy_request_callbacks_.erase(request_id); 806 } 807 808 void BrowserPluginGuest::OnUpdateGeometry(int instance_id, 809 const gfx::Rect& view_rect) { 810 // The plugin has moved within the embedder without resizing or the 811 // embedder/container's view rect changing. 812 guest_window_rect_ = view_rect; 813 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>( 814 GetWebContents()->GetRenderViewHost()); 815 if (rvh) 816 rvh->SendScreenRects(); 817 } 818 819 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) { 820 SendMessageToEmbedder( 821 new BrowserPluginMsg_ShouldAcceptTouchEvents(instance_id(), accept)); 822 } 823 824 void BrowserPluginGuest::OnSetCursor(const WebCursor& cursor) { 825 SendMessageToEmbedder(new BrowserPluginMsg_SetCursor(instance_id(), cursor)); 826 } 827 828 #if defined(OS_MACOSX) 829 void BrowserPluginGuest::OnShowPopup( 830 const ViewHostMsg_ShowPopup_Params& params) { 831 gfx::Rect translated_bounds(params.bounds); 832 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin()); 833 BrowserPluginPopupMenuHelper popup_menu_helper( 834 embedder_web_contents_->GetRenderViewHost(), 835 GetWebContents()->GetRenderViewHost()); 836 popup_menu_helper.ShowPopupMenu(translated_bounds, 837 params.item_height, 838 params.item_font_size, 839 params.selected_item, 840 params.popup_items, 841 params.right_aligned, 842 params.allow_multiple_selection); 843 } 844 #endif 845 846 void BrowserPluginGuest::OnShowWidget(int route_id, 847 const gfx::Rect& initial_pos) { 848 GetWebContents()->ShowCreatedWidget(route_id, initial_pos); 849 } 850 851 void BrowserPluginGuest::OnTakeFocus(bool reverse) { 852 SendMessageToEmbedder( 853 new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse)); 854 } 855 856 void BrowserPluginGuest::OnUpdateRect( 857 const ViewHostMsg_UpdateRect_Params& params) { 858 BrowserPluginMsg_UpdateRect_Params relay_params; 859 relay_params.view_size = params.view_size; 860 relay_params.scale_factor = params.scale_factor; 861 relay_params.is_resize_ack = ViewHostMsg_UpdateRect_Flags::is_resize_ack( 862 params.flags); 863 864 bool size_changed = last_seen_view_size_ != params.view_size; 865 gfx::Size old_size = last_seen_view_size_; 866 last_seen_view_size_ = params.view_size; 867 868 if ((auto_size_enabled_ || last_seen_auto_size_enabled_) && 869 size_changed && delegate_) { 870 delegate_->SizeChanged(old_size, last_seen_view_size_); 871 } 872 last_seen_auto_size_enabled_ = auto_size_enabled_; 873 874 SendMessageToEmbedder( 875 new BrowserPluginMsg_UpdateRect(instance_id(), relay_params)); 876 } 877 878 void BrowserPluginGuest::OnTextInputStateChanged( 879 const ViewHostMsg_TextInputState_Params& params) { 880 // Save the state of text input so we can restore it on focus. 881 last_text_input_type_ = params.type; 882 last_input_mode_ = params.mode; 883 last_can_compose_inline_ = params.can_compose_inline; 884 885 static_cast<RenderWidgetHostViewBase*>( 886 web_contents()->GetRenderWidgetHostView())->TextInputStateChanged(params); 887 } 888 889 void BrowserPluginGuest::OnImeCancelComposition() { 890 static_cast<RenderWidgetHostViewBase*>( 891 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition(); 892 } 893 894 #if defined(OS_MACOSX) || defined(USE_AURA) 895 void BrowserPluginGuest::OnImeCompositionRangeChanged( 896 const gfx::Range& range, 897 const std::vector<gfx::Rect>& character_bounds) { 898 static_cast<RenderWidgetHostViewBase*>( 899 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged( 900 range, character_bounds); 901 } 902 #endif 903 904 } // namespace content 905