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>
This commit is contained in:
parent
616d33c87a
commit
09805f355c
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user