summaryrefslogtreecommitdiffstats
path: root/widget/android/jni/Accessors.h
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /widget/android/jni/Accessors.h
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'widget/android/jni/Accessors.h')
-rw-r--r--widget/android/jni/Accessors.h274
1 files changed, 274 insertions, 0 deletions
diff --git a/widget/android/jni/Accessors.h b/widget/android/jni/Accessors.h
new file mode 100644
index 000000000..fe2cbc9d4
--- /dev/null
+++ b/widget/android/jni/Accessors.h
@@ -0,0 +1,274 @@
+#ifndef mozilla_jni_Accessors_h__
+#define mozilla_jni_Accessors_h__
+
+#include <jni.h>
+
+#include "mozilla/jni/Refs.h"
+#include "mozilla/jni/Types.h"
+#include "mozilla/jni/Utils.h"
+#include "AndroidBridge.h"
+
+namespace mozilla {
+namespace jni {
+
+namespace detail {
+
+// Helper class to convert an arbitrary type to a jvalue, e.g. Value(123).val.
+struct Value
+{
+ Value(jboolean z) { val.z = z; }
+ Value(jbyte b) { val.b = b; }
+ Value(jchar c) { val.c = c; }
+ Value(jshort s) { val.s = s; }
+ Value(jint i) { val.i = i; }
+ Value(jlong j) { val.j = j; }
+ Value(jfloat f) { val.f = f; }
+ Value(jdouble d) { val.d = d; }
+ Value(jobject l) { val.l = l; }
+
+ jvalue val;
+};
+
+} // namespace detail
+
+using namespace detail;
+
+// Base class for Method<>, Field<>, and Constructor<>.
+class Accessor
+{
+ static void GetNsresult(JNIEnv* env, nsresult* rv)
+ {
+ if (env->ExceptionCheck()) {
+#ifdef MOZ_CHECK_JNI
+ env->ExceptionDescribe();
+#endif
+ env->ExceptionClear();
+ *rv = NS_ERROR_FAILURE;
+ } else {
+ *rv = NS_OK;
+ }
+ }
+
+protected:
+ // Called after making a JNIEnv call.
+ template<class Traits>
+ static void EndAccess(const typename Traits::Owner::Context& ctx,
+ nsresult* rv)
+ {
+ if (Traits::exceptionMode == ExceptionMode::ABORT) {
+ MOZ_CATCH_JNI_EXCEPTION(ctx.Env());
+
+ } else if (Traits::exceptionMode == ExceptionMode::NSRESULT) {
+ GetNsresult(ctx.Env(), rv);
+ }
+ }
+};
+
+
+// Member<> is used to call a JNI method given a traits class.
+template<class Traits, typename ReturnType = typename Traits::ReturnType>
+class Method : public Accessor
+{
+ typedef Accessor Base;
+ typedef typename Traits::Owner::Context Context;
+
+protected:
+ static jmethodID sID;
+
+ static void BeginAccess(const Context& ctx)
+ {
+ MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
+ static_assert(Traits::dispatchTarget == DispatchTarget::CURRENT,
+ "Dispatching not supported for method call");
+
+ if (sID) {
+ return;
+ }
+
+ if (Traits::isStatic) {
+ MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetStaticMethodID(
+ ctx.Env(), ctx.ClassRef(), Traits::name, Traits::signature));
+ } else {
+ MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetMethodID(
+ ctx.Env(), ctx.ClassRef(), Traits::name, Traits::signature));
+ }
+ }
+
+ static void EndAccess(const Context& ctx, nsresult* rv)
+ {
+ return Base::EndAccess<Traits>(ctx, rv);
+ }
+
+public:
+ template<typename... Args>
+ static ReturnType Call(const Context& ctx, nsresult* rv, const Args&... args)
+ {
+ JNIEnv* const env = ctx.Env();
+ BeginAccess(ctx);
+
+ jvalue jargs[] = {
+ Value(TypeAdapter<Args>::FromNative(env, args)).val ...
+ };
+
+ auto result = TypeAdapter<ReturnType>::ToNative(env,
+ Traits::isStatic ?
+ (env->*TypeAdapter<ReturnType>::StaticCall)(
+ ctx.RawClassRef(), sID, jargs) :
+ (env->*TypeAdapter<ReturnType>::Call)(
+ ctx.Get(), sID, jargs));
+
+ EndAccess(ctx, rv);
+ return result;
+ }
+};
+
+// Define sID member.
+template<class T, typename R> jmethodID Method<T, R>::sID;
+
+
+// Specialize void because C++ forbids us from
+// using a "void" temporary result variable.
+template<class Traits>
+class Method<Traits, void> : public Method<Traits, bool>
+{
+ typedef Method<Traits, bool> Base;
+ typedef typename Traits::Owner::Context Context;
+
+public:
+ template<typename... Args>
+ static void Call(const Context& ctx, nsresult* rv,
+ const Args&... args)
+ {
+ JNIEnv* const env = ctx.Env();
+ Base::BeginAccess(ctx);
+
+ jvalue jargs[] = {
+ Value(TypeAdapter<Args>::FromNative(env, args)).val ...
+ };
+
+ if (Traits::isStatic) {
+ env->CallStaticVoidMethodA(ctx.RawClassRef(), Base::sID, jargs);
+ } else {
+ env->CallVoidMethodA(ctx.Get(), Base::sID, jargs);
+ }
+
+ Base::EndAccess(ctx, rv);
+ }
+};
+
+
+// Constructor<> is used to construct a JNI instance given a traits class.
+template<class Traits>
+class Constructor : protected Method<Traits, typename Traits::ReturnType> {
+ typedef typename Traits::Owner::Context Context;
+ typedef typename Traits::ReturnType ReturnType;
+ typedef Method<Traits, ReturnType> Base;
+
+public:
+ template<typename... Args>
+ static ReturnType Call(const Context& ctx, nsresult* rv,
+ const Args&... args)
+ {
+ JNIEnv* const env = ctx.Env();
+ Base::BeginAccess(ctx);
+
+ jvalue jargs[] = {
+ Value(TypeAdapter<Args>::FromNative(env, args)).val ...
+ };
+
+ auto result = TypeAdapter<ReturnType>::ToNative(
+ env, env->NewObjectA(ctx.RawClassRef(), Base::sID, jargs));
+
+ Base::EndAccess(ctx, rv);
+ return result;
+ }
+};
+
+
+// Field<> is used to access a JNI field given a traits class.
+template<class Traits>
+class Field : public Accessor
+{
+ typedef Accessor Base;
+ typedef typename Traits::Owner::Context Context;
+ typedef typename Traits::ReturnType GetterType;
+ typedef typename Traits::SetterType SetterType;
+
+private:
+
+ static jfieldID sID;
+
+ static void BeginAccess(const Context& ctx)
+ {
+ MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
+ static_assert(Traits::dispatchTarget == DispatchTarget::CURRENT,
+ "Dispatching not supported for field access");
+
+ if (sID) {
+ return;
+ }
+
+ if (Traits::isStatic) {
+ MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetStaticFieldID(
+ ctx.Env(), ctx.ClassRef(), Traits::name, Traits::signature));
+ } else {
+ MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetFieldID(
+ ctx.Env(), ctx.ClassRef(), Traits::name, Traits::signature));
+ }
+ }
+
+ static void EndAccess(const Context& ctx, nsresult* rv)
+ {
+ return Base::EndAccess<Traits>(ctx, rv);
+ }
+
+public:
+ static GetterType Get(const Context& ctx, nsresult* rv)
+ {
+ JNIEnv* const env = ctx.Env();
+ BeginAccess(ctx);
+
+ auto result = TypeAdapter<GetterType>::ToNative(
+ env, Traits::isStatic ?
+
+ (env->*TypeAdapter<GetterType>::StaticGet)
+ (ctx.RawClassRef(), sID) :
+
+ (env->*TypeAdapter<GetterType>::Get)
+ (ctx.Get(), sID));
+
+ EndAccess(ctx, rv);
+ return result;
+ }
+
+ static void Set(const Context& ctx, nsresult* rv, SetterType val)
+ {
+ JNIEnv* const env = ctx.Env();
+ BeginAccess(ctx);
+
+ if (Traits::isStatic) {
+ (env->*TypeAdapter<SetterType>::StaticSet)(
+ ctx.RawClassRef(), sID,
+ TypeAdapter<SetterType>::FromNative(env, val));
+ } else {
+ (env->*TypeAdapter<SetterType>::Set)(
+ ctx.Get(), sID,
+ TypeAdapter<SetterType>::FromNative(env, val));
+ }
+
+ EndAccess(ctx, rv);
+ }
+};
+
+// Define sID member.
+template<class T> jfieldID Field<T>::sID;
+
+
+// Define the sClassRef member declared in Refs.h and
+// used by Method and Field above.
+template<class C, typename T> jclass Context<C, T>::sClassRef;
+
+} // namespace jni
+} // namespace mozilla
+
+#endif // mozilla_jni_Accessors_h__