Xft-related bug in Qt 3.2.3
Hello.
Seems that I've found a bug in how Qt 3.2.3 interoperates with Xft.
Initial symptom was that after I upgraded my Debian SID system some time
ago, my KDE desktop became somewhat broken: cyrillic characters were
displayed in a different font than latin characters in the same string;
and in terminal windows cyrillic characters were displayed in
non-monospace fonts, causing really ugly effects.
It was obvious that after upgrade Qt lost some fonts.
After some investigation I found that is was caused by fontconfig package
upgrade, exactly - by adding /usr/local/share/fonts to default font search
directories. In that directory, I have a subdirectory with X11 fonts
without unicode characters - they are used by xfs to feed really slow X
terminals that become unacceptably slow if unicode fonts are available.
Moving that subdir away (and running fc-cache) returned normal fonts.
Moving that dir back and leaving there a single iso8859-1 fixed font (and
running fc-cache) caused the problem again.
At last I've got some time to debug the issue. It is Qt problem, caused by
the following code in kernel/qfontdatabase_x11.cpp, function loadXft():
#ifdef QT_XFT2
if (! family->xftScriptCheck) {
FcCharSet *charset = 0;
FcResult res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0,
&charset);
if (res == FcResultMatch) {
for (int i = 0; i < QFont::LastPrivateScript; ++i) {
QChar ch = sampleCharacter((QFont::Script) i);
if (ch.unicode() != 0 &&
FcCharSetHasChar(charset, ch.unicode())) {
family->scripts[i] = QtFontFamily::Supported;
} else {
family->scripts[i] |= QtFontFamily::UnSupported_Xft;
}
}
family->xftScriptCheck = TRUE;
}
}
#endif // QT_XFT2
This code assumes that all fonts with the same family have same scripts
available. So if Xft returnes Fixed iso8895-1 font earlier that Fixed
iso10646-1 font, Qt records that "Fixed" family has no cyrillic
characters! Which is definitly not true.
Qt is very complex and I'm not familiar with it enough to fix the problem.
However, I was able to workaround it by the following:
#ifdef QT_XFT2
// if (! family->xftScriptCheck) {
FcCharSet *charset = 0;
FcResult res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0,
&charset);
if (res == FcResultMatch) {
for (int i = 0; i < QFont::LastPrivateScript; ++i) {
QChar ch = sampleCharacter((QFont::Script) i);
if (!family->xftScriptCheck || family->scripts[i] !=
QtFontFamily::Supported) {
if (ch.unicode() != 0 &&
FcCharSetHasChar(charset, ch.unicode())) {
family->scripts[i] = QtFontFamily::Supported;
} else {
family->scripts[i] |= QtFontFamily::UnSupported_Xft;
}
}
}
family->xftScriptCheck = TRUE;
}
// }
#endif // QT_XFT2
This makes it to check all fonts of the family, and mark a script as
supported if there is a font providing it.
Reply to: