/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qwindowsfontdatabasebase_p.h" #include "qwindowsfontdatabase_p.h" #include #include #include #if QT_CONFIG(directwrite) # if QT_CONFIG(directwrite3) # include # else # include # endif # include # include "qwindowsfontenginedirectwrite_p.h" #endif QT_BEGIN_NAMESPACE // Helper classes for creating font engines directly from font data namespace { # pragma pack(1) // Common structure for all formats of the "name" table struct NameTable { quint16 format; quint16 count; quint16 stringOffset; }; struct NameRecord { quint16 platformID; quint16 encodingID; quint16 languageID; quint16 nameID; quint16 length; quint16 offset; }; struct OffsetSubTable { quint32 scalerType; quint16 numTables; quint16 searchRange; quint16 entrySelector; quint16 rangeShift; }; struct TableDirectory : public QWindowsFontDatabaseBase::FontTable { quint32 identifier; quint32 checkSum; quint32 offset; quint32 length; }; struct OS2Table { quint16 version; qint16 avgCharWidth; quint16 weightClass; quint16 widthClass; quint16 type; qint16 subscriptXSize; qint16 subscriptYSize; qint16 subscriptXOffset; qint16 subscriptYOffset; qint16 superscriptXSize; qint16 superscriptYSize; qint16 superscriptXOffset; qint16 superscriptYOffset; qint16 strikeOutSize; qint16 strikeOutPosition; qint16 familyClass; quint8 panose[10]; quint32 unicodeRanges[4]; quint8 vendorID[4]; quint16 selection; quint16 firstCharIndex; quint16 lastCharIndex; qint16 typoAscender; qint16 typoDescender; qint16 typoLineGap; quint16 winAscent; quint16 winDescent; quint32 codepageRanges[2]; qint16 height; qint16 capHeight; quint16 defaultChar; quint16 breakChar; quint16 maxContext; }; # pragma pack() } // Anonymous namespace QWindowsFontDatabaseBase::FontTable *QWindowsFontDatabaseBase::EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName) { Q_ASSERT(tagName.size() == 4); quint32 tagId = *(reinterpret_cast(tagName.constData())); const size_t fontDataSize = m_fontData.size(); if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable))) return nullptr; OffsetSubTable *offsetSubTable = reinterpret_cast(m_fontData.data()); TableDirectory *tableDirectory = reinterpret_cast(offsetSubTable + 1); const size_t tableCount = qFromBigEndian(offsetSubTable->numTables); if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount)) return nullptr; TableDirectory *tableDirectoryEnd = tableDirectory + tableCount; for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) { if (entry->identifier == tagId) return entry; } return nullptr; } QString QWindowsFontDatabaseBase::EmbeddedFont::familyName(QWindowsFontDatabaseBase::FontTable *directoryEntry) { QString name; TableDirectory *nameTableDirectoryEntry = static_cast(directoryEntry); if (nameTableDirectoryEntry == nullptr) nameTableDirectoryEntry = static_cast(tableDirectoryEntry("name")); if (nameTableDirectoryEntry != nullptr) { quint32 offset = qFromBigEndian(nameTableDirectoryEntry->offset); if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameTable))) return QString(); NameTable *nameTable = reinterpret_cast(m_fontData.data() + offset); NameRecord *nameRecord = reinterpret_cast(nameTable + 1); quint16 nameTableCount = qFromBigEndian(nameTable->count); if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameRecord) * nameTableCount)) return QString(); for (int i = 0; i < nameTableCount; ++i, ++nameRecord) { if (qFromBigEndian(nameRecord->nameID) == 1 && qFromBigEndian(nameRecord->platformID) == 3 // Windows && qFromBigEndian(nameRecord->languageID) == 0x0409) { // US English quint16 stringOffset = qFromBigEndian(nameTable->stringOffset); quint16 nameOffset = qFromBigEndian(nameRecord->offset); quint16 nameLength = qFromBigEndian(nameRecord->length); if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength)) return QString(); const void *ptr = reinterpret_cast(nameTable) + stringOffset + nameOffset; const quint16 *s = reinterpret_cast(ptr); const quint16 *e = s + nameLength / sizeof(quint16); while (s != e) name += QChar( qFromBigEndian(*s++)); break; } } } return name; } void QWindowsFontDatabaseBase::EmbeddedFont::updateFromOS2Table(QFontEngine *fontEngine) { TableDirectory *os2TableEntry = static_cast(tableDirectoryEntry("OS/2")); if (os2TableEntry != nullptr) { const OS2Table *os2Table = reinterpret_cast(m_fontData.constData() + qFromBigEndian(os2TableEntry->offset)); bool italic = qFromBigEndian(os2Table->selection) & (1 << 0); bool oblique = qFromBigEndian(os2Table->selection) & (1 << 9); if (italic) fontEngine->fontDef.style = QFont::StyleItalic; else if (oblique) fontEngine->fontDef.style = QFont::StyleOblique; else fontEngine->fontDef.style = QFont::StyleNormal; fontEngine->fontDef.weight = qFromBigEndian(os2Table->weightClass); } } QString QWindowsFontDatabaseBase::EmbeddedFont::changeFamilyName(const QString &newFamilyName) { TableDirectory *nameTableDirectoryEntry = static_cast(tableDirectoryEntry("name")); if (nameTableDirectoryEntry == nullptr) return QString(); QString oldFamilyName = familyName(nameTableDirectoryEntry); // Reserve size for name table header, five required name records and string const int requiredRecordCount = 5; quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 }; int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount; int newFamilyNameSize = newFamilyName.size() * int(sizeof(quint16)); const QString regularString = QString::fromLatin1("Regular"); int regularStringSize = regularString.size() * int(sizeof(quint16)); // Align table size of table to 32 bits (pad with 0) int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4; QByteArray newNameTable(fullSize, char(0)); { NameTable *nameTable = reinterpret_cast(newNameTable.data()); nameTable->count = qbswap(requiredRecordCount); nameTable->stringOffset = qbswap(sizeOfHeader); NameRecord *nameRecord = reinterpret_cast(nameTable + 1); for (int i = 0; i < requiredRecordCount; ++i, nameRecord++) { nameRecord->nameID = qbswap(nameIds[i]); nameRecord->encodingID = qbswap(1); nameRecord->languageID = qbswap(0x0409); nameRecord->platformID = qbswap(3); nameRecord->length = qbswap(newFamilyNameSize); // Special case for sub-family if (nameIds[i] == 4) { nameRecord->offset = qbswap(newFamilyNameSize); nameRecord->length = qbswap(regularStringSize); } } // nameRecord now points to string data quint16 *stringStorage = reinterpret_cast(nameRecord); const quint16 *sourceString = newFamilyName.utf16(); for (int i = 0; i < newFamilyName.size(); ++i) stringStorage[i] = qbswap(sourceString[i]); stringStorage += newFamilyName.size(); sourceString = regularString.utf16(); for (int i = 0; i < regularString.size(); ++i) stringStorage[i] = qbswap(sourceString[i]); } quint32 *p = reinterpret_cast(newNameTable.data()); quint32 *tableEnd = reinterpret_cast(newNameTable.data() + fullSize); quint32 checkSum = 0; while (p < tableEnd) checkSum += qFromBigEndian(*(p++)); nameTableDirectoryEntry->checkSum = qbswap(checkSum); nameTableDirectoryEntry->offset = qbswap(m_fontData.size()); nameTableDirectoryEntry->length = qbswap(fullSize); m_fontData.append(newNameTable); return oldFamilyName; } #if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) namespace { class DirectWriteFontFileStream: public IDWriteFontFileStream { Q_DISABLE_COPY(DirectWriteFontFileStream) public: DirectWriteFontFileStream(const QByteArray &fontData) : m_fontData(fontData) , m_referenceCount(0) { } virtual ~DirectWriteFontFileStream() { } HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object) override; ULONG STDMETHODCALLTYPE AddRef() override; ULONG STDMETHODCALLTYPE Release() override; HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset, UINT64 fragmentSize, OUT void **fragmentContext) override; void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext) override; HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize) override; HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime) override; private: QByteArray m_fontData; ULONG m_referenceCount; }; HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object) { if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { *object = this; AddRef(); return S_OK; } else { *object = NULL; return E_NOINTERFACE; } } ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef() { return InterlockedIncrement(&m_referenceCount); } ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release() { ULONG newCount = InterlockedDecrement(&m_referenceCount); if (newCount == 0) delete this; return newCount; } HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment( const void **fragmentStart, UINT64 fileOffset, UINT64 fragmentSize, OUT void **fragmentContext) { *fragmentContext = NULL; if (fileOffset + fragmentSize <= quint64(m_fontData.size())) { *fragmentStart = m_fontData.data() + fileOffset; return S_OK; } else { *fragmentStart = NULL; return E_FAIL; } } void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *) { } HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize) { *fileSize = m_fontData.size(); return S_OK; } HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) { *lastWriteTime = 0; return E_NOTIMPL; } class DirectWriteFontFileLoader: public IDWriteFontFileLoader { public: DirectWriteFontFileLoader() : m_referenceCount(0) {} virtual ~DirectWriteFontFileLoader() { } inline void addKey(const void *key, const QByteArray &fontData) { Q_ASSERT(!m_fontDatas.contains(key)); m_fontDatas.insert(key, fontData); } inline void removeKey(const void *key) { m_fontDatas.remove(key); } HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object) override; ULONG STDMETHODCALLTYPE AddRef() override; ULONG STDMETHODCALLTYPE Release() override; HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey, UINT32 fontFileReferenceKeySize, OUT IDWriteFontFileStream **fontFileStream) override; private: ULONG m_referenceCount; QHash m_fontDatas; }; HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid, void **object) { if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { *object = this; AddRef(); return S_OK; } else { *object = NULL; return E_NOINTERFACE; } } ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef() { return InterlockedIncrement(&m_referenceCount); } ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release() { ULONG newCount = InterlockedDecrement(&m_referenceCount); if (newCount == 0) delete this; return newCount; } HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey( void const *fontFileReferenceKey, UINT32 fontFileReferenceKeySize, IDWriteFontFileStream **fontFileStream) { Q_UNUSED(fontFileReferenceKeySize); if (fontFileReferenceKeySize != sizeof(const void *)) { qWarning("%s: Wrong key size", __FUNCTION__); return E_FAIL; } const void *key = *reinterpret_cast(fontFileReferenceKey); *fontFileStream = NULL; auto it = m_fontDatas.constFind(key); if (it == m_fontDatas.constEnd()) return E_FAIL; QByteArray fontData = it.value(); DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData); stream->AddRef(); *fontFileStream = stream; return S_OK; } class CustomFontFileLoader { public: CustomFontFileLoader(IDWriteFactory *factory) { m_directWriteFactory = factory; if (m_directWriteFactory) { m_directWriteFactory->AddRef(); m_directWriteFontFileLoader = new DirectWriteFontFileLoader(); m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader); } } ~CustomFontFileLoader() { if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr) m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader); if (m_directWriteFactory != nullptr) m_directWriteFactory->Release(); } void addKey(const void *key, const QByteArray &fontData) { if (m_directWriteFontFileLoader != nullptr) m_directWriteFontFileLoader->addKey(key, fontData); } void removeKey(const void *key) { if (m_directWriteFontFileLoader != nullptr) m_directWriteFontFileLoader->removeKey(key); } IDWriteFontFileLoader *loader() const { return m_directWriteFontFileLoader; } private: IDWriteFactory *m_directWriteFactory = nullptr; DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr; }; } // Anonymous namespace #endif // directwrite && direct2d QWindowsFontEngineData::~QWindowsFontEngineData() { if (hdc) DeleteDC(hdc); #if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) if (directWriteGdiInterop) directWriteGdiInterop->Release(); if (directWriteFactory) directWriteFactory->Release(); #endif } QWindowsFontDatabaseBase::QWindowsFontDatabaseBase() { } QWindowsFontDatabaseBase::~QWindowsFontDatabaseBase() { } typedef QSharedPointer QWindowsFontEngineDataPtr; typedef QThreadStorage FontEngineThreadLocalData; Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData) QSharedPointer QWindowsFontDatabaseBase::data() { FontEngineThreadLocalData *data = fontEngineThreadLocalData(); if (!data->hasLocalData()) data->setLocalData(QSharedPointer::create()); if (!init(data->localData())) qCWarning(lcQpaFonts) << "Cannot initialize common font database data"; return data->localData(); } bool QWindowsFontDatabaseBase::init(QSharedPointer d) { #if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) if (!d->directWriteFactory) { createDirectWriteFactory(&d->directWriteFactory); if (!d->directWriteFactory) return false; } if (!d->directWriteGdiInterop) { const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop); if (FAILED(hr)) { qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__); return false; } } #else Q_UNUSED(d); #endif // directwrite && direct2d return true; } #if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) // ### Qt 6: Link directly to dwrite instead typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **); static inline DWriteCreateFactoryType resolveDWriteCreateFactory() { QSystemLibrary library(QStringLiteral("dwrite")); QFunctionPointer result = library.resolve("DWriteCreateFactory"); if (Q_UNLIKELY(!result)) { qWarning("Unable to load dwrite.dll"); return nullptr; } return reinterpret_cast(result); } void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory) { *factory = nullptr; static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory(); if (!dWriteCreateFactory) return; IUnknown *result = nullptr; # if QT_CONFIG(directwrite3) dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result); # endif if (result == nullptr) dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result); if (result == nullptr) { if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) { qErrnoWarning("DWriteCreateFactory failed"); return; } } *factory = static_cast(result); } #endif // directwrite && direct2d static int s_defaultVerticalDPI = 96; // Native Pixels int QWindowsFontDatabaseBase::defaultVerticalDPI() { return s_defaultVerticalDPI; } void QWindowsFontDatabaseBase::setDefaultVerticalDPI(int d) { s_defaultVerticalDPI = d; } LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(const QFontDef &request, const QString &faceName) { LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); lf.lfHeight = -qRound(request.pixelSize); lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; if (request.weight == QFont::Normal) lf.lfWeight = FW_DONTCARE; else lf.lfWeight = request.weight; lf.lfItalic = request.style != QFont::StyleNormal; lf.lfCharSet = DEFAULT_CHARSET; int strat = OUT_DEFAULT_PRECIS; if (request.styleStrategy & QFont::PreferBitmap) { strat = OUT_RASTER_PRECIS; } else if (request.styleStrategy & QFont::PreferDevice) { strat = OUT_DEVICE_PRECIS; } else if (request.styleStrategy & QFont::PreferOutline) { strat = OUT_OUTLINE_PRECIS; } else if (request.styleStrategy & QFont::ForceOutline) { strat = OUT_TT_ONLY_PRECIS; } lf.lfOutPrecision = strat; int qual = DEFAULT_QUALITY; if (request.styleStrategy & QFont::PreferMatch) qual = DRAFT_QUALITY; else if (request.styleStrategy & QFont::PreferQuality) qual = PROOF_QUALITY; if (request.styleStrategy & QFont::PreferAntialias) { qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0 ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY; } else if (request.styleStrategy & QFont::NoAntialias) { qual = NONANTIALIASED_QUALITY; } else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && data()->clearTypeEnabled) { qual = ANTIALIASED_QUALITY; } lf.lfQuality = qual; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; int hint = FF_DONTCARE; switch (request.styleHint) { case QFont::Helvetica: hint = FF_SWISS; break; case QFont::Times: hint = FF_ROMAN; break; case QFont::Courier: hint = FF_MODERN; break; case QFont::OldEnglish: hint = FF_DECORATIVE; break; case QFont::System: hint = FF_MODERN; break; default: break; } lf.lfPitchAndFamily = DEFAULT_PITCH | hint; QString fam = faceName; if (fam.isEmpty()) fam = request.families.first(); if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) { qCritical("%s: Family name '%s' is too long.", __FUNCTION__, qPrintable(fam)); fam.truncate(LF_FACESIZE - 1); } if (fam.isEmpty()) fam = QStringLiteral("MS Sans Serif"); if (fam == QLatin1String("MS Sans Serif") && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) { fam = QStringLiteral("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale } if (fam == QLatin1String("Courier") && !(request.styleStrategy & QFont::PreferBitmap)) fam = QStringLiteral("Courier New"); memcpy(lf.lfFaceName, fam.utf16(), fam.size() * sizeof(wchar_t)); return lf; } QFont QWindowsFontDatabaseBase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In) { if (verticalDPI_In <= 0) verticalDPI_In = defaultVerticalDPI(); QFont qFont(QString::fromWCharArray(logFont.lfFaceName)); qFont.setItalic(logFont.lfItalic); if (logFont.lfWeight != FW_DONTCARE) qFont.setWeight(QFont::Weight(logFont.lfWeight)); const qreal logFontHeight = qAbs(logFont.lfHeight); qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In)); qFont.setUnderline(logFont.lfUnderline); qFont.setOverline(false); qFont.setStrikeOut(logFont.lfStrikeOut); return qFont; } // ### fixme Qt 6 (QTBUG-58610): See comment at QWindowsFontDatabase::systemDefaultFont() HFONT QWindowsFontDatabaseBase::systemFont() { static const auto stock_sysfont = reinterpret_cast(GetStockObject(DEFAULT_GUI_FONT)); return stock_sysfont; } QFont QWindowsFontDatabaseBase::systemDefaultFont() { // Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610) NONCLIENTMETRICS ncm; ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont; return systemFont; } #if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) const { QSharedPointer fontEngineData = data(); if (fontEngineData->directWriteFactory == nullptr) { qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()"; return nullptr; } CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory); fontFileLoader.addKey(this, fontData); IDWriteFontFile *fontFile = nullptr; const void *key = this; HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key, sizeof(void *), fontFileLoader.loader(), &fontFile); if (FAILED(hres)) { qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__); return nullptr; } BOOL isSupportedFontType; DWRITE_FONT_FILE_TYPE fontFileType; DWRITE_FONT_FACE_TYPE fontFaceType; UINT32 numberOfFaces; fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces); if (!isSupportedFontType) { fontFile->Release(); return nullptr; } // ### Currently no support for .ttc, but we could easily return a list here. IDWriteFontFace *directWriteFontFace = nullptr; hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType, 1, &fontFile, 0, DWRITE_FONT_SIMULATIONS_NONE, &directWriteFontFace); if (FAILED(hres)) { qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__); fontFile->Release(); return nullptr; } fontFile->Release(); return directWriteFontFace; } #endif // directwrite && direct2d QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { QFontEngine *fontEngine = nullptr; #if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) QSharedPointer fontEngineData = data(); if (fontEngineData->directWriteFactory == nullptr) return nullptr; IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData); fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace, pixelSize, fontEngineData); // Get font family from font data EmbeddedFont font(fontData); font.updateFromOS2Table(fontEngine); fontEngine->fontDef.families = QStringList(font.familyName()); fontEngine->fontDef.hintingPreference = hintingPreference; directWriteFontFace->Release(); #else // directwrite && direct2d Q_UNUSED(fontData); Q_UNUSED(pixelSize); Q_UNUSED(hintingPreference); #endif return fontEngine; } QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint) { switch (styleHint) { case QFont::Times: return QStringLiteral("Times New Roman"); case QFont::Courier: return QStringLiteral("Courier New"); case QFont::Monospace: return QStringLiteral("Courier New"); case QFont::Cursive: return QStringLiteral("Comic Sans MS"); case QFont::Fantasy: return QStringLiteral("Impact"); case QFont::Decorative: return QStringLiteral("Old English"); case QFont::Helvetica: return QStringLiteral("Arial"); case QFont::System: default: break; } return QStringLiteral("MS Shell Dlg 2"); } // Creation functions static const char *other_tryFonts[] = { "Arial", "MS UI Gothic", "Gulim", "SimSun", "PMingLiU", "Arial Unicode MS", 0 }; static const char *jp_tryFonts [] = { "MS UI Gothic", "Arial", "Gulim", "SimSun", "PMingLiU", "Arial Unicode MS", 0 }; static const char *ch_CN_tryFonts [] = { "SimSun", "Arial", "PMingLiU", "Gulim", "MS UI Gothic", "Arial Unicode MS", 0 }; static const char *ch_TW_tryFonts [] = { "PMingLiU", "Arial", "SimSun", "Gulim", "MS UI Gothic", "Arial Unicode MS", 0 }; static const char *kr_tryFonts[] = { "Gulim", "Arial", "PMingLiU", "SimSun", "MS UI Gothic", "Arial Unicode MS", 0 }; static const char **tryFonts = nullptr; QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(const QString &family) { QStringList result; if (!QFontDatabase::writingSystems(family).contains(QFontDatabase::Symbol)) { if (!tryFonts) { LANGID lid = GetUserDefaultLangID(); switch (lid&0xff) { case LANG_CHINESE: // Chinese if ( lid == 0x0804 || lid == 0x1004) // China mainland and Singapore tryFonts = ch_CN_tryFonts; else tryFonts = ch_TW_tryFonts; // Taiwan, Hong Kong and Macau break; case LANG_JAPANESE: tryFonts = jp_tryFonts; break; case LANG_KOREAN: tryFonts = kr_tryFonts; break; default: tryFonts = other_tryFonts; break; } } const QStringList families = QFontDatabase::families(); const char **tf = tryFonts; while (tf && *tf) { // QTBUG-31689, family might be an English alias for a localized font name. const QString family = QString::fromLatin1(*tf); if (families.contains(family) || QFontDatabase::hasFamily(family)) result << family; ++tf; } } result.append(QStringLiteral("Segoe UI Emoji")); result.append(QStringLiteral("Segoe UI Symbol")); return result; } QT_END_NAMESPACE