android 5.0中字库文件管理配置的变化

原创
2015/01/11 16:36
阅读数 7.7K

android 5.0中字庫文件管理配置的變化,主要需要來關注的地方是,與Typeface有關的一些變動。在android 5.0系統裏面,新增加了一個名爲fonts.xml的文件,來做系統字庫文件的配置管理,這個文件在代碼庫中的位置爲:frameworks/base/data/fonts/fonts.xml。我們可以來看一下這個新增文件的具體內容:

<?xml version="1.0" encoding="utf-8"?>
<!--
    NOTE: this is the newer (L) version of the system font configuration,
    supporting richer weight selection. Some apps will expect the older
    version, so please keep system_fonts.xml and fallback_fonts.xml in sync
    with any changes, even though framework will only read this file.

    All fonts withohut names are added to the default list. Fonts are chosen
    based on a match: full BCP-47 language tag including script, then just
    language, and finally order (the first font containing the glyph).

    Order of appearance is also the tiebreaker for weight matching. This is
    the reason why the 900 weights of Roboto precede the 700 weights - we
    prefer the former when an 800 weight is requested. Since bold spans
    effectively add 300 to the weight, this ensures that 900 is the bold
    paired with the 500 weight, ensuring adequate contrast.
-->
<familyset version="22">
    <!-- first font is default -->
    <family name="sans-serif">
        <font weight="100" style="normal">Roboto-Thin.ttf</font>
        <font weight="100" style="italic">Roboto-ThinItalic.ttf</font>
        <font weight="300" style="normal">Roboto-Light.ttf</font>
        <font weight="300" style="italic">Roboto-LightItalic.ttf</font>
        <font weight="400" style="normal">Roboto-Regular.ttf</font>
        <font weight="400" style="italic">Roboto-Italic.ttf</font>
        <font weight="500" style="normal">Roboto-Medium.ttf</font>
        <font weight="500" style="italic">Roboto-MediumItalic.ttf</font>
        <font weight="900" style="normal">Roboto-Black.ttf</font>
        <font weight="900" style="italic">Roboto-BlackItalic.ttf</font>
        <font weight="700" style="normal">Roboto-Bold.ttf</font>
        <font weight="700" style="italic">Roboto-BoldItalic.ttf</font>
    </family>

    <!-- Note that aliases must come after the fonts they reference. -->
    <alias name="sans-serif-thin" to="sans-serif" weight="100" />
    <alias name="sans-serif-light" to="sans-serif" weight="300" />
    <alias name="sans-serif-medium" to="sans-serif" weight="500" />
    <alias name="sans-serif-black" to="sans-serif" weight="900" />
    <alias name="arial" to="sans-serif" />
    <alias name="helvetica" to="sans-serif" />
    <alias name="tahoma" to="sans-serif" />
    <alias name="verdana" to="sans-serif" />

    <family name="sans-serif-condensed">
        <font weight="300" style="normal">RobotoCondensed-Light.ttf</font>
        <font weight="300" style="italic">RobotoCondensed-LightItalic.ttf</font>
        <font weight="400" style="normal">RobotoCondensed-Regular.ttf</font>
        <font weight="400" style="italic">RobotoCondensed-Italic.ttf</font>
        <font weight="700" style="normal">RobotoCondensed-Bold.ttf</font>
        <font weight="700" style="italic">RobotoCondensed-BoldItalic.ttf</font>
    </family>
    <alias name="sans-serif-condensed-light" to="sans-serif-condensed" weight="300" />

    <family name="serif">
        <font weight="400" style="normal">NotoSerif-Regular.ttf</font>
        <font weight="700" style="normal">NotoSerif-Bold.ttf</font>
        <font weight="400" style="italic">NotoSerif-Italic.ttf</font>
        <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font>
    </family>
    <alias name="times" to="serif" />
    <alias name="times new roman" to="serif" />
    <alias name="palatino" to="serif" />
    <alias name="georgia" to="serif" />
    <alias name="baskerville" to="serif" />
    <alias name="goudy" to="serif" />
    <alias name="fantasy" to="serif" />
    <alias name="ITC Stone Serif" to="serif" />

    <family name="monospace">
        <font weight="400" style="normal">DroidSansMono.ttf</font>
    </family>
    <alias name="sans-serif-monospace" to="monospace" />
    <alias name="monaco" to="monospace" />

    <family name="serif-monospace">
        <font weight="400" style="normal">CutiveMono.ttf</font>
    </family>
    <alias name="courier" to="serif-monospace" />
    <alias name="courier new" to="serif-monospace" />

    <family name="casual">
        <font weight="400" style="normal">ComingSoon.ttf</font>
    </family>

    <family name="cursive">
        <font weight="400" style="normal">DancingScript-Regular.ttf</font>
        <font weight="700" style="normal">DancingScript-Bold.ttf</font>
    </family>

    <family name="sans-serif-smallcaps">
        <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font>
    </family>

    <!-- fallback fonts -->
    <family variant="elegant">
        <font weight="400" style="normal">NotoNaskh-Regular.ttf</font>
        <font weight="700" style="normal">NotoNaskh-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoNaskhUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoNaskhUI-Bold.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
    </family>
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansThai-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font>
    </family>
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansDevanagari-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansDevanagari-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansDevanagariUI-Bold.ttf</font>
    </family>
    <!-- Gujarati should come after Devanagari -->
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansGujarati-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
    </family>
    <!-- Gurmukhi should come after Devanagari -->
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansGurmukhi-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansGurmukhi-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font>
    </family>
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansTamil-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansTamil-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansTamilUI-Bold.ttf</font>
    </family>
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansMalayalam-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansMalayalam-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansMalayalamUI-Bold.ttf</font>
    </family>
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansBengali-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansBengali-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansBengaliUI-Bold.ttf</font>
    </family>
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansTelugu-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansTelugu-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font>
    </family>
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansKannada-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansKannada-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font>
    </family>
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansKhmer-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansKhmer-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
    </family>
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansLao-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
    </family>
    <family variant="elegant">
        <font weight="400" style="normal">NotoSansMyanmar-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansMyanmar-Bold.ttf</font>
    </family>
    <family variant="compact">
        <font weight="400" style="normal">NotoSansMyanmarUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansMyanmarUI-Bold.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
    </family>
    <family lang="zh-Hans">
        <font weight="400" style="normal">NotoSansHans-Regular.otf</font>
    </family>
    <family lang="zh-Hant">
        <font weight="400" style="normal">NotoSansHant-Regular.otf</font>
    </family>
    <family lang="ja">
        <font weight="400" style="normal">NotoSansJP-Regular.otf</font>
    </family>
    <family lang="ko">
        <font weight="400" style="normal">NotoSansKR-Regular.otf</font>
    </family>
    <family>
        <font weight="400" style="normal">NanumGothic.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">NotoColorEmoji.ttf</font>
    </family>
    <family>
        <font weight="400" style="normal">DroidSansFallback.ttf</font>
    </family>
    <family lang="ja">
        <font weight="400" style="normal">MTLmr3m.ttf</font>
    </family>
