Fix application font removal when using FontConfig

This patch fixes an issue when a font that was added with QFontDatabase::addApplicationFont
can not be removed any more.
The reason for that is that QFontconfigDatabase::addApplicationFont adds the font to the FontConfig
application set from where it cannot be removed any more and is picked up every time the font database is
repopulated (e.g. after a call to QFontDatabase::removeApplicationFont).

This also fixes the QFontDatabase autotest which unfortunately does not fail on linux, because it tries
to add "FreeMono" (which in most cases is already there as a system font). So this patch removes FreeMono and adds
LED_REAL as test font.

Change-Id: I2fa5f4df0ad2099ac28673760ea25234c725dfc6
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
bb10
Fabian Bumberger 2014-01-09 01:57:41 +01:00 committed by The Qt Project
parent 22ec4ed866
commit a4ff400e25
5 changed files with 163 additions and 113 deletions

View File

@ -331,10 +331,8 @@ static const char *getFcFamilyForStyleHint(const QFont::StyleHint style)
return stylehint;
}
void QFontconfigDatabase::populateFontDatabase()
static void populateFromPattern(FcPattern *pattern)
{
FcFontSet *fonts;
QString familyName;
FcChar8 *value = 0;
int weight_value;
@ -348,6 +346,110 @@ void QFontconfigDatabase::populateFontDatabase()
FcBool scalable;
FcBool antialias;
if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) != FcResultMatch)
return;
familyName = QString::fromUtf8((const char *)value);
slant_value = FC_SLANT_ROMAN;
weight_value = FC_WEIGHT_REGULAR;
spacing_value = FC_PROPORTIONAL;
file_value = 0;
indexValue = 0;
scalable = FcTrue;
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 = 0;
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 = 0;
if (FcPatternGetString(pattern, FC_STYLE, 0, &style_value) != FcResultMatch)
style_value = 0;
if (FcPatternGetBool(pattern,FC_ANTIALIAS,0,&antialias) != FcResultMatch)
antialias = true;
QSupportedWritingSystems writingSystems;
FcLangSet *langset = 0;
FcResult res = FcPatternGetLangSet(pattern, FC_LANG, 0, &langset);
if (res == FcResultMatch) {
bool hasLang = false;
for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) {
const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[j];
if (lang) {
FcLangResult langRes = FcLangSetHasLang(langset, lang);
if (langRes != FcLangDifferentLang) {
writingSystems.setSupported(QFontDatabase::WritingSystem(j));
hasLang = true;
}
}
}
if (!hasLang)
// none of our known languages, add it to the other set
writingSystems.setSupported(QFontDatabase::Other);
} else {
// we set Other to supported for symbol fonts. It makes no
// sense to merge these with other ones, as they are
// special in a way.
writingSystems.setSupported(QFontDatabase::Other);
}
#if FC_VERSION >= 20297
for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) {
if (writingSystems.supported(QFontDatabase::WritingSystem(j))
&& requiresOpenType(j) && openType[j]) {
FcChar8 *cap;
res = FcPatternGetString (pattern, FC_CAPABILITY, 0, &cap);
if (res != FcResultMatch || !strstr((const char *)cap, openType[j]))
writingSystems.setSupported(QFontDatabase::WritingSystem(j),false);
}
}
#endif
FontFile *fontFile = new FontFile;
fontFile->fileName = QLatin1String((const char *)file_value);
fontFile->indexValue = indexValue;
QFont::Style style = (slant_value == FC_SLANT_ITALIC)
? QFont::StyleItalic
: ((slant_value == FC_SLANT_OBLIQUE)
? QFont::StyleOblique
: QFont::StyleNormal);
// Note: weight should really be an int but registerFont incorrectly uses an enum
QFont::Weight weight = QFont::Weight(weightFromFcWeight(weight_value));
double pixel_size = 0;
if (!scalable)
FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &pixel_size);
bool fixedPitch = spacing_value >= FC_MONO;
// Note: stretch should really be an int but registerFont incorrectly uses an enum
QFont::Stretch stretch = QFont::Stretch(stretchFromFcWidth(width_value));
QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString();
QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile);
// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size;
for (int k = 1; FcPatternGetString(pattern, FC_FAMILY, k, &value) == FcResultMatch; ++k)
QPlatformFontDatabase::registerAliasToFontFamily(familyName, QString::fromUtf8((const char *)value));
}
void QFontconfigDatabase::populateFontDatabase()
{
FcInitReinitialize();
FcFontSet *fonts;
{
FcObjectSet *os = FcObjectSetCreate();
FcPattern *pattern = FcPatternCreate();
@ -371,103 +473,8 @@ void QFontconfigDatabase::populateFontDatabase()
FcPatternDestroy(pattern);
}
for (int i = 0; i < fonts->nfont; i++) {
if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
continue;
// capitalize(value);
familyName = QString::fromUtf8((const char *)value);
slant_value = FC_SLANT_ROMAN;
weight_value = FC_WEIGHT_REGULAR;
spacing_value = FC_PROPORTIONAL;
file_value = 0;
indexValue = 0;
scalable = FcTrue;
if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch)
slant_value = FC_SLANT_ROMAN;
if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch)
weight_value = FC_WEIGHT_REGULAR;
if (FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width_value) != FcResultMatch)
width_value = FC_WIDTH_NORMAL;
if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch)
spacing_value = FC_PROPORTIONAL;
if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch)
file_value = 0;
if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &indexValue) != FcResultMatch)
indexValue = 0;
if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch)
scalable = FcTrue;
if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
foundry_value = 0;
if (FcPatternGetString(fonts->fonts[i], FC_STYLE, 0, &style_value) != FcResultMatch)
style_value = 0;
if(FcPatternGetBool(fonts->fonts[i],FC_ANTIALIAS,0,&antialias) != FcResultMatch)
antialias = true;
QSupportedWritingSystems writingSystems;
FcLangSet *langset = 0;
FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset);
if (res == FcResultMatch) {
bool hasLang = false;
for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) {
const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[j];
if (lang) {
FcLangResult langRes = FcLangSetHasLang(langset, lang);
if (langRes != FcLangDifferentLang) {
writingSystems.setSupported(QFontDatabase::WritingSystem(j));
hasLang = true;
}
}
}
if (!hasLang)
// none of our known languages, add it to the other set
writingSystems.setSupported(QFontDatabase::Other);
} else {
// we set Other to supported for symbol fonts. It makes no
// sense to merge these with other ones, as they are
// special in a way.
writingSystems.setSupported(QFontDatabase::Other);
}
#if FC_VERSION >= 20297
for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) {
if (writingSystems.supported(QFontDatabase::WritingSystem(j))
&& requiresOpenType(j) && openType[j]) {
FcChar8 *cap;
res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap);
if (res != FcResultMatch || !strstr((const char *)cap, openType[j]))
writingSystems.setSupported(QFontDatabase::WritingSystem(j),false);
}
}
#endif
FontFile *fontFile = new FontFile;
fontFile->fileName = QLatin1String((const char *)file_value);
fontFile->indexValue = indexValue;
QFont::Style style = (slant_value == FC_SLANT_ITALIC)
? QFont::StyleItalic
: ((slant_value == FC_SLANT_OBLIQUE)
? QFont::StyleOblique
: QFont::StyleNormal);
// Note: weight should really be an int but registerFont incorrectly uses an enum
QFont::Weight weight = QFont::Weight(weightFromFcWeight(weight_value));
double pixel_size = 0;
if (!scalable)
FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size);
bool fixedPitch = spacing_value >= FC_MONO;
// Note: stretch should really be an int but registerFont incorrectly uses an enum
QFont::Stretch stretch = QFont::Stretch(stretchFromFcWidth(width_value));
QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString();
QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile);
// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size;
for (int k = 1; FcPatternGetString(fonts->fonts[i], FC_FAMILY, k, &value) == FcResultMatch; ++k)
QPlatformFontDatabase::registerAliasToFontFamily(familyName, QString::fromUtf8((const char *)value));
}
for (int i = 0; i < fonts->nfont; i++)
populateFromPattern(fonts->fonts[i]);
FcFontSetDestroy (fonts);
@ -515,14 +522,12 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QChar::Script sc
return 0;
QFontDef fontDef = f;
QFontEngineFT *engine;
FontFile *fontfile = static_cast<FontFile *> (usrPtr);
QFontEngine::FaceId fid;
fid.filename = QFile::encodeName(fontfile->fileName);
fid.index = fontfile->indexValue;
bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
engine = new QFontEngineFT(fontDef);
QFontEngineFT::GlyphFormat format;
// try and get the pattern
@ -543,7 +548,19 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QChar::Script sc
FcResult result;
FcPattern *match = FcFontMatch(0, pattern, &result);
QFontEngineFT *engine = new QFontEngineFT(fontDef);
if (match) {
//Respect the file and index of the font config match
FcChar8 *file_value;
int indexValue;
if (FcPatternGetString(match, FC_FILE, 0, &file_value) == FcResultMatch)
fid.filename = (const char *)file_value;
if (FcPatternGetInteger(match, FC_INDEX, 0, &indexValue) == FcResultMatch)
fid.index = indexValue;
QFontEngineFT::HintStyle default_hint_style;
if (f.hintingPreference != QFont::PreferDefaultHinting) {
switch (f.hintingPreference) {
@ -620,12 +637,14 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QChar::Script sc
format = subpixelType == QFontEngineFT::Subpixel_None
? QFontEngineFT::Format_A8 : QFontEngineFT::Format_A32;
engine->subpixelType = subpixelType;
} else
} else {
format = QFontEngineFT::Format_Mono;
}
FcPatternDestroy(match);
} else
} else {
format = antialias ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono;
}
FcPatternDestroy(pattern);
@ -748,6 +767,7 @@ static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id,
QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
{
QStringList families;
FcFontSet *set = FcConfigGetFonts(0, FcSetApplication);
if (!set) {
FcConfigAppFontAddFile(0, (const FcChar8 *)":/non-existent");
@ -760,28 +780,24 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData,
FcBlanks *blanks = FcConfigGetBlanks(0);
int count = 0;
FcPattern *pattern = 0;
FcPattern *pattern;
do {
pattern = queryFont((const FcChar8 *)QFile::encodeName(fileName).constData(),
fontData, id, blanks, &count);
if (!pattern)
return families;
FcPatternDel(pattern, FC_FILE);
QByteArray cs = fileName.toUtf8();
FcPatternAddString(pattern, FC_FILE, (const FcChar8 *) cs.constData());
FcChar8 *fam = 0;
if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) {
QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
families << family;
}
populateFromPattern(pattern);
if (!FcFontSetAdd(set, pattern))
return families;
FcFontSetAdd(set, pattern);
++id;
} while (pattern && id < count);
} while (id < count);
return families;
}

