diff options
4 files changed, 177 insertions, 28 deletions
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 7d0bd53e8b..c1c25dd686 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -51,6 +51,7 @@ #include <QtCore/qmath.h> #include <QtCore/QDebug> +#include <QtCore/QtEndian> #include <wchar.h> @@ -618,14 +619,14 @@ static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, void QWindowsFontDatabase::populateFontDatabase() { - if (m_families.isEmpty()) { - QPlatformFontDatabase::populateFontDatabase(); - populate(); // Called multiple times. - // Work around EnumFontFamiliesEx() not listing the system font, see below. - const QString sysFontFamily = QGuiApplication::font().family(); - if (!m_families.contains(sysFontFamily)) - populate(sysFontFamily); - } + m_families.clear(); + removeApplicationFonts(); + QPlatformFontDatabase::populateFontDatabase(); + populate(); // Called multiple times. + // Work around EnumFontFamiliesEx() not listing the system font, see below. + const QString sysFontFamily = QGuiApplication::font().family(); + if (!m_families.contains(sysFontFamily)) + populate(sysFontFamily); } /*! @@ -669,6 +670,7 @@ QWindowsFontDatabase::QWindowsFontDatabase() : QWindowsFontDatabase::~QWindowsFontDatabase() { + removeApplicationFonts(); } QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, @@ -702,11 +704,160 @@ QStringList QWindowsFontDatabase::fallbacksForFamily(const QString family, const return result; } +static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData) +{ + QList<quint32> offsets; + const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData); + if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) { + if (headerTag != MAKE_TAG(0, 1, 0, 0) + && headerTag != MAKE_TAG('O', 'T', 'T', 'O') + && headerTag != MAKE_TAG('t', 'r', 'u', 'e') + && headerTag != MAKE_TAG('t', 'y', 'p', '1')) + return offsets; + offsets << 0; + return offsets; + } + const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8); + for (uint i = 0; i < numFonts; ++i) { + offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4); + } + return offsets; +} + +static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length) +{ + const quint16 numTables = qFromBigEndian<quint16>(data + 4); + for (uint i = 0; i < numTables; ++i) { + const quint32 offset = 12 + 16 * i; + if (*reinterpret_cast<const quint32 *>(data + offset) == tag) { + *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8); + *length = qFromBigEndian<quint32>(data + offset + 12); + return; + } + } + *table = 0; + *length = 0; + return; +} + +static void getFamiliesAndSignatures(const QByteArray &fontData, + QStringList *families, + QVector<FONTSIGNATURE> *signatures) +{ + const uchar *data = reinterpret_cast<const uchar *>(fontData.constData()); + + QList<quint32> offsets = getTrueTypeFontOffsets(data); + if (offsets.isEmpty()) + return; + + for (int i = 0; i < offsets.count(); ++i) { + const uchar *font = data + offsets.at(i); + const uchar *table; + quint32 length; + getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length); + if (!table) + continue; + QString name = getEnglishName(table, length); + if (name.isEmpty()) + continue; + + families->append(name); + + if (signatures) { + FONTSIGNATURE signature; + getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length); + if (table && length >= 86) { + // Offsets taken from OS/2 table in the TrueType spec + signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42); + signature.fsUsb[1] = qFromBigEndian<quint32>(table + 46); + signature.fsUsb[2] = qFromBigEndian<quint32>(table + 50); + signature.fsUsb[3] = qFromBigEndian<quint32>(table + 54); + + signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78); + signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82); + } else { + memset(&signature, 0, sizeof(signature)); + } + signatures->append(signature); + } + } +} + QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) { - const QStringList result = QPlatformFontDatabase::addApplicationFont(fontData, fileName); - Q_UNIMPLEMENTED(); - return result; + WinApplicationFont font; + font.fileName = fileName; + QVector<FONTSIGNATURE> signatures; + QStringList families; + + if (!fontData.isEmpty()) { + getFamiliesAndSignatures(fontData, &families, &signatures); + if (families.isEmpty()) + return families; + + DWORD dummy = 0; + font.handle = AddFontMemResourceEx((void *)fontData.constData(), fontData.size(), 0, + &dummy); + if (font.handle == 0) + return QStringList(); + + // 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); + HDC hdc = GetDC(0); + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE, familyName.size())); + lf.lfCharSet = DEFAULT_CHARSET; + HFONT hfont = CreateFontIndirect(&lf); + HGDIOBJ oldobj = SelectObject(hdc, hfont); + + TEXTMETRIC textMetrics; + GetTextMetrics(hdc, &textMetrics); + + addFontToDatabase(familyName, QString(), &textMetrics, &signatures.at(j), + TRUETYPE_FONTTYPE); + + SelectObject(hdc, oldobj); + DeleteObject(hfont); + ReleaseDC(0, hdc); + } + } else { + QFile f(fileName); + if (!f.open(QIODevice::ReadOnly)) + return families; + QByteArray data = f.readAll(); + f.close(); + + getFamiliesAndSignatures(data, &families, 0); + if (families.isEmpty()) + return families; + + if (AddFontResourceExW((wchar_t*)fileName.utf16(), FR_PRIVATE, 0) == 0) + return QStringList(); + + 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) + populate(families.at(j)); + } + + m_applicationFonts << font; + + return families; +} + +void QWindowsFontDatabase::removeApplicationFonts() +{ + foreach (const WinApplicationFont &font, m_applicationFonts) { + if (font.handle) { + RemoveFontMemResourceEx(font.handle); + } else { + RemoveFontResourceExW((LPCWSTR)font.fileName.utf16(), FR_PRIVATE, 0); + } + } + m_applicationFonts.clear(); } void QWindowsFontDatabase::releaseHandle(void *handle) diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h index 774a203a55..2fa615253e 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h @@ -100,8 +100,16 @@ public: private: void populate(const QString &family = QString()); + void removeApplicationFonts(); QSharedPointer<QWindowsFontEngineData> m_fontEngineData; QSet<QString> m_families; + + struct WinApplicationFont { + HANDLE handle; + QString fileName; + }; + + QList<WinApplicationFont> m_applicationFonts; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index f90a880cd3..500a1eeccb 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -273,14 +273,13 @@ static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, void QWindowsFontDatabaseFT::populateFontDatabase() { - if (m_families.isEmpty()) { - QPlatformFontDatabase::populateFontDatabase(); - populate(); // Called multiple times. - // Work around EnumFontFamiliesEx() not listing the system font, see below. - const QString sysFontFamily = QGuiApplication::font().family(); - if (!m_families.contains(sysFontFamily)) - populate(sysFontFamily); - } + m_families.clear(); + QPlatformFontDatabase::populateFontDatabase(); + populate(); // Called multiple times. + // Work around EnumFontFamiliesEx() not listing the system font, see below. + const QString sysFontFamily = QGuiApplication::font().family(); + if (!m_families.contains(sysFontFamily)) + populate(sysFontFamily); } /*! @@ -426,14 +425,6 @@ QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString family, con << script << result << m_families; return result; } - -QStringList QWindowsFontDatabaseFT::addApplicationFont(const QByteArray &fontData, const QString &fileName) -{ - const QStringList result = QPlatformFontDatabase::addApplicationFont(fontData, fileName); - Q_UNIMPLEMENTED(); - return result; -} - QString QWindowsFontDatabaseFT::fontDir() const { const QString result = QLatin1String(qgetenv("windir")) + QLatin1String("/Fonts");//QPlatformFontDatabase::fontDir(); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h index 24810c9202..bb55b68251 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h @@ -56,7 +56,6 @@ public: QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const; - QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); virtual QString fontDir() const; virtual QFont defaultFont() const; |