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

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

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

Powered by Google App Engine
This is Rietveld 408576698