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: I70fc823075923aa426da1eb3e052affcc416e399
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
bb10
Fabian Bumberger 2014-01-09 01:57:41 +01:00 committed by The Qt Project
parent 7ca958eb61
commit 74cade1ee4
5 changed files with 147 additions and 109 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);
@ -802,6 +809,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");
@ -814,28 +822,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"))
{
}