1 // Copyright 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/renderer/browser_plugin/browser_plugin.h" 6 7 #include "base/command_line.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "content/common/browser_plugin/browser_plugin_constants.h" 12 #include "content/common/browser_plugin/browser_plugin_messages.h" 13 #include "content/common/view_messages.h" 14 #include "content/public/common/content_client.h" 15 #include "content/public/common/content_switches.h" 16 #include "content/public/renderer/browser_plugin_delegate.h" 17 #include "content/public/renderer/content_renderer_client.h" 18 #include "content/renderer/browser_plugin/browser_plugin_manager.h" 19 #include "content/renderer/child_frame_compositing_helper.h" 20 #include "content/renderer/cursor_utils.h" 21 #include "content/renderer/drop_data_builder.h" 22 #include "content/renderer/render_thread_impl.h" 23 #include "content/renderer/sad_plugin.h" 24 #include "third_party/WebKit/public/platform/WebRect.h" 25 #include "third_party/WebKit/public/web/WebElement.h" 26 #include "third_party/WebKit/public/web/WebInputEvent.h" 27 #include "third_party/WebKit/public/web/WebPluginContainer.h" 28 #include "third_party/WebKit/public/web/WebView.h" 29 #include "third_party/skia/include/core/SkCanvas.h" 30 #include "ui/events/keycodes/keyboard_codes.h" 31 32 using blink::WebCanvas; 33 using blink::WebPluginContainer; 34 using blink::WebPoint; 35 using blink::WebRect; 36 using blink::WebURL; 37 using blink::WebVector; 38 39 namespace { 40 typedef std::map<blink::WebPluginContainer*, content::BrowserPlugin*> 41 PluginContainerMap; 42 static base::LazyInstance<PluginContainerMap> g_plugin_container_map = 43 LAZY_INSTANCE_INITIALIZER; 44 } // namespace 45 46 namespace content { 47 48 // static 49 BrowserPlugin* BrowserPlugin::GetFromNode(blink::WebNode& node) { 50 blink::WebPluginContainer* container = node.pluginContainer(); 51 if (!container) 52 return NULL; 53 54 PluginContainerMap* browser_plugins = g_plugin_container_map.Pointer(); 55 PluginContainerMap::iterator it = browser_plugins->find(container); 56 return it == browser_plugins->end() ? NULL : it->second; 57 } 58 59 BrowserPlugin::BrowserPlugin(RenderViewImpl* render_view, 60 blink::WebFrame* frame, 61 scoped_ptr<BrowserPluginDelegate> delegate) 62 : attached_(false), 63 attach_pending_(false), 64 render_view_(render_view->AsWeakPtr()), 65 render_view_routing_id_(render_view->GetRoutingID()), 66 container_(NULL), 67 last_device_scale_factor_(GetDeviceScaleFactor()), 68 sad_guest_(NULL), 69 guest_crashed_(false), 70 plugin_focused_(false), 71 visible_(true), 72 mouse_locked_(false), 73 browser_plugin_manager_(render_view->GetBrowserPluginManager()), 74 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone), 75 contents_opaque_(true), 76 delegate_(delegate.Pass()), 77 weak_ptr_factory_(this) { 78 browser_plugin_instance_id_ = browser_plugin_manager()->GetNextInstanceID(); 79 80 if (delegate_) 81 delegate_->SetElementInstanceID(browser_plugin_instance_id_); 82 } 83 84 BrowserPlugin::~BrowserPlugin() { 85 browser_plugin_manager()->RemoveBrowserPlugin(browser_plugin_instance_id_); 86 87 if (!ready()) 88 return; 89 90 browser_plugin_manager()->Send( 91 new BrowserPluginHostMsg_PluginDestroyed(render_view_routing_id_, 92 browser_plugin_instance_id_)); 93 } 94 95 bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) { 96 bool handled = true; 97 IPC_BEGIN_MESSAGE_MAP(BrowserPlugin, message) 98 IPC_MESSAGE_HANDLER(BrowserPluginMsg_Attach_ACK, OnAttachACK) 99 IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus) 100 IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped, 101 OnCompositorFrameSwapped(message)) 102 IPC_MESSAGE_HANDLER(BrowserPluginMsg_CopyFromCompositingSurface, 103 OnCopyFromCompositingSurface) 104 IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone) 105 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetContentsOpaque, OnSetContentsOpaque) 106 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor) 107 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetMouseLock, OnSetMouseLock) 108 IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents, 109 OnShouldAcceptTouchEvents) 110 IPC_MESSAGE_UNHANDLED(handled = false) 111 IPC_END_MESSAGE_MAP() 112 return handled; 113 } 114 115 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name, 116 const std::string& attribute_value) { 117 if (!container()) 118 return; 119 120 blink::WebElement element = container()->element(); 121 blink::WebString web_attribute_name = 122 blink::WebString::fromUTF8(attribute_name); 123 element.setAttribute(web_attribute_name, 124 blink::WebString::fromUTF8(attribute_value)); 125 } 126 127 void BrowserPlugin::Attach() { 128 if (ready()) { 129 attached_ = false; 130 guest_crashed_ = false; 131 EnableCompositing(false); 132 if (compositing_helper_.get()) { 133 compositing_helper_->OnContainerDestroy(); 134 compositing_helper_ = NULL; 135 } 136 } 137 138 // TODO(fsamuel): Add support for reattachment. 139 BrowserPluginHostMsg_Attach_Params attach_params; 140 attach_params.focused = ShouldGuestBeFocused(); 141 attach_params.visible = visible_; 142 attach_params.origin = plugin_rect().origin(); 143 gfx::Size view_size(width(), height()); 144 if (!view_size.IsEmpty()) { 145 PopulateResizeGuestParameters(view_size, 146 &attach_params.resize_guest_params); 147 } 148 browser_plugin_manager()->Send(new BrowserPluginHostMsg_Attach( 149 render_view_routing_id_, 150 browser_plugin_instance_id_, 151 attach_params)); 152 153 attach_pending_ = true; 154 } 155 156 void BrowserPlugin::DidCommitCompositorFrame() { 157 if (compositing_helper_.get()) 158 compositing_helper_->DidCommitCompositorFrame(); 159 } 160 161 void BrowserPlugin::OnAdvanceFocus(int browser_plugin_instance_id, 162 bool reverse) { 163 DCHECK(render_view_); 164 render_view_->GetWebView()->advanceFocus(reverse); 165 } 166 167 void BrowserPlugin::OnAttachACK(int browser_plugin_instance_id) { 168 DCHECK(!attached()); 169 attached_ = true; 170 attach_pending_ = false; 171 } 172 173 void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) { 174 BrowserPluginMsg_CompositorFrameSwapped::Param param; 175 if (!BrowserPluginMsg_CompositorFrameSwapped::Read(&message, ¶m)) 176 return; 177 178 // Note that there is no need to send ACK for this message. 179 // If the guest has updated pixels then it is no longer crashed. 180 guest_crashed_ = false; 181 182 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame); 183 param.b.frame.AssignTo(frame.get()); 184 185 EnableCompositing(true); 186 compositing_helper_->OnCompositorFrameSwapped(frame.Pass(), 187 param.b.producing_route_id, 188 param.b.output_surface_id, 189 param.b.producing_host_id, 190 param.b.shared_memory_handle); 191 } 192 193 void BrowserPlugin::OnCopyFromCompositingSurface(int browser_plugin_instance_id, 194 int request_id, 195 gfx::Rect source_rect, 196 gfx::Size dest_size) { 197 if (!compositing_helper_.get()) { 198 browser_plugin_manager()->Send( 199 new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck( 200 render_view_routing_id_, 201 browser_plugin_instance_id_, 202 request_id, 203 SkBitmap())); 204 return; 205 } 206 compositing_helper_->CopyFromCompositingSurface(request_id, source_rect, 207 dest_size); 208 } 209 210 void BrowserPlugin::OnGuestGone(int browser_plugin_instance_id) { 211 guest_crashed_ = true; 212 213 // Turn off compositing so we can display the sad graphic. Changes to 214 // compositing state will show up at a later time after a layout and commit. 215 EnableCompositing(false); 216 217 // Queue up showing the sad graphic to give content embedders an opportunity 218 // to fire their listeners and potentially overlay the webview with custom 219 // behavior. If the BrowserPlugin is destroyed in the meantime, then the 220 // task will not be executed. 221 base::MessageLoop::current()->PostTask( 222 FROM_HERE, 223 base::Bind(&BrowserPlugin::ShowSadGraphic, 224 weak_ptr_factory_.GetWeakPtr())); 225 } 226 227 void BrowserPlugin::OnSetContentsOpaque(int browser_plugin_instance_id, 228 bool opaque) { 229 if (contents_opaque_ == opaque) 230 return; 231 contents_opaque_ = opaque; 232 if (compositing_helper_.get()) 233 compositing_helper_->SetContentsOpaque(opaque); 234 } 235 236 void BrowserPlugin::OnSetCursor(int browser_plugin_instance_id, 237 const WebCursor& cursor) { 238 cursor_ = cursor; 239 } 240 241 void BrowserPlugin::OnSetMouseLock(int browser_plugin_instance_id, 242 bool enable) { 243 if (enable) { 244 if (mouse_locked_) 245 return; 246 render_view_->mouse_lock_dispatcher()->LockMouse(this); 247 } else { 248 if (!mouse_locked_) { 249 OnLockMouseACK(false); 250 return; 251 } 252 render_view_->mouse_lock_dispatcher()->UnlockMouse(this); 253 } 254 } 255 256 void BrowserPlugin::OnShouldAcceptTouchEvents(int browser_plugin_instance_id, 257 bool accept) { 258 if (container()) { 259 container()->requestTouchEventType( 260 accept ? WebPluginContainer::TouchEventRequestTypeRaw 261 : WebPluginContainer::TouchEventRequestTypeNone); 262 } 263 } 264 265 void BrowserPlugin::ShowSadGraphic() { 266 // If the BrowserPlugin is scheduled to be deleted, then container_ will be 267 // NULL so we shouldn't attempt to access it. 268 if (container_) 269 container_->invalidate(); 270 } 271 272 float BrowserPlugin::GetDeviceScaleFactor() const { 273 if (!render_view_) 274 return 1.0f; 275 return render_view_->GetWebView()->deviceScaleFactor(); 276 } 277 278 void BrowserPlugin::UpdateDeviceScaleFactor() { 279 if (last_device_scale_factor_ == GetDeviceScaleFactor()) 280 return; 281 282 BrowserPluginHostMsg_ResizeGuest_Params params; 283 PopulateResizeGuestParameters(plugin_size(), ¶ms); 284 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest( 285 render_view_routing_id_, 286 browser_plugin_instance_id_, 287 params)); 288 } 289 290 void BrowserPlugin::UpdateGuestFocusState() { 291 if (!ready()) 292 return; 293 bool should_be_focused = ShouldGuestBeFocused(); 294 browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetFocus( 295 render_view_routing_id_, 296 browser_plugin_instance_id_, 297 should_be_focused)); 298 } 299 300 bool BrowserPlugin::ShouldGuestBeFocused() const { 301 bool embedder_focused = false; 302 if (render_view_) 303 embedder_focused = render_view_->has_focus(); 304 return plugin_focused_ && embedder_focused; 305 } 306 307 WebPluginContainer* BrowserPlugin::container() const { 308 return container_; 309 } 310 311 bool BrowserPlugin::initialize(WebPluginContainer* container) { 312 if (!container) 313 return false; 314 315 container_ = container; 316 container_->setWantsWheelEvents(true); 317 318 g_plugin_container_map.Get().insert(std::make_pair(container_, this)); 319 320 // This is a way to notify observers of our attributes that this plugin is 321 // available in render tree. 322 // TODO(lazyboy): This should be done through the delegate instead. Perhaps 323 // by firing an event from there. 324 UpdateDOMAttribute("internalinstanceid", 325 base::IntToString(browser_plugin_instance_id_)); 326 327 browser_plugin_manager()->AddBrowserPlugin(browser_plugin_instance_id_, this); 328 return true; 329 } 330 331 void BrowserPlugin::EnableCompositing(bool enable) { 332 bool enabled = !!compositing_helper_.get(); 333 if (enabled == enable) 334 return; 335 336 if (enable) { 337 DCHECK(!compositing_helper_.get()); 338 if (!compositing_helper_.get()) { 339 compositing_helper_ = ChildFrameCompositingHelper::CreateForBrowserPlugin( 340 weak_ptr_factory_.GetWeakPtr()); 341 } 342 } 343 compositing_helper_->EnableCompositing(enable); 344 compositing_helper_->SetContentsOpaque(contents_opaque_); 345 346 if (!enable) { 347 DCHECK(compositing_helper_.get()); 348 compositing_helper_->OnContainerDestroy(); 349 compositing_helper_ = NULL; 350 } 351 } 352 353 void BrowserPlugin::destroy() { 354 if (container_) { 355 //container_->clearScriptObjects(); 356 357 // The BrowserPlugin's WebPluginContainer is deleted immediately after this 358 // call returns, so let's not keep a reference to it around. 359 g_plugin_container_map.Get().erase(container_); 360 } 361 362 if (compositing_helper_.get()) 363 compositing_helper_->OnContainerDestroy(); 364 container_ = NULL; 365 // Will be a no-op if the mouse is not currently locked. 366 if (render_view_) 367 render_view_->mouse_lock_dispatcher()->OnLockTargetDestroyed(this); 368 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 369 } 370 371 bool BrowserPlugin::supportsKeyboardFocus() const { 372 return true; 373 } 374 375 bool BrowserPlugin::supportsEditCommands() const { 376 return true; 377 } 378 379 bool BrowserPlugin::supportsInputMethod() const { 380 return true; 381 } 382 383 bool BrowserPlugin::canProcessDrag() const { 384 return true; 385 } 386 387 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) { 388 if (guest_crashed_) { 389 if (!sad_guest_) // Lazily initialize bitmap. 390 sad_guest_ = content::GetContentClient()->renderer()-> 391 GetSadWebViewBitmap(); 392 // content_shell does not have the sad plugin bitmap, so we'll paint black 393 // instead to make it clear that something went wrong. 394 if (sad_guest_) { 395 PaintSadPlugin(canvas, plugin_rect_, *sad_guest_); 396 return; 397 } 398 } 399 SkAutoCanvasRestore auto_restore(canvas, true); 400 canvas->translate(plugin_rect_.x(), plugin_rect_.y()); 401 SkRect image_data_rect = SkRect::MakeXYWH( 402 SkIntToScalar(0), 403 SkIntToScalar(0), 404 SkIntToScalar(plugin_rect_.width()), 405 SkIntToScalar(plugin_rect_.height())); 406 canvas->clipRect(image_data_rect); 407 // Paint black or white in case we have nothing in our backing store or we 408 // need to show a gutter. 409 SkPaint paint; 410 paint.setStyle(SkPaint::kFill_Style); 411 paint.setColor(guest_crashed_ ? SK_ColorBLACK : SK_ColorWHITE); 412 canvas->drawRect(image_data_rect, paint); 413 } 414 415 // static 416 bool BrowserPlugin::ShouldForwardToBrowserPlugin( 417 const IPC::Message& message) { 418 switch (message.type()) { 419 case BrowserPluginMsg_Attach_ACK::ID: 420 case BrowserPluginMsg_AdvanceFocus::ID: 421 case BrowserPluginMsg_CompositorFrameSwapped::ID: 422 case BrowserPluginMsg_CopyFromCompositingSurface::ID: 423 case BrowserPluginMsg_GuestGone::ID: 424 case BrowserPluginMsg_SetContentsOpaque::ID: 425 case BrowserPluginMsg_SetCursor::ID: 426 case BrowserPluginMsg_SetMouseLock::ID: 427 case BrowserPluginMsg_ShouldAcceptTouchEvents::ID: 428 return true; 429 default: 430 break; 431 } 432 return false; 433 } 434 435 void BrowserPlugin::updateGeometry( 436 const WebRect& window_rect, 437 const WebRect& clip_rect, 438 const WebVector<WebRect>& cut_outs_rects, 439 bool is_visible) { 440 int old_width = width(); 441 int old_height = height(); 442 plugin_rect_ = window_rect; 443 if (!attached()) 444 return; 445 446 if (old_width == window_rect.width && old_height == window_rect.height) { 447 // Let the browser know about the updated view rect. 448 browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateGeometry( 449 render_view_routing_id_, browser_plugin_instance_id_, plugin_rect_)); 450 return; 451 } 452 453 BrowserPluginHostMsg_ResizeGuest_Params params; 454 PopulateResizeGuestParameters(plugin_size(), ¶ms); 455 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest( 456 render_view_routing_id_, 457 browser_plugin_instance_id_, 458 params)); 459 } 460 461 void BrowserPlugin::PopulateResizeGuestParameters( 462 const gfx::Size& view_size, 463 BrowserPluginHostMsg_ResizeGuest_Params* params) { 464 params->view_size = view_size; 465 params->scale_factor = GetDeviceScaleFactor(); 466 if (last_device_scale_factor_ != params->scale_factor) { 467 last_device_scale_factor_ = params->scale_factor; 468 params->repaint = true; 469 } 470 } 471 472 void BrowserPlugin::updateFocus(bool focused) { 473 plugin_focused_ = focused; 474 UpdateGuestFocusState(); 475 } 476 477 void BrowserPlugin::updateVisibility(bool visible) { 478 if (visible_ == visible) 479 return; 480 481 visible_ = visible; 482 if (!ready()) 483 return; 484 485 if (compositing_helper_.get()) 486 compositing_helper_->UpdateVisibility(visible); 487 488 browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetVisibility( 489 render_view_routing_id_, 490 browser_plugin_instance_id_, 491 visible)); 492 } 493 494 bool BrowserPlugin::acceptsInputEvents() { 495 return true; 496 } 497 498 bool BrowserPlugin::handleInputEvent(const blink::WebInputEvent& event, 499 blink::WebCursorInfo& cursor_info) { 500 if (guest_crashed_ || !ready()) 501 return false; 502 503 if (event.type == blink::WebInputEvent::ContextMenu) 504 return true; 505 506 if (blink::WebInputEvent::isKeyboardEventType(event.type) && 507 !edit_commands_.empty()) { 508 browser_plugin_manager()->Send( 509 new BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent( 510 render_view_routing_id_, 511 browser_plugin_instance_id_, 512 edit_commands_)); 513 edit_commands_.clear(); 514 } 515 516 browser_plugin_manager()->Send( 517 new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_, 518 browser_plugin_instance_id_, 519 plugin_rect_, 520 &event)); 521 GetWebKitCursorInfo(cursor_, &cursor_info); 522 return true; 523 } 524 525 bool BrowserPlugin::handleDragStatusUpdate(blink::WebDragStatus drag_status, 526 const blink::WebDragData& drag_data, 527 blink::WebDragOperationsMask mask, 528 const blink::WebPoint& position, 529 const blink::WebPoint& screen) { 530 if (guest_crashed_ || !ready()) 531 return false; 532 browser_plugin_manager()->Send( 533 new BrowserPluginHostMsg_DragStatusUpdate( 534 render_view_routing_id_, 535 browser_plugin_instance_id_, 536 drag_status, 537 DropDataBuilder::Build(drag_data), 538 mask, 539 position)); 540 return true; 541 } 542 543 void BrowserPlugin::didReceiveResponse( 544 const blink::WebURLResponse& response) { 545 } 546 547 void BrowserPlugin::didReceiveData(const char* data, int data_length) { 548 if (delegate_) 549 delegate_->DidReceiveData(data, data_length); 550 } 551 552 void BrowserPlugin::didFinishLoading() { 553 if (delegate_) 554 delegate_->DidFinishLoading(); 555 } 556 557 void BrowserPlugin::didFailLoading(const blink::WebURLError& error) { 558 } 559 560 void BrowserPlugin::didFinishLoadingFrameRequest(const blink::WebURL& url, 561 void* notify_data) { 562 } 563 564 void BrowserPlugin::didFailLoadingFrameRequest( 565 const blink::WebURL& url, 566 void* notify_data, 567 const blink::WebURLError& error) { 568 } 569 570 bool BrowserPlugin::executeEditCommand(const blink::WebString& name) { 571 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ExecuteEditCommand( 572 render_view_routing_id_, 573 browser_plugin_instance_id_, 574 name.utf8())); 575 576 // BrowserPlugin swallows edit commands. 577 return true; 578 } 579 580 bool BrowserPlugin::executeEditCommand(const blink::WebString& name, 581 const blink::WebString& value) { 582 edit_commands_.push_back(EditCommand(name.utf8(), value.utf8())); 583 // BrowserPlugin swallows edit commands. 584 return true; 585 } 586 587 bool BrowserPlugin::setComposition( 588 const blink::WebString& text, 589 const blink::WebVector<blink::WebCompositionUnderline>& underlines, 590 int selectionStart, 591 int selectionEnd) { 592 if (!ready()) 593 return false; 594 std::vector<blink::WebCompositionUnderline> std_underlines; 595 for (size_t i = 0; i < underlines.size(); ++i) { 596 std_underlines.push_back(underlines[i]); 597 } 598 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeSetComposition( 599 render_view_routing_id_, 600 browser_plugin_instance_id_, 601 text.utf8(), 602 std_underlines, 603 selectionStart, 604 selectionEnd)); 605 // TODO(kochi): This assumes the IPC handling always succeeds. 606 return true; 607 } 608 609 bool BrowserPlugin::confirmComposition( 610 const blink::WebString& text, 611 blink::WebWidget::ConfirmCompositionBehavior selectionBehavior) { 612 if (!ready()) 613 return false; 614 bool keep_selection = (selectionBehavior == blink::WebWidget::KeepSelection); 615 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeConfirmComposition( 616 render_view_routing_id_, 617 browser_plugin_instance_id_, 618 text.utf8(), 619 keep_selection)); 620 // TODO(kochi): This assumes the IPC handling always succeeds. 621 return true; 622 } 623 624 void BrowserPlugin::extendSelectionAndDelete(int before, int after) { 625 if (!ready()) 626 return; 627 browser_plugin_manager()->Send( 628 new BrowserPluginHostMsg_ExtendSelectionAndDelete( 629 render_view_routing_id_, 630 browser_plugin_instance_id_, 631 before, 632 after)); 633 } 634 635 void BrowserPlugin::OnLockMouseACK(bool succeeded) { 636 mouse_locked_ = succeeded; 637 browser_plugin_manager()->Send(new BrowserPluginHostMsg_LockMouse_ACK( 638 render_view_routing_id_, 639 browser_plugin_instance_id_, 640 succeeded)); 641 } 642 643 void BrowserPlugin::OnMouseLockLost() { 644 mouse_locked_ = false; 645 browser_plugin_manager()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK( 646 render_view_routing_id_, 647 browser_plugin_instance_id_)); 648 } 649 650 bool BrowserPlugin::HandleMouseLockedInputEvent( 651 const blink::WebMouseEvent& event) { 652 browser_plugin_manager()->Send( 653 new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_, 654 browser_plugin_instance_id_, 655 plugin_rect_, 656 &event)); 657 return true; 658 } 659 660 } // namespace content 661