2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Collabora Ltd. All rights reserved.
4 * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
29 #include "PluginView.h"
32 #include "BridgeJSC.h"
35 #include "ChromeClient.h"
37 #include "DocumentLoader.h"
39 #include "FloatPoint.h"
40 #include "FocusController.h"
42 #include "FrameLoadRequest.h"
43 #include "FrameLoader.h"
44 #include "FrameTree.h"
45 #include "FrameView.h"
46 #include "GraphicsContext.h"
47 #include "HTMLNames.h"
48 #include "HTMLPlugInElement.h"
49 #include "HostWindow.h"
50 #include "IFrameShimSupport.h"
53 #include "JSDOMBinding.h"
55 #include "KeyboardEvent.h"
56 #include "MouseEvent.h"
57 #include "NotImplemented.h"
59 #include "PlatformMouseEvent.h"
60 #include "PlatformKeyboardEvent.h"
61 #include "PluginContainerQt.h"
62 #include "PluginDebug.h"
63 #include "PluginPackage.h"
64 #include "PluginMainThreadScheduler.h"
65 #include "QWebPageClient.h"
66 #include "RenderLayer.h"
68 #include "npruntime_impl.h"
70 #include "runtime_root.h"
73 #include <QApplication>
74 #include <QDesktopWidget>
75 #include <QGraphicsWidget>
78 #include <QStyleOptionGraphicsItem>
85 #include <X11/extensions/Xrender.h>
87 #include <runtime/JSLock.h>
88 #include <runtime/JSValue.h>
92 using JSC::Interpreter;
104 bool PluginView::s_isRunningUnderDRT = false;
106 using namespace HTMLNames;
108 #if USE(ACCELERATED_COMPOSITING)
109 // Qt's GraphicsLayer (GraphicsLayerQt) requires layers to be QGraphicsWidgets
110 class PluginGraphicsLayerQt : public QGraphicsWidget {
112 PluginGraphicsLayerQt(PluginView* view) : m_view(view) { }
113 ~PluginGraphicsLayerQt() { }
115 void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0)
118 m_view->paintUsingXPixmap(painter, option->exposedRect.toRect());
125 bool PluginView::shouldUseAcceleratedCompositing() const
127 return m_parentFrame->page()->chrome()->client()->allowsAcceleratedCompositing()
128 && m_parentFrame->page()->settings()
129 && m_parentFrame->page()->settings()->acceleratedCompositingEnabled();
133 void PluginView::updatePluginWidget()
138 ASSERT(parent()->isFrameView());
139 FrameView* frameView = static_cast<FrameView*>(parent());
141 IntRect oldWindowRect = m_windowRect;
142 IntRect oldClipRect = m_clipRect;
144 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
145 m_clipRect = windowClipRect();
146 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
148 if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
151 // The plugin had a zero width or height before but was resized, we need to show it again.
152 if (oldWindowRect.isEmpty())
155 if (!m_isWindowed && m_windowRect.size() != oldWindowRect.size()) {
157 XFreePixmap(QX11Info::display(), m_drawable);
159 m_drawable = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), m_windowRect.width(), m_windowRect.height(),
160 ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth);
161 QApplication::syncX(); // make sure that the server knows about the Drawable
164 // do not call setNPWindowIfNeeded immediately, will be called on paint()
165 m_hasPendingGeometryChange = true;
167 // (i) in order to move/resize the plugin window at the same time as the
168 // rest of frame during e.g. scrolling, we set the window geometry
169 // in the paint() function, but as paint() isn't called when the
170 // plugin window is outside the frame which can be caused by a
171 // scroll, we need to move/resize immediately.
172 // (ii) if we are running layout tests from DRT, paint() won't ever get called
173 // so we need to call setNPWindowIfNeeded() if window geometry has changed
174 if (!m_windowRect.intersects(frameView->frameRect())
175 || (s_isRunningUnderDRT && platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)))
176 setNPWindowIfNeeded();
178 if (!m_platformLayer) {
179 // Make sure we get repainted afterwards. This is necessary for downward
180 // scrolling to move the plugin widget properly.
181 // Note that we don't invalidate the frameRect() here. This is because QWebFrame::renderRelativeCoords()
182 // imitates ScrollView and adds the scroll offset back on to the rect we damage here (making the co-ordinates absolute
183 // to the frame again) before passing it to FrameView.
188 void PluginView::setFocus(bool focused)
190 if (platformPluginWidget()) {
192 static_cast<QWidget*>(platformPluginWidget())->setFocus(Qt::OtherFocusReason);
194 Widget::setFocus(focused);
198 void PluginView::show()
200 Q_ASSERT(platformPluginWidget() == platformWidget());
204 void PluginView::hide()
206 Q_ASSERT(platformPluginWidget() == platformWidget());
210 void PluginView::paintUsingXPixmap(QPainter* painter, const QRect &exposedRect)
212 QPixmap qtDrawable = QPixmap::fromX11Pixmap(m_drawable, QPixmap::ExplicitlyShared);
213 const int drawableDepth = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth;
214 ASSERT(drawableDepth == qtDrawable.depth());
215 const bool syncX = m_pluginDisplay && m_pluginDisplay != QX11Info::display();
217 // When printing, Qt uses a QPicture to capture the output in preview mode. The
218 // QPicture holds a reference to the X Pixmap. As a result, the print preview would
219 // update itself when the X Pixmap changes. To prevent this, we create a copy.
220 if (m_element->document()->printing())
221 qtDrawable = qtDrawable.copy();
223 if (m_isTransparent && drawableDepth != 32) {
224 // Attempt content propagation for drawable with no alpha by copying over from the backing store
226 QPaintDevice* backingStoreDevice = QPainter::redirected(painter->device(), &offset);
227 offset = -offset; // negating the offset gives us the offset of the view within the backing store pixmap
229 const bool hasValidBackingStore = backingStoreDevice && backingStoreDevice->devType() == QInternal::Pixmap;
230 QPixmap* backingStorePixmap = static_cast<QPixmap*>(backingStoreDevice);
232 // We cannot grab contents from the backing store when painting on QGraphicsView items
233 // (because backing store contents are already transformed). What we really mean to do
234 // here is to check if we are painting on QWebView, but let's be a little permissive :)
235 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
236 const bool backingStoreHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent());
238 if (hasValidBackingStore && backingStorePixmap->depth() == drawableDepth
239 && backingStoreHasUntransformedContents) {
240 GC gc = XDefaultGC(QX11Info::display(), QX11Info::appScreen());
241 XCopyArea(QX11Info::display(), backingStorePixmap->handle(), m_drawable, gc,
242 offset.x() + m_windowRect.x() + exposedRect.x(), offset.y() + m_windowRect.y() + exposedRect.y(),
243 exposedRect.width(), exposedRect.height(), exposedRect.x(), exposedRect.y());
244 } else { // no backing store, clean the pixmap because the plugin thinks its transparent
245 QPainter painter(&qtDrawable);
246 painter.fillRect(exposedRect, Qt::white);
250 QApplication::syncX();
254 memset(&xevent, 0, sizeof(XEvent));
255 XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
256 exposeEvent.type = GraphicsExpose;
257 exposeEvent.display = QX11Info::display();
258 exposeEvent.drawable = qtDrawable.handle();
259 exposeEvent.x = exposedRect.x();
260 exposeEvent.y = exposedRect.y();
261 exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode
262 exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode
264 dispatchNPEvent(xevent);
267 XSync(m_pluginDisplay, false); // sync changes by plugin
269 painter->drawPixmap(QPoint(exposedRect.x(), exposedRect.y()), qtDrawable, exposedRect);
272 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
275 paintMissingPluginIcon(context, rect);
279 if (context->paintingDisabled())
282 setNPWindowIfNeeded();
287 #if USE(ACCELERATED_COMPOSITING)
295 QPainter* painter = context->platformContext();
296 IntRect exposedRect(rect);
297 exposedRect.intersect(frameRect());
298 exposedRect.move(-frameRect().x(), -frameRect().y());
300 painter->translate(frameRect().x(), frameRect().y());
301 paintUsingXPixmap(painter, exposedRect);
302 painter->translate(-frameRect().x(), -frameRect().y());
305 // TODO: Unify across ports.
306 bool PluginView::dispatchNPEvent(NPEvent& event)
308 if (!m_plugin->pluginFuncs()->event)
311 bool shouldPop = false;
313 if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE
314 && (event.type == ButtonRelease || event.type == 3 /*KeyRelease*/)) {
315 pushPopupsEnabledState(true);
319 PluginView::setCurrentPluginView(this);
321 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
323 setCallingPlugin(true);
324 bool accepted = !m_plugin->pluginFuncs()->event(m_instance, &event);
325 setCallingPlugin(false);
326 PluginView::setCurrentPluginView(0);
329 popPopupsEnabledState();
334 void setSharedXEventFields(XEvent* xEvent, QWidget* ownerWidget)
336 xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server
337 xEvent->xany.send_event = false;
338 xEvent->xany.display = QX11Info::display();
339 // NOTE: event->xany.window doesn't always respond to the .window property of other XEvent's
340 // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify
341 // events; thus, this is right:
342 xEvent->xany.window = ownerWidget ? ownerWidget->window()->handle() : 0;
345 void PluginView::initXEvent(XEvent* xEvent)
347 memset(xEvent, 0, sizeof(XEvent));
349 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
350 QWidget* ownerWidget = client ? client->ownerWidget() : 0;
351 setSharedXEventFields(xEvent, ownerWidget);
354 void PluginView::setXKeyEventSpecificFields(XEvent* xEvent, KeyboardEvent* event)
356 const PlatformKeyboardEvent* keyEvent = event->keyEvent();
358 xEvent->type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // ints as Qt unsets KeyPress and KeyRelease
359 xEvent->xkey.root = QX11Info::appRootWindow();
360 xEvent->xkey.subwindow = 0; // we have no child window
361 xEvent->xkey.time = event->timeStamp();
362 xEvent->xkey.state = keyEvent->nativeModifiers();
363 xEvent->xkey.keycode = keyEvent->nativeScanCode();
365 // We may not have a nativeScanCode() if the key event is from DRT's eventsender. In that
366 // case fetch the XEvent's keycode from the event's text. The only
367 // place this keycode will be used is in webkit_test_plugin_handle_event().
368 // FIXME: Create Qt API so that we can set the appropriate keycode in DRT EventSender instead.
369 if (s_isRunningUnderDRT && !xEvent->xkey.keycode) {
370 QKeyEvent* qKeyEvent = keyEvent->qtEvent();
372 QString keyText = qKeyEvent->text().left(1);
373 xEvent->xkey.keycode = XKeysymToKeycode(QX11Info::display(), XStringToKeysym(keyText.toUtf8().constData()));
376 xEvent->xkey.same_screen = true;
378 // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window
379 // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not
380 // set to their normal Xserver values. e.g. Key events don't have a position.
381 // source: https://developer.mozilla.org/en/NPEvent
384 xEvent->xkey.x_root = 0;
385 xEvent->xkey.y_root = 0;
388 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
393 if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent)
397 initXEvent(&npEvent);
398 setXKeyEventSpecificFields(&npEvent, event);
400 if (dispatchNPEvent(npEvent))
401 event->setDefaultHandled();
404 static unsigned int inputEventState(MouseEvent* event)
406 unsigned int state = 0;
407 if (event->ctrlKey())
408 state |= ControlMask;
409 if (event->shiftKey())
413 if (event->metaKey())
418 static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
420 XButtonEvent& xbutton = xEvent->xbutton;
421 xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease;
422 xbutton.root = QX11Info::appRootWindow();
423 xbutton.subwindow = 0;
424 xbutton.time = event->timeStamp();
425 xbutton.x = postZoomPos.x();
426 xbutton.y = postZoomPos.y();
427 xbutton.x_root = event->screenX();
428 xbutton.y_root = event->screenY();
429 xbutton.state = inputEventState(event);
430 switch (event->button()) {
432 xbutton.button = Button2;
435 xbutton.button = Button3;
439 xbutton.button = Button1;
442 xbutton.same_screen = true;
445 static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
447 XMotionEvent& xmotion = xEvent->xmotion;
448 xmotion.type = MotionNotify;
449 xmotion.root = QX11Info::appRootWindow();
450 xmotion.subwindow = 0;
451 xmotion.time = event->timeStamp();
452 xmotion.x = postZoomPos.x();
453 xmotion.y = postZoomPos.y();
454 xmotion.x_root = event->screenX();
455 xmotion.y_root = event->screenY();
456 xmotion.state = inputEventState(event);
457 xmotion.is_hint = NotifyNormal;
458 xmotion.same_screen = true;
461 static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
463 XCrossingEvent& xcrossing = xEvent->xcrossing;
464 xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify;
465 xcrossing.root = QX11Info::appRootWindow();
466 xcrossing.subwindow = 0;
467 xcrossing.time = event->timeStamp();
468 xcrossing.x = postZoomPos.y();
469 xcrossing.y = postZoomPos.x();
470 xcrossing.x_root = event->screenX();
471 xcrossing.y_root = event->screenY();
472 xcrossing.state = inputEventState(event);
473 xcrossing.mode = NotifyNormal;
474 xcrossing.detail = NotifyDetailNone;
475 xcrossing.same_screen = true;
476 xcrossing.focus = false;
479 void PluginView::handleMouseEvent(MouseEvent* event)
484 if (event->button() == RightButton && m_plugin->quirks().contains(PluginQuirkIgnoreRightClickInWindowlessMode))
487 if (event->type() == eventNames().mousedownEvent) {
488 // Give focus to the plugin on click
489 if (Page* page = m_parentFrame->page())
490 page->focusController()->setActive(true);
492 focusPluginElement();
496 initXEvent(&npEvent);
498 IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
500 if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
501 setXButtonEventSpecificFields(&npEvent, event, postZoomPos);
502 else if (event->type() == eventNames().mousemoveEvent)
503 setXMotionEventSpecificFields(&npEvent, event, postZoomPos);
504 else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent)
505 setXCrossingEventSpecificFields(&npEvent, event, postZoomPos);
509 if (dispatchNPEvent(npEvent))
510 event->setDefaultHandled();
513 void PluginView::handleFocusInEvent()
516 initXEvent(&npEvent);
518 XFocusChangeEvent& event = npEvent.xfocus;
519 event.type = 9; /* int as Qt unsets FocusIn */
520 event.mode = NotifyNormal;
521 event.detail = NotifyDetailNone;
523 dispatchNPEvent(npEvent);
526 void PluginView::handleFocusOutEvent()
529 initXEvent(&npEvent);
531 XFocusChangeEvent& event = npEvent.xfocus;
532 event.type = 10; /* int as Qt unsets FocusOut */
533 event.mode = NotifyNormal;
534 event.detail = NotifyDetailNone;
536 dispatchNPEvent(npEvent);
539 void PluginView::setParent(ScrollView* parent)
541 Widget::setParent(parent);
547 void PluginView::setNPWindowRect(const IntRect&)
550 setNPWindowIfNeeded();
553 void PluginView::setNPWindowIfNeeded()
555 if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
558 // If the plugin didn't load sucessfully, no point in calling setwindow
559 if (m_status != PluginStatusLoadedSuccessfully)
562 // On Unix, only call plugin if it's full-page or windowed
563 if (m_mode != NP_FULL && m_mode != NP_EMBED)
566 // Check if the platformPluginWidget still exists
567 if (m_isWindowed && !platformPluginWidget())
570 if (!m_hasPendingGeometryChange)
572 m_hasPendingGeometryChange = false;
575 QWidget* widget = static_cast<QWidget*>(platformPluginWidget());
576 widget->setGeometry(m_windowRect);
578 // Cut out areas of the plugin occluded by iframe shims
579 Vector<IntRect> cutOutRects;
580 QRegion clipRegion = QRegion(m_clipRect);
581 getPluginOcclusions(m_element, this->parent(), frameRect(), cutOutRects);
582 for (size_t i = 0; i < cutOutRects.size(); i++) {
583 cutOutRects[i].move(-frameRect().x(), -frameRect().y());
584 clipRegion = clipRegion.subtracted(QRegion(cutOutRects[i]));
586 // if setMask is set with an empty QRegion, no clipping will
587 // be performed, so in that case we hide the plugin view
588 widget->setVisible(!clipRegion.isEmpty());
589 widget->setMask(clipRegion);
591 m_npWindow.x = m_windowRect.x();
592 m_npWindow.y = m_windowRect.y();
598 // If the width or height are null, set the clipRect to null, indicating that
599 // the plugin is not visible/scrolled out.
600 if (!m_clipRect.width() || !m_clipRect.height()) {
601 m_npWindow.clipRect.left = 0;
602 m_npWindow.clipRect.right = 0;
603 m_npWindow.clipRect.top = 0;
604 m_npWindow.clipRect.bottom = 0;
606 // Clipping rectangle of the plug-in; the origin is the top left corner of the drawable or window.
607 m_npWindow.clipRect.left = m_npWindow.x + m_clipRect.x();
608 m_npWindow.clipRect.top = m_npWindow.y + m_clipRect.y();
609 m_npWindow.clipRect.right = m_npWindow.x + m_clipRect.x() + m_clipRect.width();
610 m_npWindow.clipRect.bottom = m_npWindow.y + m_clipRect.y() + m_clipRect.height();
613 if (m_plugin->quirks().contains(PluginQuirkDontCallSetWindowMoreThanOnce)) {
614 // FLASH WORKAROUND: Only set initially. Multiple calls to
615 // setNPWindow() cause the plugin to crash in windowed mode.
616 if (!m_isWindowed || m_npWindow.width == -1 || m_npWindow.height == -1) {
617 m_npWindow.width = m_windowRect.width();
618 m_npWindow.height = m_windowRect.height();
621 m_npWindow.width = m_windowRect.width();
622 m_npWindow.height = m_windowRect.height();
625 PluginView::setCurrentPluginView(this);
627 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
629 setCallingPlugin(true);
630 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
631 setCallingPlugin(false);
632 PluginView::setCurrentPluginView(0);
635 void PluginView::setParentVisible(bool visible)
637 if (isParentVisible() == visible)
640 Widget::setParentVisible(visible);
642 if (isSelfVisible() && platformPluginWidget())
643 static_cast<QWidget*>(platformPluginWidget())->setVisible(visible);
646 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
648 String filename(buf, len);
650 if (filename.startsWith("file:///"))
651 filename = filename.substring(8);
654 if (!getFileSize(filename, size))
655 return NPERR_FILE_NOT_FOUND;
657 FILE* fileHandle = fopen((filename.utf8()).data(), "r");
659 return NPERR_FILE_NOT_FOUND;
662 int bytesRead = fread(buffer.data(), 1, size, fileHandle);
667 return NPERR_FILE_NOT_FOUND;
669 return NPERR_NO_ERROR;
672 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
676 *static_cast<uint32_t*>(value) = 0;
677 *result = NPERR_NO_ERROR;
680 case NPNVSupportsXEmbedBool:
681 *static_cast<NPBool*>(value) = true;
682 *result = NPERR_NO_ERROR;
685 case NPNVjavascriptEnabledBool:
686 *static_cast<NPBool*>(value) = true;
687 *result = NPERR_NO_ERROR;
690 case NPNVSupportsWindowless:
691 *static_cast<NPBool*>(value) = true;
692 *result = NPERR_NO_ERROR;
700 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
704 *(void **)value = QX11Info::display();
705 *result = NPERR_NO_ERROR;
708 case NPNVxtAppContext:
709 *result = NPERR_GENERIC_ERROR;
712 case NPNVnetscapeWindow: {
713 void* w = reinterpret_cast<void*>(value);
714 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
715 *((XID *)w) = client ? client->ownerWidget()->window()->winId() : 0;
716 *result = NPERR_NO_ERROR;
721 if (m_plugin->quirks().contains(PluginQuirkRequiresGtkToolKit)) {
722 *((uint32_t *)value) = 2;
723 *result = NPERR_NO_ERROR;
733 void PluginView::invalidateRect(const IntRect& rect)
735 #if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER)
736 if (m_platformLayer) {
737 m_platformLayer->update(QRectF(rect));
743 if (platformWidget()) {
744 // update() will schedule a repaint of the widget so ensure
745 // its knowledge of its position on the page is up to date.
746 QWidget* w = static_cast<QWidget*>(platformWidget());
747 w->setGeometry(m_windowRect);
753 invalidateWindowlessPluginRect(rect);
756 void PluginView::invalidateRect(NPRect* rect)
762 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
766 void PluginView::invalidateRegion(NPRegion region)
772 void PluginView::forceRedraw()
777 static Display *getPluginDisplay()
779 // The plugin toolkit might run using a different X connection. At the moment, we only
780 // support gdk based plugins (like flash) that use a different X connection.
781 // The code below has the same effect as this one:
782 // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
783 QLibrary library(QLatin1String("libgdk-x11-2.0"), 0);
787 typedef void *(*gdk_init_check_ptr)(void*, void*);
788 gdk_init_check_ptr gdk_init_check = (gdk_init_check_ptr)library.resolve("gdk_init_check");
792 typedef void *(*gdk_display_get_default_ptr)();
793 gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default");
794 if (!gdk_display_get_default)
797 typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *);
798 gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay");
799 if (!gdk_x11_display_get_xdisplay)
802 gdk_init_check(0, 0);
803 return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default());
806 static void getVisualAndColormap(int depth, Visual **visual, Colormap *colormap)
811 #ifndef QT_NO_XRENDER
812 static const bool useXRender = qgetenv("QT_X11_NO_XRENDER").isNull(); // Should also check for XRender >= 0.5
814 static const bool useXRender = false;
817 if (!useXRender && depth == 32)
822 templ.screen = QX11Info::appScreen();
824 templ.c_class = TrueColor;
825 XVisualInfo* xvi = XGetVisualInfo(QX11Info::display(), VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi);
830 #ifndef QT_NO_XRENDER
832 for (int idx = 0; idx < nvi; ++idx) {
833 XRenderPictFormat* format = XRenderFindVisualFormat(QX11Info::display(), xvi[idx].visual);
834 if (format->type == PictTypeDirect && format->direct.alphaMask) {
835 *visual = xvi[idx].visual;
840 #endif // QT_NO_XRENDER
841 *visual = xvi[0].visual;
846 *colormap = XCreateColormap(QX11Info::display(), QX11Info::appRootWindow(), *visual, AllocNone);
849 bool PluginView::platformStart()
852 ASSERT(m_status == PluginStatusLoadedSuccessfully);
854 if (m_plugin->pluginFuncs()->getvalue) {
855 PluginView::setCurrentPluginView(this);
857 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
859 setCallingPlugin(true);
860 m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed);
861 setCallingPlugin(false);
862 PluginView::setCurrentPluginView(0);
866 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
867 if (m_needsXEmbed && client) {
868 setPlatformWidget(new PluginContainerQt(this, client->ownerWidget()));
869 // sync our XEmbed container window creation before sending the xid to plugins.
870 QApplication::syncX();
873 m_status = PluginStatusCanNotLoadPlugin;
877 setPlatformWidget(0);
878 m_pluginDisplay = getPluginDisplay();
880 #if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER)
881 if (shouldUseAcceleratedCompositing()) {
882 m_platformLayer = adoptPtr(new PluginGraphicsLayerQt(this));
883 // Trigger layer computation in RenderLayerCompositor
884 m_element->setNeedsStyleRecalc(SyntheticStyleChange);
889 // If the width and the height are not zero we show the PluginView.
890 if (!frameRect().isEmpty())
893 NPSetWindowCallbackStruct* wsi = new NPSetWindowCallbackStruct();
897 const QX11Info* x11Info = &static_cast<QWidget*>(platformPluginWidget())->x11Info();
899 wsi->display = x11Info->display();
900 wsi->visual = (Visual*)x11Info->visual();
901 wsi->depth = x11Info->depth();
902 wsi->colormap = x11Info->colormap();
904 m_npWindow.type = NPWindowTypeWindow;
905 m_npWindow.window = (void*)static_cast<QWidget*>(platformPluginWidget())->winId();
906 m_npWindow.width = -1;
907 m_npWindow.height = -1;
909 const QX11Info* x11Info = &QApplication::desktop()->x11Info();
911 if (x11Info->depth() == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) {
912 getVisualAndColormap(32, &m_visual, &m_colormap);
917 getVisualAndColormap(x11Info->depth(), &m_visual, &m_colormap);
918 wsi->depth = x11Info->depth();
921 wsi->display = x11Info->display();
922 wsi->visual = m_visual;
923 wsi->colormap = m_colormap;
925 m_npWindow.type = NPWindowTypeDrawable;
926 m_npWindow.window = 0; // Not used?
929 m_npWindow.width = -1;
930 m_npWindow.height = -1;
933 m_npWindow.ws_info = wsi;
935 if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) {
936 updatePluginWidget();
937 setNPWindowIfNeeded();
943 void PluginView::platformDestroy()
945 if (platformPluginWidget())
946 delete platformPluginWidget();
949 XFreePixmap(QX11Info::display(), m_drawable);
952 XFreeColormap(QX11Info::display(), m_colormap);
955 #if USE(ACCELERATED_COMPOSITING)
956 PlatformLayer* PluginView::platformLayer() const
958 return m_platformLayer.get();
962 } // namespace WebCore