8c1fef6d2f4dce2dbe9f37abe868bcfe5b50d08f
[WebKit-https.git] / Source / WebKit2 / WebProcess / Plugins / Netscape / x11 / NetscapePluginX11.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 University of Szeged
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "NetscapePlugin.h"
29
30 #include "WebEvent.h"
31 #include <WebCore/GraphicsContext.h>
32 #include <WebCore/NotImplemented.h>
33
34 #if PLATFORM(QT)
35 #include <QApplication>
36 #include <QDesktopWidget>
37 #include <QPixmap>
38 #include <QX11Info>
39 #elif PLATFORM(GTK)
40 #include <gdk/gdkx.h>
41 #endif
42
43 using namespace WebCore;
44
45 namespace WebKit {
46
47 static Display *getPluginDisplay()
48 {
49 #if PLATFORM(QT)
50     // At the moment, we only support gdk based plugins (like Flash) that use a different X connection.
51     // The code below has the same effect as this one:
52     // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
53
54     QLibrary library("libgdk-x11-2.0", 0);
55     if (!library.load())
56         return 0;
57
58     typedef void *(*gdk_display_get_default_ptr)();
59     gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default");
60     if (!gdk_display_get_default)
61         return 0;
62
63     typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *);
64     gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay");
65     if (!gdk_x11_display_get_xdisplay)
66         return 0;
67
68     return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default());
69 #elif PLATFORM(GTK)
70     // Since we're a gdk/gtk app, we'll (probably?) have the same X connection as any gdk-based
71     // plugins, so we can return that. We might want to add other implementations here later.
72     return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
73 #else
74     return 0;
75 #endif
76 }
77
78 static inline Display* x11Display()
79 {
80 #if PLATFORM(QT)
81     return QX11Info::display();
82 #elif PLATFORM(GTK)
83     return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
84 #else
85     return 0;
86 #endif
87 }
88
89 static inline int displayDepth()
90 {
91 #if PLATFORM(QT)
92     return QApplication::desktop()->x11Info().depth();
93 #elif PLATFORM(GTK)
94     return gdk_visual_get_depth(gdk_screen_get_system_visual(gdk_screen_get_default()));
95 #else
96     return 0;
97 #endif
98 }
99
100 static inline unsigned long rootWindowID()
101 {
102 #if PLATFORM(QT)
103     return QX11Info::appRootWindow();
104 #elif PLATFORM(GTK)
105     return GDK_ROOT_WINDOW();
106 #else
107     return 0;
108 #endif
109 }
110
111 static inline int x11Screen()
112 {
113 #if PLATFORM(QT)
114     return QX11Info::appScreen();
115 #elif PLATFORM(GTK)
116     return gdk_screen_get_number(gdk_screen_get_default());
117 #else
118     return 0;
119 #endif
120 }
121
122 bool NetscapePlugin::platformPostInitialize()
123 {
124     if (m_isWindowed)
125         return false;
126
127     if (!(m_pluginDisplay = getPluginDisplay()))
128         return false;
129
130     NPSetWindowCallbackStruct* callbackStruct = new NPSetWindowCallbackStruct;
131     callbackStruct->type = 0;
132     Display* display = x11Display();
133     int depth = displayDepth();
134     callbackStruct->display = display;
135     callbackStruct->depth = depth;
136
137     XVisualInfo visualTemplate;
138     visualTemplate.screen = x11Screen();
139     visualTemplate.depth = depth;
140     visualTemplate.c_class = TrueColor;
141     int numMatching;
142     XVisualInfo* visualInfo = XGetVisualInfo(display, VisualScreenMask | VisualDepthMask | VisualClassMask,
143                                              &visualTemplate, &numMatching);
144     ASSERT(visualInfo);
145     Visual* visual = visualInfo[0].visual;
146     ASSERT(visual);
147     XFree(visualInfo);
148
149     callbackStruct->visual = visual;
150     callbackStruct->colormap = XCreateColormap(display, rootWindowID(), visual, AllocNone);
151
152     m_npWindow.type = NPWindowTypeDrawable;
153     m_npWindow.window = 0;
154     m_npWindow.ws_info = callbackStruct;
155
156     callSetWindow();
157
158     return true;
159 }
160
161 void NetscapePlugin::platformDestroy()
162 {
163     delete static_cast<NPSetWindowCallbackStruct*>(m_npWindow.ws_info);
164
165     if (m_drawable) {
166         XFreePixmap(x11Display(), m_drawable);
167         m_drawable = 0;
168     }
169 }
170
171 bool NetscapePlugin::platformInvalidate(const IntRect&)
172 {
173     notImplemented();
174     return false;
175 }
176
177 void NetscapePlugin::platformGeometryDidChange()
178 {
179     if (m_isWindowed) {
180         notImplemented();
181         return;
182     }
183
184     Display* display = x11Display();
185     if (m_drawable)
186         XFreePixmap(display, m_drawable);
187
188     m_drawable = XCreatePixmap(display, rootWindowID(), m_frameRect.width(), m_frameRect.height(), displayDepth());
189
190     XSync(display, false); // Make sure that the server knows about the Drawable.
191 }
192
193 void NetscapePlugin::platformPaint(GraphicsContext* context, const IntRect& dirtyRect, bool /*isSnapshot*/)
194 {
195     if (m_isWindowed) {
196         notImplemented();
197         return;
198     }
199
200     if (!m_isStarted) {
201         // FIXME: we should paint a missing plugin icon.
202         return;
203     }
204
205     if (context->paintingDisabled())
206         return;
207
208     ASSERT(m_drawable);
209
210 #if PLATFORM(QT)
211     QPainter* painter = context->platformContext();
212     painter->translate(m_frameRect.x(), m_frameRect.y());
213 #else
214     notImplemented();
215     return;
216 #endif
217
218     XEvent xevent;
219     memset(&xevent, 0, sizeof(XEvent));
220     XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
221     exposeEvent.type = GraphicsExpose;
222     exposeEvent.display = x11Display();
223     exposeEvent.drawable = m_drawable;
224
225     IntRect exposedRect(dirtyRect);
226     exposedRect.intersect(m_frameRect);
227     exposedRect.move(-m_frameRect.x(), -m_frameRect.y());
228     exposeEvent.x = exposedRect.x();
229     exposeEvent.y = exposedRect.y();
230
231     // Note: in transparent mode Flash thinks width is the right and height is the bottom.
232     // We should take it into account if we want to support transparency.
233     exposeEvent.width = exposedRect.width();
234     exposeEvent.height = exposedRect.height();
235
236     NPP_HandleEvent(&xevent);
237
238     if (m_pluginDisplay != x11Display())
239         XSync(m_pluginDisplay, false);
240
241 #if PLATFORM(QT)
242     QPixmap qtDrawable = QPixmap::fromX11Pixmap(m_drawable, QPixmap::ExplicitlyShared);
243     ASSERT(qtDrawable.depth() == static_cast<NPSetWindowCallbackStruct*>(m_npWindow.ws_info)->depth);
244     painter->drawPixmap(QPoint(exposedRect.x(), exposedRect.y()), qtDrawable, exposedRect);
245
246     painter->translate(-m_frameRect.x(), -m_frameRect.y());
247 #endif
248 }
249
250 static inline void initializeXEvent(XEvent& event)
251 {
252     memset(&event, 0, sizeof(XEvent));
253     event.xany.serial = 0;
254     event.xany.send_event = false;
255     event.xany.display = x11Display();
256     event.xany.window = 0;
257 }
258
259 static inline uint64_t xTimeStamp(double timestampInSeconds)
260 {
261     return timestampInSeconds * 1000;
262 }
263
264 static inline unsigned xKeyModifiers(const WebEvent& event)
265 {
266     unsigned xModifiers = 0;
267     if (event.controlKey())
268         xModifiers |= ControlMask;
269     if (event.shiftKey())
270         xModifiers |= ShiftMask;
271     if (event.altKey())
272         xModifiers |= Mod1Mask;
273     if (event.metaKey())
274         xModifiers |= Mod4Mask;
275
276     return xModifiers;
277 }
278
279 template <typename XEventType>
280 static inline void setCommonMouseEventFields(XEventType& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation)
281 {
282     xEvent.root = rootWindowID();
283     xEvent.subwindow = 0;
284     xEvent.time = xTimeStamp(webEvent.timestamp());
285     xEvent.x = webEvent.position().x() - pluginLocation.x();
286     xEvent.y = webEvent.position().y() - pluginLocation.y();
287     xEvent.x_root = webEvent.globalPosition().x();
288     xEvent.y_root = webEvent.globalPosition().y();
289     xEvent.state = xKeyModifiers(webEvent);
290     xEvent.same_screen = true;
291 }
292
293 static inline void setXMotionEventFields(XEvent& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation)
294 {
295     XMotionEvent& xMotion = xEvent.xmotion;
296     setCommonMouseEventFields(xMotion, webEvent, pluginLocation);
297     xMotion.type = MotionNotify;
298 }
299
300 static inline void setXButtonEventFields(XEvent& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation)
301 {
302     XButtonEvent& xButton = xEvent.xbutton;
303     setCommonMouseEventFields(xButton, webEvent, pluginLocation);
304
305     xButton.type = (webEvent.type() == WebEvent::MouseDown) ? ButtonPress : ButtonRelease;
306     switch (webEvent.button()) {
307     case WebMouseEvent::LeftButton:
308         xButton.button = Button1;
309         break;
310     case WebMouseEvent::MiddleButton:
311         xButton.button = Button2;
312         break;
313     case WebMouseEvent::RightButton:
314         xButton.button = Button3;
315         break;
316     }
317 }
318
319 static inline void setXCrossingEventFields(XEvent& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation, int type)
320 {
321     XCrossingEvent& xCrossing = xEvent.xcrossing;
322     setCommonMouseEventFields(xCrossing, webEvent, pluginLocation);
323
324     xCrossing.type = type;
325     xCrossing.mode = NotifyNormal;
326     xCrossing.detail = NotifyDetailNone;
327     xCrossing.focus = false;
328 }
329
330 bool NetscapePlugin::platformHandleMouseEvent(const WebMouseEvent& event)
331 {
332     if (m_isWindowed)
333         return false;
334
335     XEvent xEvent;
336     initializeXEvent(xEvent);
337
338     switch (event.type()) {
339     case WebEvent::MouseDown:
340     case WebEvent::MouseUp:
341         setXButtonEventFields(xEvent, event, m_frameRect.location());
342         break;
343     case WebEvent::MouseMove:
344         setXMotionEventFields(xEvent, event, m_frameRect.location());
345         break;
346     }
347
348     return NPP_HandleEvent(&xEvent);
349 }
350
351 // We undefine these constants in npruntime_internal.h to avoid collision
352 // with WebKit and platform headers. Values are defined in X.h.
353 const int kKeyPressType = 2;
354 const int kKeyReleaseType = 3;
355 const int kFocusInType = 9;
356 const int kFocusOutType = 10;
357
358 bool NetscapePlugin::platformHandleWheelEvent(const WebWheelEvent&)
359 {
360     notImplemented();
361     return false;
362 }
363
364 void NetscapePlugin::platformSetFocus(bool)
365 {
366     notImplemented();
367 }
368
369 bool NetscapePlugin::platformHandleMouseEnterEvent(const WebMouseEvent& event)
370 {
371     if (m_isWindowed)
372         return false;
373
374     XEvent xEvent;
375     initializeXEvent(xEvent);
376     setXCrossingEventFields(xEvent, event, m_frameRect.location(), EnterNotify);
377
378     return NPP_HandleEvent(&xEvent);
379 }
380
381 bool NetscapePlugin::platformHandleMouseLeaveEvent(const WebMouseEvent& event)
382 {
383     if (m_isWindowed)
384         return false;
385
386     XEvent xEvent;
387     initializeXEvent(xEvent);
388     setXCrossingEventFields(xEvent, event, m_frameRect.location(), LeaveNotify);
389
390     return NPP_HandleEvent(&xEvent);
391 }
392
393 static inline void setXKeyEventFields(XEvent& xEvent, const WebKeyboardEvent& webEvent)
394 {
395     xEvent.xany.type = (webEvent.type() == WebEvent::KeyDown) ? kKeyPressType : kKeyReleaseType;
396     XKeyEvent& xKey = xEvent.xkey;
397     xKey.root = rootWindowID();
398     xKey.subwindow = 0;
399     xKey.time = xTimeStamp(webEvent.timestamp());
400     xKey.state = xKeyModifiers(webEvent);
401     xKey.keycode = webEvent.nativeVirtualKeyCode();
402
403     xKey.same_screen = true;
404
405     // Key events propagated to the plugin does not need to have position.
406     // source: https://developer.mozilla.org/en/NPEvent
407     xKey.x = 0;
408     xKey.y = 0;
409     xKey.x_root = 0;
410     xKey.y_root = 0;
411 }
412
413 bool NetscapePlugin::platformHandleKeyboardEvent(const WebKeyboardEvent& event)
414 {
415     // We don't generate other types of keyboard events via WebEventFactory.
416     ASSERT(event.type() == WebEvent::KeyDown || event.type() == WebEvent::KeyUp);
417
418     XEvent xEvent;
419     initializeXEvent(xEvent);
420     setXKeyEventFields(xEvent, event);
421
422     return NPP_HandleEvent(&xEvent);
423 }
424
425 } // namespace WebKit