diff options
author | Ben Murdoch <benm@google.com> | 2011-05-13 16:23:25 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-05-16 11:35:02 +0100 |
commit | 65f03d4f644ce73618e5f4f50dd694b26f55ae12 (patch) | |
tree | f478babb801e720de7bfaee23443ffe029f58731 /Source/WebKit2/WebProcess/Plugins | |
parent | 47de4a2fb7262c7ebdb9cd133ad2c54c187454d0 (diff) | |
download | external_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')
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 |