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 68typedef void (*_qtwebkit_page_plugin_created)(QWebFrame*, void*, void*); // frame, plugin instance, plugin functions 69static _qtwebkit_page_plugin_created qtwebkit_page_plugin_created = 0; 70QWEBKIT_EXPORT void qtwebkit_setPluginCreatedCallback(_qtwebkit_page_plugin_created cb) 71{ 72 qtwebkit_page_plugin_created = cb; 73} 74 75using JSC::ExecState; 76using JSC::Interpreter; 77using JSC::JSLock; 78using JSC::JSObject; 79using JSC::UString; 80 81using namespace std; 82 83using namespace WTF; 84 85namespace WebCore { 86 87using namespace HTMLNames; 88 89void 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 108void 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 118void PluginView::show() 119{ 120 setSelfVisible(true); 121 122 if (isParentVisible() && platformPluginWidget()) 123 platformPluginWidget()->setVisible(true); 124} 125 126void PluginView::hide() 127{ 128 setSelfVisible(false); 129 130 if (isParentVisible() && platformPluginWidget()) 131 platformPluginWidget()->setVisible(false); 132} 133 134void 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. 166bool 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 182void 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 193void 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 246void 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 257void PluginView::setNPWindowRect(const IntRect&) 258{ 259 if (!m_isWindowed) 260 setNPWindowIfNeeded(); 261} 262 263void 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 306void 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 317NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf) 318{ 319 notImplemented(); 320 return NPERR_NO_ERROR; 321} 322 323bool 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 341bool PluginView::platformGetValue(NPNVariable, void*, NPError*) 342{ 343 return false; 344} 345 346void PluginView::invalidateRect(const IntRect& rect) 347{ 348 if (m_isWindowed) { 349 platformWidget()->update(rect); 350 return; 351 } 352 353 invalidateWindowlessPluginRect(rect); 354} 355 356void 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 370void 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 387void PluginView::forceRedraw() 388{ 389 if (m_isWindowed) 390 return; 391 invalidate(); 392} 393 394bool 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 429void 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 440void PluginView::halt() 441{ 442} 443 444void PluginView::restart() 445{ 446} 447 448} // namespace WebCore 449