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.
5 #include "content/child/npapi/webplugin_delegate_impl.h"
13 #include "base/metrics/stats_counters.h"
14 #include "content/child/npapi/plugin_instance.h"
15 #include "content/child/npapi/webplugin.h"
16 #include "content/public/common/content_constants.h"
17 #include "skia/ext/platform_canvas.h"
18 #include "third_party/WebKit/public/web/WebInputEvent.h"
19 #include "ui/gfx/blit.h"
20 #include "ui/gfx/gtk_compat.h"
21 #include "webkit/common/cursors/webcursor.h"
23 #include "third_party/npapi/bindings/npapi_x11.h"
25 using blink::WebKeyboardEvent
;
26 using blink::WebInputEvent
;
27 using blink::WebMouseEvent
;
31 WebPluginDelegateImpl::WebPluginDelegateImpl(
33 PluginInstance
* instance
)
34 : windowed_handle_(0),
35 windowed_did_set_window_(false),
39 windowless_shm_pixmap_(None
),
41 first_event_time_(-1.0),
45 handle_event_depth_(0),
46 first_set_window_call_(true),
47 plugin_has_focus_(false),
48 has_webkit_focus_(false),
49 containing_view_has_focus_(true),
50 creation_succeeded_(false) {
51 memset(&window_
, 0, sizeof(window_
));
52 if (instance_
->mime_type() == kFlashPluginSwfMimeType
) {
53 // Flash is tied to Firefox's whacky behavior with windowless plugins. See
54 // comments in WindowlessPaint.
55 // TODO(viettrungluu): PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK: Don't allow
56 // right-clicks in windowless content since Flash 10.1 (initial release, at
57 // least) hangs in that case. Remove this once Flash is fixed.
58 quirks_
|= PLUGIN_QUIRK_WINDOWLESS_OFFSET_WINDOW_TO_DRAW
59 | PLUGIN_QUIRK_WINDOWLESS_INVALIDATE_AFTER_SET_WINDOW
60 | PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK
;
63 // TODO(evanm): I played with this for quite a while but couldn't
64 // figure out a way to make Flash not crash unless I didn't call
66 // However, after piman's grand refactor of windowed plugins, maybe
67 // this is no longer necessary.
68 quirks_
|= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY
;
71 WebPluginDelegateImpl::~WebPluginDelegateImpl() {
75 WindowedDestroyWindow();
77 if (window_
.ws_info
) {
78 // We only ever use ws_info as an NPSetWindowCallbackStruct.
79 delete static_cast<NPSetWindowCallbackStruct
*>(window_
.ws_info
);
83 g_object_unref(pixmap_
);
88 bool WebPluginDelegateImpl::PlatformInitialize() {
89 gfx::PluginWindowHandle handle
=
90 windowless_
? 0 : gtk_plug_get_id(GTK_PLUG(plug_
));
91 plugin_
->SetWindow(handle
);
95 void WebPluginDelegateImpl::PlatformDestroyInstance() {
96 // Nothing to do here.
99 void WebPluginDelegateImpl::Paint(SkCanvas
* canvas
, const gfx::Rect
& rect
) {
100 if (!windowless_
|| !skia::SupportsPlatformPaint(canvas
))
102 skia::ScopedPlatformPaint
scoped_platform_paint(canvas
);
103 cairo_t
* context
= scoped_platform_paint
.GetPlatformSurface();
104 WindowlessPaint(context
, rect
);
107 bool WebPluginDelegateImpl::WindowedCreatePlugin() {
108 DCHECK(!windowed_handle_
);
111 // NPP_GetValue() might write 4 bytes of data to this variable. Don't use a
112 // single byte bool, use an int instead and make sure it is initialized.
114 NPError err
= instance_
->NPP_GetValue(NPPVpluginNeedsXEmbed
, &xembed
);
115 if (err
!= NPERR_NO_ERROR
|| !xembed
) {
116 NOTIMPLEMENTED() << " windowed plugin but without xembed. "
117 "See http://code.google.com/p/chromium/issues/detail?id=38229";
121 // Passing 0 as the socket XID creates a plug without plugging it in a socket
122 // yet, so that it can be latter added with gtk_socket_add_id().
123 plug_
= gtk_plug_new(0);
124 gtk_widget_show(plug_
);
125 socket_
= gtk_socket_new();
126 gtk_widget_show(socket_
);
127 gtk_container_add(GTK_CONTAINER(plug_
), socket_
);
128 gtk_widget_show_all(plug_
);
130 // Prevent the plug from being destroyed if the browser kills the container
132 g_signal_connect(plug_
, "delete-event", G_CALLBACK(gtk_true
), NULL
);
133 // Prevent the socket from being destroyed when the plugin removes itself.
134 g_signal_connect(socket_
, "plug_removed", G_CALLBACK(gtk_true
), NULL
);
136 windowed_handle_
= gtk_socket_get_id(GTK_SOCKET(socket_
));
138 window_
.window
= reinterpret_cast<void*>(windowed_handle_
);
140 if (!window_
.ws_info
)
141 window_
.ws_info
= new NPSetWindowCallbackStruct
;
142 NPSetWindowCallbackStruct
* extra
=
143 static_cast<NPSetWindowCallbackStruct
*>(window_
.ws_info
);
144 extra
->type
= NP_SETWINDOW
;
145 extra
->display
= GDK_DISPLAY();
146 int screen
= DefaultScreen(GDK_DISPLAY());
147 extra
->visual
= DefaultVisual(GDK_DISPLAY(), screen
);
148 extra
->depth
= DefaultDepth(GDK_DISPLAY(), screen
);
149 extra
->colormap
= DefaultColormap(GDK_DISPLAY(), screen
);
154 void WebPluginDelegateImpl::WindowedDestroyWindow() {
156 plugin_
->WillDestroyWindow(gtk_plug_get_id(GTK_PLUG(plug_
)));
158 gtk_widget_destroy(plug_
);
161 windowed_handle_
= 0;
165 bool WebPluginDelegateImpl::WindowedReposition(
166 const gfx::Rect
& window_rect
,
167 const gfx::Rect
& clip_rect
) {
168 if (window_rect
== window_rect_
&& clip_rect
== clip_rect_
)
171 window_rect_
= window_rect
;
172 clip_rect_
= clip_rect
;
177 void WebPluginDelegateImpl::WindowedSetWindow() {
178 if (!instance_
.get())
181 if (!windowed_handle_
) {
186 // See https://bugzilla.mozilla.org/show_bug.cgi?id=108347
187 // If we call NPP_SetWindow with a <= 0 width or height, problems arise in
188 // Flash (and possibly other plugins).
189 // TODO(piman): the Mozilla code suggests that for the Java plugin, we should
190 // still call NPP_SetWindow in that case. We need to verify that.
191 if (window_rect_
.width() <= 0 || window_rect_
.height() <= 0) {
195 instance()->set_window_handle(windowed_handle_
);
197 DCHECK(!instance()->windowless());
199 window_
.clipRect
.top
= clip_rect_
.y();
200 window_
.clipRect
.left
= clip_rect_
.x();
201 window_
.clipRect
.bottom
= clip_rect_
.y() + clip_rect_
.height();
202 window_
.clipRect
.right
= clip_rect_
.x() + clip_rect_
.width();
203 window_
.height
= window_rect_
.height();
204 window_
.width
= window_rect_
.width();
205 window_
.x
= window_rect_
.x();
206 window_
.y
= window_rect_
.y();
207 window_
.type
= NPWindowTypeWindow
;
209 // Reset this flag before entering the instance in case of side-effects.
210 windowed_did_set_window_
= true;
212 NPError err
= instance()->NPP_SetWindow(&window_
);
213 DCHECK(err
== NPERR_NO_ERROR
);
216 void WebPluginDelegateImpl::WindowlessUpdateGeometry(
217 const gfx::Rect
& window_rect
,
218 const gfx::Rect
& clip_rect
) {
219 // Only resend to the instance if the geometry has changed.
220 if (window_rect
== window_rect_
&& clip_rect
== clip_rect_
)
223 clip_rect_
= clip_rect
;
224 window_rect_
= window_rect
;
225 WindowlessSetWindow();
228 void WebPluginDelegateImpl::EnsurePixmapAtLeastSize(int width
, int height
) {
230 gint cur_width
, cur_height
;
231 gdk_pixmap_get_size(pixmap_
, &cur_width
, &cur_height
);
232 if (cur_width
>= width
&& cur_height
>= height
)
233 return; // We are already the appropriate size.
235 // Otherwise, we need to recreate ourselves.
236 g_object_unref(pixmap_
);
240 // |sys_visual| is owned by gdk; we shouldn't free it.
241 GdkVisual
* sys_visual
= gdk_visual_get_system();
242 pixmap_
= gdk_pixmap_new(NULL
, // use width/height/depth params
243 std::max(1, width
), std::max(1, height
),
245 // TODO(erg): Replace this with GdkVisual when we move to GTK3.
246 GdkColormap
* colormap
= gdk_colormap_new(gdk_visual_get_system(),
248 gdk_drawable_set_colormap(pixmap_
, colormap
);
249 // The GdkDrawable now owns the GdkColormap.
250 g_object_unref(colormap
);
253 #ifdef DEBUG_RECTANGLES
256 // Draw a rectangle on a Cairo context.
257 // Useful for debugging various rectangles involved in drawing plugins.
258 void DrawDebugRectangle(cairo_t
* cairo
,
259 const gfx::Rect
& rect
,
260 float r
, float g
, float b
) {
261 cairo_set_source_rgba(cairo
, r
, g
, b
, 0.5);
262 cairo_rectangle(cairo
, rect
.x(), rect
.y(),
263 rect
.width(), rect
.height());
270 void WebPluginDelegateImpl::WindowlessPaint(cairo_t
* context
,
271 const gfx::Rect
& damage_rect
) {
273 // http://mxr.mozilla.org/firefox/source/layout/generic/nsObjectFrame.cpp:
274 // nsPluginInstanceOwner::Renderer::NativeDraw().
278 // TODO(darin): we should avoid calling NPP_SetWindow here since it may
279 // cause page layout to be invalidated.
281 // The actual dirty region is just the intersection of the plugin window and
282 // the clip window with the damage region. However, the plugin wants to draw
283 // relative to the containing window's origin, so our pixmap must be from the
284 // window's origin down to the bottom-right edge of the dirty region.
287 // X-----------------------------------+-----------------------------+
289 // | pixmap +-------------------+ |
290 // | | damage | window |
292 // | +---+-------------------+-------------+ |
294 // | +---+---+-------------------+----------+ | |
296 // | | | | draw | | | |
298 // +-------+---+---+-------------------+----------+--+ |
300 // | | +-------------------+ | |
303 // | +--------------------------------------+ |
306 // +-----------------------------------------------------------------+
309 // NPAPI doesn't properly define which coordinates each of
310 // - window.clipRect, window.x and window.y in the SetWindow call
311 // - x and y in GraphicsExpose HandleEvent call
312 // are relative to, nor does it define what the pixmap is relative to.
314 // Any sane values for them just don't work with the flash plugin. Firefox
315 // has some interesting behavior. Experiments showed that:
316 // - window.clipRect is always in the same space as window.x and window.y
317 // - in the first SetWindow call, or when scrolling, window.x and window.y are
318 // the coordinates of the plugin relative to the window.
319 // - whenever only a part of the plugin is drawn, Firefox issues a SetWindow
320 // call before each GraphicsExpose event, that sets the drawing origin to
321 // (0, 0) as if the plugin was scrolled to be partially out of the view. The
322 // GraphicsExpose event has coordinates relative to the "window" (assuming
323 // that virtual scroll). The pixmap is also relative to the window. It always
324 // sets the clip rect to the draw rect.
326 // Attempts to deviate from that makes Flash render at the wrong place in the
327 // pixmap, or render the wrong pixels.
330 // X-----------------------------------------------------------------+
332 // | +-------------------+ "real" window |
335 // | +---+-------------------+-------------+ |
336 // | | | | "real" clip | |
337 // | +---+---O===================#==========#==#===============#
338 // | | | H draw | | | H
339 // | | | H = pixmap | | | H
340 // | | | H = "apparent" clip | | | H
341 // | + +---#-------------------+----------+--+ H
343 // | | H-------------------+ | H
346 // | +-------#------------------------------+ H
348 // | H "apparent" window H
349 // +---------------#=================================================#
351 // O = "apparent" origin
352 // "real" means as seen by Chrome
353 // "apparent" means as seen by the plugin.
355 gfx::Rect draw_rect
= gfx::IntersectRects(window_rect_
, damage_rect
);
357 // clip_rect_ is relative to the plugin
358 gfx::Rect clip_rect_window
= clip_rect_
;
359 clip_rect_window
.Offset(window_rect_
.x(), window_rect_
.y());
360 draw_rect
.Intersect(clip_rect_window
);
362 // These offsets represent by how much the view is shifted to accomodate
363 // Flash (the coordinates of X relative to O in the diagram above).
366 if (quirks_
& PLUGIN_QUIRK_WINDOWLESS_OFFSET_WINDOW_TO_DRAW
) {
367 offset_x
= -draw_rect
.x();
368 offset_y
= -draw_rect
.y();
369 window_
.clipRect
.top
= 0;
370 window_
.clipRect
.left
= 0;
371 window_
.clipRect
.bottom
= draw_rect
.height();
372 window_
.clipRect
.right
= draw_rect
.width();
373 window_
.height
= window_rect_
.height();
374 window_
.width
= window_rect_
.width();
375 window_
.x
= window_rect_
.x() - draw_rect
.x();
376 window_
.y
= window_rect_
.y() - draw_rect
.y();
377 window_
.type
= NPWindowTypeDrawable
;
378 DCHECK(window_
.ws_info
);
379 NPError err
= instance()->NPP_SetWindow(&window_
);
380 DCHECK_EQ(err
, NPERR_NO_ERROR
);
383 gfx::Rect pixmap_draw_rect
= draw_rect
;
384 pixmap_draw_rect
.Offset(offset_x
, offset_y
);
386 gfx::Rect
pixmap_rect(0, 0,
387 pixmap_draw_rect
.right(),
388 pixmap_draw_rect
.bottom());
390 // Construct the paint message, targeting the pixmap.
391 NPEvent np_event
= {0};
392 XGraphicsExposeEvent
& event
= np_event
.xgraphicsexpose
;
393 event
.type
= GraphicsExpose
;
394 event
.x
= pixmap_draw_rect
.x();
395 event
.y
= pixmap_draw_rect
.y();
396 event
.width
= pixmap_draw_rect
.width();
397 event
.height
= pixmap_draw_rect
.height();
398 event
.display
= GDK_DISPLAY();
400 if (windowless_shm_pixmap_
!= None
) {
401 Pixmap pixmap
= None
;
403 Display
* display
= event
.display
;
404 gfx::Rect plugin_draw_rect
= draw_rect
;
406 // Make plugin_draw_rect relative to the plugin window.
407 plugin_draw_rect
.Offset(-window_rect_
.x(), -window_rect_
.y());
409 // In case the drawing area does not start with the plugin window origin,
410 // we can not let the plugin directly draw over the shared memory pixmap.
411 if (plugin_draw_rect
.x() != pixmap_draw_rect
.x() ||
412 plugin_draw_rect
.y() != pixmap_draw_rect
.y()) {
413 pixmap
= XCreatePixmap(display
, windowless_shm_pixmap_
,
414 std::max(1, pixmap_rect
.width()),
415 std::max(1, pixmap_rect
.height()),
416 DefaultDepth(display
, DefaultScreen(display
)));
417 xgc
= XCreateGC(display
, windowless_shm_pixmap_
, 0, NULL
);
418 // Copy the current image into the pixmap, so the plugin can draw over it.
419 XCopyArea(display
, windowless_shm_pixmap_
, pixmap
, xgc
,
420 plugin_draw_rect
.x(), plugin_draw_rect
.y(),
421 pixmap_draw_rect
.width(), pixmap_draw_rect
.height(),
422 pixmap_draw_rect
.x(), pixmap_draw_rect
.y());
424 event
.drawable
= pixmap
;
426 event
.drawable
= windowless_shm_pixmap_
;
429 // Tell the plugin to paint into the pixmap.
430 base::StatsRate
plugin_paint("Plugin.Paint");
431 base::StatsScope
<base::StatsRate
> scope(plugin_paint
);
432 instance()->NPP_HandleEvent(&np_event
);
434 if (pixmap
!= None
) {
435 // Copy the rendered image pixmap back into the shm pixmap
436 // and thus the drawing buffer.
437 XCopyArea(display
, pixmap
, windowless_shm_pixmap_
, xgc
,
438 pixmap_draw_rect
.x(), pixmap_draw_rect
.y(),
439 pixmap_draw_rect
.width(), pixmap_draw_rect
.height(),
440 plugin_draw_rect
.x(), plugin_draw_rect
.y());
441 XSync(display
, FALSE
);
443 XFreeGC(display
, xgc
);
444 XFreePixmap(display
, pixmap
);
446 XSync(display
, FALSE
);
449 EnsurePixmapAtLeastSize(pixmap_rect
.width(), pixmap_rect
.height());
451 // Copy the current image into the pixmap, so the plugin can draw over
453 cairo_t
* cairo
= gdk_cairo_create(pixmap_
);
454 BlitContextToContext(cairo
, pixmap_draw_rect
, context
, draw_rect
.origin());
455 cairo_destroy(cairo
);
457 event
.drawable
= GDK_PIXMAP_XID(pixmap_
);
459 // Tell the plugin to paint into the pixmap.
460 base::StatsRate
plugin_paint("Plugin.Paint");
461 base::StatsScope
<base::StatsRate
> scope(plugin_paint
);
462 instance()->NPP_HandleEvent(&np_event
);
465 // Now copy the rendered image pixmap back into the drawing buffer.
466 gdk_cairo_set_source_pixmap(context
, pixmap_
, -offset_x
, -offset_y
);
467 cairo_rectangle(context
, draw_rect
.x(), draw_rect
.y(),
468 draw_rect
.width(), draw_rect
.height());
470 cairo_paint(context
);
472 #ifdef DEBUG_RECTANGLES
473 // Draw some debugging rectangles.
474 // Pixmap rect = blue.
475 DrawDebugRectangle(context
, pixmap_rect
, 0, 0, 1);
476 // Drawing rect = red.
477 DrawDebugRectangle(context
, draw_rect
, 1, 0, 0);
479 cairo_restore(context
);
483 void WebPluginDelegateImpl::WindowlessSetWindow() {
487 if (window_rect_
.IsEmpty()) // wait for geometry to be set.
490 DCHECK(instance()->windowless());
491 // Mozilla docs say that this window param is not used for windowless
492 // plugins; rather, the window is passed during the GraphicsExpose event.
493 DCHECK_EQ(window_
.window
, static_cast<void*>(NULL
));
495 window_
.clipRect
.top
= clip_rect_
.y() + window_rect_
.y();
496 window_
.clipRect
.left
= clip_rect_
.x() + window_rect_
.x();
497 window_
.clipRect
.bottom
=
498 clip_rect_
.y() + clip_rect_
.height() + window_rect_
.y();
499 window_
.clipRect
.right
=
500 clip_rect_
.x() + clip_rect_
.width() + window_rect_
.x();
501 window_
.height
= window_rect_
.height();
502 window_
.width
= window_rect_
.width();
503 window_
.x
= window_rect_
.x();
504 window_
.y
= window_rect_
.y();
505 window_
.type
= NPWindowTypeDrawable
;
507 if (!window_
.ws_info
)
508 window_
.ws_info
= new NPSetWindowCallbackStruct
;
509 NPSetWindowCallbackStruct
* extra
=
510 static_cast<NPSetWindowCallbackStruct
*>(window_
.ws_info
);
511 extra
->display
= GDK_DISPLAY();
512 int screen
= DefaultScreen(GDK_DISPLAY());
513 extra
->visual
= DefaultVisual(GDK_DISPLAY(), screen
);
514 extra
->depth
= DefaultDepth(GDK_DISPLAY(), screen
);
515 extra
->colormap
= DefaultColormap(GDK_DISPLAY(), screen
);
517 NPError err
= instance()->NPP_SetWindow(&window_
);
518 DCHECK(err
== NPERR_NO_ERROR
);
519 if (quirks_
& PLUGIN_QUIRK_WINDOWLESS_INVALIDATE_AFTER_SET_WINDOW
) {
520 // After a NPP_SetWindow, Flash cancels its timer that generates the
521 // invalidates until it gets a paint event, but doesn't explicitly call
522 // NPP_InvalidateRect.
523 plugin_
->InvalidateRect(clip_rect_
);
527 bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused
) {
528 DCHECK(instance()->windowless());
530 NPEvent np_event
= {0};
531 XFocusChangeEvent
& event
= np_event
.xfocus
;
532 event
.type
= focused
? FocusIn
: FocusOut
;
533 event
.display
= GDK_DISPLAY();
534 // Same values as Firefox. .serial and .window stay 0.
536 event
.detail
= NotifyDetailNone
;
537 instance()->NPP_HandleEvent(&np_event
);
541 // Converts a WebInputEvent::Modifiers bitfield into a
542 // corresponding X modifier state.
543 static int GetXModifierState(int modifiers
) {
545 if (modifiers
& WebInputEvent::ControlKey
)
546 x_state
|= ControlMask
;
547 if (modifiers
& WebInputEvent::ShiftKey
)
548 x_state
|= ShiftMask
;
549 if (modifiers
& WebInputEvent::AltKey
)
551 if (modifiers
& WebInputEvent::MetaKey
)
553 if (modifiers
& WebInputEvent::LeftButtonDown
)
554 x_state
|= Button1Mask
;
555 if (modifiers
& WebInputEvent::MiddleButtonDown
)
556 x_state
|= Button2Mask
;
557 if (modifiers
& WebInputEvent::RightButtonDown
)
558 x_state
|= Button3Mask
;
559 // TODO(piman@google.com): There are other modifiers, e.g. Num Lock, that
560 // should be set (and Firefox does), but we didn't keep the information in
565 static bool NPEventFromWebMouseEvent(const WebMouseEvent
& event
,
568 np_event
->xany
.display
= GDK_DISPLAY();
569 // NOTE: Firefox keeps xany.serial and xany.window as 0.
571 int modifier_state
= GetXModifierState(event
.modifiers
);
573 Window root
= GDK_ROOT_WINDOW();
574 switch (event
.type
) {
575 case WebInputEvent::MouseMove
: {
576 np_event
->type
= MotionNotify
;
577 XMotionEvent
& motion_event
= np_event
->xmotion
;
578 motion_event
.root
= root
;
579 motion_event
.time
= timestamp
;
580 motion_event
.x
= event
.x
;
581 motion_event
.y
= event
.y
;
582 motion_event
.x_root
= event
.globalX
;
583 motion_event
.y_root
= event
.globalY
;
584 motion_event
.state
= modifier_state
;
585 motion_event
.is_hint
= NotifyNormal
;
586 motion_event
.same_screen
= True
;
589 case WebInputEvent::MouseLeave
:
590 case WebInputEvent::MouseEnter
: {
591 if (event
.type
== WebInputEvent::MouseEnter
) {
592 np_event
->type
= EnterNotify
;
594 np_event
->type
= LeaveNotify
;
596 XCrossingEvent
& crossing_event
= np_event
->xcrossing
;
597 crossing_event
.root
= root
;
598 crossing_event
.time
= timestamp
;
599 crossing_event
.x
= event
.x
;
600 crossing_event
.y
= event
.y
;
601 crossing_event
.x_root
= event
.globalX
;
602 crossing_event
.y_root
= event
.globalY
;
603 crossing_event
.mode
= -1; // This is what Firefox sets it to.
604 crossing_event
.detail
= NotifyDetailNone
;
605 crossing_event
.same_screen
= True
;
606 // TODO(piman@google.com): set this to the correct value. Firefox does. I
607 // don't know where to get the information though, we get focus
608 // notifications, but no unfocus.
609 crossing_event
.focus
= 0;
610 crossing_event
.state
= modifier_state
;
613 case WebInputEvent::MouseUp
:
614 case WebInputEvent::MouseDown
: {
615 if (event
.type
== WebInputEvent::MouseDown
) {
616 np_event
->type
= ButtonPress
;
618 np_event
->type
= ButtonRelease
;
620 XButtonEvent
& button_event
= np_event
->xbutton
;
621 button_event
.root
= root
;
622 button_event
.time
= timestamp
;
623 button_event
.x
= event
.x
;
624 button_event
.y
= event
.y
;
625 button_event
.x_root
= event
.globalX
;
626 button_event
.y_root
= event
.globalY
;
627 button_event
.state
= modifier_state
;
628 switch (event
.button
) {
629 case WebMouseEvent::ButtonLeft
:
630 button_event
.button
= Button1
;
632 case WebMouseEvent::ButtonMiddle
:
633 button_event
.button
= Button2
;
635 case WebMouseEvent::ButtonRight
:
636 button_event
.button
= Button3
;
641 button_event
.same_screen
= True
;
651 static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent
& event
,
654 np_event
->xany
.display
= GDK_DISPLAY();
655 // NOTE: Firefox keeps xany.serial and xany.window as 0.
657 switch (event
.type
) {
658 case WebKeyboardEvent::KeyDown
:
659 np_event
->type
= KeyPress
;
661 case WebKeyboardEvent::KeyUp
:
662 np_event
->type
= KeyRelease
;
668 XKeyEvent
& key_event
= np_event
->xkey
;
669 key_event
.send_event
= False
;
670 key_event
.display
= GDK_DISPLAY();
671 // NOTE: Firefox keeps xany.serial and xany.window as 0.
672 // TODO(piman@google.com): is this right for multiple screens ?
673 key_event
.root
= DefaultRootWindow(key_event
.display
);
674 key_event
.time
= timestamp
;
675 // NOTE: We don't have the correct information for x/y/x_root/y_root. Firefox
676 // doesn't have it either, so we pass the same values.
679 key_event
.x_root
= -1;
680 key_event
.y_root
= -1;
681 key_event
.state
= GetXModifierState(event
.modifiers
);
682 key_event
.keycode
= event
.nativeKeyCode
;
683 key_event
.same_screen
= True
;
687 static bool NPEventFromWebInputEvent(const WebInputEvent
& event
,
690 switch (event
.type
) {
691 case WebInputEvent::MouseMove
:
692 case WebInputEvent::MouseLeave
:
693 case WebInputEvent::MouseEnter
:
694 case WebInputEvent::MouseDown
:
695 case WebInputEvent::MouseUp
:
696 if (event
.size
< sizeof(WebMouseEvent
)) {
700 return NPEventFromWebMouseEvent(
701 *static_cast<const WebMouseEvent
*>(&event
), timestamp
, np_event
);
702 case WebInputEvent::KeyDown
:
703 case WebInputEvent::KeyUp
:
704 if (event
.size
< sizeof(WebKeyboardEvent
)) {
708 return NPEventFromWebKeyboardEvent(
709 *static_cast<const WebKeyboardEvent
*>(&event
), timestamp
, np_event
);
715 bool WebPluginDelegateImpl::PlatformHandleInputEvent(
716 const WebInputEvent
& event
, WebCursor::CursorInfo
* cursor_info
) {
718 if (first_event_time_
< 0.0)
719 first_event_time_
= event
.timeStampSeconds
;
720 Time timestamp
= static_cast<Time
>(
721 (event
.timeStampSeconds
- first_event_time_
) * 1.0e3
);
722 NPEvent np_event
= {0};
723 if (!NPEventFromWebInputEvent(event
, timestamp
, &np_event
)) {
726 // See comment about PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK in constructor.
728 (quirks_
& PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK
) &&
729 (np_event
.type
== ButtonPress
|| np_event
.type
== ButtonRelease
) &&
730 (np_event
.xbutton
.button
== Button3
)) {
734 bool ret
= instance()->NPP_HandleEvent(&np_event
) != 0;
736 // Flash always returns false, even when the event is handled.
740 if (event
->event
== WM_MOUSEMOVE
) {
741 // Snag a reference to the current cursor ASAP in case the plugin modified
742 // it. There is a nasty race condition here with the multiprocess browser
743 // as someone might be setting the cursor in the main process as well.
744 *cursor
= current_windowless_cursor_
;
751 } // namespace content