summaryrefslogtreecommitdiff
path: root/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
commit40736c5763bf61337c8c14e16d8587db021a87d4 (patch)
treeb17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp
downloadqtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp')
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp964
1 files changed, 964 insertions, 0 deletions
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp
new file mode 100644
index 000000000..1f09dc408
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp
@@ -0,0 +1,964 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "NetscapePlugin.h"
+
+#include "NPRuntimeObjectMap.h"
+#include "NPRuntimeUtilities.h"
+#include "NetscapePluginStream.h"
+#include "PluginController.h"
+#include "ShareableBitmap.h"
+#include <WebCore/GraphicsContext.h>
+#include <WebCore/HTTPHeaderMap.h>
+#include <WebCore/IntRect.h>
+#include <WebCore/KURL.h>
+#include <utility>
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+using namespace std;
+
+namespace WebKit {
+
+// The plug-in that we're currently calling NPP_New for.
+static NetscapePlugin* currentNPPNewPlugin;
+
+PassRefPtr<NetscapePlugin> NetscapePlugin::create(PassRefPtr<NetscapePluginModule> pluginModule)
+{
+ if (!pluginModule)
+ return 0;
+
+ return adoptRef(new NetscapePlugin(pluginModule));
+}
+
+NetscapePlugin::NetscapePlugin(PassRefPtr<NetscapePluginModule> pluginModule)
+ : m_nextRequestID(0)
+ , m_pluginModule(pluginModule)
+ , m_npWindow()
+ , m_isStarted(false)
+#if PLATFORM(MAC)
+ , m_isWindowed(false)
+#else
+ , m_isWindowed(true)
+#endif
+ , m_isTransparent(false)
+ , m_inNPPNew(false)
+ , m_loadManually(false)
+ , m_nextTimerID(0)
+#if PLATFORM(MAC)
+ , m_drawingModel(static_cast<NPDrawingModel>(-1))
+ , m_eventModel(static_cast<NPEventModel>(-1))
+ , m_pluginReturnsNonretainedLayer(!m_pluginModule->pluginQuirks().contains(PluginQuirks::ReturnsRetainedCoreAnimationLayer))
+ , m_currentMouseEvent(0)
+ , m_pluginHasFocus(false)
+ , m_windowHasFocus(false)
+ , m_pluginWantsLegacyCocoaTextInput(true)
+ , m_isComplexTextInputEnabled(false)
+ , m_hasHandledAKeyDownEvent(false)
+ , m_ignoreNextKeyUpEventCounter(0)
+#ifndef NP_NO_CARBON
+ , m_nullEventTimer(RunLoop::main(), this, &NetscapePlugin::nullEventTimerFired)
+ , m_npCGContext()
+#endif
+#elif PLUGIN_ARCHITECTURE(X11)
+ , m_drawable(0)
+ , m_pluginDisplay(0)
+#endif
+{
+ m_npp.ndata = this;
+ m_npp.pdata = 0;
+
+ m_pluginModule->incrementLoadCount();
+}
+
+NetscapePlugin::~NetscapePlugin()
+{
+ ASSERT(!m_isStarted);
+ ASSERT(m_timers.isEmpty());
+
+ m_pluginModule->decrementLoadCount();
+}
+
+PassRefPtr<NetscapePlugin> NetscapePlugin::fromNPP(NPP npp)
+{
+ if (npp)
+ return static_cast<NetscapePlugin*>(npp->ndata);
+
+ // FIXME: Return the current NetscapePlugin here.
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void NetscapePlugin::invalidate(const NPRect* invalidRect)
+{
+ IntRect rect;
+
+ if (!invalidRect)
+ rect = IntRect(0, 0, m_pluginSize.width(), m_pluginSize.height());
+ else
+ rect = IntRect(invalidRect->left, invalidRect->top, invalidRect->right - invalidRect->left, invalidRect->bottom - invalidRect->top);
+
+ if (platformInvalidate(rect))
+ return;
+
+ controller()->invalidate(rect);
+}
+
+const char* NetscapePlugin::userAgent(NPP npp)
+{
+ if (npp)
+ return fromNPP(npp)->userAgent();
+
+ if (currentNPPNewPlugin)
+ return currentNPPNewPlugin->userAgent();
+
+ return 0;
+}
+
+const char* NetscapePlugin::userAgent()
+{
+#if PLUGIN_ARCHITECTURE(WIN)
+ static const char* MozillaUserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";
+
+ if (quirks().contains(PluginQuirks::WantsMozillaUserAgent))
+ return MozillaUserAgent;
+#endif
+
+ if (m_userAgent.isNull()) {
+ String userAgent = controller()->userAgent();
+ ASSERT(!userAgent.isNull());
+
+#if PLUGIN_ARCHITECTURE(MAC)
+ if (quirks().contains(PluginQuirks::AppendVersion3UserAgent))
+ userAgent += " Version/3.2.1";
+#endif
+
+ m_userAgent = userAgent.utf8();
+ }
+ return m_userAgent.data();
+}
+
+void NetscapePlugin::loadURL(const String& method, const String& urlString, const String& target, const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody,
+ bool sendNotification, void* notificationData)
+{
+ uint64_t requestID = ++m_nextRequestID;
+
+ controller()->loadURL(requestID, method, urlString, target, headerFields, httpBody, allowPopups());
+
+ if (target.isNull()) {
+ // The browser is going to send the data in a stream, create a plug-in stream.
+ RefPtr<NetscapePluginStream> pluginStream = NetscapePluginStream::create(this, requestID, urlString, sendNotification, notificationData);
+ ASSERT(!m_streams.contains(requestID));
+
+ m_streams.set(requestID, pluginStream.release());
+ return;
+ }
+
+ if (sendNotification) {
+ // Eventually we are going to get a frameDidFinishLoading or frameDidFail call for this request.
+ // Keep track of the notification data so we can call NPP_URLNotify.
+ ASSERT(!m_pendingURLNotifications.contains(requestID));
+ m_pendingURLNotifications.set(requestID, make_pair(urlString, notificationData));
+ }
+}
+
+NPError NetscapePlugin::destroyStream(NPStream* stream, NPReason reason)
+{
+ NetscapePluginStream* pluginStream = 0;
+
+ for (StreamsMap::const_iterator it = m_streams.begin(), end = m_streams.end(); it != end; ++it) {
+ if (it->second->npStream() == stream) {
+ pluginStream = it->second.get();
+ break;
+ }
+ }
+
+ if (!pluginStream)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ return pluginStream->destroy(reason);
+}
+
+void NetscapePlugin::setIsWindowed(bool isWindowed)
+{
+ // Once the plugin has started, it's too late to change whether the plugin is windowed or not.
+ // (This is true in Firefox and Chrome, too.) Disallow setting m_isWindowed in that case to
+ // keep our internal state consistent.
+ if (m_isStarted)
+ return;
+
+ m_isWindowed = isWindowed;
+}
+
+void NetscapePlugin::setIsTransparent(bool isTransparent)
+{
+ m_isTransparent = isTransparent;
+}
+
+void NetscapePlugin::setStatusbarText(const String& statusbarText)
+{
+ controller()->setStatusbarText(statusbarText);
+}
+
+static void (*setExceptionFunction)(const String&);
+
+void NetscapePlugin::setSetExceptionFunction(void (*function)(const String&))
+{
+ ASSERT(!setExceptionFunction || setExceptionFunction == function);
+ setExceptionFunction = function;
+}
+
+void NetscapePlugin::setException(const String& exceptionString)
+{
+ ASSERT(setExceptionFunction);
+ setExceptionFunction(exceptionString);
+}
+
+bool NetscapePlugin::evaluate(NPObject* npObject, const String& scriptString, NPVariant* result)
+{
+ return controller()->evaluate(npObject, scriptString, result, allowPopups());
+}
+
+bool NetscapePlugin::isPrivateBrowsingEnabled()
+{
+ return controller()->isPrivateBrowsingEnabled();
+}
+
+NPObject* NetscapePlugin::windowScriptNPObject()
+{
+ return controller()->windowScriptNPObject();
+}
+
+NPObject* NetscapePlugin::pluginElementNPObject()
+{
+ return controller()->pluginElementNPObject();
+}
+
+bool NetscapePlugin::tryToShortCircuitInvoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, bool& returnValue, NPVariant& result)
+{
+ return controller()->tryToShortCircuitInvoke(npObject, methodName, arguments, argumentCount, returnValue, result);
+}
+
+void NetscapePlugin::cancelStreamLoad(NetscapePluginStream* pluginStream)
+{
+ if (pluginStream == m_manualStream) {
+ controller()->cancelManualStreamLoad();
+ return;
+ }
+
+ // Ask the plug-in controller to cancel this stream load.
+ controller()->cancelStreamLoad(pluginStream->streamID());
+}
+
+void NetscapePlugin::removePluginStream(NetscapePluginStream* pluginStream)
+{
+ if (pluginStream == m_manualStream) {
+ m_manualStream = 0;
+ return;
+ }
+
+ ASSERT(m_streams.get(pluginStream->streamID()) == pluginStream);
+ m_streams.remove(pluginStream->streamID());
+}
+
+bool NetscapePlugin::isAcceleratedCompositingEnabled()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ return controller()->isAcceleratedCompositingEnabled();
+#else
+ return false;
+#endif
+}
+
+void NetscapePlugin::pushPopupsEnabledState(bool state)
+{
+ m_popupEnabledStates.append(state);
+}
+
+void NetscapePlugin::popPopupsEnabledState()
+{
+ ASSERT(!m_popupEnabledStates.isEmpty());
+
+ m_popupEnabledStates.removeLast();
+}
+
+void NetscapePlugin::pluginThreadAsyncCall(void (*function)(void*), void* userData)
+{
+ RunLoop::main()->dispatch(bind(&NetscapePlugin::handlePluginThreadAsyncCall, this, function, userData));
+}
+
+void NetscapePlugin::handlePluginThreadAsyncCall(void (*function)(void*), void* userData)
+{
+ if (!m_isStarted)
+ return;
+
+ function(userData);
+}
+
+PassOwnPtr<NetscapePlugin::Timer> NetscapePlugin::Timer::create(NetscapePlugin* netscapePlugin, unsigned timerID, unsigned interval, bool repeat, TimerFunc timerFunc)
+{
+ return adoptPtr(new Timer(netscapePlugin, timerID, interval, repeat, timerFunc));
+}
+
+NetscapePlugin::Timer::Timer(NetscapePlugin* netscapePlugin, unsigned timerID, unsigned interval, bool repeat, TimerFunc timerFunc)
+ : m_netscapePlugin(netscapePlugin)
+ , m_timerID(timerID)
+ , m_interval(interval)
+ , m_repeat(repeat)
+ , m_timerFunc(timerFunc)
+ , m_timer(RunLoop::main(), this, &Timer::timerFired)
+{
+}
+
+NetscapePlugin::Timer::~Timer()
+{
+}
+
+void NetscapePlugin::Timer::start()
+{
+ double timeInterval = m_interval / 1000.0;
+
+ if (m_repeat)
+ m_timer.startRepeating(timeInterval);
+ else
+ m_timer.startOneShot(timeInterval);
+}
+
+void NetscapePlugin::Timer::stop()
+{
+ m_timer.stop();
+}
+
+void NetscapePlugin::Timer::timerFired()
+{
+ m_timerFunc(&m_netscapePlugin->m_npp, m_timerID);
+
+ if (!m_repeat)
+ m_netscapePlugin->unscheduleTimer(m_timerID);
+}
+
+uint32_t NetscapePlugin::scheduleTimer(unsigned interval, bool repeat, void (*timerFunc)(NPP, unsigned timerID))
+{
+ if (!timerFunc)
+ return 0;
+
+ // FIXME: Handle wrapping around.
+ unsigned timerID = ++m_nextTimerID;
+
+ OwnPtr<Timer> timer = Timer::create(this, timerID, interval, repeat, timerFunc);
+
+ // FIXME: Based on the plug-in visibility, figure out if we should throttle the timer, or if we should start it at all.
+ timer->start();
+ m_timers.set(timerID, timer.leakPtr());
+
+ return timerID;
+}
+
+void NetscapePlugin::unscheduleTimer(unsigned timerID)
+{
+ TimerMap::iterator it = m_timers.find(timerID);
+ if (it == m_timers.end())
+ return;
+
+ OwnPtr<Timer> timer = adoptPtr(it->second);
+ m_timers.remove(it);
+
+ timer->stop();
+}
+
+double NetscapePlugin::contentsScaleFactor()
+{
+ return controller()->contentsScaleFactor();
+}
+
+String NetscapePlugin::proxiesForURL(const String& urlString)
+{
+ return controller()->proxiesForURL(urlString);
+}
+
+String NetscapePlugin::cookiesForURL(const String& urlString)
+{
+ return controller()->cookiesForURL(urlString);
+}
+
+void NetscapePlugin::setCookiesForURL(const String& urlString, const String& cookieString)
+{
+ controller()->setCookiesForURL(urlString, cookieString);
+}
+
+bool NetscapePlugin::getAuthenticationInfo(const ProtectionSpace& protectionSpace, String& username, String& password)
+{
+ return controller()->getAuthenticationInfo(protectionSpace, username, password);
+}
+
+NPError NetscapePlugin::NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* savedData)
+{
+ return m_pluginModule->pluginFuncs().newp(pluginType, &m_npp, mode, argc, argn, argv, savedData);
+}
+
+NPError NetscapePlugin::NPP_Destroy(NPSavedData** savedData)
+{
+ return m_pluginModule->pluginFuncs().destroy(&m_npp, savedData);
+}
+
+NPError NetscapePlugin::NPP_SetWindow(NPWindow* npWindow)
+{
+ return m_pluginModule->pluginFuncs().setwindow(&m_npp, npWindow);
+}
+
+NPError NetscapePlugin::NPP_NewStream(NPMIMEType mimeType, NPStream* stream, NPBool seekable, uint16_t* streamType)
+{
+ return m_pluginModule->pluginFuncs().newstream(&m_npp, mimeType, stream, seekable, streamType);
+}
+
+NPError NetscapePlugin::NPP_DestroyStream(NPStream* stream, NPReason reason)
+{
+ return m_pluginModule->pluginFuncs().destroystream(&m_npp, stream, reason);
+}
+
+void NetscapePlugin::NPP_StreamAsFile(NPStream* stream, const char* filename)
+{
+ return m_pluginModule->pluginFuncs().asfile(&m_npp, stream, filename);
+}
+
+int32_t NetscapePlugin::NPP_WriteReady(NPStream* stream)
+{
+ return m_pluginModule->pluginFuncs().writeready(&m_npp, stream);
+}
+
+int32_t NetscapePlugin::NPP_Write(NPStream* stream, int32_t offset, int32_t len, void* buffer)
+{
+ return m_pluginModule->pluginFuncs().write(&m_npp, stream, offset, len, buffer);
+}
+
+int16_t NetscapePlugin::NPP_HandleEvent(void* event)
+{
+ return m_pluginModule->pluginFuncs().event(&m_npp, event);
+}
+
+void NetscapePlugin::NPP_URLNotify(const char* url, NPReason reason, void* notifyData)
+{
+ m_pluginModule->pluginFuncs().urlnotify(&m_npp, url, reason, notifyData);
+}
+
+NPError NetscapePlugin::NPP_GetValue(NPPVariable variable, void *value)
+{
+ if (!m_pluginModule->pluginFuncs().getvalue)
+ return NPERR_GENERIC_ERROR;
+
+ return m_pluginModule->pluginFuncs().getvalue(&m_npp, variable, value);
+}
+
+NPError NetscapePlugin::NPP_SetValue(NPNVariable variable, void *value)
+{
+ if (!m_pluginModule->pluginFuncs().setvalue)
+ return NPERR_GENERIC_ERROR;
+
+ return m_pluginModule->pluginFuncs().setvalue(&m_npp, variable, value);
+}
+
+void NetscapePlugin::callSetWindow()
+{
+ if (wantsPluginRelativeNPWindowCoordinates()) {
+ m_npWindow.x = 0;
+ m_npWindow.y = 0;
+ m_npWindow.clipRect.top = m_clipRect.y();
+ m_npWindow.clipRect.left = m_clipRect.x();
+ } else {
+ IntPoint pluginLocationInRootViewCoordinates = convertToRootView(IntPoint());
+ IntPoint clipRectInRootViewCoordinates = convertToRootView(m_clipRect.location());
+
+ m_npWindow.x = pluginLocationInRootViewCoordinates.x();
+ m_npWindow.y = pluginLocationInRootViewCoordinates.y();
+ m_npWindow.clipRect.top = clipRectInRootViewCoordinates.y();
+ m_npWindow.clipRect.left = clipRectInRootViewCoordinates.x();
+ }
+
+ m_npWindow.width = m_pluginSize.width();
+ m_npWindow.height = m_pluginSize.height();
+ m_npWindow.clipRect.right = m_npWindow.clipRect.left + m_clipRect.width();
+ m_npWindow.clipRect.bottom = m_npWindow.clipRect.top + m_clipRect.height();
+
+ NPP_SetWindow(&m_npWindow);
+}
+
+bool NetscapePlugin::shouldLoadSrcURL()
+{
+ // Check if we should cancel the load
+ NPBool cancelSrcStream = false;
+
+ if (NPP_GetValue(NPPVpluginCancelSrcStream, &cancelSrcStream) != NPERR_NO_ERROR)
+ return true;
+
+ return !cancelSrcStream;
+}
+
+NetscapePluginStream* NetscapePlugin::streamFromID(uint64_t streamID)
+{
+ return m_streams.get(streamID).get();
+}
+
+void NetscapePlugin::stopAllStreams()
+{
+ Vector<RefPtr<NetscapePluginStream> > streams;
+ copyValuesToVector(m_streams, streams);
+
+ for (size_t i = 0; i < streams.size(); ++i)
+ streams[i]->stop(NPRES_USER_BREAK);
+}
+
+bool NetscapePlugin::allowPopups() const
+{
+ if (m_pluginModule->pluginFuncs().version >= NPVERS_HAS_POPUPS_ENABLED_STATE) {
+ if (!m_popupEnabledStates.isEmpty())
+ return m_popupEnabledStates.last();
+ }
+
+ // FIXME: Check if the current event is a user gesture.
+ // Really old versions of Flash required this for popups to work, but all newer versions
+ // support NPN_PushPopupEnabledState/NPN_PopPopupEnabledState.
+ return false;
+}
+
+bool NetscapePlugin::initialize(const Parameters& parameters)
+{
+ uint16_t mode = parameters.loadManually ? NP_FULL : NP_EMBED;
+
+ m_loadManually = parameters.loadManually;
+
+ CString mimeTypeCString = parameters.mimeType.utf8();
+
+ ASSERT(parameters.names.size() == parameters.values.size());
+
+ Vector<CString> paramNames;
+ Vector<CString> paramValues;
+ for (size_t i = 0; i < parameters.names.size(); ++i) {
+ String parameterName = parameters.names[i];
+
+#if PLUGIN_ARCHITECTURE(MAC)
+ if (m_pluginModule->pluginQuirks().contains(PluginQuirks::WantsLowercaseParameterNames))
+ parameterName = parameterName.lower();
+#endif
+
+ paramNames.append(parameterName.utf8());
+ paramValues.append(parameters.values[i].utf8());
+ }
+
+ // The strings that these pointers point to are kept alive by paramNames and paramValues.
+ Vector<const char*> names;
+ Vector<const char*> values;
+ for (size_t i = 0; i < paramNames.size(); ++i) {
+ names.append(paramNames[i].data());
+ values.append(paramValues[i].data());
+ }
+
+#if PLUGIN_ARCHITECTURE(MAC)
+ if (m_pluginModule->pluginQuirks().contains(PluginQuirks::MakeTransparentIfBackgroundAttributeExists)) {
+ for (size_t i = 0; i < parameters.names.size(); ++i) {
+ if (equalIgnoringCase(parameters.names[i], "background")) {
+ setIsTransparent(true);
+ break;
+ }
+ }
+ }
+#endif
+
+ NetscapePlugin* previousNPPNewPlugin = currentNPPNewPlugin;
+
+ m_inNPPNew = true;
+ currentNPPNewPlugin = this;
+
+ NPError error = NPP_New(const_cast<char*>(mimeTypeCString.data()), mode, names.size(),
+ const_cast<char**>(names.data()), const_cast<char**>(values.data()), 0);
+
+ m_inNPPNew = false;
+ currentNPPNewPlugin = previousNPPNewPlugin;
+
+ if (error != NPERR_NO_ERROR)
+ return false;
+
+ m_isStarted = true;
+
+ // FIXME: This is not correct in all cases.
+ m_npWindow.type = NPWindowTypeDrawable;
+
+ if (!platformPostInitialize()) {
+ destroy();
+ return false;
+ }
+
+ // Load the src URL if needed.
+ if (!parameters.loadManually && !parameters.url.isEmpty() && shouldLoadSrcURL())
+ loadURL("GET", parameters.url.string(), String(), HTTPHeaderMap(), Vector<uint8_t>(), false, 0);
+
+ return true;
+}
+
+void NetscapePlugin::destroy()
+{
+ ASSERT(m_isStarted);
+
+ // Stop all streams.
+ stopAllStreams();
+
+#if !PLUGIN_ARCHITECTURE(MAC) && !PLUGIN_ARCHITECTURE(X11)
+ m_npWindow.window = 0;
+ callSetWindow();
+#endif
+
+ NPP_Destroy(0);
+
+ m_isStarted = false;
+
+ platformDestroy();
+
+ deleteAllValues(m_timers);
+ m_timers.clear();
+}
+
+void NetscapePlugin::paint(GraphicsContext* context, const IntRect& dirtyRect)
+{
+ ASSERT(m_isStarted);
+
+ platformPaint(context, dirtyRect);
+}
+
+PassRefPtr<ShareableBitmap> NetscapePlugin::snapshot()
+{
+ if (!supportsSnapshotting() || m_pluginSize.isEmpty())
+ return 0;
+
+ ASSERT(m_isStarted);
+
+ IntSize backingStoreSize = m_pluginSize;
+ backingStoreSize.scale(contentsScaleFactor());
+
+ RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(backingStoreSize, ShareableBitmap::SupportsAlpha);
+ OwnPtr<GraphicsContext> context = bitmap->createGraphicsContext();
+
+ // FIXME: We should really call applyDeviceScaleFactor instead of scale, but that ends up calling into WKSI
+ // which we currently don't have initiated in the plug-in process.
+ context->scale(FloatSize(contentsScaleFactor(), contentsScaleFactor()));
+
+ platformPaint(context.get(), IntRect(IntPoint(), m_pluginSize), true);
+
+ return bitmap.release();
+}
+
+bool NetscapePlugin::isTransparent()
+{
+ return m_isTransparent;
+}
+
+void NetscapePlugin::geometryDidChange(const IntSize& pluginSize, const IntRect& clipRect, const AffineTransform& pluginToRootViewTransform)
+{
+ ASSERT(m_isStarted);
+
+ if (pluginSize == m_pluginSize && m_clipRect == clipRect && m_pluginToRootViewTransform == pluginToRootViewTransform) {
+ // Nothing to do.
+ return;
+ }
+
+ bool shouldCallWindow = true;
+
+ // If the plug-in doesn't want window relative coordinates, we don't need to call setWindow unless its size or clip rect changes.
+ if (wantsPluginRelativeNPWindowCoordinates() && m_pluginSize == pluginSize && m_clipRect == clipRect)
+ shouldCallWindow = false;
+
+ m_pluginSize = pluginSize;
+ m_clipRect = clipRect;
+ m_pluginToRootViewTransform = pluginToRootViewTransform;
+
+ IntPoint frameRectLocationInWindowCoordinates = m_pluginToRootViewTransform.mapPoint(IntPoint());
+ m_frameRectInWindowCoordinates = IntRect(frameRectLocationInWindowCoordinates, m_pluginSize);
+
+ platformGeometryDidChange();
+
+ if (!shouldCallWindow)
+ return;
+
+ callSetWindow();
+}
+
+void NetscapePlugin::visibilityDidChange()
+{
+ ASSERT(m_isStarted);
+
+ platformVisibilityDidChange();
+}
+
+void NetscapePlugin::frameDidFinishLoading(uint64_t requestID)
+{
+ ASSERT(m_isStarted);
+
+ PendingURLNotifyMap::iterator it = m_pendingURLNotifications.find(requestID);
+ if (it == m_pendingURLNotifications.end())
+ return;
+
+ String url = it->second.first;
+ void* notificationData = it->second.second;
+
+ m_pendingURLNotifications.remove(it);
+
+ NPP_URLNotify(url.utf8().data(), NPRES_DONE, notificationData);
+}
+
+void NetscapePlugin::frameDidFail(uint64_t requestID, bool wasCancelled)
+{
+ ASSERT(m_isStarted);
+
+ PendingURLNotifyMap::iterator it = m_pendingURLNotifications.find(requestID);
+ if (it == m_pendingURLNotifications.end())
+ return;
+
+ String url = it->second.first;
+ void* notificationData = it->second.second;
+
+ m_pendingURLNotifications.remove(it);
+
+ NPP_URLNotify(url.utf8().data(), wasCancelled ? NPRES_USER_BREAK : NPRES_NETWORK_ERR, notificationData);
+}
+
+void NetscapePlugin::didEvaluateJavaScript(uint64_t requestID, const String& result)
+{
+ ASSERT(m_isStarted);
+
+ if (NetscapePluginStream* pluginStream = streamFromID(requestID))
+ pluginStream->sendJavaScriptStream(result);
+}
+
+void NetscapePlugin::streamDidReceiveResponse(uint64_t streamID, const KURL& responseURL, uint32_t streamLength,
+ uint32_t lastModifiedTime, const String& mimeType, const String& headers, const String& /* suggestedFileName */)
+{
+ ASSERT(m_isStarted);
+
+ if (NetscapePluginStream* pluginStream = streamFromID(streamID))
+ pluginStream->didReceiveResponse(responseURL, streamLength, lastModifiedTime, mimeType, headers);
+}
+
+void NetscapePlugin::streamDidReceiveData(uint64_t streamID, const char* bytes, int length)
+{
+ ASSERT(m_isStarted);
+
+ if (NetscapePluginStream* pluginStream = streamFromID(streamID))
+ pluginStream->didReceiveData(bytes, length);
+}
+
+void NetscapePlugin::streamDidFinishLoading(uint64_t streamID)
+{
+ ASSERT(m_isStarted);
+
+ if (NetscapePluginStream* pluginStream = streamFromID(streamID))
+ pluginStream->didFinishLoading();
+}
+
+void NetscapePlugin::streamDidFail(uint64_t streamID, bool wasCancelled)
+{
+ ASSERT(m_isStarted);
+
+ if (NetscapePluginStream* pluginStream = streamFromID(streamID))
+ pluginStream->didFail(wasCancelled);
+}
+
+void NetscapePlugin::manualStreamDidReceiveResponse(const KURL& responseURL, uint32_t streamLength, uint32_t lastModifiedTime,
+ const String& mimeType, const String& headers, const String& /* suggestedFileName */)
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_loadManually);
+ ASSERT(!m_manualStream);
+
+ m_manualStream = NetscapePluginStream::create(this, 0, responseURL.string(), false, 0);
+ m_manualStream->didReceiveResponse(responseURL, streamLength, lastModifiedTime, mimeType, headers);
+}
+
+void NetscapePlugin::manualStreamDidReceiveData(const char* bytes, int length)
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_loadManually);
+ ASSERT(m_manualStream);
+
+ m_manualStream->didReceiveData(bytes, length);
+}
+
+void NetscapePlugin::manualStreamDidFinishLoading()
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_loadManually);
+ ASSERT(m_manualStream);
+
+ m_manualStream->didFinishLoading();
+}
+
+void NetscapePlugin::manualStreamDidFail(bool wasCancelled)
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_loadManually);
+
+ if (!m_manualStream)
+ return;
+ m_manualStream->didFail(wasCancelled);
+}
+
+bool NetscapePlugin::handleMouseEvent(const WebMouseEvent& mouseEvent)
+{
+ ASSERT(m_isStarted);
+
+ return platformHandleMouseEvent(mouseEvent);
+}
+
+bool NetscapePlugin::handleWheelEvent(const WebWheelEvent& wheelEvent)
+{
+ ASSERT(m_isStarted);
+
+ return platformHandleWheelEvent(wheelEvent);
+}
+
+bool NetscapePlugin::handleMouseEnterEvent(const WebMouseEvent& mouseEvent)
+{
+ ASSERT(m_isStarted);
+
+ return platformHandleMouseEnterEvent(mouseEvent);
+}
+
+bool NetscapePlugin::handleMouseLeaveEvent(const WebMouseEvent& mouseEvent)
+{
+ ASSERT(m_isStarted);
+
+ return platformHandleMouseLeaveEvent(mouseEvent);
+}
+
+bool NetscapePlugin::handleContextMenuEvent(const WebMouseEvent&)
+{
+ // We don't know if the plug-in has handled mousedown event by displaying a context menu, so we never want WebKit to show a default one.
+ return true;
+}
+
+bool NetscapePlugin::handleKeyboardEvent(const WebKeyboardEvent& keyboardEvent)
+{
+ ASSERT(m_isStarted);
+
+ return platformHandleKeyboardEvent(keyboardEvent);
+}
+
+void NetscapePlugin::setFocus(bool hasFocus)
+{
+ ASSERT(m_isStarted);
+
+ platformSetFocus(hasFocus);
+}
+
+NPObject* NetscapePlugin::pluginScriptableNPObject()
+{
+ ASSERT(m_isStarted);
+ NPObject* scriptableNPObject = 0;
+
+ if (NPP_GetValue(NPPVpluginScriptableNPObject, &scriptableNPObject) != NPERR_NO_ERROR)
+ return 0;
+
+#if PLUGIN_ARCHITECTURE(MAC)
+ if (m_pluginModule->pluginQuirks().contains(PluginQuirks::ReturnsNonRetainedScriptableNPObject))
+ retainNPObject(scriptableNPObject);
+#endif
+
+ return scriptableNPObject;
+}
+
+void NetscapePlugin::contentsScaleFactorChanged(float scaleFactor)
+{
+ ASSERT(m_isStarted);
+
+#if PLUGIN_ARCHITECTURE(MAC)
+ double contentsScaleFactor = scaleFactor;
+ NPP_SetValue(NPNVcontentsScaleFactor, &contentsScaleFactor);
+#endif
+}
+
+void NetscapePlugin::privateBrowsingStateChanged(bool privateBrowsingEnabled)
+{
+ ASSERT(m_isStarted);
+
+ // From https://wiki.mozilla.org/Plugins:PrivateMode
+ // When the browser turns private mode on or off it will call NPP_SetValue for "NPNVprivateModeBool"
+ // (assigned enum value 18) with a pointer to an NPBool value on all applicable instances.
+ // Plugins should check the boolean value pointed to, not the pointer itself.
+ // The value will be true when private mode is on.
+ NPBool value = privateBrowsingEnabled;
+ NPP_SetValue(NPNVprivateModeBool, &value);
+}
+
+bool NetscapePlugin::getFormValue(String& formValue)
+{
+ ASSERT(m_isStarted);
+
+ char* formValueString = 0;
+ if (NPP_GetValue(NPPVformValue, &formValueString) != NPERR_NO_ERROR)
+ return false;
+
+ formValue = String::fromUTF8(formValueString);
+
+ // The plug-in allocates the form value string with NPN_MemAlloc so it needs to be freed with NPN_MemFree.
+ npnMemFree(formValueString);
+ return true;
+}
+
+bool NetscapePlugin::handleScroll(ScrollDirection, ScrollGranularity)
+{
+ return false;
+}
+
+Scrollbar* NetscapePlugin::horizontalScrollbar()
+{
+ return 0;
+}
+
+Scrollbar* NetscapePlugin::verticalScrollbar()
+{
+ return 0;
+}
+
+bool NetscapePlugin::supportsSnapshotting() const
+{
+#if PLATFORM(MAC)
+ return m_pluginModule && m_pluginModule->pluginQuirks().contains(PluginQuirks::SupportsSnapshotting);
+#endif
+ return false;
+}
+
+IntPoint NetscapePlugin::convertToRootView(const IntPoint& pointInPluginCoordinates) const
+{
+ return m_pluginToRootViewTransform.mapPoint(pointInPluginCoordinates);
+}
+
+bool NetscapePlugin::convertFromRootView(const IntPoint& pointInRootViewCoordinates, IntPoint& pointInPluginCoordinates)
+{
+ if (!m_pluginToRootViewTransform.isInvertible())
+ return false;
+
+ pointInPluginCoordinates = m_pluginToRootViewTransform.inverse().mapPoint(pointInRootViewCoordinates);
+ return true;
+}
+
+} // namespace WebKit