Home | History | Annotate | Download | only in gtk
      1 /*
      2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2008 Collabora Ltd. All rights reserved.
      4  * Copyright (C) 2009, 2010 Kakai, Inc. <brian (at) kakai.com>
      5  * Copyright (C) 2010 Igalia S.L.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 #include "PluginView.h"
     31 
     32 #include "BridgeJSC.h"
     33 #include "Document.h"
     34 #include "DocumentLoader.h"
     35 #include "Element.h"
     36 #include "FocusController.h"
     37 #include "FrameLoader.h"
     38 #include "FrameLoadRequest.h"
     39 #include "FrameTree.h"
     40 #include "Frame.h"
     41 #include "FrameView.h"
     42 #include "GraphicsContext.h"
     43 #include "GtkVersioning.h"
     44 #include "HTMLNames.h"
     45 #include "HTMLPlugInElement.h"
     46 #include "HostWindow.h"
     47 #include "Image.h"
     48 #include "KeyboardEvent.h"
     49 #include "MouseEvent.h"
     50 #include "NotImplemented.h"
     51 #include "Page.h"
     52 #include "PlatformContextCairo.h"
     53 #include "PlatformKeyboardEvent.h"
     54 #include "PlatformMouseEvent.h"
     55 #include "PluginDebug.h"
     56 #include "PluginMainThreadScheduler.h"
     57 #include "PluginPackage.h"
     58 #include "RenderLayer.h"
     59 #include "Settings.h"
     60 #include "JSDOMBinding.h"
     61 #include "ScriptController.h"
     62 #include "npruntime_impl.h"
     63 #include "runtime_root.h"
     64 #include <runtime/JSLock.h>
     65 #include <runtime/JSValue.h>
     66 
     67 #ifdef GTK_API_VERSION_2
     68 #include <gdkconfig.h>
     69 #endif
     70 #include <gtk/gtk.h>
     71 
     72 #if defined(XP_UNIX)
     73 #include "RefPtrCairo.h"
     74 #include "gtk2xtbin.h"
     75 #define Bool int // this got undefined somewhere
     76 #define Status int // ditto
     77 #include <X11/extensions/Xrender.h>
     78 #include <cairo/cairo-xlib.h>
     79 #include <gdk/gdkx.h>
     80 #elif defined(GDK_WINDOWING_WIN32)
     81 #include "PluginMessageThrottlerWin.h"
     82 #include <gdk/gdkwin32.h>
     83 #endif
     84 
     85 using JSC::ExecState;
     86 using JSC::Interpreter;
     87 using JSC::JSLock;
     88 using JSC::JSObject;
     89 using JSC::UString;
     90 
     91 using std::min;
     92 
     93 using namespace WTF;
     94 
     95 namespace WebCore {
     96 
     97 using namespace HTMLNames;
     98 
     99 bool PluginView::dispatchNPEvent(NPEvent& event)
    100 {
    101     // sanity check
    102     if (!m_plugin->pluginFuncs()->event)
    103         return false;
    104 
    105     PluginView::setCurrentPluginView(this);
    106     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    107     setCallingPlugin(true);
    108 
    109     bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
    110 
    111     setCallingPlugin(false);
    112     PluginView::setCurrentPluginView(0);
    113     return accepted;
    114 }
    115 
    116 #if defined(XP_UNIX)
    117 static Window getRootWindow(Frame* parentFrame)
    118 {
    119     GtkWidget* parentWidget = parentFrame->view()->hostWindow()->platformPageClient();
    120     GdkScreen* gscreen = gtk_widget_get_screen(parentWidget);
    121     return GDK_WINDOW_XWINDOW(gdk_screen_get_root_window(gscreen));
    122 }
    123 #endif
    124 
    125 void PluginView::updatePluginWidget()
    126 {
    127     if (!parent())
    128         return;
    129 
    130     ASSERT(parent()->isFrameView());
    131     FrameView* frameView = static_cast<FrameView*>(parent());
    132 
    133     IntRect oldWindowRect = m_windowRect;
    134     IntRect oldClipRect = m_clipRect;
    135 
    136     m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
    137     m_clipRect = windowClipRect();
    138     m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
    139 
    140     if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
    141         return;
    142 
    143 #if defined(XP_UNIX)
    144     if (!m_isWindowed) {
    145         Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
    146         if (m_drawable)
    147             XFreePixmap(display, m_drawable);
    148 
    149         m_drawable = XCreatePixmap(display, getRootWindow(m_parentFrame.get()),
    150                                    m_windowRect.width(), m_windowRect.height(),
    151                                    ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth);
    152         XSync(display, false); // make sure that the server knows about the Drawable
    153     }
    154 #endif
    155 
    156     setNPWindowIfNeeded();
    157 }
    158 
    159 void PluginView::setFocus(bool focused)
    160 {
    161     ASSERT(platformPluginWidget() == platformWidget());
    162     Widget::setFocus(focused);
    163 }
    164 
    165 void PluginView::show()
    166 {
    167     ASSERT(platformPluginWidget() == platformWidget());
    168     Widget::show();
    169 }
    170 
    171 void PluginView::hide()
    172 {
    173     ASSERT(platformPluginWidget() == platformWidget());
    174     Widget::hide();
    175 }
    176 
    177 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
    178 {
    179     if (!m_isStarted) {
    180         paintMissingPluginIcon(context, rect);
    181         return;
    182     }
    183 
    184     if (context->paintingDisabled())
    185         return;
    186 
    187     setNPWindowIfNeeded();
    188 
    189     if (m_isWindowed)
    190         return;
    191 
    192 #if defined(XP_UNIX)
    193     if (!m_drawable)
    194         return;
    195 
    196     Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
    197     const bool syncX = m_pluginDisplay && m_pluginDisplay != display;
    198 
    199     IntRect exposedRect(rect);
    200     exposedRect.intersect(frameRect());
    201     exposedRect.move(-frameRect().x(), -frameRect().y());
    202 
    203     RefPtr<cairo_surface_t> drawableSurface = adoptRef(cairo_xlib_surface_create(display,
    204                                                        m_drawable,
    205                                                        m_visual,
    206                                                        m_windowRect.width(),
    207                                                        m_windowRect.height()));
    208 
    209     if (m_isTransparent) {
    210         // If we have a 32 bit drawable and the plugin wants transparency,
    211         // we'll clear the exposed area to transparent first.  Otherwise,
    212         // we'd end up with junk in there from the last paint, or, worse,
    213         // uninitialized data.
    214         RefPtr<cairo_t> cr = adoptRef(cairo_create(drawableSurface.get()));
    215 
    216         if (!(cairo_surface_get_content(drawableSurface.get()) & CAIRO_CONTENT_ALPHA)) {
    217             // Attempt to fake it when we don't have an alpha channel on our
    218             // pixmap.  If that's not possible, at least clear the window to
    219             // avoid drawing artifacts.
    220 
    221             // This Would not work without double buffering, but we always use it.
    222             cairo_set_source_surface(cr.get(), cairo_get_group_target(context->platformContext()->cr()),
    223                                      -m_windowRect.x(), -m_windowRect.y());
    224             cairo_set_operator(cr.get(), CAIRO_OPERATOR_SOURCE);
    225         } else
    226             cairo_set_operator(cr.get(), CAIRO_OPERATOR_CLEAR);
    227 
    228         cairo_rectangle(cr.get(), exposedRect.x(), exposedRect.y(),
    229                         exposedRect.width(), exposedRect.height());
    230         cairo_fill(cr.get());
    231     }
    232 
    233     XEvent xevent;
    234     memset(&xevent, 0, sizeof(XEvent));
    235     XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
    236     exposeEvent.type = GraphicsExpose;
    237     exposeEvent.display = display;
    238     exposeEvent.drawable = m_drawable;
    239     exposeEvent.x = exposedRect.x();
    240     exposeEvent.y = exposedRect.y();
    241     exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode
    242     exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode
    243 
    244     dispatchNPEvent(xevent);
    245 
    246     if (syncX)
    247         XSync(m_pluginDisplay, false); // sync changes by plugin
    248 
    249     cairo_t* cr = context->platformContext()->cr();
    250     cairo_save(cr);
    251 
    252     cairo_set_source_surface(cr, drawableSurface.get(), frameRect().x(), frameRect().y());
    253 
    254     cairo_rectangle(cr,
    255                     frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y(),
    256                     exposedRect.width(), exposedRect.height());
    257     cairo_clip(cr);
    258 
    259     if (m_isTransparent)
    260         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
    261     else
    262         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
    263     cairo_paint(cr);
    264 
    265     cairo_restore(cr);
    266 #endif // defined(XP_UNIX)
    267 }
    268 
    269 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
    270 {
    271     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    272 
    273     if (m_isWindowed)
    274         return;
    275 
    276     if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent)
    277         return;
    278 
    279     NPEvent xEvent;
    280 #if defined(XP_UNIX)
    281     initXEvent(&xEvent);
    282     GdkEventKey* gdkEvent = event->keyEvent()->gdkEventKey();
    283 
    284     xEvent.type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // KeyPress/Release get unset somewhere
    285     xEvent.xkey.root = getRootWindow(m_parentFrame.get());
    286     xEvent.xkey.subwindow = 0; // we have no child window
    287     xEvent.xkey.time = event->timeStamp();
    288     xEvent.xkey.state = gdkEvent->state; // GdkModifierType mirrors xlib state masks
    289     xEvent.xkey.keycode = gdkEvent->hardware_keycode;
    290     xEvent.xkey.same_screen = true;
    291 
    292     // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window
    293     // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not
    294     // set to their normal Xserver values. e.g. Key events don't have a position.
    295     // source: https://developer.mozilla.org/en/NPEvent
    296     xEvent.xkey.x = 0;
    297     xEvent.xkey.y = 0;
    298     xEvent.xkey.x_root = 0;
    299     xEvent.xkey.y_root = 0;
    300 #endif
    301 
    302     if (!dispatchNPEvent(xEvent))
    303         event->setDefaultHandled();
    304 }
    305 
    306 #if defined(XP_UNIX)
    307 static unsigned int inputEventState(MouseEvent* event)
    308 {
    309     unsigned int state = 0;
    310     if (event->ctrlKey())
    311         state |= ControlMask;
    312     if (event->shiftKey())
    313         state |= ShiftMask;
    314     if (event->altKey())
    315         state |= Mod1Mask;
    316     if (event->metaKey())
    317         state |= Mod4Mask;
    318     return state;
    319 }
    320 
    321 void PluginView::initXEvent(XEvent* xEvent)
    322 {
    323     memset(xEvent, 0, sizeof(XEvent));
    324 
    325     xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server
    326     xEvent->xany.send_event = false;
    327     GtkWidget* widget = m_parentFrame->view()->hostWindow()->platformPageClient();
    328     xEvent->xany.display = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(widget));
    329 
    330     // Mozilla also sends None here for windowless plugins. See nsObjectFrame.cpp in the Mozilla sources.
    331     // This method also sets up FocusIn and FocusOut events for windows plugins, but Mozilla doesn't
    332     // even send these types of events to windowed plugins. In the future, it may be good to only
    333     // send them to windowless plugins.
    334     xEvent->xany.window = None;
    335 }
    336 
    337 static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
    338 {
    339     XButtonEvent& xbutton = xEvent->xbutton;
    340     xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease;
    341     xbutton.root = getRootWindow(parentFrame);
    342     xbutton.subwindow = 0;
    343     xbutton.time = event->timeStamp();
    344     xbutton.x = postZoomPos.x();
    345     xbutton.y = postZoomPos.y();
    346     xbutton.x_root = event->screenX();
    347     xbutton.y_root = event->screenY();
    348     xbutton.state = inputEventState(event);
    349     switch (event->button()) {
    350     case MiddleButton:
    351         xbutton.button = Button2;
    352         break;
    353     case RightButton:
    354         xbutton.button = Button3;
    355         break;
    356     case LeftButton:
    357     default:
    358         xbutton.button = Button1;
    359         break;
    360     }
    361     xbutton.same_screen = true;
    362 }
    363 
    364 static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
    365 {
    366     XMotionEvent& xmotion = xEvent->xmotion;
    367     xmotion.type = MotionNotify;
    368     xmotion.root = getRootWindow(parentFrame);
    369     xmotion.subwindow = 0;
    370     xmotion.time = event->timeStamp();
    371     xmotion.x = postZoomPos.x();
    372     xmotion.y = postZoomPos.y();
    373     xmotion.x_root = event->screenX();
    374     xmotion.y_root = event->screenY();
    375     xmotion.state = inputEventState(event);
    376     xmotion.is_hint = NotifyNormal;
    377     xmotion.same_screen = true;
    378 }
    379 
    380 static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
    381 {
    382     XCrossingEvent& xcrossing = xEvent->xcrossing;
    383     xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify;
    384     xcrossing.root = getRootWindow(parentFrame);
    385     xcrossing.subwindow = 0;
    386     xcrossing.time = event->timeStamp();
    387     xcrossing.x = postZoomPos.y();
    388     xcrossing.y = postZoomPos.x();
    389     xcrossing.x_root = event->screenX();
    390     xcrossing.y_root = event->screenY();
    391     xcrossing.state = inputEventState(event);
    392     xcrossing.mode = NotifyNormal;
    393     xcrossing.detail = NotifyDetailNone;
    394     xcrossing.same_screen = true;
    395     xcrossing.focus = false;
    396 }
    397 #endif
    398 
    399 void PluginView::handleMouseEvent(MouseEvent* event)
    400 {
    401     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    402 
    403     if (m_isWindowed)
    404         return;
    405 
    406     if (event->type() == eventNames().mousedownEvent) {
    407         if (Page* page = m_parentFrame->page())
    408             page->focusController()->setActive(true);
    409         focusPluginElement();
    410     }
    411 
    412     NPEvent xEvent;
    413 #if defined(XP_UNIX)
    414     initXEvent(&xEvent);
    415 
    416     IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
    417 
    418     if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
    419         setXButtonEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
    420     else if (event->type() == eventNames().mousemoveEvent)
    421         setXMotionEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
    422     else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent) {
    423         setXCrossingEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
    424 
    425         // This is a work-around for plugins which change the cursor. When that happens we
    426         // get out of sync with GDK somehow. Resetting the cursor here seems to fix the issue.
    427         if (event->type() == eventNames().mouseoutEvent)
    428             gdk_window_set_cursor(gtk_widget_get_window(m_parentFrame->view()->hostWindow()->platformPageClient()), 0);
    429     }
    430     else
    431         return;
    432 #endif
    433 
    434     if (!dispatchNPEvent(xEvent))
    435         event->setDefaultHandled();
    436 }
    437 
    438 #if defined(XP_UNIX)
    439 void PluginView::handleFocusInEvent()
    440 {
    441     XEvent npEvent;
    442     initXEvent(&npEvent);
    443 
    444     XFocusChangeEvent& event = npEvent.xfocus;
    445     event.type = 9; // FocusIn gets unset somewhere
    446     event.mode = NotifyNormal;
    447     event.detail = NotifyDetailNone;
    448 
    449     dispatchNPEvent(npEvent);
    450 }
    451 
    452 void PluginView::handleFocusOutEvent()
    453 {
    454     XEvent npEvent;
    455     initXEvent(&npEvent);
    456 
    457     XFocusChangeEvent& event = npEvent.xfocus;
    458     event.type = 10; // FocusOut gets unset somewhere
    459     event.mode = NotifyNormal;
    460     event.detail = NotifyDetailNone;
    461 
    462     dispatchNPEvent(npEvent);
    463 }
    464 #endif
    465 
    466 void PluginView::setParent(ScrollView* parent)
    467 {
    468     Widget::setParent(parent);
    469 
    470     if (parent)
    471         init();
    472 }
    473 
    474 void PluginView::setNPWindowRect(const IntRect&)
    475 {
    476     if (!m_isWindowed)
    477         setNPWindowIfNeeded();
    478 }
    479 
    480 void PluginView::setNPWindowIfNeeded()
    481 {
    482     if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
    483         return;
    484 
    485     // If the plugin didn't load sucessfully, no point in calling setwindow
    486     if (m_status != PluginStatusLoadedSuccessfully)
    487         return;
    488 
    489     // On Unix, only call plugin's setwindow if it's full-page or windowed
    490     if (m_mode != NP_FULL && m_mode != NP_EMBED)
    491         return;
    492 
    493     // Check if the platformPluginWidget still exists
    494     if (m_isWindowed && !platformPluginWidget())
    495         return;
    496 
    497     if (m_isWindowed) {
    498         m_npWindow.x = m_windowRect.x();
    499         m_npWindow.y = m_windowRect.y();
    500         m_npWindow.width = m_windowRect.width();
    501         m_npWindow.height = m_windowRect.height();
    502 
    503         m_npWindow.clipRect.left = max(0, m_clipRect.x());
    504         m_npWindow.clipRect.top = max(0, m_clipRect.y());
    505         m_npWindow.clipRect.right = m_clipRect.x() + m_clipRect.width();
    506         m_npWindow.clipRect.bottom = m_clipRect.y() + m_clipRect.height();
    507     } else {
    508         m_npWindow.x = 0;
    509         m_npWindow.y = 0;
    510         m_npWindow.width = m_windowRect.width();
    511         m_npWindow.height = m_windowRect.height();
    512 
    513         m_npWindow.clipRect.left = 0;
    514         m_npWindow.clipRect.top = 0;
    515         m_npWindow.clipRect.right = 0;
    516         m_npWindow.clipRect.bottom = 0;
    517     }
    518 
    519     PluginView::setCurrentPluginView(this);
    520     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    521     setCallingPlugin(true);
    522     m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
    523     setCallingPlugin(false);
    524     PluginView::setCurrentPluginView(0);
    525 
    526     if (!m_isWindowed)
    527         return;
    528 
    529 #if defined(XP_UNIX)
    530     // GtkXtBin will call gtk_widget_size_allocate, so we don't need to do it here.
    531     if (!m_needsXEmbed) {
    532         gtk_xtbin_set_position(GTK_XTBIN(platformPluginWidget()), m_windowRect.x(), m_windowRect.y());
    533         gtk_xtbin_resize(platformPluginWidget(), m_windowRect.width(), m_windowRect.height());
    534         return;
    535     }
    536 #endif
    537 
    538     GtkAllocation allocation = { m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height() };
    539 
    540     // If the window has not been embedded yet (the plug added), we delay setting its allocation until
    541     // that point. This fixes issues with some Java plugin instances not rendering immediately.
    542     if (!m_plugAdded) {
    543         m_delayedAllocation = allocation;
    544         return;
    545     }
    546     gtk_widget_size_allocate(platformPluginWidget(), &allocation);
    547 }
    548 
    549 void PluginView::setParentVisible(bool visible)
    550 {
    551     if (isParentVisible() == visible)
    552         return;
    553 
    554     Widget::setParentVisible(visible);
    555 
    556     if (isSelfVisible() && platformPluginWidget()) {
    557         if (visible)
    558             gtk_widget_show(platformPluginWidget());
    559         else
    560             gtk_widget_hide(platformPluginWidget());
    561     }
    562 }
    563 
    564 NPError PluginView::handlePostReadFile(Vector<char>& outputBuffer, uint32_t filenameLength, const char* filenameBuffer)
    565 {
    566     // There doesn't seem to be any documentation about what encoding the filename
    567     // is in, but most ports seem to assume UTF-8 here and the test plugin is definitely
    568     // sending the path in UTF-8 encoding.
    569     CString filename(filenameBuffer, filenameLength);
    570 
    571     GRefPtr<GFile> file = adoptGRef(g_file_new_for_commandline_arg(filename.data()));
    572     if (g_file_query_file_type(file.get(), G_FILE_QUERY_INFO_NONE, 0) != G_FILE_TYPE_REGULAR)
    573         return NPERR_FILE_NOT_FOUND;
    574 
    575     GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_info(file.get(),
    576                                                               G_FILE_ATTRIBUTE_STANDARD_SIZE,
    577                                                               G_FILE_QUERY_INFO_NONE,
    578                                                               0, 0));
    579     if (!fileInfo)
    580         return NPERR_FILE_NOT_FOUND;
    581 
    582     GRefPtr<GFileInputStream> inputStream = adoptGRef(g_file_read(file.get(), 0, 0));
    583     if (!inputStream)
    584         return NPERR_FILE_NOT_FOUND;
    585 
    586     outputBuffer.resize(g_file_info_get_size(fileInfo.get()));
    587     gsize bytesRead = 0;
    588     if (!g_input_stream_read_all(G_INPUT_STREAM(inputStream.get()),
    589                                  outputBuffer.data(), outputBuffer.size(), &bytesRead, 0, 0))
    590         return NPERR_FILE_NOT_FOUND;
    591 
    592     return NPERR_NO_ERROR;
    593 }
    594 
    595 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
    596 {
    597     switch (variable) {
    598     case NPNVToolkit:
    599 #if defined(XP_UNIX)
    600         *static_cast<uint32_t*>(value) = 2;
    601 #else
    602         *static_cast<uint32_t*>(value) = 0;
    603 #endif
    604         *result = NPERR_NO_ERROR;
    605         return true;
    606 
    607     case NPNVSupportsXEmbedBool:
    608 #if defined(XP_UNIX)
    609         *static_cast<NPBool*>(value) = true;
    610 #else
    611         *static_cast<NPBool*>(value) = false;
    612 #endif
    613         *result = NPERR_NO_ERROR;
    614         return true;
    615 
    616     case NPNVjavascriptEnabledBool:
    617         *static_cast<NPBool*>(value) = true;
    618         *result = NPERR_NO_ERROR;
    619         return true;
    620 
    621     case NPNVSupportsWindowless:
    622 #if defined(XP_UNIX)
    623         *static_cast<NPBool*>(value) = true;
    624 #else
    625         *static_cast<NPBool*>(value) = false;
    626 #endif
    627         *result = NPERR_NO_ERROR;
    628         return true;
    629 
    630     default:
    631         return false;
    632     }
    633 }
    634 
    635 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
    636 {
    637     switch (variable) {
    638     case NPNVxDisplay:
    639 #if defined(XP_UNIX)
    640         if (m_needsXEmbed)
    641             *(void **)value = (void *)GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
    642         else
    643             *(void **)value = (void *)GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay;
    644         *result = NPERR_NO_ERROR;
    645 #else
    646         *result = NPERR_GENERIC_ERROR;
    647 #endif
    648         return true;
    649 
    650 #if defined(XP_UNIX)
    651     case NPNVxtAppContext:
    652         if (!m_needsXEmbed) {
    653             *(void **)value = XtDisplayToApplicationContext (GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay);
    654 
    655             *result = NPERR_NO_ERROR;
    656         } else
    657             *result = NPERR_GENERIC_ERROR;
    658         return true;
    659 #endif
    660 
    661         case NPNVnetscapeWindow: {
    662             GdkWindow* gdkWindow = gtk_widget_get_window(m_parentFrame->view()->hostWindow()->platformPageClient());
    663 #if defined(XP_UNIX)
    664             *static_cast<Window*>(value) = GDK_WINDOW_XWINDOW(gdk_window_get_toplevel(gdkWindow));
    665 #elif defined(GDK_WINDOWING_WIN32)
    666             *static_cast<HGDIOBJ*>(value) = GDK_WINDOW_HWND(gdkWindow);
    667 #endif
    668             *result = NPERR_NO_ERROR;
    669             return true;
    670         }
    671 
    672     default:
    673         return false;
    674     }
    675 }
    676 
    677 void PluginView::invalidateRect(const IntRect& rect)
    678 {
    679     if (m_isWindowed) {
    680         gtk_widget_queue_draw_area(GTK_WIDGET(platformPluginWidget()), rect.x(), rect.y(), rect.width(), rect.height());
    681         return;
    682     }
    683 
    684     invalidateWindowlessPluginRect(rect);
    685 }
    686 
    687 void PluginView::invalidateRect(NPRect* rect)
    688 {
    689     if (!rect) {
    690         invalidate();
    691         return;
    692     }
    693 
    694     IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
    695     invalidateWindowlessPluginRect(r);
    696 }
    697 
    698 void PluginView::invalidateRegion(NPRegion)
    699 {
    700     // TODO: optimize
    701     invalidate();
    702 }
    703 
    704 void PluginView::forceRedraw()
    705 {
    706     if (m_isWindowed)
    707         gtk_widget_queue_draw(platformPluginWidget());
    708     else
    709         gtk_widget_queue_draw(m_parentFrame->view()->hostWindow()->platformPageClient());
    710 }
    711 
    712 #ifndef GDK_WINDOWING_WIN32
    713 static Display* getPluginDisplay()
    714 {
    715     // The plugin toolkit might have a different X connection open.  Since we're
    716     // a gdk/gtk app, we'll (probably?) have the same X connection as any gdk-based
    717     // plugins, so we can return that.  We might want to add other implementations here
    718     // later.
    719 
    720 #if defined(XP_UNIX)
    721     return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
    722 #else
    723     return 0;
    724 #endif
    725 }
    726 #endif
    727 
    728 #if defined(XP_UNIX)
    729 static void getVisualAndColormap(int depth, Visual** visual, Colormap* colormap)
    730 {
    731     *visual = 0;
    732     *colormap = 0;
    733 
    734     Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
    735     int rmaj, rmin;
    736     if (depth == 32 && (!XRenderQueryVersion(display, &rmaj, &rmin) || (rmaj == 0 && rmin < 5)))
    737         return;
    738 
    739     XVisualInfo templ;
    740     templ.screen  = gdk_screen_get_number(gdk_screen_get_default());
    741     templ.depth   = depth;
    742     templ.c_class = TrueColor;
    743     int nVisuals;
    744     XVisualInfo* visualInfo = XGetVisualInfo(display, VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nVisuals);
    745 
    746     if (!nVisuals)
    747         return;
    748 
    749     if (depth == 32) {
    750         for (int idx = 0; idx < nVisuals; ++idx) {
    751             XRenderPictFormat* format = XRenderFindVisualFormat(display, visualInfo[idx].visual);
    752             if (format->type == PictTypeDirect && format->direct.alphaMask) {
    753                  *visual = visualInfo[idx].visual;
    754                  break;
    755             }
    756          }
    757     } else
    758         *visual = visualInfo[0].visual;
    759 
    760     XFree(visualInfo);
    761 
    762     if (*visual)
    763         *colormap = XCreateColormap(display, GDK_ROOT_WINDOW(), *visual, AllocNone);
    764 }
    765 #endif
    766 
    767 gboolean PluginView::plugRemovedCallback(GtkSocket* socket, PluginView* view)
    768 {
    769     view->m_plugAdded = false;
    770     return TRUE;
    771 }
    772 
    773 void PluginView::plugAddedCallback(GtkSocket* socket, PluginView* view)
    774 {
    775     ASSERT(socket);
    776     ASSERT(view);
    777 
    778     view->m_plugAdded = true;
    779     if (!view->m_delayedAllocation.isEmpty()) {
    780         GtkAllocation allocation(view->m_delayedAllocation);
    781         gtk_widget_size_allocate(GTK_WIDGET(socket), &allocation);
    782         view->m_delayedAllocation.setSize(IntSize());
    783     }
    784 }
    785 
    786 bool PluginView::platformStart()
    787 {
    788     ASSERT(m_isStarted);
    789     ASSERT(m_status == PluginStatusLoadedSuccessfully);
    790 
    791 #if defined(XP_UNIX)
    792     if (m_plugin->pluginFuncs()->getvalue) {
    793         PluginView::setCurrentPluginView(this);
    794         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    795         setCallingPlugin(true);
    796         m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed);
    797         setCallingPlugin(false);
    798         PluginView::setCurrentPluginView(0);
    799     }
    800 #endif
    801 
    802     if (m_isWindowed) {
    803         GtkWidget* pageClient = m_parentFrame->view()->hostWindow()->platformPageClient();
    804 #if defined(XP_UNIX)
    805         if (m_needsXEmbed) {
    806             // If our parent is not anchored the startup process will
    807             // fail miserably for XEmbed plugins a bit later on when
    808             // we try to get the ID of our window (since realize will
    809             // fail), so let's just abort here.
    810             if (!gtk_widget_get_parent(pageClient))
    811                 return false;
    812 
    813             m_plugAdded = false;
    814             setPlatformWidget(gtk_socket_new());
    815             gtk_container_add(GTK_CONTAINER(pageClient), platformPluginWidget());
    816             g_signal_connect(platformPluginWidget(), "plug-added", G_CALLBACK(PluginView::plugAddedCallback), this);
    817             g_signal_connect(platformPluginWidget(), "plug-removed", G_CALLBACK(PluginView::plugRemovedCallback), this);
    818         } else
    819             setPlatformWidget(gtk_xtbin_new(pageClient, 0));
    820 #else
    821         setPlatformWidget(gtk_socket_new());
    822         gtk_container_add(GTK_CONTAINER(pageClient), platformPluginWidget());
    823 #endif
    824     } else {
    825         setPlatformWidget(0);
    826 #if defined(XP_UNIX)
    827         m_pluginDisplay = getPluginDisplay();
    828 #endif
    829     }
    830 
    831     show();
    832 
    833 #if defined(XP_UNIX)
    834         NPSetWindowCallbackStruct* ws = new NPSetWindowCallbackStruct();
    835         ws->type = 0;
    836 #endif
    837 
    838     if (m_isWindowed) {
    839         m_npWindow.type = NPWindowTypeWindow;
    840 #if defined(XP_UNIX)
    841         if (m_needsXEmbed) {
    842             GtkWidget* widget = platformPluginWidget();
    843             gtk_widget_realize(widget);
    844             m_npWindow.window = (void*)gtk_socket_get_id(GTK_SOCKET(platformPluginWidget()));
    845             GdkWindow* window = gtk_widget_get_window(widget);
    846             ws->display = GDK_WINDOW_XDISPLAY(window);
    847             ws->visual = GDK_VISUAL_XVISUAL(gdk_window_get_visual(window));
    848             ws->depth = gdk_visual_get_depth(gdk_window_get_visual(window));
    849             ws->colormap = XCreateColormap(ws->display, GDK_ROOT_WINDOW(), ws->visual, AllocNone);
    850         } else {
    851             m_npWindow.window = (void*)GTK_XTBIN(platformPluginWidget())->xtwindow;
    852             ws->display = GTK_XTBIN(platformPluginWidget())->xtdisplay;
    853             ws->visual = GTK_XTBIN(platformPluginWidget())->xtclient.xtvisual;
    854             ws->depth = GTK_XTBIN(platformPluginWidget())->xtclient.xtdepth;
    855             ws->colormap = GTK_XTBIN(platformPluginWidget())->xtclient.xtcolormap;
    856         }
    857         XFlush (ws->display);
    858 #elif defined(GDK_WINDOWING_WIN32)
    859         m_npWindow.window = (void*)GDK_WINDOW_HWND(gtk_widget_get_window(platformPluginWidget()));
    860 #endif
    861     } else {
    862         m_npWindow.type = NPWindowTypeDrawable;
    863         m_npWindow.window = 0; // Not used?
    864 
    865 #if defined(XP_UNIX)
    866         GdkScreen* gscreen = gdk_screen_get_default();
    867         GdkVisual* gvisual = gdk_screen_get_system_visual(gscreen);
    868 
    869         if (gdk_visual_get_depth(gvisual) == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) {
    870             getVisualAndColormap(32, &m_visual, &m_colormap);
    871             ws->depth = 32;
    872         }
    873 
    874         if (!m_visual) {
    875             getVisualAndColormap(gdk_visual_get_depth(gvisual), &m_visual, &m_colormap);
    876             ws->depth = gdk_visual_get_depth(gvisual);
    877         }
    878 
    879         ws->display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
    880         ws->visual = m_visual;
    881         ws->colormap = m_colormap;
    882 
    883         m_npWindow.x = 0;
    884         m_npWindow.y = 0;
    885         m_npWindow.width = -1;
    886         m_npWindow.height = -1;
    887 #else
    888         notImplemented();
    889         m_status = PluginStatusCanNotLoadPlugin;
    890         return false;
    891 #endif
    892     }
    893 
    894 #if defined(XP_UNIX)
    895     m_npWindow.ws_info = ws;
    896 #endif
    897 
    898     // TODO remove in favor of null events, like mac port?
    899     if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall)))
    900         updatePluginWidget(); // was: setNPWindowIfNeeded(), but this doesn't produce 0x0 rects at first go
    901 
    902     return true;
    903 }
    904 
    905 void PluginView::platformDestroy()
    906 {
    907 #if defined(XP_UNIX)
    908     if (m_drawable) {
    909         XFreePixmap(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), m_drawable);
    910         m_drawable = 0;
    911     }
    912 #endif
    913 }
    914 
    915 void PluginView::halt()
    916 {
    917 }
    918 
    919 void PluginView::restart()
    920 {
    921 }
    922 
    923 } // namespace WebCore
    924