diff --git a/src/gui/text/freetype/qfontengine_ft.cpp b/src/gui/text/freetype/qfontengine_ft.cpp index b7eb9f412b7..f3a80d925d5 100644 --- a/src/gui/text/freetype/qfontengine_ft.cpp +++ b/src/gui/text/freetype/qfontengine_ft.cpp @@ -2241,15 +2241,6 @@ Qt::HANDLE QFontEngineFT::handle() const return non_locked_face(); } -bool QFontEngineFT::supportsVariableApplicationFonts() const -{ -#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900 - return true; -#else - return false; -#endif -} - QT_END_NAMESPACE #endif // QT_NO_FREETYPE diff --git a/src/gui/text/freetype/qfontengine_ft_p.h b/src/gui/text/freetype/qfontengine_ft_p.h index 85f1d87a3c3..e1951749602 100644 --- a/src/gui/text/freetype/qfontengine_ft_p.h +++ b/src/gui/text/freetype/qfontengine_ft_p.h @@ -159,8 +159,6 @@ private: return supportsHorizontalSubPixelPositions(); } - bool supportsVariableApplicationFonts() const override; - bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override; int synthesized() const override; diff --git a/src/gui/text/freetype/qfreetypefontdatabase.cpp b/src/gui/text/freetype/qfreetypefontdatabase.cpp index 2441deaa38e..df64d2ce90f 100644 --- a/src/gui/text/freetype/qfreetypefontdatabase.cpp +++ b/src/gui/text/freetype/qfreetypefontdatabase.cpp @@ -335,4 +335,13 @@ QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const Q return families; } +bool QFreeTypeFontDatabase::supportsVariableApplicationFonts() const +{ +#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900 + return true; +#else + return false; +#endif +} + QT_END_NAMESPACE diff --git a/src/gui/text/freetype/qfreetypefontdatabase_p.h b/src/gui/text/freetype/qfreetypefontdatabase_p.h index 46ffa4353c7..5fcec585d29 100644 --- a/src/gui/text/freetype/qfreetypefontdatabase_p.h +++ b/src/gui/text/freetype/qfreetypefontdatabase_p.h @@ -42,6 +42,7 @@ public: QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr) override; void releaseHandle(void *handle) override; + bool supportsVariableApplicationFonts() const override; static void addNamedInstancesForFace(void *face, int faceIndex, const QString &family, const QString &styleName, diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 66b0e885989..8f2336f2ace 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -247,11 +247,6 @@ bool QFontEngine::supportsTransformation(const QTransform &transform) const return transform.type() < QTransform::TxProject; } -bool QFontEngine::supportsVariableApplicationFonts() const -{ - return false; -} - bool QFontEngine::expectsGammaCorrectedBlending() const { return true; diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 50e427e46ee..bf6514a0bdd 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -213,7 +213,6 @@ public: inline bool canRender(uint ucs4) const { return glyphIndex(ucs4) != 0; } virtual bool canRender(const QChar *str, int len) const; - virtual bool supportsVariableApplicationFonts() const; virtual bool supportsTransformation(const QTransform &transform) const; diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp index ce7713db035..a146254f68a 100644 --- a/src/gui/text/qplatformfontdatabase.cpp +++ b/src/gui/text/qplatformfontdatabase.cpp @@ -645,6 +645,18 @@ bool QPlatformFontDatabase::isFamilyPopulated(const QString &familyName) return qt_isFontFamilyPopulated(familyName); } +/*! + Returns true if this font database supports loading named instances from variable application + fonts. + + \since 6.7 +*/ +bool QPlatformFontDatabase::supportsVariableApplicationFonts() const +{ + return false; +} + + /*! \class QPlatformFontDatabase \since 5.0 diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h index a5e65086a8c..3007a11838f 100644 --- a/src/gui/text/qplatformfontdatabase.h +++ b/src/gui/text/qplatformfontdatabase.h @@ -89,6 +89,8 @@ public: virtual bool fontsAlwaysScalable() const; virtual QList standardSizes() const; + virtual bool supportsVariableApplicationFonts() const; + // helper static QSupportedWritingSystems writingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]); static QSupportedWritingSystems writingSystemsFromOS2Table(const char *os2Table, size_t length); diff --git a/src/gui/text/unix/qfontconfigdatabase.cpp b/src/gui/text/unix/qfontconfigdatabase.cpp index 4a402cd7641..8043602542e 100644 --- a/src/gui/text/unix/qfontconfigdatabase.cpp +++ b/src/gui/text/unix/qfontconfigdatabase.cpp @@ -1042,4 +1042,13 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef engine->glyphFormat = format; } +bool QFontconfigDatabase::supportsVariableApplicationFonts() const +{ +#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900 + return true; +#else + return false; +#endif +} + QT_END_NAMESPACE diff --git a/src/gui/text/unix/qfontconfigdatabase_p.h b/src/gui/text/unix/qfontconfigdatabase_p.h index cf15306e40d..dd7a70a375e 100644 --- a/src/gui/text/unix/qfontconfigdatabase_p.h +++ b/src/gui/text/unix/qfontconfigdatabase_p.h @@ -28,6 +28,7 @@ public: ~QFontconfigDatabase() override; void populateFontDatabase() override; void invalidate() override; + bool supportsVariableApplicationFonts() const override; QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) override; QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp index 23dbe1f4d61..e8251ac9448 100644 --- a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp +++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp @@ -249,99 +249,102 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray loadedData = file.readAll(); } - IDWriteFontFace *face = createDirectWriteFace(loadedData); - if (face == nullptr) { + QList faces = createDirectWriteFaces(loadedData); + if (faces.isEmpty()) { qCWarning(lcQpaFonts) << "Failed to create DirectWrite face from font data. Font may be unsupported."; return QStringList(); } - wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH]; - bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0; - 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); - QStringList ret; - IDWriteFontFace3 *face3 = nullptr; - if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3), - reinterpret_cast(&face3)))) { - QString defaultLocaleFamilyName; - QString englishLocaleFamilyName; + for (int i = 0; i < faces.size(); ++i) { + IDWriteFontFace *face = faces.at(i); + wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH]; + bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0; + wchar_t englishLocale[] = L"en-us"; - IDWriteLocalizedStrings *names; - if (SUCCEEDED(face3->GetFamilyNames(&names))) { - defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); - englishLocaleFamilyName = localeString(names, englishLocale); + 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; - names->Release(); - } + QSupportedWritingSystems writingSystems; + writingSystems.setSupported(QFontDatabase::Any); + writingSystems.setSupported(QFontDatabase::Latin); - QString defaultLocaleStyleName; - QString englishLocaleStyleName; - if (SUCCEEDED(face3->GetFaceNames(&names))) { - defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); - englishLocaleStyleName = localeString(names, englishLocale); + IDWriteFontFace3 *face3 = nullptr; + if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3), + reinterpret_cast(&face3)))) { + QString defaultLocaleFamilyName; + QString englishLocaleFamilyName; - names->Release(); - } + IDWriteLocalizedStrings *names; + if (SUCCEEDED(face3->GetFamilyNames(&names))) { + defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); + englishLocaleFamilyName = localeString(names, englishLocale); - QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch()); - QFont::Style style = fromDirectWriteStyle(face3->GetStyle()); - QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight()); - bool fixed = face3->IsMonospacedFont(); - - qCDebug(lcQpaFonts) << "\tFont names:" << englishLocaleFamilyName << ", " << defaultLocaleFamilyName - << ", style names:" << englishLocaleStyleName << ", " << defaultLocaleStyleName - << ", stretch:" << stretch - << ", style:" << style - << ", weight:" << weight - << ", fixed:" << fixed; - - if (!englishLocaleFamilyName.isEmpty()) { - if (applicationFont != nullptr) { - QFontDatabasePrivate::ApplicationFont::Properties properties; - properties.style = style; - properties.weight = weight; - properties.familyName = englishLocaleFamilyName; - properties.styleName = englishLocaleStyleName; - applicationFont->properties.append(properties); + names->Release(); } - ret.append(englishLocaleFamilyName); - QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); - } + QString defaultLocaleStyleName; + QString englishLocaleStyleName; + if (SUCCEEDED(face3->GetFaceNames(&names))) { + defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); + englishLocaleStyleName = localeString(names, englishLocale); - if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) { - if (applicationFont != nullptr) { - QFontDatabasePrivate::ApplicationFont::Properties properties; - properties.style = style; - properties.weight = weight; - properties.familyName = englishLocaleFamilyName; - properties.styleName = englishLocaleStyleName; - applicationFont->properties.append(properties); + names->Release(); } - ret.append(defaultLocaleFamilyName); - QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); + QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch()); + QFont::Style style = fromDirectWriteStyle(face3->GetStyle()); + QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight()); + bool fixed = face3->IsMonospacedFont(); + + qCDebug(lcQpaFonts) << "\tFont names:" << englishLocaleFamilyName << ", " << defaultLocaleFamilyName + << ", style names:" << englishLocaleStyleName << ", " << defaultLocaleStyleName + << ", stretch:" << stretch + << ", style:" << style + << ", weight:" << weight + << ", fixed:" << fixed; + + if (!englishLocaleFamilyName.isEmpty()) { + if (applicationFont != nullptr) { + QFontDatabasePrivate::ApplicationFont::Properties properties; + properties.style = style; + properties.weight = weight; + properties.familyName = englishLocaleFamilyName; + properties.styleName = englishLocaleStyleName; + applicationFont->properties.append(properties); + } + + ret.append(englishLocaleFamilyName); + QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); + face->AddRef(); + } + + if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) { + if (applicationFont != nullptr) { + QFontDatabasePrivate::ApplicationFont::Properties properties; + properties.style = style; + properties.weight = weight; + properties.familyName = englishLocaleFamilyName; + properties.styleName = englishLocaleStyleName; + applicationFont->properties.append(properties); + } + + ret.append(defaultLocaleFamilyName); + QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); + face->AddRef(); + } + + face3->Release(); + } else { + qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face."; } - face3->Release(); - } else { - qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face."; + face->Release(); } - face->Release(); - return ret; } @@ -425,4 +428,17 @@ QFont QWindowsDirectWriteFontDatabase::defaultFont() const return QFont(QStringLiteral("Segoe UI")); } +bool QWindowsDirectWriteFontDatabase::supportsVariableApplicationFonts() const +{ + QSharedPointer fontEngineData = data(); + IDWriteFactory5 *factory5 = nullptr; + if (SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5), + reinterpret_cast(&factory5)))) { + factory5->Release(); + return true; + } + + return false; +} + QT_END_NAMESPACE diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h index 1babf6e05c2..41a1640c169 100644 --- a/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h +++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h @@ -47,6 +47,7 @@ public: bool fontsAlwaysScalable() const override; bool isPrivateFontFamily(const QString &family) const override; + bool supportsVariableApplicationFonts() const override; private: friend class QWindowsFontEngineDirectWrite; diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp index f9b36b48527..9343e447ae4 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -550,8 +550,12 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory IUnknown *result = nullptr; # if QT_CONFIG(directwrite3) - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result); + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result); + + if (result == nullptr) + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result); # endif + if (result == nullptr) DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result); @@ -692,12 +696,22 @@ QFont QWindowsFontDatabaseBase::systemDefaultFont() } #if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) -IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) const +IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) { + QList faces = createDirectWriteFaces(fontData, false); + Q_ASSERT(faces.size() <= 1); + + return faces.isEmpty() ? nullptr : faces.first(); +} + +QList QWindowsFontDatabaseBase::createDirectWriteFaces(const QByteArray &fontData, + bool queryVariations) const +{ + QList ret; QSharedPointer fontEngineData = data(); if (fontEngineData->directWriteFactory == nullptr) { qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()"; - return nullptr; + return ret; } CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory); @@ -712,7 +726,7 @@ IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArra &fontFile); if (FAILED(hres)) { qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__); - return nullptr; + return ret; } BOOL isSupportedFontType; @@ -722,25 +736,64 @@ IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArra fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces); if (!isSupportedFontType) { fontFile->Release(); - return nullptr; + return ret; } +#if QT_CONFIG(directwrite3) + IDWriteFactory5 *factory5 = nullptr; + if (queryVariations && SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5), + reinterpret_cast(&factory5)))) { + + IDWriteFontSetBuilder1 *builder; + if (SUCCEEDED(factory5->CreateFontSetBuilder(&builder))) { + if (SUCCEEDED(builder->AddFontFile(fontFile))) { + IDWriteFontSet *fontSet; + if (SUCCEEDED(builder->CreateFontSet(&fontSet))) { + int count = fontSet->GetFontCount(); + qCDebug(lcQpaFonts) << "Found" << count << "variations in font file"; + for (int i = 0; i < count; ++i) { + IDWriteFontFaceReference *ref; + if (SUCCEEDED(fontSet->GetFontFaceReference(i, &ref))) { + IDWriteFontFace3 *face; + if (SUCCEEDED(ref->CreateFontFace(&face))) { + ret.append(face); + } + ref->Release(); + } + } + fontSet->Release(); + } + } + + builder->Release(); + } + + factory5->Release(); + } +#else + Q_UNUSED(queryVariations); +#endif + // ### Currently no support for .ttc, but we could easily return a list here. - IDWriteFontFace *directWriteFontFace = nullptr; - hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType, - 1, - &fontFile, - 0, - DWRITE_FONT_SIMULATIONS_NONE, - &directWriteFontFace); - if (FAILED(hres)) { - qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__); - fontFile->Release(); - return nullptr; + if (ret.isEmpty()) { + IDWriteFontFace *directWriteFontFace = nullptr; + hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType, + 1, + &fontFile, + 0, + DWRITE_FONT_SIMULATIONS_NONE, + &directWriteFontFace); + if (FAILED(hres)) { + qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__); + fontFile->Release(); + return ret; + } else { + ret.append(directWriteFontFace); + } } fontFile->Release(); - return directWriteFontFace; + return ret; } #endif // directwrite && direct2d @@ -760,7 +813,10 @@ QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qr if (fontEngineData->directWriteFactory == nullptr) return nullptr; - IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData); + IDWriteFontFace * directWriteFontFace = createDirectWriteFace(fontData); + if (directWriteFontFace == nullptr) + return nullptr; + fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace, pixelSize, fontEngineData); diff --git a/src/gui/text/windows/qwindowsfontdatabasebase_p.h b/src/gui/text/windows/qwindowsfontdatabasebase_p.h index 60acc5cb06d..b7bd47ba84c 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase_p.h +++ b/src/gui/text/windows/qwindowsfontdatabasebase_p.h @@ -91,7 +91,9 @@ public: protected: #if QT_CONFIG(directwrite) - IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData) const; + QList createDirectWriteFaces(const QByteArray &fontData, + bool queryVariations = true) const; + IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData); #endif private: diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp index 81c402cd89a..fb61037c95d 100644 --- a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp +++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp @@ -12,6 +12,9 @@ #include #include #include +#include + +#include using namespace Qt::StringLiterals; @@ -513,11 +516,9 @@ void tst_QFontDatabase::findCourier() void tst_QFontDatabase::variableFont() { { - QFont f; - f.setStyleStrategy(QFont::NoFontMerging); - QFontPrivate *font_d = QFontPrivate::get(f); - if (!font_d->engineForScript(QChar::Script_Common)->supportsVariableApplicationFonts()) - QSKIP("Variable application fonts only supported on Freetype currently"); + QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); + if (!pfdb->supportsVariableApplicationFonts()) + QSKIP("Variable application fonts not supported on this platform"); } int id = QFontDatabase::addApplicationFont(m_testFontVariable); diff --git a/tests/auto/shared/resources/testfont_variable.ttf b/tests/auto/shared/resources/testfont_variable.ttf index f183b9333d2..70f76444842 100644 Binary files a/tests/auto/shared/resources/testfont_variable.ttf and b/tests/auto/shared/resources/testfont_variable.ttf differ