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  *
      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 "FrameLoader.h"
     36 #include "FrameLoadRequest.h"
     37 #include "FrameTree.h"
     38 #include "Frame.h"
     39 #include "FrameView.h"
     40 #include "GraphicsContext.h"
     41 #include "HTMLNames.h"
     42 #include "HTMLPlugInElement.h"
     43 #include "HostWindow.h"
     44 #include "Image.h"
     45 #include "KeyboardEvent.h"
     46 #include "MouseEvent.h"
     47 #include "Page.h"
     48 #include "PlatformKeyboardEvent.h"
     49 #include "PlatformMouseEvent.h"
     50 #include "PluginDebug.h"
     51 #include "PluginMainThreadScheduler.h"
     52 #include "PluginPackage.h"
     53 #include "RenderLayer.h"
     54 #include "Settings.h"
     55 #include "JSDOMBinding.h"
     56 #include "ScriptController.h"
     57 #include "npruntime_impl.h"
     58 #include "runtime_root.h"
     59 #include <runtime/JSLock.h>
     60 #include <runtime/JSValue.h>
     61 
     62 #include <gdkconfig.h>
     63 #include <gtk/gtk.h>
     64 
     65 #if defined(XP_UNIX)
     66 #include "gtk2xtbin.h"
     67 #define Bool int // this got undefined somewhere
     68 #define Status int // ditto
     69 #include <X11/extensions/Xrender.h>
     70 #include <cairo/cairo-xlib.h>
     71 #include <gdk/gdkx.h>
     72 #elif defined(GDK_WINDOWING_WIN32)
     73 #include "PluginMessageThrottlerWin.h"
     74 #include <gdk/gdkwin32.h>
     75 #endif
     76 
     77 using JSC::ExecState;
     78 using JSC::Interpreter;
     79 using JSC::JSLock;
     80 using JSC::JSObject;
     81 using JSC::UString;
     82 
     83 using std::min;
     84 
     85 using namespace WTF;
     86 
     87 namespace WebCore {
     88 
     89 using namespace HTMLNames;
     90 
     91 bool PluginView::dispatchNPEvent(NPEvent& event)
     92 {
     93     // sanity check
     94     if (!m_plugin->pluginFuncs()->event)
     95         return false;
     96 
     97     PluginView::setCurrentPluginView(this);
     98     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
     99     setCallingPlugin(true);
    100 
    101     bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
    102 
    103     setCallingPlugin(false);
    104     PluginView::setCurrentPluginView(0);
    105     return accepted;
    106 }
    107 
    108 #if defined(XP_UNIX)
    109 static Window getRootWindow(Frame* parentFrame)
    110 {
    111     GtkWidget* parentWidget = parentFrame->view()->hostWindow()->platformPageClient();
    112     GdkScreen* gscreen = gtk_widget_get_screen(parentWidget);
    113     return GDK_WINDOW_XWINDOW(gdk_screen_get_root_window(gscreen));
    114 }
    115 #endif
    116 
    117 void PluginView::updatePluginWidget()
    118 {
    119     if (!parent())
    120         return;
    121 
    122     ASSERT(parent()->isFrameView());
    123     FrameView* frameView = static_cast<FrameView*>(parent());
    124 
    125     IntRect oldWindowRect = m_windowRect;
    126     IntRect oldClipRect = m_clipRect;
    127 
    128     m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
    129     m_clipRect = windowClipRect();
    130     m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
    131 
    132     if (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect))
    133         setNPWindowIfNeeded();
    134 
    135 #if defined(XP_UNIX)
    136     if (!m_isWindowed && m_windowRect.size() != oldWindowRect.size()) {
    137         if (m_drawable)
    138             XFreePixmap(GDK_DISPLAY(), m_drawable);
    139 
    140         m_drawable = XCreatePixmap(GDK_DISPLAY(), getRootWindow(m_parentFrame.get()),
    141                                    m_windowRect.width(), m_windowRect.height(),
    142                                    ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth);
    143         XSync(GDK_DISPLAY(), False); // make sure that the server knows about the Drawable
    144     }
    145 
    146     // do not call setNPWindowIfNeeded() immediately, will be called on paint()
    147     m_hasPendingGeometryChange = true;
    148 #endif
    149 
    150     // In order to move/resize the plugin window at the same time as the
    151     // rest of frame during e.g. scrolling, we set the window geometry
    152     // in the paint() function, but as paint() isn't called when the
    153     // plugin window is outside the frame which can be caused by a
    154     // scroll, we need to move/resize immediately.
    155     if (!m_windowRect.intersects(frameView->frameRect()))
    156         setNPWindowIfNeeded();
    157 }
    158 
    159 void PluginView::setFocus()
    160 {
    161     if (platformPluginWidget())
    162         gtk_widget_grab_focus(platformPluginWidget());
    163 
    164     Widget::setFocus();
    165 }
    166 
    167 void PluginView::show()
    168 {
    169     setSelfVisible(true);
    170 
    171     if (isParentVisible() && platformPluginWidget())
    172         gtk_widget_show(platformPluginWidget());
    173 
    174     Widget::show();
    175 }
    176 
    177 void PluginView::hide()
    178 {
    179     setSelfVisible(false);
    180 
    181     if (isParentVisible() && platformPluginWidget())
    182         gtk_widget_hide(platformPluginWidget());
    183 
    184     Widget::hide();
    185 }
    186 
    187 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
    188 {
    189     if (!m_isStarted) {
    190         paintMissingPluginIcon(context, rect);
    191         return;
    192     }
    193 
    194     if (context->paintingDisabled())
    195         return;
    196 
    197     setNPWindowIfNeeded();
    198 
    199     if (m_isWindowed)
    200         return;
    201 
    202 #if defined(XP_UNIX)
    203     if (!m_drawable)
    204         return;
    205 
    206     const bool syncX = m_pluginDisplay && m_pluginDisplay != GDK_DISPLAY();
    207 
    208     IntRect exposedRect(rect);
    209     exposedRect.intersect(frameRect());
    210     exposedRect.move(-frameRect().x(), -frameRect().y());
    211 
    212     Window dummyW;
    213     int dummyI;
    214     unsigned int dummyUI, actualDepth = 0;
    215     XGetGeometry(GDK_DISPLAY(), m_drawable, &dummyW, &dummyI, &dummyI,
    216                  &dummyUI, &dummyUI, &dummyUI, &actualDepth);
    217 
    218     const unsigned int drawableDepth = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth;
    219     ASSERT(drawableDepth == actualDepth);
    220 
    221     cairo_surface_t* drawableSurface = cairo_xlib_surface_create(GDK_DISPLAY(),
    222                                                                  m_drawable,
    223                                                                  m_visual,
    224                                                                  m_windowRect.width(),
    225                                                                  m_windowRect.height());
    226 
    227     if (m_isTransparent && drawableDepth != 32) {
    228         // Attempt to fake it when we don't have an alpha channel on our
    229         // pixmap.  If that's not possible, at least clear the window to
    230         // avoid drawing artifacts.
    231         GtkWidget* widget = m_parentFrame->view()->hostWindow()->platformPageClient();
    232         GdkDrawable* gdkBackingStore = 0;
    233         gint xoff = 0, yoff = 0;
    234 
    235         gdk_window_get_internal_paint_info(widget->window, &gdkBackingStore, &xoff, &yoff);
    236 
    237         GC gc = XDefaultGC(GDK_DISPLAY(), gdk_screen_get_number(gdk_screen_get_default()));
    238         if (gdkBackingStore) {
    239             XCopyArea(GDK_DISPLAY(), GDK_DRAWABLE_XID(gdkBackingStore), m_drawable, gc,
    240                       m_windowRect.x() + exposedRect.x() - xoff,
    241                       m_windowRect.y() + exposedRect.y() - yoff,
    242                       exposedRect.width(), exposedRect.height(),
    243                       exposedRect.x(), exposedRect.y());
    244         } else {
    245             // no valid backing store; clear to the background color
    246             XFillRectangle(GDK_DISPLAY(), m_drawable, gc,
    247                            exposedRect.x(), exposedRect.y(),
    248                            exposedRect.width(), exposedRect.height());
    249         }
    250     } else if (m_isTransparent) {
    251         // If we have a 32 bit drawable and the plugin wants transparency,
    252         // we'll clear the exposed area to transparent first.  Otherwise,
    253         // we'd end up with junk in there from the last paint, or, worse,
    254         // uninitialized data.
    255         cairo_t* crFill = cairo_create(drawableSurface);
    256 
    257         cairo_set_operator(crFill, CAIRO_OPERATOR_SOURCE);
    258         cairo_pattern_t* fill = cairo_pattern_create_rgba(0., 0., 0., 0.);
    259         cairo_set_source(crFill, fill);
    260 
    261         cairo_rectangle(crFill, exposedRect.x(), exposedRect.y(),
    262                         exposedRect.width(), exposedRect.height());
    263         cairo_clip(crFill);
    264         cairo_paint(crFill);
    265 
    266         cairo_destroy(crFill);
    267         cairo_pattern_destroy(fill);
    268     }
    269 
    270     XEvent xevent;
    271     memset(&xevent, 0, sizeof(XEvent));
    272     XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
    273     exposeEvent.type = GraphicsExpose;
    274     exposeEvent.display = GDK_DISPLAY();
    275     exposeEvent.drawable = m_drawable;
    276     exposeEvent.x = exposedRect.x();
    277     exposeEvent.y = exposedRect.y();
    278     exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode
    279     exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode
    280 
    281     dispatchNPEvent(xevent);
    282 
    283     if (syncX)
    284         XSync(m_pluginDisplay, False); // sync changes by plugin
    285 
    286     cairo_t* cr = context->platformContext();
    287     cairo_save(cr);
    288 
    289     cairo_set_source_surface(cr, drawableSurface, frameRect().x(), frameRect().y());
    290 
    291     cairo_rectangle(cr,
    292                     frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y(),
    293                     exposedRect.width(), exposedRect.height());
    294     cairo_clip(cr);
    295 
    296     if (m_isTransparent)
    297         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
    298     else
    299         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
    300     cairo_paint(cr);
    301 
    302     cairo_restore(cr);
    303     cairo_surface_destroy(drawableSurface);
    304 #endif // defined(XP_UNIX)
    305 }
    306 
    307 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
    308 {
    309     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    310 
    311     if (m_isWindowed)
    312         return;
    313 
    314     if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent)
    315         return;
    316 
    317     NPEvent xEvent;
    318 #if defined(XP_UNIX)
    319     GdkEventKey* gdkEvent = event->keyEvent()->gdkEventKey();
    320 
    321     xEvent.type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // KeyPress/Release get unset somewhere
    322     xEvent.xkey.root = getRootWindow(m_parentFrame.get());
    323     xEvent.xkey.subwindow = 0; // we have no child window
    324     xEvent.xkey.time = event->timeStamp();
    325     xEvent.xkey.state = gdkEvent->state; // GdkModifierType mirrors xlib state masks
    326     xEvent.xkey.keycode = gdkEvent->hardware_keycode;
    327     xEvent.xkey.same_screen = true;
    328 
    329     // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window
    330     // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not
    331     // set to their normal Xserver values. e.g. Key events don't have a position.
    332     // source: https://developer.mozilla.org/en/NPEvent
    333     xEvent.xkey.x = 0;
    334     xEvent.xkey.y = 0;
    335     xEvent.xkey.x_root = 0;
    336     xEvent.xkey.y_root = 0;
    337 #endif
    338 
    339     if (!dispatchNPEvent(xEvent))
    340         event->setDefaultHandled();
    341 }
    342 
    343 #if defined(XP_UNIX)
    344 static unsigned int inputEventState(MouseEvent* event)
    345 {
    346     unsigned int state = 0;
    347     if (event->ctrlKey())
    348         state |= ControlMask;
    349     if (event->shiftKey())
    350         state |= ShiftMask;
    351     if (event->altKey())
    352         state |= Mod1Mask;
    353     if (event->metaKey())
    354         state |= Mod4Mask;
    355     return state;
    356 }
    357 
    358 void PluginView::initXEvent(XEvent* xEvent)
    359 {
    360     memset(xEvent, 0, sizeof(XEvent));
    361 
    362     xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server
    363     xEvent->xany.send_event = false;
    364     xEvent->xany.display = GDK_DISPLAY();
    365     // NOTE: event->xany.window doesn't always correspond to the .window property of other XEvent's
    366     // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify
    367     // events; thus, this is right:
    368     GtkWidget* widget = m_parentFrame->view()->hostWindow()->platformPageClient();
    369     xEvent->xany.window = widget ? GDK_WINDOW_XWINDOW(widget->window) : 0;
    370 }
    371 
    372 static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
    373 {
    374     XButtonEvent& xbutton = xEvent->xbutton;
    375     xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease;
    376     xbutton.root = getRootWindow(parentFrame);
    377     xbutton.subwindow = 0;
    378     xbutton.time = event->timeStamp();
    379     xbutton.x = postZoomPos.x();
    380     xbutton.y = postZoomPos.y();
    381     xbutton.x_root = event->screenX();
    382     xbutton.y_root = event->screenY();
    383     xbutton.state = inputEventState(event);
    384     switch (event->button()) {
    385     case MiddleButton:
    386         xbutton.button = Button2;
    387         break;
    388     case RightButton:
    389         xbutton.button = Button3;
    390         break;
    391     case LeftButton:
    392     default:
    393         xbutton.button = Button1;
    394         break;
    395     }
    396     xbutton.same_screen = true;
    397 }
    398 
    399 static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
    400 {
    401     XMotionEvent& xmotion = xEvent->xmotion;
    402     xmotion.type = MotionNotify;
    403     xmotion.root = getRootWindow(parentFrame);
    404     xmotion.subwindow = 0;
    405     xmotion.time = event->timeStamp();
    406     xmotion.x = postZoomPos.x();
    407     xmotion.y = postZoomPos.y();
    408     xmotion.x_root = event->screenX();
    409     xmotion.y_root = event->screenY();
    410     xmotion.state = inputEventState(event);
    411     xmotion.is_hint = NotifyNormal;
    412     xmotion.same_screen = true;
    413 }
    414 
    415 static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
    416 {
    417     XCrossingEvent& xcrossing = xEvent->xcrossing;
    418     xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify;
    419     xcrossing.root = getRootWindow(parentFrame);
    420     xcrossing.subwindow = 0;
    421     xcrossing.time = event->timeStamp();
    422     xcrossing.x = postZoomPos.y();
    423     xcrossing.y = postZoomPos.x();
    424     xcrossing.x_root = event->screenX();
    425     xcrossing.y_root = event->screenY();
    426     xcrossing.state = inputEventState(event);
    427     xcrossing.mode = NotifyNormal;
    428     xcrossing.detail = NotifyDetailNone;
    429     xcrossing.same_screen = true;
    430     xcrossing.focus = false;
    431 }
    432 #endif
    433 
    434 void PluginView::handleMouseEvent(MouseEvent* event)
    435 {
    436     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    437 
    438     if (m_isWindowed)
    439         return;
    440 
    441     NPEvent xEvent;
    442 #if defined(XP_UNIX)
    443     initXEvent(&xEvent);
    444 
    445     IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
    446 
    447     if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
    448         setXButtonEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
    449     else if (event->type() == eventNames().mousemoveEvent)
    450         setXMotionEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
    451     else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent)
    452         setXCrossingEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
    453     else
    454         return;
    455 #endif
    456 
    457     if (!dispatchNPEvent(xEvent))
    458         event->setDefaultHandled();
    459 }
    460 
    461 #if defined(XP_UNIX)
    462 void PluginView::handleFocusInEvent()
    463 {
    464     XEvent npEvent;
    465     initXEvent(&npEvent);
    466 
    467     XFocusChangeEvent& event = npEvent.xfocus;
    468     event.type = 9; // FocusIn gets unset somewhere
    469     event.mode = NotifyNormal;
    470     event.detail = NotifyDetailNone;
    471 
    472     dispatchNPEvent(npEvent);
    473 }
    474 
    475 void PluginView::handleFocusOutEvent()
    476 {
    477     XEvent npEvent;
    478     initXEvent(&npEvent);
    479 
    480     XFocusChangeEvent& event = npEvent.xfocus;
    481     event.type = 10; // FocusOut gets unset somewhere
    482     event.mode = NotifyNormal;
    483     event.detail = NotifyDetailNone;
    484 
    485     dispatchNPEvent(npEvent);
    486 }
    487 #endif
    488 
    489 void PluginView::setParent(ScrollView* parent)
    490 {
    491     Widget::setParent(parent);
    492 
    493     if (parent)
    494         init();
    495 }
    496 
    497 void PluginView::setNPWindowRect(const IntRect&)
    498 {
    499     if (!m_isWindowed)
    500         setNPWindowIfNeeded();
    501 }
    502 
    503 void PluginView::setNPWindowIfNeeded()
    504 {
    505     if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
    506         return;
    507 
    508     // If the plugin didn't load sucessfully, no point in calling setwindow
    509     if (m_status != PluginStatusLoadedSuccessfully)
    510         return;
    511 
    512     // On Unix, only call plugin's setwindow if it's full-page or windowed
    513     if (m_mode != NP_FULL && m_mode != NP_EMBED)
    514         return;
    515 
    516     // Check if the platformPluginWidget still exists
    517     if (m_isWindowed && !platformPluginWidget())
    518         return;
    519 
    520 #if defined(XP_UNIX)
    521     if (!m_hasPendingGeometryChange)
    522         return;
    523     m_hasPendingGeometryChange = false;
    524 #endif
    525 
    526     if (m_isWindowed) {
    527         m_npWindow.x = m_windowRect.x();
    528         m_npWindow.y = m_windowRect.y();
    529         m_npWindow.width = m_windowRect.width();
    530         m_npWindow.height = m_windowRect.height();
    531 
    532         m_npWindow.clipRect.left = m_clipRect.x();
    533         m_npWindow.clipRect.top = m_clipRect.y();
    534         m_npWindow.clipRect.right = m_clipRect.width();
    535         m_npWindow.clipRect.bottom = m_clipRect.height();
    536 
    537         GtkAllocation allocation = { m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height() };
    538         gtk_widget_size_allocate(platformPluginWidget(), &allocation);
    539 #if defined(XP_UNIX)
    540         if (!m_needsXEmbed) {
    541             gtk_xtbin_set_position(GTK_XTBIN(platformPluginWidget()), m_windowRect.x(), m_windowRect.y());
    542             gtk_xtbin_resize(platformPluginWidget(), m_windowRect.width(), m_windowRect.height());
    543         }
    544 #endif
    545     } else {
    546         m_npWindow.x = 0;
    547         m_npWindow.y = 0;
    548 
    549         m_npWindow.clipRect.left = 0;
    550         m_npWindow.clipRect.top = 0;
    551         m_npWindow.clipRect.right = 0;
    552         m_npWindow.clipRect.bottom = 0;
    553     }
    554 
    555     // FLASH WORKAROUND: Only set initially. Multiple calls to
    556     // setNPWindow() cause the plugin to crash in windowed mode.
    557     if (!m_isWindowed || m_npWindow.width == (unsigned int)-1 || m_npWindow.height == (unsigned int)-1) {
    558         m_npWindow.width = m_windowRect.width();
    559         m_npWindow.height = m_windowRect.height();
    560     }
    561 
    562     PluginView::setCurrentPluginView(this);
    563     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    564     setCallingPlugin(true);
    565     m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
    566     setCallingPlugin(false);
    567     PluginView::setCurrentPluginView(0);
    568 }
    569 
    570 void PluginView::setParentVisible(bool visible)
    571 {
    572     if (isParentVisible() == visible)
    573         return;
    574 
    575     Widget::setParentVisible(visible);
    576 
    577     if (isSelfVisible() && platformPluginWidget()) {
    578         if (visible)
    579             gtk_widget_show(platformPluginWidget());
    580         else
    581             gtk_widget_hide(platformPluginWidget());
    582     }
    583 }
    584 
    585 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf)
    586 {
    587     String filename(buf, len);
    588 
    589     if (filename.startsWith("file:///"))
    590         filename = filename.substring(8);
    591 
    592     // Get file info
    593     if (!g_file_test ((filename.utf8()).data(), (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)))
    594         return NPERR_FILE_NOT_FOUND;
    595 
    596     //FIXME - read the file data into buffer
    597     FILE* fileHandle = fopen((filename.utf8()).data(), "r");
    598 
    599     if (fileHandle == 0)
    600         return NPERR_FILE_NOT_FOUND;
    601 
    602     //buffer.resize();
    603 
    604     int bytesRead = fread(buffer.data(), 1, 0, fileHandle);
    605 
    606     fclose(fileHandle);
    607 
    608     if (bytesRead <= 0)
    609         return NPERR_FILE_NOT_FOUND;
    610 
    611     return NPERR_NO_ERROR;
    612 }
    613 
    614 NPError PluginView::getValueStatic(NPNVariable variable, void* value)
    615 {
    616     LOG(Plugins, "PluginView::getValueStatic(%s)", prettyNameForNPNVariable(variable).data());
    617 
    618     switch (variable) {
    619     case NPNVToolkit:
    620 #if defined(XP_UNIX)
    621         *static_cast<uint32*>(value) = 2;
    622 #else
    623         *static_cast<uint32*>(value) = 0;
    624 #endif
    625         return NPERR_NO_ERROR;
    626 
    627     case NPNVSupportsXEmbedBool:
    628 #if defined(XP_UNIX)
    629         *static_cast<NPBool*>(value) = true;
    630 #else
    631         *static_cast<NPBool*>(value) = false;
    632 #endif
    633         return NPERR_NO_ERROR;
    634 
    635     case NPNVjavascriptEnabledBool:
    636         *static_cast<NPBool*>(value) = true;
    637         return NPERR_NO_ERROR;
    638 
    639     case NPNVSupportsWindowless:
    640 #if defined(XP_UNIX)
    641         *static_cast<NPBool*>(value) = true;
    642 #else
    643         *static_cast<NPBool*>(value) = false;
    644 #endif
    645         return NPERR_NO_ERROR;
    646 
    647     default:
    648         return NPERR_GENERIC_ERROR;
    649     }
    650 }
    651 
    652 NPError PluginView::getValue(NPNVariable variable, void* value)
    653 {
    654     LOG(Plugins, "PluginView::getValue(%s)", prettyNameForNPNVariable(variable).data());
    655 
    656     switch (variable) {
    657     case NPNVxDisplay:
    658 #if defined(XP_UNIX)
    659         if (m_needsXEmbed)
    660             *(void **)value = (void *)GDK_DISPLAY();
    661         else
    662             *(void **)value = (void *)GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay;
    663         return NPERR_NO_ERROR;
    664 #else
    665         return NPERR_GENERIC_ERROR;
    666 #endif
    667 
    668 #if defined(XP_UNIX)
    669     case NPNVxtAppContext:
    670         if (!m_needsXEmbed) {
    671             *(void **)value = XtDisplayToApplicationContext (GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay);
    672 
    673             return NPERR_NO_ERROR;
    674         } else
    675             return NPERR_GENERIC_ERROR;
    676 #endif
    677 
    678 #if ENABLE(NETSCAPE_PLUGIN_API)
    679         case NPNVWindowNPObject: {
    680             if (m_isJavaScriptPaused)
    681                 return NPERR_GENERIC_ERROR;
    682 
    683             NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject();
    684 
    685             // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
    686             if (windowScriptObject)
    687                 _NPN_RetainObject(windowScriptObject);
    688 
    689             void** v = (void**)value;
    690             *v = windowScriptObject;
    691 
    692             return NPERR_NO_ERROR;
    693         }
    694 
    695         case NPNVPluginElementNPObject: {
    696             if (m_isJavaScriptPaused)
    697                 return NPERR_GENERIC_ERROR;
    698 
    699             NPObject* pluginScriptObject = 0;
    700 
    701             if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag))
    702                 pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject();
    703 
    704             // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
    705             if (pluginScriptObject)
    706                 _NPN_RetainObject(pluginScriptObject);
    707 
    708             void** v = (void**)value;
    709             *v = pluginScriptObject;
    710 
    711             return NPERR_NO_ERROR;
    712         }
    713 #endif
    714 
    715         case NPNVnetscapeWindow: {
    716 #if defined(XP_UNIX)
    717             void* w = reinterpret_cast<void*>(value);
    718             *((XID *)w) = GDK_WINDOW_XWINDOW(m_parentFrame->view()->hostWindow()->platformPageClient()->window);
    719 #endif
    720 #ifdef GDK_WINDOWING_WIN32
    721             HGDIOBJ* w = reinterpret_cast<HGDIOBJ*>(value);
    722             *w = GDK_WINDOW_HWND(m_parentFrame->view()->hostWindow()->platformPageClient()->window);
    723 #endif
    724             return NPERR_NO_ERROR;
    725         }
    726 
    727         default:
    728             return getValueStatic(variable, value);
    729     }
    730 }
    731 
    732 void PluginView::invalidateRect(const IntRect& rect)
    733 {
    734     if (m_isWindowed) {
    735         gtk_widget_queue_draw_area(GTK_WIDGET(platformPluginWidget()), rect.x(), rect.y(), rect.width(), rect.height());
    736         return;
    737     }
    738 
    739     invalidateWindowlessPluginRect(rect);
    740 }
    741 
    742 void PluginView::invalidateRect(NPRect* rect)
    743 {
    744     if (!rect) {
    745         invalidate();
    746         return;
    747     }
    748 
    749     IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
    750     invalidateWindowlessPluginRect(r);
    751 }
    752 
    753 void PluginView::invalidateRegion(NPRegion)
    754 {
    755     // TODO: optimize
    756     invalidate();
    757 }
    758 
    759 void PluginView::forceRedraw()
    760 {
    761     if (m_isWindowed)
    762         gtk_widget_queue_draw(platformPluginWidget());
    763     else
    764         gtk_widget_queue_draw(m_parentFrame->view()->hostWindow()->platformPageClient());
    765 }
    766 
    767 static Display* getPluginDisplay()
    768 {
    769     // The plugin toolkit might have a different X connection open.  Since we're
    770     // a gdk/gtk app, we'll (probably?) have the same X connection as any gdk-based
    771     // plugins, so we can return that.  We might want to add other implementations here
    772     // later.
    773 
    774 #if defined(XP_UNIX)
    775     return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
    776 #else
    777     return 0;
    778 #endif
    779 }
    780 
    781 static gboolean
    782 plug_removed_cb(GtkSocket* socket, gpointer)
    783 {
    784     return TRUE;
    785 }
    786 
    787 #if defined(XP_UNIX)
    788 static void getVisualAndColormap(int depth, Visual** visual, Colormap* colormap)
    789 {
    790     *visual = 0;
    791     *colormap = 0;
    792 
    793     int rmaj, rmin;
    794     if (depth == 32 && (!XRenderQueryVersion(GDK_DISPLAY(), &rmaj, &rmin) || (rmaj == 0 && rmin < 5)))
    795         return;
    796 
    797     XVisualInfo templ;
    798     templ.screen  = gdk_screen_get_number(gdk_screen_get_default());
    799     templ.depth   = depth;
    800     templ.c_class = TrueColor;
    801     int nVisuals;
    802     XVisualInfo* visualInfo = XGetVisualInfo(GDK_DISPLAY(), VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nVisuals);
    803 
    804     if (!nVisuals)
    805         return;
    806 
    807     if (depth == 32) {
    808         for (int idx = 0; idx < nVisuals; ++idx) {
    809             XRenderPictFormat* format = XRenderFindVisualFormat(GDK_DISPLAY(), visualInfo[idx].visual);
    810             if (format->type == PictTypeDirect && format->direct.alphaMask) {
    811                  *visual = visualInfo[idx].visual;
    812                  break;
    813             }
    814          }
    815     } else
    816         *visual = visualInfo[0].visual;
    817 
    818     XFree(visualInfo);
    819 
    820     if (*visual)
    821         *colormap = XCreateColormap(GDK_DISPLAY(), GDK_ROOT_WINDOW(), *visual, AllocNone);
    822 }
    823 #endif
    824 
    825 bool PluginView::platformStart()
    826 {
    827     ASSERT(m_isStarted);
    828     ASSERT(m_status == PluginStatusLoadedSuccessfully);
    829 
    830     if (m_plugin->pluginFuncs()->getvalue) {
    831         PluginView::setCurrentPluginView(this);
    832         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    833         setCallingPlugin(true);
    834         m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed);
    835         setCallingPlugin(false);
    836         PluginView::setCurrentPluginView(0);
    837     }
    838 
    839     if (m_isWindowed) {
    840 #if defined(XP_UNIX)
    841         if (m_needsXEmbed) {
    842             setPlatformWidget(gtk_socket_new());
    843             gtk_container_add(GTK_CONTAINER(m_parentFrame->view()->hostWindow()->platformPageClient()), platformPluginWidget());
    844             g_signal_connect(platformPluginWidget(), "plug_removed", G_CALLBACK(plug_removed_cb), NULL);
    845         } else
    846             setPlatformWidget(gtk_xtbin_new(m_parentFrame->view()->hostWindow()->platformPageClient()->window, 0));
    847 #else
    848         setPlatformWidget(gtk_socket_new());
    849         gtk_container_add(GTK_CONTAINER(m_parentFrame->view()->hostWindow()->platformPageClient()), platformPluginWidget());
    850 #endif
    851     } else {
    852         setPlatformWidget(0);
    853         m_pluginDisplay = getPluginDisplay();
    854     }
    855 
    856     show();
    857 
    858 #if defined(XP_UNIX)
    859         NPSetWindowCallbackStruct* ws = new NPSetWindowCallbackStruct();
    860         ws->type = 0;
    861 #endif
    862 
    863     if (m_isWindowed) {
    864         m_npWindow.type = NPWindowTypeWindow;
    865 #if defined(XP_UNIX)
    866         if (m_needsXEmbed) {
    867             gtk_widget_realize(platformPluginWidget());
    868             m_npWindow.window = (void*)gtk_socket_get_id(GTK_SOCKET(platformPluginWidget()));
    869             ws->display = GDK_WINDOW_XDISPLAY(platformPluginWidget()->window);
    870             ws->visual = GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(GDK_DRAWABLE(platformPluginWidget()->window)));
    871             ws->depth = gdk_drawable_get_visual(GDK_DRAWABLE(platformPluginWidget()->window))->depth;
    872             ws->colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(GDK_DRAWABLE(platformPluginWidget()->window)));
    873         } else {
    874             m_npWindow.window = (void*)GTK_XTBIN(platformPluginWidget())->xtwindow;
    875             ws->display = GTK_XTBIN(platformPluginWidget())->xtdisplay;
    876             ws->visual = GTK_XTBIN(platformPluginWidget())->xtclient.xtvisual;
    877             ws->depth = GTK_XTBIN(platformPluginWidget())->xtclient.xtdepth;
    878             ws->colormap = GTK_XTBIN(platformPluginWidget())->xtclient.xtcolormap;
    879         }
    880         XFlush (ws->display);
    881 #elif defined(GDK_WINDOWING_WIN32)
    882         m_npWindow.window = (void*)GDK_WINDOW_HWND(platformPluginWidget()->window);
    883 #endif
    884     } else {
    885         m_npWindow.type = NPWindowTypeDrawable;
    886         m_npWindow.window = 0; // Not used?
    887 
    888 #if defined(XP_UNIX)
    889         GdkScreen* gscreen = gdk_screen_get_default();
    890         GdkVisual* gvisual = gdk_screen_get_system_visual(gscreen);
    891 
    892         if (gvisual->depth == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) {
    893             getVisualAndColormap(32, &m_visual, &m_colormap);
    894             ws->depth = 32;
    895         }
    896 
    897         if (!m_visual) {
    898             getVisualAndColormap(gvisual->depth, &m_visual, &m_colormap);
    899             ws->depth = gvisual->depth;
    900         }
    901 
    902         ws->display = GDK_DISPLAY();
    903         ws->visual = m_visual;
    904         ws->colormap = m_colormap;
    905 
    906         m_npWindow.x = 0;
    907         m_npWindow.y = 0;
    908         m_npWindow.width = -1;
    909         m_npWindow.height = -1;
    910 #else
    911         notImplemented();
    912         m_status = PluginStatusCanNotLoadPlugin;
    913         return false;
    914 #endif
    915     }
    916 
    917 #if defined(XP_UNIX)
    918     m_npWindow.ws_info = ws;
    919 #endif
    920 
    921     // TODO remove in favor of null events, like mac port?
    922     if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) {
    923         updatePluginWidget(); // was: setNPWindowIfNeeded(), but this doesn't produce 0x0 rects at first go
    924         setNPWindowIfNeeded();
    925     }
    926 
    927     return true;
    928 }
    929 
    930 void PluginView::platformDestroy()
    931 {
    932 #if defined(XP_UNIX)
    933     if (m_drawable) {
    934         XFreePixmap(GDK_DISPLAY(), m_drawable);
    935         m_drawable = 0;
    936     }
    937 #endif
    938 }
    939 
    940 void PluginView::halt()
    941 {
    942 }
    943 
    944 void PluginView::restart()
    945 {
    946 }
    947 
    948 } // namespace WebCore
    949 
    950