/* Copyright (C) 2012 Digia Plc 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 #include #include #include #include #include #include #include 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(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(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& 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(value) = true; *result = NPERR_NO_ERROR; return true; case NPNVSupportsWindowless: *static_cast(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 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(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(platformPluginWidget()); if (container && container->proxy()) delete container->proxy(); else delete container; } } void PluginView::halt() { } void PluginView::restart() { } } // namespace WebCore