Home | History | Annotate | Download | only in symbian
      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