標籤:chromium skia typeface android jni 瀏覽器開發
這也就是說,Java Activity層的使用者自訂預設字型通過標準framework/JNI的途徑是無法傳遞應用到Chromium核心的。
本來的基本想法是:通過Typeface.DEFAULT獲得Java層的系統當前預設字型設定,通過Java動態反射調用獲得native_instance控制代碼,然後嘗試用JNI C++代碼獲得SkTypeface*指標,調用SkTypeface::serialize序列化到一個臨時字型檔,然後將此路徑回傳Java,再重新傳到Chromium核心代碼。
帖2段核心demo代碼:
AwSettings.java:
//#if ENABLE_USER_OVERRIDES_FONTFALLBACK //hacker techniques to get current system's default typeface and apply it to chromium/skia kernel code: @CalledByNative private static long getDefaultTypefaceNativePointer() { try{ android.graphics.Typeface defaultTypeface = android.graphics.Typeface.DEFAULT; java.lang.reflect.Field field = null; field = android.graphics.Typeface.class.getDeclaredField("native_instance"); long ret = 0; if (android.os.Build.VERSION.SDK_INT>=21) { //5.0+ ret = field.getLong(defaultTypeface); }else{ //4.4- ret = field.getInt(defaultTypeface);//boost to long } Log.i(TAG, "android.graphics.Typeface.DEFAULT.native_instance="+ret); return ret; }catch(Exception e){ Log.e(TAG, e.getMessage(), e); return 0; } } //private boolean sUserOverridesFontFallbackEnabled = false; private static native String nativeGetTempUserOverridesFontFallbackPath(); public void setUserOverridesFontFallbackEnabled(boolean enable) { if (enable) { String path = AwSettings.nativeGetTempUserOverridesFontFallbackPath(); setUserOverridesFontFallback(true, path); }else{ setUserOverridesFontFallback(false, ""); } } //#if
aw_settings.cc:
#if ENABLE_USER_OVERRIDES_FONTFALLBACKstatic jstring GetTempUserOverridesFontFallbackPath(JNIEnv* env, jclass clazz) { VLOG(0)<<"GetTempUserOverridesFontFallbackPath enter"; jlong native_instance_pointer = Java_AwSettings_getDefaultTypefaceNativePointer(env); if(native_instance_pointer==0){ VLOG(0)<<"GetTempUserOverridesFontFallbackPath getDefaultTypefaceNativePointer failed!"; return 0; } //SkTypeface* typeface = (SkTypeface*)(int)native_instance_pointer; // //ALERT: this C++ SkTypeface is got from framework layer, it may not have the same ABI compatibility with chromioum's internal skia library TypefaceImpl* typefaceImpl = (TypefaceImpl*)native_instance_pointer; SkTypeface* typeface = 0; //TODO: cannot get SkTypeface* from TypefaceImpl* //i need a writable path! FilePath cache_dir_filepath; /*bool ret = */base::android::GetCacheDirectory(&cache_dir_filepath); FilePath temp_filepath = cache_dir_filepath.Append( FilePath("test.ttf.ser") ); //<-- TODO: generate this std::string gen_temp_path = temp_filepath.AsUTF8Unsafe(); const char* temp_path = gen_temp_path.c_str(); //"/data/local/test.ttf.ser"; VLOG(0)<<"GetTempUserOverridesFontFallbackPath gen_temp_path="<<temp_path; SkFILEWStream wstream(temp_path); typeface->serialize(&wstream);//may fail, but we don't know! ScopedJavaLocalRef<jstring> jpath = ConvertUTF8ToJavaString(env, temp_path); return jpath.Release(); }#endif
遺憾的是,native_instance實際上對應於不透明的TypefaceImpl*,在JNI下可能也是無法訪問的。即使能訪問,從TypefaceImpl*也得不到SkTypeface*。
Android Chromium:不成功的嘗試,無法從Typeface.java類獲得C++ SkTypeface對象