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; 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 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 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 118 void PluginView::show() 119 { 120 setSelfVisible(true); 121 122 if (isParentVisible() && platformPluginWidget()) 123 platformPluginWidget()->setVisible(true); 124 } 125 126 void PluginView::hide() 127 { 128 setSelfVisible(false); 129 130 if (isParentVisible() && platformPluginWidget()) 131 platformPluginWidget()->setVisible(false); 132 } 133 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. 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 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 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 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 257 void PluginView::setNPWindowRect(const IntRect&) 258 { 259 if (!m_isWindowed) 260 setNPWindowIfNeeded(); 261 } 262 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 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 317 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf) 318 { 319 notImplemented(); 320 return NPERR_NO_ERROR; 321 } 322 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 341 bool PluginView::platformGetValue(NPNVariable, void*, NPError*) 342 { 343 return false; 344 } 345 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 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 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 387 void PluginView::forceRedraw() 388 { 389 if (m_isWindowed) 390 return; 391 invalidate(); 392 } 393 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 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 440 void PluginView::halt() 441 { 442 } 443 444 void PluginView::restart() 445 { 446 } 447 448 } // namespace WebCore 449