Android 字体加载

来源:互联网 发布:野兽骑行 知乎 编辑:程序博客网 时间:2024/05/22 04:02

1.      Font配置文件

    位于frameworks/base/data/fonts

    system_fonts.xml  fallback_fonts.xml

 

文件结构

    <family>

        <nameset>

            <name>sans-serif</name>

            <name>arial</name>

            <name>helvetica</name>

            <name>tahoma</name>

            <name>verdana</name>

        </nameset>

        <fileset>

            <file>Roboto-Regular.ttf</file>

            <file>Roboto-Bold.ttf</file>

            <file>Roboto-Italic.ttf</file>

            <file>Roboto-BoldItalic.ttf</file>

        </fileset>

    </family>

 

可以称每一个 family为一个字体族。 包括:正常字体,粗体,斜体,粗体斜体,每个家族包括四种字体,这四种字体不是都必须的。

2.      字体加载

zygote初始化时preloadclass会加载Typeface类,在这个类中会调用jni-->skia 加载字体。

 

(1)一些数据类型,加载字体解析xml文件,保存到这些数据结构中。

 

structFontFamily {                           --->  family    SkTDArray<const char*>   fNames;        --->   name     ---> gDefaultNames    SkTDArray<FontFileInfo*>fFontFileArray;     --->  file       ---> gSystemFonts    int order;};

 

FontFamily可以理解为字体族,对应一个<family>标签。

SkTDArray<constchar*>   fNames 保存了<name>字段。

SkTDArray<FontFileInfo*>fFontFileArray 保存了<file>。

 

一个SkTDArray<FontFamily*>,可以保存整个xml文件信息。

structFontFileInfo {    FontFileInfo() : fFileName(NULL),fVariant(SkPaint::kDefault_Variant),            fLanguage() {    }    const char*          fFileName;    SkPaint::FontVariant fVariant;    SkLanguage           fLanguage;};


FontFileInfo包含了三个字段,fFileName代表标签<file>里的字体文件名字;file 可以有属性 variant="elegant" 和 lang="ja",fVariant指属性variant;fLanguage指属性lang。

staticSkTArray<FontInitRec> gSystemFonts;structFontInitRec {    const char*          fFileName;    const char* const*   fNames;    // null-terminated list    SkPaint::FontVariant fVariant;    SkLanguage           fLanguage;};


FontInitRec包含fFileName字体文件名,字体名fNames,及两个属性fVariant,fLanguage。

gSystemFonts 保存的信息与SkTDArray<FontFamily*>相同,也就是整个xml,是把SkTDArray<FontFamily*>又转存为gSystemFonts。loadFontInfoLocked通过遍历SkTDArray<FontFamily*> fontFamilies,将信息保存gSystemFonts,fFileName,fVariant,fLanguage对应fontFamilies 的fontFileInfo。fNames只有第一个<file>才被赋予<nameset>标签名字列表,其余则为null。

 

char**gDefaultNames保存里第一个<family>标签里的<nameset>。

staticFamilyRec* gDefaultFamily 保存里第一个<family>标签里的字体。

staticSkTypeface* gDefaultNormal 默认字库,normal类型


FamilyRec*gFamilyHead = NULL;  gFamilyHead是FamilyRec链表,每个FamilyRec是一个字体族的实例,fFaces[4]即字体族里的4个字体

structFamilyRec {    FamilyRec* fNext;    SkTypeface* fFaces[4];     FamilyRec() : fNext(NULL) {        memset(fFaces, 0, sizeof(fFaces));    }};

 

 

(2)字体加载流程

zygote初始化时preloadclass会加载Typeface类,进行初始化。

Typeface.java静态块

   static {        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),        };    }


create->nativeCreate->Typeface_create->

     SkTypeface::CreateFromName->SkFontHost::CreateTypeface->createTypefaceLocked

 

从 SkTypeface::CreateFromName 进入了skia图形库。


loadSystemFontsLocked是createTypefaceLocked最重要的一步,其余的步骤就是查找最合适的字体类型。


