• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "PluginContainerQt.h"
62 #include "PluginDebug.h"
63 #include "PluginPackage.h"
64 #include "PluginMainThreadScheduler.h"
65 #include "QWebPageClient.h"
66 #include "RenderLayer.h"
67 #include "ScriptController.h"
68 #include "Settings.h"
69 #include "npruntime_impl.h"
70 #include "qwebpage_p.h"
71 #if USE(JSC)
72 #include "runtime_root.h"
73 #endif
74 
75 #include <QApplication>
76 #include <QDesktopWidget>
77 #include <QGraphicsWidget>
78 #include <QKeyEvent>
79 #include <QPainter>
80 #include <QStyleOptionGraphicsItem>
81 #include <QWidget>
82 #include <QX11Info>
83 #include <X11/X.h>
84 #ifndef QT_NO_XRENDER
85 #define Bool int
86 #define Status int
87 #include <X11/extensions/Xrender.h>
88 #endif
89 #include <runtime/JSLock.h>
90 #include <runtime/JSValue.h>
91 
92 using JSC::ExecState;
93 #if USE(JSC)
94 using JSC::Interpreter;
95 #endif
96 using JSC::JSLock;
97 using JSC::JSObject;
98 using JSC::UString;
99 
100 using std::min;
101 
102 using namespace WTF;
103 
104 namespace WebCore {
105 
106 using namespace HTMLNames;
107 
108 #if USE(ACCELERATED_COMPOSITING)
109 // Qt's GraphicsLayer (GraphicsLayerQt) requires layers to be QGraphicsWidgets
110 class PluginGraphicsLayerQt : public QGraphicsWidget {
111 public:
PluginGraphicsLayerQt(PluginView * view)112     PluginGraphicsLayerQt(PluginView* view) : m_view(view) { }
~PluginGraphicsLayerQt()113     ~PluginGraphicsLayerQt() { }
114 
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget=0)115     void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0)
116     {
117         Q_UNUSED(widget);
118         m_view->paintUsingXPixmap(painter, option->exposedRect.toRect());
119     }
120 
121 private:
122     PluginView* m_view;
123 };
124 #endif
125 
updatePluginWidget()126 void PluginView::updatePluginWidget()
127 {
128     if (!parent())
129         return;
130 
131     ASSERT(parent()->isFrameView());
132     FrameView* frameView = static_cast<FrameView*>(parent());
133 
134     IntRect oldWindowRect = m_windowRect;
135     IntRect oldClipRect = m_clipRect;
136 
137     m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
138     m_clipRect = windowClipRect();
139     m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
140 
141     if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
142         return;
143 
144     // The plugin had a zero width or height before but was resized, we need to show it again.
145     if (oldWindowRect.isEmpty())
146         show();
147 
148     if (!m_isWindowed && m_windowRect.size() != oldWindowRect.size()) {
149 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
150         // On Maemo5, Flash always renders to 16-bit buffer
151         if (m_renderToImage)
152             m_image = QImage(m_windowRect.width(), m_windowRect.height(), QImage::Format_RGB16);
153         else
154 #endif
155         {
156             if (m_drawable)
157                 XFreePixmap(QX11Info::display(), m_drawable);
158 
159             m_drawable = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), m_windowRect.width(), m_windowRect.height(),
160                                        ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth);
161             QApplication::syncX(); // make sure that the server knows about the Drawable
162         }
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         || (QWebPagePrivate::drtRun && 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 
setFocus(bool focused)189 void PluginView::setFocus(bool focused)
190 {
191     if (platformPluginWidget()) {
192         if (focused)
193             platformPluginWidget()->setFocus(Qt::OtherFocusReason);
194     } else {
195         Widget::setFocus(focused);
196     }
197 }
198 
show()199 void PluginView::show()
200 {
201     Q_ASSERT(platformPluginWidget() == platformWidget());
202     Widget::show();
203 }
204 
hide()205 void PluginView::hide()
206 {
207     Q_ASSERT(platformPluginWidget() == platformWidget());
208     Widget::hide();
209 }
210 
211 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
paintUsingImageSurfaceExtension(QPainter * painter,const IntRect & exposedRect)212 void PluginView::paintUsingImageSurfaceExtension(QPainter* painter, const IntRect& exposedRect)
213 {
214     NPImageExpose imageExpose;
215     QPoint offset;
216     QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
217     const bool surfaceHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent());
218 
219     QPaintDevice* surface =  QPainter::redirected(painter->device(), &offset);
220 
221     // If the surface is a QImage, we can render directly into it
222     if (surfaceHasUntransformedContents && surface && surface->devType() == QInternal::Image) {
223         QImage* image = static_cast<QImage*>(surface);
224         offset = -offset; // negating the offset gives us the offset of the view within the surface
225         imageExpose.data = reinterpret_cast<char*>(image->bits());
226         imageExpose.dataSize.width = image->width();
227         imageExpose.dataSize.height = image->height();
228         imageExpose.stride = image->bytesPerLine();
229         imageExpose.depth = image->depth(); // this is guaranteed to be 16 on Maemo5
230         imageExpose.translateX = offset.x() + m_windowRect.x();
231         imageExpose.translateY = offset.y() + m_windowRect.y();
232         imageExpose.scaleX = 1;
233         imageExpose.scaleY = 1;
234     } else {
235         if (m_isTransparent) {
236             // On Maemo5, Flash expects the buffer to contain the contents that are below it.
237             // We don't support transparency for non-raster graphicssystem, so clean the image
238             // before giving to Flash.
239             QPainter imagePainter(&m_image);
240             imagePainter.fillRect(exposedRect, Qt::white);
241         }
242 
243         imageExpose.data = reinterpret_cast<char*>(m_image.bits());
244         imageExpose.dataSize.width = m_image.width();
245         imageExpose.dataSize.height = m_image.height();
246         imageExpose.stride = m_image.bytesPerLine();
247         imageExpose.depth = m_image.depth();
248         imageExpose.translateX = 0;
249         imageExpose.translateY = 0;
250         imageExpose.scaleX = 1;
251         imageExpose.scaleY = 1;
252     }
253     imageExpose.x = exposedRect.x();
254     imageExpose.y = exposedRect.y();
255     imageExpose.width = exposedRect.width();
256     imageExpose.height = exposedRect.height();
257 
258     XEvent xevent;
259     memset(&xevent, 0, sizeof(XEvent));
260     XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
261     exposeEvent.type = GraphicsExpose;
262     exposeEvent.display = 0;
263     exposeEvent.drawable = reinterpret_cast<XID>(&imageExpose);
264     exposeEvent.x = exposedRect.x();
265     exposeEvent.y = exposedRect.y();
266     exposeEvent.width = exposedRect.width();
267     exposeEvent.height = exposedRect.height();
268 
269     dispatchNPEvent(xevent);
270 
271     if (!surfaceHasUntransformedContents || !surface || surface->devType() != QInternal::Image)
272         painter->drawImage(QPoint(frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y()), m_image, exposedRect);
273 }
274 #endif
275 
paintUsingXPixmap(QPainter * painter,const QRect & exposedRect)276 void PluginView::paintUsingXPixmap(QPainter* painter, const QRect &exposedRect)
277 {
278     QPixmap qtDrawable = QPixmap::fromX11Pixmap(m_drawable, QPixmap::ExplicitlyShared);
279     const int drawableDepth = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth;
280     ASSERT(drawableDepth == qtDrawable.depth());
281     const bool syncX = m_pluginDisplay && m_pluginDisplay != QX11Info::display();
282 
283     // When printing, Qt uses a QPicture to capture the output in preview mode. The
284     // QPicture holds a reference to the X Pixmap. As a result, the print preview would
285     // update itself when the X Pixmap changes. To prevent this, we create a copy.
286     if (m_element->document()->printing())
287         qtDrawable = qtDrawable.copy();
288 
289     if (m_isTransparent && drawableDepth != 32) {
290         // Attempt content propagation for drawable with no alpha by copying over from the backing store
291         QPoint offset;
292         QPaintDevice* backingStoreDevice =  QPainter::redirected(painter->device(), &offset);
293         offset = -offset; // negating the offset gives us the offset of the view within the backing store pixmap
294 
295         const bool hasValidBackingStore = backingStoreDevice && backingStoreDevice->devType() == QInternal::Pixmap;
296         QPixmap* backingStorePixmap = static_cast<QPixmap*>(backingStoreDevice);
297 
298         // We cannot grab contents from the backing store when painting on QGraphicsView items
299         // (because backing store contents are already transformed). What we really mean to do
300         // here is to check if we are painting on QWebView, but let's be a little permissive :)
301         QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
302         const bool backingStoreHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent());
303 
304         if (hasValidBackingStore && backingStorePixmap->depth() == drawableDepth
305             && backingStoreHasUntransformedContents) {
306             GC gc = XDefaultGC(QX11Info::display(), QX11Info::appScreen());
307             XCopyArea(QX11Info::display(), backingStorePixmap->handle(), m_drawable, gc,
308                 offset.x() + m_windowRect.x() + exposedRect.x(), offset.y() + m_windowRect.y() + exposedRect.y(),
309                 exposedRect.width(), exposedRect.height(), exposedRect.x(), exposedRect.y());
310         } else { // no backing store, clean the pixmap because the plugin thinks its transparent
311             QPainter painter(&qtDrawable);
312             painter.fillRect(exposedRect, Qt::white);
313         }
314 
315         if (syncX)
316             QApplication::syncX();
317     }
318 
319     XEvent xevent;
320     memset(&xevent, 0, sizeof(XEvent));
321     XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
322     exposeEvent.type = GraphicsExpose;
323     exposeEvent.display = QX11Info::display();
324     exposeEvent.drawable = qtDrawable.handle();
325     exposeEvent.x = exposedRect.x();
326     exposeEvent.y = exposedRect.y();
327     exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode
328     exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode
329 
330     dispatchNPEvent(xevent);
331 
332     if (syncX)
333         XSync(m_pluginDisplay, false); // sync changes by plugin
334 
335     painter->drawPixmap(QPoint(exposedRect.x(), exposedRect.y()), qtDrawable, exposedRect);
336 }
337 
paint(GraphicsContext * context,const IntRect & rect)338 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
339 {
340     if (!m_isStarted) {
341         paintMissingPluginIcon(context, rect);
342         return;
343     }
344 
345     if (context->paintingDisabled())
346         return;
347 
348     setNPWindowIfNeeded();
349 
350     if (m_isWindowed)
351         return;
352 
353 #if USE(ACCELERATED_COMPOSITING)
354     if (m_platformLayer)
355         return;
356 #endif
357 
358     if (!m_drawable
359 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
360         && m_image.isNull()
361 #endif
362        )
363         return;
364 
365     QPainter* painter = context->platformContext();
366     IntRect exposedRect(rect);
367     exposedRect.intersect(frameRect());
368     exposedRect.move(-frameRect().x(), -frameRect().y());
369 
370 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
371     if (!m_image.isNull()) {
372         paintUsingImageSurfaceExtension(painter, exposedRect);
373         return;
374     }
375 #endif
376 
377     painter->translate(frameRect().x(), frameRect().y());
378     paintUsingXPixmap(painter, exposedRect);
379     painter->translate(-frameRect().x(), -frameRect().y());
380 }
381 
382 // TODO: Unify across ports.
dispatchNPEvent(NPEvent & event)383 bool PluginView::dispatchNPEvent(NPEvent& event)
384 {
385     if (!m_plugin->pluginFuncs()->event)
386         return false;
387 
388     PluginView::setCurrentPluginView(this);
389 #if USE(JSC)
390     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
391 #endif
392     setCallingPlugin(true);
393     bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
394     setCallingPlugin(false);
395     PluginView::setCurrentPluginView(0);
396 
397     return accepted;
398 }
399 
setSharedXEventFields(XEvent * xEvent,QWidget * ownerWidget)400 void setSharedXEventFields(XEvent* xEvent, QWidget* ownerWidget)
401 {
402     xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server
403     xEvent->xany.send_event = false;
404     xEvent->xany.display = QX11Info::display();
405     // NOTE: event->xany.window doesn't always respond to the .window property of other XEvent's
406     // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify
407     // events; thus, this is right:
408     xEvent->xany.window = ownerWidget ? ownerWidget->window()->handle() : 0;
409 }
410 
initXEvent(XEvent * xEvent)411 void PluginView::initXEvent(XEvent* xEvent)
412 {
413     memset(xEvent, 0, sizeof(XEvent));
414 
415     QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
416     QWidget* ownerWidget = client ? client->ownerWidget() : 0;
417     setSharedXEventFields(xEvent, ownerWidget);
418 }
419 
setXKeyEventSpecificFields(XEvent * xEvent,KeyboardEvent * event)420 void setXKeyEventSpecificFields(XEvent* xEvent, KeyboardEvent* event)
421 {
422     const PlatformKeyboardEvent* keyEvent = event->keyEvent();
423 
424     xEvent->type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // ints as Qt unsets KeyPress and KeyRelease
425     xEvent->xkey.root = QX11Info::appRootWindow();
426     xEvent->xkey.subwindow = 0; // we have no child window
427     xEvent->xkey.time = event->timeStamp();
428     xEvent->xkey.state = keyEvent->nativeModifiers();
429     xEvent->xkey.keycode = keyEvent->nativeScanCode();
430 
431     // We may not have a nativeScanCode() if the key event is from DRT's eventsender. In that
432     // case fetch the XEvent's keycode from the event's text. The only
433     // place this keycode will be used is in webkit_test_plugin_handle_event().
434     // FIXME: Create Qt API so that we can set the appropriate keycode in DRT EventSender instead.
435     if (QWebPagePrivate::drtRun && !xEvent->xkey.keycode) {
436         QKeyEvent* qKeyEvent = keyEvent->qtEvent();
437         ASSERT(qKeyEvent);
438         QString keyText = qKeyEvent->text().left(1);
439         xEvent->xkey.keycode = XKeysymToKeycode(QX11Info::display(), XStringToKeysym(keyText.toUtf8().constData()));
440     }
441 
442     xEvent->xkey.same_screen = true;
443 
444     // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window
445     // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not
446     // set to their normal Xserver values. e.g. Key events don't have a position.
447     // source: https://developer.mozilla.org/en/NPEvent
448     xEvent->xkey.x = 0;
449     xEvent->xkey.y = 0;
450     xEvent->xkey.x_root = 0;
451     xEvent->xkey.y_root = 0;
452 }
453 
handleKeyboardEvent(KeyboardEvent * event)454 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
455 {
456     if (m_isWindowed)
457         return;
458 
459     if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent)
460         return;
461 
462     XEvent npEvent;
463     initXEvent(&npEvent);
464     setXKeyEventSpecificFields(&npEvent, event);
465 
466     if (!dispatchNPEvent(npEvent))
467         event->setDefaultHandled();
468 }
469 
inputEventState(MouseEvent * event)470 static unsigned int inputEventState(MouseEvent* event)
471 {
472     unsigned int state = 0;
473     if (event->ctrlKey())
474         state |= ControlMask;
475     if (event->shiftKey())
476         state |= ShiftMask;
477     if (event->altKey())
478         state |= Mod1Mask;
479     if (event->metaKey())
480         state |= Mod4Mask;
481     return state;
482 }
483 
setXButtonEventSpecificFields(XEvent * xEvent,MouseEvent * event,const IntPoint & postZoomPos)484 static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
485 {
486     XButtonEvent& xbutton = xEvent->xbutton;
487     xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease;
488     xbutton.root = QX11Info::appRootWindow();
489     xbutton.subwindow = 0;
490     xbutton.time = event->timeStamp();
491     xbutton.x = postZoomPos.x();
492     xbutton.y = postZoomPos.y();
493     xbutton.x_root = event->screenX();
494     xbutton.y_root = event->screenY();
495     xbutton.state = inputEventState(event);
496     switch (event->button()) {
497     case MiddleButton:
498         xbutton.button = Button2;
499         break;
500     case RightButton:
501         xbutton.button = Button3;
502         break;
503     case LeftButton:
504     default:
505         xbutton.button = Button1;
506         break;
507     }
508     xbutton.same_screen = true;
509 }
510 
setXMotionEventSpecificFields(XEvent * xEvent,MouseEvent * event,const IntPoint & postZoomPos)511 static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
512 {
513     XMotionEvent& xmotion = xEvent->xmotion;
514     xmotion.type = MotionNotify;
515     xmotion.root = QX11Info::appRootWindow();
516     xmotion.subwindow = 0;
517     xmotion.time = event->timeStamp();
518     xmotion.x = postZoomPos.x();
519     xmotion.y = postZoomPos.y();
520     xmotion.x_root = event->screenX();
521     xmotion.y_root = event->screenY();
522     xmotion.state = inputEventState(event);
523     xmotion.is_hint = NotifyNormal;
524     xmotion.same_screen = true;
525 }
526 
setXCrossingEventSpecificFields(XEvent * xEvent,MouseEvent * event,const IntPoint & postZoomPos)527 static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
528 {
529     XCrossingEvent& xcrossing = xEvent->xcrossing;
530     xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify;
531     xcrossing.root = QX11Info::appRootWindow();
532     xcrossing.subwindow = 0;
533     xcrossing.time = event->timeStamp();
534     xcrossing.x = postZoomPos.y();
535     xcrossing.y = postZoomPos.x();
536     xcrossing.x_root = event->screenX();
537     xcrossing.y_root = event->screenY();
538     xcrossing.state = inputEventState(event);
539     xcrossing.mode = NotifyNormal;
540     xcrossing.detail = NotifyDetailNone;
541     xcrossing.same_screen = true;
542     xcrossing.focus = false;
543 }
544 
handleMouseEvent(MouseEvent * event)545 void PluginView::handleMouseEvent(MouseEvent* event)
546 {
547     if (m_isWindowed)
548         return;
549 
550     if (event->button() == RightButton && m_plugin->quirks().contains(PluginQuirkIgnoreRightClickInWindowlessMode))
551         return;
552 
553     if (event->type() == eventNames().mousedownEvent) {
554         // Give focus to the plugin on click
555         if (Page* page = m_parentFrame->page())
556             page->focusController()->setActive(true);
557 
558         focusPluginElement();
559     }
560 
561     XEvent npEvent;
562     initXEvent(&npEvent);
563 
564     IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
565 
566     if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
567         setXButtonEventSpecificFields(&npEvent, event, postZoomPos);
568     else if (event->type() == eventNames().mousemoveEvent)
569         setXMotionEventSpecificFields(&npEvent, event, postZoomPos);
570     else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent)
571         setXCrossingEventSpecificFields(&npEvent, event, postZoomPos);
572     else
573         return;
574 
575     if (!dispatchNPEvent(npEvent))
576         event->setDefaultHandled();
577 }
578 
handleFocusInEvent()579 void PluginView::handleFocusInEvent()
580 {
581     XEvent npEvent;
582     initXEvent(&npEvent);
583 
584     XFocusChangeEvent& event = npEvent.xfocus;
585     event.type = 9; /* int as Qt unsets FocusIn */
586     event.mode = NotifyNormal;
587     event.detail = NotifyDetailNone;
588 
589     dispatchNPEvent(npEvent);
590 }
591 
handleFocusOutEvent()592 void PluginView::handleFocusOutEvent()
593 {
594     XEvent npEvent;
595     initXEvent(&npEvent);
596 
597     XFocusChangeEvent& event = npEvent.xfocus;
598     event.type = 10; /* int as Qt unsets FocusOut */
599     event.mode = NotifyNormal;
600     event.detail = NotifyDetailNone;
601 
602     dispatchNPEvent(npEvent);
603 }
604 
setParent(ScrollView * parent)605 void PluginView::setParent(ScrollView* parent)
606 {
607     Widget::setParent(parent);
608 
609     if (parent)
610         init();
611 }
612 
setNPWindowRect(const IntRect &)613 void PluginView::setNPWindowRect(const IntRect&)
614 {
615     if (!m_isWindowed)
616         setNPWindowIfNeeded();
617 }
618 
setNPWindowIfNeeded()619 void PluginView::setNPWindowIfNeeded()
620 {
621     if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
622         return;
623 
624     // If the plugin didn't load sucessfully, no point in calling setwindow
625     if (m_status != PluginStatusLoadedSuccessfully)
626         return;
627 
628     // On Unix, only call plugin if it's full-page or windowed
629     if (m_mode != NP_FULL && m_mode != NP_EMBED)
630         return;
631 
632     // Check if the platformPluginWidget still exists
633     if (m_isWindowed && !platformPluginWidget())
634         return;
635 
636     if (!m_hasPendingGeometryChange)
637         return;
638     m_hasPendingGeometryChange = false;
639 
640     if (m_isWindowed) {
641         platformPluginWidget()->setGeometry(m_windowRect);
642 
643         // Cut out areas of the plugin occluded by iframe shims
644         Vector<IntRect> cutOutRects;
645         QRegion clipRegion = QRegion(m_clipRect);
646         getPluginOcclusions(m_element, this->parent(), frameRect(), cutOutRects);
647         for (size_t i = 0; i < cutOutRects.size(); i++) {
648             cutOutRects[i].move(-frameRect().x(), -frameRect().y());
649             clipRegion = clipRegion.subtracted(QRegion(cutOutRects[i]));
650         }
651         // if setMask is set with an empty QRegion, no clipping will
652         // be performed, so in that case we hide the plugin view
653         platformPluginWidget()->setVisible(!clipRegion.isEmpty());
654         platformPluginWidget()->setMask(clipRegion);
655 
656         m_npWindow.x = m_windowRect.x();
657         m_npWindow.y = m_windowRect.y();
658     } else {
659         m_npWindow.x = 0;
660         m_npWindow.y = 0;
661     }
662 
663     // If the width or height are null, set the clipRect to null, indicating that
664     // the plugin is not visible/scrolled out.
665     if (!m_clipRect.width() || !m_clipRect.height()) {
666         m_npWindow.clipRect.left = 0;
667         m_npWindow.clipRect.right = 0;
668         m_npWindow.clipRect.top = 0;
669         m_npWindow.clipRect.bottom = 0;
670     } else {
671         // Clipping rectangle of the plug-in; the origin is the top left corner of the drawable or window.
672         m_npWindow.clipRect.left = m_npWindow.x + m_clipRect.x();
673         m_npWindow.clipRect.top = m_npWindow.y + m_clipRect.y();
674         m_npWindow.clipRect.right = m_npWindow.x + m_clipRect.x() + m_clipRect.width();
675         m_npWindow.clipRect.bottom = m_npWindow.y + m_clipRect.y() + m_clipRect.height();
676     }
677 
678     if (m_plugin->quirks().contains(PluginQuirkDontCallSetWindowMoreThanOnce)) {
679         // FLASH WORKAROUND: Only set initially. Multiple calls to
680         // setNPWindow() cause the plugin to crash in windowed mode.
681         if (!m_isWindowed || m_npWindow.width == -1 || m_npWindow.height == -1) {
682             m_npWindow.width = m_windowRect.width();
683             m_npWindow.height = m_windowRect.height();
684         }
685     } else {
686         m_npWindow.width = m_windowRect.width();
687         m_npWindow.height = m_windowRect.height();
688     }
689 
690     PluginView::setCurrentPluginView(this);
691 #if USE(JSC)
692     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
693 #endif
694     setCallingPlugin(true);
695     m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
696     setCallingPlugin(false);
697     PluginView::setCurrentPluginView(0);
698 }
699 
setParentVisible(bool visible)700 void PluginView::setParentVisible(bool visible)
701 {
702     if (isParentVisible() == visible)
703         return;
704 
705     Widget::setParentVisible(visible);
706 
707     if (isSelfVisible() && platformPluginWidget())
708         platformPluginWidget()->setVisible(visible);
709 }
710 
handlePostReadFile(Vector<char> & buffer,uint32_t len,const char * buf)711 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
712 {
713     String filename(buf, len);
714 
715     if (filename.startsWith("file:///"))
716         filename = filename.substring(8);
717 
718     long long size;
719     if (!getFileSize(filename, size))
720         return NPERR_FILE_NOT_FOUND;
721 
722     FILE* fileHandle = fopen((filename.utf8()).data(), "r");
723     if (!fileHandle)
724         return NPERR_FILE_NOT_FOUND;
725 
726     buffer.resize(size);
727     int bytesRead = fread(buffer.data(), 1, size, fileHandle);
728 
729     fclose(fileHandle);
730 
731     if (bytesRead <= 0)
732         return NPERR_FILE_NOT_FOUND;
733 
734     return NPERR_NO_ERROR;
735 }
736 
platformGetValueStatic(NPNVariable variable,void * value,NPError * result)737 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
738 {
739     switch (variable) {
740     case NPNVToolkit:
741         *static_cast<uint32_t*>(value) = 0;
742         *result = NPERR_NO_ERROR;
743         return true;
744 
745     case NPNVSupportsXEmbedBool:
746         *static_cast<NPBool*>(value) = true;
747         *result = NPERR_NO_ERROR;
748         return true;
749 
750     case NPNVjavascriptEnabledBool:
751         *static_cast<NPBool*>(value) = true;
752         *result = NPERR_NO_ERROR;
753         return true;
754 
755     case NPNVSupportsWindowless:
756         *static_cast<NPBool*>(value) = true;
757         *result = NPERR_NO_ERROR;
758         return true;
759 
760 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
761     case NPNVSupportsWindowlessLocal:
762         *static_cast<NPBool*>(value) = true;
763         *result = NPERR_NO_ERROR;
764         return true;
765 #endif
766 
767     default:
768         return false;
769     }
770 }
771 
platformGetValue(NPNVariable variable,void * value,NPError * result)772 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
773 {
774     switch (variable) {
775     case NPNVxDisplay:
776         *(void **)value = QX11Info::display();
777         *result = NPERR_NO_ERROR;
778         return true;
779 
780     case NPNVxtAppContext:
781         *result = NPERR_GENERIC_ERROR;
782         return true;
783 
784     case NPNVnetscapeWindow: {
785         void* w = reinterpret_cast<void*>(value);
786         QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
787         *((XID *)w) = client ? client->ownerWidget()->window()->winId() : 0;
788         *result = NPERR_NO_ERROR;
789         return true;
790     }
791 
792     case NPNVToolkit:
793         if (m_plugin->quirks().contains(PluginQuirkRequiresGtkToolKit)) {
794             *((uint32_t *)value) = 2;
795             *result = NPERR_NO_ERROR;
796             return true;
797         }
798         return false;
799 
800     default:
801         return false;
802     }
803 }
804 
invalidateRect(const IntRect & rect)805 void PluginView::invalidateRect(const IntRect& rect)
806 {
807 #if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER)
808     if (m_platformLayer) {
809         m_platformLayer->update(QRectF(rect));
810         return;
811     }
812 #endif
813 
814     if (m_isWindowed) {
815         if (platformWidget()) {
816             // update() will schedule a repaint of the widget so ensure
817             // its knowledge of its position on the page is up to date.
818             platformWidget()->setGeometry(m_windowRect);
819             platformWidget()->update(rect);
820         }
821         return;
822     }
823 
824     invalidateWindowlessPluginRect(rect);
825 }
826 
invalidateRect(NPRect * rect)827 void PluginView::invalidateRect(NPRect* rect)
828 {
829     if (!rect) {
830         invalidate();
831         return;
832     }
833     IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
834     invalidateRect(r);
835 }
836 
invalidateRegion(NPRegion region)837 void PluginView::invalidateRegion(NPRegion region)
838 {
839     Q_UNUSED(region);
840     invalidate();
841 }
842 
forceRedraw()843 void PluginView::forceRedraw()
844 {
845     invalidate();
846 }
847 
getPluginDisplay()848 static Display *getPluginDisplay()
849 {
850     // The plugin toolkit might run using a different X connection. At the moment, we only
851     // support gdk based plugins (like flash) that use a different X connection.
852     // The code below has the same effect as this one:
853     // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
854     QLibrary library(QLatin1String("libgdk-x11-2.0"), 0);
855     if (!library.load())
856         return 0;
857 
858     typedef void *(*gdk_display_get_default_ptr)();
859     gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default");
860     if (!gdk_display_get_default)
861         return 0;
862 
863     typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *);
864     gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay");
865     if (!gdk_x11_display_get_xdisplay)
866         return 0;
867 
868     return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default());
869 }
870 
getVisualAndColormap(int depth,Visual ** visual,Colormap * colormap)871 static void getVisualAndColormap(int depth, Visual **visual, Colormap *colormap)
872 {
873     *visual = 0;
874     *colormap = 0;
875 
876 #ifndef QT_NO_XRENDER
877     static const bool useXRender = qgetenv("QT_X11_NO_XRENDER").isNull(); // Should also check for XRender >= 0.5
878 #else
879     static const bool useXRender = false;
880 #endif
881 
882     if (!useXRender && depth == 32)
883         return;
884 
885     int nvi;
886     XVisualInfo templ;
887     templ.screen  = QX11Info::appScreen();
888     templ.depth   = depth;
889     templ.c_class = TrueColor;
890     XVisualInfo* xvi = XGetVisualInfo(QX11Info::display(), VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi);
891 
892     if (!xvi)
893         return;
894 
895 #ifndef QT_NO_XRENDER
896     if (depth == 32) {
897         for (int idx = 0; idx < nvi; ++idx) {
898             XRenderPictFormat* format = XRenderFindVisualFormat(QX11Info::display(), xvi[idx].visual);
899             if (format->type == PictTypeDirect && format->direct.alphaMask) {
900                  *visual = xvi[idx].visual;
901                  break;
902             }
903          }
904     } else
905 #endif // QT_NO_XRENDER
906         *visual = xvi[0].visual;
907 
908     XFree(xvi);
909 
910     if (*visual)
911         *colormap = XCreateColormap(QX11Info::display(), QX11Info::appRootWindow(), *visual, AllocNone);
912 }
913 
platformStart()914 bool PluginView::platformStart()
915 {
916     ASSERT(m_isStarted);
917     ASSERT(m_status == PluginStatusLoadedSuccessfully);
918 
919     if (m_plugin->pluginFuncs()->getvalue) {
920         PluginView::setCurrentPluginView(this);
921 #if USE(JSC)
922         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
923 #endif
924         setCallingPlugin(true);
925         m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed);
926         setCallingPlugin(false);
927         PluginView::setCurrentPluginView(0);
928     }
929 
930     if (m_isWindowed) {
931         QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
932         if (m_needsXEmbed && client) {
933             setPlatformWidget(new PluginContainerQt(this, client->ownerWidget()));
934             // sync our XEmbed container window creation before sending the xid to plugins.
935             QApplication::syncX();
936         } else {
937             notImplemented();
938             m_status = PluginStatusCanNotLoadPlugin;
939             return false;
940         }
941     } else {
942         setPlatformWidget(0);
943         m_pluginDisplay = getPluginDisplay();
944 
945 #if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER)
946         if (m_parentFrame->page()->chrome()->client()->allowsAcceleratedCompositing()
947             && m_parentFrame->page()->settings()
948             && m_parentFrame->page()->settings()->acceleratedCompositingEnabled()) {
949             m_platformLayer = new PluginGraphicsLayerQt(this);
950             // Trigger layer computation in RenderLayerCompositor
951             m_element->setNeedsStyleRecalc(SyntheticStyleChange);
952         }
953 #endif
954     }
955 
956     // If the width and the height are not zero we show the PluginView.
957     if (!frameRect().isEmpty())
958         show();
959 
960     NPSetWindowCallbackStruct* wsi = new NPSetWindowCallbackStruct();
961     wsi->type = 0;
962 
963     if (m_isWindowed) {
964         const QX11Info* x11Info = &platformPluginWidget()->x11Info();
965 
966         wsi->display = x11Info->display();
967         wsi->visual = (Visual*)x11Info->visual();
968         wsi->depth = x11Info->depth();
969         wsi->colormap = x11Info->colormap();
970 
971         m_npWindow.type = NPWindowTypeWindow;
972         m_npWindow.window = (void*)platformPluginWidget()->winId();
973         m_npWindow.width = -1;
974         m_npWindow.height = -1;
975     } else {
976         const QX11Info* x11Info = &QApplication::desktop()->x11Info();
977 
978         if (x11Info->depth() == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) {
979             getVisualAndColormap(32, &m_visual, &m_colormap);
980             wsi->depth = 32;
981         }
982 
983         if (!m_visual) {
984             getVisualAndColormap(x11Info->depth(), &m_visual, &m_colormap);
985             wsi->depth = x11Info->depth();
986         }
987 
988         wsi->display = x11Info->display();
989         wsi->visual = m_visual;
990         wsi->colormap = m_colormap;
991 
992         m_npWindow.type = NPWindowTypeDrawable;
993         m_npWindow.window = 0; // Not used?
994         m_npWindow.x = 0;
995         m_npWindow.y = 0;
996         m_npWindow.width = -1;
997         m_npWindow.height = -1;
998     }
999 
1000     m_npWindow.ws_info = wsi;
1001 
1002     if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) {
1003         updatePluginWidget();
1004         setNPWindowIfNeeded();
1005     }
1006 
1007     return true;
1008 }
1009 
platformDestroy()1010 void PluginView::platformDestroy()
1011 {
1012     if (platformPluginWidget())
1013         delete platformPluginWidget();
1014 
1015     if (m_drawable)
1016         XFreePixmap(QX11Info::display(), m_drawable);
1017 
1018     if (m_colormap)
1019         XFreeColormap(QX11Info::display(), m_colormap);
1020 }
1021 
halt()1022 void PluginView::halt()
1023 {
1024 }
1025 
restart()1026 void PluginView::restart()
1027 {
1028 }
1029 
1030 #if USE(ACCELERATED_COMPOSITING)
platformLayer() const1031 PlatformLayer* PluginView::platformLayer() const
1032 {
1033     return m_platformLayer.get();
1034 }
1035 #endif
1036 
1037 } // namespace WebCore
1038