• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
dispatchNPEvent(NPEvent & event)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)
getRootWindow(Frame * parentFrame)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 
updatePluginWidget()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 
setFocus(bool focused)159 void PluginView::setFocus(bool focused)
160 {
161     ASSERT(platformPluginWidget() == platformWidget());
162     Widget::setFocus(focused);
163 }
164 
show()165 void PluginView::show()
166 {
167     ASSERT(platformPluginWidget() == platformWidget());
168     Widget::show();
169 }
170 
hide()171 void PluginView::hide()
172 {
173     ASSERT(platformPluginWidget() == platformWidget());
174     Widget::hide();
175 }
176 
paint(GraphicsContext * context,const IntRect & rect)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 
handleKeyboardEvent(KeyboardEvent * event)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)
inputEventState(MouseEvent * event)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 
initXEvent(XEvent * xEvent)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 
setXButtonEventSpecificFields(XEvent * xEvent,MouseEvent * event,const IntPoint & postZoomPos,Frame * parentFrame)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 
setXMotionEventSpecificFields(XEvent * xEvent,MouseEvent * event,const IntPoint & postZoomPos,Frame * parentFrame)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 
setXCrossingEventSpecificFields(XEvent * xEvent,MouseEvent * event,const IntPoint & postZoomPos,Frame * parentFrame)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 
handleMouseEvent(MouseEvent * event)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)
handleFocusInEvent()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 
handleFocusOutEvent()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 
setParent(ScrollView * parent)466 void PluginView::setParent(ScrollView* parent)
467 {
468     Widget::setParent(parent);
469 
470     if (parent)
471         init();
472 }
473 
setNPWindowRect(const IntRect &)474 void PluginView::setNPWindowRect(const IntRect&)
475 {
476     if (!m_isWindowed)
477         setNPWindowIfNeeded();
478 }
479 
setNPWindowIfNeeded()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 
setParentVisible(bool visible)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 
handlePostReadFile(Vector<char> & outputBuffer,uint32_t filenameLength,const char * filenameBuffer)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 
platformGetValueStatic(NPNVariable variable,void * value,NPError * result)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 
platformGetValue(NPNVariable variable,void * value,NPError * result)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 
invalidateRect(const IntRect & rect)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 
invalidateRect(NPRect * rect)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 
invalidateRegion(NPRegion)698 void PluginView::invalidateRegion(NPRegion)
699 {
700     // TODO: optimize
701     invalidate();
702 }
703 
forceRedraw()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
getPluginDisplay()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)
getVisualAndColormap(int depth,Visual ** visual,Colormap * colormap)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 
plugRemovedCallback(GtkSocket * socket,PluginView * view)767 gboolean PluginView::plugRemovedCallback(GtkSocket* socket, PluginView* view)
768 {
769     view->m_plugAdded = false;
770     return TRUE;
771 }
772 
plugAddedCallback(GtkSocket * socket,PluginView * view)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 
platformStart()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 
platformDestroy()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 
halt()915 void PluginView::halt()
916 {
917 }
918 
restart()919 void PluginView::restart()
920 {
921 }
922 
923 } // namespace WebCore
924