</familyset>

如同這個文件開頭的註釋中所描述的那樣,暫時爲了保持兼容性,仍然會保留老的字庫配置文件system_fonts.xml和fallback_fonts.xml,並要求這個文件隨時要與那兩個文件同步。也就是說,這個文件中會包含那兩個文件所包含的全部內容,並且這個文件還會提供更加豐富的功能。

看到這裏,我們難免會產生疑問,這個文件是在什麼地方加載解析的呢?而加載解析出來的信息又是如何被使用的呢?

簡單搜索,不難明白,這個文件正是在android.graphics.Typeface class初始化的時候進行加載的,其整個的過程如下:

static Typeface[] sDefaults;
    private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache =
            new LongSparseArray<SparseArray<Typeface>>(3);

    static Typeface sDefaultTypeface;
    static Map<String, Typeface> sSystemFontMap;
    static FontFamily[] sFallbackFonts;

    static final String FONTS_CONFIG = "fonts.xml";


    private static void setDefault(Typeface t) {
        sDefaultTypeface = t;
        nativeSetDefault(t.native_instance);
    }


    /**
     * Create a new typeface from an array of font families.
     *
     * @param families array of font families
     * @hide
     */
    public static Typeface createFromFamilies(FontFamily[] families) {
        long[] ptrArray = new long[families.length];
        for (int i = 0; i < families.length; i++) {
            ptrArray[i] = families[i].mNativePtr;
        }
        return new Typeface(nativeCreateFromArray(ptrArray));
    }

    /**
     * Create a new typeface from an array of font families, including
     * also the font families in the fallback list.
     *
     * @param families array of font families
     * @hide
     */
    public static Typeface createFromFamiliesWithDefault(FontFamily[] families) {
        long[] ptrArray = new long[families.length + sFallbackFonts.length];
        for (int i = 0; i < families.length; i++) {
            ptrArray[i] = families[i].mNativePtr;
        }
        for (int i = 0; i < sFallbackFonts.length; i++) {
            ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr;
        }
        return new Typeface(nativeCreateFromArray(ptrArray));
    }

    // don't allow clients to call this directly
    private Typeface(long ni) {
        if (ni == 0) {
            throw new RuntimeException("native typeface cannot be made");
        }

        native_instance = ni;
        mStyle = nativeGetStyle(ni);
    }

    private static FontFamily makeFamilyFromParsed(FontListParser.Family family) {
        FontFamily fontFamily = new FontFamily(family.lang, family.variant);
        for (FontListParser.Font font : family.fonts) {
            fontFamily.addFontWeightStyle(font.fontName, font.weight, font.isItalic);
        }
        return fontFamily;
    }

    /*
     * (non-Javadoc)
     *
     * This should only be called once, from the static class initializer block.
     */
    private static void init() {
        // Load font config and initialize Minikin state
        File systemFontConfigLocation = getSystemFontConfigLocation();
        File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
        try {
            FileInputStream fontsIn = new FileInputStream(configFilename);
            FontListParser.Config fontConfig = FontListParser.parse(fontsIn);

            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++) {
                Family f = fontConfig.families.get(i);
                if (i == 0 || f.name == null) {
                    familyList.add(makeFamilyFromParsed(f));
                }
            }
            sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
            setDefault(Typeface.createFromFamilies(sFallbackFonts));

            Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
            for (int i = 0; i < fontConfig.families.size(); i++) {
                Typeface typeface;
                Family f = fontConfig.families.get(i);
                if (f.name != null) {
                    if (i == 0) {
                        // The first entry is the default typeface; no sense in
                        // duplicating the corresponding FontFamily.
                        typeface = sDefaultTypeface;
                    } else {
                        FontFamily fontFamily = makeFamilyFromParsed(f);
                        FontFamily[] families = { fontFamily };
                        typeface = Typeface.createFromFamiliesWithDefault(families);
                    }
                    systemFonts.put(f.name, typeface);
                }
            }
            for (FontListParser.Alias alias : fontConfig.aliases) {
                Typeface base = systemFonts.get(alias.toName);
                Typeface newFace = base;
                int weight = alias.weight;
                if (weight != 400) {
                    newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
                }
                systemFonts.put(alias.name, newFace);
            }
            sSystemFontMap = systemFonts;

        } catch (RuntimeException e) {
            Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
            // TODO: normal in non-Minikin case, remove or make error when Minikin-only
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Error opening " + configFilename);
        } catch (IOException e) {
            Log.e(TAG, "Error reading " + configFilename);
        } catch (XmlPullParserException e) {
            Log.e(TAG, "XML parse exception for " + configFilename);
        }
    }

    static {
        init();
        // Set up defaults and typefaces exposed in public API
        DEFAULT         = create((String) null, 0);
        DEFAULT_BOLD    = create((String) null, Typeface.BOLD);
        SANS_SERIF      = create("sans-serif", 0);
        SERIF           = create("serif", 0);
        MONOSPACE       = create("monospace", 0);

        sDefaults = new Typeface[] {
            DEFAULT,
            DEFAULT_BOLD,
            create((String) null, Typeface.ITALIC),
            create((String) null, Typeface.BOLD_ITALIC),
        };

    }


    private static File getSystemFontConfigLocation() {
        return new File("/system/etc/");
    }


    private static native long nativeCreateFromTypeface(long native_instance, int style);
    private static native long nativeCreateWeightAlias(long native_instance, int weight);

