1 /*
2 Copyright (C) 2009, 2010 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 "BridgeJSC.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 "qgraphicswebview.h"
56 #include "qwebframe.h"
57 #include "qwebframe_p.h"
58 #include "runtime_root.h"
59 #include <QGraphicsProxyWidget>
60 #include <QKeyEvent>
61 #include <QPixmap>
62 #include <QRegion>
63 #include <QVector>
64 #include <QWidget>
65 #include <runtime/JSLock.h>
66 #include <runtime/JSValue.h>
67
68 typedef void (*_qtwebkit_page_plugin_created)(QWebFrame*, void*, void*); // frame, plugin instance, plugin functions
69 static _qtwebkit_page_plugin_created qtwebkit_page_plugin_created = 0;
qtwebkit_setPluginCreatedCallback(_qtwebkit_page_plugin_created cb)70 QWEBKIT_EXPORT void qtwebkit_setPluginCreatedCallback(_qtwebkit_page_plugin_created cb)
71 {
72 qtwebkit_page_plugin_created = cb;
73 }
74
75 using JSC::ExecState;
76 using JSC::Interpreter;
77 using JSC::JSLock;
78 using JSC::JSObject;
79 using JSC::UString;
80
81 using namespace std;
82
83 using namespace WTF;
84
85 namespace WebCore {
86
87 using namespace HTMLNames;
88
updatePluginWidget()89 void PluginView::updatePluginWidget()
90 {
91 if (!parent())
92 return;
93 ASSERT(parent()->isFrameView());
94 FrameView* frameView = static_cast<FrameView*>(parent());
95 IntRect oldWindowRect = m_windowRect;
96 IntRect oldClipRect = m_clipRect;
97
98 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
99
100 m_clipRect = windowClipRect();
101 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
102 if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
103 return;
104
105 setNPWindowIfNeeded();
106 }
107
setFocus(bool focused)108 void PluginView::setFocus(bool focused)
109 {
110 if (platformPluginWidget()) {
111 if (focused)
112 platformPluginWidget()->setFocus(Qt::OtherFocusReason);
113 } else {
114 Widget::setFocus(focused);
115 }
116 }
117
show()118 void PluginView::show()
119 {
120 setSelfVisible(true);
121
122 if (isParentVisible() && platformPluginWidget())
123 platformPluginWidget()->setVisible(true);
124 }
125
hide()126 void PluginView::hide()
127 {
128 setSelfVisible(false);
129
130 if (isParentVisible() && platformPluginWidget())
131 platformPluginWidget()->setVisible(false);
132 }
133
paint(GraphicsContext * context,const IntRect & rect)134 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
135 {
136 if (!m_isStarted) {
137 paintMissingPluginIcon(context, rect);
138 return;
139 }
140
141 if (context->paintingDisabled())
142 return;
143 m_npWindow.ws_info = (void*)(context->platformContext());
144 setNPWindowIfNeeded();
145
146 if (m_isWindowed && platformPluginWidget())
147 static_cast<PluginContainerSymbian*>(platformPluginWidget())->adjustGeometry();
148
149 if (m_isWindowed)
150 return;
151
152 context->save();
153 IntRect clipRect(rect);
154 clipRect.intersect(frameRect());
155 context->clip(clipRect);
156 context->translate(frameRect().location().x(), frameRect().location().y());
157
158 QPaintEvent ev(rect);
159 QEvent& npEvent = ev;
160 dispatchNPEvent(npEvent);
161
162 context->restore();
163 }
164
165 // TODO: Unify across ports.
dispatchNPEvent(NPEvent & event)166 bool PluginView::dispatchNPEvent(NPEvent& event)
167 {
168 if (!m_plugin->pluginFuncs()->event)
169 return false;
170
171 PluginView::setCurrentPluginView(this);
172 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
173
174 setCallingPlugin(true);
175 bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
176 setCallingPlugin(false);
177 PluginView::setCurrentPluginView(0);
178
179 return accepted;
180 }
181
handleKeyboardEvent(KeyboardEvent * event)182 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
183 {
184 if (m_isWindowed)
185 return;
186
187 ASSERT(event->keyEvent()->qtEvent());
188 QEvent& npEvent = *(event->keyEvent()->qtEvent());
189 if (!dispatchNPEvent(npEvent))
190 event->setDefaultHandled();
191 }
192
handleMouseEvent(MouseEvent * event)193 void PluginView::handleMouseEvent(MouseEvent* event)
194 {
195 if (m_isWindowed)
196 return;
197
198 if (event->type() == eventNames().mousedownEvent) {
199 // Give focus to the plugin on click
200 if (Page* page = m_parentFrame->page())
201 page->focusController()->setActive(true);
202
203 focusPluginElement();
204 }
205
206 QEvent::Type type;
207 if (event->type() == eventNames().mousedownEvent)
208 type = QEvent::MouseButtonPress;
209 else if (event->type() == eventNames().mousemoveEvent)
210 type = QEvent::MouseMove;
211 else if (event->type() == eventNames().mouseupEvent)
212 type = QEvent::MouseButtonRelease;
213 else
214 return;
215
216 QPoint position(event->offsetX(), event->offsetY());
217 Qt::MouseButton button;
218 switch (event->which()) {
219 case 1:
220 button = Qt::LeftButton;
221 break;
222 case 2:
223 button = Qt::MidButton;
224 break;
225 case 3:
226 button = Qt::RightButton;
227 break;
228 default:
229 button = Qt::NoButton;
230 }
231 Qt::KeyboardModifiers modifiers = 0;
232 if (event->ctrlKey())
233 modifiers |= Qt::ControlModifier;
234 if (event->altKey())
235 modifiers |= Qt::AltModifier;
236 if (event->shiftKey())
237 modifiers |= Qt::ShiftModifier;
238 if (event->metaKey())
239 modifiers |= Qt::MetaModifier;
240 QMouseEvent mouseEvent(type, position, button, button, modifiers);
241 QEvent& npEvent = mouseEvent;
242 if (!dispatchNPEvent(npEvent))
243 event->setDefaultHandled();
244 }
245
setParent(ScrollView * parent)246 void PluginView::setParent(ScrollView* parent)
247 {
248 Widget::setParent(parent);
249
250 if (parent) {
251 init();
252 if (m_status == PluginStatusLoadedSuccessfully)
253 updatePluginWidget();
254 }
255 }
256
setNPWindowRect(const IntRect &)257 void PluginView::setNPWindowRect(const IntRect&)
258 {
259 if (!m_isWindowed)
260 setNPWindowIfNeeded();
261 }
262
setNPWindowIfNeeded()263 void PluginView::setNPWindowIfNeeded()
264 {
265 if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
266 return;
267 if (m_isWindowed) {
268 ASSERT(platformPluginWidget());
269 platformPluginWidget()->setGeometry(m_windowRect);
270 // if setMask is set with an empty QRegion, no clipping will
271 // be performed, so in that case we hide the plugin view
272 platformPluginWidget()->setVisible(!m_clipRect.isEmpty());
273 platformPluginWidget()->setMask(QRegion(m_clipRect));
274
275 m_npWindow.x = m_windowRect.x();
276 m_npWindow.y = m_windowRect.y();
277
278 m_npWindow.clipRect.left = max(0, m_clipRect.x());
279 m_npWindow.clipRect.top = max(0, m_clipRect.y());
280 m_npWindow.clipRect.right = m_clipRect.x() + m_clipRect.width();
281 m_npWindow.clipRect.bottom = m_clipRect.y() + m_clipRect.height();
282
283 } else {
284 // always call this method before painting.
285 m_npWindow.x = m_windowRect.x();
286 m_npWindow.y = m_windowRect.y();
287
288 m_npWindow.clipRect.left = 0;
289 m_npWindow.clipRect.top = 0;
290 m_npWindow.clipRect.right = m_windowRect.width();
291 m_npWindow.clipRect.bottom = m_windowRect.height();
292 m_npWindow.window = 0;
293 }
294
295 m_npWindow.width = m_windowRect.width();
296 m_npWindow.height = m_windowRect.height();
297
298 PluginView::setCurrentPluginView(this);
299 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
300 setCallingPlugin(true);
301 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
302 setCallingPlugin(false);
303 PluginView::setCurrentPluginView(0);
304 }
305
setParentVisible(bool visible)306 void PluginView::setParentVisible(bool visible)
307 {
308 if (isParentVisible() == visible)
309 return;
310
311 Widget::setParentVisible(visible);
312
313 if (isSelfVisible() && platformPluginWidget())
314 platformPluginWidget()->setVisible(visible);
315 }
316
handlePostReadFile(Vector<char> & buffer,uint32_t len,const char * buf)317 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
318 {
319 notImplemented();
320 return NPERR_NO_ERROR;
321 }
322
platformGetValueStatic(NPNVariable variable,void * value,NPError * result)323 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
324 {
325 switch (variable) {
326 case NPNVjavascriptEnabledBool:
327 *static_cast<NPBool*>(value) = true;
328 *result = NPERR_NO_ERROR;
329 return true;
330
331 case NPNVSupportsWindowless:
332 *static_cast<NPBool*>(value) = true;
333 *result = NPERR_NO_ERROR;
334 return true;
335
336 default:
337 return false;
338 }
339 }
340
platformGetValue(NPNVariable,void *,NPError *)341 bool PluginView::platformGetValue(NPNVariable, void*, NPError*)
342 {
343 return false;
344 }
345
invalidateRect(const IntRect & rect)346 void PluginView::invalidateRect(const IntRect& rect)
347 {
348 if (m_isWindowed) {
349 platformWidget()->update(rect);
350 return;
351 }
352
353 invalidateWindowlessPluginRect(rect);
354 }
355
invalidateRect(NPRect * rect)356 void PluginView::invalidateRect(NPRect* rect)
357 {
358 if (m_isWindowed)
359 return;
360 if (!rect) {
361 invalidate();
362 return;
363 }
364 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
365 m_invalidRects.append(r);
366 if (!m_invalidateTimer.isActive())
367 m_invalidateTimer.startOneShot(0.001);
368 }
369
invalidateRegion(NPRegion region)370 void PluginView::invalidateRegion(NPRegion region)
371 {
372 if (m_isWindowed)
373 return;
374
375 if (!region)
376 return;
377
378 QVector<QRect> rects = region->rects();
379 for (int i = 0; i < rects.size(); ++i) {
380 const QRect& qRect = rects.at(i);
381 m_invalidRects.append(qRect);
382 if (!m_invalidateTimer.isActive())
383 m_invalidateTimer.startOneShot(0.001);
384 }
385 }
386
forceRedraw()387 void PluginView::forceRedraw()
388 {
389 if (m_isWindowed)
390 return;
391 invalidate();
392 }
393
platformStart()394 bool PluginView::platformStart()
395 {
396 ASSERT(m_isStarted);
397 ASSERT(m_status == PluginStatusLoadedSuccessfully);
398
399 show();
400
401 if (m_isWindowed) {
402 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
403 QGraphicsProxyWidget* proxy = 0;
404 if (QGraphicsWebView *webView = qobject_cast<QGraphicsWebView*>(client->pluginParent()))
405 proxy = new QGraphicsProxyWidget(webView);
406
407 PluginContainerSymbian* container = new PluginContainerSymbian(this, proxy ? 0 : client->ownerWidget(), proxy);
408 setPlatformWidget(container);
409 if (proxy)
410 proxy->setWidget(container);
411
412 m_npWindow.type = NPWindowTypeWindow;
413 m_npWindow.window = (void*)platformPluginWidget();
414
415 } else {
416 setPlatformWidget(0);
417 m_npWindow.type = NPWindowTypeDrawable;
418 m_npWindow.window = 0; // Not used?
419 }
420 updatePluginWidget();
421 setNPWindowIfNeeded();
422
423 if (qtwebkit_page_plugin_created)
424 qtwebkit_page_plugin_created(QWebFramePrivate::kit(m_parentFrame.get()), m_instance, (void*)(m_plugin->pluginFuncs()));
425
426 return true;
427 }
428
platformDestroy()429 void PluginView::platformDestroy()
430 {
431 if (platformPluginWidget()) {
432 PluginContainerSymbian* container = static_cast<PluginContainerSymbian*>(platformPluginWidget());
433 if (container && container->proxy())
434 delete container->proxy();
435 else
436 delete container;
437 }
438 }
439
halt()440 void PluginView::halt()
441 {
442 }
443
restart()444 void PluginView::restart()
445 {
446 }
447
448 } // namespace WebCore
449