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/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;
+}