diff options
| author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2025-04-04 12:55:14 +0200 |
|---|---|---|
| committer | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2025-04-23 11:32:40 +0200 |
| commit | 09805f355c7eb2ece70bcc58e731433980e31126 (patch) | |
| tree | d8a2aa2bf7527b421d7fd6aa9de77c24dcee9314 /src | |
| parent | 616d33c87ab6dd77809ee56e39e08eed30089130 (diff) | |
directwrite: Fix embedding fonts in PDF
For a reason still unclear to me, the PDF engine refuses to
embed fonts if the file name is empty (so fonts that are loaded
directly from byte arrays typically). It could be that this in
itself is outdated.
However, embedding fonts that are loaded from the file system has
worked so far, but in Qt 6.8 we moved to the DirectWrite engine on
Windows and this stopped working there.
The reason is that our custom file loader did not support tracking
the file name and thus it would always be empty. This is experienced
as a regression and can only be worked around by manually selecting
the GDI engine instead (with the limitations that implies).
We fix this by implementing the loader as a IDWriteLocalFontFileLoader
instead, which supports the API which we currently use to retrieve the
paths of system-wide fonts.
Pick-to: 6.8 6.9
Fixes: QTBUG-134695
Change-Id: I1411b0617fd1c113c7c28154968c234920f5289e
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Diffstat (limited to 'src')
| -rw-r--r-- | src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp | 2 | ||||
| -rw-r--r-- | src/gui/text/windows/qwindowsfontdatabasebase.cpp | 70 | ||||
| -rw-r--r-- | src/gui/text/windows/qwindowsfontdatabasebase_p.h | 1 |
3 files changed, 62 insertions, 11 deletions
diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp index 66990a563f6..25bb1863298 100644 --- a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp +++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp @@ -371,7 +371,7 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray loadedData = file.readAll(); } - QList<IDWriteFontFace *> faces = createDirectWriteFaces(loadedData); + QList<IDWriteFontFace *> faces = createDirectWriteFaces(loadedData, fileName); if (faces.isEmpty()) { qCWarning(lcQpaFonts) << "Failed to create DirectWrite face from font data. Font may be unsupported."; return QStringList(); diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp index 7dfd415ff92..990f20fa447 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -352,7 +352,7 @@ namespace { return E_NOTIMPL; } - class DirectWriteFontFileLoader: public IDWriteFontFileLoader + class DirectWriteFontFileLoader: public IDWriteLocalFontFileLoader { public: DirectWriteFontFileLoader() : m_referenceCount(0) {} @@ -360,12 +360,59 @@ namespace { { } - inline void addKey(const QByteArray &fontData) + inline void addKey(const QByteArray &fontData, const QString &filename) { if (!m_fontDatas.contains(fontData.data())) - m_fontDatas.insert(fontData.data(), fontData); + m_fontDatas.insert(fontData.data(), qMakePair(fontData, filename)); } + HRESULT STDMETHODCALLTYPE GetFilePathLengthFromKey(void const* fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + UINT32* filePathLength) override + { + Q_UNUSED(fontFileReferenceKeySize); + const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey); + auto it = m_fontDatas.constFind(key); + if (it == m_fontDatas.constEnd()) + return E_FAIL; + + *filePathLength = it.value().second.size(); + return 0; + } + + HRESULT STDMETHODCALLTYPE GetFilePathFromKey(void const* fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + WCHAR* filePath, + UINT32 filePathSize) override + { + Q_UNUSED(fontFileReferenceKeySize); + const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey); + const auto it = m_fontDatas.constFind(key); + if (it == m_fontDatas.constEnd()) + return E_FAIL; + + const QString &path = it.value().second; + if (filePathSize < path.size() + 1) + return E_FAIL; + + const qsizetype length = path.toWCharArray(filePath); + filePath[length] = '\0'; + + return 0; + } + + HRESULT STDMETHODCALLTYPE GetLastWriteTimeFromKey(void const* fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + FILETIME* lastWriteTime) override + { + Q_UNUSED(fontFileReferenceKey); + Q_UNUSED(fontFileReferenceKeySize); + Q_UNUSED(lastWriteTime); + // We never call this, so just fail + return E_FAIL; + } + + inline void removeKey(const void *key) { m_fontDatas.remove(key); @@ -386,13 +433,15 @@ namespace { private: ULONG m_referenceCount; - QHash<const void *, QByteArray> m_fontDatas; + QHash<const void *, QPair<QByteArray, QString> > m_fontDatas; }; HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid, void **object) { - if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { + if (iid == IID_IUnknown + || iid == __uuidof(IDWriteFontFileLoader) + || iid == __uuidof(IDWriteLocalFontFileLoader)) { *object = this; AddRef(); return S_OK; @@ -433,7 +482,7 @@ namespace { if (it == m_fontDatas.constEnd()) return E_FAIL; - QByteArray fontData = it.value(); + QByteArray fontData = it.value().first; DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData); stream->AddRef(); *fontFileStream = stream; @@ -469,10 +518,10 @@ public: m_directWriteFactory->Release(); } - void addKey(const QByteArray &fontData) + void addKey(const QByteArray &fontData, const QString &filename) { if (m_directWriteFontFileLoader != nullptr) - m_directWriteFontFileLoader->addKey(fontData); + m_directWriteFontFileLoader->addKey(fontData, filename); } void removeKey(const void *key) @@ -732,13 +781,14 @@ void QWindowsFontDatabaseBase::invalidate() #if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) { - QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, false); + QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, QString{}, false); Q_ASSERT(faces.size() <= 1); return faces.isEmpty() ? nullptr : faces.first(); } QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const QByteArray &fontData, + const QString &filename, bool queryVariations) const { QList<IDWriteFontFace *> ret; @@ -751,7 +801,7 @@ QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const if (m_fontFileLoader == nullptr) m_fontFileLoader.reset(new QCustomFontFileLoader(fontEngineData->directWriteFactory)); - m_fontFileLoader->addKey(fontData); + m_fontFileLoader->addKey(fontData, filename); IDWriteFontFile *fontFile = nullptr; const void *key = fontData.data(); diff --git a/src/gui/text/windows/qwindowsfontdatabasebase_p.h b/src/gui/text/windows/qwindowsfontdatabasebase_p.h index beb9b52fe48..2c5f8f63c8b 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase_p.h +++ b/src/gui/text/windows/qwindowsfontdatabasebase_p.h @@ -99,6 +99,7 @@ protected: #if QT_CONFIG(directwrite) QList<IDWriteFontFace *> createDirectWriteFaces(const QByteArray &fontData, + const QString &filename, bool queryVariations = true) const; IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData); #endif |
