文档章节

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

WolfCS
 WolfCS
发布于 2015/01/11 16:36
字数 3237
阅读 6987
收藏 14

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。

© 著作权归作者所有

WolfCS
粉丝 82
博文 147
码字总数 505184
作品 4
杭州
高级程序员
私信 提问
android游戏开发框架libgdx的使用(二十一)—使用TTF字库支持中文

好久没有更新这个系列的文章了。今天下午在群上讨论libgdx对中文的支持问题。本来Hiero做是最好的,但是LIbgdx的BitmapFont不支持多图,常用汉字3500个,是在做不到一张图上。 libgdx很早之前...

长平狐
2013/11/25
1K
0
Android assets的一个bug

由于要显示一些奇奇怪怪的日文字符,我们在应用里放了一个字库文件,譬如叫做,放在目录下打包。 开发、调试一切正常。可是突然发现,在Android 2.2的设备上,文字无法显示。折腾一番后发现了...

loveisbug
2013/12/13
365
0
谷歌悄无声息地发布安卓 5.1 Lollipop

突如其来地,谷歌在没有任何正式声明的情况下确认发布安卓5.1 Lollipop。 该公司官方网站Android One(该网站出售便宜的库存安卓手机)上的一则更新消息宣布,其每一部新设备都“将运行最新、...

空云万里晴
2015/02/07
5.6K
5
Skia中遍历Linux系统字库文件

Skia 是android平台使用的2D图形库。但这个库的设计目标是能够跨平台的使用,因而尽管目前还不是很完善,但在Linux平台下大部分功能还是能够使用的。 Skia内建字库文件管理系统。Skia用SkTyp...

WolfCS
2013/02/24
1K
2
编译android源代码以及ramdisk.img system.img userdata.i...

一、编译android 源码 参考 http://my.oschina.net/u/561492/blog/89965 编译完成后,可以在源码目录的out/target/product/generic/目录下看到编译好的ramdisk.img、system.img 和 userdata...

wangxigui
2012/11/19
555
0

没有更多内容

加载失败,请刷新页面

加载更多

MySQL左连接问题,右表做筛选,左表列依然在

两张表,一张user表,一张user_log表 CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFA......

bengozhong
6分钟前
2
0
重新开始学Java——多线程基础

多线程 进程 主流计算机操作系统都支持同时运行多个任务 , 每个任务通常就是一个程序 , 每个运行中的程序就是一个进程或者多个进程 。 进程的特点 独立性 进程是系统中独立存在的实体 可以...

大家都是低调来的
7分钟前
1
0
注解在Java中是如何工作的?

> 来一点咖啡,准备好进入注解的世界。 注解一直是 Java 的一个非常重要的部分,它从 J2SE 5.0 开始就已经存在了。在我们的应用程序代码中,经常看到 @Override 和 @Deprecated 这样的注解。...

liululee
9分钟前
3
0
Docker 容器连接

Docker 容器连接 容器间的链接有两种方法,你选择其一即可 网络端口映射 docker run -d -P docker run -d -p-P :是容器内部端口随机映射到主机的高端口。-p : 是容器内部端口绑定到指定...

测者陈磊
12分钟前
2
0
车载导航应用中基于Sketch UI主题定制方案的实现

1.导读 关于应用的主题定制,相信大家或多或少都有接触,基本上,实现思路可以分为两类: 内置主题(应用内自定义style) 外部加载方式(资源apk形式、压缩资源、插件等) 其实,针对不同的主题...

阿里云官方博客
17分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部