![e0754c67c3e24feb1cc238f569a70494.png](https://img-blog.csdnimg.cn/img_convert/e0754c67c3e24feb1cc238f569a70494.png)
简介
Qt中对于字体处理最常用的三个类
- QFontDataBase
- QFont
- QFontInfo
今天主要讲的是Qt在Linux下字体的基础-QFontDataBase类。
QFontDataBase
QFontDataBase为Qt提供了当前系统所有可用的字体及其信息
Linux平台
Linux平台下,Qt解析字体相关的库使用的是FontConfig。 Fontconfig是用于配置和自定义字体访问的库。
Fontconfig可以: 自动安装时发现新字体,从而消除了常见的配置问题。 执行字体名称替换,以便在缺少字体时可以选择适当的替代字体。 确定完全覆盖一组语言所需的一组字体。 因为使用基于XML的配置文件而构建了GUI配置工具(尽管具有自动发现功能,但我们认为这种需求已最小化)。 即使已安装了数千种字体,也可以在减少内存使用的同时,高效,快速地在已安装的字体集中找到所需的字体。 与X Render Extension和FreeType配合使用,可在显示器上实现高质量,抗锯齿和亚像素渲染的文本。
Fontconfig不会: 自己渲染字体(留给FreeType或其他渲染机制) 以任何方式依赖于X Window系统,因此仅打印机应用程序不具有此类依赖关系
Qt的流程
所以Qt解析字体的一个流程即
使用FontConfig提取字体相关的信息(比如字体名称,风格)。组织成Qt自己的数据结构。然后再提供给QFont,QFontInfo等类来使用。
先上Qt中使用FontConfig解析字体相关信息的代码
//qt-everywhere-src-5.15.0/qtbase/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
void QFontconfigDatabase::populateFontDatabase()
{
FcInit();
FcFontSet *fonts;
{
FcObjectSet *os = FcObjectSetCreate();
FcPattern *pattern = FcPatternCreate();
const char *properties [] = {
FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT,
FC_SPACING, FC_FILE, FC_INDEX,
FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE,
FC_WIDTH, FC_FAMILYLANG,
#if FC_VERSION >= 20297
FC_CAPABILITY,
#endif
(const char *)nullptr
};
const char **p = properties;
while (*p) {
FcObjectSetAdd(os, *p);
++p;
}
fonts = FcFontList(nullptr, pattern, os);
FcObjectSetDestroy(os);
FcPatternDestroy(pattern);
}
上面代码首先将 字体中需要解析的信息(比如字体名称FC_FAMILY,字体风格FC_STYLEden 等等) 塞到FcObjectSet
中,等待解析。然后通过函数FcFontList
获取系统中所有的字体信息(上面我们添加的)FcFontSet *fonts
然后开始通过循环解析我们系统中的字体
for (int i = 0; i < fonts->nfont; i++)
populateFromPattern(fonts->fonts[i]);
下面开始讲解 populateFromPattern
if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) != FcResultMatch)
return;
familyName = QString::fromUtf8((const char *)value);
if (FcPatternGetString(pattern, FC_FAMILYLANG, 0, &value) == FcResultMatch)
familyNameLang = QString::fromUtf8((const char *)value);
通过上面的函数我们得到了字体的名称,跟名称对应的语言。即 FC_FAMILY FC_FAMILYLANG。这里只上了部分代码,其它的函数也是如此获取的字体相关的信息
//xxxxxxxxxxxxxxxxxxxxxxxxxxx
if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant_value) != FcResultMatch)
slant_value = FC_SLANT_ROMAN;
if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight_value) != FcResultMatch)
weight_value = FC_WEIGHT_REGULAR;
if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width_value) != FcResultMatch)
width_value = FC_WIDTH_NORMAL;
if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing_value) != FcResultMatch)
spacing_value = FC_PROPORTIONAL;
if (FcPatternGetString(pattern, FC_FILE, 0, &file_value) != FcResultMatch)
file_value = nullptr;
if (FcPatternGetInteger(pattern, FC_INDEX, 0, &indexValue) != FcResultMatch)
indexValue = 0;
if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch)
scalable = FcTrue;
if (FcPatternGetString(pattern, FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
foundry_value = nullptr;
if (FcPatternGetString(pattern, FC_STYLE, 0, &style_value) != FcResultMatch)
style_value = nullptr;
if (FcPatternGetBool(pattern,FC_ANTIALIAS,0,&antialias) != FcResultMatch)
antialias = true;
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
这样,我们就得到了所有的字体信息,然后最后通过函数放入到Qt中
void qt_registerFont(const QString &familyName, const QString &stylename,
const QString &foundryname, int weight,
QFont::Style style, int stretch, bool antialiased,
bool scalable, int pixelSize, bool fixedPitch,
const QSupportedWritingSystems &writingSystems, void *handle)
{
QFontDatabasePrivate *d = privateDb();
qCDebug(lcFontDb) << "Adding font: familyName" << familyName << "stylename" << stylename << "weight" << weight
<< "style" << style << "pixelSize" << pixelSize << "antialiased" << antialiased << "fixed" << fixedPitch;
QtFontStyle::Key styleKey;
styleKey.style = style;
styleKey.weight = weight;
styleKey.stretch = stretch;
QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::EnsureCreated);
f->fixedPitch = fixedPitch;
for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
if (writingSystems.supported(QFontDatabase::WritingSystem(i)))
f->writingSystems[i] = QtFontFamily::Supported;
}
QtFontFoundry *foundry = f->foundry(foundryname, true);
QtFontStyle *fontStyle = foundry->style(styleKey, stylename, true);
fontStyle->smoothScalable = scalable;
fontStyle->antialiased = antialiased;
QtFontSize *size = fontStyle->pixelSize(pixelSize ? pixelSize : SMOOTH_SCALABLE, true);
if (size->handle) {
QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
if (integration)
integration->fontDatabase()->releaseHandle(size->handle);
}
size->handle = handle;
f->populated = true;
}
最后总结下:实际上,Qt在不同的平台,分别调用的当前系统的库函数,来封装成统一的接口提供给开发者,我们不需要自己再引用对应的库了。这才是Qt的理念。 Code Less