mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 787271 - Add methods to call in jni through ctypes. r=mfinkle,blassey
This commit is contained in:
parent
40565bd9e7
commit
8234baf59c
193
mobile/android/modules/JNI.jsm
Normal file
193
mobile/android/modules/JNI.jsm
Normal file
@ -0,0 +1,193 @@
|
||||
/* Very basic JNI support for JS
|
||||
*
|
||||
* Example Usage:
|
||||
* let jni = new JNI();
|
||||
* cls = jni.findClass("org.mozilla.gecko.GeckoAppShell");
|
||||
* method = jni.getStaticMethodID(cls, "getPreferredIconSize", "(I)I");
|
||||
*
|
||||
* let val = jni.callStaticIntMethod(cls, method, 3);
|
||||
* // close the jni library when you are done
|
||||
* jni.close();
|
||||
*/
|
||||
let EXPORTED_SYMBOLS = ["JNI"];
|
||||
|
||||
Components.utils.import("resource://gre/modules/ctypes.jsm")
|
||||
Components.utils.import("resource://gre/modules/Services.jsm")
|
||||
|
||||
function JNI() { }
|
||||
|
||||
JNI.prototype = {
|
||||
get lib() {
|
||||
delete this.lib;
|
||||
return this.lib = ctypes.open("libxul.so");
|
||||
},
|
||||
|
||||
getType: function(aType) {
|
||||
switch(aType) {
|
||||
case "B": return ctypes.char;
|
||||
case "C": return ctypes.char;
|
||||
case "D": return ctypes.double;
|
||||
case "F": return ctypes.float;
|
||||
case "I": return ctypes.int32_t;
|
||||
case "J": return ctypes.long;
|
||||
case "S": return ctypes.short;
|
||||
case "V": return ctypes.void_t;
|
||||
case "Z": return ctypes.bool;
|
||||
default: return this.types.jobject
|
||||
}
|
||||
},
|
||||
|
||||
getArgs: function(aMethod, aArgs) {
|
||||
if (aArgs.length != aMethod.parameters.length)
|
||||
throw ("Incorrect number of arguments passed to " + aMethod.name);
|
||||
|
||||
// Convert arguments to an array of jvalue objects
|
||||
let modifiedArgs = new ctypes.ArrayType(this.types.jvalue, aMethod.parameters.length)();
|
||||
for (let i = 0; i < aMethod.parameters.length; i++) {
|
||||
let parameter = aMethod.parameters[i];
|
||||
let arg = new this.types.jvalue();
|
||||
|
||||
if (aArgs[i] instanceof Array || parameter[0] == "[")
|
||||
throw "No support for array arguments yet";
|
||||
else
|
||||
ctypes.cast(arg, this.getType(parameter)).value = aArgs[i];
|
||||
|
||||
modifiedArgs[i] = arg;
|
||||
}
|
||||
|
||||
return modifiedArgs;
|
||||
},
|
||||
|
||||
types: {
|
||||
jobject: ctypes.StructType("_jobject").ptr,
|
||||
jclass: ctypes.StructType("_jobject").ptr,
|
||||
jmethodID: ctypes.StructType("jmethodID").ptr,
|
||||
jvalue: ctypes.double
|
||||
},
|
||||
|
||||
get _findClass() {
|
||||
delete this._findClass;
|
||||
return this._findClass = this.lib.declare("FindClass",
|
||||
ctypes.default_abi,
|
||||
this.types.jclass,
|
||||
ctypes.char.ptr);
|
||||
},
|
||||
|
||||
findClass: function(name) {
|
||||
let ret = this._findClass(name);
|
||||
if (this.exceptionCheck())
|
||||
throw("Can't find class " + name);
|
||||
return ret;
|
||||
},
|
||||
|
||||
get _getStaticMethodID() {
|
||||
delete this._getStatisMethodID;
|
||||
return this._getStaticMethodID = this.lib.declare("GetStaticMethodID",
|
||||
ctypes.default_abi,
|
||||
this.types.jmethodID,
|
||||
this.types.jclass, // class
|
||||
ctypes.char.ptr, // method name
|
||||
ctypes.char.ptr); // signature
|
||||
},
|
||||
|
||||
getStaticMethodID: function(aClass, aName, aSignature) {
|
||||
let ret = this._getStaticMethodID(aClass, aName, aSignature);
|
||||
if (this.exceptionCheck())
|
||||
throw("Can't find method " + aName);
|
||||
return new jMethod(aName, ret, aSignature);
|
||||
},
|
||||
|
||||
get _exceptionCheck() {
|
||||
delete this._exceptionCheck;
|
||||
return this._exceptionCheck = this.lib.declare("ExceptionCheck",
|
||||
ctypes.default_abi,
|
||||
ctypes.bool);
|
||||
},
|
||||
|
||||
exceptionCheck: function() {
|
||||
return this._exceptionCheck();
|
||||
},
|
||||
|
||||
get _callStaticVoidMethod() {
|
||||
delete this._callStaticVoidMethod;
|
||||
return this._callStaticVoidMethod = this.lib.declare("CallStaticVoidMethodA",
|
||||
ctypes.default_abi,
|
||||
ctypes.void_t,
|
||||
this.types.jclass,
|
||||
this.types.jmethodID,
|
||||
this.types.jvalue.ptr);
|
||||
},
|
||||
|
||||
callStaticVoidMethod: function(aClass, aMethod) {
|
||||
let args = Array.prototype.slice.apply(arguments, [2]);
|
||||
this._callStaticVoidMethod(aClass, aMethodId.methodId, this.getArgs(aMethod, args));
|
||||
if (this.exceptionCheck())
|
||||
throw("Error calling static void method");
|
||||
},
|
||||
|
||||
get _callStaticIntMethod() {
|
||||
delete this._callStaticIntMethod;
|
||||
return this._callStaticIntMethod = this.lib.declare("CallStaticIntMethodA",
|
||||
ctypes.default_abi,
|
||||
ctypes.int,
|
||||
this.types.jclass,
|
||||
this.types.jmethodID,
|
||||
this.types.jvalue.ptr);
|
||||
},
|
||||
|
||||
callStaticIntMethod: function(aClass, aMethod) {
|
||||
let args = Array.prototype.slice.apply(arguments, [2]);
|
||||
let ret = this._callStaticIntMethod(aClass, aMethod.methodId, this.getArgs(aMethod, args));
|
||||
if (this.exceptionCheck())
|
||||
throw("Error calling static int method");
|
||||
return ret;
|
||||
},
|
||||
|
||||
close: function() {
|
||||
this.lib.close();
|
||||
},
|
||||
}
|
||||
|
||||
function jMethod(name, jMethodId, signature) {
|
||||
this.name = name;
|
||||
this.methodId = jMethodId;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
jMethod.prototype = {
|
||||
parameters: [],
|
||||
returnType: null,
|
||||
_signature: "",
|
||||
|
||||
// this just splits up the return value from the parameters
|
||||
signatureRegExp: /^\(([^\)]*)\)(.*)$/,
|
||||
|
||||
// This splits up the actual parameters
|
||||
parameterRegExp: /(\[*)(B|C|D|F|I|J|S|V|Z|L[^;]*;)/y,
|
||||
|
||||
parseSignature: function(aSignature) {
|
||||
let [, parameters, returnType] = this.signatureRegExp.exec(aSignature);
|
||||
|
||||
// parse the parameters that should be passed to this method
|
||||
if (parameters) {
|
||||
let parameter = this.parameterRegExp.exec(parameters);
|
||||
while (parameter) {
|
||||
this.parameters.push(parameter[0]);
|
||||
parameter = this.parameterRegExp.exec(parameters);
|
||||
}
|
||||
} else {
|
||||
this.parameters = [];
|
||||
}
|
||||
|
||||
// parse the return type
|
||||
this.returnType = returnType;
|
||||
},
|
||||
|
||||
_signature: "",
|
||||
get signature() { return this._signature; },
|
||||
set signature(val) {
|
||||
this.parameters = [];
|
||||
this.returnType = null;
|
||||
this.parseSignature(val);
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ EXTRA_JS_MODULES = \
|
||||
LocaleRepository.jsm \
|
||||
linuxTypes.jsm \
|
||||
video.jsm \
|
||||
JNI.jsm \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_PP_JS_MODULES = \
|
||||
|
@ -2538,3 +2538,55 @@ AndroidBridge::NotifyPaintedRect(float top, float left, float bottom, float righ
|
||||
AutoLocalJNIFrame jniFrame(env, 0);
|
||||
env->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyPaintedRect, top, left, bottom, right);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
__attribute__ ((visibility("default")))
|
||||
jclass
|
||||
jsjni_FindClass(const char *className) {
|
||||
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
||||
if (!env) return NULL;
|
||||
return env->FindClass(className);
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("default")))
|
||||
jmethodID
|
||||
jsjni_GetStaticMethodID(jclass methodClass,
|
||||
const char *methodName,
|
||||
const char *signature) {
|
||||
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
||||
if (!env) return NULL;
|
||||
return env->GetStaticMethodID(methodClass, methodName, signature);
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("default")))
|
||||
bool
|
||||
jsjni_ExceptionCheck() {
|
||||
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
||||
if (!env) return NULL;
|
||||
return env->ExceptionCheck();
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("default")))
|
||||
void
|
||||
jsjni_CallStaticVoidMethodA(jclass cls,
|
||||
jmethodID method,
|
||||
jvalue *values) {
|
||||
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
||||
if (!env) return;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
env->CallStaticVoidMethodA(cls, method, values);
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("default")))
|
||||
int
|
||||
jsjni_CallStaticIntMethodA(jclass cls,
|
||||
jmethodID method,
|
||||
jvalue *values) {
|
||||
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
||||
if (!env) return -1;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
return env->CallStaticIntMethodA(cls, method, values);
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,13 @@ class nsIDOMMozSmsMessage;
|
||||
|
||||
/* See the comment in AndroidBridge about this function before using it */
|
||||
extern "C" JNIEnv * GetJNIForThread();
|
||||
extern "C" jclass jsjni_FindClass(const char *className);
|
||||
extern "C" jmethodID jsjni_GetStaticMethodID(jclass methodClass,
|
||||
const char *methodName,
|
||||
const char *signature);
|
||||
extern "C" bool jsjni_ExceptionCheck();
|
||||
extern "C" void jsjni_CallStaticVoidMethodA(jclass cls, jmethodID method, jvalue *values);
|
||||
extern "C" int jsjni_CallStaticIntMethodA(jclass cls, jmethodID method, jvalue *values);
|
||||
|
||||
extern bool mozilla_AndroidBridge_SetMainThread(void *);
|
||||
extern jclass GetGeckoAppShellClass();
|
||||
|
Loading…
Reference in New Issue
Block a user