8#include <QtCore/QThreadStorage>
9#include <QtCore/QtEndian>
11#if QT_CONFIG(directwrite)
12# if QT_CONFIG(directwrite3)
18# include "qwindowsfontenginedirectwrite_p.h"
25using namespace Qt::StringLiterals;
55 quint16 entrySelector;
59 struct TableDirectory :
public QWindowsFontDatabaseBase::FontTable
74 qint16 subscriptXSize;
75 qint16 subscriptYSize;
76 qint16 subscriptXOffset;
77 qint16 subscriptYOffset;
78 qint16 superscriptXSize;
79 qint16 superscriptYSize;
80 qint16 superscriptXOffset;
81 qint16 superscriptYOffset;
83 qint16 strikeOutPosition;
86 quint32 unicodeRanges[4];
89 quint16 firstCharIndex;
90 quint16 lastCharIndex;
96 quint32 codepageRanges[2];
108QWindowsFontDatabaseBase::FontTable *QWindowsFontDatabaseBase::EmbeddedFont::tableDirectoryEntry(
const QByteArray &tagName)
110 Q_ASSERT(tagName.size() == 4);
111 quint32 tagId = *(
reinterpret_cast<
const quint32 *>(tagName.constData()));
112 const size_t fontDataSize = m_fontData.size();
113 if (Q_UNLIKELY(fontDataSize <
sizeof(OffsetSubTable)))
116 OffsetSubTable *offsetSubTable =
reinterpret_cast<OffsetSubTable *>(m_fontData.data());
117 TableDirectory *tableDirectory =
reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
119 const size_t tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables);
120 if (Q_UNLIKELY(fontDataSize <
sizeof(OffsetSubTable) +
sizeof(TableDirectory) * tableCount))
123 TableDirectory *tableDirectoryEnd = tableDirectory + tableCount;
124 for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) {
125 if (entry->identifier == tagId)
132QString QWindowsFontDatabaseBase::EmbeddedFont::familyName(QWindowsFontDatabaseBase::FontTable *directoryEntry)
136 TableDirectory *nameTableDirectoryEntry =
static_cast<TableDirectory *>(directoryEntry);
137 if (nameTableDirectoryEntry ==
nullptr)
138 nameTableDirectoryEntry =
static_cast<TableDirectory *>(tableDirectoryEntry(
"name"));
140 if (nameTableDirectoryEntry !=
nullptr) {
141 quint32 offset = qFromBigEndian<quint32>(nameTableDirectoryEntry->offset);
142 if (Q_UNLIKELY(quint32(m_fontData.size()) < offset +
sizeof(NameTable)))
145 NameTable *nameTable =
reinterpret_cast<NameTable *>(m_fontData.data() + offset);
146 NameRecord *nameRecord =
reinterpret_cast<NameRecord *>(nameTable + 1);
148 quint16 nameTableCount = qFromBigEndian<quint16>(nameTable->count);
149 if (Q_UNLIKELY(quint32(m_fontData.size()) < offset +
sizeof(NameRecord) * nameTableCount))
152 for (
int i = 0; i < nameTableCount; ++i, ++nameRecord) {
153 if (qFromBigEndian<quint16>(nameRecord->nameID) == 1
154 && qFromBigEndian<quint16>(nameRecord->platformID) == 3
155 && qFromBigEndian<quint16>(nameRecord->languageID) == 0x0409) {
156 quint16 stringOffset = qFromBigEndian<quint16>(nameTable->stringOffset);
157 quint16 nameOffset = qFromBigEndian<quint16>(nameRecord->offset);
158 quint16 nameLength = qFromBigEndian<quint16>(nameRecord->length);
160 if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength))
163 const void *ptr =
reinterpret_cast<
const quint8 *>(nameTable)
167 const quint16 *s =
reinterpret_cast<
const quint16 *>(ptr);
168 const quint16 *e = s + nameLength /
sizeof(quint16);
170 name += QChar( qFromBigEndian<quint16>(*s++));
179void QWindowsFontDatabaseBase::EmbeddedFont::updateFromOS2Table(QFontEngine *fontEngine)
181 TableDirectory *os2TableEntry =
static_cast<TableDirectory *>(tableDirectoryEntry(
"OS/2"));
182 if (os2TableEntry !=
nullptr) {
183 const quint32 os2TableOffset = qFromBigEndian<quint32>(os2TableEntry->offset);
184 if (Q_UNLIKELY(qsizetype(os2TableOffset) + qsizetype(
sizeof(OS2Table)) > m_fontData.size())) {
185 qCWarning(lcQpaFonts) <<
"QWindowsFontDatabaseBase::EmbeddedFont::updateFromOS2Table: "
186 <<
"Invalid OS/2 table offset:" << os2TableOffset;
190 const OS2Table *os2Table =
191 reinterpret_cast<
const OS2Table *>(m_fontData.constData() + os2TableOffset);
193 bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0);
194 bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9);
197 fontEngine->fontDef.style = QFont::StyleItalic;
199 fontEngine->fontDef.style = QFont::StyleOblique;
201 fontEngine->fontDef.style = QFont::StyleNormal;
203 fontEngine->fontDef.weight = qFromBigEndian<quint16>(os2Table->weightClass);
207QString QWindowsFontDatabaseBase::EmbeddedFont::changeFamilyName(
const QString &newFamilyName)
209 TableDirectory *nameTableDirectoryEntry =
static_cast<TableDirectory *>(tableDirectoryEntry(
"name"));
210 if (nameTableDirectoryEntry ==
nullptr)
213 QString oldFamilyName = familyName(nameTableDirectoryEntry);
216 const int requiredRecordCount = 5;
217 quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 };
219 int sizeOfHeader =
sizeof(NameTable) +
sizeof(NameRecord) * requiredRecordCount;
220 int newFamilyNameSize = newFamilyName.size() *
int(
sizeof(quint16));
222 const QString regularString = QString::fromLatin1(
"Regular");
223 int regularStringSize = regularString.size() *
int(
sizeof(quint16));
226 int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4;
228 QByteArray newNameTable(fullSize,
char(0));
231 NameTable *nameTable =
reinterpret_cast<NameTable *>(newNameTable.data());
232 nameTable->count = qbswap<quint16>(requiredRecordCount);
233 nameTable->stringOffset = qbswap<quint16>(sizeOfHeader);
235 NameRecord *nameRecord =
reinterpret_cast<NameRecord *>(nameTable + 1);
236 for (
int i = 0; i < requiredRecordCount; ++i, nameRecord++) {
237 nameRecord->nameID = qbswap<quint16>(nameIds[i]);
238 nameRecord->encodingID = qbswap<quint16>(1);
239 nameRecord->languageID = qbswap<quint16>(0x0409);
240 nameRecord->platformID = qbswap<quint16>(3);
241 nameRecord->length = qbswap<quint16>(newFamilyNameSize);
244 if (nameIds[i] == 4) {
245 nameRecord->offset = qbswap<quint16>(newFamilyNameSize);
246 nameRecord->length = qbswap<quint16>(regularStringSize);
251 quint16 *stringStorage =
reinterpret_cast<quint16 *>(nameRecord);
252 for (QChar ch : newFamilyName)
253 *stringStorage++ = qbswap<quint16>(quint16(ch.unicode()));
255 for (QChar ch : regularString)
256 *stringStorage++ = qbswap<quint16>(quint16(ch.unicode()));
259 quint32 *p =
reinterpret_cast<quint32 *>(newNameTable.data());
260 quint32 *tableEnd =
reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
262 quint32 checkSum = 0;
264 checkSum += qFromBigEndian<quint32>(*(p++));
266 nameTableDirectoryEntry->checkSum = qbswap<quint32>(checkSum);
267 nameTableDirectoryEntry->offset = qbswap<quint32>(m_fontData.size());
268 nameTableDirectoryEntry->length = qbswap<quint32>(fullSize);
270 m_fontData.append(newNameTable);
272 return oldFamilyName;
275#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
278 class DirectWriteFontFileStream:
public IDWriteFontFileStream
280 Q_DISABLE_COPY(DirectWriteFontFileStream)
282 DirectWriteFontFileStream(
const QByteArray &fontData)
283 : m_fontData(fontData)
284 , m_referenceCount(0)
287 virtual ~DirectWriteFontFileStream()
291 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
void **object) override;
292 ULONG STDMETHODCALLTYPE AddRef() override;
293 ULONG STDMETHODCALLTYPE Release() override;
295 HRESULT STDMETHODCALLTYPE ReadFileFragment(
const void **fragmentStart, UINT64 fileOffset,
296 UINT64 fragmentSize, OUT
void **fragmentContext) override;
297 void STDMETHODCALLTYPE ReleaseFileFragment(
void *fragmentContext) override;
298 HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize) override;
299 HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime) override;
302 QByteArray m_fontData;
303 ULONG m_referenceCount;
306 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid,
void **object)
308 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
314 return E_NOINTERFACE;
318 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef()
320 return InterlockedIncrement(&m_referenceCount);
323 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release()
325 ULONG newCount = InterlockedDecrement(&m_referenceCount);
331 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment(
332 const void **fragmentStart,
335 OUT
void **fragmentContext)
337 *fragmentContext = NULL;
338 const UINT64 size = UINT64(m_fontData.size());
339 if (fileOffset <= size && fragmentSize <= size - fileOffset) {
340 *fragmentStart = m_fontData.data() + fileOffset;
343 *fragmentStart = NULL;
348 void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(
void *)
352 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize)
354 *fileSize = m_fontData.size();
358 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
364 class DirectWriteFontFileLoader:
public IDWriteLocalFontFileLoader
367 DirectWriteFontFileLoader() : m_referenceCount(0) {}
368 virtual ~DirectWriteFontFileLoader()
372 inline void addKey(
const QByteArray &fontData,
const QString &filename)
374 if (!m_fontDatas.contains(fontData.data()))
375 m_fontDatas.insert(fontData.data(), {fontData, filename});
378 HRESULT STDMETHODCALLTYPE GetFilePathLengthFromKey(
void const* fontFileReferenceKey,
379 UINT32 fontFileReferenceKeySize,
380 UINT32* filePathLength) override
382 Q_UNUSED(fontFileReferenceKeySize);
383 const void *key = *
reinterpret_cast<
void *
const *>(fontFileReferenceKey);
384 auto it = m_fontDatas.constFind(key);
385 if (it == m_fontDatas.constEnd())
388 *filePathLength = it.value().second.size();
392 HRESULT STDMETHODCALLTYPE GetFilePathFromKey(
void const* fontFileReferenceKey,
393 UINT32 fontFileReferenceKeySize,
395 UINT32 filePathSize) override
397 Q_UNUSED(fontFileReferenceKeySize);
398 const void *key = *
reinterpret_cast<
void *
const *>(fontFileReferenceKey);
399 const auto it = m_fontDatas.constFind(key);
400 if (it == m_fontDatas.constEnd())
403 const QString &path = it.value().second;
404 if (filePathSize < path.size() + 1)
407 const qsizetype length = path.toWCharArray(filePath);
408 filePath[length] =
'\0';
413 HRESULT STDMETHODCALLTYPE GetLastWriteTimeFromKey(
void const* fontFileReferenceKey,
414 UINT32 fontFileReferenceKeySize,
415 FILETIME* lastWriteTime) override
417 Q_UNUSED(fontFileReferenceKey);
418 Q_UNUSED(fontFileReferenceKeySize);
419 Q_UNUSED(lastWriteTime);
425 inline void removeKey(
const void *key)
427 m_fontDatas.remove(key);
430 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
void **object) override;
431 ULONG STDMETHODCALLTYPE AddRef() override;
432 ULONG STDMETHODCALLTYPE Release() override;
434 HRESULT STDMETHODCALLTYPE CreateStreamFromKey(
void const *fontFileReferenceKey,
435 UINT32 fontFileReferenceKeySize,
436 OUT IDWriteFontFileStream **fontFileStream) override;
444 ULONG m_referenceCount;
445 QHash<
const void *, std::pair<QByteArray, QString> > m_fontDatas;
448 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(
const IID &iid,
451 if (iid == IID_IUnknown
452 || iid == __uuidof(IDWriteFontFileLoader)
453 || iid == __uuidof(IDWriteLocalFontFileLoader)) {
459 return E_NOINTERFACE;
463 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
465 return InterlockedIncrement(&m_referenceCount);
468 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
470 ULONG newCount = InterlockedDecrement(&m_referenceCount);
476 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
477 void const *fontFileReferenceKey,
478 UINT32 fontFileReferenceKeySize,
479 IDWriteFontFileStream **fontFileStream)
481 Q_UNUSED(fontFileReferenceKeySize);
483 if (fontFileReferenceKeySize !=
sizeof(
const void *)) {
484 qWarning(
"%s: Wrong key size",
__FUNCTION__);
488 const void *key = *
reinterpret_cast<
void *
const *>(fontFileReferenceKey);
489 *fontFileStream = NULL;
490 auto it = m_fontDatas.constFind(key);
491 if (it == m_fontDatas.constEnd())
494 QByteArray fontData = it.value().first;
495 DirectWriteFontFileStream *stream =
new DirectWriteFontFileStream(fontData);
497 *fontFileStream = stream;
504class QCustomFontFileLoader
507 QCustomFontFileLoader(IDWriteFactory *factory)
509 m_directWriteFactory = factory;
511 if (m_directWriteFactory) {
512 m_directWriteFactory->AddRef();
514 m_directWriteFontFileLoader =
new DirectWriteFontFileLoader();
515 m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
519 ~QCustomFontFileLoader()
523 if (m_directWriteFactory !=
nullptr && m_directWriteFontFileLoader !=
nullptr)
524 m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
526 if (m_directWriteFactory !=
nullptr)
527 m_directWriteFactory->Release();
530 void addKey(
const QByteArray &fontData,
const QString &filename)
532 if (m_directWriteFontFileLoader !=
nullptr)
533 m_directWriteFontFileLoader->addKey(fontData, filename);
536 void removeKey(
const void *key)
538 if (m_directWriteFontFileLoader !=
nullptr)
539 m_directWriteFontFileLoader->removeKey(key);
542 IDWriteFontFileLoader *loader()
const
544 return m_directWriteFontFileLoader;
549 if (m_directWriteFontFileLoader !=
nullptr)
550 m_directWriteFontFileLoader->clear();
554 IDWriteFactory *m_directWriteFactory =
nullptr;
555 DirectWriteFontFileLoader *m_directWriteFontFileLoader =
nullptr;
562QWindowsFontEngineData::~QWindowsFontEngineData()
567#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
568 if (directWriteGdiInterop)
569 directWriteGdiInterop->Release();
570 if (directWriteFactory)
571 directWriteFactory->Release();
575QWindowsFontDatabaseBase::QWindowsFontDatabaseBase()
579QWindowsFontDatabaseBase::~QWindowsFontDatabaseBase()
585Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData)
587QSharedPointer<QWindowsFontEngineData> QWindowsFontDatabaseBase::data()
589 FontEngineThreadLocalData *data = fontEngineThreadLocalData();
590 if (!data->hasLocalData())
591 data->setLocalData(QSharedPointer<QWindowsFontEngineData>::create());
593 if (!init(data->localData()))
594 qCWarning(lcQpaFonts) <<
"Cannot initialize common font database data";
596 return data->localData();
599bool QWindowsFontDatabaseBase::init(QSharedPointer<QWindowsFontEngineData> d)
601#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
602 if (!d->directWriteFactory) {
603 createDirectWriteFactory(&d->directWriteFactory);
604 if (!d->directWriteFactory)
607 if (!d->directWriteGdiInterop) {
608 const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop);
610 qErrnoWarning(
"%s: GetGdiInterop failed",
__FUNCTION__);
620#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
621void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory)
624 IUnknown *result =
nullptr;
626# if QT_CONFIG(directwrite3)
627 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory6";
628 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory6), &result);
630 if (result ==
nullptr) {
631 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory5";
632 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result);
635 if (result ==
nullptr) {
636 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory4";
637 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory4), &result);
640 if (result ==
nullptr) {
641 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory3";
642 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
646 if (result ==
nullptr) {
647 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory2";
648 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
651 if (result ==
nullptr) {
652 qCDebug(lcQpaFonts) <<
"Trying to create plain IDWriteFactory";
653 if (FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
654 qErrnoWarning(
"DWriteCreateFactory failed");
659 *factory =
static_cast<IDWriteFactory *>(result);
663int QWindowsFontDatabaseBase::defaultVerticalDPI()
668LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(
const QFontDef &request,
const QString &faceName)
671 memset(&lf, 0,
sizeof(LOGFONT));
673 lf.lfHeight = -qRound(request.pixelSize);
676 lf.lfOrientation = 0;
677 if (request.weight == QFont::Normal)
678 lf.lfWeight = FW_DONTCARE;
680 lf.lfWeight = request.weight;
681 lf.lfItalic = request.style != QFont::StyleNormal;
682 lf.lfCharSet = DEFAULT_CHARSET;
684 int strat = OUT_DEFAULT_PRECIS;
685 if (request.styleStrategy & QFont::PreferBitmap) {
686 strat = OUT_RASTER_PRECIS;
687 }
else if (request.styleStrategy & QFont::PreferDevice) {
688 strat = OUT_DEVICE_PRECIS;
689 }
else if (request.styleStrategy & QFont::PreferOutline) {
690 strat = OUT_OUTLINE_PRECIS;
691 }
else if (request.styleStrategy & QFont::ForceOutline) {
692 strat = OUT_TT_ONLY_PRECIS;
695 lf.lfOutPrecision = strat;
697 int qual = DEFAULT_QUALITY;
699 if (request.styleStrategy & QFont::PreferMatch)
700 qual = DRAFT_QUALITY;
701 else if (request.styleStrategy & QFont::PreferQuality)
702 qual = PROOF_QUALITY;
704 if (request.styleStrategy & QFont::PreferAntialias) {
705 qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0
706 ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY;
707 }
else if (request.styleStrategy & QFont::NoAntialias) {
708 qual = NONANTIALIASED_QUALITY;
709 }
else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && data()->clearTypeEnabled) {
710 qual = ANTIALIASED_QUALITY;
715 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
717 int hint = FF_DONTCARE;
718 switch (request.styleHint) {
719 case QFont::Helvetica:
728 case QFont::OldEnglish:
729 hint = FF_DECORATIVE;
738 lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
740 QString fam = faceName;
742 fam = request.family();
745 if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) {
746 qCritical(
"%s: Family name '%s' is too long.",
__FUNCTION__, qPrintable(fam));
747 fam.truncate(LF_FACESIZE - 1);
750 memcpy(lf.lfFaceName, fam.utf16(), fam.size() *
sizeof(
wchar_t));
755QFont QWindowsFontDatabaseBase::LOGFONT_to_QFont(
const LOGFONT& logFont,
int verticalDPI_In)
757 if (verticalDPI_In <= 0)
758 verticalDPI_In = defaultVerticalDPI();
759 QFont qFont(QString::fromWCharArray(logFont.lfFaceName));
760 qFont.setItalic(logFont.lfItalic);
761 if (logFont.lfWeight != FW_DONTCARE)
762 qFont.setWeight(QFont::Weight(logFont.lfWeight));
763 const qreal logFontHeight = qAbs(logFont.lfHeight);
764 qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In));
765 qFont.setUnderline(logFont.lfUnderline);
766 qFont.setOverline(
false);
767 qFont.setStrikeOut(logFont.lfStrikeOut);
772HFONT QWindowsFontDatabaseBase::systemFont()
774 static const auto stock_sysfont =
775 reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
776 return stock_sysfont;
779QFont QWindowsFontDatabaseBase::systemDefaultFont()
782 NONCLIENTMETRICS ncm = {};
783 ncm.cbSize =
sizeof(ncm);
784 SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI());
785 const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont);
786 qCDebug(lcQpaFonts) <<
__FUNCTION__ << systemFont;
790void QWindowsFontDatabaseBase::invalidate()
792#if QT_CONFIG(directwrite)
793 m_fontFileLoader.reset(
nullptr);
797#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
798IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(
const QByteArray &fontData)
800 QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, QString{},
false);
801 Q_ASSERT(faces.size() <= 1);
803 return faces.isEmpty() ?
nullptr : faces.first();
806QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(
const QByteArray &fontData,
807 const QString &filename,
808 bool queryVariations)
const
810 QList<IDWriteFontFace *> ret;
811 QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
812 if (fontEngineData->directWriteFactory ==
nullptr) {
813 qCWarning(lcQpaFonts) <<
"DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()";
817 if (m_fontFileLoader ==
nullptr)
818 m_fontFileLoader.reset(
new QCustomFontFileLoader(fontEngineData->directWriteFactory));
820 m_fontFileLoader->addKey(fontData, filename);
822 IDWriteFontFile *fontFile =
nullptr;
823 const void *key = fontData.data();
825 HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
827 m_fontFileLoader->loader(),
830 qErrnoWarning(hres,
"%s: CreateCustomFontFileReference failed",
__FUNCTION__);
834 BOOL isSupportedFontType;
835 DWRITE_FONT_FILE_TYPE fontFileType;
836 DWRITE_FONT_FACE_TYPE fontFaceType;
837 UINT32 numberOfFaces;
838 if (FAILED(fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces))
839 || !isSupportedFontType) {
844#if QT_CONFIG(directwrite3)
845 IDWriteFactory5 *factory5 =
nullptr;
846 if (queryVariations && SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
847 reinterpret_cast<
void **>(&factory5)))) {
849 IDWriteFontSetBuilder1 *builder;
850 if (SUCCEEDED(factory5->CreateFontSetBuilder(&builder))) {
851 if (SUCCEEDED(builder->AddFontFile(fontFile))) {
852 IDWriteFontSet *fontSet;
853 if (SUCCEEDED(builder->CreateFontSet(&fontSet))) {
854 int count = fontSet->GetFontCount();
855 qCDebug(lcQpaFonts) <<
"Found" << count <<
"variations in font file";
856 for (
int i = 0; i < count; ++i) {
857 IDWriteFontFaceReference *ref;
858 if (SUCCEEDED(fontSet->GetFontFaceReference(i, &ref))) {
859 IDWriteFontFace3 *face;
860 if (SUCCEEDED(ref->CreateFontFace(&face))) {
876 Q_UNUSED(queryVariations);
881 IDWriteFontFace *directWriteFontFace =
nullptr;
882 hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
886 DWRITE_FONT_SIMULATIONS_NONE,
887 &directWriteFontFace);
889 qErrnoWarning(hres,
"%s: CreateFontFace failed",
__FUNCTION__);
893 ret.append(directWriteFontFace);
903QFontEngine *QWindowsFontDatabaseBase::fontEngine(
const QFontDef &fontDef,
void *handle)
907 return QPlatformFontDatabase::fontEngine(fontDef, handle);
910QFontEngine *QWindowsFontDatabaseBase::fontEngine(
const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
912 QFontEngine *fontEngine =
nullptr;
914#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
915 QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
916 if (fontEngineData->directWriteFactory ==
nullptr)
919 IDWriteFontFace * directWriteFontFace = createDirectWriteFace(fontData);
920 if (directWriteFontFace ==
nullptr)
923 fontEngine =
new QWindowsFontEngineDirectWrite(directWriteFontFace,
928 EmbeddedFont font(fontData);
929 font.updateFromOS2Table(fontEngine);
930 fontEngine->fontDef.families = QStringList(font.familyName());
931 fontEngine->fontDef.hintingPreference = hintingPreference;
933 directWriteFontFace->Release();
937 Q_UNUSED(hintingPreference);
943QStringList QWindowsFontDatabaseBase::familiesForScript(QFontDatabasePrivate::ExtendedScript script)
945 if (script == QFontDatabasePrivate::Script_Emoji)
946 return QStringList{} << QStringLiteral(
"Segoe UI Emoji");
948 return QStringList{};
951QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint)
955 return QStringLiteral(
"Times New Roman");
957 return QStringLiteral(
"Courier New");
958 case QFont::Monospace:
959 return QStringLiteral(
"Courier New");
961 return QStringLiteral(
"Comic Sans MS");
963 return QStringLiteral(
"Impact");
964 case QFont::Decorative:
965 return QStringLiteral(
"Old English");
966 case QFont::Helvetica:
967 return QStringLiteral(
"Arial");
972 return QStringLiteral(
"Tahoma");
977static const char *other_tryFonts[] = {
1031QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(
const QString &family)
1034 if (!QFontDatabase::writingSystems(family).contains(QFontDatabase::Symbol)) {
1036 LANGID lid = GetUserDefaultLangID();
1039 if ( lid == 0x0804 || lid == 0x1004)
1040 tryFonts = ch_CN_tryFonts;
1042 tryFonts = ch_TW_tryFonts;
1045 tryFonts = jp_tryFonts;
1048 tryFonts = kr_tryFonts;
1051 tryFonts = other_tryFonts;
1055 const QStringList families = QFontDatabase::families();
1056 const char **tf = tryFonts;
1059 const QString family = QString::fromLatin1(*tf);
1060 if (families.contains(family) || QFontDatabase::hasFamily(family))
1065 result.append(QStringLiteral(
"Segoe UI Emoji"));
1066 result.append(QStringLiteral(
"Segoe UI Symbol"));
1070QFontDef QWindowsFontDatabaseBase::sanitizeRequest(QFontDef request)
const
1072 QFontDef req = request;
1073 const QString fam = request.families.front();
1075 req.families[0] = QStringLiteral(
"MS Sans Serif");
1077 if (fam ==
"MS Sans Serif"_L1) {
1078 int height = -qRound(request.pixelSize);
1080 if (request.style == QFont::StyleItalic || (height > 18 && height != 24))
1081 req.families[0] = QStringLiteral(
"Arial");
1084 if (!(request.styleStrategy & QFont::StyleStrategy::PreferBitmap) && fam == u"Courier")
1085 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