staticSkTypeface* createTypefaceLocked(const SkTypeface* familyFace,        const char familyName[], const void*data, size_t bytelength,        SkTypeface::Style style) {    loadSystemFontsLocked();     // clip to legal style bits    style = (SkTypeface::Style)(style &SkTypeface::kBoldItalic);     SkTypeface* tf = NULL;     if (NULL != familyFace) {        tf = findTypefaceLocked(familyFace,style);    } else if (NULL != familyName) {        tf = findTypefaceLocked(familyName,style);    }     if (NULL == tf) {        tf = findBestFaceLocked(gDefaultFamily,style);    }     // we ref(), since the semantic is toreturn a new instance    tf->ref();    return tf;}staticvoid initSystemFontsLocked() {    // check if we've already been called    if (gDefaultNormal) {        return;    }     SkASSERT(gUniqueFontID == 0);     loadFontInfoLocked(); → 解析xml文件,保存到gSystemFonts等数据结构中     SkTypeface* firstInFamily = NULL;    for (int i = 0; i <gSystemFonts.count(); i++) {        // if we're the first in a new family,clear firstInFamily        const char* const* names =gSystemFonts[i].fNames;        if (names != NULL) {            firstInFamily = NULL;        }         bool isFixedWidth;        SkString name;        SkTypeface::Style style;         // we expect all the fonts, except the"fallback" fonts        bool isExpected = (names != gFBNames);        if(!getNameAndStyle(gSystemFonts[i].fFileName, &name, &style,                &isFixedWidth, isExpected)){ → 读取ttf字体文件,获取字体的name和sytle            // We need to increasegUniqueFontID here so that the unique id of            // each font matches its index ingSystemFonts array, as expected            // by findUniqueIDLocked.            sk_atomic_inc(&gUniqueFontID);            continue;        }         SkString fullpath;        getFullPathForSysFonts(&fullpath,gSystemFonts[i].fFileName);         tf = SkNEW_ARGS(FileTypeface, (style,                    true,  // system-font (cannot delete)                    datapath.c_str(), //filename                    isFixedWidth));        → 为每个ttf创建字体类型  FileTypeface         addTypefaceLocked(tf, firstInFamily); →将每个字体FileTypeface放到gFamilyHead中         if (names != NULL) {            // see if this is one of our fallbackfonts            if (names == gFBNames) {                // add to appropriate fallbackchains                FallbackFontRec fallbackRec;                fallbackRec.fFontID =tf->uniqueID();                fallbackRec.fVariant =gSystemFonts[i].fVariant;                addFallbackFontLocked(fallbackRec,gSystemFonts[i].fLanguage);            }             firstInFamily = tf;            FamilyRec* family =findFamilyLocked(tf);             // record the default family ifthis is it            if (names == gDefaultNames) {                gDefaultFamily = family;       → gDefaultFamily保存里第一个<family>里的<fileset>            }            // add the names to map to thisfamily            while (*names) {                addNameLocked(*names, family);                names += 1;            }        }    }    finaliseFallbackFontListsLocked();     // do this after all fonts are loaded. Thisis our default font, and it    // acts as a sentinel so we only executeloadSystemFontsLocked() once    gDefaultNormal= findBestFaceLocked(gDefaultFamily, SkTypeface::kNormal); → gDefaultNormal 保存第一个<family>里的normal 字体} staticvoid loadFontInfoLocked() {    resetFallbackFontListsLocked();     SkTDArray<FontFamily*> fontFamilies;    getFontFamilies(fontFamilies);  → 解析system_fonts.xml 文件     gSystemFonts.reset();     for (int i = 0; i <fontFamilies.count(); ++i) {        FontFamily *family = fontFamilies[i];        for (int j = 0; j <family->fFontFileArray.count(); ++j) {→遍历每个family的字体            const char* filename =family->fFontFileArray[j]->fFileName;            if (haveSystemFont(filename)){→  根据文件名判断,如果gSystemFonts 已经保存了,则跳过。                continue;            }             FontInitRec fontInfoRecord;            fontInfoRecord.fFileName =filename;            fontInfoRecord.fVariant =family->fFontFileArray[j]->fVariant;            fontInfoRecord.fLanguage =family->fFontFileArray[j]->fLanguage;            if (j == 0) {                if (family->fNames.count()== 0) {                    // Fallback font                    fontInfoRecord.fNames =(char **)gFBNames;                } else {                    SkTDArray<constchar*> names = family->fNames;                    const char **nameList =(const char**)                            malloc((names.count() + 1) *sizeof(char*));                    if (nameList == NULL) {                        // shouldn't get here                        break;                    }                    if (gDefaultNames == NULL){                        gDefaultNames = (char**)nameList; →  gDefaultNames指向第一个family的名字                    }                    for (int i = 0; i <names.count(); ++i) {                        nameList[i] = names[i];                    }                    nameList[names.count()] = NULL;                    fontInfoRecord.fNames =nameList;                }            } else {                fontInfoRecord.fNames = NULL; →除了family的第一个字体,其他的fNames都是null            }            gSystemFonts.push_back(fontInfoRecord);→ 将每一个family保存到 gSystemFonts        }    }    fontFamilies.deleteAll(); }


 

 

loadSystemFontsLocked->initSystemFontsLocked

loadFontInfoLocked解析 system_fonts.xmlfallback_fonts.xml,保存到gSystemFonts。


    getFontFamilies

        从/system/etc/system_fonts.xml读取字体信息,并加载字体信息,保存到 SkTDArray<FontFamily*> fontFamilies;

        然后遍历 fontFamilies,将数据保存到gSystemFonts。


    gDefaultNames保存里第一个<family>标签里的<nameset>。

 

    SkNEW_ARGS:创建每种字体FileTypeface

    addTypefaceLocked:把创建的字体保存到gFamilyHead链表,gFamilyHead每个节点保存了一个字体family,包含常规、粗体、斜体、粗斜体4种类型。

 

    gdefaultFamily 保存里第一个<family>标签里的字体。

   

    gdefaultNormal 默认字库normal类型

0 0
原创粉丝点击