diff options
Diffstat (limited to 'src/gui/text/windows/qwindowsfontdatabase.cpp')
-rw-r--r-- | src/gui/text/windows/qwindowsfontdatabase.cpp | 349 |
1 files changed, 194 insertions, 155 deletions
diff --git a/src/gui/text/windows/qwindowsfontdatabase.cpp b/src/gui/text/windows/qwindowsfontdatabase.cpp index 381bcea0b3..adc06a6c2a 100644 --- a/src/gui/text/windows/qwindowsfontdatabase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabase.cpp @@ -1,57 +1,23 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qwindowsfontdatabase_p.h" -#include "qwindowsfontdatabase_ft_p.h" // for default font +#ifndef QT_NO_FREETYPE +# include "qwindowsfontdatabase_ft_p.h" // for default font +#endif #include "qwindowsfontengine_p.h" #include <QtCore/qt_windows.h> #include <QtGui/QFont> #include <QtGui/QGuiApplication> -#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/private/qtgui-config_p.h> #include <QtCore/qmath.h> #include <QtCore/QDebug> #include <QtCore/QFile> #include <QtCore/QtEndian> -#include <QtCore/private/qsystemlibrary_p.h> +#include <QtCore/QStandardPaths> +#include <QtCore/private/qduplicatetracker_p.h> #include <QtCore/private/qwinregistry_p.h> #include <wchar.h> @@ -65,13 +31,13 @@ # include "qwindowsfontenginedirectwrite_p.h" #endif -QT_BEGIN_NAMESPACE +#include <mutex> -#if QT_CONFIG(directwrite) -// ### fixme: Consider direct linking of dwrite.dll once Windows Vista pre SP2 is dropped (QTBUG-49711) +QT_BEGIN_NAMESPACE -typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **); +using namespace Qt::StringLiterals; +#if QT_CONFIG(directwrite) static inline bool useDirectWrite(QFont::HintingPreference hintingPreference, const QString &familyName = QString(), bool isColorFont = false) @@ -82,7 +48,7 @@ static inline bool useDirectWrite(QFont::HintingPreference hintingPreference, // At some scales, GDI will misrender the MingLiU font, so we force use of // DirectWrite to work around the issue. - if (Q_UNLIKELY(familyName.startsWith(QLatin1String("MingLiU")))) + if (Q_UNLIKELY(familyName.startsWith("MingLiU"_L1))) return true; if (isColorFont) @@ -90,7 +56,7 @@ static inline bool useDirectWrite(QFont::HintingPreference hintingPreference, return hintingPreference == QFont::PreferNoHinting || hintingPreference == QFont::PreferVerticalHinting - || (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting); + || (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0) && hintingPreference == QFont::PreferDefaultHinting); } #endif // !QT_NO_DIRECTWRITE @@ -225,17 +191,6 @@ static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSe return QFontDatabase::Any; } -#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 qt_localizedName(const QString &name) { const QChar *c = name.unicode(); @@ -413,7 +368,7 @@ QString qt_getEnglishName(const QString &familyName, bool includeStyle) HGDIOBJ oldobj = SelectObject( hdc, hfont ); - const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' ); + const DWORD name_tag = qFromBigEndian(QFont::Tag("name").value()); // get the name table unsigned char *table = 0; @@ -434,7 +389,7 @@ QString qt_getEnglishName(const QString &familyName, bool includeStyle) const QFontNames names = qt_getCanonicalFontNames(table, bytes); i18n_name = names.name; if (includeStyle) - i18n_name += QLatin1Char(' ') + names.style; + i18n_name += u' ' + names.style; } error: delete [] table; @@ -462,7 +417,7 @@ QFontNames qt_getCanonicalFontNames(const LOGFONT &lf) // get the name table QByteArray table; - const DWORD name_tag = MAKE_TAG('n', 'a', 'm', 'e'); + const DWORD name_tag = qFromBigEndian(QFont::Tag("name").value()); DWORD bytes = GetFontData(hdc, name_tag, 0, 0, 0); if (bytes != GDI_ERROR) { table.resize(bytes); @@ -478,18 +433,6 @@ QFontNames qt_getCanonicalFontNames(const LOGFONT &lf) return fontNames; } -static QChar *createFontFile(const QString &faceName) -{ - QChar *faceNamePtr = nullptr; - if (!faceName.isEmpty()) { - const int nameLength = qMin(faceName.length(), LF_FACESIZE - 1); - faceNamePtr = new QChar[nameLength + 1]; - memcpy(static_cast<void *>(faceNamePtr), faceName.utf16(), sizeof(wchar_t) * nameLength); - faceNamePtr[nameLength] = u'\0'; - } - return faceNamePtr; -} - namespace { struct StoreFontPayload { StoreFontPayload(const QString &family, @@ -499,7 +442,7 @@ namespace { {} QString populatedFontFamily; - QSet<FontAndStyle> foundFontAndStyles; + QDuplicateTracker<FontAndStyle> foundFontAndStyles; QWindowsFontDatabase *windowsFontDatabase; }; } @@ -513,7 +456,7 @@ static bool addFontToDatabase(QString familyName, StoreFontPayload *sfp) { // the "@family" fonts are just the same as "family". Ignore them. - if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_"))) + if (familyName.isEmpty() || familyName.at(0) == u'@' || familyName.startsWith("WST_"_L1)) return false; uchar charSet = logFont.lfCharSet; @@ -522,7 +465,9 @@ static bool addFontToDatabase(QString familyName, const QString foundryName; // No such concept. const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH); const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE); - const bool scalable = textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE); + const bool unreliableTextMetrics = type == 0; + const bool scalable = (textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) + && !unreliableTextMetrics; const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight; const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal; const bool antialias = false; @@ -542,7 +487,7 @@ static bool addFontToDatabase(QString familyName, str << " TRUETYPE"; str << " scalable=" << scalable << " Size=" << size << " Style=" << style << " Weight=" << weight - << " stretch=" << stretch; + << " stretch=" << stretch << " styleName=" << styleName; qCDebug(lcQpaFonts) << message; } #endif @@ -560,7 +505,13 @@ static bool addFontToDatabase(QString familyName, subFamilyStyle = styleName; faceName = familyName; // Remember the original name for later lookups familyName = canonicalNames.preferredName; - styleName = canonicalNames.preferredStyle; + // Preferred style / typographic subfamily name: + // "If it is absent, then name ID 2 is considered to be the typographic subfamily name." + // From: https://docs.microsoft.com/en-us/windows/win32/directwrite/opentype-variable-fonts + // Name ID 2 is already stored in the styleName variable. Furthermore, for variable fonts, + // styleName holds the variation instance name, which should be used over name ID 2. + if (!canonicalNames.preferredStyle.isEmpty()) + styleName = canonicalNames.preferredStyle; } QSupportedWritingSystems writingSystems; @@ -580,7 +531,7 @@ static bool addFontToDatabase(QString familyName, // display Thai text by default. As a temporary work around, we special case Segoe UI // and remove the Thai script from its list of supported writing systems. if (writingSystems.supported(QFontDatabase::Thai) && - familyName == QLatin1String("Segoe UI")) + familyName == "Segoe UI"_L1) writingSystems.setSupported(QFontDatabase::Thai, false); } else { const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet); @@ -588,33 +539,35 @@ static bool addFontToDatabase(QString familyName, writingSystems.setSupported(ws); } - // We came here from populating a different font family, so we have - // to ensure the entire typographic family is populated before we - // mark it as such inside registerFont() - if (!subFamilyName.isEmpty() - && familyName != subFamilyName - && sfp->populatedFontFamily != familyName - && !QPlatformFontDatabase::isFamilyPopulated(familyName)) { - sfp->windowsFontDatabase->populateFamily(familyName); - } - + const bool wasPopulated = QPlatformFontDatabase::isFamilyPopulated(familyName); QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, - style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); + style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName)); + // add fonts windows can generate for us: if (weight <= QFont::DemiBold && styleName.isEmpty()) QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold, - style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); + style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName)); if (style != QFont::StyleItalic && styleName.isEmpty()) QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight, - QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); + QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName)); if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty()) QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold, - QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); + QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName)); + + // We came here from populating a different font family, so we have + // to ensure the entire typographic family is populated before we + // mark it as such inside registerFont() + if (!subFamilyName.isEmpty() + && familyName != subFamilyName + && sfp->populatedFontFamily != familyName + && !wasPopulated) { + sfp->windowsFontDatabase->populateFamily(familyName); + } if (!subFamilyName.isEmpty() && familyName != subFamilyName) { QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight, - style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); + style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName)); } if (!englishName.isEmpty() && englishName != familyName) @@ -628,8 +581,6 @@ 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); - if (familyName == QLatin1String("Lucida Calligraphy")) - qDebug("BP"); const QString styleName = QString::fromWCharArray(f->elfStyle); // NEWTEXTMETRICEX (passed for TT fonts) is a NEWTEXTMETRIC, which according @@ -642,10 +593,8 @@ static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *t signature = &reinterpret_cast<const NEWTEXTMETRICEX *>(textmetric)->ntmFontSig; // We get a callback for each script-type supported, but we register them all // at once using the signature, so we only need one call to addFontToDatabase(). - FontAndStyle fontAndStyle = {familyName, styleName}; - if (sfp->foundFontAndStyles.contains(fontAndStyle)) + if (sfp->foundFontAndStyles.hasSeen({familyName, styleName})) return 1; - sfp->foundFontAndStyles.insert(fontAndStyle); } addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type, sfp); @@ -671,8 +620,8 @@ bool QWindowsFontDatabase::populateFamilyAliases(const QString &missingFamily) void QWindowsFontDatabase::populateFamily(const QString &familyName) { qCDebug(lcQpaFonts) << familyName; - if (familyName.size() >= LF_FACESIZE) { - qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\''; + if (familyName.size() >= LF_FACESIZE) { // Field length of LOGFONT::lfFaceName + qCDebug(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\''; return; } HDC dummy = GetDC(0); @@ -706,24 +655,48 @@ static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TE return 1; // continue } +namespace { + +QString resolveFontPath(const QString &fontPath) +{ + if (fontPath.isEmpty()) + return QString(); + + if (QFile::exists(fontPath)) + return fontPath; + + // resolve the path relatively to Windows Fonts directory + return QStandardPaths::locate(QStandardPaths::FontsLocation, fontPath); +} + +} + void QWindowsFontDatabase::addDefaultEUDCFont() { const QString path = QWinRegistryKey(HKEY_CURRENT_USER, LR"(EUDC\1252)") .stringValue(L"SystemDefaultEUDCFont"); - if (!path.isEmpty()) { - QFile file(path); - if (!file.open(QIODevice::ReadOnly)) { - qCWarning(lcQpaFonts) << "Unable to open default EUDC font:" << path; - return; - } + if (path.isEmpty()) { + qCDebug(lcQpaFonts) << "There's no default EUDC font specified"; + return; + } + + const QString absolutePath = resolveFontPath(path); + if (absolutePath.isEmpty()) { + qCDebug(lcQpaFonts) << "Unable to locate default EUDC font:" << path; + return; + } - m_eudcFonts = addApplicationFont(file.readAll(), path); + QFile file(absolutePath); + if (!file.open(QIODevice::ReadOnly)) { + qCWarning(lcQpaFonts) << "Unable to open default EUDC font:" << absolutePath; + return; } + + m_eudcFonts = addApplicationFont(file.readAll(), absolutePath); } void QWindowsFontDatabase::populateFontDatabase() { - removeApplicationFonts(); HDC dummy = GetDC(0); LOGFONT lf; lf.lfCharSet = DEFAULT_CHARSET; @@ -732,12 +705,18 @@ void QWindowsFontDatabase::populateFontDatabase() EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0); ReleaseDC(0, dummy); // Work around EnumFontFamiliesEx() not listing the system font. - const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().first(); + const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().constFirst(); if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily) QPlatformFontDatabase::registerFontFamily(systemDefaultFamily); addDefaultEUDCFont(); } +void QWindowsFontDatabase::invalidate() +{ + QWindowsFontDatabaseBase::invalidate(); + removeApplicationFonts(); +} + QWindowsFontDatabase::QWindowsFontDatabase() { // Properties accessed by QWin32PrintEngine (Qt Print Support) @@ -760,7 +739,8 @@ QWindowsFontDatabase::~QWindowsFontDatabase() QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) { - const QString faceName(static_cast<const QChar*>(handle)); + FontHandle *fontHandle = static_cast<FontHandle *>(handle); + const QString faceName = fontHandle->faceName.left(LF_FACESIZE - 1); QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName, defaultVerticalDPI(), data()); @@ -782,10 +762,10 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wstrict-aliasing") - QString uniqueFamilyName = QLatin1Char('f') - + QString::number(guid.Data1, 36) + QLatin1Char('-') - + QString::number(guid.Data2, 36) + QLatin1Char('-') - + QString::number(guid.Data3, 36) + QLatin1Char('-') + QString uniqueFamilyName = u'f' + + QString::number(guid.Data1, 36) + u'-' + + QString::number(guid.Data2, 36) + u'-' + + QString::number(guid.Data3, 36) + u'-' + QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36); QT_WARNING_POP @@ -822,7 +802,7 @@ QT_WARNING_POP if (fontEngine) { if (request.families != fontEngine->fontDef.families) { qWarning("%s: Failed to load font. Got fallback instead: %s", __FUNCTION__, - qPrintable(fontEngine->fontDef.families.first())); + qPrintable(fontEngine->fontDef.families.constFirst())); if (fontEngine->ref.loadRelaxed() == 0) delete fontEngine; fontEngine = 0; @@ -846,10 +826,13 @@ QT_WARNING_POP Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled font engine."); } - UniqueFontData uniqueData; + UniqueFontData uniqueData{}; uniqueData.handle = fontHandle; - uniqueData.refCount.ref(); - m_uniqueFontData[uniqueFamilyName] = uniqueData; + ++uniqueData.refCount; + { + const std::scoped_lock lock(m_uniqueFontDataMutex); + m_uniqueFontData[uniqueFamilyName] = uniqueData; + } } } else { RemoveFontMemResourceEx(fontHandle); @@ -870,36 +853,70 @@ QT_WARNING_POP return fontEngine; } -static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData) +static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData, const uchar *fileEndSentinel) { 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')) + if (fileEndSentinel - fontData < 12) { + qCWarning(lcQpaFonts) << "Corrupted font data detected"; + return offsets; + } + + const quint32 headerTag = qFromUnaligned<quint32>(fontData); + if (headerTag != qFromBigEndian(QFont::Tag("ttcf").value())) { + if (headerTag != qFromBigEndian(QFont::Tag("\0\1\0\0").value()) + && headerTag != qFromBigEndian(QFont::Tag("OTTO").value()) + && headerTag != qFromBigEndian(QFont::Tag("true").value()) + && headerTag != qFromBigEndian(QFont::Tag("typ1").value())) { return offsets; + } offsets << 0; return offsets; } + + const quint32 maximumNumFonts = 0xffff; const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8); - for (uint i = 0; i < numFonts; ++i) { - offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4); + if (numFonts > maximumNumFonts) { + qCWarning(lcQpaFonts) << "Font collection of" << numFonts << "fonts is too large. Aborting."; + return offsets; } + + if (quintptr(fileEndSentinel - fontData) > 12 + (numFonts - 1) * 4) { + for (quint32 i = 0; i < numFonts; ++i) + offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4); + } else { + qCWarning(lcQpaFonts) << "Corrupted font data detected"; + } + return offsets; } -static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length) +static void getFontTable(const uchar *fileBegin, const uchar *fileEndSentinel, 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; + if (fileEndSentinel - data >= 6) { + const quint16 numTables = qFromBigEndian<quint16>(data + 4); + if (fileEndSentinel - data >= 28 + 16 * (numTables - 1)) { + for (quint32 i = 0; i < numTables; ++i) { + const quint32 offset = 12 + 16 * i; + if (qFromUnaligned<quint32>(data + offset) == tag) { + const quint32 tableOffset = qFromBigEndian<quint32>(data + offset + 8); + if (quintptr(fileEndSentinel - fileBegin) <= tableOffset) { + qCWarning(lcQpaFonts) << "Corrupted font data detected"; + break; + } + *table = fileBegin + tableOffset; + *length = qFromBigEndian<quint32>(data + offset + 12); + if (quintptr(fileEndSentinel - *table) < *length) { + qCWarning(lcQpaFonts) << "Corrupted font data detected"; + break; + } + return; + } + } + } else { + qCWarning(lcQpaFonts) << "Corrupted font data detected"; } + } else { + qCWarning(lcQpaFonts) << "Corrupted font data detected"; } *table = 0; *length = 0; @@ -912,8 +929,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData, QList<QFontValues> *values) { const uchar *data = reinterpret_cast<const uchar *>(fontData.constData()); + const uchar *dataEndSentinel = data + fontData.size(); - QList<quint32> offsets = getTrueTypeFontOffsets(data); + QList<quint32> offsets = getTrueTypeFontOffsets(data, dataEndSentinel); if (offsets.isEmpty()) return; @@ -921,7 +939,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData, const uchar *font = data + offsets.at(i); const uchar *table; quint32 length; - getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length); + getFontTable(data, dataEndSentinel, font, + qFromBigEndian(QFont::Tag("name").value()), + &table, &length); if (!table) continue; QFontNames names = qt_getCanonicalFontNames(table, length); @@ -930,8 +950,11 @@ static void getFamiliesAndSignatures(const QByteArray &fontData, families->append(std::move(names)); - if (values || signatures) - getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length); + if (values || signatures) { + getFontTable(data, dataEndSentinel, font, + qFromBigEndian(QFont::Tag("OS/2").value()), + &table, &length); + } if (values) { QFontValues fontValues; @@ -996,7 +1019,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, HDC hdc = GetDC(0); LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); - memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size())); + memcpy(lf.lfFaceName, familyName.data(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size())); lf.lfCharSet = DEFAULT_CHARSET; const QFontValues &values = fontValues.at(j); lf.lfWeight = values.weight; @@ -1077,7 +1100,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, void QWindowsFontDatabase::removeApplicationFonts() { - for (const WinApplicationFont &font : qAsConst(m_applicationFonts)) { + for (const WinApplicationFont &font : std::as_const(m_applicationFonts)) { if (font.handle) { RemoveFontMemResourceEx(font.handle); } else { @@ -1089,10 +1112,22 @@ void QWindowsFontDatabase::removeApplicationFonts() m_eudcFonts.clear(); } +QWindowsFontDatabase::FontHandle::FontHandle(IDWriteFontFace *face, const QString &name) + : fontFace(face), faceName(name) +{ + fontFace->AddRef(); +} + + +QWindowsFontDatabase::FontHandle::~FontHandle() +{ + if (fontFace != nullptr) + fontFace->Release(); +} + void QWindowsFontDatabase::releaseHandle(void *handle) { - const QChar *faceName = reinterpret_cast<const QChar *>(handle); - delete[] faceName; + delete static_cast<FontHandle *>(handle); } QString QWindowsFontDatabase::fontDir() const @@ -1109,18 +1144,22 @@ bool QWindowsFontDatabase::fontsAlwaysScalable() const void QWindowsFontDatabase::derefUniqueFont(const QString &uniqueFont) { - if (m_uniqueFontData.contains(uniqueFont)) { - if (!m_uniqueFontData[uniqueFont].refCount.deref()) { - RemoveFontMemResourceEx(m_uniqueFontData[uniqueFont].handle); - m_uniqueFontData.remove(uniqueFont); + const std::scoped_lock lock(m_uniqueFontDataMutex); + const auto it = m_uniqueFontData.find(uniqueFont); + if (it != m_uniqueFontData.end()) { + if (--it->refCount == 0) { + RemoveFontMemResourceEx(it->handle); + m_uniqueFontData.erase(it); } } } void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont) { - if (m_uniqueFontData.contains(uniqueFont)) - m_uniqueFontData[uniqueFont].refCount.ref(); + const std::scoped_lock lock(m_uniqueFontDataMutex); + const auto it = m_uniqueFontData.find(uniqueFont); + if (it != m_uniqueFontData.end()) + ++it->refCount; } QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const @@ -1170,7 +1209,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam); if (nameSubstitute != fam) { const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1); - memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t)); + memcpy(lf.lfFaceName, nameSubstitute.data(), nameSubstituteLength * sizeof(wchar_t)); lf.lfFaceName[nameSubstituteLength] = 0; } @@ -1188,6 +1227,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace); if (SUCCEEDED(hr)) { bool isColorFont = false; + bool needsSimulation = false; #if QT_CONFIG(direct2d) IDWriteFontFace2 *directWriteFontFace2 = nullptr; if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2), @@ -1195,10 +1235,12 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q if (directWriteFontFace2->IsColorFont()) isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0; + needsSimulation = directWriteFontFace2->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE; + directWriteFontFace2->Release(); } #endif // direct2d - useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont); + useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont) || needsSimulation; qCDebug(lcQpaFonts) << __FUNCTION__ << request.families.first() << request.pointSize << "pt" << "hintingPreference=" << hintingPreference << "color=" << isColorFont @@ -1214,9 +1256,6 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q QFontDef fontDef = request; fontDef.families = QStringList(QString::fromWCharArray(n)); - - if (isColorFont) - fedw->glyphFormat = QFontEngine::Format_ARGB; fedw->initFontInfo(fontDef, dpi); fe = fedw; } |