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"
69 #include "qwebpage_p.h"
71 #include "runtime_root.h"
74 #include <QApplication>
75 #include <QDesktopWidget>
76 #include <QGraphicsWidget>
79 #include <QStyleOptionGraphicsItem>
86 #include <X11/extensions/Xrender.h>
88 #include <runtime/JSLock.h>
89 #include <runtime/JSValue.h>
93 using JSC::Interpreter;
105 using namespace HTMLNames;
107 #if USE(ACCELERATED_COMPOSITING)
108 // Qt's GraphicsLayer (GraphicsLayerQt) requires layers to be QGraphicsWidgets
109 class PluginGraphicsLayerQt : public QGraphicsWidget {
111 PluginGraphicsLayerQt(PluginView* view) : m_view(view) { }
112 ~PluginGraphicsLayerQt() { }
114 void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0)
117 m_view->paintUsingXPixmap(painter, option->exposedRect.toRect());
124 bool PluginView::shouldUseAcceleratedCompositing() const
126 return m_parentFrame->page()->chrome()->client()->allowsAcceleratedCompositing()
127 && m_parentFrame->page()->settings()
128 && m_parentFrame->page()->settings()->acceleratedCompositingEnabled();
132 void PluginView::updatePluginWidget()
137 ASSERT(parent()->isFrameView());
138 FrameView* frameView = static_cast<FrameView*>(parent());
140 IntRect oldWindowRect = m_windowRect;
141 IntRect oldClipRect = m_clipRect;
143 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
144 m_clipRect = windowClipRect();
145 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
147 if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
150 // The plugin had a zero width or height before but was resized, we need to show it again.
151 if (oldWindowRect.isEmpty())
154 if (!m_isWindowed && m_windowRect.size() != oldWindowRect.size()) {
155 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
156 // On Maemo5, Flash always renders to 16-bit buffer
158 m_image = QImage(m_windowRect.width(), m_windowRect.height(), QImage::Format_RGB16);
163 XFreePixmap(QX11Info::display(), m_drawable);
165 m_drawable = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), m_windowRect.width(), m_windowRect.height(),
166 ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth);
167 QApplication::syncX(); // make sure that the server knows about the Drawable
171 // do not call setNPWindowIfNeeded immediately, will be called on paint()
172 m_hasPendingGeometryChange = true;
174 // (i) in order to move/resize the plugin window at the same time as the
175 // rest of frame during e.g. scrolling, we set the window geometry
176 // in the paint() function, but as paint() isn't called when the
177 // plugin window is outside the frame which can be caused by a
178 // scroll, we need to move/resize immediately.
179 // (ii) if we are running layout tests from DRT, paint() won't ever get called
180 // so we need to call setNPWindowIfNeeded() if window geometry has changed
181 if (!m_windowRect.intersects(frameView->frameRect())
182 || (QWebPagePrivate::drtRun && platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)))
183 setNPWindowIfNeeded();
185 if (!m_platformLayer) {
186 // Make sure we get repainted afterwards. This is necessary for downward
187 // scrolling to move the plugin widget properly.
188 // Note that we don't invalidate the frameRect() here. This is because QWebFrame::renderRelativeCoords()
189 // imitates ScrollView and adds the scroll offset back on to the rect we damage here (making the co-ordinates absolute
190 // to the frame again) before passing it to FrameView.
195 void PluginView::setFocus(bool focused)
197 if (platformPluginWidget()) {
199 platformPluginWidget()->setFocus(Qt::OtherFocusReason);
201 Widget::setFocus(focused);
205 void PluginView::show()
207 Q_ASSERT(platformPluginWidget() == platformWidget());
211 void PluginView::hide()
213 Q_ASSERT(platformPluginWidget() == platformWidget());
217 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
218 void PluginView::paintUsingImageSurfaceExtension(QPainter* painter, const IntRect& exposedRect)
220 NPImageExpose imageExpose;
222 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
223 const bool surfaceHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent());
225 QPaintDevice* surface = QPainter::redirected(painter->device(), &offset);
227 // If the surface is a QImage, we can render directly into it
228 if (surfaceHasUntransformedContents && surface && surface->devType() == QInternal::Image) {
229 QImage* image = static_cast<QImage*>(surface);
230 offset = -offset; // negating the offset gives us the offset of the view within the surface
231 imageExpose.data = reinterpret_cast<char*>(image->bits());
232 imageExpose.dataSize.width = image->width();
233 imageExpose.dataSize.height = image->height();
234 imageExpose.stride = image->bytesPerLine();
235 imageExpose.depth = image->depth(); // this is guaranteed to be 16 on Maemo5
236 imageExpose.translateX = offset.x() + m_windowRect.x();
237 imageExpose.translateY = offset.y() + m_windowRect.y();
238 imageExpose.scaleX = 1;
239 imageExpose.scaleY = 1;
241 if (m_isTransparent) {
242 // On Maemo5, Flash expects the buffer to contain the contents that are below it.
243 // We don't support transparency for non-raster graphicssystem, so clean the image
244 // before giving to Flash.
245 QPainter imagePainter(&m_image);
246 imagePainter.fillRect(exposedRect, Qt::white);
249 imageExpose.data = reinterpret_cast<char*>(m_image.bits());
250 imageExpose.dataSize.width = m_image.width();
251 imageExpose.dataSize.height = m_image.height();
252 imageExpose.stride = m_image.bytesPerLine();
253 imageExpose.depth = m_image.depth();
254 imageExpose.translateX = 0;
255 imageExpose.translateY = 0;
256 imageExpose.scaleX = 1;
257 imageExpose.scaleY = 1;
259 imageExpose.x = exposedRect.x();
260 imageExpose.y = exposedRect.y();
261 imageExpose.width = exposedRect.width();
262 imageExpose.height = exposedRect.height();
265 memset(&xevent, 0, sizeof(XEvent));
266 XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
267 exposeEvent.type = GraphicsExpose;
268 exposeEvent.display = 0;
269 exposeEvent.drawable = reinterpret_cast<XID>(&imageExpose);
270 exposeEvent.x = exposedRect.x();
271 exposeEvent.y = exposedRect.y();
272 exposeEvent.width = exposedRect.width();
273 exposeEvent.height = exposedRect.height();
275 dispatchNPEvent(xevent);
277 if (!surfaceHasUntransformedContents || !surface || surface->devType() != QInternal::Image)
278 painter->drawImage(QPoint(frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y()), m_image, exposedRect);
282 void PluginView::paintUsingXPixmap(QPainter* painter, const QRect &exposedRect)
284 QPixmap qtDrawable = QPixmap::fromX11Pixmap(m_drawable, QPixmap::ExplicitlyShared);
285 const int drawableDepth = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth;
286 ASSERT(drawableDepth == qtDrawable.depth());
287 const bool syncX = m_pluginDisplay && m_pluginDisplay != QX11Info::display();
289 // When printing, Qt uses a QPicture to capture the output in preview mode. The
290 // QPicture holds a reference to the X Pixmap. As a result, the print preview would
291 // update itself when the X Pixmap changes. To prevent this, we create a copy.
292 if (m_element->document()->printing())
293 qtDrawable = qtDrawable.copy();
295 if (m_isTransparent && drawableDepth != 32) {
296 // Attempt content propagation for drawable with no alpha by copying over from the backing store
298 QPaintDevice* backingStoreDevice = QPainter::redirected(painter->device(), &offset);
299 offset = -offset; // negating the offset gives us the offset of the view within the backing store pixmap
301 const bool hasValidBackingStore = backingStoreDevice && backingStoreDevice->devType() == QInternal::Pixmap;
302 QPixmap* backingStorePixmap = static_cast<QPixmap*>(backingStoreDevice);
304 // We cannot grab contents from the backing store when painting on QGraphicsView items
305 // (because backing store contents are already transformed). What we really mean to do
306 // here is to check if we are painting on QWebView, but let's be a little permissive :)
307 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
308 const bool backingStoreHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent());
310 if (hasValidBackingStore && backingStorePixmap->depth() == drawableDepth
311 && backingStoreHasUntransformedContents) {
312 GC gc = XDefaultGC(QX11Info::display(), QX11Info::appScreen());
313 XCopyArea(QX11Info::display(), backingStorePixmap->handle(), m_drawable, gc,
314 offset.x() + m_windowRect.x() + exposedRect.x(), offset.y() + m_windowRect.y() + exposedRect.y(),
315 exposedRect.width(), exposedRect.height(), exposedRect.x(), exposedRect.y());
316 } else { // no backing store, clean the pixmap because the plugin thinks its transparent
317 QPainter painter(&qtDrawable);
318 painter.fillRect(exposedRect, Qt::white);
322 QApplication::syncX();
326 memset(&xevent, 0, sizeof(XEvent));
327 XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
328 exposeEvent.type = GraphicsExpose;
329 exposeEvent.display = QX11Info::display();
330 exposeEvent.drawable = qtDrawable.handle();
331 exposeEvent.x = exposedRect.x();
332 exposeEvent.y = exposedRect.y();
333 exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode
334 exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode
336 dispatchNPEvent(xevent);
339 XSync(m_pluginDisplay, false); // sync changes by plugin
341 painter->drawPixmap(QPoint(exposedRect.x(), exposedRect.y()), qtDrawable, exposedRect);
344 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
347 paintMissingPluginIcon(context, rect);
351 if (context->paintingDisabled())
354 setNPWindowIfNeeded();
359 #if USE(ACCELERATED_COMPOSITING)
365 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
371 QPainter* painter = context->platformContext();
372 IntRect exposedRect(rect);
373 exposedRect.intersect(frameRect());
374 exposedRect.move(-frameRect().x(), -frameRect().y());
376 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
377 if (!m_image.isNull()) {
378 paintUsingImageSurfaceExtension(painter, exposedRect);
383 painter->translate(frameRect().x(), frameRect().y());
384 paintUsingXPixmap(painter, exposedRect);
385 painter->translate(-frameRect().x(), -frameRect().y());
388 // TODO: Unify across ports.
389 bool PluginView::dispatchNPEvent(NPEvent& event)
391 if (!m_plugin->pluginFuncs()->event)
394 bool shouldPop = false;
396 if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE
397 && (event.type == ButtonRelease || event.type == 3 /*KeyRelease*/)) {
398 pushPopupsEnabledState(true);
402 PluginView::setCurrentPluginView(this);
404 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
406 setCallingPlugin(true);
407 bool accepted = !m_plugin->pluginFuncs()->event(m_instance, &event);
408 setCallingPlugin(false);
409 PluginView::setCurrentPluginView(0);
412 popPopupsEnabledState();
417 void setSharedXEventFields(XEvent* xEvent, QWidget* ownerWidget)
419 xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server
420 xEvent->xany.send_event = false;
421 xEvent->xany.display = QX11Info::display();
422 // NOTE: event->xany.window doesn't always respond to the .window property of other XEvent's
423 // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify
424 // events; thus, this is right:
425 xEvent->xany.window = ownerWidget ? ownerWidget->window()->handle() : 0;
428 void PluginView::initXEvent(XEvent* xEvent)
430 memset(xEvent, 0, sizeof(XEvent));
432 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
433 QWidget* ownerWidget = client ? client->ownerWidget() : 0;
434 setSharedXEventFields(xEvent, ownerWidget);
437 void setXKeyEventSpecificFields(XEvent* xEvent, KeyboardEvent* event)
439 const PlatformKeyboardEvent* keyEvent = event->keyEvent();
441 xEvent->type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // ints as Qt unsets KeyPress and KeyRelease
442 xEvent->xkey.root = QX11Info::appRootWindow();
443 xEvent->xkey.subwindow = 0; // we have no child window
444 xEvent->xkey.time = event->timeStamp();
445 xEvent->xkey.state = keyEvent->nativeModifiers();
446 xEvent->xkey.keycode = keyEvent->nativeScanCode();
448 // We may not have a nativeScanCode() if the key event is from DRT's eventsender. In that
449 // case fetch the XEvent's keycode from the event's text. The only
450 // place this keycode will be used is in webkit_test_plugin_handle_event().
451 // FIXME: Create Qt API so that we can set the appropriate keycode in DRT EventSender instead.
452 if (QWebPagePrivate::drtRun && !xEvent->xkey.keycode) {
453 QKeyEvent* qKeyEvent = keyEvent->qtEvent();
455 QString keyText = qKeyEvent->text().left(1);
456 xEvent->xkey.keycode = XKeysymToKeycode(QX11Info::display(), XStringToKeysym(keyText.toUtf8().constData()));
459 xEvent->xkey.same_screen = true;
461 // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window
462 // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not
463 // set to their normal Xserver values. e.g. Key events don't have a position.
464 // source: https://developer.mozilla.org/en/NPEvent
467 xEvent->xkey.x_root = 0;
468 xEvent->xkey.y_root = 0;
471 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
476 if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent)
480 initXEvent(&npEvent);
481 setXKeyEventSpecificFields(&npEvent, event);
483 if (dispatchNPEvent(npEvent))
484 event->setDefaultHandled();
487 static unsigned int inputEventState(MouseEvent* event)
489 unsigned int state = 0;
490 if (event->ctrlKey())
491 state |= ControlMask;
492 if (event->shiftKey())
496 if (event->metaKey())
501 static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
503 XButtonEvent& xbutton = xEvent->xbutton;
504 xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease;
505 xbutton.root = QX11Info::appRootWindow();
506 xbutton.subwindow = 0;
507 xbutton.time = event->timeStamp();
508 xbutton.x = postZoomPos.x();
509 xbutton.y = postZoomPos.y();
510 xbutton.x_root = event->screenX();
511 xbutton.y_root = event->screenY();
512 xbutton.state = inputEventState(event);
513 switch (event->button()) {
515 xbutton.button = Button2;
518 xbutton.button = Button3;
522 xbutton.button = Button1;
525 xbutton.same_screen = true;
528 static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
530 XMotionEvent& xmotion = xEvent->xmotion;
531 xmotion.type = MotionNotify;
532 xmotion.root = QX11Info::appRootWindow();
533 xmotion.subwindow = 0;
534 xmotion.time = event->timeStamp();
535 xmotion.x = postZoomPos.x();
536 xmotion.y = postZoomPos.y();
537 xmotion.x_root = event->screenX();
538 xmotion.y_root = event->screenY();
539 xmotion.state = inputEventState(event);
540 xmotion.is_hint = NotifyNormal;
541 xmotion.same_screen = true;
544 static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
546 XCrossingEvent& xcrossing = xEvent->xcrossing;
547 xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify;
548 xcrossing.root = QX11Info::appRootWindow();
549 xcrossing.subwindow = 0;
550 xcrossing.time = event->timeStamp();
551 xcrossing.x = postZoomPos.y();
552 xcrossing.y = postZoomPos.x();
553 xcrossing.x_root = event->screenX();
554 xcrossing.y_root = event->screenY();
555 xcrossing.state = inputEventState(event);
556 xcrossing.mode = NotifyNormal;
557 xcrossing.detail = NotifyDetailNone;
558 xcrossing.same_screen = true;
559 xcrossing.focus = false;
562 void PluginView::handleMouseEvent(MouseEvent* event)
567 if (event->button() == RightButton && m_plugin->quirks().contains(PluginQuirkIgnoreRightClickInWindowlessMode))
570 if (event->type() == eventNames().mousedownEvent) {
571 // Give focus to the plugin on click
572 if (Page* page = m_parentFrame->page())
573 page->focusController()->setActive(true);
575 focusPluginElement();
579 initXEvent(&npEvent);
581 IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
583 if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
584 setXButtonEventSpecificFields(&npEvent, event, postZoomPos);
585 else if (event->type() == eventNames().mousemoveEvent)
586 setXMotionEventSpecificFields(&npEvent, event, postZoomPos);
587 else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent)
588 setXCrossingEventSpecificFields(&npEvent, event, postZoomPos);
592 if (dispatchNPEvent(npEvent))
593 event->setDefaultHandled();
596 void PluginView::handleFocusInEvent()
599 initXEvent(&npEvent);
601 XFocusChangeEvent& event = npEvent.xfocus;
602 event.type = 9; /* int as Qt unsets FocusIn */
603 event.mode = NotifyNormal;
604 event.detail = NotifyDetailNone;
606 dispatchNPEvent(npEvent);
609 void PluginView::handleFocusOutEvent()
612 initXEvent(&npEvent);
614 XFocusChangeEvent& event = npEvent.xfocus;
615 event.type = 10; /* int as Qt unsets FocusOut */
616 event.mode = NotifyNormal;
617 event.detail = NotifyDetailNone;
619 dispatchNPEvent(npEvent);
622 void PluginView::setParent(ScrollView* parent)
624 Widget::setParent(parent);
630 void PluginView::setNPWindowRect(const IntRect&)
633 setNPWindowIfNeeded();
636 void PluginView::setNPWindowIfNeeded()
638 if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
641 // If the plugin didn't load sucessfully, no point in calling setwindow
642 if (m_status != PluginStatusLoadedSuccessfully)
645 // On Unix, only call plugin if it's full-page or windowed
646 if (m_mode != NP_FULL && m_mode != NP_EMBED)
649 // Check if the platformPluginWidget still exists
650 if (m_isWindowed && !platformPluginWidget())
653 if (!m_hasPendingGeometryChange)
655 m_hasPendingGeometryChange = false;
658 platformPluginWidget()->setGeometry(m_windowRect);
660 // Cut out areas of the plugin occluded by iframe shims
661 Vector<IntRect> cutOutRects;
662 QRegion clipRegion = QRegion(m_clipRect);
663 getPluginOcclusions(m_element, this->parent(), frameRect(), cutOutRects);
664 for (size_t i = 0; i < cutOutRects.size(); i++) {
665 cutOutRects[i].move(-frameRect().x(), -frameRect().y());
666 clipRegion = clipRegion.subtracted(QRegion(cutOutRects[i]));
668 // if setMask is set with an empty QRegion, no clipping will
669 // be performed, so in that case we hide the plugin view
670 platformPluginWidget()->setVisible(!clipRegion.isEmpty());
671 platformPluginWidget()->setMask(clipRegion);
673 m_npWindow.x = m_windowRect.x();
674 m_npWindow.y = m_windowRect.y();
680 // If the width or height are null, set the clipRect to null, indicating that
681 // the plugin is not visible/scrolled out.
682 if (!m_clipRect.width() || !m_clipRect.height()) {
683 m_npWindow.clipRect.left = 0;
684 m_npWindow.clipRect.right = 0;
685 m_npWindow.clipRect.top = 0;
686 m_npWindow.clipRect.bottom = 0;
688 // Clipping rectangle of the plug-in; the origin is the top left corner of the drawable or window.
689 m_npWindow.clipRect.left = m_npWindow.x + m_clipRect.x();
690 m_npWindow.clipRect.top = m_npWindow.y + m_clipRect.y();
691 m_npWindow.clipRect.right = m_npWindow.x + m_clipRect.x() + m_clipRect.width();
692 m_npWindow.clipRect.bottom = m_npWindow.y + m_clipRect.y() + m_clipRect.height();
695 if (m_plugin->quirks().contains(PluginQuirkDontCallSetWindowMoreThanOnce)) {
696 // FLASH WORKAROUND: Only set initially. Multiple calls to
697 // setNPWindow() cause the plugin to crash in windowed mode.
698 if (!m_isWindowed || m_npWindow.width == -1 || m_npWindow.height == -1) {
699 m_npWindow.width = m_windowRect.width();
700 m_npWindow.height = m_windowRect.height();
703 m_npWindow.width = m_windowRect.width();
704 m_npWindow.height = m_windowRect.height();
707 PluginView::setCurrentPluginView(this);
709 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
711 setCallingPlugin(true);
712 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
713 setCallingPlugin(false);
714 PluginView::setCurrentPluginView(0);
717 void PluginView::setParentVisible(bool visible)
719 if (isParentVisible() == visible)
722 Widget::setParentVisible(visible);
724 if (isSelfVisible() && platformPluginWidget())
725 platformPluginWidget()->setVisible(visible);
728 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
730 String filename(buf, len);
732 if (filename.startsWith("file:///"))
733 filename = filename.substring(8);
736 if (!getFileSize(filename, size))
737 return NPERR_FILE_NOT_FOUND;
739 FILE* fileHandle = fopen((filename.utf8()).data(), "r");
741 return NPERR_FILE_NOT_FOUND;
744 int bytesRead = fread(buffer.data(), 1, size, fileHandle);
749 return NPERR_FILE_NOT_FOUND;
751 return NPERR_NO_ERROR;
754 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
758 *static_cast<uint32_t*>(value) = 0;
759 *result = NPERR_NO_ERROR;
762 case NPNVSupportsXEmbedBool:
763 *static_cast<NPBool*>(value) = true;
764 *result = NPERR_NO_ERROR;
767 case NPNVjavascriptEnabledBool:
768 *static_cast<NPBool*>(value) = true;
769 *result = NPERR_NO_ERROR;
772 case NPNVSupportsWindowless:
773 *static_cast<NPBool*>(value) = true;
774 *result = NPERR_NO_ERROR;
777 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
778 case NPNVSupportsWindowlessLocal:
779 *static_cast<NPBool*>(value) = true;
780 *result = NPERR_NO_ERROR;
789 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
793 *(void **)value = QX11Info::display();
794 *result = NPERR_NO_ERROR;
797 case NPNVxtAppContext:
798 *result = NPERR_GENERIC_ERROR;
801 case NPNVnetscapeWindow: {
802 void* w = reinterpret_cast<void*>(value);
803 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
804 *((XID *)w) = client ? client->ownerWidget()->window()->winId() : 0;
805 *result = NPERR_NO_ERROR;
810 if (m_plugin->quirks().contains(PluginQuirkRequiresGtkToolKit)) {
811 *((uint32_t *)value) = 2;
812 *result = NPERR_NO_ERROR;
822 void PluginView::invalidateRect(const IntRect& rect)
824 #if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER)
825 if (m_platformLayer) {
826 m_platformLayer->update(QRectF(rect));
832 if (platformWidget()) {
833 // update() will schedule a repaint of the widget so ensure
834 // its knowledge of its position on the page is up to date.
835 platformWidget()->setGeometry(m_windowRect);
836 platformWidget()->update(rect);
841 invalidateWindowlessPluginRect(rect);
844 void PluginView::invalidateRect(NPRect* rect)
850 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
854 void PluginView::invalidateRegion(NPRegion region)
860 void PluginView::forceRedraw()
865 static Display *getPluginDisplay()
867 // The plugin toolkit might run using a different X connection. At the moment, we only
868 // support gdk based plugins (like flash) that use a different X connection.
869 // The code below has the same effect as this one:
870 // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
871 QLibrary library(QLatin1String("libgdk-x11-2.0"), 0);
875 typedef void *(*gdk_init_check_ptr)(void*, void*);
876 gdk_init_check_ptr gdk_init_check = (gdk_init_check_ptr)library.resolve("gdk_init_check");
880 typedef void *(*gdk_display_get_default_ptr)();
881 gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default");
882 if (!gdk_display_get_default)
885 typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *);
886 gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay");
887 if (!gdk_x11_display_get_xdisplay)
890 gdk_init_check(0, 0);
891 return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default());
894 static void getVisualAndColormap(int depth, Visual **visual, Colormap *colormap)
899 #ifndef QT_NO_XRENDER
900 static const bool useXRender = qgetenv("QT_X11_NO_XRENDER").isNull(); // Should also check for XRender >= 0.5
902 static const bool useXRender = false;
905 if (!useXRender && depth == 32)
910 templ.screen = QX11Info::appScreen();
912 templ.c_class = TrueColor;
913 XVisualInfo* xvi = XGetVisualInfo(QX11Info::display(), VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi);
918 #ifndef QT_NO_XRENDER
920 for (int idx = 0; idx < nvi; ++idx) {
921 XRenderPictFormat* format = XRenderFindVisualFormat(QX11Info::display(), xvi[idx].visual);
922 if (format->type == PictTypeDirect && format->direct.alphaMask) {
923 *visual = xvi[idx].visual;
928 #endif // QT_NO_XRENDER
929 *visual = xvi[0].visual;
934 *colormap = XCreateColormap(QX11Info::display(), QX11Info::appRootWindow(), *visual, AllocNone);
937 bool PluginView::platformStart()
940 ASSERT(m_status == PluginStatusLoadedSuccessfully);
942 if (m_plugin->pluginFuncs()->getvalue) {
943 PluginView::setCurrentPluginView(this);
945 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
947 setCallingPlugin(true);
948 m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed);
949 setCallingPlugin(false);
950 PluginView::setCurrentPluginView(0);
954 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
955 if (m_needsXEmbed && client) {
956 setPlatformWidget(new PluginContainerQt(this, client->ownerWidget()));
957 // sync our XEmbed container window creation before sending the xid to plugins.
958 QApplication::syncX();
961 m_status = PluginStatusCanNotLoadPlugin;
965 setPlatformWidget(0);
966 m_pluginDisplay = getPluginDisplay();
968 #if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER)
969 if (shouldUseAcceleratedCompositing()) {
970 m_platformLayer = adoptPtr(new PluginGraphicsLayerQt(this));
971 // Trigger layer computation in RenderLayerCompositor
972 m_element->setNeedsStyleRecalc(SyntheticStyleChange);
977 // If the width and the height are not zero we show the PluginView.
978 if (!frameRect().isEmpty())
981 NPSetWindowCallbackStruct* wsi = new NPSetWindowCallbackStruct();
985 const QX11Info* x11Info = &platformPluginWidget()->x11Info();
987 wsi->display = x11Info->display();
988 wsi->visual = (Visual*)x11Info->visual();
989 wsi->depth = x11Info->depth();
990 wsi->colormap = x11Info->colormap();
992 m_npWindow.type = NPWindowTypeWindow;
993 m_npWindow.window = (void*)platformPluginWidget()->winId();
994 m_npWindow.width = -1;
995 m_npWindow.height = -1;
997 const QX11Info* x11Info = &QApplication::desktop()->x11Info();
999 if (x11Info->depth() == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) {
1000 getVisualAndColormap(32, &m_visual, &m_colormap);
1005 getVisualAndColormap(x11Info->depth(), &m_visual, &m_colormap);
1006 wsi->depth = x11Info->depth();
1009 wsi->display = x11Info->display();
1010 wsi->visual = m_visual;
1011 wsi->colormap = m_colormap;
1013 m_npWindow.type = NPWindowTypeDrawable;
1014 m_npWindow.window = 0; // Not used?
1017 m_npWindow.width = -1;
1018 m_npWindow.height = -1;
1021 m_npWindow.ws_info = wsi;
1023 if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) {
1024 updatePluginWidget();
1025 setNPWindowIfNeeded();
1031 void PluginView::platformDestroy()
1033 if (platformPluginWidget())
1034 delete platformPluginWidget();
1037 XFreePixmap(QX11Info::display(), m_drawable);
1040 XFreeColormap(QX11Info::display(), m_colormap);
1043 #if USE(ACCELERATED_COMPOSITING)
1044 PlatformLayer* PluginView::platformLayer() const
1046 return m_platformLayer.get();
1050 } // namespace WebCore