Use english name to match font in windows platform

In windows platform, simplified chinese envrionment, the default font
family name is "SimSun" which is not in the font list generated by
EnumFontFamiliesEx(), this will cause chinese font can't be displayed.

This patch will generate font's english name during font enumeration in
windows platform, and take font's english name into consideration in font
matching. The english name generation code is taken from Qt4.8

Change-Id: Ie939ec0c8c08c628a835c7a53fb22d0545626d9c
Reviewed-by: Jiang Jiang <jiang.jiang@nokia.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
This commit is contained in:
jian liang 2012-02-13 21:26:28 +08:00 committed by Qt by Nokia
parent dfddabe115
commit 0347ac1982
4 changed files with 238 additions and 12 deletions

View File

@ -349,6 +349,7 @@ struct QtFontFamily
#endif
QString name;
QStringList aliases;
int count;
QtFontFoundry **foundries;
@ -996,6 +997,25 @@ unsigned int bestFoundry(int script, unsigned int score, int styleStrategy,
return score;
}
static bool matchFamilyName(const QString &familyName, QtFontFamily *f)
{
if (familyName.isEmpty())
return true;
if (f->name.compare(familyName, Qt::CaseInsensitive) == 0)
return true;
QStringList::const_iterator it = f->aliases.constBegin();
while (it != f->aliases.constEnd()) {
if ((*it).compare(familyName, Qt::CaseInsensitive) == 0)
return true;
++it;
}
return false;
}
/*!
\internal
@ -1045,9 +1065,7 @@ static void match(int script, const QFontDef &request,
test.family = db->families[x];
test.familyIndex = x;
if (!family_name.isEmpty()
&& test.family->name.compare(family_name, Qt::CaseInsensitive) != 0
)
if (!matchFamilyName(family_name, test.family))
continue;
if (family_name.isEmpty())

View File

@ -87,6 +87,22 @@ Q_GUI_EXPORT void qt_registerFont(const QString &familyName, const QString &fou
size->handle = handle;
}
Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
{
if (alias.isEmpty())
return;
QFontDatabasePrivate *d = privateDb();
QtFontFamily *f = d->family(familyName, false);
if (!f)
return;
if (f->aliases.contains(alias, Qt::CaseInsensitive))
return;
f->aliases.push_back(alias);
}
static QStringList fallbackFamilies(const QString &family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script)
{
QStringList retList = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script);

View File

@ -329,6 +329,11 @@ static inline QFontDatabase::WritingSystem writingSystemFromScript(const QString
return QFontDatabase::Any;
}
extern bool localizedName(const QString &name);
extern QString getEnglishName(const QString &familyName);
Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias);
static bool addFontToDatabase(QString familyName, const QString &scriptName,
const TEXTMETRIC *textmetric,
const FONTSIGNATURE *signature,
@ -365,10 +370,10 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
<< " stretch=" << stretch;
}
/* Fixme: omitted for the moment
if(ttf && localizedName(familyName) && family->english_name.isEmpty())
family->english_name = getEnglishName(familyName);
*/
QString englishName;
if (ttf && localizedName(familyName))
englishName = getEnglishName(familyName);
QSupportedWritingSystems writingSystems;
if (type & TRUETYPE_FONTTYPE) {
quint32 unicodeRange[4] = {
@ -405,6 +410,10 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
if (weight <= QFont::DemiBold && style != QFont::StyleItalic)
QPlatformFontDatabase::registerFont(familyName, foundryName, QFont::Bold,
QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, 0);
if (!englishName.isEmpty())
qt_registerAliasToFontFamily(familyName, englishName);
return true;
}

View File

@ -100,6 +100,184 @@ static inline QFont::Weight weightFromInteger(long weight)
return QFont::Black;
}
#ifdef MAKE_TAG
#undef MAKE_TAG
#endif
// GetFontData expects the tags in little endian ;(
#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
(((quint32)(ch4)) << 24) | \
(((quint32)(ch3)) << 16) | \
(((quint32)(ch2)) << 8) | \
((quint32)(ch1)) \
)
bool localizedName(const QString &name)
{
const QChar *c = name.unicode();
for (int i = 0; i < name.length(); ++i) {
if (c[i].unicode() >= 0x100)
return true;
}
return false;
}
static inline quint16 getUShort(const unsigned char *p)
{
quint16 val;
val = *p++ << 8;
val |= *p;
return val;
}
static QString getEnglishName(const uchar *table, quint32 bytes)
{
QString i18n_name;
enum {
NameRecordSize = 12,
FamilyId = 1,
MS_LangIdEnglish = 0x009
};
// get the name table
quint16 count;
quint16 string_offset;
const unsigned char *names;
int microsoft_id = -1;
int apple_id = -1;
int unicode_id = -1;
if (getUShort(table) != 0)
goto error;
count = getUShort(table+2);
string_offset = getUShort(table+4);
names = table + 6;
if (string_offset >= bytes || 6 + count*NameRecordSize > string_offset)
goto error;
for (int i = 0; i < count; ++i) {
// search for the correct name entry
quint16 platform_id = getUShort(names + i*NameRecordSize);
quint16 encoding_id = getUShort(names + 2 + i*NameRecordSize);
quint16 language_id = getUShort(names + 4 + i*NameRecordSize);
quint16 name_id = getUShort(names + 6 + i*NameRecordSize);
if (name_id != FamilyId)
continue;
enum {
PlatformId_Unicode = 0,
PlatformId_Apple = 1,
PlatformId_Microsoft = 3
};
quint16 length = getUShort(names + 8 + i*NameRecordSize);
quint16 offset = getUShort(names + 10 + i*NameRecordSize);
if (DWORD(string_offset + offset + length) >= bytes)
continue;
if ((platform_id == PlatformId_Microsoft
&& (encoding_id == 0 || encoding_id == 1))
&& (language_id & 0x3ff) == MS_LangIdEnglish
&& microsoft_id == -1)
microsoft_id = i;
// not sure if encoding id 4 for Unicode is utf16 or ucs4...
else if (platform_id == PlatformId_Unicode && encoding_id < 4 && unicode_id == -1)
unicode_id = i;
else if (platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0)
apple_id = i;
}
{
bool unicode = false;
int id = -1;
if (microsoft_id != -1) {
id = microsoft_id;
unicode = true;
} else if (apple_id != -1) {
id = apple_id;
unicode = false;
} else if (unicode_id != -1) {
id = unicode_id;
unicode = true;
}
if (id != -1) {
quint16 length = getUShort(names + 8 + id*NameRecordSize);
quint16 offset = getUShort(names + 10 + id*NameRecordSize);
if (unicode) {
// utf16
length /= 2;
i18n_name.resize(length);
QChar *uc = (QChar *) i18n_name.unicode();
const unsigned char *string = table + string_offset + offset;
for (int i = 0; i < length; ++i)
uc[i] = getUShort(string + 2*i);
} else {
// Apple Roman
i18n_name.resize(length);
QChar *uc = (QChar *) i18n_name.unicode();
const unsigned char *string = table + string_offset + offset;
for (int i = 0; i < length; ++i)
uc[i] = QLatin1Char(string[i]);
}
}
}
error:
//qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
return i18n_name;
}
QString getEnglishName(const QString &familyName)
{
QString i18n_name;
HDC hdc = GetDC( 0 );
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
memcpy(lf.lfFaceName, familyName.utf16(), qMin(LF_FACESIZE, familyName.length()) * sizeof(wchar_t));
lf.lfCharSet = DEFAULT_CHARSET;
HFONT hfont = CreateFontIndirect(&lf);
if (!hfont) {
ReleaseDC(0, hdc);
return QString();
}
HGDIOBJ oldobj = SelectObject( hdc, hfont );
const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
// get the name table
unsigned char *table = 0;
DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
if ( bytes == GDI_ERROR ) {
// ### Unused variable
// int err = GetLastError();
goto error;
}
table = new unsigned char[bytes];
GetFontData(hdc, name_tag, 0, table, bytes);
if ( bytes == GDI_ERROR )
goto error;
i18n_name = getEnglishName(table, bytes);
error:
delete [] table;
SelectObject( hdc, oldobj );
DeleteObject( hfont );
ReleaseDC( 0, hdc );
//qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
return i18n_name;
}
static FontFile * createFontFile(const QString &fileName, int index)
{
FontFile *fontFile = new FontFile;
@ -108,6 +286,8 @@ static FontFile * createFontFile(const QString &fileName, int index)
return fontFile;
}
Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias);
static bool addFontToDatabase(QString familyName, const QString &scriptName,
const TEXTMETRIC *textmetric,
const FONTSIGNATURE *signature,
@ -151,10 +331,10 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
<< " stretch=" << stretch;
}
/* Fixme: omitted for the moment
if(ttf && localizedName(faceName) && family->english_name.isEmpty())
family->english_name = getEnglishName(faceName);
*/
QString englishName;
if (ttf && localizedName(faceName))
englishName = getEnglishName(faceName);
QSupportedWritingSystems writingSystems;
if (type & TRUETYPE_FONTTYPE) {
quint32 unicodeRange[4] = {
@ -204,7 +384,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
const FontKey &fontKey = allFonts.at(k);
for (int i = 0; i < fontKey.second.length(); ++i) {
const QString &font = fontKey.second.at(i);
if (font == faceName || (faceName != fullName && fullName == font)) {
if (font == faceName || fullName == font || englishName == font) {
value = fontRegistry.value(fontKey.first).toString();
index = i;
break;
@ -236,6 +416,9 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
QPlatformFontDatabase::registerFont(faceName, foundryName, QFont::Bold, QFont::StyleItalic, stretch,
antialias, scalable, size, fixed, writingSystems, createFontFile(value, index));
if (!englishName.isEmpty())
qt_registerAliasToFontFamily(faceName, englishName);
return true;
}