OSDN Git Service

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