OSDN Git Service

am a8a44d01: am be2b5a3f: Cherry-pick security fix in WebKit change 62873
[android-x86/external-webkit.git] / WebCore / plugins / qt / PluginViewQt.cpp
1 /*
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>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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. 
26  */
27
28 #include "config.h"
29 #include "PluginView.h"
30
31 #include "Bridge.h"
32 #include "Document.h"
33 #include "DocumentLoader.h"
34 #include "Element.h"
35 #include "FloatPoint.h"
36 #include "FocusController.h"
37 #include "Frame.h"
38 #include "FrameLoadRequest.h"
39 #include "FrameLoader.h"
40 #include "FrameTree.h"
41 #include "FrameView.h"
42 #include "GraphicsContext.h"
43 #include "HTMLNames.h"
44 #include "HTMLPlugInElement.h"
45 #include "HostWindow.h"
46 #include "Image.h"
47 #include "JSDOMBinding.h"
48 #include "KeyboardEvent.h"
49 #include "MouseEvent.h"
50 #include "NotImplemented.h"
51 #include "Page.h"
52 #include "PlatformMouseEvent.h"
53 #include "PlatformKeyboardEvent.h"
54 #include "PluginContainerQt.h"
55 #include "PluginDebug.h"
56 #include "PluginPackage.h"
57 #include "PluginMainThreadScheduler.h"
58 #include "QWebPageClient.h"
59 #include "RenderLayer.h"
60 #include "ScriptController.h"
61 #include "Settings.h"
62 #include "npruntime_impl.h"
63 #include "qwebpage_p.h"
64 #include "runtime_root.h"
65
66 #include <QApplication>
67 #include <QDesktopWidget>
68 #include <QKeyEvent>
69 #include <QPainter>
70 #include <QWidget>
71 #include <QX11Info>
72 #include <X11/X.h>
73 #ifndef QT_NO_XRENDER
74 #define Bool int
75 #define Status int
76 #include <X11/extensions/Xrender.h>
77 #endif
78 #include <runtime/JSLock.h>
79 #include <runtime/JSValue.h>
80
81 using JSC::ExecState;
82 using JSC::Interpreter;
83 using JSC::JSLock;
84 using JSC::JSObject;
85 using JSC::UString;
86
87 using std::min;
88
89 using namespace WTF;
90
91 namespace WebCore {
92
93 using namespace HTMLNames;
94
95 void PluginView::updatePluginWidget()
96 {
97     if (!parent())
98         return;
99
100     ASSERT(parent()->isFrameView());
101     FrameView* frameView = static_cast<FrameView*>(parent());
102
103     IntRect oldWindowRect = m_windowRect;
104     IntRect oldClipRect = m_clipRect;
105
106     m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
107     m_clipRect = windowClipRect();
108     m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
109
110     if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
111         return;
112
113     if (!m_isWindowed && m_windowRect.size() != oldWindowRect.size()) {
114 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5)
115         // On Maemo5, Flash always renders to 16-bit buffer
116         if (m_renderToImage)
117             m_image = QImage(m_windowRect.width(), m_windowRect.height(), QImage::Format_RGB16);
118         else
119 #endif
120         {
121             if (m_drawable)
122                 XFreePixmap(QX11Info::display(), m_drawable);
123
124             m_drawable = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), m_windowRect.width(), m_windowRect.height(), 
125                                        ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth);
126             QApplication::syncX(); // make sure that the server knows about the Drawable
127         }
128     }
129
130     // do not call setNPWindowIfNeeded immediately, will be called on paint()
131     m_hasPendingGeometryChange = true;
132
133     // (i) in order to move/resize the plugin window at the same time as the
134     // rest of frame during e.g. scrolling, we set the window geometry
135     // in the paint() function, but as paint() isn't called when the
136     // plugin window is outside the frame which can be caused by a
137     // scroll, we need to move/resize immediately.
138     // (ii) if we are running layout tests from DRT, paint() won't ever get called
139     // so we need to call setNPWindowIfNeeded() if window geometry has changed
140     if (!m_windowRect.intersects(frameView->frameRect())
141         || (QWebPagePrivate::drtRun && platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)))
142         setNPWindowIfNeeded();
143
144     // Make sure we get repainted afterwards. This is necessary for downward
145     // scrolling to move the plugin widget properly.
146     invalidate();
147 }
148
149 void PluginView::setFocus(bool focused)
150 {
151     if (platformPluginWidget()) {
152         if (focused)
153             platformPluginWidget()->setFocus(Qt::OtherFocusReason);
154     } else {
155         Widget::setFocus(focused);
156     }
157 }
158
159 void PluginView::show()
160 {
161     Q_ASSERT(platformPluginWidget() == platformWidget());
162     Widget::show();
163 }
164
165 void PluginView::hide()
166 {
167     Q_ASSERT(platformPluginWidget() == platformWidget());
168     Widget::hide();
169 }
170
171 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5)
172 void PluginView::paintUsingImageSurfaceExtension(QPainter* painter, const IntRect& exposedRect)
173 {
174     NPImageExpose imageExpose;
175     QPoint offset;
176     QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
177     const bool surfaceHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent());
178
179     QPaintDevice* surface =  QPainter::redirected(painter->device(), &offset);
180
181     // If the surface is a QImage, we can render directly into it
182     if (surfaceHasUntransformedContents && surface && surface->devType() == QInternal::Image) {
183         QImage* image = static_cast<QImage*>(surface);
184         offset = -offset; // negating the offset gives us the offset of the view within the surface
185         imageExpose.data = reinterpret_cast<char*>(image->bits());
186         imageExpose.dataSize.width = image->width();
187         imageExpose.dataSize.height = image->height();
188         imageExpose.stride = image->bytesPerLine();
189         imageExpose.depth = image->depth(); // this is guaranteed to be 16 on Maemo5
190         imageExpose.translateX = offset.x() + m_windowRect.x();
191         imageExpose.translateY = offset.y() + m_windowRect.y();
192         imageExpose.scaleX = 1;
193         imageExpose.scaleY = 1;
194     } else {
195         if (m_isTransparent) {
196             // On Maemo5, Flash expects the buffer to contain the contents that are below it.
197             // We don't support transparency for non-raster graphicssystem, so clean the image 
198             // before giving to Flash.
199             QPainter imagePainter(&m_image);
200             imagePainter.fillRect(exposedRect, Qt::white);
201         }
202
203         imageExpose.data = reinterpret_cast<char*>(m_image.bits());
204         imageExpose.dataSize.width = m_image.width();
205         imageExpose.dataSize.height = m_image.height();
206         imageExpose.stride = m_image.bytesPerLine();
207         imageExpose.depth = m_image.depth();
208         imageExpose.translateX = 0;
209         imageExpose.translateY = 0;
210         imageExpose.scaleX = 1;
211         imageExpose.scaleY = 1;
212     }
213     imageExpose.x = exposedRect.x();
214     imageExpose.y = exposedRect.y();
215     imageExpose.width = exposedRect.width();
216     imageExpose.height = exposedRect.height();
217
218     XEvent xevent;
219     memset(&xevent, 0, sizeof(XEvent));
220     XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
221     exposeEvent.type = GraphicsExpose;
222     exposeEvent.display = 0;
223     exposeEvent.drawable = reinterpret_cast<XID>(&imageExpose);
224     exposeEvent.x = exposedRect.x();
225     exposeEvent.y = exposedRect.y();
226     exposeEvent.width = exposedRect.width();
227     exposeEvent.height = exposedRect.height();
228
229     dispatchNPEvent(xevent);
230
231     if (!surfaceHasUntransformedContents || !surface || surface->devType() != QInternal::Image)
232         painter->drawImage(QPoint(frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y()), m_image, exposedRect);
233 }
234 #endif
235
236 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
237 {
238     if (!m_isStarted) {
239         paintMissingPluginIcon(context, rect);
240         return;
241     }
242
243     if (context->paintingDisabled())
244         return;
245
246     setNPWindowIfNeeded();
247
248     if (m_isWindowed)
249         return;
250
251     if (!m_drawable
252 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5)
253         && m_image.isNull()
254 #endif
255        )
256         return;
257
258     QPainter* painter = context->platformContext();
259     IntRect exposedRect(rect);
260     exposedRect.intersect(frameRect());
261     exposedRect.move(-frameRect().x(), -frameRect().y());
262
263 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5)
264     if (!m_image.isNull()) {
265         paintUsingImageSurfaceExtension(painter, exposedRect);
266         return;
267     }
268 #endif
269
270     QPixmap qtDrawable = QPixmap::fromX11Pixmap(m_drawable, QPixmap::ExplicitlyShared);
271     const int drawableDepth = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth;
272     ASSERT(drawableDepth == qtDrawable.depth());
273     const bool syncX = m_pluginDisplay && m_pluginDisplay != QX11Info::display();
274
275     // When printing, Qt uses a QPicture to capture the output in preview mode. The
276     // QPicture holds a reference to the X Pixmap. As a result, the print preview would
277     // update itself when the X Pixmap changes. To prevent this, we create a copy.
278     if (m_element->document()->printing())
279         qtDrawable = qtDrawable.copy();
280
281     if (m_isTransparent && drawableDepth != 32) {
282         // Attempt content propagation for drawable with no alpha by copying over from the backing store
283         QPoint offset;
284         QPaintDevice* backingStoreDevice =  QPainter::redirected(painter->device(), &offset);
285         offset = -offset; // negating the offset gives us the offset of the view within the backing store pixmap
286
287         const bool hasValidBackingStore = backingStoreDevice && backingStoreDevice->devType() == QInternal::Pixmap;
288         QPixmap* backingStorePixmap = static_cast<QPixmap*>(backingStoreDevice);
289
290         // We cannot grab contents from the backing store when painting on QGraphicsView items
291         // (because backing store contents are already transformed). What we really mean to do 
292         // here is to check if we are painting on QWebView, but let's be a little permissive :)
293         QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
294         const bool backingStoreHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent());
295
296         if (hasValidBackingStore && backingStorePixmap->depth() == drawableDepth 
297             && backingStoreHasUntransformedContents) {
298             GC gc = XDefaultGC(QX11Info::display(), QX11Info::appScreen());
299             XCopyArea(QX11Info::display(), backingStorePixmap->handle(), m_drawable, gc,
300                 offset.x() + m_windowRect.x() + exposedRect.x(), offset.y() + m_windowRect.y() + exposedRect.y(),
301                 exposedRect.width(), exposedRect.height(), exposedRect.x(), exposedRect.y());
302         } else { // no backing store, clean the pixmap because the plugin thinks its transparent
303             QPainter painter(&qtDrawable);
304             painter.fillRect(exposedRect, Qt::white);
305         }
306
307         if (syncX)
308             QApplication::syncX();
309     }
310
311     XEvent xevent;
312     memset(&xevent, 0, sizeof(XEvent));
313     XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
314     exposeEvent.type = GraphicsExpose;
315     exposeEvent.display = QX11Info::display();
316     exposeEvent.drawable = qtDrawable.handle();
317     exposeEvent.x = exposedRect.x();
318     exposeEvent.y = exposedRect.y();
319     exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode
320     exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode
321
322     dispatchNPEvent(xevent);
323
324     if (syncX)
325         XSync(m_pluginDisplay, False); // sync changes by plugin
326
327     painter->drawPixmap(QPoint(frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y()), qtDrawable,
328                         exposedRect);
329 }
330
331 // TODO: Unify across ports.
332 bool PluginView::dispatchNPEvent(NPEvent& event)
333 {
334     if (!m_plugin->pluginFuncs()->event)
335         return false;
336
337     PluginView::setCurrentPluginView(this);
338     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
339     setCallingPlugin(true);
340     bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
341     setCallingPlugin(false);
342     PluginView::setCurrentPluginView(0);
343
344     return accepted;
345 }
346
347 void setSharedXEventFields(XEvent* xEvent, QWidget* ownerWidget)
348 {
349     xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server
350     xEvent->xany.send_event = false;
351     xEvent->xany.display = QX11Info::display();
352     // NOTE: event->xany.window doesn't always respond to the .window property of other XEvent's
353     // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify
354     // events; thus, this is right:
355     xEvent->xany.window = ownerWidget ? ownerWidget->window()->handle() : 0;
356 }
357
358 void PluginView::initXEvent(XEvent* xEvent)
359 {
360     memset(xEvent, 0, sizeof(XEvent));
361
362     QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
363     QWidget* ownerWidget = client ? client->ownerWidget() : 0;
364     setSharedXEventFields(xEvent, ownerWidget);
365 }
366
367 void setXKeyEventSpecificFields(XEvent* xEvent, KeyboardEvent* event)
368 {
369     QKeyEvent* qKeyEvent = event->keyEvent()->qtEvent();
370
371     xEvent->type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // ints as Qt unsets KeyPress and KeyRelease
372     xEvent->xkey.root = QX11Info::appRootWindow();
373     xEvent->xkey.subwindow = 0; // we have no child window
374     xEvent->xkey.time = event->timeStamp();
375     xEvent->xkey.state = qKeyEvent->nativeModifiers();
376     xEvent->xkey.keycode = qKeyEvent->nativeScanCode();
377     xEvent->xkey.same_screen = true;
378
379     // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window
380     // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not
381     // set to their normal Xserver values. e.g. Key events don't have a position.
382     // source: https://developer.mozilla.org/en/NPEvent
383     xEvent->xkey.x = 0;
384     xEvent->xkey.y = 0;
385     xEvent->xkey.x_root = 0;
386     xEvent->xkey.y_root = 0;
387 }
388
389 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
390 {
391     if (m_isWindowed)
392         return;
393
394     if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent)
395         return;
396
397     XEvent npEvent;
398     initXEvent(&npEvent);
399     setXKeyEventSpecificFields(&npEvent, event);
400
401     if (!dispatchNPEvent(npEvent))
402         event->setDefaultHandled();
403 }
404
405 static unsigned int inputEventState(MouseEvent* event)
406 {
407     unsigned int state = 0;
408     if (event->ctrlKey())
409         state |= ControlMask;
410     if (event->shiftKey())
411         state |= ShiftMask;
412     if (event->altKey())
413         state |= Mod1Mask;
414     if (event->metaKey())
415         state |= Mod4Mask;
416     return state;
417 }
418
419 static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
420 {
421     XButtonEvent& xbutton = xEvent->xbutton;
422     xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease;
423     xbutton.root = QX11Info::appRootWindow();
424     xbutton.subwindow = 0;
425     xbutton.time = event->timeStamp();
426     xbutton.x = postZoomPos.x();
427     xbutton.y = postZoomPos.y();
428     xbutton.x_root = event->screenX();
429     xbutton.y_root = event->screenY();
430     xbutton.state = inputEventState(event);
431     switch (event->button()) {
432     case MiddleButton:
433         xbutton.button = Button2;
434         break;
435     case RightButton:
436         xbutton.button = Button3;
437         break;
438     case LeftButton:
439     default:
440         xbutton.button = Button1;
441         break;
442     }
443     xbutton.same_screen = true;
444 }
445
446 static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
447 {
448     XMotionEvent& xmotion = xEvent->xmotion;
449     xmotion.type = MotionNotify;
450     xmotion.root = QX11Info::appRootWindow();
451     xmotion.subwindow = 0;
452     xmotion.time = event->timeStamp();
453     xmotion.x = postZoomPos.x();
454     xmotion.y = postZoomPos.y();
455     xmotion.x_root = event->screenX();
456     xmotion.y_root = event->screenY();
457     xmotion.state = inputEventState(event);
458     xmotion.is_hint = NotifyNormal;
459     xmotion.same_screen = true;
460 }
461
462 static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
463 {
464     XCrossingEvent& xcrossing = xEvent->xcrossing;
465     xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify;
466     xcrossing.root = QX11Info::appRootWindow();
467     xcrossing.subwindow = 0;
468     xcrossing.time = event->timeStamp();
469     xcrossing.x = postZoomPos.y();
470     xcrossing.y = postZoomPos.x();
471     xcrossing.x_root = event->screenX();
472     xcrossing.y_root = event->screenY();
473     xcrossing.state = inputEventState(event);
474     xcrossing.mode = NotifyNormal;
475     xcrossing.detail = NotifyDetailNone;
476     xcrossing.same_screen = true;
477     xcrossing.focus = false;
478 }
479
480 void PluginView::handleMouseEvent(MouseEvent* event)
481 {
482     if (m_isWindowed)
483         return;
484
485     if (event->type() == eventNames().mousedownEvent) {
486         // Give focus to the plugin on click
487         if (Page* page = m_parentFrame->page())
488             page->focusController()->setActive(true);
489
490         focusPluginElement();
491     }
492
493     XEvent npEvent;
494     initXEvent(&npEvent);
495
496     IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
497
498     if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
499         setXButtonEventSpecificFields(&npEvent, event, postZoomPos);
500     else if (event->type() == eventNames().mousemoveEvent)
501         setXMotionEventSpecificFields(&npEvent, event, postZoomPos);
502     else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent)
503         setXCrossingEventSpecificFields(&npEvent, event, postZoomPos);
504     else
505         return;
506
507     if (!dispatchNPEvent(npEvent))
508         event->setDefaultHandled();
509 }
510
511 void PluginView::handleFocusInEvent()
512 {
513     XEvent npEvent;
514     initXEvent(&npEvent);
515
516     XFocusChangeEvent& event = npEvent.xfocus;
517     event.type = 9; /* int as Qt unsets FocusIn */
518     event.mode = NotifyNormal;
519     event.detail = NotifyDetailNone;
520
521     dispatchNPEvent(npEvent);
522 }
523
524 void PluginView::handleFocusOutEvent()
525 {
526     XEvent npEvent;
527     initXEvent(&npEvent);
528
529     XFocusChangeEvent& event = npEvent.xfocus;
530     event.type = 10; /* int as Qt unsets FocusOut */
531     event.mode = NotifyNormal;
532     event.detail = NotifyDetailNone;
533
534     dispatchNPEvent(npEvent);
535 }
536
537 void PluginView::setParent(ScrollView* parent)
538 {
539     Widget::setParent(parent);
540
541     if (parent)
542         init();
543 }
544
545 void PluginView::setNPWindowRect(const IntRect&)
546 {
547     if (!m_isWindowed)
548         setNPWindowIfNeeded();
549 }
550
551 void PluginView::setNPWindowIfNeeded()
552 {
553     if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
554         return;
555
556     // If the plugin didn't load sucessfully, no point in calling setwindow
557     if (m_status != PluginStatusLoadedSuccessfully)
558         return;
559
560     // On Unix, only call plugin if it's full-page or windowed
561     if (m_mode != NP_FULL && m_mode != NP_EMBED)
562         return;
563
564     // Check if the platformPluginWidget still exists
565     if (m_isWindowed && !platformPluginWidget())
566         return;
567
568     if (!m_hasPendingGeometryChange)
569         return;
570     m_hasPendingGeometryChange = false;
571
572     if (m_isWindowed) {
573         platformPluginWidget()->setGeometry(m_windowRect);
574         // if setMask is set with an empty QRegion, no clipping will
575         // be performed, so in that case we hide the plugin view
576         platformPluginWidget()->setVisible(!m_clipRect.isEmpty());
577         platformPluginWidget()->setMask(QRegion(m_clipRect));
578
579         m_npWindow.x = m_windowRect.x();
580         m_npWindow.y = m_windowRect.y();
581
582         m_npWindow.clipRect.left = max(0, m_clipRect.x());
583         m_npWindow.clipRect.top = max(0, m_clipRect.y());
584         m_npWindow.clipRect.right = m_clipRect.x() + m_clipRect.width();
585         m_npWindow.clipRect.bottom = m_clipRect.y() + m_clipRect.height();
586     } else {
587         m_npWindow.x = 0;
588         m_npWindow.y = 0;
589
590         m_npWindow.clipRect.left = 0;
591         m_npWindow.clipRect.top = 0;
592         m_npWindow.clipRect.right = 0;
593         m_npWindow.clipRect.bottom = 0;
594     }
595
596     if (m_plugin->quirks().contains(PluginQuirkDontCallSetWindowMoreThanOnce)) {
597         // FLASH WORKAROUND: Only set initially. Multiple calls to
598         // setNPWindow() cause the plugin to crash in windowed mode.
599         if (!m_isWindowed || m_npWindow.width == -1 || m_npWindow.height == -1) {
600             m_npWindow.width = m_windowRect.width();
601             m_npWindow.height = m_windowRect.height();
602         }
603     } else {
604         m_npWindow.width = m_windowRect.width();
605         m_npWindow.height = m_windowRect.height();
606     }
607
608     PluginView::setCurrentPluginView(this);
609     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
610     setCallingPlugin(true);
611     m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
612     setCallingPlugin(false);
613     PluginView::setCurrentPluginView(0);
614 }
615
616 void PluginView::setParentVisible(bool visible)
617 {
618     if (isParentVisible() == visible)
619         return;
620
621     Widget::setParentVisible(visible);
622
623     if (isSelfVisible() && platformPluginWidget())
624         platformPluginWidget()->setVisible(visible);
625 }
626
627 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
628 {
629     String filename(buf, len);
630
631     if (filename.startsWith("file:///"))
632         filename = filename.substring(8);
633
634     long long size;
635     if (!getFileSize(filename, size))
636         return NPERR_FILE_NOT_FOUND;
637
638     FILE* fileHandle = fopen((filename.utf8()).data(), "r");
639     if (!fileHandle)
640         return NPERR_FILE_NOT_FOUND;
641
642     buffer.resize(size);
643     int bytesRead = fread(buffer.data(), 1, size, fileHandle);
644
645     fclose(fileHandle);
646
647     if (bytesRead <= 0)
648         return NPERR_FILE_NOT_FOUND;
649
650     return NPERR_NO_ERROR;
651 }
652
653 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
654 {
655     switch (variable) {
656     case NPNVToolkit:
657         *static_cast<uint32_t*>(value) = 0;
658         *result = NPERR_NO_ERROR;
659         return true;
660
661     case NPNVSupportsXEmbedBool:
662         *static_cast<NPBool*>(value) = true;
663         *result = NPERR_NO_ERROR;
664         return true;
665
666     case NPNVjavascriptEnabledBool:
667         *static_cast<NPBool*>(value) = true;
668         *result = NPERR_NO_ERROR;
669         return true;
670
671     case NPNVSupportsWindowless:
672         *static_cast<NPBool*>(value) = true;
673         *result = NPERR_NO_ERROR;
674         return true;
675
676 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5)
677     case NPNVSupportsWindowlessLocal:
678         *static_cast<NPBool*>(value) = true;
679         *result = NPERR_NO_ERROR;
680         return true;
681 #endif
682
683     default:
684         return false;
685     }
686 }
687
688 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
689 {
690     switch (variable) {
691     case NPNVxDisplay:
692         *(void **)value = QX11Info::display();
693         *result = NPERR_NO_ERROR;
694         return true;
695
696     case NPNVxtAppContext:
697         *result = NPERR_GENERIC_ERROR;
698         return true;
699
700     case NPNVnetscapeWindow: {
701         void* w = reinterpret_cast<void*>(value);
702         QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
703         *((XID *)w) = client ? client->ownerWidget()->window()->winId() : 0;
704         *result = NPERR_NO_ERROR;
705         return true;
706     }
707
708     case NPNVToolkit:
709         if (m_plugin->quirks().contains(PluginQuirkRequiresGtkToolKit)) {
710             *((uint32_t *)value) = 2;
711             *result = NPERR_NO_ERROR;
712             return true;
713         }
714         return false;
715
716     default:
717         return false;
718     }
719 }
720
721 void PluginView::invalidateRect(const IntRect& rect)
722 {
723     if (m_isWindowed) {
724         if (platformWidget())
725             platformWidget()->update(rect);
726         return;
727     }
728
729     invalidateWindowlessPluginRect(rect);
730 }
731
732 void PluginView::invalidateRect(NPRect* rect)
733 {
734     if (!rect) {
735         invalidate();
736         return;
737     }
738     IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
739     invalidateWindowlessPluginRect(r);
740 }
741
742 void PluginView::invalidateRegion(NPRegion region)
743 {
744     invalidate();
745 }
746
747 void PluginView::forceRedraw()
748 {
749     invalidate();
750 }
751
752 static Display *getPluginDisplay()
753 {
754     // The plugin toolkit might run using a different X connection. At the moment, we only
755     // support gdk based plugins (like flash) that use a different X connection.
756     // The code below has the same effect as this one:
757     // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
758     QLibrary library("libgdk-x11-2.0.so.0");
759     if (!library.load())
760         return 0;
761
762     typedef void *(*gdk_display_get_default_ptr)();
763     gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default");
764     if (!gdk_display_get_default)
765         return 0;
766
767     typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *);
768     gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay");
769     if (!gdk_x11_display_get_xdisplay)
770         return 0;
771
772     return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default());
773 }
774
775 static void getVisualAndColormap(int depth, Visual **visual, Colormap *colormap)
776 {
777     *visual = 0;
778     *colormap = 0;
779
780 #ifndef QT_NO_XRENDER
781     static const bool useXRender = qgetenv("QT_X11_NO_XRENDER").isNull(); // Should also check for XRender >= 0.5
782 #else
783     static const bool useXRender = false;
784 #endif
785
786     if (!useXRender && depth == 32)
787         return;
788
789     int nvi;
790     XVisualInfo templ;
791     templ.screen  = QX11Info::appScreen();
792     templ.depth   = depth;
793     templ.c_class = TrueColor;
794     XVisualInfo* xvi = XGetVisualInfo(QX11Info::display(), VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi);
795
796     if (!xvi)
797         return;
798
799 #ifndef QT_NO_XRENDER
800     if (depth == 32) {
801         for (int idx = 0; idx < nvi; ++idx) {
802             XRenderPictFormat* format = XRenderFindVisualFormat(QX11Info::display(), xvi[idx].visual);
803             if (format->type == PictTypeDirect && format->direct.alphaMask) {
804                  *visual = xvi[idx].visual;
805                  break;
806             }
807          }
808     } else
809 #endif // QT_NO_XRENDER
810         *visual = xvi[0].visual;
811
812     XFree(xvi);
813
814     if (*visual)
815         *colormap = XCreateColormap(QX11Info::display(), QX11Info::appRootWindow(), *visual, AllocNone);
816 }
817
818 bool PluginView::platformStart()
819 {
820     ASSERT(m_isStarted);
821     ASSERT(m_status == PluginStatusLoadedSuccessfully);
822
823     if (m_plugin->pluginFuncs()->getvalue) {
824         PluginView::setCurrentPluginView(this);
825         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
826         setCallingPlugin(true);
827         m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed);
828         setCallingPlugin(false);
829         PluginView::setCurrentPluginView(0);
830     }
831
832     if (m_isWindowed) {
833         QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
834         if (m_needsXEmbed && client) {
835             setPlatformWidget(new PluginContainerQt(this, client->ownerWidget()));
836             // sync our XEmbed container window creation before sending the xid to plugins.
837             QApplication::syncX();
838         } else {
839             notImplemented();
840             m_status = PluginStatusCanNotLoadPlugin;
841             return false;
842         }
843     } else {
844         setPlatformWidget(0);
845         m_pluginDisplay = getPluginDisplay();
846     }
847
848     show();
849
850     NPSetWindowCallbackStruct* wsi = new NPSetWindowCallbackStruct();
851     wsi->type = 0;
852
853     if (m_isWindowed) {
854         const QX11Info* x11Info = &platformPluginWidget()->x11Info();
855
856         wsi->display = x11Info->display();
857         wsi->visual = (Visual*)x11Info->visual();
858         wsi->depth = x11Info->depth();
859         wsi->colormap = x11Info->colormap();
860
861         m_npWindow.type = NPWindowTypeWindow;
862         m_npWindow.window = (void*)platformPluginWidget()->winId();
863         m_npWindow.width = -1;
864         m_npWindow.height = -1;
865     } else {
866         const QX11Info* x11Info = &QApplication::desktop()->x11Info();
867
868         if (x11Info->depth() == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) {
869             getVisualAndColormap(32, &m_visual, &m_colormap);
870             wsi->depth = 32;
871         }
872
873         if (!m_visual) {
874             getVisualAndColormap(x11Info->depth(), &m_visual, &m_colormap);
875             wsi->depth = x11Info->depth();
876         }
877
878         wsi->display = x11Info->display();
879         wsi->visual = m_visual;
880         wsi->colormap = m_colormap;
881
882         m_npWindow.type = NPWindowTypeDrawable;
883         m_npWindow.window = 0; // Not used?
884         m_npWindow.x = 0;
885         m_npWindow.y = 0;
886         m_npWindow.width = -1;
887         m_npWindow.height = -1;
888     }
889
890     m_npWindow.ws_info = wsi;
891
892     if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) {
893         updatePluginWidget();
894         setNPWindowIfNeeded();
895     }
896
897     return true;
898 }
899
900 void PluginView::platformDestroy()
901 {
902     if (platformPluginWidget())
903         delete platformPluginWidget();
904
905     if (m_drawable)
906         XFreePixmap(QX11Info::display(), m_drawable);
907
908     if (m_colormap)
909         XFreeColormap(QX11Info::display(), m_colormap);
910 }
911
912 void PluginView::halt()
913 {
914 }
915
916 void PluginView::restart()
917 {
918 }
919
920 } // namespace WebCore