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