Binary file not shown.

View File

@ -0,0 +1,34 @@
Font: LED Real (led_real.ttf)
Created By: Matthew Welch
E-Mail: daffy-duck@worldnet.att.net
Web Address: http://home.att.net/~daffy-duck
(PGP public key available here)
LED Real, like all of my fonts, is free. You can use it for most
personal or business uses you'd like, and I ask for no money. I
would, however, like to hear from you. If you use my fonts for
something please send me a postcard or e-mail letting me know how
you used it. Send me a copy if you can or let me know where I can
find your work.
You may use this font for graphical or printed work, but you may not
sell it or include it in a collection of fonts (on CD or otherwise)
being sold. You can redistribute this font as long as you charge
nothing to receive it. If you redistribute it include this text file
with it as is (without modifications).
If you use this font for commercial purposes please credit me in
at least some little way.
About the font:
Unlike most LED/LCD style fonts mine could be recreated with an
actual LED. I created this font working from memories of the good
old Speak and Spell display. Since I don't have an actual Speak
and Spell to work from I had to just do as well as I could in its
spirit. Be warned that some characters look just like others. The
( and the <, for instance. Also C and [. Most of these will be
pretty clear in context. To see all the sections of the LED "lit
up" at once use character 127 (hold down alt and type 0127 on the
numeric keypad). This font is, of course, monospaced.

View File

@ -83,7 +83,7 @@ private:
};
tst_QFontDatabase::tst_QFontDatabase()
: m_testFont(QFINDTESTDATA("FreeMono.ttf"))
: m_testFont(QFINDTESTDATA("LED_REAL.TTF"))
{
}