| /* |
| * 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. |
| */ |
| JsRootedValue* GetFieldAsRootedValue(JSContext* context, jclass clazz, |
| jobject obj, jstring fieldName) |
| { |
| jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "getField", |
| "(Ljava/lang/String;I)V"); |
| if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) |
| return 0; |
| |
| JsRootedValue* jsRootedValue = new JsRootedValue(context); |
| 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 |
| */ |
| bool SetFieldFromRootedValue(JSContext* context, jclass clazz, |
| jobject obj, jstring fieldName, JsRootedValue* jsRootedValue) |
| { |
| 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); |
| } |
| |
| |
| enum JsValueType { |
| JSVAL_TYPE_VOID=0, |
| JSVAL_TYPE_NULL, |
| JSVAL_TYPE_BOOLEAN, |
| JSVAL_TYPE_NUMBER, |
| JSVAL_TYPE_STRING, |
| JSVAL_TYPE_OBJECT, |
| JSVAL_TYPE_UNKNOWN, |
| }; |
| |
| static const char* JsValueTypeStrings[]={ |
| "undefined", |
| "null", |
| "boolean", |
| "number", |
| "string", |
| "object", |
| "unknown", |
| }; |
| |
| 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; |
| } |
| } |
| |
| /* |
| * Class: com_google_gwt_dev_shell_moz_JsValueMoz |
| * Method: _createJsRootedValue() |
| * Signature: (II)I |
| */ |
| extern "C" JNIEXPORT jint JNICALL |
| Java_com_google_gwt_dev_shell_moz_JsValueMoz__1createJsRootedValue |
| (JNIEnv* jniEnv, jclass, jint scriptObjInt, jint jsval) |
| { |
| Tracer tracer("JsValueMoz._createJsRootedValue"); |
| nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt); |
| nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext()); |
| if (!scriptContext) { |
| ThrowHostedModeException(jniEnv, "Unable to get script context"); |
| tracer.setFail("Unable to get script context"); |
| return 0; |
| } |
| JSContext* context = NS_REINTERPRET_CAST(JSContext*, scriptContext->GetNativeContext()); |
| JsRootedValue* jsRootedValue = new JsRootedValue(context, 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() |
| * |
| * TODO(jat): unboxing Javascript Integer type? |
| */ |
| 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(); |
| } |
| |
| /** |
| * 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* context = jsRootedValue->getContext(); |
| 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(context, jsObject); |
| if (JS_InstanceOf(context, 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); |
| jsval val = jsRootedValue->getValue(); |
| if(!JSVAL_IS_OBJECT(val)) { |
| tracer.throwHostedModeException(jniEnv, "Javascript value not an object"); |
| return 0; |
| } |
| JSObject* jsObject = JSVAL_TO_OBJECT(val); |
| JSContext* context = jsRootedValue->getContext(); |
| if(!JS_InstanceOf(context, jsObject, &gwt_nativewrapper_class, 0)) { |
| tracer.throwHostedModeException(jniEnv, |
| "Javascript object not a Java object"); |
| return 0; |
| } |
| jobject javaObject |
| = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(context, 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->getContext(), 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->getContext(), 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->setContextValue(jsOtherRootedValue->getContext(), |
| jsOtherRootedValue->getValue()); |
| } |
| |
| /* |
| * 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))) { |
| 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* context = jsRootedValue->getContext(); |
| JSObject* scriptWindow = JS_GetGlobalObject(context); |
| JSObject* newObj = JS_NewObject(context, &gwt_nativewrapper_class, 0, |
| scriptWindow); |
| if (!newObj) { |
| tracer.throwHostedModeException(jniEnv, |
| "Unable to allocate JS object to wrap Java object"); |
| return; |
| } |
| tracer.log("jsobject=%08x", unsigned(newObj)); |
| |
| // TODO(jat): how does this globalref get freed? |
| jobject dispObjRef = jniEnv->NewGlobalRef(obj); |
| if (!dispObjRef || jniEnv->ExceptionCheck()) { |
| tracer.throwHostedModeException(jniEnv, |
| "Unable to allocate global reference for JS wrapper"); |
| return; |
| } |
| if (!JS_SetPrivate(context, 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()) { |
| jniEnv->DeleteGlobalRef(dispObjRef); |
| tracer.setFail("can't get object class"); |
| return; |
| } |
| jmethodID getFieldMeth = jniEnv->GetMethodID(dispClass, "getField", |
| "(Ljava/lang/String;I)V"); |
| if (!getFieldMeth || jniEnv->ExceptionCheck()) { |
| jniEnv->DeleteGlobalRef(dispObjRef); |
| tracer.setFail("can't get getField method"); |
| return; |
| } |
| jstring ident = jniEnv->NewStringUTF("@java.lang.Object::toString()"); |
| if (!ident || jniEnv->ExceptionCheck()) { |
| jniEnv->DeleteGlobalRef(dispObjRef); |
| tracer.setFail("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(context, JSVAL_VOID); |
| jniEnv->CallVoidMethod(obj, getFieldMeth, ident, |
| NS_REINTERPRET_CAST(jint, toStringFunc)); |
| if (toStringFunc->isUndefined() || jniEnv->ExceptionCheck()) { |
| jniEnv->DeleteGlobalRef(dispObjRef); |
| tracer.setFail("getField(toString) failed"); |
| return; |
| } |
| if (!JS_DefineProperty(context, newObj, "toString", toStringFunc->getValue(), |
| JS_PropertyStub, JS_PropertyStub, JSPROP_READONLY | JSPROP_PERMANENT)) { |
| jniEnv->DeleteGlobalRef(dispObjRef); |
| tracer.setFail("can't define JS toString method"); |
| return; |
| } |
| jsRootedValue->setObject(newObj); |
| } |
| |
| /* |
| * 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* context = jsRootedValue->getContext(); |
| JSObject* scriptWindow = JS_GetGlobalObject(context); |
| 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(context, 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; |
| } |
| // Create a wrapper object to hold and clean up dispMeth |
| JSObject* cleanupObj = JS_NewObject(context, &gwt_functionwrapper_class, 0, |
| scriptWindow); |
| if (!cleanupObj) { |
| tracer.throwHostedModeException(jniEnv, "JS_NewObject failed"); |
| return; |
| } |
| jobject dispMethRef = jniEnv->NewGlobalRef(dispatchMethod); |
| if (!dispMethRef || jniEnv->ExceptionCheck()) { |
| return; |
| } |
| |
| // Store our global ref in the wrapper object |
| if (!JS_SetPrivate(context, cleanupObj, dispMethRef)) { |
| jniEnv->DeleteGlobalRef(dispMethRef); |
| tracer.throwHostedModeException(jniEnv, "JS_SetPrivate(cleanupObj) failed"); |
| return; |
| } |
| // Store the wrapper object in funObj's reserved slot |
| if(!JS_SetReservedSlot(context, funObj, 0, OBJECT_TO_JSVAL(cleanupObj))) { |
| // TODO(jat): what to do with global ref? |
| tracer.throwHostedModeException(jniEnv, "JS_SetReservedSlot failed"); |
| return; |
| } |
| jsRootedValue->setObject(funObj); |
| } |
| |
| /* |
| * 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->getContext(); |
| |
| // 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; |
| } |