summaryrefslogtreecommitdiffstats
path: root/Source/WebKit2/WebProcess/Plugins
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-13 16:23:25 +0100
committerBen Murdoch <benm@google.com>2011-05-16 11:35:02 +0100
commit65f03d4f644ce73618e5f4f50dd694b26f55ae12 (patch)
treef478babb801e720de7bfaee23443ffe029f58731 /Source/WebKit2/WebProcess/Plugins
parent47de4a2fb7262c7ebdb9cd133ad2c54c187454d0 (diff)
downloadexternal_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.zip
external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.gz
external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.bz2
Merge WebKit at r75993: Initial merge by git.
Change-Id: I602bbdc3974787a3b0450456a30a7868286921c3
Diffstat (limited to 'Source/WebKit2/WebProcess/Plugins')
-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
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Plugin.cpp76
-rw-r--r--Source/WebKit2/WebProcess/Plugins/Plugin.h174
-rw-r--r--Source/WebKit2/WebProcess/Plugins/PluginController.h114
-rw-r--r--Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.cpp119
-rw-r--r--Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.h86
-rw-r--r--Source/WebKit2/WebProcess/Plugins/PluginProcessConnectionManager.cpp87
-rw-r--r--Source/WebKit2/WebProcess/Plugins/PluginProcessConnectionManager.h59
-rw-r--r--Source/WebKit2/WebProcess/Plugins/PluginProxy.cpp458
-rw-r--r--Source/WebKit2/WebProcess/Plugins/PluginProxy.h161
-rw-r--r--Source/WebKit2/WebProcess/Plugins/PluginProxy.messages.in65
-rw-r--r--Source/WebKit2/WebProcess/Plugins/PluginView.cpp1013
-rw-r--r--Source/WebKit2/WebProcess/Plugins/PluginView.h185
33 files changed, 8031 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
diff --git a/Source/WebKit2/WebProcess/Plugins/Plugin.cpp b/Source/WebKit2/WebProcess/Plugins/Plugin.cpp
new file mode 100644
index 0000000..32ad92d
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Plugin.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 "Plugin.h"
+
+#include "WebCoreArgumentCoders.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+void Plugin::Parameters::encode(CoreIPC::ArgumentEncoder* encoder) const
+{
+ encoder->encode(url.string());
+ encoder->encode(names);
+ encoder->encode(values);
+ encoder->encode(mimeType);
+ encoder->encode(loadManually);
+}
+
+bool Plugin::Parameters::decode(CoreIPC::ArgumentDecoder* decoder, Parameters& parameters)
+{
+ String urlString;
+ if (!decoder->decode(urlString))
+ return false;
+ // FIXME: We can't assume that the url passed in here is valid.
+ parameters.url = KURL(ParsedURLString, urlString);
+
+ if (!decoder->decode(parameters.names))
+ return false;
+ if (!decoder->decode(parameters.values))
+ return false;
+ if (!decoder->decode(parameters.mimeType))
+ return false;
+ if (!decoder->decode(parameters.loadManually))
+ return false;
+
+ if (parameters.names.size() != parameters.values.size()) {
+ decoder->markInvalid();
+ return false;
+ }
+
+ return true;
+}
+
+Plugin::Plugin()
+{
+}
+
+Plugin::~Plugin()
+{
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/Plugin.h b/Source/WebKit2/WebProcess/Plugins/Plugin.h
new file mode 100644
index 0000000..6f20159
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/Plugin.h
@@ -0,0 +1,174 @@
+/*
+ * 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 Plugin_h
+#define Plugin_h
+
+#include <WebCore/GraphicsLayer.h>
+#include <WebCore/KURL.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+struct NPObject;
+
+namespace CoreIPC {
+ class ArgumentEncoder;
+ class ArgumentDecoder;
+}
+
+namespace WebCore {
+ class GraphicsContext;
+ class IntRect;
+}
+
+namespace WebKit {
+
+class WebKeyboardEvent;
+class WebMouseEvent;
+class WebWheelEvent;
+
+class PluginController;
+
+class Plugin : public RefCounted<Plugin> {
+public:
+ struct Parameters {
+ WebCore::KURL url;
+ Vector<String> names;
+ Vector<String> values;
+ String mimeType;
+ bool loadManually;
+
+ void encode(CoreIPC::ArgumentEncoder*) const;
+ static bool decode(CoreIPC::ArgumentDecoder*, Parameters&);
+ };
+
+ virtual ~Plugin();
+
+ // Initializes the plug-in. If the plug-in fails to initialize this should return false.
+ virtual bool initialize(PluginController*, const Parameters&) = 0;
+
+ // Destroys the plug-in.
+ virtual void destroy() = 0;
+
+ // Tells the plug-in to paint itself into the given graphics context. The passed-in context and
+ // dirty rect are in window coordinates. The context is saved/restored by the caller.
+ virtual void paint(WebCore::GraphicsContext*, const WebCore::IntRect& dirtyRect) = 0;
+
+#if PLATFORM(MAC)
+ // If a plug-in is using the Core Animation drawing model, this returns its plug-in layer.
+ virtual PlatformLayer* pluginLayer() = 0;
+#endif
+
+ // Tells the plug-in that either the plug-ins frame rect or its clip rect has changed. Both rects are in window coordinates.
+ virtual void geometryDidChange(const WebCore::IntRect& frameRect, const WebCore::IntRect& clipRect) = 0;
+
+ // Tells the plug-in that a frame load request that the plug-in made by calling PluginController::loadURL has finished.
+ virtual void frameDidFinishLoading(uint64_t requestID) = 0;
+
+ // Tells the plug-in that a frame load request that the plug-in made by calling PluginController::loadURL has failed.
+ virtual void frameDidFail(uint64_t requestID, bool wasCancelled) = 0;
+
+ // Tells the plug-in that a request to evaluate JavaScript (using PluginController::loadURL) has been fulfilled and passes
+ // back the result. If evaluating the script failed, result will be null.
+ virtual void didEvaluateJavaScript(uint64_t requestID, const String& requestURLString, const String& result) = 0;
+
+ // Tells the plug-in that a stream has received its HTTP response.
+ virtual void streamDidReceiveResponse(uint64_t streamID, const WebCore::KURL& responseURL, uint32_t streamLength,
+ uint32_t lastModifiedTime, const String& mimeType, const String& headers) = 0;
+
+ // Tells the plug-in that a stream did receive data.
+ virtual void streamDidReceiveData(uint64_t streamID, const char* bytes, int length) = 0;
+
+ // Tells the plug-in that a stream has finished loading.
+ virtual void streamDidFinishLoading(uint64_t streamID) = 0;
+
+ // Tells the plug-in that a stream has failed to load, either because of network errors or because the load was cancelled.
+ virtual void streamDidFail(uint64_t streamID, bool wasCancelled) = 0;
+
+ // Tells the plug-in that the manual stream has received its HTTP response.
+ virtual void manualStreamDidReceiveResponse(const WebCore::KURL& responseURL, uint32_t streamLength,
+ uint32_t lastModifiedTime, const String& mimeType, const String& headers) = 0;
+
+ // Tells the plug-in that the manual stream did receive data.
+ virtual void manualStreamDidReceiveData(const char* bytes, int length) = 0;
+
+ // Tells the plug-in that a stream has finished loading.
+ virtual void manualStreamDidFinishLoading() = 0;
+
+ // Tells the plug-in that a stream has failed to load, either because of network errors or because the load was cancelled.
+ virtual void manualStreamDidFail(bool wasCancelled) = 0;
+
+ // Tells the plug-in to handle the passed in mouse event. The plug-in should return true if it processed the event.
+ virtual bool handleMouseEvent(const WebMouseEvent&) = 0;
+
+ // Tells the plug-in to handle the passed in wheel event. The plug-in should return true if it processed the event.
+ virtual bool handleWheelEvent(const WebWheelEvent&) = 0;
+
+ // Tells the plug-in to handle the passed in mouse over event. The plug-in should return true if it processed the event.
+ virtual bool handleMouseEnterEvent(const WebMouseEvent&) = 0;
+
+ // Tells the plug-in to handle the passed in mouse leave event. The plug-in should return true if it processed the event.
+ virtual bool handleMouseLeaveEvent(const WebMouseEvent&) = 0;
+
+ // Tells the plug-in to handle the passed in keyboard event. The plug-in should return true if it processed the event.
+ virtual bool handleKeyboardEvent(const WebKeyboardEvent&) = 0;
+
+ // Tells the plug-in about focus changes.
+ virtual void setFocus(bool) = 0;
+
+ // Get the NPObject that corresponds to the plug-in's scriptable object. Returns a retained object.
+ virtual NPObject* pluginScriptableNPObject() = 0;
+
+#if PLATFORM(MAC)
+ // Tells the plug-in about window focus changes.
+ virtual void windowFocusChanged(bool) = 0;
+
+ // Tells the plug-in about window and plug-in frame changes.
+ virtual void windowAndViewFramesChanged(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates) = 0;
+
+ // Tells the plug-in about window visibility changes.
+ virtual void windowVisibilityChanged(bool) = 0;
+
+ // Get the per complex text input identifier.
+ virtual uint64_t pluginComplexTextInputIdentifier() const = 0;
+
+ // Send the complex text input to the plug-in.
+ virtual void sendComplexTextInput(const String& textInput) = 0;
+#endif
+
+ // Called when the private browsing state for this plug-in changes.
+ virtual void privateBrowsingStateChanged(bool) = 0;
+
+ // Returns the plug-in controller for this plug-in.
+ // FIXME: We could just have the controller be a member variable of Plugin.
+ virtual PluginController* controller() = 0;
+
+protected:
+ Plugin();
+};
+
+} // namespace WebKit
+
+#endif // Plugin_h
diff --git a/Source/WebKit2/WebProcess/Plugins/PluginController.h b/Source/WebKit2/WebProcess/Plugins/PluginController.h
new file mode 100644
index 0000000..06cf2d7
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/PluginController.h
@@ -0,0 +1,114 @@
+/*
+ * 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 PluginController_h
+#define PluginController_h
+
+#include <wtf/Forward.h>
+
+struct NPObject;
+typedef struct _NPVariant NPVariant;
+
+namespace WebCore {
+ class HTTPHeaderMap;
+ class IntRect;
+ class KURL;
+}
+
+namespace WebKit {
+
+class PluginController {
+public:
+ // Tells the controller that the plug-in wants the given rect to be repainted. The rect is in the plug-in's coordinate system.
+ virtual void invalidate(const WebCore::IntRect&) = 0;
+
+ // Returns the user agent string.
+ virtual String userAgent() = 0;
+
+ // Loads the given URL and associates it with the request ID.
+ //
+ // If a target is specified, then the URL will be loaded in the window or frame that the target refers to.
+ // Once the URL finishes loading, Plugin::frameDidFinishLoading will be called with the given requestID. If the URL
+ // fails to load, Plugin::frameDidFailToLoad will be called.
+ //
+ // If the URL is a JavaScript URL, the JavaScript code will be evaluated and the result sent back using Plugin::didEvaluateJavaScript.
+ virtual void loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target,
+ const WebCore::HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups) = 0;
+
+ /// Cancels the load of a stream that was requested by loadURL.
+ virtual void cancelStreamLoad(uint64_t streamID) = 0;
+
+ // Cancels the load of the manual stream.
+ virtual void cancelManualStreamLoad() = 0;
+
+ // Get the NPObject that corresponds to the window JavaScript object. Returns a retained object.
+ virtual NPObject* windowScriptNPObject() = 0;
+
+ // Get the NPObject that corresponds to the plug-in's element. Returns a retained object.
+ virtual NPObject* pluginElementNPObject() = 0;
+
+ // Evaluates the given script string in the context of the given NPObject.
+ virtual bool evaluate(NPObject*, const String& scriptString, NPVariant* result, bool allowPopups) = 0;
+
+ // Set the statusbar text.
+ virtual void setStatusbarText(const String&) = 0;
+
+#if USE(ACCELERATED_COMPOSITING)
+ // Return whether accelerated compositing is enabled.
+ virtual bool isAcceleratedCompositingEnabled() = 0;
+#endif
+
+ // Tells the controller that the plug-in process has crashed.
+ virtual void pluginProcessCrashed() = 0;
+
+#if PLATFORM(WIN)
+ // The window to use as the parent of the plugin's window.
+ virtual HWND nativeParentWindow() = 0;
+#endif
+
+#if PLATFORM(MAC)
+ // Tells the controller that complex text input be enabled or disabled for the plug-in.
+ virtual void setComplexTextInputEnabled(bool) = 0;
+#endif
+
+ // Returns the proxies for the given URL or null on failure.
+ virtual String proxiesForURL(const String&) = 0;
+
+ // Returns the cookies for the given URL or null on failure.
+ virtual String cookiesForURL(const String&) = 0;
+
+ // Sets the cookies for the given URL.
+ virtual void setCookiesForURL(const String& urlString, const String& cookieString) = 0;
+
+ // Returns whether private browsing is enabled.
+ virtual bool isPrivateBrowsingEnabled() = 0;
+
+protected:
+ virtual ~PluginController() { }
+};
+
+} // namespace WebKit
+
+#endif // PluginController_h
diff --git a/Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.cpp b/Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.cpp
new file mode 100644
index 0000000..7c09e56
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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 "PluginProcessConnection.h"
+
+#include "NPRemoteObjectMap.h"
+#include "PluginProcessConnectionManager.h"
+#include "PluginProxy.h"
+#include "WebProcess.h"
+
+namespace WebKit {
+
+PluginProcessConnection::PluginProcessConnection(PluginProcessConnectionManager* pluginProcessConnectionManager, const String& pluginPath, CoreIPC::Connection::Identifier connectionIdentifier)
+ : m_pluginProcessConnectionManager(pluginProcessConnectionManager)
+ , m_pluginPath(pluginPath)
+{
+ m_connection = CoreIPC::Connection::createClientConnection(connectionIdentifier, this, WebProcess::shared().runLoop());
+ m_npRemoteObjectMap = NPRemoteObjectMap::create(m_connection.get());
+
+ m_connection->open();
+}
+
+PluginProcessConnection::~PluginProcessConnection()
+{
+ ASSERT(!m_connection);
+ ASSERT(!m_npRemoteObjectMap);
+}
+
+void PluginProcessConnection::addPluginProxy(PluginProxy* plugin)
+{
+ ASSERT(!m_plugins.contains(plugin->pluginInstanceID()));
+ m_plugins.set(plugin->pluginInstanceID(), plugin);
+}
+
+void PluginProcessConnection::removePluginProxy(PluginProxy* plugin)
+{
+ ASSERT(m_plugins.contains(plugin->pluginInstanceID()));
+ m_plugins.remove(plugin->pluginInstanceID());
+
+ if (!m_plugins.isEmpty())
+ return;
+
+ // Invalidate our remote object map.
+ m_npRemoteObjectMap->invalidate();
+ m_npRemoteObjectMap = 0;
+
+ // We have no more plug-ins, invalidate the connection to the plug-in process.
+ ASSERT(m_connection);
+ m_connection->invalidate();
+ m_connection = nullptr;
+
+ // This will cause us to be deleted.
+ m_pluginProcessConnectionManager->removePluginProcessConnection(this);
+}
+
+void PluginProcessConnection::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
+{
+ if (arguments->destinationID()) {
+ if (PluginProxy* pluginProxy = m_plugins.get(arguments->destinationID()))
+ pluginProxy->didReceivePluginProxyMessage(connection, messageID, arguments);
+ return;
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
+CoreIPC::SyncReplyMode PluginProcessConnection::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply)
+{
+ if (messageID.is<CoreIPC::MessageClassNPObjectMessageReceiver>())
+ return m_npRemoteObjectMap->didReceiveSyncMessage(connection, messageID, arguments, reply);
+
+ if (PluginProxy* pluginProxy = m_plugins.get(arguments->destinationID()))
+ return pluginProxy->didReceiveSyncPluginProxyMessage(connection, messageID, arguments, reply);
+
+ ASSERT_NOT_REACHED();
+ return CoreIPC::AutomaticReply;
+}
+
+void PluginProcessConnection::didClose(CoreIPC::Connection*)
+{
+ // The plug-in process must have crashed.
+ for (HashMap<uint64_t, PluginProxy*>::const_iterator::Values it = m_plugins.begin().values(), end = m_plugins.end().values(); it != end; ++it) {
+ PluginProxy* pluginProxy = (*it);
+
+ pluginProxy->pluginProcessCrashed();
+ }
+}
+
+void PluginProcessConnection::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID)
+{
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(PLUGIN_PROCESS)
diff --git a/Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.h b/Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.h
new file mode 100644
index 0000000..76e2315
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.h
@@ -0,0 +1,86 @@
+/*
+ * 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 PluginProcessConnection_h
+#define PluginProcessConnection_h
+
+#if ENABLE(PLUGIN_PROCESS)
+
+#include "Connection.h"
+#include "Plugin.h"
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+// A CoreIPC connection to a plug-in process.
+
+namespace WebKit {
+
+class NPRemoteObjectMap;
+class PluginProcessConnectionManager;
+class PluginProxy;
+
+class PluginProcessConnection : public RefCounted<PluginProcessConnection>, CoreIPC::Connection::Client {
+public:
+ static PassRefPtr<PluginProcessConnection> create(PluginProcessConnectionManager* pluginProcessConnectionManager, const String& pluginPath, CoreIPC::Connection::Identifier connectionIdentifier)
+ {
+ return adoptRef(new PluginProcessConnection(pluginProcessConnectionManager, pluginPath, connectionIdentifier));
+ }
+ ~PluginProcessConnection();
+
+ const String& pluginPath() const { return m_pluginPath; }
+
+ CoreIPC::Connection* connection() const { return m_connection.get(); }
+
+ void addPluginProxy(PluginProxy*);
+ void removePluginProxy(PluginProxy*);
+
+ NPRemoteObjectMap* npRemoteObjectMap() const { return m_npRemoteObjectMap.get(); }
+
+private:
+ PluginProcessConnection(PluginProcessConnectionManager* pluginProcessConnectionManager, const String& pluginPath, CoreIPC::Connection::Identifier connectionIdentifier);
+
+ // CoreIPC::Connection::Client
+ virtual void didReceiveMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*);
+ virtual CoreIPC::SyncReplyMode didReceiveSyncMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*, CoreIPC::ArgumentEncoder*);
+ virtual void didClose(CoreIPC::Connection*);
+ virtual void didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID);
+
+ PluginProcessConnectionManager* m_pluginProcessConnectionManager;
+ String m_pluginPath;
+
+ // The connection from the web process to the plug-in process.
+ RefPtr<CoreIPC::Connection> m_connection;
+
+ // The plug-ins. We use a weak reference to the plug-in proxies because the plug-in view holds the strong reference.
+ HashMap<uint64_t, PluginProxy*> m_plugins;
+
+ RefPtr<NPRemoteObjectMap> m_npRemoteObjectMap;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(PLUGIN_PROCESS)
+
+#endif // PluginProcessConnection_h
diff --git a/Source/WebKit2/WebProcess/Plugins/PluginProcessConnectionManager.cpp b/Source/WebKit2/WebProcess/Plugins/PluginProcessConnectionManager.cpp
new file mode 100644
index 0000000..99848ef
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/PluginProcessConnectionManager.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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 "PluginProcessConnectionManager.h"
+
+#include "ArgumentDecoder.h"
+#include "ArgumentEncoder.h"
+#include "MachPort.h"
+#include "PluginProcessConnection.h"
+#include "WebCoreArgumentCoders.h"
+#include "WebProcess.h"
+#include "WebProcessProxyMessageKinds.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebKit {
+
+PluginProcessConnectionManager& PluginProcessConnectionManager::shared()
+{
+ DEFINE_STATIC_LOCAL(PluginProcessConnectionManager, pluginProcessConnectionManager, ());
+ return pluginProcessConnectionManager;
+}
+
+PluginProcessConnectionManager::PluginProcessConnectionManager()
+{
+}
+
+PluginProcessConnectionManager::~PluginProcessConnectionManager()
+{
+}
+
+PluginProcessConnection* PluginProcessConnectionManager::getPluginProcessConnection(const String& pluginPath)
+{
+ for (size_t i = 0; i < m_pluginProcessConnections.size(); ++i) {
+ if (m_pluginProcessConnections[i]->pluginPath() == pluginPath)
+ return m_pluginProcessConnections[i].get();
+ }
+
+ CoreIPC::Connection::Identifier connectionIdentifier;
+ CoreIPC::MachPort connectionMachPort;
+ if (!WebProcess::shared().connection()->sendSync(WebProcessProxyLegacyMessage::GetPluginProcessConnection, 0, CoreIPC::In(pluginPath), CoreIPC::Out(connectionMachPort)))
+ return 0;
+
+ connectionIdentifier = connectionMachPort.port();
+ if (!connectionIdentifier)
+ return 0;
+
+ RefPtr<PluginProcessConnection> pluginProcessConnection = PluginProcessConnection::create(this, pluginPath, connectionIdentifier);
+ m_pluginProcessConnections.append(pluginProcessConnection);
+
+ return pluginProcessConnection.get();
+}
+
+void PluginProcessConnectionManager::removePluginProcessConnection(PluginProcessConnection* pluginProcessConnection)
+{
+ size_t vectorIndex = m_pluginProcessConnections.find(pluginProcessConnection);
+ ASSERT(vectorIndex != notFound);
+
+ m_pluginProcessConnections.remove(vectorIndex);
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(PLUGIN_PROCESS)
diff --git a/Source/WebKit2/WebProcess/Plugins/PluginProcessConnectionManager.h b/Source/WebKit2/WebProcess/Plugins/PluginProcessConnectionManager.h
new file mode 100644
index 0000000..d7ba853
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/PluginProcessConnectionManager.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 PluginProcessConnectionManager_h
+#define PluginProcessConnectionManager_h
+
+#if ENABLE(PLUGIN_PROCESS)
+
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+// Manages plug-in process connections for the given web process.
+
+namespace WebKit {
+
+class PluginProcessConnection;
+
+class PluginProcessConnectionManager : Noncopyable {
+public:
+ static PluginProcessConnectionManager& shared();
+
+ PluginProcessConnection* getPluginProcessConnection(const String& pluginPath);
+ void removePluginProcessConnection(PluginProcessConnection*);
+
+private:
+ PluginProcessConnectionManager();
+ ~PluginProcessConnectionManager();
+
+ Vector<RefPtr<PluginProcessConnection> > m_pluginProcessConnections;
+};
+
+}
+
+#endif // ENABLE(PLUGIN_PROCESS)
+
+#endif // PluginProcessConnectionManager_h
diff --git a/Source/WebKit2/WebProcess/Plugins/PluginProxy.cpp b/Source/WebKit2/WebProcess/Plugins/PluginProxy.cpp
new file mode 100644
index 0000000..f029cbf
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/PluginProxy.cpp
@@ -0,0 +1,458 @@
+/*
+ * 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 "DataReference.h"
+#include "NPRemoteObjectMap.h"
+#include "NPRuntimeUtilities.h"
+#include "NPVariantData.h"
+#include "PluginController.h"
+#include "PluginControllerProxyMessages.h"
+#include "PluginProcessConnection.h"
+#include "PluginProcessConnectionManager.h"
+#include "ShareableBitmap.h"
+#include "WebCoreArgumentCoders.h"
+#include "WebEvent.h"
+#include "WebProcessConnectionMessages.h"
+#include <WebCore/GraphicsContext.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+static uint64_t generatePluginInstanceID()
+{
+ static uint64_t uniquePluginInstanceID;
+ return ++uniquePluginInstanceID;
+}
+
+PassRefPtr<PluginProxy> PluginProxy::create(const String& pluginPath)
+{
+ return adoptRef(new PluginProxy(pluginPath));
+}
+
+PluginProxy::PluginProxy(const String& pluginPath)
+ : m_pluginPath(pluginPath)
+ , m_pluginInstanceID(generatePluginInstanceID())
+ , m_pluginController(0)
+ , m_pluginBackingStoreContainsValidData(false)
+ , m_isStarted(false)
+ , m_waitingForPaintInResponseToUpdate(false)
+ , m_remoteLayerClientID(0)
+{
+}
+
+PluginProxy::~PluginProxy()
+{
+}
+
+void PluginProxy::pluginProcessCrashed()
+{
+ if (m_pluginController)
+ m_pluginController->pluginProcessCrashed();
+}
+
+bool PluginProxy::initialize(PluginController* pluginController, const Parameters& parameters)
+{
+ ASSERT(!m_pluginController);
+ ASSERT(pluginController);
+
+ m_pluginController = pluginController;
+
+ ASSERT(!m_connection);
+ m_connection = PluginProcessConnectionManager::shared().getPluginProcessConnection(m_pluginPath);
+
+ if (!m_connection)
+ return false;
+
+ // Add the plug-in proxy before creating the plug-in; it needs to be in the map because CreatePlugin
+ // can call back out to the plug-in proxy.
+ m_connection->addPluginProxy(this);
+
+ // Ask the plug-in process to create a plug-in.
+ bool result = false;
+
+ uint32_t remoteLayerClientID = 0;
+ if (!m_connection->connection()->sendSync(Messages::WebProcessConnection::CreatePlugin(m_pluginInstanceID, parameters, pluginController->userAgent(), pluginController->isPrivateBrowsingEnabled(), pluginController->isAcceleratedCompositingEnabled()), Messages::WebProcessConnection::CreatePlugin::Reply(result, remoteLayerClientID), 0) || !result) {
+ m_connection->removePluginProxy(this);
+ return false;
+ }
+
+ m_remoteLayerClientID = remoteLayerClientID;
+ m_isStarted = true;
+
+ return true;
+}
+
+void PluginProxy::destroy()
+{
+ ASSERT(m_isStarted);
+
+ m_connection->connection()->sendSync(Messages::WebProcessConnection::DestroyPlugin(m_pluginInstanceID), Messages::WebProcessConnection::DestroyPlugin::Reply(), 0);
+
+ m_isStarted = false;
+ m_connection->removePluginProxy(this);
+}
+
+void PluginProxy::paint(GraphicsContext* graphicsContext, const IntRect& dirtyRect)
+{
+ if (!needsBackingStore() || !m_backingStore)
+ return;
+
+ if (!m_pluginBackingStoreContainsValidData) {
+ m_connection->connection()->sendSync(Messages::PluginControllerProxy::PaintEntirePlugin(), Messages::PluginControllerProxy::PaintEntirePlugin::Reply(), m_pluginInstanceID);
+
+ // Blit the plug-in backing store into our own backing store.
+ OwnPtr<WebCore::GraphicsContext> graphicsContext = m_backingStore->createGraphicsContext();
+
+ m_pluginBackingStore->paint(*graphicsContext, IntPoint(), IntRect(0, 0, m_frameRect.width(), m_frameRect.height()));
+
+ m_pluginBackingStoreContainsValidData = true;
+ }
+
+ IntRect dirtyRectInPluginCoordinates = dirtyRect;
+ dirtyRectInPluginCoordinates.move(-m_frameRect.x(), -m_frameRect.y());
+
+ m_backingStore->paint(*graphicsContext, dirtyRect.location(), dirtyRectInPluginCoordinates);
+
+ if (m_waitingForPaintInResponseToUpdate) {
+ m_waitingForPaintInResponseToUpdate = false;
+ m_connection->connection()->send(Messages::PluginControllerProxy::DidUpdate(), m_pluginInstanceID);
+ return;
+ }
+}
+
+void PluginProxy::geometryDidChange(const IntRect& frameRect, const IntRect& clipRect)
+{
+ ASSERT(m_isStarted);
+
+ m_frameRect = frameRect;
+
+ if (!needsBackingStore()) {
+ SharedMemory::Handle pluginBackingStoreHandle;
+ m_connection->connection()->send(Messages::PluginControllerProxy::GeometryDidChange(frameRect, clipRect, pluginBackingStoreHandle), m_pluginInstanceID);
+ return;
+ }
+
+ bool didUpdateBackingStore = false;
+ if (!m_backingStore) {
+ m_backingStore = ShareableBitmap::create(frameRect.size());
+ didUpdateBackingStore = true;
+ } else if (frameRect.size() != m_backingStore->size()) {
+ // The backing store already exists, just resize it.
+ if (!m_backingStore->resize(frameRect.size()))
+ return;
+
+ didUpdateBackingStore = true;
+ }
+
+ SharedMemory::Handle pluginBackingStoreHandle;
+
+ if (didUpdateBackingStore) {
+ // Create a new plug-in backing store.
+ m_pluginBackingStore = ShareableBitmap::createShareable(frameRect.size());
+ if (!m_pluginBackingStore)
+ return;
+
+ // Create a handle to the plug-in backing store so we can send it over.
+ if (!m_pluginBackingStore->createHandle(pluginBackingStoreHandle)) {
+ m_pluginBackingStore.clear();
+ return;
+ }
+
+ m_pluginBackingStoreContainsValidData = false;
+ }
+
+ m_connection->connection()->send(Messages::PluginControllerProxy::GeometryDidChange(frameRect, clipRect, pluginBackingStoreHandle), m_pluginInstanceID);
+}
+
+void PluginProxy::frameDidFinishLoading(uint64_t requestID)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::FrameDidFinishLoading(requestID), m_pluginInstanceID);
+}
+
+void PluginProxy::frameDidFail(uint64_t requestID, bool wasCancelled)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::FrameDidFail(requestID, wasCancelled), m_pluginInstanceID);
+}
+
+void PluginProxy::didEvaluateJavaScript(uint64_t requestID, const WTF::String& requestURLString, const WTF::String& result)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::DidEvaluateJavaScript(requestID, requestURLString, result), m_pluginInstanceID);
+}
+
+void PluginProxy::streamDidReceiveResponse(uint64_t streamID, const KURL& responseURL, uint32_t streamLength, uint32_t lastModifiedTime, const WTF::String& mimeType, const WTF::String& headers)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidReceiveResponse(streamID, responseURL.string(), streamLength, lastModifiedTime, mimeType, headers), m_pluginInstanceID);
+}
+
+void PluginProxy::streamDidReceiveData(uint64_t streamID, const char* bytes, int length)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidReceiveData(streamID, CoreIPC::DataReference(reinterpret_cast<const uint8_t*>(bytes), length)), m_pluginInstanceID);
+}
+
+void PluginProxy::streamDidFinishLoading(uint64_t streamID)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidFinishLoading(streamID), m_pluginInstanceID);
+}
+
+void PluginProxy::streamDidFail(uint64_t streamID, bool wasCancelled)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidFail(streamID, wasCancelled), m_pluginInstanceID);
+}
+
+void PluginProxy::manualStreamDidReceiveResponse(const KURL& responseURL, uint32_t streamLength, uint32_t lastModifiedTime, const WTF::String& mimeType, const WTF::String& headers)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidReceiveResponse(responseURL.string(), streamLength, lastModifiedTime, mimeType, headers), m_pluginInstanceID);
+}
+
+void PluginProxy::manualStreamDidReceiveData(const char* bytes, int length)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidReceiveData(CoreIPC::DataReference(reinterpret_cast<const uint8_t*>(bytes), length)), m_pluginInstanceID);
+}
+
+void PluginProxy::manualStreamDidFinishLoading()
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidFinishLoading(), m_pluginInstanceID);
+}
+
+void PluginProxy::manualStreamDidFail(bool wasCancelled)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidFail(wasCancelled), m_pluginInstanceID);
+}
+
+bool PluginProxy::handleMouseEvent(const WebMouseEvent& mouseEvent)
+{
+ bool handled = false;
+ if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleMouseEvent(mouseEvent), Messages::PluginControllerProxy::HandleMouseEvent::Reply(handled), m_pluginInstanceID))
+ return false;
+
+ return handled;
+}
+
+bool PluginProxy::handleWheelEvent(const WebWheelEvent& wheelEvent)
+{
+ bool handled = false;
+ if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleWheelEvent(wheelEvent), Messages::PluginControllerProxy::HandleWheelEvent::Reply(handled), m_pluginInstanceID))
+ return false;
+
+ return handled;
+}
+
+bool PluginProxy::handleMouseEnterEvent(const WebMouseEvent& mouseEnterEvent)
+{
+ bool handled = false;
+ if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleMouseEnterEvent(mouseEnterEvent), Messages::PluginControllerProxy::HandleMouseEnterEvent::Reply(handled), m_pluginInstanceID))
+ return false;
+
+ return handled;
+}
+
+bool PluginProxy::handleMouseLeaveEvent(const WebMouseEvent& mouseLeaveEvent)
+{
+ bool handled = false;
+ if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleMouseLeaveEvent(mouseLeaveEvent), Messages::PluginControllerProxy::HandleMouseLeaveEvent::Reply(handled), m_pluginInstanceID))
+ return false;
+
+ return handled;
+}
+
+bool PluginProxy::handleKeyboardEvent(const WebKeyboardEvent& keyboardEvent)
+{
+ bool handled = false;
+ if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleKeyboardEvent(keyboardEvent), Messages::PluginControllerProxy::HandleKeyboardEvent::Reply(handled), m_pluginInstanceID))
+ return false;
+
+ return handled;
+}
+
+void PluginProxy::setFocus(bool hasFocus)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::SetFocus(hasFocus), m_pluginInstanceID);
+}
+
+NPObject* PluginProxy::pluginScriptableNPObject()
+{
+ uint64_t pluginScriptableNPObjectID = 0;
+
+ if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::GetPluginScriptableNPObject(), Messages::PluginControllerProxy::GetPluginScriptableNPObject::Reply(pluginScriptableNPObjectID), m_pluginInstanceID))
+ return 0;
+
+ if (!pluginScriptableNPObjectID)
+ return 0;
+
+ return m_connection->npRemoteObjectMap()->createNPObjectProxy(pluginScriptableNPObjectID);
+}
+
+#if PLATFORM(MAC)
+void PluginProxy::windowFocusChanged(bool hasFocus)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::WindowFocusChanged(hasFocus), m_pluginInstanceID);
+}
+
+void PluginProxy::windowAndViewFramesChanged(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::WindowAndViewFramesChanged(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates), m_pluginInstanceID);
+}
+
+void PluginProxy::windowVisibilityChanged(bool isVisible)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::WindowVisibilityChanged(isVisible), m_pluginInstanceID);
+}
+
+uint64_t PluginProxy::pluginComplexTextInputIdentifier() const
+{
+ return m_pluginInstanceID;
+}
+
+void PluginProxy::sendComplexTextInput(const String& textInput)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::SendComplexTextInput(textInput), m_pluginInstanceID);
+}
+
+#endif
+
+void PluginProxy::privateBrowsingStateChanged(bool isPrivateBrowsingEnabled)
+{
+ m_connection->connection()->send(Messages::PluginControllerProxy::PrivateBrowsingStateChanged(isPrivateBrowsingEnabled), m_pluginInstanceID);
+}
+
+PluginController* PluginProxy::controller()
+{
+ return m_pluginController;
+}
+
+void PluginProxy::loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target, const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups)
+{
+ m_pluginController->loadURL(requestID, method, urlString, target, headerFields, httpBody, allowPopups);
+}
+
+void PluginProxy::proxiesForURL(const String& urlString, String& proxyString)
+{
+ proxyString = m_pluginController->proxiesForURL(urlString);
+}
+
+void PluginProxy::cookiesForURL(const String& urlString, String& cookieString)
+{
+ cookieString = m_pluginController->cookiesForURL(urlString);
+}
+
+void PluginProxy::setCookiesForURL(const String& urlString, const String& cookieString)
+{
+ m_pluginController->setCookiesForURL(urlString, cookieString);
+}
+
+void PluginProxy::getWindowScriptNPObject(uint64_t& windowScriptNPObjectID)
+{
+ NPObject* windowScriptNPObject = m_pluginController->windowScriptNPObject();
+ if (!windowScriptNPObject) {
+ windowScriptNPObjectID = 0;
+ return;
+ }
+
+ windowScriptNPObjectID = m_connection->npRemoteObjectMap()->registerNPObject(windowScriptNPObject);
+ releaseNPObject(windowScriptNPObject);
+}
+
+void PluginProxy::getPluginElementNPObject(uint64_t& pluginElementNPObjectID)
+{
+ NPObject* pluginElementNPObject = m_pluginController->pluginElementNPObject();
+ if (!pluginElementNPObject) {
+ pluginElementNPObjectID = 0;
+ return;
+ }
+
+ pluginElementNPObjectID = m_connection->npRemoteObjectMap()->registerNPObject(pluginElementNPObject);
+ releaseNPObject(pluginElementNPObject);
+}
+
+void PluginProxy::evaluate(const NPVariantData& npObjectAsVariantData, const String& scriptString, bool allowPopups, bool& returnValue, NPVariantData& resultData)
+{
+ NPVariant npObjectAsVariant = m_connection->npRemoteObjectMap()->npVariantDataToNPVariant(npObjectAsVariantData);
+ ASSERT(NPVARIANT_IS_OBJECT(npObjectAsVariant));
+
+ NPVariant result;
+ returnValue = m_pluginController->evaluate(NPVARIANT_TO_OBJECT(npObjectAsVariant), scriptString, &result, allowPopups);
+ if (!returnValue)
+ return;
+
+ // Convert the NPVariant to an NPVariantData.
+ resultData = m_connection->npRemoteObjectMap()->npVariantToNPVariantData(result);
+
+ // And release the result.
+ releaseNPVariantValue(&result);
+
+ releaseNPVariantValue(&npObjectAsVariant);
+}
+
+void PluginProxy::cancelStreamLoad(uint64_t streamID)
+{
+ m_pluginController->cancelStreamLoad(streamID);
+}
+
+void PluginProxy::cancelManualStreamLoad()
+{
+ m_pluginController->cancelManualStreamLoad();
+}
+
+void PluginProxy::setStatusbarText(const String& statusbarText)
+{
+ m_pluginController->setStatusbarText(statusbarText);
+}
+
+#if PLATFORM(MAC)
+void PluginProxy::setComplexTextInputEnabled(bool complexTextInputEnabled)
+{
+ m_pluginController->setComplexTextInputEnabled(complexTextInputEnabled);
+}
+#endif
+
+void PluginProxy::update(const IntRect& paintedRect)
+{
+ if (paintedRect == m_frameRect)
+ m_pluginBackingStoreContainsValidData = true;
+
+ IntRect paintedRectPluginCoordinates = paintedRect;
+ paintedRectPluginCoordinates.move(-m_frameRect.x(), -m_frameRect.y());
+
+ if (m_backingStore) {
+ // Blit the plug-in backing store into our own backing store.
+ OwnPtr<GraphicsContext> graphicsContext = m_backingStore->createGraphicsContext();
+
+ m_pluginBackingStore->paint(*graphicsContext, paintedRectPluginCoordinates.location(),
+ paintedRectPluginCoordinates);
+ }
+
+ // Ask the controller to invalidate the rect for us.
+ m_waitingForPaintInResponseToUpdate = true;
+ m_pluginController->invalidate(paintedRectPluginCoordinates);
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(PLUGIN_PROCESS)
diff --git a/Source/WebKit2/WebProcess/Plugins/PluginProxy.h b/Source/WebKit2/WebProcess/Plugins/PluginProxy.h
new file mode 100644
index 0000000..2c3b052
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/PluginProxy.h
@@ -0,0 +1,161 @@
+/*
+ * 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 PluginProxy_h
+#define PluginProxy_h
+
+#if ENABLE(PLUGIN_PROCESS)
+
+#include "Connection.h"
+#include "Plugin.h"
+
+#if PLATFORM(MAC)
+#include <wtf/RetainPtr.h>
+#ifdef __OBJC__
+@class CALayer;
+#else
+class CALayer;
+#endif
+#endif
+
+namespace WebCore {
+ class HTTPHeaderMap;
+}
+
+namespace WebKit {
+
+class ShareableBitmap;
+class NPVariantData;
+class PluginProcessConnection;
+
+class PluginProxy : public Plugin {
+public:
+ static PassRefPtr<PluginProxy> create(const String& pluginPath);
+ ~PluginProxy();
+
+ uint64_t pluginInstanceID() const { return m_pluginInstanceID; }
+ void pluginProcessCrashed();
+
+ void didReceivePluginProxyMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments);
+ CoreIPC::SyncReplyMode didReceiveSyncPluginProxyMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*, CoreIPC::ArgumentEncoder*);
+
+private:
+ explicit PluginProxy(const String& pluginPath);
+
+ // 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 WTF::String& requestURLString, const WTF::String& result);
+ virtual void streamDidReceiveResponse(uint64_t streamID, const WebCore::KURL& responseURL, uint32_t streamLength, uint32_t lastModifiedTime, const WTF::String& mimeType, const WTF::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 WTF::String& mimeType, const WTF::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();
+
+ bool needsBackingStore() const;
+
+ // Message handlers.
+ void loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target, const WebCore::HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups);
+ void update(const WebCore::IntRect& paintedRect);
+ void proxiesForURL(const String& urlString, String& proxyString);
+ void cookiesForURL(const String& urlString, String& cookieString);
+ void setCookiesForURL(const String& urlString, const String& cookieString);
+ void getWindowScriptNPObject(uint64_t& windowScriptNPObjectID);
+ void getPluginElementNPObject(uint64_t& pluginElementNPObjectID);
+ void evaluate(const NPVariantData& npObjectAsVariantData, const String& scriptString, bool allowPopups, bool& returnValue, NPVariantData& resultData);
+ void cancelStreamLoad(uint64_t streamID);
+ void cancelManualStreamLoad();
+ void setStatusbarText(const String& statusbarText);
+#if PLATFORM(MAC)
+ void setComplexTextInputEnabled(bool);
+#endif
+
+ String m_pluginPath;
+
+ RefPtr<PluginProcessConnection> m_connection;
+ uint64_t m_pluginInstanceID;
+
+ PluginController* m_pluginController;
+
+ // The plug-in rect in window coordinates.
+ WebCore::IntRect m_frameRect;
+
+ // This is the backing store that we paint when we're told to paint.
+ RefPtr<ShareableBitmap> m_backingStore;
+
+ // This is the shared memory backing store that the plug-in paints into. When the plug-in tells us
+ // that it's painted something in it, we'll blit from it to our own backing store.
+ RefPtr<ShareableBitmap> m_pluginBackingStore;
+
+ // Whether all of the plug-in backing store contains valid data.
+ bool m_pluginBackingStoreContainsValidData;
+
+ bool m_isStarted;
+
+ // Whether we're called invalidate in response to an update call, and are now waiting for a paint call.
+ bool m_waitingForPaintInResponseToUpdate;
+
+ // The client ID for the CA layer in the plug-in process. Will be 0 if the plug-in is not a CA plug-in.
+ uint32_t m_remoteLayerClientID;
+
+#if PLATFORM(MAC)
+ RetainPtr<CALayer> m_pluginLayer;
+#endif
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(PLUGIN_PROCESS)
+
+#endif // PluginProxy_h
diff --git a/Source/WebKit2/WebProcess/Plugins/PluginProxy.messages.in b/Source/WebKit2/WebProcess/Plugins/PluginProxy.messages.in
new file mode 100644
index 0000000..81761ee
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/PluginProxy.messages.in
@@ -0,0 +1,65 @@
+# 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)
+
+messages -> PluginProxy {
+ # Asks the web process to load a URL.
+ LoadURL(uint64_t requestID, WTF::String method, WTF::String urlString, WTF::String target, WebCore::HTTPHeaderMap headerFields, Vector<uint8_t> httpBody, bool allowPopups);
+
+ # Called when the plug-in has painted into its backing store.
+ Update(WebCore::IntRect paintedRect)
+
+ # Returns a PAC style string with proxies for the given URL.
+ ProxiesForURL(WTF::String urlString) -> (WTF::String proxiesString)
+
+ # Returns the cookies for the given URL.
+ CookiesForURL(WTF::String urlString) -> (WTF::String cookieString)
+
+ # Sets the cookies for the given URL.
+ SetCookiesForURL(WTF::String urlString, WTF::String cookieString)
+
+ # Gets a reference to the window NPObject.
+ GetWindowScriptNPObject() -> (uint64_t windowScriptNPObjectID)
+
+ # Gets a reference to the plug-in element NPObject.
+ GetPluginElementNPObject() -> (uint64_t pluginElementNPObjectID)
+
+ # Evaluates the given JavaScript string.
+ Evaluate(WebKit::NPVariantData npObjectAsVariantData, WTF::String scriptString, bool allowPopups) -> (bool returnValue, WebKit::NPVariantData resultData)
+
+ # Cancels the given stream load.
+ CancelStreamLoad(uint64_t streamID)
+
+ # Cancel the manual stream load.
+ CancelManualStreamLoad()
+
+ # Set the status bar text.
+ SetStatusbarText(WTF::String statusbarText)
+
+#if PLATFORM(MAC)
+ # Change whether complext text input is enabled for this plug-in.
+ SetComplexTextInputEnabled(bool complexTextInputEnabled)
+#endif
+}
+
+#endif
diff --git a/Source/WebKit2/WebProcess/Plugins/PluginView.cpp b/Source/WebKit2/WebProcess/Plugins/PluginView.cpp
new file mode 100644
index 0000000..00271c1
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/PluginView.cpp
@@ -0,0 +1,1013 @@
+/*
+ * 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 "PluginView.h"
+
+#include "NPRuntimeUtilities.h"
+#include "Plugin.h"
+#include "WebEvent.h"
+#include "WebPage.h"
+#include "WebPageProxyMessages.h"
+#include <WebCore/Chrome.h>
+#include <WebCore/CookieJar.h>
+#include <WebCore/DocumentLoader.h>
+#include <WebCore/Event.h>
+#include <WebCore/FocusController.h>
+#include <WebCore/FrameLoadRequest.h>
+#include <WebCore/FrameLoaderClient.h>
+#include <WebCore/FrameView.h>
+#include <WebCore/GraphicsContext.h>
+#include <WebCore/HTMLPlugInElement.h>
+#include <WebCore/HostWindow.h>
+#include <WebCore/NetscapePlugInStreamLoader.h>
+#include <WebCore/NetworkingContext.h>
+#include <WebCore/ProxyServer.h>
+#include <WebCore/RenderEmbeddedObject.h>
+#include <WebCore/RenderLayer.h>
+#include <WebCore/ResourceLoadScheduler.h>
+#include <WebCore/ScrollView.h>
+#include <WebCore/Settings.h>
+
+using namespace JSC;
+using namespace WebCore;
+
+namespace WebKit {
+
+class PluginView::URLRequest : public RefCounted<URLRequest> {
+public:
+ static PassRefPtr<PluginView::URLRequest> create(uint64_t requestID, const FrameLoadRequest& request, bool allowPopups)
+ {
+ return adoptRef(new URLRequest(requestID, request, allowPopups));
+ }
+
+ uint64_t requestID() const { return m_requestID; }
+ const String& target() const { return m_request.frameName(); }
+ const ResourceRequest & request() const { return m_request.resourceRequest(); }
+ bool allowPopups() const { return m_allowPopups; }
+
+private:
+ URLRequest(uint64_t requestID, const FrameLoadRequest& request, bool allowPopups)
+ : m_requestID(requestID)
+ , m_request(request)
+ , m_allowPopups(allowPopups)
+ {
+ }
+
+ uint64_t m_requestID;
+ FrameLoadRequest m_request;
+ bool m_allowPopups;
+};
+
+class PluginView::Stream : public RefCounted<PluginView::Stream>, NetscapePlugInStreamLoaderClient {
+public:
+ static PassRefPtr<Stream> create(PluginView* pluginView, uint64_t streamID, const ResourceRequest& request)
+ {
+ return adoptRef(new Stream(pluginView, streamID, request));
+ }
+ ~Stream();
+
+ void start();
+ void cancel();
+
+ uint64_t streamID() const { return m_streamID; }
+
+private:
+ Stream(PluginView* pluginView, uint64_t streamID, const ResourceRequest& request)
+ : m_pluginView(pluginView)
+ , m_streamID(streamID)
+ , m_request(request)
+ , m_streamWasCancelled(false)
+ {
+ }
+
+ // NetscapePluginStreamLoaderClient
+ virtual void didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse&);
+ virtual void didReceiveData(NetscapePlugInStreamLoader*, const char*, int);
+ virtual void didFail(NetscapePlugInStreamLoader*, const ResourceError&);
+ virtual void didFinishLoading(NetscapePlugInStreamLoader*);
+
+ PluginView* m_pluginView;
+ uint64_t m_streamID;
+ const ResourceRequest m_request;
+
+ // True if the stream was explicitly cancelled by calling cancel().
+ // (As opposed to being cancelled by the user hitting the stop button for example.
+ bool m_streamWasCancelled;
+
+ RefPtr<NetscapePlugInStreamLoader> m_loader;
+};
+
+PluginView::Stream::~Stream()
+{
+ ASSERT(!m_pluginView);
+}
+
+void PluginView::Stream::start()
+{
+ ASSERT(!m_loader);
+
+ Frame* frame = m_pluginView->m_pluginElement->document()->frame();
+ ASSERT(frame);
+
+ m_loader = resourceLoadScheduler()->schedulePluginStreamLoad(frame, this, m_request);
+}
+
+void PluginView::Stream::cancel()
+{
+ ASSERT(m_loader);
+
+ m_streamWasCancelled = true;
+ m_loader->cancel(m_loader->cancelledError());
+ m_loader = 0;
+}
+
+static String buildHTTPHeaders(const ResourceResponse& response, long long& expectedContentLength)
+{
+ if (!response.isHTTP())
+ return String();
+
+ Vector<UChar> stringBuilder;
+ String separator(": ");
+
+ String statusLine = String::format("HTTP %d ", response.httpStatusCode());
+ stringBuilder.append(statusLine.characters(), statusLine.length());
+ stringBuilder.append(response.httpStatusText().characters(), response.httpStatusText().length());
+ stringBuilder.append('\n');
+
+ HTTPHeaderMap::const_iterator end = response.httpHeaderFields().end();
+ for (HTTPHeaderMap::const_iterator it = response.httpHeaderFields().begin(); it != end; ++it) {
+ stringBuilder.append(it->first.characters(), it->first.length());
+ stringBuilder.append(separator.characters(), separator.length());
+ stringBuilder.append(it->second.characters(), it->second.length());
+ stringBuilder.append('\n');
+ }
+
+ String headers = String::adopt(stringBuilder);
+
+ // If the content is encoded (most likely compressed), then don't send its length to the plugin,
+ // which is only interested in the decoded length, not yet known at the moment.
+ // <rdar://problem/4470599> tracks a request for -[NSURLResponse expectedContentLength] to incorporate this logic.
+ String contentEncoding = response.httpHeaderField("Content-Encoding");
+ if (!contentEncoding.isNull() && contentEncoding != "identity")
+ expectedContentLength = -1;
+
+ return headers;
+}
+
+void PluginView::Stream::didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse& response)
+{
+ // Compute the stream related data from the resource response.
+ const KURL& responseURL = response.url();
+ const String& mimeType = response.mimeType();
+ long long expectedContentLength = response.expectedContentLength();
+
+ String headers = buildHTTPHeaders(response, expectedContentLength);
+
+ uint32_t streamLength = 0;
+ if (expectedContentLength > 0)
+ streamLength = expectedContentLength;
+
+ m_pluginView->m_plugin->streamDidReceiveResponse(m_streamID, responseURL, streamLength, response.lastModifiedDate(), mimeType, headers);
+}
+
+void PluginView::Stream::didReceiveData(NetscapePlugInStreamLoader*, const char* bytes, int length)
+{
+ m_pluginView->m_plugin->streamDidReceiveData(m_streamID, bytes, length);
+}
+
+void PluginView::Stream::didFail(NetscapePlugInStreamLoader*, const ResourceError& error)
+{
+ // Calling streamDidFail could cause us to be deleted, so we hold on to a reference here.
+ RefPtr<Stream> protect(this);
+
+ // We only want to call streamDidFail if the stream was not explicitly cancelled by the plug-in.
+ if (!m_streamWasCancelled)
+ m_pluginView->m_plugin->streamDidFail(m_streamID, error.isCancellation());
+
+ m_pluginView->removeStream(this);
+ m_pluginView = 0;
+}
+
+void PluginView::Stream::didFinishLoading(NetscapePlugInStreamLoader*)
+{
+ // Calling streamDidFinishLoading could cause us to be deleted, so we hold on to a reference here.
+ RefPtr<Stream> protectStream(this);
+
+ // Protect the plug-in while we're calling into it.
+ NPRuntimeObjectMap::PluginProtector pluginProtector(&m_pluginView->m_npRuntimeObjectMap);
+ m_pluginView->m_plugin->streamDidFinishLoading(m_streamID);
+
+ m_pluginView->removeStream(this);
+ m_pluginView = 0;
+}
+
+static inline WebPage* webPage(HTMLPlugInElement* pluginElement)
+{
+ Frame* frame = pluginElement->document()->frame();
+ ASSERT(frame);
+
+ WebPage* webPage = static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame()->page();
+ ASSERT(webPage);
+
+ return webPage;
+}
+
+PassRefPtr<PluginView> PluginView::create(PassRefPtr<HTMLPlugInElement> pluginElement, PassRefPtr<Plugin> plugin, const Plugin::Parameters& parameters)
+{
+ return adoptRef(new PluginView(pluginElement, plugin, parameters));
+}
+
+PluginView::PluginView(PassRefPtr<HTMLPlugInElement> pluginElement, PassRefPtr<Plugin> plugin, const Plugin::Parameters& parameters)
+ : PluginViewBase(0)
+ , m_pluginElement(pluginElement)
+ , m_plugin(plugin)
+ , m_webPage(webPage(m_pluginElement.get()))
+ , m_parameters(parameters)
+ , m_isInitialized(false)
+ , m_isWaitingUntilMediaCanStart(false)
+ , m_isBeingDestroyed(false)
+ , m_pendingURLRequestsTimer(RunLoop::main(), this, &PluginView::pendingURLRequestsTimerFired)
+ , m_npRuntimeObjectMap(this)
+ , m_manualStreamState(StreamStateInitial)
+{
+#if PLATFORM(MAC)
+ m_webPage->addPluginView(this);
+#endif
+}
+
+PluginView::~PluginView()
+{
+#if PLATFORM(MAC)
+ m_webPage->removePluginView(this);
+#endif
+
+ ASSERT(!m_isBeingDestroyed);
+
+ if (m_isWaitingUntilMediaCanStart)
+ m_pluginElement->document()->removeMediaCanStartListener(this);
+
+ // Cancel all pending frame loads.
+ FrameLoadMap::iterator end = m_pendingFrameLoads.end();
+ for (FrameLoadMap::iterator it = m_pendingFrameLoads.begin(), end = m_pendingFrameLoads.end(); it != end; ++it)
+ it->first->setLoadListener(0);
+
+ if (m_plugin && m_isInitialized) {
+ m_isBeingDestroyed = true;
+ m_plugin->destroy();
+ m_isBeingDestroyed = false;
+ }
+
+ // Invalidate the object map.
+ m_npRuntimeObjectMap.invalidate();
+
+ // Cancel all streams.
+ cancelAllStreams();
+}
+
+Frame* PluginView::frame()
+{
+ return m_pluginElement->document()->frame();
+}
+
+void PluginView::manualLoadDidReceiveResponse(const ResourceResponse& response)
+{
+ // The plug-in can be null here if it failed to initialize.
+ if (!m_plugin)
+ return;
+
+ if (!m_isInitialized) {
+ ASSERT(m_manualStreamState == StreamStateInitial);
+ m_manualStreamState = StreamStateHasReceivedResponse;
+ m_manualStreamResponse = response;
+ return;
+ }
+
+ // Compute the stream related data from the resource response.
+ const KURL& responseURL = response.url();
+ const String& mimeType = response.mimeType();
+ long long expectedContentLength = response.expectedContentLength();
+
+ String headers = buildHTTPHeaders(response, expectedContentLength);
+
+ uint32_t streamLength = 0;
+ if (expectedContentLength > 0)
+ streamLength = expectedContentLength;
+
+ m_plugin->manualStreamDidReceiveResponse(responseURL, streamLength, response.lastModifiedDate(), mimeType, headers);
+}
+
+void PluginView::manualLoadDidReceiveData(const char* bytes, int length)
+{
+ // The plug-in can be null here if it failed to initialize.
+ if (!m_plugin)
+ return;
+
+ if (!m_isInitialized) {
+ ASSERT(m_manualStreamState == StreamStateHasReceivedResponse);
+ if (!m_manualStreamData)
+ m_manualStreamData = SharedBuffer::create();
+
+ m_manualStreamData->append(bytes, length);
+ return;
+ }
+
+ m_plugin->manualStreamDidReceiveData(bytes, length);
+}
+
+void PluginView::manualLoadDidFinishLoading()
+{
+ // The plug-in can be null here if it failed to initialize.
+ if (!m_plugin)
+ return;
+
+ if (!m_isInitialized) {
+ ASSERT(m_manualStreamState == StreamStateHasReceivedResponse);
+ m_manualStreamState = StreamStateFinished;
+ return;
+ }
+
+ m_plugin->manualStreamDidFinishLoading();
+}
+
+void PluginView::manualLoadDidFail(const ResourceError& error)
+{
+ // The plug-in can be null here if it failed to initialize.
+ if (!m_plugin)
+ return;
+
+ if (!m_isInitialized) {
+ m_manualStreamState = StreamStateFinished;
+ m_manualStreamError = error;
+ m_manualStreamData = nullptr;
+ return;
+ }
+
+ m_plugin->manualStreamDidFail(error.isCancellation());
+}
+
+#if PLATFORM(MAC)
+void PluginView::setWindowIsVisible(bool windowIsVisible)
+{
+ if (!m_plugin)
+ return;
+
+ // FIXME: Implement.
+}
+
+void PluginView::setWindowIsFocused(bool windowIsFocused)
+{
+ if (!m_isInitialized || !m_plugin)
+ return;
+
+ m_plugin->windowFocusChanged(windowIsFocused);
+}
+
+void PluginView::windowAndViewFramesChanged(const IntRect& windowFrameInScreenCoordinates, const IntRect& viewFrameInWindowCoordinates)
+{
+ if (!m_isInitialized || !m_plugin)
+ return;
+
+ m_plugin->windowAndViewFramesChanged(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates);
+}
+
+bool PluginView::sendComplexTextInput(uint64_t pluginComplexTextInputIdentifier, const String& textInput)
+{
+ if (!m_plugin)
+ return false;
+
+ if (m_plugin->pluginComplexTextInputIdentifier() != pluginComplexTextInputIdentifier)
+ return false;
+
+ m_plugin->sendComplexTextInput(textInput);
+ return true;
+}
+
+#endif
+
+void PluginView::initializePlugin()
+{
+ if (m_isInitialized)
+ return;
+
+ if (!m_plugin) {
+ // We've already tried and failed to initialize the plug-in.
+ return;
+ }
+
+ if (Frame* frame = m_pluginElement->document()->frame()) {
+ if (Page* page = frame->page()) {
+
+ // We shouldn't initialize the plug-in right now, add a listener.
+ if (!page->canStartMedia()) {
+ if (m_isWaitingUntilMediaCanStart)
+ return;
+
+ m_isWaitingUntilMediaCanStart = true;
+ m_pluginElement->document()->addMediaCanStartListener(this);
+ return;
+ }
+ }
+ }
+
+ if (!m_plugin->initialize(this, m_parameters)) {
+ // We failed to initialize the plug-in.
+ m_plugin = 0;
+
+ return;
+ }
+
+ m_isInitialized = true;
+
+ viewGeometryDidChange();
+
+ redeliverManualStream();
+
+#if PLATFORM(MAC)
+ if (m_plugin->pluginLayer()) {
+ if (frame()) {
+ frame()->view()->enterCompositingMode();
+ m_pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
+ }
+ }
+
+ windowAndViewFramesChanged(m_webPage->windowFrameInScreenCoordinates(), m_webPage->viewFrameInWindowCoordinates());
+ setWindowIsVisible(m_webPage->windowIsVisible());
+ setWindowIsFocused(m_webPage->windowIsFocused());
+#endif
+}
+
+#if PLATFORM(MAC)
+PlatformLayer* PluginView::platformLayer() const
+{
+ // The plug-in can be null here if it failed to initialize.
+ if (!m_isInitialized || !m_plugin)
+ return 0;
+
+ return m_plugin->pluginLayer();
+}
+#endif
+
+JSObject* PluginView::scriptObject(JSGlobalObject* globalObject)
+{
+ // The plug-in can be null here if it failed to initialize.
+ if (!m_isInitialized || !m_plugin)
+ return 0;
+
+ NPObject* scriptableNPObject = m_plugin->pluginScriptableNPObject();
+ if (!scriptableNPObject)
+ return 0;
+
+ JSObject* jsObject = m_npRuntimeObjectMap.getOrCreateJSObject(globalObject, scriptableNPObject);
+ releaseNPObject(scriptableNPObject);
+
+ return jsObject;
+}
+
+void PluginView::privateBrowsingStateChanged(bool privateBrowsingEnabled)
+{
+ // The plug-in can be null here if it failed to initialize.
+ if (!m_isInitialized || !m_plugin)
+ return;
+
+ m_plugin->privateBrowsingStateChanged(privateBrowsingEnabled);
+}
+
+void PluginView::setFrameRect(const WebCore::IntRect& rect)
+{
+ Widget::setFrameRect(rect);
+ viewGeometryDidChange();
+}
+
+void PluginView::paint(GraphicsContext* context, const IntRect& dirtyRect)
+{
+ if (context->paintingDisabled() || !m_plugin || !m_isInitialized)
+ return;
+
+ IntRect dirtyRectInWindowCoordinates = parent()->contentsToWindow(dirtyRect);
+
+ IntRect paintRectInWindowCoordinates = intersection(dirtyRectInWindowCoordinates, clipRectInWindowCoordinates());
+ if (paintRectInWindowCoordinates.isEmpty())
+ return;
+
+ // context is in document coordinates. Translate it to window coordinates.
+ IntPoint documentOriginInWindowCoordinates = parent()->contentsToWindow(IntPoint());
+ context->save();
+ context->translate(-documentOriginInWindowCoordinates.x(), -documentOriginInWindowCoordinates.y());
+
+ m_plugin->paint(context, paintRectInWindowCoordinates);
+
+ context->restore();
+}
+
+void PluginView::frameRectsChanged()
+{
+ Widget::frameRectsChanged();
+ viewGeometryDidChange();
+}
+
+void PluginView::setParent(ScrollView* scrollView)
+{
+ Widget::setParent(scrollView);
+
+ if (scrollView)
+ initializePlugin();
+}
+
+void PluginView::handleEvent(Event* event)
+{
+ if (!m_isInitialized || !m_plugin)
+ return;
+
+ const WebEvent* currentEvent = WebPage::currentEvent();
+ if (!currentEvent)
+ return;
+
+ bool didHandleEvent = false;
+
+ if ((event->type() == eventNames().mousemoveEvent && currentEvent->type() == WebEvent::MouseMove)
+ || (event->type() == eventNames().mousedownEvent && currentEvent->type() == WebEvent::MouseDown)
+ || (event->type() == eventNames().mouseupEvent && currentEvent->type() == WebEvent::MouseUp)) {
+ // We have a mouse event.
+ if (currentEvent->type() == WebEvent::MouseDown)
+ focusPluginElement();
+
+ didHandleEvent = m_plugin->handleMouseEvent(static_cast<const WebMouseEvent&>(*currentEvent));
+ } else if (event->type() == eventNames().mousewheelEvent && currentEvent->type() == WebEvent::Wheel) {
+ // We have a wheel event.
+ didHandleEvent = m_plugin->handleWheelEvent(static_cast<const WebWheelEvent&>(*currentEvent));
+ } else if (event->type() == eventNames().mouseoverEvent && currentEvent->type() == WebEvent::MouseMove) {
+ // We have a mouse enter event.
+ didHandleEvent = m_plugin->handleMouseEnterEvent(static_cast<const WebMouseEvent&>(*currentEvent));
+ } else if (event->type() == eventNames().mouseoutEvent && currentEvent->type() == WebEvent::MouseMove) {
+ // We have a mouse leave event.
+ didHandleEvent = m_plugin->handleMouseLeaveEvent(static_cast<const WebMouseEvent&>(*currentEvent));
+ } else if ((event->type() == eventNames().keydownEvent && currentEvent->type() == WebEvent::KeyDown)
+ || (event->type() == eventNames().keyupEvent && currentEvent->type() == WebEvent::KeyUp)) {
+ // We have a keyboard event.
+ didHandleEvent = m_plugin->handleKeyboardEvent(static_cast<const WebKeyboardEvent&>(*currentEvent));
+ }
+
+ if (didHandleEvent)
+ event->setDefaultHandled();
+}
+
+void PluginView::viewGeometryDidChange()
+{
+ if (!m_isInitialized || !m_plugin || !parent())
+ return;
+
+ // Get the frame rect in window coordinates.
+ IntRect frameRectInWindowCoordinates = parent()->contentsToWindow(frameRect());
+
+ m_plugin->geometryDidChange(frameRectInWindowCoordinates, clipRectInWindowCoordinates());
+}
+
+IntRect PluginView::clipRectInWindowCoordinates() const
+{
+ ASSERT(parent());
+
+ // Get the frame rect in window coordinates.
+ IntRect frameRectInWindowCoordinates = parent()->contentsToWindow(frameRect());
+
+ // Get the window clip rect for the enclosing layer (in window coordinates).
+ RenderLayer* layer = m_pluginElement->renderer()->enclosingLayer();
+ FrameView* parentView = m_pluginElement->document()->frame()->view();
+ IntRect windowClipRect = parentView->windowClipRectForLayer(layer, true);
+
+ // Intersect the two rects to get the view clip rect in window coordinates.
+ return intersection(frameRectInWindowCoordinates, windowClipRect);
+}
+
+void PluginView::focusPluginElement()
+{
+ ASSERT(frame());
+
+ if (Page* page = frame()->page())
+ page->focusController()->setFocusedFrame(frame());
+ frame()->document()->setFocusedNode(m_pluginElement);
+}
+
+void PluginView::pendingURLRequestsTimerFired()
+{
+ ASSERT(!m_pendingURLRequests.isEmpty());
+
+ RefPtr<URLRequest> urlRequest = m_pendingURLRequests.takeFirst();
+
+ // If there are more requests to perform, reschedule the timer.
+ if (!m_pendingURLRequests.isEmpty())
+ m_pendingURLRequestsTimer.startOneShot(0);
+
+ performURLRequest(urlRequest.get());
+}
+
+void PluginView::performURLRequest(URLRequest* request)
+{
+ // First, check if this is a javascript: url.
+ if (protocolIsJavaScript(request->request().url())) {
+ performJavaScriptURLRequest(request);
+ return;
+ }
+
+ if (!request->target().isNull()) {
+ performFrameLoadURLRequest(request);
+ return;
+ }
+
+ // This request is to load a URL and create a stream.
+ RefPtr<Stream> stream = PluginView::Stream::create(this, request->requestID(), request->request());
+ addStream(stream.get());
+ stream->start();
+}
+
+void PluginView::performFrameLoadURLRequest(URLRequest* request)
+{
+ ASSERT(!request->target().isNull());
+
+ Frame* frame = m_pluginElement->document()->frame();
+ if (!frame)
+ return;
+
+ if (!m_pluginElement->document()->securityOrigin()->canDisplay(request->request().url())) {
+ // We can't load the request, send back a reply to the plug-in.
+ m_plugin->frameDidFail(request->requestID(), false);
+ return;
+ }
+
+ // First, try to find a target frame.
+ Frame* targetFrame = frame->loader()->findFrameForNavigation(request->target());
+ if (!targetFrame) {
+ // We did not find a target frame. Ask our frame to load the page. This may or may not create a popup window.
+ frame->loader()->load(request->request(), request->target(), false);
+
+ // FIXME: We don't know whether the window was successfully created here so we just assume that it worked.
+ // It's better than not telling the plug-in anything.
+ m_plugin->frameDidFinishLoading(request->requestID());
+ return;
+ }
+
+ // Now ask the frame to load the request.
+ targetFrame->loader()->load(request->request(), false);
+
+ WebFrame* targetWebFrame = static_cast<WebFrameLoaderClient*>(targetFrame->loader()->client())->webFrame();
+ if (WebFrame::LoadListener* loadListener = targetWebFrame->loadListener()) {
+ // Check if another plug-in view or even this view is waiting for the frame to load.
+ // If it is, tell it that the load was cancelled because it will be anyway.
+ loadListener->didFailLoad(targetWebFrame, true);
+ }
+
+ m_pendingFrameLoads.set(targetWebFrame, request);
+ targetWebFrame->setLoadListener(this);
+}
+
+void PluginView::performJavaScriptURLRequest(URLRequest* request)
+{
+ ASSERT(protocolIsJavaScript(request->request().url()));
+
+ RefPtr<Frame> frame = m_pluginElement->document()->frame();
+ if (!frame)
+ return;
+
+ String jsString = decodeURLEscapeSequences(request->request().url().string().substring(sizeof("javascript:") - 1));
+
+ if (!request->target().isNull()) {
+ // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
+ if (frame->tree()->find(request->target()) != frame) {
+ // Let the plug-in know that its frame load failed.
+ m_plugin->frameDidFail(request->requestID(), false);
+ return;
+ }
+ }
+
+ // Evaluate the JavaScript code. Note that running JavaScript here could cause the plug-in to be destroyed, so we
+ // grab references to the plug-in here.
+ RefPtr<Plugin> plugin = m_plugin;
+
+ bool oldAllowPopups = frame->script()->allowPopupsFromPlugin();
+ frame->script()->setAllowPopupsFromPlugin(request->allowPopups());
+
+ ScriptValue result = m_pluginElement->document()->frame()->script()->executeScript(jsString);
+
+ frame->script()->setAllowPopupsFromPlugin(oldAllowPopups);
+
+ // Check if evaluating the JavaScript destroyed the plug-in.
+ if (!plugin->controller())
+ return;
+
+ ScriptState* scriptState = m_pluginElement->document()->frame()->script()->globalObject(pluginWorld())->globalExec();
+ String resultString;
+ result.getString(scriptState, resultString);
+
+ if (!request->target().isNull()) {
+ // Just send back whether the frame load succeeded or not.
+ if (resultString.isNull())
+ m_plugin->frameDidFail(request->requestID(), false);
+ else
+ m_plugin->frameDidFinishLoading(request->requestID());
+ return;
+ }
+
+ // Send the result back to the plug-in.
+ plugin->didEvaluateJavaScript(request->requestID(), decodeURLEscapeSequences(request->request().url()), resultString);
+}
+
+void PluginView::addStream(Stream* stream)
+{
+ ASSERT(!m_streams.contains(stream->streamID()));
+ m_streams.set(stream->streamID(), stream);
+}
+
+void PluginView::removeStream(Stream* stream)
+{
+ ASSERT(m_streams.get(stream->streamID()) == stream);
+
+ m_streams.remove(stream->streamID());
+}
+
+void PluginView::cancelAllStreams()
+{
+ Vector<RefPtr<Stream> > streams;
+ copyValuesToVector(m_streams, streams);
+
+ for (size_t i = 0; i < streams.size(); ++i)
+ streams[i]->cancel();
+
+ // Cancelling a stream removes it from the m_streams map, so if we cancel all streams the map should be empty.
+ ASSERT(m_streams.isEmpty());
+}
+
+void PluginView::redeliverManualStream()
+{
+ if (m_manualStreamState == StreamStateInitial) {
+ // Nothing to do.
+ return;
+ }
+
+ if (m_manualStreamState == StreamStateFailed) {
+ manualLoadDidFail(m_manualStreamError);
+ return;
+ }
+
+ // Deliver the response.
+ manualLoadDidReceiveResponse(m_manualStreamResponse);
+
+ // Deliver the data.
+ if (m_manualStreamData) {
+ const char* data;
+ unsigned position = 0;
+
+ while (unsigned length = m_manualStreamData->getSomeData(data, position)) {
+ manualLoadDidReceiveData(data, length);
+ position += length;
+ }
+
+ m_manualStreamData = nullptr;
+ }
+
+ if (m_manualStreamState == StreamStateFinished)
+ manualLoadDidFinishLoading();
+}
+
+void PluginView::invalidateRect(const IntRect& dirtyRect)
+{
+ if (!parent() || !m_plugin || !m_isInitialized)
+ return;
+
+ IntRect dirtyRectInWindowCoordinates = convertToContainingWindow(dirtyRect);
+
+ parent()->hostWindow()->invalidateContentsAndWindow(intersection(dirtyRectInWindowCoordinates, clipRectInWindowCoordinates()), false);
+}
+
+void PluginView::setFocus(bool hasFocus)
+{
+ Widget::setFocus(hasFocus);
+
+ if (!m_isInitialized || !m_plugin)
+ return;
+
+ m_plugin->setFocus(hasFocus);
+}
+
+void PluginView::mediaCanStart()
+{
+ ASSERT(m_isWaitingUntilMediaCanStart);
+ m_isWaitingUntilMediaCanStart = false;
+
+ initializePlugin();
+}
+
+void PluginView::invalidate(const IntRect& dirtyRect)
+{
+ invalidateRect(dirtyRect);
+}
+
+String PluginView::userAgent()
+{
+ Frame* frame = m_pluginElement->document()->frame();
+ if (!frame)
+ return String();
+
+ return frame->loader()->client()->userAgent(KURL());
+}
+
+void PluginView::loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target,
+ const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups)
+{
+ FrameLoadRequest frameLoadRequest(m_pluginElement->document()->securityOrigin());
+ frameLoadRequest.resourceRequest().setHTTPMethod(method);
+ frameLoadRequest.resourceRequest().setURL(m_pluginElement->document()->completeURL(urlString));
+ frameLoadRequest.resourceRequest().addHTTPHeaderFields(headerFields);
+ frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(httpBody.data(), httpBody.size()));
+ frameLoadRequest.setFrameName(target);
+
+ m_pendingURLRequests.append(URLRequest::create(requestID, frameLoadRequest, allowPopups));
+ m_pendingURLRequestsTimer.startOneShot(0);
+}
+
+void PluginView::cancelStreamLoad(uint64_t streamID)
+{
+ // Keep a reference to the stream. Stream::cancel might remove the stream from the map, and thus
+ // releasing its last reference.
+ RefPtr<Stream> stream = m_streams.get(streamID).get();
+ if (!stream)
+ return;
+
+ // Cancelling the stream here will remove it from the map.
+ stream->cancel();
+ ASSERT(!m_streams.contains(streamID));
+}
+
+void PluginView::cancelManualStreamLoad()
+{
+ if (!frame())
+ return;
+
+ DocumentLoader* documentLoader = frame()->loader()->activeDocumentLoader();
+ ASSERT(documentLoader);
+
+ if (documentLoader->isLoadingMainResource())
+ documentLoader->cancelMainResourceLoad(frame()->loader()->cancelledError(m_parameters.url));
+}
+
+NPObject* PluginView::windowScriptNPObject()
+{
+ if (!frame())
+ return 0;
+
+ // FIXME: Handle JavaScript being disabled.
+ ASSERT(frame()->script()->canExecuteScripts(NotAboutToExecuteScript));
+
+ return m_npRuntimeObjectMap.getOrCreateNPObject(frame()->script()->windowShell(pluginWorld())->window());
+}
+
+NPObject* PluginView::pluginElementNPObject()
+{
+ if (!frame())
+ return 0;
+
+ // FIXME: Handle JavaScript being disabled.
+ JSObject* object = frame()->script()->jsObjectForPluginElement(m_pluginElement.get());
+ ASSERT(object);
+
+ return m_npRuntimeObjectMap.getOrCreateNPObject(object);
+}
+
+bool PluginView::evaluate(NPObject* npObject, const String& scriptString, NPVariant* result, bool allowPopups)
+{
+ if (!frame())
+ return false;
+
+ bool oldAllowPopups = frame()->script()->allowPopupsFromPlugin();
+ frame()->script()->setAllowPopupsFromPlugin(allowPopups);
+
+ bool returnValue = m_npRuntimeObjectMap.evaluate(npObject, scriptString, result);
+
+ frame()->script()->setAllowPopupsFromPlugin(oldAllowPopups);
+
+ return returnValue;
+}
+
+void PluginView::setStatusbarText(const String& statusbarText)
+{
+ if (!frame())
+ return;
+
+ Page* page = frame()->page();
+ if (!page)
+ return;
+
+ page->chrome()->setStatusbarText(frame(), statusbarText);
+}
+
+bool PluginView::isAcceleratedCompositingEnabled()
+{
+ if (!frame())
+ return false;
+
+ Settings* settings = frame()->settings();
+ if (!settings)
+ return false;
+
+ return settings->acceleratedCompositingEnabled();
+}
+
+void PluginView::pluginProcessCrashed()
+{
+ if (!m_pluginElement->renderer())
+ return;
+
+ // FIXME: The renderer could also be a RenderApplet, we should handle that.
+ if (!m_pluginElement->renderer()->isEmbeddedObject())
+ return;
+
+ RenderEmbeddedObject* renderer = toRenderEmbeddedObject(m_pluginElement->renderer());
+ renderer->setShowsCrashedPluginIndicator();
+
+ invalidateRect(frameRect());
+}
+
+#if PLATFORM(WIN)
+HWND PluginView::nativeParentWindow()
+{
+ return m_webPage->nativeWindow();
+}
+#endif
+
+#if PLATFORM(MAC)
+void PluginView::setComplexTextInputEnabled(bool complexTextInputEnabled)
+{
+ m_webPage->send(Messages::WebPageProxy::SetComplexTextInputEnabled(m_plugin->pluginComplexTextInputIdentifier(), complexTextInputEnabled));
+}
+#endif
+
+String PluginView::proxiesForURL(const String& urlString)
+{
+ const FrameLoader* frameLoader = frame() ? frame()->loader() : 0;
+ const NetworkingContext* context = frameLoader ? frameLoader->networkingContext() : 0;
+ Vector<ProxyServer> proxyServers = proxyServersForURL(KURL(KURL(), urlString), context);
+ return toString(proxyServers);
+}
+
+String PluginView::cookiesForURL(const String& urlString)
+{
+ return cookies(m_pluginElement->document(), KURL(KURL(), urlString));
+}
+
+void PluginView::setCookiesForURL(const String& urlString, const String& cookieString)
+{
+ setCookies(m_pluginElement->document(), KURL(KURL(), urlString), cookieString);
+}
+
+bool PluginView::isPrivateBrowsingEnabled()
+{
+ // If we can't get the real setting, we'll assume that private browsing is enabled.
+ if (!frame())
+ return true;
+
+ Settings* settings = frame()->settings();
+ if (!settings)
+ return true;
+
+ return settings->privateBrowsingEnabled();
+}
+
+void PluginView::didFinishLoad(WebFrame* webFrame)
+{
+ RefPtr<URLRequest> request = m_pendingFrameLoads.take(webFrame);
+ ASSERT(request);
+ webFrame->setLoadListener(0);
+
+ m_plugin->frameDidFinishLoading(request->requestID());
+}
+
+void PluginView::didFailLoad(WebFrame* webFrame, bool wasCancelled)
+{
+ RefPtr<URLRequest> request = m_pendingFrameLoads.take(webFrame);
+ ASSERT(request);
+ webFrame->setLoadListener(0);
+
+ m_plugin->frameDidFail(request->requestID(), wasCancelled);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/WebProcess/Plugins/PluginView.h b/Source/WebKit2/WebProcess/Plugins/PluginView.h
new file mode 100644
index 0000000..07511d7
--- /dev/null
+++ b/Source/WebKit2/WebProcess/Plugins/PluginView.h
@@ -0,0 +1,185 @@
+/*
+ * 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 PluginView_h
+#define PluginView_h
+
+#include "NPRuntimeObjectMap.h"
+#include "Plugin.h"
+#include "PluginController.h"
+#include "RunLoop.h"
+#include "WebFrame.h"
+
+#include <WebCore/MediaCanStartListener.h>
+#include <WebCore/ResourceError.h>
+#include <WebCore/ResourceResponse.h>
+#include <WebCore/PluginViewBase.h>
+#include <wtf/Deque.h>
+
+// FIXME: Eventually this should move to WebCore.
+
+namespace WebCore {
+ class Frame;
+ class HTMLPlugInElement;
+}
+
+namespace WebKit {
+
+class PluginView : public WebCore::PluginViewBase, WebCore::MediaCanStartListener, PluginController, WebFrame::LoadListener {
+public:
+ static PassRefPtr<PluginView> create(PassRefPtr<WebCore::HTMLPlugInElement>, PassRefPtr<Plugin>, const Plugin::Parameters&);
+
+ WebCore::Frame* frame();
+
+ bool isBeingDestroyed() const { return m_isBeingDestroyed; }
+
+ void manualLoadDidReceiveResponse(const WebCore::ResourceResponse&);
+ void manualLoadDidReceiveData(const char* bytes, int length);
+ void manualLoadDidFinishLoading();
+ void manualLoadDidFail(const WebCore::ResourceError&);
+
+#if PLATFORM(MAC)
+ void setWindowIsVisible(bool);
+ void setWindowIsFocused(bool);
+ void windowAndViewFramesChanged(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates);
+ bool sendComplexTextInput(uint64_t pluginComplexTextInputIdentifier, const String& textInput);
+#endif
+
+private:
+ PluginView(PassRefPtr<WebCore::HTMLPlugInElement>, PassRefPtr<Plugin>, const Plugin::Parameters& parameters);
+ virtual ~PluginView();
+
+ void initializePlugin();
+ void destroyPlugin();
+
+ void viewGeometryDidChange();
+ WebCore::IntRect clipRectInWindowCoordinates() const;
+ void focusPluginElement();
+
+ void pendingURLRequestsTimerFired();
+ class URLRequest;
+ void performURLRequest(URLRequest*);
+
+ // Perform a URL request where the frame target is not null.
+ void performFrameLoadURLRequest(URLRequest*);
+
+ // Perform a URL request where the URL protocol is "javascript:".
+ void performJavaScriptURLRequest(URLRequest*);
+
+ class Stream;
+ void addStream(Stream*);
+ void removeStream(Stream*);
+ void cancelAllStreams();
+
+ void redeliverManualStream();
+
+ // WebCore::PluginViewBase
+#if PLATFORM(MAC)
+ virtual PlatformLayer* platformLayer() const;
+#endif
+ virtual JSC::JSObject* scriptObject(JSC::JSGlobalObject*);
+ virtual void privateBrowsingStateChanged(bool);
+
+ // WebCore::Widget
+ virtual void setFrameRect(const WebCore::IntRect&);
+ virtual void paint(WebCore::GraphicsContext*, const WebCore::IntRect&);
+ virtual void invalidateRect(const WebCore::IntRect&);
+ virtual void setFocus(bool);
+ virtual void frameRectsChanged();
+ virtual void setParent(WebCore::ScrollView*);
+ virtual void handleEvent(WebCore::Event*);
+
+ // WebCore::MediaCanStartListener
+ virtual void mediaCanStart();
+
+ // PluginController
+ virtual void invalidate(const WebCore::IntRect&);
+ virtual String userAgent();
+ virtual void loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target,
+ const WebCore::HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups);
+ virtual void cancelStreamLoad(uint64_t streamID);
+ virtual void cancelManualStreamLoad();
+ virtual NPObject* windowScriptNPObject();
+ virtual NPObject* pluginElementNPObject();
+ virtual bool evaluate(NPObject*, const String&scriptString, NPVariant* result, bool allowPopups);
+ virtual void setStatusbarText(const String&);
+ virtual bool isAcceleratedCompositingEnabled();
+ virtual void pluginProcessCrashed();
+#if PLATFORM(WIN)
+ virtual HWND nativeParentWindow();
+#endif
+#if PLATFORM(MAC)
+ virtual void setComplexTextInputEnabled(bool);
+#endif
+ virtual String proxiesForURL(const String&);
+ virtual String cookiesForURL(const String&);
+ virtual void setCookiesForURL(const String& urlString, const String& cookieString);
+ virtual bool isPrivateBrowsingEnabled();
+
+ // WebFrame::LoadListener
+ virtual void didFinishLoad(WebFrame*);
+ virtual void didFailLoad(WebFrame*, bool wasCancelled);
+
+ RefPtr<WebCore::HTMLPlugInElement> m_pluginElement;
+ RefPtr<Plugin> m_plugin;
+ WebPage* m_webPage;
+ Plugin::Parameters m_parameters;
+
+ bool m_isInitialized;
+ bool m_isWaitingUntilMediaCanStart;
+ bool m_isBeingDestroyed;
+
+ // Pending URLRequests that the plug-in has made.
+ Deque<RefPtr<URLRequest> > m_pendingURLRequests;
+ RunLoop::Timer<PluginView> m_pendingURLRequestsTimer;
+
+ // Pending frame loads that the plug-in has made.
+ typedef HashMap<RefPtr<WebFrame>, RefPtr<URLRequest> > FrameLoadMap;
+ FrameLoadMap m_pendingFrameLoads;
+
+ // Streams that the plug-in has requested to load.
+ HashMap<uint64_t, RefPtr<Stream> > m_streams;
+
+ // A map of all related NPObjects for this plug-in view.
+ NPRuntimeObjectMap m_npRuntimeObjectMap;
+
+ // The manual stream state. This is used so we can deliver a manual stream to a plug-in
+ // when it is initialized.
+ enum ManualStreamState {
+ StreamStateInitial,
+ StreamStateHasReceivedResponse,
+ StreamStateFinished,
+ StreamStateFailed
+ };
+ ManualStreamState m_manualStreamState;
+
+ WebCore::ResourceResponse m_manualStreamResponse;
+ WebCore::ResourceError m_manualStreamError;
+ RefPtr<WebCore::SharedBuffer> m_manualStreamData;
+};
+
+} // namespace WebKit
+
+#endif // PluginView_h