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