• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
3 
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Library General Public
6     License as published by the Free Software Foundation; either
7     version 2 of the License, or (at your option) any later version.
8 
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Library General Public License for more details.
13 
14     You should have received a copy of the GNU Library General Public License
15     along with this library; see the file COPYING.LIB.  If not, write to
16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     Boston, MA 02110-1301, USA.
18 */
19 #include "config.h"
20 #include "PluginView.h"
21 
22 #include "Bridge.h"
23 #include "Document.h"
24 #include "DocumentLoader.h"
25 #include "Element.h"
26 #include "FocusController.h"
27 #include "Frame.h"
28 #include "FrameLoadRequest.h"
29 #include "FrameLoader.h"
30 #include "FrameTree.h"
31 #include "FrameView.h"
32 #include "GraphicsContext.h"
33 #include "HTMLNames.h"
34 #include "HTMLPlugInElement.h"
35 #include "HostWindow.h"
36 #include "Image.h"
37 #include "JSDOMBinding.h"
38 #include "KeyboardEvent.h"
39 #include "MouseEvent.h"
40 #include "NotImplemented.h"
41 #include "Page.h"
42 #include "PlatformKeyboardEvent.h"
43 #include "PlatformMouseEvent.h"
44 #include "PluginContainerSymbian.h"
45 #include "PluginDebug.h"
46 #include "PluginMainThreadScheduler.h"
47 #include "PluginPackage.h"
48 #include "QWebPageClient.h"
49 #include "RenderLayer.h"
50 #include "ScriptController.h"
51 #include "Settings.h"
52 #include "npfunctions.h"
53 #include "npinterface.h"
54 #include "npruntime_impl.h"
55 #include "runtime_root.h"
56 #include <QKeyEvent>
57 #include <QPixmap>
58 #include <QRegion>
59 #include <QVector>
60 #include <QWidget>
61 #include <runtime/JSLock.h>
62 #include <runtime/JSValue.h>
63 
64 using JSC::ExecState;
65 using JSC::Interpreter;
66 using JSC::JSLock;
67 using JSC::JSObject;
68 using JSC::UString;
69 
70 using namespace std;
71 
72 using namespace WTF;
73 
74 namespace WebCore {
75 
76 using namespace HTMLNames;
77 
updatePluginWidget()78 void PluginView::updatePluginWidget()
79 {
80     if (!parent())
81         return;
82     ASSERT(parent()->isFrameView());
83     FrameView* frameView = static_cast<FrameView*>(parent());
84     IntRect oldWindowRect = m_windowRect;
85     IntRect oldClipRect = m_clipRect;
86 
87     m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
88     m_clipRect = windowClipRect();
89     m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
90     if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
91         return;
92 
93     // in order to move/resize the plugin window at the same time as the rest of frame
94     // during e.g. scrolling, we set the mask and geometry in the paint() function, but
95     // as paint() isn't called when the plugin window is outside the frame which can
96     // be caused by a scroll, we need to move/resize immediately.
97     if (!m_windowRect.intersects(frameView->frameRect()))
98         setNPWindowIfNeeded();
99 }
100 
setFocus()101 void PluginView::setFocus()
102 {
103     if (platformPluginWidget())
104         platformPluginWidget()->setFocus(Qt::OtherFocusReason);
105     else
106         Widget::setFocus();
107 }
108 
show()109 void PluginView::show()
110 {
111     setSelfVisible(true);
112 
113     if (isParentVisible() && platformPluginWidget())
114         platformPluginWidget()->setVisible(true);
115 }
116 
hide()117 void PluginView::hide()
118 {
119     setSelfVisible(false);
120 
121     if (isParentVisible() && platformPluginWidget())
122         platformPluginWidget()->setVisible(false);
123 }
124 
paint(GraphicsContext * context,const IntRect & rect)125 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
126 {
127     if (!m_isStarted) {
128         paintMissingPluginIcon(context, rect);
129         return;
130     }
131 
132     if (context->paintingDisabled())
133         return;
134     m_npWindow.ws_info = (void*)(context->platformContext());
135     setNPWindowIfNeeded();
136 
137     if (m_isWindowed && platformPluginWidget())
138         static_cast<PluginContainerSymbian*>(platformPluginWidget())->adjustGeometry();
139 
140     if (m_isWindowed)
141         return;
142 
143     context->save();
144     IntRect clipRect(rect);
145     clipRect.intersect(frameRect());
146     context->clip(clipRect);
147     context->translate(frameRect().location().x(), frameRect().location().y());
148 
149     QPaintEvent ev(rect);
150     QEvent& npEvent = ev;
151     dispatchNPEvent(npEvent);
152 
153     context->restore();
154 }
155 
156 // TODO: Unify across ports.
dispatchNPEvent(NPEvent & event)157 bool PluginView::dispatchNPEvent(NPEvent& event)
158 {
159     if (!m_plugin->pluginFuncs()->event)
160         return false;
161 
162     PluginView::setCurrentPluginView(this);
163     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
164 
165     setCallingPlugin(true);
166     bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
167     setCallingPlugin(false);
168     PluginView::setCurrentPluginView(0);
169 
170     return accepted;
171 }
172 
handleKeyboardEvent(KeyboardEvent * event)173 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
174 {
175     if (m_isWindowed)
176         return;
177 
178     QEvent& npEvent = *(event->keyEvent()->qtEvent());
179     if (!dispatchNPEvent(npEvent))
180         event->setDefaultHandled();
181 }
182 
handleMouseEvent(MouseEvent * event)183 void PluginView::handleMouseEvent(MouseEvent* event)
184 {
185     if (m_isWindowed)
186         return;
187 
188     if (event->type() == eventNames().mousedownEvent) {
189         // Give focus to the plugin on click
190         if (Page* page = m_parentFrame->page())
191             page->focusController()->setActive(true);
192 
193         focusPluginElement();
194     }
195 
196     QEvent::Type type;
197     if (event->type() == eventNames().mousedownEvent)
198         type = QEvent::MouseButtonPress;
199     else if (event->type() == eventNames().mousemoveEvent)
200         type = QEvent::MouseMove;
201     else if (event->type() == eventNames().mouseupEvent)
202         type = QEvent::MouseButtonRelease;
203     else
204         return;
205 
206     QPoint position(event->offsetX(), event->offsetY());
207     Qt::MouseButton button;
208     switch (event->which()) {
209     case 1:
210         button = Qt::LeftButton;
211         break;
212     case 2:
213         button = Qt::MidButton;
214         break;
215     case 3:
216         button = Qt::RightButton;
217         break;
218     default:
219         button = Qt::NoButton;
220     }
221     Qt::KeyboardModifiers modifiers = 0;
222     if (event->ctrlKey())
223         modifiers |= Qt::ControlModifier;
224     if (event->altKey())
225         modifiers |= Qt::AltModifier;
226     if (event->shiftKey())
227         modifiers |= Qt::ShiftModifier;
228     if (event->metaKey())
229         modifiers |= Qt::MetaModifier;
230     QMouseEvent mouseEvent(type, position, button, button, modifiers);
231     QEvent& npEvent = mouseEvent;
232     if (!dispatchNPEvent(npEvent))
233         event->setDefaultHandled();
234 }
235 
setParent(ScrollView * parent)236 void PluginView::setParent(ScrollView* parent)
237 {
238     Widget::setParent(parent);
239 
240     if (parent)
241         init();
242 }
243 
setNPWindowRect(const IntRect &)244 void PluginView::setNPWindowRect(const IntRect&)
245 {
246     if (!m_isWindowed)
247         setNPWindowIfNeeded();
248 }
249 
setNPWindowIfNeeded()250 void PluginView::setNPWindowIfNeeded()
251 {
252     if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
253         return;
254     if (m_isWindowed) {
255         ASSERT(platformPluginWidget());
256         platformPluginWidget()->setGeometry(m_windowRect);
257         // if setMask is set with an empty QRegion, no clipping will
258         // be performed, so in that case we hide the plugin view
259         platformPluginWidget()->setVisible(!m_clipRect.isEmpty());
260         platformPluginWidget()->setMask(QRegion(m_clipRect));
261 
262         m_npWindow.x = m_windowRect.x();
263         m_npWindow.y = m_windowRect.y();
264 
265         m_npWindow.clipRect.left = m_clipRect.x();
266         m_npWindow.clipRect.top = m_clipRect.y();
267         m_npWindow.clipRect.right = m_clipRect.width();
268         m_npWindow.clipRect.bottom = m_clipRect.height();
269 
270     } else {
271         // always call this method before painting.
272         m_npWindow.x = 0;
273         m_npWindow.y = 0;
274 
275         m_npWindow.clipRect.left = 0;
276         m_npWindow.clipRect.top = 0;
277         m_npWindow.clipRect.right = m_windowRect.width();
278         m_npWindow.clipRect.bottom = m_windowRect.height();
279         m_npWindow.window = 0;
280     }
281 
282     m_npWindow.width = m_windowRect.width();
283     m_npWindow.height = m_windowRect.height();
284 
285     PluginView::setCurrentPluginView(this);
286     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
287     setCallingPlugin(true);
288     m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
289     setCallingPlugin(false);
290     PluginView::setCurrentPluginView(0);
291 }
292 
setParentVisible(bool visible)293 void PluginView::setParentVisible(bool visible)
294 {
295     if (isParentVisible() == visible)
296         return;
297 
298     Widget::setParentVisible(visible);
299 
300     if (isSelfVisible() && platformPluginWidget())
301         platformPluginWidget()->setVisible(visible);
302 }
303 
handlePostReadFile(Vector<char> & buffer,uint32 len,const char * buf)304 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf)
305 {
306     notImplemented();
307     return NPERR_NO_ERROR;
308 }
309 
getValueStatic(NPNVariable variable,void * value)310 NPError PluginView::getValueStatic(NPNVariable variable, void* value)
311 {
312     LOG(Plugins, "PluginView::getValueStatic(%s)", prettyNameForNPNVariable(variable).data());
313 
314     switch (variable) {
315     case NPNVjavascriptEnabledBool:
316         *static_cast<NPBool*>(value) = true;
317         return NPERR_NO_ERROR;
318 
319     case NPNVSupportsWindowless:
320         *static_cast<NPBool*>(value) = true;
321         return NPERR_NO_ERROR;
322 
323     default:
324         return NPERR_GENERIC_ERROR;
325     }
326 }
327 
getValue(NPNVariable variable,void * value)328 NPError PluginView::getValue(NPNVariable variable, void* value)
329 {
330     LOG(Plugins, "PluginView::getValue(%s)", prettyNameForNPNVariable(variable).data());
331 
332     switch (variable) {
333     case NPNVWindowNPObject: {
334         if (m_isJavaScriptPaused)
335             return NPERR_GENERIC_ERROR;
336 
337         NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject();
338 
339         // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
340         if (windowScriptObject)
341             _NPN_RetainObject(windowScriptObject);
342 
343         void** v = (void**)value;
344         *v = windowScriptObject;
345 
346         return NPERR_NO_ERROR;
347     }
348 
349     case NPNVPluginElementNPObject: {
350         if (m_isJavaScriptPaused)
351             return NPERR_GENERIC_ERROR;
352 
353         NPObject* pluginScriptObject = 0;
354 
355         if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag))
356             pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject();
357 
358         // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
359         if (pluginScriptObject)
360             _NPN_RetainObject(pluginScriptObject);
361 
362         void** v = (void**)value;
363         *v = pluginScriptObject;
364 
365         return NPERR_NO_ERROR;
366     }
367     default:
368         return getValueStatic(variable, value);
369     }
370 }
371 
invalidateRect(const IntRect & rect)372 void PluginView::invalidateRect(const IntRect& rect)
373 {
374     if (m_isWindowed) {
375         platformWidget()->update(rect);
376         return;
377     }
378 
379     invalidateWindowlessPluginRect(rect);
380 }
381 
invalidateRect(NPRect * rect)382 void PluginView::invalidateRect(NPRect* rect)
383 {
384     if (m_isWindowed)
385         return;
386     if (!rect) {
387         invalidate();
388         return;
389     }
390     IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
391     m_invalidRects.append(r);
392     if (!m_invalidateTimer.isActive())
393         m_invalidateTimer.startOneShot(0.001);
394 }
395 
invalidateRegion(NPRegion region)396 void PluginView::invalidateRegion(NPRegion region)
397 {
398     if (m_isWindowed)
399         return;
400 
401     if (!region)
402         return;
403 
404     QVector<QRect> rects = region->rects();
405     for (int i = 0; i < rects.size(); ++i) {
406         const QRect& qRect = rects.at(i);
407         m_invalidRects.append(qRect);
408         if (!m_invalidateTimer.isActive())
409             m_invalidateTimer.startOneShot(0.001);
410     }
411 }
412 
forceRedraw()413 void PluginView::forceRedraw()
414 {
415     if (m_isWindowed)
416         return;
417     invalidate();
418 }
419 
platformStart()420 bool PluginView::platformStart()
421 {
422     ASSERT(m_isStarted);
423     ASSERT(m_status == PluginStatusLoadedSuccessfully);
424 
425     show();
426 
427     if (m_isWindowed) {
428         QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
429         // FIXME this will not work for QGraphicsView.
430         // But we cannot use winId because it will create a window and on S60,
431         // QWidgets should not create a window.
432         Q_ASSERT(qobject_cast<QWidget*>(client->pluginParent()));
433         setPlatformWidget(new PluginContainerSymbian(this,
434             qobject_cast<QWidget*>(client->pluginParent())));
435         m_npWindow.type = NPWindowTypeWindow;
436         m_npWindow.window = (void*)platformPluginWidget();
437 
438     } else {
439         setPlatformWidget(0);
440         m_npWindow.type = NPWindowTypeDrawable;
441         m_npWindow.window = 0; // Not used?
442     }
443     setNPWindowIfNeeded();
444 
445     return true;
446 }
447 
platformDestroy()448 void PluginView::platformDestroy()
449 {
450     delete platformPluginWidget();
451 }
452 
halt()453 void PluginView::halt()
454 {
455 }
456 
restart()457 void PluginView::restart()
458 {
459 }
460 
461 } // namespace WebCore
462