Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(466)

Side by Side Diff: webkit/plugins/npapi/webplugin_delegate_impl_gtk.cc

Issue 19761007: Move NPAPI implementation out of webkit/plugins/npapi and into content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: fix mac Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "webkit/plugins/npapi/webplugin_delegate_impl.h"
6
7 #include <gtk/gtk.h>
8 #include <gdk/gdkx.h>
9
10 #include <string>
11 #include <vector>
12
13 #include "base/metrics/stats_counters.h"
14 #include "skia/ext/platform_canvas.h"
15 #include "third_party/WebKit/public/web/WebInputEvent.h"
16 #include "ui/base/gtk/gtk_compat.h"
17 #include "ui/gfx/blit.h"
18 #include "webkit/common/cursors/webcursor.h"
19 #include "webkit/plugins/npapi/plugin_instance.h"
20 #include "webkit/plugins/npapi/webplugin.h"
21 #include "webkit/plugins/plugin_constants.h"
22
23 #include "third_party/npapi/bindings/npapi_x11.h"
24
25 using WebKit::WebKeyboardEvent;
26 using WebKit::WebInputEvent;
27 using WebKit::WebMouseEvent;
28
29 namespace webkit {
30 namespace npapi {
31
32 WebPluginDelegateImpl::WebPluginDelegateImpl(
33 PluginInstance* instance)
34 : windowed_handle_(0),
35 windowed_did_set_window_(false),
36 windowless_(false),
37 plugin_(NULL),
38 instance_(instance),
39 windowless_shm_pixmap_(None),
40 pixmap_(NULL),
41 first_event_time_(-1.0),
42 plug_(NULL),
43 socket_(NULL),
44 quirks_(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;
61 }
62
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
65 // NPP_SetWindow.
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;
69 }
70
71 WebPluginDelegateImpl::~WebPluginDelegateImpl() {
72 DestroyInstance();
73
74 if (!windowless_)
75 WindowedDestroyWindow();
76
77 if (window_.ws_info) {
78 // We only ever use ws_info as an NPSetWindowCallbackStruct.
79 delete static_cast<NPSetWindowCallbackStruct*>(window_.ws_info);
80 }
81
82 if (pixmap_) {
83 g_object_unref(pixmap_);
84 pixmap_ = NULL;
85 }
86 }
87
88 bool WebPluginDelegateImpl::PlatformInitialize() {
89 gfx::PluginWindowHandle handle =
90 windowless_ ? 0 : gtk_plug_get_id(GTK_PLUG(plug_));
91 plugin_->SetWindow(handle);
92 return true;
93 }
94
95 void WebPluginDelegateImpl::PlatformDestroyInstance() {
96 // Nothing to do here.
97 }
98
99 void WebPluginDelegateImpl::Paint(WebKit::WebCanvas* canvas,
100 const gfx::Rect& rect) {
101 if (!windowless_ || !skia::SupportsPlatformPaint(canvas))
102 return;
103 skia::ScopedPlatformPaint scoped_platform_paint(canvas);
104 cairo_t* context = scoped_platform_paint.GetPlatformSurface();
105 WindowlessPaint(context, rect);
106 }
107
108 bool WebPluginDelegateImpl::WindowedCreatePlugin() {
109 DCHECK(!windowed_handle_);
110 DCHECK(!plug_);
111
112 // NPP_GetValue() might write 4 bytes of data to this variable. Don't use a
113 // single byte bool, use an int instead and make sure it is initialized.
114 int xembed = 0;
115 NPError err = instance_->NPP_GetValue(NPPVpluginNeedsXEmbed, &xembed);
116 if (err != NPERR_NO_ERROR || !xembed) {
117 NOTIMPLEMENTED() << " windowed plugin but without xembed. "
118 "See http://code.google.com/p/chromium/issues/detail?id=38229";
119 return false;
120 }
121
122 // Passing 0 as the socket XID creates a plug without plugging it in a socket
123 // yet, so that it can be latter added with gtk_socket_add_id().
124 plug_ = gtk_plug_new(0);
125 gtk_widget_show(plug_);
126 socket_ = gtk_socket_new();
127 gtk_widget_show(socket_);
128 gtk_container_add(GTK_CONTAINER(plug_), socket_);
129 gtk_widget_show_all(plug_);
130
131 // Prevent the plug from being destroyed if the browser kills the container
132 // window.
133 g_signal_connect(plug_, "delete-event", G_CALLBACK(gtk_true), NULL);
134 // Prevent the socket from being destroyed when the plugin removes itself.
135 g_signal_connect(socket_, "plug_removed", G_CALLBACK(gtk_true), NULL);
136
137 windowed_handle_ = gtk_socket_get_id(GTK_SOCKET(socket_));
138
139 window_.window = reinterpret_cast<void*>(windowed_handle_);
140
141 if (!window_.ws_info)
142 window_.ws_info = new NPSetWindowCallbackStruct;
143 NPSetWindowCallbackStruct* extra =
144 static_cast<NPSetWindowCallbackStruct*>(window_.ws_info);
145 extra->type = NP_SETWINDOW;
146 extra->display = GDK_DISPLAY();
147 int screen = DefaultScreen(GDK_DISPLAY());
148 extra->visual = DefaultVisual(GDK_DISPLAY(), screen);
149 extra->depth = DefaultDepth(GDK_DISPLAY(), screen);
150 extra->colormap = DefaultColormap(GDK_DISPLAY(), screen);
151
152 return true;
153 }
154
155 void WebPluginDelegateImpl::WindowedDestroyWindow() {
156 if (plug_) {
157 plugin_->WillDestroyWindow(gtk_plug_get_id(GTK_PLUG(plug_)));
158
159 gtk_widget_destroy(plug_);
160 plug_ = NULL;
161 socket_ = NULL;
162 windowed_handle_ = 0;
163 }
164 }
165
166 bool WebPluginDelegateImpl::WindowedReposition(
167 const gfx::Rect& window_rect,
168 const gfx::Rect& clip_rect) {
169 if (window_rect == window_rect_ && clip_rect == clip_rect_)
170 return false;
171
172 window_rect_ = window_rect;
173 clip_rect_ = clip_rect;
174
175 return true;
176 }
177
178 void WebPluginDelegateImpl::WindowedSetWindow() {
179 if (!instance_.get())
180 return;
181
182 if (!windowed_handle_) {
183 NOTREACHED();
184 return;
185 }
186
187 // See https://bugzilla.mozilla.org/show_bug.cgi?id=108347
188 // If we call NPP_SetWindow with a <= 0 width or height, problems arise in
189 // Flash (and possibly other plugins).
190 // TODO(piman): the Mozilla code suggests that for the Java plugin, we should
191 // still call NPP_SetWindow in that case. We need to verify that.
192 if (window_rect_.width() <= 0 || window_rect_.height() <= 0) {
193 return;
194 }
195
196 instance()->set_window_handle(windowed_handle_);
197
198 DCHECK(!instance()->windowless());
199
200 window_.clipRect.top = clip_rect_.y();
201 window_.clipRect.left = clip_rect_.x();
202 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
203 window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
204 window_.height = window_rect_.height();
205 window_.width = window_rect_.width();
206 window_.x = window_rect_.x();
207 window_.y = window_rect_.y();
208 window_.type = NPWindowTypeWindow;
209
210 // Reset this flag before entering the instance in case of side-effects.
211 windowed_did_set_window_ = true;
212
213 NPError err = instance()->NPP_SetWindow(&window_);
214 DCHECK(err == NPERR_NO_ERROR);
215 }
216
217 void WebPluginDelegateImpl::WindowlessUpdateGeometry(
218 const gfx::Rect& window_rect,
219 const gfx::Rect& clip_rect) {
220 // Only resend to the instance if the geometry has changed.
221 if (window_rect == window_rect_ && clip_rect == clip_rect_)
222 return;
223
224 clip_rect_ = clip_rect;
225 window_rect_ = window_rect;
226 WindowlessSetWindow();
227 }
228
229 void WebPluginDelegateImpl::EnsurePixmapAtLeastSize(int width, int height) {
230 if (pixmap_) {
231 gint cur_width, cur_height;
232 gdk_pixmap_get_size(pixmap_, &cur_width, &cur_height);
233 if (cur_width >= width && cur_height >= height)
234 return; // We are already the appropriate size.
235
236 // Otherwise, we need to recreate ourselves.
237 g_object_unref(pixmap_);
238 pixmap_ = NULL;
239 }
240
241 // |sys_visual| is owned by gdk; we shouldn't free it.
242 GdkVisual* sys_visual = gdk_visual_get_system();
243 pixmap_ = gdk_pixmap_new(NULL, // use width/height/depth params
244 std::max(1, width), std::max(1, height),
245 sys_visual->depth);
246 // TODO(erg): Replace this with GdkVisual when we move to GTK3.
247 GdkColormap* colormap = gdk_colormap_new(gdk_visual_get_system(),
248 FALSE);
249 gdk_drawable_set_colormap(pixmap_, colormap);
250 // The GdkDrawable now owns the GdkColormap.
251 g_object_unref(colormap);
252 }
253
254 #ifdef DEBUG_RECTANGLES
255 namespace {
256
257 // Draw a rectangle on a Cairo context.
258 // Useful for debugging various rectangles involved in drawing plugins.
259 void DrawDebugRectangle(cairo_t* cairo,
260 const gfx::Rect& rect,
261 float r, float g, float b) {
262 cairo_set_source_rgba(cairo, r, g, b, 0.5);
263 cairo_rectangle(cairo, rect.x(), rect.y(),
264 rect.width(), rect.height());
265 cairo_stroke(cairo);
266 }
267
268 } // namespace
269 #endif
270
271 void WebPluginDelegateImpl::WindowlessPaint(cairo_t* context,
272 const gfx::Rect& damage_rect) {
273 // Compare to:
274 // http://mxr.mozilla.org/firefox/source/layout/generic/nsObjectFrame.cpp:
275 // nsPluginInstanceOwner::Renderer::NativeDraw().
276
277 DCHECK(context);
278
279 // TODO(darin): we should avoid calling NPP_SetWindow here since it may
280 // cause page layout to be invalidated.
281
282 // The actual dirty region is just the intersection of the plugin window and
283 // the clip window with the damage region. However, the plugin wants to draw
284 // relative to the containing window's origin, so our pixmap must be from the
285 // window's origin down to the bottom-right edge of the dirty region.
286 //
287 // Typical case:
288 // X-----------------------------------+-----------------------------+
289 // | | |
290 // | pixmap +-------------------+ |
291 // | | damage | window |
292 // | | | |
293 // | +---+-------------------+-------------+ |
294 // | | | | clip | |
295 // | +---+---+-------------------+----------+ | |
296 // | | | | | | | |
297 // | | | | draw | | | |
298 // | | | | | | | |
299 // +-------+---+---+-------------------+----------+--+ |
300 // | | | | | |
301 // | | +-------------------+ | |
302 // | | | |
303 // | | plugin | |
304 // | +--------------------------------------+ |
305 // | |
306 // | |
307 // +-----------------------------------------------------------------+
308 // X = origin
309 //
310 // NPAPI doesn't properly define which coordinates each of
311 // - window.clipRect, window.x and window.y in the SetWindow call
312 // - x and y in GraphicsExpose HandleEvent call
313 // are relative to, nor does it define what the pixmap is relative to.
314 //
315 // Any sane values for them just don't work with the flash plugin. Firefox
316 // has some interesting behavior. Experiments showed that:
317 // - window.clipRect is always in the same space as window.x and window.y
318 // - in the first SetWindow call, or when scrolling, window.x and window.y are
319 // the coordinates of the plugin relative to the window.
320 // - whenever only a part of the plugin is drawn, Firefox issues a SetWindow
321 // call before each GraphicsExpose event, that sets the drawing origin to
322 // (0, 0) as if the plugin was scrolled to be partially out of the view. The
323 // GraphicsExpose event has coordinates relative to the "window" (assuming
324 // that virtual scroll). The pixmap is also relative to the window. It always
325 // sets the clip rect to the draw rect.
326 //
327 // Attempts to deviate from that makes Flash render at the wrong place in the
328 // pixmap, or render the wrong pixels.
329 //
330 // Flash plugin:
331 // X-----------------------------------------------------------------+
332 // | |
333 // | +-------------------+ "real" window |
334 // | | damage | |
335 // | | | |
336 // | +---+-------------------+-------------+ |
337 // | | | | "real" clip | |
338 // | +---+---O===================#==========#==#===============#
339 // | | | H draw | | | H
340 // | | | H = pixmap | | | H
341 // | | | H = "apparent" clip | | | H
342 // | + +---#-------------------+----------+--+ H
343 // | | H | | H
344 // | | H-------------------+ | H
345 // | | H | H
346 // | | H plugin | H
347 // | +-------#------------------------------+ H
348 // | H H
349 // | H "apparent" window H
350 // +---------------#=================================================#
351 // X = "real" origin
352 // O = "apparent" origin
353 // "real" means as seen by Chrome
354 // "apparent" means as seen by the plugin.
355
356 gfx::Rect draw_rect = gfx::IntersectRects(window_rect_, damage_rect);
357
358 // clip_rect_ is relative to the plugin
359 gfx::Rect clip_rect_window = clip_rect_;
360 clip_rect_window.Offset(window_rect_.x(), window_rect_.y());
361 draw_rect.Intersect(clip_rect_window);
362
363 // These offsets represent by how much the view is shifted to accomodate
364 // Flash (the coordinates of X relative to O in the diagram above).
365 int offset_x = 0;
366 int offset_y = 0;
367 if (quirks_ & PLUGIN_QUIRK_WINDOWLESS_OFFSET_WINDOW_TO_DRAW) {
368 offset_x = -draw_rect.x();
369 offset_y = -draw_rect.y();
370 window_.clipRect.top = 0;
371 window_.clipRect.left = 0;
372 window_.clipRect.bottom = draw_rect.height();
373 window_.clipRect.right = draw_rect.width();
374 window_.height = window_rect_.height();
375 window_.width = window_rect_.width();
376 window_.x = window_rect_.x() - draw_rect.x();
377 window_.y = window_rect_.y() - draw_rect.y();
378 window_.type = NPWindowTypeDrawable;
379 DCHECK(window_.ws_info);
380 NPError err = instance()->NPP_SetWindow(&window_);
381 DCHECK_EQ(err, NPERR_NO_ERROR);
382 }
383
384 gfx::Rect pixmap_draw_rect = draw_rect;
385 pixmap_draw_rect.Offset(offset_x, offset_y);
386
387 gfx::Rect pixmap_rect(0, 0,
388 pixmap_draw_rect.right(),
389 pixmap_draw_rect.bottom());
390
391 // Construct the paint message, targeting the pixmap.
392 NPEvent np_event = {0};
393 XGraphicsExposeEvent& event = np_event.xgraphicsexpose;
394 event.type = GraphicsExpose;
395 event.x = pixmap_draw_rect.x();
396 event.y = pixmap_draw_rect.y();
397 event.width = pixmap_draw_rect.width();
398 event.height = pixmap_draw_rect.height();
399 event.display = GDK_DISPLAY();
400
401 if (windowless_shm_pixmap_ != None) {
402 Pixmap pixmap = None;
403 GC xgc = NULL;
404 Display* display = event.display;
405 gfx::Rect plugin_draw_rect = draw_rect;
406
407 // Make plugin_draw_rect relative to the plugin window.
408 plugin_draw_rect.Offset(-window_rect_.x(), -window_rect_.y());
409
410 // In case the drawing area does not start with the plugin window origin,
411 // we can not let the plugin directly draw over the shared memory pixmap.
412 if (plugin_draw_rect.x() != pixmap_draw_rect.x() ||
413 plugin_draw_rect.y() != pixmap_draw_rect.y()) {
414 pixmap = XCreatePixmap(display, windowless_shm_pixmap_,
415 std::max(1, pixmap_rect.width()),
416 std::max(1, pixmap_rect.height()),
417 DefaultDepth(display, DefaultScreen(display)));
418 xgc = XCreateGC(display, windowless_shm_pixmap_, 0, NULL);
419 // Copy the current image into the pixmap, so the plugin can draw over it.
420 XCopyArea(display, windowless_shm_pixmap_, pixmap, xgc,
421 plugin_draw_rect.x(), plugin_draw_rect.y(),
422 pixmap_draw_rect.width(), pixmap_draw_rect.height(),
423 pixmap_draw_rect.x(), pixmap_draw_rect.y());
424
425 event.drawable = pixmap;
426 } else {
427 event.drawable = windowless_shm_pixmap_;
428 }
429
430 // Tell the plugin to paint into the pixmap.
431 base::StatsRate plugin_paint("Plugin.Paint");
432 base::StatsScope<base::StatsRate> scope(plugin_paint);
433 instance()->NPP_HandleEvent(&np_event);
434
435 if (pixmap != None) {
436 // Copy the rendered image pixmap back into the shm pixmap
437 // and thus the drawing buffer.
438 XCopyArea(display, pixmap, windowless_shm_pixmap_, xgc,
439 pixmap_draw_rect.x(), pixmap_draw_rect.y(),
440 pixmap_draw_rect.width(), pixmap_draw_rect.height(),
441 plugin_draw_rect.x(), plugin_draw_rect.y());
442 XSync(display, FALSE);
443 if (xgc)
444 XFreeGC(display, xgc);
445 XFreePixmap(display, pixmap);
446 } else {
447 XSync(display, FALSE);
448 }
449 } else {
450 EnsurePixmapAtLeastSize(pixmap_rect.width(), pixmap_rect.height());
451
452 // Copy the current image into the pixmap, so the plugin can draw over
453 // this background.
454 cairo_t* cairo = gdk_cairo_create(pixmap_);
455 BlitContextToContext(cairo, pixmap_draw_rect, context, draw_rect.origin());
456 cairo_destroy(cairo);
457
458 event.drawable = GDK_PIXMAP_XID(pixmap_);
459
460 // Tell the plugin to paint into the pixmap.
461 base::StatsRate plugin_paint("Plugin.Paint");
462 base::StatsScope<base::StatsRate> scope(plugin_paint);
463 instance()->NPP_HandleEvent(&np_event);
464
465 cairo_save(context);
466 // Now copy the rendered image pixmap back into the drawing buffer.
467 gdk_cairo_set_source_pixmap(context, pixmap_, -offset_x, -offset_y);
468 cairo_rectangle(context, draw_rect.x(), draw_rect.y(),
469 draw_rect.width(), draw_rect.height());
470 cairo_clip(context);
471 cairo_paint(context);
472
473 #ifdef DEBUG_RECTANGLES
474 // Draw some debugging rectangles.
475 // Pixmap rect = blue.
476 DrawDebugRectangle(context, pixmap_rect, 0, 0, 1);
477 // Drawing rect = red.
478 DrawDebugRectangle(context, draw_rect, 1, 0, 0);
479 #endif
480 cairo_restore(context);
481 }
482 }
483
484 void WebPluginDelegateImpl::WindowlessSetWindow() {
485 if (!instance())
486 return;
487
488 if (window_rect_.IsEmpty()) // wait for geometry to be set.
489 return;
490
491 DCHECK(instance()->windowless());
492 // Mozilla docs say that this window param is not used for windowless
493 // plugins; rather, the window is passed during the GraphicsExpose event.
494 DCHECK_EQ(window_.window, static_cast<void*>(NULL));
495
496 window_.clipRect.top = clip_rect_.y() + window_rect_.y();
497 window_.clipRect.left = clip_rect_.x() + window_rect_.x();
498 window_.clipRect.bottom =
499 clip_rect_.y() + clip_rect_.height() + window_rect_.y();
500 window_.clipRect.right =
501 clip_rect_.x() + clip_rect_.width() + window_rect_.x();
502 window_.height = window_rect_.height();
503 window_.width = window_rect_.width();
504 window_.x = window_rect_.x();
505 window_.y = window_rect_.y();
506 window_.type = NPWindowTypeDrawable;
507
508 if (!window_.ws_info)
509 window_.ws_info = new NPSetWindowCallbackStruct;
510 NPSetWindowCallbackStruct* extra =
511 static_cast<NPSetWindowCallbackStruct*>(window_.ws_info);
512 extra->display = GDK_DISPLAY();
513 int screen = DefaultScreen(GDK_DISPLAY());
514 extra->visual = DefaultVisual(GDK_DISPLAY(), screen);
515 extra->depth = DefaultDepth(GDK_DISPLAY(), screen);
516 extra->colormap = DefaultColormap(GDK_DISPLAY(), screen);
517
518 NPError err = instance()->NPP_SetWindow(&window_);
519 DCHECK(err == NPERR_NO_ERROR);
520 if (quirks_ & PLUGIN_QUIRK_WINDOWLESS_INVALIDATE_AFTER_SET_WINDOW) {
521 // After a NPP_SetWindow, Flash cancels its timer that generates the
522 // invalidates until it gets a paint event, but doesn't explicitly call
523 // NPP_InvalidateRect.
524 plugin_->InvalidateRect(clip_rect_);
525 }
526 }
527
528 bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) {
529 DCHECK(instance()->windowless());
530
531 NPEvent np_event = {0};
532 XFocusChangeEvent& event = np_event.xfocus;
533 event.type = focused ? FocusIn : FocusOut;
534 event.display = GDK_DISPLAY();
535 // Same values as Firefox. .serial and .window stay 0.
536 event.mode = -1;
537 event.detail = NotifyDetailNone;
538 instance()->NPP_HandleEvent(&np_event);
539 return true;
540 }
541
542 // Converts a WebInputEvent::Modifiers bitfield into a
543 // corresponding X modifier state.
544 static int GetXModifierState(int modifiers) {
545 int x_state = 0;
546 if (modifiers & WebInputEvent::ControlKey)
547 x_state |= ControlMask;
548 if (modifiers & WebInputEvent::ShiftKey)
549 x_state |= ShiftMask;
550 if (modifiers & WebInputEvent::AltKey)
551 x_state |= Mod1Mask;
552 if (modifiers & WebInputEvent::MetaKey)
553 x_state |= Mod2Mask;
554 if (modifiers & WebInputEvent::LeftButtonDown)
555 x_state |= Button1Mask;
556 if (modifiers & WebInputEvent::MiddleButtonDown)
557 x_state |= Button2Mask;
558 if (modifiers & WebInputEvent::RightButtonDown)
559 x_state |= Button3Mask;
560 // TODO(piman@google.com): There are other modifiers, e.g. Num Lock, that
561 // should be set (and Firefox does), but we didn't keep the information in
562 // the WebKit event.
563 return x_state;
564 }
565
566 static bool NPEventFromWebMouseEvent(const WebMouseEvent& event,
567 Time timestamp,
568 NPEvent* np_event) {
569 np_event->xany.display = GDK_DISPLAY();
570 // NOTE: Firefox keeps xany.serial and xany.window as 0.
571
572 int modifier_state = GetXModifierState(event.modifiers);
573
574 Window root = GDK_ROOT_WINDOW();
575 switch (event.type) {
576 case WebInputEvent::MouseMove: {
577 np_event->type = MotionNotify;
578 XMotionEvent& motion_event = np_event->xmotion;
579 motion_event.root = root;
580 motion_event.time = timestamp;
581 motion_event.x = event.x;
582 motion_event.y = event.y;
583 motion_event.x_root = event.globalX;
584 motion_event.y_root = event.globalY;
585 motion_event.state = modifier_state;
586 motion_event.is_hint = NotifyNormal;
587 motion_event.same_screen = True;
588 break;
589 }
590 case WebInputEvent::MouseLeave:
591 case WebInputEvent::MouseEnter: {
592 if (event.type == WebInputEvent::MouseEnter) {
593 np_event->type = EnterNotify;
594 } else {
595 np_event->type = LeaveNotify;
596 }
597 XCrossingEvent& crossing_event = np_event->xcrossing;
598 crossing_event.root = root;
599 crossing_event.time = timestamp;
600 crossing_event.x = event.x;
601 crossing_event.y = event.y;
602 crossing_event.x_root = event.globalX;
603 crossing_event.y_root = event.globalY;
604 crossing_event.mode = -1; // This is what Firefox sets it to.
605 crossing_event.detail = NotifyDetailNone;
606 crossing_event.same_screen = True;
607 // TODO(piman@google.com): set this to the correct value. Firefox does. I
608 // don't know where to get the information though, we get focus
609 // notifications, but no unfocus.
610 crossing_event.focus = 0;
611 crossing_event.state = modifier_state;
612 break;
613 }
614 case WebInputEvent::MouseUp:
615 case WebInputEvent::MouseDown: {
616 if (event.type == WebInputEvent::MouseDown) {
617 np_event->type = ButtonPress;
618 } else {
619 np_event->type = ButtonRelease;
620 }
621 XButtonEvent& button_event = np_event->xbutton;
622 button_event.root = root;
623 button_event.time = timestamp;
624 button_event.x = event.x;
625 button_event.y = event.y;
626 button_event.x_root = event.globalX;
627 button_event.y_root = event.globalY;
628 button_event.state = modifier_state;
629 switch (event.button) {
630 case WebMouseEvent::ButtonLeft:
631 button_event.button = Button1;
632 break;
633 case WebMouseEvent::ButtonMiddle:
634 button_event.button = Button2;
635 break;
636 case WebMouseEvent::ButtonRight:
637 button_event.button = Button3;
638 break;
639 default:
640 NOTREACHED();
641 }
642 button_event.same_screen = True;
643 break;
644 }
645 default:
646 NOTREACHED();
647 return false;
648 }
649 return true;
650 }
651
652 static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event,
653 Time timestamp,
654 NPEvent* np_event) {
655 np_event->xany.display = GDK_DISPLAY();
656 // NOTE: Firefox keeps xany.serial and xany.window as 0.
657
658 switch (event.type) {
659 case WebKeyboardEvent::KeyDown:
660 np_event->type = KeyPress;
661 break;
662 case WebKeyboardEvent::KeyUp:
663 np_event->type = KeyRelease;
664 break;
665 default:
666 NOTREACHED();
667 return false;
668 }
669 XKeyEvent& key_event = np_event->xkey;
670 key_event.send_event = False;
671 key_event.display = GDK_DISPLAY();
672 // NOTE: Firefox keeps xany.serial and xany.window as 0.
673 // TODO(piman@google.com): is this right for multiple screens ?
674 key_event.root = DefaultRootWindow(key_event.display);
675 key_event.time = timestamp;
676 // NOTE: We don't have the correct information for x/y/x_root/y_root. Firefox
677 // doesn't have it either, so we pass the same values.
678 key_event.x = 0;
679 key_event.y = 0;
680 key_event.x_root = -1;
681 key_event.y_root = -1;
682 key_event.state = GetXModifierState(event.modifiers);
683 key_event.keycode = event.nativeKeyCode;
684 key_event.same_screen = True;
685 return true;
686 }
687
688 static bool NPEventFromWebInputEvent(const WebInputEvent& event,
689 Time timestamp,
690 NPEvent* np_event) {
691 switch (event.type) {
692 case WebInputEvent::MouseMove:
693 case WebInputEvent::MouseLeave:
694 case WebInputEvent::MouseEnter:
695 case WebInputEvent::MouseDown:
696 case WebInputEvent::MouseUp:
697 if (event.size < sizeof(WebMouseEvent)) {
698 NOTREACHED();
699 return false;
700 }
701 return NPEventFromWebMouseEvent(
702 *static_cast<const WebMouseEvent*>(&event), timestamp, np_event);
703 case WebInputEvent::KeyDown:
704 case WebInputEvent::KeyUp:
705 if (event.size < sizeof(WebKeyboardEvent)) {
706 NOTREACHED();
707 return false;
708 }
709 return NPEventFromWebKeyboardEvent(
710 *static_cast<const WebKeyboardEvent*>(&event), timestamp, np_event);
711 default:
712 return false;
713 }
714 }
715
716 bool WebPluginDelegateImpl::PlatformHandleInputEvent(
717 const WebInputEvent& event, WebCursor::CursorInfo* cursor_info) {
718
719 if (first_event_time_ < 0.0)
720 first_event_time_ = event.timeStampSeconds;
721 Time timestamp = static_cast<Time>(
722 (event.timeStampSeconds - first_event_time_) * 1.0e3);
723 NPEvent np_event = {0};
724 if (!NPEventFromWebInputEvent(event, timestamp, &np_event)) {
725 return false;
726 }
727 // See comment about PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK in constructor.
728 if (windowless_ &&
729 (quirks_ & PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK) &&
730 (np_event.type == ButtonPress || np_event.type == ButtonRelease) &&
731 (np_event.xbutton.button == Button3)) {
732 return false;
733 }
734
735 bool ret = instance()->NPP_HandleEvent(&np_event) != 0;
736
737 // Flash always returns false, even when the event is handled.
738 ret = true;
739
740 #if 0
741 if (event->event == WM_MOUSEMOVE) {
742 // Snag a reference to the current cursor ASAP in case the plugin modified
743 // it. There is a nasty race condition here with the multiprocess browser
744 // as someone might be setting the cursor in the main process as well.
745 *cursor = current_windowless_cursor_;
746 }
747 #endif
748
749 return ret;
750 }
751
752 } // namespace npapi
753 } // namespace webkit
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698