summaryrefslogtreecommitdiffstats
path: root/widget/android/jni/Types.h
blob: 1fe5fa440008392b01c91850f930bdcbd7b3198e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_jni_Types_h__
#define mozilla_jni_Types_h__

#include <jni.h>

#include "mozilla/jni/Refs.h"
#include "mozilla/jni/TypeAdapter.h"

namespace mozilla {
namespace jni {
namespace detail {

// TypeAdapter specializations are the interfaces between native/C++ types such
// as int32_t and JNI types such as jint. The template parameter T is the native
// type, and each TypeAdapter specialization can have the following members:
//
//  * Call: JNIEnv member pointer for making a method call that returns T.
//  * StaticCall: JNIEnv member pointer for making a static call that returns T.
//  * Get: JNIEnv member pointer for getting a field of type T.
//  * StaticGet: JNIEnv member pointer for getting a static field of type T.
//  * Set: JNIEnv member pointer for setting a field of type T.
//  * StaticGet: JNIEnv member pointer for setting a static field of type T.
//  * ToNative: static function that converts the JNI type to the native type.
//  * FromNative: static function that converts the native type to the JNI type.

// TypeAdapter<LocalRef<Cls>> applies when jobject is a return value.
template <class Cls>
struct TypeAdapter<LocalRef<Cls>> {
  using JNIType = typename Cls::Ref::JNIType;

  static constexpr auto Call = &JNIEnv::CallObjectMethodA;
  static constexpr auto StaticCall = &JNIEnv::CallStaticObjectMethodA;
  static constexpr auto Get = &JNIEnv::GetObjectField;
  static constexpr auto StaticGet = &JNIEnv::GetStaticObjectField;

  // Declare instance as jobject because JNI methods return
  // jobject even if the return value is really jstring, etc.
  static LocalRef<Cls> ToNative(JNIEnv* env, jobject instance) {
    return LocalRef<Cls>::Adopt(env, JNIType(instance));
  }

  static JNIType FromNative(JNIEnv*, LocalRef<Cls>&& instance) {
    return instance.Forget();
  }
};

// clang is picky about function types, including attributes that modify the
// calling convention, lining up.  GCC appears to be somewhat less so.
#ifdef __clang__
#  define MOZ_JNICALL_ABI JNICALL
#else
#  define MOZ_JNICALL_ABI
#endif

// NDK r18 made jvalue* method parameters const. We detect the change directly
// instead of using ndk-version.h in order to remain compatible with r15 for
// now, which doesn't include those headers.
class CallArgs {
  static const jvalue* test(void (JNIEnv::*)(jobject, jmethodID,
                                             const jvalue*));
  static jvalue* test(void (JNIEnv::*)(jobject, jmethodID, jvalue*));

 public:
  using JValueType = decltype(test(&JNIEnv::CallVoidMethodA));
};

template <class Cls>
constexpr jobject (JNIEnv::*TypeAdapter<LocalRef<Cls>>::Call)(
    jobject, jmethodID, CallArgs::JValueType) MOZ_JNICALL_ABI;
template <class Cls>
constexpr jobject (JNIEnv::*TypeAdapter<LocalRef<Cls>>::StaticCall)(
    jclass, jmethodID, CallArgs::JValueType) MOZ_JNICALL_ABI;
template <class Cls>
constexpr jobject (JNIEnv::*TypeAdapter<LocalRef<Cls>>::Get)(jobject, jfieldID);
template <class Cls>
constexpr jobject (JNIEnv::*TypeAdapter<LocalRef<Cls>>::StaticGet)(jclass,
                                                                   jfieldID);

// TypeAdapter<Ref<Cls>> applies when jobject is a parameter value.
template <class Cls, typename T>
struct TypeAdapter<Ref<Cls, T>> {
  using JNIType = typename Ref<Cls, T>::JNIType;

  static constexpr auto Set = &JNIEnv::SetObjectField;
  static constexpr auto StaticSet = &JNIEnv::SetStaticObjectField;

  static DependentRef<Cls> ToNative(JNIEnv* env, JNIType instance) {
    return DependentRef<Cls>(instance);
  }

  static JNIType FromNative(JNIEnv*, const Ref<Cls, T>& instance) {
    return instance.Get();
  }
};

template <class Cls, typename T>
constexpr void (JNIEnv::*TypeAdapter<Ref<Cls, T>>::Set)(jobject, jfieldID,
                                                        jobject);
template <class Cls, typename T>
constexpr void (JNIEnv::*TypeAdapter<Ref<Cls, T>>::StaticSet)(jclass, jfieldID,
                                                              jobject);

// jstring has its own Param type.
template <>
struct TypeAdapter<StringParam> : public TypeAdapter<String::Ref> {};

template <class Cls>
struct TypeAdapter<const Cls&> : public TypeAdapter<Cls> {};

}  // namespace detail

using namespace detail;

}  // namespace jni
}  // namespace mozilla

#endif  // mozilla_jni_Types_h__