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