diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index fa9cae4359..77262d66f0 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -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()) diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp index c3d7529c2e..2a9c37fb13 100644 --- a/src/gui/text/qfontdatabase_qpa.cpp +++ b/src/gui/text/qfontdatabase_qpa.cpp @@ -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); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index fa95f4f529..1df985c8a7 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -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; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 8455e9e6d0..6b6d1a294a 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -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; }