Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb956993 authored by Ben Wagner's avatar Ben Wagner
Browse files

Deduplicate font file mappings.

With ttc and gx variation fonts, it is now possible and common that a
number of fonts will use the same font file for data but with different
parameters. In the current code each font will map the font file data,
taking up an unecessary amount of virtual address space and is
inefficient with respect to memory management (like the tlb). This CL
deduplicates these file mappings so that a given font file will only be
mapped into memory once.

DO NOT MERGE
Change-Id: I5ca69f963a434c72ec4028402ecbf9e0f0ee7148
(cherry picked from commit fffcf0a3)
parent e2caaa9c
Loading
Loading
Loading
Loading
+43 −9
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "GraphicsJNI.h"
#include <ScopedPrimitiveArray.h>
#include <ScopedUtfChars.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/AssetManager.h>
#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<jobject>(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<SkFontMgr::FontParameters::Axis[]> skiaAxes;
@@ -109,19 +133,29 @@ static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong
        }
    }

    ScopedUtfChars str(env, path);
    SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
    std::unique_ptr<SkStreamAsset> 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<SkData> data(SkData::NewWithProc(fontPtr, fontSize,
            release_global_ref, reinterpret_cast<void*>(fontRef)));
    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(data));

    SkFontMgr::FontParameters params;
    params.setCollectionIndex(ttcIndex);
    params.setAxes(skiaAxes.get(), skiaAxesLength);

    SkAutoTUnref<SkFontMgr> 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<FontFamily*>(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 },
+4 −3
Original line number Diff line number Diff line
@@ -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<FontListParser.Axis> axes,
    public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontListParser.Axis> 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<FontListParser.Axis> listOfAxis,
            int weight, boolean isItalic);
    private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr,
+24 −5
Original line number Diff line number Diff line
@@ -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<String, ByteBuffer> 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<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>();

            List<FontFamily> familyList = new ArrayList<FontFamily>();
            // 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);
                    }