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类型
- Android 字体加载
- Android WebView加载TTF字体
- Android系统字体加载流程
- 浅析Android字体加载原理
- Android Webview使用自定义字体加载网页
- android自定义字体和程序启动时的加载页面
- android加载第三方字体的方法与效率
- Android 解决TextVIew加载自定义字体慢的问题
- Android中字体设置和calligraphy(高效加载字体包)用法
- 加载新字体
- fcitx加载字体失败
- Flash 动态加载字体
- css加载字体
- WINCE字体动态加载
- 动态加载字体
- css 加载字体
- ios字体加载
- css 加载字体
- lync2013 错误: 已为不同的传输层安全性(TLS)目标找到类型为“McxInternal”且完全限定的域名(FQDN)为
- 线性表顺序表插入操作题
- 十进制转化为二进制、二进制转化为十进制
- javascript
- Android debug.keystore 密码
- Android 字体加载
- 内核线程
- typeid详解
- cookie和session(一)——原理
- Toplitz矩阵 Hankel矩阵 Hilbert矩阵
- stm32之USART
- I/O口推挽输出与开漏输出的区别
- 编程回忆之Android回忆(个性化控件(View)篇)
- NYOJ 236 心急的C小加(最长递增子序列长度)