Home | History | Annotate | Download | only in qt
      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 (at) 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:
    112     PluginGraphicsLayerQt(PluginView* view) : m_view(view) { }
    113     ~PluginGraphicsLayerQt() { }
    114 
    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 
    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 
    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 
    199 void PluginView::show()
    200 {
    201     Q_ASSERT(platformPluginWidget() == platformWidget());
    202     Widget::show();
    203 }
    204 
    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)
    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 
    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 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    605 void PluginView::setParent(ScrollView* parent)
    606 {
    607     Widget::setParent(parent);
    608 
    609     if (parent)
    610         init();
    611 }
    612 
    613 void PluginView::setNPWindowRect(const IntRect&)
    614 {
    615     if (!m_isWindowed)
    616         setNPWindowIfNeeded();
    617 }
    618 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    837 void PluginView::invalidateRegion(NPRegion region)
    838 {
    839     Q_UNUSED(region);
    840     invalidate();
    841 }
    842 
    843 void PluginView::forceRedraw()
    844 {
    845     invalidate();
    846 }
    847 
    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 
    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 
    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 
   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 
   1022 void PluginView::halt()
   1023 {
   1024 }
   1025 
   1026 void PluginView::restart()
   1027 {
   1028 }
   1029 
   1030 #if USE(ACCELERATED_COMPOSITING)
   1031 PlatformLayer* PluginView::platformLayer() const
   1032 {
   1033     return m_platformLayer.get();
   1034 }
   1035 #endif
   1036 
   1037 } // namespace WebCore
   1038