diff options
Diffstat (limited to 'src/plugins/platforms/windows/qwindowsfontdatabase.cpp')
-rw-r--r-- | src/plugins/platforms/windows/qwindowsfontdatabase.cpp | 257 |
1 files changed, 148 insertions, 109 deletions
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 314da702eb..9f2d0c8a33 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -43,7 +43,7 @@ #include "qwindowsintegration.h" #include "qwindowsfontengine.h" #include "qwindowsfontenginedirectwrite.h" -#include "qtwindows_additional.h" +#include <QtCore/qt_windows.h> #include <QtGui/QFont> #include <QtGui/QGuiApplication> @@ -58,10 +58,6 @@ #include <wchar.h> -#ifdef Q_OS_WINCE -# include "qplatformfunctions_wince.h" -#endif - #if !defined(QT_NO_DIRECTWRITE) # if defined(QT_USE_DIRECTWRITE2) # include <dwrite_2.h> @@ -759,116 +755,170 @@ static inline quint16 getUShort(const unsigned char *p) return val; } -static QString getEnglishName(const uchar *table, quint32 bytes) +namespace { + +struct FontNames { + QString name; // e.g. "DejaVu Sans Condensed" + QString style; // e.g. "Italic" + QString preferredName; // e.g. "DejaVu Sans" + QString preferredStyle; // e.g. "Condensed Italic" +}; + +static QString readName(bool unicode, const uchar *string, int length) { - QString i18n_name; - enum { - NameRecordSize = 12, - FamilyId = 1, - MS_LangIdEnglish = 0x009 - }; + QString out; + if (unicode) { + // utf16 + + length /= 2; + out.resize(length); + QChar *uc = out.data(); + for (int i = 0; i < length; ++i) + uc[i] = getUShort(string + 2*i); + } else { + // Apple Roman + + out.resize(length); + QChar *uc = out.data(); + for (int i = 0; i < length; ++i) + uc[i] = QLatin1Char(char(string[i])); + } + return out; +} + +enum FieldTypeValue { + FamilyId = 1, + StyleId = 2, + PreferredFamilyId = 16, + PreferredStyleId = 17, +}; + +enum PlatformFieldValue { + PlatformId_Unicode = 0, + PlatformId_Apple = 1, + PlatformId_Microsoft = 3 +}; + +static FontNames getCanonicalFontNames(const uchar *table, quint32 bytes) +{ + FontNames out; + const int NameRecordSize = 12; + const int 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 (bytes < 8) + return out; if (getUShort(table) != 0) - goto error; + return out; count = getUShort(table+2); string_offset = getUShort(table+4); names = table + 6; if (string_offset >= bytes || 6 + count*NameRecordSize > string_offset) - goto error; + return out; + + enum PlatformIdType { + NotFound = 0, + Unicode = 1, + Apple = 2, + Microsoft = 3 + }; + + PlatformIdType idStatus[4] = { NotFound, NotFound, NotFound, NotFound }; + int ids[4] = { -1, -1, -1, -1 }; for (int i = 0; i < count; ++i) { - // search for the correct name entry + // search for the correct name entries 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; + PlatformIdType *idType = nullptr; + int *id = nullptr; - enum { - PlatformId_Unicode = 0, - PlatformId_Apple = 1, - PlatformId_Microsoft = 3 - }; + switch (name_id) { + case FamilyId: + idType = &idStatus[0]; + id = &ids[0]; + break; + case StyleId: + idType = &idStatus[1]; + id = &ids[1]; + break; + case PreferredFamilyId: + idType = &idStatus[2]; + id = &ids[2]; + break; + case PreferredStyleId: + idType = &idStatus[3]; + id = &ids[3]; + break; + default: + continue; + } quint16 length = getUShort(names + 8 + i*NameRecordSize); quint16 offset = getUShort(names + 10 + i*NameRecordSize); - if (DWORD(string_offset + offset + length) >= bytes) + 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; + && *idType < Microsoft) { + *id = i; + *idType = Microsoft; + } // 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; + else if (platform_id == PlatformId_Unicode && encoding_id < 4 && *idType < Unicode) { + *id = i; + *idType = Unicode; } - 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 = const_cast<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 = const_cast<QChar *>(i18n_name.unicode()); - const unsigned char *string = table + string_offset + offset; - for (int i = 0; i < length; ++i) - uc[i] = QLatin1Char(char(string[i])); - } + else if (platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0 && *idType < Apple) { + *id = i; + *idType = Apple; } } -error: - //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data()); - return i18n_name; + + QString strings[4]; + for (int i = 0; i < 4; ++i) { + if (idStatus[i] == NotFound) + continue; + int id = ids[i]; + quint16 length = getUShort(names + 8 + id * NameRecordSize); + quint16 offset = getUShort(names + 10 + id * NameRecordSize); + const unsigned char *string = table + string_offset + offset; + strings[i] = readName(idStatus[i] != Apple, string, length); + } + + out.name = strings[0]; + out.style = strings[1]; + out.preferredName = strings[2]; + out.preferredStyle = strings[3]; + return out; } +} // namespace + QString getEnglishName(const QString &familyName) { QString i18n_name; + QString faceName = familyName; + faceName.truncate(LF_FACESIZE - 1); HDC hdc = GetDC( 0 ); LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); - memcpy(lf.lfFaceName, familyName.utf16(), qMin(familyName.length(), LF_FACESIZE - 1) * sizeof(wchar_t)); + faceName.toWCharArray(lf.lfFaceName); + lf.lfFaceName[faceName.size()] = 0; lf.lfCharSet = DEFAULT_CHARSET; HFONT hfont = CreateFontIndirect(&lf); @@ -896,7 +946,7 @@ QString getEnglishName(const QString &familyName) if ( bytes == GDI_ERROR ) goto error; - i18n_name = getEnglishName(table, bytes); + i18n_name = getCanonicalFontNames(table, bytes).name; error: delete [] table; SelectObject( hdc, oldobj ); @@ -907,7 +957,7 @@ error: return i18n_name; } -static bool addFontToDatabase(const QString &familyName, uchar charSet, +static bool addFontToDatabase(const QString &familyName, const QString &styleName, uchar charSet, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, int type, @@ -960,17 +1010,6 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, quint32 codePageRange[2] = { signature->fsCsb[0], signature->fsCsb[1] }; -#ifdef Q_OS_WINCE - if (signature->fsUsb[0] == 0) { - // If the unicode ranges bit mask is zero then - // EnumFontFamiliesEx failed to determine it properly. - // In this case we just pretend that the font supports all languages. - unicodeRange[0] = 0xbfffffff; // second most significant bit must be zero - unicodeRange[1] = 0xffffffff; - unicodeRange[2] = 0xffffffff; - unicodeRange[3] = 0xffffffff; - } -#endif writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains // the symbol for Baht, and Windows thus reports that it supports the Thai script. @@ -986,16 +1025,16 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, writingSystems.setSupported(ws); } - QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight, + QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch, antialias, scalable, size, fixed, writingSystems, 0); // add fonts windows can generate for us: - if (weight <= QFont::DemiBold) + if (weight <= QFont::DemiBold && styleName.isEmpty()) QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold, style, stretch, antialias, scalable, size, fixed, writingSystems, 0); - if (style != QFont::StyleItalic) + if (style != QFont::StyleItalic && styleName.isEmpty()) QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight, QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, 0); - if (weight <= QFont::DemiBold && style != QFont::StyleItalic) + if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty()) QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold, QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, 0); @@ -1010,6 +1049,7 @@ static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *t { const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont); const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName); + const QString styleName = QString::fromWCharArray(f->elfStyle); const uchar charSet = f->elfLogFont.lfCharSet; const bool registerAlias = bool(lParam); @@ -1019,7 +1059,7 @@ static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *t const FONTSIGNATURE *signature = Q_NULLPTR; if (type & TRUETYPE_FONTTYPE) signature = &reinterpret_cast<const NEWTEXTMETRICEX *>(textmetric)->ntmFontSig; - addFontToDatabase(familyName, charSet, textmetric, signature, type, registerAlias); + addFontToDatabase(familyName, styleName, charSet, textmetric, signature, type, registerAlias); // keep on enumerating return 1; @@ -1130,9 +1170,8 @@ QWindowsFontEngineDataPtr sharedFontData() } #endif // QT_NO_THREAD -#ifndef Q_OS_WINCE extern Q_GUI_EXPORT bool qt_needs_a8_gamma_correction; -#endif + QWindowsFontDatabase::QWindowsFontDatabase() { // Properties accessed by QWin32PrintEngine (Qt Print Support) @@ -1146,9 +1185,7 @@ QWindowsFontDatabase::QWindowsFontDatabase() qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: " << data->clearTypeEnabled << "gamma: " << data->fontSmoothingGamma; } -#ifndef Q_OS_WINCE qt_needs_a8_gamma_correction = true; -#endif } QWindowsFontDatabase::~QWindowsFontDatabase() @@ -1364,7 +1401,7 @@ static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, } static void getFamiliesAndSignatures(const QByteArray &fontData, - QStringList *families, + QList<FontNames> *families, QVector<FONTSIGNATURE> *signatures) { const uchar *data = reinterpret_cast<const uchar *>(fontData.constData()); @@ -1380,11 +1417,11 @@ static void getFamiliesAndSignatures(const QByteArray &fontData, getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length); if (!table) continue; - QString name = getEnglishName(table, length); - if (name.isEmpty()) + FontNames names = getCanonicalFontNames(table, length); + if (names.name.isEmpty()) continue; - families->append(name); + families->append(qMove(names)); if (signatures) { FONTSIGNATURE signature; @@ -1411,12 +1448,13 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, WinApplicationFont font; font.fileName = fileName; QVector<FONTSIGNATURE> signatures; - QStringList families; + QList<FontNames> families; + QStringList familyNames; if (!fontData.isEmpty()) { getFamiliesAndSignatures(fontData, &families, &signatures); if (families.isEmpty()) - return families; + return familyNames; DWORD dummy = 0; font.handle = @@ -1427,7 +1465,9 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, // Memory fonts won't show up in enumeration, so do add them the hard way. for (int j = 0; j < families.count(); ++j) { - const QString familyName = families.at(j); + const QString familyName = families.at(j).name; + const QString styleName = families.at(j).style; + familyNames << familyName; HDC hdc = GetDC(0); LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); @@ -1439,7 +1479,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, TEXTMETRIC textMetrics; GetTextMetrics(hdc, &textMetrics); - addFontToDatabase(familyName, lf.lfCharSet, &textMetrics, &signatures.at(j), + addFontToDatabase(familyName, styleName, lf.lfCharSet, &textMetrics, &signatures.at(j), TRUETYPE_FONTTYPE, true); SelectObject(hdc, oldobj); @@ -1449,13 +1489,13 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, } else { QFile f(fileName); if (!f.open(QIODevice::ReadOnly)) - return families; + return QStringList(); QByteArray data = f.readAll(); f.close(); getFamiliesAndSignatures(data, &families, 0); if (families.isEmpty()) - return families; + return QStringList(); if (AddFontResourceExW((wchar_t*)fileName.utf16(), FR_PRIVATE, 0) == 0) return QStringList(); @@ -1463,13 +1503,16 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, font.handle = 0; // Fonts based on files are added via populate, as they will show up in font enumeration. - for (int j = 0; j < families.count(); ++j) - populateFamily(families.at(j), true); + for (int j = 0; j < families.count(); ++j) { + const QString familyName = families.at(j).name; + familyNames << familyName; + populateFamily(familyName, true); + } } m_applicationFonts << font; - return families; + return familyNames; } void QWindowsFontDatabase::removeApplicationFonts() @@ -1595,14 +1638,12 @@ LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request) int strat = OUT_DEFAULT_PRECIS; if (request.styleStrategy & QFont::PreferBitmap) { strat = OUT_RASTER_PRECIS; -#ifndef Q_OS_WINCE } else if (request.styleStrategy & QFont::PreferDevice) { strat = OUT_DEVICE_PRECIS; } else if (request.styleStrategy & QFont::PreferOutline) { strat = OUT_OUTLINE_PRECIS; } else if (request.styleStrategy & QFont::ForceOutline) { strat = OUT_TT_ONLY_PRECIS; -#endif } lf.lfOutPrecision = strat; @@ -1611,10 +1652,8 @@ LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request) if (request.styleStrategy & QFont::PreferMatch) qual = DRAFT_QUALITY; -#ifndef Q_OS_WINCE else if (request.styleStrategy & QFont::PreferQuality) qual = PROOF_QUALITY; -#endif if (request.styleStrategy & QFont::PreferAntialias) { if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && !(request.styleStrategy & QFont::NoSubpixelAntialias)) { |