| /* |
| Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Library General Public |
| License as published by the Free Software Foundation; either |
| version 2 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Library General Public License for more details. |
| |
| You should have received a copy of the GNU Library General Public License |
| along with this library; see the file COPYING.LIB. If not, write to |
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| Boston, MA 02110-1301, USA. |
| */ |
| #include "config.h" |
| #include "PluginView.h" |
| |
| #include "Bridge.h" |
| #include "Document.h" |
| #include "DocumentLoader.h" |
| #include "Element.h" |
| #include "FocusController.h" |
| #include "Frame.h" |
| #include "FrameLoadRequest.h" |
| #include "FrameLoader.h" |
| #include "FrameTree.h" |
| #include "FrameView.h" |
| #include "GraphicsContext.h" |
| #include "HTMLNames.h" |
| #include "HTMLPlugInElement.h" |
| #include "HostWindow.h" |
| #include "Image.h" |
| #include "JSDOMBinding.h" |
| #include "KeyboardEvent.h" |
| #include "MouseEvent.h" |
| #include "NotImplemented.h" |
| #include "Page.h" |
| #include "PlatformKeyboardEvent.h" |
| #include "PlatformMouseEvent.h" |
| #include "PluginContainerSymbian.h" |
| #include "PluginDebug.h" |
| #include "PluginMainThreadScheduler.h" |
| #include "PluginPackage.h" |
| #include "QWebPageClient.h" |
| #include "RenderLayer.h" |
| #include "ScriptController.h" |
| #include "Settings.h" |
| #include "npfunctions.h" |
| #include "npinterface.h" |
| #include "npruntime_impl.h" |
| #include "qgraphicswebview.h" |
| #include "runtime_root.h" |
| #include <QGraphicsProxyWidget> |
| #include <QKeyEvent> |
| #include <QPixmap> |
| #include <QRegion> |
| #include <QVector> |
| #include <QWidget> |
| #include <runtime/JSLock.h> |
| #include <runtime/JSValue.h> |
| |
| using JSC::ExecState; |
| using JSC::Interpreter; |
| using JSC::JSLock; |
| using JSC::JSObject; |
| using JSC::UString; |
| |
| using namespace std; |
| |
| using namespace WTF; |
| |
| namespace WebCore { |
| |
| using namespace HTMLNames; |
| |
| void PluginView::updatePluginWidget() |
| { |
| if (!parent()) |
| return; |
| ASSERT(parent()->isFrameView()); |
| FrameView* frameView = static_cast<FrameView*>(parent()); |
| IntRect oldWindowRect = m_windowRect; |
| IntRect oldClipRect = m_clipRect; |
| |
| m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); |
| |
| m_clipRect = windowClipRect(); |
| m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); |
| if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect) |
| return; |
| |
| // in order to move/resize the plugin window at the same time as the rest of frame |
| // during e.g. scrolling, we set the mask and geometry in the paint() function, but |
| // as paint() isn't called when the plugin window is outside the frame which can |
| // be caused by a scroll, we need to move/resize immediately. |
| if (!m_windowRect.intersects(frameView->frameRect())) |
| setNPWindowIfNeeded(); |
| } |
| |
| void PluginView::setFocus() |
| { |
| if (platformPluginWidget()) |
| platformPluginWidget()->setFocus(Qt::OtherFocusReason); |
| else |
| Widget::setFocus(); |
| } |
| |
| void PluginView::show() |
| { |
| setSelfVisible(true); |
| |
| if (isParentVisible() && platformPluginWidget()) |
| platformPluginWidget()->setVisible(true); |
| } |
| |
| void PluginView::hide() |
| { |
| setSelfVisible(false); |
| |
| if (isParentVisible() && platformPluginWidget()) |
| platformPluginWidget()->setVisible(false); |
| } |
| |
| void PluginView::paint(GraphicsContext* context, const IntRect& rect) |
| { |
| if (!m_isStarted) { |
| paintMissingPluginIcon(context, rect); |
| return; |
| } |
| |
| if (context->paintingDisabled()) |
| return; |
| m_npWindow.ws_info = (void*)(context->platformContext()); |
| setNPWindowIfNeeded(); |
| |
| if (m_isWindowed && platformPluginWidget()) |
| static_cast<PluginContainerSymbian*>(platformPluginWidget())->adjustGeometry(); |
| |
| if (m_isWindowed) |
| return; |
| |
| context->save(); |
| IntRect clipRect(rect); |
| clipRect.intersect(frameRect()); |
| context->clip(clipRect); |
| context->translate(frameRect().location().x(), frameRect().location().y()); |
| |
| QPaintEvent ev(rect); |
| QEvent& npEvent = ev; |
| dispatchNPEvent(npEvent); |
| |
| context->restore(); |
| } |
| |
| // TODO: Unify across ports. |
| bool PluginView::dispatchNPEvent(NPEvent& event) |
| { |
| if (!m_plugin->pluginFuncs()->event) |
| return false; |
| |
| PluginView::setCurrentPluginView(this); |
| JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); |
| |
| setCallingPlugin(true); |
| bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event); |
| setCallingPlugin(false); |
| PluginView::setCurrentPluginView(0); |
| |
| return accepted; |
| } |
| |
| void PluginView::handleKeyboardEvent(KeyboardEvent* event) |
| { |
| if (m_isWindowed) |
| return; |
| |
| QEvent& npEvent = *(event->keyEvent()->qtEvent()); |
| if (!dispatchNPEvent(npEvent)) |
| event->setDefaultHandled(); |
| } |
| |
| void PluginView::handleMouseEvent(MouseEvent* event) |
| { |
| if (m_isWindowed) |
| return; |
| |
| if (event->type() == eventNames().mousedownEvent) { |
| // Give focus to the plugin on click |
| if (Page* page = m_parentFrame->page()) |
| page->focusController()->setActive(true); |
| |
| focusPluginElement(); |
| } |
| |
| QEvent::Type type; |
| if (event->type() == eventNames().mousedownEvent) |
| type = QEvent::MouseButtonPress; |
| else if (event->type() == eventNames().mousemoveEvent) |
| type = QEvent::MouseMove; |
| else if (event->type() == eventNames().mouseupEvent) |
| type = QEvent::MouseButtonRelease; |
| else |
| return; |
| |
| QPoint position(event->offsetX(), event->offsetY()); |
| Qt::MouseButton button; |
| switch (event->which()) { |
| case 1: |
| button = Qt::LeftButton; |
| break; |
| case 2: |
| button = Qt::MidButton; |
| break; |
| case 3: |
| button = Qt::RightButton; |
| break; |
| default: |
| button = Qt::NoButton; |
| } |
| Qt::KeyboardModifiers modifiers = 0; |
| if (event->ctrlKey()) |
| modifiers |= Qt::ControlModifier; |
| if (event->altKey()) |
| modifiers |= Qt::AltModifier; |
| if (event->shiftKey()) |
| modifiers |= Qt::ShiftModifier; |
| if (event->metaKey()) |
| modifiers |= Qt::MetaModifier; |
| QMouseEvent mouseEvent(type, position, button, button, modifiers); |
| QEvent& npEvent = mouseEvent; |
| if (!dispatchNPEvent(npEvent)) |
| event->setDefaultHandled(); |
| } |
| |
| void PluginView::setParent(ScrollView* parent) |
| { |
| Widget::setParent(parent); |
| |
| if (parent) |
| init(); |
| } |
| |
| void PluginView::setNPWindowRect(const IntRect&) |
| { |
| if (!m_isWindowed) |
| setNPWindowIfNeeded(); |
| } |
| |
| void PluginView::setNPWindowIfNeeded() |
| { |
| if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow) |
| return; |
| if (m_isWindowed) { |
| ASSERT(platformPluginWidget()); |
| platformPluginWidget()->setGeometry(m_windowRect); |
| // if setMask is set with an empty QRegion, no clipping will |
| // be performed, so in that case we hide the plugin view |
| platformPluginWidget()->setVisible(!m_clipRect.isEmpty()); |
| platformPluginWidget()->setMask(QRegion(m_clipRect)); |
| |
| m_npWindow.x = m_windowRect.x(); |
| m_npWindow.y = m_windowRect.y(); |
| |
| m_npWindow.clipRect.left = m_clipRect.x(); |
| m_npWindow.clipRect.top = m_clipRect.y(); |
| m_npWindow.clipRect.right = m_clipRect.width(); |
| m_npWindow.clipRect.bottom = m_clipRect.height(); |
| |
| } else { |
| // always call this method before painting. |
| m_npWindow.x = 0; |
| m_npWindow.y = 0; |
| |
| m_npWindow.clipRect.left = 0; |
| m_npWindow.clipRect.top = 0; |
| m_npWindow.clipRect.right = m_windowRect.width(); |
| m_npWindow.clipRect.bottom = m_windowRect.height(); |
| m_npWindow.window = 0; |
| } |
| |
| m_npWindow.width = m_windowRect.width(); |
| m_npWindow.height = m_windowRect.height(); |
| |
| PluginView::setCurrentPluginView(this); |
| JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); |
| setCallingPlugin(true); |
| m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); |
| setCallingPlugin(false); |
| PluginView::setCurrentPluginView(0); |
| } |
| |
| void PluginView::setParentVisible(bool visible) |
| { |
| if (isParentVisible() == visible) |
| return; |
| |
| Widget::setParentVisible(visible); |
| |
| if (isSelfVisible() && platformPluginWidget()) |
| platformPluginWidget()->setVisible(visible); |
| } |
| |
| NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf) |
| { |
| notImplemented(); |
| return NPERR_NO_ERROR; |
| } |
| |
| bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result) |
| { |
| switch (variable) { |
| case NPNVjavascriptEnabledBool: |
| *static_cast<NPBool*>(value) = true; |
| *result = NPERR_NO_ERROR; |
| return true; |
| |
| case NPNVSupportsWindowless: |
| *static_cast<NPBool*>(value) = true; |
| *result = NPERR_NO_ERROR; |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| |
| bool PluginView::platformGetValue(NPNVariable, void*, NPError*) |
| { |
| return false; |
| } |
| |
| void PluginView::invalidateRect(const IntRect& rect) |
| { |
| if (m_isWindowed) { |
| platformWidget()->update(rect); |
| return; |
| } |
| |
| invalidateWindowlessPluginRect(rect); |
| } |
| |
| void PluginView::invalidateRect(NPRect* rect) |
| { |
| if (m_isWindowed) |
| return; |
| if (!rect) { |
| invalidate(); |
| return; |
| } |
| IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); |
| m_invalidRects.append(r); |
| if (!m_invalidateTimer.isActive()) |
| m_invalidateTimer.startOneShot(0.001); |
| } |
| |
| void PluginView::invalidateRegion(NPRegion region) |
| { |
| if (m_isWindowed) |
| return; |
| |
| if (!region) |
| return; |
| |
| QVector<QRect> rects = region->rects(); |
| for (int i = 0; i < rects.size(); ++i) { |
| const QRect& qRect = rects.at(i); |
| m_invalidRects.append(qRect); |
| if (!m_invalidateTimer.isActive()) |
| m_invalidateTimer.startOneShot(0.001); |
| } |
| } |
| |
| void PluginView::forceRedraw() |
| { |
| if (m_isWindowed) |
| return; |
| invalidate(); |
| } |
| |
| bool PluginView::platformStart() |
| { |
| ASSERT(m_isStarted); |
| ASSERT(m_status == PluginStatusLoadedSuccessfully); |
| |
| show(); |
| |
| if (m_isWindowed) { |
| QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); |
| QGraphicsProxyWidget* proxy = 0; |
| if (QGraphicsWebView *webView = qobject_cast<QGraphicsWebView*>(client->pluginParent())) |
| proxy = new QGraphicsProxyWidget(webView); |
| |
| PluginContainerSymbian* container = new PluginContainerSymbian(this, proxy ? 0 : client->ownerWidget(), proxy); |
| setPlatformWidget(container); |
| if (proxy) |
| proxy->setWidget(container); |
| |
| m_npWindow.type = NPWindowTypeWindow; |
| m_npWindow.window = (void*)platformPluginWidget(); |
| |
| } else { |
| setPlatformWidget(0); |
| m_npWindow.type = NPWindowTypeDrawable; |
| m_npWindow.window = 0; // Not used? |
| } |
| setNPWindowIfNeeded(); |
| |
| return true; |
| } |
| |
| void PluginView::platformDestroy() |
| { |
| if (platformPluginWidget()) { |
| PluginContainerSymbian* container = static_cast<PluginContainerSymbian*>(platformPluginWidget()); |
| if (container && container->proxy()) |
| delete container->proxy(); |
| else |
| delete container; |
| } |
| } |
| |
| void PluginView::halt() |
| { |
| } |
| |
| void PluginView::restart() |
| { |
| } |
| |
| } // namespace WebCore |