| /* |
| * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
| * Copyright (C) 2008 Collabora Ltd. All rights reserved. |
| * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in> |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "PluginView.h" |
| |
| #include "Bridge.h" |
| #include "Document.h" |
| #include "DocumentLoader.h" |
| #include "Element.h" |
| #include "FloatPoint.h" |
| #include "FocusController.h" |
| #include "Frame.h" |
| #include "FrameLoadRequest.h" |
| #include "FrameLoader.h" |
| #include "FrameTree.h" |
| #include "FrameView.h" |
| #include "GraphicsContext.h" |
| #include "HTMLNames.h" |
| #include "HTMLPlugInElement.h" |
| #include "HostWindow.h" |
| #include "Image.h" |
| #include "JSDOMBinding.h" |
| #include "KeyboardEvent.h" |
| #include "MouseEvent.h" |
| #include "NotImplemented.h" |
| #include "Page.h" |
| #include "PlatformMouseEvent.h" |
| #include "PlatformKeyboardEvent.h" |
| #include "PluginContainerQt.h" |
| #include "PluginDebug.h" |
| #include "PluginPackage.h" |
| #include "PluginMainThreadScheduler.h" |
| #include "QWebPageClient.h" |
| #include "RenderLayer.h" |
| #include "ScriptController.h" |
| #include "Settings.h" |
| #include "npruntime_impl.h" |
| #include "qwebpage_p.h" |
| #include "runtime_root.h" |
| |
| #include <QApplication> |
| #include <QDesktopWidget> |
| #include <QKeyEvent> |
| #include <QPainter> |
| #include <QWidget> |
| #include <QX11Info> |
| #include <X11/X.h> |
| #ifndef QT_NO_XRENDER |
| #define Bool int |
| #define Status int |
| #include <X11/extensions/Xrender.h> |
| #endif |
| #include <runtime/JSLock.h> |
| #include <runtime/JSValue.h> |
| |
| using JSC::ExecState; |
| using JSC::Interpreter; |
| using JSC::JSLock; |
| using JSC::JSObject; |
| using JSC::UString; |
| |
| using std::min; |
| |
| using namespace WTF; |
| |
| namespace WebCore { |
| |
| using namespace HTMLNames; |
| |
| void PluginView::updatePluginWidget() |
| { |
| if (!parent()) |
| return; |
| |
| ASSERT(parent()->isFrameView()); |
| FrameView* frameView = static_cast<FrameView*>(parent()); |
| |
| IntRect oldWindowRect = m_windowRect; |
| IntRect oldClipRect = m_clipRect; |
| |
| m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); |
| m_clipRect = windowClipRect(); |
| m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); |
| |
| if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect) |
| return; |
| |
| if (!m_isWindowed && m_windowRect.size() != oldWindowRect.size()) { |
| #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5) |
| // On Maemo5, Flash always renders to 16-bit buffer |
| if (m_renderToImage) |
| m_image = QImage(m_windowRect.width(), m_windowRect.height(), QImage::Format_RGB16); |
| else |
| #endif |
| { |
| if (m_drawable) |
| XFreePixmap(QX11Info::display(), m_drawable); |
| |
| m_drawable = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), m_windowRect.width(), m_windowRect.height(), |
| ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth); |
| QApplication::syncX(); // make sure that the server knows about the Drawable |
| } |
| } |
| |
| // do not call setNPWindowIfNeeded immediately, will be called on paint() |
| m_hasPendingGeometryChange = true; |
| |
| // (i) in order to move/resize the plugin window at the same time as the |
| // rest of frame during e.g. scrolling, we set the window geometry |
| // in the paint() function, but as paint() isn't called when the |
| // plugin window is outside the frame which can be caused by a |
| // scroll, we need to move/resize immediately. |
| // (ii) if we are running layout tests from DRT, paint() won't ever get called |
| // so we need to call setNPWindowIfNeeded() if window geometry has changed |
| if (!m_windowRect.intersects(frameView->frameRect()) |
| || (QWebPagePrivate::drtRun && platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect))) |
| setNPWindowIfNeeded(); |
| |
| // Make sure we get repainted afterwards. This is necessary for downward |
| // scrolling to move the plugin widget properly. |
| invalidate(); |
| } |
| |
| void PluginView::setFocus(bool focused) |
| { |
| if (platformPluginWidget()) { |
| if (focused) |
| platformPluginWidget()->setFocus(Qt::OtherFocusReason); |
| } else { |
| Widget::setFocus(focused); |
| } |
| } |
| |
| void PluginView::show() |
| { |
| Q_ASSERT(platformPluginWidget() == platformWidget()); |
| Widget::show(); |
| } |
| |
| void PluginView::hide() |
| { |
| Q_ASSERT(platformPluginWidget() == platformWidget()); |
| Widget::hide(); |
| } |
| |
| #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5) |
| void PluginView::paintUsingImageSurfaceExtension(QPainter* painter, const IntRect& exposedRect) |
| { |
| NPImageExpose imageExpose; |
| QPoint offset; |
| QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); |
| const bool surfaceHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent()); |
| |
| QPaintDevice* surface = QPainter::redirected(painter->device(), &offset); |
| |
| // If the surface is a QImage, we can render directly into it |
| if (surfaceHasUntransformedContents && surface && surface->devType() == QInternal::Image) { |
| QImage* image = static_cast<QImage*>(surface); |
| offset = -offset; // negating the offset gives us the offset of the view within the surface |
| imageExpose.data = reinterpret_cast<char*>(image->bits()); |
| imageExpose.dataSize.width = image->width(); |
| imageExpose.dataSize.height = image->height(); |
| imageExpose.stride = image->bytesPerLine(); |
| imageExpose.depth = image->depth(); // this is guaranteed to be 16 on Maemo5 |
| imageExpose.translateX = offset.x() + m_windowRect.x(); |
| imageExpose.translateY = offset.y() + m_windowRect.y(); |
| imageExpose.scaleX = 1; |
| imageExpose.scaleY = 1; |
| } else { |
| if (m_isTransparent) { |
| // On Maemo5, Flash expects the buffer to contain the contents that are below it. |
| // We don't support transparency for non-raster graphicssystem, so clean the image |
| // before giving to Flash. |
| QPainter imagePainter(&m_image); |
| imagePainter.fillRect(exposedRect, Qt::white); |
| } |
| |
| imageExpose.data = reinterpret_cast<char*>(m_image.bits()); |
| imageExpose.dataSize.width = m_image.width(); |
| imageExpose.dataSize.height = m_image.height(); |
| imageExpose.stride = m_image.bytesPerLine(); |
| imageExpose.depth = m_image.depth(); |
| imageExpose.translateX = 0; |
| imageExpose.translateY = 0; |
| imageExpose.scaleX = 1; |
| imageExpose.scaleY = 1; |
| } |
| imageExpose.x = exposedRect.x(); |
| imageExpose.y = exposedRect.y(); |
| imageExpose.width = exposedRect.width(); |
| imageExpose.height = exposedRect.height(); |
| |
| XEvent xevent; |
| memset(&xevent, 0, sizeof(XEvent)); |
| XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose; |
| exposeEvent.type = GraphicsExpose; |
| exposeEvent.display = 0; |
| exposeEvent.drawable = reinterpret_cast<XID>(&imageExpose); |
| exposeEvent.x = exposedRect.x(); |
| exposeEvent.y = exposedRect.y(); |
| exposeEvent.width = exposedRect.width(); |
| exposeEvent.height = exposedRect.height(); |
| |
| dispatchNPEvent(xevent); |
| |
| if (!surfaceHasUntransformedContents || !surface || surface->devType() != QInternal::Image) |
| painter->drawImage(QPoint(frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y()), m_image, exposedRect); |
| } |
| #endif |
| |
| void PluginView::paint(GraphicsContext* context, const IntRect& rect) |
| { |
| if (!m_isStarted) { |
| paintMissingPluginIcon(context, rect); |
| return; |
| } |
| |
| if (context->paintingDisabled()) |
| return; |
| |
| setNPWindowIfNeeded(); |
| |
| if (m_isWindowed) |
| return; |
| |
| if (!m_drawable |
| #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5) |
| && m_image.isNull() |
| #endif |
| ) |
| return; |
| |
| QPainter* painter = context->platformContext(); |
| IntRect exposedRect(rect); |
| exposedRect.intersect(frameRect()); |
| exposedRect.move(-frameRect().x(), -frameRect().y()); |
| |
| #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5) |
| if (!m_image.isNull()) { |
| paintUsingImageSurfaceExtension(painter, exposedRect); |
| return; |
| } |
| #endif |
| |
| QPixmap qtDrawable = QPixmap::fromX11Pixmap(m_drawable, QPixmap::ExplicitlyShared); |
| const int drawableDepth = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth; |
| ASSERT(drawableDepth == qtDrawable.depth()); |
| const bool syncX = m_pluginDisplay && m_pluginDisplay != QX11Info::display(); |
| |
| // When printing, Qt uses a QPicture to capture the output in preview mode. The |
| // QPicture holds a reference to the X Pixmap. As a result, the print preview would |
| // update itself when the X Pixmap changes. To prevent this, we create a copy. |
| if (m_element->document()->printing()) |
| qtDrawable = qtDrawable.copy(); |
| |
| if (m_isTransparent && drawableDepth != 32) { |
| // Attempt content propagation for drawable with no alpha by copying over from the backing store |
| QPoint offset; |
| QPaintDevice* backingStoreDevice = QPainter::redirected(painter->device(), &offset); |
| offset = -offset; // negating the offset gives us the offset of the view within the backing store pixmap |
| |
| const bool hasValidBackingStore = backingStoreDevice && backingStoreDevice->devType() == QInternal::Pixmap; |
| QPixmap* backingStorePixmap = static_cast<QPixmap*>(backingStoreDevice); |
| |
| // We cannot grab contents from the backing store when painting on QGraphicsView items |
| // (because backing store contents are already transformed). What we really mean to do |
| // here is to check if we are painting on QWebView, but let's be a little permissive :) |
| QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); |
| const bool backingStoreHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent()); |
| |
| if (hasValidBackingStore && backingStorePixmap->depth() == drawableDepth |
| && backingStoreHasUntransformedContents) { |
| GC gc = XDefaultGC(QX11Info::display(), QX11Info::appScreen()); |
| XCopyArea(QX11Info::display(), backingStorePixmap->handle(), m_drawable, gc, |
| offset.x() + m_windowRect.x() + exposedRect.x(), offset.y() + m_windowRect.y() + exposedRect.y(), |
| exposedRect.width(), exposedRect.height(), exposedRect.x(), exposedRect.y()); |
| } else { // no backing store, clean the pixmap because the plugin thinks its transparent |
| QPainter painter(&qtDrawable); |
| painter.fillRect(exposedRect, Qt::white); |
| } |
| |
| if (syncX) |
| QApplication::syncX(); |
| } |
| |
| XEvent xevent; |
| memset(&xevent, 0, sizeof(XEvent)); |
| XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose; |
| exposeEvent.type = GraphicsExpose; |
| exposeEvent.display = QX11Info::display(); |
| exposeEvent.drawable = qtDrawable.handle(); |
| exposeEvent.x = exposedRect.x(); |
| exposeEvent.y = exposedRect.y(); |
| exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode |
| exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode |
| |
| dispatchNPEvent(xevent); |
| |
| if (syncX) |
| XSync(m_pluginDisplay, False); // sync changes by plugin |
| |
| painter->drawPixmap(QPoint(frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y()), qtDrawable, |
| exposedRect); |
| } |
| |
| // TODO: Unify across ports. |
| bool PluginView::dispatchNPEvent(NPEvent& event) |
| { |
| if (!m_plugin->pluginFuncs()->event) |
| return false; |
| |
| PluginView::setCurrentPluginView(this); |
| JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); |
| setCallingPlugin(true); |
| bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event); |
| setCallingPlugin(false); |
| PluginView::setCurrentPluginView(0); |
| |
| return accepted; |
| } |
| |
| void setSharedXEventFields(XEvent* xEvent, QWidget* ownerWidget) |
| { |
| xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server |
| xEvent->xany.send_event = false; |
| xEvent->xany.display = QX11Info::display(); |
| // NOTE: event->xany.window doesn't always respond to the .window property of other XEvent's |
| // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify |
| // events; thus, this is right: |
| xEvent->xany.window = ownerWidget ? ownerWidget->window()->handle() : 0; |
| } |
| |
| void PluginView::initXEvent(XEvent* xEvent) |
| { |
| memset(xEvent, 0, sizeof(XEvent)); |
| |
| QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); |
| QWidget* ownerWidget = client ? client->ownerWidget() : 0; |
| setSharedXEventFields(xEvent, ownerWidget); |
| } |
| |
| void setXKeyEventSpecificFields(XEvent* xEvent, KeyboardEvent* event) |
| { |
| QKeyEvent* qKeyEvent = event->keyEvent()->qtEvent(); |
| |
| xEvent->type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // ints as Qt unsets KeyPress and KeyRelease |
| xEvent->xkey.root = QX11Info::appRootWindow(); |
| xEvent->xkey.subwindow = 0; // we have no child window |
| xEvent->xkey.time = event->timeStamp(); |
| xEvent->xkey.state = qKeyEvent->nativeModifiers(); |
| xEvent->xkey.keycode = qKeyEvent->nativeScanCode(); |
| |
| // We may not have a nativeScanCode() if the key event is from DRT's eventsender. In that |
| // case just populate the XEvent's keycode with the Qt platform-independent keycode. The only |
| // place this keycode will be used is in webkit_test_plugin_handle_event(). |
| if (QWebPagePrivate::drtRun && !xEvent->xkey.keycode) { |
| if (!qKeyEvent->text().isEmpty()) |
| xEvent->xkey.keycode = int(qKeyEvent->text().at(0).unicode() + qKeyEvent->modifiers()); |
| else if (qKeyEvent->key() && (qKeyEvent->key() != Qt::Key_unknown)) |
| xEvent->xkey.keycode = int(qKeyEvent->key() + qKeyEvent->modifiers()); |
| } |
| |
| xEvent->xkey.same_screen = true; |
| |
| // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window |
| // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not |
| // set to their normal Xserver values. e.g. Key events don't have a position. |
| // source: https://developer.mozilla.org/en/NPEvent |
| xEvent->xkey.x = 0; |
| xEvent->xkey.y = 0; |
| xEvent->xkey.x_root = 0; |
| xEvent->xkey.y_root = 0; |
| } |
| |
| void PluginView::handleKeyboardEvent(KeyboardEvent* event) |
| { |
| if (m_isWindowed) |
| return; |
| |
| if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent) |
| return; |
| |
| XEvent npEvent; |
| initXEvent(&npEvent); |
| setXKeyEventSpecificFields(&npEvent, event); |
| |
| if (!dispatchNPEvent(npEvent)) |
| event->setDefaultHandled(); |
| } |
| |
| static unsigned int inputEventState(MouseEvent* event) |
| { |
| unsigned int state = 0; |
| if (event->ctrlKey()) |
| state |= ControlMask; |
| if (event->shiftKey()) |
| state |= ShiftMask; |
| if (event->altKey()) |
| state |= Mod1Mask; |
| if (event->metaKey()) |
| state |= Mod4Mask; |
| return state; |
| } |
| |
| static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos) |
| { |
| XButtonEvent& xbutton = xEvent->xbutton; |
| xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease; |
| xbutton.root = QX11Info::appRootWindow(); |
| xbutton.subwindow = 0; |
| xbutton.time = event->timeStamp(); |
| xbutton.x = postZoomPos.x(); |
| xbutton.y = postZoomPos.y(); |
| xbutton.x_root = event->screenX(); |
| xbutton.y_root = event->screenY(); |
| xbutton.state = inputEventState(event); |
| switch (event->button()) { |
| case MiddleButton: |
| xbutton.button = Button2; |
| break; |
| case RightButton: |
| xbutton.button = Button3; |
| break; |
| case LeftButton: |
| default: |
| xbutton.button = Button1; |
| break; |
| } |
| xbutton.same_screen = true; |
| } |
| |
| static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos) |
| { |
| XMotionEvent& xmotion = xEvent->xmotion; |
| xmotion.type = MotionNotify; |
| xmotion.root = QX11Info::appRootWindow(); |
| xmotion.subwindow = 0; |
| xmotion.time = event->timeStamp(); |
| xmotion.x = postZoomPos.x(); |
| xmotion.y = postZoomPos.y(); |
| xmotion.x_root = event->screenX(); |
| xmotion.y_root = event->screenY(); |
| xmotion.state = inputEventState(event); |
| xmotion.is_hint = NotifyNormal; |
| xmotion.same_screen = true; |
| } |
| |
| static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos) |
| { |
| XCrossingEvent& xcrossing = xEvent->xcrossing; |
| xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify; |
| xcrossing.root = QX11Info::appRootWindow(); |
| xcrossing.subwindow = 0; |
| xcrossing.time = event->timeStamp(); |
| xcrossing.x = postZoomPos.y(); |
| xcrossing.y = postZoomPos.x(); |
| xcrossing.x_root = event->screenX(); |
| xcrossing.y_root = event->screenY(); |
| xcrossing.state = inputEventState(event); |
| xcrossing.mode = NotifyNormal; |
| xcrossing.detail = NotifyDetailNone; |
| xcrossing.same_screen = true; |
| xcrossing.focus = false; |
| } |
| |
| void PluginView::handleMouseEvent(MouseEvent* event) |
| { |
| if (m_isWindowed) |
| return; |
| |
| if (event->type() == eventNames().mousedownEvent) { |
| // Give focus to the plugin on click |
| if (Page* page = m_parentFrame->page()) |
| page->focusController()->setActive(true); |
| |
| focusPluginElement(); |
| } |
| |
| XEvent npEvent; |
| initXEvent(&npEvent); |
| |
| IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation())); |
| |
| if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent) |
| setXButtonEventSpecificFields(&npEvent, event, postZoomPos); |
| else if (event->type() == eventNames().mousemoveEvent) |
| setXMotionEventSpecificFields(&npEvent, event, postZoomPos); |
| else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent) |
| setXCrossingEventSpecificFields(&npEvent, event, postZoomPos); |
| else |
| return; |
| |
| if (!dispatchNPEvent(npEvent)) |
| event->setDefaultHandled(); |
| } |
| |
| void PluginView::handleFocusInEvent() |
| { |
| XEvent npEvent; |
| initXEvent(&npEvent); |
| |
| XFocusChangeEvent& event = npEvent.xfocus; |
| event.type = 9; /* int as Qt unsets FocusIn */ |
| event.mode = NotifyNormal; |
| event.detail = NotifyDetailNone; |
| |
| dispatchNPEvent(npEvent); |
| } |
| |
| void PluginView::handleFocusOutEvent() |
| { |
| XEvent npEvent; |
| initXEvent(&npEvent); |
| |
| XFocusChangeEvent& event = npEvent.xfocus; |
| event.type = 10; /* int as Qt unsets FocusOut */ |
| event.mode = NotifyNormal; |
| event.detail = NotifyDetailNone; |
| |
| dispatchNPEvent(npEvent); |
| } |
| |
| void PluginView::setParent(ScrollView* parent) |
| { |
| Widget::setParent(parent); |
| |
| if (parent) |
| init(); |
| } |
| |
| void PluginView::setNPWindowRect(const IntRect&) |
| { |
| if (!m_isWindowed) |
| setNPWindowIfNeeded(); |
| } |
| |
| void PluginView::setNPWindowIfNeeded() |
| { |
| if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow) |
| return; |
| |
| // If the plugin didn't load sucessfully, no point in calling setwindow |
| if (m_status != PluginStatusLoadedSuccessfully) |
| return; |
| |
| // On Unix, only call plugin if it's full-page or windowed |
| if (m_mode != NP_FULL && m_mode != NP_EMBED) |
| return; |
| |
| // Check if the platformPluginWidget still exists |
| if (m_isWindowed && !platformPluginWidget()) |
| return; |
| |
| if (!m_hasPendingGeometryChange) |
| return; |
| m_hasPendingGeometryChange = false; |
| |
| if (m_isWindowed) { |
| platformPluginWidget()->setGeometry(m_windowRect); |
| // if setMask is set with an empty QRegion, no clipping will |
| // be performed, so in that case we hide the plugin view |
| platformPluginWidget()->setVisible(!m_clipRect.isEmpty()); |
| platformPluginWidget()->setMask(QRegion(m_clipRect)); |
| |
| m_npWindow.x = m_windowRect.x(); |
| m_npWindow.y = m_windowRect.y(); |
| } else { |
| m_npWindow.x = 0; |
| m_npWindow.y = 0; |
| } |
| |
| // If the width or height are null, set the clipRect to null, indicating that |
| // the plugin is not visible/scrolled out. |
| if (!m_clipRect.width() || !m_clipRect.height()) { |
| m_npWindow.clipRect.left = 0; |
| m_npWindow.clipRect.right = 0; |
| m_npWindow.clipRect.top = 0; |
| m_npWindow.clipRect.bottom = 0; |
| } else { |
| // Clipping rectangle of the plug-in; the origin is the top left corner of the drawable or window. |
| m_npWindow.clipRect.left = m_npWindow.x + m_clipRect.x(); |
| m_npWindow.clipRect.top = m_npWindow.y + m_clipRect.y(); |
| m_npWindow.clipRect.right = m_npWindow.x + m_clipRect.x() + m_clipRect.width(); |
| m_npWindow.clipRect.bottom = m_npWindow.y + m_clipRect.y() + m_clipRect.height(); |
| } |
| |
| if (m_plugin->quirks().contains(PluginQuirkDontCallSetWindowMoreThanOnce)) { |
| // FLASH WORKAROUND: Only set initially. Multiple calls to |
| // setNPWindow() cause the plugin to crash in windowed mode. |
| if (!m_isWindowed || m_npWindow.width == -1 || m_npWindow.height == -1) { |
| m_npWindow.width = m_windowRect.width(); |
| m_npWindow.height = m_windowRect.height(); |
| } |
| } else { |
| m_npWindow.width = m_windowRect.width(); |
| m_npWindow.height = m_windowRect.height(); |
| } |
| |
| PluginView::setCurrentPluginView(this); |
| JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); |
| setCallingPlugin(true); |
| m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); |
| setCallingPlugin(false); |
| PluginView::setCurrentPluginView(0); |
| } |
| |
| void PluginView::setParentVisible(bool visible) |
| { |
| if (isParentVisible() == visible) |
| return; |
| |
| Widget::setParentVisible(visible); |
| |
| if (isSelfVisible() && platformPluginWidget()) |
| platformPluginWidget()->setVisible(visible); |
| } |
| |
| NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf) |
| { |
| String filename(buf, len); |
| |
| if (filename.startsWith("file:///")) |
| filename = filename.substring(8); |
| |
| long long size; |
| if (!getFileSize(filename, size)) |
| return NPERR_FILE_NOT_FOUND; |
| |
| FILE* fileHandle = fopen((filename.utf8()).data(), "r"); |
| if (!fileHandle) |
| return NPERR_FILE_NOT_FOUND; |
| |
| buffer.resize(size); |
| int bytesRead = fread(buffer.data(), 1, size, fileHandle); |
| |
| fclose(fileHandle); |
| |
| if (bytesRead <= 0) |
| return NPERR_FILE_NOT_FOUND; |
| |
| return NPERR_NO_ERROR; |
| } |
| |
| bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result) |
| { |
| switch (variable) { |
| case NPNVToolkit: |
| *static_cast<uint32_t*>(value) = 0; |
| *result = NPERR_NO_ERROR; |
| return true; |
| |
| case NPNVSupportsXEmbedBool: |
| *static_cast<NPBool*>(value) = true; |
| *result = NPERR_NO_ERROR; |
| return true; |
| |
| case NPNVjavascriptEnabledBool: |
| *static_cast<NPBool*>(value) = true; |
| *result = NPERR_NO_ERROR; |
| return true; |
| |
| case NPNVSupportsWindowless: |
| *static_cast<NPBool*>(value) = true; |
| *result = NPERR_NO_ERROR; |
| return true; |
| |
| #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5) |
| case NPNVSupportsWindowlessLocal: |
| *static_cast<NPBool*>(value) = true; |
| *result = NPERR_NO_ERROR; |
| return true; |
| #endif |
| |
| default: |
| return false; |
| } |
| } |
| |
| bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result) |
| { |
| switch (variable) { |
| case NPNVxDisplay: |
| *(void **)value = QX11Info::display(); |
| *result = NPERR_NO_ERROR; |
| return true; |
| |
| case NPNVxtAppContext: |
| *result = NPERR_GENERIC_ERROR; |
| return true; |
| |
| case NPNVnetscapeWindow: { |
| void* w = reinterpret_cast<void*>(value); |
| QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); |
| *((XID *)w) = client ? client->ownerWidget()->window()->winId() : 0; |
| *result = NPERR_NO_ERROR; |
| return true; |
| } |
| |
| case NPNVToolkit: |
| if (m_plugin->quirks().contains(PluginQuirkRequiresGtkToolKit)) { |
| *((uint32_t *)value) = 2; |
| *result = NPERR_NO_ERROR; |
| return true; |
| } |
| return false; |
| |
| default: |
| return false; |
| } |
| } |
| |
| void PluginView::invalidateRect(const IntRect& rect) |
| { |
| if (m_isWindowed) { |
| if (platformWidget()) |
| platformWidget()->update(rect); |
| return; |
| } |
| |
| invalidateWindowlessPluginRect(rect); |
| } |
| |
| void PluginView::invalidateRect(NPRect* rect) |
| { |
| if (!rect) { |
| invalidate(); |
| return; |
| } |
| IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); |
| invalidateWindowlessPluginRect(r); |
| } |
| |
| void PluginView::invalidateRegion(NPRegion region) |
| { |
| invalidate(); |
| } |
| |
| void PluginView::forceRedraw() |
| { |
| invalidate(); |
| } |
| |
| static Display *getPluginDisplay() |
| { |
| // The plugin toolkit might run using a different X connection. At the moment, we only |
| // support gdk based plugins (like flash) that use a different X connection. |
| // The code below has the same effect as this one: |
| // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default()); |
| QLibrary library("libgdk-x11-2.0", 0); |
| if (!library.load()) |
| return 0; |
| |
| typedef void *(*gdk_display_get_default_ptr)(); |
| gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default"); |
| if (!gdk_display_get_default) |
| return 0; |
| |
| typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *); |
| gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay"); |
| if (!gdk_x11_display_get_xdisplay) |
| return 0; |
| |
| return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default()); |
| } |
| |
| static void getVisualAndColormap(int depth, Visual **visual, Colormap *colormap) |
| { |
| *visual = 0; |
| *colormap = 0; |
| |
| #ifndef QT_NO_XRENDER |
| static const bool useXRender = qgetenv("QT_X11_NO_XRENDER").isNull(); // Should also check for XRender >= 0.5 |
| #else |
| static const bool useXRender = false; |
| #endif |
| |
| if (!useXRender && depth == 32) |
| return; |
| |
| int nvi; |
| XVisualInfo templ; |
| templ.screen = QX11Info::appScreen(); |
| templ.depth = depth; |
| templ.c_class = TrueColor; |
| XVisualInfo* xvi = XGetVisualInfo(QX11Info::display(), VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi); |
| |
| if (!xvi) |
| return; |
| |
| #ifndef QT_NO_XRENDER |
| if (depth == 32) { |
| for (int idx = 0; idx < nvi; ++idx) { |
| XRenderPictFormat* format = XRenderFindVisualFormat(QX11Info::display(), xvi[idx].visual); |
| if (format->type == PictTypeDirect && format->direct.alphaMask) { |
| *visual = xvi[idx].visual; |
| break; |
| } |
| } |
| } else |
| #endif // QT_NO_XRENDER |
| *visual = xvi[0].visual; |
| |
| XFree(xvi); |
| |
| if (*visual) |
| *colormap = XCreateColormap(QX11Info::display(), QX11Info::appRootWindow(), *visual, AllocNone); |
| } |
| |
| bool PluginView::platformStart() |
| { |
| ASSERT(m_isStarted); |
| ASSERT(m_status == PluginStatusLoadedSuccessfully); |
| |
| if (m_plugin->pluginFuncs()->getvalue) { |
| PluginView::setCurrentPluginView(this); |
| JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); |
| setCallingPlugin(true); |
| m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed); |
| setCallingPlugin(false); |
| PluginView::setCurrentPluginView(0); |
| } |
| |
| if (m_isWindowed) { |
| QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); |
| if (m_needsXEmbed && client) { |
| setPlatformWidget(new PluginContainerQt(this, client->ownerWidget())); |
| // sync our XEmbed container window creation before sending the xid to plugins. |
| QApplication::syncX(); |
| } else { |
| notImplemented(); |
| m_status = PluginStatusCanNotLoadPlugin; |
| return false; |
| } |
| } else { |
| setPlatformWidget(0); |
| m_pluginDisplay = getPluginDisplay(); |
| } |
| |
| show(); |
| |
| NPSetWindowCallbackStruct* wsi = new NPSetWindowCallbackStruct(); |
| wsi->type = 0; |
| |
| if (m_isWindowed) { |
| const QX11Info* x11Info = &platformPluginWidget()->x11Info(); |
| |
| wsi->display = x11Info->display(); |
| wsi->visual = (Visual*)x11Info->visual(); |
| wsi->depth = x11Info->depth(); |
| wsi->colormap = x11Info->colormap(); |
| |
| m_npWindow.type = NPWindowTypeWindow; |
| m_npWindow.window = (void*)platformPluginWidget()->winId(); |
| m_npWindow.width = -1; |
| m_npWindow.height = -1; |
| } else { |
| const QX11Info* x11Info = &QApplication::desktop()->x11Info(); |
| |
| if (x11Info->depth() == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) { |
| getVisualAndColormap(32, &m_visual, &m_colormap); |
| wsi->depth = 32; |
| } |
| |
| if (!m_visual) { |
| getVisualAndColormap(x11Info->depth(), &m_visual, &m_colormap); |
| wsi->depth = x11Info->depth(); |
| } |
| |
| wsi->display = x11Info->display(); |
| wsi->visual = m_visual; |
| wsi->colormap = m_colormap; |
| |
| m_npWindow.type = NPWindowTypeDrawable; |
| m_npWindow.window = 0; // Not used? |
| m_npWindow.x = 0; |
| m_npWindow.y = 0; |
| m_npWindow.width = -1; |
| m_npWindow.height = -1; |
| } |
| |
| m_npWindow.ws_info = wsi; |
| |
| if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) { |
| updatePluginWidget(); |
| setNPWindowIfNeeded(); |
| } |
| |
| return true; |
| } |
| |
| void PluginView::platformDestroy() |
| { |
| if (platformPluginWidget()) |
| delete platformPluginWidget(); |
| |
| if (m_drawable) |
| XFreePixmap(QX11Info::display(), m_drawable); |
| |
| if (m_colormap) |
| XFreeColormap(QX11Info::display(), m_colormap); |
| } |
| |
| void PluginView::halt() |
| { |
| } |
| |
| void PluginView::restart() |
| { |
| } |
| |
| } // namespace WebCore |