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 OS2Table *os2Table =
184 reinterpret_cast<
const OS2Table *>(m_fontData.constData()
185 + qFromBigEndian<quint32>(os2TableEntry->offset));
187 bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0);
188 bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9);
191 fontEngine->fontDef.style = QFont::StyleItalic;
193 fontEngine->fontDef.style = QFont::StyleOblique;
195 fontEngine->fontDef.style = QFont::StyleNormal;
197 fontEngine->fontDef.weight = qFromBigEndian<quint16>(os2Table->weightClass);
201QString QWindowsFontDatabaseBase::EmbeddedFont::changeFamilyName(
const QString &newFamilyName)
203 TableDirectory *nameTableDirectoryEntry =
static_cast<TableDirectory *>(tableDirectoryEntry(
"name"));
204 if (nameTableDirectoryEntry ==
nullptr)
207 QString oldFamilyName = familyName(nameTableDirectoryEntry);
210 const int requiredRecordCount = 5;
211 quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 };
213 int sizeOfHeader =
sizeof(NameTable) +
sizeof(NameRecord) * requiredRecordCount;
214 int newFamilyNameSize = newFamilyName.size() *
int(
sizeof(quint16));
216 const QString regularString = QString::fromLatin1(
"Regular");
217 int regularStringSize = regularString.size() *
int(
sizeof(quint16));
220 int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4;
222 QByteArray newNameTable(fullSize,
char(0));
225 NameTable *nameTable =
reinterpret_cast<NameTable *>(newNameTable.data());
226 nameTable->count = qbswap<quint16>(requiredRecordCount);
227 nameTable->stringOffset = qbswap<quint16>(sizeOfHeader);
229 NameRecord *nameRecord =
reinterpret_cast<NameRecord *>(nameTable + 1);
230 for (
int i = 0; i < requiredRecordCount; ++i, nameRecord++) {
231 nameRecord->nameID = qbswap<quint16>(nameIds[i]);
232 nameRecord->encodingID = qbswap<quint16>(1);
233 nameRecord->languageID = qbswap<quint16>(0x0409);
234 nameRecord->platformID = qbswap<quint16>(3);
235 nameRecord->length = qbswap<quint16>(newFamilyNameSize);
238 if (nameIds[i] == 4) {
239 nameRecord->offset = qbswap<quint16>(newFamilyNameSize);
240 nameRecord->length = qbswap<quint16>(regularStringSize);
245 quint16 *stringStorage =
reinterpret_cast<quint16 *>(nameRecord);
246 for (QChar ch : newFamilyName)
247 *stringStorage++ = qbswap<quint16>(quint16(ch.unicode()));
249 for (QChar ch : regularString)
250 *stringStorage++ = qbswap<quint16>(quint16(ch.unicode()));
253 quint32 *p =
reinterpret_cast<quint32 *>(newNameTable.data());
254 quint32 *tableEnd =
reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
256 quint32 checkSum = 0;
258 checkSum += qFromBigEndian<quint32>(*(p++));
260 nameTableDirectoryEntry->checkSum = qbswap<quint32>(checkSum);
261 nameTableDirectoryEntry->offset = qbswap<quint32>(m_fontData.size());
262 nameTableDirectoryEntry->length = qbswap<quint32>(fullSize);
264 m_fontData.append(newNameTable);
266 return oldFamilyName;
269#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
272 class DirectWriteFontFileStream:
public IDWriteFontFileStream
274 Q_DISABLE_COPY(DirectWriteFontFileStream)
276 DirectWriteFontFileStream(
const QByteArray &fontData)
277 : m_fontData(fontData)
278 , m_referenceCount(0)
281 virtual ~DirectWriteFontFileStream()
285 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
void **object) override;
286 ULONG STDMETHODCALLTYPE AddRef() override;
287 ULONG STDMETHODCALLTYPE Release() override;
289 HRESULT STDMETHODCALLTYPE ReadFileFragment(
const void **fragmentStart, UINT64 fileOffset,
290 UINT64 fragmentSize, OUT
void **fragmentContext) override;
291 void STDMETHODCALLTYPE ReleaseFileFragment(
void *fragmentContext) override;
292 HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize) override;
293 HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime) override;
296 QByteArray m_fontData;
297 ULONG m_referenceCount;
300 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid,
void **object)
302 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
308 return E_NOINTERFACE;
312 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef()
314 return InterlockedIncrement(&m_referenceCount);
317 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release()
319 ULONG newCount = InterlockedDecrement(&m_referenceCount);
325 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment(
326 const void **fragmentStart,
329 OUT
void **fragmentContext)
331 *fragmentContext = NULL;
332 if (fileOffset + fragmentSize <= quint64(m_fontData.size())) {
333 *fragmentStart = m_fontData.data() + fileOffset;
336 *fragmentStart = NULL;
341 void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(
void *)
345 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize)
347 *fileSize = m_fontData.size();
351 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
357 class DirectWriteFontFileLoader:
public IDWriteLocalFontFileLoader
360 DirectWriteFontFileLoader() : m_referenceCount(0) {}
361 virtual ~DirectWriteFontFileLoader()
365 inline void addKey(
const QByteArray &fontData,
const QString &filename)
367 if (!m_fontDatas.contains(fontData.data()))
368 m_fontDatas.insert(fontData.data(), {fontData, filename});
371 HRESULT STDMETHODCALLTYPE GetFilePathLengthFromKey(
void const* fontFileReferenceKey,
372 UINT32 fontFileReferenceKeySize,
373 UINT32* filePathLength) override
375 Q_UNUSED(fontFileReferenceKeySize);
376 const void *key = *
reinterpret_cast<
void *
const *>(fontFileReferenceKey);
377 auto it = m_fontDatas.constFind(key);
378 if (it == m_fontDatas.constEnd())
381 *filePathLength = it.value().second.size();
385 HRESULT STDMETHODCALLTYPE GetFilePathFromKey(
void const* fontFileReferenceKey,
386 UINT32 fontFileReferenceKeySize,
388 UINT32 filePathSize) override
390 Q_UNUSED(fontFileReferenceKeySize);
391 const void *key = *
reinterpret_cast<
void *
const *>(fontFileReferenceKey);
392 const auto it = m_fontDatas.constFind(key);
393 if (it == m_fontDatas.constEnd())
396 const QString &path = it.value().second;
397 if (filePathSize < path.size() + 1)
400 const qsizetype length = path.toWCharArray(filePath);
401 filePath[length] =
'\0';
406 HRESULT STDMETHODCALLTYPE GetLastWriteTimeFromKey(
void const* fontFileReferenceKey,
407 UINT32 fontFileReferenceKeySize,
408 FILETIME* lastWriteTime) override
410 Q_UNUSED(fontFileReferenceKey);
411 Q_UNUSED(fontFileReferenceKeySize);
412 Q_UNUSED(lastWriteTime);
418 inline void removeKey(
const void *key)
420 m_fontDatas.remove(key);
423 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
void **object) override;
424 ULONG STDMETHODCALLTYPE AddRef() override;
425 ULONG STDMETHODCALLTYPE Release() override;
427 HRESULT STDMETHODCALLTYPE CreateStreamFromKey(
void const *fontFileReferenceKey,
428 UINT32 fontFileReferenceKeySize,
429 OUT IDWriteFontFileStream **fontFileStream) override;
437 ULONG m_referenceCount;
438 QHash<
const void *, std::pair<QByteArray, QString> > m_fontDatas;
441 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(
const IID &iid,
444 if (iid == IID_IUnknown
445 || iid == __uuidof(IDWriteFontFileLoader)
446 || iid == __uuidof(IDWriteLocalFontFileLoader)) {
452 return E_NOINTERFACE;
456 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
458 return InterlockedIncrement(&m_referenceCount);
461 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
463 ULONG newCount = InterlockedDecrement(&m_referenceCount);
469 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
470 void const *fontFileReferenceKey,
471 UINT32 fontFileReferenceKeySize,
472 IDWriteFontFileStream **fontFileStream)
474 Q_UNUSED(fontFileReferenceKeySize);
476 if (fontFileReferenceKeySize !=
sizeof(
const void *)) {
477 qWarning(
"%s: Wrong key size",
__FUNCTION__);
481 const void *key = *
reinterpret_cast<
void *
const *>(fontFileReferenceKey);
482 *fontFileStream = NULL;
483 auto it = m_fontDatas.constFind(key);
484 if (it == m_fontDatas.constEnd())
487 QByteArray fontData = it.value().first;
488 DirectWriteFontFileStream *stream =
new DirectWriteFontFileStream(fontData);
490 *fontFileStream = stream;
497class QCustomFontFileLoader
500 QCustomFontFileLoader(IDWriteFactory *factory)
502 m_directWriteFactory = factory;
504 if (m_directWriteFactory) {
505 m_directWriteFactory->AddRef();
507 m_directWriteFontFileLoader =
new DirectWriteFontFileLoader();
508 m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
512 ~QCustomFontFileLoader()
516 if (m_directWriteFactory !=
nullptr && m_directWriteFontFileLoader !=
nullptr)
517 m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
519 if (m_directWriteFactory !=
nullptr)
520 m_directWriteFactory->Release();
523 void addKey(
const QByteArray &fontData,
const QString &filename)
525 if (m_directWriteFontFileLoader !=
nullptr)
526 m_directWriteFontFileLoader->addKey(fontData, filename);
529 void removeKey(
const void *key)
531 if (m_directWriteFontFileLoader !=
nullptr)
532 m_directWriteFontFileLoader->removeKey(key);
535 IDWriteFontFileLoader *loader()
const
537 return m_directWriteFontFileLoader;
542 if (m_directWriteFontFileLoader !=
nullptr)
543 m_directWriteFontFileLoader->clear();
547 IDWriteFactory *m_directWriteFactory =
nullptr;
548 DirectWriteFontFileLoader *m_directWriteFontFileLoader =
nullptr;
560#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
561 if (directWriteGdiInterop)
562 directWriteGdiInterop->Release();
563 if (directWriteFactory)
564 directWriteFactory->Release();
568QWindowsFontDatabaseBase::QWindowsFontDatabaseBase()
572QWindowsFontDatabaseBase::~QWindowsFontDatabaseBase()
578Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData)
580QSharedPointer<QWindowsFontEngineData> QWindowsFontDatabaseBase::data()
582 FontEngineThreadLocalData *data = fontEngineThreadLocalData();
583 if (!data->hasLocalData())
584 data->setLocalData(QSharedPointer<QWindowsFontEngineData>::create());
586 if (!init(data->localData()))
587 qCWarning(lcQpaFonts) <<
"Cannot initialize common font database data";
589 return data->localData();
592bool QWindowsFontDatabaseBase::init(QSharedPointer<QWindowsFontEngineData> d)
594#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
595 if (!d->directWriteFactory) {
596 createDirectWriteFactory(&d->directWriteFactory);
597 if (!d->directWriteFactory)
600 if (!d->directWriteGdiInterop) {
601 const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop);
603 qErrnoWarning(
"%s: GetGdiInterop failed",
__FUNCTION__);
613#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
614void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory)
617 IUnknown *result =
nullptr;
619# if QT_CONFIG(directwrite3)
620 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory6";
621 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory6), &result);
623 if (result ==
nullptr) {
624 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory5";
625 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result);
628 if (result ==
nullptr) {
629 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory4";
630 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory4), &result);
633 if (result ==
nullptr) {
634 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory3";
635 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
639 if (result ==
nullptr) {
640 qCDebug(lcQpaFonts) <<
"Trying to create IDWriteFactory2";
641 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
644 if (result ==
nullptr) {
645 qCDebug(lcQpaFonts) <<
"Trying to create plain IDWriteFactory";
646 if (FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
647 qErrnoWarning(
"DWriteCreateFactory failed");
652 *factory =
static_cast<IDWriteFactory *>(result);
656int QWindowsFontDatabaseBase::defaultVerticalDPI()
661LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(
const QFontDef &request,
const QString &faceName)
664 memset(&lf, 0,
sizeof(LOGFONT));
666 lf.lfHeight = -qRound(request.pixelSize);
669 lf.lfOrientation = 0;
670 if (request.weight == QFont::Normal)
671 lf.lfWeight = FW_DONTCARE;
673 lf.lfWeight = request.weight;
674 lf.lfItalic = request.style != QFont::StyleNormal;
675 lf.lfCharSet = DEFAULT_CHARSET;
677 int strat = OUT_DEFAULT_PRECIS;
678 if (request.styleStrategy & QFont::PreferBitmap) {
679 strat = OUT_RASTER_PRECIS;
680 }
else if (request.styleStrategy & QFont::PreferDevice) {
681 strat = OUT_DEVICE_PRECIS;
682 }
else if (request.styleStrategy & QFont::PreferOutline) {
683 strat = OUT_OUTLINE_PRECIS;
684 }
else if (request.styleStrategy & QFont::ForceOutline) {
685 strat = OUT_TT_ONLY_PRECIS;
688 lf.lfOutPrecision = strat;
690 int qual = DEFAULT_QUALITY;
692 if (request.styleStrategy & QFont::PreferMatch)
693 qual = DRAFT_QUALITY;
694 else if (request.styleStrategy & QFont::PreferQuality)
695 qual = PROOF_QUALITY;
697 if (request.styleStrategy & QFont::PreferAntialias) {
698 qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0
699 ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY;
700 }
else if (request.styleStrategy & QFont::NoAntialias) {
701 qual = NONANTIALIASED_QUALITY;
702 }
else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && data()->clearTypeEnabled) {
703 qual = ANTIALIASED_QUALITY;
708 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
710 int hint = FF_DONTCARE;
711 switch (request.styleHint) {
712 case QFont::Helvetica:
721 case QFont::OldEnglish:
722 hint = FF_DECORATIVE;
731 lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
733 QString fam = faceName;
735 fam = request.families.first();
736 if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) {
737 qCritical(
"%s: Family name '%s' is too long.",
__FUNCTION__, qPrintable(fam));
738 fam.truncate(LF_FACESIZE - 1);
741 memcpy(lf.lfFaceName, fam.utf16(), fam.size() *
sizeof(
wchar_t));
746QFont QWindowsFontDatabaseBase::LOGFONT_to_QFont(
const LOGFONT& logFont,
int verticalDPI_In)
748 if (verticalDPI_In <= 0)
749 verticalDPI_In = defaultVerticalDPI();
750 QFont qFont(QString::fromWCharArray(logFont.lfFaceName));
751 qFont.setItalic(logFont.lfItalic);
752 if (logFont.lfWeight != FW_DONTCARE)
753 qFont.setWeight(QFont::Weight(logFont.lfWeight));
754 const qreal logFontHeight = qAbs(logFont.lfHeight);
755 qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In));
756 qFont.setUnderline(logFont.lfUnderline);
757 qFont.setOverline(
false);
758 qFont.setStrikeOut(logFont.lfStrikeOut);
763HFONT QWindowsFontDatabaseBase::systemFont()
765 static const auto stock_sysfont =
766 reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
767 return stock_sysfont;
770QFont QWindowsFontDatabaseBase::systemDefaultFont()
773 NONCLIENTMETRICS ncm = {};
774 ncm.cbSize =
sizeof(ncm);
775 SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI());
776 const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont);
777 qCDebug(lcQpaFonts) <<
__FUNCTION__ << systemFont;
781void QWindowsFontDatabaseBase::invalidate()
783#if QT_CONFIG(directwrite)
784 m_fontFileLoader.reset(
nullptr);
788#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
789IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(
const QByteArray &fontData)
791 QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, QString{},
false);
792 Q_ASSERT(faces.size() <= 1);
794 return faces.isEmpty() ?
nullptr : faces.first();
797QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(
const QByteArray &fontData,
798 const QString &filename,
799 bool queryVariations)
const
801 QList<IDWriteFontFace *> ret;
802 QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
803 if (fontEngineData->directWriteFactory ==
nullptr) {
804 qCWarning(lcQpaFonts) <<
"DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()";
808 if (m_fontFileLoader ==
nullptr)
809 m_fontFileLoader.reset(
new QCustomFontFileLoader(fontEngineData->directWriteFactory));
811 m_fontFileLoader->addKey(fontData, filename);
813 IDWriteFontFile *fontFile =
nullptr;
814 const void *key = fontData.data();
816 HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
818 m_fontFileLoader->loader(),
821 qErrnoWarning(hres,
"%s: CreateCustomFontFileReference failed",
__FUNCTION__);
825 BOOL isSupportedFontType;
826 DWRITE_FONT_FILE_TYPE fontFileType;
827 DWRITE_FONT_FACE_TYPE fontFaceType;
828 UINT32 numberOfFaces;
829 fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
830 if (!isSupportedFontType) {
835#if QT_CONFIG(directwrite3)
836 IDWriteFactory5 *factory5 =
nullptr;
837 if (queryVariations && SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
838 reinterpret_cast<
void **>(&factory5)))) {
840 IDWriteFontSetBuilder1 *builder;
841 if (SUCCEEDED(factory5->CreateFontSetBuilder(&builder))) {
842 if (SUCCEEDED(builder->AddFontFile(fontFile))) {
843 IDWriteFontSet *fontSet;
844 if (SUCCEEDED(builder->CreateFontSet(&fontSet))) {
845 int count = fontSet->GetFontCount();
846 qCDebug(lcQpaFonts) <<
"Found" << count <<
"variations in font file";
847 for (
int i = 0; i < count; ++i) {
848 IDWriteFontFaceReference *ref;
849 if (SUCCEEDED(fontSet->GetFontFaceReference(i, &ref))) {
850 IDWriteFontFace3 *face;
851 if (SUCCEEDED(ref->CreateFontFace(&face))) {
867 Q_UNUSED(queryVariations);
872 IDWriteFontFace *directWriteFontFace =
nullptr;
873 hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
877 DWRITE_FONT_SIMULATIONS_NONE,
878 &directWriteFontFace);
880 qErrnoWarning(hres,
"%s: CreateFontFace failed",
__FUNCTION__);
884 ret.append(directWriteFontFace);
894QFontEngine *QWindowsFontDatabaseBase::fontEngine(
const QFontDef &fontDef,
void *handle)
898 return QPlatformFontDatabase::fontEngine(fontDef, handle);
901QFontEngine *QWindowsFontDatabaseBase::fontEngine(
const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
903 QFontEngine *fontEngine =
nullptr;
905#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
906 QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
907 if (fontEngineData->directWriteFactory ==
nullptr)
910 IDWriteFontFace * directWriteFontFace = createDirectWriteFace(fontData);
911 if (directWriteFontFace ==
nullptr)
914 fontEngine =
new QWindowsFontEngineDirectWrite(directWriteFontFace,
919 EmbeddedFont font(fontData);
920 font.updateFromOS2Table(fontEngine);
921 fontEngine->fontDef.families = QStringList(font.familyName());
922 fontEngine->fontDef.hintingPreference = hintingPreference;
924 directWriteFontFace->Release();
928 Q_UNUSED(hintingPreference);
934QStringList QWindowsFontDatabaseBase::familiesForScript(QFontDatabasePrivate::ExtendedScript script)
936 if (script == QFontDatabasePrivate::Script_Emoji)
937 return QStringList{} << QStringLiteral(
"Segoe UI Emoji");
939 return QStringList{};
942QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint)
946 return QStringLiteral(
"Times New Roman");
948 return QStringLiteral(
"Courier New");
949 case QFont::Monospace:
950 return QStringLiteral(
"Courier New");
952 return QStringLiteral(
"Comic Sans MS");
954 return QStringLiteral(
"Impact");
955 case QFont::Decorative:
956 return QStringLiteral(
"Old English");
957 case QFont::Helvetica:
958 return QStringLiteral(
"Arial");
963 return QStringLiteral(
"Tahoma");
968static const char *other_tryFonts[] = {
1021QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(
const QString &family)
1024 if (!QFontDatabase::writingSystems(family).contains(QFontDatabase::Symbol)) {
1026 LANGID lid = GetUserDefaultLangID();
1029 if ( lid == 0x0804 || lid == 0x1004)
1030 tryFonts = ch_CN_tryFonts;
1032 tryFonts = ch_TW_tryFonts;
1035 tryFonts = jp_tryFonts;
1038 tryFonts = kr_tryFonts;
1041 tryFonts = other_tryFonts;
1045 const QStringList families = QFontDatabase::families();
1046 const char **tf = tryFonts;
1049 const QString family = QString::fromLatin1(*tf);
1050 if (families.contains(family) || QFontDatabase::hasFamily(family))
1055 result.append(QStringLiteral(
"Segoe UI Emoji"));
1056 result.append(QStringLiteral(
"Segoe UI Symbol"));
1060QFontDef QWindowsFontDatabaseBase::sanitizeRequest(QFontDef request)
const
1062 QFontDef req = request;
1063 const QString fam = request.families.front();
1065 req.families[0] = QStringLiteral(
"MS Sans Serif");
1067 if (fam ==
"MS Sans Serif"_L1) {
1068 int height = -qRound(request.pixelSize);
1070 if (request.style == QFont::StyleItalic || (height > 18 && height != 24))
1071 req.families[0] = QStringLiteral(
"Arial");
1074 if (!(request.styleStrategy & QFont::StyleStrategy::PreferBitmap) && fam == u"Courier")
1075 req.families[0] = QStringLiteral(
"Courier New");
Static constant data shared by the font engines.
~QWindowsFontEngineData()
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