android_emoji_EmojiFactory.cpp revision cf6f7a0f006c0fcf59bb634cbe79f2a8500fd92a
1#include "SkTypes.h"
2#include "SkImageDecoder.h"
3
4#define LOG_TAG "EmojiFactory_jni"
5#include <utils/Log.h>
6#include <utils/String8.h>
7#include <utils/String16.h>
8
9#include "EmojiFactory.h"
10#include <nativehelper/JNIHelp.h>
11
12#include <dlfcn.h>
13// #include <pthread.h>
14
15namespace android {
16
17class EmojiFactoryCaller {
18 public:
19  EmojiFactoryCaller() {}
20  virtual ~EmojiFactoryCaller();
21  bool Init();
22  EmojiFactory *TryCallGetImplementation(const char* name);
23  EmojiFactory *TryCallGetAvailableImplementation();
24 private:
25  void *m_handle;
26  EmojiFactory *(*m_get_implementation)(const char*);
27  EmojiFactory *(*m_get_available_implementation)();
28};
29
30bool EmojiFactoryCaller::Init() {
31  const char* error_msg;
32  m_handle = dlopen("libemoji.so", RTLD_LAZY | RTLD_LOCAL);
33
34  if (m_handle == NULL) {
35    error_msg = "Failed to load libemoji.so";
36    goto FAIL;
37  }
38
39  m_get_implementation =
40      reinterpret_cast<EmojiFactory *(*)(const char*)>(
41          dlsym(m_handle, "GetImplementation"));
42  if (m_get_implementation == NULL) {
43    error_msg = "Failed to get symbol of GetImplementation";
44    goto FAIL;
45  }
46
47  m_get_available_implementation =
48      reinterpret_cast<EmojiFactory *(*)()>(
49          dlsym(m_handle,"GetAvailableImplementation"));
50  if (m_get_available_implementation == NULL) {
51    error_msg = "Failed to get symbol of GetAvailableImplementation";
52    goto FAIL;
53  }
54
55  return true;
56
57FAIL:
58  const char* error_str = dlerror();
59  if (error_str == NULL) {
60    error_str = "unknown reason";
61  }
62
63  LOGE("%s: %s", error_msg, error_str);
64  if (m_handle != NULL) {
65    dlclose(m_handle);
66    m_handle = NULL;
67  }
68  return false;
69}
70
71EmojiFactoryCaller::~EmojiFactoryCaller() {
72  if (m_handle) {
73    dlclose(m_handle);
74  }
75}
76
77EmojiFactory *EmojiFactoryCaller::TryCallGetImplementation(
78    const char* name) {
79  if (NULL == m_handle) {
80    return NULL;
81  }
82  return m_get_implementation(name);
83}
84
85EmojiFactory *EmojiFactoryCaller::TryCallGetAvailableImplementation() {
86  if (NULL == m_handle) {
87    return NULL;
88  }
89  return m_get_available_implementation();
90}
91
92static EmojiFactoryCaller* gCaller;
93static pthread_once_t g_once = PTHREAD_ONCE_INIT;
94static bool lib_emoji_factory_is_ready;
95
96static jclass    gBitmap_class;
97static jmethodID gBitmap_constructorMethodID;
98
99static jclass    gEmojiFactory_class;
100static jmethodID gEmojiFactory_constructorMethodID;
101
102static void InitializeCaller() {
103  gCaller = new EmojiFactoryCaller();
104  lib_emoji_factory_is_ready = gCaller->Init();
105}
106
107static jobject create_java_EmojiFactory(
108    JNIEnv* env, EmojiFactory* factory, jstring name) {
109  jobject obj = env->NewObject(gEmojiFactory_class, gEmojiFactory_constructorMethodID,
110      static_cast<jint>(reinterpret_cast<uintptr_t>(factory)), name);
111  if (env->ExceptionCheck() != 0) {
112    LOGE("*** Uncaught exception returned from Java call!\n");
113    env->ExceptionDescribe();
114  }
115  return obj;
116}
117
118static jobject android_emoji_EmojiFactory_newInstance(
119    JNIEnv* env, jobject clazz, jstring name) {
120  if (NULL == name) {
121    return NULL;
122  }
123  pthread_once(&g_once, InitializeCaller);
124  if (!lib_emoji_factory_is_ready) {
125    return NULL;
126  }
127
128  const jchar* jchars = env->GetStringChars(name, NULL);
129  jsize len = env->GetStringLength(name);
130  String8 str(String16(jchars, len));
131
132  EmojiFactory *factory = gCaller->TryCallGetImplementation(str.string());
133  // EmojiFactory *factory = EmojiFactory::GetImplementation(str.string());
134  if (NULL == factory) {
135    return NULL;
136  }
137  env->ReleaseStringChars(name, jchars);
138
139  return create_java_EmojiFactory(env, factory, name);
140}
141
142static jobject android_emoji_EmojiFactory_newAvailableInstance(
143    JNIEnv* env, jobject clazz) {
144  pthread_once(&g_once, InitializeCaller);
145  if (!lib_emoji_factory_is_ready) {
146    return NULL;
147  }
148
149  EmojiFactory *factory = gCaller->TryCallGetAvailableImplementation();
150  // EmojiFactory *factory = EmojiFactory::GetAvailableImplementation();
151  if (NULL == factory) {
152    return NULL;
153  }
154  String16 name_16(String8(factory->Name()));
155  jstring jname = env->NewString(name_16.string(), name_16.size());
156  if (NULL == jname) {
157    return NULL;
158  }
159
160  return create_java_EmojiFactory(env, factory, jname);
161}
162
163static jobject android_emoji_EmojiFactory_getBitmapFromAndroidPua(
164    JNIEnv* env, jobject clazz, jint nativeEmojiFactory, jint pua) {
165  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
166
167  int size;
168  const char *bytes = factory->GetImageBinaryFromAndroidPua(pua, &size);
169  if (bytes == NULL) {
170    return NULL;
171  }
172
173  SkBitmap *bitmap = new SkBitmap;
174  if (!SkImageDecoder::DecodeMemory(bytes, size, bitmap)) {
175    LOGE("SkImageDecoder::DecodeMemory() failed.");
176    return NULL;
177  }
178
179  jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
180      static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)), NULL, false, NULL, -1);
181  if (env->ExceptionCheck() != 0) {
182    LOGE("*** Uncaught exception returned from Java call!\n");
183    env->ExceptionDescribe();
184  }
185  return obj;
186}
187
188static void android_emoji_EmojiFactory_destructor(
189    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
190  /*
191  // Must not delete this object!!
192  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
193  delete factory;
194  */
195}
196
197static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis(
198    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jchar sjis) {
199  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
200  return factory->GetAndroidPuaFromVendorSpecificSjis(sjis);
201}
202
203static jint android_emoji_EmojiFactory_getVendorSpecificSjisFromAndroidPua(
204    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint pua) {
205  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
206  return factory->GetVendorSpecificSjisFromAndroidPua(pua);
207}
208
209static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificPua(
210    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint vsu) {
211  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
212  return factory->GetAndroidPuaFromVendorSpecificPua(vsu);
213}
214
215static jint android_emoji_EmojiFactory_getVendorSpecificPuaFromAndroidPua(
216    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint pua) {
217  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
218  return factory->GetVendorSpecificPuaFromAndroidPua(pua);
219}
220
221static jint android_emoji_EmojiFactory_getMaximumVendorSpecificPua(
222    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
223  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
224  return factory->GetMaximumVendorSpecificPua();
225}
226
227static jint android_emoji_EmojiFactory_getMinimumVendorSpecificPua(
228    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
229  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
230  return factory->GetMinimumVendorSpecificPua();
231}
232
233static jint android_emoji_EmojiFactory_getMaximumAndroidPua(
234    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
235  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
236  return factory->GetMaximumAndroidPua();
237}
238
239static jint android_emoji_EmojiFactory_getMinimumAndroidPua(
240    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
241  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
242  return factory->GetMinimumAndroidPua();
243}
244
245static JNINativeMethod gMethods[] = {
246  { "newInstance", "(Ljava/lang/String;)Landroid/emoji/EmojiFactory;",
247    (void*)android_emoji_EmojiFactory_newInstance},
248  { "newAvailableInstance", "()Landroid/emoji/EmojiFactory;",
249    (void*)android_emoji_EmojiFactory_newAvailableInstance},
250  { "nativeDestructor", "(I)V",
251    (void*)android_emoji_EmojiFactory_destructor},
252  { "nativeGetBitmapFromAndroidPua", "(II)Landroid/graphics/Bitmap;",
253    (void*)android_emoji_EmojiFactory_getBitmapFromAndroidPua},
254  { "nativeGetAndroidPuaFromVendorSpecificSjis", "(IC)I",
255    (void*)android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis},
256  { "nativeGetVendorSpecificSjisFromAndroidPua", "(II)I",
257    (void*)android_emoji_EmojiFactory_getVendorSpecificSjisFromAndroidPua},
258  { "nativeGetAndroidPuaFromVendorSpecificPua", "(II)I",
259    (void*)android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificPua},
260  { "nativeGetVendorSpecificPuaFromAndroidPua", "(II)I",
261    (void*)android_emoji_EmojiFactory_getVendorSpecificPuaFromAndroidPua},
262  { "nativeGetMaximumVendorSpecificPua", "(I)I",
263    (void*)android_emoji_EmojiFactory_getMaximumVendorSpecificPua},
264  { "nativeGetMinimumVendorSpecificPua", "(I)I",
265    (void*)android_emoji_EmojiFactory_getMinimumVendorSpecificPua},
266  { "nativeGetMaximumAndroidPua", "(I)I",
267    (void*)android_emoji_EmojiFactory_getMaximumAndroidPua},
268  { "nativeGetMinimumAndroidPua", "(I)I",
269    (void*)android_emoji_EmojiFactory_getMinimumAndroidPua}
270};
271
272static jclass make_globalref(JNIEnv* env, const char classname[])
273{
274    jclass c = env->FindClass(classname);
275    SkASSERT(c);
276    return (jclass)env->NewGlobalRef(c);
277}
278
279static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
280                                const char fieldname[], const char type[])
281{
282    jfieldID id = env->GetFieldID(clazz, fieldname, type);
283    SkASSERT(id);
284    return id;
285}
286
287int register_android_emoji_EmojiFactory(JNIEnv* env) {
288  gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
289  gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
290                                                 "(I[BZ[BI)V");
291  gEmojiFactory_class = make_globalref(env, "android/emoji/EmojiFactory");
292  gEmojiFactory_constructorMethodID = env->GetMethodID(
293      gEmojiFactory_class, "<init>", "(ILjava/lang/String;)V");
294  return jniRegisterNativeMethods(env, "android/emoji/EmojiFactory",
295                                  gMethods, NELEM(gMethods));
296}
297
298}  // namespace android
299