1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/modules/JNI.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,197 @@ 1.4 +/* Very basic JNI support for JS 1.5 + * 1.6 + * Example Usage: 1.7 + * let jni = new JNI(); 1.8 + * cls = jni.findClass("org/mozilla/gecko/GeckoAppShell"); 1.9 + * method = jni.getStaticMethodID(cls, "getPreferredIconSize", "(I)I"); 1.10 + * 1.11 + * let val = jni.callStaticIntMethod(cls, method, 3); 1.12 + * // close the jni library when you are done 1.13 + * jni.close(); 1.14 + * 1.15 + * Note: the getters in this file are deleted and replaced with static 1.16 + * values once computed, as in, for example 1.17 + * http://code.activestate.com/recipes/577310-using-a-getter-for-a-one-time-calculation-of-a-jav/ 1.18 + */ 1.19 +this.EXPORTED_SYMBOLS = ["JNI"]; 1.20 + 1.21 +Components.utils.import("resource://gre/modules/ctypes.jsm") 1.22 +Components.utils.import("resource://gre/modules/Services.jsm") 1.23 + 1.24 +this.JNI = function JNI() { } 1.25 + 1.26 +JNI.prototype = { 1.27 + get lib() { 1.28 + delete this.lib; 1.29 + return this.lib = ctypes.open("libxul.so"); 1.30 + }, 1.31 + 1.32 + getType: function(aType) { 1.33 + switch(aType) { 1.34 + case "B": return ctypes.char; 1.35 + case "C": return ctypes.char; 1.36 + case "D": return ctypes.double; 1.37 + case "F": return ctypes.float; 1.38 + case "I": return ctypes.int32_t; 1.39 + case "J": return ctypes.int64_t; 1.40 + case "S": return ctypes.int16_t; 1.41 + case "V": return ctypes.void_t; 1.42 + case "Z": return ctypes.bool; 1.43 + default: return this.types.jobject 1.44 + } 1.45 + }, 1.46 + 1.47 + getArgs: function(aMethod, aArgs) { 1.48 + if (aArgs.length != aMethod.parameters.length) 1.49 + throw ("Incorrect number of arguments passed to " + aMethod.name); 1.50 + 1.51 + // Convert arguments to an array of jvalue objects 1.52 + let modifiedArgs = new ctypes.ArrayType(this.types.jvalue, aMethod.parameters.length)(); 1.53 + for (let i = 0; i < aMethod.parameters.length; i++) { 1.54 + let parameter = aMethod.parameters[i]; 1.55 + let arg = new this.types.jvalue(); 1.56 + 1.57 + if (aArgs[i] instanceof Array || parameter[0] == "[") 1.58 + throw "No support for array arguments yet"; 1.59 + else 1.60 + ctypes.cast(arg, this.getType(parameter)).value = aArgs[i]; 1.61 + 1.62 + modifiedArgs[i] = arg; 1.63 + } 1.64 + 1.65 + return modifiedArgs; 1.66 + }, 1.67 + 1.68 + types: { 1.69 + jobject: ctypes.StructType("_jobject").ptr, 1.70 + jclass: ctypes.StructType("_jobject").ptr, 1.71 + jmethodID: ctypes.StructType("jmethodID").ptr, 1.72 + jvalue: ctypes.double 1.73 + }, 1.74 + 1.75 + get _findClass() { 1.76 + delete this._findClass; 1.77 + return this._findClass = this.lib.declare("jsjni_FindClass", 1.78 + ctypes.default_abi, 1.79 + this.types.jclass, 1.80 + ctypes.char.ptr); 1.81 + }, 1.82 + 1.83 + findClass: function(name) { 1.84 + let ret = this._findClass(name); 1.85 + if (this.exceptionCheck()) 1.86 + throw("Can't find class " + name); 1.87 + return ret; 1.88 + }, 1.89 + 1.90 + get _getStaticMethodID() { 1.91 + delete this._getStaticMethodID; 1.92 + return this._getStaticMethodID = this.lib.declare("jsjni_GetStaticMethodID", 1.93 + ctypes.default_abi, 1.94 + this.types.jmethodID, 1.95 + this.types.jclass, // class 1.96 + ctypes.char.ptr, // method name 1.97 + ctypes.char.ptr); // signature 1.98 + }, 1.99 + 1.100 + getStaticMethodID: function(aClass, aName, aSignature) { 1.101 + let ret = this._getStaticMethodID(aClass, aName, aSignature); 1.102 + if (this.exceptionCheck()) 1.103 + throw("Can't find method " + aName); 1.104 + return new jMethod(aName, ret, aSignature); 1.105 + }, 1.106 + 1.107 + get _exceptionCheck() { 1.108 + delete this._exceptionCheck; 1.109 + return this._exceptionCheck = this.lib.declare("jsjni_ExceptionCheck", 1.110 + ctypes.default_abi, 1.111 + ctypes.bool); 1.112 + }, 1.113 + 1.114 + exceptionCheck: function() { 1.115 + return this._exceptionCheck(); 1.116 + }, 1.117 + 1.118 + get _callStaticVoidMethod() { 1.119 + delete this._callStaticVoidMethod; 1.120 + return this._callStaticVoidMethod = this.lib.declare("jsjni_CallStaticVoidMethodA", 1.121 + ctypes.default_abi, 1.122 + ctypes.void_t, 1.123 + this.types.jclass, 1.124 + this.types.jmethodID, 1.125 + this.types.jvalue.ptr); 1.126 + }, 1.127 + 1.128 + callStaticVoidMethod: function(aClass, aMethod) { 1.129 + let args = Array.prototype.slice.apply(arguments, [2]); 1.130 + this._callStaticVoidMethod(aClass, aMethod.methodId, this.getArgs(aMethod, args)); 1.131 + if (this.exceptionCheck()) 1.132 + throw("Error calling static void method"); 1.133 + }, 1.134 + 1.135 + get _callStaticIntMethod() { 1.136 + delete this._callStaticIntMethod; 1.137 + return this._callStaticIntMethod = this.lib.declare("jsjni_CallStaticIntMethodA", 1.138 + ctypes.default_abi, 1.139 + ctypes.int, 1.140 + this.types.jclass, 1.141 + this.types.jmethodID, 1.142 + this.types.jvalue.ptr); 1.143 + }, 1.144 + 1.145 + callStaticIntMethod: function(aClass, aMethod) { 1.146 + let args = Array.prototype.slice.apply(arguments, [2]); 1.147 + let ret = this._callStaticIntMethod(aClass, aMethod.methodId, this.getArgs(aMethod, args)); 1.148 + if (this.exceptionCheck()) 1.149 + throw("Error calling static int method"); 1.150 + return ret; 1.151 + }, 1.152 + 1.153 + close: function() { 1.154 + this.lib.close(); 1.155 + }, 1.156 +} 1.157 + 1.158 +function jMethod(name, jMethodId, signature) { 1.159 + this.name = name; 1.160 + this.methodId = jMethodId; 1.161 + this.signature = signature; 1.162 +} 1.163 + 1.164 +jMethod.prototype = { 1.165 + parameters: [], 1.166 + returnType: null, 1.167 + _signature: "", 1.168 + 1.169 + // this just splits up the return value from the parameters 1.170 + signatureRegExp: /^\(([^\)]*)\)(.*)$/, 1.171 + 1.172 + // This splits up the actual parameters 1.173 + parameterRegExp: /(\[*)(B|C|D|F|I|J|S|V|Z|L[^;]*;)/y, 1.174 + 1.175 + parseSignature: function(aSignature) { 1.176 + let [, parameters, returnType] = this.signatureRegExp.exec(aSignature); 1.177 + 1.178 + // parse the parameters that should be passed to this method 1.179 + if (parameters) { 1.180 + let parameter = this.parameterRegExp.exec(parameters); 1.181 + while (parameter) { 1.182 + this.parameters.push(parameter[0]); 1.183 + parameter = this.parameterRegExp.exec(parameters); 1.184 + } 1.185 + } else { 1.186 + this.parameters = []; 1.187 + } 1.188 + 1.189 + // parse the return type 1.190 + this.returnType = returnType; 1.191 + }, 1.192 + 1.193 + _signature: "", 1.194 + get signature() { return this._signature; }, 1.195 + set signature(val) { 1.196 + this.parameters = []; 1.197 + this.returnType = null; 1.198 + this.parseSignature(val); 1.199 + } 1.200 +}