cc: Make picture pile base thread safe.
[chromium-blink-merge.git] / content / renderer / browser_plugin / browser_plugin.cc
blobe6c1f5eb61b38155de77ff32797e7668683a21a0
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 typedef std::map<blink::WebPluginContainer*, content::BrowserPlugin*>
43 PluginContainerMap;
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 NULL;
56 PluginContainerMap* browser_plugins = g_plugin_container_map.Pointer();
57 PluginContainerMap::iterator it = browser_plugins->find(container);
58 return it == browser_plugins->end() ? NULL : it->second;
61 BrowserPlugin::BrowserPlugin(RenderViewImpl* render_view,
62 blink::WebFrame* frame,
63 scoped_ptr<BrowserPluginDelegate> delegate)
64 : attached_(false),
65 attach_pending_(false),
66 render_view_(render_view->AsWeakPtr()),
67 render_view_routing_id_(render_view->GetRoutingID()),
68 container_(NULL),
69 last_device_scale_factor_(GetDeviceScaleFactor()),
70 sad_guest_(NULL),
71 guest_crashed_(false),
72 plugin_focused_(false),
73 visible_(true),
74 mouse_locked_(false),
75 ready_(false),
76 browser_plugin_manager_(render_view->GetBrowserPluginManager()),
77 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
78 contents_opaque_(true),
79 delegate_(delegate.Pass()),
80 weak_ptr_factory_(this) {
81 browser_plugin_instance_id_ = browser_plugin_manager()->GetNextInstanceID();
83 if (delegate_)
84 delegate_->SetElementInstanceID(browser_plugin_instance_id_);
87 BrowserPlugin::~BrowserPlugin() {
88 browser_plugin_manager()->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_Attach_ACK, OnAttachACK)
95 IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
96 IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped,
97 OnCompositorFrameSwapped(message))
98 IPC_MESSAGE_HANDLER(BrowserPluginMsg_CopyFromCompositingSurface,
99 OnCopyFromCompositingSurface)
100 IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone)
101 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetContentsOpaque, OnSetContentsOpaque)
102 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
103 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetMouseLock, OnSetMouseLock)
104 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetTooltipText, OnSetTooltipText)
105 IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
106 OnShouldAcceptTouchEvents)
107 IPC_MESSAGE_UNHANDLED(handled = false)
108 IPC_END_MESSAGE_MAP()
109 return handled;
112 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
113 const base::string16& attribute_value) {
114 if (!container())
115 return;
117 blink::WebElement element = container()->element();
118 blink::WebString web_attribute_name =
119 blink::WebString::fromUTF8(attribute_name);
120 element.setAttribute(web_attribute_name, attribute_value);
123 void BrowserPlugin::Attach() {
124 if (ready()) {
125 attached_ = false;
126 guest_crashed_ = false;
127 EnableCompositing(false);
128 if (compositing_helper_.get()) {
129 compositing_helper_->OnContainerDestroy();
130 compositing_helper_ = NULL;
134 // TODO(fsamuel): Add support for reattachment.
135 BrowserPluginHostMsg_Attach_Params attach_params;
136 attach_params.focused = ShouldGuestBeFocused();
137 attach_params.visible = visible_;
138 attach_params.origin = plugin_rect().origin();
139 attach_params.is_full_page_plugin = false;
140 if (container()) {
141 blink::WebLocalFrame* frame = container()->element().document().frame();
142 attach_params.is_full_page_plugin =
143 frame->view()->mainFrame()->document().isPluginDocument();
145 gfx::Size view_size(width(), height());
146 if (!view_size.IsEmpty()) {
147 PopulateResizeGuestParameters(view_size,
148 &attach_params.resize_guest_params);
150 browser_plugin_manager()->Send(new BrowserPluginHostMsg_Attach(
151 render_view_routing_id_,
152 browser_plugin_instance_id_,
153 attach_params));
155 attach_pending_ = true;
158 void BrowserPlugin::DidCommitCompositorFrame() {
159 if (compositing_helper_.get())
160 compositing_helper_->DidCommitCompositorFrame();
163 void BrowserPlugin::OnAdvanceFocus(int browser_plugin_instance_id,
164 bool reverse) {
165 DCHECK(render_view_);
166 render_view_->GetWebView()->advanceFocus(reverse);
169 void BrowserPlugin::OnAttachACK(int browser_plugin_instance_id) {
170 DCHECK(!attached());
171 attached_ = true;
172 attach_pending_ = false;
175 void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) {
176 BrowserPluginMsg_CompositorFrameSwapped::Param param;
177 if (!BrowserPluginMsg_CompositorFrameSwapped::Read(&message, &param))
178 return;
179 // Note that there is no need to send ACK for this message.
180 // If the guest has updated pixels then it is no longer crashed.
181 guest_crashed_ = false;
183 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
184 param.b.frame.AssignTo(frame.get());
186 EnableCompositing(true);
187 compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
188 param.b.producing_route_id,
189 param.b.output_surface_id,
190 param.b.producing_host_id,
191 param.b.shared_memory_handle);
194 void BrowserPlugin::OnCopyFromCompositingSurface(int browser_plugin_instance_id,
195 int request_id,
196 gfx::Rect source_rect,
197 gfx::Size dest_size) {
198 if (!compositing_helper_.get()) {
199 browser_plugin_manager()->Send(
200 new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck(
201 render_view_routing_id_,
202 browser_plugin_instance_id_,
203 request_id,
204 SkBitmap()));
205 return;
207 compositing_helper_->CopyFromCompositingSurface(request_id, source_rect,
208 dest_size);
211 void BrowserPlugin::OnGuestGone(int browser_plugin_instance_id) {
212 guest_crashed_ = true;
214 // Turn off compositing so we can display the sad graphic. Changes to
215 // compositing state will show up at a later time after a layout and commit.
216 EnableCompositing(false);
218 // Queue up showing the sad graphic to give content embedders an opportunity
219 // to fire their listeners and potentially overlay the webview with custom
220 // behavior. If the BrowserPlugin is destroyed in the meantime, then the
221 // task will not be executed.
222 base::MessageLoop::current()->PostTask(
223 FROM_HERE,
224 base::Bind(&BrowserPlugin::ShowSadGraphic,
225 weak_ptr_factory_.GetWeakPtr()));
228 void BrowserPlugin::OnSetContentsOpaque(int browser_plugin_instance_id,
229 bool opaque) {
230 if (contents_opaque_ == opaque)
231 return;
232 contents_opaque_ = opaque;
233 if (compositing_helper_.get())
234 compositing_helper_->SetContentsOpaque(opaque);
237 void BrowserPlugin::OnSetCursor(int browser_plugin_instance_id,
238 const WebCursor& cursor) {
239 cursor_ = cursor;
242 void BrowserPlugin::OnSetMouseLock(int browser_plugin_instance_id,
243 bool enable) {
244 if (enable) {
245 if (mouse_locked_)
246 return;
247 render_view_->mouse_lock_dispatcher()->LockMouse(this);
248 } else {
249 if (!mouse_locked_) {
250 OnLockMouseACK(false);
251 return;
253 render_view_->mouse_lock_dispatcher()->UnlockMouse(this);
257 void BrowserPlugin::OnSetTooltipText(int instance_id,
258 const base::string16& tooltip_text) {
259 // Show tooltip text by setting the BrowserPlugin's |title| attribute.
260 UpdateDOMAttribute("title", tooltip_text);
263 void BrowserPlugin::OnShouldAcceptTouchEvents(int browser_plugin_instance_id,
264 bool accept) {
265 if (container()) {
266 container()->requestTouchEventType(
267 accept ? WebPluginContainer::TouchEventRequestTypeRaw
268 : WebPluginContainer::TouchEventRequestTypeNone);
272 void BrowserPlugin::ShowSadGraphic() {
273 // If the BrowserPlugin is scheduled to be deleted, then container_ will be
274 // NULL so we shouldn't attempt to access it.
275 if (container_)
276 container_->invalidate();
279 float BrowserPlugin::GetDeviceScaleFactor() const {
280 if (!render_view_)
281 return 1.0f;
282 return render_view_->GetWebView()->deviceScaleFactor();
285 void BrowserPlugin::UpdateDeviceScaleFactor() {
286 if (last_device_scale_factor_ == GetDeviceScaleFactor())
287 return;
289 BrowserPluginHostMsg_ResizeGuest_Params params;
290 PopulateResizeGuestParameters(plugin_size(), &params);
291 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
292 render_view_routing_id_,
293 browser_plugin_instance_id_,
294 params));
297 void BrowserPlugin::UpdateGuestFocusState() {
298 if (!ready())
299 return;
300 bool should_be_focused = ShouldGuestBeFocused();
301 browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetFocus(
302 render_view_routing_id_,
303 browser_plugin_instance_id_,
304 should_be_focused));
307 bool BrowserPlugin::ShouldGuestBeFocused() const {
308 bool embedder_focused = false;
309 if (render_view_)
310 embedder_focused = render_view_->has_focus();
311 return plugin_focused_ && embedder_focused;
314 WebPluginContainer* BrowserPlugin::container() const {
315 return container_;
318 bool BrowserPlugin::initialize(WebPluginContainer* container) {
319 if (!container)
320 return false;
322 container_ = container;
323 container_->setWantsWheelEvents(true);
325 g_plugin_container_map.Get().insert(std::make_pair(container_, this));
327 browser_plugin_manager()->AddBrowserPlugin(browser_plugin_instance_id_, this);
329 // This is a way to notify observers of our attributes that this plugin is
330 // available in render tree.
331 // TODO(lazyboy): This should be done through the delegate instead. Perhaps
332 // by firing an event from there.
333 UpdateDOMAttribute(
334 "internalinstanceid",
335 base::UTF8ToUTF16(base::IntToString(browser_plugin_instance_id_)));
337 return true;
340 void BrowserPlugin::EnableCompositing(bool enable) {
341 bool enabled = !!compositing_helper_.get();
342 if (enabled == enable)
343 return;
345 if (enable) {
346 DCHECK(!compositing_helper_.get());
347 if (!compositing_helper_.get()) {
348 compositing_helper_ = ChildFrameCompositingHelper::CreateForBrowserPlugin(
349 weak_ptr_factory_.GetWeakPtr());
352 compositing_helper_->EnableCompositing(enable);
353 compositing_helper_->SetContentsOpaque(contents_opaque_);
355 if (!enable) {
356 DCHECK(compositing_helper_.get());
357 compositing_helper_->OnContainerDestroy();
358 compositing_helper_ = NULL;
362 void BrowserPlugin::destroy() {
363 if (container_) {
364 //container_->clearScriptObjects();
366 // The BrowserPlugin's WebPluginContainer is deleted immediately after this
367 // call returns, so let's not keep a reference to it around.
368 g_plugin_container_map.Get().erase(container_);
371 if (compositing_helper_.get())
372 compositing_helper_->OnContainerDestroy();
373 container_ = NULL;
374 // Will be a no-op if the mouse is not currently locked.
375 if (render_view_)
376 render_view_->mouse_lock_dispatcher()->OnLockTargetDestroyed(this);
377 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
380 bool BrowserPlugin::supportsKeyboardFocus() const {
381 return true;
384 bool BrowserPlugin::supportsEditCommands() const {
385 return true;
388 bool BrowserPlugin::supportsInputMethod() const {
389 return true;
392 bool BrowserPlugin::canProcessDrag() const {
393 return true;
396 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
397 if (guest_crashed_) {
398 if (!sad_guest_) // Lazily initialize bitmap.
399 sad_guest_ = content::GetContentClient()->renderer()->
400 GetSadWebViewBitmap();
401 // content_shell does not have the sad plugin bitmap, so we'll paint black
402 // instead to make it clear that something went wrong.
403 if (sad_guest_) {
404 PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
405 return;
408 SkAutoCanvasRestore auto_restore(canvas, true);
409 canvas->translate(plugin_rect_.x(), plugin_rect_.y());
410 SkRect image_data_rect = SkRect::MakeXYWH(
411 SkIntToScalar(0),
412 SkIntToScalar(0),
413 SkIntToScalar(plugin_rect_.width()),
414 SkIntToScalar(plugin_rect_.height()));
415 canvas->clipRect(image_data_rect);
416 // Paint black or white in case we have nothing in our backing store or we
417 // need to show a gutter.
418 SkPaint paint;
419 paint.setStyle(SkPaint::kFill_Style);
420 paint.setColor(guest_crashed_ ? SK_ColorBLACK : SK_ColorWHITE);
421 canvas->drawRect(image_data_rect, paint);
424 // static
425 bool BrowserPlugin::ShouldForwardToBrowserPlugin(
426 const IPC::Message& message) {
427 switch (message.type()) {
428 case BrowserPluginMsg_Attach_ACK::ID:
429 case BrowserPluginMsg_AdvanceFocus::ID:
430 case BrowserPluginMsg_CompositorFrameSwapped::ID:
431 case BrowserPluginMsg_CopyFromCompositingSurface::ID:
432 case BrowserPluginMsg_GuestGone::ID:
433 case BrowserPluginMsg_SetContentsOpaque::ID:
434 case BrowserPluginMsg_SetCursor::ID:
435 case BrowserPluginMsg_SetMouseLock::ID:
436 case BrowserPluginMsg_SetTooltipText::ID:
437 case BrowserPluginMsg_ShouldAcceptTouchEvents::ID:
438 return true;
439 default:
440 break;
442 return false;
445 void BrowserPlugin::updateGeometry(
446 const WebRect& window_rect,
447 const WebRect& clip_rect,
448 const WebVector<WebRect>& cut_outs_rects,
449 bool is_visible) {
450 int old_width = width();
451 int old_height = height();
452 plugin_rect_ = window_rect;
453 if (!ready_) {
454 if (delegate_)
455 delegate_->Ready();
456 ready_ = true;
458 if (!attached())
459 return;
461 if (old_width == window_rect.width && old_height == window_rect.height) {
462 // Let the browser know about the updated view rect.
463 browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateGeometry(
464 render_view_routing_id_, browser_plugin_instance_id_, plugin_rect_));
465 return;
468 BrowserPluginHostMsg_ResizeGuest_Params params;
469 PopulateResizeGuestParameters(plugin_size(), &params);
470 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
471 render_view_routing_id_,
472 browser_plugin_instance_id_,
473 params));
476 void BrowserPlugin::PopulateResizeGuestParameters(
477 const gfx::Size& view_size,
478 BrowserPluginHostMsg_ResizeGuest_Params* params) {
479 params->view_size = view_size;
480 params->scale_factor = GetDeviceScaleFactor();
481 if (last_device_scale_factor_ != params->scale_factor) {
482 last_device_scale_factor_ = params->scale_factor;
483 params->repaint = true;
487 void BrowserPlugin::updateFocus(bool focused) {
488 plugin_focused_ = focused;
489 UpdateGuestFocusState();
492 void BrowserPlugin::updateVisibility(bool visible) {
493 if (visible_ == visible)
494 return;
496 visible_ = visible;
497 if (!ready())
498 return;
500 if (compositing_helper_.get())
501 compositing_helper_->UpdateVisibility(visible);
503 browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetVisibility(
504 render_view_routing_id_,
505 browser_plugin_instance_id_,
506 visible));
509 bool BrowserPlugin::acceptsInputEvents() {
510 return true;
513 bool BrowserPlugin::handleInputEvent(const blink::WebInputEvent& event,
514 blink::WebCursorInfo& cursor_info) {
515 if (guest_crashed_ || !ready())
516 return false;
518 if (event.type == blink::WebInputEvent::ContextMenu)
519 return true;
521 if (blink::WebInputEvent::isKeyboardEventType(event.type) &&
522 !edit_commands_.empty()) {
523 browser_plugin_manager()->Send(
524 new BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent(
525 render_view_routing_id_,
526 browser_plugin_instance_id_,
527 edit_commands_));
528 edit_commands_.clear();
531 browser_plugin_manager()->Send(
532 new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
533 browser_plugin_instance_id_,
534 plugin_rect_,
535 &event));
536 GetWebKitCursorInfo(cursor_, &cursor_info);
537 return true;
540 bool BrowserPlugin::handleDragStatusUpdate(blink::WebDragStatus drag_status,
541 const blink::WebDragData& drag_data,
542 blink::WebDragOperationsMask mask,
543 const blink::WebPoint& position,
544 const blink::WebPoint& screen) {
545 if (guest_crashed_ || !ready())
546 return false;
547 browser_plugin_manager()->Send(
548 new BrowserPluginHostMsg_DragStatusUpdate(
549 render_view_routing_id_,
550 browser_plugin_instance_id_,
551 drag_status,
552 DropDataBuilder::Build(drag_data),
553 mask,
554 position));
555 return true;
558 void BrowserPlugin::didReceiveResponse(
559 const blink::WebURLResponse& response) {
562 void BrowserPlugin::didReceiveData(const char* data, int data_length) {
563 if (delegate_)
564 delegate_->DidReceiveData(data, data_length);
567 void BrowserPlugin::didFinishLoading() {
568 if (delegate_)
569 delegate_->DidFinishLoading();
572 void BrowserPlugin::didFailLoading(const blink::WebURLError& error) {
575 void BrowserPlugin::didFinishLoadingFrameRequest(const blink::WebURL& url,
576 void* notify_data) {
579 void BrowserPlugin::didFailLoadingFrameRequest(
580 const blink::WebURL& url,
581 void* notify_data,
582 const blink::WebURLError& error) {
585 bool BrowserPlugin::executeEditCommand(const blink::WebString& name) {
586 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
587 render_view_routing_id_,
588 browser_plugin_instance_id_,
589 name.utf8()));
591 // BrowserPlugin swallows edit commands.
592 return true;
595 bool BrowserPlugin::executeEditCommand(const blink::WebString& name,
596 const blink::WebString& value) {
597 edit_commands_.push_back(EditCommand(name.utf8(), value.utf8()));
598 // BrowserPlugin swallows edit commands.
599 return true;
602 bool BrowserPlugin::setComposition(
603 const blink::WebString& text,
604 const blink::WebVector<blink::WebCompositionUnderline>& underlines,
605 int selectionStart,
606 int selectionEnd) {
607 if (!ready())
608 return false;
609 std::vector<blink::WebCompositionUnderline> std_underlines;
610 for (size_t i = 0; i < underlines.size(); ++i) {
611 std_underlines.push_back(underlines[i]);
613 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeSetComposition(
614 render_view_routing_id_,
615 browser_plugin_instance_id_,
616 text.utf8(),
617 std_underlines,
618 selectionStart,
619 selectionEnd));
620 // TODO(kochi): This assumes the IPC handling always succeeds.
621 return true;
624 bool BrowserPlugin::confirmComposition(
625 const blink::WebString& text,
626 blink::WebWidget::ConfirmCompositionBehavior selectionBehavior) {
627 if (!ready())
628 return false;
629 bool keep_selection = (selectionBehavior == blink::WebWidget::KeepSelection);
630 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeConfirmComposition(
631 render_view_routing_id_,
632 browser_plugin_instance_id_,
633 text.utf8(),
634 keep_selection));
635 // TODO(kochi): This assumes the IPC handling always succeeds.
636 return true;
639 void BrowserPlugin::extendSelectionAndDelete(int before, int after) {
640 if (!ready())
641 return;
642 browser_plugin_manager()->Send(
643 new BrowserPluginHostMsg_ExtendSelectionAndDelete(
644 render_view_routing_id_,
645 browser_plugin_instance_id_,
646 before,
647 after));
650 void BrowserPlugin::OnLockMouseACK(bool succeeded) {
651 mouse_locked_ = succeeded;
652 browser_plugin_manager()->Send(new BrowserPluginHostMsg_LockMouse_ACK(
653 render_view_routing_id_,
654 browser_plugin_instance_id_,
655 succeeded));
658 void BrowserPlugin::OnMouseLockLost() {
659 mouse_locked_ = false;
660 browser_plugin_manager()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK(
661 render_view_routing_id_,
662 browser_plugin_instance_id_));
665 bool BrowserPlugin::HandleMouseLockedInputEvent(
666 const blink::WebMouseEvent& event) {
667 browser_plugin_manager()->Send(
668 new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
669 browser_plugin_instance_id_,
670 plugin_rect_,
671 &event));
672 return true;
675 } // namespace content