summaryrefslogtreecommitdiffstats
path: root/WebCore/bridge/jni
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
commit1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch)
tree4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /WebCore/bridge/jni
parent9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff)
downloadexternal_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'WebCore/bridge/jni')
-rw-r--r--WebCore/bridge/jni/jni_class.cpp143
-rw-r--r--WebCore/bridge/jni/jni_class.h66
-rw-r--r--WebCore/bridge/jni/jni_instance.cpp334
-rw-r--r--WebCore/bridge/jni/jni_instance.h110
-rw-r--r--WebCore/bridge/jni/jni_jsobject.h129
-rw-r--r--WebCore/bridge/jni/jni_jsobject.mm720
-rw-r--r--WebCore/bridge/jni/jni_objc.mm83
-rw-r--r--WebCore/bridge/jni/jni_runtime.cpp547
-rw-r--r--WebCore/bridge/jni/jni_runtime.h191
-rw-r--r--WebCore/bridge/jni/jni_utility.cpp584
-rw-r--r--WebCore/bridge/jni/jni_utility.h288
11 files changed, 3195 insertions, 0 deletions
diff --git a/WebCore/bridge/jni/jni_class.cpp b/WebCore/bridge/jni/jni_class.cpp
new file mode 100644
index 0000000..4140524
--- /dev/null
+++ b/WebCore/bridge/jni/jni_class.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2003 Apple Computer, 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 "jni_class.h"
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#include "JSDOMWindow.h"
+#include <kjs/identifier.h>
+#include <runtime/JSLock.h>
+#include "jni_utility.h"
+#include "jni_runtime.h"
+
+using namespace JSC::Bindings;
+
+JavaClass::JavaClass(jobject anInstance)
+{
+ jobject aClass = callJNIMethod<jobject>(anInstance, "getClass", "()Ljava/lang/Class;");
+
+ if (!aClass) {
+ fprintf(stderr, "%s: unable to call getClass on instance %p\n", __PRETTY_FUNCTION__, anInstance);
+ return;
+ }
+
+ jstring className = (jstring)callJNIMethod<jobject>(aClass, "getName", "()Ljava/lang/String;");
+ const char *classNameC = getCharactersFromJString(className);
+ _name = strdup(classNameC);
+ releaseCharactersForJString(className, classNameC);
+
+ int i;
+ JNIEnv *env = getJNIEnv();
+
+ JSGlobalData* globalData = WebCore::JSDOMWindow::commonJSGlobalData();
+
+ // Get the fields
+ jarray fields = (jarray)callJNIMethod<jobject>(aClass, "getFields", "()[Ljava/lang/reflect/Field;");
+ int numFields = env->GetArrayLength(fields);
+ for (i = 0; i < numFields; i++) {
+ jobject aJField = env->GetObjectArrayElement((jobjectArray)fields, i);
+ Field *aField = new JavaField(env, aJField); // deleted in the JavaClass destructor
+ {
+ JSLock lock(false);
+ _fields.set(Identifier(globalData, UString(aField->name())).ustring().rep(), aField);
+ }
+ env->DeleteLocalRef(aJField);
+ }
+
+ // Get the methods
+ jarray methods = (jarray)callJNIMethod<jobject>(aClass, "getMethods", "()[Ljava/lang/reflect/Method;");
+ int numMethods = env->GetArrayLength(methods);
+ for (i = 0; i < numMethods; i++) {
+ jobject aJMethod = env->GetObjectArrayElement((jobjectArray)methods, i);
+ Method *aMethod = new JavaMethod(env, aJMethod); // deleted in the JavaClass destructor
+ MethodList* methodList;
+ {
+ JSLock lock(false);
+
+ methodList = _methods.get(Identifier(globalData, UString(aMethod->name())).ustring().rep());
+ if (!methodList) {
+ methodList = new MethodList();
+ _methods.set(Identifier(globalData, UString(aMethod->name())).ustring().rep(), methodList);
+ }
+ }
+ methodList->append(aMethod);
+ env->DeleteLocalRef(aJMethod);
+ }
+}
+
+JavaClass::~JavaClass() {
+ free((void *)_name);
+
+ JSLock lock(false);
+
+ deleteAllValues(_fields);
+ _fields.clear();
+
+ MethodListMap::const_iterator end = _methods.end();
+ for (MethodListMap::const_iterator it = _methods.begin(); it != end; ++it) {
+ const MethodList* methodList = it->second;
+ deleteAllValues(*methodList);
+ delete methodList;
+ }
+ _methods.clear();
+}
+
+MethodList JavaClass::methodsNamed(const Identifier& identifier, Instance*) const
+{
+ MethodList *methodList = _methods.get(identifier.ustring().rep());
+
+ if (methodList)
+ return *methodList;
+ return MethodList();
+}
+
+Field *JavaClass::fieldNamed(const Identifier& identifier, Instance*) const
+{
+ return _fields.get(identifier.ustring().rep());
+}
+
+bool JavaClass::isNumberClass() const
+{
+ return ((strcmp(_name, "java.lang.Byte") == 0 ||
+ strcmp(_name, "java.lang.Short") == 0 ||
+ strcmp(_name, "java.lang.Integer") == 0 ||
+ strcmp(_name, "java.lang.Long") == 0 ||
+ strcmp(_name, "java.lang.Float") == 0 ||
+ strcmp(_name, "java.lang.Double") == 0) );
+}
+
+bool JavaClass::isBooleanClass() const
+{
+ return strcmp(_name, "java.lang.Boolean") == 0;
+}
+
+bool JavaClass::isStringClass() const
+{
+ return strcmp(_name, "java.lang.String") == 0;
+}
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
diff --git a/WebCore/bridge/jni/jni_class.h b/WebCore/bridge/jni/jni_class.h
new file mode 100644
index 0000000..75cfd89
--- /dev/null
+++ b/WebCore/bridge/jni/jni_class.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2003 Apple Computer, 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.
+ */
+
+#ifndef JNI_CLASS_H_
+#define JNI_CLASS_H_
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#include <jni_runtime.h>
+#include <wtf/HashMap.h>
+
+namespace JSC {
+
+namespace Bindings {
+
+class JavaClass : public Class {
+public:
+ JavaClass (jobject anInstance);
+ ~JavaClass ();
+
+ virtual const char *name() const { return _name; };
+
+ virtual MethodList methodsNamed(const Identifier&, Instance* instance) const;
+ virtual Field *fieldNamed(const Identifier&, Instance* instance) const;
+
+ bool isNumberClass() const;
+ bool isBooleanClass() const;
+ bool isStringClass() const;
+
+private:
+ JavaClass (); // prevent default construction
+
+ const char *_name;
+ FieldMap _fields;
+ MethodListMap _methods;
+};
+
+} // namespace Bindings
+
+} // namespace JSC
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
+
+#endif // JNI_CLASS_H_
diff --git a/WebCore/bridge/jni/jni_instance.cpp b/WebCore/bridge/jni/jni_instance.cpp
new file mode 100644
index 0000000..6b23900
--- /dev/null
+++ b/WebCore/bridge/jni/jni_instance.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2003, 2008 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 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 "jni_instance.h"
+
+#ifdef ANDROID
+#include <assert.h>
+#endif
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#include "jni_class.h"
+#include "jni_runtime.h"
+#include "jni_utility.h"
+#include "runtime_object.h"
+#include "runtime_root.h"
+#include <runtime/ArgList.h>
+#include <runtime/Error.h>
+#include <runtime/JSLock.h>
+
+#ifdef NDEBUG
+#define JS_LOG(formatAndArgs...) ((void)0)
+#else
+#define JS_LOG(formatAndArgs...) { \
+ fprintf (stderr, "%s:%d -- %s: ", __FILE__, __LINE__, __FUNCTION__); \
+ fprintf(stderr, formatAndArgs); \
+}
+#endif
+
+using namespace JSC::Bindings;
+using namespace JSC;
+
+JavaInstance::JavaInstance (jobject instance, PassRefPtr<RootObject> rootObject)
+ : Instance(rootObject)
+{
+ _instance = new JObjectWrapper (instance);
+ _class = 0;
+}
+
+JavaInstance::~JavaInstance ()
+{
+ delete _class;
+}
+
+#define NUM_LOCAL_REFS 64
+
+void JavaInstance::virtualBegin()
+{
+ getJNIEnv()->PushLocalFrame (NUM_LOCAL_REFS);
+}
+
+void JavaInstance::virtualEnd()
+{
+ getJNIEnv()->PopLocalFrame (NULL);
+}
+
+Class *JavaInstance::getClass() const
+{
+ if (_class == 0)
+ _class = new JavaClass (_instance->_instance);
+ return _class;
+}
+
+JSValue* JavaInstance::stringValue(ExecState* exec) const
+{
+ JSLock lock(false);
+
+ jstring stringValue = (jstring)callJNIMethod<jobject>(_instance->_instance, "toString", "()Ljava/lang/String;");
+ JNIEnv *env = getJNIEnv();
+ const jchar *c = getUCharactersFromJStringInEnv(env, stringValue);
+ UString u((const UChar *)c, (int)env->GetStringLength(stringValue));
+ releaseUCharactersForJStringInEnv(env, stringValue, c);
+ return jsString(exec, u);
+}
+
+JSValue* JavaInstance::numberValue(ExecState* exec) const
+{
+ jdouble doubleValue = callJNIMethod<jdouble>(_instance->_instance, "doubleValue", "()D");
+ return jsNumber(exec, doubleValue);
+}
+
+JSValue* JavaInstance::booleanValue() const
+{
+ jboolean booleanValue = callJNIMethod<jboolean>(_instance->_instance, "booleanValue", "()Z");
+ return jsBoolean(booleanValue);
+}
+
+JSValue* JavaInstance::invokeMethod (ExecState *exec, const MethodList &methodList, const ArgList &args)
+{
+ int i, count = args.size();
+ jvalue *jArgs;
+ JSValue* resultValue;
+ Method *method = 0;
+ size_t numMethods = methodList.size();
+
+ // Try to find a good match for the overloaded method. The
+ // fundamental problem is that JavaScript doesn have the
+ // notion of method overloading and Java does. We could
+ // get a bit more sophisticated and attempt to does some
+ // type checking as we as checking the number of parameters.
+ Method *aMethod;
+ for (size_t methodIndex = 0; methodIndex < numMethods; methodIndex++) {
+ aMethod = methodList[methodIndex];
+ if (aMethod->numParameters() == count) {
+ method = aMethod;
+ break;
+ }
+ }
+ if (method == 0) {
+ JS_LOG ("unable to find an appropiate method\n");
+ return jsUndefined();
+ }
+
+ const JavaMethod *jMethod = static_cast<const JavaMethod*>(method);
+ JS_LOG ("call %s %s on %p\n", method->name(), jMethod->signature(), _instance->_instance);
+
+ if (count > 0) {
+ jArgs = (jvalue *)malloc (count * sizeof(jvalue));
+ }
+ else
+ jArgs = 0;
+
+ for (i = 0; i < count; i++) {
+ JavaParameter* aParameter = jMethod->parameterAt(i);
+ jArgs[i] = convertValueToJValue(exec, args.at(exec, i), aParameter->getJNIType(), aParameter->type());
+ JS_LOG("arg[%d] = %s\n", i, args.at(exec, i)->toString(exec).ascii());
+ }
+
+ jvalue result;
+
+ // Try to use the JNI abstraction first, otherwise fall back to
+ // nornmal JNI. The JNI dispatch abstraction allows the Java plugin
+ // to dispatch the call on the appropriate internal VM thread.
+ RootObject* rootObject = this->rootObject();
+ if (!rootObject)
+ return jsUndefined();
+
+ bool handled = false;
+ if (rootObject->nativeHandle()) {
+ jobject obj = _instance->_instance;
+ JSValue* exceptionDescription = noValue();
+ const char *callingURL = 0; // FIXME, need to propagate calling URL to Java
+ handled = dispatchJNICall(exec, rootObject->nativeHandle(), obj, jMethod->isStatic(), jMethod->JNIReturnType(), jMethod->methodID(obj), jArgs, result, callingURL, exceptionDescription);
+ if (exceptionDescription) {
+ throwError(exec, GeneralError, exceptionDescription->toString(exec));
+ free (jArgs);
+ return jsUndefined();
+ }
+ }
+
+ // The following code can be conditionally removed once we have a Tiger update that
+ // contains the new Java plugin. It is needed for builds prior to Tiger.
+ if (!handled) {
+ jobject obj = _instance->_instance;
+ switch (jMethod->JNIReturnType()){
+ case void_type:
+ callJNIMethodIDA<void>(obj, jMethod->methodID(obj), jArgs);
+ break;
+ case object_type:
+ result.l = callJNIMethodIDA<jobject>(obj, jMethod->methodID(obj), jArgs);
+ break;
+ case boolean_type:
+ result.z = callJNIMethodIDA<jboolean>(obj, jMethod->methodID(obj), jArgs);
+ break;
+ case byte_type:
+ result.b = callJNIMethodIDA<jbyte>(obj, jMethod->methodID(obj), jArgs);
+ break;
+ case char_type:
+ result.c = callJNIMethodIDA<jchar>(obj, jMethod->methodID(obj), jArgs);
+ break;
+ case short_type:
+ result.s = callJNIMethodIDA<jshort>(obj, jMethod->methodID(obj), jArgs);
+ break;
+ case int_type:
+ result.i = callJNIMethodIDA<jint>(obj, jMethod->methodID(obj), jArgs);
+ break;
+
+ case long_type:
+ result.j = callJNIMethodIDA<jlong>(obj, jMethod->methodID(obj), jArgs);
+ break;
+ case float_type:
+ result.f = callJNIMethodIDA<jfloat>(obj, jMethod->methodID(obj), jArgs);
+ break;
+ case double_type:
+ result.d = callJNIMethodIDA<jdouble>(obj, jMethod->methodID(obj), jArgs);
+ break;
+ case invalid_type:
+ default:
+ break;
+ }
+ }
+
+ switch (jMethod->JNIReturnType()){
+ case void_type: {
+ resultValue = jsUndefined();
+ }
+ break;
+
+ case object_type: {
+ if (result.l != 0) {
+ const char *arrayType = jMethod->returnType();
+ if (arrayType[0] == '[') {
+ resultValue = JavaArray::convertJObjectToArray(exec, result.l, arrayType, rootObject);
+ }
+ else {
+ resultValue = Instance::createRuntimeObject(exec, JavaInstance::create(result.l, rootObject));
+ }
+ }
+ else {
+ resultValue = jsUndefined();
+ }
+ }
+ break;
+
+ case boolean_type: {
+ resultValue = jsBoolean(result.z);
+ }
+ break;
+
+ case byte_type: {
+ resultValue = jsNumber(exec, result.b);
+ }
+ break;
+
+ case char_type: {
+ resultValue = jsNumber(exec, result.c);
+ }
+ break;
+
+ case short_type: {
+ resultValue = jsNumber(exec, result.s);
+ }
+ break;
+
+ case int_type: {
+ resultValue = jsNumber(exec, result.i);
+ }
+ break;
+
+ case long_type: {
+ resultValue = jsNumber(exec, result.j);
+ }
+ break;
+
+ case float_type: {
+ resultValue = jsNumber(exec, result.f);
+ }
+ break;
+
+ case double_type: {
+ resultValue = jsNumber(exec, result.d);
+ }
+ break;
+
+ case invalid_type:
+ default: {
+ resultValue = jsUndefined();
+ }
+ break;
+ }
+
+ free (jArgs);
+
+ return resultValue;
+}
+
+JSValue* JavaInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
+{
+ if (hint == PreferString)
+ return stringValue(exec);
+ if (hint == PreferNumber)
+ return numberValue(exec);
+ JavaClass *aClass = static_cast<JavaClass*>(getClass());
+ if (aClass->isStringClass())
+ return stringValue(exec);
+ if (aClass->isNumberClass())
+ return numberValue(exec);
+ if (aClass->isBooleanClass())
+ return booleanValue();
+ return valueOf(exec);
+}
+
+JSValue* JavaInstance::valueOf(ExecState* exec) const
+{
+ return stringValue(exec);
+}
+
+JObjectWrapper::JObjectWrapper(jobject instance)
+: _refCount(0)
+{
+ assert (instance != 0);
+
+ // Cache the JNIEnv used to get the global ref for this java instanace.
+ // It'll be used to delete the reference.
+ _env = getJNIEnv();
+
+ _instance = _env->NewGlobalRef (instance);
+
+ JS_LOG ("new global ref %p for %p\n", _instance, instance);
+
+ if (_instance == NULL) {
+ fprintf (stderr, "%s: could not get GlobalRef for %p\n", __PRETTY_FUNCTION__, instance);
+ }
+}
+
+JObjectWrapper::~JObjectWrapper() {
+ JS_LOG ("deleting global ref %p\n", _instance);
+ _env->DeleteGlobalRef (_instance);
+}
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
diff --git a/WebCore/bridge/jni/jni_instance.h b/WebCore/bridge/jni/jni_instance.h
new file mode 100644
index 0000000..7104865
--- /dev/null
+++ b/WebCore/bridge/jni/jni_instance.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2003 Apple Computer, 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.
+ */
+
+#ifndef _JNI_INSTANCE_H_
+#define _JNI_INSTANCE_H_
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#include "runtime.h"
+#include "runtime_root.h"
+
+#include <JavaVM/jni.h>
+
+namespace JSC {
+
+namespace Bindings {
+
+class JavaClass;
+
+class JObjectWrapper
+{
+friend class RefPtr<JObjectWrapper>;
+friend class JavaArray;
+friend class JavaField;
+friend class JavaInstance;
+friend class JavaMethod;
+
+protected:
+ JObjectWrapper(jobject instance);
+ ~JObjectWrapper();
+
+ void ref() { _refCount++; }
+ void deref()
+ {
+ if (--_refCount == 0)
+ delete this;
+ }
+
+ jobject _instance;
+
+private:
+ JNIEnv *_env;
+ unsigned int _refCount;
+};
+
+class JavaInstance : public Instance
+{
+public:
+ static PassRefPtr<JavaInstance> create(jobject instance, PassRefPtr<RootObject> rootObject)
+ {
+ return adoptRef(new JavaInstance(instance, rootObject));
+ }
+
+ ~JavaInstance();
+
+ virtual Class *getClass() const;
+
+ virtual JSValue* valueOf(ExecState*) const;
+ virtual JSValue* defaultValue(ExecState*, PreferredPrimitiveType) const;
+
+ virtual JSValue* invokeMethod(ExecState* exec, const MethodList& method, const ArgList& args);
+
+ jobject javaInstance() const { return _instance->_instance; }
+
+ JSValue* stringValue(ExecState*) const;
+ JSValue* numberValue(ExecState*) const;
+ JSValue* booleanValue() const;
+
+ virtual BindingLanguage getBindingLanguage() const { return JavaLanguage; }
+
+protected:
+ virtual void virtualBegin();
+ virtual void virtualEnd();
+
+private:
+ JavaInstance(jobject instance, PassRefPtr<RootObject>);
+
+ RefPtr<JObjectWrapper> _instance;
+ mutable JavaClass *_class;
+};
+
+} // namespace Bindings
+
+} // namespace JSC
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
+
+#endif // _JNI_INSTANCE_H_
diff --git a/WebCore/bridge/jni/jni_jsobject.h b/WebCore/bridge/jni/jni_jsobject.h
new file mode 100644
index 0000000..812317d
--- /dev/null
+++ b/WebCore/bridge/jni/jni_jsobject.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2003 Apple Computer, 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.
+ */
+
+#ifndef JAVASCRIPTCORE_BINDINGS_JNI_JSOBJECT_H
+#define JAVASCRIPTCORE_BINDINGS_JNI_JSOBJECT_H
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <JavaVM/jni.h>
+#include <runtime/JSValue.h>
+#include <wtf/RefPtr.h>
+
+#define jlong_to_ptr(a) ((void*)(uintptr_t)(a))
+#define jlong_to_impptr(a) (static_cast<JSC::JSObject*>(((void*)(uintptr_t)(a))))
+#define ptr_to_jlong(a) ((jlong)(uintptr_t)(a))
+
+namespace JSC {
+
+class ArgList;
+class ExecState;
+class JSObject;
+
+namespace Bindings {
+
+class RootObject;
+
+enum JSObjectCallType {
+ CreateNative,
+ Call,
+ Eval,
+ GetMember,
+ SetMember,
+ RemoveMember,
+ GetSlot,
+ SetSlot,
+ ToString,
+ Finalize
+};
+
+struct JSObjectCallContext
+{
+ JSObjectCallType type;
+ jlong nativeHandle;
+ jstring string;
+ jobjectArray args;
+ jint index;
+ jobject value;
+ CFRunLoopRef originatingLoop;
+ jvalue result;
+};
+
+class JavaJSObject
+{
+public:
+ JavaJSObject(jlong nativeHandle);
+
+ static jlong createNative(jlong nativeHandle);
+ jobject call(jstring methodName, jobjectArray args) const;
+ jobject eval(jstring script) const;
+ jobject getMember(jstring memberName) const;
+ void setMember(jstring memberName, jobject value) const;
+ void removeMember(jstring memberName) const;
+ jobject getSlot(jint index) const;
+ void setSlot(jint index, jobject value) const;
+ jstring toString() const;
+ void finalize() const;
+
+ static jvalue invoke(JSObjectCallContext*);
+
+ jobject convertValueToJObject(JSValue*) const;
+ JSValue* convertJObjectToValue(ExecState*, jobject) const;
+ void getListFromJArray(ExecState*, jobjectArray, ArgList&) const;
+
+ RootObject* rootObject() const;
+
+ // Must be called from the thread that will be used to access JavaScript.
+ static void initializeJNIThreading();
+private:
+ RefPtr<RootObject> _rootObject;
+ JSObject* _imp;
+};
+
+
+} // namespace Bindings
+
+} // namespace JSC
+
+extern "C" {
+
+// The Java VM calls these functions to handle calls to methods in Java's JSObject class.
+jlong KJS_JSCreateNativeJSObject(JNIEnv*, jclass, jstring jurl, jlong nativeHandle, jboolean ctx);
+void KJS_JSObject_JSFinalize(JNIEnv*, jclass, jlong nativeJSObject);
+jobject KJS_JSObject_JSObjectCall(JNIEnv*, jclass, jlong nativeJSObject, jstring jurl, jstring methodName, jobjectArray args, jboolean ctx);
+jobject KJS_JSObject_JSObjectEval(JNIEnv*, jclass, jlong nativeJSObject, jstring jurl, jstring jscript, jboolean ctx);
+jobject KJS_JSObject_JSObjectGetMember(JNIEnv*, jclass, jlong nativeJSObject, jstring jurl, jstring jname, jboolean ctx);
+void KJS_JSObject_JSObjectSetMember(JNIEnv*, jclass, jlong nativeJSObject, jstring jurl, jstring jname, jobject value, jboolean ctx);
+void KJS_JSObject_JSObjectRemoveMember(JNIEnv*, jclass, jlong nativeJSObject, jstring jurl, jstring jname, jboolean ctx);
+jobject KJS_JSObject_JSObjectGetSlot(JNIEnv*, jclass, jlong nativeJSObject, jstring jurl, jint jindex, jboolean ctx);
+void KJS_JSObject_JSObjectSetSlot(JNIEnv*, jclass, jlong nativeJSObject, jstring jurl, jint jindex, jobject value, jboolean ctx);
+jstring KJS_JSObject_JSObjectToString(JNIEnv*, jclass, jlong nativeJSObject);
+
+}
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
+
+#endif // JAVASCRIPTCORE_BINDINGS_JNI_JSOBJECT_H
diff --git a/WebCore/bridge/jni/jni_jsobject.mm b/WebCore/bridge/jni/jni_jsobject.mm
new file mode 100644
index 0000000..042d1ed
--- /dev/null
+++ b/WebCore/bridge/jni/jni_jsobject.mm
@@ -0,0 +1,720 @@
+/*
+ * Copyright (C) 2003, 2008 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 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 "jni_jsobject.h"
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#include "Frame.h"
+#include "WebCoreFrameView.h"
+#include "jni_runtime.h"
+#include "jni_utility.h"
+#include "ScriptController.h"
+#include "runtime_object.h"
+#include "runtime_root.h"
+#include <runtime/ExecState.h>
+#include <runtime/JSGlobalObject.h>
+#include <runtime/JSLock.h>
+#include <kjs/completion.h>
+#include <kjs/interpreter.h>
+#include <wtf/Assertions.h>
+#include <kjs/SourceProvider.h>
+
+using WebCore::Frame;
+
+using namespace JSC::Bindings;
+using namespace JSC;
+
+#ifdef NDEBUG
+#define JS_LOG(formatAndArgs...) ((void)0)
+#else
+#define JS_LOG(formatAndArgs...) { \
+ fprintf (stderr, "%s(%p,%p): ", __PRETTY_FUNCTION__, _performJavaScriptRunLoop, CFRunLoopGetCurrent()); \
+ fprintf(stderr, formatAndArgs); \
+}
+#endif
+
+#define UndefinedHandle 1
+
+static CFRunLoopSourceRef _performJavaScriptSource;
+static CFRunLoopRef _performJavaScriptRunLoop;
+
+// May only be set by dispatchToJavaScriptThread().
+static CFRunLoopSourceRef completionSource;
+
+static void completedJavaScriptAccess (void *i)
+{
+ assert (CFRunLoopGetCurrent() != _performJavaScriptRunLoop);
+
+ JSObjectCallContext *callContext = (JSObjectCallContext *)i;
+ CFRunLoopRef runLoop = (CFRunLoopRef)callContext->originatingLoop;
+
+ assert (CFRunLoopGetCurrent() == runLoop);
+
+ CFRunLoopStop(runLoop);
+}
+
+static pthread_once_t javaScriptAccessLockOnce = PTHREAD_ONCE_INIT;
+static pthread_mutex_t javaScriptAccessLock;
+static int javaScriptAccessLockCount = 0;
+
+static void initializeJavaScriptAccessLock()
+{
+ pthread_mutexattr_t attr;
+
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
+
+ pthread_mutex_init(&javaScriptAccessLock, &attr);
+}
+
+static inline void lockJavaScriptAccess()
+{
+ // Perhaps add deadlock detection?
+ pthread_once(&javaScriptAccessLockOnce, initializeJavaScriptAccessLock);
+ pthread_mutex_lock(&javaScriptAccessLock);
+ javaScriptAccessLockCount++;
+}
+
+static inline void unlockJavaScriptAccess()
+{
+ javaScriptAccessLockCount--;
+ pthread_mutex_unlock(&javaScriptAccessLock);
+}
+
+static void dispatchToJavaScriptThread(JSObjectCallContext *context)
+{
+ // This lock guarantees that only one thread can invoke
+ // at a time, and also guarantees that completionSource;
+ // won't get clobbered.
+ lockJavaScriptAccess();
+
+ CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent();
+
+ assert (currentRunLoop != _performJavaScriptRunLoop);
+
+ // Setup a source to signal once the invocation of the JavaScript
+ // call completes.
+ //
+ // FIXME: This could be a potential performance issue. Creating and
+ // adding run loop sources is expensive. We could create one source
+ // per thread, as needed, instead.
+ context->originatingLoop = currentRunLoop;
+ CFRunLoopSourceContext sourceContext = {0, context, NULL, NULL, NULL, NULL, NULL, NULL, NULL, completedJavaScriptAccess};
+ completionSource = CFRunLoopSourceCreate(NULL, 0, &sourceContext);
+ CFRunLoopAddSource(currentRunLoop, completionSource, kCFRunLoopDefaultMode);
+
+ // Wakeup JavaScript access thread and make it do it's work.
+ CFRunLoopSourceSignal(_performJavaScriptSource);
+ if (CFRunLoopIsWaiting(_performJavaScriptRunLoop))
+ CFRunLoopWakeUp(_performJavaScriptRunLoop);
+
+ // Wait until the JavaScript access thread is done.
+ CFRunLoopRun ();
+
+ CFRunLoopRemoveSource(currentRunLoop, completionSource, kCFRunLoopDefaultMode);
+ CFRelease (completionSource);
+
+ unlockJavaScriptAccess();
+}
+
+static void performJavaScriptAccess(void*)
+{
+ assert (CFRunLoopGetCurrent() == _performJavaScriptRunLoop);
+
+ // Dispatch JavaScript calls here.
+ CFRunLoopSourceContext sourceContext;
+ CFRunLoopSourceGetContext (completionSource, &sourceContext);
+ JSObjectCallContext *callContext = (JSObjectCallContext *)sourceContext.info;
+ CFRunLoopRef originatingLoop = callContext->originatingLoop;
+
+ JavaJSObject::invoke (callContext);
+
+ // Signal the originating thread that we're done.
+ CFRunLoopSourceSignal (completionSource);
+ if (CFRunLoopIsWaiting(originatingLoop))
+ CFRunLoopWakeUp(originatingLoop);
+}
+
+// Must be called from the thread that will be used to access JavaScript.
+void JavaJSObject::initializeJNIThreading() {
+ // Should only be called once.
+ ASSERT(!_performJavaScriptRunLoop);
+
+ // Assume that we can retain this run loop forever. It'll most
+ // likely (always?) be the main loop.
+ _performJavaScriptRunLoop = (CFRunLoopRef)CFRetain(CFRunLoopGetCurrent());
+
+ // Setup a source the other threads can use to signal the _runLoop
+ // thread that a JavaScript call needs to be invoked.
+ CFRunLoopSourceContext sourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, performJavaScriptAccess};
+ _performJavaScriptSource = CFRunLoopSourceCreate(NULL, 0, &sourceContext);
+ CFRunLoopAddSource(_performJavaScriptRunLoop, _performJavaScriptSource, kCFRunLoopDefaultMode);
+}
+
+static bool isJavaScriptThread()
+{
+ return (_performJavaScriptRunLoop == CFRunLoopGetCurrent());
+}
+
+jvalue JavaJSObject::invoke(JSObjectCallContext *context)
+{
+ jvalue result;
+
+ bzero ((void *)&result, sizeof(jvalue));
+
+ if (!isJavaScriptThread()) {
+ // Send the call context to the thread that is allowed to
+ // call JavaScript.
+ dispatchToJavaScriptThread(context);
+ result = context->result;
+ }
+ else {
+ jlong nativeHandle = context->nativeHandle;
+ if (nativeHandle == UndefinedHandle || nativeHandle == 0) {
+ return result;
+ }
+
+ if (context->type == CreateNative) {
+ result.j = JavaJSObject::createNative(nativeHandle);
+ }
+ else {
+ JSObject *imp = jlong_to_impptr(nativeHandle);
+ if (!findProtectingRootObject(imp)) {
+ fprintf (stderr, "%s:%d: Attempt to access JavaScript from destroyed applet, type %d.\n", __FILE__, __LINE__, context->type);
+ return result;
+ }
+
+ switch (context->type){
+ case Call: {
+ result.l = JavaJSObject(nativeHandle).call(context->string, context->args);
+ break;
+ }
+
+ case Eval: {
+ result.l = JavaJSObject(nativeHandle).eval(context->string);
+ break;
+ }
+
+ case GetMember: {
+ result.l = JavaJSObject(nativeHandle).getMember(context->string);
+ break;
+ }
+
+ case SetMember: {
+ JavaJSObject(nativeHandle).setMember(context->string, context->value);
+ break;
+ }
+
+ case RemoveMember: {
+ JavaJSObject(nativeHandle).removeMember(context->string);
+ break;
+ }
+
+ case GetSlot: {
+ result.l = JavaJSObject(nativeHandle).getSlot(context->index);
+ break;
+ }
+
+ case SetSlot: {
+ JavaJSObject(nativeHandle).setSlot(context->index, context->value);
+ break;
+ }
+
+ case ToString: {
+ result.l = (jobject) JavaJSObject(nativeHandle).toString();
+ break;
+ }
+
+ case Finalize: {
+ JavaJSObject(nativeHandle).finalize();
+ break;
+ }
+
+ default: {
+ fprintf (stderr, "%s: invalid JavaScript call\n", __PRETTY_FUNCTION__);
+ }
+ }
+ }
+ context->result = result;
+ }
+
+ return result;
+}
+
+
+JavaJSObject::JavaJSObject(jlong nativeJSObject)
+{
+ _imp = jlong_to_impptr(nativeJSObject);
+
+ ASSERT(_imp);
+ _rootObject = findProtectingRootObject(_imp);
+ ASSERT(_rootObject);
+}
+
+RootObject* JavaJSObject::rootObject() const
+{
+ return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
+}
+
+jobject JavaJSObject::call(jstring methodName, jobjectArray args) const
+{
+ JS_LOG ("methodName = %s\n", JavaString(methodName).UTF8String());
+
+ RootObject* rootObject = this->rootObject();
+ if (!rootObject)
+ return 0;
+
+ // Lookup the function object.
+ ExecState* exec = rootObject->globalObject()->globalExec();
+ JSLock lock(false);
+
+ Identifier identifier(exec, JavaString(methodName));
+ JSValue* function = _imp->get(exec, identifier);
+ CallData callData;
+ CallType callType = function->getCallData(callData);
+ if (callType == CallTypeNone)
+ return 0;
+
+ // Call the function object.
+ ArgList argList;
+ getListFromJArray(exec, args, argList);
+ rootObject->globalObject()->startTimeoutCheck();
+ JSValue* result = JSC::call(exec, function, callType, callData, _imp, argList);
+ rootObject->globalObject()->stopTimeoutCheck();
+
+ return convertValueToJObject(result);
+}
+
+jobject JavaJSObject::eval(jstring script) const
+{
+ JS_LOG ("script = %s\n", JavaString(script).UTF8String());
+
+ JSValue* result;
+
+ JSLock lock(false);
+
+ RootObject* rootObject = this->rootObject();
+ if (!rootObject)
+ return 0;
+
+ rootObject->globalObject()->startTimeoutCheck();
+ Completion completion = Interpreter::evaluate(rootObject->globalObject()->globalExec(), rootObject->globalObject()->globalScopeChain(), makeSource(JavaString(script)));
+ rootObject->globalObject()->stopTimeoutCheck();
+ ComplType type = completion.complType();
+
+ if (type == Normal) {
+ result = completion.value();
+ if (!result)
+ result = jsUndefined();
+ } else
+ result = jsUndefined();
+
+ return convertValueToJObject (result);
+}
+
+jobject JavaJSObject::getMember(jstring memberName) const
+{
+ JS_LOG ("(%p) memberName = %s\n", _imp, JavaString(memberName).UTF8String());
+
+ RootObject* rootObject = this->rootObject();
+ if (!rootObject)
+ return 0;
+
+ ExecState* exec = rootObject->globalObject()->globalExec();
+
+ JSLock lock(false);
+ JSValue* result = _imp->get(exec, Identifier(exec, JavaString(memberName)));
+
+ return convertValueToJObject(result);
+}
+
+void JavaJSObject::setMember(jstring memberName, jobject value) const
+{
+ JS_LOG ("memberName = %s, value = %p\n", JavaString(memberName).UTF8String(), value);
+
+ RootObject* rootObject = this->rootObject();
+ if (!rootObject)
+ return;
+
+ ExecState* exec = rootObject->globalObject()->globalExec();
+
+ JSLock lock(false);
+ PutPropertySlot slot;
+ _imp->put(exec, Identifier(exec, JavaString(memberName)), convertJObjectToValue(exec, value), slot);
+}
+
+
+void JavaJSObject::removeMember(jstring memberName) const
+{
+ JS_LOG ("memberName = %s\n", JavaString(memberName).UTF8String());
+
+ RootObject* rootObject = this->rootObject();
+ if (!rootObject)
+ return;
+
+ ExecState* exec = rootObject->globalObject()->globalExec();
+ JSLock lock(false);
+ _imp->deleteProperty(exec, Identifier(exec, JavaString(memberName)));
+}
+
+
+jobject JavaJSObject::getSlot(jint index) const
+{
+#ifdef __LP64__
+ JS_LOG ("index = %d\n", index);
+#else
+ JS_LOG ("index = %ld\n", index);
+#endif
+
+ RootObject* rootObject = this->rootObject();
+ if (!rootObject)
+ return 0;
+
+ ExecState* exec = rootObject->globalObject()->globalExec();
+
+ JSLock lock(false);
+ JSValue* result = _imp->get(exec, index);
+
+ return convertValueToJObject(result);
+}
+
+
+void JavaJSObject::setSlot(jint index, jobject value) const
+{
+#ifdef __LP64__
+ JS_LOG ("index = %d, value = %p\n", index, value);
+#else
+ JS_LOG ("index = %ld, value = %p\n", index, value);
+#endif
+
+ RootObject* rootObject = this->rootObject();
+ if (!rootObject)
+ return;
+
+ ExecState* exec = rootObject->globalObject()->globalExec();
+ JSLock lock(false);
+ _imp->put(exec, (unsigned)index, convertJObjectToValue(exec, value));
+}
+
+
+jstring JavaJSObject::toString() const
+{
+ JS_LOG ("\n");
+
+ RootObject* rootObject = this->rootObject();
+ if (!rootObject)
+ return 0;
+
+ JSLock lock(false);
+ JSObject *thisObj = const_cast<JSObject*>(_imp);
+ ExecState* exec = rootObject->globalObject()->globalExec();
+
+ return (jstring)convertValueToJValue (exec, thisObj, object_type, "java.lang.String").l;
+}
+
+void JavaJSObject::finalize() const
+{
+ if (RootObject* rootObject = this->rootObject())
+ rootObject->gcUnprotect(_imp);
+}
+
+static PassRefPtr<RootObject> createRootObject(void* nativeHandle)
+{
+ Frame* frame = 0;
+ for (NSView *view = (NSView *)nativeHandle; view; view = [view superview]) {
+ if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
+ NSView<WebCoreFrameView> *webCoreFrameView = static_cast<NSView<WebCoreFrameView>*>(view);
+ frame = [webCoreFrameView _web_frame];
+ break;
+ }
+ }
+ if (!frame)
+ return 0;
+ return frame->script()->createRootObject(nativeHandle);
+}
+
+// We're either creating a 'Root' object (via a call to JavaJSObject.getWindow()), or
+// another JavaJSObject.
+jlong JavaJSObject::createNative(jlong nativeHandle)
+{
+ JS_LOG ("nativeHandle = %d\n", (int)nativeHandle);
+
+ if (nativeHandle == UndefinedHandle)
+ return nativeHandle;
+
+ if (findProtectingRootObject(jlong_to_impptr(nativeHandle)))
+ return nativeHandle;
+
+ RefPtr<RootObject> rootObject = createRootObject(jlong_to_ptr(nativeHandle));
+
+ // If rootObject is !NULL We must have been called via netscape.javascript.JavaJSObject.getWindow(),
+ // otherwise we are being called after creating a JavaJSObject in
+ // JavaJSObject::convertValueToJObject().
+ if (rootObject) {
+ JSObject* globalObject = rootObject->globalObject();
+ // We call gcProtect here to get the object into the root object's "protect set" which
+ // is used to test if a native handle is valid as well as getting the root object given the handle.
+ rootObject->gcProtect(globalObject);
+ return ptr_to_jlong(globalObject);
+ }
+
+ return nativeHandle;
+}
+
+jobject JavaJSObject::convertValueToJObject(JSValue* value) const
+{
+ JSLock lock(false);
+
+ RootObject* rootObject = this->rootObject();
+ if (!rootObject)
+ return 0;
+
+ ExecState* exec = rootObject->globalObject()->globalExec();
+ JNIEnv *env = getJNIEnv();
+ jobject result = 0;
+
+ // See section 22.7 of 'JavaScript: The Definitive Guide, 4th Edition',
+ // figure 22-5.
+ // number -> java.lang.Double
+ // string -> java.lang.String
+ // boolean -> java.lang.Boolean
+ // Java instance -> Java instance
+ // Everything else -> JavaJSObject
+
+ if (value->isNumber()) {
+ jclass JSObjectClass = env->FindClass ("java/lang/Double");
+ jmethodID constructorID = env->GetMethodID (JSObjectClass, "<init>", "(D)V");
+ if (constructorID != NULL) {
+ result = env->NewObject (JSObjectClass, constructorID, (jdouble)value->toNumber(exec));
+ }
+ } else if (value->isString()) {
+ UString stringValue = value->toString(exec);
+ JNIEnv *env = getJNIEnv();
+ result = env->NewString ((const jchar *)stringValue.data(), stringValue.size());
+ } else if (value->isBoolean()) {
+ jclass JSObjectClass = env->FindClass ("java/lang/Boolean");
+ jmethodID constructorID = env->GetMethodID (JSObjectClass, "<init>", "(Z)V");
+ if (constructorID != NULL) {
+ result = env->NewObject (JSObjectClass, constructorID, (jboolean)value->toBoolean(exec));
+ }
+ }
+ else {
+ // Create a JavaJSObject.
+ jlong nativeHandle;
+
+ if (value->isObject()) {
+ JSObject* imp = asObject(value);
+
+ // We either have a wrapper around a Java instance or a JavaScript
+ // object. If we have a wrapper around a Java instance, return that
+ // instance, otherwise create a new Java JavaJSObject with the JSObject*
+ // as it's nativeHandle.
+ if (imp->classInfo() && strcmp(imp->classInfo()->className, "RuntimeObject") == 0) {
+ RuntimeObjectImp* runtimeImp = static_cast<RuntimeObjectImp*>(imp);
+ JavaInstance *runtimeInstance = static_cast<JavaInstance *>(runtimeImp->getInternalInstance());
+ if (!runtimeInstance)
+ return 0;
+
+ return runtimeInstance->javaInstance();
+ }
+ else {
+ nativeHandle = ptr_to_jlong(imp);
+ rootObject->gcProtect(imp);
+ }
+ }
+ // All other types will result in an undefined object.
+ else {
+ nativeHandle = UndefinedHandle;
+ }
+
+ // Now create the Java JavaJSObject. Look for the JavaJSObject in it's new (Tiger)
+ // location and in the original Java 1.4.2 location.
+ jclass JSObjectClass;
+
+ JSObjectClass = env->FindClass ("sun/plugin/javascript/webkit/JSObject");
+ if (!JSObjectClass) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ JSObjectClass = env->FindClass ("apple/applet/JSObject");
+ }
+
+ jmethodID constructorID = env->GetMethodID (JSObjectClass, "<init>", "(J)V");
+ if (constructorID != NULL) {
+ result = env->NewObject (JSObjectClass, constructorID, nativeHandle);
+ }
+ }
+
+ return result;
+}
+
+JSValue* JavaJSObject::convertJObjectToValue(ExecState* exec, jobject theObject) const
+{
+ // Instances of netscape.javascript.JSObject get converted back to
+ // JavaScript objects. All other objects are wrapped. It's not
+ // possible to pass primitive types from the Java to JavaScript.
+ // See section 22.7 of 'JavaScript: The Definitive Guide, 4th Edition',
+ // figure 22-4.
+ jobject classOfInstance = callJNIMethod<jobject>(theObject, "getClass", "()Ljava/lang/Class;");
+ jstring className = (jstring)callJNIMethod<jobject>(classOfInstance, "getName", "()Ljava/lang/String;");
+
+ // Only the sun.plugin.javascript.webkit.JSObject has a member called nativeJSObject. This class is
+ // created above to wrap internal browser objects. The constructor of this class takes the native
+ // pointer and stores it in this object, so that it can be retrieved below.
+ if (strcmp(JavaString(className).UTF8String(), "sun.plugin.javascript.webkit.JSObject") == 0) {
+ // Pull the nativeJSObject value from the Java instance. This is a
+ // pointer to the JSObject.
+ JNIEnv *env = getJNIEnv();
+ jfieldID fieldID = env->GetFieldID((jclass)classOfInstance, "nativeJSObject", "J");
+ if (fieldID == NULL) {
+ return jsUndefined();
+ }
+ jlong nativeHandle = env->GetLongField(theObject, fieldID);
+ if (nativeHandle == UndefinedHandle) {
+ return jsUndefined();
+ }
+ JSObject *imp = static_cast<JSObject*>(jlong_to_impptr(nativeHandle));
+ return imp;
+ }
+
+ JSLock lock(false);
+
+ return JSC::Bindings::Instance::createRuntimeObject(exec, JavaInstance::create(theObject, _rootObject));
+}
+
+void JavaJSObject::getListFromJArray(ExecState* exec, jobjectArray jArray, ArgList& list) const
+{
+ JNIEnv *env = getJNIEnv();
+ int numObjects = jArray ? env->GetArrayLength(jArray) : 0;
+
+ for (int i = 0; i < numObjects; i++) {
+ jobject anObject = env->GetObjectArrayElement ((jobjectArray)jArray, i);
+ if (anObject) {
+ list.append(convertJObjectToValue(exec, anObject));
+ env->DeleteLocalRef (anObject);
+ }
+ else {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ }
+}
+
+extern "C" {
+
+jlong KJS_JSCreateNativeJSObject (JNIEnv*, jclass, jstring, jlong nativeHandle, jboolean)
+{
+ JSObjectCallContext context;
+ context.type = CreateNative;
+ context.nativeHandle = nativeHandle;
+ return JavaJSObject::invoke (&context).j;
+}
+
+void KJS_JSObject_JSFinalize (JNIEnv*, jclass, jlong nativeHandle)
+{
+ JSObjectCallContext context;
+ context.type = Finalize;
+ context.nativeHandle = nativeHandle;
+ JavaJSObject::invoke (&context);
+}
+
+jobject KJS_JSObject_JSObjectCall (JNIEnv*, jclass, jlong nativeHandle, jstring, jstring methodName, jobjectArray args, jboolean)
+{
+ JSObjectCallContext context;
+ context.type = Call;
+ context.nativeHandle = nativeHandle;
+ context.string = methodName;
+ context.args = args;
+ return JavaJSObject::invoke (&context).l;
+}
+
+jobject KJS_JSObject_JSObjectEval (JNIEnv*, jclass, jlong nativeHandle, jstring, jstring jscript, jboolean)
+{
+ JSObjectCallContext context;
+ context.type = Eval;
+ context.nativeHandle = nativeHandle;
+ context.string = jscript;
+ return JavaJSObject::invoke (&context).l;
+}
+
+jobject KJS_JSObject_JSObjectGetMember (JNIEnv*, jclass, jlong nativeHandle, jstring, jstring jname, jboolean)
+{
+ JSObjectCallContext context;
+ context.type = GetMember;
+ context.nativeHandle = nativeHandle;
+ context.string = jname;
+ return JavaJSObject::invoke (&context).l;
+}
+
+void KJS_JSObject_JSObjectSetMember (JNIEnv*, jclass, jlong nativeHandle, jstring, jstring jname, jobject value, jboolean)
+{
+ JSObjectCallContext context;
+ context.type = SetMember;
+ context.nativeHandle = nativeHandle;
+ context.string = jname;
+ context.value = value;
+ JavaJSObject::invoke (&context);
+}
+
+void KJS_JSObject_JSObjectRemoveMember (JNIEnv*, jclass, jlong nativeHandle, jstring, jstring jname, jboolean)
+{
+ JSObjectCallContext context;
+ context.type = RemoveMember;
+ context.nativeHandle = nativeHandle;
+ context.string = jname;
+ JavaJSObject::invoke (&context);
+}
+
+jobject KJS_JSObject_JSObjectGetSlot (JNIEnv*, jclass, jlong nativeHandle, jstring, jint jindex, jboolean)
+{
+ JSObjectCallContext context;
+ context.type = GetSlot;
+ context.nativeHandle = nativeHandle;
+ context.index = jindex;
+ return JavaJSObject::invoke (&context).l;
+}
+
+void KJS_JSObject_JSObjectSetSlot (JNIEnv*, jclass, jlong nativeHandle, jstring, jint jindex, jobject value, jboolean)
+{
+ JSObjectCallContext context;
+ context.type = SetSlot;
+ context.nativeHandle = nativeHandle;
+ context.index = jindex;
+ context.value = value;
+ JavaJSObject::invoke (&context);
+}
+
+jstring KJS_JSObject_JSObjectToString (JNIEnv*, jclass, jlong nativeHandle)
+{
+ JSObjectCallContext context;
+ context.type = ToString;
+ context.nativeHandle = nativeHandle;
+ return (jstring)JavaJSObject::invoke (&context).l;
+}
+
+}
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
diff --git a/WebCore/bridge/jni/jni_objc.mm b/WebCore/bridge/jni/jni_objc.mm
new file mode 100644
index 0000000..45ee9f5
--- /dev/null
+++ b/WebCore/bridge/jni/jni_objc.mm
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2004 Apple Computer, 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"
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#import <Foundation/Foundation.h>
+#import "jni_utility.h"
+#import "objc_utility.h"
+#include <runtime/JSLock.h>
+
+using namespace JSC::Bindings;
+
+@interface NSObject (WebScriptingPrivate)
+- (jvalue)webPlugInCallJava:(jobject)object method:(jmethodID)method returnType:(JNIType)returnType arguments:(jvalue*)args;
+- (jvalue)webPlugInCallJava:(jobject)object
+ isStatic:(BOOL)isStatic
+ returnType:(JNIType)returnType
+ method:(jmethodID)method
+ arguments:(jvalue*)args
+ callingURL:(NSURL *)url
+ exceptionDescription:(NSString **)exceptionString;
+@end
+
+bool JSC::Bindings::dispatchJNICall(ExecState* exec, const void* targetAppletView, jobject obj, bool isStatic, JNIType returnType, jmethodID methodID, jvalue* args, jvalue &result, const char*, JSValue*& exceptionDescription)
+{
+ id view = (id)targetAppletView;
+
+ // As array_type is not known by the Mac JVM, change it to a compatible type.
+ if (returnType == array_type)
+ returnType = object_type;
+
+ if ([view respondsToSelector:@selector(webPlugInCallJava:isStatic:returnType:method:arguments:callingURL:exceptionDescription:)]) {
+ NSString *_exceptionDescription = 0;
+
+ // Passing nil as the calling URL will cause the Java plugin to use the URL
+ // of the page that contains the applet. The execution restrictions
+ // implemented in WebCore will guarantee that only appropriate JavaScript
+ // can reference the applet.
+ {
+ JSLock::DropAllLocks dropAllLocks(false);
+ result = [view webPlugInCallJava:obj isStatic:isStatic returnType:returnType method:methodID arguments:args callingURL:nil exceptionDescription:&_exceptionDescription];
+ }
+
+ if (_exceptionDescription != 0) {
+ exceptionDescription = convertNSStringToString(exec, _exceptionDescription);
+ }
+ return true;
+ }
+ else if ([view respondsToSelector:@selector(webPlugInCallJava:method:returnType:arguments:)]) {
+ JSLock::DropAllLocks dropAllLocks(false);
+ result = [view webPlugInCallJava:obj method:methodID returnType:returnType arguments:args];
+ return true;
+ }
+
+ bzero (&result, sizeof(jvalue));
+ return false;
+}
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
diff --git a/WebCore/bridge/jni/jni_runtime.cpp b/WebCore/bridge/jni/jni_runtime.cpp
new file mode 100644
index 0000000..3a9b950
--- /dev/null
+++ b/WebCore/bridge/jni/jni_runtime.cpp
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2003 Apple Computer, 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 <jni_runtime.h>
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#include <jni_utility.h>
+
+#include "runtime_array.h"
+#include "runtime_object.h"
+#include "runtime_root.h"
+#include <runtime/Error.h>
+#include <runtime/JSLock.h>
+
+#ifdef NDEBUG
+#define JS_LOG(formatAndArgs...) ((void)0)
+#else
+#define JS_LOG(formatAndArgs...) { \
+ fprintf (stderr, "%s:%d -- %s: ", __FILE__, __LINE__, __FUNCTION__); \
+ fprintf(stderr, formatAndArgs); \
+}
+#endif
+
+using namespace JSC;
+using namespace JSC::Bindings;
+
+
+JavaParameter::JavaParameter (JNIEnv *env, jstring type)
+{
+ _type = JavaString (env, type);
+ _JNIType = JNITypeFromClassName (_type.UTF8String());
+}
+
+JavaField::JavaField (JNIEnv *env, jobject aField)
+{
+ // Get field type
+ jobject fieldType = callJNIMethod<jobject>(aField, "getType", "()Ljava/lang/Class;");
+ jstring fieldTypeName = (jstring)callJNIMethod<jobject>(fieldType, "getName", "()Ljava/lang/String;");
+ _type = JavaString(env, fieldTypeName);
+ _JNIType = JNITypeFromClassName (_type.UTF8String());
+
+ // Get field name
+ jstring fieldName = (jstring)callJNIMethod<jobject>(aField, "getName", "()Ljava/lang/String;");
+ _name = JavaString(env, fieldName);
+
+ _field = new JObjectWrapper(aField);
+}
+
+JSValue* JavaArray::convertJObjectToArray(ExecState* exec, jobject anObject, const char* type, PassRefPtr<RootObject> rootObject)
+{
+ if (type[0] != '[')
+ return jsUndefined();
+
+ return new (exec) RuntimeArray(exec, new JavaArray((jobject)anObject, type, rootObject));
+}
+
+jvalue JavaField::dispatchValueFromInstance(ExecState *exec, const JavaInstance *instance, const char *name, const char *sig, JNIType returnType) const
+{
+ jobject jinstance = instance->javaInstance();
+ jobject fieldJInstance = _field->_instance;
+ JNIEnv *env = getJNIEnv();
+ jvalue result;
+
+ bzero (&result, sizeof(jvalue));
+ jclass cls = env->GetObjectClass(fieldJInstance);
+ if ( cls != NULL ) {
+ jmethodID mid = env->GetMethodID(cls, name, sig);
+ if ( mid != NULL )
+ {
+ RootObject* rootObject = instance->rootObject();
+ if (rootObject && rootObject->nativeHandle()) {
+ JSValue* exceptionDescription = noValue();
+ jvalue args[1];
+
+ args[0].l = jinstance;
+ dispatchJNICall(exec, rootObject->nativeHandle(), fieldJInstance, false, returnType, mid, args, result, 0, exceptionDescription);
+ if (exceptionDescription)
+ throwError(exec, GeneralError, exceptionDescription->toString(exec));
+ }
+ }
+ }
+ return result;
+}
+
+JSValue* JavaField::valueFromInstance(ExecState* exec, const Instance* i) const
+{
+ const JavaInstance *instance = static_cast<const JavaInstance *>(i);
+
+ JSValue* jsresult = jsUndefined();
+
+ switch (_JNIType) {
+ case array_type:
+ case object_type: {
+ jvalue result = dispatchValueFromInstance (exec, instance, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", object_type);
+ jobject anObject = result.l;
+
+ const char *arrayType = type();
+ if (arrayType[0] == '[') {
+ jsresult = JavaArray::convertJObjectToArray(exec, anObject, arrayType, instance->rootObject());
+ }
+ else if (anObject != 0){
+ jsresult = Instance::createRuntimeObject(exec, JavaInstance::create(anObject, instance->rootObject()));
+ }
+ }
+ break;
+
+ case boolean_type:
+ jsresult = jsBoolean(dispatchValueFromInstance(exec, instance, "getBoolean", "(Ljava/lang/Object;)Z", boolean_type).z);
+ break;
+
+ case byte_type:
+ case char_type:
+ case short_type:
+
+ case int_type: {
+ jint value;
+ jvalue result = dispatchValueFromInstance (exec, instance, "getInt", "(Ljava/lang/Object;)I", int_type);
+ value = result.i;
+ jsresult = jsNumber(exec, (int)value);
+ }
+ break;
+
+ case long_type:
+ case float_type:
+ case double_type: {
+ jdouble value;
+ jvalue result = dispatchValueFromInstance (exec, instance, "getDouble", "(Ljava/lang/Object;)D", double_type);
+ value = result.i;
+ jsresult = jsNumber(exec, (double)value);
+ }
+ break;
+ default:
+ break;
+ }
+
+ JS_LOG ("getting %s = %s\n", name(), jsresult->toString(exec).ascii());
+
+ return jsresult;
+}
+
+void JavaField::dispatchSetValueToInstance(ExecState *exec, const JavaInstance *instance, jvalue javaValue, const char *name, const char *sig) const
+{
+ jobject jinstance = instance->javaInstance();
+ jobject fieldJInstance = _field->_instance;
+ JNIEnv *env = getJNIEnv();
+
+ jclass cls = env->GetObjectClass(fieldJInstance);
+ if ( cls != NULL ) {
+ jmethodID mid = env->GetMethodID(cls, name, sig);
+ if ( mid != NULL )
+ {
+ RootObject* rootObject = instance->rootObject();
+ if (rootObject && rootObject->nativeHandle()) {
+ JSValue* exceptionDescription = noValue();
+ jvalue args[2];
+ jvalue result;
+
+ args[0].l = jinstance;
+ args[1] = javaValue;
+ dispatchJNICall(exec, rootObject->nativeHandle(), fieldJInstance, false, void_type, mid, args, result, 0, exceptionDescription);
+ if (exceptionDescription)
+ throwError(exec, GeneralError, exceptionDescription->toString(exec));
+ }
+ }
+ }
+}
+
+void JavaField::setValueToInstance(ExecState* exec, const Instance* i, JSValue* aValue) const
+{
+ const JavaInstance *instance = static_cast<const JavaInstance *>(i);
+ jvalue javaValue = convertValueToJValue (exec, aValue, _JNIType, type());
+
+ JS_LOG ("setting value %s to %s\n", name(), aValue->toString(exec).ascii());
+
+ switch (_JNIType) {
+ case array_type:
+ case object_type: {
+ dispatchSetValueToInstance (exec, instance, javaValue, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V");
+ }
+ break;
+
+ case boolean_type: {
+ dispatchSetValueToInstance (exec, instance, javaValue, "setBoolean", "(Ljava/lang/Object;Z)V");
+ }
+ break;
+
+ case byte_type: {
+ dispatchSetValueToInstance (exec, instance, javaValue, "setByte", "(Ljava/lang/Object;B)V");
+ }
+ break;
+
+ case char_type: {
+ dispatchSetValueToInstance (exec, instance, javaValue, "setChar", "(Ljava/lang/Object;C)V");
+ }
+ break;
+
+ case short_type: {
+ dispatchSetValueToInstance (exec, instance, javaValue, "setShort", "(Ljava/lang/Object;S)V");
+ }
+ break;
+
+ case int_type: {
+ dispatchSetValueToInstance (exec, instance, javaValue, "setInt", "(Ljava/lang/Object;I)V");
+ }
+ break;
+
+ case long_type: {
+ dispatchSetValueToInstance (exec, instance, javaValue, "setLong", "(Ljava/lang/Object;J)V");
+ }
+ break;
+
+ case float_type: {
+ dispatchSetValueToInstance (exec, instance, javaValue, "setFloat", "(Ljava/lang/Object;F)V");
+ }
+ break;
+
+ case double_type: {
+ dispatchSetValueToInstance (exec, instance, javaValue, "setDouble", "(Ljava/lang/Object;D)V");
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+JavaMethod::JavaMethod (JNIEnv *env, jobject aMethod)
+{
+ // Get return type
+ jobject returnType = callJNIMethod<jobject>(aMethod, "getReturnType", "()Ljava/lang/Class;");
+ jstring returnTypeName = (jstring)callJNIMethod<jobject>(returnType, "getName", "()Ljava/lang/String;");
+ _returnType =JavaString (env, returnTypeName);
+ _JNIReturnType = JNITypeFromClassName (_returnType.UTF8String());
+ env->DeleteLocalRef (returnType);
+ env->DeleteLocalRef (returnTypeName);
+
+ // Get method name
+ jstring methodName = (jstring)callJNIMethod<jobject>(aMethod, "getName", "()Ljava/lang/String;");
+ _name = JavaString (env, methodName);
+ env->DeleteLocalRef (methodName);
+
+ // Get parameters
+ jarray jparameters = (jarray)callJNIMethod<jobject>(aMethod, "getParameterTypes", "()[Ljava/lang/Class;");
+ _numParameters = env->GetArrayLength (jparameters);
+ _parameters = new JavaParameter[_numParameters];
+
+ int i;
+ for (i = 0; i < _numParameters; i++) {
+ jobject aParameter = env->GetObjectArrayElement ((jobjectArray)jparameters, i);
+ jstring parameterName = (jstring)callJNIMethod<jobject>(aParameter, "getName", "()Ljava/lang/String;");
+ _parameters[i] = JavaParameter(env, parameterName);
+ env->DeleteLocalRef (aParameter);
+ env->DeleteLocalRef (parameterName);
+ }
+ env->DeleteLocalRef (jparameters);
+
+ // Created lazily.
+ _signature = 0;
+ _methodID = 0;
+
+ jclass modifierClass = env->FindClass("java/lang/reflect/Modifier");
+ int modifiers = callJNIMethod<jint>(aMethod, "getModifiers", "()I");
+ _isStatic = (bool)callJNIStaticMethod<jboolean>(modifierClass, "isStatic", "(I)Z", modifiers);
+}
+
+JavaMethod::~JavaMethod()
+{
+ if (_signature)
+ free(_signature);
+ delete [] _parameters;
+};
+
+// JNI method signatures use '/' between components of a class name, but
+// we get '.' between components from the reflection API.
+static void appendClassName(UString& aString, const char* className)
+{
+ ASSERT(JSLock::lockCount() > 0);
+
+ char *result, *cp = strdup(className);
+
+ result = cp;
+ while (*cp) {
+ if (*cp == '.')
+ *cp = '/';
+ cp++;
+ }
+
+ aString.append(result);
+
+ free (result);
+}
+
+const char *JavaMethod::signature() const
+{
+ if (!_signature) {
+ JSLock lock(false);
+
+ UString signatureBuilder("(");
+ for (int i = 0; i < _numParameters; i++) {
+ JavaParameter* aParameter = parameterAt(i);
+ JNIType _JNIType = aParameter->getJNIType();
+ if (_JNIType == array_type)
+ appendClassName(signatureBuilder, aParameter->type());
+ else {
+ signatureBuilder.append(signatureFromPrimitiveType(_JNIType));
+ if (_JNIType == object_type) {
+ appendClassName(signatureBuilder, aParameter->type());
+ signatureBuilder.append(";");
+ }
+ }
+ }
+ signatureBuilder.append(")");
+
+ const char *returnType = _returnType.UTF8String();
+ if (_JNIReturnType == array_type) {
+ appendClassName(signatureBuilder, returnType);
+ } else {
+ signatureBuilder.append(signatureFromPrimitiveType(_JNIReturnType));
+ if (_JNIReturnType == object_type) {
+ appendClassName(signatureBuilder, returnType);
+ signatureBuilder.append(";");
+ }
+ }
+
+ _signature = strdup(signatureBuilder.ascii());
+ }
+
+ return _signature;
+}
+
+JNIType JavaMethod::JNIReturnType() const
+{
+ return _JNIReturnType;
+}
+
+jmethodID JavaMethod::methodID (jobject obj) const
+{
+ if (_methodID == 0) {
+ _methodID = getMethodID (obj, name(), signature());
+ }
+ return _methodID;
+}
+
+
+JavaArray::JavaArray(jobject array, const char* type, PassRefPtr<RootObject> rootObject)
+ : Array(rootObject)
+{
+ _array = new JObjectWrapper(array);
+ // Java array are fixed length, so we can cache length.
+ JNIEnv *env = getJNIEnv();
+ _length = env->GetArrayLength((jarray)_array->_instance);
+ _type = strdup(type);
+ _rootObject = rootObject;
+}
+
+JavaArray::~JavaArray ()
+{
+ free ((void *)_type);
+}
+
+RootObject* JavaArray::rootObject() const
+{
+ return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
+}
+
+void JavaArray::setValueAt(ExecState* exec, unsigned index, JSValue* aValue) const
+{
+ JNIEnv *env = getJNIEnv();
+ char *javaClassName = 0;
+
+ JNIType arrayType = JNITypeFromPrimitiveType(_type[1]);
+ if (_type[1] == 'L'){
+ // The type of the array will be something like:
+ // "[Ljava.lang.string;". This is guaranteed, so no need
+ // for extra sanity checks.
+ javaClassName = strdup(&_type[2]);
+ javaClassName[strchr(javaClassName, ';')-javaClassName] = 0;
+ }
+ jvalue aJValue = convertValueToJValue (exec, aValue, arrayType, javaClassName);
+
+ switch (arrayType) {
+ case object_type: {
+ env->SetObjectArrayElement((jobjectArray)javaArray(), index, aJValue.l);
+ break;
+ }
+
+ case boolean_type: {
+ env->SetBooleanArrayRegion((jbooleanArray)javaArray(), index, 1, &aJValue.z);
+ break;
+ }
+
+ case byte_type: {
+ env->SetByteArrayRegion((jbyteArray)javaArray(), index, 1, &aJValue.b);
+ break;
+ }
+
+ case char_type: {
+ env->SetCharArrayRegion((jcharArray)javaArray(), index, 1, &aJValue.c);
+ break;
+ }
+
+ case short_type: {
+ env->SetShortArrayRegion((jshortArray)javaArray(), index, 1, &aJValue.s);
+ break;
+ }
+
+ case int_type: {
+ env->SetIntArrayRegion((jintArray)javaArray(), index, 1, &aJValue.i);
+ break;
+ }
+
+ case long_type: {
+ env->SetLongArrayRegion((jlongArray)javaArray(), index, 1, &aJValue.j);
+ }
+
+ case float_type: {
+ env->SetFloatArrayRegion((jfloatArray)javaArray(), index, 1, &aJValue.f);
+ break;
+ }
+
+ case double_type: {
+ env->SetDoubleArrayRegion((jdoubleArray)javaArray(), index, 1, &aJValue.d);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (javaClassName)
+ free ((void *)javaClassName);
+}
+
+
+JSValue* JavaArray::valueAt(ExecState* exec, unsigned index) const
+{
+ JNIEnv *env = getJNIEnv();
+ JNIType arrayType = JNITypeFromPrimitiveType(_type[1]);
+ switch (arrayType) {
+ case object_type: {
+ jobjectArray objectArray = (jobjectArray)javaArray();
+ jobject anObject;
+ anObject = env->GetObjectArrayElement(objectArray, index);
+
+ // No object?
+ if (!anObject) {
+ return jsNull();
+ }
+
+ // Nested array?
+ if (_type[1] == '[') {
+ return JavaArray::convertJObjectToArray(exec, anObject, _type+1, rootObject());
+ }
+ // or array of other object type?
+ return Instance::createRuntimeObject(exec, JavaInstance::create(anObject, rootObject()));
+ }
+
+ case boolean_type: {
+ jbooleanArray booleanArray = (jbooleanArray)javaArray();
+ jboolean aBoolean;
+ env->GetBooleanArrayRegion(booleanArray, index, 1, &aBoolean);
+ return jsBoolean(aBoolean);
+ }
+
+ case byte_type: {
+ jbyteArray byteArray = (jbyteArray)javaArray();
+ jbyte aByte;
+ env->GetByteArrayRegion(byteArray, index, 1, &aByte);
+ return jsNumber(exec, aByte);
+ }
+
+ case char_type: {
+ jcharArray charArray = (jcharArray)javaArray();
+ jchar aChar;
+ env->GetCharArrayRegion(charArray, index, 1, &aChar);
+ return jsNumber(exec, aChar);
+ break;
+ }
+
+ case short_type: {
+ jshortArray shortArray = (jshortArray)javaArray();
+ jshort aShort;
+ env->GetShortArrayRegion(shortArray, index, 1, &aShort);
+ return jsNumber(exec, aShort);
+ }
+
+ case int_type: {
+ jintArray intArray = (jintArray)javaArray();
+ jint anInt;
+ env->GetIntArrayRegion(intArray, index, 1, &anInt);
+ return jsNumber(exec, anInt);
+ }
+
+ case long_type: {
+ jlongArray longArray = (jlongArray)javaArray();
+ jlong aLong;
+ env->GetLongArrayRegion(longArray, index, 1, &aLong);
+ return jsNumber(exec, aLong);
+ }
+
+ case float_type: {
+ jfloatArray floatArray = (jfloatArray)javaArray();
+ jfloat aFloat;
+ env->GetFloatArrayRegion(floatArray, index, 1, &aFloat);
+ return jsNumber(exec, aFloat);
+ }
+
+ case double_type: {
+ jdoubleArray doubleArray = (jdoubleArray)javaArray();
+ jdouble aDouble;
+ env->GetDoubleArrayRegion(doubleArray, index, 1, &aDouble);
+ return jsNumber(exec, aDouble);
+ }
+ default:
+ break;
+ }
+ return jsUndefined();
+}
+
+unsigned int JavaArray::getLength() const
+{
+ return _length;
+}
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
diff --git a/WebCore/bridge/jni/jni_runtime.h b/WebCore/bridge/jni/jni_runtime.h
new file mode 100644
index 0000000..67bc06e
--- /dev/null
+++ b/WebCore/bridge/jni/jni_runtime.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2003 Apple Computer, 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.
+ */
+
+#ifndef _JNI_RUNTIME_H_
+#define _JNI_RUNTIME_H_
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#include <jni_utility.h>
+#include <jni_instance.h>
+#include <runtime/JSLock.h>
+
+
+namespace JSC
+{
+
+namespace Bindings
+{
+
+typedef const char* RuntimeType;
+
+class JavaString
+{
+public:
+ JavaString()
+ {
+ JSLock lock(false);
+ _rep = UString().rep();
+ }
+
+ void _commonInit (JNIEnv *e, jstring s)
+ {
+ int _size = e->GetStringLength (s);
+ const jchar *uc = getUCharactersFromJStringInEnv (e, s);
+ {
+ JSLock lock(false);
+ _rep = UString((UChar *)uc,_size).rep();
+ }
+ releaseUCharactersForJStringInEnv (e, s, uc);
+ }
+
+ JavaString (JNIEnv *e, jstring s) {
+ _commonInit (e, s);
+ }
+
+ JavaString (jstring s) {
+ _commonInit (getJNIEnv(), s);
+ }
+
+ ~JavaString()
+ {
+ JSLock lock(false);
+ _rep = 0;
+ }
+
+ const char *UTF8String() const {
+ if (_utf8String.c_str() == 0) {
+ JSLock lock(false);
+ _utf8String = UString(_rep).UTF8String();
+ }
+ return _utf8String.c_str();
+ }
+ const jchar *uchars() const { return (const jchar *)_rep->data(); }
+ int length() const { return _rep->size(); }
+ operator UString() const { return UString(_rep); }
+
+private:
+ RefPtr<UString::Rep> _rep;
+ mutable CString _utf8String;
+};
+
+class JavaParameter
+{
+public:
+ JavaParameter () : _JNIType(invalid_type) {};
+ JavaParameter (JNIEnv *env, jstring type);
+ virtual ~JavaParameter() { }
+
+ RuntimeType type() const { return _type.UTF8String(); }
+ JNIType getJNIType() const { return _JNIType; }
+
+private:
+ JavaString _type;
+ JNIType _JNIType;
+};
+
+
+class JavaField : public Field
+{
+public:
+ JavaField (JNIEnv *env, jobject aField);
+
+ virtual JSValue* valueFromInstance(ExecState *exec, const Instance *instance) const;
+ virtual void setValueToInstance(ExecState *exec, const Instance *instance, JSValue* aValue) const;
+
+ virtual const char *name() const { return _name.UTF8String(); }
+ virtual RuntimeType type() const { return _type.UTF8String(); }
+
+ JNIType getJNIType() const { return _JNIType; }
+
+private:
+ void dispatchSetValueToInstance(ExecState *exec, const JavaInstance *instance, jvalue javaValue, const char *name, const char *sig) const;
+ jvalue dispatchValueFromInstance(ExecState *exec, const JavaInstance *instance, const char *name, const char *sig, JNIType returnType) const;
+
+ JavaString _name;
+ JavaString _type;
+ JNIType _JNIType;
+ RefPtr<JObjectWrapper> _field;
+};
+
+
+class JavaMethod : public Method
+{
+public:
+ JavaMethod(JNIEnv* env, jobject aMethod);
+ ~JavaMethod();
+
+ virtual const char *name() const { return _name.UTF8String(); };
+ RuntimeType returnType() const { return _returnType.UTF8String(); };
+ JavaParameter* parameterAt(int i) const { return &_parameters[i]; };
+ int numParameters() const { return _numParameters; };
+
+ const char *signature() const;
+ JNIType JNIReturnType() const;
+
+ jmethodID methodID (jobject obj) const;
+
+ bool isStatic() const { return _isStatic; }
+
+private:
+ JavaParameter* _parameters;
+ int _numParameters;
+ JavaString _name;
+ mutable char* _signature;
+ JavaString _returnType;
+ JNIType _JNIReturnType;
+ mutable jmethodID _methodID;
+ bool _isStatic;
+};
+
+class JavaArray : public Array
+{
+public:
+ JavaArray(jobject array, const char* type, PassRefPtr<RootObject>);
+ virtual ~JavaArray();
+
+ RootObject* rootObject() const;
+
+ virtual void setValueAt(ExecState *exec, unsigned int index, JSValue* aValue) const;
+ virtual JSValue* valueAt(ExecState *exec, unsigned int index) const;
+ virtual unsigned int getLength() const;
+
+ jobject javaArray() const { return _array->_instance; }
+
+ static JSValue* convertJObjectToArray (ExecState* exec, jobject anObject, const char* type, PassRefPtr<RootObject>);
+
+private:
+ RefPtr<JObjectWrapper> _array;
+ unsigned int _length;
+ const char *_type;
+};
+
+} // namespace Bindings
+
+} // namespace JSC
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
+
+#endif // _JNI_RUNTIME_H_
diff --git a/WebCore/bridge/jni/jni_utility.cpp b/WebCore/bridge/jni/jni_utility.cpp
new file mode 100644
index 0000000..0fe7174
--- /dev/null
+++ b/WebCore/bridge/jni/jni_utility.cpp
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2003 Apple Computer, 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 "jni_utility.h"
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#include "jni_runtime.h"
+#include "runtime_array.h"
+#include "runtime_object.h"
+#include <runtime/JSArray.h>
+#include <runtime/JSLock.h>
+#include <dlfcn.h>
+
+namespace JSC {
+
+namespace Bindings {
+
+static jint KJS_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
+{
+ static void* javaVMFramework = 0;
+ if (!javaVMFramework)
+ javaVMFramework = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY);
+ if (!javaVMFramework)
+ return JNI_ERR;
+
+ static jint(*functionPointer)(JavaVM**, jsize, jsize *) = 0;
+ if (!functionPointer)
+ functionPointer = (jint(*)(JavaVM**, jsize, jsize *))dlsym(javaVMFramework, "JNI_GetCreatedJavaVMs");
+ if (!functionPointer)
+ return JNI_ERR;
+ return functionPointer(vmBuf, bufLen, nVMs);
+}
+
+static JavaVM *jvm = 0;
+
+// Provide the ability for an outside component to specify the JavaVM to use
+// If the jvm value is set, the getJavaVM function below will just return.
+// In getJNIEnv(), if AttachCurrentThread is called to a VM that is already
+// attached, the result is a no-op.
+void setJavaVM(JavaVM *javaVM)
+{
+ jvm = javaVM;
+}
+
+JavaVM *getJavaVM()
+{
+ if (jvm)
+ return jvm;
+
+ JavaVM *jvmArray[1];
+ jsize bufLen = 1;
+ jsize nJVMs = 0;
+ jint jniError = 0;
+
+ // Assumes JVM is already running ..., one per process
+ jniError = KJS_GetCreatedJavaVMs(jvmArray, bufLen, &nJVMs);
+ if ( jniError == JNI_OK && nJVMs > 0 ) {
+ jvm = jvmArray[0];
+ }
+ else
+ fprintf(stderr, "%s: JNI_GetCreatedJavaVMs failed, returned %ld\n", __PRETTY_FUNCTION__, (long)jniError);
+
+ return jvm;
+}
+
+JNIEnv* getJNIEnv()
+{
+ union {
+ JNIEnv* env;
+ void* dummy;
+ } u;
+ jint jniError = 0;
+
+ jniError = (getJavaVM())->AttachCurrentThread(&u.dummy, NULL);
+ if (jniError == JNI_OK)
+ return u.env;
+ else
+ fprintf(stderr, "%s: AttachCurrentThread failed, returned %ld\n", __PRETTY_FUNCTION__, (long)jniError);
+ return NULL;
+}
+
+jmethodID getMethodID (jobject obj, const char *name, const char *sig)
+{
+ JNIEnv *env = getJNIEnv();
+ jmethodID mid = 0;
+
+ if ( env != NULL) {
+ jclass cls = env->GetObjectClass(obj);
+ if ( cls != NULL ) {
+ mid = env->GetMethodID(cls, name, sig);
+ if (!mid) {
+ env->ExceptionClear();
+ mid = env->GetStaticMethodID(cls, name, sig);
+ if (!mid) {
+ env->ExceptionClear();
+ }
+ }
+ }
+ env->DeleteLocalRef(cls);
+ }
+ return mid;
+}
+
+const char *getCharactersFromJString (jstring aJString)
+{
+ return getCharactersFromJStringInEnv (getJNIEnv(), aJString);
+}
+
+void releaseCharactersForJString (jstring aJString, const char *s)
+{
+ releaseCharactersForJStringInEnv (getJNIEnv(), aJString, s);
+}
+
+const char *getCharactersFromJStringInEnv (JNIEnv *env, jstring aJString)
+{
+ jboolean isCopy;
+ const char *s = env->GetStringUTFChars((jstring)aJString, &isCopy);
+ if (!s) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ fprintf (stderr, "\n");
+ }
+ return s;
+}
+
+void releaseCharactersForJStringInEnv (JNIEnv *env, jstring aJString, const char *s)
+{
+ env->ReleaseStringUTFChars (aJString, s);
+}
+
+const jchar *getUCharactersFromJStringInEnv (JNIEnv *env, jstring aJString)
+{
+ jboolean isCopy;
+ const jchar *s = env->GetStringChars((jstring)aJString, &isCopy);
+ if (!s) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ fprintf (stderr, "\n");
+ }
+ return s;
+}
+
+void releaseUCharactersForJStringInEnv (JNIEnv *env, jstring aJString, const jchar *s)
+{
+ env->ReleaseStringChars (aJString, s);
+}
+
+JNIType JNITypeFromClassName(const char *name)
+{
+ JNIType type;
+
+ if (strcmp("byte",name) == 0)
+ type = byte_type;
+ else if (strcmp("short",name) == 0)
+ type = short_type;
+ else if (strcmp("int",name) == 0)
+ type = int_type;
+ else if (strcmp("long",name) == 0)
+ type = long_type;
+ else if (strcmp("float",name) == 0)
+ type = float_type;
+ else if (strcmp("double",name) == 0)
+ type = double_type;
+ else if (strcmp("char",name) == 0)
+ type = char_type;
+ else if (strcmp("boolean",name) == 0)
+ type = boolean_type;
+ else if (strcmp("void",name) == 0)
+ type = void_type;
+ else if ('[' == name[0])
+ type = array_type;
+ else
+ type = object_type;
+
+ return type;
+}
+
+const char *signatureFromPrimitiveType(JNIType type)
+{
+ switch (type){
+ case void_type:
+ return "V";
+
+ case array_type:
+ return "[";
+
+ case object_type:
+ return "L";
+
+ case boolean_type:
+ return "Z";
+
+ case byte_type:
+ return "B";
+
+ case char_type:
+ return "C";
+
+ case short_type:
+ return "S";
+
+ case int_type:
+ return "I";
+
+ case long_type:
+ return "J";
+
+ case float_type:
+ return "F";
+
+ case double_type:
+ return "D";
+
+ case invalid_type:
+ default:
+ break;
+ }
+ return "";
+}
+
+JNIType JNITypeFromPrimitiveType(char type)
+{
+ switch (type){
+ case 'V':
+ return void_type;
+
+ case 'L':
+ return object_type;
+
+ case '[':
+ return array_type;
+
+ case 'Z':
+ return boolean_type;
+
+ case 'B':
+ return byte_type;
+
+ case 'C':
+ return char_type;
+
+ case 'S':
+ return short_type;
+
+ case 'I':
+ return int_type;
+
+ case 'J':
+ return long_type;
+
+ case 'F':
+ return float_type;
+
+ case 'D':
+ return double_type;
+
+ default:
+ break;
+ }
+ return invalid_type;
+}
+
+jvalue getJNIField( jobject obj, JNIType type, const char *name, const char *signature)
+{
+ JavaVM *jvm = getJavaVM();
+ JNIEnv *env = getJNIEnv();
+ jvalue result;
+
+ bzero (&result, sizeof(jvalue));
+ if ( obj != NULL && jvm != NULL && env != NULL) {
+ jclass cls = env->GetObjectClass(obj);
+ if ( cls != NULL ) {
+ jfieldID field = env->GetFieldID(cls, name, signature);
+ if ( field != NULL ) {
+ switch (type) {
+ case array_type:
+ case object_type:
+ result.l = env->functions->GetObjectField(env, obj, field);
+ break;
+ case boolean_type:
+ result.z = env->functions->GetBooleanField(env, obj, field);
+ break;
+ case byte_type:
+ result.b = env->functions->GetByteField(env, obj, field);
+ break;
+ case char_type:
+ result.c = env->functions->GetCharField(env, obj, field);
+ break;
+ case short_type:
+ result.s = env->functions->GetShortField(env, obj, field);
+ break;
+ case int_type:
+ result.i = env->functions->GetIntField(env, obj, field);
+ break;
+ case long_type:
+ result.j = env->functions->GetLongField(env, obj, field);
+ break;
+ case float_type:
+ result.f = env->functions->GetFloatField(env, obj, field);
+ break;
+ case double_type:
+ result.d = env->functions->GetDoubleField(env, obj, field);
+ break;
+ default:
+ fprintf(stderr, "%s: invalid field type (%d)\n", __PRETTY_FUNCTION__, (int)type);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "%s: Could not find field: %s\n", __PRETTY_FUNCTION__, name);
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ fprintf (stderr, "\n");
+ }
+
+ env->DeleteLocalRef(cls);
+ }
+ else {
+ fprintf(stderr, "%s: Could not find class for object\n", __PRETTY_FUNCTION__);
+ }
+ }
+
+ return result;
+}
+
+static jobject convertArrayInstanceToJavaArray(ExecState* exec, JSArray* jsArray, const char* javaClassName)
+{
+ JNIEnv *env = getJNIEnv();
+ // As JS Arrays can contain a mixture of objects, assume we can convert to
+ // the requested Java Array type requested, unless the array type is some object array
+ // other than a string.
+ unsigned length = jsArray->length();
+ jobjectArray jarray = 0;
+
+ // Build the correct array type
+ switch (JNITypeFromPrimitiveType(javaClassName[1])) {
+ case object_type: {
+ // Only support string object types
+ if (0 == strcmp("[Ljava.lang.String;", javaClassName)) {
+ jarray = (jobjectArray)env->NewObjectArray(length,
+ env->FindClass("java/lang/String"),
+ env->NewStringUTF(""));
+ for(unsigned i = 0; i < length; i++) {
+ JSValue* item = jsArray->get(exec, i);
+ UString stringValue = item->toString(exec);
+ env->SetObjectArrayElement(jarray,i,
+ env->functions->NewString(env, (const jchar *)stringValue.data(), stringValue.size()));
+ }
+ }
+ break;
+ }
+
+ case boolean_type: {
+ jarray = (jobjectArray)env->NewBooleanArray(length);
+ for(unsigned i = 0; i < length; i++) {
+ JSValue* item = jsArray->get(exec, i);
+ jboolean value = (jboolean)item->toNumber(exec);
+ env->SetBooleanArrayRegion((jbooleanArray)jarray, (jsize)i, (jsize)1, &value);
+ }
+ break;
+ }
+
+ case byte_type: {
+ jarray = (jobjectArray)env->NewByteArray(length);
+ for(unsigned i = 0; i < length; i++) {
+ JSValue* item = jsArray->get(exec, i);
+ jbyte value = (jbyte)item->toNumber(exec);
+ env->SetByteArrayRegion((jbyteArray)jarray, (jsize)i, (jsize)1, &value);
+ }
+ break;
+ }
+
+ case char_type: {
+ jarray = (jobjectArray)env->NewCharArray(length);
+ for(unsigned i = 0; i < length; i++) {
+ JSValue* item = jsArray->get(exec, i);
+ UString stringValue = item->toString(exec);
+ jchar value = 0;
+ if (stringValue.size() > 0)
+ value = ((const jchar*)stringValue.data())[0];
+ env->SetCharArrayRegion((jcharArray)jarray, (jsize)i, (jsize)1, &value);
+ }
+ break;
+ }
+
+ case short_type: {
+ jarray = (jobjectArray)env->NewShortArray(length);
+ for(unsigned i = 0; i < length; i++) {
+ JSValue* item = jsArray->get(exec, i);
+ jshort value = (jshort)item->toNumber(exec);
+ env->SetShortArrayRegion((jshortArray)jarray, (jsize)i, (jsize)1, &value);
+ }
+ break;
+ }
+
+ case int_type: {
+ jarray = (jobjectArray)env->NewIntArray(length);
+ for(unsigned i = 0; i < length; i++) {
+ JSValue* item = jsArray->get(exec, i);
+ jint value = (jint)item->toNumber(exec);
+ env->SetIntArrayRegion((jintArray)jarray, (jsize)i, (jsize)1, &value);
+ }
+ break;
+ }
+
+ case long_type: {
+ jarray = (jobjectArray)env->NewLongArray(length);
+ for(unsigned i = 0; i < length; i++) {
+ JSValue* item = jsArray->get(exec, i);
+ jlong value = (jlong)item->toNumber(exec);
+ env->SetLongArrayRegion((jlongArray)jarray, (jsize)i, (jsize)1, &value);
+ }
+ break;
+ }
+
+ case float_type: {
+ jarray = (jobjectArray)env->NewFloatArray(length);
+ for(unsigned i = 0; i < length; i++) {
+ JSValue* item = jsArray->get(exec, i);
+ jfloat value = (jfloat)item->toNumber(exec);
+ env->SetFloatArrayRegion((jfloatArray)jarray, (jsize)i, (jsize)1, &value);
+ }
+ break;
+ }
+
+ case double_type: {
+ jarray = (jobjectArray)env->NewDoubleArray(length);
+ for(unsigned i = 0; i < length; i++) {
+ JSValue* item = jsArray->get(exec, i);
+ jdouble value = (jdouble)item->toNumber(exec);
+ env->SetDoubleArrayRegion((jdoubleArray)jarray, (jsize)i, (jsize)1, &value);
+ }
+ break;
+ }
+
+ case array_type: // don't handle embedded arrays
+ case void_type: // Don't expect arrays of void objects
+ case invalid_type: // Array of unknown objects
+ break;
+ }
+
+ // if it was not one of the cases handled, then null is returned
+ return jarray;
+}
+
+
+jvalue convertValueToJValue(ExecState* exec, JSValue* value, JNIType _JNIType, const char* javaClassName)
+{
+ JSLock lock(false);
+
+ jvalue result;
+
+ switch (_JNIType){
+ case array_type:
+ case object_type: {
+ result.l = (jobject)0;
+
+ // First see if we have a Java instance.
+ if (value->isObject()){
+ JSObject* objectImp = asObject(value);
+ if (objectImp->classInfo() == &RuntimeObjectImp::s_info) {
+ RuntimeObjectImp* imp = static_cast<RuntimeObjectImp*>(objectImp);
+ JavaInstance *instance = static_cast<JavaInstance*>(imp->getInternalInstance());
+ if (instance)
+ result.l = instance->javaInstance();
+ }
+ else if (objectImp->classInfo() == &RuntimeArray::s_info) {
+ // Input is a JavaScript Array that was originally created from a Java Array
+ RuntimeArray* imp = static_cast<RuntimeArray*>(objectImp);
+ JavaArray *array = static_cast<JavaArray*>(imp->getConcreteArray());
+ result.l = array->javaArray();
+ }
+ else if (objectImp->classInfo() == &JSArray::info) {
+ // Input is a Javascript Array. We need to create it to a Java Array.
+ result.l = convertArrayInstanceToJavaArray(exec, asArray(value), javaClassName);
+ }
+ }
+
+ // Now convert value to a string if the target type is a java.lang.string, and we're not
+ // converting from a Null.
+ if (result.l == 0 && strcmp(javaClassName, "java.lang.String") == 0) {
+#ifdef CONVERT_NULL_TO_EMPTY_STRING
+ if (value->isNull()) {
+ JNIEnv *env = getJNIEnv();
+ jchar buf[2];
+ jobject javaString = env->functions->NewString (env, buf, 0);
+ result.l = javaString;
+ }
+ else
+#else
+ if (!value->isNull())
+#endif
+ {
+ UString stringValue = value->toString(exec);
+ JNIEnv *env = getJNIEnv();
+ jobject javaString = env->functions->NewString (env, (const jchar *)stringValue.data(), stringValue.size());
+ result.l = javaString;
+ }
+ } else if (result.l == 0)
+ bzero (&result, sizeof(jvalue)); // Handle it the same as a void case
+ }
+ break;
+
+ case boolean_type: {
+ result.z = (jboolean)value->toNumber(exec);
+ }
+ break;
+
+ case byte_type: {
+ result.b = (jbyte)value->toNumber(exec);
+ }
+ break;
+
+ case char_type: {
+ result.c = (jchar)value->toNumber(exec);
+ }
+ break;
+
+ case short_type: {
+ result.s = (jshort)value->toNumber(exec);
+ }
+ break;
+
+ case int_type: {
+ result.i = (jint)value->toNumber(exec);
+ }
+ break;
+
+ case long_type: {
+ result.j = (jlong)value->toNumber(exec);
+ }
+ break;
+
+ case float_type: {
+ result.f = (jfloat)value->toNumber(exec);
+ }
+ break;
+
+ case double_type: {
+ result.d = (jdouble)value->toNumber(exec);
+ }
+ break;
+
+ break;
+
+ case invalid_type:
+ default:
+ case void_type: {
+ bzero (&result, sizeof(jvalue));
+ }
+ break;
+ }
+ return result;
+}
+
+} // end of namespace Bindings
+
+} // end of namespace JSC
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
diff --git a/WebCore/bridge/jni/jni_utility.h b/WebCore/bridge/jni/jni_utility.h
new file mode 100644
index 0000000..b30c654
--- /dev/null
+++ b/WebCore/bridge/jni/jni_utility.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2003 Apple Computer, 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.
+ */
+
+#ifndef _JNI_UTILITY_H_
+#define _JNI_UTILITY_H_
+
+#if ENABLE(MAC_JAVA_BRIDGE)
+
+#include <runtime/JSValue.h>
+#include <JavaVM/jni.h>
+
+// The order of these items can not be modified as they are tightly
+// bound with the JVM on Mac OSX. If new types need to be added, they
+// should be added to the end. It is used in jni_obc.mm when calling
+// through to the JVM. Newly added items need to be made compatible
+// in that file.
+typedef enum {
+ invalid_type = 0,
+ void_type,
+ object_type,
+ boolean_type,
+ byte_type,
+ char_type,
+ short_type,
+ int_type,
+ long_type,
+ float_type,
+ double_type,
+ array_type
+} JNIType;
+
+namespace JSC {
+
+class ExecState;
+class JSObject;
+
+namespace Bindings {
+
+class JavaParameter;
+
+const char *getCharactersFromJString(jstring aJString);
+void releaseCharactersForJString(jstring aJString, const char *s);
+
+const char *getCharactersFromJStringInEnv(JNIEnv *env, jstring aJString);
+void releaseCharactersForJStringInEnv(JNIEnv *env, jstring aJString, const char *s);
+const jchar *getUCharactersFromJStringInEnv(JNIEnv *env, jstring aJString);
+void releaseUCharactersForJStringInEnv(JNIEnv *env, jstring aJString, const jchar *s);
+
+JNIType JNITypeFromClassName(const char *name);
+JNIType JNITypeFromPrimitiveType(char type);
+const char *signatureFromPrimitiveType(JNIType type);
+
+jvalue convertValueToJValue(ExecState*, JSValue*, JNIType, const char* javaClassName);
+
+jvalue getJNIField(jobject obj, JNIType type, const char *name, const char *signature);
+
+jmethodID getMethodID(jobject obj, const char *name, const char *sig);
+JNIEnv* getJNIEnv();
+JavaVM* getJavaVM();
+void setJavaVM(JavaVM*);
+
+
+template <typename T> struct JNICaller;
+
+template<> struct JNICaller<void> {
+ static void callA(jobject obj, jmethodID mid, jvalue* args)
+ {
+ return getJNIEnv()->CallVoidMethodA(obj, mid, args);
+ }
+ static void callV(jobject obj, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallVoidMethodV(obj, mid, args);
+ }
+};
+
+template<> struct JNICaller<jobject> {
+ static jobject callA(jobject obj, jmethodID mid, jvalue* args)
+ {
+ return getJNIEnv()->CallObjectMethodA(obj, mid, args);
+ }
+ static jobject callV(jobject obj, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallObjectMethodV(obj, mid, args);
+ }
+};
+
+template<> struct JNICaller<jboolean> {
+ static jboolean callA(jobject obj, jmethodID mid, jvalue* args)
+ {
+ return getJNIEnv()->CallBooleanMethodA(obj, mid, args);
+ }
+ static jboolean callV(jobject obj, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallBooleanMethodV(obj, mid, args);
+ }
+ static jboolean callStaticV(jclass cls, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallStaticBooleanMethod(cls, mid, args);
+ }
+
+};
+
+template<> struct JNICaller<jbyte> {
+ static jbyte callA(jobject obj, jmethodID mid, jvalue* args)
+ {
+ return getJNIEnv()->CallByteMethodA(obj, mid, args);
+ }
+ static jbyte callV(jobject obj, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallByteMethodV(obj, mid, args);
+ }
+};
+
+template<> struct JNICaller<jchar> {
+ static jchar callA(jobject obj, jmethodID mid, jvalue* args)
+ {
+ return getJNIEnv()->CallCharMethodA(obj, mid, args);
+ }
+ static jchar callV(jobject obj, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallCharMethodV(obj, mid, args);
+ }
+};
+
+template<> struct JNICaller<jshort> {
+ static jshort callA(jobject obj, jmethodID mid, jvalue* args)
+ {
+ return getJNIEnv()->CallShortMethodA(obj, mid, args);
+ }
+ static jshort callV(jobject obj, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallShortMethodV(obj, mid, args);
+ }
+};
+
+template<> struct JNICaller<jint> {
+ static jint callA(jobject obj, jmethodID mid, jvalue* args)
+ {
+ return getJNIEnv()->CallIntMethodA(obj, mid, args);
+ }
+ static jint callV(jobject obj, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallIntMethodV(obj, mid, args);
+ }
+};
+
+template<> struct JNICaller<jlong> {
+ static jlong callA(jobject obj, jmethodID mid, jvalue* args)
+ {
+ return getJNIEnv()->CallLongMethodA(obj, mid, args);
+ }
+ static jlong callV(jobject obj, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallLongMethodV(obj, mid, args);
+ }
+};
+
+template<> struct JNICaller<jfloat> {
+ static jfloat callA(jobject obj, jmethodID mid, jvalue* args)
+ {
+ return getJNIEnv()->CallFloatMethodA(obj, mid, args);
+ }
+ static jfloat callV(jobject obj, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallFloatMethodV(obj, mid, args);
+ }
+};
+
+template<> struct JNICaller<jdouble> {
+ static jdouble callA(jobject obj, jmethodID mid, jvalue* args)
+ {
+ return getJNIEnv()->CallDoubleMethodA(obj, mid, args);
+ }
+ static jdouble callV(jobject obj, jmethodID mid, va_list args)
+ {
+ return getJNIEnv()->CallDoubleMethodV(obj, mid, args);
+ }
+};
+
+template<typename T> T callJNIMethodIDA(jobject obj, jmethodID mid, jvalue *args)
+{
+ return JNICaller<T>::callA(obj, mid, args);
+}
+
+template<typename T>
+static T callJNIMethodV(jobject obj, const char *name, const char *sig, va_list args)
+{
+ JavaVM *jvm = getJavaVM();
+ JNIEnv *env = getJNIEnv();
+
+ if ( obj != NULL && jvm != NULL && env != NULL) {
+ jclass cls = env->GetObjectClass(obj);
+ if ( cls != NULL ) {
+ jmethodID mid = env->GetMethodID(cls, name, sig);
+ if ( mid != NULL )
+ {
+ return JNICaller<T>::callV(obj, mid, args);
+ }
+ else
+ {
+ fprintf(stderr, "%s: Could not find method: %s for %p\n", __PRETTY_FUNCTION__, name, obj);
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ fprintf (stderr, "\n");
+ }
+
+ env->DeleteLocalRef(cls);
+ }
+ else {
+ fprintf(stderr, "%s: Could not find class for %p\n", __PRETTY_FUNCTION__, obj);
+ }
+ }
+
+ return 0;
+}
+
+template<typename T>
+T callJNIMethod(jobject obj, const char* methodName, const char* methodSignature, ...)
+{
+ va_list args;
+ va_start(args, methodSignature);
+
+ T result= callJNIMethodV<T>(obj, methodName, methodSignature, args);
+
+ va_end(args);
+
+ return result;
+}
+
+template<typename T>
+T callJNIStaticMethod(jclass cls, const char* methodName, const char* methodSignature, ...)
+{
+ JavaVM *jvm = getJavaVM();
+ JNIEnv *env = getJNIEnv();
+ va_list args;
+
+ va_start(args, methodSignature);
+
+ T result = 0;
+
+ if (cls != NULL && jvm != NULL && env != NULL) {
+ jmethodID mid = env->GetStaticMethodID(cls, methodName, methodSignature);
+ if (mid != NULL)
+ result = JNICaller<T>::callStaticV(cls, mid, args);
+ else {
+ fprintf(stderr, "%s: Could not find method: %s for %p\n", __PRETTY_FUNCTION__, methodName, cls);
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ fprintf (stderr, "\n");
+ }
+ }
+
+ va_end(args);
+
+ return result;
+}
+
+bool dispatchJNICall(ExecState*, const void* targetAppletView, jobject obj, bool isStatic, JNIType returnType, jmethodID methodID, jvalue* args, jvalue& result, const char* callingURL, JSValue*& exceptionDescription);
+
+} // namespace Bindings
+
+} // namespace JSC
+
+#endif // ENABLE(MAC_JAVA_BRIDGE)
+
+#endif // _JNI_UTILITY_H_