Fontconfig font database: Short-circuit matching by filename

If the filename matches, no other matching is necessary. Fontconfig
doesn't have a fast path for that, so implement one here.
Fontconfig is unlikely to add that fast path, see here:
https://gitlab.freedesktop.org/fontconfig/fontconfig/issues/103

With -O1 builds of Qt and KDE stack, 358 fonts installed according
to KDE systemsetting, on a Ryzen 1800X, startup time of kwrite
decreases as following according to perf stat:
msec task-clock: ~480 ms to ~455 ms
cycles: ~1.73e9 to ~1.65e9

Change-Id: I630a80e4bed2647d5bbd95247005aab7d0cb0363
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
bb10
Andreas Hartmetz 2019-06-10 14:39:04 +02:00
parent 619b92385e
commit eea99e1e8f
1 changed files with 52 additions and 24 deletions

View File

@ -927,38 +927,66 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef
antialias = antialiasingEnabled - 1;
}
QFontEngine::GlyphFormat format;
// try and get the pattern
// try to find a match for fid
const QFontEngine::FaceId fid = engine->faceId();
FcPattern *pattern = FcPatternCreate();
FcPattern *match = nullptr;
FcValue value;
value.type = FcTypeString;
QByteArray cs = fontDef.family.toUtf8();
value.u.s = (const FcChar8 *)cs.data();
FcPatternAdd(pattern,FC_FAMILY,value,true);
QFontEngine::FaceId fid = engine->faceId();
if (!fid.filename.isEmpty()) {
value.u.s = (const FcChar8 *)fid.filename.data();
FcPatternAdd(pattern,FC_FILE,value,true);
value.type = FcTypeInteger;
value.u.i = fid.index;
FcPatternAdd(pattern,FC_INDEX,value,true);
// try a trivial match by filename - FC_FILE is highest priority, so if it matches, FcFontMatch
// will just find the file (fine) and spend a millisecond or so doing unnecessary work (bad).
if (!fid.filename.isEmpty() && QFile::exists(QString::fromUtf8(fid.filename))) {
FcBlanks *blanks = FcConfigGetBlanks(nullptr);
int count = 0;
FcPattern *fileMatch = FcFreeTypeQuery((const FcChar8 *)fid.filename.data(), fid.index,
blanks, &count);
if (fileMatch) {
// Apply Fontconfig configuration - FcFreeTypeQuery only returns information stored in
// the font file, we also want to respect system and user settings.
FcConfigSubstitute(0, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
match = FcFontRenderPrepare(0, pattern, fileMatch);
FcPatternDestroy(fileMatch);
}
}
if (fontDef.pixelSize > 0.1)
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontDef.pixelSize);
if (!match) {
FcValue value;
FcResult result;
// Fontconfig rules might process this information for arbitrary purposes, so add it,
// even though we already know that it doesn't match an existing file.
if (!fid.filename.isEmpty()) {
value.type = FcTypeString;
value.u.s = (const FcChar8 *)fid.filename.data();
FcPatternAdd(pattern, FC_FILE, value, true);
FcConfigSubstitute(0, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
value.type = FcTypeInteger;
value.u.i = fid.index;
FcPatternAdd(pattern, FC_INDEX, value, true);
}
FcPattern *match = FcFontMatch(0, pattern, &result);
const QByteArray cs = fontDef.family.toUtf8();
value.type = FcTypeString;
value.u.s = (const FcChar8 *)cs.data();
FcPatternAdd(pattern, FC_FAMILY, value, true);
if (fontDef.pixelSize > 0.1) {
value.type = FcTypeDouble;
value.u.d = fontDef.pixelSize;
FcPatternAdd(pattern, FC_PIXEL_SIZE, value, true);
}
FcResult result;
FcConfigSubstitute(0, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
match = FcFontMatch(0, pattern, &result);
}
QFontEngine::GlyphFormat format;
if (match) {
engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)fontDef.hintingPreference, match, useXftConf));
engine->setDefaultHintStyle(defaultHintStyleFromMatch(
(QFont::HintingPreference)fontDef.hintingPreference, match, useXftConf));
FcBool fc_autohint;
if (FcPatternGetBool(match, FC_AUTOHINT,0, &fc_autohint) == FcResultMatch)