diff options
author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2023-12-07 13:09:33 +0100 |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2024-02-02 18:01:52 +0100 |
commit | 0916415ef7e909b7347c790c509280ae524482b7 (patch) | |
tree | ba3e62ef21c593675d85bf02a0d0a4fcb53ecb32 /src/gui/text/windows | |
parent | 16bcdba8e7adae79729c6347e711bd0a976dbbe7 (diff) |
Implement missing features in DirectWrite font backend
The DirectWrite font backend is an optional backend which
is planned to take over as the default on Windows. In order
to do this, though, a few gaps need to be filled in order
for it to pass all autotests.
The following things are covered by this:
1. Bitmap fonts are unsupported in DirectWrite. We enumerate
these using GDI and fall back to the GDI font engine when
loading them. As part of this, we introduce a new handle
type for fonts on Windows which can represent both
the DirectWrite and GDI engines.
2. "Legacy font names" where sub-family is embedded in the
family name is now enumerated together with the
typographic font name.
3. The DirectWrite font engine was not loading kerning pairs
from the font, like the other engines (omission which was
detected by the test)
4. Turning off antialiasing does not work with DirectWrite, so
we fall back to GDI for this.
5. Loading supported writing systems from application fonts
was not supported.
Task-number: QTBUG-119420
Change-Id: Icf6c351afb0d7487b2f4634199088d701a324aae
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src/gui/text/windows')
6 files changed, 448 insertions, 103 deletions
diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp index b897e1f1db..499f43debb 100644 --- a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp +++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp @@ -106,6 +106,12 @@ static QFont::Style fromDirectWriteStyle(DWRITE_FONT_STYLE style) void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName) { auto it = m_populatedFonts.find(familyName); + if (it == m_populatedFonts.end() && m_populatedBitmapFonts.contains(familyName)) { + qCDebug(lcQpaFonts) << "Populating bitmap font" << familyName; + QWindowsFontDatabase::populateFamily(familyName); + return; + } + IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() : nullptr; if (fontFamily == nullptr) { qCWarning(lcQpaFonts) << "Cannot find" << familyName << "in list of fonts"; @@ -173,53 +179,38 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName) IDWriteFontFace *face = nullptr; if (SUCCEEDED(font->CreateFontFace(&face))) { - QSupportedWritingSystems writingSystems; - - const void *tableData = nullptr; - UINT32 tableSize; - void *tableContext = nullptr; - BOOL exists; - HRESULT hr = face->TryGetFontTable(qFromBigEndian(QFont::Tag("OS/2").value()), - &tableData, - &tableSize, - &tableContext, - &exists); - if (SUCCEEDED(hr) && exists) { - writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast<const char *>(tableData), tableSize); - } else { // Fall back to checking first character of each Unicode range in font (may include too many writing systems) - quint32 rangeCount; - hr = font1->GetUnicodeRanges(0, nullptr, &rangeCount); - - if (rangeCount > 0) { - QVarLengthArray<DWRITE_UNICODE_RANGE, QChar::ScriptCount> ranges(rangeCount); - - hr = font1->GetUnicodeRanges(rangeCount, ranges.data(), &rangeCount); - if (SUCCEEDED(hr)) { - for (uint i = 0; i < rangeCount; ++i) { - QChar::Script script = QChar::script(ranges.at(i).first); - - QFontDatabase::WritingSystem writingSystem = qt_writing_system_for_script(script); - - if (writingSystem > QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount) - writingSystems.setSupported(writingSystem); - } - } else { - const QString errorString = qt_error_string(int(hr)); - qCWarning(lcQpaFonts) << "Failed to get unicode ranges for font" << englishLocaleFamilyName << englishLocaleStyleName << ":" << errorString; - } - } - } + QSupportedWritingSystems writingSystems = supportedWritingSystems(face); if (!englishLocaleStyleName.isEmpty() || defaultLocaleStyleName.isEmpty()) { qCDebug(lcQpaFonts) << "Font" << englishLocaleFamilyName << englishLocaleStyleName << "supports writing systems:" << writingSystems; - QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); + QPlatformFontDatabase::registerFont(englishLocaleFamilyName, + englishLocaleStyleName, + QString(), + weight, + style, + stretch, + antialias, + scalable, + size, + fixed, + writingSystems, + new FontHandle(face, englishLocaleFamilyName)); } if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) { - QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); + QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, + defaultLocaleStyleName, + QString(), + weight, + style, + stretch, + antialias, + scalable, + size, + fixed, + writingSystems, + new FontHandle(face, defaultLocaleFamilyName)); } face->Release(); @@ -238,10 +229,144 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName) } } +QSupportedWritingSystems QWindowsDirectWriteFontDatabase::supportedWritingSystems(IDWriteFontFace *face) const +{ + QSupportedWritingSystems writingSystems; + writingSystems.setSupported(QFontDatabase::Any); + + DirectWriteScope<IDWriteFontFace1> face1; + if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace1), + reinterpret_cast<void **>(&face1)))) { + const void *tableData = nullptr; + UINT32 tableSize; + void *tableContext = nullptr; + BOOL exists; + HRESULT hr = face->TryGetFontTable(qFromBigEndian(QFont::Tag("OS/2").value()), + &tableData, + &tableSize, + &tableContext, + &exists); + if (SUCCEEDED(hr) && exists) { + writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast<const char *>(tableData), tableSize); + } else { // Fall back to checking first character of each Unicode range in font (may include too many writing systems) + quint32 rangeCount; + hr = face1->GetUnicodeRanges(0, nullptr, &rangeCount); + + if (rangeCount > 0) { + QVarLengthArray<DWRITE_UNICODE_RANGE, QChar::ScriptCount> ranges(rangeCount); + + hr = face1->GetUnicodeRanges(rangeCount, ranges.data(), &rangeCount); + if (SUCCEEDED(hr)) { + for (uint i = 0; i < rangeCount; ++i) { + QChar::Script script = QChar::script(ranges.at(i).first); + + QFontDatabase::WritingSystem writingSystem = qt_writing_system_for_script(script); + + if (writingSystem > QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount) + writingSystems.setSupported(writingSystem); + } + } else { + const QString errorString = qt_error_string(int(hr)); + qCWarning(lcQpaFonts) << "Failed to get unicode ranges for font:" << errorString; + } + } + } + } + + return writingSystems; +} + +bool QWindowsDirectWriteFontDatabase::populateFamilyAliases(const QString &missingFamily) +{ + // If the font has not been populated, it is possible this is a legacy font family supported + // by GDI. We make an attempt at loading it via GDI and then add this face directly to the + // database. + if (!missingFamily.isEmpty() + && missingFamily.size() < LF_FACESIZE + && !m_populatedFonts.contains(missingFamily) + && !m_populatedBitmapFonts.contains(missingFamily)) { + qCDebug(lcQpaFonts) << "Loading unpopulated" << missingFamily << ". Trying GDI."; + + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + memcpy(lf.lfFaceName, missingFamily.utf16(), missingFamily.size() * sizeof(wchar_t)); + + HFONT hfont = CreateFontIndirect(&lf); + if (hfont) { + HDC dummy = GetDC(0); + HGDIOBJ oldFont = SelectObject(dummy, hfont); + + DirectWriteScope<IDWriteFontFace> directWriteFontFace; + if (SUCCEEDED(data()->directWriteGdiInterop->CreateFontFaceFromHdc(dummy, &directWriteFontFace))) { + DirectWriteScope<IDWriteFontCollection> fontCollection; + if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) { + DirectWriteScope<IDWriteFont> font; + if (SUCCEEDED(fontCollection->GetFontFromFontFace(*directWriteFontFace, &font))) { + + DirectWriteScope<IDWriteFont1> font1; + if (SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1), + reinterpret_cast<void **>(&font1)))) { + IDWriteLocalizedStrings *names; + if (SUCCEEDED(font1->GetFaceNames(&names))) { + wchar_t englishLocale[] = L"en-us"; + QString englishLocaleStyleName = localeString(names, englishLocale); + + QFont::Stretch stretch = fromDirectWriteStretch(font1->GetStretch()); + QFont::Style style = fromDirectWriteStyle(font1->GetStyle()); + QFont::Weight weight = fromDirectWriteWeight(font1->GetWeight()); + bool fixed = font1->IsMonospacedFont(); + + QSupportedWritingSystems writingSystems = supportedWritingSystems(*directWriteFontFace); + + qCDebug(lcQpaFonts) << "Registering legacy font family" << missingFamily; + QPlatformFontDatabase::registerFont(missingFamily, + englishLocaleStyleName, + QString(), + weight, + style, + stretch, + false, + true, + 0xffff, + fixed, + writingSystems, + new FontHandle(*directWriteFontFace, missingFamily)); + + SelectObject(dummy, oldFont); + DeleteObject(hfont); + + return true; + } + } + } + } + } + + SelectObject(dummy, oldFont); + DeleteObject(hfont); + } + } + + // Skip over implementation in QWindowsFontDatabase + return QWindowsFontDatabaseBase::populateFamilyAliases(missingFamily); +} + +QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(const QByteArray &fontData, + qreal pixelSize, + QFont::HintingPreference hintingPreference) +{ + // Skip over implementation in QWindowsFontDatabase + return QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference); +} + QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) { - IDWriteFontFace *face = reinterpret_cast<IDWriteFontFace *>(handle); - Q_ASSERT(face != nullptr); + const FontHandle *fontHandle = static_cast<const FontHandle *>(handle); + IDWriteFontFace *face = fontHandle->fontFace; + if (face == nullptr || fontDef.styleStrategy & QFont::NoAntialias) { + qCDebug(lcQpaFonts) << "Falling back to GDI"; + return QWindowsFontDatabase::fontEngine(fontDef, handle); + } DWRITE_FONT_SIMULATIONS simulations = DWRITE_FONT_SIMULATIONS_NONE; if (fontDef.weight >= QFont::DemiBold || fontDef.style != QFont::StyleNormal) { @@ -327,7 +452,7 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray return QStringList(); } - QStringList ret; + QSet<QString> ret; for (int i = 0; i < faces.size(); ++i) { IDWriteFontFace *face = faces.at(i); wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH]; @@ -335,22 +460,18 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray wchar_t englishLocale[] = L"en-us"; static const int SMOOTH_SCALABLE = 0xffff; - const QString foundryName; // No such concept. const bool scalable = true; const bool antialias = false; const int size = SMOOTH_SCALABLE; - QSupportedWritingSystems writingSystems; - writingSystems.setSupported(QFontDatabase::Any); - writingSystems.setSupported(QFontDatabase::Latin); - - IDWriteFontFace3 *face3 = nullptr; + QSupportedWritingSystems writingSystems = supportedWritingSystems(face); + DirectWriteScope<IDWriteFontFace3> face3; if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3), - reinterpret_cast<void **>(&face3)))) { + reinterpret_cast<void **>(&face3)))) { QString defaultLocaleFamilyName; QString englishLocaleFamilyName; - IDWriteLocalizedStrings *names; + IDWriteLocalizedStrings *names = nullptr; if (SUCCEEDED(face3->GetFamilyNames(&names))) { defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); englishLocaleFamilyName = localeString(names, englishLocale); @@ -367,6 +488,43 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray names->Release(); } + BOOL ok; + QString defaultLocaleGdiCompatibleFamilyName; + QString englishLocaleGdiCompatibleFamilyName; + if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &ok)) && ok) { + defaultLocaleGdiCompatibleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); + englishLocaleGdiCompatibleFamilyName = localeString(names, englishLocale); + + names->Release(); + } + + QString defaultLocaleGdiCompatibleStyleName; + QString englishLocaleGdiCompatibleStyleName; + if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, &names, &ok)) && ok) { + defaultLocaleGdiCompatibleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); + englishLocaleGdiCompatibleStyleName = localeString(names, englishLocale); + + names->Release(); + } + + QString defaultLocaleTypographicFamilyName; + QString englishLocaleTypographicFamilyName; + if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_FAMILY_NAMES, &names, &ok)) && ok) { + defaultLocaleTypographicFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); + englishLocaleTypographicFamilyName = localeString(names, englishLocale); + + names->Release(); + } + + QString defaultLocaleTypographicStyleName; + QString englishLocaleTypographicStyleName; + if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_SUBFAMILY_NAMES, &names, &ok)) && ok) { + defaultLocaleTypographicStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); + englishLocaleTypographicStyleName = localeString(names, englishLocale); + + names->Release(); + } + QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch()); QFont::Style style = fromDirectWriteStyle(face3->GetStyle()); QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight()); @@ -389,12 +547,22 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray applicationFont->properties.append(properties); } - ret.append(englishLocaleFamilyName); - QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); + ret.insert(englishLocaleFamilyName); + QPlatformFontDatabase::registerFont(englishLocaleFamilyName, + englishLocaleStyleName, + QString(), + weight, + style, + stretch, + antialias, + scalable, + size, + fixed, + writingSystems, + new FontHandle(face, englishLocaleFamilyName)); } - if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) { + if (!defaultLocaleFamilyName.isEmpty() && !ret.contains(defaultLocaleFamilyName)) { if (applicationFont != nullptr) { QFontDatabasePrivate::ApplicationFont::Properties properties; properties.style = style; @@ -404,12 +572,121 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray applicationFont->properties.append(properties); } - ret.append(defaultLocaleFamilyName); - QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); + ret.insert(defaultLocaleFamilyName); + QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, + defaultLocaleStyleName, + QString(), + weight, + style, + stretch, + antialias, + scalable, + size, + fixed, + writingSystems, + new FontHandle(face, defaultLocaleFamilyName)); + } + + if (!englishLocaleGdiCompatibleFamilyName.isEmpty() && + !ret.contains(englishLocaleGdiCompatibleFamilyName)) { + if (applicationFont != nullptr) { + QFontDatabasePrivate::ApplicationFont::Properties properties; + properties.style = style; + properties.weight = weight; + properties.familyName = englishLocaleGdiCompatibleFamilyName; + applicationFont->properties.append(properties); + } + + ret.insert(englishLocaleGdiCompatibleFamilyName); + QPlatformFontDatabase::registerFont(englishLocaleGdiCompatibleFamilyName, + englishLocaleGdiCompatibleStyleName, + QString(), + weight, + style, + stretch, + antialias, + scalable, + size, + fixed, + writingSystems, + new FontHandle(face, englishLocaleGdiCompatibleFamilyName)); + } + + if (!defaultLocaleGdiCompatibleFamilyName.isEmpty() + && !ret.contains(defaultLocaleGdiCompatibleFamilyName)) { + if (applicationFont != nullptr) { + QFontDatabasePrivate::ApplicationFont::Properties properties; + properties.style = style; + properties.weight = weight; + properties.familyName = defaultLocaleGdiCompatibleFamilyName; + applicationFont->properties.append(properties); + } + + ret.insert(defaultLocaleGdiCompatibleFamilyName); + QPlatformFontDatabase::registerFont(defaultLocaleGdiCompatibleFamilyName, + defaultLocaleGdiCompatibleStyleName, + QString(), + weight, + style, + stretch, + antialias, + scalable, + size, + fixed, + writingSystems, + new FontHandle(face, defaultLocaleGdiCompatibleFamilyName)); + } + + if (!englishLocaleTypographicFamilyName.isEmpty() + && !ret.contains(englishLocaleTypographicFamilyName)) { + if (applicationFont != nullptr) { + QFontDatabasePrivate::ApplicationFont::Properties properties; + properties.style = style; + properties.weight = weight; + properties.familyName = englishLocaleTypographicFamilyName; + applicationFont->properties.append(properties); + } + + ret.insert(englishLocaleTypographicFamilyName); + QPlatformFontDatabase::registerFont(englishLocaleTypographicFamilyName, + englishLocaleTypographicStyleName, + QString(), + weight, + style, + stretch, + antialias, + scalable, + size, + fixed, + writingSystems, + new FontHandle(face, englishLocaleTypographicFamilyName)); + } + + if (!defaultLocaleTypographicFamilyName.isEmpty() + && !ret.contains(defaultLocaleTypographicFamilyName)) { + if (applicationFont != nullptr) { + QFontDatabasePrivate::ApplicationFont::Properties properties; + properties.style = style; + properties.weight = weight; + properties.familyName = defaultLocaleTypographicFamilyName; + applicationFont->properties.append(properties); + } + + ret.insert(defaultLocaleTypographicFamilyName); + QPlatformFontDatabase::registerFont(defaultLocaleTypographicFamilyName, + defaultLocaleTypographicStyleName, + QString(), + weight, + style, + stretch, + antialias, + scalable, + size, + fixed, + writingSystems, + new FontHandle(face, defaultLocaleTypographicFamilyName)); } - face3->Release(); } else { qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face."; } @@ -417,18 +694,7 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray face->Release(); } - return ret; -} - -void QWindowsDirectWriteFontDatabase::releaseHandle(void *handle) -{ - IDWriteFontFace *face = reinterpret_cast<IDWriteFontFace *>(handle); - face->Release(); -} - -bool QWindowsDirectWriteFontDatabase::fontsAlwaysScalable() const -{ - return true; + return ret.values(); } bool QWindowsDirectWriteFontDatabase::isPrivateFontFamily(const QString &family) const @@ -437,6 +703,29 @@ bool QWindowsDirectWriteFontDatabase::isPrivateFontFamily(const QString &family) return false; } +static int QT_WIN_CALLBACK populateBitmapFonts(const LOGFONT *logFont, + const TEXTMETRIC *textmetric, + DWORD type, + LPARAM lparam) +{ + Q_UNUSED(textmetric); + + // the "@family" fonts are just the same as "family". Ignore them. + const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont); + const wchar_t *faceNameW = f->elfLogFont.lfFaceName; + if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) { + const QString faceName = QString::fromWCharArray(faceNameW); + if (type & RASTER_FONTTYPE || type == 0) { + QWindowsDirectWriteFontDatabase *db = reinterpret_cast<QWindowsDirectWriteFontDatabase *>(lparam); + if (!db->hasPopulatedFont(faceName)) { + db->registerFontFamily(faceName); + db->registerBitmapFont(faceName); + } + } + } + return 1; // continue +} + void QWindowsDirectWriteFontDatabase::populateFontDatabase() { wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH]; @@ -446,10 +735,19 @@ void QWindowsDirectWriteFontDatabase::populateFontDatabase() const QString defaultFontName = defaultFont().families().constFirst(); const QString systemDefaultFontName = systemDefaultFont().families().constFirst(); - IDWriteFontCollection *fontCollection; - if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) { + DirectWriteScope<IDWriteFontCollection2> fontCollection; + DirectWriteScope<IDWriteFactory6> factory6; + if (FAILED(data()->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory6), + reinterpret_cast<void **>(&factory6)))) { + qCWarning(lcQpaFonts) << "Can't initialize IDWriteFactory6. Use GDI font engine instead."; + return; + } + + if (SUCCEEDED(factory6->GetSystemFontCollection(false, + DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC, + &fontCollection))) { for (uint i = 0; i < fontCollection->GetFontFamilyCount(); ++i) { - IDWriteFontFamily *fontFamily; + IDWriteFontFamily2 *fontFamily; if (SUCCEEDED(fontCollection->GetFontFamily(i, &fontFamily))) { QString defaultLocaleName; QString englishLocaleName; @@ -493,6 +791,17 @@ void QWindowsDirectWriteFontDatabase::populateFontDatabase() } } } + + // Since bitmap fonts are not supported by DirectWrite, we need to populate these as well + { + HDC dummy = GetDC(0); + LOGFONT lf; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfFaceName[0] = 0; + lf.lfPitchAndFamily = 0; + EnumFontFamiliesEx(dummy, &lf, populateBitmapFonts, reinterpret_cast<intptr_t>(this), 0); + ReleaseDC(0, dummy); + } } QFont QWindowsDirectWriteFontDatabase::defaultFont() const diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h index 41a1640c16..093c629a16 100644 --- a/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h +++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h @@ -20,17 +20,18 @@ QT_REQUIRE_CONFIG(directwrite3); -#include "qwindowsfontdatabasebase_p.h" +#include "qwindowsfontdatabase_p.h" #include <QtCore/qloggingcategory.h> struct IDWriteFactory; struct IDWriteFont; +struct IDWriteFont1; struct IDWriteFontFamily; struct IDWriteLocalizedStrings; QT_BEGIN_NAMESPACE -class Q_GUI_EXPORT QWindowsDirectWriteFontDatabase : public QWindowsFontDatabaseBase +class Q_GUI_EXPORT QWindowsDirectWriteFontDatabase : public QWindowsFontDatabase { Q_DISABLE_COPY_MOVE(QWindowsDirectWriteFontDatabase) public: @@ -39,21 +40,34 @@ public: void populateFontDatabase() override; void populateFamily(const QString &familyName) override; + bool populateFamilyAliases(const QString &missingFamily) override; QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; + QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override; QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *font = nullptr) override; - void releaseHandle(void *handle) override; QFont defaultFont() const override; - bool fontsAlwaysScalable() const override; bool isPrivateFontFamily(const QString &family) const override; bool supportsVariableApplicationFonts() const override; + void registerBitmapFont(const QString &bitmapFont) + { + m_populatedBitmapFonts.insert(bitmapFont); + } + + bool hasPopulatedFont(const QString &fontFamily) const + { + return m_populatedFonts.contains(fontFamily); + } + private: friend class QWindowsFontEngineDirectWrite; static QString localeString(IDWriteLocalizedStrings *names, wchar_t localeName[]); + QSupportedWritingSystems supportedWritingSystems(IDWriteFontFace *face) const; + QHash<QString, IDWriteFontFamily *> m_populatedFonts; + QSet<QString> m_populatedBitmapFonts; }; QT_END_NAMESPACE diff --git a/src/gui/text/windows/qwindowsfontdatabase.cpp b/src/gui/text/windows/qwindowsfontdatabase.cpp index 51254f7727..0d84475049 100644 --- a/src/gui/text/windows/qwindowsfontdatabase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabase.cpp @@ -434,18 +434,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.data(), sizeof(wchar_t) * nameLength); - faceNamePtr[nameLength] = u'\0'; - } - return faceNamePtr; -} - namespace { struct StoreFontPayload { StoreFontPayload(const QString &family, @@ -554,19 +542,19 @@ static bool addFontToDatabase(QString 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 @@ -580,7 +568,7 @@ static bool addFontToDatabase(QString 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) @@ -752,7 +740,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()); @@ -1124,10 +1113,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 diff --git a/src/gui/text/windows/qwindowsfontdatabase_p.h b/src/gui/text/windows/qwindowsfontdatabase_p.h index dfaa1f9c0e..0c99c91fde 100644 --- a/src/gui/text/windows/qwindowsfontdatabase_p.h +++ b/src/gui/text/windows/qwindowsfontdatabase_p.h @@ -75,9 +75,16 @@ public: static void debugFormat(QDebug &d, const LOGFONT &lf); #endif // !QT_NO_DEBUG_STREAM + struct FontHandle { + FontHandle(const QString &name) : faceName(name) {} + FontHandle(IDWriteFontFace *face, const QString &name); + ~FontHandle(); -private: + IDWriteFontFace *fontFace = nullptr; + QString faceName; + }; +private: void addDefaultEUDCFont(); struct WinApplicationFont { diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp index cef739201b..84e619b0d9 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -565,16 +565,27 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory IUnknown *result = nullptr; # if QT_CONFIG(directwrite3) - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result); + qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory6"; + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory6), &result); - if (result == nullptr) + if (result == nullptr) { + qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory5"; + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result); + } + + if (result == nullptr) { + qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory3"; DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result); + } # endif - if (result == nullptr) + if (result == nullptr) { + qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory2"; DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result); + } if (result == nullptr) { + qCDebug(lcQpaFonts) << "Trying to create plain IDWriteFactory"; if (FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) { qErrnoWarning("DWriteCreateFactory failed"); return; diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp index e5a2c7a2b8..6043406c4d 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -365,6 +365,8 @@ void QWindowsFontEngineDirectWrite::collectMetrics() quint16 advanceWidthMax = qFromBigEndian<quint16>(table.constData() + advanceWidthMaxLocation); m_maxAdvanceWidth = DESIGN_TO_LOGICAL(advanceWidthMax); } + + loadKerningPairs(emSquareSize() / QFixed::fromReal(fontDef.pixelSize)); } QFixed QWindowsFontEngineDirectWrite::underlinePosition() const @@ -672,7 +674,8 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, bool QWindowsFontEngineDirectWrite::supportsHorizontalSubPixelPositions() const { - return true; + DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef); + return (renderMode != DWRITE_RENDERING_MODE_GDI_CLASSIC && renderMode != DWRITE_RENDERING_MODE_GDI_NATURAL); } QFontEngine::Properties QWindowsFontEngineDirectWrite::properties() const |