Skip to content

Commit 09805f3

Browse files
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 <[email protected]>
1 parent 616d33c commit 09805f3

File tree

3 files changed

+62
-11
lines changed

3 files changed

+62
-11
lines changed

src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray
371371
loadedData = file.readAll();
372372
}
373373

374-
QList<IDWriteFontFace *> faces = createDirectWriteFaces(loadedData);
374+
QList<IDWriteFontFace *> faces = createDirectWriteFaces(loadedData, fileName);
375375
if (faces.isEmpty()) {
376376
qCWarning(lcQpaFonts) << "Failed to create DirectWrite face from font data. Font may be unsupported.";
377377
return QStringList();

src/gui/text/windows/qwindowsfontdatabasebase.cpp

+60-10
Original file line numberDiff line numberDiff line change
@@ -352,20 +352,67 @@ namespace {
352352
return E_NOTIMPL;
353353
}
354354

355-
class DirectWriteFontFileLoader: public IDWriteFontFileLoader
355+
class DirectWriteFontFileLoader: public IDWriteLocalFontFileLoader
356356
{
357357
public:
358358
DirectWriteFontFileLoader() : m_referenceCount(0) {}
359359
virtual ~DirectWriteFontFileLoader()
360360
{
361361
}
362362

363-
inline void addKey(const QByteArray &fontData)
363+
inline void addKey(const QByteArray &fontData, const QString &filename)
364364
{
365365
if (!m_fontDatas.contains(fontData.data()))
366-
m_fontDatas.insert(fontData.data(), fontData);
366+
m_fontDatas.insert(fontData.data(), qMakePair(fontData, filename));
367367
}
368368

369+
HRESULT STDMETHODCALLTYPE GetFilePathLengthFromKey(void const* fontFileReferenceKey,
370+
UINT32 fontFileReferenceKeySize,
371+
UINT32* filePathLength) override
372+
{
373+
Q_UNUSED(fontFileReferenceKeySize);
374+
const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey);
375+
auto it = m_fontDatas.constFind(key);
376+
if (it == m_fontDatas.constEnd())
377+
return E_FAIL;
378+
379+
*filePathLength = it.value().second.size();
380+
return 0;
381+
}
382+
383+
HRESULT STDMETHODCALLTYPE GetFilePathFromKey(void const* fontFileReferenceKey,
384+
UINT32 fontFileReferenceKeySize,
385+
WCHAR* filePath,
386+
UINT32 filePathSize) override
387+
{
388+
Q_UNUSED(fontFileReferenceKeySize);
389+
const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey);
390+
const auto it = m_fontDatas.constFind(key);
391+
if (it == m_fontDatas.constEnd())
392+
return E_FAIL;
393+
394+
const QString &path = it.value().second;
395+
if (filePathSize < path.size() + 1)
396+
return E_FAIL;
397+
398+
const qsizetype length = path.toWCharArray(filePath);
399+
filePath[length] = '\0';
400+
401+
return 0;
402+
}
403+
404+
HRESULT STDMETHODCALLTYPE GetLastWriteTimeFromKey(void const* fontFileReferenceKey,
405+
UINT32 fontFileReferenceKeySize,
406+
FILETIME* lastWriteTime) override
407+
{
408+
Q_UNUSED(fontFileReferenceKey);
409+
Q_UNUSED(fontFileReferenceKeySize);
410+
Q_UNUSED(lastWriteTime);
411+
// We never call this, so just fail
412+
return E_FAIL;
413+
}
414+
415+
369416
inline void removeKey(const void *key)
370417
{
371418
m_fontDatas.remove(key);
@@ -386,13 +433,15 @@ namespace {
386433

387434
private:
388435
ULONG m_referenceCount;
389-
QHash<const void *, QByteArray> m_fontDatas;
436+
QHash<const void *, QPair<QByteArray, QString> > m_fontDatas;
390437
};
391438

392439
HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid,
393440
void **object)
394441
{
395-
if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
442+
if (iid == IID_IUnknown
443+
|| iid == __uuidof(IDWriteFontFileLoader)
444+
|| iid == __uuidof(IDWriteLocalFontFileLoader)) {
396445
*object = this;
397446
AddRef();
398447
return S_OK;
@@ -433,7 +482,7 @@ namespace {
433482
if (it == m_fontDatas.constEnd())
434483
return E_FAIL;
435484

436-
QByteArray fontData = it.value();
485+
QByteArray fontData = it.value().first;
437486
DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData);
438487
stream->AddRef();
439488
*fontFileStream = stream;
@@ -469,10 +518,10 @@ class QCustomFontFileLoader
469518
m_directWriteFactory->Release();
470519
}
471520

472-
void addKey(const QByteArray &fontData)
521+
void addKey(const QByteArray &fontData, const QString &filename)
473522
{
474523
if (m_directWriteFontFileLoader != nullptr)
475-
m_directWriteFontFileLoader->addKey(fontData);
524+
m_directWriteFontFileLoader->addKey(fontData, filename);
476525
}
477526

478527
void removeKey(const void *key)
@@ -732,13 +781,14 @@ void QWindowsFontDatabaseBase::invalidate()
732781
#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
733782
IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData)
734783
{
735-
QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, false);
784+
QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, QString{}, false);
736785
Q_ASSERT(faces.size() <= 1);
737786

738787
return faces.isEmpty() ? nullptr : faces.first();
739788
}
740789

741790
QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const QByteArray &fontData,
791+
const QString &filename,
742792
bool queryVariations) const
743793
{
744794
QList<IDWriteFontFace *> ret;
@@ -751,7 +801,7 @@ QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const
751801
if (m_fontFileLoader == nullptr)
752802
m_fontFileLoader.reset(new QCustomFontFileLoader(fontEngineData->directWriteFactory));
753803

754-
m_fontFileLoader->addKey(fontData);
804+
m_fontFileLoader->addKey(fontData, filename);
755805

756806
IDWriteFontFile *fontFile = nullptr;
757807
const void *key = fontData.data();

src/gui/text/windows/qwindowsfontdatabasebase_p.h

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class Q_GUI_EXPORT QWindowsFontDatabaseBase : public QPlatformFontDatabase
9999

100100
#if QT_CONFIG(directwrite)
101101
QList<IDWriteFontFace *> createDirectWriteFaces(const QByteArray &fontData,
102+
const QString &filename,
102103
bool queryVariations = true) const;
103104
IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData);
104105
#endif

0 commit comments

Comments
 (0)