summaryrefslogtreecommitdiffstats
path: root/Source/WebKit2/WebProcess/Plugins/Netscape
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/WebProcess/Plugins/Netscape')
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/JSNPMethod.cpp79
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/JSNPMethod.h59
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp412
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.h84
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NPJSObject.cpp383
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NPJSObject.h94
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp277
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.h94
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.cpp134
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.h62
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NetscapeBrowserFuncs.cpp871
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NetscapeBrowserFuncs.h38
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp678
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.h229
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePluginStream.cpp355
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePluginStream.h112
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/gtk/NetscapePluginGtk.cpp104
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/mac/NetscapePluginMac.mm903
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/mac/PluginProxyMac.mm49
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/qt/NetscapePluginQt.cpp124
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Netscape/win/NetscapePluginWin.cpp293
21 files changed, 5434 insertions, 0 deletions
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPMethod.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPMethod.cpp
new file mode 100644
index 0000000..c094505
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPMethod.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "JSNPMethod.h"
+
+#include "JSNPObject.h"
+#include "NotImplemented.h"
+#include <JavaScriptCore/Error.h>
+#include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/JSGlobalObject.h>
+#include <WebCore/JSHTMLElement.h>
+#include <WebCore/JSPluginElementFunctions.h>
+
+using namespace JSC;
+using namespace WebCore;
+
+namespace WebKit {
+
+const ClassInfo JSNPMethod::s_info = { "NPMethod", &InternalFunction::info, 0, 0 };
+
+JSNPMethod::JSNPMethod(ExecState* exec, JSGlobalObject* globalObject, const Identifier& name, NPIdentifier npIdentifier)
+ : InternalFunction(&exec->globalData(), globalObject, createStructure(globalObject->functionPrototype()), name)
+ , m_npIdentifier(npIdentifier)
+{
+}
+
+static EncodedJSValue JSC_HOST_CALL callMethod(ExecState* exec)
+{
+ JSNPMethod* jsNPMethod = static_cast<JSNPMethod*>(exec->callee());
+
+ JSValue thisValue = exec->hostThisValue();
+
+ // Check if we're calling a method on the plug-in script object.
+ if (thisValue.inherits(&JSHTMLElement::s_info)) {
+ JSHTMLElement* element = static_cast<JSHTMLElement*>(asObject(thisValue));
+
+ // Try to get the script object from the element
+ if (JSObject* scriptObject = pluginScriptObject(exec, element))
+ thisValue = scriptObject;
+ }
+
+ if (thisValue.inherits(&JSNPObject::s_info)) {
+ JSNPObject* jsNPObject = static_cast<JSNPObject*>(asObject(thisValue));
+
+ return JSValue::encode(jsNPObject->callMethod(exec, jsNPMethod->npIdentifier()));
+ }
+
+ return throwVMTypeError(exec);
+}
+
+CallType JSNPMethod::getCallData(CallData& callData)
+{
+ callData.native.function = callMethod;
+ return CallTypeHost;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPMethod.h b/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPMethod.h
new file mode 100644
index 0000000..9a8578c
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPMethod.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef JSNPMethod_h
+#define JSNPMethod_h
+
+#include <JavaScriptCore/InternalFunction.h>
+
+typedef void* NPIdentifier;
+
+namespace WebKit {
+
+// A JSObject that wraps an NPMethod.
+class JSNPMethod : public JSC::InternalFunction {
+public:
+ JSNPMethod(JSC::ExecState*, JSC::JSGlobalObject*, const JSC::Identifier&, NPIdentifier);
+
+ static const JSC::ClassInfo s_info;
+
+ NPIdentifier npIdentifier() const { return m_npIdentifier; }
+
+private:
+ static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount);
+ }
+
+ virtual JSC::CallType getCallData(JSC::CallData&);
+ virtual const JSC::ClassInfo* classInfo() const { return &s_info; }
+
+ NPIdentifier m_npIdentifier;
+};
+
+
+} // namespace WebKit
+
+#endif // JSNPMethod_h
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp
new file mode 100644
index 0000000..d7d626f
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp
@@ -0,0 +1,412 @@
+/*
+ * 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 "JSNPObject.h"
+
+#include "JSNPMethod.h"
+#include "NPJSObject.h"
+#include "NPRuntimeObjectMap.h"
+#include "NPRuntimeUtilities.h"
+#include <JavaScriptCore/Error.h>
+#include <JavaScriptCore/JSGlobalObject.h>
+#include <JavaScriptCore/JSLock.h>
+#include <JavaScriptCore/ObjectPrototype.h>
+#include <WebCore/IdentifierRep.h>
+#include <wtf/text/WTFString.h>
+
+using namespace JSC;
+using namespace WebCore;
+
+namespace WebKit {
+
+static NPIdentifier npIdentifierFromIdentifier(const Identifier& identifier)
+{
+ return static_cast<NPIdentifier>(IdentifierRep::get(identifier.ustring().utf8().data()));
+}
+
+const ClassInfo JSNPObject::s_info = { "NPObject", 0, 0, 0 };
+
+JSNPObject::JSNPObject(JSGlobalObject* globalObject, NPRuntimeObjectMap* objectMap, NPObject* npObject)
+ : JSObjectWithGlobalObject(globalObject, createStructure(globalObject->objectPrototype()))
+ , m_objectMap(objectMap)
+ , m_npObject(npObject)
+{
+ // We should never have an NPJSObject inside a JSNPObject.
+ ASSERT(!NPJSObject::isNPJSObject(m_npObject));
+
+ retainNPObject(m_npObject);
+}
+
+JSNPObject::~JSNPObject()
+{
+ if (!m_npObject)
+ return;
+
+ m_objectMap->jsNPObjectDestroyed(this);
+ releaseNPObject(m_npObject);
+}
+
+void JSNPObject::invalidate()
+{
+ ASSERT(m_npObject);
+
+ releaseNPObject(m_npObject);
+ m_npObject = 0;
+}
+
+JSValue JSNPObject::callMethod(ExecState* exec, NPIdentifier methodName)
+{
+ if (!m_npObject)
+ return throwInvalidAccessError(exec);
+
+ size_t argumentCount = exec->argumentCount();
+ Vector<NPVariant, 8> arguments(argumentCount);
+
+ // Convert all arguments to NPVariants.
+ for (size_t i = 0; i < argumentCount; ++i)
+ m_objectMap->convertJSValueToNPVariant(exec, exec->argument(i), arguments[i]);
+
+ // Calling NPClass::invoke will call into plug-in code, and there's no telling what the plug-in can do.
+ // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until
+ // the call has finished.
+ NPRuntimeObjectMap::PluginProtector protector(m_objectMap);
+
+ bool returnValue;
+ NPVariant result;
+ VOID_TO_NPVARIANT(result);
+
+ {
+ JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
+ returnValue = m_npObject->_class->invoke(m_npObject, methodName, arguments.data(), argumentCount, &result);
+ NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
+ }
+
+ // Release all arguments;
+ for (size_t i = 0; i < argumentCount; ++i)
+ releaseNPVariantValue(&arguments[i]);
+
+ if (!returnValue)
+ throwError(exec, createError(exec, "Error calling method on NPObject."));
+
+ JSValue propertyValue = m_objectMap->convertNPVariantToJSValue(exec, globalObject(), result);
+ releaseNPVariantValue(&result);
+ return propertyValue;
+}
+
+JSC::JSValue JSNPObject::callObject(JSC::ExecState* exec)
+{
+ if (!m_npObject)
+ return throwInvalidAccessError(exec);
+
+ size_t argumentCount = exec->argumentCount();
+ Vector<NPVariant, 8> arguments(argumentCount);
+
+ // Convert all arguments to NPVariants.
+ for (size_t i = 0; i < argumentCount; ++i)
+ m_objectMap->convertJSValueToNPVariant(exec, exec->argument(i), arguments[i]);
+
+ // Calling NPClass::invokeDefault will call into plug-in code, and there's no telling what the plug-in can do.
+ // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until
+ // the call has finished.
+ NPRuntimeObjectMap::PluginProtector protector(m_objectMap);
+
+ bool returnValue;
+ NPVariant result;
+ VOID_TO_NPVARIANT(result);
+
+ {
+ JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
+ returnValue = m_npObject->_class->invokeDefault(m_npObject, arguments.data(), argumentCount, &result);
+ NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
+ }
+
+ // Release all arguments;
+ for (size_t i = 0; i < argumentCount; ++i)
+ releaseNPVariantValue(&arguments[i]);
+
+ if (!returnValue)
+ throwError(exec, createError(exec, "Error calling method on NPObject."));
+
+ JSValue propertyValue = m_objectMap->convertNPVariantToJSValue(exec, globalObject(), result);
+ releaseNPVariantValue(&result);
+ return propertyValue;
+}
+
+JSValue JSNPObject::callConstructor(ExecState* exec)
+{
+ if (!m_npObject)
+ return throwInvalidAccessError(exec);
+
+ size_t argumentCount = exec->argumentCount();
+ Vector<NPVariant, 8> arguments(argumentCount);
+
+ // Convert all arguments to NPVariants.
+ for (size_t i = 0; i < argumentCount; ++i)
+ m_objectMap->convertJSValueToNPVariant(exec, exec->argument(i), arguments[i]);
+
+ // Calling NPClass::construct will call into plug-in code, and there's no telling what the plug-in can do.
+ // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until
+ // the call has finished.
+ NPRuntimeObjectMap::PluginProtector protector(m_objectMap);
+
+ bool returnValue;
+ NPVariant result;
+ VOID_TO_NPVARIANT(result);
+
+ {
+ JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
+ returnValue = m_npObject->_class->construct(m_npObject, arguments.data(), argumentCount, &result);
+ NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
+ }
+
+ if (!returnValue)
+ throwError(exec, createError(exec, "Error calling method on NPObject."));
+
+ JSValue value = m_objectMap->convertNPVariantToJSValue(exec, globalObject(), result);
+ releaseNPVariantValue(&result);
+ return value;
+}
+
+static EncodedJSValue JSC_HOST_CALL callNPJSObject(ExecState* exec)
+{
+ JSObject* object = exec->callee();
+ ASSERT(object->inherits(&JSNPObject::s_info));
+
+ return JSValue::encode(static_cast<JSNPObject*>(object)->callObject(exec));
+}
+
+JSC::CallType JSNPObject::getCallData(JSC::CallData& callData)
+{
+ if (!m_npObject || !m_npObject->_class->invokeDefault)
+ return CallTypeNone;
+
+ callData.native.function = callNPJSObject;
+ return CallTypeHost;
+}
+
+static EncodedJSValue JSC_HOST_CALL constructWithConstructor(ExecState* exec)
+{
+ JSObject* constructor = exec->callee();
+ ASSERT(constructor->inherits(&JSNPObject::s_info));
+
+ return JSValue::encode(static_cast<JSNPObject*>(constructor)->callConstructor(exec));
+}
+
+ConstructType JSNPObject::getConstructData(ConstructData& constructData)
+{
+ if (!m_npObject || !m_npObject->_class->construct)
+ return ConstructTypeNone;
+
+ constructData.native.function = constructWithConstructor;
+ return ConstructTypeHost;
+}
+
+bool JSNPObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (!m_npObject) {
+ throwInvalidAccessError(exec);
+ return false;
+ }
+
+ NPIdentifier npIdentifier = npIdentifierFromIdentifier(propertyName);
+
+ // First, check if the NPObject has a property with this name.
+ if (m_npObject->_class->hasProperty && m_npObject->_class->hasProperty(m_npObject, npIdentifier)) {
+ slot.setCustom(this, propertyGetter);
+ return true;
+ }
+
+ // Second, check if the NPObject has a method with this name.
+ if (m_npObject->_class->hasMethod && m_npObject->_class->hasMethod(m_npObject, npIdentifier)) {
+ slot.setCustom(this, methodGetter);
+ return true;
+ }
+
+ return false;
+}
+
+bool JSNPObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ if (!m_npObject) {
+ throwInvalidAccessError(exec);
+ return false;
+ }
+
+ NPIdentifier npIdentifier = npIdentifierFromIdentifier(propertyName);
+
+ // First, check if the NPObject has a property with this name.
+ if (m_npObject->_class->hasProperty && m_npObject->_class->hasProperty(m_npObject, npIdentifier)) {
+ PropertySlot slot;
+ slot.setCustom(this, propertyGetter);
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete);
+ return true;
+ }
+
+ // Second, check if the NPObject has a method with this name.
+ if (m_npObject->_class->hasMethod && m_npObject->_class->hasMethod(m_npObject, npIdentifier)) {
+ PropertySlot slot;
+ slot.setCustom(this, methodGetter);
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly);
+ return true;
+ }
+
+ return false;
+}
+
+void JSNPObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot&)
+{
+ if (!m_npObject) {
+ throwInvalidAccessError(exec);
+ return;
+ }
+
+ NPIdentifier npIdentifier = npIdentifierFromIdentifier(propertyName);
+
+ if (!m_npObject->_class->hasProperty || !m_npObject->_class->hasProperty(m_npObject, npIdentifier)) {
+ // FIXME: Should we throw an exception here?
+ return;
+ }
+
+ if (!m_npObject->_class->setProperty)
+ return;
+
+ NPVariant variant;
+ m_objectMap->convertJSValueToNPVariant(exec, value, variant);
+
+ // Calling NPClass::setProperty will call into plug-in code, and there's no telling what the plug-in can do.
+ // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until
+ // the call has finished.
+ NPRuntimeObjectMap::PluginProtector protector(m_objectMap);
+
+ {
+ JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
+ m_npObject->_class->setProperty(m_npObject, npIdentifier, &variant);
+
+ NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
+
+ // FIXME: Should we throw an exception if setProperty returns false?
+ }
+
+ releaseNPVariantValue(&variant);
+}
+
+void JSNPObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNameArray, EnumerationMode mode)
+{
+ if (!m_npObject) {
+ throwInvalidAccessError(exec);
+ return;
+ }
+
+ if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(m_npObject->_class) || !m_npObject->_class->enumerate)
+ return;
+
+ NPIdentifier* identifiers = 0;
+ uint32_t identifierCount = 0;
+
+ // Calling NPClass::enumerate will call into plug-in code, and there's no telling what the plug-in can do.
+ // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until
+ // the call has finished.
+ NPRuntimeObjectMap::PluginProtector protector(m_objectMap);
+
+ {
+ JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
+
+ // FIXME: Should we throw an exception if enumerate returns false?
+ if (!m_npObject->_class->enumerate(m_npObject, &identifiers, &identifierCount))
+ return;
+
+ NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
+ }
+
+ for (uint32_t i = 0; i < identifierCount; ++i) {
+ IdentifierRep* identifierRep = static_cast<IdentifierRep*>(identifiers[i]);
+
+ Identifier identifier;
+ if (identifierRep->isString()) {
+ const char* string = identifierRep->string();
+ int length = strlen(string);
+
+ identifier = Identifier(exec, String::fromUTF8WithLatin1Fallback(string, length).impl());
+ } else
+ identifier = Identifier::from(exec, identifierRep->number());
+
+ propertyNameArray.add(identifier);
+ }
+
+ npnMemFree(identifiers);
+}
+
+JSValue JSNPObject::propertyGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
+{
+ JSNPObject* thisObj = static_cast<JSNPObject*>(asObject(slotBase));
+
+ if (!thisObj->m_npObject)
+ return throwInvalidAccessError(exec);
+
+ if (!thisObj->m_npObject->_class->getProperty)
+ return jsUndefined();
+
+ NPVariant result;
+ VOID_TO_NPVARIANT(result);
+
+ // Calling NPClass::getProperty will call into plug-in code, and there's no telling what the plug-in can do.
+ // (including destroying the plug-in). Because of this, we make sure to keep the plug-in alive until
+ // the call has finished.
+ NPRuntimeObjectMap::PluginProtector protector(thisObj->m_objectMap);
+
+ bool returnValue;
+ {
+ JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
+ NPIdentifier npIdentifier = npIdentifierFromIdentifier(propertyName);
+ returnValue = thisObj->m_npObject->_class->getProperty(thisObj->m_npObject, npIdentifier, &result);
+
+ NPRuntimeObjectMap::moveGlobalExceptionToExecState(exec);
+ }
+
+ if (!returnValue)
+ return jsUndefined();
+
+ JSValue propertyValue = thisObj->m_objectMap->convertNPVariantToJSValue(exec, thisObj->globalObject(), result);
+ releaseNPVariantValue(&result);
+ return propertyValue;
+}
+
+JSValue JSNPObject::methodGetter(ExecState* exec, JSValue slotBase, const Identifier& methodName)
+{
+ JSNPObject* thisObj = static_cast<JSNPObject*>(asObject(slotBase));
+
+ if (!thisObj->m_npObject)
+ return throwInvalidAccessError(exec);
+
+ NPIdentifier npIdentifier = npIdentifierFromIdentifier(methodName);
+ return new (exec) JSNPMethod(exec, thisObj->globalObject(), methodName, npIdentifier);
+}
+
+JSObject* JSNPObject::throwInvalidAccessError(ExecState* exec)
+{
+ return throwError(exec, createReferenceError(exec, "Trying to access object from destroyed plug-in."));
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.h b/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.h
new file mode 100644
index 0000000..af1369a
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef JSNPObject_h
+#define JSNPObject_h
+
+#include <JavaScriptCore/JSObjectWithGlobalObject.h>
+
+typedef void* NPIdentifier;
+struct NPObject;
+
+namespace WebKit {
+
+class NPRuntimeObjectMap;
+
+// JSNPObject is a JSObject that wraps an NPObject.
+
+class JSNPObject : public JSC::JSObjectWithGlobalObject {
+public:
+ JSNPObject(JSC::JSGlobalObject*, NPRuntimeObjectMap* objectMap, NPObject* npObject);
+ ~JSNPObject();
+
+ void invalidate();
+
+ JSC::JSValue callMethod(JSC::ExecState*, NPIdentifier methodName);
+ JSC::JSValue callObject(JSC::ExecState*);
+ JSC::JSValue callConstructor(JSC::ExecState*);
+
+ static const JSC::ClassInfo s_info;
+
+ NPObject* npObject() const { return m_npObject; }
+
+private:
+ static const unsigned StructureFlags = JSC::OverridesGetOwnPropertySlot | JSObject::StructureFlags;
+
+ static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount);
+ }
+
+ virtual JSC::CallType getCallData(JSC::CallData&);
+ virtual JSC::ConstructType getConstructData(JSC::ConstructData&);
+
+ virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor&);
+ virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&);
+
+ virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);
+
+ static JSC::JSValue propertyGetter(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
+ static JSC::JSValue methodGetter(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
+ static JSC::JSObject* throwInvalidAccessError(JSC::ExecState*);
+
+ virtual const JSC::ClassInfo* classInfo() const { return &s_info; }
+
+ NPRuntimeObjectMap* m_objectMap;
+ NPObject* m_npObject;
+};
+
+} // namespace WebKit
+
+#endif // JSNPObject_h
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NPJSObject.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/NPJSObject.cpp
new file mode 100644
index 0000000..45c1e6e
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NPJSObject.cpp
@@ -0,0 +1,383 @@
+/*
+ * 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 "NPJSObject.h"
+
+#include "JSNPObject.h"
+#include "NPRuntimeObjectMap.h"
+#include "NPRuntimeUtilities.h"
+#include "NotImplemented.h"
+#include "PluginView.h"
+#include <JavaScriptCore/JSLock.h>
+#include <JavaScriptCore/JSObject.h>
+#include <WebCore/Frame.h>
+#include <WebCore/IdentifierRep.h>
+#include <wtf/text/WTFString.h>
+
+using namespace JSC;
+using namespace WebCore;
+
+namespace WebKit {
+
+NPJSObject* NPJSObject::create(NPRuntimeObjectMap* objectMap, JSObject* jsObject)
+{
+ // We should never have a JSNPObject inside an NPJSObject.
+ ASSERT(!jsObject->inherits(&JSNPObject::s_info));
+
+ NPJSObject* npJSObject = toNPJSObject(createNPObject(0, npClass()));
+ npJSObject->initialize(objectMap, jsObject);
+
+ return npJSObject;
+}
+
+NPJSObject::NPJSObject()
+ : m_objectMap(0)
+{
+}
+
+NPJSObject::~NPJSObject()
+{
+ m_objectMap->npJSObjectDestroyed(this);
+}
+
+bool NPJSObject::isNPJSObject(NPObject* npObject)
+{
+ return npObject->_class == npClass();
+}
+
+void NPJSObject::initialize(NPRuntimeObjectMap* objectMap, JSObject* jsObject)
+{
+ ASSERT(!m_objectMap);
+ ASSERT(!m_jsObject);
+
+ m_objectMap = objectMap;
+ m_jsObject = jsObject;
+}
+
+static Identifier identifierFromIdentifierRep(ExecState* exec, IdentifierRep* identifierRep)
+{
+ ASSERT(identifierRep->isString());
+
+ const char* string = identifierRep->string();
+ int length = strlen(string);
+
+ return Identifier(exec, String::fromUTF8WithLatin1Fallback(string, length).impl());
+}
+
+bool NPJSObject::hasMethod(NPIdentifier methodName)
+{
+ IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName);
+
+ if (!identifierRep->isString())
+ return false;
+
+ ExecState* exec = m_objectMap->globalExec();
+ if (!exec)
+ return false;
+
+ JSLock lock(SilenceAssertionsOnly);
+
+ JSValue value = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
+ exec->clearException();
+
+ CallData callData;
+ return getCallData(value, callData) != CallTypeNone;
+}
+
+bool NPJSObject::invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+{
+ IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName);
+
+ if (!identifierRep->isString())
+ return false;
+
+ ExecState* exec = m_objectMap->globalExec();
+ if (!exec)
+ return false;
+
+ JSLock lock(SilenceAssertionsOnly);
+
+ JSValue function = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
+ return invoke(exec, m_objectMap->globalObject(), function, arguments, argumentCount, result);
+}
+
+bool NPJSObject::invokeDefault(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+{
+ ExecState* exec = m_objectMap->globalExec();
+ if (!exec)
+ return false;
+
+ JSLock lock(SilenceAssertionsOnly);
+
+ JSValue function = m_jsObject;
+ return invoke(exec, m_objectMap->globalObject(), function, arguments, argumentCount, result);
+}
+
+bool NPJSObject::hasProperty(NPIdentifier identifier)
+{
+ IdentifierRep* identifierRep = static_cast<IdentifierRep*>(identifier);
+
+ ExecState* exec = m_objectMap->globalExec();
+ if (!exec)
+ return false;
+
+ JSLock lock(SilenceAssertionsOnly);
+
+ bool result;
+ if (identifierRep->isString())
+ result = m_jsObject->hasProperty(exec, identifierFromIdentifierRep(exec, identifierRep));
+ else
+ result = m_jsObject->hasProperty(exec, identifierRep->number());
+
+ exec->clearException();
+ return result;
+}
+
+bool NPJSObject::getProperty(NPIdentifier propertyName, NPVariant* result)
+{
+ IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
+
+ ExecState* exec = m_objectMap->globalExec();
+ if (!exec)
+ return false;
+
+ JSLock lock(SilenceAssertionsOnly);
+ JSValue jsResult;
+ if (identifierRep->isString())
+ jsResult = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
+ else
+ jsResult = m_jsObject->get(exec, identifierRep->number());
+
+ m_objectMap->convertJSValueToNPVariant(exec, jsResult, *result);
+ exec->clearException();
+ return true;
+}
+
+bool NPJSObject::setProperty(NPIdentifier propertyName, const NPVariant* value)
+{
+ IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
+
+ ExecState* exec = m_objectMap->globalExec();
+ if (!exec)
+ return false;
+
+ JSLock lock(SilenceAssertionsOnly);
+
+ JSValue jsValue = m_objectMap->convertNPVariantToJSValue(exec, m_objectMap->globalObject(), *value);
+ if (identifierRep->isString()) {
+ PutPropertySlot slot;
+ m_jsObject->put(exec, identifierFromIdentifierRep(exec, identifierRep), jsValue, slot);
+ } else
+ m_jsObject->put(exec, identifierRep->number(), jsValue);
+ exec->clearException();
+
+ return true;
+}
+
+bool NPJSObject::removeProperty(NPIdentifier propertyName)
+{
+ IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
+
+ ExecState* exec = m_objectMap->globalExec();
+ if (!exec)
+ return false;
+
+ JSLock lock(SilenceAssertionsOnly);
+ if (identifierRep->isString()) {
+ Identifier identifier = identifierFromIdentifierRep(exec, identifierRep);
+
+ if (!m_jsObject->hasProperty(exec, identifier)) {
+ exec->clearException();
+ return false;
+ }
+
+ m_jsObject->deleteProperty(exec, identifier);
+ } else {
+ if (!m_jsObject->hasProperty(exec, identifierRep->number())) {
+ exec->clearException();
+ return false;
+ }
+
+ m_jsObject->deleteProperty(exec, identifierRep->number());
+ }
+
+ exec->clearException();
+ return true;
+}
+
+bool NPJSObject::enumerate(NPIdentifier** identifiers, uint32_t* identifierCount)
+{
+ ExecState* exec = m_objectMap->globalExec();
+ if (!exec)
+ return false;
+
+ JSLock lock(SilenceAssertionsOnly);
+
+ PropertyNameArray propertyNames(exec);
+ m_jsObject->getPropertyNames(exec, propertyNames);
+
+ NPIdentifier* nameIdentifiers = npnMemNewArray<NPIdentifier>(propertyNames.size());
+
+ for (size_t i = 0; i < propertyNames.size(); ++i)
+ nameIdentifiers[i] = static_cast<NPIdentifier>(IdentifierRep::get(propertyNames[i].ustring().utf8().data()));
+
+ *identifiers = nameIdentifiers;
+ *identifierCount = propertyNames.size();
+
+ return true;
+}
+
+bool NPJSObject::construct(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+{
+ ExecState* exec = m_objectMap->globalExec();
+ if (!exec)
+ return false;
+
+ JSLock lock(SilenceAssertionsOnly);
+
+ ConstructData constructData;
+ ConstructType constructType = getConstructData(m_jsObject, constructData);
+ if (constructType == ConstructTypeNone)
+ return false;
+
+ // Convert the passed in arguments.
+ MarkedArgumentBuffer argumentList;
+ for (uint32_t i = 0; i < argumentCount; ++i)
+ argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, m_objectMap->globalObject(), arguments[i]));
+
+ exec->globalData().timeoutChecker.start();
+ JSValue value = JSC::construct(exec, m_jsObject, constructType, constructData, argumentList);
+ exec->globalData().timeoutChecker.stop();
+
+ // Convert and return the new object.
+ m_objectMap->convertJSValueToNPVariant(exec, value, *result);
+ exec->clearException();
+
+ return true;
+}
+
+bool NPJSObject::invoke(ExecState* exec, JSGlobalObject* globalObject, JSValue function, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+{
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return false;
+
+ // Convert the passed in arguments.
+ MarkedArgumentBuffer argumentList;
+ for (uint32_t i = 0; i < argumentCount; ++i)
+ argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, globalObject, arguments[i]));
+
+ exec->globalData().timeoutChecker.start();
+ JSValue value = JSC::call(exec, function, callType, callData, m_jsObject, argumentList);
+ exec->globalData().timeoutChecker.stop();
+
+ // Convert and return the result of the function call.
+ m_objectMap->convertJSValueToNPVariant(exec, value, *result);
+ exec->clearException();
+
+ return true;
+}
+
+NPClass* NPJSObject::npClass()
+{
+ static NPClass npClass = {
+ NP_CLASS_STRUCT_VERSION,
+ NP_Allocate,
+ NP_Deallocate,
+ 0,
+ NP_HasMethod,
+ NP_Invoke,
+ NP_InvokeDefault,
+ NP_HasProperty,
+ NP_GetProperty,
+ NP_SetProperty,
+ NP_RemoveProperty,
+ NP_Enumerate,
+ NP_Construct
+ };
+
+ return &npClass;
+}
+
+NPObject* NPJSObject::NP_Allocate(NPP npp, NPClass*)
+{
+ ASSERT_UNUSED(npp, !npp);
+
+ return new NPJSObject;
+}
+
+void NPJSObject::NP_Deallocate(NPObject* npObject)
+{
+ NPJSObject* npJSObject = toNPJSObject(npObject);
+ delete npJSObject;
+}
+
+bool NPJSObject::NP_HasMethod(NPObject* npObject, NPIdentifier methodName)
+{
+ return toNPJSObject(npObject)->hasMethod(methodName);
+}
+
+bool NPJSObject::NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+{
+ return toNPJSObject(npObject)->invoke(methodName, arguments, argumentCount, result);
+}
+
+bool NPJSObject::NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+{
+ return toNPJSObject(npObject)->invokeDefault(arguments, argumentCount, result);
+}
+
+bool NPJSObject::NP_HasProperty(NPObject* npObject, NPIdentifier propertyName)
+{
+ return toNPJSObject(npObject)->hasProperty(propertyName);
+}
+
+bool NPJSObject::NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
+{
+ return toNPJSObject(npObject)->getProperty(propertyName, result);
+}
+
+bool NPJSObject::NP_SetProperty(NPObject* npObject, NPIdentifier propertyName, const NPVariant* value)
+{
+ return toNPJSObject(npObject)->setProperty(propertyName, value);
+}
+
+bool NPJSObject::NP_RemoveProperty(NPObject* npObject, NPIdentifier propertyName)
+{
+ return toNPJSObject(npObject)->removeProperty(propertyName);
+}
+
+bool NPJSObject::NP_Enumerate(NPObject* npObject, NPIdentifier** identifiers, uint32_t* identifierCount)
+{
+ return toNPJSObject(npObject)->enumerate(identifiers, identifierCount);
+}
+
+bool NPJSObject::NP_Construct(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+{
+ return toNPJSObject(npObject)->construct(arguments, argumentCount, result);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NPJSObject.h b/Source/WebKit2/WebProcess/Plugins/Netscape/NPJSObject.h
new file mode 100644
index 0000000..6737bd4
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NPJSObject.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#ifndef NPJSObject_h
+#define NPJSObject_h
+
+#include <JavaScriptCore/Protect.h>
+#include <WebCore/npruntime_internal.h>
+#include <wtf/Noncopyable.h>
+
+namespace JSC {
+ class JSGlobalObject;
+ class JSObject;
+}
+
+namespace WebKit {
+
+class NPRuntimeObjectMap;
+
+// NPJSObject is an NPObject that wraps a JSObject.
+class NPJSObject : public NPObject, Noncopyable {
+public:
+ static NPJSObject* create(NPRuntimeObjectMap* objectMap, JSC::JSObject* jsObject);
+
+ JSC::JSObject* jsObject() const { return m_jsObject.get(); }
+
+ static bool isNPJSObject(NPObject*);
+
+ static NPJSObject* toNPJSObject(NPObject* npObject)
+ {
+ ASSERT(isNPJSObject(npObject));
+ return static_cast<NPJSObject*>(npObject);
+ }
+
+private:
+ NPJSObject();
+ ~NPJSObject();
+
+ void initialize(NPRuntimeObjectMap*, JSC::JSObject* jsObject);
+
+ bool hasMethod(NPIdentifier methodName);
+ bool invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result);
+ bool invokeDefault(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result);
+ bool hasProperty(NPIdentifier propertyName);
+ bool getProperty(NPIdentifier propertyName, NPVariant* result);
+ bool setProperty(NPIdentifier propertyName, const NPVariant* value);
+ bool removeProperty(NPIdentifier propertyName);
+ bool enumerate(NPIdentifier** identifiers, uint32_t* identifierCount);
+ bool construct(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result);
+
+ bool invoke(JSC::ExecState*, JSC::JSGlobalObject*, JSC::JSValue function, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result);
+
+ static NPClass* npClass();
+ static NPObject* NP_Allocate(NPP, NPClass*);
+ static void NP_Deallocate(NPObject*);
+ static bool NP_HasMethod(NPObject*, NPIdentifier methodName);
+ static bool NP_Invoke(NPObject*, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result);
+ static bool NP_InvokeDefault(NPObject*, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result);
+ static bool NP_HasProperty(NPObject*, NPIdentifier propertyName);
+ static bool NP_GetProperty(NPObject*, NPIdentifier propertyName, NPVariant* result);
+ static bool NP_SetProperty(NPObject*, NPIdentifier propertyName, const NPVariant* value);
+ static bool NP_RemoveProperty(NPObject*, NPIdentifier propertyName);
+ static bool NP_Enumerate(NPObject*, NPIdentifier** identifiers, uint32_t* identifierCount);
+ static bool NP_Construct(NPObject*, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result);
+
+ NPRuntimeObjectMap* m_objectMap;
+ JSC::ProtectedPtr<JSC::JSObject> m_jsObject;
+};
+
+} // namespace WebKit
+
+#endif // NPJSObject_h
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp
new file mode 100644
index 0000000..4fa37c1
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp
@@ -0,0 +1,277 @@
+/*
+ * 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 "NPRuntimeObjectMap.h"
+
+#include "JSNPObject.h"
+#include "NPJSObject.h"
+#include "NPRuntimeUtilities.h"
+#include "NotImplemented.h"
+#include "PluginView.h"
+#include <JavaScriptCore/Error.h>
+#include <JavaScriptCore/JSLock.h>
+#include <JavaScriptCore/SourceCode.h>
+#include <WebCore/Frame.h>
+
+using namespace JSC;
+using namespace WebCore;
+
+namespace WebKit {
+
+
+NPRuntimeObjectMap::NPRuntimeObjectMap(PluginView* pluginView)
+ : m_pluginView(pluginView)
+{
+}
+
+NPRuntimeObjectMap::PluginProtector::PluginProtector(NPRuntimeObjectMap* npRuntimeObjectMap)
+{
+ // If we're already in the plug-in view destructor, we shouldn't try to keep it alive.
+ if (!npRuntimeObjectMap->m_pluginView->isBeingDestroyed())
+ m_pluginView = npRuntimeObjectMap->m_pluginView;
+}
+
+NPRuntimeObjectMap::PluginProtector::~PluginProtector()
+{
+}
+
+NPObject* NPRuntimeObjectMap::getOrCreateNPObject(JSObject* jsObject)
+{
+ // If this is a JSNPObject, we can just get its underlying NPObject.
+ if (jsObject->classInfo() == &JSNPObject::s_info) {
+ JSNPObject* jsNPObject = static_cast<JSNPObject*>(jsObject);
+ NPObject* npObject = jsNPObject->npObject();
+
+ retainNPObject(npObject);
+ return npObject;
+ }
+
+ // First, check if we already know about this object.
+ if (NPJSObject* npJSObject = m_npJSObjects.get(jsObject)) {
+ retainNPObject(npJSObject);
+ return npJSObject;
+ }
+
+ NPJSObject* npJSObject = NPJSObject::create(this, jsObject);
+ m_npJSObjects.set(jsObject, npJSObject);
+
+ return npJSObject;
+}
+
+void NPRuntimeObjectMap::npJSObjectDestroyed(NPJSObject* npJSObject)
+{
+ // Remove the object from the map.
+ ASSERT(m_npJSObjects.contains(npJSObject->jsObject()));
+ m_npJSObjects.remove(npJSObject->jsObject());
+}
+
+JSObject* NPRuntimeObjectMap::getOrCreateJSObject(JSGlobalObject* globalObject, NPObject* npObject)
+{
+ // If this is an NPJSObject, we can just get the JSObject that it's wrapping.
+ if (NPJSObject::isNPJSObject(npObject))
+ return NPJSObject::toNPJSObject(npObject)->jsObject();
+
+ if (JSNPObject* jsNPObject = m_jsNPObjects.get(npObject))
+ return jsNPObject;
+
+ JSNPObject* jsNPObject = new (&globalObject->globalData()) JSNPObject(globalObject, this, npObject);
+ m_jsNPObjects.set(npObject, jsNPObject);
+
+ return jsNPObject;
+}
+
+void NPRuntimeObjectMap::jsNPObjectDestroyed(JSNPObject* jsNPObject)
+{
+ // Remove the object from the map.
+ ASSERT(m_jsNPObjects.contains(jsNPObject->npObject()));
+ m_jsNPObjects.remove(jsNPObject->npObject());
+}
+
+JSValue NPRuntimeObjectMap::convertNPVariantToJSValue(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject, const NPVariant& variant)
+{
+ switch (variant.type) {
+ case NPVariantType_Void:
+ return jsUndefined();
+
+ case NPVariantType_Null:
+ return jsNull();
+
+ case NPVariantType_Bool:
+ return jsBoolean(variant.value.boolValue);
+
+ case NPVariantType_Int32:
+ return jsNumber(variant.value.intValue);
+
+ case NPVariantType_Double:
+ return jsNumber(variant.value.doubleValue);
+
+ case NPVariantType_String:
+ return jsString(exec, String::fromUTF8WithLatin1Fallback(variant.value.stringValue.UTF8Characters,
+ variant.value.stringValue.UTF8Length));
+ case NPVariantType_Object:
+ return getOrCreateJSObject(globalObject, variant.value.objectValue);
+ }
+
+ ASSERT_NOT_REACHED();
+ return jsUndefined();
+}
+
+void NPRuntimeObjectMap::convertJSValueToNPVariant(ExecState* exec, JSValue value, NPVariant& variant)
+{
+ JSLock lock(SilenceAssertionsOnly);
+
+ VOID_TO_NPVARIANT(variant);
+
+ if (value.isNull()) {
+ NULL_TO_NPVARIANT(variant);
+ return;
+ }
+
+ if (value.isUndefined()) {
+ VOID_TO_NPVARIANT(variant);
+ return;
+ }
+
+ if (value.isBoolean()) {
+ BOOLEAN_TO_NPVARIANT(value.toBoolean(exec), variant);
+ return;
+ }
+
+ if (value.isNumber()) {
+ DOUBLE_TO_NPVARIANT(value.toNumber(exec), variant);
+ return;
+ }
+
+ if (value.isString()) {
+ NPString npString = createNPString(value.toString(exec).utf8());
+ STRINGN_TO_NPVARIANT(npString.UTF8Characters, npString.UTF8Length, variant);
+ return;
+ }
+
+ if (value.isObject()) {
+ NPObject* npObject = getOrCreateNPObject(asObject(value));
+ OBJECT_TO_NPVARIANT(npObject, variant);
+ return;
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
+bool NPRuntimeObjectMap::evaluate(NPObject* npObject, const String&scriptString, NPVariant* result)
+{
+ ProtectedPtr<JSGlobalObject> globalObject = this->globalObject();
+ if (!globalObject)
+ return false;
+
+ ExecState* exec = globalObject->globalExec();
+
+ JSLock lock(SilenceAssertionsOnly);
+ JSValue thisValue = getOrCreateJSObject(globalObject, npObject);
+
+ globalObject->globalData().timeoutChecker.start();
+ Completion completion = JSC::evaluate(exec, globalObject->globalScopeChain(), makeSource(UString(scriptString.impl())), thisValue);
+ globalObject->globalData().timeoutChecker.stop();
+
+ ComplType completionType = completion.complType();
+
+ JSValue resultValue;
+ if (completionType == Normal) {
+ resultValue = completion.value();
+ if (!resultValue)
+ resultValue = jsUndefined();
+ } else
+ resultValue = jsUndefined();
+
+ exec->clearException();
+
+ convertJSValueToNPVariant(exec, resultValue, *result);
+ return true;
+}
+
+void NPRuntimeObjectMap::invalidate()
+{
+ Vector<NPJSObject*> npJSObjects;
+ copyValuesToVector(m_npJSObjects, npJSObjects);
+
+ // Deallocate all the object wrappers so we won't leak any JavaScript objects.
+ for (size_t i = 0; i < npJSObjects.size(); ++i)
+ deallocateNPObject(npJSObjects[i]);
+
+ // We shouldn't have any NPJSObjects left now.
+ ASSERT(m_npJSObjects.isEmpty());
+
+ Vector<JSNPObject*> jsNPObjects;
+ copyValuesToVector(m_jsNPObjects, jsNPObjects);
+
+ // Invalidate all the JSObjects that wrap NPObjects.
+ for (size_t i = 0; i < jsNPObjects.size(); ++i)
+ jsNPObjects[i]->invalidate();
+
+ m_jsNPObjects.clear();
+}
+
+JSGlobalObject* NPRuntimeObjectMap::globalObject() const
+{
+ Frame* frame = m_pluginView->frame();
+ if (!frame)
+ return 0;
+
+ return frame->script()->globalObject(pluginWorld());
+}
+
+ExecState* NPRuntimeObjectMap::globalExec() const
+{
+ JSGlobalObject* globalObject = this->globalObject();
+ if (!globalObject)
+ return 0;
+
+ return globalObject->globalExec();
+}
+
+static String& globalExceptionString()
+{
+ DEFINE_STATIC_LOCAL(String, exceptionString, ());
+ return exceptionString;
+}
+
+void NPRuntimeObjectMap::setGlobalException(const String& exceptionString)
+{
+ globalExceptionString() = exceptionString;
+}
+
+void NPRuntimeObjectMap::moveGlobalExceptionToExecState(ExecState* exec)
+{
+ if (globalExceptionString().isNull())
+ return;
+
+ {
+ JSLock lock(SilenceAssertionsOnly);
+ throwError(exec, createError(exec, stringToUString(globalExceptionString())));
+ }
+
+ globalExceptionString() = String();
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.h b/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.h
new file mode 100644
index 0000000..a11c354
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#ifndef NPJSObjectWrapperMap_h
+#define NPJSObjectWrapperMap_h
+
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+
+struct NPObject;
+typedef struct _NPVariant NPVariant;
+
+namespace JSC {
+ class ExecState;
+ class JSGlobalObject;
+ class JSObject;
+ class JSValue;
+}
+
+namespace WebKit {
+
+class JSNPObject;
+class NPJSObject;
+class PluginView;
+
+// A per plug-in map of NPObjects that wrap JavaScript objects.
+class NPRuntimeObjectMap {
+public:
+ explicit NPRuntimeObjectMap(PluginView*);
+
+ class PluginProtector {
+ public:
+ explicit PluginProtector(NPRuntimeObjectMap* npRuntimeObjectMap);
+ ~PluginProtector();
+
+ private:
+ RefPtr<PluginView> m_pluginView;
+ };
+
+ // Returns an NPObject that wraps the given JSObject object. If there is already an NPObject that wraps this JSObject, it will
+ // retain it and return it.
+ NPObject* getOrCreateNPObject(JSC::JSObject*);
+ void npJSObjectDestroyed(NPJSObject*);
+
+ // Returns a JSObject object that wraps the given NPObject.
+ JSC::JSObject* getOrCreateJSObject(JSC::JSGlobalObject*, NPObject*);
+ void jsNPObjectDestroyed(JSNPObject*);
+
+ void convertJSValueToNPVariant(JSC::ExecState*, JSC::JSValue, NPVariant&);
+ JSC::JSValue convertNPVariantToJSValue(JSC::ExecState*, JSC::JSGlobalObject*, const NPVariant&);
+
+ bool evaluate(NPObject*, const String& scriptString, NPVariant* result);
+
+ // Called when the plug-in is destroyed. Will invalidate all the NPObjects.
+ void invalidate();
+
+ JSC::JSGlobalObject* globalObject() const;
+ JSC::ExecState* globalExec() const;
+
+ static void setGlobalException(const String& exceptionString);
+ static void moveGlobalExceptionToExecState(JSC::ExecState*);
+
+private:
+ PluginView* m_pluginView;
+
+ HashMap<JSC::JSObject*, NPJSObject*> m_npJSObjects;
+ HashMap<NPObject*, JSNPObject*> m_jsNPObjects;
+};
+
+} // namespace WebKit
+
+#endif // NPJSObjectWrapperMap_h
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.cpp
new file mode 100644
index 0000000..20ff478
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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 "NPRuntimeUtilities.h"
+
+#include <wtf/text/CString.h>
+
+namespace WebKit {
+
+void* npnMemAlloc(uint32_t size)
+{
+ // We could use fastMalloc here, but there might be plug-ins that mix NPN_MemAlloc/NPN_MemFree with malloc and free,
+ // so having them be equivalent seems like a good idea.
+ return malloc(size);
+}
+
+void npnMemFree(void* ptr)
+{
+ // We could use fastFree here, but there might be plug-ins that mix NPN_MemAlloc/NPN_MemFree with malloc and free,
+ // so having them be equivalent seems like a good idea.
+ free(ptr);
+}
+
+NPString createNPString(const CString& string)
+{
+ char* utf8Characters = npnMemNewArray<char>(string.length());
+ memcpy(utf8Characters, string.data(), string.length());
+
+ NPString npString;
+ npString.UTF8Characters = utf8Characters;
+ npString.UTF8Length = string.length();
+
+ return npString;
+}
+
+NPObject* createNPObject(NPP npp, NPClass* npClass)
+{
+ ASSERT(npClass);
+
+ NPObject* npObject;
+ if (npClass->allocate)
+ npObject = npClass->allocate(npp, npClass);
+ else
+ npObject = npnMemNew<NPObject>();
+
+ npObject->_class = npClass;
+ npObject->referenceCount = 1;
+
+ return npObject;
+}
+
+void deallocateNPObject(NPObject* npObject)
+{
+ ASSERT(npObject);
+ if (!npObject)
+ return;
+
+ if (npObject->_class->deallocate)
+ npObject->_class->deallocate(npObject);
+ else
+ npnMemFree(npObject);
+}
+
+void retainNPObject(NPObject* npObject)
+{
+ ASSERT(npObject);
+ if (!npObject)
+ return;
+
+ npObject->referenceCount++;
+}
+
+void releaseNPObject(NPObject* npObject)
+{
+ ASSERT(npObject);
+ if (!npObject)
+ return;
+
+ ASSERT(npObject->referenceCount >= 1);
+ npObject->referenceCount--;
+ if (!npObject->referenceCount)
+ deallocateNPObject(npObject);
+}
+
+void releaseNPVariantValue(NPVariant* variant)
+{
+ ASSERT(variant);
+
+ switch (variant->type) {
+ case NPVariantType_Void:
+ case NPVariantType_Null:
+ case NPVariantType_Bool:
+ case NPVariantType_Int32:
+ case NPVariantType_Double:
+ // Nothing to do.
+ break;
+
+ case NPVariantType_String:
+ npnMemFree(const_cast<NPUTF8*>(variant->value.stringValue.UTF8Characters));
+ variant->value.stringValue.UTF8Characters = 0;
+ variant->value.stringValue.UTF8Length = 0;
+ break;
+ case NPVariantType_Object:
+ releaseNPObject(variant->value.objectValue);
+ variant->value.objectValue = 0;
+ break;
+ }
+
+ variant->type = NPVariantType_Void;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.h b/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.h
new file mode 100644
index 0000000..7309fd4
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeUtilities.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef NPRuntimeUtilities_h
+#define NPRuntimeUtilities_h
+
+#include <WebCore/npruntime_internal.h>
+#include <wtf/Forward.h>
+
+struct NPClass;
+struct NPObject;
+
+namespace WebKit {
+
+void* npnMemAlloc(uint32_t);
+void npnMemFree(void*);
+
+template<typename T> T* npnMemNew()
+{
+ return static_cast<T*>(npnMemAlloc(sizeof(T)));
+}
+
+template<typename T> T* npnMemNewArray(size_t count)
+{
+ return static_cast<T*>(npnMemAlloc(sizeof(T) * count));
+}
+
+NPString createNPString(const CString&);
+
+NPObject* createNPObject(NPP, NPClass*);
+void deallocateNPObject(NPObject*);
+
+void retainNPObject(NPObject*);
+void releaseNPObject(NPObject*);
+
+void releaseNPVariantValue(NPVariant*);
+
+}
+
+#endif // NPRuntimeUtilities_h
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapeBrowserFuncs.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapeBrowserFuncs.cpp
new file mode 100644
index 0000000..566d48d
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapeBrowserFuncs.cpp
@@ -0,0 +1,871 @@
+/*
+ * 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 "NetscapeBrowserFuncs.h"
+
+#include "NPRuntimeUtilities.h"
+#include "NetscapePlugin.h"
+#include "NotImplemented.h"
+#include <WebCore/HTTPHeaderMap.h>
+#include <WebCore/IdentifierRep.h>
+#include <WebCore/SharedBuffer.h>
+#include <utility>
+
+using namespace WebCore;
+using namespace std;
+
+namespace WebKit {
+
+static bool startsWithBlankLine(const char* bytes, unsigned length)
+{
+ return length > 0 && bytes[0] == '\n';
+}
+
+static int locationAfterFirstBlankLine(const char* bytes, unsigned length)
+{
+ for (unsigned i = 0; i < length - 4; i++) {
+ // Support for Acrobat. It sends "\n\n".
+ if (bytes[i] == '\n' && bytes[i + 1] == '\n')
+ return i + 2;
+
+ // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
+ if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
+ i += 2;
+ if (i == 2)
+ return i;
+
+ if (bytes[i] == '\n') {
+ // Support for Director. It sends "\r\n\n" (3880387).
+ return i + 1;
+ }
+
+ if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
+ // Support for Flash. It sends "\r\n\r\n" (3758113).
+ return i + 2;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static const char* findEndOfLine(const char* bytes, unsigned length)
+{
+ // According to the HTTP specification EOL is defined as
+ // a CRLF pair. Unfortunately, some servers will use LF
+ // instead. Worse yet, some servers will use a combination
+ // of both (e.g. <header>CRLFLF<body>), so findEOL needs
+ // to be more forgiving. It will now accept CRLF, LF or
+ // CR.
+ //
+ // It returns 0 if EOLF is not found or it will return
+ // a pointer to the first terminating character.
+ for (unsigned i = 0; i < length; i++) {
+ if (bytes[i] == '\n')
+ return bytes + i;
+ if (bytes[i] == '\r') {
+ // Check to see if spanning buffer bounds
+ // (CRLF is across reads). If so, wait for
+ // next read.
+ if (i + 1 == length)
+ break;
+
+ return bytes + i;
+ }
+ }
+
+ return 0;
+}
+
+static String capitalizeRFC822HeaderFieldName(const String& name)
+{
+ bool capitalizeCharacter = true;
+ String result;
+
+ for (unsigned i = 0; i < name.length(); i++) {
+ UChar c;
+
+ if (capitalizeCharacter && name[i] >= 'a' && name[i] <= 'z')
+ c = toASCIIUpper(name[i]);
+ else if (!capitalizeCharacter && name[i] >= 'A' && name[i] <= 'Z')
+ c = toASCIILower(name[i]);
+ else
+ c = name[i];
+
+ if (name[i] == '-')
+ capitalizeCharacter = true;
+ else
+ capitalizeCharacter = false;
+
+ result.append(c);
+ }
+
+ return result;
+}
+
+static HTTPHeaderMap parseRFC822HeaderFields(const char* bytes, unsigned length)
+{
+ String lastHeaderKey;
+ HTTPHeaderMap headerFields;
+
+ // Loop over lines until we're past the header, or we can't find any more end-of-lines
+ while (const char* endOfLine = findEndOfLine(bytes, length)) {
+ const char* line = bytes;
+ int lineLength = endOfLine - bytes;
+
+ // Move bytes to the character after the terminator as returned by findEndOfLine.
+ bytes = endOfLine + 1;
+ if ((*endOfLine == '\r') && (*bytes == '\n'))
+ bytes++; // Safe since findEndOfLine won't return a spanning CRLF.
+
+ length -= (bytes - line);
+ if (!lineLength) {
+ // Blank line; we're at the end of the header
+ break;
+ }
+
+ if (*line == ' ' || *line == '\t') {
+ // Continuation of the previous header
+ if (lastHeaderKey.isNull()) {
+ // malformed header; ignore it and continue
+ continue;
+ }
+
+ // Merge the continuation of the previous header
+ String currentValue = headerFields.get(lastHeaderKey);
+ String newValue(line, lineLength);
+
+ headerFields.set(lastHeaderKey, currentValue + newValue);
+ } else {
+ // Brand new header
+ const char* colon = line;
+ while (*colon != ':' && colon != endOfLine)
+ colon++;
+
+ if (colon == endOfLine) {
+ // malformed header; ignore it and continue
+ continue;
+ }
+
+ lastHeaderKey = capitalizeRFC822HeaderFieldName(String(line, colon - line));
+ String value;
+
+ for (colon++; colon != endOfLine; colon++) {
+ if (*colon != ' ' && *colon != '\t')
+ break;
+ }
+ if (colon == endOfLine)
+ value = "";
+ else
+ value = String(colon, endOfLine - colon);
+
+ String oldValue = headerFields.get(lastHeaderKey);
+ if (!oldValue.isNull()) {
+ String tmp = oldValue;
+ tmp += ", ";
+ tmp += value;
+ value = tmp;
+ }
+
+ headerFields.set(lastHeaderKey, value);
+ }
+ }
+
+ return headerFields;
+}
+
+static NPError parsePostBuffer(bool isFile, const char *buffer, uint32_t length, bool parseHeaders, HTTPHeaderMap& headerFields, Vector<uint8_t>& bodyData)
+{
+ RefPtr<SharedBuffer> fileContents;
+ const char* postBuffer = 0;
+ uint32_t postBufferSize = 0;
+
+ if (isFile) {
+ fileContents = SharedBuffer::createWithContentsOfFile(String::fromUTF8(buffer));
+ if (!fileContents)
+ return NPERR_FILE_NOT_FOUND;
+
+ postBuffer = fileContents->data();
+ postBufferSize = fileContents->size();
+
+ // FIXME: The NPAPI spec states that the file should be deleted here.
+ } else {
+ postBuffer = buffer;
+ postBufferSize = length;
+ }
+
+ if (parseHeaders) {
+ if (startsWithBlankLine(postBuffer, postBufferSize)) {
+ postBuffer++;
+ postBufferSize--;
+ } else {
+ int location = locationAfterFirstBlankLine(postBuffer, postBufferSize);
+ if (location != -1) {
+ // If the blank line is somewhere in the middle of the buffer, everything before is the header
+ headerFields = parseRFC822HeaderFields(postBuffer, location);
+ unsigned dataLength = postBufferSize - location;
+
+ // Sometimes plugins like to set Content-Length themselves when they post,
+ // but WebFoundation does not like that. So we will remove the header
+ // and instead truncate the data to the requested length.
+ String contentLength = headerFields.get("Content-Length");
+
+ if (!contentLength.isNull())
+ dataLength = min(contentLength.toInt(), (int)dataLength);
+ headerFields.remove("Content-Length");
+
+ postBuffer += location;
+ postBufferSize = dataLength;
+
+ }
+ }
+ }
+
+ ASSERT(bodyData.isEmpty());
+ bodyData.append(postBuffer, postBufferSize);
+
+ return NPERR_NO_ERROR;
+}
+
+static String makeURLString(const char* url)
+{
+ String urlString(url);
+
+ // Strip return characters.
+ urlString.replace('\r', "");
+ urlString.replace('\n', "");
+
+ return urlString;
+}
+
+static NPError NPN_GetURL(NPP npp, const char* url, const char* target)
+{
+ if (!url)
+ return NPERR_GENERIC_ERROR;
+
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ plugin->loadURL("GET", makeURLString(url), target, HTTPHeaderMap(), Vector<uint8_t>(), false, 0);
+
+ return NPERR_GENERIC_ERROR;
+}
+
+static NPError NPN_PostURL(NPP npp, const char* url, const char* target, uint32_t len, const char* buf, NPBool file)
+{
+ HTTPHeaderMap headerFields;
+ Vector<uint8_t> postData;
+
+ // NPN_PostURL only allows headers if the post buffer points to a file.
+ bool parseHeaders = file;
+
+ NPError error = parsePostBuffer(file, buf, len, parseHeaders, headerFields, postData);
+ if (error != NPERR_NO_ERROR)
+ return error;
+
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ plugin->loadURL("POST", makeURLString(url), target, headerFields, postData, false, 0);
+ return NPERR_NO_ERROR;
+}
+
+static NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
+{
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+}
+
+static NPError NPN_NewStream(NPP instance, NPMIMEType type, const char* target, NPStream** stream)
+{
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+}
+
+static int32_t NPN_Write(NPP instance, NPStream* stream, int32_t len, void* buffer)
+{
+ notImplemented();
+ return -1;
+}
+
+static NPError NPN_DestroyStream(NPP npp, NPStream* stream, NPReason reason)
+{
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ return plugin->destroyStream(stream, reason);
+}
+
+static void NPN_Status(NPP npp, const char* message)
+{
+ String statusbarText;
+ if (!message)
+ statusbarText = "";
+ else
+ statusbarText = String::fromUTF8WithLatin1Fallback(message, strlen(message));
+
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ plugin->setStatusbarText(statusbarText);
+}
+
+static const char* NPN_UserAgent(NPP npp)
+{
+ return NetscapePlugin::userAgent(npp);
+}
+
+static void* NPN_MemAlloc(uint32_t size)
+{
+ return npnMemAlloc(size);
+}
+
+static void NPN_MemFree(void* ptr)
+{
+ npnMemFree(ptr);
+}
+
+static uint32_t NPN_MemFlush(uint32_t size)
+{
+ return 0;
+}
+
+static void NPN_ReloadPlugins(NPBool reloadPages)
+{
+ notImplemented();
+}
+
+static JRIEnv* NPN_GetJavaEnv(void)
+{
+ notImplemented();
+ return 0;
+}
+
+static jref NPN_GetJavaPeer(NPP instance)
+{
+ notImplemented();
+ return 0;
+}
+
+static NPError NPN_GetURLNotify(NPP npp, const char* url, const char* target, void* notifyData)
+{
+ if (!url)
+ return NPERR_GENERIC_ERROR;
+
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ plugin->loadURL("GET", makeURLString(url), target, HTTPHeaderMap(), Vector<uint8_t>(), true, notifyData);
+
+ return NPERR_NO_ERROR;
+}
+
+static NPError NPN_PostURLNotify(NPP npp, const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData)
+{
+ HTTPHeaderMap headerFields;
+ Vector<uint8_t> postData;
+ NPError error = parsePostBuffer(file, buf, len, true, headerFields, postData);
+ if (error != NPERR_NO_ERROR)
+ return error;
+
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ plugin->loadURL("POST", makeURLString(url), target, headerFields, postData, true, notifyData);
+ return NPERR_NO_ERROR;
+}
+
+#if PLATFORM(MAC)
+/* TRUE if the browser supports hardware compositing of Core Animation plug-ins */
+static const unsigned WKNVSupportsCompositingCoreAnimationPluginsBool = 74656;
+#endif
+
+static NPError NPN_GetValue(NPP npp, NPNVariable variable, void *value)
+{
+ switch (variable) {
+ case NPNVWindowNPObject: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ NPObject* windowNPObject = plugin->windowScriptNPObject();
+ *(NPObject**)value = windowNPObject;
+ break;
+ }
+ case NPNVPluginElementNPObject: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ NPObject* pluginElementNPObject = plugin->pluginElementNPObject();
+ *(NPObject**)value = pluginElementNPObject;
+ break;
+ }
+ case NPNVprivateModeBool: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ *(NPBool*)value = plugin->isPrivateBrowsingEnabled();
+ break;
+ }
+#if PLATFORM(MAC)
+ case NPNVsupportsCoreGraphicsBool:
+ // Always claim to support the Core Graphics drawing model.
+ *(NPBool*)value = true;
+ break;
+
+ case WKNVSupportsCompositingCoreAnimationPluginsBool:
+ case NPNVsupportsCoreAnimationBool: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ *(NPBool*)value = plugin->isAcceleratedCompositingEnabled();
+ break;
+ }
+ case NPNVsupportsCocoaBool:
+ // Always claim to support the Cocoa event model.
+ *(NPBool*)value = true;
+ break;
+
+#ifndef NP_NO_QUICKDRAW
+ case NPNVsupportsQuickDrawBool:
+ // We don't support the QuickDraw drawing model.
+ *(NPBool*)value = false;
+ break;
+#endif
+#ifndef NP_NO_CARBON
+ case NPNVsupportsCarbonBool:
+ // FIXME: We should support the Carbon event model.
+ *(NPBool*)value = false;
+ break;
+#endif
+#elif PLATFORM(WIN)
+ case NPNVnetscapeWindow: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ *reinterpret_cast<HWND*>(value) = plugin->containingWindow();
+ break;
+ }
+ case NPNVSupportsWindowless:
+ *(NPBool*)value = true;
+ break;
+#endif
+ default:
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+static NPError NPN_SetValue(NPP npp, NPPVariable variable, void *value)
+{
+ switch (variable) {
+#if PLATFORM(MAC)
+ case NPPVpluginDrawingModel: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ NPDrawingModel drawingModel = static_cast<NPDrawingModel>(reinterpret_cast<uintptr_t>(value));
+ return plugin->setDrawingModel(drawingModel);
+ }
+
+ case NPPVpluginEventModel: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ NPEventModel eventModel = static_cast<NPEventModel>(reinterpret_cast<uintptr_t>(value));
+ return plugin->setEventModel(eventModel);
+ }
+#endif
+
+ case NPPVpluginWindowBool: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ plugin->setIsWindowed(value);
+ return NPERR_NO_ERROR;
+ }
+
+ case NPPVpluginTransparentBool:
+ default:
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+static void NPN_InvalidateRect(NPP npp, NPRect* invalidRect)
+{
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ plugin->invalidate(invalidRect);
+}
+
+static void NPN_InvalidateRegion(NPP npp, NPRegion invalidRegion)
+{
+ // FIXME: We could at least figure out the bounding rectangle of the invalid region.
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ plugin->invalidate(0);
+}
+
+static void NPN_ForceRedraw(NPP instance)
+{
+ notImplemented();
+}
+
+static NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name)
+{
+ return static_cast<NPIdentifier>(IdentifierRep::get(name));
+}
+
+static void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers)
+{
+ ASSERT(names);
+ ASSERT(identifiers);
+
+ if (!names || !identifiers)
+ return;
+
+ for (int32_t i = 0; i < nameCount; ++i)
+ identifiers[i] = NPN_GetStringIdentifier(names[i]);
+}
+
+static NPIdentifier NPN_GetIntIdentifier(int32_t intid)
+{
+ return static_cast<NPIdentifier>(IdentifierRep::get(intid));
+}
+
+static bool NPN_IdentifierIsString(NPIdentifier identifier)
+{
+ return static_cast<IdentifierRep*>(identifier)->isString();
+}
+
+static NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier)
+{
+ const char* string = static_cast<IdentifierRep*>(identifier)->string();
+ if (!string)
+ return 0;
+
+ uint32_t stringLength = strlen(string);
+ char* utf8String = npnMemNewArray<char>(stringLength + 1);
+ memcpy(utf8String, string, stringLength);
+ utf8String[stringLength] = '\0';
+
+ return utf8String;
+}
+
+static int32_t NPN_IntFromIdentifier(NPIdentifier identifier)
+{
+ return static_cast<IdentifierRep*>(identifier)->number();
+}
+
+static NPObject* NPN_CreateObject(NPP npp, NPClass *npClass)
+{
+ return createNPObject(npp, npClass);
+}
+
+static NPObject *NPN_RetainObject(NPObject *npObject)
+{
+ retainNPObject(npObject);
+ return npObject;
+}
+
+static void NPN_ReleaseObject(NPObject *npObject)
+{
+ releaseNPObject(npObject);
+}
+
+static bool NPN_Invoke(NPP, NPObject *npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+{
+ if (npObject->_class->invoke)
+ return npObject->_class->invoke(npObject, methodName, arguments, argumentCount, result);
+
+ return false;
+}
+
+static bool NPN_InvokeDefault(NPP, NPObject *npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+{
+ if (npObject->_class->invokeDefault)
+ return npObject->_class->invokeDefault(npObject, arguments, argumentCount, result);
+
+ return false;
+}
+
+static bool NPN_Evaluate(NPP npp, NPObject *npObject, NPString *script, NPVariant* result)
+{
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ String scriptString = String::fromUTF8WithLatin1Fallback(script->UTF8Characters, script->UTF8Length);
+
+ return plugin->evaluate(npObject, scriptString, result);
+}
+
+static bool NPN_GetProperty(NPP, NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
+{
+ if (npObject->_class->getProperty)
+ return npObject->_class->getProperty(npObject, propertyName, result);
+
+ return false;
+}
+
+static bool NPN_SetProperty(NPP, NPObject* npObject, NPIdentifier propertyName, const NPVariant* value)
+{
+ if (npObject->_class->setProperty)
+ return npObject->_class->setProperty(npObject, propertyName, value);
+
+ return false;
+}
+
+static bool NPN_RemoveProperty(NPP, NPObject* npObject, NPIdentifier propertyName)
+{
+ if (npObject->_class->removeProperty)
+ return npObject->_class->removeProperty(npObject, propertyName);
+
+ return false;
+}
+
+static bool NPN_HasProperty(NPP, NPObject* npObject, NPIdentifier propertyName)
+{
+ if (npObject->_class->hasProperty)
+ return npObject->_class->hasProperty(npObject, propertyName);
+
+ return false;
+}
+
+static bool NPN_HasMethod(NPP, NPObject* npObject, NPIdentifier methodName)
+{
+ if (npObject->_class->hasMethod)
+ return npObject->_class->hasMethod(npObject, methodName);
+
+ return false;
+}
+
+static void NPN_ReleaseVariantValue(NPVariant* variant)
+{
+ releaseNPVariantValue(variant);
+}
+
+static void NPN_SetException(NPObject*, const NPUTF8* message)
+{
+ NetscapePlugin::setException(message);
+}
+
+static void NPN_PushPopupsEnabledState(NPP npp, NPBool enabled)
+{
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ plugin->pushPopupsEnabledState(enabled);
+}
+
+static void NPN_PopPopupsEnabledState(NPP npp)
+{
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+ plugin->popPopupsEnabledState();
+}
+
+static bool NPN_Enumerate(NPP, NPObject* npObject, NPIdentifier** identifiers, uint32_t* identifierCount)
+{
+ if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npObject->_class) && npObject->_class->enumerate)
+ return npObject->_class->enumerate(npObject, identifiers, identifierCount);
+
+ return false;
+}
+
+static void NPN_PluginThreadAsyncCall(NPP instance, void (*func) (void*), void* userData)
+{
+ notImplemented();
+}
+
+static bool NPN_Construct(NPP, NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+{
+ if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npObject->_class) && npObject->_class->construct)
+ return npObject->_class->construct(npObject, arguments, argumentCount, result);
+
+ return false;
+}
+
+static NPError copyCString(const CString& string, char** value, uint32_t* len)
+{
+ ASSERT(!string.isNull());
+ ASSERT(value);
+ ASSERT(len);
+
+ *value = npnMemNewArray<char>(string.length());
+ if (!*value)
+ return NPERR_GENERIC_ERROR;
+
+ memcpy(*value, string.data(), string.length());
+ *len = string.length();
+ return NPERR_NO_ERROR;
+}
+
+static NPError NPN_GetValueForURL(NPP npp, NPNURLVariable variable, const char* url, char** value, uint32_t* len)
+{
+ if (!value || !len)
+ return NPERR_GENERIC_ERROR;
+
+ switch (variable) {
+ case NPNURLVCookie: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ String cookies = plugin->cookiesForURL(makeURLString(url));
+ if (cookies.isNull())
+ return NPERR_GENERIC_ERROR;
+
+ return copyCString(cookies.utf8(), value, len);
+ }
+
+ case NPNURLVProxy: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ String proxies = plugin->proxiesForURL(makeURLString(url));
+ if (proxies.isNull())
+ return NPERR_GENERIC_ERROR;
+
+ return copyCString(proxies.utf8(), value, len);
+ }
+ default:
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+static NPError NPN_SetValueForURL(NPP npp, NPNURLVariable variable, const char* url, const char* value, uint32_t len)
+{
+ switch (variable) {
+ case NPNURLVCookie: {
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ plugin->setCookiesForURL(makeURLString(url), String(value, len));
+ return NPERR_NO_ERROR;
+ }
+
+ case NPNURLVProxy:
+ // Can't set the proxy for a URL.
+ return NPERR_GENERIC_ERROR;
+
+ default:
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+static NPError NPN_GetAuthenticationInfo(NPP instance, const char* protocol, const char* host, int32_t port, const char* scheme,
+ const char* realm, char** username, uint32_t* ulen, char** password, uint32_t* plen)
+{
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+}
+
+static uint32_t NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID))
+{
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+}
+
+static void NPN_UnscheduleTimer(NPP instance, uint32_t timerID)
+{
+ notImplemented();
+}
+
+#if PLATFORM(MAC)
+static NPError NPN_PopUpContextMenu(NPP instance, NPMenu* menu)
+{
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+}
+
+static NPBool NPN_ConvertPoint(NPP npp, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double* destX, double* destY, NPCoordinateSpace destSpace)
+{
+ RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+ double destinationX;
+ double destinationY;
+
+ bool returnValue = plugin->convertPoint(sourceX, sourceY, sourceSpace, destinationX, destinationY, destSpace);
+
+ if (destX)
+ *destX = destinationX;
+ if (destY)
+ *destY = destinationY;
+
+ return returnValue;
+}
+#endif
+
+static void initializeBrowserFuncs(NPNetscapeFuncs &netscapeFuncs)
+{
+ netscapeFuncs.size = sizeof(NPNetscapeFuncs);
+ netscapeFuncs.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+
+ netscapeFuncs.geturl = NPN_GetURL;
+ netscapeFuncs.posturl = NPN_PostURL;
+ netscapeFuncs.requestread = NPN_RequestRead;
+ netscapeFuncs.newstream = NPN_NewStream;
+ netscapeFuncs.write = NPN_Write;
+ netscapeFuncs.destroystream = NPN_DestroyStream;
+ netscapeFuncs.status = NPN_Status;
+ netscapeFuncs.uagent = NPN_UserAgent;
+ netscapeFuncs.memalloc = NPN_MemAlloc;
+ netscapeFuncs.memfree = NPN_MemFree;
+ netscapeFuncs.memflush = NPN_MemFlush;
+ netscapeFuncs.reloadplugins = NPN_ReloadPlugins;
+ netscapeFuncs.getJavaEnv = NPN_GetJavaEnv;
+ netscapeFuncs.getJavaPeer = NPN_GetJavaPeer;
+ netscapeFuncs.geturlnotify = NPN_GetURLNotify;
+ netscapeFuncs.posturlnotify = NPN_PostURLNotify;
+ netscapeFuncs.getvalue = NPN_GetValue;
+ netscapeFuncs.setvalue = NPN_SetValue;
+ netscapeFuncs.invalidaterect = NPN_InvalidateRect;
+ netscapeFuncs.invalidateregion = NPN_InvalidateRegion;
+ netscapeFuncs.forceredraw = NPN_ForceRedraw;
+
+ netscapeFuncs.getstringidentifier = NPN_GetStringIdentifier;
+ netscapeFuncs.getstringidentifiers = NPN_GetStringIdentifiers;
+ netscapeFuncs.getintidentifier = NPN_GetIntIdentifier;
+ netscapeFuncs.identifierisstring = NPN_IdentifierIsString;
+ netscapeFuncs.utf8fromidentifier = NPN_UTF8FromIdentifier;
+ netscapeFuncs.intfromidentifier = NPN_IntFromIdentifier;
+ netscapeFuncs.createobject = NPN_CreateObject;
+ netscapeFuncs.retainobject = NPN_RetainObject;
+ netscapeFuncs.releaseobject = NPN_ReleaseObject;
+ netscapeFuncs.invoke = NPN_Invoke;
+ netscapeFuncs.invokeDefault = NPN_InvokeDefault;
+ netscapeFuncs.evaluate = NPN_Evaluate;
+ netscapeFuncs.getproperty = NPN_GetProperty;
+ netscapeFuncs.setproperty = NPN_SetProperty;
+ netscapeFuncs.removeproperty = NPN_RemoveProperty;
+ netscapeFuncs.hasproperty = NPN_HasProperty;
+ netscapeFuncs.hasmethod = NPN_HasMethod;
+ netscapeFuncs.releasevariantvalue = NPN_ReleaseVariantValue;
+ netscapeFuncs.setexception = NPN_SetException;
+ netscapeFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
+ netscapeFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState;
+ netscapeFuncs.enumerate = NPN_Enumerate;
+ netscapeFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
+ netscapeFuncs.construct = NPN_Construct;
+ netscapeFuncs.getvalueforurl = NPN_GetValueForURL;
+ netscapeFuncs.setvalueforurl = NPN_SetValueForURL;
+ netscapeFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo;
+ netscapeFuncs.scheduletimer = NPN_ScheduleTimer;
+ netscapeFuncs.unscheduletimer = NPN_UnscheduleTimer;
+#if PLATFORM(MAC)
+ netscapeFuncs.popupcontextmenu = NPN_PopUpContextMenu;
+ netscapeFuncs.convertpoint = NPN_ConvertPoint;
+#else
+ netscapeFuncs.popupcontextmenu = 0;
+ netscapeFuncs.convertpoint = 0;
+#endif
+}
+
+NPNetscapeFuncs* netscapeBrowserFuncs()
+{
+ static NPNetscapeFuncs netscapeFuncs;
+ static bool initialized = false;
+
+ if (!initialized) {
+ initializeBrowserFuncs(netscapeFuncs);
+ initialized = true;
+ }
+
+ return &netscapeFuncs;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapeBrowserFuncs.h b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapeBrowserFuncs.h
new file mode 100644
index 0000000..49a7f3a
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapeBrowserFuncs.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef NetscapeBrowserFuncs_h
+#define NetscapeBrowserFuncs_h
+
+#include <WebCore/npfunctions.h>
+
+namespace WebKit {
+
+NPNetscapeFuncs* netscapeBrowserFuncs();
+
+} // namespace WebKit
+
+
+#endif // NetscapeBrowserFuncs_h
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp
new file mode 100644
index 0000000..0beade2
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp
@@ -0,0 +1,678 @@
+/*
+ * 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 "NetscapePlugin.h"
+
+#include "NPRuntimeObjectMap.h"
+#include "NetscapePluginStream.h"
+#include "PluginController.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_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_inNPPNew(false)
+ , m_loadManually(false)
+#if PLATFORM(MAC)
+ , m_drawingModel(static_cast<NPDrawingModel>(-1))
+ , m_eventModel(static_cast<NPEventModel>(-1))
+ , m_pluginHasFocus(false)
+ , m_windowHasFocus(false)
+#ifndef NP_NO_CARBON
+ , m_nullEventTimer(RunLoop::main(), this, &NetscapePlugin::nullEventTimerFired)
+ , m_npCGContext()
+#endif
+#endif
+{
+ m_npp.ndata = this;
+ m_npp.pdata = 0;
+
+ m_pluginModule->pluginCreated();
+}
+
+NetscapePlugin::~NetscapePlugin()
+{
+ ASSERT(!m_isStarted);
+
+ m_pluginModule->pluginDestroyed();
+}
+
+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_frameRect.width(), m_frameRect.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 (m_userAgent.isNull()) {
+ m_userAgent = m_pluginController->userAgent().utf8();
+ ASSERT(!m_userAgent.isNull());
+ }
+ 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()) {
+ // The browser is going to send the data in a stream, create a plug-in stream.
+ RefPtr<NetscapePluginStream> pluginStream = NetscapePluginStream::create(this, requestID, 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::setStatusbarText(const String& statusbarText)
+{
+ m_pluginController->setStatusbarText(statusbarText);
+}
+
+void NetscapePlugin::setException(const String& exceptionString)
+{
+ // FIXME: If the plug-in is running in its own process, this needs to send a CoreIPC message instead of
+ // calling the runtime object map directly.
+ 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();
+}
+
+void NetscapePlugin::cancelStreamLoad(NetscapePluginStream* pluginStream)
+{
+ if (pluginStream == m_manualStream) {
+ m_pluginController->cancelManualStreamLoad();
+ return;
+ }
+
+ // Ask the plug-in controller to cancel this stream load.
+ 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();
+}
+
+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);
+}
+
+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()
+{
+ m_npWindow.x = m_frameRect.x();
+ m_npWindow.y = m_frameRect.y();
+ m_npWindow.width = m_frameRect.width();
+ m_npWindow.height = m_frameRect.height();
+ m_npWindow.clipRect.top = m_clipRect.y();
+ m_npWindow.clipRect.left = m_clipRect.x();
+ m_npWindow.clipRect.bottom = m_clipRect.bottom();
+ m_npWindow.clipRect.right = m_clipRect.right();
+
+ 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(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());
+ }
+
+ // 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());
+ }
+
+ 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();
+
+ NPP_Destroy(0);
+
+ m_isStarted = false;
+ m_pluginController = 0;
+
+ platformDestroy();
+}
+
+void NetscapePlugin::paint(GraphicsContext* context, const IntRect& dirtyRect)
+{
+ ASSERT(m_isStarted);
+
+ platformPaint(context, dirtyRect);
+}
+
+void NetscapePlugin::geometryDidChange(const IntRect& frameRect, const IntRect& clipRect)
+{
+ ASSERT(m_isStarted);
+
+ if (m_frameRect == frameRect && m_clipRect == clipRect) {
+ // Nothing to do.
+ return;
+ }
+
+ m_frameRect = frameRect;
+ m_clipRect = clipRect;
+
+ platformGeometryDidChange();
+ callSetWindow();
+}
+
+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& requestURLString, const String& result)
+{
+ ASSERT(m_isStarted);
+
+ if (NetscapePluginStream* pluginStream = streamFromID(requestID))
+ pluginStream->sendJavaScriptStream(requestURLString, result);
+}
+
+void NetscapePlugin::streamDidReceiveResponse(uint64_t streamID, const KURL& responseURL, uint32_t streamLength,
+ uint32_t lastModifiedTime, const String& mimeType, const String& headers)
+{
+ 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)
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_loadManually);
+ ASSERT(!m_manualStream);
+
+ m_manualStream = NetscapePluginStream::create(this, 0, 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::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;
+
+ return scriptableNPObject;
+}
+
+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);
+}
+
+PluginController* NetscapePlugin::controller()
+{
+ return m_pluginController;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.h b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.h
new file mode 100644
index 0000000..fb5d37e
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.h
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+#ifndef NetscapePlugin_h
+#define NetscapePlugin_h
+
+#include "NetscapePluginModule.h"
+#include "Plugin.h"
+#include "RunLoop.h"
+#include <WebCore/GraphicsLayer.h>
+#include <WebCore/IntRect.h>
+#include <wtf/HashMap.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+ class HTTPHeaderMap;
+}
+
+namespace WebKit {
+
+class NetscapePluginStream;
+
+class NetscapePlugin : public Plugin {
+public:
+ static PassRefPtr<NetscapePlugin> create(PassRefPtr<NetscapePluginModule> pluginModule);
+ virtual ~NetscapePlugin();
+
+ static PassRefPtr<NetscapePlugin> fromNPP(NPP);
+
+#if PLATFORM(MAC)
+ NPError setDrawingModel(NPDrawingModel);
+ NPError setEventModel(NPEventModel);
+ NPBool convertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double& destX, double& destY, NPCoordinateSpace destSpace);
+
+#ifndef NP_NO_CARBON
+ WindowRef windowRef() const;
+ bool isWindowActive() const { return m_windowHasFocus; }
+
+ static NetscapePlugin* netscapePluginFromWindow(WindowRef);
+ static unsigned buttonState();
+#endif
+
+#elif PLATFORM(WIN)
+ HWND containingWindow() const;
+#endif
+
+ void invalidate(const NPRect*);
+ static const char* userAgent(NPP);
+ void loadURL(const String& method, const String& urlString, const String& target, const WebCore::HTTPHeaderMap& headerFields,
+ const Vector<uint8_t>& httpBody, bool sendNotification, void* notificationData);
+ NPError destroyStream(NPStream*, NPReason);
+ void setIsWindowed(bool);
+ void setStatusbarText(const String&);
+ static void setException(const String&);
+ bool evaluate(NPObject*, const String&scriptString, NPVariant* result);
+ bool isPrivateBrowsingEnabled();
+
+ // These return retained objects.
+ NPObject* windowScriptNPObject();
+ NPObject* pluginElementNPObject();
+
+ void cancelStreamLoad(NetscapePluginStream*);
+ void removePluginStream(NetscapePluginStream*);
+
+ bool isAcceleratedCompositingEnabled();
+
+ void pushPopupsEnabledState(bool enabled);
+ void popPopupsEnabledState();
+
+ String proxiesForURL(const String& urlString);
+ String cookiesForURL(const String& urlString);
+ void setCookiesForURL(const String& urlString, const String& cookieString);
+
+ // Member functions for calling into the plug-in.
+ NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData*);
+ NPError NPP_Destroy(NPSavedData**);
+ NPError NPP_SetWindow(NPWindow*);
+ NPError NPP_NewStream(NPMIMEType, NPStream*, NPBool seekable, uint16_t* stype);
+ NPError NPP_DestroyStream(NPStream*, NPReason);
+ void NPP_StreamAsFile(NPStream*, const char* filename);
+ int32_t NPP_WriteReady(NPStream*);
+ int32_t NPP_Write(NPStream*, int32_t offset, int32_t len, void* buffer);
+ int16_t NPP_HandleEvent(void* event);
+ void NPP_URLNotify(const char* url, NPReason, void* notifyData);
+ NPError NPP_GetValue(NPPVariable, void *value);
+ NPError NPP_SetValue(NPNVariable, void *value);
+
+private:
+ NetscapePlugin(PassRefPtr<NetscapePluginModule> pluginModule);
+
+ void callSetWindow();
+ bool shouldLoadSrcURL();
+ NetscapePluginStream* streamFromID(uint64_t streamID);
+ void stopAllStreams();
+ bool allowPopups() const;
+
+ const char* userAgent();
+
+ bool platformPostInitialize();
+ void platformDestroy();
+ bool platformInvalidate(const WebCore::IntRect&);
+ void platformGeometryDidChange();
+ void platformPaint(WebCore::GraphicsContext*, const WebCore::IntRect& dirtyRect);
+
+ bool platformHandleMouseEvent(const WebMouseEvent&);
+ bool platformHandleWheelEvent(const WebWheelEvent&);
+ bool platformHandleMouseEnterEvent(const WebMouseEvent&);
+ bool platformHandleMouseLeaveEvent(const WebMouseEvent&);
+ bool platformHandleKeyboardEvent(const WebKeyboardEvent&);
+ void platformSetFocus(bool);
+
+ // Plugin
+ virtual bool initialize(PluginController*, const Parameters&);
+ virtual void destroy();
+ virtual void paint(WebCore::GraphicsContext*, const WebCore::IntRect& dirtyRect);
+#if PLATFORM(MAC)
+ virtual PlatformLayer* pluginLayer();
+#endif
+ virtual void geometryDidChange(const WebCore::IntRect& frameRect, const WebCore::IntRect& clipRect);
+ virtual void frameDidFinishLoading(uint64_t requestID);
+ virtual void frameDidFail(uint64_t requestID, bool wasCancelled);
+ virtual void didEvaluateJavaScript(uint64_t requestID, const String& requestURLString, const String& result);
+ virtual void streamDidReceiveResponse(uint64_t streamID, const WebCore::KURL& responseURL, uint32_t streamLength,
+ uint32_t lastModifiedTime, const String& mimeType, const String& headers);
+ virtual void streamDidReceiveData(uint64_t streamID, const char* bytes, int length);
+ virtual void streamDidFinishLoading(uint64_t streamID);
+ virtual void streamDidFail(uint64_t streamID, bool wasCancelled);
+ virtual void manualStreamDidReceiveResponse(const WebCore::KURL& responseURL, uint32_t streamLength,
+ uint32_t lastModifiedTime, const String& mimeType, const String& headers);
+ virtual void manualStreamDidReceiveData(const char* bytes, int length);
+ virtual void manualStreamDidFinishLoading();
+ virtual void manualStreamDidFail(bool wasCancelled);
+
+ virtual bool handleMouseEvent(const WebMouseEvent&);
+ virtual bool handleWheelEvent(const WebWheelEvent&);
+ virtual bool handleMouseEnterEvent(const WebMouseEvent&);
+ virtual bool handleMouseLeaveEvent(const WebMouseEvent&);
+ virtual bool handleKeyboardEvent(const WebKeyboardEvent&);
+ virtual void setFocus(bool);
+ virtual NPObject* pluginScriptableNPObject();
+
+#if PLATFORM(MAC)
+ virtual void windowFocusChanged(bool);
+ virtual void windowAndViewFramesChanged(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates);
+ virtual void windowVisibilityChanged(bool);
+
+ virtual uint64_t pluginComplexTextInputIdentifier() const;
+ virtual void sendComplexTextInput(const String& textInput);
+#endif
+
+ virtual void privateBrowsingStateChanged(bool);
+
+ virtual PluginController* controller();
+
+ PluginController* m_pluginController;
+ uint64_t m_nextRequestID;
+
+ typedef HashMap<uint64_t, std::pair<String, void*> > PendingURLNotifyMap;
+ PendingURLNotifyMap m_pendingURLNotifications;
+
+ typedef HashMap<uint64_t, RefPtr<NetscapePluginStream> > StreamsMap;
+ StreamsMap m_streams;
+
+ RefPtr<NetscapePluginModule> m_pluginModule;
+ NPP_t m_npp;
+ NPWindow m_npWindow;
+
+ WebCore::IntRect m_frameRect;
+ WebCore::IntRect m_clipRect;
+
+ CString m_userAgent;
+
+ bool m_isStarted;
+ bool m_isWindowed;
+ bool m_inNPPNew;
+ bool m_loadManually;
+ RefPtr<NetscapePluginStream> m_manualStream;
+ Vector<bool, 8> m_popupEnabledStates;
+
+#if PLATFORM(MAC)
+ NPDrawingModel m_drawingModel;
+ NPEventModel m_eventModel;
+ RetainPtr<PlatformLayer> m_pluginLayer;
+
+ bool m_pluginHasFocus;
+ bool m_windowHasFocus;
+
+ WebCore::IntRect m_windowFrameInScreenCoordinates;
+ WebCore::IntRect m_viewFrameInWindowCoordinates;
+
+#ifndef NP_NO_CARBON
+ void nullEventTimerFired();
+
+ // FIXME: It's a bit wasteful to have one null event timer per plug-in.
+ // We should investigate having one per window.
+ RunLoop::Timer<NetscapePlugin> m_nullEventTimer;
+ NP_CGContext m_npCGContext;
+#endif
+#elif PLATFORM(WIN)
+ HWND m_window;
+#endif
+};
+
+} // namespace WebKit
+
+#endif // NetscapePlugin_h
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePluginStream.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePluginStream.cpp
new file mode 100644
index 0000000..be60795
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePluginStream.cpp
@@ -0,0 +1,355 @@
+/*
+ * 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 "NetscapePluginStream.h"
+
+#include "NetscapePlugin.h"
+#include <utility>
+
+using namespace WebCore;
+using namespace std;
+
+namespace WebKit {
+
+NetscapePluginStream::NetscapePluginStream(PassRefPtr<NetscapePlugin> plugin, uint64_t streamID, bool sendNotification, void* notificationData)
+ : m_plugin(plugin)
+ , m_streamID(streamID)
+ , m_sendNotification(sendNotification)
+ , m_notificationData(notificationData)
+ , m_npStream()
+ , m_transferMode(NP_NORMAL)
+ , m_offset(0)
+ , m_fileHandle(invalidPlatformFileHandle)
+ , m_isStarted(false)
+#if !ASSERT_DISABLED
+ , m_urlNotifyHasBeenCalled(false)
+#endif
+ , m_deliveryDataTimer(RunLoop::main(), this, &NetscapePluginStream::deliverDataToPlugin)
+ , m_stopStreamWhenDoneDelivering(false)
+{
+}
+
+NetscapePluginStream::~NetscapePluginStream()
+{
+ ASSERT(!m_isStarted);
+ ASSERT(!m_sendNotification || m_urlNotifyHasBeenCalled);
+ ASSERT(m_fileHandle == invalidPlatformFileHandle);
+}
+
+void NetscapePluginStream::didReceiveResponse(const KURL& responseURL, uint32_t streamLength, uint32_t lastModifiedTime, const String& mimeType, const String& headers)
+{
+ // Starting the stream could cause the plug-in stream to go away so we keep a reference to it here.
+ RefPtr<NetscapePluginStream> protect(this);
+
+ start(responseURL, streamLength, lastModifiedTime, mimeType, headers);
+}
+
+void NetscapePluginStream::didReceiveData(const char* bytes, int length)
+{
+ // Delivering the data could cause the plug-in stream to go away so we keep a reference to it here.
+ RefPtr<NetscapePluginStream> protect(this);
+
+ deliverData(bytes, length);
+}
+
+void NetscapePluginStream::didFinishLoading()
+{
+ // Stopping the stream could cause the plug-in stream to go away so we keep a reference to it here.
+ RefPtr<NetscapePluginStream> protect(this);
+
+ stop(NPRES_DONE);
+}
+
+void NetscapePluginStream::didFail(bool wasCancelled)
+{
+ // Stopping the stream could cause the plug-in stream to go away so we keep a reference to it here.
+ RefPtr<NetscapePluginStream> protect(this);
+
+ stop(wasCancelled ? NPRES_USER_BREAK : NPRES_NETWORK_ERR);
+}
+
+void NetscapePluginStream::sendJavaScriptStream(const String& requestURLString, const String& result)
+{
+ // starting the stream or delivering the data to it might cause the plug-in stream to go away, so we keep
+ // a reference to it here.
+ RefPtr<NetscapePluginStream> protect(this);
+
+ CString resultCString = requestURLString.utf8();
+ if (resultCString.isNull()) {
+ // There was an error evaluating the JavaScript, call NPP_URLNotify if needed and then destroy the stream.
+ notifyAndDestroyStream(NPRES_NETWORK_ERR);
+ return;
+ }
+
+ if (!start(requestURLString, resultCString.length(), 0, "text/plain", ""))
+ return;
+
+ deliverData(resultCString.data(), resultCString.length());
+ stop(NPRES_DONE);
+}
+
+NPError NetscapePluginStream::destroy(NPReason reason)
+{
+ // It doesn't make sense to call NPN_DestroyStream on a stream that hasn't been started yet.
+ if (!m_isStarted)
+ return NPERR_GENERIC_ERROR;
+
+ // It isn't really valid for a plug-in to call NPN_DestroyStream with NPRES_DONE.
+ // (At least not for browser initiated streams, and we don't support plug-in initiated streams).
+ if (reason == NPRES_DONE)
+ return NPERR_INVALID_PARAM;
+
+ cancel();
+ stop(reason);
+ return NPERR_NO_ERROR;
+}
+
+static bool isSupportedTransferMode(uint16_t transferMode)
+{
+ switch (transferMode) {
+ case NP_ASFILEONLY:
+ case NP_ASFILE:
+ case NP_NORMAL:
+ return true;
+ // FIXME: We don't support seekable streams.
+ case NP_SEEK:
+ return false;
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+bool NetscapePluginStream::start(const String& responseURLString, uint32_t streamLength, uint32_t lastModifiedTime, const String& mimeType, const String& headers)
+{
+ m_responseURL = responseURLString.utf8();
+ m_mimeType = mimeType.utf8();
+ m_headers = headers.utf8();
+
+ m_npStream.ndata = this;
+ m_npStream.url = m_responseURL.data();
+ m_npStream.end = streamLength;
+ m_npStream.lastmodified = lastModifiedTime;
+ m_npStream.notifyData = m_notificationData;
+ m_npStream.headers = m_headers.length() == 0 ? 0 : m_headers.data();
+
+ NPError error = m_plugin->NPP_NewStream(const_cast<char*>(m_mimeType.data()), &m_npStream, false, &m_transferMode);
+ if (error != NPERR_NO_ERROR) {
+ // We failed to start the stream, cancel the load and destroy it.
+ cancel();
+ notifyAndDestroyStream(NPRES_NETWORK_ERR);
+ return false;
+ }
+
+ // We successfully started the stream.
+ m_isStarted = true;
+
+ if (!isSupportedTransferMode(m_transferMode)) {
+ // Cancel the load and stop the stream.
+ cancel();
+ stop(NPRES_NETWORK_ERR);
+ return false;
+ }
+
+ return true;
+}
+
+void NetscapePluginStream::deliverData(const char* bytes, int length)
+{
+ ASSERT(m_isStarted);
+
+ if (m_transferMode != NP_ASFILEONLY) {
+ if (!m_deliveryData)
+ m_deliveryData.set(new Vector<uint8_t>);
+
+ m_deliveryData->reserveCapacity(m_deliveryData->size() + length);
+ m_deliveryData->append(bytes, length);
+
+ deliverDataToPlugin();
+ }
+
+ if (m_transferMode == NP_ASFILE || m_transferMode == NP_ASFILEONLY)
+ deliverDataToFile(bytes, length);
+}
+
+void NetscapePluginStream::deliverDataToPlugin()
+{
+ ASSERT(m_isStarted);
+
+ int32_t numBytesToDeliver = m_deliveryData->size();
+ int32_t numBytesDelivered = 0;
+
+ while (numBytesDelivered < numBytesToDeliver) {
+ int32_t numBytesPluginCanHandle = m_plugin->NPP_WriteReady(&m_npStream);
+
+ // NPP_WriteReady could call NPN_DestroyStream and destroy the stream.
+ if (!m_isStarted)
+ return;
+
+ if (numBytesPluginCanHandle <= 0) {
+ // The plug-in can't handle more data, we'll send the rest later
+ m_deliveryDataTimer.startOneShot(0);
+ break;
+ }
+
+ // Figure out how much data to send to the plug-in.
+ int32_t dataLength = min(numBytesPluginCanHandle, numBytesToDeliver - numBytesDelivered);
+ uint8_t* data = m_deliveryData->data() + numBytesDelivered;
+
+ int32_t numBytesWritten = m_plugin->NPP_Write(&m_npStream, m_offset, dataLength, data);
+ if (numBytesWritten < 0) {
+ stop(NPRES_NETWORK_ERR);
+ return;
+ }
+
+ // NPP_Write could call NPN_DestroyStream and destroy the stream.
+ if (!m_isStarted)
+ return;
+
+ numBytesWritten = min(numBytesWritten, dataLength);
+ m_offset += numBytesWritten;
+ numBytesDelivered += numBytesWritten;
+ }
+
+ // We didn't write anything.
+ if (!numBytesDelivered)
+ return;
+
+ if (numBytesDelivered < numBytesToDeliver) {
+ // Remove the bytes that we actually delivered.
+ m_deliveryData->remove(0, numBytesDelivered);
+ } else {
+ m_deliveryData->clear();
+
+ if (m_stopStreamWhenDoneDelivering)
+ stop(NPRES_DONE);
+ }
+}
+
+void NetscapePluginStream::deliverDataToFile(const char* bytes, int length)
+{
+ if (m_fileHandle == invalidPlatformFileHandle && m_filePath.isNull()) {
+ // Create a temporary file.
+ m_filePath = openTemporaryFile("WebKitPluginStream", m_fileHandle);
+
+ // We failed to open the file, stop the stream.
+ if (m_fileHandle == invalidPlatformFileHandle) {
+ stop(NPRES_NETWORK_ERR);
+ return;
+ }
+ }
+
+ if (!length)
+ return;
+
+ int byteCount = writeToFile(m_fileHandle, bytes, length);
+ if (byteCount != length) {
+ // This happens only rarely, when we are out of disk space or have a disk I/O error.
+ closeFile(m_fileHandle);
+
+ stop(NPRES_NETWORK_ERR);
+ }
+}
+
+void NetscapePluginStream::stop(NPReason reason)
+{
+ // The stream was stopped before it got a chance to start. This can happen if a stream is cancelled by
+ // WebKit before it received a response.
+ if (!m_isStarted)
+ return;
+
+ if (reason == NPRES_DONE && m_deliveryData && !m_deliveryData->isEmpty()) {
+ // There is still data left that the plug-in hasn't been able to consume yet.
+ ASSERT(m_deliveryDataTimer.isActive());
+
+ // Set m_stopStreamWhenDoneDelivering to true so that the next time the delivery timer fires
+ // and calls deliverDataToPlugin the stream will be closed if all the remaining data was
+ // successfully delivered.
+ m_stopStreamWhenDoneDelivering = true;
+ return;
+ }
+
+ m_deliveryData = 0;
+ m_deliveryDataTimer.stop();
+
+ if (m_transferMode == NP_ASFILE || m_transferMode == NP_ASFILEONLY) {
+ if (reason == NPRES_DONE) {
+ // Ensure that the file is created.
+ deliverDataToFile(0, 0);
+ if (m_fileHandle != invalidPlatformFileHandle)
+ closeFile(m_fileHandle);
+
+ ASSERT(!m_filePath.isNull());
+
+ m_plugin->NPP_StreamAsFile(&m_npStream, m_filePath.data());
+ } else {
+ // Just close the file.
+ if (m_fileHandle != invalidPlatformFileHandle)
+ closeFile(m_fileHandle);
+ }
+
+ // Delete the file after calling NPP_StreamAsFile(), instead of in the destructor. It should be OK
+ // to delete the file here -- NPP_StreamAsFile() is always called immediately before NPP_DestroyStream()
+ // (the stream destruction function), so there can be no expectation that a plugin will read the stream
+ // file asynchronously after NPP_StreamAsFile() is called.
+ deleteFile(String::fromUTF8(m_filePath.data()));
+ m_filePath = CString();
+
+ // NPP_StreamAsFile could call NPN_DestroyStream and destroy the stream.
+ if (!m_isStarted)
+ return;
+ }
+
+ // Set m_isStarted to false before calling NPP_DestroyStream in case NPP_DestroyStream calls NPN_DestroyStream.
+ m_isStarted = false;
+
+ m_plugin->NPP_DestroyStream(&m_npStream, reason);
+
+ notifyAndDestroyStream(reason);
+}
+
+void NetscapePluginStream::cancel()
+{
+ m_plugin->cancelStreamLoad(this);
+}
+
+void NetscapePluginStream::notifyAndDestroyStream(NPReason reason)
+{
+ ASSERT(!m_isStarted);
+ ASSERT(!m_deliveryDataTimer.isActive());
+ ASSERT(!m_urlNotifyHasBeenCalled);
+
+ if (m_sendNotification) {
+ m_plugin->NPP_URLNotify(m_responseURL.data(), reason, m_notificationData);
+
+#if !ASSERT_DISABLED
+ m_urlNotifyHasBeenCalled = true;
+#endif
+ }
+
+ m_plugin->removePluginStream(this);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePluginStream.h b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePluginStream.h
new file mode 100644
index 0000000..7757001
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePluginStream.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#ifndef NetscapePluginStream_h
+#define NetscapePluginStream_h
+
+#include "RunLoop.h"
+#include <WebCore/FileSystem.h>
+#include <WebCore/npruntime_internal.h>
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+ class KURL;
+}
+
+namespace WebKit {
+
+class NetscapePlugin;
+
+class NetscapePluginStream : public RefCounted<NetscapePluginStream> {
+public:
+ static PassRefPtr<NetscapePluginStream> create(PassRefPtr<NetscapePlugin> plugin, uint64_t streamID, bool sendNotification, void* notificationData)
+ {
+ return adoptRef(new NetscapePluginStream(plugin, streamID, sendNotification, notificationData));
+ }
+ ~NetscapePluginStream();
+
+ uint64_t streamID() const { return m_streamID; }
+ const NPStream* npStream() const { return &m_npStream; }
+
+ void didReceiveResponse(const WebCore::KURL& responseURL, uint32_t streamLength,
+ uint32_t lastModifiedTime, const String& mimeType, const String& headers);
+ void didReceiveData(const char* bytes, int length);
+ void didFinishLoading();
+ void didFail(bool wasCancelled);
+
+ void sendJavaScriptStream(const String& requestURLString, const String& result);
+
+ void stop(NPReason);
+ NPError destroy(NPReason);
+
+private:
+ NetscapePluginStream(PassRefPtr<NetscapePlugin>, uint64_t streamID, bool sendNotification, void* notificationData);
+
+ bool start(const String& responseURLString, uint32_t streamLength,
+ uint32_t lastModifiedTime, const String& mimeType, const String& headers);
+
+ void cancel();
+ void notifyAndDestroyStream(NPReason);
+
+ void deliverData(const char* bytes, int length);
+ void deliverDataToPlugin();
+ void deliverDataToFile(const char* bytes, int length);
+
+ RefPtr<NetscapePlugin> m_plugin;
+ uint64_t m_streamID;
+
+ bool m_sendNotification;
+ void* m_notificationData;
+
+ NPStream m_npStream;
+ uint16_t m_transferMode;
+ int32_t m_offset;
+
+ CString m_filePath;
+ WebCore::PlatformFileHandle m_fileHandle;
+
+ // Whether NPP_NewStream has successfully been called.
+ bool m_isStarted;
+
+#if !ASSERT_DISABLED
+ bool m_urlNotifyHasBeenCalled;
+#endif
+
+ CString m_responseURL;
+ CString m_mimeType;
+ CString m_headers;
+
+ RunLoop::Timer<NetscapePluginStream> m_deliveryDataTimer;
+ OwnPtr< Vector<uint8_t> > m_deliveryData;
+ bool m_stopStreamWhenDoneDelivering;
+};
+
+} // namespace WebKit
+
+#endif // NetscapePluginStream_h
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/gtk/NetscapePluginGtk.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/gtk/NetscapePluginGtk.cpp
new file mode 100644
index 0000000..64239f3
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/gtk/NetscapePluginGtk.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Portions Copyright (c) 2010 Motorola Mobility, 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 "NetscapePlugin.h"
+
+#include "NotImplemented.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+bool NetscapePlugin::platformPostInitialize()
+{
+ notImplemented();
+ return true;
+}
+
+void NetscapePlugin::platformDestroy()
+{
+ notImplemented();
+}
+
+bool NetscapePlugin::platformInvalidate(const IntRect&)
+{
+ notImplemented();
+ return false;
+}
+
+void NetscapePlugin::platformGeometryDidChange()
+{
+ notImplemented();
+}
+
+void NetscapePlugin::platformPaint(GraphicsContext* context, const IntRect& dirtyRect)
+{
+ notImplemented();
+}
+
+NPEvent toNP(const WebMouseEvent& event)
+{
+ NPEvent npEvent = NPEvent();
+ notImplemented();
+ return npEvent;
+}
+
+bool NetscapePlugin::platformHandleMouseEvent(const WebMouseEvent& event)
+{
+ notImplemented();
+ return true;
+}
+
+bool NetscapePlugin::platformHandleWheelEvent(const WebWheelEvent&)
+{
+ notImplemented();
+ return false;
+}
+
+void NetscapePlugin::platformSetFocus(bool)
+{
+ notImplemented();
+}
+
+bool NetscapePlugin::platformHandleMouseEnterEvent(const WebMouseEvent& event)
+{
+ notImplemented();
+ return true;
+}
+
+bool NetscapePlugin::platformHandleMouseLeaveEvent(const WebMouseEvent& event)
+{
+ notImplemented();
+ return true;
+}
+
+bool NetscapePlugin::platformHandleKeyboardEvent(const WebKeyboardEvent&)
+{
+ notImplemented();
+ return false;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/mac/NetscapePluginMac.mm b/Source/WebKit2/WebProcess/Plugins/Netscape/mac/NetscapePluginMac.mm
new file mode 100644
index 0000000..1240ed7
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/mac/NetscapePluginMac.mm
@@ -0,0 +1,903 @@
+/*
+ * 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 "NetscapePlugin.h"
+
+#include "PluginController.h"
+#include "WebEvent.h"
+#include <WebCore/GraphicsContext.h>
+#include <Carbon/Carbon.h>
+#include <WebKitSystemInterface.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+#ifndef NP_NO_CARBON
+static const double nullEventIntervalActive = 0.02;
+static const double nullEventIntervalNotActive = 0.25;
+
+static unsigned buttonStateFromLastMouseEvent;
+
+#endif
+
+NPError NetscapePlugin::setDrawingModel(NPDrawingModel drawingModel)
+{
+ // The drawing model can only be set from NPP_New.
+ if (!m_inNPPNew)
+ return NPERR_GENERIC_ERROR;
+
+ switch (drawingModel) {
+#ifndef NP_NO_QUICKDRAW
+ case NPDrawingModelQuickDraw:
+#endif
+ case NPDrawingModelCoreGraphics:
+ case NPDrawingModelCoreAnimation:
+ m_drawingModel = drawingModel;
+ break;
+
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NetscapePlugin::setEventModel(NPEventModel eventModel)
+{
+ // The event model can only be set from NPP_New.
+ if (!m_inNPPNew)
+ return NPERR_GENERIC_ERROR;
+
+ switch (eventModel) {
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon:
+#endif
+ case NPEventModelCocoa:
+ m_eventModel = eventModel;
+ break;
+
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+static double flipScreenYCoordinate(double y)
+{
+ return [[[NSScreen screens] objectAtIndex:0] frame].size.height - y;
+}
+
+NPBool NetscapePlugin::convertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double& destX, double& destY, NPCoordinateSpace destSpace)
+{
+ if (sourceSpace == destSpace) {
+ destX = sourceX;
+ destY = sourceY;
+ return true;
+ }
+
+ double sourceXInScreenSpace;
+ double sourceYInScreenSpace;
+
+ FloatPoint sourceInScreenSpace;
+ switch (sourceSpace) {
+ case NPCoordinateSpacePlugin:
+ sourceXInScreenSpace = sourceX + m_windowFrameInScreenCoordinates.x() + m_viewFrameInWindowCoordinates.x() + m_npWindow.x;
+ sourceYInScreenSpace = m_windowFrameInScreenCoordinates.y() + m_viewFrameInWindowCoordinates.y() + m_viewFrameInWindowCoordinates.height() - (sourceY + m_npWindow.y);
+ break;
+ case NPCoordinateSpaceWindow:
+ sourceXInScreenSpace = sourceX + m_windowFrameInScreenCoordinates.x();
+ sourceYInScreenSpace = sourceY + m_windowFrameInScreenCoordinates.y();
+ break;
+ case NPCoordinateSpaceFlippedWindow:
+ sourceXInScreenSpace = sourceX + m_windowFrameInScreenCoordinates.x();
+ sourceYInScreenSpace = m_windowFrameInScreenCoordinates.y() + m_windowFrameInScreenCoordinates.height() - sourceY;
+ break;
+ case NPCoordinateSpaceScreen:
+ sourceXInScreenSpace = sourceX;
+ sourceYInScreenSpace = sourceY;
+ break;
+ case NPCoordinateSpaceFlippedScreen:
+ sourceXInScreenSpace = sourceX;
+ sourceYInScreenSpace = flipScreenYCoordinate(sourceY);
+ default:
+ return false;
+ }
+
+ // Now convert back.
+ switch (destSpace) {
+ case NPCoordinateSpacePlugin:
+ destX = sourceXInScreenSpace - (m_windowFrameInScreenCoordinates.x() + m_viewFrameInWindowCoordinates.x() + m_npWindow.x);
+ destY = m_windowFrameInScreenCoordinates.y() + m_viewFrameInWindowCoordinates.y() + m_viewFrameInWindowCoordinates.height() - (sourceYInScreenSpace + m_npWindow.y);
+ break;
+ case NPCoordinateSpaceWindow:
+ destX = sourceXInScreenSpace - m_windowFrameInScreenCoordinates.x();
+ destY = sourceYInScreenSpace - m_windowFrameInScreenCoordinates.y();
+ break;
+ case NPCoordinateSpaceFlippedWindow:
+ destX = sourceXInScreenSpace - m_windowFrameInScreenCoordinates.x();
+ destY = sourceYInScreenSpace - m_windowFrameInScreenCoordinates.y();
+ destY = m_windowFrameInScreenCoordinates.height() - destY;
+ break;
+ case NPCoordinateSpaceScreen:
+ destX = sourceXInScreenSpace;
+ destY = sourceYInScreenSpace;
+ break;
+ case NPCoordinateSpaceFlippedScreen:
+ destX = sourceXInScreenSpace;
+ destY = flipScreenYCoordinate(sourceYInScreenSpace);
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+#ifndef NP_NO_CARBON
+typedef HashMap<WindowRef, NetscapePlugin*> WindowMap;
+
+static WindowMap& windowMap()
+{
+ DEFINE_STATIC_LOCAL(WindowMap, windowMap, ());
+
+ return windowMap;
+}
+#endif
+
+bool NetscapePlugin::platformPostInitialize()
+{
+ if (m_drawingModel == static_cast<NPDrawingModel>(-1)) {
+#ifndef NP_NO_QUICKDRAW
+ // Default to QuickDraw if the plugin did not specify a drawing model.
+ m_drawingModel = NPDrawingModelQuickDraw;
+#else
+ // QuickDraw is not available, so we can't default to it. Instead, default to CoreGraphics.
+ m_drawingModel = NPDrawingModelCoreGraphics;
+#endif
+ }
+
+ if (m_eventModel == static_cast<NPEventModel>(-1)) {
+ // If the plug-in did not specify a drawing model we default to Carbon when it is available.
+#ifndef NP_NO_CARBON
+ m_eventModel = NPEventModelCarbon;
+#else
+ m_eventModel = NPEventModelCocoa;
+#endif // NP_NO_CARBON
+ }
+
+#if !defined(NP_NO_CARBON) && !defined(NP_NO_QUICKDRAW)
+ // The CA drawing model does not work with the Carbon event model.
+ if (m_drawingModel == NPDrawingModelCoreAnimation && m_eventModel == NPEventModelCarbon)
+ return false;
+
+ // The Cocoa event model does not work with the QuickDraw drawing model.
+ if (m_eventModel == NPEventModelCocoa && m_drawingModel == NPDrawingModelQuickDraw)
+ return false;
+#endif
+
+#ifndef NP_NO_QUICKDRAW
+ // Right now we don't support the QuickDraw drawing model at all
+ if (m_drawingModel == NPDrawingModelQuickDraw)
+ return false;
+#endif
+
+ if (m_drawingModel == NPDrawingModelCoreAnimation) {
+ void* value = 0;
+ // Get the Core Animation layer.
+ if (NPP_GetValue(NPPVpluginCoreAnimationLayer, &value) == NPERR_NO_ERROR && value) {
+ ASSERT(!m_pluginLayer);
+ m_pluginLayer = reinterpret_cast<CALayer *>(value);
+ }
+ }
+
+#ifndef NP_NO_CARBON
+ if (m_eventModel == NPEventModelCarbon) {
+ // Initialize the fake Carbon window.
+ ::Rect bounds = { 0, 0, 0, 0 };
+ CreateNewWindow(kDocumentWindowClass, kWindowNoTitleBarAttribute, &bounds, reinterpret_cast<WindowRef*>(&m_npCGContext.window));
+ ASSERT(m_npCGContext.window);
+
+ // FIXME: Disable the backing store.
+
+ m_npWindow.window = &m_npCGContext;
+
+ ASSERT(!windowMap().contains(windowRef()));
+ windowMap().set(windowRef(), this);
+
+ // Start the null event timer.
+ // FIXME: Throttle null events when the plug-in isn't visible on screen.
+ m_nullEventTimer.startRepeating(nullEventIntervalActive);
+ }
+#endif
+
+ return true;
+}
+
+void NetscapePlugin::platformDestroy()
+{
+#ifndef NP_NO_CARBON
+ if (m_eventModel == NPEventModelCarbon) {
+ if (WindowRef window = windowRef()) {
+ // Destroy the fake Carbon window.
+ DisposeWindow(window);
+
+ ASSERT(windowMap().contains(window));
+ windowMap().remove(window);
+ }
+
+ // Stop the null event timer.
+ m_nullEventTimer.stop();
+ }
+#endif
+}
+
+bool NetscapePlugin::platformInvalidate(const IntRect&)
+{
+ return false;
+}
+
+void NetscapePlugin::platformGeometryDidChange()
+{
+}
+
+static inline NPCocoaEvent initializeEvent(NPCocoaEventType type)
+{
+ NPCocoaEvent event;
+
+ event.type = type;
+ event.version = 0;
+
+ return event;
+}
+
+#ifndef NP_NO_CARBON
+NetscapePlugin* NetscapePlugin::netscapePluginFromWindow(WindowRef windowRef)
+{
+ return windowMap().get(windowRef);
+}
+
+WindowRef NetscapePlugin::windowRef() const
+{
+ ASSERT(m_eventModel == NPEventModelCarbon);
+
+ return reinterpret_cast<WindowRef>(m_npCGContext.window);
+}
+
+unsigned NetscapePlugin::buttonState()
+{
+ return buttonStateFromLastMouseEvent;
+}
+
+static inline EventRecord initializeEventRecord(EventKind eventKind)
+{
+ EventRecord eventRecord;
+
+ eventRecord.what = eventKind;
+ eventRecord.message = 0;
+ eventRecord.when = TickCount();
+ eventRecord.where = Point();
+ eventRecord.modifiers = 0;
+
+ return eventRecord;
+}
+
+static bool anyMouseButtonIsDown(const WebEvent& event)
+{
+ if (event.type() == WebEvent::MouseDown)
+ return true;
+
+ if (event.type() == WebEvent::MouseMove && static_cast<const WebMouseEvent&>(event).button() != WebMouseEvent::NoButton)
+ return true;
+
+ return false;
+}
+
+static bool rightMouseButtonIsDown(const WebEvent& event)
+{
+ if (event.type() == WebEvent::MouseDown && static_cast<const WebMouseEvent&>(event).button() == WebMouseEvent::RightButton)
+ return true;
+
+ if (event.type() == WebEvent::MouseMove && static_cast<const WebMouseEvent&>(event).button() == WebMouseEvent::RightButton)
+ return true;
+
+ return false;
+}
+
+static EventModifiers modifiersForEvent(const WebEvent& event)
+{
+ EventModifiers modifiers = 0;
+
+ // We only want to set the btnState if a mouse button is _not_ down.
+ if (!anyMouseButtonIsDown(event))
+ modifiers |= btnState;
+
+ if (event.metaKey())
+ modifiers |= cmdKey;
+
+ if (event.shiftKey())
+ modifiers |= shiftKey;
+
+ if (event.altKey())
+ modifiers |= optionKey;
+
+ // Set controlKey if the control key is down or the right mouse button is down.
+ if (event.controlKey() || rightMouseButtonIsDown(event))
+ modifiers |= controlKey;
+
+ return modifiers;
+}
+
+#endif
+
+void NetscapePlugin::platformPaint(GraphicsContext* context, const IntRect& dirtyRect)
+{
+ CGContextRef platformContext = context->platformContext();
+
+ // Translate the context so that the origin is at the top left corner of the plug-in view.
+ context->translate(m_frameRect.x(), m_frameRect.y());
+
+ switch (m_eventModel) {
+ case NPEventModelCocoa: {
+ // Don't send draw events when we're using the Core Animation drawing model.
+ if (m_drawingModel == NPDrawingModelCoreAnimation)
+ return;
+
+ NPCocoaEvent event = initializeEvent(NPCocoaEventDrawRect);
+
+ event.data.draw.context = platformContext;
+ event.data.draw.x = dirtyRect.x() - m_frameRect.x();
+ event.data.draw.y = dirtyRect.y() - m_frameRect.y();
+ event.data.draw.width = dirtyRect.width();
+ event.data.draw.height = dirtyRect.height();
+
+ NPP_HandleEvent(&event);
+ break;
+ }
+
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon: {
+ if (platformContext != m_npCGContext.context) {
+ m_npCGContext.context = platformContext;
+ callSetWindow();
+ }
+
+ EventRecord event = initializeEventRecord(updateEvt);
+ event.message = reinterpret_cast<unsigned long>(windowRef());
+
+ NPP_HandleEvent(&event);
+ break;
+ }
+#endif
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+static uint32_t modifierFlags(const WebEvent& event)
+{
+ uint32_t modifiers = 0;
+
+ if (event.shiftKey())
+ modifiers |= NSShiftKeyMask;
+ if (event.controlKey())
+ modifiers |= NSControlKeyMask;
+ if (event.altKey())
+ modifiers |= NSAlternateKeyMask;
+ if (event.metaKey())
+ modifiers |= NSCommandKeyMask;
+
+ return modifiers;
+}
+
+static int32_t buttonNumber(WebMouseEvent::Button button)
+{
+ switch (button) {
+ case WebMouseEvent::NoButton:
+ case WebMouseEvent::LeftButton:
+ return 0;
+ case WebMouseEvent::RightButton:
+ return 1;
+ case WebMouseEvent::MiddleButton:
+ return 2;
+ }
+
+ ASSERT_NOT_REACHED();
+ return -1;
+}
+
+static void fillInCocoaEventFromMouseEvent(NPCocoaEvent& event, const WebMouseEvent& mouseEvent, const WebCore::IntPoint& pluginLocation)
+{
+ event.data.mouse.modifierFlags = modifierFlags(mouseEvent);
+ event.data.mouse.pluginX = mouseEvent.position().x() - pluginLocation.x();
+ event.data.mouse.pluginY = mouseEvent.position().y() - pluginLocation.y();
+ event.data.mouse.buttonNumber = buttonNumber(mouseEvent.button());
+ event.data.mouse.clickCount = mouseEvent.clickCount();
+ event.data.mouse.deltaX = mouseEvent.deltaX();
+ event.data.mouse.deltaY = mouseEvent.deltaY();
+ event.data.mouse.deltaZ = mouseEvent.deltaZ();
+}
+
+static NPCocoaEvent initializeMouseEvent(const WebMouseEvent& mouseEvent, const WebCore::IntPoint& pluginLocation)
+{
+ NPCocoaEventType eventType;
+
+ switch (mouseEvent.type()) {
+ case WebEvent::MouseDown:
+ eventType = NPCocoaEventMouseDown;
+ break;
+ case WebEvent::MouseUp:
+ eventType = NPCocoaEventMouseUp;
+ break;
+ case WebEvent::MouseMove:
+ if (mouseEvent.button() == WebMouseEvent::NoButton)
+ eventType = NPCocoaEventMouseMoved;
+ else
+ eventType = NPCocoaEventMouseDragged;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ return NPCocoaEvent();
+ }
+
+ NPCocoaEvent event = initializeEvent(eventType);
+ fillInCocoaEventFromMouseEvent(event, mouseEvent, pluginLocation);
+ return event;
+}
+
+bool NetscapePlugin::platformHandleMouseEvent(const WebMouseEvent& mouseEvent)
+{
+ switch (m_eventModel) {
+ case NPEventModelCocoa: {
+ NPCocoaEvent event = initializeMouseEvent(mouseEvent, m_frameRect.location());
+ return NPP_HandleEvent(&event);
+ }
+
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon: {
+ EventKind eventKind = nullEvent;
+
+ switch (mouseEvent.type()) {
+ case WebEvent::MouseDown:
+ eventKind = mouseDown;
+ buttonStateFromLastMouseEvent |= (1 << buttonNumber(mouseEvent.button()));
+ break;
+ case WebEvent::MouseUp:
+ eventKind = mouseUp;
+ buttonStateFromLastMouseEvent &= ~(1 << buttonNumber(mouseEvent.button()));
+ break;
+ case WebEvent::MouseMove:
+ eventKind = nullEvent;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ EventRecord event = initializeEventRecord(eventKind);
+ event.modifiers = modifiersForEvent(mouseEvent);
+ event.where.h = mouseEvent.globalPosition().x();
+ event.where.v = mouseEvent.globalPosition().y();
+
+ return NPP_HandleEvent(&event);
+ }
+#endif
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return false;
+}
+
+bool NetscapePlugin::platformHandleWheelEvent(const WebWheelEvent& wheelEvent)
+{
+ switch (m_eventModel) {
+ case NPEventModelCocoa: {
+ NPCocoaEvent event = initializeEvent(NPCocoaEventScrollWheel);
+
+ event.data.mouse.modifierFlags = modifierFlags(wheelEvent);
+ event.data.mouse.pluginX = wheelEvent.position().x() - m_frameRect.x();
+ event.data.mouse.pluginY = wheelEvent.position().y() - m_frameRect.y();
+ event.data.mouse.buttonNumber = 0;
+ event.data.mouse.clickCount = 0;
+ event.data.mouse.deltaX = wheelEvent.delta().width();
+ event.data.mouse.deltaY = wheelEvent.delta().height();
+ event.data.mouse.deltaZ = 0;
+ return NPP_HandleEvent(&event);
+ }
+
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon:
+ // Carbon doesn't have wheel events.
+ break;
+#endif
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return false;
+}
+
+bool NetscapePlugin::platformHandleMouseEnterEvent(const WebMouseEvent& mouseEvent)
+{
+ switch (m_eventModel) {
+ case NPEventModelCocoa: {
+ NPCocoaEvent event = initializeEvent(NPCocoaEventMouseEntered);
+
+ fillInCocoaEventFromMouseEvent(event, mouseEvent, m_frameRect.location());
+ return NPP_HandleEvent(&event);
+ }
+
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon: {
+ EventRecord eventRecord = initializeEventRecord(NPEventType_AdjustCursorEvent);
+ eventRecord.modifiers = modifiersForEvent(mouseEvent);
+
+ return NPP_HandleEvent(&eventRecord);
+ }
+#endif
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return false;
+}
+
+bool NetscapePlugin::platformHandleMouseLeaveEvent(const WebMouseEvent& mouseEvent)
+{
+ switch (m_eventModel) {
+ case NPEventModelCocoa: {
+ NPCocoaEvent event = initializeEvent(NPCocoaEventMouseExited);
+
+ fillInCocoaEventFromMouseEvent(event, mouseEvent, m_frameRect.location());
+ return NPP_HandleEvent(&event);
+ }
+
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon: {
+ EventRecord eventRecord = initializeEventRecord(NPEventType_AdjustCursorEvent);
+ eventRecord.modifiers = modifiersForEvent(mouseEvent);
+
+ return NPP_HandleEvent(&eventRecord);
+ }
+#endif
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return false;
+}
+
+static unsigned modifierFlags(const WebKeyboardEvent& keyboardEvent)
+{
+ unsigned modifierFlags = 0;
+
+ if (keyboardEvent.shiftKey())
+ modifierFlags |= NSShiftKeyMask;
+ if (keyboardEvent.controlKey())
+ modifierFlags |= NSControlKeyMask;
+ if (keyboardEvent.altKey())
+ modifierFlags |= NSAlternateKeyMask;
+ if (keyboardEvent.metaKey())
+ modifierFlags |= NSCommandKeyMask;
+
+ return modifierFlags;
+}
+
+static NPCocoaEvent initializeKeyboardEvent(const WebKeyboardEvent& keyboardEvent)
+{
+ NPCocoaEventType eventType;
+
+ switch (keyboardEvent.type()) {
+ case WebEvent::KeyDown:
+ eventType = NPCocoaEventKeyDown;
+ break;
+ case WebEvent::KeyUp:
+ eventType = NPCocoaEventKeyUp;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ return NPCocoaEvent();
+ }
+
+ NPCocoaEvent event = initializeEvent(eventType);
+ event.data.key.modifierFlags = modifierFlags(keyboardEvent);
+ event.data.key.characters = reinterpret_cast<NPNSString*>(static_cast<NSString*>(keyboardEvent.text()));
+ event.data.key.charactersIgnoringModifiers = reinterpret_cast<NPNSString*>(static_cast<NSString*>(keyboardEvent.unmodifiedText()));
+ event.data.key.isARepeat = keyboardEvent.isAutoRepeat();
+ event.data.key.keyCode = keyboardEvent.nativeVirtualKeyCode();
+
+ return event;
+}
+
+bool NetscapePlugin::platformHandleKeyboardEvent(const WebKeyboardEvent& keyboardEvent)
+{
+ bool handled = false;
+
+ switch (m_eventModel) {
+ case NPEventModelCocoa: {
+ NPCocoaEvent event = initializeKeyboardEvent(keyboardEvent);
+ handled = NPP_HandleEvent(&event);
+ break;
+ }
+
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon: {
+ EventKind eventKind = nullEvent;
+
+ switch (keyboardEvent.type()) {
+ case WebEvent::KeyDown:
+ eventKind = keyboardEvent.isAutoRepeat() ? autoKey : keyDown;
+ break;
+ case WebEvent::KeyUp:
+ eventKind = keyUp;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ EventRecord event = initializeEventRecord(eventKind);
+ event.modifiers = modifiersForEvent(keyboardEvent);
+ event.message = keyboardEvent.nativeVirtualKeyCode() << 8 | keyboardEvent.macCharCode();
+ handled = NPP_HandleEvent(&event);
+ break;
+ }
+#endif
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ // Most plug-ins simply return true for all keyboard events, even those that aren't handled.
+ // This leads to bugs such as <rdar://problem/8740926>. We work around this by returning false
+ // if the keyboard event has the command modifier pressed.
+ if (keyboardEvent.metaKey())
+ return false;
+
+ return handled;
+}
+
+void NetscapePlugin::platformSetFocus(bool hasFocus)
+{
+ m_pluginHasFocus = hasFocus;
+ m_pluginController->setComplexTextInputEnabled(m_pluginHasFocus && m_windowHasFocus);
+
+ switch (m_eventModel) {
+ case NPEventModelCocoa: {
+ NPCocoaEvent event = initializeEvent(NPCocoaEventFocusChanged);
+
+ event.data.focus.hasFocus = hasFocus;
+ NPP_HandleEvent(&event);
+ break;
+ }
+
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon: {
+ EventRecord event = initializeEventRecord(hasFocus ? NPEventType_GetFocusEvent : NPEventType_LoseFocusEvent);
+
+ NPP_HandleEvent(&event);
+ break;
+ }
+#endif
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void NetscapePlugin::windowFocusChanged(bool hasFocus)
+{
+ m_windowHasFocus = hasFocus;
+ m_pluginController->setComplexTextInputEnabled(m_pluginHasFocus && m_windowHasFocus);
+
+ switch (m_eventModel) {
+ case NPEventModelCocoa: {
+ NPCocoaEvent event = initializeEvent(NPCocoaEventWindowFocusChanged);
+
+ event.data.focus.hasFocus = hasFocus;
+ NPP_HandleEvent(&event);
+ break;
+ }
+
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon: {
+ HiliteWindow(windowRef(), hasFocus);
+ if (hasFocus)
+ SetUserFocusWindow(windowRef());
+
+ EventRecord event = initializeEventRecord(activateEvt);
+ event.message = reinterpret_cast<unsigned long>(windowRef());
+ if (hasFocus)
+ event.modifiers |= activeFlag;
+
+ NPP_HandleEvent(&event);
+ break;
+ }
+#endif
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+#ifndef NP_NO_CARBON
+static Rect computeFakeWindowBoundsRect(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates)
+{
+ // Carbon global coordinates has the origin set at the top left corner of the main viewing screen, so we want to flip the y coordinate.
+ CGFloat maxY = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]);
+
+ int flippedWindowFrameYCoordinate = maxY - windowFrameInScreenCoordinates.bottom();
+ int flippedViewFrameYCoordinate = windowFrameInScreenCoordinates.height() - viewFrameInWindowCoordinates.bottom();
+
+ Rect bounds;
+
+ bounds.top = flippedWindowFrameYCoordinate + flippedViewFrameYCoordinate;
+ bounds.left = windowFrameInScreenCoordinates.x();
+ bounds.right = bounds.left + viewFrameInWindowCoordinates.width();
+ bounds.bottom = bounds.top + viewFrameInWindowCoordinates.height();
+
+ return bounds;
+}
+#endif
+
+void NetscapePlugin::windowAndViewFramesChanged(const IntRect& windowFrameInScreenCoordinates, const IntRect& viewFrameInWindowCoordinates)
+{
+ m_windowFrameInScreenCoordinates = windowFrameInScreenCoordinates;
+ m_viewFrameInWindowCoordinates = viewFrameInWindowCoordinates;
+
+ switch (m_eventModel) {
+ case NPEventModelCocoa:
+ // Nothing to do.
+ break;
+
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon: {
+ Rect bounds = computeFakeWindowBoundsRect(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates);
+
+ ::SetWindowBounds(windowRef(), kWindowStructureRgn, &bounds);
+ break;
+ }
+#endif
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void NetscapePlugin::windowVisibilityChanged(bool)
+{
+ // FIXME: Implement.
+}
+
+uint64_t NetscapePlugin::pluginComplexTextInputIdentifier() const
+{
+ // This is never called for NetscapePlugin.
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+
+#ifndef NP_NO_CARBON
+static bool convertStringToKeyCodes(const String& string, ScriptCode scriptCode, Vector<UInt8>& keyCodes)
+{
+ // Create the mapping.
+ UnicodeMapping mapping;
+
+ if (GetTextEncodingFromScriptInfo(scriptCode, kTextLanguageDontCare, kTextRegionDontCare, &mapping.otherEncoding) != noErr)
+ return false;
+
+ mapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, kTextEncodingDefaultVariant, kTextEncodingDefaultFormat);
+ mapping.mappingVersion = kUnicodeUseLatestMapping;
+
+ // Create the converter
+ UnicodeToTextInfo textInfo;
+
+ if (CreateUnicodeToTextInfo(&mapping, &textInfo) != noErr)
+ return false;
+
+ ByteCount inputLength = string.length() * sizeof(UniChar);
+ ByteCount inputRead;
+ ByteCount outputLength;
+ ByteCount maxOutputLength = string.length() * sizeof(UniChar);
+
+ Vector<UInt8> outputData(maxOutputLength);
+ OSStatus status = ConvertFromUnicodeToText(textInfo, inputLength, string.characters(), kNilOptions, 0, 0, 0, 0, maxOutputLength, &inputRead, &outputLength, outputData.data());
+
+ DisposeUnicodeToTextInfo(&textInfo);
+
+ if (status != noErr)
+ return false;
+
+ outputData.swap(keyCodes);
+ return true;
+}
+#endif
+
+void NetscapePlugin::sendComplexTextInput(const String& textInput)
+{
+ switch (m_eventModel) {
+ case NPEventModelCocoa: {
+ NPCocoaEvent event = initializeEvent(NPCocoaEventTextInput);
+ event.data.text.text = reinterpret_cast<NPNSString*>(static_cast<NSString*>(textInput));
+ NPP_HandleEvent(&event);
+ break;
+ }
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon: {
+ ScriptCode scriptCode = WKGetScriptCodeFromCurrentKeyboardInputSource();
+ Vector<UInt8> keyCodes;
+
+ if (!convertStringToKeyCodes(textInput, scriptCode, keyCodes))
+ return;
+
+ // Set the script code as the keyboard script. Normally Carbon does this whenever the input source changes.
+ // However, this is only done for the process that has the keyboard focus. We cheat and do it here instead.
+ SetScriptManagerVariable(smKeyScript, scriptCode);
+
+ EventRecord event = initializeEventRecord(keyDown);
+ event.modifiers = 0;
+
+ for (size_t i = 0; i < keyCodes.size(); i++) {
+ event.message = keyCodes[i];
+ NPP_HandleEvent(&event);
+ }
+ break;
+ }
+#endif
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+PlatformLayer* NetscapePlugin::pluginLayer()
+{
+ return static_cast<PlatformLayer*>(m_pluginLayer.get());
+}
+
+#ifndef NP_NO_CARBON
+void NetscapePlugin::nullEventTimerFired()
+{
+ EventRecord event = initializeEventRecord(nullEvent);
+
+ event.message = 0;
+ CGPoint mousePosition;
+ HIGetMousePosition(kHICoordSpaceScreenPixel, 0, &mousePosition);
+ event.where.h = mousePosition.x;
+ event.where.v = mousePosition.y;
+
+ event.modifiers = GetCurrentKeyModifiers();
+ if (!Button())
+ event.modifiers |= btnState;
+
+ NPP_HandleEvent(&event);
+}
+#endif
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/mac/PluginProxyMac.mm b/Source/WebKit2/WebProcess/Plugins/Netscape/mac/PluginProxyMac.mm
new file mode 100644
index 0000000..6ecf7b9
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/mac/PluginProxyMac.mm
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#if ENABLE(PLUGIN_PROCESS)
+
+#include "PluginProxy.h"
+
+#include <WebKitSystemInterface.h>
+
+namespace WebKit {
+
+PlatformLayer* PluginProxy::pluginLayer()
+{
+ if (!m_pluginLayer && m_remoteLayerClientID)
+ m_pluginLayer = WKMakeRenderLayer(m_remoteLayerClientID);
+
+ return m_pluginLayer.get();
+}
+
+bool PluginProxy::needsBackingStore() const
+{
+ return !m_remoteLayerClientID;
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(PLUGIN_PROCESS)
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/qt/NetscapePluginQt.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/qt/NetscapePluginQt.cpp
new file mode 100644
index 0000000..77efc01
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/qt/NetscapePluginQt.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 University of Szeged
+ *
+ * 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 "NetscapePlugin.h"
+
+#include "NotImplemented.h"
+#include "WebEvent.h"
+#include <WebCore/GraphicsContext.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+bool NetscapePlugin::platformPostInitialize()
+{
+ notImplemented();
+ return true;
+}
+
+void NetscapePlugin::platformDestroy()
+{
+ notImplemented();
+}
+
+bool NetscapePlugin::platformInvalidate(const IntRect&)
+{
+ notImplemented();
+ return false;
+}
+
+void NetscapePlugin::platformGeometryDidChange()
+{
+ notImplemented();
+}
+
+void NetscapePlugin::platformPaint(GraphicsContext* context, const IntRect& dirtyRect)
+{
+ notImplemented();
+}
+
+NPEvent toNP(const WebMouseEvent& event)
+{
+#if OS(SYMBIAN)
+ NPEvent npEvent = QEvent(QEvent::None);
+#else
+ NPEvent npEvent = NPEvent();
+#endif
+
+ notImplemented();
+
+ return npEvent;
+}
+
+bool NetscapePlugin::platformHandleMouseEvent(const WebMouseEvent& event)
+{
+ if (m_isWindowed)
+ return false;
+
+ NPEvent npEvent = toNP(event);
+ NPP_HandleEvent(&npEvent);
+ return true;
+}
+
+bool NetscapePlugin::platformHandleWheelEvent(const WebWheelEvent&)
+{
+ notImplemented();
+ return false;
+}
+
+void NetscapePlugin::platformSetFocus(bool)
+{
+ notImplemented();
+}
+
+bool NetscapePlugin::platformHandleMouseEnterEvent(const WebMouseEvent& event)
+{
+ if (m_isWindowed)
+ return false;
+
+ NPEvent npEvent = toNP(event);
+ NPP_HandleEvent(&npEvent);
+ return true;
+}
+
+bool NetscapePlugin::platformHandleMouseLeaveEvent(const WebMouseEvent& event)
+{
+ if (m_isWindowed)
+ return false;
+
+ NPEvent npEvent = toNP(event);
+ NPP_HandleEvent(&npEvent);
+ return true;
+}
+
+bool NetscapePlugin::platformHandleKeyboardEvent(const WebKeyboardEvent&)
+{
+ notImplemented();
+ return false;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/win/NetscapePluginWin.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/win/NetscapePluginWin.cpp
new file mode 100644
index 0000000..930f87b
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/win/NetscapePluginWin.cpp
@@ -0,0 +1,293 @@
+/*
+ * 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 "NetscapePlugin.h"
+
+#include "NotImplemented.h"
+#include "PluginController.h"
+#include "WebEvent.h"
+#include <WebCore/GraphicsContext.h>
+#include <WebCore/LocalWindowsContext.h>
+
+using namespace WebCore;
+
+extern "C" HINSTANCE gInstance;
+
+namespace WebKit {
+
+static LPCWSTR windowClassName = L"org.webkit.NetscapePluginWindow";
+
+static void registerPluginView()
+{
+ static bool didRegister;
+ if (didRegister)
+ return;
+ didRegister = true;
+
+ WNDCLASSW windowClass = {0};
+ windowClass.style = CS_DBLCLKS;
+ windowClass.lpfnWndProc = ::DefWindowProcW;
+ windowClass.hInstance = gInstance;
+ windowClass.hCursor = ::LoadCursorW(0, IDC_ARROW);
+ windowClass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
+ windowClass.lpszClassName = windowClassName;
+
+ ::RegisterClassW(&windowClass);
+}
+
+HWND NetscapePlugin::containingWindow() const
+{
+ return m_pluginController->nativeParentWindow();
+}
+
+bool NetscapePlugin::platformPostInitialize()
+{
+ if (!m_isWindowed) {
+ m_window = 0;
+ return true;
+ }
+
+ registerPluginView();
+
+ m_window = ::CreateWindowExW(0, windowClassName, 0, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, containingWindow(), 0, 0, 0);
+ if (!m_window)
+ return false;
+
+ // FIXME: Do we need to pass our window to setPlatformWidget?
+ // FIXME: WebCore::PluginView sets the window proc to DefWindowProcA here for Shockwave Director.
+
+ m_npWindow.type = NPWindowTypeWindow;
+ m_npWindow.window = m_window;
+
+ return true;
+}
+
+void NetscapePlugin::platformDestroy()
+{
+ if (!m_isWindowed) {
+ ASSERT(!m_window);
+ return;
+ }
+
+ if (!::IsWindow(m_window))
+ return;
+ ::DestroyWindow(m_window);
+}
+
+bool NetscapePlugin::platformInvalidate(const IntRect& invalidRect)
+{
+ if (!m_isWindowed)
+ return false;
+
+ RECT rect = invalidRect;
+ ::InvalidateRect(m_window, &rect, FALSE);
+ return true;
+}
+
+enum RedrawOrNot { DoNotRedraw, Redraw };
+static void setWindowRegion(HWND window, PassOwnPtr<HRGN> popRegion, RedrawOrNot redrawOrNot)
+{
+ OwnPtr<HRGN> region = popRegion;
+
+ if (!::SetWindowRgn(window, region.get(), redrawOrNot == Redraw))
+ return;
+
+ // Windows owns the region now.
+ region.leakPtr();
+}
+
+void NetscapePlugin::platformGeometryDidChange()
+{
+ if (!m_isWindowed)
+ return;
+
+ IntRect clipRectInPluginWindowCoordinates = m_clipRect;
+ clipRectInPluginWindowCoordinates.move(-m_frameRect.x(), -m_frameRect.y());
+
+ OwnPtr<HRGN> clipRegion = adoptPtr(::CreateRectRgn(clipRectInPluginWindowCoordinates.x(), clipRectInPluginWindowCoordinates.y(), clipRectInPluginWindowCoordinates.right(), clipRectInPluginWindowCoordinates.bottom()));
+ setWindowRegion(m_window, clipRegion.release(), Redraw);
+
+ // FIXME: We should only update the size here and let the UI process update our position so
+ // that we can keep our position in sync when scrolling, etc.
+ ::MoveWindow(m_window, m_frameRect.x(), m_frameRect.y(), m_frameRect.width(), m_frameRect.height(), TRUE);
+}
+
+void NetscapePlugin::platformPaint(GraphicsContext* context, const IntRect& dirtyRect)
+{
+ // FIXME: Call SetWindow here if we haven't called it yet (see r59904).
+
+ if (m_isWindowed) {
+ // FIXME: Paint windowed plugins into context if context->shouldIncludeChildWindows() is true.
+ return;
+ }
+
+ // FIXME: Support transparent plugins.
+ LocalWindowsContext windowsContext(context, dirtyRect, false);
+
+ m_npWindow.type = NPWindowTypeDrawable;
+ m_npWindow.window = windowsContext.hdc();
+
+ WINDOWPOS windowpos = { 0, 0, 0, 0, 0, 0, 0 };
+
+ windowpos.x = m_frameRect.x();
+ windowpos.y = m_frameRect.y();
+ windowpos.cx = m_frameRect.width();
+ windowpos.cy = m_frameRect.height();
+
+ NPEvent npEvent;
+ npEvent.event = WM_WINDOWPOSCHANGED;
+ npEvent.wParam = 0;
+ npEvent.lParam = reinterpret_cast<uintptr_t>(&windowpos);
+
+ NPP_HandleEvent(&npEvent);
+
+ callSetWindow();
+
+ RECT dirtyWinRect = dirtyRect;
+
+ npEvent.event = WM_PAINT;
+ npEvent.wParam = reinterpret_cast<uintptr_t>(windowsContext.hdc());
+ npEvent.lParam = reinterpret_cast<uintptr_t>(&dirtyWinRect);
+
+ NPP_HandleEvent(&npEvent);
+}
+
+NPEvent toNP(const WebMouseEvent& event)
+{
+ NPEvent npEvent;
+
+ npEvent.wParam = 0;
+ if (event.controlKey())
+ npEvent.wParam |= MK_CONTROL;
+ if (event.shiftKey())
+ npEvent.wParam |= MK_SHIFT;
+
+ npEvent.lParam = MAKELPARAM(event.position().x(), event.position().y());
+
+ switch (event.type()) {
+ case WebEvent::MouseMove:
+ npEvent.event = WM_MOUSEMOVE;
+ switch (event.button()) {
+ case WebMouseEvent::LeftButton:
+ npEvent.wParam |= MK_LBUTTON;
+ break;
+ case WebMouseEvent::MiddleButton:
+ npEvent.wParam |= MK_MBUTTON;
+ break;
+ case WebMouseEvent::RightButton:
+ npEvent.wParam |= MK_RBUTTON;
+ break;
+ case WebMouseEvent::NoButton:
+ break;
+ }
+ break;
+ case WebEvent::MouseDown:
+ switch (event.button()) {
+ case WebMouseEvent::LeftButton:
+ npEvent.event = WM_LBUTTONDOWN;
+ break;
+ case WebMouseEvent::MiddleButton:
+ npEvent.event = WM_MBUTTONDOWN;
+ break;
+ case WebMouseEvent::RightButton:
+ npEvent.event = WM_RBUTTONDOWN;
+ break;
+ case WebMouseEvent::NoButton:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ break;
+ case WebEvent::MouseUp:
+ switch (event.button()) {
+ case WebMouseEvent::LeftButton:
+ npEvent.event = WM_LBUTTONUP;
+ break;
+ case WebMouseEvent::MiddleButton:
+ npEvent.event = WM_MBUTTONUP;
+ break;
+ case WebMouseEvent::RightButton:
+ npEvent.event = WM_RBUTTONUP;
+ break;
+ case WebMouseEvent::NoButton:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ return npEvent;
+}
+
+bool NetscapePlugin::platformHandleMouseEvent(const WebMouseEvent& event)
+{
+ if (m_isWindowed)
+ return false;
+
+ NPEvent npEvent = toNP(event);
+ NPP_HandleEvent(&npEvent);
+ return true;
+}
+
+bool NetscapePlugin::platformHandleWheelEvent(const WebWheelEvent&)
+{
+ notImplemented();
+ return false;
+}
+
+void NetscapePlugin::platformSetFocus(bool)
+{
+ notImplemented();
+}
+
+bool NetscapePlugin::platformHandleMouseEnterEvent(const WebMouseEvent& event)
+{
+ if (m_isWindowed)
+ return false;
+
+ NPEvent npEvent = toNP(event);
+ NPP_HandleEvent(&npEvent);
+ return true;
+}
+
+bool NetscapePlugin::platformHandleMouseLeaveEvent(const WebMouseEvent& event)
+{
+ if (m_isWindowed)
+ return false;
+
+ NPEvent npEvent = toNP(event);
+ NPP_HandleEvent(&npEvent);
+ return true;
+}
+
+bool NetscapePlugin::platformHandleKeyboardEvent(const WebKeyboardEvent&)
+{
+ notImplemented();
+ return false;
+}
+
+} // namespace WebKit