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