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