[ServiceWorker] Implement WebServiceWorkerContextClient::openWindow().
[chromium-blink-merge.git] / content / renderer / browser_plugin / browser_plugin.cc
blob0f1935acbdfd17d86607dbe4858aad288fc73c4e
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.
5 #include "content/renderer/browser_plugin/browser_plugin.h"
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/WebDocument.h"
26 #include "third_party/WebKit/public/web/WebElement.h"
27 #include "third_party/WebKit/public/web/WebInputEvent.h"
28 #include "third_party/WebKit/public/web/WebLocalFrame.h"
29 #include "third_party/WebKit/public/web/WebPluginContainer.h"
30 #include "third_party/WebKit/public/web/WebView.h"
31 #include "third_party/skia/include/core/SkCanvas.h"
32 #include "ui/events/keycodes/keyboard_codes.h"
34 using blink::WebCanvas;
35 using blink::WebPluginContainer;
36 using blink::WebPoint;
37 using blink::WebRect;
38 using blink::WebURL;
39 using blink::WebVector;
41 namespace {
42 using PluginContainerMap =
43 std::map<blink::WebPluginContainer*, content::BrowserPlugin*>;
44 static base::LazyInstance<PluginContainerMap> g_plugin_container_map =
45 LAZY_INSTANCE_INITIALIZER;
46 } // namespace
48 namespace content {
50 // static
51 BrowserPlugin* BrowserPlugin::GetFromNode(blink::WebNode& node) {
52 blink::WebPluginContainer* container = node.pluginContainer();
53 if (!container)
54 return nullptr;
56 PluginContainerMap* browser_plugins = g_plugin_container_map.Pointer();
57 PluginContainerMap::iterator it = browser_plugins->find(container);
58 return it == browser_plugins->end() ? nullptr : it->second;
61 BrowserPlugin::BrowserPlugin(RenderFrame* render_frame,
62 scoped_ptr<BrowserPluginDelegate> delegate)
63 : attached_(false),
64 render_view_routing_id_(render_frame->GetRenderView()->GetRoutingID()),
65 container_(nullptr),
66 last_device_scale_factor_(GetDeviceScaleFactor()),
67 sad_guest_(nullptr),
68 guest_crashed_(false),
69 plugin_focused_(false),
70 visible_(true),
71 mouse_locked_(false),
72 ready_(false),
73 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
74 contents_opaque_(true),
75 delegate_(delegate.Pass()),
76 weak_ptr_factory_(this) {
77 browser_plugin_instance_id_ =
78 BrowserPluginManager::Get()->GetNextInstanceID();
80 if (delegate_)
81 delegate_->SetElementInstanceID(browser_plugin_instance_id_);
84 BrowserPlugin::~BrowserPlugin() {
85 if (compositing_helper_.get())
86 compositing_helper_->OnContainerDestroy();
88 BrowserPluginManager::Get()->RemoveBrowserPlugin(browser_plugin_instance_id_);
91 bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
92 bool handled = true;
93 IPC_BEGIN_MESSAGE_MAP(BrowserPlugin, message)
94 IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
95 IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped,
96 OnCompositorFrameSwapped(message))
97 IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone)
98 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetContentsOpaque, OnSetContentsOpaque)
99 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
100 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetMouseLock, OnSetMouseLock)
101 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetTooltipText, OnSetTooltipText)
102 IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
103 OnShouldAcceptTouchEvents)
104 IPC_MESSAGE_UNHANDLED(
105 handled = delegate_ && delegate_->OnMessageReceived(message))
106 IPC_END_MESSAGE_MAP()
107 return handled;
110 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
111 const base::string16& attribute_value) {
112 if (!container())
113 return;
115 blink::WebElement element = container()->element();
116 blink::WebString web_attribute_name =
117 blink::WebString::fromUTF8(attribute_name);
118 element.setAttribute(web_attribute_name, attribute_value);
121 void BrowserPlugin::Attach() {
122 Detach();
124 // TODO(fsamuel): Add support for reattachment.
125 BrowserPluginHostMsg_Attach_Params attach_params;
126 attach_params.focused = ShouldGuestBeFocused();
127 attach_params.visible = visible_;
128 attach_params.origin = plugin_rect().origin();
129 attach_params.is_full_page_plugin = false;
130 if (container()) {
131 blink::WebLocalFrame* frame = container()->element().document().frame();
132 attach_params.is_full_page_plugin =
133 frame->view()->mainFrame()->document().isPluginDocument();
135 gfx::Size view_size(width(), height());
136 if (!view_size.IsEmpty()) {
137 PopulateResizeGuestParameters(view_size,
138 &attach_params.resize_guest_params);
140 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_Attach(
141 render_view_routing_id_,
142 browser_plugin_instance_id_,
143 attach_params));
145 attached_ = true;
148 void BrowserPlugin::Detach() {
149 if (!attached())
150 return;
152 attached_ = false;
153 guest_crashed_ = false;
154 EnableCompositing(false);
155 if (compositing_helper_.get()) {
156 compositing_helper_->OnContainerDestroy();
157 compositing_helper_ = nullptr;
160 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_Detach(
161 render_view_routing_id_, browser_plugin_instance_id_));
164 void BrowserPlugin::DidCommitCompositorFrame() {
165 if (compositing_helper_.get())
166 compositing_helper_->DidCommitCompositorFrame();
169 void BrowserPlugin::OnAdvanceFocus(int browser_plugin_instance_id,
170 bool reverse) {
171 auto render_view = RenderViewImpl::FromRoutingID(render_view_routing_id());
172 if (!render_view)
173 return;
174 render_view->GetWebView()->advanceFocus(reverse);
177 void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) {
178 if (!attached())
179 return;
181 BrowserPluginMsg_CompositorFrameSwapped::Param param;
182 if (!BrowserPluginMsg_CompositorFrameSwapped::Read(&message, &param))
183 return;
184 // Note that there is no need to send ACK for this message.
185 // If the guest has updated pixels then it is no longer crashed.
186 guest_crashed_ = false;
188 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
189 get<1>(param).frame.AssignTo(frame.get());
191 EnableCompositing(true);
192 compositing_helper_->OnCompositorFrameSwapped(
193 frame.Pass(),
194 get<1>(param).producing_route_id,
195 get<1>(param).output_surface_id,
196 get<1>(param).producing_host_id,
197 get<1>(param).shared_memory_handle);
200 void BrowserPlugin::OnGuestGone(int browser_plugin_instance_id) {
201 guest_crashed_ = true;
203 // Turn off compositing so we can display the sad graphic. Changes to
204 // compositing state will show up at a later time after a layout and commit.
205 EnableCompositing(false);
207 // Queue up showing the sad graphic to give content embedders an opportunity
208 // to fire their listeners and potentially overlay the webview with custom
209 // behavior. If the BrowserPlugin is destroyed in the meantime, then the
210 // task will not be executed.
211 base::MessageLoop::current()->PostTask(
212 FROM_HERE,
213 base::Bind(&BrowserPlugin::ShowSadGraphic,
214 weak_ptr_factory_.GetWeakPtr()));
217 void BrowserPlugin::OnSetContentsOpaque(int browser_plugin_instance_id,
218 bool opaque) {
219 if (contents_opaque_ == opaque)
220 return;
221 contents_opaque_ = opaque;
222 if (compositing_helper_.get())
223 compositing_helper_->SetContentsOpaque(opaque);
226 void BrowserPlugin::OnSetCursor(int browser_plugin_instance_id,
227 const WebCursor& cursor) {
228 cursor_ = cursor;
231 void BrowserPlugin::OnSetMouseLock(int browser_plugin_instance_id,
232 bool enable) {
233 auto render_view = RenderViewImpl::FromRoutingID(render_view_routing_id());
234 if (enable) {
235 if (mouse_locked_ || !render_view)
236 return;
237 render_view->mouse_lock_dispatcher()->LockMouse(this);
238 } else {
239 if (!mouse_locked_) {
240 OnLockMouseACK(false);
241 return;
243 if (!render_view)
244 return;
245 render_view->mouse_lock_dispatcher()->UnlockMouse(this);
249 void BrowserPlugin::OnSetTooltipText(int instance_id,
250 const base::string16& tooltip_text) {
251 // Show tooltip text by setting the BrowserPlugin's |title| attribute.
252 UpdateDOMAttribute("title", tooltip_text);
255 void BrowserPlugin::OnShouldAcceptTouchEvents(int browser_plugin_instance_id,
256 bool accept) {
257 if (container()) {
258 container()->requestTouchEventType(
259 accept ? WebPluginContainer::TouchEventRequestTypeRaw
260 : WebPluginContainer::TouchEventRequestTypeNone);
264 void BrowserPlugin::ShowSadGraphic() {
265 // If the BrowserPlugin is scheduled to be deleted, then container_ will be
266 // nullptr so we shouldn't attempt to access it.
267 if (container_)
268 container_->invalidate();
271 float BrowserPlugin::GetDeviceScaleFactor() const {
272 auto render_view = RenderViewImpl::FromRoutingID(render_view_routing_id());
273 if (!render_view)
274 return 1.0f;
275 return render_view->GetWebView()->deviceScaleFactor();
278 void BrowserPlugin::UpdateDeviceScaleFactor() {
279 if (last_device_scale_factor_ == GetDeviceScaleFactor())
280 return;
282 BrowserPluginHostMsg_ResizeGuest_Params params;
283 PopulateResizeGuestParameters(plugin_size(), &params);
284 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ResizeGuest(
285 render_view_routing_id_,
286 browser_plugin_instance_id_,
287 params));
290 void BrowserPlugin::UpdateGuestFocusState(blink::WebFocusType focus_type) {
291 if (!attached())
292 return;
293 bool should_be_focused = ShouldGuestBeFocused();
294 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_SetFocus(
295 render_view_routing_id_,
296 browser_plugin_instance_id_,
297 should_be_focused,
298 focus_type));
301 bool BrowserPlugin::ShouldGuestBeFocused() const {
302 bool embedder_focused = false;
303 auto render_view = RenderViewImpl::FromRoutingID(render_view_routing_id());
304 if (render_view)
305 embedder_focused = render_view->has_focus();
306 return plugin_focused_ && embedder_focused;
309 WebPluginContainer* BrowserPlugin::container() const {
310 return container_;
313 bool BrowserPlugin::initialize(WebPluginContainer* container) {
314 if (!container)
315 return false;
317 container_ = container;
318 container_->setWantsWheelEvents(true);
320 g_plugin_container_map.Get().insert(std::make_pair(container_, this));
322 BrowserPluginManager::Get()->AddBrowserPlugin(
323 browser_plugin_instance_id_, this);
325 // This is a way to notify observers of our attributes that this plugin is
326 // available in render tree.
327 // TODO(lazyboy): This should be done through the delegate instead. Perhaps
328 // by firing an event from there.
329 UpdateDOMAttribute(
330 "internalinstanceid",
331 base::UTF8ToUTF16(base::IntToString(browser_plugin_instance_id_)));
333 return true;
336 void BrowserPlugin::EnableCompositing(bool enable) {
337 bool enabled = !!compositing_helper_.get();
338 if (enabled == enable)
339 return;
341 if (enable) {
342 DCHECK(!compositing_helper_.get());
343 if (!compositing_helper_.get()) {
344 compositing_helper_ = ChildFrameCompositingHelper::CreateForBrowserPlugin(
345 weak_ptr_factory_.GetWeakPtr());
348 compositing_helper_->EnableCompositing(enable);
349 compositing_helper_->SetContentsOpaque(contents_opaque_);
351 if (!enable) {
352 DCHECK(compositing_helper_.get());
353 compositing_helper_->OnContainerDestroy();
354 compositing_helper_ = nullptr;
358 void BrowserPlugin::destroy() {
359 if (container_) {
360 // The BrowserPlugin's WebPluginContainer is deleted immediately after this
361 // call returns, so let's not keep a reference to it around.
362 g_plugin_container_map.Get().erase(container_);
365 container_ = nullptr;
366 // Will be a no-op if the mouse is not currently locked.
367 auto render_view = RenderViewImpl::FromRoutingID(render_view_routing_id());
368 if (render_view)
369 render_view->mouse_lock_dispatcher()->OnLockTargetDestroyed(this);
370 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
373 v8::Local<v8::Object> BrowserPlugin::v8ScriptableObject(v8::Isolate* isolate) {
374 return delegate_->V8ScriptableObject(isolate);
377 bool BrowserPlugin::supportsKeyboardFocus() const {
378 return true;
381 bool BrowserPlugin::supportsEditCommands() const {
382 return true;
385 bool BrowserPlugin::supportsInputMethod() const {
386 return true;
389 bool BrowserPlugin::canProcessDrag() const {
390 return true;
393 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
394 if (guest_crashed_) {
395 if (!sad_guest_) // Lazily initialize bitmap.
396 sad_guest_ = content::GetContentClient()->renderer()->
397 GetSadWebViewBitmap();
398 // content_shell does not have the sad plugin bitmap, so we'll paint black
399 // instead to make it clear that something went wrong.
400 if (sad_guest_) {
401 PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
402 return;
405 SkAutoCanvasRestore auto_restore(canvas, true);
406 canvas->translate(plugin_rect_.x(), plugin_rect_.y());
407 SkRect image_data_rect = SkRect::MakeXYWH(
408 SkIntToScalar(0),
409 SkIntToScalar(0),
410 SkIntToScalar(plugin_rect_.width()),
411 SkIntToScalar(plugin_rect_.height()));
412 canvas->clipRect(image_data_rect);
413 // Paint black or white in case we have nothing in our backing store or we
414 // need to show a gutter.
415 SkPaint paint;
416 paint.setStyle(SkPaint::kFill_Style);
417 paint.setColor(guest_crashed_ ? SK_ColorBLACK : SK_ColorWHITE);
418 canvas->drawRect(image_data_rect, paint);
421 // static
422 bool BrowserPlugin::ShouldForwardToBrowserPlugin(
423 const IPC::Message& message) {
424 switch (message.type()) {
425 case BrowserPluginMsg_AdvanceFocus::ID:
426 case BrowserPluginMsg_CompositorFrameSwapped::ID:
427 case BrowserPluginMsg_GuestGone::ID:
428 case BrowserPluginMsg_SetContentsOpaque::ID:
429 case BrowserPluginMsg_SetCursor::ID:
430 case BrowserPluginMsg_SetMouseLock::ID:
431 case BrowserPluginMsg_SetTooltipText::ID:
432 case BrowserPluginMsg_ShouldAcceptTouchEvents::ID:
433 return true;
434 default:
435 break;
437 return false;
440 void BrowserPlugin::updateGeometry(
441 const WebRect& window_rect,
442 const WebRect& clip_rect,
443 const WebVector<WebRect>& cut_outs_rects,
444 bool is_visible) {
445 int old_width = width();
446 int old_height = height();
447 plugin_rect_ = window_rect;
448 if (!ready_) {
449 if (delegate_) {
450 delegate_->DidResizeElement(gfx::Size(), plugin_size());
451 delegate_->Ready();
453 ready_ = true;
455 if (!attached())
456 return;
458 if (old_width == window_rect.width && old_height == window_rect.height) {
459 // Let the browser know about the updated view rect.
460 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UpdateGeometry(
461 render_view_routing_id_, browser_plugin_instance_id_, plugin_rect_));
462 return;
465 BrowserPluginHostMsg_ResizeGuest_Params params;
466 PopulateResizeGuestParameters(plugin_size(), &params);
467 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ResizeGuest(
468 render_view_routing_id_,
469 browser_plugin_instance_id_,
470 params));
472 if (delegate_) {
473 delegate_->DidResizeElement(
474 gfx::Size(old_width, old_height), plugin_size());
478 void BrowserPlugin::PopulateResizeGuestParameters(
479 const gfx::Size& view_size,
480 BrowserPluginHostMsg_ResizeGuest_Params* params) {
481 params->view_size = view_size;
482 params->scale_factor = GetDeviceScaleFactor();
483 if (last_device_scale_factor_ != params->scale_factor) {
484 last_device_scale_factor_ = params->scale_factor;
485 params->repaint = true;
489 void BrowserPlugin::updateFocus(bool focused, blink::WebFocusType focus_type) {
490 plugin_focused_ = focused;
491 UpdateGuestFocusState(focus_type);
494 void BrowserPlugin::updateVisibility(bool visible) {
495 if (visible_ == visible)
496 return;
498 visible_ = visible;
499 if (!attached())
500 return;
502 if (compositing_helper_.get())
503 compositing_helper_->UpdateVisibility(visible);
505 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_SetVisibility(
506 render_view_routing_id_,
507 browser_plugin_instance_id_,
508 visible));
511 bool BrowserPlugin::acceptsInputEvents() {
512 return true;
515 bool BrowserPlugin::handleInputEvent(const blink::WebInputEvent& event,
516 blink::WebCursorInfo& cursor_info) {
517 if (guest_crashed_ || !attached())
518 return false;
520 if (event.type == blink::WebInputEvent::ContextMenu)
521 return true;
523 if (blink::WebInputEvent::isKeyboardEventType(event.type) &&
524 !edit_commands_.empty()) {
525 BrowserPluginManager::Get()->Send(
526 new BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent(
527 render_view_routing_id_,
528 browser_plugin_instance_id_,
529 edit_commands_));
530 edit_commands_.clear();
533 BrowserPluginManager::Get()->Send(
534 new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
535 browser_plugin_instance_id_,
536 plugin_rect_,
537 &event));
538 GetWebKitCursorInfo(cursor_, &cursor_info);
539 return true;
542 bool BrowserPlugin::handleDragStatusUpdate(blink::WebDragStatus drag_status,
543 const blink::WebDragData& drag_data,
544 blink::WebDragOperationsMask mask,
545 const blink::WebPoint& position,
546 const blink::WebPoint& screen) {
547 if (guest_crashed_ || !attached())
548 return false;
549 BrowserPluginManager::Get()->Send(
550 new BrowserPluginHostMsg_DragStatusUpdate(
551 render_view_routing_id_,
552 browser_plugin_instance_id_,
553 drag_status,
554 DropDataBuilder::Build(drag_data),
555 mask,
556 position));
557 return true;
560 void BrowserPlugin::didReceiveResponse(
561 const blink::WebURLResponse& response) {
564 void BrowserPlugin::didReceiveData(const char* data, int data_length) {
565 if (delegate_)
566 delegate_->DidReceiveData(data, data_length);
569 void BrowserPlugin::didFinishLoading() {
570 if (delegate_)
571 delegate_->DidFinishLoading();
574 void BrowserPlugin::didFailLoading(const blink::WebURLError& error) {
577 void BrowserPlugin::didFinishLoadingFrameRequest(const blink::WebURL& url,
578 void* notify_data) {
581 void BrowserPlugin::didFailLoadingFrameRequest(
582 const blink::WebURL& url,
583 void* notify_data,
584 const blink::WebURLError& error) {
587 bool BrowserPlugin::executeEditCommand(const blink::WebString& name) {
588 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
589 render_view_routing_id_,
590 browser_plugin_instance_id_,
591 name.utf8()));
593 // BrowserPlugin swallows edit commands.
594 return true;
597 bool BrowserPlugin::executeEditCommand(const blink::WebString& name,
598 const blink::WebString& value) {
599 edit_commands_.push_back(EditCommand(name.utf8(), value.utf8()));
600 // BrowserPlugin swallows edit commands.
601 return true;
604 bool BrowserPlugin::setComposition(
605 const blink::WebString& text,
606 const blink::WebVector<blink::WebCompositionUnderline>& underlines,
607 int selectionStart,
608 int selectionEnd) {
609 if (!attached())
610 return false;
611 std::vector<blink::WebCompositionUnderline> std_underlines;
612 for (size_t i = 0; i < underlines.size(); ++i) {
613 std_underlines.push_back(underlines[i]);
615 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ImeSetComposition(
616 render_view_routing_id_,
617 browser_plugin_instance_id_,
618 text.utf8(),
619 std_underlines,
620 selectionStart,
621 selectionEnd));
622 // TODO(kochi): This assumes the IPC handling always succeeds.
623 return true;
626 bool BrowserPlugin::confirmComposition(
627 const blink::WebString& text,
628 blink::WebWidget::ConfirmCompositionBehavior selectionBehavior) {
629 if (!attached())
630 return false;
631 bool keep_selection = (selectionBehavior == blink::WebWidget::KeepSelection);
632 BrowserPluginManager::Get()->Send(
633 new BrowserPluginHostMsg_ImeConfirmComposition(
634 render_view_routing_id_,
635 browser_plugin_instance_id_,
636 text.utf8(),
637 keep_selection));
638 // TODO(kochi): This assumes the IPC handling always succeeds.
639 return true;
642 void BrowserPlugin::extendSelectionAndDelete(int before, int after) {
643 if (!attached())
644 return;
645 BrowserPluginManager::Get()->Send(
646 new BrowserPluginHostMsg_ExtendSelectionAndDelete(
647 render_view_routing_id_,
648 browser_plugin_instance_id_,
649 before,
650 after));
653 void BrowserPlugin::OnLockMouseACK(bool succeeded) {
654 mouse_locked_ = succeeded;
655 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_LockMouse_ACK(
656 render_view_routing_id_,
657 browser_plugin_instance_id_,
658 succeeded));
661 void BrowserPlugin::OnMouseLockLost() {
662 mouse_locked_ = false;
663 BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK(
664 render_view_routing_id_,
665 browser_plugin_instance_id_));
668 bool BrowserPlugin::HandleMouseLockedInputEvent(
669 const blink::WebMouseEvent& event) {
670 BrowserPluginManager::Get()->Send(
671 new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
672 browser_plugin_instance_id_,
673 plugin_rect_,
674 &event));
675 return true;
678 } // namespace content