diff options
Diffstat (limited to 'src/plugins/platforms/windows/qwindowsfontdatabase.cpp')
-rw-r--r-- | src/plugins/platforms/windows/qwindowsfontdatabase.cpp | 179 |
1 files changed, 177 insertions, 2 deletions
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 1df985c8a7..fba7794a12 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -329,8 +329,183 @@ static inline QFontDatabase::WritingSystem writingSystemFromScript(const QString return QFontDatabase::Any; } -extern bool localizedName(const QString &name); -extern QString getEnglishName(const QString &familyName); +#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; +} Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); |