Add back IE proxy handling for CheckForUpdates.
Also remove branch-info.txt inadvertently committed to trunk.
Patch by: scottb
Review by: jat
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6390 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/jni/build.xml b/jni/build.xml
new file mode 100755
index 0000000..fc25ce0
--- /dev/null
+++ b/jni/build.xml
@@ -0,0 +1,9 @@
+<project name="jni" default="build" basedir=".">
+ <property name="gwt.root" location=".." />
+ <property name="project.tail" value="jni" />
+ <import file="${gwt.root}/common.ant.xml" />
+
+ <target name="build" description="Build each platforms">
+ <gwt.ant dir="windows" target="build"/>
+ </target>
+</project>
diff --git a/jni/core/gwt-ll.cpp b/jni/core/gwt-ll.cpp
new file mode 100644
index 0000000..4076aea
--- /dev/null
+++ b/jni/core/gwt-ll.cpp
@@ -0,0 +1,66 @@
+// Copyright 2005-2006 Google Inc.
+// All Rights Reserved.
+
+// A slim and portable set of JNI methods for GWT hosted mode
+
+#include <jni.h>
+#include <stdlib.h>
+
+extern "C" {
+
+/*
+ * Class: com_google_gwt_dev_shell_LowLevel
+ * Method: newGlobalRefInt
+ * Signature: (Ljava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_LowLevel__1newGlobalRefInt(JNIEnv* env, jclass, jobject o) {
+ return reinterpret_cast<int>(env->NewGlobalRef(o));
+}
+/*
+ * Class: com_google_gwt_dev_shell_LowLevel
+ * Method: objFromGlobalRefInt
+ * Signature: (I)Ljava/lang/Object;
+ */
+JNIEXPORT jobject JNICALL Java_com_google_gwt_dev_shell_LowLevel__1objFromGlobalRefInt(JNIEnv* env, jclass, jint globalRef) {
+ return reinterpret_cast<jobject>(globalRef);
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_LowLevel
+ * Method: deleteGlobalRefInt
+ * Signature: (I)I
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_LowLevel__1deleteGlobalRefInt(JNIEnv* env, jclass, jint globalRef) {
+ env->DeleteGlobalRef(reinterpret_cast<jobject>(globalRef));
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_LowLevel
+ * Method: getEnv
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_LowLevel__1getEnv(JNIEnv* env, jclass, jstring key) {
+ if (!key) {
+ // null -> null
+ return 0;
+ }
+
+ const char* keyPtr = env->GetStringUTFChars(key, 0);
+ if (!keyPtr) {
+ // There will be a pending OutOfMemoryException on this thread, so leave immediately and let it be thrown.
+ return 0;
+ }
+
+ const char* valuePtr = getenv(keyPtr);
+ env->ReleaseStringUTFChars(key, keyPtr);
+
+ if (!valuePtr) {
+ // no match found
+ return 0;
+ }
+
+ // return the result
+ return env->NewStringUTF(valuePtr);
+}
+
+} // extern "C"
diff --git a/jni/linux/ExternalWrapper.cpp b/jni/linux/ExternalWrapper.cpp
new file mode 100644
index 0000000..3b2854e
--- /dev/null
+++ b/jni/linux/ExternalWrapper.cpp
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/*
+ * Defines the JavaScript class gwt_external_class, which interface via JNI
+ * to Java objects.
+ */
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "gwt-jni.h"
+#include "ExternalWrapper.h"
+#include "Tracer.h"
+#include "JsStringWrap.h"
+
+#ifdef ENABLE_TRACING
+extern void PrintJSValue(JSContext* cx, jsval val, char* prefix="");
+#else
+// Include a null version just to keep from cluttering up call sites.
+static inline void PrintJSValue(JSContext* cx, jsval val, char* prefix="") { }
+#endif
+
+// note that this does not use the NS_DEFINE_CID macro because it defines
+// the variable as const, which by default has internal linkage. I could
+// work around it by putting extern in front of the macro, but that seems
+// fragile if the macro changes.
+nsCID kGwtExternalCID = GWT_EXTERNAL_FACTORY_CID;
+
+/*
+ * definition of JavaScript gwtOnLoad method which maps to the Java
+ * gwtOnLoad method.
+ */
+static JSBool gwtOnLoad(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ Tracer tracer("gwtOnLoad");
+ tracer.log("context=%08x", unsigned(cx));
+ JsRootedValue::ContextManager context(cx);
+ JsRootedValue::ensureRuntime(cx);
+ if (argc < 3) {
+ tracer.setFail("less than 3 args");
+ return JS_FALSE;
+ }
+
+ JSObject* scriptWindow = 0;
+ if (argv[0] != JSVAL_NULL && argv[0] != JSVAL_VOID) {
+ if (!JS_ValueToObject(cx, argv[0], &scriptWindow)) {
+ tracer.setFail("can't get script window object");
+ return JS_FALSE;
+ }
+ }
+
+ JSString* moduleName = 0;
+ if (argv[1] != JSVAL_NULL && argv[1] != JSVAL_VOID) {
+ moduleName = JS_ValueToString(cx, argv[1]);
+ }
+
+ JSString* version = 0;
+ if (argv[2] != JSVAL_NULL && argv[2] != JSVAL_VOID) {
+ version = JS_ValueToString(cx, argv[2]);
+ }
+
+ nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(0);
+ if (scriptWindow) {
+ nsCOMPtr<nsIXPConnect> xpConnect = do_GetService(nsIXPConnect::GetCID());
+ nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
+ xpConnect->GetWrappedNativeOfJSObject(cx, scriptWindow,
+ getter_AddRefs(wrappedNative));
+ if (wrappedNative) {
+ nsCOMPtr<nsISupports> native;
+ wrappedNative->GetNative(getter_AddRefs(native));
+ scriptGlobal = do_QueryInterface(native);
+ }
+ }
+ jstring jModuleName(0);
+ if (moduleName) {
+ jModuleName = savedJNIEnv->NewString(JS_GetStringChars(moduleName),
+ JS_GetStringLength(moduleName));
+ if (!jModuleName || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get module name in Java string");
+ return JS_FALSE;
+ }
+ tracer.log("module name=%s", JS_GetStringBytes(moduleName));
+ } else {
+ tracer.log("null module name");
+ }
+
+ jstring jVersion(0);
+ if (version) {
+ jVersion = savedJNIEnv->NewString(JS_GetStringChars(version),
+ JS_GetStringLength(version));
+ if (!jVersion || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get module name in Java string");
+ return JS_FALSE;
+ }
+ tracer.log("version=%s", JS_GetStringBytes(version));
+ } else {
+ tracer.log("null version");
+ }
+
+ jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ jclass objClass = savedJNIEnv->GetObjectClass(externalObject);
+ if (!objClass || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get LowLevelMoz.ExternalObject class");
+ return JS_FALSE;
+ }
+
+ jmethodID methodID = savedJNIEnv->GetMethodID(objClass, "gwtOnLoad",
+ "(ILjava/lang/String;Ljava/lang/String;)Z");
+ if (!methodID || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get gwtOnLoad method");
+ return JS_FALSE;
+ }
+
+ tracer.log("scriptGlobal=%08x", unsigned(scriptGlobal.get()));
+
+ jboolean result = savedJNIEnv->CallBooleanMethod(externalObject, methodID,
+ NS_REINTERPRET_CAST(jint, scriptGlobal.get()), jModuleName, jVersion);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("LowLevelMoz.ExternalObject.gwtOnLoad() threw an exception");
+ return JS_FALSE;
+ }
+ *rval = BOOLEAN_TO_JSVAL((result == JNI_FALSE) ? JS_FALSE : JS_TRUE);
+ return JS_TRUE;
+}
+
+/*
+ * definition of JavaScript initModule method which maps to the Java
+ * initModule method.
+ */
+static JSBool initModule(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ Tracer tracer("initModule");
+ tracer.log("context=%08x", unsigned(cx));
+ JsRootedValue::ContextManager context(cx);
+ JsRootedValue::ensureRuntime(cx);
+ if (argc < 1) {
+ tracer.setFail("less than 1 args");
+ return JS_FALSE;
+ }
+
+ JSString* moduleName = 0;
+ if (argv[0] != JSVAL_NULL && argv[0] != JSVAL_VOID) {
+ moduleName = JS_ValueToString(cx, argv[0]);
+ }
+
+ jstring jModuleName(0);
+ if (moduleName) {
+ jModuleName = savedJNIEnv->NewString(JS_GetStringChars(moduleName),
+ JS_GetStringLength(moduleName));
+ if (!jModuleName || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get module name in Java string");
+ return JS_FALSE;
+ }
+ tracer.log("module name=%s", JS_GetStringBytes(moduleName));
+ } else {
+ tracer.log("null module name");
+ }
+
+ jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ jclass objClass = savedJNIEnv->GetObjectClass(externalObject);
+ if (!objClass || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get LowLevelMoz.ExternalObject class");
+ return JS_FALSE;
+ }
+
+ jmethodID methodID = savedJNIEnv->GetMethodID(objClass, "initModule",
+ "(Ljava/lang/String;)Z");
+ if (!methodID || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get initModule method");
+ return JS_FALSE;
+ }
+
+ jboolean result = savedJNIEnv->CallBooleanMethod(externalObject, methodID,
+ jModuleName);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("LowLevelMoz.ExternalObject.initModule() threw an exception");
+ return JS_FALSE;
+ }
+ *rval = BOOLEAN_TO_JSVAL((result == JNI_FALSE) ? JS_FALSE : JS_TRUE);
+ return JS_TRUE;
+}
+
+/*=======================================================================*/
+/* Implementation of the getProperty, setProperty, and finalize methods */
+/* for the JavaScript class gwt_external_class. */
+/*=======================================================================*/
+
+static JSBool JS_DLL_CALLBACK gwt_external_getProperty(JSContext *cx,
+ JSObject *obj, jsval id, jsval *vp)
+{
+ Tracer tracer("gwt_external_getProperty");
+ JsRootedValue::ContextManager context(cx);
+ if (*vp != JSVAL_VOID) {
+ // we setup the gwtOnLoad function as a property in GetScriptObject and
+ // do not maintain a copy of it anywhere. So, if there is a cached
+ // value for a property we must return it. As we never redefine any
+ // property values, this is safe. If we were going to keep this code
+ // around and add Toby's profiling code we would need to revisit this.
+ return JS_TRUE;
+ }
+
+ if (!JSVAL_IS_STRING(id)) {
+ tracer.setFail("not a string");
+ return JS_FALSE;
+ }
+ JsStringWrap jsStr(cx, id);
+ tracer.log("obj=%08x, property=%.*s", obj, jsStr.length(), jsStr.bytes());
+
+// All this is for calling resolveReference which only returns void. So,
+// just replace this code to return void for now. TODO(jat): revisit when
+// merging in Toby's code.
+#if 0
+ jstring jident = savedJNIEnv->NewString(jsStr.chars(), jsStr.length());
+ if (!jident || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't create Java string ");
+ return JS_FALSE;
+ }
+ jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ jclass objClass = savedJNIEnv->GetObjectClass(externalObject);
+ if (!objClass || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't find Java class for JS object");
+ return JS_FALSE;
+ }
+
+ jmethodID methodID = savedJNIEnv->GetMethodID(objClass, "resolveReference",
+ "(Ljava/lang/String;)I");
+ if (!methodID || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("exception getting method for int resolveReference(String)");
+ return JS_FALSE;
+ }
+ int retval = savedJNIEnv->CallIntMethod(externalObject, methodID, jident);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("exception calling int resolveReference(String)");
+ return JS_FALSE;
+ }
+ *vp = retval;
+#else
+ *vp = JSVAL_VOID;
+#endif
+ return JS_TRUE;
+}
+
+static void JS_DLL_CALLBACK gwt_external_finalize(JSContext *cx, JSObject *obj)
+{
+ // We don't need to push a context if all we do is DeleteGlobalRef
+ Tracer tracer("gwt_external_finalize", obj);
+ jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ if (externalObject) {
+ savedJNIEnv->DeleteGlobalRef(externalObject);
+ }
+ JS_FinalizeStub(cx, obj);
+}
+
+static JSBool JS_DLL_CALLBACK gwt_external_setProperty(JSContext *cx,
+ JSObject *obj, jsval id, jsval *vp)
+{
+ return JS_FALSE;
+}
+
+static JSClass gwt_external_class = {
+ "gwt_external_class", JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, gwt_external_getProperty,
+ gwt_external_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
+ gwt_external_finalize,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+NS_IMPL_ISUPPORTS1(ExternalWrapper, nsIScriptObjectOwner)
+
+/*
+ * Create a new LowLevelMoz.ExternalObject instance and a JavaScript object
+ * that refers to it, mapping the gwtOnLoad member function mapping to
+ * a Javascript method.
+ */
+NS_IMETHODIMP ExternalWrapper::GetScriptObject(nsIScriptContext *aContext,
+ void** aScriptObject)
+{
+ Tracer tracer("ExternalWrapper::GetScriptObject");
+ if (!aScriptObject) {
+ tracer.setFail("null script object pointer");
+ return NS_ERROR_INVALID_POINTER;
+ }
+ if (!jsWindowExternalObject) {
+ JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
+ aContext->GetNativeContext());
+ if (!cx) {
+ tracer.setFail("can't get JSContext");
+ return NS_ERROR_UNEXPECTED;
+ }
+ JsRootedValue::ContextManager context(cx);
+ *aScriptObject = 0;
+
+ nsIScriptGlobalObject* globalObject = aContext->GetGlobalObject();
+ nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(globalObject));
+ if (!domWindow) {
+ tracer.setFail("can't get DOM window");
+ return NS_ERROR_UNEXPECTED;
+ }
+ nsCOMPtr<nsIDOMWindow> topWindow;
+ domWindow->GetTop(getter_AddRefs(topWindow));
+ if (!topWindow) {
+ tracer.setFail("Can't get top window");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ tracer.log("savedJNIEnv=%08x, llClass=%08x", unsigned(savedJNIEnv),
+ lowLevelMozClass);
+
+ jmethodID methodID = savedJNIEnv->GetStaticMethodID(lowLevelMozClass,
+ "createExternalObjectForDOMWindow",
+ "(I)Lcom/google/gwt/dev/shell/moz/LowLevelMoz$ExternalObject;");
+ if (!methodID || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("Can't get createExternalObjectForDOMWindow method");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ jobject externalObject = savedJNIEnv->CallStaticObjectMethod(
+ lowLevelMozClass, methodID, NS_REINTERPRET_CAST(jint, topWindow.get()));
+ if (!externalObject || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("createExternalObjectForDOMWindow failed");
+ return NS_ERROR_UNEXPECTED;
+ }
+ externalObject = savedJNIEnv->NewGlobalRef(externalObject);
+ if (!externalObject || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get GlobalRef for external object");
+ return NS_ERROR_UNEXPECTED;
+ }
+ JSObject* newObj = JS_NewObject(cx, &gwt_external_class, 0,
+ globalObject->GetGlobalJSObject());
+ if (!newObj) {
+ tracer.setFail("can't create new gwt_external_class object");
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ if (!JS_SetPrivate(cx, newObj, externalObject)) {
+ savedJNIEnv->DeleteGlobalRef(externalObject);
+ tracer.setFail("can't store external object private reference");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ if (!JS_DefineFunction(cx, newObj, "gwtOnLoad", gwtOnLoad, 3,
+ JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+ tracer.setFail("can't define gwtOnLoad function on JavaScript object");
+ return NS_ERROR_UNEXPECTED;
+ }
+ if (!JS_DefineFunction(cx, newObj, "initModule", initModule, 1,
+ JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+ tracer.setFail("can't define initModule function on JavaScript object");
+ return NS_ERROR_UNEXPECTED;
+ }
+ jsWindowExternalObject = newObj;
+ }
+
+ *aScriptObject = jsWindowExternalObject;
+ return NS_OK;
+}
+
+NS_IMETHODIMP ExternalWrapper::SetScriptObject(void* aScriptObject)
+{
+ jsWindowExternalObject = aScriptObject;
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS1(nsRpExternalFactory, nsIFactory)
+
+NS_IMETHODIMP nsRpExternalFactory::CreateInstance(nsISupports *aOuter,
+ const nsIID& aIID, void** aResult)
+{
+ Tracer tracer("nsRpExternalFactory::CreateInstance");
+ if (!aResult) {
+ tracer.setFail("null pointer for return value");
+ return NS_ERROR_INVALID_POINTER;
+ }
+ *aResult = NULL;
+
+ if (aOuter) {
+ tracer.setFail("aOuter is not null");
+ return NS_ERROR_NO_AGGREGATION;
+ }
+
+ nsISupports* object = new ExternalWrapper();
+ if (!object) {
+ tracer.setFail("can't create a new ExternalWrapper");
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ nsresult result = object->QueryInterface(aIID, aResult);
+ if (!*aResult || NS_FAILED(result)) {
+ tracer.setFail("ExternalWrapper::QueryInterface failed");
+ delete object;
+ }
+ return result;
+}
+
+NS_IMETHODIMP nsRpExternalFactory::LockFactory(PRBool lock)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
diff --git a/jni/linux/ExternalWrapper.h b/jni/linux/ExternalWrapper.h
new file mode 100644
index 0000000..0168083
--- /dev/null
+++ b/jni/linux/ExternalWrapper.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2006 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef EXTERNALWRAPPER_H_
+#define EXTERNALWRAPPER_H_
+
+class ExternalWrapper : public nsIScriptObjectOwner {
+public:
+ NS_DECL_ISUPPORTS
+ NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void** aScriptObject);
+ NS_IMETHOD SetScriptObject(void* aScriptObject);
+ ExternalWrapper(): jsWindowExternalObject(0) { }
+private:
+ ~ExternalWrapper() { }
+ void *jsWindowExternalObject;
+};
+
+class nsRpExternalFactory : public nsIFactory {
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIFACTORY
+ nsRpExternalFactory() { }
+private:
+ ~nsRpExternalFactory() { }
+};
+
+#define GWT_EXTERNAL_FACTORY_CID \
+{ 0xF56E23F8, 0x5D06, 0x47F9, \
+{ 0x88, 0x5A, 0xD9, 0xCA, 0xC3, 0x38, 0x41, 0x7F } }
+#define GWT_EXTERNAL_CONTRACTID "@com.google/GWT/external;1"
+
+#endif /*EXTERNALWRAPPER_H_*/
diff --git a/jni/linux/JStringWrap.h b/jni/linux/JStringWrap.h
new file mode 100644
index 0000000..9d2ebcc
--- /dev/null
+++ b/jni/linux/JStringWrap.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef JNI_LINUX_JSTRINGWRAP_H_
+#define JNI_LINUX_JSTRINGWRAP_H_
+
+/*
+ * Wrapper arouond Java Strings, keeps pointers to unpacked strings
+ * and makes sure they are cleaned up.
+ */
+class JStringWrap {
+ public:
+ JStringWrap(JNIEnv* env, jstring str): env(env), s(str), p(0), jp(0) { }
+ ~JStringWrap() {
+ if (p) env->ReleaseStringUTFChars(s, p);
+ if (jp) env->ReleaseStringChars(s, jp);
+ }
+ const char* str() {
+ if (!p) p = env->GetStringUTFChars(s, 0);
+ return p;
+ }
+ const jchar* jstr() {
+ if (!jp) jp = env->GetStringChars(s, 0);
+ return jp;
+ }
+ int length() {
+ return env->GetStringLength(s);
+ }
+ private:
+ JNIEnv* env;
+ jstring s;
+ const char* p;
+ const jchar* jp;
+};
+
+
+#endif // JNI_LINUX_JSTRINGWRAP_H_
diff --git a/jni/linux/JsRootedValue.cpp b/jni/linux/JsRootedValue.cpp
new file mode 100644
index 0000000..29b95ca
--- /dev/null
+++ b/jni/linux/JsRootedValue.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "JsRootedValue.h"
+
+// Initialize static value used to hold the JavaScript String class.
+JSClass* JsRootedValue::stringClass = 0;
+
+// Initialize static reference to the sole JSRuntime value in Gecko.
+JSRuntime* JsRootedValue::runtime = 0;
+
+// Static stack of JavaScript execution contexts.
+std::stack<JSContext*> JsRootedValue::contextStack;
+
+/*
+ * Actually get the stringClass pointer from JavaScript.
+ */
+void JsRootedValue::fetchStringClass() const {
+ Tracer tracer("JsRootedValue::fetchStringClass");
+ JSContext* cx = currentContext();
+ jsval val = JS_GetEmptyStringValue(cx);
+ JSObject* obj;
+ // on error, leave stringClass null
+ if (!JS_ValueToObject(cx, val, &obj)) return;
+ if (!obj) {
+ tracer.log("ensureStringClass: null object");
+ return;
+ }
+ stringClass = JS_GET_CLASS(cx, obj);
+ tracer.log("stringClass=%08x", unsigned(stringClass));
+}
diff --git a/jni/linux/JsRootedValue.h b/jni/linux/JsRootedValue.h
new file mode 100644
index 0000000..65c25af
--- /dev/null
+++ b/jni/linux/JsRootedValue.h
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+#ifndef JNI_LINUX_JSROOTEDVALUE_H_
+#define JNI_LINUX_JSROOTEDVALUE_H_
+
+// Mozilla header files
+#include "mozilla-headers.h"
+
+#include "Tracer.h"
+#include <stack>
+
+extern "C" JSClass gwt_nativewrapper_class;
+
+/*
+ * Holds a root for Javascript objects, so the JS interpreter knows not to
+ * garbage-collect the underlying object as long as this object exists.
+ * Java code will pass a pointer to this object around (as an int/long) for
+ * referring to the underlying Javascript object.
+ *
+ * There are also convenience routines for manipulating the underlying value.
+ * Note that all get* methods assume the type is correct, so the corresponding
+ * is* method should be called first if you aren't sure of the type.
+ *
+ * See http://developer.mozilla.org/en/docs/JS_AddRoot for details.
+ *
+ * TODO(jat): rewrite this to minimize the number of roots held and to
+ * improve 64-bit compatibility.
+ */
+class JsRootedValue
+{
+private:
+ // the JavaScript String class
+ static JSClass* stringClass;
+
+ // Javascript runtime
+ static JSRuntime* runtime;
+
+ // stack of Javascript contexts
+ static std::stack<JSContext*> contextStack;
+
+ // underlying Javascript value
+ jsval value_;
+
+protected:
+ /*
+ * Fetch the JavaScript String class.
+ * Not inlined to minimize code bloat since it should only be called once.
+ */
+ void fetchStringClass() const;
+
+ /*
+ * Make sure we have the JS code to identify String objects installed.
+ */
+ void ensureStringClass() const {
+ if(stringClass) return;
+ fetchStringClass();
+ }
+
+ /*
+ * Helper for the various constructors
+ */
+ void constructorHelper(const char* ctorDesc) {
+ Tracer tracer(ctorDesc, this);
+ if (!JS_AddNamedRootRT(runtime, &value_, ctorDesc)) {
+ tracer.log("JS_AddNamedRootRT failed");
+ // TODO(jat): handle errors
+ }
+ }
+
+ /*
+ * Push a new JavaScript execution context.
+ */
+ static void pushContext(JSContext* context) {
+ Tracer tracer("JsRootedValue::pushContext");
+ tracer.log("pushed context=%08x", unsigned(context));
+ contextStack.push(context);
+ }
+
+ /*
+ * Pop a JavaScript execution context from the context stack.
+ */
+ static void popContext() {
+ Tracer tracer("JsRootedValue::popContext");
+ JSContext* context = currentContext();
+ contextStack.pop();
+ tracer.log("popped context=%08x", unsigned(context));
+ }
+
+public:
+ /*
+ * This is a helper class used to push/pop JSContext values automatically,
+ * using RAII. Simply create a ContextManager object on the stack and it
+ * will push the context at creation time and pop it at destruction time,
+ * so you don't have to worry about covering all the exit paths from a
+ * function.
+ */
+ class ContextManager {
+ public:
+ explicit ContextManager(JSContext* context) {
+ JsRootedValue::pushContext(context);
+ }
+ ~ContextManager() {
+ JsRootedValue::popContext();
+ }
+ };
+
+ /*
+ * This is a helper class to manage short-lived roots on the stack, using
+ * RAII to free the roots when no longer needed.
+ */
+ class Temp {
+ private:
+ void* ptr_;
+ public:
+ explicit Temp(void* ptr) : ptr_(ptr) {
+ JS_AddNamedRootRT(runtime, ptr_, "temporary root");
+ }
+ ~Temp() {
+ JS_RemoveRootRT(runtime, ptr_);
+ }
+ };
+
+ /*
+ * Copy constructor - make another rooted value that refers to the same
+ * JavaScript object (or has the same value if a primitive)
+ */
+ JsRootedValue(const JsRootedValue& rooted_value) : value_(rooted_value.value_)
+ {
+ constructorHelper("JsRootedValue copy ctor");
+ }
+
+ /*
+ * Create a value with a given jsval value
+ */
+ JsRootedValue(jsval value) : value_(value)
+ {
+ constructorHelper("JsRootedValue jsval ctor");
+ }
+
+ /*
+ * Create a void value
+ */
+ JsRootedValue() : value_(JSVAL_VOID) {
+ constructorHelper("JsRootedValue void ctor");
+ }
+
+ /*
+ * Destroy this object.
+ */
+ ~JsRootedValue() {
+ Tracer tracer("~JsRootedValue", this);
+ // ignore error since currently it is not possible to fail
+ JS_RemoveRootRT(runtime, &value_);
+ }
+
+ /*
+ * Save a pointer to the JSRuntime if we don't have it yet
+ */
+ static void ensureRuntime(JSContext* context) {
+ if(!runtime) runtime = JS_GetRuntime(context);
+ }
+
+ /*
+ * Return the current JavaScript execution context.
+ */
+ static JSContext* currentContext() {
+ Tracer tracer("JsRootedValue::currentContext");
+ if (contextStack.empty()) {
+ // TODO(jat): better error handling?
+ fprintf(stderr, "JsRootedValue::currentContext - context stack empty\n");
+ ::abort();
+ }
+ JSContext* context = contextStack.top();
+ tracer.log("context=%08x", unsigned(context));
+ return context;
+ }
+
+ /*
+ * Return the underlying JS object
+ */
+ jsval getValue() const { return value_; }
+
+ /*
+ * Sets the value of the underlying JS object.
+ *
+ * Returns false if an error occurred.
+ */
+ bool setValue(jsval new_value) {
+ value_ = new_value;
+ return true;
+ }
+
+ /*
+ * Returns true if the underlying value is of some number type.
+ */
+ bool isNumber() const {
+ return JSVAL_IS_NUMBER(value_);
+ }
+ /*
+ * Returns the underlying value as a double.
+ * Result is 0.0 if the underlying value is not a number
+ * type.
+ */
+ double getDouble() const {
+ jsdouble return_value=0.0;
+ // ignore return value -- if it fails, value will remain 0.0
+ JS_ValueToNumber(currentContext(), value_, &return_value);
+ return double(return_value);
+ }
+ /*
+ * Set the underlying value to a double value.
+ *
+ * Returns false on failure.
+ */
+ bool setDouble(double val) {
+ jsval js_double;
+ if(!JS_NewDoubleValue(currentContext(), jsdouble(val), &js_double)) {
+ return false;
+ }
+ return setValue(js_double);
+ }
+
+ /*
+ * Returns the underlying value as an integer value. Note that the result
+ * is undefined if isInt() does not return true.
+ */
+ int getInt() {
+ return JSVAL_TO_INT(value_);
+ }
+
+ /*
+ * Set the underlying value to an integer value.
+ *
+ * Returns false on failure.
+ */
+ bool setInt(int val) {
+ // check if it fits in 31 bits (ie, top two bits are equal).
+ // if not, store it as a double
+ if ((val & 0x80000000) != ((val << 1) & 0x80000000)) {
+ return setDouble(val);
+ } else {
+ return setValue(INT_TO_JSVAL(val));
+ }
+ }
+
+ /*
+ * Returns true if the underlying value is a boolean.
+ */
+ bool isBoolean() const {
+ return JSVAL_IS_BOOLEAN(value_);
+ }
+ /*
+ * Returns the underlying value as a boolean.
+ * Result is undefined if the value is not actually
+ * a boolean.
+ */
+ bool getBoolean() const {
+ return value_ != JSVAL_FALSE;
+ }
+ /*
+ * Set the underlying value to a boolean value.
+ *
+ * Returns false on failure (impossible?).
+ */
+ bool setBoolean(bool val) {
+ return setValue(val ? JSVAL_TRUE : JSVAL_FALSE);
+ }
+
+ /*
+ * Returns true if the underlying value is a string.
+ */
+ bool isInt() const {
+ return JSVAL_IS_INT(value_);
+ }
+
+ /*
+ * Returns true if the underlying value is a string.
+ */
+ bool isString() const {
+ return JSVAL_IS_STRING(value_);
+ }
+
+ /*
+ * Check if the value is a JavaScript String object.
+ */
+ bool isJavaScriptStringObject() const {
+ if (!isObject()) return false;
+ ensureStringClass();
+ return getObjectClass() == stringClass;
+ }
+
+ /*
+ * Return this value as a string, converting as necessary.
+ */
+ JSString* asString() const {
+ return JS_ValueToString(currentContext(), value_);
+ }
+
+ /* Returns the string as a JSString pointer.
+ * Result is undefined if the value is not actually a string or String object.
+ */
+ const JSString* getString() const {
+ if (JSVAL_IS_STRING(value_)) {
+ return JSVAL_TO_STRING(value_);
+ }
+ return asString();
+ }
+ /*
+ * Returns the string as a zero-terminated array of UTF16 characters.
+ * Note that this pointer may become invalid when JS performs GC, so it
+ * may only be used without calling other JS functions. Result is
+ * undefined if the value is not actually a string.
+ */
+ const wchar_t* getStringChars() const {
+ return reinterpret_cast<const wchar_t*>(JS_GetStringChars(
+ const_cast<JSString*>(getString())));
+ }
+
+ /*
+ * Returns the length of the underlying string. Result is undefined
+ * if the value is not actually a string.
+ */
+ int getStringLength() const {
+ return JS_GetStringLength(const_cast<JSString*>(getString()));
+ }
+
+ /*
+ * Sets the underlying value, defined by a null-terminated array of UTF16
+ * chars.
+ *
+ * Returns false on failure.
+ */
+ bool setString(const wchar_t* utf16) {
+ JSString* str = JS_NewUCStringCopyZ(currentContext(),
+ reinterpret_cast<const jschar*>(utf16));
+ return setValue(STRING_TO_JSVAL(str));
+ }
+
+ /*
+ * Sets the underlying value, defined by a counted array of UTF16 chars.
+ *
+ * Returns false on failure.
+ */
+ bool setString(const wchar_t* utf16, size_t len) {
+ JSString* str = JS_NewUCStringCopyN(currentContext(),
+ reinterpret_cast<const jschar*>(utf16), len);
+ return setValue(STRING_TO_JSVAL(str));
+ }
+
+ /*
+ * Returns true if the underlying value is an object.
+ */
+ bool isObject() const {
+ return JSVAL_IS_OBJECT(value_);
+ }
+
+ /*
+ * Returns the underlying value as an object.
+ * Result is undefined if it is not actually an object.
+ */
+ JSObject* getObject() const {
+ return isObject() ? JSVAL_TO_OBJECT(value_) : 0;
+ }
+
+ /*
+ * Returns the class name of the underlying value.
+ *
+ * Result is undefined if it is not actually an object.
+ */
+ const JSClass* getObjectClass() const {
+ return isObject() ? JS_GET_CLASS(currentContext(), getObject()) : 0;
+ }
+
+ /*
+ * Sets the underlying value to be an object.
+ *
+ * Returns false on failure.
+ */
+ bool setObject(JSObject* obj) {
+ return setValue(OBJECT_TO_JSVAL(obj));
+ }
+
+ /*
+ * Returns true if the underlying value is undefined (void).
+ */
+ bool isUndefined() const {
+ return JSVAL_IS_VOID(value_);
+ }
+
+ /*
+ * Sets the underlying value to be undefined (void).
+ *
+ * Returns false on failure (impossible?)
+ */
+ bool setUndefined() {
+ return setValue(JSVAL_VOID);
+ }
+
+ /*
+ * Returns true if the underlying value is null.
+ */
+ bool isNull() const {
+ return JSVAL_IS_NULL(value_);
+ }
+ /*
+ * Sets the underlying value to be null.
+ *
+ * Returns false on failure (impossible?)
+ */
+ bool setNull() {
+ return setValue(JSVAL_NULL);
+ }
+};
+
+#endif /*JNI_LINUX_JSROOTEDVALUE_H_*/
diff --git a/jni/linux/JsStringWrap.h b/jni/linux/JsStringWrap.h
new file mode 100644
index 0000000..7ab0ce6
--- /dev/null
+++ b/jni/linux/JsStringWrap.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef JNI_LINUX_JSSTRINGWRAP_H_
+#define JNI_LINUX_JSSTRINGWRAP_H_
+
+/*
+ * Wrapper arouond JavaScript Strings, keeps pointers to unpacked strings
+ * and makes sure they are not cleaned up early.
+ */
+class JsStringWrap {
+ private:
+ JSContext* context_;
+ JSString* string_;
+ const char* bytes_;
+ const wchar_t* chars_;
+
+ public:
+ JsStringWrap(JSContext* context, JSString* str)
+ : context_(context), string_(str), bytes_(0), chars_(0) {
+ JS_AddRoot(context_, &string_);
+ JS_AddRoot(context_, &bytes_);
+ JS_AddRoot(context_, &chars_);
+ }
+ JsStringWrap(JSContext* context, jsval str)
+ : context_(context), string_(JSVAL_TO_STRING(str)), bytes_(0), chars_(0) {
+ JS_AddRoot(context_, &string_);
+ JS_AddRoot(context_, &bytes_);
+ JS_AddRoot(context_, &chars_);
+ }
+ ~JsStringWrap() {
+ JS_RemoveRoot(context_, &string_);
+ JS_RemoveRoot(context_, &bytes_);
+ JS_RemoveRoot(context_, &chars_);
+ }
+ const char* bytes() {
+ if (!bytes_) bytes_ = JS_GetStringBytes(string_);
+ return bytes_;
+ }
+ const wchar_t* chars() {
+ if (!chars_) {
+ chars_ = reinterpret_cast<wchar_t*>(JS_GetStringChars(string_));
+ }
+ return chars_;
+ }
+ int length() {
+ return JS_GetStringLength(string_);
+ }
+};
+
+#endif // JNI_LINUX_JSSTRINGWRAP_H_
diff --git a/jni/linux/JsValueMoz.cpp b/jni/linux/JsValueMoz.cpp
new file mode 100644
index 0000000..195306c
--- /dev/null
+++ b/jni/linux/JsValueMoz.cpp
@@ -0,0 +1,993 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "gwt-jni.h"
+#include "ExternalWrapper.h"
+#include "Tracer.h"
+
+// include javah-generated header to make sure things match
+#include "JsValueMoz.h"
+
+/*
+ * Returns the value of a field on a Java object.
+ *
+ * context - JavaScript context
+ * clazz - class of obj
+ * obj - Java object to retreive field from
+ * fieldName - name of field on Java object to retrieve
+ *
+ * Returns null on failure. Caller is responsible for deleting
+ * returned JsRootedValue when done with it.
+ */
+static JsRootedValue* GetFieldAsRootedValue(JSContext* cx, jclass clazz,
+ jobject obj, jstring fieldName)
+{
+ Tracer tracer("GetFieldAsRootedValue");
+ JsRootedValue::ContextManager context(cx);
+ jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "getField",
+ "(Ljava/lang/String;I)V");
+ if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
+ return 0;
+ }
+
+ JsRootedValue* jsRootedValue = new JsRootedValue();
+ savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
+ reinterpret_cast<jint>(jsRootedValue));
+ if (savedJNIEnv->ExceptionCheck()) {
+ delete jsRootedValue;
+ return 0;
+ }
+ return jsRootedValue;
+}
+
+/*
+ * Sets the value of a field on a Java object.
+ *
+ * context - JavaScript context
+ * clazz - class of obj
+ * obj - Java object to store into field
+ * fieldName - name of field on Java object to store into
+ * jsRootedValue - the value to store in the field
+ *
+ * returns true on success, false on failure
+ */
+static bool SetFieldFromRootedValue(JSContext* cx, jclass clazz,
+ jobject obj, jstring fieldName, JsRootedValue* jsRootedValue)
+{
+ Tracer tracer("SetFieldAsRootedValue");
+ JsRootedValue::ContextManager context(cx);
+ jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "setField",
+ "(Ljava/lang/String;I)V");
+ if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
+ return false;
+ }
+
+ savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
+ reinterpret_cast<jint>(jsRootedValue));
+ if (savedJNIEnv->ExceptionCheck()) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Throws a HostedModeException with the specified message.
+ */
+static void ThrowHostedModeException(JNIEnv* jniEnv, const char* msg) {
+ jclass exceptionClass
+ = jniEnv->FindClass("com/google/gwt/dev/shell/HostedModeException");
+ jniEnv->ThrowNew(exceptionClass, msg);
+}
+
+/*
+ * Types of jsvals.
+ */
+enum JsValueType {
+ JSVAL_TYPE_VOID=0,
+ JSVAL_TYPE_NULL,
+ JSVAL_TYPE_BOOLEAN,
+ JSVAL_TYPE_NUMBER,
+ JSVAL_TYPE_STRING,
+ JSVAL_TYPE_OBJECT,
+ JSVAL_TYPE_UNKNOWN,
+};
+
+/*
+ * Names of jsval types -- must match the order of the enum above.
+ */
+static const char* JsValueTypeStrings[]={
+ "undefined",
+ "null",
+ "boolean",
+ "number",
+ "string",
+ "object",
+ "unknown",
+};
+
+/*
+ * Return the type of a jsval.
+ */
+static JsValueType GetValueType(jsval val) {
+ if(JSVAL_IS_VOID(val)) {
+ return JSVAL_TYPE_VOID;
+ } else if(JSVAL_IS_NULL(val)) {
+ return JSVAL_TYPE_NULL;
+ } else if(JSVAL_IS_BOOLEAN(val)) {
+ return JSVAL_TYPE_BOOLEAN;
+ } else if(JSVAL_IS_NUMBER(val)) {
+ return JSVAL_TYPE_NUMBER;
+ } else if(JSVAL_IS_STRING(val)) {
+ return JSVAL_TYPE_STRING;
+ } else if(JSVAL_IS_OBJECT(val)) {
+ return JSVAL_TYPE_OBJECT;
+ } else {
+ return JSVAL_TYPE_UNKNOWN;
+ }
+}
+
+/*
+ * Called from JavaScript to call a Java method that has previously been
+ * wrapped. See _setWrappedFunction for use.
+ */
+static JSBool invokeJavaMethod(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ Tracer tracer("invokeJavaMethod");
+ JsRootedValue::ContextManager context(cx);
+
+ // I kid you not; this is how XPConnect gets their function object so they can
+ // multiplex dispatch the call from a common site. See XPCDispObject.cpp(466)
+ //
+ // I now have a secondary confirmation that this trick is legit.
+ // brandon@mozilla.org writes:
+ //
+ // argv[-2] is part of the JS API, unabstracted. Just as argv[0] is the
+ // first argument (if argc != 0), argv[-1] is the |this| parameter (equal
+ // to OBJECT_TO_JSVAL(obj) in a native method with the standard |obj|
+ // second formal parameter name), and argv[-2] is the callee object, tagged
+ // as a jsval.
+ if (JS_TypeOfValue(cx, argv[-2]) != JSTYPE_FUNCTION) {
+ tracer.setFail("not a function type");
+ return JS_FALSE;
+ }
+ JSObject* funObj = JSVAL_TO_OBJECT(argv[-2]);
+
+ // Pull the wrapper object out of the funObj's reserved slot
+ jsval jsCleanupObj;
+ if (!JS_GetReservedSlot(cx, funObj, 0, &jsCleanupObj)) {
+ tracer.setFail("JS_GetReservedSlot failed");
+ return JS_FALSE;
+ }
+ JSObject* cleanupObj = JSVAL_TO_OBJECT(jsCleanupObj);
+ if (!cleanupObj) {
+ tracer.setFail("cleanupObj is null");
+ return JS_FALSE;
+ }
+
+ // Get DispatchMethod instance out of the wrapper object
+ jobject dispMeth =
+ NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, cleanupObj));
+ if (!dispMeth) {
+ tracer.setFail("dispMeth is null");
+ return JS_FALSE;
+ }
+ jclass dispClass = savedJNIEnv->GetObjectClass(dispMeth);
+ if (!dispClass || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("GetObjectClass returns null");
+ return JS_FALSE;
+ }
+
+ // lookup the invoke method on the dispatch object
+ jmethodID invokeID =
+ savedJNIEnv->GetMethodID(dispClass, "invoke", "(I[II)V");
+ if (!invokeID || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("GetMethodID failed");
+ return JS_FALSE;
+ }
+
+ // create an array of integers to hold the JsRootedValue pointers passed
+ // to the invoke method
+ jintArray args = savedJNIEnv->NewIntArray(argc);
+ if (!args || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("NewIntArray failed");
+ return JS_FALSE;
+ }
+
+ // these arguments are already rooted by the JS interpreter, but we
+ // can't easily take advantage of that without complicating the JsRootedValue
+ // interface.
+
+ // argv[-1] is OBJECT_TO_JSVAL(this)
+ JsRootedValue* jsThis = new JsRootedValue(argv[-1]);
+ tracer.log("jsthis=%08x, RV=%08x", unsigned(argv[-1]), unsigned(jsThis));
+
+ // create JsRootedValues for arguments
+ JsRootedValue *jsArgs[argc];
+ for (uintN i = 0; i < argc; ++i) {
+ jsArgs[i] = new JsRootedValue(argv[i]);
+ }
+ savedJNIEnv->SetIntArrayRegion(args, 0, argc,
+ reinterpret_cast<jint*>(jsArgs));
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("SetIntArrayRegion failed");
+ return JS_FALSE;
+ }
+
+ // slot for return value
+ JsRootedValue* jsReturnVal = new JsRootedValue();
+
+ // TODO(jat): small window here where invocation may fail before Java
+ // takes ownership of the JsRootedValue objects. One solution would be
+ // to reference-count them between Java and C++ (so the reference count
+ // would always be 0, 1, or 2). Also setField has a similar problem.
+ // I plan to fix this when switching away from Java holding pointers to
+ // C++ objects as part of the fix for 64-bit support (which we could
+ // accomplish inefficiently by changing int to long everywhere, but there
+ // are other 64-bit issues to resolve and we need to reduce the number of
+ // roots the JS interpreter has to search.
+
+ // call Java method
+ savedJNIEnv->CallVoidMethod(dispMeth, invokeID, reinterpret_cast<int>(jsThis),
+ args, reinterpret_cast<int>(jsReturnVal));
+
+ JSBool returnValue = JS_TRUE;
+
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.log("dispMeth=%08x", unsigned(dispMeth));
+ tracer.setFail("java exception is active:");
+ jobject exception = savedJNIEnv->ExceptionOccurred();
+ if (exception) {
+ fprintf(stderr, "Exception occurred in MethodDispatch.invoke:\n");
+ savedJNIEnv->ExceptionDescribe();
+ savedJNIEnv->DeleteLocalRef(exception);
+ }
+ returnValue = JS_FALSE;
+ } else if (JS_IsExceptionPending(cx)) {
+ tracer.setFail("js exception is active");
+ returnValue = JS_FALSE;
+ }
+
+ // extract return value
+ *rval = jsReturnVal->getValue();
+
+#if 0
+ // NOTE: C++ objects are not cleaned up here because Java now owns them.
+ // TODO(jat): if reference-counted, they *do* need to be Released here.
+
+ // free JsRootedValues
+ for (uintN i = 0; i < argc; ++i) {
+ delete jsArgs[i];
+ }
+ delete jsThis;
+ delete jsReturnVal;
+#endif
+
+ return returnValue;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _createJsRootedValue()
+ * Signature: (I)I
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1createJsRootedValue
+ (JNIEnv* jniEnv, jclass, jint jsval)
+{
+ Tracer tracer("JsValueMoz._createJsRootedValue");
+ JsRootedValue* jsRootedValue = new JsRootedValue(jsval);
+ return NS_REINTERPRET_CAST(jint, jsRootedValue);
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _copyJsRootedValue()
+ * Signature: (I)I
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1copyJsRootedValue
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ const JsRootedValue* jsRootedValue = reinterpret_cast<const JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._copyJsRootedValue", jsRootedValue);
+ JsRootedValue* newRootedValue = new JsRootedValue(*jsRootedValue);
+ return NS_REINTERPRET_CAST(jint, newRootedValue);
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _destroyJsRootedValue()
+ * Signature: (I)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1destroyJsRootedValue
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._destroyJsRootedValue", jsRootedValue);
+ delete jsRootedValue;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getBoolean()
+ * Signature: (I)Z
+ *
+ * TODO(jat): unboxing Javascript Boolean type?
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getBoolean
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getBoolean", jsRootedValue);
+ return jsRootedValue->getBoolean();
+}
+
+/**
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getInt()
+ * Signature: (I)I
+ *
+ * @see com.google.gwt.dev.shell.moz.JsValueMoz#getInt()
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getInt
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getInt", jsRootedValue);
+ int val = jsRootedValue->getInt();
+ tracer.log("value=%d", val);
+ return val;
+}
+
+/**
+ * Return a Javascript number as a Java double.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getNumber()
+ * Signature: (I)D
+ */
+extern "C" JNIEXPORT jdouble JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getNumber
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getNumber", jsRootedValue);
+ return jsRootedValue->getDouble();
+}
+
+/**
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getJsval()
+ * Signature: (I)I
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getJsval
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getObjectPointer", jsRootedValue);
+ int val = jsRootedValue->getValue();
+ tracer.log("value=%d", val);
+ return val;
+}
+
+/**
+ * Return a Javascript string as a Java string.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getString()
+ * Signature: (I)Ljava/lang/String;
+ *
+ * Note that this relies on jschar being assignment compatible with jchar
+ */
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getString", jsRootedValue);
+ const JSString* str = jsRootedValue->getString();
+ int len = JS_GetStringLength(const_cast<JSString*>(str));
+ jstring javaStr =jniEnv->NewString(reinterpret_cast<const jchar*>(
+ JS_GetStringChars(const_cast<JSString*>(str))), len);
+ return javaStr;
+}
+
+/*
+ * Returns a human-readable Java string describing the type of a
+ * JavaScript object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getTypeString
+ * Signature: (I)Ljava/lang/String;
+ */
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getTypeString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getTypeString", jsRootedValue);
+ jsval val = jsRootedValue->getValue();
+ JSContext* cx = JsRootedValue::currentContext();
+ JsValueType valueType = GetValueType(val);
+ const char* typeString = 0;
+ char buf[256];
+ if(valueType == JSVAL_TYPE_OBJECT) {
+ JSObject* jsObject = JSVAL_TO_OBJECT(val);
+ JSClass* objClass = JS_GET_CLASS(cx, jsObject);
+ if (JS_InstanceOf(cx, jsObject,
+ &gwt_nativewrapper_class, 0)) {
+ typeString = "Java object";
+ } else {
+ snprintf(buf, sizeof(buf), "class %s", objClass->name);
+ typeString = buf;
+ }
+ } else {
+ typeString = JsValueTypeStrings[valueType];
+ }
+ jstring returnValue = jniEnv->NewStringUTF(typeString);
+ return returnValue;
+}
+
+/*
+ * Unwraps a wrapped Java object from a JS object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getWrappedJavaObject
+ * Signature: (I)Ljava/lang/Object;
+ */
+extern "C" JNIEXPORT jobject JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getWrappedJavaObject
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getWrappedJavaObject", jsRootedValue);
+ JSObject* jsObject = jsRootedValue->getObject();
+ if(!jsObject) {
+ tracer.throwHostedModeException(jniEnv, "Javascript value not an object");
+ return 0;
+ }
+ JSContext* cx = JsRootedValue::currentContext();
+ if(!JS_InstanceOf(cx, jsObject, &gwt_nativewrapper_class, 0)) {
+ tracer.throwHostedModeException(jniEnv,
+ "Javascript object not a Java object");
+ return 0;
+ }
+ jobject javaObject
+ = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, jsObject));
+ return javaObject;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isBoolean()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isBoolean
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isBoolean", jsRootedValue);
+ return jsRootedValue->isBoolean();
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isInt()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isInt
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isBoolean", jsRootedValue);
+ return jsRootedValue->isInt();
+}
+
+/*
+ * Checks if a JS object is a JavaScript object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isJavaScriptObject
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isJavaScriptObject
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isJavaScriptObject", jsRootedValue);
+ jsval val = jsRootedValue->getValue();
+ bool returnValue = false;
+ if(JSVAL_IS_OBJECT(val)) {
+ JSObject* jsObject = JSVAL_TO_OBJECT(val);
+ returnValue = !JS_InstanceOf(JsRootedValue::currentContext(), jsObject,
+ &gwt_nativewrapper_class, 0);
+ tracer.log("jsobject=%08x, isJSObject=%s", unsigned(jsObject),
+ returnValue ? "true" : "false");
+ } else {
+ tracer.log("not an object");
+ }
+ return returnValue;
+}
+
+/*
+ * Checks if a JS object is a JavaScript String object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isJavaScriptString
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isJavaScriptString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isJavaScriptString", jsRootedValue);
+ bool returnValue = jsRootedValue->isJavaScriptStringObject();
+ tracer.log("value=%s", returnValue ? "true" : "false");
+ return returnValue;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isNull()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isNull
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isNull", jsRootedValue);
+ return jsRootedValue->isNull();
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isNumber()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isNumber
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isNumber", jsRootedValue);
+ return jsRootedValue->isNumber();
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isString()
+ * Signature: (I)Z
+ *
+ * Handles the case of JavaScript String objects as well
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isString", jsRootedValue);
+ return jsRootedValue->isString();
+}
+
+/*
+ * Checks if a JS object is undefined (void)
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isUndefined
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isUndefined
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isUndefined", jsRootedValue);
+ return jsRootedValue->isUndefined();
+}
+
+/*
+ * Checks if a JS object is a wrapped Java object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isWrappedJavaObject
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isWrappedJavaObject
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isWrappedJavaObject", jsRootedValue);
+ jsval val = jsRootedValue->getValue();
+ bool returnValue = false;
+ if(JSVAL_IS_OBJECT(val)) {
+ JSObject* jsObject = JSVAL_TO_OBJECT(val);
+ returnValue = JS_InstanceOf(JsRootedValue::currentContext(), jsObject,
+ &gwt_nativewrapper_class, 0);
+ tracer.log("jsobject=%08x, wrappedJava=%s", unsigned(jsObject),
+ returnValue ? "true" : "false");
+ } else {
+ tracer.log("not an object");
+ }
+ return returnValue;
+}
+
+/*
+ * Set the JavaScript value to be a boolean of the supplied value.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setBoolean()
+ * Signature: (IZ)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setBoolean
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jboolean val)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setBoolean", jsRootedValue);
+ jsRootedValue->setBoolean(val == JNI_TRUE);
+ return;
+}
+
+/*
+ * Set the JavaScript value to be a double of the supplied value.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setDouble()
+ * Signature: (ID)V
+ */
+extern "C" JNIEXPORT void
+JNICALL Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setDouble
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jdouble val)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setDouble", jsRootedValue);
+ if(!jsRootedValue->setDouble(val)) {
+ tracer.throwHostedModeException(jniEnv, "Unable to allocate JS double");
+ return;
+ }
+}
+
+/*
+ * Set the Javascript value to be an integer.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setInt()
+ * Signature: (II)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setInt
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jint val)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setInt", jsRootedValue);
+ tracer.log("val=%d", val);
+ jsRootedValue->setInt(val);
+}
+
+/*
+ * Set the Javascript value to be another JsRootedValue's value.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setJsRootedValue()
+ * Signature: (II)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setJsRootedValue
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jint jsOtherRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ JsRootedValue* jsOtherRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsOtherRootedValueInt);
+ Tracer tracer("JsValueMoz._setJsRootedValue", jsRootedValue);
+ jsRootedValue->setValue(jsOtherRootedValue->getValue());
+}
+
+/*
+ * Set the Javascript value to a specific jsval.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setJsval()
+ * Signature: (II)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setJsval
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jint jsval)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setJsval", jsRootedValue);
+ jsRootedValue->setValue(jsval);
+}
+
+/*
+ * Set the JavaScript value to be null.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setNull()
+ * Signature: (I)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setNull
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setNull", jsRootedValue);
+ jsRootedValue->setNull();
+}
+
+/*
+ * Set the JavaScript value to be a string of the supplied value.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setString()
+ * Signature: (ILjava/lang/String;)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jstring val)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setString", jsRootedValue);
+ JStringWrap strVal(jniEnv, val);
+ const jchar* stringUTF16 = strVal.jstr();
+ if(!stringUTF16) {
+ tracer.throwHostedModeException(jniEnv, "Unable to retrieve Java string");
+ return;
+ }
+ tracer.log("string=%s", strVal.str());
+ if(!jsRootedValue->setString(reinterpret_cast<const wchar_t*>(stringUTF16),
+ strVal.length())) {
+ tracer.throwHostedModeException(jniEnv, "Unable to allocate JS string");
+ return;
+ }
+}
+
+/*
+ * Set the JavaScript value to be undefined (void).
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setUndefined()
+ * Signature: (I)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setUndefined
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setUndefined", jsRootedValue);
+ jsRootedValue->setUndefined();
+}
+
+/*
+ * Wraps a Java object in a JS object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setWrappedJavaObject
+ * Signature: (ILjava/lang/Object)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setWrappedJavaObject
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jobject obj)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setWrappedJavaObject", jsRootedValue);
+ JSContext* cx = JsRootedValue::currentContext();
+ JSObject* scriptWindow = JS_GetGlobalObject(cx);
+ JSObject* newObj = JS_NewObject(cx, &gwt_nativewrapper_class, 0,
+ scriptWindow);
+ if (!newObj) {
+ tracer.throwHostedModeException(jniEnv,
+ "Unable to allocate JS object to wrap Java object");
+ return;
+ }
+ // Save in output value so it won't get GCed.
+ jsRootedValue->setObject(newObj);
+ tracer.log("jsobject=%08x", unsigned(newObj));
+
+ // This is collected when the gwt_nativewrapper_class destructor runs.
+ jobject dispObjRef = jniEnv->NewGlobalRef(obj);
+ if (!dispObjRef || jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv,
+ "Unable to allocate global reference for JS wrapper");
+ return;
+ }
+ if (!JS_SetPrivate(cx, newObj, dispObjRef)) {
+ jniEnv->DeleteGlobalRef(dispObjRef);
+ tracer.throwHostedModeException(jniEnv,
+ "Unable to allocate global reference for JS wrapper");
+ return;
+ }
+ // forcibly setup a "toString" method to override the default
+ jclass dispClass = jniEnv->GetObjectClass(obj);
+ if (jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv, "Can't get object class");
+ return;
+ }
+ jmethodID getFieldMeth = jniEnv->GetMethodID(dispClass, "getField",
+ "(Ljava/lang/String;I)V");
+ if (!getFieldMeth || jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv, "Can't get getField method");
+ return;
+ }
+ jstring ident = jniEnv->NewStringUTF("@java.lang.Object::toString()");
+ if (!ident || jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv,
+ "Can't create Java string for toString method name");
+ return;
+ }
+ // allocate a new root to hold the result of the getField call
+ JsRootedValue* toStringFunc = new JsRootedValue();
+ jniEnv->CallVoidMethod(obj, getFieldMeth, ident,
+ NS_REINTERPRET_CAST(jint, toStringFunc));
+ if (toStringFunc->isUndefined() || jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv, "getField(toString) failed");
+ return;
+ }
+ if (!JS_DefineProperty(cx, newObj, "toString", toStringFunc->getValue(),
+ JS_PropertyStub, JS_PropertyStub, JSPROP_READONLY | JSPROP_PERMANENT)) {
+ tracer.throwHostedModeException(jniEnv, "Can't define JS toString method");
+ return;
+ }
+}
+
+/*
+ * Wraps a Java function in a JS object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setWrappedFunction
+ * Signature: (ILjava/lang/String;Lcom/google/gwt/dev/shell/moz/DispatchMethod;)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setWrappedFunction
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jstring methodName,
+ jobject dispatchMethod)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setWrappedFunction", jsRootedValue);
+ JSContext* cx = JsRootedValue::currentContext();
+ JSObject* scriptWindow = JS_GetGlobalObject(cx);
+ JStringWrap nameStr(jniEnv, methodName);
+ if (!nameStr.str()) {
+ tracer.throwHostedModeException(jniEnv,
+ "null method name passed to setWrappedFunction");
+ return;
+ }
+ tracer.log("JsRootedValue=%08x, method=%s, obj=%08x", jsRootedValueInt,
+ nameStr.str(), unsigned(dispatchMethod));
+ JSFunction* function = JS_NewFunction(cx, invokeJavaMethod, 0,
+ JSFUN_LAMBDA, 0, nameStr.str());
+ if (!function) {
+ tracer.throwHostedModeException(jniEnv, "JS_NewFunction failed");
+ return;
+ }
+ JSObject* funObj = JS_GetFunctionObject(function);
+ if (!funObj) {
+ tracer.throwHostedModeException(jniEnv, "JS_GetFunctionObject failed");
+ return;
+ }
+ // Save in output value so it won't get GCed.
+ jsRootedValue->setObject(funObj);
+
+ // Create a cleanup object to hold and clean up dispMeth
+ JSObject* cleanupObj = JS_NewObject(cx, &gwt_functionwrapper_class, 0,
+ scriptWindow);
+ if (!cleanupObj) {
+ tracer.throwHostedModeException(jniEnv, "JS_NewObject failed");
+ return;
+ }
+ tracer.log("funObj=%08x, cleanupObj=%08x", unsigned(funObj),
+ unsigned(cleanupObj));
+ // Store the cleanup object in funObj's reserved slot; now GC protected.
+ if(!JS_SetReservedSlot(cx, funObj, 0, OBJECT_TO_JSVAL(cleanupObj))) {
+ tracer.throwHostedModeException(jniEnv, "JS_SetReservedSlot failed");
+ return;
+ }
+ jobject dispMethRef = jniEnv->NewGlobalRef(dispatchMethod);
+ if (!dispMethRef || jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv,
+ "NewGlobalRef(dispatchMethod) failed");
+ return;
+ }
+ // Store our global ref in the wrapper object
+ if (!JS_SetPrivate(cx, cleanupObj, dispMethRef)) {
+ jniEnv->DeleteGlobalRef(dispMethRef);
+ tracer.throwHostedModeException(jniEnv, "JS_SetPrivate(cleanupObj) failed");
+ return;
+ }
+}
+
+/*
+ * Returns a JavaScript value as a string.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _toString
+ * Signature: (I)Ljava/lang/String;
+ */
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1toString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._toString", jsRootedValue);
+ jsval val = jsRootedValue->getValue();
+ JSContext* cx = JsRootedValue::currentContext();
+
+ // if it is a JavaScript object that has a toString member function
+ // call that, otherwise call JS_ValueToString
+ if(JSVAL_IS_OBJECT(val)) {
+ JSObject* jsObject = JSVAL_TO_OBJECT(val);
+ jsval fval;
+ jsval rval;
+ if (!JS_InstanceOf(cx, jsObject, &gwt_nativewrapper_class, 0)
+ && JS_GetProperty(cx, jsObject, "toString", &fval)
+ && JS_ValueToFunction(cx, fval)
+ && JS_CallFunctionValue(cx, jsObject, fval, 0, 0, &rval)) {
+ // all the steps succeeded, so use the result of toString() instead
+ // of the value for JS_ValueToString below
+ val = rval;
+ }
+ }
+ JSString* str = JS_ValueToString(cx, val);
+ if (!str) {
+ return 0;
+ }
+ int len = JS_GetStringLength(str);
+ jstring javaStr =jniEnv->NewString(reinterpret_cast<const jchar*>(
+ JS_GetStringChars(str)), len);
+ return javaStr;
+}
diff --git a/jni/linux/LowLevelMoz.cpp b/jni/linux/LowLevelMoz.cpp
new file mode 100644
index 0000000..9c3aba2
--- /dev/null
+++ b/jni/linux/LowLevelMoz.cpp
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+// Mozilla-specific hosted-mode methods
+
+// Define to log debug-level output rather than just warnings.
+#define DEBUG
+
+#include <cstdio>
+#include <cstdarg>
+#include <cwchar>
+
+// Mozilla header files
+#include "mozilla-headers.h"
+
+#include <jni.h>
+#include "gwt-jni.h"
+#include "JsRootedValue.h"
+#include "ExternalWrapper.h"
+#include "Tracer.h"
+#include "JsStringWrap.h"
+
+/*
+ * Debug definitions -- define FILETRACE to have debug output written to
+ * a file named gwt-ll.log, or JAVATRACE to have debug output passed to the
+ * Java LowLevelMoz.trace method.
+ */
+#ifdef ENABLE_TRACING
+#define FILETRACE
+//#define JAVATRACE
+#endif
+
+// include javah-generated header to make sure we match
+#include "LowLevelMoz.h"
+
+JNIEnv* savedJNIEnv = 0;
+jclass lowLevelMozClass;
+
+// Only include debugging code if we are tracing somewhere.
+#ifdef ENABLE_TRACING
+
+/*
+ * Template so vsnprintf/vswprintf can be used interchangeably in the
+ * append_sprintf template below.
+ * buf - pointer to the start of the output buffer
+ * len - maximum number of characters to write into the buffer
+ * (including the null terminator)
+ * fmt - printf-style format string
+ * args - stdarg-style variable arguments list
+ * Returns the number of characters written (excluding the null terminator)
+ * or -1 if an error occurred.
+ *
+ * Note that %lc and %ls are only legal in the wchar_t implementation.
+ */
+template<class charT>
+int safe_vsprintf(charT* buf, size_t len, const charT* fmt, va_list args);
+
+// specialization for char that maps to vsnprintf
+template<>
+inline int safe_vsprintf<char>(char* buf, size_t len, const char* fmt,
+ va_list args) {
+ return ::vsnprintf(buf, len, fmt, args);
+}
+
+// specialization for wchar_t that maps to vswprintf
+template<>
+inline int safe_vsprintf<wchar_t>(wchar_t* buf, size_t len, const wchar_t* fmt,
+ va_list args) {
+ return ::vswprintf(buf, len, fmt, args);
+}
+
+/*
+ * Safely append to a string buffer, updating the output pointer and always
+ * reserving the last character of the buffer for a null terminator.
+ * bufStart - pointer to the start of the output buffer
+ * bufEnd - pointer just past the end of the output buffer
+ * fmt - format string
+ * additional arguments as passed to *printf
+ * Returns the number of characters actually written, not including the null
+ * terminator. Nothing is written, including the null terminator, if the
+ * buffer start points beyond the output buffer.
+ *
+ * Templated to work with any character type that has a safe_vsprintf
+ * implementation.
+ */
+template<class charT>
+static int append_sprintf(charT* bufStart, const charT* bufEnd,
+ const charT* fmt, ...) {
+ va_list args;
+ va_start(args, fmt); // initialize variable arguments list
+ // compute space left in buffer: -1 for null terminator
+ int maxlen = bufEnd - bufStart - 1;
+ if (maxlen <= 0) return 0;
+ int n = safe_vsprintf(bufStart, maxlen, fmt, args);
+ va_end(args);
+ if (n > maxlen) {
+ n = maxlen;
+ }
+ bufStart[n] = 0;
+ return n;
+}
+
+/*
+ * Log a given jsval with a prefix.
+ * cx - JSContext for the JS execution context to use
+ * val - jsval to print
+ * prefix - string to print before the value, defaults to empty string
+ *
+ * TODO(jat): this whole printf-style logging needs to be replaced, but we
+ * run into library version issues if we use C++ iostreams so we would need
+ * to implement our own equivalent. Given that this code is all likely to
+ * be rewritten for out-of-process hosted mode, it seems unlikely to be worth
+ * the effort until that is completed.
+ */
+void PrintJSValue(JSContext* cx, jsval val, char* prefix="") {
+ JSType type = JS_TypeOfValue(cx, val);
+ const char* typeString=JS_GetTypeName(cx, type);
+ static const int BUF_SIZE = 256;
+ char buf[BUF_SIZE];
+ const char *bufEnd = buf + BUF_SIZE;
+ char* p = buf;
+ p += append_sprintf(p, bufEnd, "%s%s", prefix, typeString);
+ switch(type) {
+ case JSTYPE_VOID:
+ break;
+ case JSTYPE_BOOLEAN:
+ p += append_sprintf(p, bufEnd, ": %s",
+ JSVAL_TO_BOOLEAN(val) ? "true" : "false");
+ break;
+ case JSTYPE_NUMBER:
+ if (JSVAL_IS_INT(val)) {
+ p += append_sprintf(p, bufEnd, ": %d", JSVAL_TO_INT(val));
+ } else {
+ p += append_sprintf(p, bufEnd, ": %lf", (double)*JSVAL_TO_DOUBLE(val));
+ }
+ break;
+ case JSTYPE_OBJECT: {
+ JSObject* obj = JSVAL_TO_OBJECT(val);
+ if (!JSVAL_IS_OBJECT(val)) break;
+ JSClass* clazz = obj ? JS_GET_CLASS(cx, obj) : 0;
+ p += append_sprintf(p, bufEnd, " @ %08x, class %s",
+ (unsigned)obj, clazz ? clazz->name : "<null>");
+ break;
+ }
+ case JSTYPE_FUNCTION:
+ case JSTYPE_LIMIT:
+ break;
+ case JSTYPE_STRING: {
+ /*
+ * TODO(jat): support JS strings with international characters
+ */
+ JsStringWrap str(cx, JSVAL_TO_STRING(val));
+ p += append_sprintf(p, bufEnd, ": %.*s", str.length(), str.bytes());
+ break;
+ }
+ }
+ Tracer::log("%s", buf);
+}
+#else
+// Include a null version just to keep from cluttering up call sites.
+static inline void PrintJSValue(JSContext* cx, jsval val, char* prefix="") { }
+#endif
+
+
+static bool InitGlobals(JNIEnv* env, jclass llClass) {
+ if (savedJNIEnv)
+ return false;
+
+#ifdef FILETRACE
+ Tracer::setFile("gwt-ll.log");
+#endif // FILETRACE
+
+#ifdef JAVATRACE
+ Tracer::setJava(env, llClass);
+#endif // JAVATRACE
+
+#ifdef DEBUG
+ Tracer::setLevel(Tracer::LEVEL_DEBUG);
+#endif
+
+ savedJNIEnv = env;
+ lowLevelMozClass = static_cast<jclass>(env->NewGlobalRef(llClass));
+ return true;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method: _executeScriptWithInfo
+ * Signature: (ILjava/lang/String;Ljava/lang/String;I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1executeScriptWithInfo
+ (JNIEnv* env, jclass llClass, jint scriptObjectInt, jstring code,
+ jstring file, jint line)
+{
+ Tracer tracer("LowLevelMoz._executeScriptWithInfo");
+ JStringWrap jcode(env, code);
+ if (!jcode.jstr()) {
+ tracer.setFail("null code string");
+ return JNI_FALSE;
+ }
+ JStringWrap jfile(env, file);
+ if (!jfile.str()) {
+ tracer.setFail("null file name");
+ return JNI_FALSE;
+ }
+ tracer.log("code=%s, file=%s, line=%d", jcode.str(), jfile.str(), line);
+ JSContext* cx = JsRootedValue::currentContext();
+ nsCOMPtr<nsIScriptContext> scriptContext(GetScriptContextFromJSContext(cx));
+
+ nsIScriptGlobalObject* scriptObject =
+ NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjectInt);
+ JSObject* scriptWindow =
+ reinterpret_cast<JSObject*>(scriptObject->GetGlobalJSObject());
+ nsXPIDLString scriptString;
+ scriptString = jcode.jstr();
+
+ nsXPIDLString aRetValue;
+ PRBool aIsUndefined;
+ if (NS_FAILED(scriptContext->EvaluateString(scriptString, scriptWindow, 0,
+ jfile.str(), line, 0, aRetValue, &aIsUndefined))) {
+ tracer.setFail("EvaluateString failed");
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method: _invoke
+ * Signature: (ILjava/lang/String;I[I)I
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1invoke
+ (JNIEnv* env, jclass, jint scriptObjInt, jstring methodName, jint jsThisInt,
+ jintArray jsArgsInt, jint jsRetValInt)
+{
+ Tracer tracer("LowLevelMoz._invoke");
+
+ JStringWrap methodStr(env, methodName);
+ if (!methodStr.str()) {
+ tracer.setFail("null method name");
+ return JNI_FALSE;
+ }
+ JsRootedValue* jsThisRV = reinterpret_cast<JsRootedValue*>(jsThisInt);
+ jint jsArgc = env->GetArrayLength(jsArgsInt);
+ tracer.log("method=%s, jsthis=%08x, #args=%d", methodStr.str(), jsThisInt,
+ jsArgc);
+ JSContext* cx = JsRootedValue::currentContext();
+ nsIScriptGlobalObject* scriptObject =
+ NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+ JSObject* scriptWindow
+ = reinterpret_cast<JSObject*>(scriptObject->GetGlobalJSObject());
+
+ jsval fval;
+ if (!JS_GetProperty(cx, scriptWindow, methodStr.str(), &fval)) {
+ tracer.setFail("JS_GetProperty(method) failed");
+ return JNI_FALSE;
+ }
+ JSFunction* jsFunction = JS_ValueToFunction(cx, fval);
+ if (!jsFunction) {
+ tracer.setFail("JS_ValueToFunction failed");
+ return JNI_FALSE;
+ }
+
+ // extract arguments in jsval form
+ nsAutoArrayPtr<jint> jsargvals(new jint[jsArgc]);
+ if (!jsargvals) {
+ tracer.setFail("failed to allocate arg array");
+ return JNI_FALSE;
+ }
+ env->GetIntArrayRegion(jsArgsInt, 0, jsArgc, jsargvals);
+ if (env->ExceptionCheck()) {
+ tracer.setFail("copy from Java array failed");
+ return JNI_FALSE;
+ }
+ nsAutoArrayPtr<jsval> jsargs(new jsval[jsArgc]);
+ for (int i = 0; i < jsArgc; ++i) {
+ JsRootedValue* arg = reinterpret_cast<JsRootedValue*>(jsargvals[i]);
+ jsargs[i] = arg->getValue();
+ }
+
+ jsval jsrval;
+ JSObject* jsThis;
+ if (jsThisRV->isNull()) {
+ jsThis = scriptWindow;
+ } else {
+ jsThis = jsThisRV->getObject();
+ }
+
+ PrintJSValue(cx, OBJECT_TO_JSVAL(jsThis), "jsThis=");
+ for (int i = 0; i < jsArgc; ++i) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "arg[%d]=", i);
+ PrintJSValue(cx, jsargs[i], buf);
+ }
+ //tracer.log("fval = %08x, args=%08x", fval, jsargs.get());
+ if (!JS_CallFunctionValue(cx, jsThis, fval, jsArgc, jsargs.get(), &jsrval)) {
+ tracer.setFail("JS_CallFunctionValue failed");
+ return JNI_FALSE;
+ }
+
+ PrintJSValue(cx, jsrval, "return value=");
+ JsRootedValue* returnVal = reinterpret_cast<JsRootedValue*>(jsRetValInt);
+ returnVal->setValue(jsrval);
+ return JNI_TRUE;
+}
+
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method: _raiseJavaScriptException
+ * Signature: ()Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1raiseJavaScriptException
+ (JNIEnv* env, jclass)
+{
+ Tracer tracer("LowLevelMoz._raiseJavaScriptException");
+ JS_SetPendingException(JsRootedValue::currentContext(), JSVAL_NULL);
+ return JNI_TRUE;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method: _registerExternalFactoryHandler
+ * Signature: ()Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1registerExternalFactoryHandler
+ (JNIEnv* env, jclass llClass)
+{
+ if (!InitGlobals(env, llClass))
+ return JNI_FALSE;
+
+ // tracing isn't setup until after InitGlobals is called
+ Tracer tracer("LowLevelMoz._registerExternalFactoryHandler");
+
+ char buf[256];
+ sprintf(buf, " jniEnv=%08x, llClass=%08x", (unsigned)env, (unsigned)llClass);
+ tracer.log(buf);
+
+ // Register "window.external" as our own class
+ if (NS_FAILED(nsComponentManager::RegisterFactory(
+ kGwtExternalCID, "externalFactory", GWT_EXTERNAL_CONTRACTID,
+ new nsRpExternalFactory(), PR_TRUE))) {
+ tracer.setFail("RegisterFactory failed");
+ return JNI_FALSE;
+ }
+
+ nsCOMPtr<nsICategoryManager> categoryManager =
+ do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
+ if (!categoryManager) {
+ tracer.setFail("unable to get category manager");
+ return JNI_FALSE;
+ }
+
+ nsXPIDLCString previous;
+ if (NS_FAILED(categoryManager->AddCategoryEntry(
+ JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY, "external", GWT_EXTERNAL_CONTRACTID,
+ PR_TRUE, PR_TRUE, getter_Copies(previous)))) {
+ tracer.setFail("AddCategoryEntry failed");
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
diff --git a/jni/linux/Makefile b/jni/linux/Makefile
new file mode 100644
index 0000000..8b3a8cf
--- /dev/null
+++ b/jni/linux/Makefile
@@ -0,0 +1,153 @@
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+##
+# Target settings
+##
+#JAVA_HOME
+#JAVA_HOME=/usr/lib/j2sdk1.5-sun
+
+# set GWT_TOOLS only if it is not already defined
+GWT_TOOLS ?= ../../../tools
+
+GWT_ROOT = ../../
+OBJDIR := $(GWT_ROOT)build/out/jni/linux/
+OUTDIR := $(GWT_ROOT)build/jni/linux/
+OUT := $(OUTDIR)libgwt-ll.so
+STAGING := $(GWT_ROOT)build/staging/gwt-linux-0.0.0/
+
+##
+# The location to get .class files from for javah
+##
+CLASSDIR := $(GWT_ROOT)build/out/dev/linux/bin
+
+# use this instead if you want to use eclipse to build the class files during
+# development
+#CLASSDIR := $(GWT_ROOT)eclipse/dev/linux/bin
+
+##
+# Tools
+##
+CXX := g++
+AR := ar
+STRIP := strip
+LD := $(CXX)
+JAVAH := $(JAVA_HOME)/bin/javah
+
+##
+# List of source, object, and dependency paths plus the path to them
+##
+SRCDIRS := ./:../core/
+VPATH := .:../core
+SRCS := gwt-ll.cpp LowLevelMoz.cpp JsValueMoz.cpp Tracer.cpp \
+ ExternalWrapper.cpp NativeWrapper.cpp JsRootedValue.cpp
+OBJS := $(addprefix $(OBJDIR),$(SRCS:.cpp=.o))
+DEPS := $(addprefix $(OBJDIR),$(SRCS:.cpp=.d))
+
+MOZDIR = $(GWT_TOOLS)/sdk/mozilla-1.7.12
+MOZINC = $(MOZDIR)/include
+MOZLIB = $(MOZDIR)/lib
+
+##
+# Include path configuration
+##
+SYSINCS := \
+ $(JAVA_HOME)/include \
+ $(JAVA_HOME)/include/linux \
+ $(MOZINC) $(MOZINC)/extra
+
+INCS := $(OBJDIR)
+INCS := $(addprefix -I ,$(INCS)) $(addprefix -isystem ,$(SYSINCS))
+
+##
+# Libraries and library path
+##
+LIBS = xpcomglue_s
+LIBPATH = -L$(MOZLIB)
+LIBS := $(addprefix -l,$(LIBS))
+
+# for notes on auto-dependency generation, see
+# http://make.paulandlesley.org/autodep.html
+# -MP obviates the need for sed hackery
+CFLAGS := -ggdb -m32 -Os -fPIC -fno-omit-frame-pointer -fno-strict-aliasing -D_REENTRANT -MMD -MP -Wno-system-headers $(CFLAGS)
+LDFLAGS := -ggdb -m32 -s -fPIC -fno-omit-frame-pointer -fno-strict-aliasing -D_REENTRANT -Wl,-shared-gcc $(LDFLAGS)
+
+#-------------------------------------------------------------------------------
+# Rules
+#-------------------------------------------------------------------------------
+
+##
+# default rule
+##
+all: $(OUT)
+
+# install into prebuilt directory
+install: $(OUT)
+ cp $(OUT) prebuilt/
+
+##
+# Include the dependency rules
+##
+-include $(DEPS)
+
+##
+# javah-generated headers for native methods
+##
+$(OBJDIR)LowLevelMoz.h : $(CLASSDIR)/com/google/gwt/dev/shell/moz/LowLevelMoz.class
+ $(JAVAH) -classpath $(CLASSDIR) -o $(OBJDIR)LowLevelMoz.h com.google.gwt.dev.shell.moz.LowLevelMoz
+
+$(OBJDIR)JsValueMoz.h : $(CLASSDIR)/com/google/gwt/dev/shell/moz/JsValueMoz.class
+ $(JAVAH) -classpath $(CLASSDIR) -o $(OBJDIR)JsValueMoz.h com.google.gwt.dev.shell.moz.JsValueMoz
+
+##
+# Dependency rules for generated headers
+# TODO(jat): autogenerate these and others
+##
+$(OBJDIR)LowLevelMoz.o: $(OBJDIR)LowLevelMoz.h $(JAVA_HOME)/include/jni.h
+$(OBJDIR)JsValueMoz.o: $(OBJDIR)JsValueMoz.h $(JAVA_HOME)/include/jni.h
+
+##
+# Compilation rule for cpp files
+##
+$(OBJDIR)%.o : $(SRCDIR)%.cpp
+ @[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
+ $(CXX) -c $(CFLAGS) $(INCS) -o $@ $<
+
+# generate preprocessed output files upon request for debugging
+%.i : $(SRCDIR)%.cpp
+ $(CXX) -E $(CFLAGS) $(INCS) -o $@ $<
+
+%.I : $(SRCDIR)%.cpp
+ $(CXX) -E -dDI $(CFLAGS) $(INCS) -o $@ $<
+
+##
+# Actual output file
+##
+$(OUT): $(OBJS) $(MOZLIB)/libxpcomglue_s.a
+ @[ -d $(OUTDIR) ] || mkdir -p $(OUTDIR)
+ $(LD) -shared $(LDFLAGS) $(LIBPATH) -o $@ $^ $(LIBS)
+ $(STRIP) --strip-unneeded $@
+
+##
+# copy to staging area for hosted-mode development
+##
+staging: $(OUT)
+ @[ -d $(STAGING) ] || mkdir -p $(STAGING)
+ cp $(OUT) $(STAGING)
+
+##
+# Clean rule
+##
+clean:
+ @-rm -rf $(OBJDIR) $(OUT)
diff --git a/jni/linux/NativeWrapper.cpp b/jni/linux/NativeWrapper.cpp
new file mode 100644
index 0000000..38958d0
--- /dev/null
+++ b/jni/linux/NativeWrapper.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/*
+ * Defines the JavaScript classes gwt_nativewrapper_class and
+ * gwt_functionwrapper_class, which interface via JNI to Java objects.
+ */
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "gwt-jni.h"
+#include "Tracer.h"
+
+/*
+ * Helper function to get reference Java attributes from Javascript.
+ *
+ * cx - JSContext pointer
+ * obj - JavaScript object which is a wrapped Java object
+ * id - property name, as a jsval string
+ * dispClass - output parameter of DispatchMethod subclass
+ * dispObj - output parameter of Java object
+ * jident - output parameter of property name as a Java string
+ */
+static JSBool getJavaPropertyStats(JSContext *cx, JSObject *obj, jsval id,
+ jclass& dispClass, jobject& dispObj, jstring& jident)
+{
+ Tracer tracer("getJavaPropertyStats");
+ if (!JSVAL_IS_STRING(id)) {
+ tracer.setFail("id is not a string");
+ return JS_FALSE;
+ }
+
+ jident = savedJNIEnv->NewString(JS_GetStringChars(JSVAL_TO_STRING(id)),
+ JS_GetStringLength(JSVAL_TO_STRING(id)));
+ if (!jident || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("unable to create Java string");
+ return JS_FALSE;
+ }
+
+ dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ if (!dispObj) {
+ tracer.setFail("can't get dispatch object");
+ return JS_FALSE;
+ }
+
+ dispClass = savedJNIEnv->GetObjectClass(dispObj);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get class of dispatch object");
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+/*
+ * Returns the value of a field on a Java object.
+ *
+ * context - JavaScript context
+ * clazz - class of obj
+ * obj - Java object to retreive field from
+ * fieldName - name of field on Java object to retrieve
+ *
+ * Returns null on failure. Caller is responsible for deleting
+ * returned JsRootedValue when done with it.
+ */
+static JsRootedValue* GetFieldAsRootedValue(JSContext* cx, jclass clazz,
+ jobject obj, jstring fieldName)
+{
+ Tracer tracer("GetFieldAsRootedValue");
+ JsRootedValue::ContextManager context(cx);
+ jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "getField",
+ "(Ljava/lang/String;I)V");
+ if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
+ return 0;
+ }
+
+ JsRootedValue* jsRootedValue = new JsRootedValue();
+ savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
+ reinterpret_cast<jint>(jsRootedValue));
+ if (savedJNIEnv->ExceptionCheck()) {
+ delete jsRootedValue;
+ return 0;
+ }
+ return jsRootedValue;
+}
+
+/*
+ * Sets the value of a field on a Java object.
+ *
+ * context - JavaScript context
+ * clazz - class of obj
+ * obj - Java object to store into field
+ * fieldName - name of field on Java object to store into
+ * jsRootedValue - the value to store in the field
+ *
+ * returns true on success, false on failure
+ */
+static bool SetFieldFromRootedValue(JSContext* cx, jclass clazz,
+ jobject obj, jstring fieldName, JsRootedValue* jsRootedValue)
+{
+ Tracer tracer("SetFieldAsRootedValue");
+ JsRootedValue::ContextManager context(cx);
+ jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "setField",
+ "(Ljava/lang/String;I)V");
+ if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
+ return false;
+ }
+
+ savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
+ reinterpret_cast<jint>(jsRootedValue));
+ if (savedJNIEnv->ExceptionCheck()) {
+ return false;
+ }
+
+ return true;
+}
+
+static JSBool JS_DLL_CALLBACK gwt_nativewrapper_getProperty(JSContext *cx,
+ JSObject *obj, jsval id, jsval *vp)
+{
+ Tracer tracer("gwt_nativewrapper_getProperty");
+ tracer.log("context=%08x, obj=%08x", unsigned(cx), unsigned(obj));
+ JsRootedValue::ContextManager context(cx);
+
+ jclass dispClass;
+ jobject dispObj;
+ jstring ident;
+ if (!getJavaPropertyStats(cx, obj, id, dispClass, dispObj, ident)) {
+ tracer.setFail("getJavaPropertyStats failed");
+ return JS_FALSE;
+ }
+ JsRootedValue* js_rooted_value = GetFieldAsRootedValue(cx, dispClass,
+ dispObj, ident);
+ if (!js_rooted_value) {
+ tracer.setFail("can't get field");
+ return JS_FALSE;
+ }
+ *vp = js_rooted_value->getValue();
+ return JS_TRUE;
+}
+
+static void JS_DLL_CALLBACK gwt_nativewrapper_finalize(JSContext *cx,
+ JSObject *obj)
+{
+ Tracer tracer("gwt_nativewrapper_finalize");
+ jobject dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ if (dispObj) {
+ // Remove this pairing from the global map.
+ jmethodID removeMethod = savedJNIEnv->GetStaticMethodID(lowLevelMozClass, "removeJsvalForObject",
+ "(Ljava/lang/Object;)V");
+ if (!removeMethod || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("Cannot GetMethodID for removeJsvalForObject");
+ return;
+ }
+ savedJNIEnv->CallStaticVoidMethod(lowLevelMozClass, removeMethod, dispObj);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("Exception calling removeJsvalForObject");
+ return;
+ }
+ savedJNIEnv->DeleteGlobalRef(dispObj);
+ }
+}
+
+static JSBool JS_DLL_CALLBACK gwt_nativewrapper_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ Tracer tracer("gwt_nativewrapper_setProperty");
+ tracer.log("context=%08x", unsigned(cx));
+ JsRootedValue::ContextManager context(cx);
+ jclass dispClass;
+ jobject dispObj;
+ jstring ident;
+ if (!getJavaPropertyStats(cx, obj, id, dispClass, dispObj, ident)) {
+ tracer.setFail("getJavaPropertyStats failed");
+ return JS_FALSE;
+ }
+ JsRootedValue* js_rooted_value = new JsRootedValue(*vp);
+ if (!SetFieldFromRootedValue(cx, dispClass, dispObj, ident,
+ js_rooted_value)) {
+ tracer.setFail("can't set field");
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JSClass gwt_nativewrapper_class = {
+ "gwt_nativewrapper_class", JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, gwt_nativewrapper_getProperty,
+ gwt_nativewrapper_setProperty, JS_EnumerateStub, JS_ResolveStub,
+ JS_ConvertStub, gwt_nativewrapper_finalize,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+JSClass gwt_functionwrapper_class = {
+ "gwt_functionwrapper_class", JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, gwt_nativewrapper_finalize,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
diff --git a/jni/linux/Tracer.cpp b/jni/linux/Tracer.cpp
new file mode 100644
index 0000000..e5f3189
--- /dev/null
+++ b/jni/linux/Tracer.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "Tracer.h"
+
+#ifdef ENABLE_TRACING
+
+// initialize static fields
+FILE* Tracer::outfp = 0;
+JNIEnv* Tracer::jniEnv = 0;
+jclass Tracer::traceClass;
+jmethodID Tracer::traceMethod;
+int Tracer::indentation = 0;
+Tracer::LogLevel Tracer::logLevel = Tracer::LEVEL_WARNING;
+
+/*
+ * Sets a JNI environment and Java class to pass trace messages to.
+ *
+ * env - JNI environment to use for trace calls
+ * clazz - Java class, which must provide static void trace(String)
+ */
+bool Tracer::setJava(JNIEnv* env, jclass clazz) {
+ jniEnv = env;
+ if (!env) {
+ return true;
+ }
+ traceClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ if (!traceClass || env->ExceptionCheck()) {
+ return false;
+ }
+ traceMethod = env->GetStaticMethodID(traceClass, "trace",
+ "(Ljava/lang/String;)V");
+ if (!traceMethod || env->ExceptionCheck()) {
+ return false;
+ }
+
+ jstring msg = jniEnv->NewStringUTF("== Java trace started ==");
+ jniEnv->CallStaticVoidMethod(traceClass, traceMethod, msg);
+ return true;
+}
+
+#endif // ENABLE_TRACING
+
+/*
+ * Throw a HostedModeException and log a failure message.
+ *
+ * Creates a new HostedModeException with the failure message,
+ * and also logs the failure message
+ *
+ * env - JNI environment to throw the exception in
+ * msg - failure message
+ */
+void Tracer::throwHostedModeException(JNIEnv* env, const char* msg) {
+#ifdef ENABLE_TRACING
+ setFail(msg);
+#endif // ENABLE_TRACING
+ jclass exceptionClass
+ = env->FindClass("com/google/gwt/dev/shell/HostedModeException");
+ env->ThrowNew(exceptionClass, msg);
+}
diff --git a/jni/linux/Tracer.h b/jni/linux/Tracer.h
new file mode 100644
index 0000000..ef9fd7d
--- /dev/null
+++ b/jni/linux/Tracer.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+#ifndef JNI_LINUX_TRACER_H_
+#define JNI_LINUX_TRACER_H_
+
+#include <cstdio>
+#include <cstdarg>
+#include <cstring>
+#include <jni.h>
+
+// comment this out to remove almost all runtime overhead (with usual compiler
+// support) from tracing.
+//#define ENABLE_TRACING
+
+/*
+ * Utility class for tracing. This class is intended to be used as follows:
+ *
+ * {
+ * Tracer tracer("method name");
+ * ... do work
+ * if (fail) {
+ * tracer.setFail("failure explanation");
+ * return;
+ * }
+ * if (fail2) {
+ * tracer.throwHostedModeException("failure explanation");
+ * return;
+ * }
+ * return;
+ * }
+ *
+ * The class automatically logs an enter message when it is created, as well
+ * as leave/fail messages when it is destroyed. Logging is performed to a
+ * file or to a Java static member function on a class (or both) -- these
+ * are configured by using static member functions setFile() and setJava().
+ *
+ * This class knows about the Java class
+ * com.google.gwt.dev.shell.HostedModeException
+ * and throws a new instance of that exception if requested.
+ */
+class Tracer {
+public:
+ enum LogLevel {
+ LEVEL_ERROR = 0,
+ LEVEL_WARNING,
+ LEVEL_NOTICE,
+ LEVEL_INFO,
+ LEVEL_DEBUG,
+ LEVEL_DEBUG_V1,
+ LEVEL_DEBUG_V2,
+ };
+protected:
+#ifdef ENABLE_TRACING
+ // static variables that specify where logging is performed. This are
+ // set by calling setFile() and setJava().
+ static FILE* outfp;
+ static JNIEnv* jniEnv;
+ static jclass traceClass;
+ static jmethodID traceMethod;
+ static int indentation;
+ static LogLevel logLevel;
+
+ // method is set when the instance is created.
+ const char* method_;
+ // fail_msg is set to indicate a failure has occurred.
+ const char* fail_msg_;
+ // level of this trace object
+ LogLevel log_level_;
+#endif
+
+public:
+ /*
+ * Set the logging level.
+ */
+ static void setLevel(LogLevel level) {
+#ifdef ENABLE_TRACING
+ logLevel = level;
+#endif
+ }
+
+protected:
+ /*
+ * Log a message (with supplied prefix) to the configured file.
+ * Only called if a file was specified and successfully opened for writing.
+ */
+ static void logFile(const char* msg) {
+#ifdef ENABLE_TRACING
+ for (int i = 0; i < indentation; ++i) {
+ putc(' ', outfp);
+ }
+ fputs(msg, outfp);
+ putc('\n', outfp);
+ fflush(outfp);
+#else
+ (void)msg; // avoid unused warning
+#endif
+ }
+
+ /*
+ * Log a message (with supplied prefix) to the configured Java class.
+ * Only called if a file was specified and successfully accessed.
+ *
+ * Call static void trace(String msg) on the configured class.
+ */
+ static void logJava(const char* msg) {
+#ifdef ENABLE_TRACING
+ // TODO(jat): fixed buffer size
+ char buf[512];
+ for (int i = 0; (i < indentation) && (i < int(sizeof(buf))); ++i) {
+ buf[i] = ' ';
+ }
+ strncpy(buf + indentation, msg, sizeof(buf) - indentation);
+ buf[sizeof(buf) - 1] = 0; // ensure null termination
+ jstring str = jniEnv->NewStringUTF(buf);
+ jniEnv->CallStaticVoidMethod(traceClass, traceMethod, str);
+#else
+ (void)msg; // avoid unused warning
+#endif
+ }
+
+ /*
+ * Log a message to a file and/or class with the default logging level.
+ *
+ * If the preprocessor symbol DISABLE_TRACING has been defined, this is
+ * completely removed from the code path.
+ */
+ void logPrefix(const char* prefix) {
+#ifdef ENABLE_TRACING
+ logPrefix(prefix, log_level_);
+#else
+ (void)prefix; // avoid unused warning
+#endif
+ }
+
+ /*
+ * Log a message to a file and/or class.
+ *
+ * If the preprocessor symbol DISABLE_TRACING has been defined, this is
+ * completely removed from the code path.
+ */
+ void logPrefix(const char* prefix, LogLevel level) {
+#ifdef ENABLE_TRACING
+ if (level>logLevel) return;
+ log("%-5.5s %s%s%s", prefix, method_, fail_msg_ ? ": " : "",
+ fail_msg_ ? fail_msg_ : "");
+#endif
+ }
+
+public:
+ /*
+ * Create an instance with the specified method name and no failure
+ * message. Log an ENTER message.
+ */
+ Tracer(const char* method, LogLevel log_level = LEVEL_ERROR)
+#ifdef ENABLE_TRACING
+ : method_(method), fail_msg_(0), log_level_(log_level) {
+ log("ENTER %s", method);
+ indentation++;
+#else
+ { (void)method; (void)log_level; // avoid unused warnings
+#endif
+ }
+
+ /*
+ * Create an instance with the specified method name and no failure
+ * message. Log an ENTER message and the this pointer.
+ */
+ Tracer(const char* method, const void* objThis,
+ LogLevel log_level = LEVEL_ERROR)
+#ifdef ENABLE_TRACING
+ : method_(method), fail_msg_(0), log_level_(log_level) {
+ log("ENTER %s(this=%08x)", method, unsigned(objThis));
+ indentation++;
+#else
+ { (void)method; (void)objThis; (void)log_level; // avoid unused warnings
+#endif
+ }
+
+ /*
+ * Destroy the instance and log a fail or leave message.
+ */
+ ~Tracer() {
+#ifdef ENABLE_TRACING
+ --indentation;
+ if(fail_msg_) {
+ logPrefix("*FAIL", LEVEL_ERROR);
+ } else {
+ logPrefix("LEAVE");
+ }
+#endif
+ }
+
+ /*
+ * Specify a filename to receive logging output. Close any previously
+ * opened file. If a null filename is passed, disable logging to a
+ * file.
+ *
+ * filename - the file path to receive logging output. This file is
+ * truncated if it already exists.
+ *
+ * Returns false on failure.
+ */
+ static bool setFile(const char* filename) {
+#ifdef ENABLE_TRACING
+ if (outfp) {
+ fclose(outfp);
+ outfp = 0;
+ }
+ if (!filename) {
+ return true;
+ }
+ outfp = fopen(filename, "w");
+ if (!outfp) {
+ return false;
+ }
+ fprintf(outfp, "== started logging ==\n");
+ fflush(outfp);
+#else
+ (void)filename; // avoid unused warning
+#endif
+ return true;
+ }
+
+ /*
+ * Specify a Java class to receive logging output. The supplied class
+ * must have a static void trace(String) member function which is called
+ * for output. Logging to a Java class is disabled if the supplied JNI
+ * environment is null.
+ *
+ * env - JNI environment
+ * clazz - the Java class to receive logging output
+ *
+ * Returns false on failure.
+ */
+ static bool setJava(JNIEnv* env, jclass clazz)
+#ifdef ENABLE_TRACING
+ ;
+#else
+ // inline a null body if we aren't debugging; avoid unused warnings
+ { (void)env; (void)clazz; return true; }
+#endif
+
+ /*
+ * Set a failure message, overwriting any previously specified failure
+ * message. Passing a null string will remove any previous failure
+ * notification.
+ */
+ void setFail(const char* fail_msg) {
+#ifdef ENABLE_TRACING
+ fail_msg_ = fail_msg;
+#else
+ (void)fail_msg; // avoid unused warning
+#endif
+ }
+
+ /*
+ * Throw a Java HostedModeException as well as set a failure message to
+ * be logged.
+ *
+ * env - JNI environment to throw exception into
+ * fail_msg - failure message
+ */
+ void throwHostedModeException(JNIEnv* env, const char* fail_msg);
+
+ /*
+ * Log an arbitrary message.
+ */
+ static void log(const char* format, ...) {
+#ifdef ENABLE_TRACING
+ va_list args;
+ va_start(args, format);
+ char msg[512]; // TODO(jat): fixed size buffer
+ vsnprintf(msg, sizeof(msg), format, args);
+ msg[sizeof(msg) - 1] = 0; // ensure null termination
+ if(outfp) logFile(msg);
+ if(jniEnv) logJava(msg);
+ va_end(args);
+#else
+ (void)format; // avoid unused warning
+#endif
+ }
+};
+
+#endif /* JNI_LINUX_TRACER_H_ */
diff --git a/jni/linux/build.xml b/jni/linux/build.xml
new file mode 100755
index 0000000..5f0db6b
--- /dev/null
+++ b/jni/linux/build.xml
@@ -0,0 +1,18 @@
+<project name="jni-linux" default="build" basedir=".">
+ <property name="gwt.root" location="../.." />
+ <property name="project.tail" value="jni/linux" />
+ <import file="${gwt.root}/common.ant.xml" />
+
+ <target name="build" description="Builds a JNI lib">
+ <mkdir dir="${project.jni}" />
+ <!-- TODO: Actually build this from source! -->
+ <copy todir="${project.jni}">
+ <fileset dir="prebuilt" />
+ </copy>
+ </target>
+
+ <target name="clean" description="Cleans this project's intermediate and output files">
+ <delete dir="${project.build}" failonerror="false" />
+ <delete dir="${project.jni}" failonerror="false" />
+ </target>
+</project>
diff --git a/jni/linux/gwt-jni.h b/jni/linux/gwt-jni.h
new file mode 100644
index 0000000..c477f1c
--- /dev/null
+++ b/jni/linux/gwt-jni.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+#ifndef JNI_LINUX_GWT_JNI_H_
+#define JNI_LINUX_GWT_JNI_H_
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "JStringWrap.h"
+
+extern JNIEnv* savedJNIEnv;
+extern jclass lowLevelMozClass;
+
+extern nsCID kGwtExternalCID;
+
+// JavaScript class objects
+extern JSClass gwt_nativewrapper_class;
+extern JSClass gwt_functionwrapper_class;
+
+#endif /*JNI_LINUX_GWT_JNI_H_*/
diff --git a/jni/linux/mozilla-headers.h b/jni/linux/mozilla-headers.h
new file mode 100644
index 0000000..6259b41
--- /dev/null
+++ b/jni/linux/mozilla-headers.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+// include all of the necessary Mozilla headers.
+#include "mozilla-config.h"
+#include "nsIServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsICategoryManager.h"
+#include "nsIScriptNameSpaceManager.h"
+#include "nsIScriptObjectOwner.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsIScriptContext.h"
+#include "nsIDOMWindow.h"
+#include "nsIXPConnect.h"
+#include "nsIFactory.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
diff --git a/jni/linux/prebuilt/libgwt-ll.so b/jni/linux/prebuilt/libgwt-ll.so
new file mode 100755
index 0000000..97ead651
--- /dev/null
+++ b/jni/linux/prebuilt/libgwt-ll.so
Binary files differ
diff --git a/jni/mac/JStringWrap.h b/jni/mac/JStringWrap.h
new file mode 100644
index 0000000..e17981f
--- /dev/null
+++ b/jni/mac/JStringWrap.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+#ifndef JSTRINGWRAP_H
+#define JSTRINGWRAP_H
+
+#include <jni.h>
+
+/*
+ * Wrap a Java String and automatically clean up temporary storage allocated
+ * for accessing its contents.
+ */
+struct JStringWrap
+{
+ JStringWrap(JNIEnv* env, jstring str): env(env), s(str), p(0), jp(0) { }
+ ~JStringWrap() {
+ if (p) env->ReleaseStringUTFChars(s, p);
+ if (jp) env->ReleaseStringChars(s, jp);
+ }
+ const char* str() { if (!p) p = env->GetStringUTFChars(s, 0); return p; }
+ const jchar* jstr() { if (!jp) jp = env->GetStringChars(s, 0); return jp; }
+ jsize length() { return env->GetStringLength(s); }
+private:
+ JNIEnv* env;
+ jstring s;
+ const char* p;
+ const jchar* jp;
+};
+
+#endif
diff --git a/jni/mac/Makefile b/jni/mac/Makefile
new file mode 100644
index 0000000..867b511
--- /dev/null
+++ b/jni/mac/Makefile
@@ -0,0 +1,89 @@
+# Copyright 2008 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+CC = g++
+JAVAH = javah
+
+##
+# Try a GWT_TOOLS default if it isn't set
+##
+GWT_TOOLS ?= ../../../tools
+GWT_ROOT ?= ../..
+
+##
+# The location to get .class files for javah
+##
+CLASSDIR := $(GWT_ROOT)/build/out/dev/mac/bin
+
+##
+# External SWT products.
+##
+SWT_ORIGINAL_SRC = $(GWT_TOOLS)/lib/eclipse/org.eclipse.swt.carbon-macosx-3.2.1.src.zip
+SWT_PATCH_DIR = ./swt-build
+SWT_LIBS=$(SWT_PATCH_DIR)/libswt-webkit-carbon-3235.jnilib \
+ $(SWT_PATCH_DIR)/libswt-agl-carbon-3235.jnilib \
+ $(SWT_PATCH_DIR)/libswt-carbon-3235.jnilib \
+ $(SWT_PATCH_DIR)/libswt-pi-carbon-3235.jnilib
+
+GWT_LL_LIB = libgwt-ll.jnilib
+GWT_LL_OBJS = gwt-ll.o java-dispatch.o gwt-webkit.o trace.o
+GWT_LL_JNI = gwt-webkit.h
+
+TARGETS = $(GWT_LL_LIB) $(SWT_LIBS)
+ARCHS = -arch i386 -arch ppc
+CFLAGS = -I/System/Library/Frameworks/JavaScriptCore.framework/Headers -I/System/Library/Frameworks/JavaVM.framework/Headers
+LFLAGS = -bundle -framework JavaScriptCore
+
+ALL : $(TARGETS)
+
+##
+# Unpack and patch SWT source.
+##
+$(SWT_PATCH_DIR): $(SWT_ORIGINAL_SRC) ./org.eclipse.swt/webkit.c
+ unzip $(SWT_ORIGINAL_SRC) -d $(SWT_PATCH_DIR)
+ cp ./org.eclipse.swt/webkit.c $(SWT_PATCH_DIR)
+
+##
+# Build SWT.
+##
+$(SWT_LIBS):$(SWT_PATCH_DIR)
+ make -C $(SWT_PATCH_DIR) -f make_macosx.mak
+
+##
+# Build core gwt-ll object.
+##
+gwt-ll.o : ../core/gwt-ll.cpp
+ $(CC) -c -Wall -o $@ $(ARCHS) $(CFLAGS) $<
+
+##
+# General coff target.
+##
+%.o : %.cpp
+ $(CC) -c -Wall -o $@ $(ARCHS) $(CFLAGS) $<
+
+##
+# Generate JNI Header
+##
+gwt-webkit.h : $(CLASSDIR)/com/google/gwt/dev/shell/mac/LowLevelSaf.class
+ $(JAVAH) -classpath $(CLASSDIR) -o gwt-webkit.h com.google.gwt.dev.shell.mac.LowLevelSaf
+
+##
+# Build gwt-ll library.
+##
+$(GWT_LL_LIB) : $(GWT_LL_JNI) $(GWT_LL_OBJS)
+ $(CC) -Wall -o $@ $(ARCHS) $(LFLAGS) $(GWT_LL_OBJS)
+
+clean:
+ rm -f $(GWT_LL_JNI) $(GWT_LL_OBJS) $(TARGETS)
+ rm -rf $(SWT_PATCH_DIR)
diff --git a/jni/mac/build.xml b/jni/mac/build.xml
new file mode 100755
index 0000000..66b6580
--- /dev/null
+++ b/jni/mac/build.xml
@@ -0,0 +1,18 @@
+<project name="jni-mac" default="build" basedir=".">
+ <property name="gwt.root" location="../.." />
+ <property name="project.tail" value="jni/mac" />
+ <import file="${gwt.root}/common.ant.xml" />
+
+ <target name="build" description="Builds a JNI lib">
+ <mkdir dir="${project.jni}" />
+ <!-- TODO: Actually build this from source! -->
+ <copy todir="${project.jni}">
+ <fileset dir="prebuilt" />
+ </copy>
+ </target>
+
+ <target name="clean" description="Cleans this project's intermediate and output files">
+ <delete dir="${project.build}" failonerror="false" />
+ <delete dir="${project.jni}" failonerror="false" />
+ </target>
+</project>
diff --git a/jni/mac/gwt-webkit.cpp b/jni/mac/gwt-webkit.cpp
new file mode 100644
index 0000000..477b312
--- /dev/null
+++ b/jni/mac/gwt-webkit.cpp
@@ -0,0 +1,886 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <iostream>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include "gwt-webkit.h"
+#include "JStringWrap.h"
+#include "java-dispatch.h"
+#include "trace.h"
+
+
+// http://unixjunkie.blogspot.com/2006/07/access-argc-and-argv-from-anywhere.html
+extern "C" int *_NSGetArgc(void);
+extern "C" char ***_NSGetArgv(void);
+
+/*
+ *
+ */
+JSContextRef ToJSContextRef(jint context) {
+ return reinterpret_cast<JSContextRef>(context);
+}
+
+/*
+ *
+ */
+JSValueRef ToJSValueRef(jint value) {
+ return reinterpret_cast<JSValueRef>(value);
+}
+
+/*
+ *
+ */
+JSObjectRef ToJSObjectRef(JSContextRef jsContext, jint object,
+ JSValueRef* jsException) {
+ JSValueRef jsValue = reinterpret_cast<JSValueRef>(object);
+ if (!jsValue || !JSValueIsObject(jsContext, jsValue)) {
+ return NULL;
+ }
+ return JSValueToObject(jsContext, jsValue, jsException);
+}
+
+/*
+ *
+ */
+JSObjectRef ToJSObjectRef(JSContextRef jsContext, JSValueRef jsValue,
+ JSValueRef* jsException) {
+ if (!jsValue || !JSValueIsObject(jsContext, jsValue)) {
+ return NULL;
+ }
+ return JSValueToObject(jsContext, jsValue, jsException);
+}
+
+/*
+ *
+ */
+JSObjectRef GetStringConstructor(JSContextRef jsContext,
+ JSValueRef* jsException) {
+ // This could only be cached relative to jsContext.
+ JSStringRef script = JSStringCreateWithUTF8CString("(String)");
+ JSValueRef ctorVal = JSEvaluateScript(jsContext, script, NULL, NULL, 0, jsException);
+ JSStringRelease(script);
+ return ToJSObjectRef(jsContext, ctorVal, jsException);
+}
+
+/*
+ *
+ */
+bool IsObjectOfStringConstructor(JSContextRef jsContext, JSValueRef jsValue,
+ JSValueRef* jsException) {
+ JSObjectRef jsObject = ToJSObjectRef(jsContext, jsValue, jsException);
+ if (!jsObject) {
+ return false;
+ }
+ JSObjectRef stringCtor = GetStringConstructor(jsContext, jsException);
+ if (!stringCtor) {
+ return false;
+ }
+ return JSValueIsInstanceOfConstructor(jsContext, jsObject, stringCtor,
+ jsException);
+}
+
+#if 0 // For debugging purposes only.
+void PrintJSString(JSStringRef jsString)
+{
+ size_t length = JSStringGetMaximumUTF8CStringSize(jsString);
+ char* buffer = new char[length];
+ JSStringGetUTF8CString(jsString, buffer, length);
+ std::cerr << "JSString: " << buffer << std::endl;
+ delete[] buffer;
+}
+
+void PrintJSValue(JSContextRef jsContext, JSValueRef jsValue)
+{
+ JSValueRef jsException = NULL;
+ JSStringRef jsResult = JSValueToStringCopy(jsContext, jsValue,
+ &jsException);
+ if (!jsException && jsValue) {
+ PrintJSString(jsResult);
+ } else {
+ std::cerr << "Could not convert the value to string." << std::endl;
+ }
+}
+#endif
+
+/*
+ *
+ */
+JSStringRef ToJSStringRef(JNIEnv* env, jstring jstr) {
+ if (!jstr) {
+ return NULL;
+ }
+
+ JStringWrap jstrw(env, jstr);
+ if (!jstrw.jstr()) {
+ return NULL;
+ }
+
+ return JSStringCreateWithCharacters(static_cast<const JSChar*>(jstrw.jstr()),
+ static_cast<size_t>(jstrw.length()));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsNull
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsNull(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsUndefined
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsUndefined(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getJsUndefined
+ (JNIEnv *env, jclass klass, jint context) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ return static_cast<jint>(NULL);
+ }
+
+ JSValueRef jsUndefined = JSValueMakeUndefined(jsContext);
+ JSValueProtectChecked(jsContext, jsUndefined);
+ TR_LEAVE();
+ return reinterpret_cast<jint>(jsUndefined);
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getJsNull
+ (JNIEnv *env, jclass klass, jint context) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ return static_cast<jint>(NULL);
+ }
+ JSValueRef jsNull = JSValueMakeNull(jsContext);
+ JSValueProtectChecked(jsContext, jsNull);
+ TR_LEAVE();
+ return reinterpret_cast<jint>(jsNull);
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsBoolean
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsBoolean(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsNumber
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsNumber(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsBooleanImpl
+ (JNIEnv *env, jclass klass, jint context, jboolean jValue, jintArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsValue = JSValueMakeBoolean(jsContext, static_cast<bool>(jValue));
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ JSValueProtectChecked(jsContext, jsValue);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_gcUnprotect
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ return;
+ }
+ JSValueUnprotectChecked(jsContext, jsValue);
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsNumberImpl
+ (JNIEnv *env, jclass klass, jint context, jdouble jValue, jintArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsValue = JSValueMakeNumber(jsContext, static_cast<jdouble>(jValue));
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsValue);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_executeScriptWithInfoImpl
+ (JNIEnv *env, jclass klass, jint context, jstring jScript, jstring jUrl,
+ jint jLine, jintArray rval) {
+ TR_ENTER();
+ JSValueRef jsException = NULL;
+
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRef jsScript = ToJSStringRef(env, jScript);
+ if (!jsScript) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRef jsUrl = ToJSStringRef(env, jUrl);
+
+ // Evaluate will set this to global object.
+ JSValueRef jsResult = JSEvaluateScript(jsContext, jsScript, NULL, jsUrl,
+ static_cast<int>(jLine), &jsException);
+ if (jsException) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRelease(jsScript);
+ if (jsUrl) {
+ JSStringRelease(jsUrl);
+ }
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsResult));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsResult);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsStringImpl
+ (JNIEnv *env, jclass klass, jint context, jstring jValue, jintArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRef jsString = ToJSStringRef(env, jValue);
+ if (!jsString) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsValue = JSValueMakeString(jsContext, jsString);
+ JSStringRelease(jsString);
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsValue);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsStringImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ bool isString = JSValueIsString(jsContext, jsValue);
+ if (!isString) {
+ JSValueRef jsException = NULL;
+ isString = IsObjectOfStringConstructor(jsContext, jsValue, &jsException);
+ if (jsException) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ }
+
+ jboolean jIsString = static_cast<jboolean>(isString);
+ env->SetBooleanArrayRegion(rval, 0, 1, &jIsString);
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_invokeImpl
+ (JNIEnv *env, jclass klass, jint context, jint scriptValue,
+ jstring jMethodName, jint thisVal, jintArray jArgs, jint jArgsLength,
+ jintArray rval) {
+ TR_ENTER();
+
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSObjectRef jsScriptObj = ToJSObjectRef(jsContext, scriptValue, NULL);
+ if (!jsScriptObj) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsThisVal = ToJSValueRef(thisVal);
+ JSObjectRef jsThisObj = NULL;
+ // If thisVal is null, jsNull, or jsUndefined use the script object
+ // as this.
+ if (!jsThisVal || JSValueIsNull(jsContext, jsThisVal)
+ || JSValueIsUndefined(jsContext, jsThisVal)) {
+ jsThisObj = jsScriptObj;
+ } else {
+ // If we are given a value, ensure that it is an object.
+ jsThisObj = ToJSObjectRef(jsContext, jsThisVal, NULL);
+ if (!jsThisObj) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ }
+
+ JSStringRef jsMethodName = ToJSStringRef(env, jMethodName);
+ if (!jsMethodName) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSObjectRef jsMethod = ToJSObjectRef(jsContext, JSObjectGetProperty(jsContext,
+ jsScriptObj, jsMethodName, NULL), NULL);
+ if (!jsMethod || !JSObjectIsFunction(jsContext, jsMethod)) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRelease(jsMethodName);
+
+ // NOTE (knorton): Fix for 64-bit.
+ JSValueRef* jsArgs = new JSValueRef[static_cast<size_t>(jArgsLength)];
+ env->GetIntArrayRegion(jArgs, 0, jArgsLength,
+ reinterpret_cast<jint*>(jsArgs));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ delete[] jsArgs;
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsException = NULL;
+ JSValueRef jsResult = JSObjectCallAsFunction(jsContext, jsMethod, jsThisObj,
+ static_cast<size_t>(jArgsLength), jsArgs, &jsException);
+ if (jsException) {
+ TR_FAIL();
+ delete[] jsArgs;
+ return JNI_FALSE;
+ }
+ delete[] jsArgs;
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsResult));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsResult);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsObject
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsObject(jsContext, jsValue));
+}
+
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toBooleanImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ jboolean jResult = static_cast<jboolean>(JSValueToBoolean(jsContext, jsValue));
+ env->SetBooleanArrayRegion(rval, 0, 1, &jResult);
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toDoubleImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jdoubleArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsException = NULL;
+ double result = JSValueToNumber(jsContext, jsValue, &jsException);
+ if (jsException) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ env->SetDoubleArrayRegion(rval, 0, 1, static_cast<jdouble*>(&result));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toStringImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jobjectArray rval) {
+ TR_ENTER();
+ JSValueRef jsException = NULL;
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ jstring jResult = NULL;
+ // Convert all objects to their string representation, EXCEPT
+ // null and undefined which will be returned as a true NULL.
+ if (!JSValueIsNull(jsContext, jsValue) &&
+ !JSValueIsUndefined(jsContext, jsValue)) {
+ JSStringRef jsResult = JSValueToStringCopy(jsContext, jsValue, &jsException);
+ if (jsException) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ jResult = env->NewString(
+ static_cast<const jchar*>(JSStringGetCharactersPtr(jsResult)),
+ static_cast<jsize>(JSStringGetLength(jsResult)));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRelease(jsResult);
+ }
+
+ env->SetObjectArrayElement(rval, 0, jResult);
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_wrapDispatchObjectImpl
+ (JNIEnv *env, jclass klass, jint context, jobject dispatch, jintArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSObjectRef jsDispatch = gwt::DispatchObjectCreate(jsContext, dispatch);
+ if (!jsDispatch || env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsDispatch));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsDispatch);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_unwrapDispatchObjectImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jobjectArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ if (!JSValueIsObjectOfClass(jsContext, jsValue, gwt::GetDispatchObjectClass())) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSObjectRef jsObject = ToJSObjectRef(jsContext, jsValue, NULL);
+ if (!jsObject) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ env->SetObjectArrayElement(rval, 0, reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject)));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_initImpl
+ (JNIEnv *env, jclass klass, jclass dispatchObjectClass,
+ jclass dispatchMethodClass, jclass lowLevelSafClass) {
+ TR_ENTER();
+ TR_LEAVE();
+ return static_cast<jboolean>(gwt::Initialize(env, dispatchObjectClass, dispatchMethodClass, lowLevelSafClass));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_wrapDispatchMethodImpl
+ (JNIEnv *env, jclass klass, jint context, jstring name, jobject jDispatch,
+ jintArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JStringWrap nameWrap(env, name);
+ std::string nameStr(nameWrap.str());
+ JSObjectRef jsDispatch = gwt::DispatchMethodCreate(jsContext, nameStr,
+ jDispatch);
+ if (!jsDispatch || env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsDispatch));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsDispatch);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getTypeString
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ return NULL;
+ }
+
+ switch (JSValueGetType(jsContext, jsValue)) {
+ case kJSTypeUndefined:
+ return env->NewStringUTF("undefined");
+ case kJSTypeNull:
+ return env->NewStringUTF("null");
+ case kJSTypeBoolean:
+ return env->NewStringUTF("boolean");
+ case kJSTypeNumber:
+ return env->NewStringUTF("number");
+ case kJSTypeString:
+ return env->NewStringUTF("string");
+ case kJSTypeObject:
+ return (JSValueIsObjectOfClass(jsContext, jsValue, gwt::GetDispatchObjectClass()))
+ ? env->NewStringUTF("Java object") : env->NewStringUTF("JavaScript object");
+ default:
+ return env->NewStringUTF("unknown");
+ }
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isDispatchObjectImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ jboolean jIsDispatchObject = static_cast<jboolean>(JSValueIsObjectOfClass(
+ jsContext, jsValue, gwt::GetDispatchObjectClass()));
+ env->SetBooleanArrayRegion(rval, 0, 1, &jIsDispatchObject);
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getArgc
+ (JNIEnv *env, jclass klass) {
+ return *_NSGetArgc();
+}
+
+/*
+ *
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getArgv
+ (JNIEnv *env, jclass klass, jint index) {
+ int argc = *_NSGetArgc();
+ if (index < 0 || index >= argc) {
+ return 0;
+ }
+ char **argv = *_NSGetArgv();
+ return env->NewStringUTF(argv[index]);
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getGlobalJsObjectImpl
+ (JNIEnv *env, jclass klass, jint context, jintArray rval) {
+ TR_ENTER();
+
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSObjectRef jsGlobalObject = JSContextGetGlobalObject(jsContext);
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsGlobalObject));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsGlobalObject);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_gcProtect
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ return;
+ }
+
+ JSValueProtectChecked(jsContext, jsValue);
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_retainJsGlobalContext
+ (JNIEnv *env, jclass klass, jint context) {
+ TR_ENTER();
+ JSGlobalContextRef jsContext = reinterpret_cast<JSGlobalContextRef>(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return;
+ }
+ JSGlobalContextRetain(jsContext);
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_releaseJsGlobalContext
+ (JNIEnv *env, jclass klass, jint context) {
+ TR_ENTER();
+ JSGlobalContextRef jsContext = reinterpret_cast<JSGlobalContextRef>(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return;
+ }
+ JSGlobalContextRelease(jsContext);
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isGcProtected
+ (JNIEnv *env, jclass klass, jint value) {
+ JSValueRef jsValue = ToJSValueRef(value);
+ TR_ENTER();
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsProtected(jsValue));
+}
+
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsValueProtectionCheckingEnabledImpl
+ (JNIEnv *env, jclass klass) {
+ TR_ENTER();
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueProtectCheckingIsEnabled());
+}
diff --git a/jni/mac/java-dispatch.cpp b/jni/mac/java-dispatch.cpp
new file mode 100644
index 0000000..fafab11
--- /dev/null
+++ b/jni/mac/java-dispatch.cpp
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include <sstream>
+#include "jni.h"
+#include "java-dispatch.h"
+#include "trace.h"
+#include "JStringWrap.h"
+
+namespace gwt {
+
+ /*
+ * Declarations for private functions.
+ */
+ JSClassRef DispatchObjectClassCreate();
+
+ JSClassRef DispatchMethodClassCreate();
+
+ JSValueRef DispatchObjectGetProperty(JSContextRef, JSObjectRef, JSStringRef,
+ JSValueRef*);
+
+ JSValueRef DispatchObjectToString(JSContextRef, JSObjectRef, JSObjectRef,
+ size_t, const JSValueRef*, JSValueRef*);
+
+ bool DispatchObjectSetProperty(JSContextRef, JSObjectRef, JSStringRef,
+ JSValueRef, JSValueRef*);
+
+ void DispatchObjectFinalize(JSObjectRef);
+
+ JSValueRef DispatchMethodCallAsFunction(JSContextRef, JSObjectRef,
+ JSObjectRef, size_t,
+ const JSValueRef*, JSValueRef*);
+
+ JSValueRef DispatchMethodGetToString(JSContextRef, JSObjectRef, JSStringRef,
+ JSValueRef*);
+
+ JSValueRef DispatchMethodToString(JSContextRef, JSObjectRef, JSObjectRef,
+ size_t, const JSValueRef*, JSValueRef*);
+
+ void DispatchMethodFinalize(JSObjectRef);
+
+ /*
+ * Call this when an underlying Java Object should be freed.
+ */
+ void ReleaseJavaObject(jobject jObject);
+
+
+ /*
+ * The class definition stuct for DispatchObjects.
+ */
+ static JSClassDefinition _dispatchObjectClassDef = { 0,
+ kJSClassAttributeNone, "DispatchObject", 0, 0, 0, 0,
+ DispatchObjectFinalize, 0, DispatchObjectGetProperty,
+ DispatchObjectSetProperty, 0, 0, 0, 0, 0, 0 };
+
+ /*
+ * The class definition structs for DispatchMethods.
+ */
+ static JSStaticValue _dispatchMethodStaticValues[] = {
+ { "toString", DispatchMethodGetToString, 0, kJSPropertyAttributeNone },
+ { 0, 0, 0, 0 }
+ };
+ static JSClassDefinition _dispatchMethodClassDef = { 0,
+ kJSClassAttributeNoAutomaticPrototype, "DispatchMethod", 0,
+ _dispatchMethodStaticValues, 0, 0, DispatchMethodFinalize, 0, 0, 0, 0,
+ 0, DispatchMethodCallAsFunction, 0, 0, 0 };
+
+ /*
+ * The classes used to create DispatchObjects and DispatchMethods.
+ */
+ static JSClassRef _dispatchObjectClass = DispatchObjectClassCreate();
+ static JSClassRef _dispatchMethodClass = DispatchMethodClassCreate();
+
+ /*
+ * Java class and method references needed to do delegation.
+ */
+
+ /*
+ * The main JVM, used by foreign threads to attach.
+ */
+ static JavaVM* _javaVM;
+
+ /*
+ * Only valid for the main thread! WebKit can finalized on a foreign thread.
+ */
+ static JNIEnv* _javaEnv;
+
+ static jclass _javaDispatchObjectClass;
+ static jclass _javaDispatchMethodClass;
+ static jclass _lowLevelSafClass;
+ static jmethodID _javaDispatchObjectSetFieldMethod;
+ static jmethodID _javaDispatchObjectGetFieldMethod;
+ static jmethodID _javaDispatchMethodInvokeMethod;
+ static jmethodID _javaDispatchObjectToStringMethod;
+ static jmethodID _lowLevelSafReleaseObject;
+
+ /*
+ * Structure to hold DispatchMethod private data.
+ *
+ * NOTE: utf8Name is defensively copied.
+ */
+ class DispatchMethodData {
+ public:
+ DispatchMethodData(jobject jObject, std::string& utf8Name)
+ : _jObject(jObject), _utf8Name(utf8Name) { }
+ ~DispatchMethodData() {
+ ReleaseJavaObject(_jObject);
+ }
+ jobject _jObject;
+ std::string _utf8Name;
+ };
+
+/*
+ * The following takes the prototype from the Function constructor, this allows
+ * us to easily support call and apply on our objects that support CallAsFunction.
+ *
+ * NOTE: The return value is not protected.
+ */
+JSValueRef GetFunctionPrototype(JSContextRef jsContext, JSValueRef* exception) {
+ TR_ENTER();
+ JSObjectRef globalObject = JSContextGetGlobalObject(jsContext);
+ JSStringRef fnPropName= JSStringCreateWithUTF8CString("Function");
+ JSValueRef fnCtorValue = JSObjectGetProperty(jsContext, globalObject,
+ fnPropName, exception);
+ JSStringRelease(fnPropName);
+ if (!fnCtorValue) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ JSObjectRef fnCtorObject = JSValueToObject(jsContext, fnCtorValue, exception);
+ if (!fnCtorObject) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ JSStringRef protoPropName = JSStringCreateWithUTF8CString("prototype");
+ JSValueRef fnPrototype = JSObjectGetProperty(jsContext, fnCtorObject,
+ protoPropName, exception);
+ JSStringRelease(protoPropName);
+ if (!fnPrototype) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ TR_LEAVE();
+ return fnPrototype;
+}
+
+/*
+ *
+ */
+JSClassRef GetDispatchObjectClass() {
+ TR_ENTER();
+ TR_LEAVE();
+ return _dispatchObjectClass;
+}
+
+/*
+ *
+ */
+JSClassRef GetDispatchMethodClass() {
+ TR_ENTER();
+ TR_LEAVE();
+ return _dispatchMethodClass;
+}
+
+/*
+ *
+ */
+JSClassRef DispatchObjectClassCreate() {
+ TR_ENTER();
+ JSClassRef dispClass = JSClassCreate(&_dispatchObjectClassDef);
+ JSClassRetain(dispClass);
+ TR_LEAVE();
+ return dispClass;
+}
+
+/*
+ *
+ */
+JSClassRef DispatchMethodClassCreate() {
+ TR_ENTER();
+ JSClassRef dispClass = JSClassCreate(&_dispatchMethodClassDef);
+ JSClassRetain(dispClass);
+ TR_LEAVE();
+ return dispClass;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSObjectRef DispatchObjectCreate(JSContextRef jsContext, jobject jObject) {
+ TR_ENTER();
+ JSObjectRef dispInst = JSObjectMake(jsContext, _dispatchObjectClass,
+ _javaEnv->NewGlobalRef(jObject));
+ TR_LEAVE();
+ return dispInst;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSObjectRef DispatchMethodCreate(JSContextRef jsContext, std::string& name,
+ jobject jObject) {
+ TR_ENTER();
+
+ JSObjectRef dispInst = JSObjectMake(jsContext, _dispatchMethodClass,
+ new DispatchMethodData(_javaEnv->NewGlobalRef(jObject), name));
+
+ // This could only be cached relative to jsContext.
+ JSValueRef fnProtoValue = GetFunctionPrototype(jsContext, NULL);
+ JSObjectSetPrototype(jsContext, dispInst, fnProtoValue);
+ TR_LEAVE();
+ return dispInst;
+}
+
+/*
+ * NOTE: The value returned from this function is not protected, but all
+ * JSValues that are passed into Java are protected before the invocation.
+ */
+JSValueRef DispatchObjectGetProperty(JSContextRef jsContext,
+ JSObjectRef jsObject, JSStringRef jsPropertyName,
+ JSValueRef* jsException) {
+ TR_ENTER();
+
+ // If you call toString on a DispatchObject, you should get the results
+ // of the java object's toString invcation.
+ if (JSStringIsEqualToUTF8CString(jsPropertyName, "toString")) {
+ JSObjectRef jsFunction = JSObjectMakeFunctionWithCallback(jsContext,
+ jsPropertyName, DispatchObjectToString);
+ return jsFunction;
+ }
+
+ // The class check is omitted because it should not be possible to tear off
+ // a getter.
+ jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+
+ jstring jPropertyName = _javaEnv->NewString(
+ static_cast<const jchar*>(JSStringGetCharactersPtr(jsPropertyName)),
+ static_cast<jsize>(JSStringGetLength(jsPropertyName)));
+ if (!jObject || !jPropertyName || _javaEnv->ExceptionCheck()) {
+ TR_FAIL();
+ _javaEnv->ExceptionClear();
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ JSValueRef jsResult = reinterpret_cast<JSValueRef>(
+ _javaEnv->CallIntMethod(jObject, _javaDispatchObjectGetFieldMethod,
+ reinterpret_cast<jint>(jsContext),
+ jPropertyName));
+ if (!jsResult || _javaEnv->ExceptionCheck()) {
+ TR_FAIL();
+ _javaEnv->ExceptionClear();
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ // Java left us an extra reference to eat.
+ JSValueUnprotectChecked(jsContext, jsResult);
+ TR_LEAVE();
+ return jsResult;
+}
+
+/*
+ *
+ */
+bool DispatchObjectSetProperty(JSContextRef jsContext, JSObjectRef jsObject,
+ JSStringRef jsPropertyName, JSValueRef jsValue, JSValueRef* jsException) {
+ TR_ENTER();
+
+ // The class check is omitted because it should not be possible to tear off
+ // a getter.
+ jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+
+ jstring jPropertyName = _javaEnv->NewString(
+ static_cast<const jchar*>(JSStringGetCharactersPtr(jsPropertyName)),
+ static_cast<jsize>(JSStringGetLength(jsPropertyName)));
+ if (!jObject || !jPropertyName || _javaEnv->ExceptionCheck()) {
+ _javaEnv->ExceptionClear();
+ return false;
+ }
+
+ JSValueProtectChecked(jsContext, jsValue);
+
+ _javaEnv->CallIntMethod(jObject, _javaDispatchObjectSetFieldMethod,
+ reinterpret_cast<jint>(jsContext), jPropertyName,
+ reinterpret_cast<jint>(jsValue));
+ if (_javaEnv->ExceptionCheck()) {
+ _javaEnv->ExceptionClear();
+ return false;
+ }
+
+ TR_LEAVE();
+ return true;
+}
+
+/*
+ *
+ */
+void DispatchObjectFinalize(JSObjectRef jsObject) {
+ TR_ENTER();
+ jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+ ReleaseJavaObject(jObject);
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+void DispatchMethodFinalize(JSObjectRef jsObject) {
+ TR_ENTER();
+ DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+ JSObjectGetPrivate(jsObject));
+ delete data;
+ TR_LEAVE();
+}
+
+/*
+ * NOTE: The value returned from this function is not protected.
+ */
+JSValueRef DispatchObjectToString(JSContextRef jsContext, JSObjectRef,
+ JSObjectRef jsThis, size_t, const JSValueRef*, JSValueRef*) {
+ TR_ENTER();
+
+ // This function cannot be torn off and applied to any JSValue. If this does
+ // not reference a DispatchObject, return undefined.
+ if (!JSValueIsObjectOfClass(jsContext, jsThis, GetDispatchObjectClass())) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsThis));
+ jstring jResult = reinterpret_cast<jstring>(
+ _javaEnv->CallObjectMethod(jObject, _javaDispatchObjectToStringMethod));
+ if (_javaEnv->ExceptionCheck()) {
+ return JSValueMakeUndefined(jsContext);
+ } else if (!jResult) {
+ return JSValueMakeNull(jsContext);
+ } else {
+ JStringWrap result(_javaEnv, jResult);
+ JSStringRef resultString = JSStringCreateWithCharacters(
+ static_cast<const JSChar*>(result.jstr()),
+ static_cast<size_t>(result.length()));
+ JSValueRef jsResultString = JSValueMakeString(jsContext, resultString);
+ JSStringRelease(resultString);
+ return jsResultString;
+ }
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+JSValueRef DispatchMethodCallAsFunction(JSContextRef jsContext,
+ JSObjectRef jsFunction, JSObjectRef jsThis, size_t argumentCount,
+ const JSValueRef arguments[], JSValueRef* exception) {
+ TR_ENTER();
+
+ // We don't need to check the class here because we take the private
+ // data from jsFunction and not jsThis.
+
+ DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+ JSObjectGetPrivate(jsFunction));
+ jobject jObject = data->_jObject;
+
+ jintArray jArguments = _javaEnv->NewIntArray(argumentCount);
+ if (!jArguments || _javaEnv->ExceptionCheck()) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ // This single element int array will be passed into the java call to allow the
+ // called java method to raise an exception. We will check for a non-null value
+ // after the call is dispatched.
+ jintArray jException = _javaEnv->NewIntArray(1);
+ if (!jException || _javaEnv->ExceptionCheck()) {
+ return JNI_FALSE;
+ }
+
+ for (size_t i = 0; i < argumentCount; ++i) {
+ JSValueRef arg = arguments[i];
+ // Java will take ownership of the arguments.
+ JSValueProtectChecked(jsContext, arg);
+ _javaEnv->SetIntArrayRegion(jArguments, i, 1, reinterpret_cast<jint*>(&arg));
+ if (_javaEnv->ExceptionCheck()) {
+ return JSValueMakeUndefined(jsContext);
+ }
+ }
+
+ // Java will take ownership of this.
+ JSValueProtectChecked(jsContext, jsThis);
+
+ JSValueRef jsResult = reinterpret_cast<JSValueRef>(_javaEnv->CallIntMethod(jObject,
+ _javaDispatchMethodInvokeMethod, reinterpret_cast<jint>(jsContext),
+ reinterpret_cast<jint>(jsThis), jArguments, jException));
+ if (_javaEnv->ExceptionCheck()) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ JSValueRef jsException = NULL;
+ _javaEnv->GetIntArrayRegion(jException, 0, 1, reinterpret_cast<jint*>(&jsException));
+ if (!_javaEnv->ExceptionCheck() && jsException) {
+ // If the java dispatch set an exception, then we pass it back to our caller.
+ if (exception) {
+ *exception = jsException;
+ }
+ // Java left us an extra reference to eat.
+ JSValueUnprotectChecked(jsContext, jsException);
+ }
+
+ // Java left us an extra reference to eat.
+ JSValueUnprotectChecked(jsContext, jsResult);
+ TR_LEAVE();
+ return jsResult;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSValueRef DispatchMethodToString(JSContextRef jsContext, JSObjectRef,
+ JSObjectRef thisObject, size_t, const JSValueRef*, JSValueRef*) {
+ TR_ENTER();
+
+ // This function cannot be torn off and applied to any JSValue. If this does
+ // not reference a DispatchMethod, return undefined.
+ if (!JSValueIsObjectOfClass(jsContext, thisObject, GetDispatchMethodClass())) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ std::ostringstream ss;
+ DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+ JSObjectGetPrivate(thisObject));
+ ss << "function " << data->_utf8Name << "() {\n [native code]\n}\n";
+ JSStringRef stringRep = JSStringCreateWithUTF8CString(ss.str().c_str());
+ JSValueRef jsStringRep = JSValueMakeString(jsContext, stringRep);
+ JSStringRelease(stringRep);
+ TR_LEAVE();
+ return jsStringRep;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSValueRef DispatchMethodGetToString(JSContextRef jsContext,
+ JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef* jsException) {
+ TR_ENTER();
+ JSObjectRef toStringFn = JSObjectMakeFunctionWithCallback(jsContext,
+ jsPropertyName, DispatchMethodToString);
+ TR_LEAVE();
+ return toStringFn;
+}
+
+/*
+ *
+ */
+bool Initialize(JNIEnv* javaEnv, jclass javaDispatchObjectClass,
+ jclass javaDispatchMethodClass, jclass lowLevelSafClass) {
+ TR_ENTER();
+ if (!javaEnv || !javaDispatchObjectClass || !javaDispatchMethodClass
+ || !lowLevelSafClass) {
+ return false;
+ }
+
+ _javaVM = 0;
+ javaEnv->GetJavaVM(&_javaVM);
+
+ _javaEnv = javaEnv;
+ _javaDispatchObjectClass = static_cast<jclass>(
+ javaEnv->NewGlobalRef(javaDispatchObjectClass));
+ _javaDispatchMethodClass = static_cast<jclass>(
+ javaEnv->NewGlobalRef(javaDispatchMethodClass));
+ _lowLevelSafClass = static_cast<jclass>(
+ javaEnv->NewGlobalRef(lowLevelSafClass));
+ _javaDispatchObjectSetFieldMethod = javaEnv->GetMethodID(
+ javaDispatchObjectClass, "setField", "(ILjava/lang/String;I)V");
+ _javaDispatchObjectGetFieldMethod = javaEnv->GetMethodID(
+ javaDispatchObjectClass, "getField", "(ILjava/lang/String;)I");
+ _javaDispatchMethodInvokeMethod = javaEnv->GetMethodID(
+ javaDispatchMethodClass, "invoke", "(II[I[I)I");
+ _javaDispatchObjectToStringMethod = javaEnv->GetMethodID(
+ javaDispatchObjectClass, "toString", "()Ljava/lang/String;");
+ _lowLevelSafReleaseObject = javaEnv->GetStaticMethodID(
+ lowLevelSafClass, "releaseObject", "(Ljava/lang/Object;)V");
+
+ if (!_javaVM
+ || !_javaDispatchObjectSetFieldMethod || !_javaDispatchObjectGetFieldMethod
+ || !_javaDispatchMethodInvokeMethod || !_javaDispatchObjectToStringMethod
+ || !_lowLevelSafReleaseObject || javaEnv->ExceptionCheck()) {
+ return false;
+ }
+
+ TR_LEAVE();
+ return true;
+}
+
+void ReleaseJavaObject(jobject jObject) {
+ // Tricky: this call may be on a foreign thread.
+ JNIEnv* javaEnv = 0;
+ if ((_javaVM->AttachCurrentThreadAsDaemon(reinterpret_cast<void**>(&javaEnv),
+ NULL) < 0) || !javaEnv) {
+ TR_FAIL();
+ return;
+ }
+
+ // Tell the Java code we're done with this object.
+ javaEnv->CallStaticVoidMethod(_lowLevelSafClass, _lowLevelSafReleaseObject,
+ jObject);
+ if (javaEnv->ExceptionCheck()) {
+ TR_FAIL();
+ return;
+ }
+ javaEnv->DeleteGlobalRef(jObject);
+}
+
+} // namespace gwt
diff --git a/jni/mac/java-dispatch.h b/jni/mac/java-dispatch.h
new file mode 100644
index 0000000..f8fa80b
--- /dev/null
+++ b/jni/mac/java-dispatch.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef JAVA_DISPATCHER_H__
+#define JAVA_DISPATCHER_H__
+#include <iostream>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <jni.h>
+
+namespace gwt {
+
+/*
+ * Initializes static members needed by DispatchObject, DispatchMethod,
+ * and LowLevelSaf. This should be called before before calling anything
+ * else.
+ */
+bool Initialize(JNIEnv*, jclass, jclass, jclass);
+
+/*
+ * Returns a shared reference to the DispatchObject class
+ */
+JSClassRef GetDispatchObjectClass();
+
+/*
+ * Constructs a new DispatchObject.
+ *
+ * jContext - the JavaScript context
+ * jObject - the java instance of DispatchObject to which
+ * this instance will dispatch calls
+ */
+JSObjectRef DispatchObjectCreate(JSContextRef jContext, jobject jObject);
+
+/*
+ * Returns a shared reference to the DispatchMethod class
+ */
+JSClassRef GetDispatchMethodClass();
+
+/*
+ * Constructs a new DispatchMethod object.
+ *
+ * jsContext - the JavaScript context
+ * name - the name of the method (used in toString)
+ * jObject - the java instance of DispatchMethod to which this object will
+ * delegate calls.
+ */
+JSObjectRef DispatchMethodCreate(JSContextRef jsContext, std::string& name,
+ jobject jObject);
+
+
+} // namespace gwt
+
+#endif // JAVA_DISPATCHER_H__
diff --git a/jni/mac/org.eclipse.swt/webkit.c b/jni/mac/org.eclipse.swt/webkit.c
new file mode 100644
index 0000000..3b704ec
--- /dev/null
+++ b/jni/mac/org.eclipse.swt/webkit.c
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+// Modified by Google
+#include <Carbon/Carbon.h>
+#include <WebKit/WebKit.h>
+#include <WebKit/HIWebView.h>
+
+#include "jni.h"
+
+JNIEXPORT void JNICALL Java_org_eclipse_swt_browser_WebKit_WebInitForCarbon(JNIEnv *env, jclass zz) {
+ WebInitForCarbon();
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_HIWebViewCreate(JNIEnv *env, jclass zz, jintArray outView) {
+ jint *a = (*env)->GetIntArrayElements(env, outView, NULL);
+ jint status = (jint) HIWebViewCreate((HIViewRef *)a);
+ (*env)->ReleaseIntArrayElements(env, outView, a, 0);
+ return status;
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_HIWebViewGetWebView(JNIEnv *env, jclass zz, jint viewRef) {
+ return (jint) HIWebViewGetWebView((HIViewRef)viewRef);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__II(JNIEnv *env, jclass zz, jint obj, jint sel) {
+ return (jint) objc_msgSend((void *)obj, (void *)sel);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__III(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0) {
+ return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1) {
+ return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1, jint arg2) {
+ return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1, (void *)arg2);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIIIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1, jint arg2, jint arg3) {
+ return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1, (void *)arg2, (void *)arg3);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1getClass(JNIEnv *env, jclass zz, jbyteArray name) {
+ jbyte *a = (*env)->GetByteArrayElements(env, name, NULL);
+ jint id = (jint) objc_getClass((const char *)a);
+ (*env)->ReleaseByteArrayElements(env, name, a, 0);
+ return id;
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_sel_1registerName(JNIEnv *env, jclass zz, jbyteArray name) {
+ jbyte *a= (*env)->GetByteArrayElements(env, name, NULL);
+ jint sel= (jint) sel_registerName((const char *)a);
+ (*env)->ReleaseByteArrayElements(env, name, a, 0);
+ return sel;
+}
+
+@interface WebKitDelegate : NSObject
+{
+ int user_data;
+ int (*proc) (int sender, int user_data, int selector, int arg0, int arg1, int arg2, int arg3);
+}
+@end
+
+@implementation WebKitDelegate
+
+- (id)initWithProc:(id)prc user_data:(int)data
+{
+ [super init];
+ proc= (void *) prc;
+ user_data = data;
+ return self;
+}
+
+/* WebFrameLoadDelegate */
+
+- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 1, (int)error, (int)frame, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 2, (int)frame, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 3, (int)title, (int)frame, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 4, (int)frame, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 10, (int)frame, 0, 0, 0);
+}
+
+/* WebResourceLoadDelegate */
+
+- (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource
+{
+ proc((int)sender, user_data, 5, (int)identifier, (int)dataSource, 0, 0);
+}
+
+- (void)webView:(WebView *)sender resource:(id)identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource
+{
+ proc((int)sender, user_data, 6, (int)identifier, (int)error, (int)dataSource, 0);
+}
+
+- (id)webView:(WebView *)sender identifierForInitialRequest:(NSURLRequest *)request fromDataSource:(WebDataSource *)dataSource
+{
+ return (id) proc((int)sender, user_data, 7, (int)request, (int)dataSource, 0, 0);
+}
+
+- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource
+{
+ return (NSURLRequest *) proc((int)sender, user_data, 8, (int)identifier, (int)request, (int)redirectResponse, (int)dataSource);
+}
+
+/* handleNotification */
+
+- (void)handleNotification:(NSNotification *)notification
+{
+ proc((int)[notification object], user_data, 9, (int)notification, 0, 0, 0);
+}
+
+/* UIDelegate */
+
+- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request
+{
+ return (WebView *) proc((int)sender, user_data, 11, (int)request, 0, 0, 0);
+}
+
+- (void)webViewShow:(WebView *)sender
+{
+ proc((int)sender, user_data, 12, 0, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setFrame:(NSRect)frame
+{
+ proc((int)sender, user_data, 13, (int)&frame, 0, 0, 0);
+}
+
+- (void)webViewClose:(WebView *)sender
+{
+ proc((int)sender, user_data, 14, 0, 0, 0, 0);
+}
+
+- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems
+{
+ return (NSArray *)proc((int)sender, user_data, 15, (int)element, (int)defaultMenuItems, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setStatusBarVisible:(BOOL)visible
+{
+ proc((int)sender, user_data, 16, (int)visible, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setResizable:(BOOL)resizable
+{
+ proc((int)sender, user_data, 17, (int)resizable, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setToolbarsVisible:(BOOL)visible
+{
+ proc((int)sender, user_data, 18, (int)visible, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setStatusText:(NSString *)text
+{
+ proc((int)sender, user_data, 23, (int)text, 0, 0, 0);
+}
+
+- (void)webViewFocus:(WebView *)sender
+{
+ proc((int)sender, user_data, 24, 0, 0, 0, 0);
+}
+
+- (void)webViewUnfocus:(WebView *)sender
+{
+ proc((int)sender, user_data, 25, 0, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message
+{
+ proc((int)sender, user_data, 26, (int)message, 0, 0, 0);
+}
+
+- (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message
+{
+ return (BOOL) proc((int)sender, user_data, 27, (int)message, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)resultListener
+{
+ proc((int)sender, user_data, 28, (int)resultListener, 0, 0, 0);
+}
+
+/* WebPolicyDelegate */
+- (void)webView:(WebView *)sender decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame*)frame decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+ proc((int)sender, user_data, 19, (int)type, (int)request, (int)frame, (int)listener);
+}
+
+- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+ proc((int)sender, user_data, 20, (int)actionInformation, (int)request, (int)frame, (int)listener);
+}
+
+
+- (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+ proc((int)sender, user_data, 21, (int)actionInformation, (int)request, (int)frameName, (int)listener);
+}
+
+
+- (void)webView:(WebView *)sender unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 22, (int)error, (int)frame, 0, 0);
+}
+
+/* WebDownload */
+
+- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
+{
+ proc((int)download, user_data, 29, (int)download, (int)filename, 0, 0);
+}
+
+// GOOGLE: we need a notification when the window object is available so we can
+// setup our own hooks before any JavaScript runs.
+- (void)webView:(WebView *)sender windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject
+{
+ proc((int)sender, user_data, 99, (int)windowScriptObject, 0, 0, 0);
+}
+
+@end
+
diff --git a/jni/mac/prebuilt/libgwt-ll.jnilib b/jni/mac/prebuilt/libgwt-ll.jnilib
new file mode 100755
index 0000000..5a4030f
--- /dev/null
+++ b/jni/mac/prebuilt/libgwt-ll.jnilib
Binary files differ
diff --git a/jni/mac/trace.cpp b/jni/mac/trace.cpp
new file mode 100644
index 0000000..2127351
--- /dev/null
+++ b/jni/mac/trace.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <iostream>
+#include <map>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include "trace.h"
+
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+static std::map<JSValueRef, int> _protectMap;
+#endif
+
+/*
+ *
+ */
+void JSValueProtectChecked(JSContextRef jsContext, JSValueRef jsValue) {
+ JSValueProtect(jsContext, jsValue);
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+ _protectMap[jsValue]++;
+#endif
+}
+
+/*
+ *
+ */
+void JSValueUnprotectChecked(JSContextRef jsContext, JSValueRef jsValue) {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+ // Unrecord in a hash_map
+ unsigned count = _protectMap[jsValue];
+ if (count == 0) {
+ std::cerr << "[WARNING] JSValueUnprotect called on unprotected JSValueRef (0x"
+ << std::hex << ((unsigned)jsValue) << ")" << std::endl;
+ return;
+ }
+ _protectMap[jsValue] = count - 1;
+#else
+ JSValueUnprotect(jsContext, jsValue);
+#endif
+}
+
+bool JSValueIsProtected(JSValueRef jsValue) {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+ return _protectMap[jsValue] > 0;
+#else
+ return true;
+#endif
+}
+
+bool JSValueProtectCheckingIsEnabled() {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/jni/mac/trace.h b/jni/mac/trace.h
new file mode 100644
index 0000000..e58ca96
--- /dev/null
+++ b/jni/mac/trace.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef TRACE_H__
+#define TRACE_H__
+#include <iostream>
+#include <map>
+
+// Uncomment to trace enter, exit and fail for all native calls.
+// #define ENABLE_CALL_TRACE
+
+// Uncomment to double check that JSValueRef's are protected and
+// unprotected properly.
+// #define ENABLE_JSVALUE_PROTECTION_CHECKING
+
+#ifdef ENABLE_CALL_TRACE
+#define TR_ENTER() std::cout << "ENTER " << __PRETTY_FUNCTION__ << std::endl
+#define TR_LEAVE() std::cout << "LEAVE " << __PRETTY_FUNCTION__ << std::endl
+#define TR_FAIL() std::cout << "FAIL " << __FILE__ << "@" << __LINE__ \
+ << std::endl;
+#else
+#define TR_ENTER()
+#define TR_LEAVE()
+#define TR_FAIL()
+#endif // ENABLE_CALL_TRACE
+
+void JSValueUnprotectChecked(JSContextRef, JSValueRef);
+void JSValueProtectChecked(JSContextRef, JSValueRef);
+bool JSValueIsProtected(JSValueRef jsValue);
+bool JSValueProtectCheckingIsEnabled();
+
+#endif // TRACE_H__
diff --git a/jni/windows/IE6.cpp b/jni/windows/IE6.cpp
new file mode 100644
index 0000000..58330a1
--- /dev/null
+++ b/jni/windows/IE6.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2006 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+// A very slim and portable set of JNI methods for GWT.
+
+#include <jni.h>
+#include <windows.h>
+#include "wininet.h"
+
+// A home-brewed vector class to eliminate dependence on STL.
+// Reuse at your own peril, it hasn't been tested to do anything
+// more than we're actually using it for here.
+struct char_vector {
+ char_vector(long initSize=0): sz(0), cap(0), buf(0) {
+ resize(initSize);
+ }
+
+ ~char_vector() {
+ clear();
+ }
+
+ char& operator[](long i) {
+ return buf[i];
+ }
+
+ void append(const char* start, const char* end) {
+ long len = end - start;
+ long cursize = sz;
+ resize(sz + len);
+ memcpy(&buf[cursize], start, len);
+ }
+
+ void clear() {
+ if (buf)
+ free(buf);
+ buf = 0;
+ sz = cap = 0;
+ }
+
+ void reserve(long newcap) {
+ if (newcap <= cap)
+ return;
+ char* newbuf = (char*)malloc(newcap);
+ if (!newbuf)
+ return;
+ if (buf) {
+ memcpy(newbuf, buf, sz);
+ free(buf);
+ }
+ buf = newbuf;
+ cap = newcap;
+ }
+
+ void resize(long newsize) {
+ reserve(newsize);
+ sz = newsize;
+ }
+
+ long size() {
+ return sz;
+ }
+
+private:
+ long sz;
+ long cap;
+ char* buf;
+};
+
+// Does an HTTP GET on the specified URL using the WinInet subsystem, which respects proxy settings.
+// Returns a status code such that
+// 0 Success
+// < 0 Failure at some step (see the code below)
+// > 0 Windows system error code
+//
+int fetch(const char* userAgent, const char* url, char_vector& response) {
+ int status = -1;
+ HINTERNET h1 = InternetOpenA(userAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+ if (h1 != NULL) {
+ status = -2;
+ DWORD flags = INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI;
+ HINTERNET h2 = InternetOpenUrlA(h1, url, "", -1L, flags, 0);
+ if (h2 != NULL) {
+ status = -3;
+ const int MAX_BUFFER = 1024 * 1024; // don't grow past this ever
+ bool notDone = true;
+ response.clear();
+ response.reserve(4096);
+ char_vector chunk(4096); // initial buffer size
+ while (notDone && chunk.size() < MAX_BUFFER) {
+ DWORD toRead = (DWORD)chunk.size();
+ DWORD didRead;
+ while (true) {
+ if (InternetReadFile(h2, (LPVOID)&chunk[0], toRead, &didRead)) {
+ if (didRead != 0) {
+ // Copy to response.
+ //
+ response.append(&chunk[0], &chunk[0] + didRead);
+
+ // Keep going.
+ //
+ } else {
+ // EOF.
+ //
+ status = 0;
+ notDone = false;
+ break;
+ }
+ } else {
+ // Oops -- why?
+ //
+ DWORD err = GetLastError();
+ if (err == ERROR_INSUFFICIENT_BUFFER) {
+ // Grow the buffer and retry.
+ //
+ chunk.resize(toRead * 2);
+ break;
+ } else {
+ // Give up.
+ //
+ status = err;
+ notDone = false;
+ break;
+ }
+ }
+ }
+ }
+ InternetCloseHandle(h2);
+ }
+ InternetCloseHandle(h1);
+ }
+ return status;
+}
+
+extern "C" {
+
+class UTFChars {
+public:
+ UTFChars(JNIEnv* env, jstring str): m_env(env), m_str(str) {
+ m_ptr = env->GetStringUTFChars(str, NULL);
+ }
+
+ ~UTFChars() {
+ if (m_ptr) {
+ m_env->ReleaseStringUTFChars(m_str, m_ptr);
+ }
+ }
+
+ operator const char*() const {
+ return m_ptr;
+ }
+
+ JNIEnv* m_env;
+ jstring m_str;
+ const char* m_ptr;
+};
+
+/*
+ * Class: com_google_gwt_dev_shell_ie_LowLevelIE6
+ * Method: _httpGet
+ * Signature: (Ljava/lang/String;Ljava/lang/String;[[B)I
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_ie_LowLevelIE6__1httpGet(JNIEnv* env, jclass, jstring userAgent, jstring url, jobjectArray out) {
+ UTFChars userAgentChars(env, userAgent);
+ if (!userAgentChars || env->ExceptionCheck()) {
+ return -100;
+ }
+
+ UTFChars urlChars(env, url);
+ if (!urlChars || env->ExceptionCheck()) {
+ return -101;
+ }
+
+ // Do the fetch.
+ //
+ char_vector response;
+ int status = fetch(userAgentChars, urlChars, response);
+
+ if (status != 0) {
+ // Failure.
+ //
+ return status;
+ }
+
+ // Copy the response.
+ //
+ jbyteArray byteArray = env->NewByteArray(response.size());
+ if (!byteArray || env->ExceptionCheck()) {
+ return -102;
+ }
+
+ jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
+ if (!bytes || env->ExceptionCheck()) {
+ return -103;
+ }
+
+ memcpy(bytes, &response[0], response.size());
+
+ env->ReleaseByteArrayElements(byteArray, bytes, 0);
+
+ // May throw immediately after return if out array is bad.
+ //
+ env->SetObjectArrayElement(out, 0, byteArray);
+
+ return 0;
+}
+
+} // extern "C"
diff --git a/jni/windows/Makefile b/jni/windows/Makefile
new file mode 100644
index 0000000..14da521
--- /dev/null
+++ b/jni/windows/Makefile
@@ -0,0 +1,113 @@
+# Copyright 2006 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+##
+# Target settings
+##
+GWT_ROOT = ../../
+OBJDIR := $(GWT_ROOT)build/out/jni/win32/
+OUTDIR := $(GWT_ROOT)build/jni/win32/
+OUT := $(OUTDIR)gwt-ll.dll
+STAGING := $(GWT_ROOT)build/staging/gwt-windows-0.0.0/
+
+##
+# Tools
+##
+CXX := mingw-gcc
+AR := mingw-ar
+STRIP := mingw-strip
+LD := $(CXX)
+
+##
+# List of source, object, and dependency paths plus the path to them
+##
+SRCDIRS := ./:../core/
+VPATH := .:../core
+SRCS := gwt-ll.cpp IE6.cpp
+OBJS := $(addprefix $(OBJDIR),$(SRCS:.cpp=.o))
+DEPS := $(addprefix $(OBJDIR),$(SRCS:.cpp=.d))
+
+##
+# Include path configuration
+##
+SYSINCS := \
+ $(JAVA_HOME)/include \
+ $(JAVA_HOME)/include/win32
+INCS := $(addprefix -isystem ,$(SYSINCS))
+
+##
+# Libraries and library path
+##
+LIBS := wininet
+LIBPATH := -L$(OBJDIR)
+LIBS := $(addprefix -l,$(LIBS))
+
+# for notes on auto-dependency generation, see
+# http://make.paulandlesley.org/autodep.html
+# -MP obviates the need for sed hackery
+CFLAGS := -Os -fno-exceptions -fshort-wchar -c -MMD -MP -Wno-system-headers $(CFLAGS)
+LDFLAGS := -s -Wl,--kill-at $(LDFLAGS)
+
+#-------------------------------------------------------------------------------
+# Rules
+#-------------------------------------------------------------------------------
+
+##
+# default rule
+##
+all: $(OUT)
+
+# install into prebuilt directory
+install: $(OUT)
+ cp $(OUT) prebuilt/
+
+##
+# Include the dependency rules
+##
+-include $(DEPS)
+
+##
+# Compilation rule for cpp files
+##
+$(OBJDIR)%.o : $(SRCDIR)%.cpp
+ @[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
+ $(CXX) $(CFLAGS) $(INCS) -o $@ $<
+
+##
+# Compilation rule for .def files to lib*.a files
+##
+$(OBJDIR)lib%.a : $(SRCDIR)%.def
+ @[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
+ mingw-dlltool -k -d $< -l $@
+
+##
+# Actual output file
+##
+$(OUT): $(OBJS) $(OBJDIR)libwininet.a
+ @[ -d $(OUTDIR) ] || mkdir -p $(OUTDIR)
+ $(LD) -shared $(LDFLAGS) $(LIBPATH) -o $@ $^ $(LIBS)
+ $(STRIP) --strip-unneeded $@
+
+##
+# copy to staging area for hosted-mode development
+##
+staging: $(OUT)
+ @[ -d $(STAGING) ] || mkdir -p $(STAGING)
+ cp $(OUT) $(STAGING)
+
+##
+# Clean rule
+##
+clean:
+ @-rm -rf $(OBJDIR) $(OUT)
diff --git a/jni/windows/build.xml b/jni/windows/build.xml
new file mode 100755
index 0000000..f5951cf
--- /dev/null
+++ b/jni/windows/build.xml
@@ -0,0 +1,18 @@
+<project name="jni-windows" default="build" basedir=".">
+ <property name="gwt.root" location="../.." />
+ <property name="project.tail" value="jni/windows" />
+ <import file="${gwt.root}/common.ant.xml" />
+
+ <target name="build" description="Builds a JNI lib">
+ <mkdir dir="${project.jni}" />
+ <!-- TODO: Actually build this from source! -->
+ <copy todir="${project.jni}">
+ <fileset dir="prebuilt" />
+ </copy>
+ </target>
+
+ <target name="clean" description="Cleans this project's intermediate and output files">
+ <delete dir="${project.build}" failonerror="false" />
+ <delete dir="${project.jni}" failonerror="false" />
+ </target>
+</project>
diff --git a/jni/windows/gwt-ll.vcproj b/jni/windows/gwt-ll.vcproj
new file mode 100644
index 0000000..18fee56
--- /dev/null
+++ b/jni/windows/gwt-ll.vcproj
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gwt-ll"
+ ProjectGUID="{AA853538-40A6-4413-A5B1-74031CB4E887}"
+ RootNamespace="gwt-ll"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="2"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""$(ProjectDir)..\..\..\..\..\third_party\j2sdk1.4.2_09\include";"$(ProjectDir)..\..\..\..\..\third_party\j2sdk1.4.2_09\include\win32""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL"
+ MinimalRebuild="TRUE"
+ ExceptionHandling="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ ForceConformanceInForLoopScope="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wininet.lib"
+ OutputFile="$(OutDir)\$(ProjectName).dll"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/$(ProjectName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="2"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""$(ProjectDir)..\..\..\..\..\third_party\j2sdk1.4.2_09\include";"$(ProjectDir)..\..\..\..\..\third_party\j2sdk1.4.2_09\include\win32""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="0"
+ ForceConformanceInForLoopScope="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wininet.lib"
+ OutputFile="$(OutDir)\$(ProjectName).dll"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ImportLibrary="$(OutDir)/$(ProjectName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\..\..\..\gwt-ll-core\src\main\cpp\gwt-ll.cpp">
+ </File>
+ <File
+ RelativePath=".\IE6.cpp">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/jni/windows/prebuilt/gwt-ll.dll b/jni/windows/prebuilt/gwt-ll.dll
new file mode 100755
index 0000000..49a0a1f
--- /dev/null
+++ b/jni/windows/prebuilt/gwt-ll.dll
Binary files differ
diff --git a/jni/windows/wininet.def b/jni/windows/wininet.def
new file mode 100644
index 0000000..83d6751
--- /dev/null
+++ b/jni/windows/wininet.def
@@ -0,0 +1,6 @@
+LIBRARY wininet.dll
+EXPORTS
+InternetOpenA@20 @264
+InternetOpenUrlA@24 @265
+InternetReadFile@16 @272
+InternetCloseHandle@4 @223
diff --git a/jni/windows/wininet.h b/jni/windows/wininet.h
new file mode 100644
index 0000000..935c615
--- /dev/null
+++ b/jni/windows/wininet.h
@@ -0,0 +1,20 @@
+#ifndef __wininet_h__
+#define __wininet_h__
+
+extern "C" {
+
+#define INTERNET_OPEN_TYPE_PRECONFIG 0
+#define INTERNET_FLAG_PRAGMA_NOCACHE 0x00000100
+#define INTERNET_FLAG_RELOAD 0x80000000
+#define INTERNET_FLAG_NO_COOKIES 0x00080000
+#define INTERNET_FLAG_NO_UI 0x00000200
+
+typedef void* HINTERNET;
+HINTERNET STDAPICALLTYPE InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags);
+HINTERNET STDAPICALLTYPE InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl, LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext);
+BOOL STDAPICALLTYPE InternetReadFile(HINTERNET hFile, void* lpBuffer, DWORD dwNumberOfBytesToRead, LPDWORD lpdwNumberOfBytesRead);
+BOOL STDAPICALLTYPE InternetCloseHandle(HINTERNET hInternet);
+
+}
+
+#endif // __wininet_h__