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