Support variable applications fonts with DirectWrite

For GDI, there doesn't seem to be any way to do this, so it depends
on selecting the DirectWrite font database explicitly.

This moves the supportsVariableApplicationFonts() check into the
QPlatformFontDatabase instead of the font engine, since that's
where it belongs.

[ChangeLog][Fonts] Added support for selecting named instances in
variable application fonts when using the DirectWrite backend.

Task-number: QTBUG-108624
Change-Id: I51e0fedd7a9616088a06453a1d17f48bd18fa5a7
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2023-08-18 09:00:21 +02:00
parent 0138d910b2
commit 500be123f4
16 changed files with 208 additions and 115 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -89,6 +89,8 @@ public:
virtual bool fontsAlwaysScalable() const;
virtual QList<int> 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);

View File

@ -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

View File

@ -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;

View File

@ -249,12 +249,15 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray
loadedData = file.readAll();
}
IDWriteFontFace *face = createDirectWriteFace(loadedData);
if (face == nullptr) {
QList<IDWriteFontFace *> faces = createDirectWriteFaces(loadedData);
if (faces.isEmpty()) {
qCWarning(lcQpaFonts) << "Failed to create DirectWrite face from font data. Font may be unsupported.";
return QStringList();
}
QStringList ret;
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";
@ -269,7 +272,6 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray
writingSystems.setSupported(QFontDatabase::Any);
writingSystems.setSupported(QFontDatabase::Latin);
QStringList ret;
IDWriteFontFace3 *face3 = nullptr;
if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
reinterpret_cast<void **>(&face3)))) {
@ -341,6 +343,7 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray
}
face->Release();
}
return ret;
}
@ -425,4 +428,17 @@ QFont QWindowsDirectWriteFontDatabase::defaultFont() const
return QFont(QStringLiteral("Segoe UI"));
}
bool QWindowsDirectWriteFontDatabase::supportsVariableApplicationFonts() const
{
QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
IDWriteFactory5 *factory5 = nullptr;
if (SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
reinterpret_cast<void **>(&factory5)))) {
factory5->Release();
return true;
}
return false;
}
QT_END_NAMESPACE

View File

@ -47,6 +47,7 @@ public:
bool fontsAlwaysScalable() const override;
bool isPrivateFontFamily(const QString &family) const override;
bool supportsVariableApplicationFonts() const override;
private:
friend class QWindowsFontEngineDirectWrite;

View File

@ -550,8 +550,12 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory
IUnknown *result = nullptr;
# if QT_CONFIG(directwrite3)
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<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, false);
Q_ASSERT(faces.size() <= 1);
return faces.isEmpty() ? nullptr : faces.first();
}
QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const QByteArray &fontData,
bool queryVariations) const
{
QList<IDWriteFontFace *> ret;
QSharedPointer<QWindowsFontEngineData> 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,10 +736,46 @@ 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<void **>(&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.
if (ret.isEmpty()) {
IDWriteFontFace *directWriteFontFace = nullptr;
hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
1,
@ -736,11 +786,14 @@ IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArra
if (FAILED(hres)) {
qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
fontFile->Release();
return nullptr;
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);

View File

@ -91,7 +91,9 @@ public:
protected:
#if QT_CONFIG(directwrite)
IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData) const;
QList<IDWriteFontFace *> createDirectWriteFaces(const QByteArray &fontData,
bool queryVariations = true) const;
IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData);
#endif
private:

View File

@ -12,6 +12,9 @@
#include <private/qfont_p.h>
#include <private/qfontengine_p.h>
#include <qpa/qplatformfontdatabase.h>
#include <qpa/qplatformintegration.h>
#include <QtGui/private/qguiapplication_p.h>
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);