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