From 2eb312b025971ee1529b3a6c67d715055cb77906 Mon Sep 17 00:00:00 2001 From: "brettw@chromium.org" Date: Thu, 5 Mar 2009 20:17:08 +0000 Subject: Address some of the review comments on comment 2 of https://bugs.webkit.org/show_bug.cgi?id=24299 This is everything up to "not supposed to be using STL container classes." Review URL: http://codereview.chromium.org/40122 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11025 0039d316-1c4b-4281-b951-d872f2087c98 --- webkit/port/bindings/v8/NPV8Object.cpp | 495 ++++++++++++++++++++++++++ webkit/port/bindings/v8/NPV8Object.h | 37 ++ webkit/port/bindings/v8/ScriptController.cpp | 8 +- webkit/port/bindings/v8/V8NPObject.cpp | 369 ++++++++++++++++++++ webkit/port/bindings/v8/V8NPObject.h | 53 +++ webkit/port/bindings/v8/V8NPUtils.cpp | 124 +++++++ webkit/port/bindings/v8/V8NPUtils.h | 28 ++ webkit/port/bindings/v8/np_v8object.cpp | 496 --------------------------- webkit/port/bindings/v8/np_v8object.h | 38 -- webkit/port/bindings/v8/npruntime.cpp | 10 +- webkit/port/bindings/v8/v8_custom.cpp | 2 +- webkit/port/bindings/v8/v8_helpers.cpp | 4 +- webkit/port/bindings/v8/v8_helpers.h | 2 +- webkit/port/bindings/v8/v8_np_utils.cpp | 124 ------- webkit/port/bindings/v8/v8_np_utils.h | 28 -- webkit/port/bindings/v8/v8_npobject.cpp | 369 -------------------- webkit/port/bindings/v8/v8_npobject.h | 52 +-- 17 files changed, 1122 insertions(+), 1117 deletions(-) create mode 100644 webkit/port/bindings/v8/NPV8Object.cpp create mode 100644 webkit/port/bindings/v8/NPV8Object.h create mode 100644 webkit/port/bindings/v8/V8NPObject.cpp create mode 100644 webkit/port/bindings/v8/V8NPObject.h create mode 100644 webkit/port/bindings/v8/V8NPUtils.cpp create mode 100644 webkit/port/bindings/v8/V8NPUtils.h delete mode 100644 webkit/port/bindings/v8/np_v8object.cpp delete mode 100644 webkit/port/bindings/v8/np_v8object.h delete mode 100644 webkit/port/bindings/v8/v8_np_utils.cpp delete mode 100644 webkit/port/bindings/v8/v8_np_utils.h delete mode 100644 webkit/port/bindings/v8/v8_npobject.cpp (limited to 'webkit/port') diff --git a/webkit/port/bindings/v8/NPV8Object.cpp b/webkit/port/bindings/v8/NPV8Object.cpp new file mode 100644 index 0000000..829fd074 --- /dev/null +++ b/webkit/port/bindings/v8/NPV8Object.cpp @@ -0,0 +1,495 @@ +/* + * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007-2009 Google, 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include + +#define max max +#define min min +#include +#include "NPV8Object.h" +#include "ChromiumBridge.h" +#include "Frame.h" +#include "bindings/npruntime.h" +#include "npruntime_priv.h" +#include "PlatformString.h" +#include "ScriptController.h" +#include "v8_custom.h" +#include "v8_helpers.h" +#include "V8NPUtils.h" +#include "v8_proxy.h" +#include "DOMWindow.h" + +using WebCore::V8ClassIndex; +using WebCore::V8Custom; +using WebCore::V8Proxy; + +// FIXME(mbelshe): comments on why use malloc and free. +static NPObject* AllocV8NPObject(NPP, NPClass*) +{ + return static_cast(malloc(sizeof(V8NPObject))); +} + +static void FreeV8NPObject(NPObject* npobj) +{ + V8NPObject *object = reinterpret_cast(npobj); +#ifndef NDEBUG + V8Proxy::UnregisterGlobalHandle(object, object->v8Object); +#endif + object->v8Object.Dispose(); + free(object); +} + +static v8::Handle* listFromVariantArgs(const NPVariant* args, + uint32_t argCount, + NPObject *owner) +{ + v8::Handle* argv = new v8::Handle[argCount]; + for (uint32_t index = 0; index < argCount; index++) { + const NPVariant *arg = &args[index]; + argv[index] = convertNPVariantToV8Object(arg, owner); + } + return argv; +} + +// Create an identifier (null terminated utf8 char*) from the NPIdentifier. +static v8::Local NPIdentifierToV8Identifier(NPIdentifier name) +{ + PrivateIdentifier* identifier = static_cast(name); + if (identifier->isString) + return v8::String::New(static_cast(identifier->value.string)); + + char buf[32]; + sprintf(buf, "%d", identifier->value.number); + return v8::String::New(buf); +} + +static NPClass V8NPObjectClass = { NP_CLASS_STRUCT_VERSION, + AllocV8NPObject, + FreeV8NPObject, + 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +// NPAPI's npruntime functions +NPClass* npScriptObjectClass = &V8NPObjectClass; + +NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle object, WebCore::DOMWindow* root) +{ + // Check to see if this object is already wrapped. + if (object->InternalFieldCount() == V8Custom::kNPObjectInternalFieldCount && + object->GetInternalField(V8Custom::kDOMWrapperTypeIndex)->IsNumber() && + object->GetInternalField(V8Custom::kDOMWrapperTypeIndex)->Uint32Value() == V8ClassIndex::NPOBJECT) { + + NPObject* rv = V8Proxy::ToNativeObject(V8ClassIndex::NPOBJECT, object); + NPN_RetainObject(rv); + return rv; + } + + V8NPObject* obj = reinterpret_cast(NPN_CreateObject(npp, &V8NPObjectClass)); + obj->v8Object = v8::Persistent::New(object); +#ifndef NDEBUG + V8Proxy::RegisterGlobalHandle(WebCore::NPOBJECT, obj, obj->v8Object); +#endif + obj->rootObject = root; + return reinterpret_cast(obj); +} + +bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName, + const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast(npobj); + + PrivateIdentifier *identifier = static_cast(methodName); + if (!identifier->isString) + return false; + + v8::HandleScope handleScope; + // FIXME: should use the plugin's owner frame as the security context + v8::Handle context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + // Special case the "eval" method. + if (methodName == NPN_GetStringIdentifier("eval")) { + if (argCount != 1) + return false; + if (args[0].type != NPVariantType_String) + return false; + return NPN_Evaluate(npp, npobj, const_cast(&args[0].value.stringValue), result); + } + + v8::Handle funcObj = object->v8Object->Get(v8::String::New(identifier->value.string)); + if (funcObj.IsEmpty() || funcObj->IsNull()) { + NULL_TO_NPVARIANT(*result); + return false; + } + if (funcObj->IsUndefined()) { + VOID_TO_NPVARIANT(*result); + return false; + } + + WebCore::V8Proxy* proxy = GetV8Proxy(npobj); + ASSERT(proxy); // must not be null + + // FIXME: fix variable naming + // Call the function object + v8::Handle func = v8::Handle::Cast(funcObj); + // Create list of args to pass to v8 + v8::Handle* argv = listFromVariantArgs(args, argCount, npobj); + v8::Local resultObj = proxy->CallFunction(func, object->v8Object, argCount, argv); + delete[] argv; + + // If we had an error, return false. The spec is a little unclear here, but + // says "Returns true if the method was successfully invoked". If we get an + // error return value, was that successfully invoked? + if (resultObj.IsEmpty()) + return false; + + // Convert the result back to an NPVariant + convertV8ObjectToNPVariant(resultObj, npobj, result); + return true; + } + + if (npobj->_class->invoke) + return npobj->_class->invoke(npobj, methodName, args, argCount, result); + + VOID_TO_NPVARIANT(*result); + return true; +} + +// FIXME: Fix it same as NPN_Invoke (HandleScope and such) +bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args, + uint32_t argCount, NPVariant *result) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast(npobj); + + VOID_TO_NPVARIANT(*result); + + v8::HandleScope handleScope; + v8::Handle context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + // Lookup the function object + v8::Handle funcObj(object->v8Object); + if (!funcObj->IsFunction()) + return false; + + // Call the function object + v8::Local resultObj; + v8::Handle func(v8::Function::Cast(*funcObj)); + if (!func->IsNull()) { + WebCore::V8Proxy* proxy = GetV8Proxy(npobj); + ASSERT(proxy); + + // Create list of args to pass to v8 + v8::Handle* argv = listFromVariantArgs(args, argCount, npobj); + resultObj = proxy->CallFunction(func, funcObj, argCount, argv); + delete[] argv; + } + + // If we had an error, return false. The spec is a little unclear here, but + // says "Returns true if the method was successfully invoked". If we get an + // error return value, was that successfully invoked? + if (resultObj.IsEmpty()) + return false; + + // Convert the result back to an NPVariant. + convertV8ObjectToNPVariant(resultObj, npobj, result); + return true; + } + + if (npobj->_class->invokeDefault) + return npobj->_class->invokeDefault(npobj, args, argCount, result); + + VOID_TO_NPVARIANT(*result); + return true; +} + +bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *npscript, NPVariant *result) +{ + bool popupsAllowed = WebCore::ChromiumBridge::popupsAllowed(npp); + return NPN_EvaluateHelper(npp, popupsAllowed, npobj, npscript, result); +} + +bool NPN_EvaluateHelper(NPP npp, bool popupsAllowed, NPObject* npobj, NPString* npscript, NPVariant *result) +{ + VOID_TO_NPVARIANT(*result); + if (!npobj) + return false; + + if (npobj->_class != npScriptObjectClass) + return false; + + v8::HandleScope handleScope; + v8::Handle context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + WebCore::V8Proxy* proxy = GetV8Proxy(npobj); + ASSERT(proxy); + + v8::Context::Scope scope(context); + + WebCore::String filename; + if (!popupsAllowed) + filename = "npscript"; + + // Convert UTF-8 stream to WebCore::String. + WebCore::String script = WebCore::String::fromUTF8(npscript->UTF8Characters, npscript->UTF8Length); + v8::Local v8result = proxy->Evaluate(filename, 0, script, 0); + + // If we had an error, return false. + if (v8result.IsEmpty()) + return false; + + convertV8ObjectToNPVariant(v8result, npobj, result); + return true; +} + +bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, NPVariant *result) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast(npobj); + + v8::HandleScope handleScope; + v8::Handle context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + v8::Handle obj(object->v8Object); + v8::Local v8result = obj->Get(NPIdentifierToV8Identifier(propertyName)); + + convertV8ObjectToNPVariant(v8result, npobj, result); + return true; + } + + if (npobj->_class->hasProperty && npobj->_class->getProperty) { + if (npobj->_class->hasProperty(npobj, propertyName)) + return npobj->_class->getProperty(npobj, propertyName, result); + } + + VOID_TO_NPVARIANT(*result); + return false; +} + +bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast(npobj); + + v8::HandleScope handleScope; + v8::Handle context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + v8::Handle obj(object->v8Object); + obj->Set(NPIdentifierToV8Identifier(propertyName), + convertNPVariantToV8Object(value, object->rootObject->frame()->script()->windowScriptNPObject())); + return true; + } + + if (npobj->_class->setProperty) + return npobj->_class->setProperty(npobj, propertyName, value); + + return false; +} + +bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName) +{ + if (!npobj) + return false; + if (npobj->_class != npScriptObjectClass) + return false; + + V8NPObject *object = reinterpret_cast(npobj); + + v8::HandleScope handleScope; + v8::Handle context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle obj(object->v8Object); + // FIXME(mbelshe) - verify that setting to undefined is right. + obj->Set(NPIdentifierToV8Identifier(propertyName), v8::Undefined()); + return true; +} + +bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast(npobj); + + v8::HandleScope handleScope; + v8::Handle context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle obj(object->v8Object); + return obj->Has(NPIdentifierToV8Identifier(propertyName)); + } + + if (npobj->_class->hasProperty) + return npobj->_class->hasProperty(npobj, propertyName); + return false; +} + +bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast(npobj); + + v8::HandleScope handleScope; + v8::Handle context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle obj(object->v8Object); + v8::Handle prop = obj->Get(NPIdentifierToV8Identifier(methodName)); + return prop->IsFunction(); + } + + if (npobj->_class->hasMethod) + return npobj->_class->hasMethod(npobj, methodName); + return false; +} + +void NPN_SetException(NPObject *npobj, const NPUTF8 *message) +{ + if (npobj->_class != npScriptObjectClass) + return; + v8::HandleScope handleScope; + v8::Handle context = getV8Context(0, npobj); + if (context.IsEmpty()) + return; + + v8::Context::Scope scope(context); + V8Proxy::ThrowError(V8Proxy::GENERAL_ERROR, message); +} + +bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast(npobj); + + v8::HandleScope handleScope; + v8::Handle context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle obj(object->v8Object); + + // FIXME(fqian): http://b/issue?id=1210340: Use a v8::Object::Keys() method + // when it exists, instead of evaluating javascript. + + // FIXME(mpcomplete): figure out how to cache this helper function. + // Run a helper function that collects the properties on the object into + // an array. + const char enumeratorCode[] = + "(function (obj) {" + " var props = [];" + " for (var prop in obj) {" + " props[props.length] = prop;" + " }" + " return props;" + "});"; + v8::Handle source = v8::String::New(enumeratorCode); + v8::Handle script = v8::Script::Compile(source, 0); + v8::Handle enumeratorObj = script->Run(); + v8::Handle enumerator = v8::Handle::Cast(enumeratorObj); + v8::Handle argv[] = { obj }; + v8::Local propsObj = enumerator->Call(v8::Handle::Cast(enumeratorObj), ARRAYSIZE_UNSAFE(argv), argv); + if (propsObj.IsEmpty()) + return false; + + // Convert the results into an array of NPIdentifiers. + v8::Handle props = v8::Handle::Cast(propsObj); + *count = props->Length(); + *identifier = static_cast(malloc(sizeof(NPIdentifier*) * *count)); + for (uint32_t i = 0; i < *count; ++i) { + v8::Local name = props->Get(v8::Integer::New(i)); + (*identifier)[i] = getStringIdentifier(v8::Local::Cast(name)); + } + return true; + } + + if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) && npobj->_class->enumerate) + return npobj->_class->enumerate(npobj, identifier, count); + + return false; +} + +bool NPN_Construct(NPP npp, NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (!npobj) + return false; + + // FIXME(estade): implement this case. + if (npobj->_class == npScriptObjectClass) { + VOID_TO_NPVARIANT(*result); + return false; + } + + if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) && npobj->_class->construct) + return npobj->_class->construct(npobj, args, argCount, result); + + return false; +} diff --git a/webkit/port/bindings/v8/NPV8Object.h b/webkit/port/bindings/v8/NPV8Object.h new file mode 100644 index 0000000..a3cade9 --- /dev/null +++ b/webkit/port/bindings/v8/NPV8Object.h @@ -0,0 +1,37 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef np_v8object_h +#define np_v8object_h + +#include "bindings/npruntime.h" +#include + +namespace WebCore { + class DOMWindow; +} + +extern NPClass* npScriptObjectClass; + +// A V8NPObject is a NPObject which carries additional V8-specific +// information. It is allocated and deallocated by AllocV8NPObject() +// and FreeV8NPObject() methods. +struct V8NPObject { + NPObject object; + v8::Persistent v8Object; + WebCore::DOMWindow* rootObject; +}; + +struct PrivateIdentifier { + union { + const NPUTF8* string; + int32_t number; + } value; + bool isString; +}; + +NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle, WebCore::DOMWindow*); + +#endif // np_v8object_h + diff --git a/webkit/port/bindings/v8/ScriptController.cpp b/webkit/port/bindings/v8/ScriptController.cpp index 9f2a5be..4da169b 100644 --- a/webkit/port/bindings/v8/ScriptController.cpp +++ b/webkit/port/bindings/v8/ScriptController.cpp @@ -41,13 +41,13 @@ #include "Node.h" #include "NotImplemented.h" #include "npruntime_priv.h" -#include "np_v8object.h" +#include "NPV8Object.h" #include "ScriptSourceCode.h" #include "Widget.h" #include "v8_proxy.h" #include "v8_binding.h" -#include "v8_npobject.h" +#include "V8NPObject.h" NPRuntimeFunctions npruntime_functions = { NPN_GetStringIdentifier, @@ -382,7 +382,7 @@ static NPObject* createScriptObject(Frame* frame) DOMWindow* window = frame->domWindow(); v8::Handle global = V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, window); ASSERT(global->IsObject()); - return NPN_CreateScriptObject(0, v8::Handle::Cast(global), window); + return npCreateV8ScriptObject(0, v8::Handle::Cast(global), window); } NPObject* ScriptController::windowScriptNPObject() @@ -421,7 +421,7 @@ NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement if (!v8plugin->IsObject()) return createNoScriptObject(); - return NPN_CreateScriptObject(0, v8::Handle::Cast(v8plugin), window); + return npCreateV8ScriptObject(0, v8::Handle::Cast(v8plugin), window); } diff --git a/webkit/port/bindings/v8/V8NPObject.cpp b/webkit/port/bindings/v8/V8NPObject.cpp new file mode 100644 index 0000000..60e66a9 --- /dev/null +++ b/webkit/port/bindings/v8/V8NPObject.cpp @@ -0,0 +1,369 @@ +// Copyright (c) 2008, Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "v8_custom.h" +#include "v8_helpers.h" +#include "V8NPObject.h" +#include "V8NPUtils.h" +#include "NPV8Object.h" +#include "npruntime_priv.h" +#include "v8_proxy.h" +#include "dom_wrapper_map.h" +#include "HTMLPlugInElement.h" +#include "V8HTMLAppletElement.h" +#include "V8HTMLEmbedElement.h" +#include "V8HTMLObjectElement.h" + +using namespace WebCore; + +enum InvokeFunctionType { + INVOKE_METHOD = 1, + INVOKE_DEFAULT = 2 +}; + +// TODO(mbelshe): need comments. +// Params: holder could be HTMLEmbedElement or NPObject +static v8::Handle NPObjectInvokeImpl(const v8::Arguments& args, InvokeFunctionType funcId) +{ + NPObject* npobject; + + // These three types are subtypes of HTMLPlugInElement. + if (V8HTMLAppletElement::HasInstance(args.Holder()) || + V8HTMLEmbedElement::HasInstance(args.Holder()) || + V8HTMLObjectElement::HasInstance(args.Holder())) { + // The holder object is a subtype of HTMLPlugInElement. + HTMLPlugInElement* imp = V8Proxy::DOMWrapperToNode(args.Holder()); + ScriptInstance scriptInstance = imp->getInstance(); + if (scriptInstance) + npobject = V8Proxy::ToNativeObject(V8ClassIndex::NPOBJECT, scriptInstance->instance()); + else + npobject = NULL; + } else { + // The holder object is not a subtype of HTMLPlugInElement, it + // must be an NPObject which has three internal fields. + if (args.Holder()->InternalFieldCount() != V8Custom::kNPObjectInternalFieldCount) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPMethod called on non-NPObject"); + return v8::Undefined(); + } + npobject = V8Proxy::ToNativeObject(V8ClassIndex::NPOBJECT, args.Holder()); + } + + // Verify that our wrapper wasn't using a NPObject which + // has already been deleted. + if (!npobject || !_NPN_IsAlive(npobject)) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); + return v8::Undefined(); + } + + // wrap up parameters + int argc = args.Length(); + NPVariant* npArgs = new NPVariant[argc]; + + for (int i = 0; i < argc; i++) + convertV8ObjectToNPVariant(args[i], npobject, &npArgs[i]); + + NPVariant result; + VOID_TO_NPVARIANT(result); + + switch (funcId) { + case INVOKE_METHOD: + if (npobject->_class->invoke) { + v8::Handle function_name(v8::String::Cast(*args.Data())); + NPIdentifier ident = getStringIdentifier(function_name); + npobject->_class->invoke(npobject, ident, npArgs, argc, &result); + } + break; + case INVOKE_DEFAULT: + if (npobject->_class->invokeDefault) + npobject->_class->invokeDefault(npobject, npArgs, argc, &result); + break; + default: + break; + } + + for (int i=0; i < argc; i++) + NPN_ReleaseVariantValue(&npArgs[i]); + delete[] npArgs; + + // unwrap return values + v8::Handle rv = convertNPVariantToV8Object(&result, npobject); + NPN_ReleaseVariantValue(&result); + + return rv; +} + + +v8::Handle NPObjectMethodHandler(const v8::Arguments& args) +{ + return NPObjectInvokeImpl(args, INVOKE_METHOD); +} + + +v8::Handle NPObjectInvokeDefaultHandler(const v8::Arguments& args) +{ + return NPObjectInvokeImpl(args, INVOKE_DEFAULT); +} + + +static void WeakTemplateCallback(v8::Persistent obj, void* param); + +// NPIdentifier is PrivateIdentifier*. +static WeakReferenceMap \ + static_template_map(&WeakTemplateCallback); + +static void WeakTemplateCallback(v8::Persistent obj, void* param) +{ + PrivateIdentifier* iden = static_cast(param); + ASSERT(iden != NULL); + ASSERT(static_template_map.contains(iden)); + + static_template_map.forget(iden); +} + + +static v8::Handle NPObjectGetProperty(v8::Local self, + NPIdentifier ident, + v8::Local key) +{ + NPObject* npobject = V8Proxy::ToNativeObject(V8ClassIndex::NPOBJECT, self); + + // Verify that our wrapper wasn't using a NPObject which + // has already been deleted. + if (!npobject || !_NPN_IsAlive(npobject)) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); + return v8::Handle(); + } + + if (npobject->_class->hasProperty && + npobject->_class->hasProperty(npobject, ident) && + npobject->_class->getProperty) { + + NPVariant result; + VOID_TO_NPVARIANT(result); + if (!npobject->_class->getProperty(npobject, ident, &result)) + return v8::Handle(); + + v8::Handle rv = convertNPVariantToV8Object(&result, npobject); + NPN_ReleaseVariantValue(&result); + return rv; + } else if (key->IsString() && npobject->_class->hasMethod && npobject->_class->hasMethod(npobject, ident)) { + PrivateIdentifier* id = static_cast(ident); + v8::Persistent desc = static_template_map.get(id); + // Cache templates using identifier as the key. + if (desc.IsEmpty()) { + // Create a new template + v8::Local temp = v8::FunctionTemplate::New(); + temp->SetCallHandler(NPObjectMethodHandler, key); + desc = v8::Persistent::New(temp); + static_template_map.set(id, desc); + } + + // FunctionTemplate caches function for each context. + v8::Local func = desc->GetFunction(); + func->SetName(v8::Handle::Cast(key)); + return func; + } + + return v8::Handle(); +} + +v8::Handle NPObjectNamedPropertyGetter(v8::Local name, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectGetProperty(info.Holder(), ident, name); +} + +v8::Handle NPObjectIndexedPropertyGetter(uint32_t index, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectGetProperty(info.Holder(), ident, v8::Number::New(index)); +} + +v8::Handle NPObjectGetNamedProperty(v8::Local self, + v8::Local name) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectGetProperty(self, ident, name); +} + +v8::Handle NPObjectGetIndexedProperty(v8::Local self, + uint32_t index) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectGetProperty(self, ident, v8::Number::New(index)); +} + +static v8::Handle NPObjectSetProperty(v8::Local self, + NPIdentifier ident, + v8::Local value) +{ + NPObject* npobject = V8Proxy::ToNativeObject(V8ClassIndex::NPOBJECT, self); + + // Verify that our wrapper wasn't using a NPObject which + // has already been deleted. + if (!npobject || !_NPN_IsAlive(npobject)) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); + return value; // intercepted, but an exception was thrown + } + + if (npobject->_class->hasProperty && + npobject->_class->hasProperty(npobject, ident) && + npobject->_class->setProperty) { + + NPVariant npvalue; + VOID_TO_NPVARIANT(npvalue); + convertV8ObjectToNPVariant(value, npobject, &npvalue); + bool succ = npobject->_class->setProperty(npobject, ident, &npvalue); + NPN_ReleaseVariantValue(&npvalue); + if (succ) + return value; // intercept the call + } + return v8::Local(); // do not intercept the call +} + + +v8::Handle NPObjectNamedPropertySetter(v8::Local name, + v8::Local value, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectSetProperty(info.Holder(), ident, value); +} + + +v8::Handle NPObjectIndexedPropertySetter(uint32_t index, + v8::Local value, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectSetProperty(info.Holder(), ident, value); +} + +v8::Handle NPObjectSetNamedProperty(v8::Local self, + v8::Local name, + v8::Local value) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectSetProperty(self, ident, value); +} + +v8::Handle NPObjectSetIndexedProperty(v8::Local self, + uint32_t index, + v8::Local value) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectSetProperty(self, ident, value); +} + + +static void WeakNPObjectCallback(v8::Persistent obj, void* param); + +static DOMWrapperMap staticNpobjectMap(&WeakNPObjectCallback); + +static void WeakNPObjectCallback(v8::Persistent obj, void* param) +{ + NPObject* npobject = static_cast(param); + ASSERT(staticNpobjectMap.contains(npobject)); + ASSERT(npobject != NULL); + + // Must remove from our map before calling NPN_ReleaseObject(). + // NPN_ReleaseObject can call ForgetV8ObjectForNPObject, which + // uses the table as well. + staticNpobjectMap.forget(npobject); + + if (_NPN_IsAlive(npobject)) + NPN_ReleaseObject(npobject); +} + + +v8::Local CreateV8ObjectForNPObject(NPObject* object, NPObject* root) +{ + static v8::Persistent npObjectDesc; + + ASSERT(v8::Context::InContext()); + + // If this is a v8 object, just return it. + if (object->_class == npScriptObjectClass) { + V8NPObject* v8npobject = reinterpret_cast(object); + return v8::Local::New(v8npobject->v8Object); + } + + // If we've already wrapped this object, just return it. + if (staticNpobjectMap.contains(object)) + return v8::Local::New(staticNpobjectMap.get(object)); + + // TODO: we should create a Wrapper type as a subclass of JSObject. + // It has two internal fields, field 0 is the wrapped pointer, + // and field 1 is the type. There should be an api function that + // returns unused type id. + // The same Wrapper type can be used by DOM bindings. + if (npObjectDesc.IsEmpty()) { + npObjectDesc = v8::Persistent::New(v8::FunctionTemplate::New()); + npObjectDesc->InstanceTemplate()->SetInternalFieldCount(V8Custom::kNPObjectInternalFieldCount); + npObjectDesc->InstanceTemplate()->SetNamedPropertyHandler(NPObjectNamedPropertyGetter, NPObjectNamedPropertySetter); + npObjectDesc->InstanceTemplate()->SetIndexedPropertyHandler(NPObjectIndexedPropertyGetter, NPObjectIndexedPropertySetter); + npObjectDesc->InstanceTemplate()->SetCallAsFunctionHandler(NPObjectInvokeDefaultHandler); + } + + v8::Handle func = npObjectDesc->GetFunction(); + v8::Local value = SafeAllocation::NewInstance(func); + + // If we were unable to allocate the instance we avoid wrapping + // and registering the NP object. + if (value.IsEmpty()) + return value; + + WrapNPObject(value, object); + + // KJS retains the object as part of its wrapper (see Bindings::CInstance) + NPN_RetainObject(object); + + _NPN_RegisterObject(object, root); + + // Maintain a weak pointer for v8 so we can cleanup the object. + v8::Persistent weakRef = v8::Persistent::New(value); + staticNpobjectMap.set(object, weakRef); + + return value; +} + +void ForgetV8ObjectForNPObject(NPObject* object) +{ + if (staticNpobjectMap.contains(object)) { + v8::HandleScope scope; + v8::Persistent handle(staticNpobjectMap.get(object)); + WebCore::V8Proxy::SetDOMWrapper(handle, WebCore::V8ClassIndex::NPOBJECT, NULL); + staticNpobjectMap.forget(object); + NPN_ReleaseObject(object); + } +} diff --git a/webkit/port/bindings/v8/V8NPObject.h b/webkit/port/bindings/v8/V8NPObject.h new file mode 100644 index 0000000..c236c60 --- /dev/null +++ b/webkit/port/bindings/v8/V8NPObject.h @@ -0,0 +1,53 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_npobject_h +#define v8_npobject_h + +#include +#include "third_party/npapi/bindings/npruntime.h" + +// These functions can be replaced by normal JS operation. +// Getters +v8::Handle NPObjectNamedPropertyGetter(v8::Local name, + const v8::AccessorInfo& info); +v8::Handle NPObjectIndexedPropertyGetter(uint32_t index, + const v8::AccessorInfo& info); +v8::Handle NPObjectGetNamedProperty(v8::Local self, + v8::Local name); +v8::Handle NPObjectGetIndexedProperty(v8::Local self, + uint32_t index); + +// Setters +v8::Handle NPObjectNamedPropertySetter(v8::Local name, + v8::Local value, + const v8::AccessorInfo& info); +v8::Handle NPObjectIndexedPropertySetter(uint32_t index, + const v8::AccessorInfo& info); +v8::Handle NPObjectSetNamedProperty(v8::Local self, + v8::Local name, + v8::Local value); +v8::Handle NPObjectSetIndexedProperty(v8::Local self, + uint32_t index, + v8::Local value); + +v8::Handle NPObjectInvokeDefaultHandler(const v8::Arguments& args); + +// Get a wrapper for a NPObject. +// If the object is already wrapped, the pre-existing wrapper +// will be returned. +// If the object is not wrapped, wrap it, and give V8 a weak +// reference to the wrapper which will cleanup when there are +// no more JS references to the object. +v8::Local CreateV8ObjectForNPObject(NPObject* object, NPObject *root); + +// Tell V8 to forcibly remove an object. +// This is used at plugin teardown so that the caller can +// aggressively unload the plugin library. After calling this +// function, the persistent handle to the wrapper will be +// gone, and the wrapped NPObject will be removed so that +// it cannot be referred to. +void ForgetV8ObjectForNPObject(NPObject*object); + +#endif // v8_npobject_h diff --git a/webkit/port/bindings/v8/V8NPUtils.cpp b/webkit/port/bindings/v8/V8NPUtils.cpp new file mode 100644 index 0000000..04e6ede --- /dev/null +++ b/webkit/port/bindings/v8/V8NPUtils.cpp @@ -0,0 +1,124 @@ +// Copyright (c) 2008, Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "V8NPUtils.h" + +#include "DOMWindow.h" +#include "Frame.h" +#include "PlatformString.h" +#undef LOG + +#include "npruntime_priv.h" +#include "NPV8Object.h" +#include "V8NPObject.h" +#include "v8_proxy.h" + +void convertV8ObjectToNPVariant(v8::Local object, NPObject *owner, NPVariant* result) +{ + VOID_TO_NPVARIANT(*result); + + // It is really the caller's responsibility to deal with the empty handle + // case because there could be different actions to take in different + // contexts. + ASSERT(!object.IsEmpty()); + + if (object.IsEmpty()) + return; + + if (object->IsInt32()) + INT32_TO_NPVARIANT(object->NumberValue(), *result); + else if (object->IsNumber()) + DOUBLE_TO_NPVARIANT(object->NumberValue(), *result); + else if (object->IsBoolean()) + BOOLEAN_TO_NPVARIANT(object->BooleanValue(), *result); + else if (object->IsNull()) + NULL_TO_NPVARIANT(*result); + else if (object->IsUndefined()) + VOID_TO_NPVARIANT(*result); + else if (object->IsString()) { + v8::String::Utf8Value utf8(object); + char* utf8_chars = strdup(*utf8); + STRINGN_TO_NPVARIANT(utf8_chars, utf8.length(), *result); + } else if (object->IsObject()) { + WebCore::DOMWindow* window = WebCore::V8Proxy::retrieveWindow(); + NPObject* npobject = npCreateV8ScriptObject(0, v8::Handle::Cast(object), window); + if (npobject) + _NPN_RegisterObject(npobject, owner); + OBJECT_TO_NPVARIANT(npobject, *result); + } +} + + +v8::Handle convertNPVariantToV8Object(const NPVariant* variant, NPObject* npobject) +{ + NPVariantType type = variant->type; + + if (type == NPVariantType_Int32) + return v8::Integer::New(NPVARIANT_TO_INT32(*variant)); + if (type == NPVariantType_Double) + return v8::Number::New(NPVARIANT_TO_DOUBLE(*variant)); + if (type == NPVariantType_Bool) + return NPVARIANT_TO_BOOLEAN(*variant) ? v8::True() : v8::False(); + if (type == NPVariantType_Null) + return v8::Null(); + if (type == NPVariantType_Void) + return v8::Undefined(); + if (type == NPVariantType_String) { + NPString src = NPVARIANT_TO_STRING(*variant); + return v8::String::New(src.UTF8Characters, src.UTF8Length); + } + if (type == NPVariantType_Object) { + NPObject* obj = NPVARIANT_TO_OBJECT(*variant); + if (obj->_class == npScriptObjectClass) + return reinterpret_cast(obj)->v8Object; + return CreateV8ObjectForNPObject(obj, npobject); + } + return v8::Undefined(); +} + +// Helper function to create an NPN String Identifier from a v8 string. +NPIdentifier getStringIdentifier(v8::Handle str) +{ + const int kStackBufSize = 100; + + int bufLen = str->Length() + 1; + if (bufLen <= kStackBufSize) { + // Use local stack buffer to avoid heap allocations for small strings. + // Here we should only use the stack space for stack_buf when it's used, + // not when we use the heap. + char stackBuf[kStackBufSize]; + str->WriteAscii(stackBuf); + return NPN_GetStringIdentifier(stackBuf); + } + + v8::String::AsciiValue ascii(str); + return NPN_GetStringIdentifier(*ascii); +} diff --git a/webkit/port/bindings/v8/V8NPUtils.h b/webkit/port/bindings/v8/V8NPUtils.h new file mode 100644 index 0000000..4b6fc2b --- /dev/null +++ b/webkit/port/bindings/v8/V8NPUtils.h @@ -0,0 +1,28 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_np_utils_h +#define v8_np_utils_h + +#include +#include "third_party/npapi/bindings/npruntime.h" + +namespace WebCore { + class Frame; +} + +// Convert a V8 Value of any type (string, bool, object, etc) to a NPVariant. +void convertV8ObjectToNPVariant(v8::Local object, NPObject *owner, NPVariant* result); + +// Convert a NPVariant (string, bool, object, etc) back to a V8 Value. +// The owner object is the NPObject which relates to the object, if the object +// is an Object. The created NPObject will be tied to the lifetime of the +// owner. +v8::Handle convertNPVariantToV8Object(const NPVariant* value, NPObject* owner); + +// Helper function to create an NPN String Identifier from a v8 string. +NPIdentifier getStringIdentifier(v8::Handle str); + +#endif // v8_np_utils_h + diff --git a/webkit/port/bindings/v8/np_v8object.cpp b/webkit/port/bindings/v8/np_v8object.cpp deleted file mode 100644 index 731bd9d..0000000 --- a/webkit/port/bindings/v8/np_v8object.cpp +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. - * Copyright (C) 2007 Google, 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include - -#define max max -#define min min -#include -#include "np_v8object.h" -#include "ChromiumBridge.h" -#include "Frame.h" -#include "bindings/npruntime.h" -#include "npruntime_priv.h" -#include "PlatformString.h" -#include "ScriptController.h" -#include "v8_custom.h" -#include "v8_helpers.h" -#include "v8_np_utils.h" -#include "v8_proxy.h" -#include "DOMWindow.h" - -using WebCore::V8ClassIndex; -using WebCore::V8Custom; -using WebCore::V8Proxy; - -// TODO(mbelshe): comments on why use malloc and free. -static NPObject* AllocV8NPObject(NPP, NPClass*) -{ - return static_cast(malloc(sizeof(V8NPObject))); -} - -static void FreeV8NPObject(NPObject* npobj) -{ - V8NPObject *object = reinterpret_cast(npobj); -#ifndef NDEBUG - V8Proxy::UnregisterGlobalHandle(object, object->v8Object); -#endif - object->v8Object.Dispose(); - free(object); -} - -static v8::Handle* listFromVariantArgs(const NPVariant* args, - uint32_t argCount, - NPObject *owner) -{ - v8::Handle* argv = new v8::Handle[argCount]; - for (uint32_t index = 0; index < argCount; index++) { - const NPVariant *arg = &args[index]; - argv[index] = ConvertNPVariantToV8Object(arg, owner); - } - return argv; -} - -// Create an identifier (null terminated utf8 char*) from the NPIdentifier. -static v8::Local NPIdentifierToV8Identifier(NPIdentifier name) -{ - PrivateIdentifier* identifier = static_cast(name); - if (identifier->isString) - return v8::String::New(static_cast(identifier->value.string)); - - char buf[32]; - sprintf(buf, "%d", identifier->value.number); - return v8::String::New(buf); -} - -static NPClass V8NPObjectClass = { NP_CLASS_STRUCT_VERSION, - AllocV8NPObject, - FreeV8NPObject, - 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -// NPAPI's npruntime functions -NPClass* NPScriptObjectClass = &V8NPObjectClass; - -NPObject* NPN_CreateScriptObject(NPP npp, v8::Handle object, WebCore::DOMWindow* root) -{ - // Check to see if this object is already wrapped. - if (object->InternalFieldCount() == V8Custom::kNPObjectInternalFieldCount && - object->GetInternalField(V8Custom::kDOMWrapperTypeIndex)->IsNumber() && - object->GetInternalField(V8Custom::kDOMWrapperTypeIndex)->Uint32Value() == V8ClassIndex::NPOBJECT) { - - NPObject* rv = V8Proxy::ToNativeObject(V8ClassIndex::NPOBJECT, object); - NPN_RetainObject(rv); - return rv; - } - - V8NPObject* obj = reinterpret_cast(NPN_CreateObject(npp, &V8NPObjectClass)); - obj->v8Object = v8::Persistent::New(object); -#ifndef NDEBUG - V8Proxy::RegisterGlobalHandle(WebCore::NPOBJECT, obj, obj->v8Object); -#endif - obj->rootObject = root; - return reinterpret_cast(obj); -} - -bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName, - const NPVariant *args, uint32_t argCount, NPVariant *result) -{ - if (!npobj) - return false; - - if (npobj->_class == NPScriptObjectClass) { - V8NPObject *object = reinterpret_cast(npobj); - - PrivateIdentifier *identifier = static_cast(methodName); - if (!identifier->isString) - return false; - - v8::HandleScope handleScope; - // TODO: should use the plugin's owner frame as the security context - v8::Handle context = GetV8Context(npp, npobj); - if (context.IsEmpty()) - return false; - - v8::Context::Scope scope(context); - - // Special case the "eval" method. - if (methodName == NPN_GetStringIdentifier("eval")) { - if (argCount != 1) - return false; - if (args[0].type != NPVariantType_String) - return false; - return NPN_Evaluate(npp, npobj, const_cast(&args[0].value.stringValue), result); - } - - v8::Handle funcObj = object->v8Object->Get(v8::String::New(identifier->value.string)); - if (funcObj.IsEmpty() || funcObj->IsNull()) { - NULL_TO_NPVARIANT(*result); - return false; - } - if (funcObj->IsUndefined()) { - VOID_TO_NPVARIANT(*result); - return false; - } - - WebCore::V8Proxy* proxy = GetV8Proxy(npobj); - ASSERT(proxy); // must not be null - - // TODO: fix variable naming - // Call the function object - v8::Handle func = v8::Handle::Cast(funcObj); - // Create list of args to pass to v8 - v8::Handle* argv = listFromVariantArgs(args, argCount, npobj); - v8::Local resultObj = proxy->CallFunction(func, object->v8Object, argCount, argv); - delete[] argv; - - // If we had an error, return false. The spec is a little unclear here, but - // says "Returns true if the method was successfully invoked". If we get an - // error return value, was that successfully invoked? - if (resultObj.IsEmpty()) - return false; - - // Convert the result back to an NPVariant - ConvertV8ObjectToNPVariant(resultObj, npobj, result); - return true; - } - - if (npobj->_class->invoke) - return npobj->_class->invoke(npobj, methodName, args, argCount, result); - - VOID_TO_NPVARIANT(*result); - return true; -} - - -// TODO: Fix it same as NPN_Invoke (HandleScope and such) -bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args, - uint32_t argCount, NPVariant *result) -{ - if (!npobj) - return false; - - if (npobj->_class == NPScriptObjectClass) { - V8NPObject *object = reinterpret_cast(npobj); - - VOID_TO_NPVARIANT(*result); - - v8::HandleScope handleScope; - v8::Handle context = GetV8Context(npp, npobj); - if (context.IsEmpty()) - return false; - - v8::Context::Scope scope(context); - - // Lookup the function object - v8::Handle funcObj(object->v8Object); - if (!funcObj->IsFunction()) - return false; - - // Call the function object - v8::Local resultObj; - v8::Handle func(v8::Function::Cast(*funcObj)); - if (!func->IsNull()) { - WebCore::V8Proxy* proxy = GetV8Proxy(npobj); - ASSERT(proxy); - - // Create list of args to pass to v8 - v8::Handle* argv = listFromVariantArgs(args, argCount, npobj); - resultObj = proxy->CallFunction(func, funcObj, argCount, argv); - delete[] argv; - } - - // If we had an error, return false. The spec is a little unclear here, but - // says "Returns true if the method was successfully invoked". If we get an - // error return value, was that successfully invoked? - if (resultObj.IsEmpty()) - return false; - - // Convert the result back to an NPVariant. - ConvertV8ObjectToNPVariant(resultObj, npobj, result); - return true; - } - - if (npobj->_class->invokeDefault) - return npobj->_class->invokeDefault(npobj, args, argCount, result); - - VOID_TO_NPVARIANT(*result); - return true; -} - -bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *npscript, NPVariant *result) -{ - bool popupsAllowed = WebCore::ChromiumBridge::popupsAllowed(npp); - return NPN_EvaluateHelper(npp, popupsAllowed, npobj, npscript, result); -} - -bool NPN_EvaluateHelper(NPP npp, bool popupsAllowed, NPObject* npobj, NPString* npscript, NPVariant *result) -{ - VOID_TO_NPVARIANT(*result); - if (!npobj) - return false; - - if (npobj->_class != NPScriptObjectClass) - return false; - - v8::HandleScope handleScope; - v8::Handle context = GetV8Context(npp, npobj); - if (context.IsEmpty()) - return false; - - WebCore::V8Proxy* proxy = GetV8Proxy(npobj); - ASSERT(proxy); - - v8::Context::Scope scope(context); - - WebCore::String filename; - if (!popupsAllowed) - filename = "npscript"; - - // Convert UTF-8 stream to WebCore::String. - WebCore::String script = WebCore::String::fromUTF8(npscript->UTF8Characters, npscript->UTF8Length); - v8::Local v8result = proxy->Evaluate(filename, 0, script, 0); - - // If we had an error, return false. - if (v8result.IsEmpty()) - return false; - - ConvertV8ObjectToNPVariant(v8result, npobj, result); - return true; -} - -bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, NPVariant *result) -{ - if (!npobj) - return false; - - if (npobj->_class == NPScriptObjectClass) { - V8NPObject *object = reinterpret_cast(npobj); - - v8::HandleScope handleScope; - v8::Handle context = GetV8Context(npp, npobj); - if (context.IsEmpty()) - return false; - - v8::Context::Scope scope(context); - - v8::Handle obj(object->v8Object); - v8::Local v8result = obj->Get(NPIdentifierToV8Identifier(propertyName)); - - ConvertV8ObjectToNPVariant(v8result, npobj, result); - return true; - } - - if (npobj->_class->hasProperty && npobj->_class->getProperty) { - if (npobj->_class->hasProperty(npobj, propertyName)) - return npobj->_class->getProperty(npobj, propertyName, result); - } - - VOID_TO_NPVARIANT(*result); - return false; -} - -bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) -{ - if (!npobj) - return false; - - if (npobj->_class == NPScriptObjectClass) { - V8NPObject *object = reinterpret_cast(npobj); - - v8::HandleScope handleScope; - v8::Handle context = GetV8Context(npp, npobj); - if (context.IsEmpty()) - return false; - - v8::Context::Scope scope(context); - - v8::Handle obj(object->v8Object); - obj->Set(NPIdentifierToV8Identifier(propertyName), - ConvertNPVariantToV8Object(value, object->rootObject->frame()->script()->windowScriptNPObject())); - return true; - } - - if (npobj->_class->setProperty) - return npobj->_class->setProperty(npobj, propertyName, value); - - return false; -} - -bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName) -{ - if (!npobj) - return false; - if (npobj->_class != NPScriptObjectClass) - return false; - - V8NPObject *object = reinterpret_cast(npobj); - - v8::HandleScope handleScope; - v8::Handle context = GetV8Context(npp, npobj); - if (context.IsEmpty()) - return false; - v8::Context::Scope scope(context); - - v8::Handle obj(object->v8Object); - // TODO(mbelshe) - verify that setting to undefined is right. - obj->Set(NPIdentifierToV8Identifier(propertyName), v8::Undefined()); - return true; -} - -bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName) -{ - if (!npobj) - return false; - - if (npobj->_class == NPScriptObjectClass) { - V8NPObject *object = reinterpret_cast(npobj); - - v8::HandleScope handleScope; - v8::Handle context = GetV8Context(npp, npobj); - if (context.IsEmpty()) - return false; - v8::Context::Scope scope(context); - - v8::Handle obj(object->v8Object); - return obj->Has(NPIdentifierToV8Identifier(propertyName)); - } - - if (npobj->_class->hasProperty) - return npobj->_class->hasProperty(npobj, propertyName); - return false; -} - -bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName) -{ - if (!npobj) - return false; - - if (npobj->_class == NPScriptObjectClass) { - V8NPObject *object = reinterpret_cast(npobj); - - v8::HandleScope handleScope; - v8::Handle context = GetV8Context(npp, npobj); - if (context.IsEmpty()) - return false; - v8::Context::Scope scope(context); - - v8::Handle obj(object->v8Object); - v8::Handle prop = obj->Get(NPIdentifierToV8Identifier(methodName)); - return prop->IsFunction(); - } - - if (npobj->_class->hasMethod) - return npobj->_class->hasMethod(npobj, methodName); - return false; -} - -void NPN_SetException(NPObject *npobj, const NPUTF8 *message) -{ - if (npobj->_class != NPScriptObjectClass) - return; - v8::HandleScope handleScope; - v8::Handle context = GetV8Context(0, npobj); - if (context.IsEmpty()) - return; - - v8::Context::Scope scope(context); - V8Proxy::ThrowError(V8Proxy::GENERAL_ERROR, message); -} - -bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count) -{ - if (!npobj) - return false; - - if (npobj->_class == NPScriptObjectClass) { - V8NPObject *object = reinterpret_cast(npobj); - - v8::HandleScope handleScope; - v8::Handle context = GetV8Context(npp, npobj); - if (context.IsEmpty()) - return false; - v8::Context::Scope scope(context); - - v8::Handle obj(object->v8Object); - - // TODO(fqian): http://b/issue?id=1210340: Use a v8::Object::Keys() method - // when it exists, instead of evaluating javascript. - - // TODO(mpcomplete): figure out how to cache this helper function. - // Run a helper function that collects the properties on the object into - // an array. - const char kEnumeratorCode[] = - "(function (obj) {" - " var props = [];" - " for (var prop in obj) {" - " props[props.length] = prop;" - " }" - " return props;" - "});"; - v8::Handle source = v8::String::New(kEnumeratorCode); - v8::Handle script = v8::Script::Compile(source, 0); - v8::Handle enumeratorObj = script->Run(); - v8::Handle enumerator = v8::Handle::Cast(enumeratorObj); - v8::Handle argv[] = { obj }; - v8::Local propsObj = enumerator->Call(v8::Handle::Cast(enumeratorObj), ARRAYSIZE_UNSAFE(argv), argv); - if (propsObj.IsEmpty()) - return false; - - // Convert the results into an array of NPIdentifiers. - v8::Handle props = v8::Handle::Cast(propsObj); - *count = props->Length(); - *identifier = static_cast(malloc(sizeof(NPIdentifier*) * *count)); - for (uint32_t i = 0; i < *count; ++i) { - v8::Local name = props->Get(v8::Integer::New(i)); - (*identifier)[i] = GetStringIdentifier(v8::Local::Cast(name)); - } - return true; - } - - if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) && npobj->_class->enumerate) - return npobj->_class->enumerate(npobj, identifier, count); - - return false; -} - -bool NPN_Construct(NPP npp, NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) -{ - if (!npobj) - return false; - - // TODO(estade): implement this case. - if (npobj->_class == NPScriptObjectClass) { - VOID_TO_NPVARIANT(*result); - return false; - } - - if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) && npobj->_class->construct) - return npobj->_class->construct(npobj, args, argCount, result); - - return false; -} diff --git a/webkit/port/bindings/v8/np_v8object.h b/webkit/port/bindings/v8/np_v8object.h deleted file mode 100644 index cd89b5a..0000000 --- a/webkit/port/bindings/v8/np_v8object.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef np_v8object_h -#define np_v8object_h - -#include "third_party/npapi/bindings/npruntime.h" -#include - -namespace WebCore { - class DOMWindow; -} - -extern NPClass* NPScriptObjectClass; - -// A V8NPObject is a NPObject which carries additional V8-specific -// information. It is allocated and deallocated by AllocV8NPObject() -// and FreeV8NPObject() methods. -struct V8NPObject { - NPObject object; - v8::Persistent v8Object; - WebCore::DOMWindow* rootObject; -}; - -struct PrivateIdentifier { - union { - const NPUTF8* string; - int32_t number; - } value; - bool isString; -}; - -NPObject* NPN_CreateScriptObject(NPP npp, v8::Handle, WebCore::DOMWindow*); -NPObject* NPN_CreateNoScriptObject(); - -#endif // np_v8object_h - diff --git a/webkit/port/bindings/v8/npruntime.cpp b/webkit/port/bindings/v8/npruntime.cpp index 9b21c36..f95d621 100644 --- a/webkit/port/bindings/v8/npruntime.cpp +++ b/webkit/port/bindings/v8/npruntime.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. - * Copyright (C) 2007 Google, Inc. All rights reserved. + * Copyright (C) 2007-2009 Google, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,16 +33,16 @@ #include "bindings/npruntime.h" #include "ChromiumBridge.h" -#include "np_v8object.h" +#include "NPV8Object.h" #include "npruntime_priv.h" -#include "v8_npobject.h" +#include "V8NPObject.h" #include using namespace v8; -// TODO: Consider removing locks if we're singlethreaded already. +// FIXME: Consider removing locks if we're singlethreaded already. // The static initializer here should work okay, but we want to avoid // static initialization in general. // @@ -81,7 +81,7 @@ static StringIdentifierMap* getStringIdentifierMap() { return stringIdentifierMap; } -// TODO: Consider removing locks if we're singlethreaded already. +// FIXME: Consider removing locks if we're singlethreaded already. // static Lock IntIdentifierMapLock; typedef std::map IntIdentifierMap; diff --git a/webkit/port/bindings/v8/v8_custom.cpp b/webkit/port/bindings/v8/v8_custom.cpp index 32a5f14..f5e3e5a 100644 --- a/webkit/port/bindings/v8/v8_custom.cpp +++ b/webkit/port/bindings/v8/v8_custom.cpp @@ -29,7 +29,7 @@ #include "v8_proxy.h" #include "v8_events.h" #include "v8_binding.h" -#include "v8_npobject.h" +#include "V8NPObject.h" #include "v8_custom.h" #include "V8Attr.h" diff --git a/webkit/port/bindings/v8/v8_helpers.cpp b/webkit/port/bindings/v8/v8_helpers.cpp index f09c2e0..7a72ab5e 100644 --- a/webkit/port/bindings/v8/v8_helpers.cpp +++ b/webkit/port/bindings/v8/v8_helpers.cpp @@ -34,7 +34,7 @@ #include "v8_helpers.h" #include "v8_proxy.h" #include "v8_index.h" -#include "np_v8object.h" +#include "NPV8Object.h" #include "DOMWindow.h" @@ -45,7 +45,7 @@ void WrapNPObject(v8::Handle obj, NPObject* npobj) WebCore::V8Proxy::SetDOMWrapper(obj, WebCore::V8ClassIndex::NPOBJECT, npobj); } -v8::Local GetV8Context(NPP npp, NPObject* npobj) +v8::Local getV8Context(NPP npp, NPObject* npobj) { V8NPObject* object = reinterpret_cast(npobj); return WebCore::V8Proxy::GetContext(object->rootObject->frame()); diff --git a/webkit/port/bindings/v8/v8_helpers.h b/webkit/port/bindings/v8/v8_helpers.h index 28d7bf1..4c49a4a 100644 --- a/webkit/port/bindings/v8/v8_helpers.h +++ b/webkit/port/bindings/v8/v8_helpers.h @@ -16,7 +16,7 @@ namespace WebCore { void WrapNPObject(v8::Handle obj, NPObject *npobj); // Retrieves the V8 Context from the NP context pr obj (at most 1 may be NULL). -v8::Local GetV8Context(NPP npp, NPObject* npobj); +v8::Local getV8Context(NPP npp, NPObject* npobj); // Get V8Proxy object from an NPObject. WebCore::V8Proxy* GetV8Proxy(NPObject* npobj); diff --git a/webkit/port/bindings/v8/v8_np_utils.cpp b/webkit/port/bindings/v8/v8_np_utils.cpp deleted file mode 100644 index f7bb20a..0000000 --- a/webkit/port/bindings/v8/v8_np_utils.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2008, Google 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: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "config.h" - -#include "v8_np_utils.h" - -#include "DOMWindow.h" -#include "Frame.h" -#include "PlatformString.h" -#undef LOG - -#include "npruntime_priv.h" -#include "np_v8object.h" -#include "v8_npobject.h" -#include "v8_proxy.h" - -void ConvertV8ObjectToNPVariant(v8::Local object, NPObject *owner, NPVariant* result) -{ - VOID_TO_NPVARIANT(*result); - - // It is really the caller's responsibility to deal with the empty handle - // case because there could be different actions to take in different - // contexts. - ASSERT(!object.IsEmpty()); - - if (object.IsEmpty()) - return; - - if (object->IsInt32()) - INT32_TO_NPVARIANT(object->NumberValue(), *result); - else if (object->IsNumber()) - DOUBLE_TO_NPVARIANT(object->NumberValue(), *result); - else if (object->IsBoolean()) - BOOLEAN_TO_NPVARIANT(object->BooleanValue(), *result); - else if (object->IsNull()) - NULL_TO_NPVARIANT(*result); - else if (object->IsUndefined()) - VOID_TO_NPVARIANT(*result); - else if (object->IsString()) { - v8::String::Utf8Value utf8(object); - char* utf8_chars = strdup(*utf8); - STRINGN_TO_NPVARIANT(utf8_chars, utf8.length(), *result); - } else if (object->IsObject()) { - WebCore::DOMWindow* window = WebCore::V8Proxy::retrieveWindow(); - NPObject* npobject = NPN_CreateScriptObject(0, v8::Handle::Cast(object), window); - if (npobject) - _NPN_RegisterObject(npobject, owner); - OBJECT_TO_NPVARIANT(npobject, *result); - } -} - - -v8::Handle ConvertNPVariantToV8Object(const NPVariant* variant, NPObject* npobject) -{ - NPVariantType type = variant->type; - - if (type == NPVariantType_Int32) - return v8::Integer::New(NPVARIANT_TO_INT32(*variant)); - if (type == NPVariantType_Double) - return v8::Number::New(NPVARIANT_TO_DOUBLE(*variant)); - if (type == NPVariantType_Bool) - return NPVARIANT_TO_BOOLEAN(*variant) ? v8::True() : v8::False(); - if (type == NPVariantType_Null) - return v8::Null(); - if (type == NPVariantType_Void) - return v8::Undefined(); - if (type == NPVariantType_String) { - NPString src = NPVARIANT_TO_STRING(*variant); - return v8::String::New(src.UTF8Characters, src.UTF8Length); - } - if (type == NPVariantType_Object) { - NPObject* obj = NPVARIANT_TO_OBJECT(*variant); - if (obj->_class == NPScriptObjectClass) - return reinterpret_cast(obj)->v8Object; - return CreateV8ObjectForNPObject(obj, npobject); - } - return v8::Undefined(); -} - -// Helper function to create an NPN String Identifier from a v8 string. -NPIdentifier GetStringIdentifier(v8::Handle str) -{ - const int kStackBufSize = 100; - - int bufLen = str->Length() + 1; - if (bufLen <= kStackBufSize) { - // Use local stack buffer to avoid heap allocations for small strings. - // Here we should only use the stack space for stack_buf when it's used, - // not when we use the heap. - char stackBuf[kStackBufSize]; - str->WriteAscii(stackBuf); - return NPN_GetStringIdentifier(stackBuf); - } - - v8::String::AsciiValue ascii(str); - return NPN_GetStringIdentifier(*ascii); -} diff --git a/webkit/port/bindings/v8/v8_np_utils.h b/webkit/port/bindings/v8/v8_np_utils.h deleted file mode 100644 index 6e8290b..0000000 --- a/webkit/port/bindings/v8/v8_np_utils.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef v8_np_utils_h -#define v8_np_utils_h - -#include -#include "third_party/npapi/bindings/npruntime.h" - -namespace WebCore { - class Frame; -} - -// Convert a V8 Value of any type (string, bool, object, etc) to a NPVariant. -void ConvertV8ObjectToNPVariant(v8::Local object, NPObject *owner, NPVariant* result); - -// Convert a NPVariant (string, bool, object, etc) back to a V8 Value. -// The owner object is the NPObject which relates to the object, if the object -// is an Object. The created NPObject will be tied to the lifetime of the -// owner. -v8::Handle ConvertNPVariantToV8Object(const NPVariant* value, NPObject* owner); - -// Helper function to create an NPN String Identifier from a v8 string. -NPIdentifier GetStringIdentifier(v8::Handle str); - -#endif // v8_np_utils_h - diff --git a/webkit/port/bindings/v8/v8_npobject.cpp b/webkit/port/bindings/v8/v8_npobject.cpp deleted file mode 100644 index cdb9bee..0000000 --- a/webkit/port/bindings/v8/v8_npobject.cpp +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright (c) 2008, Google 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: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "config.h" - -#include "v8_custom.h" -#include "v8_helpers.h" -#include "v8_npobject.h" -#include "v8_np_utils.h" -#include "np_v8object.h" -#include "npruntime_priv.h" -#include "v8_proxy.h" -#include "dom_wrapper_map.h" -#include "HTMLPlugInElement.h" -#include "V8HTMLAppletElement.h" -#include "V8HTMLEmbedElement.h" -#include "V8HTMLObjectElement.h" - -using namespace WebCore; - -enum InvokeFunctionType { - INVOKE_METHOD = 1, - INVOKE_DEFAULT = 2 -}; - -// TODO(mbelshe): need comments. -// Params: holder could be HTMLEmbedElement or NPObject -static v8::Handle NPObjectInvokeImpl(const v8::Arguments& args, InvokeFunctionType funcId) -{ - NPObject* npobject; - - // These three types are subtypes of HTMLPlugInElement. - if (V8HTMLAppletElement::HasInstance(args.Holder()) || - V8HTMLEmbedElement::HasInstance(args.Holder()) || - V8HTMLObjectElement::HasInstance(args.Holder())) { - // The holder object is a subtype of HTMLPlugInElement. - HTMLPlugInElement* imp = V8Proxy::DOMWrapperToNode(args.Holder()); - ScriptInstance scriptInstance = imp->getInstance(); - if (scriptInstance) - npobject = V8Proxy::ToNativeObject(V8ClassIndex::NPOBJECT, scriptInstance->instance()); - else - npobject = NULL; - } else { - // The holder object is not a subtype of HTMLPlugInElement, it - // must be an NPObject which has three internal fields. - if (args.Holder()->InternalFieldCount() != V8Custom::kNPObjectInternalFieldCount) { - V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPMethod called on non-NPObject"); - return v8::Undefined(); - } - npobject = V8Proxy::ToNativeObject(V8ClassIndex::NPOBJECT, args.Holder()); - } - - // Verify that our wrapper wasn't using a NPObject which - // has already been deleted. - if (!npobject || !_NPN_IsAlive(npobject)) { - V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); - return v8::Undefined(); - } - - // wrap up parameters - int argc = args.Length(); - NPVariant* npArgs = new NPVariant[argc]; - - for (int i = 0; i < argc; i++) - ConvertV8ObjectToNPVariant(args[i], npobject, &npArgs[i]); - - NPVariant result; - VOID_TO_NPVARIANT(result); - - switch (funcId) { - case INVOKE_METHOD: - if (npobject->_class->invoke) { - v8::Handle function_name(v8::String::Cast(*args.Data())); - NPIdentifier ident = GetStringIdentifier(function_name); - npobject->_class->invoke(npobject, ident, npArgs, argc, &result); - } - break; - case INVOKE_DEFAULT: - if (npobject->_class->invokeDefault) - npobject->_class->invokeDefault(npobject, npArgs, argc, &result); - break; - default: - break; - } - - for (int i=0; i < argc; i++) - NPN_ReleaseVariantValue(&npArgs[i]); - delete[] npArgs; - - // unwrap return values - v8::Handle rv = ConvertNPVariantToV8Object(&result, npobject); - NPN_ReleaseVariantValue(&result); - - return rv; -} - - -v8::Handle NPObjectMethodHandler(const v8::Arguments& args) -{ - return NPObjectInvokeImpl(args, INVOKE_METHOD); -} - - -v8::Handle NPObjectInvokeDefaultHandler(const v8::Arguments& args) -{ - return NPObjectInvokeImpl(args, INVOKE_DEFAULT); -} - - -static void WeakTemplateCallback(v8::Persistent obj, void* param); - -// NPIdentifier is PrivateIdentifier*. -static WeakReferenceMap \ - static_template_map(&WeakTemplateCallback); - -static void WeakTemplateCallback(v8::Persistent obj, void* param) -{ - PrivateIdentifier* iden = static_cast(param); - ASSERT(iden != NULL); - ASSERT(static_template_map.contains(iden)); - - static_template_map.forget(iden); -} - - -static v8::Handle NPObjectGetProperty(v8::Local self, - NPIdentifier ident, - v8::Local key) -{ - NPObject* npobject = V8Proxy::ToNativeObject(V8ClassIndex::NPOBJECT, self); - - // Verify that our wrapper wasn't using a NPObject which - // has already been deleted. - if (!npobject || !_NPN_IsAlive(npobject)) { - V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); - return v8::Handle(); - } - - if (npobject->_class->hasProperty && - npobject->_class->hasProperty(npobject, ident) && - npobject->_class->getProperty) { - - NPVariant result; - VOID_TO_NPVARIANT(result); - if (!npobject->_class->getProperty(npobject, ident, &result)) - return v8::Handle(); - - v8::Handle rv = ConvertNPVariantToV8Object(&result, npobject); - NPN_ReleaseVariantValue(&result); - return rv; - } else if (key->IsString() && npobject->_class->hasMethod && npobject->_class->hasMethod(npobject, ident)) { - PrivateIdentifier* id = static_cast(ident); - v8::Persistent desc = static_template_map.get(id); - // Cache templates using identifier as the key. - if (desc.IsEmpty()) { - // Create a new template - v8::Local temp = v8::FunctionTemplate::New(); - temp->SetCallHandler(NPObjectMethodHandler, key); - desc = v8::Persistent::New(temp); - static_template_map.set(id, desc); - } - - // FunctionTemplate caches function for each context. - v8::Local func = desc->GetFunction(); - func->SetName(v8::Handle::Cast(key)); - return func; - } - - return v8::Handle(); -} - -v8::Handle NPObjectNamedPropertyGetter(v8::Local name, - const v8::AccessorInfo& info) -{ - NPIdentifier ident = GetStringIdentifier(name); - return NPObjectGetProperty(info.Holder(), ident, name); -} - -v8::Handle NPObjectIndexedPropertyGetter(uint32_t index, - const v8::AccessorInfo& info) -{ - NPIdentifier ident = NPN_GetIntIdentifier(index); - return NPObjectGetProperty(info.Holder(), ident, v8::Number::New(index)); -} - -v8::Handle NPObjectGetNamedProperty(v8::Local self, - v8::Local name) -{ - NPIdentifier ident = GetStringIdentifier(name); - return NPObjectGetProperty(self, ident, name); -} - -v8::Handle NPObjectGetIndexedProperty(v8::Local self, - uint32_t index) -{ - NPIdentifier ident = NPN_GetIntIdentifier(index); - return NPObjectGetProperty(self, ident, v8::Number::New(index)); -} - -static v8::Handle NPObjectSetProperty(v8::Local self, - NPIdentifier ident, - v8::Local value) -{ - NPObject* npobject = V8Proxy::ToNativeObject(V8ClassIndex::NPOBJECT, self); - - // Verify that our wrapper wasn't using a NPObject which - // has already been deleted. - if (!npobject || !_NPN_IsAlive(npobject)) { - V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); - return value; // intercepted, but an exception was thrown - } - - if (npobject->_class->hasProperty && - npobject->_class->hasProperty(npobject, ident) && - npobject->_class->setProperty) { - - NPVariant npvalue; - VOID_TO_NPVARIANT(npvalue); - ConvertV8ObjectToNPVariant(value, npobject, &npvalue); - bool succ = npobject->_class->setProperty(npobject, ident, &npvalue); - NPN_ReleaseVariantValue(&npvalue); - if (succ) - return value; // intercept the call - } - return v8::Local(); // do not intercept the call -} - - -v8::Handle NPObjectNamedPropertySetter(v8::Local name, - v8::Local value, - const v8::AccessorInfo& info) -{ - NPIdentifier ident = GetStringIdentifier(name); - return NPObjectSetProperty(info.Holder(), ident, value); -} - - -v8::Handle NPObjectIndexedPropertySetter(uint32_t index, - v8::Local value, - const v8::AccessorInfo& info) -{ - NPIdentifier ident = NPN_GetIntIdentifier(index); - return NPObjectSetProperty(info.Holder(), ident, value); -} - -v8::Handle NPObjectSetNamedProperty(v8::Local self, - v8::Local name, - v8::Local value) -{ - NPIdentifier ident = GetStringIdentifier(name); - return NPObjectSetProperty(self, ident, value); -} - -v8::Handle NPObjectSetIndexedProperty(v8::Local self, - uint32_t index, - v8::Local value) -{ - NPIdentifier ident = NPN_GetIntIdentifier(index); - return NPObjectSetProperty(self, ident, value); -} - - -static void WeakNPObjectCallback(v8::Persistent obj, void* param); - -static DOMWrapperMap staticNpobjectMap(&WeakNPObjectCallback); - -static void WeakNPObjectCallback(v8::Persistent obj, void* param) -{ - NPObject* npobject = static_cast(param); - ASSERT(staticNpobjectMap.contains(npobject)); - ASSERT(npobject != NULL); - - // Must remove from our map before calling NPN_ReleaseObject(). - // NPN_ReleaseObject can call ForgetV8ObjectForNPObject, which - // uses the table as well. - staticNpobjectMap.forget(npobject); - - if (_NPN_IsAlive(npobject)) - NPN_ReleaseObject(npobject); -} - - -v8::Local CreateV8ObjectForNPObject(NPObject* object, NPObject* root) -{ - static v8::Persistent npObjectDesc; - - ASSERT(v8::Context::InContext()); - - // If this is a v8 object, just return it. - if (object->_class == NPScriptObjectClass) { - V8NPObject* v8npobject = reinterpret_cast(object); - return v8::Local::New(v8npobject->v8Object); - } - - // If we've already wrapped this object, just return it. - if (staticNpobjectMap.contains(object)) - return v8::Local::New(staticNpobjectMap.get(object)); - - // TODO: we should create a Wrapper type as a subclass of JSObject. - // It has two internal fields, field 0 is the wrapped pointer, - // and field 1 is the type. There should be an api function that - // returns unused type id. - // The same Wrapper type can be used by DOM bindings. - if (npObjectDesc.IsEmpty()) { - npObjectDesc = v8::Persistent::New(v8::FunctionTemplate::New()); - npObjectDesc->InstanceTemplate()->SetInternalFieldCount(V8Custom::kNPObjectInternalFieldCount); - npObjectDesc->InstanceTemplate()->SetNamedPropertyHandler(NPObjectNamedPropertyGetter, NPObjectNamedPropertySetter); - npObjectDesc->InstanceTemplate()->SetIndexedPropertyHandler(NPObjectIndexedPropertyGetter, NPObjectIndexedPropertySetter); - npObjectDesc->InstanceTemplate()->SetCallAsFunctionHandler(NPObjectInvokeDefaultHandler); - } - - v8::Handle func = npObjectDesc->GetFunction(); - v8::Local value = SafeAllocation::NewInstance(func); - - // If we were unable to allocate the instance we avoid wrapping - // and registering the NP object. - if (value.IsEmpty()) - return value; - - WrapNPObject(value, object); - - // KJS retains the object as part of its wrapper (see Bindings::CInstance) - NPN_RetainObject(object); - - _NPN_RegisterObject(object, root); - - // Maintain a weak pointer for v8 so we can cleanup the object. - v8::Persistent weakRef = v8::Persistent::New(value); - staticNpobjectMap.set(object, weakRef); - - return value; -} - -void ForgetV8ObjectForNPObject(NPObject* object) -{ - if (staticNpobjectMap.contains(object)) { - v8::HandleScope scope; - v8::Persistent handle(staticNpobjectMap.get(object)); - WebCore::V8Proxy::SetDOMWrapper(handle, WebCore::V8ClassIndex::NPOBJECT, NULL); - staticNpobjectMap.forget(object); - NPN_ReleaseObject(object); - } -} diff --git a/webkit/port/bindings/v8/v8_npobject.h b/webkit/port/bindings/v8/v8_npobject.h index c236c60..c2d8550 100644 --- a/webkit/port/bindings/v8/v8_npobject.h +++ b/webkit/port/bindings/v8/v8_npobject.h @@ -2,52 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef v8_npobject_h -#define v8_npobject_h - -#include -#include "third_party/npapi/bindings/npruntime.h" - -// These functions can be replaced by normal JS operation. -// Getters -v8::Handle NPObjectNamedPropertyGetter(v8::Local name, - const v8::AccessorInfo& info); -v8::Handle NPObjectIndexedPropertyGetter(uint32_t index, - const v8::AccessorInfo& info); -v8::Handle NPObjectGetNamedProperty(v8::Local self, - v8::Local name); -v8::Handle NPObjectGetIndexedProperty(v8::Local self, - uint32_t index); - -// Setters -v8::Handle NPObjectNamedPropertySetter(v8::Local name, - v8::Local value, - const v8::AccessorInfo& info); -v8::Handle NPObjectIndexedPropertySetter(uint32_t index, - const v8::AccessorInfo& info); -v8::Handle NPObjectSetNamedProperty(v8::Local self, - v8::Local name, - v8::Local value); -v8::Handle NPObjectSetIndexedProperty(v8::Local self, - uint32_t index, - v8::Local value); - -v8::Handle NPObjectInvokeDefaultHandler(const v8::Arguments& args); - -// Get a wrapper for a NPObject. -// If the object is already wrapped, the pre-existing wrapper -// will be returned. -// If the object is not wrapped, wrap it, and give V8 a weak -// reference to the wrapper which will cleanup when there are -// no more JS references to the object. -v8::Local CreateV8ObjectForNPObject(NPObject* object, NPObject *root); - -// Tell V8 to forcibly remove an object. -// This is used at plugin teardown so that the caller can -// aggressively unload the plugin library. After calling this -// function, the persistent handle to the wrapper will be -// gone, and the wrapped NPObject will be removed so that -// it cannot be referred to. -void ForgetV8ObjectForNPObject(NPObject*object); - -#endif // v8_npobject_h +// This is a temporary file until V8HTMLPlugInElementCustom.cpp in WebKit +// includes the new name of this file. +#include "V8NPObject.h" -- cgit v1.1