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