summaryrefslogtreecommitdiffstats
path: root/webkit/port/bindings/v8/npruntime.cpp
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
commitf5b16fed647e941aa66933178da85db2860d639b (patch)
treef00e9856c04aad3b558a140955e7674add33f051 /webkit/port/bindings/v8/npruntime.cpp
parent920c091ac3ee15079194c82ae8a7a18215f3f23c (diff)
downloadchromium_src-f5b16fed647e941aa66933178da85db2860d639b.zip
chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.gz
chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.bz2
Add webkit to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/port/bindings/v8/npruntime.cpp')
-rw-r--r--webkit/port/bindings/v8/npruntime.cpp346
1 files changed, 346 insertions, 0 deletions
diff --git a/webkit/port/bindings/v8/npruntime.cpp b/webkit/port/bindings/v8/npruntime.cpp
new file mode 100644
index 0000000..074fa46
--- /dev/null
+++ b/webkit/port/bindings/v8/npruntime.cpp
@@ -0,0 +1,346 @@
+/*
+ * 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 <map>
+#include <set>
+#include <string>
+#include <v8.h>
+#include "base/stats_counters.h"
+#include "bindings/npruntime.h"
+#include "np_v8object.h"
+#include "npruntime_priv.h"
+#include "v8_npobject.h"
+
+#include <wtf/Assertions.h>
+
+using namespace v8;
+
+
+// TODO: Consider removing locks if we're singlethreaded already.
+// The static initializer here should work okay, but we want to avoid
+// static initialization in general.
+//
+// Commenting out the locks to avoid dependencies on chrome for now.
+// Need a platform abstraction which we can use.
+// static Lock StringIdentifierMapLock;
+
+typedef std::map<std::string, PrivateIdentifier*> StringIdentifierMap;
+
+static StringIdentifierMap* getStringIdentifierMap() {
+ static StringIdentifierMap* stringIdentifierMap = 0;
+ if (!stringIdentifierMap)
+ stringIdentifierMap = new StringIdentifierMap();
+ return stringIdentifierMap;
+}
+
+// TODO: Consider removing locks if we're singlethreaded already.
+// static Lock IntIdentifierMapLock;
+
+typedef std::map<int, PrivateIdentifier*> IntIdentifierMap;
+
+static IntIdentifierMap* getIntIdentifierMap() {
+ static IntIdentifierMap* intIdentifierMap = 0;
+ if (!intIdentifierMap)
+ intIdentifierMap = new IntIdentifierMap;
+ return intIdentifierMap;
+}
+
+extern "C" {
+
+NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name) {
+ ASSERT(name);
+
+ if (name) {
+ // AutoLock safeLock(StringIdentifierMapLock);
+
+ StringIdentifierMap::iterator iter =
+ getStringIdentifierMap()->find(std::string(name));
+ if (iter != getStringIdentifierMap()->end())
+ return static_cast<NPIdentifier>(iter->second);
+
+ PrivateIdentifier* identifier = reinterpret_cast<PrivateIdentifier*>(
+ malloc(sizeof(PrivateIdentifier)));
+ // We never release identifier names, so this dictionary will grow,
+ // as will the memory for the identifier name strings.
+ identifier->isString = true;
+ identifier->value.string = strdup(name);
+ (*getStringIdentifierMap())[std::string(name)] = identifier;
+ return (NPIdentifier)identifier;
+ }
+
+ return 0;
+}
+
+void NPN_GetStringIdentifiers(const NPUTF8** names, int32_t nameCount,
+ NPIdentifier* identifiers) {
+ ASSERT(names);
+ ASSERT(identifiers);
+
+ if (names && identifiers)
+ for (int i = 0; i < nameCount; i++)
+ identifiers[i] = NPN_GetStringIdentifier(names[i]);
+}
+
+NPIdentifier NPN_GetIntIdentifier(int32_t intid) {
+ // AutoLock safeLock(IntIdentifierMapLock);
+
+ IntIdentifierMap::iterator iter = getIntIdentifierMap()->find(intid);
+ if (iter != getIntIdentifierMap()->end())
+ return static_cast<NPIdentifier>(iter->second);
+
+ PrivateIdentifier* identifier = reinterpret_cast<PrivateIdentifier*>(
+ malloc(sizeof(PrivateIdentifier)));
+ // We never release identifier names, so this dictionary will grow.
+ identifier->isString = false;
+ identifier->value.number = intid;
+ (*getIntIdentifierMap())[intid] = identifier;
+ return (NPIdentifier)identifier;
+}
+
+bool NPN_IdentifierIsString(NPIdentifier identifier) {
+ PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier);
+ return i->isString;
+}
+
+NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier) {
+ PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier);
+ if (!i->isString || !i->value.string)
+ return NULL;
+
+ return (NPUTF8 *)strdup(i->value.string);
+}
+
+int32_t NPN_IntFromIdentifier(NPIdentifier identifier) {
+ PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier);
+ if (i->isString)
+ return 0;
+ return i->value.number;
+}
+
+void NPN_ReleaseVariantValue(NPVariant* variant) {
+ ASSERT(variant);
+
+ if (variant->type == NPVariantType_Object) {
+ NPN_ReleaseObject(variant->value.objectValue);
+ variant->value.objectValue = 0;
+ } else if (variant->type == NPVariantType_String) {
+ free((void*)variant->value.stringValue.UTF8Characters);
+ variant->value.stringValue.UTF8Characters = 0;
+ variant->value.stringValue.UTF8Length = 0;
+ }
+
+ variant->type = NPVariantType_Void;
+}
+
+static StatsCounter global_npobjects(L"NPObjects");
+
+NPObject *NPN_CreateObject(NPP npp, NPClass* aClass) {
+ ASSERT(aClass);
+
+ if (aClass) {
+ NPObject* obj;
+ if (aClass->allocate != NULL)
+ obj = aClass->allocate(npp, aClass);
+ else
+ obj = reinterpret_cast<NPObject*>(malloc(sizeof(NPObject)));
+
+ obj->_class = aClass;
+ obj->referenceCount = 1;
+
+ global_npobjects.Increment();
+ return obj;
+ }
+
+ return 0;
+}
+
+NPObject* NPN_RetainObject(NPObject* obj) {
+ ASSERT(obj);
+ ASSERT(obj->referenceCount > 0);
+
+ if (obj)
+ obj->referenceCount++;
+
+ return obj;
+}
+
+// _NPN_DeallocateObject actually deletes the object. Technically,
+// callers should use NPN_ReleaseObject. Webkit exposes this function
+// to kill objects which plugins may not have properly released.
+void _NPN_DeallocateObject(NPObject *obj) {
+ ASSERT(obj);
+ ASSERT(obj->referenceCount >= 0);
+
+ if (obj) {
+ global_npobjects.Decrement();
+
+ // NPObjects that remain in pure C++ may never have wrappers.
+ // Hence, if it's not already alive, don't unregister it.
+ // If it is alive, unregister it as the *last* thing we do
+ // so that it can do as much cleanup as possible on its own.
+ if (_NPN_IsAlive(obj))
+ _NPN_UnregisterObject(obj);
+
+ obj->referenceCount = -1;
+ if (obj->_class->deallocate)
+ obj->_class->deallocate(obj);
+ else
+ free(obj);
+ }
+}
+
+void NPN_ReleaseObject(NPObject* obj) {
+ ASSERT(obj);
+ ASSERT(obj->referenceCount >= 1);
+
+ if (obj && obj->referenceCount >= 1) {
+ if (--obj->referenceCount == 0)
+ _NPN_DeallocateObject(obj);
+ }
+}
+
+void _NPN_InitializeVariantWithStringCopy(NPVariant* variant,
+ const NPString* value) {
+ variant->type = NPVariantType_String;
+ variant->value.stringValue.UTF8Length = value->UTF8Length;
+ variant->value.stringValue.UTF8Characters =
+ reinterpret_cast<NPUTF8*>(malloc(sizeof(NPUTF8) * value->UTF8Length));
+ memcpy((void*)variant->value.stringValue.UTF8Characters,
+ value->UTF8Characters,
+ sizeof(NPUTF8) * value->UTF8Length);
+}
+
+
+// NPN_Registry
+//
+// The registry is designed for quick lookup of NPObjects.
+// JS needs to be able to quickly lookup a given NPObject to determine
+// if it is alive or not.
+// The browser needs to be able to quickly lookup all NPObjects which are
+// "owned" by an object.
+//
+// The g_live_objects is a hash table of all live objects to their owner
+// objects. Presence in this table is used primarily to determine if
+// objects are live or not.
+//
+// The g_root_objects is a hash table of root objects to a set of
+// objects that should be deactivated in sync with the root. A
+// root is defined as a top-level owner object. This is used on
+// Frame teardown to deactivate all objects associated
+// with a particular plugin.
+
+typedef std::set<NPObject*> NPObjectSet;
+typedef std::map<NPObject*, NPObject*> NPObjectMap;
+typedef std::map<NPObject*, NPObjectSet*> NPRootObjectMap;
+
+// A map of live NPObjects with pointers to their Roots.
+NPObjectMap g_live_objects;
+
+// A map of the root objects and the list of NPObjects
+// associated with that object.
+NPRootObjectMap g_root_objects;
+
+void _NPN_RegisterObject(NPObject* obj, NPObject* owner) {
+ ASSERT(obj);
+
+ // Check if already registered.
+ if (g_live_objects.find(obj) != g_live_objects.end()) {
+ return;
+ }
+
+ if (!owner) {
+ // Registering a new owner object.
+ ASSERT(g_root_objects.find(obj) == g_root_objects.end());
+ g_root_objects[obj] = new NPObjectSet();
+ } else {
+ // Always associate this object with it's top-most parent.
+ // Since we always flatten, we only have to look up one level.
+ NPObjectMap::iterator owner_entry = g_live_objects.find(owner);
+ NPObject* parent = NULL;
+ if (g_live_objects.end() != owner_entry)
+ parent = owner_entry->second;
+
+ if (parent) {
+ owner = parent;
+ }
+ ASSERT(g_root_objects.find(obj) == g_root_objects.end());
+ if (g_root_objects.find(owner) != g_root_objects.end())
+ (g_root_objects[owner])->insert(obj);
+ }
+
+ ASSERT(g_live_objects.find(obj) == g_live_objects.end());
+ g_live_objects[obj] = owner;
+}
+
+void _NPN_UnregisterObject(NPObject* obj) {
+ ASSERT(obj);
+ ASSERT(g_live_objects.find(obj) != g_live_objects.end());
+
+ NPObject* owner = NULL;
+ if (g_live_objects.find(obj) != g_live_objects.end())
+ owner = g_live_objects.find(obj)->second;
+
+ if (owner == NULL) {
+ // Unregistering a owner object; also unregister it's descendants.
+ ASSERT(g_root_objects.find(obj) != g_root_objects.end());
+ NPObjectSet* set = g_root_objects[obj];
+ while (set->size() > 0) {
+ size_t size = set->size();
+ NPObject* sub_object = *(set->begin());
+ // The sub-object should not be a owner!
+ ASSERT(g_root_objects.find(sub_object) == g_root_objects.end());
+
+ // First, unregister the object.
+ set->erase(sub_object);
+ g_live_objects.erase(sub_object);
+
+ // Remove the JS references to the object.
+ ForgetV8ObjectForNPObject(sub_object);
+
+ ASSERT(set->size() < size);
+ }
+ delete set;
+ g_root_objects.erase(obj);
+ } else {
+ NPRootObjectMap::iterator owner_entry = g_root_objects.find(owner);
+ if (owner_entry != g_root_objects.end()) {
+ NPObjectSet* list = owner_entry->second;
+ ASSERT(list->find(obj) != list->end());
+ list->erase(obj);
+ }
+ }
+ ForgetV8ObjectForNPObject(obj);
+
+ g_live_objects.erase(obj);
+}
+
+bool _NPN_IsAlive(NPObject* obj) {
+ return g_live_objects.find(obj) != g_live_objects.end();
+}
+
+} // extern "C"