前面我們提到的那個fonts.xml文件,在編譯的時候,會被放在system/etc/下,此處會加載那個文件。通過FontListParser.parse(fontsIn)將文件中的所有信息解析爲一個FontListParser.Config結構。

此處我們還是先來看一下,相關的這樣一些結構(android.graphics.FontListParser):

public class FontListParser {

    public static class Config {
        Config() {
            families = new ArrayList<Family>();
            aliases = new ArrayList<Alias>();
        }
        public List<Family> families;
        public List<Alias> aliases;
    }

    public static class Font {
        Font(String fontName, int weight, boolean isItalic) {
            this.fontName = fontName;
            this.weight = weight;
            this.isItalic = isItalic;
        }
        public String fontName;
        public int weight;
        public boolean isItalic;
    }

    public static class Alias {
        public String name;
        public String toName;
        public int weight;
    }

    public static class Family {
        public Family(String name, List<Font> fonts, String lang, String variant) {
            this.name = name;
            this.fonts = fonts;
            this.lang = lang;
            this.variant = variant;
        }

        public String name;
        public List<Font> fonts;
        public String lang;
        public String variant;
    }

用一张图来简单描述上面各个结构之间的关系:

FontListParser.Config中包含一个FontListParser.Family的列表和一个FontListParser.Alias的列表。FontListParser.Alias描述了一个FontListParser.Family的别名,它会帮忙建立别名到FontListParser.Family的映射关系。一个FontListParser.Family则可能有一个或多个FontListParser.Font组成。每个FontListParser.Font描述了一个字库文件,会包含有字库文件的路径、语言、variant等信息。可以认为FontListParser.Config就是fonts.xml文件中根元素familyset的映射,FontListParser.Family就是fonts.xml文件中一个family元素的映射,FontListParser.Alias是一个alias元素的映射,而FontListParser.Font则是一个font元素的映射。

我们简单地扫一眼FontListParser中解析整个文件的过程,唯一值得注意的地方就是FontListParser.Font的fontName。解析之后,这个字段中保存的不再仅仅是一个字库文件的文件名,而是字库文件的完整的路径名,系统的字库文件存放路径均为/system/fonts/。至于其他方面,则这些结构就都是文件内容的比较直接的映射了。

了解了这些相关的结构之后,我们继续来看前面Typeface.init()对于FontListParser.Config中保存的解析出来的数据的处理。

在解析出了FontListParser.Config之后,它首先会创建fallback font family的列表。它会为每个fallback font的FontListParser.Family创建一个FontFamily结构,并将这所有的这些fallback font的FontFamily保存在一个数组sFallbackFonts中。Family list中的第一个family或者没有family name的font family会被认为是fallback font family。

紧接着它就会创建default 的typeface。

然后它会创建一个system font family的typeface列表。首先呢,它会为每一个system类型,即family name不会空的FontListParser.Family创建typeface。紧接着,它会为所有的FontListParser.Alias创建system font family的typeface。

以个人的理解,android 5.0中,Java framework层似乎是在此处用sDefaultTypeface和sSystemFontMap将系统中所有的字库文件的typeface都给串起来了。整个的结构大体如下图这样:


这个过程似乎还有一个谜没有解开,那就是nativeCreateFromArray(),拿到了一堆的native层FontFamily结构的指针去创建native的typeface,它究竟都干了什么事情呢?接着我们就来看一下,在frameworks/base/core/jni/android/graphics/Typeface.cpp文件中这个方法的实现:

static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray) {
    ScopedLongArrayRO families(env, familyArray);
    return reinterpret_cast<jlong>(TypefaceImpl_createFromFamilies(families.get(), families.size()));
}
进一步是TypefaceImpl_createFromFamilies(),在frameworks/base/core/jni/android/graphics/TypefaceImpl.cpp中:

TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
    std::vector<FontFamily *>familyVec;
    for (size_t i = 0; i < size; i++) {
        FontFamily* family = reinterpret_cast<FontFamily*>(families[i]);
        familyVec.push_back(family);
    }
    TypefaceImpl* result = new TypefaceImpl;
    result->fFontCollection = new FontCollection(familyVec);
    if (size == 0) {
        ALOGW("createFromFamilies creating empty collection");
        result->fSkiaStyle = SkTypeface::kNormal;
    } else {
        const FontStyle defaultStyle;
        FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]);
        MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
        if (mf != NULL) {
            SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
            // TODO: probably better to query more precise style from family, will be important
            // when we open up API to access 100..900 weights
            result->fSkiaStyle = skTypeface->style();
        } else {
            result->fSkiaStyle = SkTypeface::kNormal;
        }
    }
    result->fBaseWeight = 400;
    resolveStyle(result);
    return result;
}

可以看到,在此处,创建一个TypefaceImpl,然后这个结构会指向一个FontCollection,而在后者中,将保存传入的所有的字库文件的Typeface的引用。

那创建的这些结构究竟都有些什么用呢?可以看一些android.graphics.Typeface中的其他方法:

/**
     * Create a typeface object given a family name, and option style information.
     * If null is passed for the name, then the "default" font will be chosen.
     * The resulting typeface object can be queried (getStyle()) to discover what
     * its "real" style characteristics are.
     *
     * @param familyName May be null. The name of the font family.
     * @param style  The style (normal, bold, italic) of the typeface.
     *               e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
     * @return The best matching typeface.
     */
    public static Typeface create(String familyName, int style) {
        if (sSystemFontMap != null) {
            return create(sSystemFontMap.get(familyName), style);
        }
        return null;
    }


    /**
     * Create a new typeface from the specified font data.
     * @param mgr The application's asset manager
     * @param path  The file name of the font data in the assets directory
     * @return The new typeface.
     */
    public static Typeface createFromAsset(AssetManager mgr, String path) {
        if (sFallbackFonts != null) {
            FontFamily fontFamily = new FontFamily();
            if (fontFamily.addFontFromAsset(mgr, path)) {
                FontFamily[] families = { fontFamily };
                return createFromFamiliesWithDefault(families);
            }
        }
        throw new RuntimeException("Font asset not found " + path);
    }


    /**
     * Create a new typeface from the specified font file.
     *
     * @param path The full path to the font data.
     * @return The new typeface.
     */
    public static Typeface createFromFile(String path) {
        if (sFallbackFonts != null) {
            FontFamily fontFamily = new FontFamily();
            if (fontFamily.addFont(path)) {
                FontFamily[] families = { fontFamily };
                return createFromFamiliesWithDefault(families);
            }
        }
        throw new RuntimeException("Font not found " + path);
    }
指定字库文件创建Typeface时就总是会用到fallback fonts的信息,而不指定字库文件创建Typeface时,则总是会用到system fonts的有关信息。

Done。

展开阅读全文
打赏
0
14 收藏
分享
加载中
更多评论
打赏
0 评论
14 收藏
0
分享
返回顶部
顶部