[Qt] Remove unused code path in PluginView
[WebKit-https.git] / Source / WebCore / plugins / qt / PluginViewQt.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
3  * Copyright (C) 2008 Collabora Ltd. All rights reserved.
4  * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "config.h"
29 #include "PluginView.h"
30
31 #include "BridgeJSC.h"
32 #include "Chrome.h"
33 #include "ChromeClient.h"
34 #include "Document.h"
35 #include "DocumentLoader.h"
36 #include "Element.h"
37 #include "FloatPoint.h"
38 #include "FocusController.h"
39 #include "Frame.h"
40 #include "FrameLoadRequest.h"
41 #include "FrameLoader.h"
42 #include "FrameTree.h"
43 #include "FrameView.h"
44 #include "GraphicsContext.h"
45 #include "HTMLNames.h"
46 #include "HTMLPlugInElement.h"
47 #include "HostWindow.h"
48 #include "IFrameShimSupport.h"
49 #include "Image.h"
50 #include "JSDOMBinding.h"
51 #include "JSDOMWindowBase.h"
52 #include "KeyboardEvent.h"
53 #include "MouseEvent.h"
54 #include "NotImplemented.h"
55 #include "Page.h"
56 #include "PlatformKeyboardEvent.h"
57 #include "PlatformMouseEvent.h"
58 #include "PluginDebug.h"
59 #include "PluginMainThreadScheduler.h"
60 #include "PluginPackage.h"
61 #include "QWebPageClient.h"
62 #include "RenderObject.h"
63 #include "Settings.h"
64 #include "npruntime_impl.h"
65 #include "runtime_root.h"
66 #include <QKeyEvent>
67 #include <QPainter>
68 #include <X11/X.h>
69 #ifndef QT_NO_XRENDER
70 #define Bool int
71 #define Status int
72 #include <X11/extensions/Xrender.h>
73 #endif
74 #include <runtime/JSCJSValue.h>
75 #include <runtime/JSLock.h>
76
77 #include "QtX11ImageConversion.h"
78 #include <QGuiApplication>
79 #include <QWindow>
80 #include <qpa/qplatformnativeinterface.h>
81
82 using JSC::ExecState;
83 using JSC::Interpreter;
84 using JSC::JSLock;
85 using JSC::JSObject;
86
87 using std::min;
88
89 using namespace WTF;
90
91 namespace WebCore {
92
93 bool PluginView::s_isRunningUnderDRT = false;
94
95 using namespace HTMLNames;
96
97 struct X11Environment {
98     Display* display;
99     int screenID;
100     unsigned long rootWindowID;
101     int displayDepth;
102 };
103
104 static X11Environment x11Environment = { 0, 0, 0, 0 };
105
106 static inline Display* x11Display() { return x11Environment.display; }
107 static inline int x11Screen() { return x11Environment.screenID; }
108 static inline unsigned long rootWindowID() { return x11Environment.rootWindowID; }
109 static inline int displayDepth() { return x11Environment.displayDepth; }
110
111 static inline void syncX()
112 {
113     XSync(x11Display(), false);
114 }
115
116 QWebPageClient* PluginView::platformPageClient() const
117 {
118     FrameView* view = m_parentFrame->view();
119     if (!view)
120         return 0;
121     HostWindow* hostWindow = view->hostWindow();
122     if (!hostWindow)
123         return 0;
124     return hostWindow->platformPageClient();
125 }
126
127 void PluginView::updatePluginWidget()
128 {
129     if (!parent())
130         return;
131
132     ASSERT(parent()->isFrameView());
133     FrameView* frameView = toFrameView(parent());
134
135     IntRect oldWindowRect = m_windowRect;
136     IntRect oldClipRect = m_clipRect;
137
138     m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
139     m_clipRect = windowClipRect();
140     m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
141
142     if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
143         return;
144
145     // The plugin had a zero width or height before but was resized, we need to show it again.
146     if (oldWindowRect.isEmpty())
147         show();
148
149     if (!m_isWindowed && m_windowRect.size() != oldWindowRect.size()) {
150         if (m_drawable)
151             XFreePixmap(x11Display(), m_drawable);
152
153         m_drawable = XCreatePixmap(x11Display(), rootWindowID(), m_windowRect.width(), m_windowRect.height(),
154                                    ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth);
155         syncX(); // make sure that the server knows about the Drawable
156     }
157
158     // do not call setNPWindowIfNeeded immediately, will be called on paint()
159     m_hasPendingGeometryChange = true;
160
161     // (i) in order to move/resize the plugin window at the same time as the
162     // rest of frame during e.g. scrolling, we set the window geometry
163     // in the paint() function, but as paint() isn't called when the
164     // plugin window is outside the frame which can be caused by a
165     // scroll, we need to move/resize immediately.
166     // (ii) if we are running layout tests from DRT, paint() won't ever get called
167     // so we need to call setNPWindowIfNeeded() if window geometry has changed
168     if (!m_windowRect.intersects(frameView->frameRect())
169         || (s_isRunningUnderDRT && platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)))
170         setNPWindowIfNeeded();
171
172     invalidate();
173 }
174
175 void PluginView::setFocus(bool focused)
176 {
177     Widget::setFocus(focused);
178 }
179
180 void PluginView::show()
181 {
182     Q_ASSERT(platformPluginWidget() == platformWidget());
183     Widget::show();
184 }
185
186 void PluginView::hide()
187 {
188     Q_ASSERT(platformPluginWidget() == platformWidget());
189     Widget::hide();
190 }
191
192 static void setupGraphicsExposeEvent(Pixmap drawable, const QRect& exposedRect, XEvent& xevent)
193 {
194     memset(&xevent, 0, sizeof(XEvent));
195     XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
196     exposeEvent.type = GraphicsExpose;
197     exposeEvent.display = x11Display();
198     exposeEvent.drawable = drawable;
199     exposeEvent.x = exposedRect.x();
200     exposeEvent.y = exposedRect.y();
201     exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode
202     exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode
203 }
204
205 void PluginView::paintUsingXPixmap(QPainter* painter, const QRect &exposedRect)
206 {
207     bool shouldSyncX = m_pluginDisplay && m_pluginDisplay != x11Display();
208     XEvent xevent;
209
210     setupGraphicsExposeEvent(m_drawable, exposedRect, xevent);
211     dispatchNPEvent(xevent);
212
213     if (shouldSyncX)
214         XSync(m_pluginDisplay, false); // sync changes by plugin
215
216     XImage* xImage = XGetImage(x11Display(), m_drawable, exposedRect.x(), exposedRect.y(),
217                                exposedRect.width(), exposedRect.height(), ULONG_MAX, ZPixmap);
218     painter->drawImage(QPoint(exposedRect.x(), exposedRect.y()), qimageFromXImage(xImage));
219     XDestroyImage(xImage);
220 }
221
222 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
223 {
224     if (!m_isStarted) {
225         paintMissingPluginIcon(context, rect);
226         return;
227     }
228
229     if (context->paintingDisabled())
230         return;
231
232     setNPWindowIfNeeded();
233
234     if (m_isWindowed)
235         return;
236
237     if (!m_drawable)
238         return;
239
240     QPainter* painter = context->platformContext();
241     IntRect exposedRect(rect);
242     exposedRect.intersect(frameRect());
243     exposedRect.move(-frameRect().x(), -frameRect().y());
244
245     painter->translate(frameRect().x(), frameRect().y());
246     paintUsingXPixmap(painter, exposedRect);
247     painter->translate(-frameRect().x(), -frameRect().y());
248 }
249
250 // TODO: Unify across ports.
251 bool PluginView::dispatchNPEvent(NPEvent& event)
252 {
253     if (!m_plugin->pluginFuncs()->event)
254         return false;
255
256     bool shouldPop = false;
257
258     if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE
259         && (event.type == ButtonRelease || event.type == 3 /*KeyRelease*/)) {
260         pushPopupsEnabledState(true);
261         shouldPop = true;
262     }
263
264     PluginView::setCurrentPluginView(this);
265     JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
266     setCallingPlugin(true);
267     bool accepted = !m_plugin->pluginFuncs()->event(m_instance, &event);
268     setCallingPlugin(false);
269     PluginView::setCurrentPluginView(0);
270
271     if (shouldPop)
272         popPopupsEnabledState();
273
274     return accepted;
275 }
276
277 void setSharedXEventFields(XEvent* xEvent, QWebPageClient* pageClient)
278 {
279     xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server
280     xEvent->xany.send_event = false;
281     xEvent->xany.display = x11Display();
282     // NOTE: event->xany.window doesn't always respond to the .window property of other XEvent's
283     // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify
284     // events; thus, this is right:
285     QWindow* window = pageClient ? pageClient->ownerWindow() : 0;
286     xEvent->xany.window = window ? window->winId() : 0;
287 }
288
289 void PluginView::initXEvent(XEvent* xEvent)
290 {
291     memset(xEvent, 0, sizeof(XEvent));
292
293     QWebPageClient* client = platformPageClient();
294     setSharedXEventFields(xEvent, client);
295 }
296
297 void PluginView::setXKeyEventSpecificFields(XEvent* xEvent, KeyboardEvent* event)
298 {
299     const PlatformKeyboardEvent* keyEvent = event->keyEvent();
300
301     xEvent->type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // ints as Qt unsets KeyPress and KeyRelease
302     xEvent->xkey.root = rootWindowID();
303     xEvent->xkey.subwindow = 0; // we have no child window
304     xEvent->xkey.time = event->timeStamp();
305     xEvent->xkey.state = keyEvent->nativeModifiers();
306     xEvent->xkey.keycode = keyEvent->nativeScanCode();
307
308     // We may not have a nativeScanCode() if the key event is from DRT's eventsender. In that
309     // case fetch the XEvent's keycode from the event's text. The only
310     // place this keycode will be used is in webkit_test_plugin_handle_event().
311     // FIXME: Create Qt API so that we can set the appropriate keycode in DRT EventSender instead.
312     if (s_isRunningUnderDRT && !xEvent->xkey.keycode) {
313         QKeyEvent* qKeyEvent = keyEvent->qtEvent();
314         ASSERT(qKeyEvent);
315         QString keyText = qKeyEvent->text().left(1);
316         xEvent->xkey.keycode = XKeysymToKeycode(x11Display(), XStringToKeysym(keyText.toUtf8().constData()));
317     }
318
319     xEvent->xkey.same_screen = true;
320
321     // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window
322     // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not
323     // set to their normal Xserver values. e.g. Key events don't have a position.
324     // source: https://developer.mozilla.org/en/NPEvent
325     xEvent->xkey.x = 0;
326     xEvent->xkey.y = 0;
327     xEvent->xkey.x_root = 0;
328     xEvent->xkey.y_root = 0;
329 }
330
331 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
332 {
333     if (m_isWindowed)
334         return;
335
336     if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent)
337         return;
338
339     XEvent npEvent;
340     initXEvent(&npEvent);
341     setXKeyEventSpecificFields(&npEvent, event);
342
343     if (dispatchNPEvent(npEvent))
344         event->setDefaultHandled();
345 }
346
347 static unsigned int inputEventState(MouseEvent* event)
348 {
349     unsigned int state = 0;
350     if (event->ctrlKey())
351         state |= ControlMask;
352     if (event->shiftKey())
353         state |= ShiftMask;
354     if (event->altKey())
355         state |= Mod1Mask;
356     if (event->metaKey())
357         state |= Mod4Mask;
358     return state;
359 }
360
361 static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
362 {
363     XButtonEvent& xbutton = xEvent->xbutton;
364     xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease;
365     xbutton.root = rootWindowID();
366     xbutton.subwindow = 0;
367     xbutton.time = event->timeStamp();
368     xbutton.x = postZoomPos.x();
369     xbutton.y = postZoomPos.y();
370     xbutton.x_root = event->screenX();
371     xbutton.y_root = event->screenY();
372     xbutton.state = inputEventState(event);
373     switch (event->button()) {
374     case MiddleButton:
375         xbutton.button = Button2;
376         break;
377     case RightButton:
378         xbutton.button = Button3;
379         break;
380     case LeftButton:
381     default:
382         xbutton.button = Button1;
383         break;
384     }
385     xbutton.same_screen = true;
386 }
387
388 static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
389 {
390     XMotionEvent& xmotion = xEvent->xmotion;
391     xmotion.type = MotionNotify;
392     xmotion.root = rootWindowID();
393     xmotion.subwindow = 0;
394     xmotion.time = event->timeStamp();
395     xmotion.x = postZoomPos.x();
396     xmotion.y = postZoomPos.y();
397     xmotion.x_root = event->screenX();
398     xmotion.y_root = event->screenY();
399     xmotion.state = inputEventState(event);
400     xmotion.is_hint = NotifyNormal;
401     xmotion.same_screen = true;
402 }
403
404 static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
405 {
406     XCrossingEvent& xcrossing = xEvent->xcrossing;
407     xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify;
408     xcrossing.root = rootWindowID();
409     xcrossing.subwindow = 0;
410     xcrossing.time = event->timeStamp();
411     xcrossing.x = postZoomPos.y();
412     xcrossing.y = postZoomPos.x();
413     xcrossing.x_root = event->screenX();
414     xcrossing.y_root = event->screenY();
415     xcrossing.state = inputEventState(event);
416     xcrossing.mode = NotifyNormal;
417     xcrossing.detail = NotifyDetailNone;
418     xcrossing.same_screen = true;
419     xcrossing.focus = false;
420 }
421
422 void PluginView::handleMouseEvent(MouseEvent* event)
423 {
424     if (m_isWindowed)
425         return;
426
427     if (event->button() == RightButton && m_plugin->quirks().contains(PluginQuirkIgnoreRightClickInWindowlessMode))
428         return;
429
430     if (event->type() == eventNames().mousedownEvent) {
431         // Give focus to the plugin on click
432         if (Page* page = m_parentFrame->page())
433             page->focusController().setActive(true);
434
435         focusPluginElement();
436     }
437
438     XEvent npEvent;
439     initXEvent(&npEvent);
440
441     IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
442
443     if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
444         setXButtonEventSpecificFields(&npEvent, event, postZoomPos);
445     else if (event->type() == eventNames().mousemoveEvent)
446         setXMotionEventSpecificFields(&npEvent, event, postZoomPos);
447     else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent)
448         setXCrossingEventSpecificFields(&npEvent, event, postZoomPos);
449     else
450         return;
451
452     if (dispatchNPEvent(npEvent))
453         event->setDefaultHandled();
454 }
455
456 void PluginView::handleFocusInEvent()
457 {
458     XEvent npEvent;
459     initXEvent(&npEvent);
460
461     XFocusChangeEvent& event = npEvent.xfocus;
462     event.type = 9; /* int as Qt unsets FocusIn */
463     event.mode = NotifyNormal;
464     event.detail = NotifyDetailNone;
465
466     dispatchNPEvent(npEvent);
467 }
468
469 void PluginView::handleFocusOutEvent()
470 {
471     XEvent npEvent;
472     initXEvent(&npEvent);
473
474     XFocusChangeEvent& event = npEvent.xfocus;
475     event.type = 10; /* int as Qt unsets FocusOut */
476     event.mode = NotifyNormal;
477     event.detail = NotifyDetailNone;
478
479     dispatchNPEvent(npEvent);
480 }
481
482 void PluginView::setParent(ScrollView* parent)
483 {
484     Widget::setParent(parent);
485
486     if (parent)
487         init();
488 }
489
490 void PluginView::setNPWindowRect(const IntRect&)
491 {
492     if (!m_isWindowed)
493         setNPWindowIfNeeded();
494 }
495
496 void PluginView::setNPWindowIfNeeded()
497 {
498     if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
499         return;
500
501     // If the plugin didn't load sucessfully, no point in calling setwindow
502     if (m_status != PluginStatusLoadedSuccessfully)
503         return;
504
505     // On Unix, only call plugin if it's full-page or windowed
506     if (m_mode != NP_FULL && m_mode != NP_EMBED)
507         return;
508
509     // Check if the platformPluginWidget still exists
510     if (m_isWindowed && !platformPluginWidget())
511         return;
512
513     if (!m_hasPendingGeometryChange)
514         return;
515     m_hasPendingGeometryChange = false;
516
517     m_npWindow.x = 0;
518     m_npWindow.y = 0;
519
520     // If the width or height are null, set the clipRect to null, indicating that
521     // the plugin is not visible/scrolled out.
522     if (!m_clipRect.width() || !m_clipRect.height()) {
523         m_npWindow.clipRect.left = 0;
524         m_npWindow.clipRect.right = 0;
525         m_npWindow.clipRect.top = 0;
526         m_npWindow.clipRect.bottom = 0;
527     } else {
528         // Clipping rectangle of the plug-in; the origin is the top left corner of the drawable or window. 
529         m_npWindow.clipRect.left = m_npWindow.x + m_clipRect.x();
530         m_npWindow.clipRect.top = m_npWindow.y + m_clipRect.y();
531         m_npWindow.clipRect.right = m_npWindow.x + m_clipRect.x() + m_clipRect.width();
532         m_npWindow.clipRect.bottom = m_npWindow.y + m_clipRect.y() + m_clipRect.height();
533     }
534
535     if (m_plugin->quirks().contains(PluginQuirkDontCallSetWindowMoreThanOnce)) {
536         // FLASH WORKAROUND: Only set initially. Multiple calls to
537         // setNPWindow() cause the plugin to crash in windowed mode.
538         if (!m_isWindowed || m_npWindow.width == -1 || m_npWindow.height == -1) {
539             m_npWindow.width = m_windowRect.width();
540             m_npWindow.height = m_windowRect.height();
541         }
542     } else {
543         m_npWindow.width = m_windowRect.width();
544         m_npWindow.height = m_windowRect.height();
545     }
546
547     PluginView::setCurrentPluginView(this);
548     JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
549     setCallingPlugin(true);
550     m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
551     setCallingPlugin(false);
552     PluginView::setCurrentPluginView(0);
553 }
554
555 void PluginView::setParentVisible(bool visible)
556 {
557     if (isParentVisible() == visible)
558         return;
559
560     Widget::setParentVisible(visible);
561 }
562
563 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
564 {
565     String filename(buf, len);
566
567     if (filename.startsWith("file:///"))
568         filename = filename.substring(8);
569
570     long long size;
571     if (!getFileSize(filename, size))
572         return NPERR_FILE_NOT_FOUND;
573
574     FILE* fileHandle = fopen((filename.utf8()).data(), "r");
575     if (!fileHandle)
576         return NPERR_FILE_NOT_FOUND;
577
578     buffer.resize(size);
579     int bytesRead = fread(buffer.data(), 1, size, fileHandle);
580
581     fclose(fileHandle);
582
583     if (bytesRead <= 0)
584         return NPERR_FILE_NOT_FOUND;
585
586     return NPERR_NO_ERROR;
587 }
588
589 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
590 {
591     switch (variable) {
592     case NPNVToolkit:
593         *static_cast<uint32_t*>(value) = 0;
594         *result = NPERR_NO_ERROR;
595         return true;
596
597     case NPNVSupportsXEmbedBool:
598         *static_cast<NPBool*>(value) = true;
599         *result = NPERR_NO_ERROR;
600         return true;
601
602     case NPNVjavascriptEnabledBool:
603         *static_cast<NPBool*>(value) = true;
604         *result = NPERR_NO_ERROR;
605         return true;
606
607     case NPNVSupportsWindowless:
608         *static_cast<NPBool*>(value) = true;
609         *result = NPERR_NO_ERROR;
610         return true;
611
612     default:
613         return false;
614     }
615 }
616
617 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
618 {
619     switch (variable) {
620     case NPNVxDisplay:
621         *reinterpret_cast<void**>(value) = x11Display();
622         *result = NPERR_NO_ERROR;
623         return true;
624
625     case NPNVxtAppContext:
626         *result = NPERR_GENERIC_ERROR;
627         return true;
628
629     case NPNVnetscapeWindow: {
630         QWebPageClient* client = platformPageClient();
631         QWindow* window = client ? client->ownerWindow() : 0;
632         *reinterpret_cast<XID*>(value) = window ? window->winId() : 0;
633         *result = NPERR_NO_ERROR;
634         return true;
635     }
636
637     case NPNVToolkit:
638         if (m_plugin->quirks().contains(PluginQuirkRequiresGtkToolKit)) {
639             *((uint32_t *)value) = 2;
640             *result = NPERR_NO_ERROR;
641             return true;
642         }
643         return false;
644
645     default:
646         return false;
647     }
648 }
649
650 void PluginView::invalidateRect(const IntRect& rect)
651 {
652     invalidateWindowlessPluginRect(rect);
653 }
654
655 void PluginView::invalidateRect(NPRect* rect)
656 {
657     if (!rect) {
658         invalidate();
659         return;
660     }
661     IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
662     invalidateRect(r);
663 }
664
665 void PluginView::invalidateRegion(NPRegion region)
666 {
667     Q_UNUSED(region);
668     invalidate();
669 }
670
671 void PluginView::forceRedraw()
672 {
673     invalidate();
674 }
675
676 static Display *getPluginDisplay()
677 {
678     // The plugin toolkit might run using a different X connection. At the moment, we only
679     // support gdk based plugins (like flash) that use a different X connection.
680     // The code below has the same effect as this one:
681     // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
682     QLibrary library(QLatin1String("libgdk-x11-2.0"), 0);
683     if (!library.load())
684         return 0;
685
686     typedef void *(*gdk_init_check_ptr)(void*, void*);
687     gdk_init_check_ptr gdk_init_check = (gdk_init_check_ptr)library.resolve("gdk_init_check");
688     if (!gdk_init_check)
689         return 0;
690
691     typedef void *(*gdk_display_get_default_ptr)();
692     gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default");
693     if (!gdk_display_get_default)
694         return 0;
695
696     typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *);
697     gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay");
698     if (!gdk_x11_display_get_xdisplay)
699         return 0;
700
701     gdk_init_check(0, 0);
702     return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default());
703 }
704
705 static bool getVisualAndColormap(int depth, Visual*& visual, Colormap& colormap, bool forceARGB32)
706 {
707     ASSERT(depth == 32 || !forceARGB32);
708
709     visual = 0;
710     colormap = 0;
711
712     if (forceARGB32)
713         return false;
714
715     int nvi;
716     XVisualInfo templ;
717     templ.screen  = x11Screen();
718     templ.depth   = depth;
719     templ.c_class = TrueColor;
720     XVisualInfo* xvi = XGetVisualInfo(x11Display(), VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi);
721     ASSERT(xvi || forceARGB32);
722     if (!xvi)
723         return false;
724
725     visual = xvi[0].visual;
726     ASSERT(visual);
727
728     XFree(xvi);
729
730     colormap = XCreateColormap(x11Display(), rootWindowID(), visual, AllocNone);
731     return true;
732 }
733
734 bool PluginView::platformStart()
735 {
736     ASSERT(m_isStarted);
737     ASSERT(m_status == PluginStatusLoadedSuccessfully);
738
739     if (!x11Environment.display) {
740         Display* display;
741         display = static_cast<Display*>(QGuiApplication::platformNativeInterface()->nativeResourceForWindow("display", 0));
742         x11Environment.display = display;
743         x11Environment.screenID = XDefaultScreen(display);
744         x11Environment.displayDepth = XDefaultDepth(display, x11Environment.screenID);
745         x11Environment.rootWindowID = XDefaultRootWindow(display);
746     }
747
748     // Windowed mode is not supported with Qt5 yet.
749     if (m_isWindowed)
750         return false;
751     setPlatformWidget(0);
752     m_pluginDisplay = getPluginDisplay();
753
754     // If the width and the height are not zero we show the PluginView.
755     if (!frameRect().isEmpty())
756         show();
757
758     NPSetWindowCallbackStruct* wsi = new NPSetWindowCallbackStruct();
759     wsi->type = 0;
760
761     int depth = displayDepth();
762     bool found = getVisualAndColormap(depth, m_visual, m_colormap, /* forceARGB32 = */ false);
763     ASSERT_UNUSED(found, found);
764     wsi->depth = depth;
765
766     wsi->display = x11Display();
767     wsi->visual = m_visual;
768     wsi->colormap = m_colormap;
769
770     m_npWindow.type = NPWindowTypeDrawable;
771     m_npWindow.window = 0; // Not used?
772     m_npWindow.x = 0;
773     m_npWindow.y = 0;
774     m_npWindow.width = -1;
775     m_npWindow.height = -1;
776
777     m_npWindow.ws_info = wsi;
778
779     if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) {
780         updatePluginWidget();
781         setNPWindowIfNeeded();
782     }
783
784     return true;
785 }
786
787 void PluginView::platformDestroy()
788 {
789     if (platformPluginWidget())
790         delete platformPluginWidget();
791
792     if (m_drawable)
793         XFreePixmap(x11Display(), m_drawable);
794
795     if (m_colormap)
796         XFreeColormap(x11Display(), m_colormap);
797 }
798
799 } // namespace WebCore