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