8#include <QtCore/QThreadStorage>
9#include <QtCore/QtEndian>
11#if QT_CONFIG(directwrite)
12# if QT_CONFIG(directwrite3)
18# include "qwindowsfontenginedirectwrite_p.h"
23using namespace Qt::StringLiterals;
53 quint16 entrySelector;
57 struct TableDirectory :
public QWindowsFontDatabaseBase::FontTable
72 qint16 subscriptXSize;
73 qint16 subscriptYSize;
74 qint16 subscriptXOffset;
75 qint16 subscriptYOffset;
76 qint16 superscriptXSize;
77 qint16 superscriptYSize;
78 qint16 superscriptXOffset;
79 qint16 superscriptYOffset;
81 qint16 strikeOutPosition;
84 quint32 unicodeRanges[4];
87 quint16 firstCharIndex;
88 quint16 lastCharIndex;
94 quint32 codepageRanges[2];
106QWindowsFontDatabaseBase::FontTable *QWindowsFontDatabaseBase::EmbeddedFont::tableDirectoryEntry(
const QByteArray &tagName)
108 Q_ASSERT(tagName.size() == 4);
109 quint32 tagId = *(
reinterpret_cast<
const quint32 *>(tagName.constData()));
110 const size_t fontDataSize = m_fontData.size();
111 if (Q_UNLIKELY(fontDataSize <
sizeof(OffsetSubTable)))
114 OffsetSubTable *offsetSubTable =
reinterpret_cast<OffsetSubTable *>(m_fontData.data());
115 TableDirectory *tableDirectory =
reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
117 const size_t tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables);
118 if (Q_UNLIKELY(fontDataSize <
sizeof(OffsetSubTable) +
sizeof(TableDirectory) * tableCount))
121 TableDirectory *tableDirectoryEnd = tableDirectory + tableCount;
122 for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) {
123 if (entry->identifier == tagId)
130QString QWindowsFontDatabaseBase::EmbeddedFont::familyName(QWindowsFontDatabaseBase::FontTable *directoryEntry)
134 TableDirectory *nameTableDirectoryEntry =
static_cast<TableDirectory *>(directoryEntry);
135 if (nameTableDirectoryEntry ==
nullptr)
136 nameTableDirectoryEntry =
static_cast<TableDirectory *>(tableDirectoryEntry(
"name"));
138 if (nameTableDirectoryEntry !=
nullptr) {
139 quint32 offset = qFromBigEndian<quint32>(nameTableDirectoryEntry->offset);
140 if (Q_UNLIKELY(quint32(m_fontData.size()) < offset +
sizeof(NameTable)))
143 NameTable *nameTable =
reinterpret_cast<NameTable *>(m_fontData.data() + offset);
144 NameRecord *nameRecord =
reinterpret_cast<NameRecord *>(nameTable + 1);
146 quint16 nameTableCount = qFromBigEndian<quint16>(nameTable->count);
147 if (Q_UNLIKELY(quint32(m_fontData.size()) < offset +
sizeof(NameRecord) * nameTableCount))
150 for (
int i = 0; i < nameTableCount; ++i, ++nameRecord) {
151 if (qFromBigEndian<quint16>(nameRecord->nameID) == 1
152 && qFromBigEndian<quint16>(nameRecord->platformID) == 3
153 && qFromBigEndian<quint16>(nameRecord->languageID) == 0x0409) {
154 quint16 stringOffset = qFromBigEndian<quint16>(nameTable->stringOffset);
155 quint16 nameOffset = qFromBigEndian<quint16>(nameRecord->offset);
156 quint16 nameLength = qFromBigEndian<quint16>(nameRecord->length);
158 if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength))
161 const void *ptr =
reinterpret_cast<
const quint8 *>(nameTable)
165 const quint16 *s =
reinterpret_cast<
const quint16 *>(ptr);
166 const quint16 *e = s + nameLength /
sizeof(quint16);
168 name += QChar( qFromBigEndian<quint16>(*s++));
177void QWindowsFontDatabaseBase::EmbeddedFont::updateFromOS2Table(QFontEngine *fontEngine)
179 TableDirectory *os2TableEntry =
static_cast<TableDirectory *>(tableDirectoryEntry(
"OS/2"));
180 if (os2TableEntry !=
nullptr) {
181 const OS2Table *os2Table =
182 reinterpret_cast<
const OS2Table *>(m_fontData.constData()
183 + qFromBigEndian<quint32>(os2TableEntry->offset));
185 bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0);
186 bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9);
189 fontEngine->fontDef.style = QFont::StyleItalic;
191 fontEngine->fontDef.style = QFont::StyleOblique;
193 fontEngine->fontDef.style = QFont::StyleNormal;
195 fontEngine->fontDef.weight = qFromBigEndian<quint16>(os2Table->weightClass);
199QString QWindowsFontDatabaseBase::EmbeddedFont::changeFamilyName(
const QString &newFamilyName)
201 TableDirectory *nameTableDirectoryEntry =
static_cast<TableDirectory *>(tableDirectoryEntry(
"name"));
202 if (nameTableDirectoryEntry ==
nullptr)
205 QString oldFamilyName = familyName(nameTableDirectoryEntry);
208 const int requiredRecordCount = 5;
209 quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 };
211 int sizeOfHeader =
sizeof(NameTable) +
sizeof(NameRecord) * requiredRecordCount;
212 int newFamilyNameSize = newFamilyName.size() *
int(
sizeof(quint16));
214 const QString regularString = QString::fromLatin1(
"Regular");
215 int regularStringSize = regularString.size() *
int(
sizeof(quint16));
218 int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4;
220 QByteArray newNameTable(fullSize,
char(0));
223 NameTable *nameTable =
reinterpret_cast<NameTable *>(newNameTable.data());
224 nameTable->count = qbswap<quint16>(requiredRecordCount);
225 nameTable->stringOffset = qbswap<quint16>(sizeOfHeader);
227 NameRecord *nameRecord =
reinterpret_cast<NameRecord *>(nameTable + 1);
228 for (
int i = 0; i < requiredRecordCount; ++i, nameRecord++) {
229 nameRecord->nameID = qbswap<quint16>(nameIds[i]);
230 nameRecord->encodingID = qbswap<quint16>(1);
231 nameRecord->languageID = qbswap<quint16>(0x0409);
232 nameRecord->platformID = qbswap<quint16>(3);
233 nameRecord->length = qbswap<quint16>(newFamilyNameSize);
236 if (nameIds[i] == 4) {
237 nameRecord->offset = qbswap<quint16>(newFamilyNameSize);
238 nameRecord->length = qbswap<quint16>(regularStringSize);
243 quint16 *stringStorage =
reinterpret_cast<quint16 *>(nameRecord);
244 for (QChar ch : newFamilyName)
245 *stringStorage++ = qbswap<quint16>(quint16(ch.unicode()));
247 for (QChar ch : regularString)
248 *stringStorage++ = qbswap<quint16>(quint16(ch.unicode()));
251 quint32 *p =
reinterpret_cast<quint32 *>(newNameTable.data());
252 quint32 *tableEnd =
reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
254 quint32 checkSum = 0;
256 checkSum += qFromBigEndian<quint32>(*(p++));
258 nameTableDirectoryEntry->checkSum = qbswap<quint32>(checkSum);
259 nameTableDirectoryEntry->offset = qbswap<quint32>(m_fontData.size());
260 nameTableDirectoryEntry->length = qbswap<quint32>(fullSize);
262 m_fontData.append(newNameTable);
264 return oldFamilyName;
267#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
270 class DirectWriteFontFileStream:
public IDWriteFontFileStream
272 Q_DISABLE_COPY(DirectWriteFontFileStream)
274 DirectWriteFontFileStream(
const QByteArray &fontData)
275 : m_fontData(fontData)
276 , m_referenceCount(0)
279 virtual ~DirectWriteFontFileStream()
283 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
void **object) override;
284 ULONG STDMETHODCALLTYPE AddRef() override;
285 ULONG STDMETHODCALLTYPE Release() override;
287 HRESULT STDMETHODCALLTYPE ReadFileFragment(
const void **fragmentStart, UINT64 fileOffset,
288 UINT64 fragmentSize, OUT
void **fragmentContext) override;
289 void STDMETHODCALLTYPE ReleaseFileFragment(
void *fragmentContext) override;
290 HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize) override;
291 HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime) override;
294 QByteArray m_fontData;
295 ULONG m_referenceCount;
298 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid,
void **object)
300 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
306 return E_NOINTERFACE;
310 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef()
312 return InterlockedIncrement(&m_referenceCount);
315 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release()
317 ULONG newCount = InterlockedDecrement(&m_referenceCount);
323 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment(
324 const void **fragmentStart,
327 OUT
void **fragmentContext)
329 *fragmentContext = NULL;
330 if (fileOffset + fragmentSize <= quint64(m_fontData.size())) {
331 *fragmentStart = m_fontData.data() + fileOffset;
334 *fragmentStart = NULL;
339 void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(
void *)
343 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize)
345 *fileSize = m_fontData.size();
349 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
355 class DirectWriteFontFileLoader:
public IDWriteLocalFontFileLoader
358 DirectWriteFontFileLoader() : m_referenceCount(0) {}
359 virtual ~DirectWriteFontFileLoader()
363 inline void addKey(
const QByteArray &fontData,
const QString &filename)
365 if (!m_fontDatas.contains(fontData.data()))
366 m_fontDatas.insert(fontData.data(), qMakePair(fontData, filename));
369 HRESULT STDMETHODCALLTYPE GetFilePathLengthFromKey(
void const* fontFileReferenceKey,
370 UINT32 fontFileReferenceKeySize,
371 UINT32* filePathLength) override
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())
379 *filePathLength = it.value().second.size();
383 HRESULT STDMETHODCALLTYPE GetFilePathFromKey(
void const* fontFileReferenceKey,
384 UINT32 fontFileReferenceKeySize,
386 UINT32 filePathSize) override
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())
394 const QString &path = it.value().second;
395 if (filePathSize < path.size() + 1)
398 const qsizetype length = path.toWCharArray(filePath);
399 filePath[length] =
'\0';
404 HRESULT STDMETHODCALLTYPE GetLastWriteTimeFromKey(
void const* fontFileReferenceKey,
405 UINT32 fontFileReferenceKeySize,
406 FILETIME* lastWriteTime) override
408 Q_UNUSED(fontFileReferenceKey);
409 Q_UNUSED(fontFileReferenceKeySize);
410 Q_UNUSED(lastWriteTime);
416 inline void removeKey(
const void *key)
418 m_fontDatas.remove(key);
421 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
void **object) override;
422 ULONG STDMETHODCALLTYPE AddRef() override;
423 ULONG STDMETHODCALLTYPE Release() override;
425 HRESULT STDMETHODCALLTYPE CreateStreamFromKey(
void const *fontFileReferenceKey,
426 UINT32 fontFileReferenceKeySize,
427 OUT IDWriteFontFileStream **fontFileStream) override;
435 ULONG m_referenceCount;
436 QHash<
const void *, QPair<QByteArray, QString> > m_fontDatas;
439 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(
const IID &iid,
442 if (iid == IID_IUnknown
443 || iid == __uuidof(IDWriteFontFileLoader)
444 || iid == __uuidof(IDWriteLocalFontFileLoader)) {
450 return E_NOINTERFACE;
454 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
456 return InterlockedIncrement(&m_referenceCount);
459 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
461 ULONG newCount = InterlockedDecrement(&m_referenceCount);
467 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
468 void const *fontFileReferenceKey,
469 UINT32 fontFileReferenceKeySize,
470 IDWriteFontFileStream **fontFileStream)
472 Q_UNUSED(fontFileReferenceKeySize);
474 if (fontFileReferenceKeySize !=
sizeof(
const void *)) {
475 qWarning(
"%s: Wrong key size",
__FUNCTION__);
479 const void *key = *
reinterpret_cast<
void *
const *>(fontFileReferenceKey);
480 *fontFileStream = NULL;
481 auto it = m_fontDatas.constFind(key);
482 if (it == m_fontDatas.constEnd())
485 QByteArray fontData = it.value().first;
486 DirectWriteFontFileStream *stream =
new DirectWriteFontFileStream(fontData);
488 *fontFileStream = stream;
495class QCustomFontFileLoader
498 QCustomFontFileLoader(IDWriteFactory *factory)
500 m_directWriteFactory = factory;
502 if (m_directWriteFactory) {
503 m_directWriteFactory->AddRef();
505 m_directWriteFontFileLoader =
new DirectWriteFontFileLoader();
506 m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
510 ~QCustomFontFileLoader()
514 if (m_directWriteFactory !=
nullptr && m_directWriteFontFileLoader !=
nullptr)
515 m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
517 if (m_directWriteFactory !=
nullptr)
518 m_directWriteFactory->Release();
521 void addKey(
const QByteArray &fontData,
const QString &filename)
523 if (m_directWriteFontFileLoader !=
nullptr)
524 m_directWriteFontFileLoader->addKey(fontData, filename);
527 void removeKey(
const void *key)
529 if (m_directWriteFontFileLoader !=
nullptr)
530 m_directWriteFontFileLoader->removeKey(key);
533 IDWriteFontFileLoader *loader()
const
535 return m_directWriteFontFileLoader;
540 if (m_directWriteFontFileLoader !=
nullptr)
541 m_directWriteFontFileLoader->clear();
545 IDWriteFactory *m_directWriteFactory =
nullptr;
546 DirectWriteFontFileLoader *m_directWriteFontFileLoader =
nullptr;
553QWindowsFontEngineData::~QWindowsFontEngineData()
558#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
559 if (directWriteGdiInterop)
560 directWriteGdiInterop->Release();
561 if (directWriteFactory)
562 directWriteFactory->Release();
566QWindowsFontDatabaseBase::QWindowsFontDatabaseBase()
570QWindowsFontDatabaseBase::~QWindowsFontDatabaseBase()
576Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData)
578QSharedPointer<QWindowsFontEngineData> QWindowsFontDatabaseBase::data()
580 FontEngineThreadLocalData *data = fontEngineThreadLocalData();
581 if (!data->hasLocalData())
582 data->setLocalData(QSharedPointer<QWindowsFontEngineData>::create());
584 if (!init(data->localData()))
585 qCWarning(lcQpaFonts) <<
"Cannot initialize common font database data";
587 return data->localData();
590bool QWindowsFontDatabaseBase::init(QSharedPointer<QWindowsFontEngineData> d)
592#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
593 if (!d->directWriteFactory) {
594 createDirectWriteFactory(&d->directWriteFactory);
595 if (!d->directWriteFactory)
598 if (!d->directWriteGdiInterop) {
599 const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop);
601 qErrnoWarning(
"%s: GetGdiInterop failed",
__FUNCTION__);
611#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
612void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory)
615 IUnknown *result =
nullptr;
617# if QT_CONFIG(directwrite3)
618 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory6";
619 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory6), &result);
621 if (result ==
nullptr) {
622 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory5";
623 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result);
626 if (result ==
nullptr) {
627 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory3";
628 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
632 if (result ==
nullptr) {
633 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory2";
634 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
637 if (result ==
nullptr) {
638 qCDebug(lcQpaFonts) <<
"Trying to create plain IDWriteFactory";
639 if (FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
640 qErrnoWarning(
"DWriteCreateFactory failed");
645 *factory =
static_cast<IDWriteFactory *>(result);
649int QWindowsFontDatabaseBase::defaultVerticalDPI()
654LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(
const QFontDef &request,
const QString &faceName)
657 memset(&lf, 0,
sizeof(LOGFONT));
659 lf.lfHeight = -qRound(request.pixelSize);
662 lf.lfOrientation = 0;
663 if (request.weight == QFont::Normal)
664 lf.lfWeight = FW_DONTCARE;
666 lf.lfWeight = request.weight;
667 lf.lfItalic = request.style != QFont::StyleNormal;
668 lf.lfCharSet = DEFAULT_CHARSET;
670 int strat = OUT_DEFAULT_PRECIS;
671 if (request.styleStrategy & QFont::PreferBitmap) {
672 strat = OUT_RASTER_PRECIS;
673 }
else if (request.styleStrategy & QFont::PreferDevice) {
674 strat = OUT_DEVICE_PRECIS;
675 }
else if (request.styleStrategy & QFont::PreferOutline) {
676 strat = OUT_OUTLINE_PRECIS;
677 }
else if (request.styleStrategy & QFont::ForceOutline) {
678 strat = OUT_TT_ONLY_PRECIS;
681 lf.lfOutPrecision = strat;
683 int qual = DEFAULT_QUALITY;
685 if (request.styleStrategy & QFont::PreferMatch)
686 qual = DRAFT_QUALITY;
687 else if (request.styleStrategy & QFont::PreferQuality)
688 qual = PROOF_QUALITY;
690 if (request.styleStrategy & QFont::PreferAntialias) {
691 qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0
692 ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY;
693 }
else if (request.styleStrategy & QFont::NoAntialias) {
694 qual = NONANTIALIASED_QUALITY;
695 }
else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && data()->clearTypeEnabled) {
696 qual = ANTIALIASED_QUALITY;
701 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
703 int hint = FF_DONTCARE;
704 switch (request.styleHint) {
705 case QFont::Helvetica:
714 case QFont::OldEnglish:
715 hint = FF_DECORATIVE;
724 lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
726 QString fam = faceName;
728 fam = request.families.first();
729 if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) {
730 qCritical(
"%s: Family name '%s' is too long.",
__FUNCTION__, qPrintable(fam));
731 fam.truncate(LF_FACESIZE - 1);
734 memcpy(lf.lfFaceName, fam.utf16(), fam.size() *
sizeof(
wchar_t));
739QFont QWindowsFontDatabaseBase::LOGFONT_to_QFont(
const LOGFONT& logFont,
int verticalDPI_In)
741 if (verticalDPI_In <= 0)
742 verticalDPI_In = defaultVerticalDPI();
743 QFont qFont(QString::fromWCharArray(logFont.lfFaceName));
744 qFont.setItalic(logFont.lfItalic);
745 if (logFont.lfWeight != FW_DONTCARE)
746 qFont.setWeight(QFont::Weight(logFont.lfWeight));
747 const qreal logFontHeight = qAbs(logFont.lfHeight);
748 qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In));
749 qFont.setUnderline(logFont.lfUnderline);
750 qFont.setOverline(
false);
751 qFont.setStrikeOut(logFont.lfStrikeOut);
756HFONT QWindowsFontDatabaseBase::systemFont()
758 static const auto stock_sysfont =
759 reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
760 return stock_sysfont;
763QFont QWindowsFontDatabaseBase::systemDefaultFont()
766 NONCLIENTMETRICS ncm = {};
767 ncm.cbSize =
sizeof(ncm);
768 SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI());
769 const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont);
770 qCDebug(lcQpaFonts) <<
__FUNCTION__ << systemFont;
774void QWindowsFontDatabaseBase::invalidate()
776#if QT_CONFIG(directwrite)
777 m_fontFileLoader.reset(
nullptr);
781#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
782IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(
const QByteArray &fontData)
784 QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, QString{},
false);
785 Q_ASSERT(faces.size() <= 1);
787 return faces.isEmpty() ?
nullptr : faces.first();
790QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(
const QByteArray &fontData,
791 const QString &filename,
792 bool queryVariations)
const
794 QList<IDWriteFontFace *> ret;
795 QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
796 if (fontEngineData->directWriteFactory ==
nullptr) {
797 qCWarning(lcQpaFonts) <<
"DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()";
801 if (m_fontFileLoader ==
nullptr)
802 m_fontFileLoader.reset(
new QCustomFontFileLoader(fontEngineData->directWriteFactory));
804 m_fontFileLoader->addKey(fontData, filename);
806 IDWriteFontFile *fontFile =
nullptr;
807 const void *key = fontData.data();
809 HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
811 m_fontFileLoader->loader(),
814 qErrnoWarning(hres,
"%s: CreateCustomFontFileReference failed",
__FUNCTION__);
818 BOOL isSupportedFontType;
819 DWRITE_FONT_FILE_TYPE fontFileType;
820 DWRITE_FONT_FACE_TYPE fontFaceType;
821 UINT32 numberOfFaces;
822 fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
823 if (!isSupportedFontType) {
828#if QT_CONFIG(directwrite3)
829 IDWriteFactory5 *factory5 =
nullptr;
830 if (queryVariations && SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
831 reinterpret_cast<
void **>(&factory5)))) {
833 IDWriteFontSetBuilder1 *builder;
834 if (SUCCEEDED(factory5->CreateFontSetBuilder(&builder))) {
835 if (SUCCEEDED(builder->AddFontFile(fontFile))) {
836 IDWriteFontSet *fontSet;
837 if (SUCCEEDED(builder->CreateFontSet(&fontSet))) {
838 int count = fontSet->GetFontCount();
839 qCDebug(lcQpaFonts) <<
"Found" << count <<
"variations in font file";
840 for (
int i = 0; i < count; ++i) {
841 IDWriteFontFaceReference *ref;
842 if (SUCCEEDED(fontSet->GetFontFaceReference(i, &ref))) {
843 IDWriteFontFace3 *face;
844 if (SUCCEEDED(ref->CreateFontFace(&face))) {
860 Q_UNUSED(queryVariations);
865 IDWriteFontFace *directWriteFontFace =
nullptr;
866 hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
870 DWRITE_FONT_SIMULATIONS_NONE,
871 &directWriteFontFace);
873 qErrnoWarning(hres,
"%s: CreateFontFace failed",
__FUNCTION__);
877 ret.append(directWriteFontFace);
887QFontEngine *QWindowsFontDatabaseBase::fontEngine(
const QFontDef &fontDef,
void *handle)
891 return QPlatformFontDatabase::fontEngine(fontDef, handle);
894QFontEngine *QWindowsFontDatabaseBase::fontEngine(
const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
896 QFontEngine *fontEngine =
nullptr;
898#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
899 QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
900 if (fontEngineData->directWriteFactory ==
nullptr)
903 IDWriteFontFace * directWriteFontFace = createDirectWriteFace(fontData);
904 if (directWriteFontFace ==
nullptr)
907 fontEngine =
new QWindowsFontEngineDirectWrite(directWriteFontFace,
912 EmbeddedFont font(fontData);
913 font.updateFromOS2Table(fontEngine);
914 fontEngine->fontDef.families = QStringList(font.familyName());
915 fontEngine->fontDef.hintingPreference = hintingPreference;
917 directWriteFontFace->Release();
921 Q_UNUSED(hintingPreference);
927QStringList QWindowsFontDatabaseBase::familiesForScript(QFontDatabasePrivate::ExtendedScript script)
929 if (script == QFontDatabasePrivate::Script_Emoji)
930 return QStringList{} << QStringLiteral(
"Segoe UI Emoji");
932 return QStringList{};
935QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint)
939 return QStringLiteral(
"Times New Roman");
941 return QStringLiteral(
"Courier New");
942 case QFont::Monospace:
943 return QStringLiteral(
"Courier New");
945 return QStringLiteral(
"Comic Sans MS");
947 return QStringLiteral(
"Impact");
948 case QFont::Decorative:
949 return QStringLiteral(
"Old English");
950 case QFont::Helvetica:
951 return QStringLiteral(
"Arial");
956 return QStringLiteral(
"Tahoma");
961static const char *other_tryFonts[] = {
1014QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(
const QString &family)
1017 if (!QFontDatabase::writingSystems(family).contains(QFontDatabase::Symbol)) {
1019 LANGID lid = GetUserDefaultLangID();
1022 if ( lid == 0x0804 || lid == 0x1004)
1023 tryFonts = ch_CN_tryFonts;
1025 tryFonts = ch_TW_tryFonts;
1028 tryFonts = jp_tryFonts;
1031 tryFonts = kr_tryFonts;
1034 tryFonts = other_tryFonts;
1038 const QStringList families = QFontDatabase::families();
1039 const char **tf = tryFonts;
1042 const QString family = QString::fromLatin1(*tf);
1043 if (families.contains(family) || QFontDatabase::hasFamily(family))
1048 result.append(QStringLiteral(
"Segoe UI Emoji"));
1049 result.append(QStringLiteral(
"Segoe UI Symbol"));
1053QFontDef QWindowsFontDatabaseBase::sanitizeRequest(QFontDef request)
const
1055 QFontDef req = request;
1056 const QString fam = request.families.front();
1058 req.families[0] = QStringLiteral(
"MS Sans Serif");
1060 if (fam ==
"MS Sans Serif"_L1) {
1061 int height = -qRound(request.pixelSize);
1063 if (request.style == QFont::StyleItalic || (height > 18 && height != 24))
1064 req.families[0] = QStringLiteral(
"Arial");
1067 if (!(request.styleStrategy & QFont::StyleStrategy::PreferBitmap) && fam == u"Courier")
1068 req.families[0] = QStringLiteral(
"Courier New");
static const char * ch_CN_tryFonts[]
static const char * jp_tryFonts[]
static const char * kr_tryFonts[]
static const char ** tryFonts
QThreadStorage< QWindowsFontEngineDataPtr > FontEngineThreadLocalData
static const char * ch_TW_tryFonts[]
QSharedPointer< QWindowsFontEngineData > QWindowsFontEngineDataPtr