NetscapePlugin.cpp [plain text]
#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 {
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_pluginController(0)
, 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)
#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)
#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);
m_pluginModule->decrementLoadCount();
}
PassRefPtr<NetscapePlugin> NetscapePlugin::fromNPP(NPP npp)
{
if (npp)
return static_cast<NetscapePlugin*>(npp->ndata);
ASSERT_NOT_REACHED();
return 0;
}
void NetscapePlugin::invalidate(const NPRect* invalidRect)
{
IntRect rect;
if (!invalidRect)
rect = IntRect(0, 0, m_frameRectInWindowCoordinates.width(), m_frameRectInWindowCoordinates.height());
else
rect = IntRect(invalidRect->left, invalidRect->top,
invalidRect->right - invalidRect->left, invalidRect->bottom - invalidRect->top);
if (platformInvalidate(rect))
return;
m_pluginController->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;
m_pluginController->loadURL(requestID, method, urlString, target, headerFields, httpBody, allowPopups());
if (target.isNull()) {
RefPtr<NetscapePluginStream> pluginStream = NetscapePluginStream::create(this, requestID, urlString, sendNotification, notificationData);
ASSERT(!m_streams.contains(requestID));
m_streams.set(requestID, pluginStream.release());
return;
}
if (sendNotification) {
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)
{
if (m_isStarted)
return;
m_isWindowed = isWindowed;
}
void NetscapePlugin::setIsTransparent(bool isTransparent)
{
m_isTransparent = isTransparent;
}
void NetscapePlugin::setStatusbarText(const String& statusbarText)
{
m_pluginController->setStatusbarText(statusbarText);
}
void NetscapePlugin::setException(const String& exceptionString)
{
NPRuntimeObjectMap::setGlobalException(exceptionString);
}
bool NetscapePlugin::evaluate(NPObject* npObject, const String& scriptString, NPVariant* result)
{
return m_pluginController->evaluate(npObject, scriptString, result, allowPopups());
}
bool NetscapePlugin::isPrivateBrowsingEnabled()
{
return m_pluginController->isPrivateBrowsingEnabled();
}
NPObject* NetscapePlugin::windowScriptNPObject()
{
return m_pluginController->windowScriptNPObject();
}
NPObject* NetscapePlugin::pluginElementNPObject()
{
return m_pluginController->pluginElementNPObject();
}
bool NetscapePlugin::tryToShortCircuitInvoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, bool& returnValue, NPVariant& result)
{
return m_pluginController->tryToShortCircuitInvoke(npObject, methodName, arguments, argumentCount, returnValue, result);
}
void NetscapePlugin::cancelStreamLoad(NetscapePluginStream* pluginStream)
{
if (pluginStream == m_manualStream) {
m_pluginController->cancelManualStreamLoad();
return;
}
m_pluginController->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 m_pluginController->isAcceleratedCompositingEnabled();
#else
return false;
#endif
}
void NetscapePlugin::pushPopupsEnabledState(bool state)
{
m_popupEnabledStates.append(state);
}
void NetscapePlugin::popPopupsEnabledState()
{
ASSERT(!m_popupEnabledStates.isEmpty());
m_popupEnabledStates.removeLast();
}
double NetscapePlugin::contentsScaleFactor()
{
return controller()->contentsScaleFactor();
}
String NetscapePlugin::proxiesForURL(const String& urlString)
{
return m_pluginController->proxiesForURL(urlString);
}
String NetscapePlugin::cookiesForURL(const String& urlString)
{
return m_pluginController->cookiesForURL(urlString);
}
void NetscapePlugin::setCookiesForURL(const String& urlString, const String& cookieString)
{
m_pluginController->setCookiesForURL(urlString, cookieString);
}
bool NetscapePlugin::getAuthenticationInfo(const ProtectionSpace& protectionSpace, String& username, String& password)
{
return m_pluginController->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 PLUGIN_ARCHITECTURE(X11)
m_npWindow.x = 0;
m_npWindow.y = 0;
#else
m_npWindow.x = m_frameRectInWindowCoordinates.x();
m_npWindow.y = m_frameRectInWindowCoordinates.y();
#endif
m_npWindow.width = m_frameRectInWindowCoordinates.width();
m_npWindow.height = m_frameRectInWindowCoordinates.height();
m_npWindow.clipRect.top = m_clipRectInWindowCoordinates.y();
m_npWindow.clipRect.left = m_clipRectInWindowCoordinates.x();
m_npWindow.clipRect.bottom = m_clipRectInWindowCoordinates.maxY();
m_npWindow.clipRect.right = m_clipRectInWindowCoordinates.maxX();
NPP_SetWindow(&m_npWindow);
}
bool NetscapePlugin::shouldLoadSrcURL()
{
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();
}
return false;
}
bool NetscapePlugin::initialize(PluginController* pluginController, const Parameters& parameters)
{
ASSERT(!m_pluginController);
ASSERT(pluginController);
m_pluginController = pluginController;
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) {
paramNames.append(parameters.names[i].utf8());
paramValues.append(parameters.values[i].utf8());
}
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 PLATFORM(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;
m_npWindow.type = NPWindowTypeDrawable;
if (!platformPostInitialize()) {
destroy();
return false;
}
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);
stopAllStreams();
#if !PLUGIN_ARCHITECTURE(MAC)
m_npWindow.window = 0;
callSetWindow();
#endif
NPP_Destroy(0);
m_isStarted = false;
m_pluginController = 0;
platformDestroy();
}
void NetscapePlugin::paint(GraphicsContext* context, const IntRect& dirtyRect)
{
ASSERT(m_isStarted);
platformPaint(context, dirtyRect);
}
PassRefPtr<ShareableBitmap> NetscapePlugin::snapshot()
{
if (!supportsSnapshotting() || m_frameRectInWindowCoordinates.isEmpty())
return 0;
ASSERT(m_isStarted);
IntSize backingStoreSize = m_frameRectInWindowCoordinates.size();
backingStoreSize.scale(contentsScaleFactor());
RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(backingStoreSize, ShareableBitmap::SupportsAlpha);
OwnPtr<GraphicsContext> context = bitmap->createGraphicsContext();
context->scale(FloatSize(contentsScaleFactor(), contentsScaleFactor()));
context->translate(-m_frameRectInWindowCoordinates.x(), -m_frameRectInWindowCoordinates.y());
platformPaint(context.get(), m_frameRectInWindowCoordinates, true);
return bitmap.release();
}
bool NetscapePlugin::isTransparent()
{
return m_isTransparent;
}
void NetscapePlugin::deprecatedGeometryDidChange(const IntRect& frameRectInWindowCoordinates, const IntRect& clipRectInWindowCoordinates)
{
ASSERT(m_isStarted);
if (m_frameRectInWindowCoordinates == frameRectInWindowCoordinates && m_clipRectInWindowCoordinates == clipRectInWindowCoordinates) {
return;
}
m_frameRectInWindowCoordinates = frameRectInWindowCoordinates;
m_clipRectInWindowCoordinates = clipRectInWindowCoordinates;
platformGeometryDidChange();
callSetWindow();
}
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) {
return;
}
m_pluginSize = pluginSize;
m_clipRect = clipRect;
m_pluginToRootViewTransform = pluginToRootViewTransform;
IntPoint frameRectLocationInWindowCoordinates = m_pluginToRootViewTransform.mapPoint(IntPoint());
m_frameRectInWindowCoordinates = IntRect(frameRectLocationInWindowCoordinates, m_pluginSize);
IntPoint clipRectLocationInWindowCoordinates = m_pluginToRootViewTransform.mapPoint(clipRect.location());
m_clipRectInWindowCoordinates = IntRect(clipRectLocationInWindowCoordinates, m_clipRect.size());
platformGeometryDidChange();
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& )
{
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& )
{
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);
ASSERT(m_manualStream);
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&)
{
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);
NPBool value = privateBrowsingEnabled;
NPP_SetValue(NPNVprivateModeBool, &value);
}
bool NetscapePlugin::handleScroll(ScrollDirection, ScrollGranularity)
{
return false;
}
bool NetscapePlugin::wantsWindowRelativeCoordinates()
{
return true;
}
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;
}
PluginController* NetscapePlugin::controller()
{
return m_pluginController;
}
}