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类型