diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp index 149ff557645da..2e974a3ecaa38 100644 --- a/core/jni/android/graphics/FontFamily.cpp +++ b/core/jni/android/graphics/FontFamily.cpp @@ -26,6 +26,7 @@ #include "GraphicsJNI.h" #include #include +#include #include #include #include "Utils.h" @@ -82,9 +83,32 @@ static struct { jfieldID mStyleValue; } gAxisClassInfo; +static void release_global_ref(const void* /*data*/, void* context) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + bool needToAttach = (env == NULL); + if (needToAttach) { + JavaVMAttachArgs args; + args.version = JNI_VERSION_1_4; + args.name = "release_font_data"; + args.group = NULL; + jint result = AndroidRuntime::getJavaVM()->AttachCurrentThread(&env, &args); + if (result != JNI_OK) { + ALOGE("failed to attach to thread to release global ref."); + return; + } + } + + jobject obj = reinterpret_cast(context); + env->DeleteGlobalRef(obj); + + if (needToAttach) { + AndroidRuntime::getJavaVM()->DetachCurrentThread(); + } +} + static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr, - jstring path, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) { - NPE_CHECK_RETURN_ZERO(env, path); + jobject font, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) { + NPE_CHECK_RETURN_ZERO(env, font); // Declare axis native type. std::unique_ptr skiaAxes; @@ -109,19 +133,29 @@ static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong } } - ScopedUtfChars str(env, path); - SkAutoTUnref fm(SkFontMgr::RefDefault()); - std::unique_ptr fontData(SkStream::NewFromFile(str.c_str())); - if (!fontData) { - ALOGE("addFont failed to open %s", str.c_str()); + void* fontPtr = env->GetDirectBufferAddress(font); + if (fontPtr == NULL) { + ALOGE("addFont failed to create font, buffer invalid"); return false; } + jlong fontSize = env->GetDirectBufferCapacity(font); + if (fontSize < 0) { + ALOGE("addFont failed to create font, buffer size invalid"); + return false; + } + jobject fontRef = MakeGlobalRefOrDie(env, font); + SkAutoTUnref data(SkData::NewWithProc(fontPtr, fontSize, + release_global_ref, reinterpret_cast(fontRef))); + std::unique_ptr fontData(new SkMemoryStream(data)); + SkFontMgr::FontParameters params; params.setCollectionIndex(ttcIndex); params.setAxes(skiaAxes.get(), skiaAxesLength); + + SkAutoTUnref fm(SkFontMgr::RefDefault()); SkTypeface* face = fm->createFromStream(fontData.release(), params); if (face == NULL) { - ALOGE("addFont failed to create font %s#%d", str.c_str(), ttcIndex); + ALOGE("addFont failed to create font, invalid request"); return false; } FontFamily* fontFamily = reinterpret_cast(familyPtr); @@ -175,7 +209,7 @@ static const JNINativeMethod gFontFamilyMethods[] = { { "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create }, { "nUnrefFamily", "(J)V", (void*)FontFamily_unref }, { "nAddFont", "(JLjava/lang/String;I)Z", (void*)FontFamily_addFont }, - { "nAddFontWeightStyle", "(JLjava/lang/String;ILjava/util/List;IZ)Z", + { "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z", (void*)FontFamily_addFontWeightStyle }, { "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z", (void*)FontFamily_addFontFromAsset }, diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java index 3897c3bf45d8b..f741e3cb5f8de 100644 --- a/graphics/java/android/graphics/FontFamily.java +++ b/graphics/java/android/graphics/FontFamily.java @@ -18,6 +18,7 @@ package android.graphics; import android.content.res.AssetManager; +import java.nio.ByteBuffer; import java.util.List; /** @@ -64,9 +65,9 @@ public class FontFamily { return nAddFont(mNativePtr, path, ttcIndex); } - public boolean addFontWeightStyle(String path, int ttcIndex, List axes, + public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List axes, int weight, boolean style) { - return nAddFontWeightStyle(mNativePtr, path, ttcIndex, axes, weight, style); + return nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style); } public boolean addFontFromAsset(AssetManager mgr, String path) { @@ -76,7 +77,7 @@ public class FontFamily { private static native long nCreateFamily(String lang, int variant); private static native void nUnrefFamily(long nativePtr); private static native boolean nAddFont(long nativeFamily, String path, int ttcIndex); - private static native boolean nAddFontWeightStyle(long nativeFamily, String path, + private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font, int ttcIndex, List listOfAxis, int weight, boolean isItalic); private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 345f257c9371f..f15aff7de39c2 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -27,6 +27,8 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -258,11 +260,26 @@ public class Typeface { mStyle = nativeGetStyle(ni); } - private static FontFamily makeFamilyFromParsed(FontListParser.Family family) { + private static FontFamily makeFamilyFromParsed(FontListParser.Family family, + Map bufferForPath) { FontFamily fontFamily = new FontFamily(family.lang, family.variant); for (FontListParser.Font font : family.fonts) { - fontFamily.addFontWeightStyle(font.fontName, font.ttcIndex, font.axes, - font.weight, font.isItalic); + ByteBuffer fontBuffer = bufferForPath.get(font.fontName); + if (fontBuffer == null) { + try (FileInputStream file = new FileInputStream(font.fontName)) { + FileChannel fileChannel = file.getChannel(); + long fontSize = fileChannel.size(); + fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); + bufferForPath.put(font.fontName, fontBuffer); + } catch (IOException e) { + Log.e(TAG, "Error mapping font file " + font.fontName); + continue; + } + } + if (!fontFamily.addFontWeightStyle(fontBuffer, font.ttcIndex, font.axes, + font.weight, font.isItalic)) { + Log.e(TAG, "Error creating font " + font.fontName + "#" + font.ttcIndex); + } } return fontFamily; } @@ -280,13 +297,15 @@ public class Typeface { FileInputStream fontsIn = new FileInputStream(configFilename); FontListParser.Config fontConfig = FontListParser.parse(fontsIn); + Map bufferForPath = new HashMap(); + List familyList = new ArrayList(); // Note that the default typeface is always present in the fallback list; // this is an enhancement from pre-Minikin behavior. for (int i = 0; i < fontConfig.families.size(); i++) { FontListParser.Family f = fontConfig.families.get(i); if (i == 0 || f.name == null) { - familyList.add(makeFamilyFromParsed(f)); + familyList.add(makeFamilyFromParsed(f, bufferForPath)); } } sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]); @@ -302,7 +321,7 @@ public class Typeface { // duplicating the corresponding FontFamily. typeface = sDefaultTypeface; } else { - FontFamily fontFamily = makeFamilyFromParsed(f); + FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath); FontFamily[] families = { fontFamily }; typeface = Typeface.createFromFamiliesWithDefault(families); }